mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Properly handle yum/zypper repositories in pkgrepo.managed
When comparing the current state of the repo to the desired state, there is a key called ``disabled`` which we support, which is not in the ``pkg.get_repo`` return data. This caused yum repos to always identify as needing to be modified, and calling ``pkg.mod_repo`` every time the state was run. This commit fixes this behavior and also improves the documentation for this state.
This commit is contained in:
parent
add2111fec
commit
e7fb3095ce
1 changed files with 134 additions and 80 deletions
|
@ -79,9 +79,10 @@ these states. Here is some example SLS:
|
|||
``python-pycurl`` will need to be manually installed if it is not present
|
||||
once ``python-software-properties`` is installed.
|
||||
|
||||
On Ubuntu & Debian systems, the ```python-apt`` package is required to be installed.
|
||||
To check if this package is installed, run ``dpkg -l python-software-properties``.
|
||||
``python-apt`` will need to be manually installed if it is not present.
|
||||
On Ubuntu & Debian systems, the ```python-apt`` package is required to be
|
||||
installed. To check if this package is installed, run ``dpkg -l
|
||||
python-software-properties``. ``python-apt`` will need to be manually
|
||||
installed if it is not present.
|
||||
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
|
@ -93,6 +94,7 @@ import sys
|
|||
from salt.exceptions import CommandExecutionError
|
||||
from salt.modules.aptpkg import _strip_uri
|
||||
from salt.state import STATE_INTERNAL_KEYWORDS as _STATE_INTERNAL_KEYWORDS
|
||||
import salt.utils
|
||||
|
||||
|
||||
def __virtual__():
|
||||
|
@ -102,41 +104,55 @@ def __virtual__():
|
|||
return 'pkg.mod_repo' in __salt__
|
||||
|
||||
|
||||
def managed(name, **kwargs):
|
||||
def managed(name, ppa=None, **kwargs):
|
||||
'''
|
||||
This function manages the configuration on a system that points to the
|
||||
repositories for the system's package manager.
|
||||
This state manages software package repositories. Currently, :mod:`yum
|
||||
<salt.modules.yumpkg>`, :mod:`apt <salt.modules.aptpkg>`, and :mod:`zypper
|
||||
<salt.modules.zypper>` repositories are supported.
|
||||
|
||||
**YUM OR ZYPPER-BASED SYSTEMS**
|
||||
|
||||
.. note::
|
||||
One of ``baseurl`` or ``mirrorlist`` below is required. Additionally,
|
||||
note that this state is not presently capable of managing more than one
|
||||
repo in a single repo file, so each instance of this state will manage
|
||||
a single repo file containing the configuration for a single repo.
|
||||
|
||||
name
|
||||
The name of the package repo, as it would be referred to when running
|
||||
the regular package manager commands.
|
||||
|
||||
For yum-based systems, take note of the following configuration values:
|
||||
This value will be used in two ways: Firstly, it will be the repo ID,
|
||||
as seen in the entry in square brackets (e.g. ``[foo]``) for a given
|
||||
repo. Secondly, it will be the name of the file as stored in
|
||||
/etc/yum.repos.d (e.g. ``/etc/yum.repos.d/foo.conf``).
|
||||
|
||||
humanname
|
||||
On yum-based systems, this is stored as the "name" value in the .repo
|
||||
file in /etc/yum.repos.d/. On yum-based systems, this is required.
|
||||
This is used as the "name" value in the repo file in
|
||||
``/etc/yum.repos.d/`` (or ``/etc/zypp/repos.d`` for Suse distros).
|
||||
|
||||
baseurl
|
||||
On yum-based systems, baseurl refers to a direct URL to be used for
|
||||
this yum repo.
|
||||
One of baseurl or mirrorlist is required.
|
||||
The URL to a yum repository
|
||||
|
||||
mirrorlist
|
||||
a URL which contains a collection of baseurls to choose from. On
|
||||
yum-based systems.
|
||||
One of baseurl or mirrorlist is required.
|
||||
A URL which points to a file containing a collection of baseurls
|
||||
|
||||
comments
|
||||
Sometimes you want to supply additional information, but not as
|
||||
enabled configuration. Anything supplied for this list will be saved
|
||||
in the repo configuration with a comment marker (#) in front.
|
||||
|
||||
Additional configuration values, such as gpgkey or gpgcheck, are used
|
||||
verbatim to update the options for the yum repo in question.
|
||||
Additional configuration values seen in yum repo files, such as ``gpgkey`` or
|
||||
``gpgcheck``, will be used directly as key-value pairs. For example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
foo:
|
||||
pkgrepo.managed:
|
||||
- humanname: Personal repo for foo
|
||||
- baseurl: https://mydomain.tld/repo/foo/$releasever/$basearch
|
||||
- gpgkey: file:///etc/pki/rpm-gpg/foo-signing-key
|
||||
- gpgcheck: 1
|
||||
|
||||
|
||||
For apt-based systems, take note of the following configuration values:
|
||||
**APT-BASED SYSTEMS**
|
||||
|
||||
ppa
|
||||
On Ubuntu, you can take advantage of Personal Package Archives on
|
||||
|
@ -167,7 +183,7 @@ def managed(name, **kwargs):
|
|||
On apt-based systems this must be the complete entry as it would be
|
||||
seen in the sources.list file. This can have a limited subset of
|
||||
components (i.e. 'main') which can be added/modified with the
|
||||
"comps" option.
|
||||
``comps`` option.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -175,6 +191,16 @@ def managed(name, **kwargs):
|
|||
pkgrepo.managed:
|
||||
- name: deb http://us.archive.ubuntu.com/ubuntu precise main
|
||||
|
||||
.. note::
|
||||
|
||||
The above example is intended as a more readable way of configuring
|
||||
the SLS, it is equivalent to the following:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
'deb http://us.archive.ubuntu.com/ubuntu precise main':
|
||||
pkgrepo.managed
|
||||
|
||||
disabled
|
||||
Toggles whether or not the repo is used for resolving dependencies
|
||||
and/or installing packages.
|
||||
|
@ -235,124 +261,152 @@ def managed(name, **kwargs):
|
|||
'changes': {},
|
||||
'result': None,
|
||||
'comment': ''}
|
||||
repo = {}
|
||||
|
||||
# pkg.mod_repo has conflicting kwargs, so move 'em around
|
||||
if 'pkg.get_repo' not in __salt__:
|
||||
ret['result'] = False
|
||||
ret['comment'] = 'Repo management not implemented on this platform'
|
||||
return ret
|
||||
|
||||
if 'name' in kwargs:
|
||||
if 'ppa' in kwargs:
|
||||
ret['result'] = False
|
||||
ret['comment'] = 'You may not use both the "name" argument ' \
|
||||
'and the "ppa" argument.'
|
||||
return ret
|
||||
kwargs['repo'] = kwargs['name']
|
||||
if 'ppa' in kwargs and __grains__['os'] == 'Ubuntu':
|
||||
# overload the name/repo value for PPAs cleanly
|
||||
# this allows us to have one code-path for PPAs
|
||||
repo_name = 'ppa:{0}'.format(kwargs['ppa'])
|
||||
kwargs['repo'] = repo_name
|
||||
if 'repo' not in kwargs:
|
||||
kwargs['repo'] = name
|
||||
repo = name
|
||||
if __grains__['os'] == 'Ubuntu':
|
||||
if ppa is not None:
|
||||
# overload the name/repo value for PPAs cleanly
|
||||
# this allows us to have one code-path for PPAs
|
||||
try:
|
||||
repo = ':'.join(('ppa', ppa))
|
||||
except TypeError:
|
||||
repo = ':'.join(('ppa', str(ppa)))
|
||||
|
||||
if 'humanname' in kwargs:
|
||||
kwargs['name'] = kwargs['humanname']
|
||||
elif __grains__['os_family'].lower() in ('redhat', 'suse'):
|
||||
if 'humanname' in kwargs:
|
||||
kwargs['name'] = kwargs.pop('humanname')
|
||||
_val = lambda x: '1' if salt.utils.is_true(x) else '0'
|
||||
if 'disabled' in kwargs:
|
||||
if 'enabled' in kwargs:
|
||||
ret['result'] = False
|
||||
ret['comment'] = 'Only one of enabled/disabled is permitted'
|
||||
return ret
|
||||
_reverse = lambda x: '1' if x == '0' else '0'
|
||||
kwargs['enabled'] = _reverse(_val(kwargs.pop('disabled')))
|
||||
elif 'enabled' in kwargs:
|
||||
kwargs['enabled'] = _val(kwargs['enabled'])
|
||||
if 'name' not in kwargs:
|
||||
# Fall back to the repo name if humanname not provided
|
||||
kwargs['name'] = repo
|
||||
|
||||
for kwarg in _STATE_INTERNAL_KEYWORDS:
|
||||
kwargs.pop(kwarg, None)
|
||||
|
||||
try:
|
||||
repo = __salt__['pkg.get_repo'](
|
||||
kwargs['repo'],
|
||||
ppa_auth=kwargs.get('ppa_auth', None)
|
||||
pre = __salt__['pkg.get_repo'](
|
||||
repo,
|
||||
ppa_auth=kwargs.get('ppa_auth', None)
|
||||
)
|
||||
except CommandExecutionError as exc:
|
||||
ret['result'] = False
|
||||
ret['comment'] = \
|
||||
'Failed to configure repo {0!r}: {1}'.format(name, exc)
|
||||
'Failed to examine repo \'{0}\': {1}'.format(name, exc)
|
||||
return ret
|
||||
|
||||
# this is because of how apt-sources works. This pushes distro logic
|
||||
# This is because of how apt-sources works. This pushes distro logic
|
||||
# out of the state itself and into a module that it makes more sense
|
||||
# to use. Most package providers will simply return the data provided
|
||||
# to use. Most package providers will simply return the data provided
|
||||
# it doesn't require any "specialized" data massaging.
|
||||
if 'pkg.expand_repo_def' in __salt__:
|
||||
sanitizedkwargs = __salt__['pkg.expand_repo_def'](kwargs)
|
||||
sanitizedkwargs = __salt__['pkg.expand_repo_def'](repo=repo, **kwargs)
|
||||
else:
|
||||
sanitizedkwargs = kwargs
|
||||
if __grains__['os_family'] == 'Debian':
|
||||
kwargs['repo'] = _strip_uri(kwargs['repo'])
|
||||
|
||||
if repo:
|
||||
notset = False
|
||||
if __grains__['os_family'] == 'Debian':
|
||||
repo = _strip_uri(repo)
|
||||
|
||||
if pre:
|
||||
needs_update = False
|
||||
for kwarg in sanitizedkwargs:
|
||||
if kwarg == 'repo':
|
||||
pass
|
||||
elif kwarg not in repo:
|
||||
notset = True
|
||||
if kwarg not in pre:
|
||||
if kwarg == 'enabled':
|
||||
# On a RedHat-based OS, 'enabled' is assumed to be true if
|
||||
# not explicitly set, so we don't need to update the repo
|
||||
# if it's desired to be enabled and the 'enabled' key is
|
||||
# missing from the repo definition
|
||||
if __grains__['os_family'] == 'RedHat':
|
||||
if not salt.utils.is_true(sanitizedkwargs[kwarg]):
|
||||
needs_update = True
|
||||
else:
|
||||
needs_update = True
|
||||
else:
|
||||
needs_update = True
|
||||
elif kwarg == 'comps':
|
||||
if sorted(sanitizedkwargs[kwarg]) != sorted(repo[kwarg]):
|
||||
notset = True
|
||||
if sorted(sanitizedkwargs[kwarg]) != sorted(pre[kwarg]):
|
||||
needs_update = True
|
||||
elif kwarg == 'line' and __grains__['os_family'] == 'Debian':
|
||||
# split the line and sort everything after the URL
|
||||
sanitizedsplit = sanitizedkwargs[kwarg].split()
|
||||
sanitizedsplit[3:] = sorted(sanitizedsplit[3:])
|
||||
reposplit = repo[kwarg].split()
|
||||
reposplit = pre[kwarg].split()
|
||||
reposplit[3:] = sorted(reposplit[3:])
|
||||
if sanitizedsplit != reposplit:
|
||||
notset = True
|
||||
needs_update = True
|
||||
else:
|
||||
if str(sanitizedkwargs[kwarg]) != str(repo[kwarg]):
|
||||
notset = True
|
||||
if notset is False:
|
||||
if str(sanitizedkwargs[kwarg]) != str(pre[kwarg]):
|
||||
needs_update = True
|
||||
|
||||
if not needs_update:
|
||||
ret['result'] = True
|
||||
ret['comment'] = ('Package repo {0!r} already configured'
|
||||
ret['comment'] = ('Package repo \'{0}\' already configured'
|
||||
.format(name))
|
||||
return ret
|
||||
|
||||
if __opts__['test']:
|
||||
ret['comment'] = ('Package repo {0!r} will be configured. This may '
|
||||
'cause pkg states to behave differently than stated '
|
||||
'if this action is repeated without test=True, due '
|
||||
'to the differences in the configured repositories.'
|
||||
.format(name))
|
||||
ret['comment'] = (
|
||||
'Package repo \'{0}\' will be configured. This may cause pkg '
|
||||
'states to behave differently than stated if this action is '
|
||||
'repeated without test=True, due to the differences in the '
|
||||
'configured repositories.'.format(name)
|
||||
)
|
||||
return ret
|
||||
|
||||
try:
|
||||
if __grains__['os_family'] == 'Debian':
|
||||
__salt__['pkg.mod_repo'](saltenv=__env__, **kwargs)
|
||||
__salt__['pkg.mod_repo'](repo, saltenv=__env__, **kwargs)
|
||||
else:
|
||||
__salt__['pkg.mod_repo'](**kwargs)
|
||||
__salt__['pkg.mod_repo'](repo, **kwargs)
|
||||
except Exception as exc:
|
||||
# This is another way to pass information back from the mod_repo
|
||||
# function.
|
||||
ret['result'] = False
|
||||
ret['comment'] = \
|
||||
'Failed to configure repo {0!r}: {1}'.format(name, exc)
|
||||
'Failed to configure repo \'{0}\': {1}'.format(name, exc)
|
||||
return ret
|
||||
|
||||
try:
|
||||
repodict = __salt__['pkg.get_repo'](
|
||||
kwargs['repo'], ppa_auth=kwargs.get('ppa_auth', None)
|
||||
post = __salt__['pkg.get_repo'](
|
||||
repo,
|
||||
ppa_auth=kwargs.get('ppa_auth', None)
|
||||
)
|
||||
if repo:
|
||||
if pre:
|
||||
for kwarg in sanitizedkwargs:
|
||||
if repodict.get(kwarg) != repo.get(kwarg):
|
||||
change = {'new': repodict[kwarg],
|
||||
'old': repo.get(kwarg)}
|
||||
if post.get(kwarg) != pre.get(kwarg):
|
||||
change = {'new': post[kwarg],
|
||||
'old': pre.get(kwarg)}
|
||||
ret['changes'][kwarg] = change
|
||||
else:
|
||||
ret['changes'] = {'repo': kwargs['repo']}
|
||||
ret['changes'] = {'repo': repo}
|
||||
|
||||
ret['result'] = True
|
||||
ret['comment'] = 'Configured package repo {0!r}'.format(name)
|
||||
ret['comment'] = 'Configured package repo \'{0}\''.format(name)
|
||||
except Exception as exc:
|
||||
ret['result'] = False
|
||||
ret['comment'] = \
|
||||
'Failed to confirm config of repo {0!r}: {1}'.format(name, exc)
|
||||
'Failed to confirm config of repo \'{0}\': {1}'.format(name, exc)
|
||||
|
||||
# Clear cache of available packages, if present, since changes to the
|
||||
# repositories may change the packages that are available.
|
||||
if ret['changes']:
|
||||
sys.modules[
|
||||
__salt__['test.ping'].__module__
|
||||
].__context__.pop('pkg._avail', None)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue