Merge branch '2016.3' into '2016.11'

Conflicts:
  - salt/loader.py
  - salt/output/highstate.py
  - salt/runners/fileserver.py
This commit is contained in:
rallytime 2017-02-08 16:57:54 -07:00
commit f6aad99db2
9 changed files with 119 additions and 66 deletions

View File

@ -1463,7 +1463,10 @@ class LazyLoader(salt.utils.lazy.LazyDict):
# It default's of course to the found callable attribute name
# if no alias is defined.
funcname = getattr(mod, '__func_alias__', {}).get(attr, attr)
full_funcname = '{0}.{1}'.format(module_name, funcname)
try:
full_funcname = '.'.join((module_name, funcname))
except TypeError:
full_funcname = '{0}.{1}'.format(module_name, funcname)
# Save many references for lookups
# Careful not to overwrite existing (higher priority) functions
if full_funcname not in self._dict:

View File

@ -4,6 +4,11 @@ Module for controlling Jenkins
.. versionadded:: 2016.3.0
:depends: python-jenkins_ Python module (not to be confused with jenkins_)
.. _python-jenkins: https://pypi.python.org/pypi/python-jenkins
.. _jenkins: https://pypi.python.org/pypi/jenkins
:configuration: This module can be used by either passing an api key and version
directly or by specifying both in a configuration profile in the salt
master/minion config.
@ -45,9 +50,15 @@ def __virtual__():
:return: The virtual name of the module.
'''
if HAS_JENKINS:
return __virtualname__
if hasattr(jenkins, 'Jenkins'):
return __virtualname__
else:
return (False,
'The wrong Python module appears to be installed. Please '
'make sure that \'python-jenkins\' is installed, not '
'\'jenkins\'.')
return (False, 'The jenkins execution module cannot be loaded: '
'python jenkins library is not installed.')
'python-jenkins is not installed.')
def _connect():

View File

@ -2375,18 +2375,12 @@ def mod_repo(repo, basedir=None, **kwargs):
)
# Build a list of keys to be deleted
todelete = ['disabled']
todelete = []
for key in repo_opts:
if repo_opts[key] != 0 and not repo_opts[key]:
del repo_opts[key]
todelete.append(key)
# convert disabled to enabled respectively from pkgrepo state
if 'enabled' not in repo_opts:
repo_opts['enabled'] = int(str(repo_opts.pop('disabled', False)).lower() != 'true')
else:
repo_opts.pop('disabled', False)
# Add baseurl or mirrorlist to the 'todelete' list if the other was
# specified in the repo_opts
if 'mirrorlist' in repo_opts:
@ -2458,6 +2452,7 @@ def mod_repo(repo, basedir=None, **kwargs):
if key in six.iterkeys(filerepos[repo].copy()):
del filerepos[repo][key]
_bool_to_str = lambda x: '1' if x else '0'
# Old file or new, write out the repos(s)
filerepos[repo].update(repo_opts)
content = header
@ -2468,7 +2463,12 @@ def mod_repo(repo, basedir=None, **kwargs):
del filerepos[stanza]['comments']
content += '\n[{0}]'.format(stanza)
for line in six.iterkeys(filerepos[stanza]):
content += '\n{0}={1}'.format(line, filerepos[stanza][line])
content += '\n{0}={1}'.format(
line,
filerepos[stanza][line]
if not isinstance(filerepos[stanza][line], bool)
else _bool_to_str(filerepos[stanza][line])
)
content += '\n{0}\n'.format(comments)
with salt.utils.fopen(repofile, 'w') as fileout:
@ -2514,9 +2514,6 @@ def _parse_repo_file(filename):
'Failed to parse line in %s, offending line was '
'\'%s\'', filename, line.rstrip()
)
# YUM uses enabled field - create the disabled field so that comparisons works correctly in state
if comps[0].strip() == 'enabled':
repos[repo]['disabled'] = comps[1] != "1"
return (header, repos)

View File

@ -172,7 +172,7 @@ def ext_pillar(minion_id,
pil = Pillar(opts, __grains__, minion_id, environment)
compiled_pillar = pil.compile_pillar()
compiled_pillar = pil.compile_pillar(ext=False)
return compiled_pillar

View File

@ -193,4 +193,4 @@ def ext_pillar(minion_id,
opts = deepcopy(__opts__)
opts['pillar_roots'][branch] = [pillar_dir]
pil = Pillar(opts, __grains__, minion_id, branch)
return pil.compile_pillar()
return pil.compile_pillar(ext=False)

View File

@ -110,7 +110,7 @@ def managed(name, ppa=None, **kwargs):
<salt.modules.yumpkg>`, :mod:`apt <salt.modules.aptpkg>`, and :mod:`zypper
<salt.modules.zypper>` repositories are supported.
**YUM OR ZYPPER-BASED SYSTEMS**
**YUM/DNF/ZYPPER-BASED SYSTEMS**
.. note::
One of ``baseurl`` or ``mirrorlist`` below is required. Additionally,
@ -124,6 +124,16 @@ def managed(name, ppa=None, **kwargs):
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``).
enabled : True
Whether or not the repo is enabled. Can be specified as True/False or
1/0.
disabled : False
Included to reduce confusion due to APT's use of the ``disabled``
argument. If this is passed for a yum/dnf/zypper-based distro, then the
reverse will be passed as ``enabled``. For example passing
``disabled=True`` will assume ``enabled=False``.
humanname
This is used as the "name" value in the repo file in
``/etc/yum.repos.d/`` (or ``/etc/zypp/repos.d`` for SUSE distros).
@ -201,10 +211,16 @@ def managed(name, ppa=None, **kwargs):
'deb http://us.archive.ubuntu.com/ubuntu precise main':
pkgrepo.managed
disabled
disabled : False
Toggles whether or not the repo is used for resolving dependencies
and/or installing packages.
enabled : True
Included to reduce confusion due to yum/dnf/zypper's use of the
``enabled`` argument. If this is passed for an APT-based distro, then
the reverse will be passed as ``disabled``. For example, passing
``enabled=False`` will assume ``disabled=False``.
comps
On apt-based systems, comps dictate the types of packages to be
installed from the repository (e.g. main, nonfree, ...). For
@ -279,14 +295,19 @@ def managed(name, ppa=None, **kwargs):
'intended.')
return ret
if 'enabled' in kwargs:
salt.utils.warn_until(
'Nitrogen',
'The `enabled` argument has been deprecated in favor of '
'`disabled`.'
)
enabled = kwargs.pop('enabled', None)
disabled = kwargs.pop('disabled', None)
if enabled is not None and disabled is not None:
ret['result'] = False
ret['comment'] = 'Only one of enabled/disabled is allowed'
return ret
elif enabled is None and disabled is None:
# If neither argument was passed we assume the repo will be enabled
enabled = True
repo = name
os_family = __grains__['os_family'].lower()
if __grains__['os'] in ('Ubuntu', 'Mint'):
if ppa is not None:
# overload the name/repo value for PPAs cleanly
@ -296,26 +317,26 @@ def managed(name, ppa=None, **kwargs):
except TypeError:
repo = ':'.join(('ppa', str(ppa)))
elif __grains__['os_family'].lower() in ('redhat', 'suse'):
kwargs['disabled'] = not salt.utils.is_true(enabled) \
if enabled is not None \
else salt.utils.is_true(disabled)
elif os_family 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
# Replace 'enabled' from kwargs with 'disabled'
enabled = kwargs.pop('enabled', True)
kwargs['disabled'] = not salt.utils.is_true(enabled)
kwargs['enabled'] = not salt.utils.is_true(disabled) \
if disabled is not None \
else salt.utils.is_true(enabled)
elif os_family == 'nilinuxrt':
# opkg is the pkg virtual
kwargs['enabled'] = not salt.utils.is_true(disabled) \
if disabled is not None \
else salt.utils.is_true(enabled)
for kwarg in _STATE_INTERNAL_KEYWORDS:
kwargs.pop(kwarg, None)
@ -340,11 +361,10 @@ def managed(name, ppa=None, **kwargs):
else:
sanitizedkwargs = kwargs
if __grains__['os_family'] == 'Debian':
if os_family == 'debian':
repo = _strip_uri(repo)
if pre:
needs_update = False
for kwarg in sanitizedkwargs:
if kwarg not in pre:
if kwarg == 'enabled':
@ -352,33 +372,40 @@ def managed(name, ppa=None, **kwargs):
# 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 os_family == 'redhat':
if not salt.utils.is_true(sanitizedkwargs[kwarg]):
needs_update = True
break
else:
needs_update = True
break
else:
needs_update = True
break
elif kwarg == 'comps':
if sorted(sanitizedkwargs[kwarg]) != sorted(pre[kwarg]):
needs_update = True
elif kwarg == 'line' and __grains__['os_family'] == 'Debian':
break
elif kwarg == 'line' and os_family == 'debian':
# split the line and sort everything after the URL
sanitizedsplit = sanitizedkwargs[kwarg].split()
sanitizedsplit[3:] = sorted(sanitizedsplit[3:])
reposplit = pre[kwarg].split()
reposplit[3:] = sorted(reposplit[3:])
if sanitizedsplit != reposplit:
needs_update = True
break
if 'comments' in kwargs:
_line = pre[kwarg].split('#')
if str(kwargs['comments']) not in _line:
needs_update = True
break
else:
if str(sanitizedkwargs[kwarg]) != str(pre[kwarg]):
needs_update = True
if not needs_update:
if os_family in ('redhat', 'suse') \
and any(isinstance(x, bool) for x in
(sanitizedkwargs[kwarg], pre[kwarg])):
# This check disambiguates 1/0 from True/False
if salt.utils.is_true(sanitizedkwargs[kwarg]) != \
salt.utils.is_true(pre[kwarg]):
break
else:
if str(sanitizedkwargs[kwarg]) != str(pre[kwarg]):
break
else:
ret['result'] = True
ret['comment'] = ('Package repo \'{0}\' already configured'
.format(name))
@ -399,7 +426,7 @@ def managed(name, ppa=None, **kwargs):
pass
try:
if __grains__['os_family'] == 'Debian':
if os_family == 'debian':
__salt__['pkg.mod_repo'](repo, saltenv=__env__, **kwargs)
else:
__salt__['pkg.mod_repo'](repo, **kwargs)

View File

@ -87,7 +87,7 @@ def creds(provider):
proxies={'http': ''}, timeout=AWS_METADATA_TIMEOUT,
)
result.raise_for_status()
role = result.text.encode(result.encoding)
role = result.text.encode(result.encoding or 'utf-8')
except (requests.exceptions.HTTPError, requests.exceptions.ConnectionError):
return provider['id'], provider['key'], ''
@ -460,7 +460,7 @@ def query(params=None, setname=None, requesturl=None, location=None,
)
LOG.trace(
'AWS Response Text: {0}'.format(
result.text.encode(result.encoding)
result.text.encode(result.encoding or 'utf-8')
)
)
result.raise_for_status()
@ -501,7 +501,7 @@ def query(params=None, setname=None, requesturl=None, location=None,
return {'error': data}, requesturl
return {'error': data}
response = result.text.encode(result.encoding)
response = result.text.encode(result.encoding or 'utf-8')
root = ET.fromstring(response)
items = root[1]

View File

@ -7,6 +7,7 @@
'''
# Import python libs
from __future__ import absolute_import, print_function
from distutils.version import LooseVersion as _LooseVersion
# Import Salt Testing Libs
from salttesting import TestCase, skipIf
@ -23,8 +24,10 @@ try:
import jsonschema
import jsonschema.exceptions
HAS_JSONSCHEMA = True
JSONSCHEMA_VERSION = _LooseVersion(jsonschema.__version__)
except ImportError:
HAS_JSONSCHEMA = False
JSONSCHEMA_VERSION = _LooseVersion('0')
class RoosterEntryConfigTest(TestCase):
@ -296,7 +299,13 @@ class RosterItemTest(TestCase):
ssh_schemas.RosterItem.serialize(),
format_checker=jsonschema.FormatChecker()
)
self.assertIn(
'Additional properties are not allowed (\'target-1:1\' was unexpected)',
excinfo.exception.message
)
if JSONSCHEMA_VERSION < _LooseVersion('2.6.0'):
self.assertIn(
'Additional properties are not allowed (\'target-1:1\' was unexpected)',
excinfo.exception.message
)
else:
self.assertIn(
'\'target-1:1\' does not match any of the regexes',
excinfo.exception.message
)

