mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge branch '2017.7' into '2018.3'
Conflicts: - salt/daemons/flo/zero.py - salt/minion.py - salt/pillar/pillar_ldap.py - salt/transport/zeromq.py - salt/utils/async.py - salt/utils/zeromq.py - tests/integration/modules/test_service.py - tests/integration/netapi/rest_tornado/test_app.py - tests/unit/fileserver/test_gitfs.py - tests/unit/modules/test_pip.py
This commit is contained in:
commit
a94cdf8a0d
15 changed files with 286 additions and 115 deletions
|
@ -34,8 +34,8 @@ from salt.ext.six.moves import range
|
|||
from salt.utils.zeromq import zmq, ZMQDefaultLoop, install_zmq, ZMQ_VERSION_INFO
|
||||
|
||||
# pylint: enable=no-name-in-module,redefined-builtin
|
||||
import tornado
|
||||
|
||||
# Import third party libs
|
||||
HAS_RANGE = False
|
||||
try:
|
||||
import seco.range
|
||||
|
@ -1172,7 +1172,7 @@ class Minion(MinionBase):
|
|||
# I made the following 3 line oddity to preserve traceback.
|
||||
# Please read PR #23978 before changing, hopefully avoiding regressions.
|
||||
# Good luck, we're all counting on you. Thanks.
|
||||
future_exception = self._connect_master_future.exc_info()
|
||||
future_exception = self._connect_master_future.exception()
|
||||
if future_exception:
|
||||
# This needs to be re-raised to preserve restart_on_error behavior.
|
||||
raise six.reraise(*future_exception)
|
||||
|
|
|
@ -2309,10 +2309,10 @@ def create_route(route_table_id=None, destination_cidr_block=None,
|
|||
'must be provided.')
|
||||
|
||||
if not _exactly_one((gateway_id, internet_gateway_name, instance_id, interface_id, vpc_peering_connection_id,
|
||||
nat_gateway_id, nat_gateway_subnet_id, nat_gateway_subnet_name)):
|
||||
nat_gateway_id, nat_gateway_subnet_id, nat_gateway_subnet_name, vpc_peering_connection_name)):
|
||||
raise SaltInvocationError('Only one of gateway_id, internet_gateway_name, instance_id, '
|
||||
'interface_id, vpc_peering_connection_id, nat_gateway_id, '
|
||||
'nat_gateway_subnet_id or nat_gateway_subnet_name may be provided.')
|
||||
'nat_gateway_subnet_id, nat_gateway_subnet_name or vpc_peering_connection_name may be provided.')
|
||||
|
||||
if destination_cidr_block is None:
|
||||
raise SaltInvocationError('destination_cidr_block is required.')
|
||||
|
|
|
@ -458,8 +458,8 @@ def delval(key, destructive=False):
|
|||
.. versionadded:: 0.17.0
|
||||
|
||||
Delete a grain value from the grains config file. This will just set the
|
||||
grain value to `None`. To completely remove the grain run `grains.delkey`
|
||||
of pass `destructive=True` to `grains.delval`.
|
||||
grain value to ``None``. To completely remove the grain, run ``grains.delkey``
|
||||
or pass ``destructive=True`` to ``grains.delval``.
|
||||
|
||||
key
|
||||
The grain key from which to delete the value.
|
||||
|
|
|
@ -437,6 +437,9 @@ class BaseSaltAPIHandler(tornado.web.RequestHandler): # pylint: disable=W0223
|
|||
'runner_async': None, # empty, since we use the same client as `runner`
|
||||
}
|
||||
|
||||
if not hasattr(self, 'ckminions'):
|
||||
self.ckminions = salt.utils.minions.CkMinions(self.application.opts)
|
||||
|
||||
@property
|
||||
def token(self):
|
||||
'''
|
||||
|
@ -931,7 +934,8 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
|
|||
chunk['jid'] = salt.utils.jid.gen_jid(self.application.opts)
|
||||
|
||||
# Subscribe returns from minions before firing a job
|
||||
future_minion_map = self.subscribe_minion_returns(chunk['jid'], chunk['tgt'])
|
||||
minions = set(self.ckminions.check_minions(chunk['tgt'], chunk.get('tgt_type', 'glob')))
|
||||
future_minion_map = self.subscribe_minion_returns(chunk['jid'], minions)
|
||||
|
||||
f_call = self._format_call_run_job_async(chunk)
|
||||
# fire a job off
|
||||
|
@ -947,9 +951,9 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
|
|||
pass
|
||||
raise tornado.gen.Return('No minions matched the target. No command was sent, no jid was assigned.')
|
||||
|
||||
syndic_min_wait = None
|
||||
# wait syndic a while to avoid missing published events
|
||||
if self.application.opts['order_masters']:
|
||||
syndic_min_wait = tornado.gen.sleep(self.application.opts['syndic_wait'])
|
||||
yield tornado.gen.sleep(self.application.opts['syndic_wait'])
|
||||
|
||||
# To ensure job_not_running and all_return are terminated by each other, communicate using a future
|
||||
is_finished = Future()
|
||||
|
@ -959,10 +963,6 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
|
|||
f_call['kwargs']['tgt_type'],
|
||||
is_finished)
|
||||
|
||||
# if we have a min_wait, do that
|
||||
if syndic_min_wait is not None:
|
||||
yield syndic_min_wait
|
||||
|
||||
minion_returns_future = self.sanitize_minion_returns(future_minion_map, pub_data['minions'], is_finished)
|
||||
|
||||
yield job_not_running_future
|
||||
|
@ -999,7 +999,7 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
|
|||
|
||||
chunk_ret = {}
|
||||
while True:
|
||||
f = yield Any(future_minion_map.keys() + [is_finished])
|
||||
f = yield Any(list(future_minion_map.keys()) + [is_finished])
|
||||
try:
|
||||
# When finished entire routine, cleanup other futures and return result
|
||||
if f is is_finished:
|
||||
|
|
|
@ -50,66 +50,76 @@ possible to reference grains within the configuration.
|
|||
to trick the master into returning secret data.
|
||||
Use only the 'id' grain which is verified through the minion's key/cert.
|
||||
|
||||
|
||||
Map Mode
|
||||
--------
|
||||
|
||||
The ``it-admins`` configuration below returns the Pillar ``it-admins`` by:
|
||||
|
||||
- filtering for:
|
||||
- members of the group ``it-admins``
|
||||
- objects with ``objectclass=user``
|
||||
- returning the data of users (``mode: map``), where each user is a dictionary
|
||||
containing the configured string or list attributes.
|
||||
- members of the group ``it-admins``
|
||||
- objects with ``objectclass=user``
|
||||
- returning the data of users, where each user is a dictionary containing the
|
||||
configured string or list attributes.
|
||||
|
||||
**Configuration:**
|
||||
|
||||
Configuration
|
||||
*************
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
salt-users:
|
||||
server: ldap.company.tld
|
||||
port: 389
|
||||
tls: true
|
||||
dn: 'dc=company,dc=tld'
|
||||
binddn: 'cn=salt-pillars,ou=users,dc=company,dc=tld'
|
||||
bindpw: bi7ieBai5Ano
|
||||
referrals: false
|
||||
anonymous: false
|
||||
mode: map
|
||||
dn: 'ou=users,dc=company,dc=tld'
|
||||
filter: '(&(memberof=cn=it-admins,ou=groups,dc=company,dc=tld)(objectclass=user))'
|
||||
attrs:
|
||||
- cn
|
||||
- displayName
|
||||
- givenName
|
||||
- sn
|
||||
lists:
|
||||
- memberOf
|
||||
server: ldap.company.tld
|
||||
port: 389
|
||||
tls: true
|
||||
dn: 'dc=company,dc=tld'
|
||||
binddn: 'cn=salt-pillars,ou=users,dc=company,dc=tld'
|
||||
bindpw: bi7ieBai5Ano
|
||||
referrals: false
|
||||
anonymous: false
|
||||
mode: map
|
||||
dn: 'ou=users,dc=company,dc=tld'
|
||||
filter: '(&(memberof=cn=it-admins,ou=groups,dc=company,dc=tld)(objectclass=user))'
|
||||
attrs:
|
||||
- cn
|
||||
- displayName
|
||||
- givenName
|
||||
- sn
|
||||
lists:
|
||||
- memberOf
|
||||
|
||||
**Result:**
|
||||
search_order:
|
||||
- salt-users
|
||||
|
||||
.. code-block:: yaml
|
||||
Result
|
||||
******
|
||||
|
||||
salt-users:
|
||||
- cn: cn=johndoe,ou=users,dc=company,dc=tld
|
||||
displayName: John Doe
|
||||
givenName: John
|
||||
sn: Doe
|
||||
memberOf:
|
||||
- cn=it-admins,ou=groups,dc=company,dc=tld
|
||||
- cn=team01,ou=groups,dc=company
|
||||
- cn: cn=janedoe,ou=users,dc=company,dc=tld
|
||||
displayName: Jane Doe
|
||||
givenName: Jane
|
||||
sn: Doe
|
||||
memberOf:
|
||||
- cn=it-admins,ou=groups,dc=company,dc=tld
|
||||
- cn=team02,ou=groups,dc=company
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
List Mode
|
||||
---------
|
||||
|
||||
TODO: see also ``_result_to_dict()`` documentation
|
||||
{
|
||||
'salt-users': [
|
||||
{
|
||||
'cn': 'cn=johndoe,ou=users,dc=company,dc=tld',
|
||||
'displayName': 'John Doe'
|
||||
'givenName': 'John'
|
||||
'sn': 'Doe'
|
||||
'memberOf': [
|
||||
'cn=it-admins,ou=groups,dc=company,dc=tld',
|
||||
'cn=team01,ou=groups,dc=company'
|
||||
]
|
||||
},
|
||||
{
|
||||
'cn': 'cn=janedoe,ou=users,dc=company,dc=tld',
|
||||
'displayName': 'Jane Doe',
|
||||
'givenName': 'Jane',
|
||||
'sn': 'Doe',
|
||||
'memberOf': [
|
||||
'cn=it-admins,ou=groups,dc=company,dc=tld',
|
||||
'cn=team02,ou=groups,dc=company'
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
'''
|
||||
|
||||
# Import python libs
|
||||
|
@ -122,7 +132,7 @@ import salt.utils.data
|
|||
from salt.exceptions import SaltInvocationError
|
||||
|
||||
# Import third party libs
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
import jinja2
|
||||
try:
|
||||
import ldap # pylint: disable=W0611
|
||||
HAS_LDAP = True
|
||||
|
@ -148,10 +158,9 @@ def _render_template(config_file):
|
|||
Render config template, substituting grains where found.
|
||||
'''
|
||||
dirname, filename = os.path.split(config_file)
|
||||
env = Environment(loader=FileSystemLoader(dirname))
|
||||
env = jinja2.Environment(loader=jinja2.FileSystemLoader(dirname))
|
||||
template = env.get_template(filename)
|
||||
config = template.render(__grains__)
|
||||
return config
|
||||
return template.render(__grains__)
|
||||
|
||||
|
||||
def _config(name, conf):
|
||||
|
@ -185,18 +194,18 @@ def _result_to_dict(data, result, conf, source):
|
|||
For example, search result:
|
||||
|
||||
{ saltKeyValue': ['ntpserver=ntp.acme.local', 'foo=myfoo'],
|
||||
'saltList': ['vhost=www.acme.net', 'vhost=www.acme.local' }
|
||||
'saltList': ['vhost=www.acme.net', 'vhost=www.acme.local'] }
|
||||
|
||||
is written to the pillar data dictionary as:
|
||||
|
||||
{ 'ntpserver': 'ntp.acme.local', 'foo': 'myfoo',
|
||||
'vhost': ['www.acme.net', 'www.acme.local' }
|
||||
'vhost': ['www.acme.net', 'www.acme.local'] }
|
||||
'''
|
||||
attrs = _config('attrs', conf) or []
|
||||
lists = _config('lists', conf) or []
|
||||
# TODO:
|
||||
# deprecate the default 'mode: split' and make the more
|
||||
# straightforward 'mode: dict' the new default
|
||||
# straightforward 'mode: map' the new default
|
||||
mode = _config('mode', conf) or 'split'
|
||||
if mode == 'map':
|
||||
data[source] = []
|
||||
|
@ -272,22 +281,46 @@ def ext_pillar(minion_id, # pylint: disable=W0613
|
|||
'''
|
||||
Execute LDAP searches and return the aggregated data
|
||||
'''
|
||||
if os.path.isfile(config_file):
|
||||
import salt.utils.yaml
|
||||
try:
|
||||
#open(config_file, 'r') as raw_config:
|
||||
config = _render_template(config_file) or {}
|
||||
opts = salt.utils.yaml.safe_load(config) or {}
|
||||
opts['conf_file'] = config_file
|
||||
except Exception as err:
|
||||
import salt.log
|
||||
msg = 'Error parsing configuration file: {0} - {1}'.format(config_file, err)
|
||||
if salt.log.is_console_configured():
|
||||
log.warning(msg)
|
||||
else:
|
||||
print(msg)
|
||||
config_template = None
|
||||
try:
|
||||
config_template = _render_template(config_file)
|
||||
except jinja2.exceptions.TemplateNotFound:
|
||||
log.debug('pillar_ldap: missing configuration file %s', config_file)
|
||||
except Exception:
|
||||
log.debug('pillar_ldap: failed to render template for %s',
|
||||
config_file, exc_info=True)
|
||||
|
||||
if not config_template:
|
||||
# We don't have a config file
|
||||
return {}
|
||||
|
||||
import salt.utils.yaml
|
||||
try:
|
||||
opts = salt.utils.yaml.safe_load(config_template) or {}
|
||||
opts['conf_file'] = config_file
|
||||
except Exception as err:
|
||||
import salt.log
|
||||
msg = 'pillar_ldap: error parsing configuration file: {0} - {1}'
|
||||
if salt.log.is_console_configured():
|
||||
log.warning(msg.format(config_file, err))
|
||||
else:
|
||||
print(msg.format(config_file, err))
|
||||
return {}
|
||||
else:
|
||||
log.debug('Missing configuration file: %s', config_file)
|
||||
if not isinstance(opts, dict):
|
||||
log.warning(
|
||||
'pillar_ldap: %s is invalidly formatted, must be a YAML '
|
||||
'dictionary. See the documentation for more information.',
|
||||
config_file
|
||||
)
|
||||
return {}
|
||||
|
||||
if 'search_order' not in opts:
|
||||
log.warning(
|
||||
'pillar_ldap: search_order missing from configuration. See the '
|
||||
'documentation for more information.'
|
||||
)
|
||||
return {}
|
||||
|
||||
data = {}
|
||||
for source in opts['search_order']:
|
||||
|
|
|
@ -154,6 +154,16 @@ def __virtual__():
|
|||
return 'pkg.install' in __salt__
|
||||
|
||||
|
||||
def _warn_virtual(virtual):
|
||||
return [
|
||||
'The following package(s) are "virtual package" names: {0}. These '
|
||||
'will no longer be supported as of the Fluorine release. Please '
|
||||
'update your SLS file(s) to use the actual package name.'.format(
|
||||
', '.join(virtual)
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
def _get_comparison_spec(pkgver):
|
||||
'''
|
||||
Return a tuple containing the comparison operator and the version. If no
|
||||
|
@ -521,6 +531,11 @@ def _find_install_targets(name=None,
|
|||
was_refreshed = True
|
||||
refresh = False
|
||||
|
||||
def _get_virtual(desired):
|
||||
return [x for x in desired if cur_pkgs.get(x, []) == ['1']]
|
||||
|
||||
virtual_pkgs = []
|
||||
|
||||
if any((pkgs, sources)):
|
||||
if pkgs:
|
||||
desired = _repack_pkgs(pkgs, normalize=normalize)
|
||||
|
@ -538,6 +553,8 @@ def _find_install_targets(name=None,
|
|||
'comment': 'Invalidly formatted \'{0}\' parameter. See '
|
||||
'minion log.'.format('pkgs' if pkgs
|
||||
else 'sources')}
|
||||
|
||||
virtual_pkgs = _get_virtual(desired)
|
||||
to_unpurge = _find_unpurge_targets(desired)
|
||||
else:
|
||||
if salt.utils.platform.is_windows():
|
||||
|
@ -558,6 +575,7 @@ def _find_install_targets(name=None,
|
|||
else:
|
||||
desired = {name: version}
|
||||
|
||||
virtual_pkgs = _get_virtual(desired)
|
||||
to_unpurge = _find_unpurge_targets(desired)
|
||||
|
||||
# FreeBSD pkg supports `openjdk` and `java/openjdk7` package names
|
||||
|
@ -574,22 +592,28 @@ def _find_install_targets(name=None,
|
|||
and not reinstall \
|
||||
and not pkg_verify:
|
||||
# The package is installed and is the correct version
|
||||
return {'name': name,
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': 'Version {0} of package \'{1}\' is already '
|
||||
'installed'.format(version, name)}
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': 'Version {0} of package \'{1}\' is already '
|
||||
'installed'.format(version, name)}
|
||||
if virtual_pkgs:
|
||||
ret['warnings'] = _warn_virtual(virtual_pkgs)
|
||||
return ret
|
||||
|
||||
# if cver is not an empty string, the package is already installed
|
||||
elif cver and version is None \
|
||||
and not reinstall \
|
||||
and not pkg_verify:
|
||||
# The package is installed
|
||||
return {'name': name,
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': 'Package {0} is already '
|
||||
'installed'.format(name)}
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': 'Package {0} is already '
|
||||
'installed'.format(name)}
|
||||
if virtual_pkgs:
|
||||
ret['warnings'] = _warn_virtual(virtual_pkgs)
|
||||
return ret
|
||||
|
||||
version_spec = False
|
||||
if not sources:
|
||||
|
@ -627,10 +651,13 @@ def _find_install_targets(name=None,
|
|||
if comments:
|
||||
if len(comments) > 1:
|
||||
comments.append('')
|
||||
return {'name': name,
|
||||
'changes': {},
|
||||
'result': False,
|
||||
'comment': '. '.join(comments).rstrip()}
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
'result': False,
|
||||
'comment': '. '.join(comments).rstrip()}
|
||||
if virtual_pkgs:
|
||||
ret['warnings'] = _warn_virtual(virtual_pkgs)
|
||||
return ret
|
||||
|
||||
# Resolve the latest package version for any packages with "latest" in the
|
||||
# package version
|
||||
|
@ -765,10 +792,13 @@ def _find_install_targets(name=None,
|
|||
problems.append(failed_verify)
|
||||
|
||||
if problems:
|
||||
return {'name': name,
|
||||
'changes': {},
|
||||
'result': False,
|
||||
'comment': ' '.join(problems)}
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
'result': False,
|
||||
'comment': ' '.join(problems)}
|
||||
if virtual_pkgs:
|
||||
ret['warnings'] = _warn_virtual(virtual_pkgs)
|
||||
return ret
|
||||
|
||||
if not any((targets, to_unpurge, to_reinstall)):
|
||||
# All specified packages are installed
|
||||
|
@ -783,6 +813,8 @@ def _find_install_targets(name=None,
|
|||
'comment': msg}
|
||||
if warnings:
|
||||
ret.setdefault('warnings', []).extend(warnings)
|
||||
if virtual_pkgs:
|
||||
ret.setdefault('warnings', []).extend(_warn_virtual(virtual_pkgs))
|
||||
return ret
|
||||
|
||||
return (desired, targets, to_unpurge, to_reinstall, altered_files,
|
||||
|
@ -1759,6 +1791,25 @@ def installed(
|
|||
and x not in to_reinstall]
|
||||
failed = [x for x in failed if x in targets]
|
||||
|
||||
# Check for virtual packages in list of desired packages
|
||||
if not sources:
|
||||
try:
|
||||
virtual_pkgs = []
|
||||
for pkgname in [next(iter(x)) for x in pkgs] if pkgs else [name]:
|
||||
cver = new_pkgs.get(pkgname, [])
|
||||
if '1' in cver:
|
||||
virtual_pkgs.append(pkgname)
|
||||
if virtual_pkgs:
|
||||
warnings.extend(_warn_virtual(virtual_pkgs))
|
||||
except Exception:
|
||||
# This is just some temporary code to warn the user about using
|
||||
# virtual packages. Don't let an exception break the entire
|
||||
# state.
|
||||
log.debug(
|
||||
'Failed to detect virtual packages after running '
|
||||
'pkg.install', exc_info=True
|
||||
)
|
||||
|
||||
# If there was nothing unpurged, just set the changes dict to the contents
|
||||
# of changes['installed'].
|
||||
if not changes.get('purge_desired'):
|
||||
|
|
|
@ -295,7 +295,7 @@ class IPCClient(object):
|
|||
else:
|
||||
if hasattr(self, '_connecting_future'):
|
||||
# read previous future result to prevent the "unhandled future exception" error
|
||||
self._connecting_future.exc_info() # pylint: disable=E0203
|
||||
self._connecting_future.exception() # pylint: disable=E0203
|
||||
future = tornado.concurrent.Future()
|
||||
self._connecting_future = future
|
||||
self._connect(timeout=timeout)
|
||||
|
@ -752,9 +752,9 @@ class IPCMessageSubscriber(IPCClient):
|
|||
# '[ERROR ] Future exception was never retrieved:
|
||||
# StreamClosedError'
|
||||
if self._read_sync_future is not None:
|
||||
self._read_sync_future.exc_info()
|
||||
self._read_sync_future.exception()
|
||||
if self._read_stream_future is not None:
|
||||
self._read_stream_future.exc_info()
|
||||
self._read_stream_future.exception()
|
||||
|
||||
def __del__(self):
|
||||
if IPCMessageSubscriber in globals():
|
||||
|
|
|
@ -899,7 +899,7 @@ class SaltMessageClient(object):
|
|||
# This happens because the logic is always waiting to read
|
||||
# the next message and the associated read future is marked
|
||||
# 'StreamClosedError' when the stream is closed.
|
||||
self._read_until_future.exc_info()
|
||||
self._read_until_future.exception()
|
||||
if (not self._stream_return_future.done() and
|
||||
self.io_loop != tornado.ioloop.IOLoop.current(
|
||||
instance=False)):
|
||||
|
@ -1162,7 +1162,7 @@ class Subscriber(object):
|
|||
# This happens because the logic is always waiting to read
|
||||
# the next message and the associated read future is marked
|
||||
# 'StreamClosedError' when the stream is closed.
|
||||
self._read_until_future.exc_info()
|
||||
self._read_until_future.exception()
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
|
|
@ -914,7 +914,7 @@ class SaltNova(object):
|
|||
try:
|
||||
ret[item.name] = {
|
||||
'id': item.id,
|
||||
'status': 'Running'
|
||||
'state': 'Running'
|
||||
}
|
||||
except TypeError:
|
||||
pass
|
||||
|
|
|
@ -703,6 +703,7 @@ class Schedule(object):
|
|||
for global_key, value in six.iteritems(func_globals):
|
||||
self.functions[mod_name].__globals__[global_key] = value
|
||||
|
||||
self.functions.pack['__context__']['retcode'] = 0
|
||||
ret['return'] = self.functions[func](*args, **kwargs)
|
||||
|
||||
if not self.standalone:
|
||||
|
|
|
@ -36,8 +36,11 @@ if ZMQDefaultLoop is None:
|
|||
# Support for ZeroMQ 13.x
|
||||
if not hasattr(zmq.eventloop.ioloop, 'ZMQIOLoop'):
|
||||
zmq.eventloop.ioloop.ZMQIOLoop = zmq.eventloop.ioloop.IOLoop
|
||||
ZMQDefaultLoop = zmq.eventloop.ioloop.ZMQIOLoop
|
||||
if tornado.version_info < (5,):
|
||||
ZMQDefaultLoop = zmq.eventloop.ioloop.ZMQIOLoop
|
||||
except ImportError:
|
||||
ZMQDefaultLoop = None
|
||||
if ZMQDefaultLoop is None:
|
||||
ZMQDefaultLoop = tornado.ioloop.IOLoop
|
||||
|
||||
|
||||
|
@ -48,7 +51,8 @@ def install_zmq():
|
|||
:return:
|
||||
'''
|
||||
if zmq and ZMQ_VERSION_INFO[0] < 17:
|
||||
zmq.eventloop.ioloop.install()
|
||||
if tornado.version_info < (5,):
|
||||
zmq.eventloop.ioloop.install()
|
||||
|
||||
|
||||
def check_ipc_path_max_len(uri):
|
||||
|
|
|
@ -6,10 +6,11 @@ from __future__ import absolute_import, print_function, unicode_literals
|
|||
# Import Salt Testing libs
|
||||
from tests.support.case import ModuleCase
|
||||
from tests.support.helpers import destructiveTest
|
||||
from tests.support.unit import skipIf
|
||||
|
||||
# Import Salt libs
|
||||
import salt.utils.path
|
||||
|
||||
import salt.utils.platform
|
||||
|
||||
@destructiveTest
|
||||
class ServiceModuleTest(ModuleCase):
|
||||
|
@ -30,10 +31,32 @@ class ServiceModuleTest(ModuleCase):
|
|||
self.service_name = 'org.ntp.ntpd'
|
||||
if int(os_release.split('.')[1]) >= 13:
|
||||
self.service_name = 'com.apple.AirPlayXPCHelper'
|
||||
elif salt.utils.is_windows():
|
||||
self.service_name = 'Spooler'
|
||||
|
||||
if salt.utils.path.which(cmd_name) is None:
|
||||
self.pre_srv_status = self.run_function('service.status', [self.service_name])
|
||||
self.pre_srv_enabled = True if self.service_name in self.run_function('service.get_enabled') else False
|
||||
|
||||
if salt.utils.path.which(cmd_name) is None and not salt.utils.platform.is_windows():
|
||||
self.skipTest('{0} is not installed'.format(cmd_name))
|
||||
|
||||
def tearDown(self):
|
||||
post_srv_status = self.run_function('service.status', [self.service_name])
|
||||
post_srv_enabled = True if self.service_name in self.run_function('service.get_enabled') else False
|
||||
|
||||
if post_srv_status != self.pre_srv_status:
|
||||
if self.pre_srv_status:
|
||||
self.run_function('service.enable', [self.service_name])
|
||||
else:
|
||||
self.run_function('service.disable', [self.service_name])
|
||||
|
||||
if post_srv_enabled != self.pre_srv_enabled:
|
||||
if self.pre_srv_enabled:
|
||||
self.run_function('service.enable', [self.service_name])
|
||||
else:
|
||||
self.run_function('service.disable', [self.service_name])
|
||||
del self.service_name
|
||||
|
||||
def test_service_status_running(self):
|
||||
'''
|
||||
test service.status execution module
|
||||
|
@ -51,3 +74,37 @@ class ServiceModuleTest(ModuleCase):
|
|||
self.run_function('service.stop', [self.service_name])
|
||||
check_service = self.run_function('service.status', [self.service_name])
|
||||
self.assertFalse(check_service)
|
||||
|
||||
def test_service_restart(self):
|
||||
'''
|
||||
test service.restart
|
||||
'''
|
||||
self.assertTrue(self.run_function('service.restart', [self.service_name]))
|
||||
|
||||
def test_service_enable(self):
|
||||
'''
|
||||
test service.get_enabled and service.enable module
|
||||
'''
|
||||
# disable service before test
|
||||
self.assertTrue(self.run_function('service.disable', [self.service_name]))
|
||||
|
||||
self.assertTrue(self.run_function('service.enable', [self.service_name]))
|
||||
self.assertIn(self.service_name, self.run_function('service.get_enabled'))
|
||||
|
||||
def test_service_disable(self):
|
||||
'''
|
||||
test service.get_disabled and service.disable module
|
||||
'''
|
||||
# enable service before test
|
||||
self.assertTrue(self.run_function('service.enable', [self.service_name]))
|
||||
|
||||
self.assertTrue(self.run_function('service.disable', [self.service_name]))
|
||||
self.assertIn(self.service_name, self.run_function('service.get_disabled'))
|
||||
|
||||
@skipIf(not salt.utils.is_windows(), 'Windows Only Test')
|
||||
def test_service_get_service_name(self):
|
||||
'''
|
||||
test service.get_service_name
|
||||
'''
|
||||
ret = self.run_function('service.get_service_name')
|
||||
self.assertIn(self.service_name, ret.values())
|
||||
|
|
|
@ -42,6 +42,7 @@ class TestSaltAPIHandler(_SaltnadoIntegrationTestCase):
|
|||
application = self.build_tornado_app(urls)
|
||||
|
||||
application.event_listener = saltnado.EventListener({}, self.opts)
|
||||
self.application = application
|
||||
return application
|
||||
|
||||
def test_root(self):
|
||||
|
@ -78,8 +79,6 @@ class TestSaltAPIHandler(_SaltnadoIntegrationTestCase):
|
|||
self.assertEqual(response.code, 302)
|
||||
self.assertEqual(response.headers['Location'], '/login')
|
||||
|
||||
# Local client tests
|
||||
@skipIf(True, 'to be re-enabled when #23623 is merged')
|
||||
def test_simple_local_post(self):
|
||||
'''
|
||||
Test a basic API of /
|
||||
|
@ -97,7 +96,8 @@ class TestSaltAPIHandler(_SaltnadoIntegrationTestCase):
|
|||
request_timeout=30,
|
||||
)
|
||||
response_obj = salt.utils.json.loads(response.body)
|
||||
self.assertEqual(response_obj['return'], [{'minion': True, 'sub_minion': True}])
|
||||
self.assertEqual(len(response_obj['return']), 1)
|
||||
self.assertEqual(response_obj['return'][0], {'minion': True, 'sub_minion': True})
|
||||
|
||||
def test_simple_local_post_no_tgt(self):
|
||||
'''
|
||||
|
@ -118,8 +118,6 @@ class TestSaltAPIHandler(_SaltnadoIntegrationTestCase):
|
|||
response_obj = salt.utils.json.loads(response.body)
|
||||
self.assertEqual(response_obj['return'], ["No minions matched the target. No command was sent, no jid was assigned."])
|
||||
|
||||
# local client request body test
|
||||
@skipIf(True, 'Undetermined race condition in test. Temporarily disabled.')
|
||||
def test_simple_local_post_only_dictionary_request(self):
|
||||
'''
|
||||
Test a basic API of /
|
||||
|
@ -137,7 +135,8 @@ class TestSaltAPIHandler(_SaltnadoIntegrationTestCase):
|
|||
request_timeout=30,
|
||||
)
|
||||
response_obj = salt.utils.json.loads(response.body)
|
||||
self.assertEqual(response_obj['return'], [{'minion': True, 'sub_minion': True}])
|
||||
self.assertEqual(len(response_obj['return']), 1)
|
||||
self.assertEqual(response_obj['return'][0], {'minion': True, 'sub_minion': True})
|
||||
|
||||
def test_simple_local_post_invalid_request(self):
|
||||
'''
|
||||
|
@ -252,6 +251,28 @@ class TestSaltAPIHandler(_SaltnadoIntegrationTestCase):
|
|||
response_obj = salt.utils.json.loads(response.body)
|
||||
self.assertEqual(response_obj['return'], [{}])
|
||||
|
||||
def test_simple_local_post_only_dictionary_request_with_order_masters(self):
|
||||
'''
|
||||
Test a basic API of /
|
||||
'''
|
||||
low = {'client': 'local',
|
||||
'tgt': '*',
|
||||
'fun': 'test.ping',
|
||||
}
|
||||
response = self.fetch('/',
|
||||
method='POST',
|
||||
body=salt.utils.json.dumps(low),
|
||||
headers={'Content-Type': self.content_type_map['json'],
|
||||
saltnado.AUTH_TOKEN_HEADER: self.token['token']},
|
||||
connect_timeout=30,
|
||||
request_timeout=30,
|
||||
)
|
||||
response_obj = salt.utils.json.loads(response.body)
|
||||
|
||||
self.application.opts['order_masters'] = []
|
||||
self.application.opts['syndic_wait'] = 5
|
||||
self.assertEqual(response_obj['return'], [{'minion': True, 'sub_minion': True}])
|
||||
|
||||
# runner tests
|
||||
def test_simple_local_runner_post(self):
|
||||
low = [{'client': 'runner',
|
||||
|
|
|
@ -10,6 +10,7 @@ from tests.support.unit import skipIf, TestCase
|
|||
from tests.support.mock import NO_MOCK, NO_MOCK_REASON, MagicMock, patch
|
||||
|
||||
# Import salt libs
|
||||
from salt.ext import six
|
||||
import salt.utils.platform
|
||||
import salt.modules.pip as pip
|
||||
from salt.exceptions import CommandExecutionError
|
||||
|
@ -300,6 +301,8 @@ class PipTestCase(TestCase, LoaderModuleMockMixin):
|
|||
if salt.utils.platform.is_windows():
|
||||
venv_path = 'c:\\test_env'
|
||||
bin_path = os.path.join(venv_path, 'Scripts', 'pip.exe')
|
||||
if six.PY2:
|
||||
bin_path = bin_path.encode('string-escape')
|
||||
else:
|
||||
venv_path = '/test_env'
|
||||
bin_path = os.path.join(venv_path, 'bin', 'pip')
|
||||
|
|
|
@ -21,6 +21,7 @@ integration.modules.test_ntp
|
|||
integration.modules.test_pillar
|
||||
integration.modules.test_pkg
|
||||
integration.modules.test_publish
|
||||
integration.modules.test_service
|
||||
integration.modules.test_state
|
||||
integration.modules.test_status
|
||||
integration.modules.test_sysmod
|
||||
|
|
Loading…
Add table
Reference in a new issue