Merge branch '2016.11' into 'develop'

Conflicts:
  - salt/modules/napalm_network.py
This commit is contained in:
rallytime 2016-11-18 07:50:16 -07:00
commit 6479a22c1d
15 changed files with 144 additions and 86 deletions

View File

@ -1452,7 +1452,7 @@ DEFAULT_MASTER_OPTS = {
# ----- Salt Proxy Minion Configuration Defaults ----------------------------------->
# Note that proxies use the same config path as regular minions. DEFAULT_MINION_OPTS
# Note DEFAULT_MINION_OPTS
# is loaded first, then if we are setting up a proxy, the config is overwritten with
# these settings.
DEFAULT_PROXY_MINION_OPTS = {
@ -3110,10 +3110,16 @@ def apply_minion_config(overrides=None,
opts['id'] = _append_domain(opts)
for directory in opts.get('append_minionid_config_dirs', []):
if directory in ['pki_dir', 'cachedir', 'extension_modules', 'pidfile']:
if directory in ['pki_dir', 'cachedir', 'extension_modules']:
newdirectory = os.path.join(opts[directory], opts['id'])
opts[directory] = newdirectory
# pidfile can be in the list of append_minionid_config_dirs, but pidfile
# is the actual path with the filename, not a directory.
if 'pidfile' in opts.get('append_minionid_config_dirs', []):
newpath_list = os.path.split(opts['pidfile'])
opts['pidfile'] = os.path.join(newpath_list[0], 'salt', opts['id'], newpath_list[1])
if len(opts['sock_dir']) > len(opts['cachedir']) + 10:
opts['sock_dir'] = os.path.join(opts['cachedir'], '.salt-unix')

View File

@ -48,7 +48,9 @@ for service_dir in VALID_SERVICE_DIRS:
def __virtual__():
# Ensure that daemontools is installed properly.
BINS = frozenset(('svc', 'supervise', 'svok'))
return __virtualname__ if all(salt.utils.which(b) for b in BINS) else False
if all(salt.utils.which(b) for b in BINS) and SERVICE_DIR:
return __virtualname__
return False
def _service_path(name):

View File

@ -134,7 +134,8 @@ def _config_logic(loaded_result, test=False, commit_config=True):
loaded_result['already_configured'] = True
_discarded = discard_config()
if not _discarded.get('result', False):
loaded_result['comment'] += _discarded['out'] if _discarded['out'] else 'Unable to discard config.'
loaded_result['comment'] += _discarded['comment'] if _discarded.get('comment') \
else 'Unable to discard config.'
loaded_result['result'] = False
# make sure it notifies
# that something went wrong
@ -146,20 +147,29 @@ def _config_logic(loaded_result, test=False, commit_config=True):
return loaded_result
if not test and commit_config:
# if not in testing mode and trying to commit
if len(loaded_result.get('diff', '')) > 0:
# if not testing mode
# and also the user wants to commit (default)
# and there are changes to commit
_commit = commit() # calls the function commit, defined below
if not _commit.get('result', False):
loaded_result['comment'] += _commit['out'] if _commit['out'] else 'Unable to commit config.'
# if unable to commit
loaded_result['comment'] += _commit['comment'] if _commit.get('comment') else 'Unable to commit.'
loaded_result['result'] = False
# unable to commit, something went wrong
_discarded = discard_config() # try to discard, thus release the config DB
if not _discarded.get('result', False):
loaded_result['comment'] += '\n'
loaded_result['comment'] += _discarded['comment'] if _discarded.get('comment') \
else 'Unable to discard config.'
else:
# would like to commit, but there's no change
# need to call discard_config() to release the config DB
_discarded = discard_config()
if not _discarded.get('result', False):
loaded_result['comment'] += _discarded['out'] if _discarded['out'] else 'Unable to discard config.'
loaded_result['comment'] += _discarded['comment'] if _discarded.get('comment') \
else 'Unable to discard config.'
loaded_result['result'] = False
# notify if anything goes wrong
return loaded_result
@ -722,36 +732,36 @@ def mac(address='', interface='', vlan=0):
# ----- Configuration specific functions ------------------------------------------------------------------------------>
def load_config(filename=None, text=None, test=False, commit=True):
def load_config(filename=None, text=None, test=False, commit=True, replace=False):
'''
Populates the candidate configuration. It can be loaded from a file or from a string. If you send both a
filename and a string containing the configuration, the file takes precedence.
If you use this method the existing configuration will be merged with the candidate configuration once
you commit the changes.
Be aware that by default this method will commit the configuration. If there are no changes, it does not commit and
the flag `already_configured` will be set as `True` to point this out.
the flag ``already_configured`` will be set as ``True`` to point this out.
:param filename: Path to the file containing the desired configuration. By default is None.
:param text: String containing the desired configuration.
:param test: Dry run? If set as True, will apply the config, discard and return the changes. Default: False
:param test: Dry run? If set as ``True``, will apply the config, discard and return the changes. Default: ``False``\
and will commit the changes on the device.
:param commit: Commit? (default: True) Sometimes it is not needed to commit the config immediately
after loading the changes. E.g.: a state loads a couple of parts (add / remove / update)
and would not be optimal to commit after each operation.
Also, from the CLI when the user needs to apply the similar changes before committing,
can specify commit=False and will not discard the config.
:param commit: Commit? (default: ``True``) Sometimes it is not needed to commit the config immediately \
after loading the changes. E.g.: a state loads a couple of parts (add / remove / update) \
and would not be optimal to commit after each operation. \
Also, from the CLI when the user needs to apply the similar changes before committing, \
can specify ``commit=False`` and will not discard the config.
:param replace: Load and replace the configuration. Default: ``False``.
:return: a dictionary having the following keys:
:raise MergeConfigException: If there is an error on the configuration sent.
:return a dictionary having the following keys:
* result (bool): if the config was applied successfully. It is `False` only in case of failure. In case
there are no changes to be applied and successfully performs all operations it is still `True` and so will be
the `already_configured` flag (example below)
* comment (str): a message for the user
* already_configured (bool): flag to check if there were no changes applied
* diff (str): returns the config changes applied
* result (bool): if the config was applied successfully. It is ``False`` only in case of failure. In case
there are no changes to be applied and successfully performs all operations it is still ``True`` and so will be
the ``already_configured`` flag (example below)
* comment (str): a message for the user
* already_configured (bool): flag to check if there were no changes applied
* diff (str): returns the config changes applied
CLI Example:
@ -770,12 +780,16 @@ def load_config(filename=None, text=None, test=False, commit=True):
'comment': 'Configuration discarded.',
'already_configured': False,
'result': True,
'diff': '[edit interfaces xe-0/0/5]\n+ description "Adding a description";'
'diff': '[edit interfaces xe-0/0/5]+ description "Adding a description";'
}
'''
fun = 'load_merge_candidate'
if replace:
fun = 'load_replace_candidate'
_loaded = __proxy__['napalm.call'](
'load_merge_candidate',
fun,
**{
'filename': filename,
'config': text
@ -790,35 +804,37 @@ def load_template(template_name,
template_path=None,
test=False,
commit=True,
replace=False,
**template_vars):
'''
Renders a configuration template (Jinja) and loads the result on the device.
By default will commit the changes. To force a dry run, set `test=True`.
By default will commit the changes. To force a dry run, set ``test=True``.
:param template_name: Identifies the template name.
:param template_source (optional): Inline config template to be rendered and loaded on the device.
:param template_path (optional): Specifies the absolute path to a different directory for the configuration \
templates. If not specified, by default will use the default templates defined in NAPALM.
:param test: Dry run? If set to True, will apply the config, discard and return the changes. Default: False and
will commit the changes on the device.
:param commit: Commit? (default: True) Sometimes it is not needed to commit the config immediately
after loading the changes. E.g.: a state loads a couple of parts (add / remove / update)
and would not be optimal to commit after each operation.
Also, from the CLI when the user needs to apply the similar changes before committing,
can specify commit=False and will not discard the config.
:param test: Dry run? If set to ``True``, will apply the config, discard and return the changes. Default: ``False``\
and will commit the changes on the device.
:param commit: Commit? (default: ``True``) Sometimes it is not needed to commit the config immediately \
after loading the changes. E.g.: a state loads a couple of parts (add / remove / update) \
and would not be optimal to commit after each operation. \
Also, from the CLI when the user needs to apply the similar changes before committing, \
can specify ``commit=False`` and will not discard the config.
:param replace: Load and replace the configuration.
:param template_vars: Dictionary with the arguments to be used when the template is rendered.
:return: a dictionary having the following keys:
:return a dictionary having the following keys:
* result (bool): if the config was applied successfully. It is ``False`` only in case of failure. In case \
there are no changes to be applied and successfully performs all operations it is still `True` and so will be \
the ``already_configured`` flag (example below)
* comment (str): a message for the user
* already_configured (bool): flag to check if there were no changes applied
* diff (str): returns the config changes applied
* result (bool): if the config was applied successfully. It is `False` only in case of failure. In case
there are no changes to be applied and successfully performs all operations it is still `True` and so will be
the `already_configured` flag (example below)
* comment (str): a message for the user
* already_configured (bool): flag to check if there were no changes applied
* diff (str): returns the config changes applied
The template can use variables from the ``grains``, ``pillar`` or ``opts```, for example:
The template can use variables from the ``grains``, ``pillar`` or ``opts``, for example:
.. code-block:: jinja
@ -836,7 +852,7 @@ def load_template(template_name,
.. code-block:: bash
salt '*' net.load_template ntp_peers peers=[192.168.0.1] # uses NAPALM default templates
salt '*' net.load_template set_hostname template_source='system {\n\tdomain-name {{domain_name}};}' \
salt '*' net.load_template set_hostname template_source='system { domain-name {{domain_name}}; }'
domain_name='test.com'
salt '*' net.load_template my_template template_path='/tmp/tpl/' my_param='aaa' # will commit
salt '*' net.load_template my_template template_path='/tmp/tpl/' my_param='aaa' test=True # dry run
@ -849,7 +865,7 @@ def load_template(template_name,
'comment': '',
'already_configured': False,
'result': True,
'diff': '[edit system]\n+ host-name edge01.bjm01;''
'diff': '[edit system]+ host-name edge01.bjm01'
}
'''
@ -859,6 +875,7 @@ def load_template(template_name,
'template_name': template_name,
'template_source': template_source, # inline template
'template_path': template_path,
'replace': replace, # to load_replace_candidate after the template is rendered
'pillar': __pillar__, # inject pillar content, accessible as `pillar`
'grains': __grains__, # inject grains, accessible as `grains`
'opts': __opts__ # inject opts, accessible as `opts`

View File

@ -145,7 +145,8 @@ def install(feature, recurse=False, restart=False, source=None, exclude=None):
:param str exclude: The name of the feature to exclude when installing the
named feature.
..note:: As there is no exclude option for the ``Add-WindowsFeature``
.. note::
As there is no exclude option for the ``Add-WindowsFeature``
command, the feature will be installed with other sub-features and
will then be removed.

View File

@ -329,7 +329,7 @@ class Pillar(object):
opts['grains'] = {}
else:
opts['grains'] = grains
if 'environment' not in opts:
if not opts.get('environment'):
opts['environment'] = saltenv
opts['id'] = self.minion_id
if 'pillarenv' not in opts:

View File

@ -109,8 +109,9 @@ it:
'*':
- bar
If ``__env__`` is specified as the branch name, then git_pillar will use the
branch specified by :conf_master:`gitfs_base`:
If ``__env__`` is specified as the branch name, then git_pillar will first look
at the minion's :conf_minion:`environment` option. If unset, it will fall back
to using branch specified by the master's :conf_master:`gitfs_base`:
.. code-block:: yaml
@ -133,6 +134,11 @@ The corresponding Pillar top file would look like this:
described above. For 2016.3.4 and later, refer to explanation of the
``__env__`` parameter in the below section.
Versions 2016.3.0 through 2016.3.4 incorrectly check the *master's*
``environment`` config option (instead of the minion's) before falling back
to :conf_master:`gitfs_base`. This has been fixed in the 2016.3.5 and
2016.11.1 releases (2016.11.0 contains the incorrect behavior).
.. _git-pillar-2015-8-0-and-later:
Configuring git_pillar for Salt releases 2015.8.0 and later
@ -233,15 +239,25 @@ The corresponding Pillar top file would look like this:
.. note::
This feature was unintentionally omitted when git_pillar was rewritten for
the 2015.8.0 release. It was added again in the 2016.3.4 release, but it
has changed slightly in that release. On Salt masters running 2015.8.0
through 2016.3.3, this feature can only be accessed using the legacy config
in the previous section of this page.
For 2016.3.4 and later, the above example is accurate, and the value
replaced by ``__env__`` is :conf_master:`git_pillar_base`, while the legacy
config's version of this feature replaces ``__env__`` with
has changed slightly in that release. The fallback value replaced by
``{{env}}`` is :conf_master: is :conf_master:`git_pillar_base`, while the
legacy config's version of this feature replaces ``{{env}}`` with
:conf_master:`gitfs_base`.
On Salt masters running 2015.8.0 through 2016.3.3, this feature can only be
accessed using the legacy config in the previous section of this page.
The same issue which affected the behavior of the minion's
:conf_minion:`environment` config value using the legacy configuration
syntax (see the documentation in the pre-2015.8.0 section above for the
legacy support of this feature) also affects the new-style git_pillar
syntax in version 2016.3.4. This has been corrected in version 2016.3.5 and
2016.11.1 (2016.11.0 contains the incorrect behavior).
2016.3.4 incorrectly checks the *master's* ``environment`` config option
(instead of the minion's) before falling back to the master's
:conf_master:`git_pillar_base`.
With the addition of pygit2_ support, git_pillar can now interact with
authenticated remotes. Authentication works just like in gitfs (as outlined in
the :ref:`Git Fileserver Backend Walkthrough <gitfs-authentication>`), only

View File

@ -747,12 +747,12 @@ def _listeners_present(
expected_listeners_by_tuple = {}
for l in listeners:
key = __salt__['boto_elb.listener_dict_to_tuple'](l)
expected_listeners_by_tuple[key] = l
l_key = __salt__['boto_elb.listener_dict_to_tuple'](l)
expected_listeners_by_tuple[l_key] = l
actual_listeners_by_tuple = {}
for l in lb['listeners']:
key = __salt__['boto_elb.listener_dict_to_tuple'](l)
actual_listeners_by_tuple[key] = l
l_key = __salt__['boto_elb.listener_dict_to_tuple'](l)
actual_listeners_by_tuple[l_key] = l
to_delete = []
to_create = []

View File

@ -127,12 +127,16 @@ def installed(name,
for pkg_details in installed_pkgs.values():
try:
pkg_from = pkg_details.get('from', '').split('://')[1]
# Catch condition where we may have specified package as
# git://github.com/foo/bar but packager describes it as
# git://github.com/foo/bar.git in the package
if not pkg_from.endswith('.git') and pkg_name.startswith('git://'):
pkg_from += '.git'
if pkg_name.split('://')[1] == pkg_from:
return True
except IndexError:
pass
return False
for pkg in pkg_list:
pkg_name, _, pkg_ver = pkg.partition('@')
pkg_name = pkg_name.strip()

View File

@ -3,7 +3,7 @@
Installation of packages using OS package managers such as yum or apt-get
=========================================================================
..note::
.. note::
On minions running systemd>=205, as of version 2015.8.12, 2016.3.3, and
2016.11.0, `systemd-run(1)`_ is now used to isolate commands which modify
installed packages from the ``salt-minion`` daemon's control group. This is

View File

@ -330,15 +330,13 @@ def filesystem_present(name, create_parent=False, properties=None, cloned_from=N
properties : dict
additional zfs properties (-o)
..note::
.. note::
``cloned_from`` is only use if the filesystem does not exist yet,
when ``cloned_from`` is set after the filesystem exists it will be ignored.
..note::
properties do not get cloned, if you specify the properties in the state file
they will be applied on a subsequent run.
.. note::
Properties do not get cloned, if you specify the properties in the
state file they will be applied on a subsequent run.
'''
ret = {'name': name,
@ -442,20 +440,19 @@ def volume_present(name, volume_size, sparse=False, create_parent=False, propert
properties : dict
additional zfs properties (-o)
..note::
.. note::
``cloned_from`` is only use if the volume does not exist yet,
when ``cloned_from`` is set after the volume exists it will be ignored.
..note::
properties do not get cloned, if you specify the properties in the state file
.. note::
Properties do not get cloned, if you specify the properties in the state file
they will be applied on a subsequent run.
volume_size is considered a property so it the volume's size will be corrected
when the properties get update if it differs from the original volume.
``volume_size`` is considered a property, so the volume's size will be
corrected when the properties get updated if it differs from the
original volume.
the sparse parameter is ignored when using cloned_from.
The sparse parameter is ignored when using ``cloned_from``.
'''
ret = {'name': name,
@ -603,9 +600,8 @@ def snapshot_present(name, recursive=False, properties=None):
properties : dict
additional zfs properties (-o)
..note:
properties are only set at creation time.
.. note:
Properties are only set at creation time
'''
ret = {'name': name,

View File

@ -284,7 +284,8 @@ def gen_thin(cachedir, extra_mods='', overwrite=False, so_mods='',
os.chdir(tempdir)
if not os.path.isdir(top):
# top is a single file module
tfp.add(base, arcname=os.path.join('py{0}'.format(py_ver), base))
if os.path.exists(os.path.join(top_dirname, base)):
tfp.add(base, arcname=os.path.join('py{0}'.format(py_ver), base))
continue
for root, dirs, files in os.walk(base, followlinks=True):
for name in files:

View File

@ -23,6 +23,8 @@ from salt.config import cloud_providers_config
# Import Third-Party Libs
from salt.ext.six.moves import range
TIMEOUT = 500
try:
import azure # pylint: disable=unused-import
HAS_AZURE = True
@ -143,11 +145,12 @@ class AzureTest(integration.ShellCase):
'-p {0} {1}'.format(
PROFILE_NAME,
INSTANCE_NAME
)
), timeout=TIMEOUT
)]
)
except AssertionError:
self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME))
self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME),
timeout=TIMEOUT)
raise
# delete the instance
@ -157,7 +160,7 @@ class AzureTest(integration.ShellCase):
[i.strip() for i in self.run_cloud(
'-d {0} --assume-yes'.format(
INSTANCE_NAME
)
), timeout=TIMEOUT
)]
)
except AssertionError:
@ -172,7 +175,8 @@ class AzureTest(integration.ShellCase):
# if test instance is still present, delete it
if ret_str in query:
self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME))
self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME),
timeout=TIMEOUT)
if __name__ == '__main__':

View File

@ -1,6 +1,6 @@
joyent-test:
provider: joyent-config
size: g4-highcpu-512M
image: ubuntu-certified-16.10
size: k4-highcpu-kvm-250M
image: ubuntu-16.04
location: us-east-1
script_args: '-P -Z'

View File

@ -97,6 +97,8 @@ class ArchiveTest(integration.ModuleCase,
ret = self.run_state('archive.extracted', name=ARCHIVE_DIR,
source=ARCHIVE_TAR_SOURCE, archive_format='tar',
skip_verify=True)
if 'Timeout' in ret:
self.skipTest('Timeout talking to local tornado server.')
self.assertSaltTrueReturn(ret)
self._check_ext_remove(ARCHIVE_DIR, UNTAR_FILE)
@ -110,6 +112,9 @@ class ArchiveTest(integration.ModuleCase,
ret = self.run_state('archive.extracted', name=ARCHIVE_DIR,
source=ARCHIVE_TAR_SOURCE, archive_format='tar',
source_hash=ARCHIVE_TAR_HASH)
if 'Timeout' in ret:
self.skipTest('Timeout talking to local tornado server.')
self.assertSaltTrueReturn(ret)
self._check_ext_remove(ARCHIVE_DIR, UNTAR_FILE)

View File

@ -132,6 +132,12 @@ class AESReqTestCases(BaseZMQReqCase, ReqChannelMixin):
# TODO: make failed returns have a specific framing so we can raise the same exception
# on encrypted channels
#
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#
# WARNING: This test will fail randomly on any system with > 1 CPU core!!!
#
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
def test_badload(self):
'''
Test a variety of bad requests, make sure that we get some sort of error