mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 00:55:19 +00:00
Merge pull request #37619 from rallytime/merge-develop
[develop] Merge forward from 2016.11 to develop
This commit is contained in:
commit
f7f7b987b3
@ -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 = ''
|
||||
|
@ -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
|
||||
|
@ -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``
|
||||
-------------------
|
||||
|
@ -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: ``''``
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
22
doc/topics/releases/2016.3.5.rst
Normal file
22
doc/topics/releases/2016.3.5.rst
Normal 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.
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
2
salt/cache/localfs.py
vendored
2
salt/cache/localfs.py
vendored
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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',
|
||||
)
|
||||
|
@ -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):
|
||||
|
@ -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':
|
||||
|
@ -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
|
||||
|
@ -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 '
|
||||
|
@ -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(
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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'],
|
||||
|
@ -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 "", ""
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -175,6 +175,7 @@ def interfaces(root):
|
||||
|
||||
Output example:
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"r": [
|
||||
"state",
|
||||
|
@ -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:
|
||||
|
@ -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():
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -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__
|
||||
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -66,7 +66,7 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def __virtual__():
|
||||
return __virtualname__
|
||||
return 'elasticsearch.alias_exists' in __salt__
|
||||
|
||||
|
||||
def _get_options(ret=None):
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -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__
|
||||
|
||||
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -177,7 +177,7 @@ def __virtual__():
|
||||
'''
|
||||
Return virtualname
|
||||
'''
|
||||
return __virtualname__
|
||||
return 'nagios.list_plugins' in __salt__
|
||||
|
||||
|
||||
def returner(ret):
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -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__
|
||||
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -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__
|
||||
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
salt.serializers.configparser
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Manage CloudTrail Objects
|
||||
=================
|
||||
=========================
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Manage IoT Objects
|
||||
=================
|
||||
==================
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Manage Lambda Functions
|
||||
=================
|
||||
=======================
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
|
@ -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'
|
||||
|
@ -3,6 +3,7 @@
|
||||
Configure Chronos jobs via a salt proxy.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
my_job:
|
||||
chronos_job.config:
|
||||
- config:
|
||||
|
@ -420,6 +420,7 @@ def absent(name,
|
||||
|
||||
def file(name,
|
||||
source_hash='',
|
||||
source_hash_name=None,
|
||||
user='root',
|
||||
template=None,
|
||||
context=None,
|
||||
@ -447,6 +448,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.
|
||||
@ -499,6 +539,7 @@ def file(name,
|
||||
fcm = __salt__['file.check_managed'](cron_path,
|
||||
source,
|
||||
source_hash,
|
||||
source_hash_name,
|
||||
owner,
|
||||
group,
|
||||
mode,
|
||||
|
@ -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,
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Management of the GPG keychains
|
||||
==============================
|
||||
===============================
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Writing/reading defaults from an OS X minion
|
||||
=======================
|
||||
============================================
|
||||
|
||||
'''
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Installing of certificates to the keychain
|
||||
=======================
|
||||
==========================================
|
||||
|
||||
Install certificats to the OS X keychain
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
Configure Marathon apps via a salt proxy.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
my_app:
|
||||
marathon_app.config:
|
||||
- config:
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Allows you to manage proxy settings on minions
|
||||
=======================
|
||||
==============================================
|
||||
|
||||
Setup proxy settings on minions
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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': {},
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Installing of certificates to the Windows Certificate Manager
|
||||
=======================
|
||||
=============================================================
|
||||
|
||||
Install certificates to the Windows Certificate Manager
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Installing of Windows features using DISM
|
||||
=======================
|
||||
=========================================
|
||||
|
||||
Install windows features/capabilties with DISM
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Installation and activation of windows licenses
|
||||
=======================
|
||||
===============================================
|
||||
|
||||
Install and activate windows licenses
|
||||
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -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()
|
||||
|
@ -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):
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user