Merge pull request #32248 from rallytime/merge-2015.8

[2015.8] Merge forward from 2015.5 to 2015.8
This commit is contained in:
Nicole Thomas 2016-03-30 15:10:01 -06:00
commit 0f5e67de5d
7 changed files with 238 additions and 147 deletions

View File

@ -224,6 +224,7 @@ Section "MainSection" SEC01
SetOutPath "$INSTDIR\"
SetOverwrite off
CreateDirectory $INSTDIR\conf\pki\minion
CreateDirectory $INSTDIR\conf\minion.d
File /r "..\buildenv\"
Exec 'icacls c:\salt /inheritance:r /grant:r "*S-1-5-32-544":(OI)(CI)F /grant:r "*S-1-5-18":(OI)(CI)F'

View File

@ -798,9 +798,9 @@ class Single(object):
retcode = 0
if '_error' in opts_pkg:
# Refresh failed
ret = json.dumps({'local': opts_pkg})
#Refresh failed
retcode = opts_pkg['retcode']
ret = json.dumps({'local': opts_pkg['_error']})
return ret, retcode
pillar = salt.pillar.Pillar(

View File

@ -1668,16 +1668,19 @@ def mod_repo(repo, saltenv='base', **kwargs):
# secure PPAs cannot be supported as of the time of this code
# implementation via apt-add-repository. The code path for
# secure PPAs should be the same as urllib method
if HAS_SOFTWAREPROPERTIES and 'ppa_auth' not in kwargs:
if salt.utils.which('apt-add-repository') \
and 'ppa_auth' not in kwargs:
repo_info = get_repo(repo)
if repo_info:
return {repo: repo_info}
else:
if float(__grains__['osrelease']) < 12.04:
cmd = 'apt-add-repository {0}'.format(_cmd_quote(repo))
cmd = ['apt-add-repository', repo]
else:
cmd = 'apt-add-repository -y {0}'.format(_cmd_quote(repo))
out = __salt__['cmd.run_all'](cmd, **kwargs)
cmd = ['apt-add-repository', '-y', repo]
out = __salt__['cmd.run_all'](cmd,
python_shell=False,
**kwargs)
if out['retcode']:
raise CommandExecutionError(
'Unable to add PPA {0!r}. '
@ -1934,23 +1937,27 @@ def _strip_uri(repo):
return ' '.join(splits)
def expand_repo_def(repokwargs):
def expand_repo_def(**kwargs):
'''
Take a repository definition and expand it to the full pkg repository dict
that can be used for comparison. This is a helper function to make
the Debian/Ubuntu apt sources sane for comparison in the pkgrepo states.
There is no use to calling this function via the CLI.
This is designed to be called from pkgrepo states and will have little use
being called on the CLI.
'''
if 'repo' not in kwargs:
raise SaltInvocationError('missing \'repo\' argument')
_check_apt()
sanitized = {}
repo = _strip_uri(repokwargs['repo'])
repo = _strip_uri(kwargs['repo'])
if repo.startswith('ppa:') and __grains__['os'] in ('Ubuntu', 'Mint'):
dist = __grains__['lsb_distrib_codename']
owner_name, ppa_name = repo[4:].split('/', 1)
if 'ppa_auth' in repokwargs:
auth_info = '{0}@'.format(repokwargs['ppa_auth'])
if 'ppa_auth' in kwargs:
auth_info = '{0}@'.format(kwargs['ppa_auth'])
repo = LP_PVT_SRC_FORMAT.format(auth_info, owner_name, ppa_name,
dist)
else:
@ -1962,15 +1969,15 @@ def expand_repo_def(repokwargs):
else:
repo = LP_SRC_FORMAT.format(owner_name, ppa_name, dist)
if 'file' not in repokwargs:
if 'file' not in kwargs:
filename = '/etc/apt/sources.list.d/{0}-{1}-{2}.list'
repokwargs['file'] = filename.format(owner_name, ppa_name,
kwargs['file'] = filename.format(owner_name, ppa_name,
dist)
source_entry = sourceslist.SourceEntry(repo)
for kwarg in _MODIFY_OK:
if kwarg in repokwargs:
setattr(source_entry, kwarg, repokwargs[kwarg])
if kwarg in kwargs:
setattr(source_entry, kwarg, kwargs[kwarg])
sanitized['file'] = source_entry.file
sanitized['comps'] = getattr(source_entry, 'comps', [])

View File

@ -2093,7 +2093,7 @@ def list_repos(basedir=None):
return repos
def get_repo(repo, basedir=None, **kwargs): # pylint: disable=W0613
def get_repo(name, basedir=None, **kwargs): # pylint: disable=W0613
'''
Display a repo from <basedir> (default basedir: all dirs in ``reposdir``
yum option).
@ -2110,22 +2110,23 @@ def get_repo(repo, basedir=None, **kwargs): # pylint: disable=W0613
# Find out what file the repo lives in
repofile = ''
for arepo in six.iterkeys(repos):
if arepo == repo:
repofile = repos[arepo]['file']
for repo in repos:
if repo == name:
repofile = repos[repo]['file']
if repofile:
# Return just one repo
filerepos = _parse_repo_file(repofile)[1]
return filerepos[repo]
return filerepos[name]
return {}
def del_repo(repo, basedir=None, **kwargs): # pylint: disable=W0613
'''
Delete a repo from <basedir> (default basedir: all dirs in `reposdir` yum option).
Delete a repo from <basedir> (default basedir: all dirs in `reposdir` yum
option).
If the .repo file that the repo exists in does not contain any other repo
If the .repo file in which the repo exists does not contain any other repo
configuration, the file itself will be deleted.
CLI Examples:
@ -2406,18 +2407,6 @@ def file_dict(*packages):
return __salt__['lowpkg.file_dict'](*packages)
def expand_repo_def(repokwargs):
'''
Take a repository definition and expand it to the full pkg repository dict
that can be used for comparison. This is a helper function to make
certain repo managers sane for comparison in the pkgrepo states.
There is no use to calling this function via the CLI.
'''
# YUM doesn't need the data massaged.
return repokwargs
def owner(*paths):
'''
.. versionadded:: 2014.7.0

View File

@ -489,14 +489,12 @@ def _get_repo_info(alias, repos_cfg=None):
Get one repo meta-data.
'''
try:
meta = dict((repos_cfg or _get_configured_repos()).items(alias))
meta['alias'] = alias
for key, val in six.iteritems(meta):
if val in ['0', '1']:
meta[key] = int(meta[key]) == 1
elif val == 'NONE':
meta[key] = None
return meta
ret = dict((repos_cfg or _get_configured_repos()).items(alias))
ret['alias'] = alias
for key, val in six.iteritems(ret):
if val == 'NONE':
ret[key] = None
return ret
except (ValueError, configparser.NoSectionError) as error:
return {}
@ -605,11 +603,15 @@ def mod_repo(repo, **kwargs):
url = kwargs.get('url', kwargs.get('mirrorlist', kwargs.get('baseurl')))
if not url:
raise CommandExecutionError(
'Repository \'{0}\' not found and no URL passed to create one.'.format(repo))
'Repository \'{0}\' not found, and neither \'baseurl\' nor '
'\'mirrorlist\' was specified'.format(repo)
)
if not _urlparse(url).scheme:
raise CommandExecutionError(
'Repository \'{0}\' not found and passed URL looks wrong.'.format(repo))
'Repository \'{0}\' not found and URL for baseurl/mirrorlist '
'is malformed'.format(repo)
)
# Is there already such repo under different alias?
for alias in repos_cfg.sections():
@ -628,18 +630,26 @@ def mod_repo(repo, **kwargs):
if new_url == base_url:
raise CommandExecutionError(
'Repository \'{0}\' already exists as \'{1}\'.'.format(repo, alias))
'Repository \'{0}\' already exists as \'{1}\''
.format(repo, alias)
)
# Add new repo
_zypper_check_result(__salt__['cmd.run_all'](_zypper('-x', 'ar', url, repo),
output_loglevel='trace'), xml=True)
_zypper_check_result(
__salt__['cmd.run_all'](
_zypper('-x', 'ar', url, repo),
python_shell=False,
output_loglevel='trace',
),
xml=True
)
# Verify the repository has been added
repos_cfg = _get_configured_repos()
if repo not in repos_cfg.sections():
raise CommandExecutionError(
'Failed add new repository \'{0}\' for unknown reason. '
'Please look into Zypper logs.'.format(repo))
'Failed add new repository \'{0}\' for unspecified reason. '
'Please check zypper logs.'.format(repo))
added = True
# Modify added or existing repo according to the options
@ -668,14 +678,18 @@ def mod_repo(repo, **kwargs):
if cmd_opt:
cmd_opt.append(repo)
ret = __salt__['cmd.run_all'](_zypper('-x', 'mr', *cmd_opt),
output_loglevel='trace')
ret = __salt__['cmd.run_all'](
_zypper('-x', 'mr', *cmd_opt),
python_shell=False,
output_loglevel='trace'
)
_zypper_check_result(ret, xml=True)
# If repo nor added neither modified, error should be thrown
if not added and not cmd_opt:
raise CommandExecutionError(
'Modification of the repository \'{0}\' was not specified.'.format(repo))
'Specified arguments did not result in modification of repo'
)
return get_repo(repo)
@ -1463,7 +1477,7 @@ def diff(*paths):
if pkg_to_paths:
local_pkgs = __salt__['pkg.download'](*pkg_to_paths.keys())
for pkg, files in pkg_to_paths.items():
for pkg, files in six.iteritems(pkg_to_paths):
for path in files:
ret[path] = __salt__['lowpkg.diff'](local_pkgs[pkg]['path'], path) or 'Unchanged'

