Fixing merge conflict with latest from develop

This commit is contained in:
Benjamin J Cane 2016-11-11 12:21:27 -07:00
commit e188e12bc9
111 changed files with 1281 additions and 463 deletions

View File

@ -235,8 +235,8 @@ version = salt.version.__version__
latest_release = '2016.3.4' # latest release
previous_release = '2015.8.12' # latest release from previous branch
previous_release_dir = '2015.8' # path on web server for previous branch
next_release = '' # next release
next_release_dir = '' # path on web server for next release branch
next_release = '2016.11' # next release
next_release_dir = '2016.11' # path on web server for next release branch
today = ''
copyright = ''

View File

@ -44946,7 +44946,7 @@ set in the master\(aqs configuration file:
.sp
.nf
.ft C
requests_lib: True
backend: requests
.ft P
.fi
.UNINDENT
@ -232680,7 +232680,7 @@ my\-rest\-api:
url: https://api.github.com/
keys:
url: https://api.github.com/users/{{user}}/keys
requests_lib: True
backend: requests
.ft P
.fi
.UNINDENT

View File

@ -3096,7 +3096,7 @@ master, specify the log_file of the syndic daemon.
syndic_log_file: salt-syndic.log
.. master_conf:: syndic_failover
.. conf_master:: syndic_failover
``syndic_failover``
-------------------

View File

@ -992,7 +992,7 @@ The port number used for HTTP proxy access.
.. conf_minion:: proxy_username
``proxy_username``
--------------
------------------
Default: ``''``
@ -1005,7 +1005,7 @@ The username used for HTTP proxy access.
.. conf_minion:: proxy_password
``proxy_password``
--------------
------------------
Default: ``''``

View File

@ -198,7 +198,7 @@ The name of the service in which to create the VM. If this is not specified,
then a service will be created with the same name as the VM.
virtual_network_name
------------
--------------------
Optional. The name of the virtual network for the VM to join. If this is not
specified, then no virtual network will be joined.
@ -710,7 +710,7 @@ set in the master's configuration file:
.. code-block:: bash
requests_lib: True
backend: requests
The following functions are available.

View File

@ -43,10 +43,10 @@ Key events
.. salt:event:: salt/key
Fired when accepting and rejecting minions keys on the Salt master.
These happen as a result of actions undertaken by the `salt-key` command.
:var id: The minion ID.
:var act: The new status of the minion key: ``accept``, ``pend``,
``reject``, ``delete``.
:var act: The new status of the minion key: ``accept``, ``delete``,
.. warning:: If a master is in :conf_master:`auto_accept mode`, ``salt/key`` events
will not be fired when the keys are accepted. In addition, pre-seeding

View File

@ -95,6 +95,14 @@ least one item must be selected.
You will also be prompted on the final page to start the ``salt-master``
service.
Installation Prerequisites
--------------------------
Most Salt functionality should work just fine right out of the box. A few Salt
modules rely on PowerShell. The minimum version of PowerShell required for Salt
is version 3. If you intend to work with DSC then Powershell version 5 is the
minimum.
.. _windows-installer-options:
Silent Installer Options

View File

@ -0,0 +1,22 @@
===========================
Salt 2016.3.5 Release Notes
===========================
Version 2016.3.5 is a bugfix release for :doc:`2016.3.0
</topics/releases/2016.3.0>`.
Improved Checksum Handling in :py:func:`file.managed <salt.states.file.managed>`, :py:func:`archive.extracted <salt.states.archive.extracted>` States
-----------------------------------------------------------------------------------------------------------------------------------------------------
When the ``source_hash`` argument for these states refers to a file containing
checksums, Salt now looks for checksums matching the name of the source URI, as
well as the file being managed. Prior releases only looked for checksums
matching the filename being managed. Additionally, a new argument
(``source_hash_name``) has been added, which allows the user to disambiguate
ambiguous matches when more than one matching checksum is found in the
``source_hash`` file.
A more detailed explanation of this functionality can be found in the
:py:func:`file.managed <salt.states.file.managed>` documentation, in the
section for the new ``source_hash_name`` argument.

View File

@ -26,7 +26,7 @@ Builds for a few platforms are available as part of the RC at https://repo.salts
baseurl=https://repo.saltstack.com/salt_rc/yum/redhat/$releasever/$basearch/
.. code-block::
.. code-block:: none
deb http://repo.saltstack.com/salt_rc/apt/ubuntu/14.04/amd64 jessie main
@ -126,4 +126,4 @@ Then install salt using the following command:
.. code-block:: bash
sudo pip install salt==v2016.11.0rc2
sudo pip install salt==2016.11.0rc2

View File

@ -377,7 +377,7 @@ using the ``ca_bundle`` variable.
)
Updating CA Bundles
+++++++++++++++++++
'''''''''''''''''''
The ``update_ca_bundle()`` function can be used to update the bundle file at a
specified location. If the target location is not specified, then it will
attempt to auto-detect the location of the bundle file. If the URL to download

View File

@ -46,6 +46,9 @@ ln -sf /opt/salt/bin/salt-config.sh /usr/local/sbin/salt-config
# Add salt to paths.d
###############################################################################
# echo "Path: Adding salt to the path..." >> /tmp/postinstall.txt
if [ ! -d "/etc/paths.d" ]; then
mkdir /etc/paths.d
fi
sh -c 'echo "/opt/salt/bin" > /etc/paths.d/salt'
sh -c 'echo "/usr/local/sbin" >> /etc/paths.d/salt'

View File

@ -125,6 +125,7 @@ case "$1" in
echo -n "Checking for service salt-api "
checkproc $SALTAPI
rc_status -v
RETVAL=$?
elif [ -f $DEBIAN_VERSION ]; then
if [ -f $LOCKFILE ]; then
RETVAL=0

View File

@ -108,6 +108,7 @@ case "$1" in
echo -n "Checking for service salt-master "
checkproc $SALTMASTER
rc_status -v
RETVAL=$?
elif [ -f $DEBIAN_VERSION ]; then
if [ -f $LOCKFILE ]; then
RETVAL=0

View File

@ -57,6 +57,7 @@ start() {
if [ -f $SUSE_RELEASE ]; then
startproc -p /var/run/$SERVICE.pid $SALTMINION -d $MINION_ARGS
rc_status -v
RETVAL=$?
elif [ -e $DEBIAN_VERSION ]; then
if [ -f $LOCKFILE ]; then
echo -n "already started, lock file found"
@ -114,6 +115,7 @@ case "$1" in
echo -n "Checking for service salt-minion "
checkproc $SALTMINION
rc_status -v
RETVAL=$?
elif [ -f $DEBIAN_VERSION ]; then
if [ -f $LOCKFILE ]; then
RETVAL=0

View File

@ -109,6 +109,7 @@ case "$1" in
echo -n "Checking for service salt-syndic "
checkproc $SALTSYNDIC
rc_status -v
RETVAL=$?
elif [ -f $DEBIAN_VERSION ]; then
if [ -f $LOCKFILE ]; then
RETVAL=0

View File

@ -232,7 +232,7 @@ def beacon(config):
if re.search(exclude.keys()[0], event.pathname):
_append = False
except Exception:
log.warn('Failed to compile regex: {0}'.format(exclude.keys()[0]))
log.warning('Failed to compile regex: {0}'.format(exclude.keys()[0]))
else:
exclude = exclude.keys()[0]
elif '*' in exclude:

View File

@ -76,7 +76,7 @@ def updated(bank, key):
'''
key_file = os.path.join(__opts__['cachedir'], os.path.normpath(bank), '{0}.p'.format(key))
if not os.path.isfile(key_file):
log.warn('Cache file "%s" does not exist', key_file)
log.warning('Cache file "%s" does not exist', key_file)
return None
try:
return int(os.path.getmtime(key_file))

View File

@ -44,7 +44,8 @@ class SaltCMD(parsers.SaltCMDOptionParser):
self.local_client = salt.client.get_local_client(
self.get_config_file_path(),
skip_perm_errors=skip_perm_errors)
skip_perm_errors=skip_perm_errors,
auto_reconnect=True)
except SaltClientError as exc:
self.exit(2, '{0}\n'.format(exc))
return

View File

@ -72,7 +72,8 @@ def get_local_client(
c_path=os.path.join(syspaths.CONFIG_DIR, 'master'),
mopts=None,
skip_perm_errors=False,
io_loop=None):
io_loop=None,
auto_reconnect=False):
'''
.. versionadded:: 2014.7.0
@ -99,7 +100,8 @@ def get_local_client(
return LocalClient(
mopts=opts,
skip_perm_errors=skip_perm_errors,
io_loop=io_loop)
io_loop=io_loop,
auto_reconnect=auto_reconnect)
class LocalClient(object):
@ -134,7 +136,7 @@ class LocalClient(object):
def __init__(self,
c_path=os.path.join(syspaths.CONFIG_DIR, 'master'),
mopts=None, skip_perm_errors=False,
io_loop=None, keep_loop=False):
io_loop=None, keep_loop=False, auto_reconnect=False):
'''
:param IOLoop io_loop: io_loop used for events.
Pass in an io_loop if you want asynchronous
@ -157,6 +159,7 @@ class LocalClient(object):
self.salt_user = salt.utils.get_specific_user()
self.skip_perm_errors = skip_perm_errors
self.key = self.__read_master_key()
self.auto_reconnect = auto_reconnect
self.event = salt.utils.event.get_event(
'master',
self.opts['sock_dir'],
@ -164,7 +167,8 @@ class LocalClient(object):
opts=self.opts,
listen=False,
io_loop=io_loop,
keep_loop=keep_loop)
keep_loop=keep_loop,
raise_errors=auto_reconnect)
self.utils = salt.loader.utils(self.opts)
self.functions = salt.loader.minion_mods(self.opts, utils=self.utils)
self.returners = salt.loader.returners(self.opts, self.functions)
@ -903,8 +907,16 @@ class LocalClient(object):
'''
while True:
raw = self.event.get_event(wait=0.01, tag=tag, match_type=match_type, full=True, no_block=True)
yield raw
try:
raw = self.event.get_event(wait=0.01, tag=tag, match_type=match_type, full=True, no_block=True)
yield raw
except tornado.iostream.StreamClosedError:
if self.auto_reconnect:
log.warning('Connection to master lost. Reconnecting.')
self.event.close_pub()
self.event.connect_pub(timeout=self._get_timeout(None))
else:
raise
def get_iter_returns(
self,
@ -1136,7 +1148,16 @@ class LocalClient(object):
while True:
time_left = timeout_at - int(time.time())
wait = max(1, time_left)
raw = self.event.get_event(wait, jid)
try:
raw = self.event.get_event(wait, jid)
except tornado.iostream.StreamClosedError:
if self.auto_reconnect:
log.warning('Connection to master lost. Reconnecting.')
self.event.close_pub()
self.event.connect_pub(timeout=self._get_timeout(wait))
continue
else:
raise
if raw is not None and 'return' in raw:
found.add(raw['id'])
ret[raw['id']] = raw['return']
@ -1289,7 +1310,16 @@ class LocalClient(object):
# Wait 0 == forever, use a minimum of 1s
wait = max(1, time_left)
jid_tag = 'salt/job/{0}'.format(jid)
raw = self.event.get_event(wait, jid_tag)
try:
raw = self.event.get_event(wait, jid_tag)
except tornado.iostream.StreamClosedError:
if self.auto_reconnect:
log.warning('Connection to master lost. Reconnecting.')
self.event.close_pub()
self.event.connect_pub(timeout=self._get_timeout(wait))
continue
else:
raise
if raw is not None and 'return' in raw:
if 'minions' in raw.get('data', {}):
minions.update(raw['data']['minions'])
@ -1407,7 +1437,16 @@ class LocalClient(object):
raise StopIteration()
# Wait for the hosts to check in
while True:
raw = self.event.get_event(timeout)
try:
raw = self.event.get_event(timeout)
except tornado.iostream.StreamClosedError:
if self.auto_reconnect:
log.warning('Connection to master lost. Reconnecting.')
self.event.close_pub()
self.event.connect_pub(timeout=self._get_timeout(timeout))
continue
else:
raise
if raw is None or time.time() > timeout_at:
# Timeout reached
break

View File

@ -218,7 +218,7 @@ def _cache(bank, key, fun, **kwargs):
try:
item_list = fun(**kwargs)
except CloudError as exc:
log.warn('There was a cloud error calling {0} with kwargs {1}: {2}'.format(fun, kwargs, exc))
log.warning('There was a cloud error calling {0} with kwargs {1}: {2}'.format(fun, kwargs, exc))
for item in item_list:
items[item.name] = object_to_dict(item)
cache.store(bank, key, items)
@ -1024,8 +1024,8 @@ def request_instance(call=None, kwargs=None): # pylint: disable=unused-argument
try:
poller.wait()
except CloudError as exc:
log.warn('There was a cloud error: {0}'.format(exc))
log.warn('This may or may not indicate an actual problem')
log.warning('There was a cloud error: {0}'.format(exc))
log.warning('This may or may not indicate an actual problem')
try:
return show_instance(vm_['name'], call='action')
@ -1100,7 +1100,7 @@ def create(vm_):
)
except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure, SaltCloudSystemExit) as exc:
try:
log.warn(exc)
log.warning(exc)
finally:
raise SaltCloudSystemExit(str(exc))