View File

@ -11,7 +11,7 @@ import yaml
from distutils.version import LooseVersion
from distutils.version import LooseVersion
from distutils.version import LooseVersion as _LooseVersion
# Import Salt Testing Libs
from salttesting import TestCase, skipIf
@ -27,10 +27,10 @@ try:
import jsonschema
import jsonschema.exceptions
HAS_JSONSCHEMA = True
JSONSCHEMA_VERSION = jsonschema.__version__
JSONSCHEMA_VERSION = _LooseVersion(jsonschema.__version__)
except ImportError:
JSONSCHEMA_VERSION = ''
HAS_JSONSCHEMA = False
JSONSCHEMA_VERSION = _LooseVersion('0')
# pylint: disable=unused-import
@ -754,8 +754,7 @@ class ConfigTestCase(TestCase):
}
)
@skipIf(HAS_JSONSCHEMA is False, 'The \'jsonschema\' library is missing')
@skipIf(HAS_JSONSCHEMA and LooseVersion(jsonschema.__version__) <= LooseVersion('2.5.0'), 'Requires jsonschema 2.5.0 or greater')
@skipIf(JSONSCHEMA_VERSION <= _LooseVersion('2.5.0'), 'Requires jsonschema 2.5.0 or greater')
def test_ipv4_config_validation(self):
class TestConf(schema.Schema):
item = schema.IPv4Item(title='Item', description='Item description')
@ -1707,7 +1706,14 @@ class ConfigTestCase(TestCase):
with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo:
jsonschema.validate({'item': {'color': 'green', 'sides': 4, 'surfaces': 4}}, TestConf.serialize())
self.assertIn('Additional properties are not allowed', excinfo.exception.message)
if JSONSCHEMA_VERSION < _LooseVersion('2.6.0'):
self.assertIn(
'Additional properties are not allowed',
excinfo.exception.message)
else:
self.assertIn(
'\'surfaces\' does not match any of the regexes',
excinfo.exception.message)
class TestConf(schema.Schema):
item = schema.DictItem(