mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge branch '2016.3' into 'develop'
Conflicts: - salt/state.py - tests/integration/__init__.py - tests/integration/wheel/key.py
This commit is contained in:
commit
76e8dd974a
24 changed files with 334 additions and 80 deletions
|
@ -309,6 +309,11 @@
|
|||
# running any commands. It would also blacklist any use of the "cmd"
|
||||
# module. This is completely disabled by default.
|
||||
#
|
||||
#
|
||||
# Check the list of configured users in client ACL against users on the
|
||||
# system and throw errors if they do not exist.
|
||||
#client_acl_verify: True
|
||||
#
|
||||
#publisher_acl_blacklist:
|
||||
# users:
|
||||
# - root
|
||||
|
|
|
@ -113,6 +113,20 @@ Pillar data. Make sure that your Pillars which need to use the string versions
|
|||
of these values are enclosed in quotes. Pillars will be parsed twice by salt,
|
||||
so you'll need to wrap your values in multiple quotes, for example '"false"'.
|
||||
|
||||
The '%' Sign
|
||||
============
|
||||
|
||||
The `%` symbol has a special meaning in YAML, it needs to be passed as a
|
||||
string literal:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
cheese:
|
||||
ssh_auth.present:
|
||||
- user: tbortels
|
||||
- source: salt://ssh_keys/chease.pub
|
||||
- config: '%h/.ssh/authorized_keys'
|
||||
|
||||
Integers are Parsed as Integers
|
||||
===============================
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ class Beacon(object):
|
|||
'''
|
||||
def __init__(self, opts, functions):
|
||||
self.opts = opts
|
||||
self.functions = functions
|
||||
self.beacons = salt.loader.beacons(opts, functions)
|
||||
self.interval_map = dict()
|
||||
|
||||
|
@ -187,7 +188,8 @@ class Beacon(object):
|
|||
'''
|
||||
# Fire the complete event back along with the list of beacons
|
||||
evt = salt.utils.event.get_event('minion', opts=self.opts)
|
||||
evt.fire_event({'complete': True, 'beacons': self.opts['beacons']},
|
||||
b_conf = self.functions['config.merge']('beacons')
|
||||
evt.fire_event({'complete': True, 'beacons': b_conf},
|
||||
tag='/salt/minion/minion_beacons_list_complete')
|
||||
|
||||
return True
|
||||
|
|
|
@ -738,7 +738,8 @@ class Single(object):
|
|||
'root_dir': os.path.join(self.thin_dir, 'running_data'),
|
||||
'id': self.id,
|
||||
'sock_dir': '/',
|
||||
'log_file': 'salt-call.log'
|
||||
'log_file': 'salt-call.log',
|
||||
'fileserver_list_cache_time': 3,
|
||||
})
|
||||
self.minion_config = salt.serializers.yaml.serialize(self.minion_opts)
|
||||
self.target = kwargs
|
||||
|
|
|
@ -154,7 +154,9 @@ def low(data, **kwargs):
|
|||
__pillar__,
|
||||
__salt__,
|
||||
__context__['fileclient'])
|
||||
err = st_.verify_data(data)
|
||||
for chunk in chunks:
|
||||
chunk['__id__'] = chunk['name'] if not chunk.get('__id__') else chunk['__id__']
|
||||
err = st_.state.verify_data(data)
|
||||
if err:
|
||||
return err
|
||||
file_refs = salt.client.ssh.state.lowstate_file_refs(
|
||||
|
@ -223,7 +225,7 @@ def high(data, **kwargs):
|
|||
__pillar__,
|
||||
__salt__,
|
||||
__context__['fileclient'])
|
||||
chunks = st_.state.compile_high_data(high)
|
||||
chunks = st_.state.compile_high_data(data)
|
||||
file_refs = salt.client.ssh.state.lowstate_file_refs(
|
||||
chunks,
|
||||
_merge_extra_filerefs(
|
||||
|
|
|
@ -603,6 +603,7 @@ VALID_OPTS = {
|
|||
'syndic_failover': str,
|
||||
'runner_dirs': list,
|
||||
'client_acl': dict,
|
||||
'client_acl_verify': bool,
|
||||
'client_acl_blacklist': dict,
|
||||
'publisher_acl': dict,
|
||||
'publisher_acl_blacklist': dict,
|
||||
|
@ -1223,6 +1224,7 @@ DEFAULT_MASTER_OPTS = {
|
|||
'runner_dirs': [],
|
||||
'outputter_dirs': [],
|
||||
'client_acl': {},
|
||||
'client_acl_verify': True,
|
||||
'client_acl_blacklist': {},
|
||||
'publisher_acl': {},
|
||||
'publisher_acl_blacklist': {},
|
||||
|
|
|
@ -246,9 +246,11 @@ def access_keys(opts):
|
|||
if opts.get('user'):
|
||||
acl_users.add(opts['user'])
|
||||
acl_users.add(salt.utils.get_user())
|
||||
if HAS_PWD:
|
||||
if opts['client_acl_verify'] and HAS_PWD:
|
||||
log.profile('Beginning pwd.getpwall() call in masterarpi acess_keys function')
|
||||
for user in pwd.getpwall():
|
||||
users.append(user.pw_name)
|
||||
log.profile('End pwd.getpwall() call in masterarpi acess_keys function')
|
||||
for user in acl_users:
|
||||
log.info(
|
||||
'Preparing the {0} key for local communication'.format(
|
||||
|
@ -256,10 +258,12 @@ def access_keys(opts):
|
|||
)
|
||||
)
|
||||
|
||||
if HAS_PWD:
|
||||
if opts['client_acl_verify'] and HAS_PWD:
|
||||
if user not in users:
|
||||
try:
|
||||
log.profile('Beginning pwd.getpnam() call in masterarpi acess_keys function')
|
||||
user = pwd.getpwnam(user).pw_name
|
||||
log.profile('Beginning pwd.getpwnam() call in masterarpi acess_keys function')
|
||||
except KeyError:
|
||||
log.error('ACL user {0} is not available'.format(user))
|
||||
continue
|
||||
|
|
|
@ -1149,6 +1149,7 @@ def os_data():
|
|||
grains['osrelease'] = 'proxy'
|
||||
grains['os'] = 'proxy'
|
||||
grains['os_family'] = 'proxy'
|
||||
grains['osfullname'] = 'proxy'
|
||||
elif salt.utils.is_windows():
|
||||
with salt.utils.winapi.Com():
|
||||
wmi_c = wmi.WMI()
|
||||
|
|
|
@ -631,6 +631,19 @@ def setup_logfile_logger(log_path, log_level='error', log_format=None,
|
|||
shutdown_multiprocessing_logging_listener()
|
||||
sys.exit(2)
|
||||
else:
|
||||
# make sure, the logging directory exists and attempt to create it if necessary
|
||||
log_dir = os.path.dirname(log_path)
|
||||
if not os.path.exists(log_dir):
|
||||
logging.getLogger(__name__).info(
|
||||
'Log directory not found, trying to create it: {0}'.format(log_dir)
|
||||
)
|
||||
try:
|
||||
os.makedirs(log_dir, mode=0o700)
|
||||
except OSError as ose:
|
||||
logging.getLogger(__name__).warning(
|
||||
'Failed to create directory for log file: {0} ({1})'.format(log_dir, ose)
|
||||
)
|
||||
return
|
||||
try:
|
||||
# Logfile logging is UTF-8 on purpose.
|
||||
# Since salt uses YAML and YAML uses either UTF-8 or UTF-16, if a
|
||||
|
|
|
@ -2318,7 +2318,7 @@ class ClearFuncs(object):
|
|||
# always write out to the master job caches
|
||||
try:
|
||||
fstr = '{0}.save_load'.format(self.opts['master_job_cache'])
|
||||
self.mminion.returners[fstr](clear_load['jid'], clear_load)
|
||||
self.mminion.returners[fstr](clear_load['jid'], clear_load, minions)
|
||||
except KeyError:
|
||||
log.critical(
|
||||
'The specified returner used for the master job cache '
|
||||
|
|
|
@ -9,13 +9,16 @@ Module for managing the Salt beacons on a minion
|
|||
# Import Python libs
|
||||
from __future__ import absolute_import
|
||||
import difflib
|
||||
import logging
|
||||
import os
|
||||
import yaml
|
||||
|
||||
# Import Salt libs
|
||||
import salt.utils
|
||||
import salt.utils.event
|
||||
from salt.ext.six.moves import map
|
||||
|
||||
import logging
|
||||
# Get logging started
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
__func_alias__ = {
|
||||
|
@ -38,6 +41,7 @@ def list_(return_yaml=True):
|
|||
salt '*' beacons.list
|
||||
|
||||
'''
|
||||
beacons = None
|
||||
|
||||
try:
|
||||
eventer = salt.utils.event.get_event('minion', opts=__opts__)
|
||||
|
|
|
@ -1382,6 +1382,145 @@ def describe(cwd, rev='HEAD', user=None, ignore_retcode=False):
|
|||
ignore_retcode=ignore_retcode)['stdout']
|
||||
|
||||
|
||||
def diff(cwd,
|
||||
item1=None,
|
||||
item2=None,
|
||||
opts='',
|
||||
user=None,
|
||||
no_index=False,
|
||||
cached=False,
|
||||
paths=None):
|
||||
'''
|
||||
.. versionadded:: 2015.8.12,2016.3.3
|
||||
|
||||
Interface to `git-diff(1)`_
|
||||
|
||||
cwd
|
||||
The path to the git checkout
|
||||
|
||||
item1 and item2
|
||||
Revision(s) to pass to the ``git diff`` command. One or both of these
|
||||
arguments may be ignored if some of the options below are set to
|
||||
``True``. When ``cached`` is ``False``, and no revisions are passed
|
||||
to this function, then the current working tree will be compared
|
||||
against the index (i.e. unstaged changes). When two revisions are
|
||||
passed, they will be compared to each other.
|
||||
|
||||
opts
|
||||
Any additional options to add to the command line, in a single string
|
||||
|
||||
.. note::
|
||||
On the Salt CLI, if the opts are preceded with a dash, it is
|
||||
necessary to precede them with ``opts=`` (as in the CLI examples
|
||||
below) to avoid causing errors with Salt's own argument parsing.
|
||||
|
||||
user
|
||||
User under which to run the git command. By default, the command is run
|
||||
by the user under which the minion is running.
|
||||
|
||||
no_index : False
|
||||
When it is necessary to diff two files in the same repo against each
|
||||
other, and not diff two different revisions, set this option to
|
||||
``True``. If this is left ``False`` in these instances, then a normal
|
||||
``git diff`` will be performed against the index (i.e. unstaged
|
||||
changes), and files in the ``paths`` option will be used to narrow down
|
||||
the diff output.
|
||||
|
||||
.. note::
|
||||
Requires Git 1.5.1 or newer. Additionally, when set to ``True``,
|
||||
``item1`` and ``item2`` will be ignored.
|
||||
|
||||
cached : False
|
||||
If ``True``, compare staged changes to ``item1`` (if specified),
|
||||
otherwise compare them to the most recent commit.
|
||||
|
||||
.. note::
|
||||
``item2`` is ignored if this option is is set to ``True``.
|
||||
|
||||
paths
|
||||
File paths to pass to the ``git diff`` command. Can be passed as a
|
||||
comma-separated list or a Python list.
|
||||
|
||||
.. _`git-diff(1)`: http://git-scm.com/docs/git-diff
|
||||
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Perform diff against the index (staging area for next commit)
|
||||
salt myminion git.diff /path/to/repo
|
||||
# Compare staged changes to the most recent commit
|
||||
salt myminion git.diff /path/to/repo cached=True
|
||||
# Compare staged changes to a specific revision
|
||||
salt myminion git.diff /path/to/repo mybranch cached=True
|
||||
# Perform diff against the most recent commit (includes staged changes)
|
||||
salt myminion git.diff /path/to/repo HEAD
|
||||
# Diff two commits
|
||||
salt myminion git.diff /path/to/repo abcdef1 aabbccd
|
||||
# Diff two commits, only showing differences in the specified paths
|
||||
salt myminion git.diff /path/to/repo abcdef1 aabbccd paths=path/to/file1,path/to/file2
|
||||
# Diff two files with one being outside the working tree
|
||||
salt myminion git.diff /path/to/repo no_index=True paths=path/to/file1,/absolute/path/to/file2
|
||||
'''
|
||||
if no_index and cached:
|
||||
raise CommandExecutionError(
|
||||
'The \'no_index\' and \'cached\' options cannot be used together'
|
||||
)
|
||||
|
||||
command = ['git', 'diff']
|
||||
command.extend(_format_opts(opts))
|
||||
|
||||
if paths is not None and not isinstance(paths, (list, tuple)):
|
||||
try:
|
||||
paths = paths.split(',')
|
||||
except AttributeError:
|
||||
paths = str(paths).split(',')
|
||||
|
||||
ignore_retcode = False
|
||||
failhard = True
|
||||
|
||||
if no_index:
|
||||
if _LooseVersion(version(versioninfo=False)) < _LooseVersion('1.5.1'):
|
||||
raise CommandExecutionError(
|
||||
'The \'no_index\' option is only supported in Git 1.5.1 and '
|
||||
'newer'
|
||||
)
|
||||
ignore_retcode = True
|
||||
failhard = False
|
||||
command.append('--no-index')
|
||||
for value in [x for x in (item1, item2) if x]:
|
||||
log.warning(
|
||||
'Revision \'%s\' ignored in git diff, as revisions cannot be '
|
||||
'used when no_index=True', value
|
||||
)
|
||||
|
||||
elif cached:
|
||||
command.append('--cached')
|
||||
if item1:
|
||||
command.append(item1)
|
||||
if item2:
|
||||
log.warning(
|
||||
'Second revision \'%s\' ignored in git diff, at most one '
|
||||
'revision is considered when cached=True', item2
|
||||
)
|
||||
|
||||
else:
|
||||
for value in [x for x in (item1, item2) if x]:
|
||||
command.append(value)
|
||||
|
||||
if paths:
|
||||
command.append('--')
|
||||
command.extend(paths)
|
||||
|
||||
return _git_run(command,
|
||||
cwd=cwd,
|
||||
runas=user,
|
||||
ignore_retcode=ignore_retcode,
|
||||
failhard=failhard,
|
||||
redirect_stderr=True)['stdout']
|
||||
|
||||
|
||||
def fetch(cwd,
|
||||
remote=None,
|
||||
force=False,
|
||||
|
|
|
@ -61,11 +61,10 @@ def __virtual__():
|
|||
'OEL',
|
||||
'SUSE Enterprise Server',
|
||||
'SUSE',
|
||||
'McAfee OS Server'
|
||||
'McAfee OS Server',
|
||||
'VirtuozzoLinux'
|
||||
))
|
||||
if __grains__['os'] in enable:
|
||||
if __grains__['os'] == 'XenServer':
|
||||
return __virtualname__
|
||||
|
||||
if __grains__['os'] == 'SUSE':
|
||||
if str(__grains__['osrelease']).startswith('11'):
|
||||
|
@ -75,6 +74,15 @@ def __virtual__():
|
|||
|
||||
osrelease_major = __grains__.get('osrelease_info', [0])[0]
|
||||
|
||||
if __grains__['os'] == 'XenServer':
|
||||
if osrelease_major >= 7:
|
||||
return (
|
||||
False,
|
||||
'XenServer >= 7 uses systemd, will not load rh_service.py '
|
||||
'as virtual \'service\''
|
||||
)
|
||||
return __virtualname__
|
||||
|
||||
if __grains__['os'] == 'Fedora':
|
||||
if osrelease_major >= 15:
|
||||
return (
|
||||
|
|
|
@ -52,7 +52,7 @@ def __virtual__():
|
|||
except Exception:
|
||||
return (False, 'The rpm execution module failed to load: failed to detect os or os_family grains.')
|
||||
|
||||
enabled = ('amazon', 'xcp', 'xenserver')
|
||||
enabled = ('amazon', 'xcp', 'xenserver', 'VirtuozzoLinux')
|
||||
|
||||
if os_family in ['redhat', 'suse'] or os_grain in enabled:
|
||||
return __virtualname__
|
||||
|
|
|
@ -160,7 +160,7 @@ def list_upgrades(refresh=True, saltenv='base', **kwargs): # pylint: disable=W0
|
|||
ret = {}
|
||||
for name, data in six.iteritems(get_repo_data(saltenv).get('repo', {})):
|
||||
if version(name):
|
||||
latest = latest_version(name)
|
||||
latest = latest_version(name, refresh=False)
|
||||
if latest:
|
||||
ret[name] = latest
|
||||
return ret
|
||||
|
@ -663,7 +663,7 @@ def install(name=None, refresh=False, pkgs=None, saltenv='base', **kwargs):
|
|||
version_num = _get_latest_pkg_version(pkginfo)
|
||||
|
||||
# Check if the version is already installed
|
||||
if version_num == old.get(pkg_name) \
|
||||
if version_num in old.get(pkg_name, '').split(',') \
|
||||
or (pkg_name in old and old[pkg_name] == 'Not Found'):
|
||||
# Desired version number already installed
|
||||
ret[pkg_name] = {'current': version_num}
|
||||
|
@ -981,7 +981,7 @@ def remove(name=None, pkgs=None, version=None, saltenv='base', **kwargs):
|
|||
ret[target] = {'current': 'not installed'}
|
||||
continue
|
||||
else:
|
||||
if not version_num == old.get(target) \
|
||||
if version_num not in old.get(target, '').split(',') \
|
||||
and not old.get(target) == "Not Found" \
|
||||
and version_num != 'latest':
|
||||
log.error('{0} {1} not installed'.format(target, version))
|
||||
|
|
|
@ -51,7 +51,6 @@ import salt.utils.yamlloader as yamlloader
|
|||
# pylint: disable=import-error,no-name-in-module,redefined-builtin
|
||||
import salt.ext.six as six
|
||||
from salt.ext.six.moves import map, range, reload_module
|
||||
from salt.ext.six import string_types
|
||||
# pylint: enable=import-error,no-name-in-module,redefined-builtin
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
@ -791,7 +790,7 @@ class State(object):
|
|||
else:
|
||||
low_data_onlyif = low_data['onlyif']
|
||||
for entry in low_data_onlyif:
|
||||
if not isinstance(entry, string_types):
|
||||
if not isinstance(entry, six.string_types):
|
||||
ret.update({'comment': 'onlyif execution failed, bad type passed', 'result': False})
|
||||
return ret
|
||||
cmd = self.functions['cmd.retcode'](
|
||||
|
@ -812,7 +811,7 @@ class State(object):
|
|||
else:
|
||||
low_data_unless = low_data['unless']
|
||||
for entry in low_data_unless:
|
||||
if not isinstance(entry, string_types):
|
||||
if not isinstance(entry, six.string_types):
|
||||
ret.update({'comment': 'unless execution failed, bad type passed', 'result': False})
|
||||
return ret
|
||||
cmd = self.functions['cmd.retcode'](
|
||||
|
|
|
@ -177,17 +177,24 @@ def _failed_submodule_update(ret, exc, comments=None):
|
|||
return _fail(ret, msg, comments)
|
||||
|
||||
|
||||
def _not_fast_forward(ret, pre, post, branch, local_branch, comments):
|
||||
def _not_fast_forward(ret, pre, post, branch, local_branch,
|
||||
local_changes, comments):
|
||||
pre = _short_sha(pre)
|
||||
post = _short_sha(post)
|
||||
return _fail(
|
||||
ret,
|
||||
'Repository would be updated from {0} to {1}{2}, but this is not a '
|
||||
'fast-forward merge. Set \'force_reset\' to True to force this '
|
||||
'update.'.format(
|
||||
_short_sha(pre),
|
||||
_short_sha(post),
|
||||
'Repository would be updated {0}{1}, but {2}. Set \'force_reset\' to '
|
||||
'True to force this update{3}.'.format(
|
||||
'from {0} to {1}'.format(pre, post)
|
||||
if local_changes and pre != post
|
||||
else 'to {0}'.format(post),
|
||||
' (after checking out local branch \'{0}\')'.format(branch)
|
||||
if _need_branch_change(branch, local_branch)
|
||||
else ''
|
||||
else '',
|
||||
'this is not a fast-forward merge'
|
||||
if not local_changes
|
||||
else 'there are uncommitted changes',
|
||||
' and discard these changes' if local_changes else ''
|
||||
),
|
||||
comments
|
||||
)
|
||||
|
@ -730,6 +737,19 @@ def latest(name,
|
|||
redact_auth=False)
|
||||
|
||||
revs_match = _revs_equal(local_rev, remote_rev, remote_rev_type)
|
||||
try:
|
||||
local_changes = bool(
|
||||
__salt__['git.diff'](target, 'HEAD', user=user)
|
||||
)
|
||||
except CommandExecutionError:
|
||||
# No need to capture the error and log it, the _git_run()
|
||||
# helper in the git execution module will have already logged
|
||||
# the output from the command.
|
||||
log.warning(
|
||||
'git.latest: Unable to determine if %s has local changes',
|
||||
target
|
||||
)
|
||||
local_changes = False
|
||||
|
||||
if remote_rev_type == 'sha1' \
|
||||
and base_rev is not None \
|
||||
|
@ -819,13 +839,15 @@ def latest(name,
|
|||
elif remote_rev_type == 'sha1':
|
||||
has_remote_rev = True
|
||||
|
||||
if not has_remote_rev:
|
||||
# Either the remote rev could not be found with git
|
||||
# ls-remote (in which case we won't know more until
|
||||
# fetching) or we're going to be checking out a new branch
|
||||
# and don't have to worry about fast-forwarding.
|
||||
fast_forward = None
|
||||
else:
|
||||
# If has_remote_rev is False, then either the remote rev could not
|
||||
# be found with git ls-remote (in which case we won't know more
|
||||
# until fetching) or we're going to be checking out a new branch
|
||||
# and don't have to worry about fast-forwarding. So, we will set
|
||||
# fast_forward to None (to signify uncertainty) unless there are
|
||||
# local changes, in which case we will set it to False.
|
||||
fast_forward = None if not local_changes else False
|
||||
|
||||
if has_remote_rev:
|
||||
# Remote rev already present
|
||||
if (not revs_match and not update_head) \
|
||||
and (branch is None or branch == local_branch):
|
||||
|
@ -839,14 +861,18 @@ def latest(name,
|
|||
)
|
||||
return ret
|
||||
|
||||
# No need to check if this is a fast_forward if we already know
|
||||
# that it won't be (due to local changes).
|
||||
if fast_forward is not False:
|
||||
if base_rev is None:
|
||||
# If we're here, the remote_rev exists in the local
|
||||
# checkout but there is still no HEAD locally. A possible
|
||||
# reason for this is that an empty repository existed there
|
||||
# and a remote was added and fetched, but the repository
|
||||
# was not fast-forwarded. Regardless, going from no HEAD to
|
||||
# a locally-present rev is considered a fast-forward update.
|
||||
fast_forward = True
|
||||
# a locally-present rev is considered a fast-forward
|
||||
# update, unless there are local changes.
|
||||
fast_forward = not bool(local_changes)
|
||||
else:
|
||||
fast_forward = __salt__['git.merge_base'](
|
||||
target,
|
||||
|
@ -863,6 +889,7 @@ def latest(name,
|
|||
remote_rev,
|
||||
branch,
|
||||
local_branch,
|
||||
local_changes,
|
||||
comments)
|
||||
merge_action = 'hard-reset'
|
||||
elif fast_forward is True:
|
||||
|
@ -1153,11 +1180,10 @@ def latest(name,
|
|||
remote_rev,
|
||||
branch,
|
||||
local_branch,
|
||||
local_changes,
|
||||
comments)
|
||||
|
||||
if _need_branch_change(branch, local_branch):
|
||||
local_changes = __salt__['git.status'](target,
|
||||
user=user)
|
||||
if local_changes and not force_checkout:
|
||||
return _fail(
|
||||
ret,
|
||||
|
@ -1199,6 +1225,9 @@ def latest(name,
|
|||
'\'{0}\' was checked out'.format(checkout_rev)
|
||||
)
|
||||
|
||||
if local_changes:
|
||||
comments.append('Local changes were discarded')
|
||||
|
||||
if fast_forward is False:
|
||||
__salt__['git.reset'](
|
||||
target,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Send a message to Slack
|
||||
=========================
|
||||
=======================
|
||||
|
||||
This state is useful for sending messages to Slack during state runs.
|
||||
|
||||
|
@ -25,6 +25,12 @@ The api key can be specified in the master or minion configuration like below:
|
|||
|
||||
'''
|
||||
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Import Salt libs
|
||||
from salt.exceptions import SaltInvocationError
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
|
@ -96,18 +102,18 @@ def post_message(name,
|
|||
ret['comment'] = 'Slack message is missing: {0}'.format(message)
|
||||
return ret
|
||||
|
||||
result = __salt__['slack.post_message'](
|
||||
channel=channel,
|
||||
message=message,
|
||||
from_name=from_name,
|
||||
api_key=api_key,
|
||||
icon=icon,
|
||||
)
|
||||
|
||||
if result:
|
||||
try:
|
||||
result = __salt__['slack.post_message'](
|
||||
channel=channel,
|
||||
message=message,
|
||||
from_name=from_name,
|
||||
api_key=api_key,
|
||||
icon=icon,
|
||||
)
|
||||
except SaltInvocationError as sie:
|
||||
ret['comment'] = 'Failed to send message: {0} ({1})'.format(name, sie)
|
||||
else:
|
||||
ret['result'] = True
|
||||
ret['comment'] = 'Sent message: {0}'.format(name)
|
||||
else:
|
||||
ret['comment'] = 'Failed to send message: {0}'.format(name)
|
||||
|
||||
return ret
|
||||
|
|
|
@ -29,7 +29,7 @@ to use a YAML 'explicit key', as demonstrated in the second example below.
|
|||
ssh_auth.present:
|
||||
- user: root
|
||||
- source: salt://ssh_keys/thatch.id_rsa.pub
|
||||
- config: %h/.ssh/authorized_keys
|
||||
- config: '%h/.ssh/authorized_keys'
|
||||
|
||||
sshkeys:
|
||||
ssh_auth.present:
|
||||
|
|
|
@ -40,8 +40,6 @@ from salt.defaults import DEFAULT_TARGET_DELIM
|
|||
from salt.utils.validate.path import is_writeable
|
||||
from salt.utils.verify import verify_files
|
||||
import salt.exceptions
|
||||
|
||||
# Import 3rd-party libs
|
||||
import salt.ext.six as six
|
||||
from salt.ext.six.moves import range # pylint: disable=import-error,redefined-builtin
|
||||
|
||||
|
|
|
@ -54,11 +54,6 @@ except ImportError:
|
|||
# Older jinja does not need markupsafe
|
||||
HAS_MARKUPSAFE = False
|
||||
|
||||
try:
|
||||
import xml
|
||||
HAS_XML = True
|
||||
except ImportError:
|
||||
HAS_XML = False
|
||||
# pylint: enable=import-error,no-name-in-module
|
||||
|
||||
try:
|
||||
|
@ -129,10 +124,6 @@ def get_tops(extra_mods='', so_mods=''):
|
|||
if HAS_SSL_MATCH_HOSTNAME:
|
||||
tops.append(os.path.dirname(os.path.dirname(ssl_match_hostname.__file__)))
|
||||
|
||||
if HAS_XML:
|
||||
# For openSUSE, which apparently doesn't include the whole stdlib
|
||||
tops.append(os.path.dirname(xml.__file__))
|
||||
|
||||
for mod in [m for m in extra_mods.split(',') if m]:
|
||||
if mod not in locals() and mod not in globals():
|
||||
try:
|
||||
|
|
|
@ -1803,14 +1803,14 @@ class ShellCase(AdaptedConfigurationTestCaseMixIn, ShellTestCase, ScriptPathMixi
|
|||
Execute salt
|
||||
'''
|
||||
arg_str = '-c {0} {1}'.format(self.get_config_dir(), arg_str)
|
||||
return self.run_script('salt', arg_str, with_retcode=with_retcode, catch_stderr=catch_stderr, timeout=timeout)
|
||||
return self.run_script('salt', arg_str, with_retcode=with_retcode, catch_stderr=catch_stderr, timeout=30)
|
||||
|
||||
def run_ssh(self, arg_str, with_retcode=False, catch_stderr=False):
|
||||
'''
|
||||
Execute salt-ssh
|
||||
'''
|
||||
arg_str = '-W -c {0} -i --priv {1} --roster-file {2} --out=json localhost {3}'.format(self.get_config_dir(), os.path.join(TMP_CONF_DIR, 'key_test'), os.path.join(TMP_CONF_DIR, 'roster'), arg_str)
|
||||
return self.run_script('salt-ssh', arg_str, with_retcode=with_retcode, catch_stderr=catch_stderr, raw=True)
|
||||
return self.run_script('salt-ssh', arg_str, with_retcode=with_retcode, catch_stderr=catch_stderr, raw=True, timeout=30)
|
||||
|
||||
def run_run(self, arg_str, with_retcode=False, catch_stderr=False, async=False, timeout=60, config_dir=None):
|
||||
'''
|
||||
|
@ -1820,7 +1820,7 @@ class ShellCase(AdaptedConfigurationTestCaseMixIn, ShellTestCase, ScriptPathMixi
|
|||
arg_str,
|
||||
timeout=timeout,
|
||||
async_flag=' --async' if async else '')
|
||||
return self.run_script('salt-run', arg_str, with_retcode=with_retcode, catch_stderr=catch_stderr)
|
||||
return self.run_script('salt-run', arg_str, with_retcode=with_retcode, catch_stderr=catch_stderr, timeout=30)
|
||||
|
||||
def run_run_plus(self, fun, options='', *arg, **kwargs):
|
||||
'''
|
||||
|
@ -1848,7 +1848,8 @@ class ShellCase(AdaptedConfigurationTestCaseMixIn, ShellTestCase, ScriptPathMixi
|
|||
'salt-key',
|
||||
arg_str,
|
||||
catch_stderr=catch_stderr,
|
||||
with_retcode=with_retcode
|
||||
with_retcode=with_retcode,
|
||||
timeout=30
|
||||
)
|
||||
|
||||
def run_cp(self, arg_str, with_retcode=False, catch_stderr=False):
|
||||
|
@ -1856,14 +1857,14 @@ class ShellCase(AdaptedConfigurationTestCaseMixIn, ShellTestCase, ScriptPathMixi
|
|||
Execute salt-cp
|
||||
'''
|
||||
arg_str = '--config-dir {0} {1}'.format(self.get_config_dir(), arg_str)
|
||||
return self.run_script('salt-cp', arg_str, with_retcode=with_retcode, catch_stderr=catch_stderr)
|
||||
return self.run_script('salt-cp', arg_str, with_retcode=with_retcode, catch_stderr=catch_stderr, timeout=30)
|
||||
|
||||
def run_call(self, arg_str, with_retcode=False, catch_stderr=False):
|
||||
'''
|
||||
Execute salt-call.
|
||||
'''
|
||||
arg_str = '--config-dir {0} {1}'.format(self.get_config_dir(), arg_str)
|
||||
return self.run_script('salt-call', arg_str, with_retcode=with_retcode, catch_stderr=catch_stderr)
|
||||
return self.run_script('salt-call', arg_str, with_retcode=with_retcode, catch_stderr=catch_stderr, timeout=30)
|
||||
|
||||
def run_cloud(self, arg_str, catch_stderr=False, timeout=None):
|
||||
'''
|
||||
|
|
|
@ -150,6 +150,53 @@ class GitTest(integration.ModuleCase, integration.SaltReturnAssertsMixIn):
|
|||
finally:
|
||||
shutil.rmtree(name, ignore_errors=True)
|
||||
|
||||
def test_latest_with_local_changes(self):
|
||||
'''
|
||||
Ensure that we fail the state when there are local changes and succeed
|
||||
when force_reset is True.
|
||||
'''
|
||||
name = os.path.join(integration.TMP, 'salt_repo')
|
||||
try:
|
||||
# Clone repo
|
||||
ret = self.run_state(
|
||||
'git.latest',
|
||||
name='https://{0}/saltstack/salt-test-repo.git'.format(self.__domain),
|
||||
target=name
|
||||
)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
self.assertTrue(os.path.isdir(os.path.join(name, '.git')))
|
||||
|
||||
# Make change to LICENSE file.
|
||||
with salt.utils.fopen(os.path.join(name, 'LICENSE'), 'a') as fp_:
|
||||
fp_.write('Lorem ipsum dolor blah blah blah....\n')
|
||||
|
||||
# Make sure that we now have uncommitted changes
|
||||
self.assertTrue(self.run_function('git.diff', [name, 'HEAD']))
|
||||
|
||||
# Re-run state with force_reset=False, this should fail
|
||||
ret = self.run_state(
|
||||
'git.latest',
|
||||
name='https://{0}/saltstack/salt-test-repo.git'.format(self.__domain),
|
||||
target=name,
|
||||
force_reset=False
|
||||
)
|
||||
self.assertSaltFalseReturn(ret)
|
||||
|
||||
# Now run the state with force_reset=True, this should succeed
|
||||
ret = self.run_state(
|
||||
'git.latest',
|
||||
name='https://{0}/saltstack/salt-test-repo.git'.format(self.__domain),
|
||||
target=name,
|
||||
force_reset=True
|
||||
)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
# Make sure that we no longer have uncommitted changes
|
||||
self.assertFalse(self.run_function('git.diff', [name, 'HEAD']))
|
||||
|
||||
finally:
|
||||
shutil.rmtree(name, ignore_errors=True)
|
||||
|
||||
def test_present(self):
|
||||
'''
|
||||
git.present
|
||||
|
|
|
@ -14,20 +14,8 @@ class KeyWheelModuleTest(integration.TestCase, integration.AdaptedConfigurationT
|
|||
|
||||
def test_list_all(self):
|
||||
ret = self.wheel.call_func('key.list_all')
|
||||
self.assertEqual({
|
||||
'local': [
|
||||
'master.pem',
|
||||
'master.pub',
|
||||
'minion.pem',
|
||||
'minion.pub',
|
||||
'minion_master.pub',
|
||||
'syndic_master.pub'
|
||||
],
|
||||
'minions_rejected': [],
|
||||
'minions_pre': [],
|
||||
'minions_denied': [],
|
||||
'minions': ['minion', 'sub_minion'],
|
||||
}, ret)
|
||||
for host in ['minion', 'sub_minion']:
|
||||
self.assertIn(host, ret['minions'])
|
||||
|
||||
def test_gen(self):
|
||||
ret = self.wheel.call_func('key.gen', id_='soundtechniciansrock')
|
||||
|
|
Loading…
Add table
Reference in a new issue