mirror of
https://github.com/valitydev/salt.git
synced 2024-11-08 01:18:58 +00:00
Merge pull request #32107 from rallytime/merge-develop
[develop] Merge forward from 2016.3 to develop
This commit is contained in:
commit
c03e8757e3
@ -124,14 +124,6 @@ MOCK_MODULES = [
|
||||
'salt.ext.six.moves.winreg',
|
||||
'win32security',
|
||||
'ntsecuritycon',
|
||||
'jnpr',
|
||||
'jnpr.junos',
|
||||
'jnpr.junos.device',
|
||||
'lxml',
|
||||
'napalm',
|
||||
'json',
|
||||
'hashlib',
|
||||
'salt.utils.virtualbox',
|
||||
]
|
||||
|
||||
for mod_name in MOCK_MODULES:
|
||||
|
@ -392,7 +392,7 @@ def expand_ldap_entries(entries, opts=None):
|
||||
This function only gets called if auth.ldap.activedirectory = True
|
||||
'''
|
||||
bind = _bind_for_search(opts=opts)
|
||||
acl_tree = {}
|
||||
acl_tree = []
|
||||
for user_or_group_dict in entries:
|
||||
for minion_or_ou, matchers in six.iteritems(user_or_group_dict):
|
||||
permissions = matchers
|
||||
@ -407,15 +407,21 @@ def expand_ldap_entries(entries, opts=None):
|
||||
search_string,
|
||||
['cn'])
|
||||
for ldap_match in search_results:
|
||||
minion_id = ldap_match[1]['cn'][0].lower()
|
||||
retrieved_minion_ids.append(minion_id)
|
||||
try:
|
||||
minion_id = ldap_match[1]['cn'][0].lower()
|
||||
retrieved_minion_ids.append(minion_id)
|
||||
except TypeError:
|
||||
# TypeError here just means that one of the returned
|
||||
# entries didn't match the format we expected
|
||||
# from LDAP.
|
||||
pass
|
||||
|
||||
for minion_id in retrieved_minion_ids:
|
||||
acl_tree[minion_id] = permissions
|
||||
acl_tree.append({minion_id: permissions})
|
||||
except ldap.NO_SUCH_OBJECT:
|
||||
pass
|
||||
else:
|
||||
acl_tree[minion_or_ou] = matchers
|
||||
acl_tree.append({minion_or_ou: matchers})
|
||||
|
||||
log.trace('expand_ldap_entries: {0}'.format(acl_tree))
|
||||
return acl_tree
|
||||
|
@ -646,6 +646,46 @@ def avail_sizes(call=None):
|
||||
'ram': '60 GiB'
|
||||
}
|
||||
},
|
||||
'Dense Storage': {
|
||||
'd2.xlarge': {
|
||||
'id': 'd2.xlarge',
|
||||
'cores': '4',
|
||||
'disk': '6 TiB (3 x 2 TiB hard disk drives)',
|
||||
'ram': '30.5 GiB'
|
||||
},
|
||||
'd2.2xlarge': {
|
||||
'id': 'd2.2xlarge',
|
||||
'cores': '8',
|
||||
'disk': '12 TiB (6 x 2 TiB hard disk drives)',
|
||||
'ram': '61 GiB'
|
||||
},
|
||||
'd2.4xlarge': {
|
||||
'id': 'd2.4xlarge',
|
||||
'cores': '16',
|
||||
'disk': '24 TiB (12 x 2 TiB hard disk drives)',
|
||||
'ram': '122 GiB'
|
||||
},
|
||||
'd2.8xlarge': {
|
||||
'id': 'd2.8xlarge',
|
||||
'cores': '36',
|
||||
'disk': '24 TiB (24 x 2 TiB hard disk drives)',
|
||||
'ram': '244 GiB'
|
||||
},
|
||||
},
|
||||
'GPU': {
|
||||
'g2.2xlarge': {
|
||||
'id': 'g2.2xlarge',
|
||||
'cores': '8',
|
||||
'disk': '60 GiB (1 x 60 GiB SSD)',
|
||||
'ram': '15 GiB'
|
||||
},
|
||||
'g2.8xlarge': {
|
||||
'id': 'g2.8xlarge',
|
||||
'cores': '32',
|
||||
'disk': '240 GiB (2 x 120 GiB SSD)',
|
||||
'ram': '60 GiB'
|
||||
},
|
||||
},
|
||||
'High I/O': {
|
||||
'i2.xlarge': {
|
||||
'id': 'i2.xlarge',
|
||||
|
@ -1969,7 +1969,6 @@ class ClearFuncs(object):
|
||||
# Add any add'l permissions allowed by group membership
|
||||
if group_auth_match:
|
||||
auth_list = self.ckminions.fill_auth_list_from_groups(eauth_config, token['groups'], auth_list)
|
||||
|
||||
auth_list = self.ckminions.fill_auth_list_from_ou(auth_list, self.opts)
|
||||
log.trace("Compiled auth_list: {0}".format(auth_list))
|
||||
|
||||
@ -2066,7 +2065,8 @@ class ClearFuncs(object):
|
||||
self.opts['external_auth'][extra['eauth']],
|
||||
groups,
|
||||
auth_list)
|
||||
auth_list = self.ckminions.fill_auth_list_from_ou(auth_list, self.opts)
|
||||
if extra['eauth'] == 'ldap':
|
||||
auth_list = self.ckminions.fill_auth_list_from_ou(auth_list, self.opts)
|
||||
good = self.ckminions.auth_check(
|
||||
auth_list,
|
||||
clear_load['fun'],
|
||||
|
@ -194,22 +194,12 @@ def build_rule(table='filter', chain=None, command=None, position='', full=None,
|
||||
rule.append('{0}-o {1}'.format(maybe_add_negation('of'), kwargs['of']))
|
||||
del kwargs['of']
|
||||
|
||||
if 'protocol' in kwargs:
|
||||
proto = kwargs['protocol']
|
||||
proto_negation = maybe_add_negation('protocol')
|
||||
del kwargs['protocol']
|
||||
elif 'proto' in kwargs:
|
||||
proto = kwargs['proto']
|
||||
proto_negation = maybe_add_negation('proto')
|
||||
del kwargs['proto']
|
||||
|
||||
if proto:
|
||||
if proto.startswith('!') or proto.startswith('not'):
|
||||
proto = re.sub(bang_not_pat, '', proto)
|
||||
rule += '! '
|
||||
|
||||
rule.append('{0}-p {1}'.format(proto_negation, proto))
|
||||
proto = True
|
||||
for proto_arg in ('protocol', 'proto'):
|
||||
if proto_arg in kwargs:
|
||||
if not proto:
|
||||
rule.append('{0}-p {1}'.format(maybe_add_negation(proto_arg), kwargs[proto_arg]))
|
||||
proto = True
|
||||
del kwargs[proto_arg]
|
||||
|
||||
if 'match' in kwargs:
|
||||
match_value = kwargs['match']
|
||||
|
@ -134,7 +134,7 @@ def list_users(runas=None):
|
||||
python_shell=False)
|
||||
|
||||
# func to get tags from string such as "[admin, monitoring]"
|
||||
func = lambda string: [tag.strip() for tag in string[1:-1].split(' ')]
|
||||
func = lambda string: set([x.strip() for x in string[1:-1].split(',')])
|
||||
return _output_to_dict(res, func)
|
||||
|
||||
|
||||
|
@ -44,9 +44,10 @@ class daclConstants(object):
|
||||
# in ntsecuritycon has the extra bits 0x200 enabled.
|
||||
# Note that you when you set this permission what you'll generally get back is it
|
||||
# ORed with 0x200 (SI_NO_ACL_PROTECT), which is what ntsecuritycon incorrectly defines.
|
||||
FILE_ALL_ACCESS = (ntsecuritycon.STANDARD_RIGHTS_REQUIRED | ntsecuritycon.SYNCHRONIZE | 0x1ff)
|
||||
|
||||
def __init__(self):
|
||||
self.FILE_ALL_ACCESS = (ntsecuritycon.STANDARD_RIGHTS_REQUIRED | ntsecuritycon.SYNCHRONIZE | 0x1ff)
|
||||
|
||||
self.hkeys_security = {
|
||||
'HKEY_LOCAL_MACHINE': 'MACHINE',
|
||||
'HKEY_USERS': 'USERS',
|
||||
@ -88,7 +89,7 @@ class daclConstants(object):
|
||||
ntsecuritycon.DELETE,
|
||||
'TEXT': 'modify'},
|
||||
'FULLCONTROL': {
|
||||
'BITS': daclConstants.FILE_ALL_ACCESS,
|
||||
'BITS': self.FILE_ALL_ACCESS,
|
||||
'TEXT': 'full control'}
|
||||
}
|
||||
}
|
||||
@ -368,7 +369,7 @@ def add_ace(path, objectType, user, permission, acetype, propagation):
|
||||
path: path to the object (i.e. c:\\temp\\file, HKEY_LOCAL_MACHINE\\SOFTWARE\\KEY, etc)
|
||||
user: user to add
|
||||
permission: permissions for the user
|
||||
acetypes: either allow/deny for each user/permission (ALLOW, DENY)
|
||||
acetype: either allow/deny for each user/permission (ALLOW, DENY)
|
||||
propagation: how the ACE applies to children for Registry Keys and Directories(KEY, KEY&SUBKEYS, SUBKEYS)
|
||||
|
||||
CLI Example:
|
||||
|
@ -87,6 +87,30 @@ def _format_comments(comments):
|
||||
return ret
|
||||
|
||||
|
||||
def _map_port_from_yaml_to_docker(port):
|
||||
'''
|
||||
docker-py interface is not very nice:
|
||||
While for ``port_bindings`` they support:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
'8888/tcp'
|
||||
|
||||
For ``ports``, it has to be transformed into:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
(8888, 'tcp')
|
||||
|
||||
'''
|
||||
if isinstance(port, six.string_types):
|
||||
port, sep, protocol = port.partition('/')
|
||||
if protocol:
|
||||
return int(port), protocol
|
||||
return int(port)
|
||||
return port
|
||||
|
||||
|
||||
def _prep_input(kwargs):
|
||||
'''
|
||||
Repack (if necessary) data that should be in a dict but is easier to
|
||||
@ -197,7 +221,7 @@ def _compare(actual, create_kwargs, defaults_from_image):
|
||||
for port_def in data:
|
||||
if isinstance(port_def, six.integer_types):
|
||||
port_def = str(port_def)
|
||||
if isinstance(port_def, tuple):
|
||||
if isinstance(port_def, (tuple, list)):
|
||||
desired_ports.append('{0}/{1}'.format(*port_def))
|
||||
elif '/' not in port_def:
|
||||
desired_ports.append('{0}/tcp'.format(port_def))
|
||||
@ -1569,7 +1593,8 @@ def running(name,
|
||||
if create_kwargs.get('port_bindings') is not None:
|
||||
# Be smart and try to provide `ports` argument derived from
|
||||
# the "port_bindings" configuration.
|
||||
auto_ports = list(create_kwargs['port_bindings'])
|
||||
auto_ports = [_map_port_from_yaml_to_docker(port)
|
||||
for port in create_kwargs['port_bindings']]
|
||||
actual_ports = create_kwargs.setdefault('ports', [])
|
||||
actual_ports.extend([p for p in auto_ports if
|
||||
p not in actual_ports])
|
||||
|
@ -73,21 +73,14 @@ def _check_perms_changes(name, newperms, runas=None, existing=None):
|
||||
return perm_need_change
|
||||
|
||||
|
||||
def _check_tags_changes(name, new_tags, runas=None):
|
||||
def _get_current_tags(name, runas=None):
|
||||
'''
|
||||
Whether Rabbitmq user's tags need to be changed
|
||||
'''
|
||||
if new_tags:
|
||||
if isinstance(new_tags, str):
|
||||
new_tags = new_tags.split()
|
||||
try:
|
||||
old_tags = __salt__['rabbitmq.list_users'](runas=runas)[name]
|
||||
users = set(old_tags) - set(new_tags)
|
||||
except CommandExecutionError as err:
|
||||
log.error('Error: {0}'.format(err))
|
||||
return []
|
||||
return list(users)
|
||||
else:
|
||||
try:
|
||||
return list(__salt__['rabbitmq.list_users'](runas=runas)[name])
|
||||
except CommandExecutionError as err:
|
||||
log.error('Error: {0}'.format(err))
|
||||
return []
|
||||
|
||||
|
||||
@ -180,17 +173,22 @@ def present(name,
|
||||
{'old': 'Removed password.',
|
||||
'new': ''}})
|
||||
|
||||
new_tags = _check_tags_changes(name, tags, runas=runas)
|
||||
if new_tags:
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['rabbitmq.set_user_tags'](name, tags, runas=runas)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
ret['changes'].update({'tags':
|
||||
{'old': tags,
|
||||
'new': list(new_tags)}})
|
||||
if tags is not None:
|
||||
current_tags = _get_current_tags(name, runas=runas)
|
||||
if isinstance(tags, str):
|
||||
tags = tags.split()
|
||||
# Diff the tags sets. Symmetric difference operator ^ will give us
|
||||
# any element in one set, but not both
|
||||
if set(tags) ^ set(current_tags):
|
||||
if not __opts__['test']:
|
||||
try:
|
||||
__salt__['rabbitmq.set_user_tags'](name, tags, runas=runas)
|
||||
except CommandExecutionError as err:
|
||||
ret['comment'] = 'Error: {0}'.format(err)
|
||||
return ret
|
||||
ret['changes'].update({'tags':
|
||||
{'old': current_tags,
|
||||
'new': tags}})
|
||||
try:
|
||||
existing_perms = __salt__['rabbitmq.list_user_permissions'](name, runas=runas)
|
||||
except CommandExecutionError as err:
|
||||
|
@ -593,7 +593,7 @@ def query(url,
|
||||
else:
|
||||
text = True
|
||||
|
||||
if decode_out and os.path.exists(decode_out):
|
||||
if decode_out:
|
||||
with salt.utils.fopen(decode_out, 'w') as dof:
|
||||
dof.write(result_text)
|
||||
|
||||
|
@ -698,6 +698,192 @@ class CkMinions(object):
|
||||
fun,
|
||||
form)
|
||||
|
||||
def auth_check_expanded(self,
|
||||
auth_list,
|
||||
funs,
|
||||
args,
|
||||
tgt,
|
||||
tgt_type='glob',
|
||||
groups=None,
|
||||
publish_validate=False):
|
||||
|
||||
# Here's my thinking
|
||||
# 1. Retrieve anticipated targeted minions
|
||||
# 2. Iterate through each entry in the auth_list
|
||||
# 3. If it is a minion_id, check to see if any targeted minions match.
|
||||
# If there is a match, check to make sure funs are permitted
|
||||
# (if it's not a match we don't care about this auth entry and can
|
||||
# move on)
|
||||
# a. If funs are permitted, Add this minion_id to a new set of allowed minion_ids
|
||||
# If funs are NOT permitted, can short-circuit and return FALSE
|
||||
# b. At the end of the auth_list loop, make sure all targeted IDs
|
||||
# are in the set of allowed minion_ids. If not, return FALSE
|
||||
# 4. If it is a target (glob, pillar, etc), retrieve matching minions
|
||||
# and make sure that ALL targeted minions are in the set.
|
||||
# then check to see if the funs are permitted
|
||||
# a. If ALL targeted minions are not in the set, then return FALSE
|
||||
# b. If the desired fun doesn't mass the auth check with any
|
||||
# auth_entry's fun, then return FALSE
|
||||
|
||||
# NOTE we are not going to try to allow functions to run on partial
|
||||
# sets of minions. If a user targets a group of minions and does not
|
||||
# have access to run a job on ALL of these minions then the job will
|
||||
# fail with 'Eauth Failed'.
|
||||
|
||||
# The recommended workflow in that case will be for the user to narrow
|
||||
# his target.
|
||||
|
||||
# This should cover adding the AD LDAP lookup functionality while
|
||||
# preserving the existing auth behavior.
|
||||
|
||||
# Recommend we config-get this behind an entry called
|
||||
# auth.enable_expanded_auth_matching
|
||||
# and default to False
|
||||
v_tgt_type = tgt_type
|
||||
if tgt_type.lower() in ('pillar', 'pillar_pcre'):
|
||||
v_tgt_type = 'pillar_exact'
|
||||
elif tgt_type.lower() == 'compound':
|
||||
v_tgt_type = 'compound_pillar_exact'
|
||||
v_minions = set(self.check_minions(tgt, v_tgt_type))
|
||||
minions = set(self.check_minions(tgt, tgt_type))
|
||||
mismatch = bool(minions.difference(v_minions))
|
||||
# If the non-exact match gets more minions than the exact match
|
||||
# then pillar globbing or PCRE is being used, and we have a
|
||||
# problem
|
||||
if publish_validate:
|
||||
if mismatch:
|
||||
return False
|
||||
# compound commands will come in a list so treat everything as a list
|
||||
if not isinstance(funs, list):
|
||||
funs = [funs]
|
||||
args = [args]
|
||||
|
||||
# Take the auth list and get all the minion names inside it
|
||||
allowed_minions_from_auth_list = set()
|
||||
|
||||
auth_dictionary = {}
|
||||
# Make a set, so we are guaranteed to have only one of each minion
|
||||
# Also iterate through the entire auth_list and create a dictionary
|
||||
# so it's easy to look up what functions are permitted
|
||||
for auth_list_entry in auth_list:
|
||||
if isinstance(auth_list_entry, six.string_types):
|
||||
for fun in funs:
|
||||
# represents toplevel auth entry is a function.
|
||||
# so this fn is permitted by all minions
|
||||
if self.match_check(auth_list_entry, fun):
|
||||
return True
|
||||
if isinstance(auth_list_entry, dict):
|
||||
if len(auth_list_entry) != 1:
|
||||
log.info('Malformed ACL: {0}'.format(auth_list_entry))
|
||||
continue
|
||||
allowed_minions_from_auth_list.update(set(auth_list_entry.keys()))
|
||||
for key in auth_list_entry.keys():
|
||||
if key in auth_dictionary:
|
||||
auth_dictionary[key].concat(auth_list_entry[key])
|
||||
else:
|
||||
auth_dictionary[key] = auth_list_entry[key]
|
||||
|
||||
# 'minions' here are all the names of minions matched by the target
|
||||
# if we take out all the allowed minions, and there are any left, then
|
||||
# the target includes minions that are not allowed by eauth
|
||||
# so we can give up here.
|
||||
if len(minions - allowed_minions_from_auth_list) > 0:
|
||||
return False
|
||||
|
||||
try:
|
||||
log.trace('######################################')
|
||||
log.trace(funs)
|
||||
for minion in minions:
|
||||
results = []
|
||||
for num, fun in enumerate(auth_dictionary[minion]):
|
||||
results.append(self.match_check(fun, funs))
|
||||
if not any(results):
|
||||
return False
|
||||
return True
|
||||
|
||||
# for ind in auth_list:
|
||||
# if isinstance(ind, six.string_types):
|
||||
# # Allowed for all minions
|
||||
# if self.match_check(ind, fun):
|
||||
# return True
|
||||
# elif isinstance(ind, dict):
|
||||
# if len(ind) != 1:
|
||||
# # Invalid argument
|
||||
# continue
|
||||
# valid = next(six.iterkeys(ind))
|
||||
# # Check if minions are allowed
|
||||
# # if self.validate_tgt(
|
||||
# # valid,
|
||||
# # tgt,
|
||||
# # tgt_type):
|
||||
# # Minions are allowed, verify function in allowed list
|
||||
# if isinstance(ind[valid], six.string_types):
|
||||
# if self.match_check(ind[valid], fun):
|
||||
# return True
|
||||
# elif isinstance(ind[valid], list):
|
||||
# for cond in ind[valid]:
|
||||
# # Function name match
|
||||
# if isinstance(cond, six.string_types):
|
||||
# if self.match_check(cond, fun):
|
||||
# return True
|
||||
# # Function and args match
|
||||
# elif isinstance(cond, dict):
|
||||
# if len(cond) != 1:
|
||||
# # Invalid argument
|
||||
# continue
|
||||
# fcond = next(six.iterkeys(cond))
|
||||
# # cond: {
|
||||
# # 'mod.func': {
|
||||
# # 'args': [
|
||||
# # 'one.*', 'two\\|three'],
|
||||
# # 'kwargs': {
|
||||
# # 'functioin': 'teach\\|feed',
|
||||
# # 'user': 'mother\\|father'
|
||||
# # }
|
||||
# # }
|
||||
# # }
|
||||
# if self.match_check(fcond, fun): # check key that is function name match
|
||||
# acond = cond[fcond]
|
||||
# if not isinstance(acond, dict):
|
||||
# # Invalid argument
|
||||
# continue
|
||||
# # whitelist args, kwargs
|
||||
# arg_list = args[num]
|
||||
# cond_args = acond.get('args', [])
|
||||
# good = True
|
||||
# for i, cond_arg in enumerate(cond_args):
|
||||
# if len(arg_list) <= i:
|
||||
# good = False
|
||||
# break
|
||||
# if cond_arg is None: # None == '.*' i.e. allow any
|
||||
# continue
|
||||
# if not self.match_check(cond_arg, arg_list[i]):
|
||||
# good = False
|
||||
# break
|
||||
# if not good:
|
||||
# continue
|
||||
# # Check kwargs
|
||||
# cond_kwargs = acond.get('kwargs', {})
|
||||
# arg_kwargs = {}
|
||||
# for a in arg_list:
|
||||
# if isinstance(a, dict) and '__kwarg__' in a:
|
||||
# arg_kwargs = a
|
||||
# break
|
||||
# for k, v in six.iteritems(cond_kwargs):
|
||||
# if k not in arg_kwargs:
|
||||
# good = False
|
||||
# break
|
||||
# if v is None: # None == '.*' i.e. allow any
|
||||
# continue
|
||||
# if not self.match_check(v, arg_kwargs[k]):
|
||||
# good = False
|
||||
# break
|
||||
# if good:
|
||||
# return True
|
||||
except TypeError:
|
||||
return False
|
||||
return False
|
||||
|
||||
def auth_check(self,
|
||||
auth_list,
|
||||
funs,
|
||||
@ -743,9 +929,9 @@ class CkMinions(object):
|
||||
valid = next(six.iterkeys(ind))
|
||||
# Check if minions are allowed
|
||||
if self.validate_tgt(
|
||||
valid,
|
||||
tgt,
|
||||
tgt_type):
|
||||
valid,
|
||||
tgt,
|
||||
tgt_type):
|
||||
# Minions are allowed, verify function in allowed list
|
||||
if isinstance(ind[valid], six.string_types):
|
||||
if self.match_check(ind[valid], fun):
|
||||
@ -772,7 +958,8 @@ class CkMinions(object):
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
if self.match_check(fcond, fun): # check key that is function name match
|
||||
if self.match_check(fcond,
|
||||
fun): # check key that is function name match
|
||||
acond = cond[fcond]
|
||||
if not isinstance(acond, dict):
|
||||
# Invalid argument
|
||||
@ -787,7 +974,8 @@ class CkMinions(object):
|
||||
break
|
||||
if cond_arg is None: # None == '.*' i.e. allow any
|
||||
continue
|
||||
if not self.match_check(cond_arg, arg_list[i]):
|
||||
if not self.match_check(cond_arg,
|
||||
arg_list[i]):
|
||||
good = False
|
||||
break
|
||||
if not good:
|
||||
@ -796,7 +984,8 @@ class CkMinions(object):
|
||||
cond_kwargs = acond.get('kwargs', {})
|
||||
arg_kwargs = {}
|
||||
for a in arg_list:
|
||||
if isinstance(a, dict) and '__kwarg__' in a:
|
||||
if isinstance(a,
|
||||
dict) and '__kwarg__' in a:
|
||||
arg_kwargs = a
|
||||
break
|
||||
for k, v in six.iteritems(cond_kwargs):
|
||||
@ -805,7 +994,8 @@ class CkMinions(object):
|
||||
break
|
||||
if v is None: # None == '.*' i.e. allow any
|
||||
continue
|
||||
if not self.match_check(v, arg_kwargs[k]):
|
||||
if not self.match_check(v,
|
||||
arg_kwargs[k]):
|
||||
good = False
|
||||
break
|
||||
if good:
|
||||
|
@ -40,7 +40,7 @@ class RabbitmqTestCase(TestCase):
|
||||
'''
|
||||
mock_run = MagicMock(return_value='Listing users ...\nguest\t[administrator]\n')
|
||||
with patch.dict(rabbitmq.__salt__, {'cmd.run': mock_run}):
|
||||
self.assertDictEqual(rabbitmq.list_users(), {'guest': ['administrator']})
|
||||
self.assertDictEqual(rabbitmq.list_users(), {'guest': set(['administrator'])})
|
||||
|
||||
# 'list_users_with_warning' function tests: 1
|
||||
|
||||
@ -55,7 +55,7 @@ class RabbitmqTestCase(TestCase):
|
||||
])
|
||||
mock_run = MagicMock(return_value=rtn_val)
|
||||
with patch.dict(rabbitmq.__salt__, {'cmd.run': mock_run}):
|
||||
self.assertDictEqual(rabbitmq.list_users(), {'guest': ['administrator']})
|
||||
self.assertDictEqual(rabbitmq.list_users(), {'guest': set(['administrator'])})
|
||||
|
||||
# 'list_vhosts' function tests: 1
|
||||
|
||||
|
@ -200,6 +200,64 @@ class DockerngTestCase(TestCase):
|
||||
client_timeout=60)
|
||||
dockerng_start.assert_called_with('cont')
|
||||
|
||||
def test_running_with_udp_bindings(self):
|
||||
'''
|
||||
Check that `ports` contains ports defined from `port_bindings` with
|
||||
protocol declaration passed as tuple. As stated by docker-py
|
||||
documentation
|
||||
|
||||
https://docker-py.readthedocs.org/en/latest/port-bindings/
|
||||
|
||||
In sls:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
container:
|
||||
dockerng.running:
|
||||
- port_bindings:
|
||||
- '9090:9797/udp'
|
||||
|
||||
is equivalent of:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
container:
|
||||
dockerng.running:
|
||||
- ports:
|
||||
- 9797/udp
|
||||
- port_bindings:
|
||||
- '9090:9797/udp'
|
||||
'''
|
||||
dockerng_create = Mock()
|
||||
dockerng_start = Mock()
|
||||
dockerng_inspect_image = Mock(return_value={
|
||||
'Id': 'abcd',
|
||||
'Config': {'ExposedPorts': {}}
|
||||
})
|
||||
__salt__ = {'dockerng.list_containers': MagicMock(),
|
||||
'dockerng.list_tags': MagicMock(),
|
||||
'dockerng.pull': MagicMock(),
|
||||
'dockerng.state': MagicMock(),
|
||||
'dockerng.inspect_image': dockerng_inspect_image,
|
||||
'dockerng.create': dockerng_create,
|
||||
'dockerng.start': dockerng_start,
|
||||
}
|
||||
with patch.dict(dockerng_state.__dict__,
|
||||
{'__salt__': __salt__}):
|
||||
dockerng_state.running(
|
||||
'cont',
|
||||
image='image:latest',
|
||||
port_bindings=['9090:9797/udp'])
|
||||
dockerng_create.assert_called_with(
|
||||
'image:latest',
|
||||
validate_input=False,
|
||||
name='cont',
|
||||
ports=[(9797, 'udp')],
|
||||
port_bindings={'9797/udp': [9090]},
|
||||
validate_ip_addrs=False,
|
||||
client_timeout=60)
|
||||
dockerng_start.assert_called_with('cont')
|
||||
|
||||
def test_running_compare_images_by_id(self):
|
||||
'''
|
||||
Make sure the container is running
|
||||
|
Loading…
Reference in New Issue
Block a user