Merge branch '2016.3' of github.com:saltstack/salt into 2016.3

This commit is contained in:
xiaofei.sun 2016-08-28 11:39:32 +08:00
commit 1074b3355d
43 changed files with 333 additions and 233 deletions

View file

@ -15,31 +15,40 @@ from sphinx.directives import TocTree
# pylint: disable=R0903
class Mock(object):
'''
Mock out specified imports
Mock out specified imports.
This allows autodoc to do its thing without having oodles of req'd
installed libs. This doesn't work with ``import *`` imports.
This Mock class can be configured to return a specific values at specific names, if required.
http://read-the-docs.readthedocs.org/en/latest/faq.html#i-get-import-errors-on-libraries-that-depend-on-c-modules
'''
def __init__(self, *args, **kwargs):
pass
def __init__(self, mapping=None, *args, **kwargs):
"""
Mapping allows to bypass the Mock object, but actually assign
a specific value, expected by a specific attribute returned.
"""
self.__mapping = mapping or {}
__all__ = []
def __call__(self, *args, **kwargs):
ret = Mock()
# If mocked function is used as a decorator, expose decorated function.
# if args and callable(args[-1]):
# functools.update_wrapper(ret, args[0])
return ret
return Mock(mapping=self.__mapping)
@classmethod
def __getattr__(cls, name):
if name in ('__file__', '__path__'):
return '/dev/null'
def __getattr__(self, name):
#__mapping = {'total': 0}
data = None
if name in self.__mapping:
data = self.__mapping.get(name)
elif name in ('__file__', '__path__'):
data = '/dev/null'
else:
return Mock()
data = Mock(mapping=self.__mapping)
return data
# pylint: enable=R0903
MOCK_MODULES = [
@ -97,6 +106,7 @@ MOCK_MODULES = [
'tornado.stack_context',
'tornado.web',
'tornado.websocket',
'tornado.locks',
'ws4py',
'ws4py.server',
@ -111,6 +121,7 @@ MOCK_MODULES = [
'MySQLdb',
'MySQLdb.cursors',
'nagios_json',
'psutil',
'pycassa',
'pymongo',
'rabbitmq_server',
@ -131,7 +142,11 @@ MOCK_MODULES = [
]
for mod_name in MOCK_MODULES:
sys.modules[mod_name] = Mock()
if mod_name == 'psutil':
mock = Mock(mapping={'total': 0}) # Otherwise it will crash Sphinx
else:
mock = Mock()
sys.modules[mod_name] = mock
def mock_decorator_with_params(*oargs, **okwargs):
'''

View file

@ -1176,6 +1176,20 @@ environments is to isolate via the top file.
environment: dev
.. conf_minion:: state_top_saltenv
``state_top_saltenv``
---------------------
Default: not set
Set this option to an environment name, to ensure that *only* the top file from
that environment is considered during a :ref:`highstate <running-highstate>`.
.. code-block:: yaml
state_top_saltenv: base
.. conf_minion:: top_file_merging_strategy
``top_file_merging_strategy``
@ -1188,11 +1202,11 @@ for a :ref:`highstate <running-highstate>`, all environments' top files are
inspected. This config option determines how the SLS targets in those top files
are handled.
When set to ``merge``, the targets for all SLS files in all environments are
merged together. A given environment's SLS targets for the highstate will
consist of the collective SLS targets specified for that environment in all top
files. The environments will be merged in no specific order, for greater
control over the order in which the environments are merged use
When set to the default value of ``merge``, all SLS files are interpreted. The
first target expression for a given environment is kept, and when the same
target expression is used in a different top file evaluated later, it is
ignored. The environments will be evaluated in no specific order, for greater
control over the order in which the environments are evaluated use
:conf_minion:`env_order`.
When set to ``same``, then for each environment, only that environment's top
@ -1216,7 +1230,7 @@ Default: ``[]``
When :conf_minion:`top_file_merging_strategy` is set to ``merge``, and no
environment is specified for a :ref:`highstate <running-highstate>`, this
config option allows for the order in which top files are merged to be
config option allows for the order in which top files are evaluated to be
explicitly defined.
.. code-block:: yaml

View file

@ -336,7 +336,7 @@ in the minion config file:
pkg: aptpkg
The above example will force the minion to use the :py:mod:`systemd
<salt.modules.systemd>` module to provide service mangement, and the
<salt.modules.systemd>` module to provide service management, and the
:py:mod:`aptpkg <salt.modules.aptpkg>` module to provide package management.
.. __: https://github.com/saltstack/salt/issues/new

View file

@ -344,7 +344,7 @@ External Job Cache functions using the ``ret`` execution module.
Event Returners
===============
For maximimum visibility into the history of events across a Salt
For maximum visibility into the history of events across a Salt
infrastructure, all events seen by a salt master may be logged to a returner.
To enable event logging, set the ``event_return`` configuration option in the
@ -358,7 +358,7 @@ returns.
.. note::
On larger installations, many hundreds of events may be generated on a
busy master every second. Be certain to closely monitor the storage of
a given returner as Salt can easily overwhealm an underpowered server
a given returner as Salt can easily overwhelm an underpowered server
with thousands of returns.
Full List of Returners

View file

@ -82,15 +82,15 @@ and will only be fired onto the event bus.
Synchronous vs. Asynchronous
----------------------------
A runner may be fired asychronously which will immediately return control. In
A runner may be fired asynchronously which will immediately return control. In
this case, no output will be display to the user if ``salt-run`` is being used
from the command-line. If used programatically, no results will be returned.
from the command-line. If used programmatically, no results will be returned.
If results are desired, they must be gathered either by firing events on the
bus from the runner and then watching for them or by some other means.
.. note::
When running a runner in asyncronous mode, the ``--progress`` flag will
When running a runner in asynchronous mode, the ``--progress`` flag will
not deliver output to the salt-run CLI. However, progress events will
still be fired on the bus.

View file

@ -330,6 +330,14 @@ this, it can be helpful to set :conf_minion:`top_file_merging_strategy` to
top_file_merging_strategy: same
Another option would be to set :conf_minion:`state_top_saltenv` to a specific
environment, to ensure that any top files in other environments are
disregarded:
.. code-block:: yaml
state_top_saltenv: base
With :ref:`GitFS <tutorial-gitfs>`, it can also be helpful to simply manage
each environment's top file separately, and/or manually specify the environment
when executing the highstate to avoid any complicated merging scenarios.
@ -348,6 +356,7 @@ configuring a :ref:`highstate <running-highstate>`.
The following minion configuration options affect how top files are compiled
when no environment is specified:
- :conf_minion:`state_top_saltenv`
- :conf_minion:`top_file_merging_strategy`
- :conf_minion:`env_order`
- :conf_minion:`default_top`
@ -420,14 +429,30 @@ If the ``qa`` environment were specified, the :ref:`highstate
Scenario 2 - No Environment Specified, :conf_minion:`top_file_merging_strategy` is "merge"
------------------------------------------------------------------------------------------
In this scenario, ``base1`` from the ``base`` environment, ``dev1`` from the
``dev`` environment, and ``qa1`` from the ``qa`` environment are applied to all
minions. Additionally, ``base2`` from the ``base`` environment is applied to
minion1, and ``dev2`` from the ``dev`` environment is applied to minion2.
.. versionchanged:: Carbon
The default merging strategy has been renamed from ``merge`` to
``default`` to reflect the fact that SLS names from identical targets in
matching environments from multiple top files are not actually merged.
In this scenario, assuming that the ``base`` environment's top file was
evaluated first, the ``base1``, ``dev1``, and ``qa1`` states would be applied
to all minions. If, for instance, the ``qa`` environment is not defined in
**/srv/salt/base/top.sls**, then the ``qa`` section in
**/srv/salt/dev/top.sls** would be used and the ``qa2`` states would be applied
to all minions.
Scenario 3 - No Environment Specified, :conf_minion:`top_file_merging_strategy` is "same"
-----------------------------------------------------------------------------------------
.. versionchanged:: Carbon
In prior versions, "same" did not quite work as described below (see
here__). This has now been corrected. It was decided that changing
something like top file handling in a point release had the potential to
unexpectedly impact users' top files too much, and it would be better to
make this correction in a feature release.
.. __: https://github.com/saltstack/salt/issues/35045
In this scenario, ``base1`` from the ``base`` environment is applied to all
minions. Additionally, ``dev2`` from the ``dev`` environment is applied to
minion2.

View file

@ -151,7 +151,7 @@ A State Module must return a dict containing the following keys/values:
- **comment:** A string containing a summary of the result.
The return data can also, include the **pchanges** key, this statnds for
The return data can also, include the **pchanges** key, this stands for
`predictive changes`. The **pchanges** key informs the State system what
changes are predicted to occur.

View file

@ -583,7 +583,7 @@ Load Balancer
Compute Engine possess a load-balancer feature for splitting traffic across
multiple instances. Please reference the
`documentation <https://developers.google.com/compute/docs/load-balancing/>`_
for a more complete discription.
for a more complete description.
The load-balancer functionality is slightly different than that described
in Google's documentation. The concept of *TargetPool* and *ForwardingRule*

View file

@ -437,7 +437,7 @@ data from the state that will make use of the data.
Light conditionals and looping
``````````````````````````````
Jinja is extremely powerful for programatically generating Salt states. It is
Jinja is extremely powerful for programmatically generating Salt states. It is
also easy to overuse. As a rule of thumb, if it is hard to read it will be hard
to maintain!
@ -461,7 +461,7 @@ Below is a simple example of a readable loop:
Avoid putting a Jinja conditionals within Salt states where possible.
Readability suffers and the correct YAML indentation is difficult to see in the
surrounding visual noise. Parameterization (discussed below) and variables are
surrounding visual noise. Parametrization (discussed below) and variables are
both useful techniques to avoid this. For example:
.. code-block:: yaml
@ -500,7 +500,7 @@ both useful techniques to avoid this. For example:
- name: {{ name }}
Dictionaries are useful to effectively "namespace" a collection of variables.
This is useful with parameterization (discussed below). Dictionaries are also
This is useful with parametrization (discussed below). Dictionaries are also
easily combined and merged. And they can be directly serialized into YAML which
is often easier than trying to create valid YAML through templating. For
example:

View file

@ -180,7 +180,7 @@ request``.
.. note::
Although these instructions seem to be the official pull request proceedure
Although these instructions seem to be the official pull request procedure
on github's website, here are two alternative methods that are simpler.
* If you navigate to your clone of salt,

View file

@ -99,11 +99,17 @@ Salt's scheduling system allows incremental executions on minions or the
master. The schedule system exposes the execution of any execution function on
minions or any runner on the master.
Scheduling is enabled via the ``schedule`` option on either the master or minion
config files, or via a minion's pillar data. Schedules that are implemented via
pillar data, only need to refresh the minion's pillar data, for example by using
``saltutil.refresh_pillar``. Schedules implemented in the master or minion config
have to restart the application in order for the schedule to be implemented.
Scheduling can be enabled by multiple methods:
- ``schedule`` option in either the master or minion config files. These
require the master or minion application to be restarted in order for the
schedule to be implemented.
- Minion pillar data. Schedule is implemented by refreshing the minion's pillar data,
for example by using ``saltutil.refresh_pillar``.
- The :doc:`schedule state</ref/states/all/salt.states.schedule>` or
:doc:`schedule module</ref/modules/all/salt.modules.schedule>`
.. note::

View file

@ -289,7 +289,7 @@ Changes:
- **PR** `#33474`_: (*cachedout*) Fix diskusage beacon
- **PR** `#33465`_: (*meaksh*) jobs.exit_success allow to check if a job has executed and exit successfully
- **PR** `#33465`_: (*meaksh*) jobs.exit_success allow one to check if a job has executed and exit successfully
- **PR** `#33487`_: (*jtand*) Add docstring examples to glance.py and nova.py [2015.8]
@ -333,7 +333,7 @@ Changes:
* c9d0de4 Documentation update in file.serialize. (`#33421`_)
* f8a90eb Fix LVM parameter devices as a pure list. Comma seperated lists are c… (`#33398`_)
* f8a90eb Fix LVM parameter devices as a pure list. Comma separated lists are c… (`#33398`_)
* 3989e5b Spelling correction. (`#33406`_)

View file

@ -678,7 +678,7 @@ Changes:
- **PR** `#33961`_: (*jacobhammons*) 2016.3.0 known issues update
- **PR** `#33908`_: (*ticosax*) [boto_lambda] handle ommitted Permissions parameter
- **PR** `#33908`_: (*ticosax*) [boto_lambda] handle omitted Permissions parameter
- **PR** `#33896`_: (*DmitryKuzmenko*) Don't deep copy context dict values.

View file

@ -364,7 +364,7 @@ In the example configuration above, the following is true:
2. The first remote will serve all files in the repository. The second
remote will only serve files from the ``salt`` directory (and its
subdirectories). The third remote will only server files from the
``other/salt`` directory (and its subdirectorys), while the fourth remote
``other/salt`` directory (and its subdirectories), while the fourth remote
will only serve files from the ``salt/states`` directory (and its
subdirectories).

View file

@ -29,7 +29,6 @@ import salt.utils.templates
import salt.utils.url
import salt.utils.gzip_util
import salt.utils.http
import salt.utils.s3
from salt.utils.locales import sdecode
from salt.utils.openstack.swift import SaltSwift
@ -63,6 +62,7 @@ class Client(object):
'''
def __init__(self, opts):
self.opts = opts
self.utils = salt.loader.utils(self.opts)
self.serial = salt.payload.Serial(self.opts)
# Add __setstate__ and __getstate__ so that the object may be
@ -596,17 +596,17 @@ class Client(object):
return self.opts['pillar']['s3'][key]
except (KeyError, TypeError):
return default
salt.utils.s3.query(method='GET',
bucket=url_data.netloc,
path=url_data.path[1:],
return_bin=False,
local_file=dest,
action=None,
key=s3_opt('key'),
keyid=s3_opt('keyid'),
service_url=s3_opt('service_url'),
verify_ssl=s3_opt('verify_ssl', True),
location=s3_opt('location'))
self.utils['s3.query'](method='GET',
bucket=url_data.netloc,
path=url_data.path[1:],
return_bin=False,
local_file=dest,
action=None,
key=s3_opt('key'),
keyid=s3_opt('keyid'),
service_url=s3_opt('service_url'),
verify_ssl=s3_opt('verify_ssl', True),
location=s3_opt('location'))
return dest
except Exception as exc:
raise MinionError(

View file

@ -69,7 +69,6 @@ import logging
import salt.fileserver as fs
import salt.modules
import salt.utils
import salt.utils.s3 as s3
# Import 3rd-party libs
# pylint: disable=import-error,no-name-in-module,redefined-builtin
@ -400,7 +399,7 @@ def _refresh_buckets_cache_file(cache_file):
# helper s3 query function
def __get_s3_meta(bucket, key=key, keyid=keyid):
return s3.query(
return __utils__['s3.query'](
key=key,
keyid=keyid,
kms_keyid=keyid,
@ -634,7 +633,7 @@ def _get_file_from_s3(metadata, saltenv, bucket_name, path, cached_file_path):
log.debug('cached file size equal to metadata size and '
'cached file mtime later than metadata last '
'modification time.')
ret = s3.query(
ret = __utils__['s3.query'](
key=key,
keyid=keyid,
kms_keyid=keyid,
@ -665,7 +664,7 @@ def _get_file_from_s3(metadata, saltenv, bucket_name, path, cached_file_path):
return
# ... or get the file from S3
s3.query(
__utils__['s3.query'](
key=key,
keyid=keyid,
kms_keyid=keyid,

View file

@ -334,12 +334,14 @@ def pillars(opts, functions, context=None):
'''
Returns the pillars modules
'''
ret = LazyLoader(
_module_dirs(opts, 'pillar', 'pillar'),
opts,
tag='pillar',
pack={'__salt__': functions, '__context__': context},
)
if context is None:
context = {}
ret = LazyLoader(_module_dirs(opts, 'pillar', 'pillar'),
opts,
tag='pillar',
pack={'__salt__': functions,
'__context__': context,
'__utils__': utils(opts)})
ret.pack['__ext_pillar__'] = ret
return FilterDictWrapper(ret, '.ext_pillar')
@ -423,12 +425,11 @@ def fileserver(opts, backends):
'''
Returns the file server modules
'''
return LazyLoader(
_module_dirs(opts, 'fileserver', 'fileserver'),
opts,
tag='fileserver',
whitelist=backends,
)
return LazyLoader(_module_dirs(opts, 'fileserver', 'fileserver'),
opts,
tag='fileserver',
whitelist=backends,
pack={'__utils__': utils(opts)})
def roster(opts, whitelist=None):

View file

@ -27,7 +27,7 @@ __proxyenabled__ = ['fx2']
try:
run_all = __salt__['cmd.run_all']
except NameError:
except (NameError, KeyError):
import salt.modules.cmdmod
__salt__ = {
'cmd.run_all': salt.modules.cmdmod._run_all_quiet

View file

@ -910,7 +910,7 @@ def config_get(key,
Now optional if ``global`` is set to ``True``
global : False
If ``True``, query the global git configuraton. Otherwise, only the
If ``True``, query the global git configuration. Otherwise, only the
local git configuration will be queried.
.. versionadded:: 2015.8.0
@ -998,7 +998,7 @@ def config_get_regexp(key,
The path to the git checkout
global : False
If ``True``, query the global git configuraton. Otherwise, only the
If ``True``, query the global git configuration. Otherwise, only the
local git configuration will be queried.
user

View file

@ -81,7 +81,7 @@ def _do_http(opts, profile='default'):
raise Exception('missing url in profile {0}'.format(profile))
if user and passwd:
auth = _auth(url, realm, user, passwd)
auth = _auth(url=url, realm=realm, user=user, passwd=passwd)
_install_opener(auth)
url += '?{0}'.format(_urlencode(opts))

View file

@ -56,10 +56,6 @@ from __future__ import absolute_import
# Import Python libs
import logging
# Import Salt libs
import salt.utils
import salt.utils.s3
log = logging.getLogger(__name__)
@ -94,17 +90,17 @@ def delete(bucket, path=None, action=None, key=None, keyid=None,
role_arn,
)
return salt.utils.s3.query(method='DELETE',
bucket=bucket,
path=path,
action=action,
key=key,
keyid=keyid,
kms_keyid=kms_keyid,
service_url=service_url,
verify_ssl=verify_ssl,
location=location,
role_arn=role_arn)
return __utils__['s3.query'](method='DELETE',
bucket=bucket,
path=path,
action=action,
key=key,
keyid=keyid,
kms_keyid=kms_keyid,
service_url=service_url,
verify_ssl=verify_ssl,
location=location,
role_arn=role_arn)
def get(bucket=None, path=None, return_bin=False, action=None,
@ -171,19 +167,19 @@ def get(bucket=None, path=None, return_bin=False, action=None,
role_arn,
)
return salt.utils.s3.query(method='GET',
bucket=bucket,
path=path,
return_bin=return_bin,
local_file=local_file,
action=action,
key=key,
keyid=keyid,
kms_keyid=kms_keyid,
service_url=service_url,
verify_ssl=verify_ssl,
location=location,
role_arn=role_arn)
return __utils__['s3.query'](method='GET',
bucket=bucket,
path=path,
return_bin=return_bin,
local_file=local_file,
action=action,
key=key,
keyid=keyid,
kms_keyid=kms_keyid,
service_url=service_url,
verify_ssl=verify_ssl,
location=location,
role_arn=role_arn)
def head(bucket, path=None, key=None, keyid=None, service_url=None,
@ -208,17 +204,17 @@ def head(bucket, path=None, key=None, keyid=None, service_url=None,
role_arn,
)
return salt.utils.s3.query(method='HEAD',
bucket=bucket,
path=path,
key=key,
keyid=keyid,
kms_keyid=kms_keyid,
service_url=service_url,
verify_ssl=verify_ssl,
location=location,
full_headers=True,
role_arn=role_arn)
return __utils__['s3.query'](method='HEAD',
bucket=bucket,
path=path,
key=key,
keyid=keyid,
kms_keyid=kms_keyid,
service_url=service_url,
verify_ssl=verify_ssl,
location=location,
full_headers=True,
role_arn=role_arn)
def put(bucket, path=None, return_bin=False, action=None, local_file=None,
@ -249,19 +245,19 @@ def put(bucket, path=None, return_bin=False, action=None, local_file=None,
role_arn,
)
return salt.utils.s3.query(method='PUT',
bucket=bucket,
path=path,
return_bin=return_bin,
local_file=local_file,
action=action,
key=key,
keyid=keyid,
kms_keyid=kms_keyid,
service_url=service_url,
verify_ssl=verify_ssl,
location=location,
role_arn=role_arn)
return __utils__['s3.query'](method='PUT',
bucket=bucket,
path=path,
return_bin=return_bin,
local_file=local_file,
action=action,
key=key,
keyid=keyid,
kms_keyid=kms_keyid,
service_url=service_url,
verify_ssl=verify_ssl,
location=location,
role_arn=role_arn)
def _get_key(key, keyid, service_url, verify_ssl, kms_keyid, location, role_arn):

View file

@ -824,7 +824,7 @@ def refresh_db(**kwargs):
Do not refresh the specified repo
enablerepo
Refesh a disabled repo using this option
Refresh a disabled repo using this option
branch
Add the specified branch when refreshing

View file

@ -98,7 +98,6 @@ from salt.ext.six.moves.urllib.parse import quote as _quote
# Import salt libs
from salt.pillar import Pillar
import salt.utils
import salt.utils.s3 as s3
# Set up logging
log = logging.getLogger(__name__)
@ -257,7 +256,7 @@ def _refresh_buckets_cache_file(creds, cache_file, multiple_env, environment, pr
# helper s3 query function
def __get_s3_meta():
return s3.query(
return __utils__['s3.query'](
key=creds.key,
keyid=creds.keyid,
kms_keyid=creds.kms_keyid,
@ -399,7 +398,7 @@ def _get_file_from_s3(creds, metadata, saltenv, bucket, path,
return
# ... or get the file from S3
s3.query(
__utils__['s3.query'](
key=creds.key,
keyid=creds.keyid,
kms_keyid=creds.kms_keyid,

View file

@ -42,7 +42,7 @@ To override individual configuration items, append --return_kwargs '{"key:": "va
On concurrent database access
==============================
As this returner creates a couchdb document whith the salt job id as document id
As this returner creates a couchdb document with the salt job id as document id
and as only one document with a given id can exist in a given couchdb database,
it is advised for most setups that every minion be configured to write to it own
database (the value of ``couchdb.db`` may be suffixed with the minion id),

View file

@ -36,6 +36,8 @@ def enabled(name):
'''
Ensure an Apache module is enabled.
.. versionadded:: 2016.3.0
name
Name of the Apache module
'''

View file

@ -306,7 +306,7 @@ def _compare_acl(current, desired, region, key, keyid, profile):
def _compare_policy(current, desired, region, key, keyid, profile):
'''
Policy discription is always returned as a JSON string. Comparison
Policy description is always returned as a JSON string. Comparison
should be object-to-object, since order is not significant in JSON
'''
if isinstance(desired, string_types):

View file

@ -136,7 +136,7 @@ def present(
The ID of the VPC to create the security group in, if any. Exclusive with vpc_name.
vpc_name
The name of the VPC to create the security group in, if any. Exlusive with vpc_id.
The name of the VPC to create the security group in, if any. Exclusive with vpc_id.
.. versionadded:: 2016.3.0

View file

@ -39,7 +39,7 @@ def __virtual__():
def _parse_pkg_string(pkg):
'''
Parse pkg string and return a tuple of packge name, separator, and
Parse pkg string and return a tuple of package name, separator, and
package version.
Cabal support install package with following format:

View file

@ -13,7 +13,7 @@ filesystem is within the specified limits.
disk.status:
- name: /dev/xda1
- maximum: 79%
- minumum: 11%
- minimum: 11%
It can be used with an ``onfail`` requisite, for example, to take additional
action in response to or in preparation for other states.

View file

@ -68,9 +68,9 @@ def user_exists(name, password=None, htpasswd_file=None, options='',
ret['changes'] = {name: True}
return ret
useradd_ret = __salt__['webutil.useradd_all'](htpasswd_file, name,
password, opts=options,
runas=runas)
useradd_ret = __salt__['webutil.useradd'](htpasswd_file, name,
password, opts=options,
runas=runas)
if useradd_ret['retcode'] == 0:
ret['result'] = True
ret['comment'] = useradd_ret['stderr']

View file

@ -723,7 +723,7 @@ def installed(
package version will be installed à la ``pkg.latest``.
:param bool refresh:
This parameter controls whether or not the packge repo database is
This parameter controls whether or not the package repo database is
updated prior to installing the requested package(s).
If ``True``, the package database will be refreshed (``apt-get
@ -1541,7 +1541,7 @@ def latest(
Skip the GPG verification check for the package to be installed
refresh
This parameter controls whether or not the packge repo database is
This parameter controls whether or not the package repo database is
updated prior to checking for the latest available version of the
requested packages.

View file

@ -283,7 +283,7 @@ def managed(name, ppa=None, **kwargs):
if 'enabled' in kwargs:
salt.utils.warn_until(
'Carbon',
'Nitrogen',
'The `enabled` argument has been deprecated in favor of '
'`disabled`.'
)

View file

@ -462,7 +462,7 @@ def present(name,
ret['comment'] = ('The following user attributes are set to be '
'changed:\n')
for key, val in iteritems(changes):
if key == 'password':
if key == 'passwd':
val = 'XXX-REDACTED-XXX'
elif key == 'group' and not remove_groups:
key = 'ensure groups'

View file

@ -219,7 +219,7 @@ def private_key_managed(name,
whenever a new certificiate is generated.
backup:
When replacing an existing file, backup the old file onthe minion.
When replacing an existing file, backup the old file on the minion.
Default is False.
Example:
@ -516,7 +516,7 @@ def crl_managed(name,
Include expired certificates in the CRL. Default is ``False``.
backup:
When replacing an existing file, backup the old file onthe minion. Default is False.
When replacing an existing file, backup the old file on the minion. Default is False.
Example:

View file

@ -855,18 +855,39 @@ def path_join(*parts):
# Normalize path converting any os.sep as needed
parts = [os.path.normpath(p) for p in parts]
root = parts.pop(0)
try:
root = parts.pop(0)
except IndexError:
# No args passed to func
return ''
if not parts:
return root
ret = root
else:
if is_windows():
if len(root) == 1:
root += ':'
root = root.rstrip(os.sep) + os.sep
if is_windows():
if len(root) == 1:
root += ':'
root = root.rstrip(os.sep) + os.sep
return os.path.normpath(os.path.join(
root, *[p.lstrip(os.sep) for p in parts]
))
stripped = [p.lstrip(os.sep) for p in parts]
try:
ret = os.path.join(root, *stripped)
except UnicodeDecodeError:
# This is probably Python 2 and one of the parts contains unicode
# characters in a bytestring. First try to decode to the system
# encoding.
try:
enc = __salt_system_encoding__
except NameError:
enc = sys.stdin.encoding or sys.getdefaultencoding()
try:
ret = os.path.join(root.decode(enc),
*[x.decode(enc) for x in stripped])
except UnicodeDecodeError:
# Last resort, try UTF-8
ret = os.path.join(root.decode('UTF-8'),
*[x.decode('UTF-8') for x in stripped])
return os.path.normpath(ret)
def pem_finger(path=None, key=None, sum_type='sha256'):

View file

@ -568,7 +568,7 @@ def get_region_from_metadata():
return None
def get_location(opts, provider=None):
def get_location(opts=None, provider=None):
'''
Return the region to use, in this order:
opts['location']
@ -576,6 +576,8 @@ def get_location(opts, provider=None):
get_region_from_metadata()
DEFAULT_LOCATION
'''
if opts is None:
opts = __opts__
ret = opts.get('location', provider.get('location'))
if ret is None:
ret = get_region_from_metadata()

View file

@ -153,7 +153,7 @@ class GitProvider(object):
self.id = next(iter(remote))
self.get_url()
per_remote_conf = dict(
[(key, str(val)) for key, val in
[(key, six.text_type(val)) for key, val in
six.iteritems(salt.utils.repack_dictlist(remote[self.id]))]
)
if not per_remote_conf:
@ -261,7 +261,7 @@ class GitProvider(object):
hash_type = getattr(hashlib, self.opts.get('hash_type', 'md5'))
self.hash = hash_type(self.id).hexdigest()
self.cachedir_basename = getattr(self, 'name', self.hash)
self.cachedir = os.path.join(cache_root, self.cachedir_basename)
self.cachedir = salt.utils.path_join(cache_root, self.cachedir_basename)
if not os.path.isdir(self.cachedir):
os.makedirs(self.cachedir)
@ -305,7 +305,7 @@ class GitProvider(object):
return ret
def _get_lock_file(self, lock_type='update'):
return os.path.join(self.gitdir, lock_type + '.lk')
return salt.utils.path_join(self.gitdir, lock_type + '.lk')
def check_root(self):
'''
@ -313,7 +313,7 @@ class GitProvider(object):
remote. Return the full path to that relative root if it does exist,
otherwise return None.
'''
root_dir = os.path.join(self.cachedir, self.root).rstrip(os.sep)
root_dir = salt.utils.path_join(self.cachedir, self.root).rstrip(os.sep)
if os.path.isdir(root_dir):
return root_dir
log.error(
@ -718,7 +718,7 @@ class GitPython(GitProvider):
log.error(_INVALID_REPO.format(self.cachedir, self.url, self.role))
return new
self.gitdir = os.path.join(self.repo.working_dir, '.git')
self.gitdir = salt.utils.path_join(self.repo.working_dir, '.git')
if not self.repo.remotes:
try:
@ -753,7 +753,7 @@ class GitPython(GitProvider):
relpath = lambda path: os.path.relpath(path, self.root)
else:
relpath = lambda path: path
add_mountpoint = lambda path: os.path.join(self.mountpoint, path)
add_mountpoint = lambda path: salt.utils.path_join(self.mountpoint, path)
for blob in tree.traverse():
if isinstance(blob, git.Tree):
ret.add(add_mountpoint(relpath(blob.path)))
@ -829,7 +829,7 @@ class GitPython(GitProvider):
relpath = lambda path: os.path.relpath(path, self.root)
else:
relpath = lambda path: path
add_mountpoint = lambda path: os.path.join(self.mountpoint, path)
add_mountpoint = lambda path: salt.utils.path_join(self.mountpoint, path)
for file_blob in tree.traverse():
if not isinstance(file_blob, git.Blob):
continue
@ -871,9 +871,7 @@ class GitPython(GitProvider):
stream.seek(0)
link_tgt = stream.read()
stream.close()
path = os.path.normpath(
os.path.join(os.path.dirname(path), link_tgt)
)
path = salt.utils.path_join(os.path.dirname(path), link_tgt)
else:
blob = file_blob
break
@ -1201,7 +1199,7 @@ class Pygit2(GitProvider):
log.error(_INVALID_REPO.format(self.cachedir, self.url, self.role))
return new
self.gitdir = os.path.join(self.repo.workdir, '.git')
self.gitdir = salt.utils.path_join(self.repo.workdir, '.git')
if not self.repo.remotes:
try:
@ -1242,9 +1240,9 @@ class Pygit2(GitProvider):
blob = self.repo[entry.oid]
if not isinstance(blob, pygit2.Tree):
continue
blobs.append(os.path.join(prefix, entry.name))
blobs.append(salt.utils.path_join(prefix, entry.name))
if len(blob):
_traverse(blob, blobs, os.path.join(prefix, entry.name))
_traverse(blob, blobs, salt.utils.path_join(prefix, entry.name))
ret = set()
tree = self.get_tree(tgt_env)
@ -1264,7 +1262,7 @@ class Pygit2(GitProvider):
blobs = []
if len(tree):
_traverse(tree, blobs, self.root)
add_mountpoint = lambda path: os.path.join(self.mountpoint, path)
add_mountpoint = lambda path: salt.utils.path_join(self.mountpoint, path)
for blob in blobs:
ret.add(add_mountpoint(relpath(blob)))
if self.mountpoint:
@ -1352,13 +1350,13 @@ class Pygit2(GitProvider):
continue
obj = self.repo[entry.oid]
if isinstance(obj, pygit2.Blob):
repo_path = os.path.join(prefix, entry.name)
repo_path = salt.utils.path_join(prefix, entry.name)
blobs.setdefault('files', []).append(repo_path)
if stat.S_ISLNK(tree[entry.name].filemode):
link_tgt = self.repo[tree[entry.name].oid].data
blobs.setdefault('symlinks', {})[repo_path] = link_tgt
elif isinstance(obj, pygit2.Tree):
_traverse(obj, blobs, os.path.join(prefix, entry.name))
_traverse(obj, blobs, salt.utils.path_join(prefix, entry.name))
files = set()
symlinks = {}
@ -1382,7 +1380,7 @@ class Pygit2(GitProvider):
blobs = {}
if len(tree):
_traverse(tree, blobs, self.root)
add_mountpoint = lambda path: os.path.join(self.mountpoint, path)
add_mountpoint = lambda path: salt.utils.path_join(self.mountpoint, path)
for repo_path in blobs.get('files', []):
files.add(add_mountpoint(relpath(repo_path)))
for repo_path, link_tgt in six.iteritems(blobs.get('symlinks', {})):
@ -1411,9 +1409,7 @@ class Pygit2(GitProvider):
# the symlink and set path to the location indicated
# in the blob data.
link_tgt = self.repo[tree[path].oid].data
path = os.path.normpath(
os.path.join(os.path.dirname(path), link_tgt)
)
path = salt.utils.path_join(os.path.dirname(path), link_tgt)
else:
oid = tree[path].oid
blob = self.repo[oid]
@ -1596,9 +1592,9 @@ class Dulwich(GitProvider): # pylint: disable=abstract-method
continue
if not isinstance(obj, dulwich.objects.Tree):
continue
blobs.append(os.path.join(prefix, item.path))
blobs.append(salt.utils.path_join(prefix, item.path))
if len(self.repo.get_object(item.sha)):
_traverse(obj, blobs, os.path.join(prefix, item.path))
_traverse(obj, blobs, salt.utils.path_join(prefix, item.path))
ret = set()
tree = self.get_tree(tgt_env)
@ -1612,7 +1608,7 @@ class Dulwich(GitProvider): # pylint: disable=abstract-method
relpath = lambda path: os.path.relpath(path, self.root)
else:
relpath = lambda path: path
add_mountpoint = lambda path: os.path.join(self.mountpoint, path)
add_mountpoint = lambda path: salt.utils.path_join(self.mountpoint, path)
for blob in blobs:
ret.add(add_mountpoint(relpath(blob)))
if self.mountpoint:
@ -1713,14 +1709,14 @@ class Dulwich(GitProvider): # pylint: disable=abstract-method
# Entry is a submodule, skip it
continue
if isinstance(obj, dulwich.objects.Blob):
repo_path = os.path.join(prefix, item.path)
repo_path = salt.utils.path_join(prefix, item.path)
blobs.setdefault('files', []).append(repo_path)
mode, oid = tree[item.path]
if stat.S_ISLNK(mode):
link_tgt = self.repo.get_object(oid).as_raw_string()
blobs.setdefault('symlinks', {})[repo_path] = link_tgt
elif isinstance(obj, dulwich.objects.Tree):
_traverse(obj, blobs, os.path.join(prefix, item.path))
_traverse(obj, blobs, salt.utils.path_join(prefix, item.path))
files = set()
symlinks = {}
@ -1735,7 +1731,7 @@ class Dulwich(GitProvider): # pylint: disable=abstract-method
relpath = lambda path: os.path.relpath(path, self.root)
else:
relpath = lambda path: path
add_mountpoint = lambda path: os.path.join(self.mountpoint, path)
add_mountpoint = lambda path: salt.utils.path_join(self.mountpoint, path)
for repo_path in blobs.get('files', []):
files.add(add_mountpoint(relpath(repo_path)))
for repo_path, link_tgt in six.iteritems(blobs.get('symlinks', {})):
@ -1770,9 +1766,7 @@ class Dulwich(GitProvider): # pylint: disable=abstract-method
# symlink. Follow the symlink and set path to the
# location indicated in the blob data.
link_tgt = self.repo.get_object(oid).as_raw_string()
path = os.path.normpath(
os.path.join(os.path.dirname(path), link_tgt)
)
path = salt.utils.path_join(os.path.dirname(path), link_tgt)
else:
blob = self.repo.get_object(oid)
break
@ -1786,7 +1780,7 @@ class Dulwich(GitProvider): # pylint: disable=abstract-method
Returns a dulwich.config.ConfigFile object for the specified repo
'''
return dulwich.config.ConfigFile().from_path(
os.path.join(self.repo.controldir(), 'config')
salt.utils.path_join(self.repo.controldir(), 'config')
)
def get_remote_url(self, repo):
@ -1903,7 +1897,7 @@ class Dulwich(GitProvider): # pylint: disable=abstract-method
log.error(_INVALID_REPO.format(self.cachedir, self.url, self.role))
return new
self.gitdir = os.path.join(self.repo.path, '.git')
self.gitdir = salt.utils.path_join(self.repo.path, '.git')
# Read in config file and look for the remote
try:
@ -1968,11 +1962,11 @@ class GitBase(object):
if cache_root is not None:
self.cache_root = cache_root
else:
self.cache_root = os.path.join(self.opts['cachedir'], self.role)
self.env_cache = os.path.join(self.cache_root, 'envs.p')
self.hash_cachedir = os.path.join(
self.cache_root = salt.utils.path_join(self.opts['cachedir'], self.role)
self.env_cache = salt.utils.path_join(self.cache_root, 'envs.p')
self.hash_cachedir = salt.utils.path_join(
self.cache_root, 'hash')
self.file_list_cachedir = os.path.join(
self.file_list_cachedir = salt.utils.path_join(
self.opts['cachedir'], 'file_lists', self.role)
def init_remotes(self, remotes, per_remote_overrides):
@ -2016,7 +2010,7 @@ class GitBase(object):
'a bug, please report it.'.format(key)
)
failhard(self.role)
per_remote_defaults[param] = str(self.opts[key])
per_remote_defaults[param] = six.text_type(self.opts[key])
self.remotes = []
for remote in remotes:
@ -2077,7 +2071,7 @@ class GitBase(object):
for item in cachedir_ls:
if item in ('hash', 'refs'):
continue
path = os.path.join(self.cache_root, item)
path = salt.utils.path_join(self.cache_root, item)
if os.path.isdir(path):
to_remove.append(path)
failed = []
@ -2132,7 +2126,7 @@ class GitBase(object):
continue
except TypeError:
# remote was non-string, try again
if not fnmatch.fnmatch(repo.url, str(remote)):
if not fnmatch.fnmatch(repo.url, six.text_type(remote)):
continue
success, failed = repo.clear_lock(lock_type=lock_type)
cleared.extend(success)
@ -2177,7 +2171,7 @@ class GitBase(object):
continue
except TypeError:
# remote was non-string, try again
if not fnmatch.fnmatch(repo.url, str(remote)):
if not fnmatch.fnmatch(repo.url, six.text_type(remote)):
continue
success, failed = repo.lock()
locked.extend(success)
@ -2444,7 +2438,7 @@ class GitBase(object):
'''
Write the remote_map.txt
'''
remote_map = os.path.join(self.cache_root, 'remote_map.txt')
remote_map = salt.utils.path_join(self.cache_root, 'remote_map.txt')
try:
with salt.utils.fopen(remote_map, 'w+') as fp_:
timestamp = \
@ -2546,16 +2540,16 @@ class GitFS(GitBase):
(not salt.utils.is_hex(tgt_env) and tgt_env not in self.envs()):
return fnd
dest = os.path.join(self.cache_root, 'refs', tgt_env, path)
hashes_glob = os.path.join(self.hash_cachedir,
tgt_env,
'{0}.hash.*'.format(path))
blobshadest = os.path.join(self.hash_cachedir,
tgt_env,
'{0}.hash.blob_sha1'.format(path))
lk_fn = os.path.join(self.hash_cachedir,
tgt_env,
'{0}.lk'.format(path))
dest = salt.utils.path_join(self.cache_root, 'refs', tgt_env, path)
hashes_glob = salt.utils.path_join(self.hash_cachedir,
tgt_env,
'{0}.hash.*'.format(path))
blobshadest = salt.utils.path_join(self.hash_cachedir,
tgt_env,
'{0}.hash.blob_sha1'.format(path))
lk_fn = salt.utils.path_join(self.hash_cachedir,
tgt_env,
'{0}.lk'.format(path))
destdir = os.path.dirname(dest)
hashdir = os.path.dirname(blobshadest)
if not os.path.isdir(destdir):
@ -2579,7 +2573,7 @@ class GitFS(GitBase):
continue
repo_path = path[len(repo.mountpoint):].lstrip(os.path.sep)
if repo.root:
repo_path = os.path.join(repo.root, repo_path)
repo_path = salt.utils.path_join(repo.root, repo_path)
blob, blob_hexsha = repo.find_file(repo_path, tgt_env)
if blob is None:
@ -2669,10 +2663,10 @@ class GitFS(GitBase):
ret = {'hash_type': self.opts['hash_type']}
relpath = fnd['rel']
path = fnd['path']
hashdest = os.path.join(self.hash_cachedir,
load['saltenv'],
'{0}.hash.{1}'.format(relpath,
self.opts['hash_type']))
hashdest = salt.utils.path_join(self.hash_cachedir,
load['saltenv'],
'{0}.hash.{1}'.format(relpath,
self.opts['hash_type']))
if not os.path.isfile(hashdest):
if not os.path.exists(os.path.dirname(hashdest)):
os.makedirs(os.path.dirname(hashdest))
@ -2707,11 +2701,11 @@ class GitFS(GitBase):
)
)
return []
list_cache = os.path.join(
list_cache = salt.utils.path_join(
self.file_list_cachedir,
'{0}.p'.format(load['saltenv'].replace(os.path.sep, '_|-'))
)
w_lock = os.path.join(
w_lock = salt.utils.path_join(
self.file_list_cachedir,
'.{0}.w'.format(load['saltenv'].replace(os.path.sep, '_|-'))
)

View file

@ -96,6 +96,9 @@ def query(key, keyid, method='GET', params=None, headers=None,
headers['x-amz-server-side-encryption'] = 'aws:kms'
headers['x-amz-server-side-encryption-aws-kms-key-id'] = kms_keyid
if not location:
location = __utils__['aws.get_location']()
data = ''
payload_hash = None
if method == 'PUT':

View file

@ -6,7 +6,7 @@
VT Helper
This module provides the SSHConnection to expose an SSH connection object
allowing users to programatically execute commands on a remote server using
allowing users to programmatically execute commands on a remote server using
Salt VT.
'''
from __future__ import absolute_import

View file

@ -56,14 +56,23 @@ class LocalClientTestCase(TestCase,
def test_cmd_subset(self, cmd_mock):
with patch('salt.client.LocalClient.cmd_cli') as cmd_cli_mock:
self.client.cmd_subset('*', 'first.func', sub=1, cli=True)
cmd_cli_mock.assert_called_with(['minion1'], 'first.func', (), progress=False,
try:
cmd_cli_mock.assert_called_with(['minion2'], 'first.func', (), progress=False,
kwarg=None, expr_form='list',
ret=['first.func', 'second.func'])
ret='')
except AssertionError:
cmd_cli_mock.assert_called_with(['minion1'], 'first.func', (), progress=False,
kwarg=None, expr_form='list',
ret='')
self.client.cmd_subset('*', 'first.func', sub=10, cli=True)
cmd_cli_mock.assert_called_with(['minion1', 'minion2'], 'first.func', (), progress=False,
try:
cmd_cli_mock.assert_called_with(['minion2', 'minion1'], 'first.func', (), progress=False,
kwarg=None, expr_form='list',
ret=['first.func', 'second.func'])
ret='')
except AssertionError:
cmd_cli_mock.assert_called_with(['minion1', 'minion2'], 'first.func', (), progress=False,
kwarg=None, expr_form='list',
ret='')
@skipIf(NOT_ZMQ, 'This test only works with ZeroMQ')
def test_pub(self):

View file

@ -19,10 +19,10 @@ from salttesting.helpers import ensure_in_syspath
ensure_in_syspath('../../')
# Import Salt Libs
import salt.utils.s3
from salt.modules import s3
s3.__salt__ = {}
s3.__utils__ = {'s3.query': MagicMock(return_value='A')}
@skipIf(NO_MOCK, NO_MOCK_REASON)
@ -47,8 +47,7 @@ class S3TestCase(TestCase):
return_value=('key', 'keyid', 'service_url',
'verify_ssl', 'kms_keyid', 'location',
'role_arn')):
with patch.object(salt.utils.s3, 'query', return_value='A'):
self.assertEqual(s3.delete('bucket'), 'A')
self.assertEqual(s3.delete('bucket'), 'A')
def test_get(self):
'''
@ -59,8 +58,7 @@ class S3TestCase(TestCase):
return_value=('key', 'keyid', 'service_url',
'verify_ssl', 'kms_keyid', 'location',
'role_arn')):
with patch.object(salt.utils.s3, 'query', return_value='A'):
self.assertEqual(s3.get(), 'A')
self.assertEqual(s3.get(), 'A')
def test_head(self):
'''
@ -70,8 +68,7 @@ class S3TestCase(TestCase):
return_value=('key', 'keyid', 'service_url',
'verify_ssl', 'kms_keyid', 'location',
'role_arn')):
with patch.object(salt.utils.s3, 'query', return_value='A'):
self.assertEqual(s3.head('bucket'), 'A')
self.assertEqual(s3.head('bucket'), 'A')
def test_put(self):
'''
@ -81,8 +78,7 @@ class S3TestCase(TestCase):
return_value=('key', 'keyid', 'service_url',
'verify_ssl', 'kms_keyid', 'location',
'role_arn')):
with patch.object(salt.utils.s3, 'query', return_value='A'):
self.assertEqual(s3.put('bucket'), 'A')
self.assertEqual(s3.put('bucket'), 'A')
if __name__ == '__main__':

View file

@ -60,7 +60,7 @@ class HtpasswdTestCase(TestCase):
with patch.dict(htpasswd.__salt__,
{'file.grep': mock_grep,
'webutil.useradd_all': mock_useradd}):
'webutil.useradd': mock_useradd}):
ret = htpasswd.user_exists('larry', 'badpass',
'/etc/httpd/htpasswd')
expected = {'name': 'larry',
@ -80,7 +80,7 @@ class HtpasswdTestCase(TestCase):
with patch.dict(htpasswd.__salt__,
{'file.grep': mock_grep,
'webutil.useradd_all': mock_useradd}):
'webutil.useradd': mock_useradd}):
ret = htpasswd.user_exists('larry', 'badpass',
'/etc/httpd/htpasswd')
expected = {'name': 'larry',

View file

@ -17,7 +17,8 @@ import platform
import tempfile
# Import Salt Testing libs
from salttesting import TestCase
import salt.utils
from salttesting import TestCase, skipIf
from salttesting.helpers import ensure_in_syspath
ensure_in_syspath('../../')
@ -30,9 +31,6 @@ import salt.ext.six as six
class PathJoinTestCase(TestCase):
def setUp(self):
self.skipTest('Skipped until properly mocked')
PLATFORM_FUNC = platform.system
BUILTIN_MODULES = sys.builtin_module_names
@ -53,6 +51,7 @@ class PathJoinTestCase(TestCase):
(('c', r'\temp', r'\foo\bar'), 'c:\\temp\\foo\\bar')
)
@skipIf(True, 'Skipped until properly mocked')
def test_nix_paths(self):
if platform.system().lower() == "windows":
self.skipTest(
@ -65,6 +64,7 @@ class PathJoinTestCase(TestCase):
'{0}: {1}'.format(idx, expected)
)
@skipIf(True, 'Skipped until properly mocked')
def test_windows_paths(self):
if platform.system().lower() != "windows":
self.skipTest(
@ -79,6 +79,7 @@ class PathJoinTestCase(TestCase):
'{0}: {1}'.format(idx, expected)
)
@skipIf(True, 'Skipped until properly mocked')
def test_windows_paths_patched_path_module(self):
if platform.system().lower() == "windows":
self.skipTest(
@ -97,6 +98,23 @@ class PathJoinTestCase(TestCase):
self.__unpatch_path()
@skipIf(salt.utils.is_windows(), '*nix-only test')
def test_mixed_unicode_and_binary(self):
'''
This tests joining paths that contain a mix of components with unicode
strings and non-unicode strings with the unicode characters as binary.
This is no longer something we need to concern ourselves with in
Python 3, but the test should nonetheless pass on Python 3. Really what
we're testing here is that we don't get a UnicodeDecodeError when
running on Python 2.
'''
a = u'/foo/bar'
b = 'Д'
expected = u'/foo/bar/\u0414'
actual = path_join(a, b)
self.assertEqual(actual, expected)
def __patch_path(self):
import imp
modules = list(self.BUILTIN_MODULES[:])