View File

@ -14,7 +14,7 @@ The Azure cloud module is used to control access to Microsoft Azure
* ``apikey``
* ``certificate_path``
* ``subscription_id``
* ``requests_lib``
* ``backend``
A Management Certificate (.pem and .crt files) must be created and the .pem
file placed on the same machine that salt-cloud is run from. Information on
@ -23,7 +23,7 @@ The Azure cloud module is used to control access to Microsoft Azure
http://www.windowsazure.com/en-us/develop/python/how-to-guides/service-management/
For users with Python < 2.7.9, requests_lib must currently be set to True.
For users with Python < 2.7.9, ``backend`` must currently be set to ``requests``.
Example ``/etc/salt/cloud.providers`` or
``/etc/salt/cloud.providers.d/azure.conf`` configuration:
@ -404,7 +404,7 @@ def show_instance(name, call=None):
try:
__utils__['cloud.cache_node'](nodes[name], __active_provider_name__, __opts__)
except TypeError:
log.warn('Unable to show cache node data; this may be because the node has been deleted')
log.warning('Unable to show cache node data; this may be because the node has been deleted')
return nodes[name]
@ -3401,6 +3401,14 @@ def query(path, method='GET', data=None, params=None, header_dict=None, decode=T
'requests_lib',
get_configured_provider(), __opts__, search_global=False
)
if requests_lib is not None:
salt.utils.warn_until('Oxygen', '"requests_lib:True" has been replaced by "backend:requests", '
'please change your config')
backend = config.get_cloud_config_value(
'backend',
get_configured_provider(), __opts__, search_global=False
)
url = 'https://{management_host}/{subscription_id}/{path}'.format(
management_host=management_host,
subscription_id=subscription_id,
@ -3422,6 +3430,7 @@ def query(path, method='GET', data=None, params=None, header_dict=None, decode=T
text=True,
cert=certificate_path,
requests_lib=requests_lib,
backend=backend,
decode=decode,
decode_type='xml',
)

View File

@ -1495,8 +1495,8 @@ CLOUD_CONFIG_DEFAULTS = {
DEFAULT_API_OPTS = {
# ----- Salt master settings overridden by Salt-API --------------------->
'pidfile': '/var/run/salt-api.pid',
'logfile': '/var/log/salt/api',
'api_pidfile': os.path.join(salt.syspaths.PIDFILE_DIR, 'salt-api.pid'),
'api_logfile': os.path.join(salt.syspaths.LOGS_DIR, 'api'),
'rest_timeout': 300,
# <---- Salt master settings overridden by Salt-API ----------------------
}
@ -1914,6 +1914,7 @@ def minion_config(path,
opts = apply_minion_config(overrides, defaults,
cache_minion_id=cache_minion_id,
minion_id=minion_id)
apply_sdb(opts)
_validate_opts(opts)
return opts
@ -1989,7 +1990,6 @@ def syndic_config(master_config_path,
return opts
# ----- Salt Cloud Configuration Functions ---------------------------------->
def apply_sdb(opts, sdb_opts=None):
'''
Recurse for sdb:// links for opts
@ -2014,6 +2014,7 @@ def apply_sdb(opts, sdb_opts=None):
return sdb_opts
# ----- Salt Cloud Configuration Functions ---------------------------------->
def cloud_config(path, env_var='SALT_CLOUD_CONFIG', defaults=None,
master_config_path=None, master_config=None,
providers_config_path=None, providers_config=None,
@ -3199,6 +3200,7 @@ def master_config(path, env_var='SALT_MASTER_CONFIG', defaults=None, exit_on_con
opts['nodegroups'] = DEFAULT_MASTER_OPTS.get('nodegroups', {})
if opts.get('transport') == 'raet' and 'aes' in opts:
opts.pop('aes')
apply_sdb(opts)
return opts
@ -3399,12 +3401,23 @@ def api_config(path):
Read in the salt master config file and add additional configs that
need to be stubbed out for salt-api
'''
# Let's grab a copy of salt's master default opts
defaults = DEFAULT_MASTER_OPTS
# Let's grab a copy of salt's master opts
opts = client_config(path, defaults=DEFAULT_MASTER_OPTS)
# Let's override them with salt-api's required defaults
defaults.update(DEFAULT_API_OPTS)
return client_config(path, defaults=defaults)
api_opts = {
'log_file': opts.get(
'api_logfile', os.path.join(
opts['root_dir'], DEFAULT_API_OPTS['api_logfile'].lstrip('/')
)
),
'pidfile': opts.get(
'api_pidfile', os.path.join(
opts['root_dir'], DEFAULT_API_OPTS['api_pidfile'].lstrip('/')
)
),
}
opts.update(api_opts)
return opts
def spm_config(path):

View File

@ -1146,10 +1146,12 @@ _OS_FAMILY_MAP = {
'SLES_SAP': 'Suse',
'Solaris': 'Solaris',
'SmartOS': 'Solaris',
'OmniOS': 'Solaris',
'OpenIndiana Development': 'Solaris',
'OpenIndiana': 'Solaris',
'OpenSolaris Development': 'Solaris',
'OpenSolaris': 'Solaris',
'Oracle Solaris': 'Solaris',
'Arch ARM': 'Arch',
'Manjaro': 'Arch',
'Antergos': 'Arch',
@ -1514,12 +1516,19 @@ def os_data():
grains.update(_linux_cpudata())
grains.update(_linux_gpu_data())
elif grains['kernel'] == 'SunOS':
grains['os_family'] = 'Solaris'
if salt.utils.is_smartos():
# See https://github.com/joyent/smartos-live/issues/224
uname_v = os.uname()[3]
uname_v = os.uname()[3] # format: joyent_20161101T004406Z
uname_v = uname_v[uname_v.index('_')+1:]
grains['os'] = grains['osfullname'] = 'SmartOS'
grains['osrelease'] = uname_v[uname_v.index('_')+1:]
# store a parsed version of YYYY.MM.DD as osrelease
grains['osrelease'] = ".".join([
uname_v.split('T')[0][0:4],
uname_v.split('T')[0][4:6],
uname_v.split('T')[0][6:8],
])
# store a untouched copy of the timestamp in osrelease_stamp
grains['osrelease_stamp'] = uname_v
if salt.utils.is_smartos_globalzone():
grains.update(_smartos_computenode_data())
elif os.path.isfile('/etc/release'):
@ -1527,10 +1536,10 @@ def os_data():
rel_data = fp_.read()
try:
release_re = re.compile(
r'((?:Open)?Solaris|OpenIndiana) (Development)?'
r'\s*(\d+ \d+\/\d+|oi_\S+|snv_\S+)?'
r'((?:Open|Oracle )?Solaris|OpenIndiana|OmniOS) (Development)?'
r'\s*(\d+\.?\d*|v\d+)\s?[A-Z]*\s?(r\d+|\d+\/\d+|oi_\S+|snv_\S+)?'
)
osname, development, osrelease = \
osname, development, osmajorrelease, osminorrelease = \
release_re.search(rel_data).groups()
except AttributeError:
# Set a blank osrelease grain and fallback to 'Solaris'
@ -1540,8 +1549,26 @@ def os_data():
else:
if development is not None:
osname = ' '.join((osname, development))
uname_v = os.uname()[3]
grains['os'] = grains['osfullname'] = osname
grains['osrelease'] = osrelease
if osname in ['Oracle Solaris'] and uname_v.startswith(osmajorrelease):
# Oracla Solars 11 and up have minor version in uname
grains['osrelease'] = uname_v
elif osname in ['OmniOS']:
# OmniOS
osrelease = []
osrelease.append(osmajorrelease[1:])
osrelease.append(osminorrelease[1:])
grains['osrelease'] = ".".join(osrelease)
grains['osrelease_stamp'] = uname_v
else:
# Sun Solaris 10 and earlier/comparable
osrelease = []
osrelease.append(osmajorrelease)
if osminorrelease:
osrelease.append(osminorrelease)
grains['osrelease'] = ".".join(osrelease)
grains['osrelease_stamp'] = uname_v
grains.update(_sunos_cpudata())
elif grains['kernel'] == 'VMkernel':

View File

@ -166,7 +166,6 @@ def minion_mods(
context=None,
utils=None,
whitelist=None,
include_errors=False,
initial_load=False,
loaded_base_name=None,
notify=False,
@ -189,7 +188,6 @@ def minion_mods(
configuration.
:param list whitelist: A list of modules which should be whitelisted.
:param bool include_errors: Deprecated flag! Unused.
:param bool initial_load: Deprecated flag! Unused.
:param str loaded_base_name: A string marker for the loaded base name.
:param bool notify: Flag indicating that an event should be fired upon

View File

@ -2357,7 +2357,7 @@ class ClearFuncs(object):
self.opts['ext_job_cache']
)
)
except AttributeError:
except (AttributeError, KeyError):
save_load_func = False
log.critical(
'The specified returner used for the external job cache '

View File

@ -683,8 +683,7 @@ class SMinion(MinionBase):
'''
self.utils = salt.loader.utils(self.opts)
self.functions = salt.loader.minion_mods(self.opts, utils=self.utils,
include_errors=True)
self.functions = salt.loader.minion_mods(self.opts, utils=self.utils)
self.serializers = salt.loader.serializers(self.opts)
self.returners = salt.loader.returners(self.opts, self.functions)
self.proxy = salt.loader.proxy(self.opts, self.functions, self.returners, None)
@ -1533,9 +1532,13 @@ class Minion(MinionBase):
ret['id'] = opts['id']
for returner in set(data['ret'].split(',')):
try:
minion_instance.returners['{0}.returner'.format(
returner
)](ret)
returner_str = '{0}.returner'.format(returner)
if returner_str in minion_instance.returners:
minion_instance.returners[returner_str](ret)
else:
returner_err = minion_instance.returners.missing_fun_string(returner_str)
log.error('Returner {0} could not be loaded: {1}'.format(
returner_str, returner_err))
except Exception as exc:
log.error(
'The return failed for job {0} {1}'.format(

View File

@ -465,7 +465,7 @@ def list_tags(DomainName=None, ARN=None,
raise SaltInvocationError('One (but not both) of ARN or '
'domain must be specified.')
ret = conn.list_tags(ARN=ARN)
log.warn(ret)
log.warning(ret)
tlist = ret.get('TagList', [])
tagdict = {}
for tag in tlist:

View File

@ -2616,7 +2616,7 @@ def _maybe_set_dns(conn, vpcid, dns_support, dns_hostnames):
def _maybe_name_route_table(conn, vpcid, vpc_name):
route_tables = conn.get_all_route_tables(filters={'vpc_id': vpcid})
if not route_tables:
log.warn('no default route table found')
log.warning('no default route table found')
return
default_table = None
for table in route_tables:
@ -2625,7 +2625,7 @@ def _maybe_name_route_table(conn, vpcid, vpc_name):
default_table = table
break
if not default_table:
log.warn('no default route table found')
log.warning('no default route table found')
return
name = '{0}-default-table'.format(vpc_name)

View File

@ -683,7 +683,7 @@ def upgrade(name,
force_x86=False,
package_args=None):
'''
.. version-added:: 2016.3.4
.. versionadded:: 2016.3.4
Instructs Chocolatey to upgrade packages on the system. (update is being
deprecated)

View File

@ -61,14 +61,15 @@ __func_alias__ = {
'makedirs_': 'makedirs'
}
HASHES = [
['sha512', 128],
['sha384', 96],
['sha256', 64],
['sha224', 56],
['sha1', 40],
['md5', 32],
]
HASHES = {
'sha512': 128,
'sha384': 96,
'sha256': 64,
'sha224': 56,
'sha1': 40,
'md5': 32,
}
HASHES_REVMAP = dict([(y, x) for x, y in six.iteritems(HASHES)])
def __virtual__():
@ -538,12 +539,22 @@ def get_hash(path, form='sha256', chunk_size=65536):
return salt.utils.get_hash(os.path.expanduser(path), form, chunk_size)
def get_source_sum(source, source_hash, saltenv='base'):
def get_source_sum(file_name='',
source='',
source_hash=None,
source_hash_name=None,
saltenv='base'):
'''
.. versionadded:: 2016.11.0
Obtain a checksum and hash type, given a ``source_hash`` file/expression
and the source file name.
Used by :py:func:`file.get_managed <salt.modules.file.get_managed>` to
obtain the hash and hash type from the parameters specified below.
file_name
Optional file name being managed, for matching with
:py:func:`file.extract_hash <salt.modules.file.extract_hash>`.
.. versionadded:: 2016.11.1
source
Source file, as used in :py:mod:`file <salt.states.file>` and other
@ -559,27 +570,43 @@ def get_source_sum(source, source_hash, saltenv='base'):
<salt.modules.file.extract_hash>` will be used to obtain a hash from
it.
source_hash_name
Specific file name to look for when ``source_hash`` refers to a remote
file, used to disambiguate ambiguous matches.
.. versionadded:: 2016.11.1
saltenv : base
Salt fileserver environment from which to retrive the source_hash. This
value will only be used when ``source_hash`` refers to a file on the
Salt fileserver (i.e. one beginning with ``salt://``).
CLI Examples:
CLI Example:
.. code-block:: bash
salt '*' file.get_source_sum /etc/foo.conf source_hash=499ae16dcae71eeb7c3a30c75ea7a1a6
salt '*' file.get_source_sum /etc/foo.conf source_hash=md5=499ae16dcae71eeb7c3a30c75ea7a1a6
salt '*' file.get_source_sum /etc/foo.conf source_hash=https://foo.domain.tld/hashfile
salt '*' file.get_source_sum /tmp/foo.tar.gz source=http://mydomain.tld/foo.tar.gz source_hash=499ae16dcae71eeb7c3a30c75ea7a1a6
salt '*' file.get_source_sum /tmp/foo.tar.gz source=http://mydomain.tld/foo.tar.gz source_hash=https://mydomain.tld/hashes.md5
salt '*' file.get_source_sum /tmp/foo.tar.gz source=http://mydomain.tld/foo.tar.gz source_hash=https://mydomain.tld/hashes.md5 source_hash_name=./dir2/foo.tar.gz
'''
def _invalid_source_hash_format():
'''
DRY helper for reporting invalid source_hash input
'''
raise CommandExecutionError(
'Source hash {0} format is invalid. It must be in the format '
'<hash type>=<hash>, or it must be a supported protocol: {1}'
.format(source_hash, ', '.join(salt.utils.files.VALID_PROTOS))
'Source hash {0} format is invalid. The supported formats are: '
'1) a hash, 2) an expression in the format <hash_type>=<hash>, or '
'3) either a path to a local file containing hashes, or a URI of '
'a remote hash file. Supported protocols for remote hash files '
'are: {1}. The hash may also not be of a valid length, the '
'following are supported hash types and lengths: {2}.'.format(
source_hash,
', '.join(salt.utils.files.VALID_PROTOS),
', '.join(
['{0} ({1})'.format(HASHES_REVMAP[x], x)
for x in sorted(HASHES_REVMAP)]
),
)
)
hash_fn = None
@ -606,7 +633,7 @@ def get_source_sum(source, source_hash, saltenv='base'):
_invalid_source_hash_format()
if hash_fn is not None:
ret = extract_hash(hash_fn, '', source)
ret = extract_hash(hash_fn, '', file_name, source, source_hash_name)
if ret is None:
_invalid_source_hash_format()
return ret
@ -624,12 +651,34 @@ def get_source_sum(source, source_hash, saltenv='base'):
_invalid_source_hash_format()
ret['hsum'] = source_hash
source_hash_len = len(source_hash)
for hash_type, hash_len in HASHES:
if source_hash_len == hash_len:
ret['hash_type'] = hash_type
break
if source_hash_len in HASHES_REVMAP:
ret['hash_type'] = HASHES_REVMAP[source_hash_len]
else:
_invalid_source_hash_format()
if ret['hash_type'] not in HASHES:
raise CommandExecutionError(
'Invalid hash type \'{0}\'. Supported hash types are: {1}. '
'Either remove the hash type and simply use \'{2}\' as the '
'source_hash, or change the hash type to a supported type.'
.format(ret['hash_type'], ', '.join(HASHES), ret['hsum'])
)
else:
hsum_len = len(ret['hsum'])
if hsum_len not in HASHES_REVMAP:
_invalid_source_hash_format()
elif hsum_len != HASHES[ret['hash_type']]:
raise CommandExecutionError(
'Invalid length ({0}) for hash type \'{1}\'. Either '
'remove the hash type and simply use \'{2}\' as the '
'source_hash, or change the hash type to \'{3}\''.format(
hsum_len,
ret['hash_type'],
ret['hsum'],
HASHES_REVMAP[hsum_len],
)
)
return ret
@ -1506,45 +1555,66 @@ def line(path, content=None, match=None, mode=None, location=None,
'''
.. versionadded:: 2015.8.0
Edit a line in the configuration file.
Edit a line in the configuration file. The ``path`` and ``content``
arguments are required, as well as passing in one of the ``mode``
options.
:param path:
path
Filesystem path to the file to be edited.
:param content:
content
Content of the line. Allowed to be empty if mode=delete.
:param match:
match
Match the target line for an action by
a fragment of a string or regular expression.
:param mode:
:Ensure:
If line does not exist, it will be added.
If neither ``before`` nor ``after`` are provided, and ``match``
is also ``None``, match becomes the ``content`` value.
:Replace:
If line already exist, it will be replaced.
mode
Defines how to edit a line. One of the following options is
required:
:Delete:
- ensure
If line does not exist, it will be added. This is based on the
``content`` argument.
- replace
If line already exists, it will be replaced.
- delete
Delete the line, once found.
:Insert:
- insert
Insert a line.
:param location:
:start:
Place the content at the beginning of the file.
.. note::
:end:
If ``mode=insert`` is used, at least one of the following
options must also be defined: ``location``, ``before``, or
``after``. If ``location`` is used, it takes precedence
over the other two options.
location
Defines where to place content in the line. Note this option is only
used when ``mode=insert`` is specified. If a location is passed in, it
takes precedence over both the ``before`` and ``after`` kwargs. Valid
locations are:
- start
Place the content at the beginning of the file.
- end
Place the content at the end of the file.
:param before:
before
Regular expression or an exact case-sensitive fragment of the string.
This option is only used when either the ``ensure`` or ``insert`` mode
is defined.
:param after:
after
Regular expression or an exact case-sensitive fragment of the string.
This option is only used when either the ``ensure`` or ``insert`` mode
is defined.
:param show_changes:
show_changes
Output a unified diff of the old file and the new file.
If ``False`` return a boolean if any changes were made.
Default is ``True``
@ -1553,31 +1623,34 @@ def line(path, content=None, match=None, mode=None, location=None,
Using this option will store two copies of the file in-memory
(the original version and the edited version) in order to generate the diff.
:param backup:
backup
Create a backup of the original file with the extension:
"Year-Month-Day-Hour-Minutes-Seconds".
:param quiet:
quiet
Do not raise any exceptions. E.g. ignore the fact that the file that is
tried to be edited does not exist and nothing really happened.
:param indent:
Keep indentation with the previous line.
indent
Keep indentation with the previous line. This option is not considered when
the ``delete`` mode is specified.
If an equal sign (``=``) appears in an argument to a Salt command, it is
interpreted as a keyword argument in the format of ``key=val``. That
processing can be bypassed in order to pass an equal sign through to the
remote shell command by manually specifying the kwarg:
.. code-block:: bash
salt '*' file.line /path/to/file content="CREATEMAIL_SPOOL=no" match="CREATE_MAIL_SPOOL=yes" mode="replace"
CLI Examples:
CLI Example:
.. code-block:: bash
salt '*' file.line /etc/nsswitch.conf "networks:\tfiles dns" after="hosts:.*?" mode='ensure'
.. note::
If an equal sign (``=``) appears in an argument to a Salt command, it is
interpreted as a keyword argument in the format of ``key=val``. That
processing can be bypassed in order to pass an equal sign through to the
remote shell command by manually specifying the kwarg:
.. code-block:: bash
salt '*' file.line /path/to/file content="CREATEMAIL_SPOOL=no" match="CREATE_MAIL_SPOOL=yes" mode="replace"
'''
path = os.path.realpath(os.path.expanduser(path))
if not os.path.isfile(path):
@ -1614,9 +1687,13 @@ def line(path, content=None, match=None, mode=None, location=None,
body = os.linesep.join([line for line in body.split(os.linesep) if line.find(match) < 0])
elif mode == 'replace':
body = os.linesep.join([(_get_line_indent(line, content, indent)
if (line.find(match) > -1 and not line == content) else line)
for line in body.split(os.linesep)])
if os.stat(path).st_size == 0:
log.warning('Cannot find text to replace. File \'{0}\' is empty.'.format(path))
body = ''
else:
body = os.linesep.join([(_get_line_indent(file_line, content, indent)
if (file_line.find(match) > -1 and not file_line == content) else file_line)
for file_line in body.split(os.linesep)])
elif mode == 'insert':
if not location and not before and not after:
raise CommandExecutionError('On insert must be defined either "location" or "before/after" conditions.')
@ -3550,13 +3627,14 @@ def get_managed(
template,
source,
source_hash,
source_hash_name,
user,
group,
mode,
saltenv,
context,
defaults,
skip_verify,
skip_verify=False,
**kwargs):
'''
Return the managed file data for file.managed
@ -3573,20 +3651,26 @@ def get_managed(
source_hash
hash of the source file
source_hash_name
When ``source_hash`` refers to a remote file, this specifies the
filename to look for in that file.
.. versionadded:: 2016.3.5
user
user owner
Owner of file
group
group owner
Group owner of file
mode
file mode
Permissions of file
context
variables to add to the environment
Variables to add to the template context
defaults
default values of for context_dict
Default values of for context_dict
skip_verify
If ``True``, hash verification of remote file sources (``http://``,
@ -3599,7 +3683,7 @@ def get_managed(
.. code-block:: bash
salt '*' file.get_managed /etc/httpd/conf.d/httpd.conf jinja salt://http/httpd.conf '{hash_type: 'md5', 'hsum': <md5sum>}' root root '755' base None None
salt '*' file.get_managed /etc/httpd/conf.d/httpd.conf jinja salt://http/httpd.conf '{hash_type: 'md5', 'hsum': <md5sum>}' None root root '755' base None None
'''
# Copy the file to the minion and templatize it
sfn = ''
@ -3612,7 +3696,6 @@ def get_managed(
'''
return {'hsum': get_hash(path, form='sha256'), 'hash_type': 'sha256'}
source_hash_name = kwargs.pop('source_hash_name', None)
# If we have a source defined, let's figure out what the hash is
if source:
urlparsed_source = _urlparse(source)
@ -3636,8 +3719,10 @@ def get_managed(
if not skip_verify:
if source_hash:
try:
source_sum = get_source_sum(source_hash_name or source,
source_sum = get_source_sum(name,
source,
source_hash,
source_hash_name,
saltenv)
except CommandExecutionError as exc:
return '', {}, exc.strerror
@ -3712,8 +3797,31 @@ def get_managed(
return sfn, source_sum, ''
def extract_hash(hash_fn, hash_type='sha256', file_name=''):
def extract_hash(hash_fn,
hash_type='sha256',
file_name='',
source='',
source_hash_name=None):
'''
.. versionchanged:: 2016.3.5
Prior to this version, only the ``file_name`` argument was considered
for filename matches in the hash file. This would be problematic for
cases in which the user was relying on a remote checksum file that they
do not control, and they wished to use a different name for that file
on the minion from the filename on the remote server (and in the
checksum file). For example, managing ``/tmp/myfile.tar.gz`` when the
remote file was at ``https://mydomain.tld/different_name.tar.gz``. The
:py:func:`file.managed <salt.states.file.managed>` state now also
passes this function the source URI as well as the ``source_hash_name``
(if specified). In cases where ``source_hash_name`` is specified, it
takes precedence over both the ``file_name`` and ``source``. When it is
not specified, ``file_name`` takes precedence over ``source``. This
allows for better capability for matching hashes.
.. versionchanged:: 2016.11.1
File name and source URI matches are no longer disregarded when
``source_hash_name`` is specified. They will be used as fallback
matches if there is no match to the ``source_hash_name`` value.
This routine is called from the :mod:`file.managed
<salt.states.file.managed>` state to pull a hash from a remote file.
Regular expressions are used line by line on the ``source_hash`` file, to
@ -3739,72 +3847,184 @@ def extract_hash(hash_fn, hash_type='sha256', file_name=''):
.. code-block:: bash
salt '*' file.extract_hash /etc/foo sha512 /path/to/hash/file
salt '*' file.extract_hash /path/to/hash/file sha512 /etc/foo
'''
source_sum = None
partial_id = False
name_sought = os.path.basename(file_name)
log.debug(
'modules.file.py - extract_hash(): Extracting hash for file named: %s',
name_sought
)
try:
with salt.utils.fopen(hash_fn, 'r') as hash_fn_fopen:
for hash_variant in HASHES:
if hash_type == '' or hash_type == hash_variant[0]:
log.debug(
'modules.file.py - extract_hash(): Will use regex to '
'get a purely hexadecimal number of length (%s), '
'presumably hash type : %s',
hash_variant[1], hash_variant[0]
)
hash_fn_fopen.seek(0)
for line in hash_fn_fopen.read().splitlines():
hash_array = re.findall(
r'(?i)(?<![a-z0-9])[a-f0-9]{' + str(hash_variant[1]) + '}(?![a-z0-9])',
line)
log.debug(
'modules.file.py - extract_hash(): From "%s", '
'got : %s', line, hash_array
)
if hash_array:
if not partial_id:
source_sum = {'hsum': hash_array[0],
'hash_type': hash_variant[0]}
partial_id = True
log.debug(
'modules.file.py - extract_hash(): Found: %s '
'-- %s',
source_sum['hash_type'], source_sum['hsum']
)
if name_sought in line:
source_sum = {'hsum': hash_array[0],
'hash_type': hash_variant[0]}
log.debug(
'modules.file.py - extract_hash: For %s -- '
'returning the %s hash "%s".',
name_sought, source_sum['hash_type'],
source_sum['hsum']
)
return source_sum
except OSError as exc:
raise CommandExecutionError(
'Error encountered extracting hash from {0}: {1}'.format(
exc.filename, exc.strerror
hash_len = HASHES.get(hash_type)
if hash_len is None:
if hash_type:
log.warning(
'file.extract_hash: Unsupported hash_type \'%s\', falling '
'back to matching any supported hash_type', hash_type
)
hash_type = ''
hash_len_expr = '{0},{1}'.format(min(HASHES_REVMAP), max(HASHES_REVMAP))
else:
hash_len_expr = str(hash_len)
filename_separators = string.whitespace + r'\/'
if source_hash_name:
if not isinstance(source_hash_name, six.string_types):
source_hash_name = str(source_hash_name)
source_hash_name_idx = (len(source_hash_name) + 1) * -1
log.debug(
'file.extract_hash: Extracting %s hash for file matching '
'source_hash_name \'%s\'',
'any supported' if not hash_type else hash_type,
source_hash_name
)
if file_name:
if not isinstance(file_name, six.string_types):
file_name = str(file_name)
file_name_basename = os.path.basename(file_name)
file_name_idx = (len(file_name_basename) + 1) * -1
if source:
if not isinstance(source, six.string_types):
source = str(source)
urlparsed_source = _urlparse(source)
source_basename = os.path.basename(
urlparsed_source.path or urlparsed_source.netloc
)
source_idx = (len(source_basename) + 1) * -1
basename_searches = [x for x in (file_name, source) if x]
if basename_searches:
log.debug(
'file.extract_hash: %s %s hash for file matching%s: %s',
'If no source_hash_name match found, will extract'
if source_hash_name
else 'Extracting',
'any supported' if not hash_type else hash_type,
'' if len(basename_searches) == 1 else ' either of the following',
', '.join(basename_searches)
)
if partial_id:
partial = None
found = {}
with salt.utils.fopen(hash_fn, 'r') as fp_:
for line in fp_:
line = line.strip()
hash_re = r'(?i)(?<![a-z0-9])([a-f0-9]{' + hash_len_expr + '})(?![a-z0-9])'
hash_match = re.search(hash_re, line)
matched = None
if hash_match:
matched_hsum = hash_match.group(1)
if matched_hsum is not None:
matched_type = HASHES_REVMAP.get(len(matched_hsum))
if matched_type is None:
# There was a match, but it's not of the correct length
# to match one of the supported hash types.
matched = None
else:
matched = {'hsum': matched_hsum,
'hash_type': matched_type}
if matched is None:
log.debug(
'file.extract_hash: In line \'%s\', no %shash found',
line,
'' if not hash_type else hash_type + ' '
)
continue
if partial is None:
partial = matched
def _add_to_matches(found, line, match_type, value, matched):
log.debug(
'file.extract_hash: Line \'%s\' matches %s \'%s\'',
line, match_type, value
)
found.setdefault(match_type, []).append(matched)
hash_matched = False
if source_hash_name:
if line.endswith(source_hash_name):
# Checking the character before where the basename
# should start for either whitespace or a path
# separator. We can't just rsplit on spaces/whitespace,
# because the filename may contain spaces.
try:
if line[source_hash_name_idx] in string.whitespace:
_add_to_matches(found, line, 'source_hash_name',
source_hash_name, matched)
hash_matched = True
except IndexError:
pass
elif re.match(source_hash_name.replace('.', r'\.') + r'\s+',
line):
_add_to_matches(found, line, 'source_hash_name',
source_hash_name, matched)
hash_matched = True
if file_name:
if line.endswith(file_name_basename):
# Checking the character before where the basename
# should start for either whitespace or a path
# separator. We can't just rsplit on spaces/whitespace,
# because the filename may contain spaces.
try:
if line[file_name_idx] in filename_separators:
_add_to_matches(found, line, 'file_name',
file_name, matched)
hash_matched = True
except IndexError:
pass
elif re.match(file_name.replace('.', r'\.') + r'\s+', line):
_add_to_matches(found, line, 'file_name',
file_name, matched)
hash_matched = True
if source:
if line.endswith(source_basename):
# Same as above, we can't just do an rsplit here.
try:
if line[source_idx] in filename_separators:
_add_to_matches(found, line, 'source',
source, matched)
hash_matched = True
except IndexError:
pass
elif re.match(source.replace('.', r'\.') + r'\s+', line):
_add_to_matches(found, line, 'source', source, matched)
hash_matched = True
if not hash_matched:
log.debug(
'file.extract_hash: Line \'%s\' contains %s hash '
'\'%s\', but line did not meet the search criteria',
line, matched['hash_type'], matched['hsum']
)
for found_type, found_str in (('source_hash_name', source_hash_name),
('file_name', file_name),
('source', source)):
if found_type in found:
if len(found[found_type]) > 1:
log.debug(
'file.extract_hash: Multiple %s matches for %s: %s',
found_type,
found_str,
', '.join(
['{0} ({1})'.format(x['hsum'], x['hash_type'])
for x in found[found_type]]
)
)
ret = found[found_type][0]
log.debug(
'file.extract_hash: Returning %s hash \'%s\' as a match of %s',
ret['hash_type'], ret['hsum'], found_str
)
return ret
if partial:
log.debug(
'modules.file.py - extract_hash: Returning the partially '
'identified %s hash "%s".',
source_sum['hash_type'], source_sum['hsum']
'file.extract_hash: Returning the partially identified %s hash '
'\'%s\'', partial['hash_type'], partial['hsum']
)
else:
log.debug('modules.file.py - extract_hash: Returning None.')
return source_sum
return partial
log.debug('file.extract_hash: No matches, returning None')
return None
def check_perms(name, ret, user, group, mode, follow_symlinks=False):
@ -3954,6 +4174,7 @@ def check_managed(
name,
source,
source_hash,
source_hash_name,
user,
group,
mode,
@ -3988,6 +4209,7 @@ def check_managed(
template,
source,
source_hash,
source_hash_name,
user,
group,
mode,
@ -4020,6 +4242,7 @@ def check_managed_changes(
name,
source,
source_hash,
source_hash_name,
user,
group,
mode,
@ -4055,6 +4278,7 @@ def check_managed_changes(
template,
source,
source_hash,
source_hash_name,
user,
group,
mode,
@ -4394,7 +4618,10 @@ def manage_file(name,
if dl_sum != source_sum['hsum']:
ret['comment'] = (
'Specified {0} checksum for {1} ({2}) does not match '
'actual checksum ({3})'.format(
'actual checksum ({3}). If the \'source_hash\' value '
'refers to a remote file with multiple possible '
'matches, then it may be necessary to set '
'\'source_hash_name\'.'.format(
source_sum['hash_type'],
source,
source_sum['hsum'],

View File

@ -535,7 +535,7 @@ def _is_valid_secret_file(filename):
if os.path.exists(filename) and os.path.isfile(filename):
log.debug("File: {0} is valid secret file".format(filename))
return True
log.warn("File: {0} does not exists or not file".format(filename))
log.warning("File: {0} does not exists or not file".format(filename))
return False
@ -607,7 +607,7 @@ def _source_encode(source, saltenv):
# The source is a file on a server
filename = __salt__['cp.cache_file'](source, saltenv)
if not filename:
log.warn("Source file: {0} can not be retrieved".format(source))
log.warning("Source file: {0} can not be retrieved".format(source))
return "", ""
return os.path.basename(filename), _file_encode(filename)
return "", ""

View File

@ -6,7 +6,6 @@ Module for editing power settings on Mac OS X
'''
# Import python libs
from __future__ import absolute_import
import time
# Import salt libs
import salt.utils
@ -112,9 +111,14 @@ def set_sleep(minutes):
value = _validate_sleep(minutes)
cmd = 'systemsetup -setsleep {0}'.format(value)
salt.utils.mac_utils.execute_return_success(cmd)
return get_sleep() == {'Computer': value,
'Display': value,
'Hard Disk': value}
state = []
for check in (get_computer_sleep, get_display_sleep, get_harddisk_sleep):
state.append(salt.utils.mac_utils.confirm_updated(
value,
check,
))
return all(state)
def get_computer_sleep():
@ -156,7 +160,11 @@ def set_computer_sleep(minutes):
value = _validate_sleep(minutes)
cmd = 'systemsetup -setcomputersleep {0}'.format(value)
salt.utils.mac_utils.execute_return_success(cmd)
return str(value) in get_computer_sleep()
return salt.utils.mac_utils.confirm_updated(
str(value),
get_computer_sleep,
)
def get_display_sleep():
@ -198,7 +206,11 @@ def set_display_sleep(minutes):
value = _validate_sleep(minutes)
cmd = 'systemsetup -setdisplaysleep {0}'.format(value)
salt.utils.mac_utils.execute_return_success(cmd)
return str(value) in get_display_sleep()
return salt.utils.mac_utils.confirm_updated(
str(value),
get_display_sleep,
)
def get_harddisk_sleep():
@ -241,11 +253,10 @@ def set_harddisk_sleep(minutes):
cmd = 'systemsetup -setharddisksleep {0}'.format(value)
salt.utils.mac_utils.execute_return_success(cmd)
# Give macOS some time to change the setting
for i in range(5):
if str(value) in get_harddisk_sleep():
return True
time.sleep(1)
return salt.utils.mac_utils.confirm_updated(
str(value),
get_harddisk_sleep,
)
def get_wake_on_modem():
@ -288,7 +299,11 @@ def set_wake_on_modem(enabled):
state = salt.utils.mac_utils.validate_enabled(enabled)
cmd = 'systemsetup -setwakeonmodem {0}'.format(state)
salt.utils.mac_utils.execute_return_success(cmd)
return salt.utils.mac_utils.validate_enabled(get_wake_on_modem()) == state
return salt.utils.mac_utils.confirm_updated(
state,
get_wake_on_modem,
)
def get_wake_on_network():
@ -331,8 +346,11 @@ def set_wake_on_network(enabled):
state = salt.utils.mac_utils.validate_enabled(enabled)
cmd = 'systemsetup -setwakeonnetworkaccess {0}'.format(state)
salt.utils.mac_utils.execute_return_success(cmd)
return salt.utils.mac_utils.validate_enabled(
get_wake_on_network()) == state
return salt.utils.mac_utils.confirm_updated(
state,
get_wake_on_network,
)
def get_restart_power_failure():
@ -375,8 +393,11 @@ def set_restart_power_failure(enabled):
state = salt.utils.mac_utils.validate_enabled(enabled)
cmd = 'systemsetup -setrestartpowerfailure {0}'.format(state)
salt.utils.mac_utils.execute_return_success(cmd)
return salt.utils.mac_utils.validate_enabled(
get_restart_power_failure()) == state
return salt.utils.mac_utils.confirm_updated(
state,
get_restart_power_failure,
)
def get_restart_freeze():
@ -421,7 +442,11 @@ def set_restart_freeze(enabled):
state = salt.utils.mac_utils.validate_enabled(enabled)
cmd = 'systemsetup -setrestartfreeze {0}'.format(state)
salt.utils.mac_utils.execute_return_success(cmd)
return salt.utils.mac_utils.validate_enabled(get_restart_freeze()) == state
return salt.utils.mac_utils.confirm_updated(
state,
get_restart_freeze,
)
def get_sleep_on_power_button():
@ -465,5 +490,8 @@ def set_sleep_on_power_button(enabled):
state = salt.utils.mac_utils.validate_enabled(enabled)
cmd = 'systemsetup -setallowpowerbuttontosleepcomputer {0}'.format(state)
salt.utils.mac_utils.execute_return_success(cmd)
return salt.utils.mac_utils.validate_enabled(
get_sleep_on_power_button()) == state
return salt.utils.mac_utils.confirm_updated(
state,
get_sleep_on_power_button,
)

View File

@ -226,9 +226,11 @@ def set_remote_login(enable):
cmd = 'systemsetup -f -setremotelogin {0}'.format(state)
salt.utils.mac_utils.execute_return_success(cmd)
enabled = salt.utils.mac_utils.validate_enabled(get_remote_login())
return state == enabled
return salt.utils.mac_utils.confirm_updated(
state,
get_remote_login,
normalize_ret=True,
)
def get_remote_events():
@ -276,9 +278,11 @@ def set_remote_events(enable):
cmd = 'systemsetup -setremoteappleevents {0}'.format(state)
salt.utils.mac_utils.execute_return_success(cmd)
enabled = salt.utils.mac_utils.validate_enabled(get_remote_events())
return state == enabled
return salt.utils.mac_utils.confirm_updated(
state,
get_remote_events,
normalize_ret=True,
)
def get_computer_name():
@ -318,7 +322,10 @@ def set_computer_name(name):
cmd = 'systemsetup -setcomputername "{0}"'.format(name)
salt.utils.mac_utils.execute_return_success(cmd)
return get_computer_name() == name
return salt.utils.mac_utils.confirm_updated(
name,
get_computer_name,
)
def get_subnet_name():
@ -362,7 +369,10 @@ def set_subnet_name(name):
cmd = 'systemsetup -setlocalsubnetname "{0}"'.format(name)
salt.utils.mac_utils.execute_return_success(cmd)
return get_subnet_name() == name
return salt.utils.mac_utils.confirm_updated(
name,
get_subnet_name,
)
def get_startup_disk():
@ -429,7 +439,10 @@ def set_startup_disk(path):
cmd = 'systemsetup -setstartupdisk {0}'.format(path)
salt.utils.mac_utils.execute_return_result(cmd)
return get_startup_disk() == path
return salt.utils.mac_utils.confirm_updated(
path,
get_startup_disk,
)
def get_restart_delay():
@ -490,7 +503,10 @@ def set_restart_delay(seconds):
cmd = 'systemsetup -setwaitforstartupafterpowerfailure {0}'.format(seconds)
salt.utils.mac_utils.execute_return_success(cmd)
return get_restart_delay() == seconds
return salt.utils.mac_utils.confirm_updated(
seconds,
get_restart_delay,
)
def get_disable_keyboard_on_lock():
@ -540,10 +556,11 @@ def set_disable_keyboard_on_lock(enable):
'{0}'.format(state)
salt.utils.mac_utils.execute_return_success(cmd)
enabled = salt.utils.mac_utils.validate_enabled(
get_disable_keyboard_on_lock())
return enabled == state
return salt.utils.mac_utils.confirm_updated(
state,
get_disable_keyboard_on_lock,
normalize_ret=True,
)
def get_boot_arch():
@ -612,4 +629,7 @@ def set_boot_arch(arch='default'):
cmd = 'systemsetup -setkernelbootarchitecture {0}'.format(arch)
salt.utils.mac_utils.execute_return_success(cmd)
return arch in get_boot_arch()
return salt.utils.mac_utils.confirm_updated(
arch,
get_boot_arch,
)

View File

@ -149,7 +149,7 @@ def delete(name, remove=False, force=False):
# force is added for compatibility with user.absent state function
if force:
log.warn('force option is unsupported on MacOS, ignoring')
log.warning('force option is unsupported on MacOS, ignoring')
# remove home directory from filesystem
if remove:

View File

@ -75,6 +75,7 @@ def push_note(device=None, title=None, body=None):
CLI Example:
.. code-block:: bash
salt "*" pushbullet.push_note device="Chrome" title="Example title" body="Example body."
'''
spb = _SaltPushbullet(device)

View File

@ -156,7 +156,7 @@ def _get_deps(deps, tree_base, saltenv='base'):
else:
shutil.copy(deprpm, dest)
deps_list += ' --install {0}'.format(dest)
deps_list += ' {0}'.format(dest)
return deps_list
@ -250,9 +250,10 @@ def build(runas,
__salt__['cmd.run']('chown {0} -R {1}'.format(runas, results_dir))
cmd = 'mock --root={0} --resultdir={1} --init'.format(tgt, results_dir)
__salt__['cmd.run'](cmd, runas=runas)
if deps_list:
if deps_list and not deps_list.isspace():
cmd = 'mock --root={0} --resultdir={1} --install {2} {3}'.format(tgt, results_dir, deps_list, noclean)
__salt__['cmd.run'](cmd, runas=runas)
noclean += ' --no-clean'
cmd = 'mock --root={0} --resultdir={1} {2} {3} {4}'.format(
tgt,

View File

@ -175,6 +175,7 @@ def interfaces(root):
Output example:
.. code-block:: json
{
"r": [
"state",

View File

@ -3584,6 +3584,7 @@ def add_host_to_dvs(host, username, password, vmknic_name, vmnic_name,
Return Example:
.. code-block:: yaml
somehost:
----------
esxi1.corp.com:

View File

@ -262,6 +262,9 @@ def apply_config(path, source=None, salt_env='base'):
salt '*' dsc.run_config C:\\DSC\\WebSiteConfiguration salt://dsc/configs/WebSiteConfiguration
'''
# If you're getting an error along the lines of "The client cannot connect
# to the destination specified in the request.", try the following:
# Enable-PSRemoting -SkipNetworkProfileCheck
config = path
if source:
# Make sure the folder names match
@ -291,16 +294,17 @@ def apply_config(path, source=None, salt_env='base'):
# Run the DSC Configuration
# Putting quotes around the parameter protects against command injection
cmd = '$job = Start-DscConfiguration -Path "{0}"; '.format(config)
cmd += 'Do{ } While ($job.State -notin \'Completed\', \'Failed\'); ' \
'return $job.State'
cmd = 'Start-DscConfiguration -Path "{0}" -Wait -Force'.format(config)
ret = _pshell(cmd)
if ret is False:
raise CommandExecutionError('Apply Config Failed: {0}'.format(path))
cmd = '$status = Get-DscConfigurationStatus; $status.Status'
ret = _pshell(cmd)
log.info('DSC Apply Config: {0}'.format(ret))
if ret == 'Completed':
return True
else:
return False
return ret == 'Success'
def get_config():
@ -336,10 +340,7 @@ def test_config():
'''
cmd = 'Test-DscConfiguration *>&1'
ret = _pshell(cmd)
if ret == 'True':
return True
else:
return False
return ret == 'True'
def get_config_status():

View File

@ -62,8 +62,8 @@ from salt.modules.file import (check_hash, # pylint: disable=W0611
access, copy, readdir, rmdir, truncate, replace, delete_backup,
search, _get_flags, extract_hash, _error, _sed_esc, _psed,
RE_FLAG_TABLE, blockreplace, prepend, seek_read, seek_write, rename,
lstat, path_exists_glob, write, pardir, join, HASHES, comment,
uncomment, _add_flags, comment_line, apply_template_on_contents)
lstat, path_exists_glob, write, pardir, join, HASHES, HASHES_REVMAP,
comment, uncomment, _add_flags, comment_line, apply_template_on_contents)
from salt.utils import namespaced_function as _namespaced_function

View File

@ -5,6 +5,7 @@ Manage Windows features via the ServerManager powershell module
# Import Python libs
from __future__ import absolute_import
import ast
import json
import logging
@ -26,6 +27,17 @@ def __virtual__():
'''
Load only on windows with servermanager module
'''
def _module_present():
'''
Check for the presence of the ServerManager module.
'''
cmd = r"[Bool] (Get-Module -ListAvailable | Where-Object { $_.Name -eq 'ServerManager' })"
cmd_ret = __salt__['cmd.run_all'](cmd, shell='powershell', python_shell=True)
if cmd_ret['retcode'] == 0:
return ast.literal_eval(cmd_ret['stdout'])
return False
if not salt.utils.is_windows():
return False

View File

@ -1166,7 +1166,7 @@ def upgrade(refresh=True,
cmd_update.append('--no-allow-vendor-change')
log.info('Disabling vendor changes')
else:
log.warn('Disabling vendor changes is not supported on this Zypper version')
log.warning('Disabling vendor changes is not supported on this Zypper version')
if dryrun:
# Creates a solver test case for debugging.

View File

@ -728,6 +728,8 @@ def hypermedia_handler(*args, **kwargs):
except (salt.exceptions.SaltDaemonNotRunning,
salt.exceptions.SaltReqTimeoutError) as exc:
raise cherrypy.HTTPError(503, exc.strerror)
except (cherrypy.TimeoutError, salt.exceptions.SaltClientTimeout):
raise cherrypy.HTTPError(504)
except cherrypy.CherryPyException:
raise
except Exception as exc:

View File

@ -92,7 +92,8 @@ To use the cassandra returner, append '--return cassandra_cql' to the salt comma
Note: if your Cassandra instance has not been tuned much you may benefit from
altering some timeouts in `cassandra.yaml` like so:
.. code-block:: bash
.. code-block:: yaml
# How long the coordinator should wait for read operations to complete
read_request_timeout_in_ms: 5000
# How long the coordinator should wait for seq or index scans to complete
@ -175,7 +176,8 @@ __virtualname__ = 'cassandra_cql'
def __virtual__():
if not HAS_CASSANDRA_DRIVER:
return False
return False, 'Could not import cassandra_cql returner; ' \
'cassandra-driver is not installed.'
return True
@ -304,7 +306,7 @@ def save_load(jid, load, minions=None):
raise
def save_minions(jid, minions): # pylint: disable=unused-argument
def save_minions(jid, minions, syndic_id=None): # pylint: disable=unused-argument
'''
Included for API consistency
'''

View File

@ -47,7 +47,7 @@ __virtualname__ = 'cassandra'
def __virtual__():
if not HAS_PYCASSA:
return False
return False, 'Could not import cassandra returner; pycassa is not installed.'
return __virtualname__

View File

@ -54,7 +54,7 @@ VERIFIED_VIEWS = False
def __virtual__():
if not HAS_DEPS:
return False
return False, 'Could not import couchbase returner; couchbase is not installed.'
# try to load some faster json libraries. In order of fastest to slowest
json = salt.utils.import_json()

View File

@ -367,7 +367,7 @@ def prep_jid(nocache=False, passed_jid=None): # pylint: disable=unused-argument
return passed_jid if passed_jid is not None else salt.utils.jid.gen_jid()
def save_minions(jid, minions): # pylint: disable=unused-argument
def save_minions(jid, minions, syndic_id=None): # pylint: disable=unused-argument
'''
Included for API consistency
'''

View File

@ -50,7 +50,7 @@ __virtualname__ = 'django'
def __virtual__():
if not HAS_DJANGO:
return False
return False, 'Could not import django returner; django is not installed.'
return True

View File

@ -66,7 +66,7 @@ log = logging.getLogger(__name__)
def __virtual__():
return __virtualname__
return 'elasticsearch.alias_exists' in __salt__
def _get_options(ret=None):

View File

@ -90,7 +90,10 @@ def __virtual__():
'''
Only return if python-etcd is installed
'''
return __virtualname__ if HAS_LIBS else False
if HAS_LIBS:
return __virtualname__
return False, 'Could not import etcd returner; python-etcd is not installed.'
def _get_conn(opts, profile=None):
@ -150,7 +153,7 @@ def save_load(jid, load, minions=None):
)
def save_minions(jid, minions): # pylint: disable=unused-argument
def save_minions(jid, minions, syndic_id=None): # pylint: disable=unused-argument
'''
Included for API consistency
'''

View File

@ -81,7 +81,8 @@ __virtualname__ = 'influxdb'
def __virtual__():
if not HAS_INFLUXDB:
return False
return False, 'Could not import influxdb returner; ' \
'influxdb python client is not installed.'
return __virtualname__
@ -226,7 +227,7 @@ def save_load(jid, load, minions=None):
log.critical('Failed to store load with InfluxDB returner: {0}'.format(ex))
def save_minions(jid, minions): # pylint: disable=unused-argument
def save_minions(jid, minions, syndic_id=None): # pylint: disable=unused-argument
'''
Included for API consistency
'''

View File

@ -24,28 +24,26 @@ To use the kafka returner, append '--return kafka' to the Salt command, eg;
'''
# Import Python libs
from __future__ import absolute_import
import json
import logging
# Import third-party libs
try:
from kafka import KafkaClient, SimpleProducer
HAS_KAFKA = True
except ImportError:
HAS_KAFKA = False
log = logging.getLogger(__name__)
__virtualname__ = 'kafka'
def __virtual__():
if not HAS_KAFKA:
return False
return False, 'Could not import kafka returner; kafka-python is not installed.'
return __virtualname__

View File

@ -70,7 +70,8 @@ __virtualname__ = 'memcache'
def __virtual__():
if not HAS_MEMCACHE:
return False
return False, 'Could not import memcache returner; ' \
'memcache python client is not installed.'
return __virtualname__
@ -163,7 +164,7 @@ def save_load(jid, load, minions=None):
_append_list(serv, 'jids', jid)
def save_minions(jid, minions): # pylint: disable=unused-argument
def save_minions(jid, minions, syndic_id=None): # pylint: disable=unused-argument
'''
Included for API consistency
'''

View File

@ -73,7 +73,6 @@ import salt.utils.jid
import salt.returners
import salt.ext.six as six
# Import third party libs
try:
import pymongo
@ -91,7 +90,7 @@ __virtualname__ = 'mongo'
def __virtual__():
if not HAS_PYMONGO:
return False
return False, 'Could not import mongo returner; pymongo is not installed.'
return __virtualname__
@ -213,7 +212,7 @@ def save_load(jid, load, minions=None):
mdb.jobs.insert(load.copy())
def save_minions(jid, minions): # pylint: disable=unused-argument
def save_minions(jid, minions, syndic_id=None): # pylint: disable=unused-argument
'''
Included for API consistency
'''

View File

@ -89,7 +89,7 @@ __virtualname__ = 'mongo'
def __virtual__():
if not HAS_PYMONGO:
return False
return False, 'Could not import mongo returner; pymongo is not installed.'
return 'mongo_return'
@ -234,7 +234,7 @@ def prep_jid(nocache=False, passed_jid=None): # pylint: disable=unused-argument
return passed_jid if passed_jid is not None else salt.utils.jid.gen_jid()
def save_minions(jid, minions): # pylint: disable=unused-argument
def save_minions(jid, minions, syndic_id=None): # pylint: disable=unused-argument
'''
Included for API consistency
'''

View File

@ -69,7 +69,7 @@ def save_load(jid, clear_load, minions=None):
_mminion().returners['{0}.save_load'.format(returner_)](jid, clear_load)
def save_minions(jid, minions): # pylint: disable=unused-argument
def save_minions(jid, minions, syndic_id=None): # pylint: disable=unused-argument
'''
Included for API consistency
'''

View File

@ -169,7 +169,8 @@ __virtualname__ = 'mysql'
def __virtual__():
if not HAS_MYSQL:
return False
return False, 'Could not import mysql returner; ' \
'mysql python client is not installed.'
return True
@ -332,7 +333,7 @@ def save_load(jid, load, minions=None):
pass
def save_minions(jid, minions): # pylint: disable=unused-argument
def save_minions(jid, minions, syndic_id=None): # pylint: disable=unused-argument
'''
Included for API consistency
'''

View File

@ -177,7 +177,7 @@ def __virtual__():
'''
Return virtualname
'''
return __virtualname__
return 'nagios.list_plugins' in __salt__
def returner(ret):

View File

@ -149,7 +149,7 @@ __virtualname__ = 'odbc'
def __virtual__():
if not HAS_ODBC:
return False
return False, 'Could not import odbc returner; pyodbc is not installed.'
return True
@ -226,7 +226,7 @@ def save_load(jid, load, minions=None):
_close_conn(conn)
def save_minions(jid, minions): # pylint: disable=unused-argument
def save_minions(jid, minions, syndic_id=None): # pylint: disable=unused-argument
'''
Included for API consistency
'''

View File

@ -160,7 +160,7 @@ __virtualname__ = 'pgjsonb'
def __virtual__():
if not HAS_PG:
return False
return False, 'Could not import pgjsonb returner; python-psycopg2 is not installed.'
return True
@ -291,7 +291,7 @@ def save_load(jid, load, minions=None):
pass
def save_minions(jid, minions): # pylint: disable=unused-argument
def save_minions(jid, minions, syndic_id=None): # pylint: disable=unused-argument
'''
Included for API consistency
'''

View File

@ -151,7 +151,7 @@ log = logging.getLogger(__name__)
def __virtual__():
if not HAS_POSTGRES:
return False
return False, 'Could not import postgres returner; psycopg2 is not installed.'
return __virtualname__
@ -276,7 +276,7 @@ def save_load(jid, load, minions=None): # pylint: disable=unused-argument
pass
def save_minions(jid, minions): # pylint: disable=unused-argument
def save_minions(jid, minions, syndic_id=None): # pylint: disable=unused-argument
'''
Included for API consistency
'''

View File

@ -304,7 +304,7 @@ def save_load(jid, clear_load, minions=None):
_close_conn(conn)
def save_minions(jid, minions): # pylint: disable=unused-argument
def save_minions(jid, minions, syndic_id=None): # pylint: disable=unused-argument
'''
Included for API consistency
'''

View File

@ -69,7 +69,8 @@ __virtualname__ = 'redis'
def __virtual__():
if not HAS_REDIS:
return False
return False, 'Could not import redis returner; ' \
'redis python client is not installed.'
return __virtualname__
@ -137,7 +138,7 @@ def save_load(jid, load, minions=None):
serv.setex('load:{0}'.format(jid), json.dumps(load), _get_ttl())
def save_minions(jid, minions): # pylint: disable=unused-argument
def save_minions(jid, minions, syndic_id=None): # pylint: disable=unused-argument
'''
Included for API consistency
'''

View File

@ -66,7 +66,8 @@ __virtualname__ = 'sentry'
def __virtual__():
if not has_raven:
return False
return False, 'Could not import sentry returner; ' \
'raven python client is not installed.'
return __virtualname__

View File

@ -51,8 +51,8 @@ __virtualname__ = 'sms'
def __virtual__():
if HAS_TWILIO:
return __virtualname__
else:
return False
return False, 'Could not import sms returner; twilio is not installed.'
def _get_options(ret=None):

View File

@ -132,7 +132,9 @@ __virtualname__ = 'smtp'
def __virtual__():
return __virtualname__
if HAS_GNUPG:
return __virtualname__
return False, 'Could not import smtp returner; gnupg is not installed.'
def _get_options(ret=None):

View File

@ -106,7 +106,7 @@ __virtualname__ = 'sqlite3'
def __virtual__():
if not HAS_SQLITE3:
return False
return False, 'Could not import sqlite3 returner; sqlite3 is not installed.'
return __virtualname__
@ -193,7 +193,7 @@ def save_load(jid, load, minions=None):
_close_conn(conn)
def save_minions(jid, minions): # pylint: disable=unused-argument
def save_minions(jid, minions, syndic_id=None): # pylint: disable=unused-argument
'''
Included for API consistency
'''

View File

@ -168,7 +168,7 @@ def _verify_options(options):
def __virtual__():
if not HAS_SYSLOG:
return False
return False, 'Could not import syslog returner; syslog is not installed.'
return __virtualname__

View File

@ -2,6 +2,8 @@
'''
Return salt data via xmpp
:depends: sleekxmpp >= 1.3.1
The following fields can be set in the minion conf file::
xmpp.jid (required)
@ -117,14 +119,16 @@ def __virtual__():
'''
Only load this module if right version of sleekxmpp is installed on this minion.
'''
min_version = '1.3.1'
if HAS_LIBS:
import sleekxmpp
# Certain XMPP functionaility we're using doesn't work with versions under 1.3.1
sleekxmpp_version = distutils.version.LooseVersion(sleekxmpp.__version__)
valid_version = distutils.version.LooseVersion('1.3.1')
valid_version = distutils.version.LooseVersion(min_version)
if sleekxmpp_version >= valid_version:
return __virtualname__
return False
return False, 'Could not import xmpp returner; sleekxmpp python client is not ' \
'installed or is older than version \'{0}\'.'.format(min_version)
class SendMsgBot(_ClientXMPP):

View File

@ -776,8 +776,8 @@ def bootstrap(version='develop',
salt.client.ssh.SSH(client_opts).run()
except SaltSystemExit as exc:
if 'No hosts found with target' in str(exc):
log.warn('The host {0} was not found in the Salt SSH roster '
'system. Attempting to log in without Salt SSH.')
log.warning('The host {0} was not found in the Salt SSH roster '
'system. Attempting to log in without Salt SSH.')
salt.utils.warn_until('Oxygen', dep_warning)
ret = subprocess.call([
'ssh',

View File

@ -8,7 +8,7 @@ returned by several different minions.
Aggregated results are sorted by the size of the minion pools which returned
matching results.
Useful for playing the game: " some of these things are not like the others... "
Useful for playing the game: *"some of these things are not like the others..."*
when identifying discrepancies in a large infrastructure managed by salt.
'''
@ -29,20 +29,20 @@ def hash(*args, **kwargs):
.. versionadded:: 2014.7.0
This command is submitted via a salt runner using the
general form:
general form::
salt-run survey.hash [survey_sort=up/down] <target>
<salt-execution-module> <salt-execution-module parameters>
Optionally accept a "survey_sort=" parameter. Default: "survey_sort=down"
Optionally accept a ``survey_sort=`` parameter. Default: ``survey_sort=down``
CLI Example #1: ( functionally equivalent to "salt-run manage.up" )
CLI Example #1: (functionally equivalent to ``salt-run manage.up``)
.. code-block:: bash
salt-run survey.hash "*" test.ping
CLI Example #2: ( find an "outlier" minion config file )
CLI Example #2: (find an "outlier" minion config file)
.. code-block:: bash
@ -61,20 +61,23 @@ def diff(*args, **kwargs):
These pools are determined from the aggregated and sorted results of
a salt command.
This command displays the "diffs" as a series of 2-way differences-- namely
the difference between the FIRST displayed minion pool
(according to sort order) and EACH SUBSEQUENT minion pool result set.
Differences are displayed according to the Python "difflib.unified_diff()"
as in the case of the salt execution module "file.get_diff".
This command is submitted via a salt runner using the general form:
This command displays the "diffs" as a series of 2-way differences --
namely the difference between the FIRST displayed minion pool
(according to sort order) and EACH SUBSEQUENT minion pool result set.
Differences are displayed according to the Python ``difflib.unified_diff()``
as in the case of the salt execution module ``file.get_diff``.
This command is submitted via a salt runner using the general form::
salt-run survey.diff [survey_sort=up/down] <target>
<salt-execution-module> <salt-execution-module parameters>
Optionally accept a "survey_sort=" parameter. Default: "survey_sort=down"
Optionally accept a ``survey_sort=`` parameter. Default:
``survey_sort=down``
CLI Example #1: ( Example to display the "differences of files" )
CLI Example #1: (Example to display the "differences of files")
.. code-block:: bash

View File

@ -22,7 +22,7 @@ requires very little. In the example:
url: https://api.github.com/
keys:
url: https://api.github.com/users/{{user}}/keys
requests_lib: True
backend: requests
The ``driver`` refers to the REST module, and must be set to ``rest`` in order
to use this driver. Each of the other items inside this block refers to a

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
'''
salt.serializers.configparser
~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionadded:: 2016.3.0

View File

@ -123,6 +123,7 @@ def _cleanup_destdir(name):
def extracted(name,
source,
source_hash=None,
source_hash_name=None,
source_hash_update=False,
skip_verify=False,
password=None,
@ -240,6 +241,71 @@ def extracted(name,
This argument uses the same syntax as its counterpart in the
:py:func:`file.managed <salt.states.file.managed>` state.
.. versionchanged:: 2016.11.0
If this argument specifies the hash itself, instead of a URI to a
file containing hashes, the hash type can now be omitted and Salt
will determine the hash type based on the length of the hash. For
example, both of the below states are now valid, while before only
the second one would be:
.. code-block:: yaml
foo_app:
archive.extracted:
- name: /var/www
- source: https://mydomain.tld/foo.tar.gz
- source_hash: 3360db35e682f1c5f9c58aa307de16d41361618c
bar_app:
archive.extracted:
- name: /var/www
- source: https://mydomain.tld/bar.tar.gz
- source_hash: sha1=5edb7d584b82ddcbf76e311601f5d4442974aaa5
source_hash_name
When ``source_hash`` refers to a hash file, Salt will try to find the
correct hash by matching the filename part of the ``source`` URI. When
managing a file with a ``source`` of ``salt://files/foo.tar.gz``, then
the following line in a hash file would match:
.. code-block:: text
acbd18db4cc2f85cedef654fccc4a4d8 foo.tar.gz
This line would also match:
.. code-block:: text
acbd18db4cc2f85cedef654fccc4a4d8 ./dir1/foo.tar.gz
However, sometimes a hash file will include multiple similar paths:
.. code-block:: text
37b51d194a7513e45b56f6524f2d51f2 ./dir1/foo.txt
acbd18db4cc2f85cedef654fccc4a4d8 ./dir2/foo.txt
73feffa4b7f6bb68e44cf984c85f6e88 ./dir3/foo.txt
In cases like this, Salt may match the incorrect hash. This argument
can be used to tell Salt which filename to match, to ensure that the
correct hash is identified. For example:
.. code-block:: yaml
/var/www:
archive.extracted:
- source: https://mydomain.tld/dir2/foo.tar.gz
- source_hash: https://mydomain.tld/hashes
- source_hash_name: ./dir2/foo.tar.gz
.. note::
This argument must contain the full filename entry from the
checksum file, as this argument is meant to disambiguate matches
for multiple files that have the same basename. So, in the
example above, simply using ``foo.txt`` would not match.
.. versionadded:: 2016.11.1
source_hash_update
Set this to ``True`` if archive should be extracted if source_hash has
changed. This would extract regardless of the ``if_missing`` parameter.
@ -569,11 +635,11 @@ def extracted(name,
return ret
urlparsed_source = _urlparse(source_match)
source_hash_name = urlparsed_source.path or urlparsed_source.netloc
source_hash_basename = urlparsed_source.path or urlparsed_source.netloc
valid_archive_formats = ('tar', 'rar', 'zip')
if not archive_format:
archive_format = salt.utils.files.guess_archive_type(source_hash_name)
archive_format = salt.utils.files.guess_archive_type(source_hash_basename)
if archive_format is None:
ret['comment'] = (
'Could not guess archive_format from the value of the '
@ -672,7 +738,7 @@ def extracted(name,
__opts__['cachedir'],
'files',
__env__,
re.sub(r'[:/\\]', '_', source_hash_name),
re.sub(r'[:/\\]', '_', source_hash_basename),
)
if os.path.isdir(cached_source):
@ -681,8 +747,10 @@ def extracted(name,
if source_hash:
try:
source_sum = __salt__['file.get_source_sum'](source_hash_name,
source_sum = __salt__['file.get_source_sum']('',
source,
source_hash,
source_hash_name,
__env__)
except CommandExecutionError as exc:
ret['comment'] = exc.strerror
@ -710,10 +778,10 @@ def extracted(name,
cached_source,
source=source_match,
source_hash=source_hash,
source_hash_name=source_hash_name,
makedirs=True,
skip_verify=skip_verify,
saltenv=__env__,
source_hash_name=source_hash_name)
saltenv=__env__)
log.debug('file.managed: {0}'.format(file_result))
# Get actual state result. The state.single return is a single-element

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
'''
Manage CloudTrail Objects
=================
=========================
.. versionadded:: 2016.3.0

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
'''
Manage IoT Objects
=================
==================
.. versionadded:: 2016.3.0

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
'''
Manage Lambda Functions
=================
=======================
.. versionadded:: 2016.3.0

View File

@ -327,7 +327,7 @@ def _get_rule_changes(rules, _rules):
# 2. determine if rule exists in existing security group rules
for rule in rules:
try:
ip_protocol = rule.get('ip_protocol')
ip_protocol = str(rule.get('ip_protocol'))
except KeyError:
raise SaltInvocationError('ip_protocol, to_port, and from_port are'
' required arguments for security group'

View File

@ -3,6 +3,7 @@
Configure Chronos jobs via a salt proxy.
.. code-block:: yaml
my_job:
chronos_job.config:
- config:

View File

@ -421,6 +421,7 @@ def absent(name,
def file(name,
source_hash='',
source_hash_name=None,
user='root',
template=None,
context=None,
@ -448,6 +449,45 @@ def file(name,
hash algorithm followed by the hash of the file:
``md5=e138491e9d5b97023cea823fe17bac22``
source_hash_name
When ``source_hash`` refers to a hash file, Salt will try to find the
correct hash by matching the filename/URI associated with that hash. By
default, Salt will look for the filename being managed. When managing a
file at path ``/tmp/foo.txt``, then the following line in a hash file
would match:
.. code-block:: text
acbd18db4cc2f85cedef654fccc4a4d8 foo.txt
However, sometimes a hash file will include multiple similar paths:
.. code-block:: text
37b51d194a7513e45b56f6524f2d51f2 ./dir1/foo.txt
acbd18db4cc2f85cedef654fccc4a4d8 ./dir2/foo.txt
73feffa4b7f6bb68e44cf984c85f6e88 ./dir3/foo.txt
In cases like this, Salt may match the incorrect hash. This argument
can be used to tell Salt which filename to match, to ensure that the
correct hash is identified. For example:
.. code-block:: yaml
foo_crontab:
cron.file:
- name: https://mydomain.tld/dir2/foo.txt
- source_hash: https://mydomain.tld/hashes
- source_hash_name: ./dir2/foo.txt
.. note::
This argument must contain the full filename entry from the
checksum file, as this argument is meant to disambiguate matches
for multiple files that have the same basename. So, in the
example above, simply using ``foo.txt`` would not match.
.. versionadded:: 2016.3.5
user
The user to whom the crontab should be assigned. This defaults to
root.
@ -508,6 +548,7 @@ def file(name,
fcm = __salt__['file.check_managed'](cron_path,
source,
source_hash,
source_hash_name,
user,
group,
mode,

View File

@ -1106,6 +1106,7 @@ def missing(name):
def managed(name,
source=None,
source_hash='',
source_hash_name=None,
user=None,
group=None,
mode=None,
@ -1211,7 +1212,7 @@ def managed(name,
- source: https://launchpad.net/tomdroid/beta/0.7.3/+download/tomdroid-src-0.7.3.tar.gz
- source_hash: https://launchpad.net/tomdroid/beta/0.7.3/+download/tomdroid-src-0.7.3.hash
The following is an example of the supported source_hash format:
The following lines are all supported formats:
.. code-block:: text
@ -1221,7 +1222,7 @@ def managed(name,
Debian file type ``*.dsc`` files are also supported.
**Inserting the Source Hash in the sls Data**
**Inserting the Source Hash in the SLS Data**
Examples:
.. code-block:: yaml
@ -1247,6 +1248,44 @@ def managed(name,
- source: https://launchpad.net/tomdroid/beta/0.7.3/+download/tomdroid-src-0.7.3.tar.gz
- source_hash: https://launchpad.net/tomdroid/beta/0.7.3/+download/tomdroid-src-0.7.3.tar.gz/+md5
source_hash_name
When ``source_hash`` refers to a hash file, Salt will try to find the
correct hash by matching the filename/URI associated with that hash. By
default, Salt will look for the filename being managed. When managing a
file at path ``/tmp/foo.txt``, then the following line in a hash file
would match:
.. code-block:: text
acbd18db4cc2f85cedef654fccc4a4d8 foo.txt
However, sometimes a hash file will include multiple similar paths:
.. code-block:: text
37b51d194a7513e45b56f6524f2d51f2 ./dir1/foo.txt
acbd18db4cc2f85cedef654fccc4a4d8 ./dir2/foo.txt
73feffa4b7f6bb68e44cf984c85f6e88 ./dir3/foo.txt
In cases like this, Salt may match the incorrect hash. This argument
can be used to tell Salt which filename to match, to ensure that the
correct hash is identified. For example:
.. code-block:: yaml
/tmp/foo.txt:
file.managed:
- source: https://mydomain.tld/dir2/foo.txt
- source_hash: https://mydomain.tld/hashes
- source_hash_name: ./dir2/foo.txt
.. note::
This argument must contain the full filename entry from the
checksum file, as this argument is meant to disambiguate matches
for multiple files that have the same basename. So, in the
example above, simply using ``foo.txt`` would not match.
.. versionadded:: 2016.3.5,2016.11.1
user
The user to own the file, this defaults to the user salt is running as
@ -1731,6 +1770,7 @@ def managed(name,
name,
source,
source_hash,
source_hash_name,
user,
group,
mode,
@ -1776,6 +1816,7 @@ def managed(name,
template,
source,
source_hash,
source_hash_name,
user,
group,
mode,
@ -2553,15 +2594,17 @@ def recurse(name,
# Check source path relative to fileserver root, make sure it is a
# directory
source_rel = source.partition('://')[2]
master_dirs = __salt__['cp.list_master_dirs'](__env__)
if source_rel not in master_dirs \
srcpath, senv = salt.utils.url.parse(source)
if senv is None:
senv = __env__
master_dirs = __salt__['cp.list_master_dirs'](saltenv=senv)
if srcpath not in master_dirs \
and not any((x for x in master_dirs
if x.startswith(source_rel + '/'))):
if x.startswith(srcpath + '/'))):
ret['result'] = False
ret['comment'] = (
'The directory \'{0}\' does not exist on the salt fileserver '
'in saltenv \'{1}\''.format(source, __env__)
'in saltenv \'{1}\''.format(srcpath, senv)
)
return ret
@ -2700,16 +2743,15 @@ def recurse(name,
keep = set()
vdir = set()
srcpath = salt.utils.url.parse(source)[0]
if not srcpath.endswith('/'):
# we're searching for things that start with this *directory*.
# use '/' since #master only runs on POSIX
srcpath = srcpath + '/'
fns_ = __salt__['cp.list_master'](__env__, srcpath)
fns_ = __salt__['cp.list_master'](senv, srcpath)
# If we are instructed to keep symlinks, then process them.
if keep_symlinks:
# Make this global so that emptydirs can use it if needed.
symlinks = __salt__['cp.list_master_symlinks'](__env__, srcpath)
symlinks = __salt__['cp.list_master_symlinks'](senv, srcpath)
fns_ = process_symlinks(fns_, symlinks)
for fn_ in fns_:
if not fn_.strip():
@ -2748,11 +2790,11 @@ def recurse(name,
manage_directory(dirname)
vdir.add(dirname)
src = salt.utils.url.create(fn_)
src = salt.utils.url.create(fn_, saltenv=senv)
manage_file(dest, src)
if include_empty:
mdirs = __salt__['cp.list_master_dirs'](__env__, srcpath)
mdirs = __salt__['cp.list_master_dirs'](senv, srcpath)
for mdir in mdirs:
if not salt.utils.check_include_exclude(
os.path.relpath(mdir, srcpath), include_pat, exclude_pat):
@ -3001,43 +3043,61 @@ def line(name, content=None, match=None, mode=None, location=None,
.. versionadded:: 2015.8.0
:param name:
name
Filesystem path to the file to be edited.
:param content:
content
Content of the line. Allowed to be empty if mode=delete.
:param match:
match
Match the target line for an action by
a fragment of a string or regular expression.
:param mode:
:Ensure:
If neither ``before`` nor ``after`` are provided, and ``match``
is also ``None``, match becomes the ``content`` value.
mode
Defines how to edit a line. One of the following options is
required:
- ensure
If line does not exist, it will be added.
:Replace:
If line already exist, it will be replaced.
:Delete:
- replace
If line already exists, it will be replaced.
- delete
Delete the line, once found.
:Insert:
- insert
Insert a line.
:param location:
:start:
Place the content at the beginning of the file.
.. note::
:end:
If ``mode=insert`` is used, at least one of the following
options must also be defined: ``location``, ``before``, or
``after``. If ``location`` is used, it takes precedence
over the other two options.
location
Defines where to place content in the line. Note this option is only
used when ``mode=insert`` is specified. If a location is passed in, it
takes precedence over both the ``before`` and ``after`` kwargs. Valid
locations are:
- start
Place the content at the beginning of the file.
- end
Place the content at the end of the file.
:param before:
before
Regular expression or an exact case-sensitive fragment of the string.
This option is only used when either the ``ensure`` or ``insert`` mode
is defined.
:param after:
after
Regular expression or an exact case-sensitive fragment of the string.
This option is only used when either the ``ensure`` or ``insert`` mode
is defined.
:param show_changes:
show_changes
Output a unified diff of the old file and the new file.
If ``False`` return a boolean if any changes were made.
Default is ``True``
@ -3046,16 +3106,17 @@ def line(name, content=None, match=None, mode=None, location=None,
Using this option will store two copies of the file in-memory
(the original version and the edited version) in order to generate the diff.
:param backup:
backup
Create a backup of the original file with the extension:
"Year-Month-Day-Hour-Minutes-Seconds".
:param quiet:
quiet
Do not raise any exceptions. E.g. ignore the fact that the file that is
tried to be edited does not exist and nothing really happened.
:param indent:
Keep indentation with the previous line.
indent
Keep indentation with the previous line. This option is not considered when
the ``delete`` mode is specified.
:param create:
Create an empty file if doesn't exists.
@ -5080,6 +5141,7 @@ def serialize(name,
name=name,
source=None,
source_hash={},
source_hash_name=None,
user=user,
group=group,
mode=mode,

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
'''
Management of the GPG keychains
==============================
===============================
.. versionadded:: 2016.3.0

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
'''
Allows you to manage assistive access on OS X minions with 10.9+
=======================
================================================================
Install, enable and disable assitive access on OS X minions

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
'''
Writing/reading defaults from an OS X minion
=======================
============================================
'''

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
'''
Installing of certificates to the keychain
=======================
==========================================
Install certificats to the OS X keychain

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
'''
Allows you to manage extended attributes on files or directories
=======================
================================================================
Install, enable and disable assitive access on OS X minions

View File

@ -3,6 +3,7 @@
Configure Marathon apps via a salt proxy.
.. code-block:: yaml
my_app:
marathon_app.config:
- config:

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
'''
Allows you to manage proxy settings on minions
=======================
==============================================
Setup proxy settings on minions

View File

@ -5,7 +5,7 @@ Send a message to PushOver
This state is useful for sending messages to PushOver during state runs.
.. versionadded:: Lithium
.. versionadded:: 2015.5.0
.. code-block:: yaml

View File

@ -9,6 +9,9 @@ Support for Stormpath.
from __future__ import absolute_import
import pprint
# Import salt libs
import salt.utils
def __virtual__():
'''
@ -54,10 +57,18 @@ def present(name, **kwargs):
Optional. Must be specified as a dict.
'''
# Because __opts__ is not available outside of functions
if __opts__.get('requests_lib', False):
backend = __opts__.get('backend', False)
if not backend and __opts__.get('requests_lib', False):
salt.utils.warn_until('Oxygen', '"requests_lib:True" has been replaced by "backend:requests", '
'please change your config')
backend = 'requests'
if backend == 'requests':
from requests.exceptions import HTTPError
else:
elif backend == 'urrlib2':
from urllib2 import HTTPError
else:
from tornado.httpclient import HTTPError
ret = {'name': name,
'changes': {},
@ -136,10 +147,18 @@ def absent(name, directory_id=None):
performance of this state.
'''
# Because __opts__ is not available outside of functions
if __opts__.get('requests_lib', False):
backend = __opts__.get('backend', False)
if not backend and __opts__.get('requests_lib', False):
salt.utils.warn_until('Oxygen', '"requests_lib:True" has been replaced by "backend:requests", '
'please change your config')
backend = 'requests'
if backend == 'requests':
from requests.exceptions import HTTPError
else:
elif backend == 'urrlib2':
from urllib2 import HTTPError
else:
from tornado.httpclient import HTTPError
ret = {'name': name,
'changes': {},

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
'''
Installing of certificates to the Windows Certificate Manager
=======================
=============================================================
Install certificates to the Windows Certificate Manager

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
'''
Installing of Windows features using DISM
=======================
=========================================
Install windows features/capabilties with DISM

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
'''
Installation and activation of windows licenses
=======================
===============================================
Install and activate windows licenses

View File

@ -46,6 +46,7 @@ features/states of updates available for configuring:
The following example installs all driver updates that don't require a reboot:
.. code-block:: yaml
gryffindor:
win_update.installed:
- skips:
@ -56,6 +57,7 @@ The following example installs all driver updates that don't require a reboot:
To just update your windows machine, add this your sls:
.. code-block:: yaml
updates:
win_update.installed
'''

View File

@ -576,9 +576,16 @@ class TCPReqServerChannel(salt.transport.mixins.auth.AESReqServerMixin, salt.tra
self.payload_handler = payload_handler
self.io_loop = io_loop
self.serial = salt.payload.Serial(self.opts)
if 'ssl_cert' in self.opts and 'ssl_key' in self.opts:
ssl_options = {
'certfile': self.opts['ssl_cert'],
'keyfile': self.opts['ssl_key'],
}
else:
ssl_options = None
if USE_LOAD_BALANCER:
self.req_server = LoadBalancerWorker(
self.socket_queue, self.handle_message, io_loop=self.io_loop
self.socket_queue, self.handle_message, io_loop=self.io_loop, ssl_options=ssl_options
)
else:
if salt.utils.is_windows():
@ -587,7 +594,9 @@ class TCPReqServerChannel(salt.transport.mixins.auth.AESReqServerMixin, salt.tra
_set_tcp_keepalive(self._socket, self.opts)
self._socket.setblocking(0)
self._socket.bind((self.opts['interface'], int(self.opts['ret_port'])))
self.req_server = SaltMessageServer(self.handle_message, io_loop=self.io_loop)
self.req_server = SaltMessageServer(self.handle_message,
io_loop=self.io_loop,
ssl_options=ssl_options)
self.req_server.add_socket(self._socket)
self._socket.listen(self.backlog)
salt.transport.mixins.auth.AESReqServerMixin.post_fork(self, payload_handler, io_loop)
@ -828,11 +837,20 @@ class SaltMessageClient(object):
'''
Try to connect for the rest of time!
'''
if 'ssl_cert' in self.opts and 'ssl_key' in self.opts:
ssl_options = {
'certfile': self.opts['ssl_cert'],
'keyfile': self.opts['ssl_key'],
}
else:
ssl_options = None
while True:
if self._closing:
break
try:
self._stream = yield self._tcp_client.connect(self.host, self.port)
self._stream = yield self._tcp_client.connect(self.host,
self.port,
ssl_options=ssl_options)
self._connecting_future.set_result(True)
break
except Exception as e:
@ -1032,7 +1050,14 @@ class PubServer(tornado.tcpserver.TCPServer, object):
TCP publisher
'''
def __init__(self, opts, io_loop=None):
super(PubServer, self).__init__(io_loop=io_loop)
if 'ssl_cert' in opts and 'ssl_key' in opts:
ssl_options = {
'certfile': opts['ssl_cert'],
'keyfile': opts['ssl_key'],
}
else:
ssl_options = None
super(PubServer, self).__init__(io_loop=io_loop, ssl_options=ssl_options)
self.opts = opts
self._closing = False
self.clients = set()

View File

@ -111,7 +111,7 @@ TAGS = {
def get_event(
node, sock_dir=None, transport='zeromq',
opts=None, listen=True, io_loop=None, keep_loop=False):
opts=None, listen=True, io_loop=None, keep_loop=False, raise_errors=False):
'''
Return an event object suitable for the named transport
@ -124,8 +124,19 @@ def get_event(
# TODO: AIO core is separate from transport
if transport in ('zeromq', 'tcp'):
if node == 'master':
return MasterEvent(sock_dir, opts, listen=listen, io_loop=io_loop, keep_loop=keep_loop)
return SaltEvent(node, sock_dir, opts, listen=listen, io_loop=io_loop, keep_loop=keep_loop)
return MasterEvent(sock_dir,
opts,
listen=listen,
io_loop=io_loop,
keep_loop=keep_loop,
raise_errors=raise_errors)
return SaltEvent(node,
sock_dir,
opts,
listen=listen,
io_loop=io_loop,
keep_loop=keep_loop,
raise_errors=raise_errors)
elif transport == 'raet':
import salt.utils.raetevent
return salt.utils.raetevent.RAETEvent(node,
@ -134,13 +145,13 @@ def get_event(
opts=opts)
def get_master_event(opts, sock_dir, listen=True, io_loop=None):
def get_master_event(opts, sock_dir, listen=True, io_loop=None, raise_errors=False):
'''
Return an event object suitable for the named transport
'''
# TODO: AIO core is separate from transport
if opts['transport'] in ('zeromq', 'tcp', 'detect'):
return MasterEvent(sock_dir, opts, listen=listen, io_loop=io_loop)
return MasterEvent(sock_dir, opts, listen=listen, io_loop=io_loop, raise_errors=raise_errors)
elif opts['transport'] == 'raet':
import salt.utils.raetevent
return salt.utils.raetevent.MasterEvent(
@ -197,7 +208,8 @@ class SaltEvent(object):
'''
def __init__(
self, node, sock_dir=None,
opts=None, listen=True, io_loop=None, keep_loop=False):
opts=None, listen=True, io_loop=None,
keep_loop=False, raise_errors=False):
'''
:param IOLoop io_loop: Pass in an io_loop if you want asynchronous
operation for obtaining events. Eg use of
@ -220,6 +232,7 @@ class SaltEvent(object):
self.cpush = False
self.subscriber = None
self.pusher = None
self.raise_errors = raise_errors
if opts is None:
opts = {}
@ -529,7 +542,12 @@ class SaltEvent(object):
ret = {'data': data, 'tag': mtag}
except KeyboardInterrupt:
return {'tag': 'salt/event/exit', 'data': {}}
except (tornado.iostream.StreamClosedError, RuntimeError):
except tornado.iostream.StreamClosedError:
if self.raise_errors:
raise
else:
return None
except RuntimeError:
return None
if not match_func(ret['tag'], tag):
@ -839,14 +857,16 @@ class MasterEvent(SaltEvent):
opts=None,
listen=True,
io_loop=None,
keep_loop=False):
keep_loop=False,
raise_errors=False):
super(MasterEvent, self).__init__(
'master',
sock_dir,
opts,
listen=listen,
io_loop=io_loop,
keep_loop=keep_loop)
keep_loop=keep_loop,
raise_errors=raise_errors)
class LocalClientEvent(MasterEvent):
@ -879,10 +899,11 @@ class MinionEvent(SaltEvent):
RAET compatible
Create a master event management object
'''
def __init__(self, opts, listen=True, io_loop=None):
def __init__(self, opts, listen=True, io_loop=None, raise_errors=False):
super(MinionEvent, self).__init__(
'minion', sock_dir=opts.get('sock_dir'),
opts=opts, listen=listen, io_loop=io_loop)
opts=opts, listen=listen, io_loop=io_loop,
raise_errors=raise_errors)
class AsyncEventPublisher(object):

View File

@ -278,9 +278,10 @@ class GitProvider(object):
self.conf['name'] = self.conf['name'][:-4]
if 'mountpoint' in self.conf:
# Remove the 'salt://' from the beginning of the mountpoint
# Remove the 'salt://' from the beginning of the mountpoint, as
# well as any additional leading/trailing slashes
self.conf['mountpoint'] = \
salt.utils.url.strip_proto(self.conf['mountpoint'])
salt.utils.url.strip_proto(self.conf['mountpoint']).strip('/')
else:
# For providers which do not use a mountpoint, assume the
# filesystem is mounted at the root of the fileserver.

View File

@ -119,7 +119,7 @@ def query(url,
node='minion',
port=80,
opts=None,
backend='tornado',
backend=None,
requests_lib=None,
ca_bundle=None,
verify_ssl=None,
@ -152,24 +152,29 @@ def query(url,
else:
opts = {}
if requests_lib is None:
requests_lib = opts.get('requests_lib', False)
if requests_lib is True:
log.warning('Please set "backend" to "requests" instead of setting '
'"requests_lib" to "True"')
if not backend:
if requests_lib is not None or 'requests_lib' in opts:
salt.utils.warn_until('Oxygen', '"requests_lib:True" has been replaced by "backend:requests", '
'please change your config')
# beware the named arg above
if 'backend' in opts:
backend = opts['backend']
elif requests_lib or opts.get('requests_lib', False):
backend = 'requests'
else:
backend = 'tornado'
else:
backend = opts.get('backend', 'tornado')
if backend == 'requests':
if HAS_REQUESTS is False:
ret['error'] = ('http.query has been set to use requests, but the '
'requests library does not seem to be installed')
log.error(ret['error'])
return ret
backend = 'requests'
else:
requests_log = logging.getLogger('requests')
requests_log.setLevel(logging.WARNING)
else:
requests_log = logging.getLogger('requests')
requests_log.setLevel(logging.WARNING)
# Some libraries don't support separation of url and GET parameters
# Don't need a try/except block, since Salt depends on tornado
@ -466,46 +471,29 @@ def query(url,
supports_max_body_size = 'max_body_size' in client_argspec.args
try:
if supports_max_body_size:
result = HTTPClient(max_body_size=max_body).fetch(
url_full,
method=method,
headers=header_dict,
auth_username=username,
auth_password=password,
body=data,
validate_cert=verify_ssl,
allow_nonstandard_methods=True,
streaming_callback=streaming_callback,
header_callback=header_callback,
request_timeout=timeout,
proxy_host=proxy_host,
proxy_port=proxy_port,
proxy_username=proxy_username,
proxy_password=proxy_password,
raise_error=raise_error,
**req_kwargs
)
else:
result = HTTPClient().fetch(
url_full,
method=method,
headers=header_dict,
auth_username=username,
auth_password=password,
body=data,
validate_cert=verify_ssl,
allow_nonstandard_methods=True,
streaming_callback=streaming_callback,
header_callback=header_callback,
request_timeout=timeout,
proxy_host=proxy_host,
proxy_port=proxy_port,
proxy_username=proxy_username,
proxy_password=proxy_password,
raise_error=raise_error,
**req_kwargs
)
download_client = HTTPClient(max_body_size=max_body) \
if supports_max_body_size \
else HTTPClient()
result = download_client.fetch(
url_full,
method=method,
headers=header_dict,
auth_username=username,
auth_password=password,
body=data,
validate_cert=verify_ssl,
allow_nonstandard_methods=True,
streaming_callback=streaming_callback,
header_callback=header_callback,
request_timeout=timeout,
proxy_host=proxy_host,
proxy_port=proxy_port,
proxy_username=proxy_username,
proxy_password=proxy_password,
raise_error=raise_error,
decompress_response=False,
**req_kwargs
)
except tornado.httpclient.HTTPError as exc:
ret['status'] = exc.code
ret['error'] = str(exc)

View File

@ -9,8 +9,7 @@ from __future__ import absolute_import
import logging
import subprocess
import os
# Import Third Party Libs
import time
# Import Salt Libs
import salt.utils
@ -20,6 +19,9 @@ from salt.ext import six
from salt.exceptions import CommandExecutionError, SaltInvocationError,\
TimedProcTimeoutError
# Import Third Party Libs
from salt.ext.six.moves import range
DEFAULT_SHELL = salt.grains.extra.shell()['shell']
# Set up logging
@ -198,3 +200,27 @@ def validate_enabled(enabled):
return 'on' if enabled.lower() in ['on', 'yes'] else 'off'
return 'on' if bool(enabled) else 'off'
def confirm_updated(value, check_fun, normalize_ret=False, wait=5):
'''
Wait upto ``wait`` seconds for a system parameter to be changed before
deciding it hasn't changed.
:param str value: The value indicating a successful change
:param function check_fun: The function whose return is compared with
``value``
:param bool normalize_ret: Whether to normalize the return from
``check_fun`` with ``validate_enabled``
:param int wait: The maximum amount of seconds to wait for a system
parameter to change
'''
for i in range(wait):
state = validate_enabled(check_fun()) if normalize_ret else check_fun()
if value in state:
return True
time.sleep(1)
return False

View File

@ -122,7 +122,7 @@ def _generate_minion_id():
if len(a_nfo) > 3:
hosts.append(a_nfo[3])
except socket.gaierror:
log.warn('Cannot resolve address {addr} info via socket: {message}'.format(
log.warning('Cannot resolve address {addr} info via socket: {message}'.format(
addr=hosts.first() or 'localhost (N/A)', message=socket.gaierror)
)
# Universal method for everywhere (Linux, Slowlaris, Windows etc)

Some files were not shown because too many files have changed in this diff Show More