View File

@ -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
@ -95,6 +96,7 @@ import salt.utils
from salt.exceptions import CommandExecutionError, SaltInvocationError
from salt.modules.aptpkg import _strip_uri
from salt.state import STATE_INTERNAL_KEYWORDS as _STATE_INTERNAL_KEYWORDS
import salt.utils
def __virtual__():
@ -104,41 +106,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
@ -169,7 +185,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
@ -177,6 +193,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.
@ -238,27 +264,38 @@ 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'] in ('Ubuntu', 'Mint'):
# 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
if kwargs.pop('enabled', None):
kwargs['disabled'] = False
@ -272,60 +309,72 @@ def managed(name, **kwargs):
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
# empty file before configure
@ -334,42 +383,45 @@ def managed(name, **kwargs):
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

View File

@ -50,23 +50,51 @@ class PkgModuleTest(integration.ModuleCase,
'''
test modifying and deleting a software repository
'''
func = 'pkg.mod_repo'
os_grain = self.run_function('grains.item', ['os'])['os']
os_release_info = tuple(self.run_function('grains.item', ['osrelease_info'])['osrelease_info'])
if os_grain == 'Ubuntu' and os_release_info < (15, 10):
repo = 'ppa:saltstack/salt'
uri = 'http://ppa.launchpad.net/saltstack/salt/ubuntu'
ret = self.run_function(func, [repo, 'comps=main'])
self.assertNotEqual(ret, {})
if os_release_info[0] == 12:
try:
repo = None
if os_grain == 'Ubuntu':
repo = 'ppa:otto-kesselgulasch/gimp-edge'
uri = 'http://ppa.launchpad.net/otto-kesselgulasch/gimp-edge/ubuntu'
ret = self.run_function('pkg.mod_repo', [repo, 'comps=main'])
self.assertNotEqual(ret, {})
self.assertIn(repo, ret)
else:
self.assertIn(uri, ret.keys()[0])
self.run_function('pkg.del_repo', [repo])
else:
self.skipTest('{0} is unavailable on {1}'.format(func, os_grain))
ret = self.run_function('pkg.get_repo', [repo])
self.assertEqual(ret['uri'], uri)
elif os_grain == 'CentOS':
major_release = int(
self.run_function(
'grains.item',
['osmajorrelease']
)['osmajorrelease']
)
repo = 'saltstack'
name = 'SaltStack repo for RHEL/CentOS {0}'.format(major_release)
baseurl = 'http://repo.saltstack.com/yum/redhat/{0}/x86_64/latest/'.format(major_release)
gpgkey = 'https://repo.saltstack.com/yum/rhel{0}/SALTSTACK-GPG-KEY.pub'.format(major_release)
gpgcheck = 1
enabled = 1
ret = self.run_function(
'pkg.mod_repo',
[repo],
name=name,
baseurl=baseurl,
gpgkey=gpgkey,
gpgcheck=gpgcheck,
enabled=enabled,
)
# return data from pkg.mod_repo contains the file modified at
# the top level, so use next(iter(ret)) to get that key
self.assertNotEqual(ret, {})
repo_info = ret[next(iter(ret))]
self.assertIn(repo, repo_info)
self.assertEqual(repo_info[repo]['baseurl'], baseurl)
ret = self.run_function('pkg.get_repo', [repo])
self.assertEqual(ret['baseurl'], baseurl)
finally:
if repo is not None:
self.run_function('pkg.del_repo', [repo])
def test_owner(self):
'''