Merge branch 'master' into master.v3000-conda

This commit is contained in:
Daniel Wozniak 2020-03-09 18:42:20 -07:00 committed by GitHub
commit 566c03b786
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 396 additions and 168 deletions

View file

@ -592,6 +592,19 @@ Enhancements to chroot
:py:func:`highstate<salt.modules.chroot.highstate>` that allow executing
states in sls files or running apply/highstate inside of a chroot.
Minion-side ACL
---------------
Salt has had master-side ACL for the salt mine for some time, where the master
configuration contained `mine_get` that specified which minions could request
which functions. However, now you can specify which minions can access a function
in the salt mine function definition itself (or when calling :py:func:`mine.send <salt.modules.mine.send>`).
This targeting works the same as the generic minion targeting as specified
:ref:`here <targeting>`. The parameters used are ``allow_tgt`` and ``allow_tgt_type``.
See also :ref:`the documentation of the Salt Mine <mine_minion-side-acl>`. Please
note that if you want to use this new feature both your minion and masters will need
to be on atleast version 3000.
Deprecations
============

View file

@ -16,14 +16,3 @@ also support the syntax used in :py:mod:`module.run <salt.states.module.run>`.
The old syntax for the mine_function - as a dict, or as a list with dicts that
contain more than exactly one key - is still supported but discouraged in favor
of the more uniform syntax of module.run.
Minion-side ACL
---------------
Salt has had master-side ACL for the salt mine for some time, where the master
configuration contained `mine_get` that specified which minions could request
which functions. However, now you can specify which minions can access a function
in the salt mine function definition itself (or when calling :py:func:`mine.send <salt.modules.mine.send>`).
This targeting works the same as the generic minion targeting as specified
:ref:`here <targeting>`. The parameters used are ``allow_tgt`` and ``allow_tgt_type``.
See also :ref:`the documentation of the Salt Mine <mine_minion-side-acl>`.

View file

@ -12,7 +12,7 @@ import importlib
class TornadoImporter(object):
def find_module(self, module_name, package_path):
def find_module(self, module_name, package_path=None):
if module_name.startswith('tornado'):
return self
return None

View file

@ -617,14 +617,17 @@ class RemoteFuncs(object):
if 'allow_tgt' in mine_entry:
# Only determine allowed targets if any have been specified.
# This prevents having to add a list of all minions as allowed targets.
get_minion = checker.check_minions(
mine_entry['allow_tgt'],
mine_entry.get('allow_tgt_type', 'glob'))['minions']
# the minion in allow_tgt does not exist
if not get_minion:
continue
salt.utils.dictupdate.set_dict_key_value(
minion_side_acl,
'{}:{}'.format(minion, function),
checker.check_minions(
mine_entry['allow_tgt'],
mine_entry.get('allow_tgt_type', 'glob')
)['minions']
)
get_minion
)
if salt.utils.mine.minion_side_acl_denied(minion_side_acl, minion, function, load['id']):
continue
if _ret_dict:

View file

@ -27,6 +27,7 @@ from salt.ext import six
from salt._compat import ipaddress
from salt.utils.network import parse_host_port
from salt.ext.six.moves import range
from salt.template import SLS_ENCODING
from salt.utils.zeromq import zmq, ZMQDefaultLoop, install_zmq, ZMQ_VERSION_INFO
import salt.transport.client
import salt.defaults.exitcodes
@ -865,11 +866,11 @@ class SMinion(MinionBase):
penv = 'base'
cache_top = {penv: {self.opts['id']: ['cache']}}
with salt.utils.files.fopen(ptop, 'wb') as fp_:
salt.utils.yaml.safe_dump(cache_top, fp_)
salt.utils.yaml.safe_dump(cache_top, fp_, encoding=SLS_ENCODING)
os.chmod(ptop, 0o600)
cache_sls = os.path.join(pdir, 'cache.sls')
with salt.utils.files.fopen(cache_sls, 'wb') as fp_:
salt.utils.yaml.safe_dump(self.opts['pillar'], fp_)
salt.utils.yaml.safe_dump(self.opts['pillar'], fp_, encoding=SLS_ENCODING)
os.chmod(cache_sls, 0o600)

View file

@ -194,10 +194,13 @@ def update(clear=False, mine_functions=None):
log.error('Function %s in mine.update failed to execute', function_name or function_alias)
log.debug('Error: %s', trace)
continue
mine_data[function_alias] = salt.utils.mine.wrap_acl_structure(
res,
**minion_acl
)
if minion_acl.get('allow_tgt'):
mine_data[function_alias] = salt.utils.mine.wrap_acl_structure(
res,
**minion_acl
)
else:
mine_data[function_alias] = res
return _mine_store(mine_data, clear)
@ -213,9 +216,13 @@ def send(name, *args, **kwargs):
:param str mine_function: The name of the execution_module.function to run
and whose value will be stored in the salt mine. Defaults to ``name``.
:param str allow_tgt: Targeting specification for ACL. Specifies which minions
are allowed to access this function.
are allowed to access this function. Please note both your master and
minion need to be on, at least, version 3000 for this to work properly.
:param str allow_tgt_type: Type of the targeting specification. This value will
be ignored if ``allow_tgt`` is not specified.
be ignored if ``allow_tgt`` is not specified. Please note both your
master and minion need to be on, at least, version 3000 for this to work
properly.
Remaining args and kwargs will be passed on to the function to run.
@ -252,11 +259,15 @@ def send(name, *args, **kwargs):
log.error('Function %s in mine.send failed to execute', mine_function or name)
log.debug('Error: %s', trace)
return False
mine_data[name] = salt.utils.mine.wrap_acl_structure(
res,
allow_tgt=allow_tgt,
allow_tgt_type=allow_tgt_type
)
if allow_tgt:
mine_data[name] = salt.utils.mine.wrap_acl_structure(
res,
allow_tgt=allow_tgt,
allow_tgt_type=allow_tgt_type
)
else:
mine_data[name] = res
return _mine_store(mine_data)

View file

@ -39,7 +39,7 @@ log = logging.getLogger(__name__)
HAS_DJANGO = False
try:
from django import dispatch
from django import dispatch # pylint: disable=E0611
HAS_DJANGO = True
except ImportError:
HAS_DJANGO = False

View file

@ -10,7 +10,7 @@ Runner to provide F5 Load Balancer functionality
.. code-block:: yaml
load_balancers:
bigip1.example.com
bigip1.example.com:
username: admin
password: secret
bigip2.example.com:

View file

@ -319,50 +319,44 @@ class SaltStackVersion(object):
# Higher than 0.17, lower than first date based
return 0 < self.major < 2014
def min_info(self):
info = [self.major]
if self.new_version(self.major):
if self.minor:
info.append(self.minor)
else:
info.extend([self.minor,
self.bugfix,
self.mbugfix])
return info
@property
def info(self):
return (
self.major,
self.minor,
self.bugfix,
self.mbugfix
)
return tuple(self.min_info())
@property
def pre_info(self):
return (
self.major,
self.minor,
self.bugfix,
self.mbugfix,
self.pre_type,
self.pre_num
)
info = self.min_info()
info.extend([self.pre_type,
self.pre_num])
return tuple(info)
@property
def noc_info(self):
return (
self.major,
self.minor,
self.bugfix,
self.mbugfix,
self.pre_type,
self.pre_num,
self.noc
)
info = self.min_info()
info.extend([self.pre_type,
self.pre_num,
self.noc])
return tuple(info)
@property
def full_info(self):
return (
self.major,
self.minor,
self.bugfix,
self.mbugfix,
self.pre_type,
self.pre_num,
self.noc,
self.sha
)
info = self.min_info()
info.extend([self.pre_type,
self.pre_num,
self.noc,
self.sha])
return tuple(info)
@property
def string(self):
@ -402,6 +396,16 @@ class SaltStackVersion(object):
version_string += ' ({0})'.format(self.RMATCH[(self.major, self.minor)])
return version_string
@property
def pre_index(self):
if self.new_version(self.major):
pre_type = 2
if not isinstance(self.minor, int):
pre_type = 1
else:
pre_type = 4
return pre_type
def __str__(self):
return self.string
@ -418,23 +422,29 @@ class SaltStackVersion(object):
)
)
pre_type = self.pre_index
other_pre_type = other.pre_index
other_noc_info = list(other.noc_info)
noc_info = list(self.noc_info)
if self.new_version(self.major):
if isinstance(self.minor, int) and not isinstance(other.minor, int):
other_noc_info[1] = 0
if self.minor and not other.minor:
# We have minor information, the other side does not
if self.minor > 0:
other_noc_info[1] = 0
if not isinstance(self.minor, int) and isinstance(other.minor, int):
noc_info[1] = 0
if not self.minor and other.minor:
# The other side has minor information, we don't
if other.minor > 0:
noc_info[1] = 0
if self.pre_type and not other.pre_type:
# We have pre-release information, the other side doesn't
other_noc_info[4] = 'zzzzz'
other_noc_info[other_pre_type] = 'zzzzz'
if not self.pre_type and other.pre_type:
# The other side has pre-release informatio, we don't
noc_info[4] = 'zzzzz'
# The other side has pre-release information, we don't
noc_info[pre_type] = 'zzzzz'
return method(tuple(noc_info), tuple(other_noc_info))

View file

@ -95,6 +95,9 @@ config_test:
mine_functions:
test.ping: []
test.arg:
- isn't
- allow_tgt: 'sub_minion'
# sdb env module
osenv:

View file

@ -62,3 +62,8 @@ grains:
keystone.password: demopass
keystone.tenant: demo
keystone.auth_url: http://127.0.0.1:5000/v3/
mine_functions:
test.arg:
- isn't
- allow_tgt: 'sub_minion'

View file

@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
import os
import salt.loader
import salt.minion
import salt.utils.yaml
from salt.utils.files import fopen
from tests.support.case import ModuleCase
from tests.support.helpers import with_tempdir
from tests.support.mock import patch
class BasePillarTest(ModuleCase):
@with_tempdir()
def test_minion_cache_should_cache_files(self, tempdir):
pillar = {"this": {"is": {"some": "pillar data"}}}
opts = {
"file_client": "remote",
"minion_pillar_cache": "true",
"master_type": "local",
"discovery": False,
"master": "local",
"__role": "",
"id": "test",
"saltenv": "base",
"pillar_cache": True,
"pillar_cache_backend": "disk",
"pillar_cache_ttl": 3600,
"cachedir": tempdir,
"state_top": "top.sls",
"pillar_roots": {"base": tempdir},
"extension_modules": tempdir,
"file_ignore_regex": [],
"file_ignore_glob": [],
"pillar": pillar,
}
with patch("salt.loader.grains", return_value={}), patch(
"salt.minion.SMinion.gen_modules"
), patch("salt.minion.SMinion.eval_master"), patch(
"salt.minion.install_zmq"
), patch(
"salt.minion.ZMQDefaultLoop.current"
):
minion = salt.minion.SMinion(opts)
self.assertTrue("pillar" in os.listdir(tempdir))
pillar_cache = os.path.join(tempdir, "pillar")
self.assertTrue("top.sls" in os.listdir(pillar_cache))
self.assertTrue("cache.sls" in os.listdir(pillar_cache))
with fopen(os.path.join(pillar_cache, "cache.sls"), "rb") as f:
cached_data = salt.utils.yaml.safe_load(f)
assert cached_data == pillar

View file

@ -8,29 +8,29 @@ import time
import pprint
# Import Salt Testing libs
from tests.support.case import ModuleCase
from tests.support.case import ModuleCase, ShellCase
from tests.support.runtests import RUNTIME_VARS
# Import Salt libs
import salt.utils.platform
class MineTest(ModuleCase):
class MineTest(ModuleCase, ShellCase):
'''
Test the mine system
'''
def setUp(self):
self.tgt = r'\*'
if salt.utils.platform.is_windows():
self.tgt = '*'
self.wait_for_all_jobs()
def test_get(self):
'''
test mine.get and mine.update
'''
self.assertTrue(self.run_function('mine.update', minion_tgt='minion'))
# The sub_minion does not have mine_functions defined in its configuration
# In this case, mine.update returns None
self.assertIsNone(
self.run_function(
'mine.update',
minion_tgt='sub_minion'
)
)
assert self.run_function('mine.update', minion_tgt='minion')
assert self.run_function('mine.update', minion_tgt='sub_minion')
# Since the minion has mine_functions defined in its configuration,
# mine.update will return True
self.assertTrue(
@ -40,6 +40,78 @@ class MineTest(ModuleCase):
)
)
def test_get_allow_tgt(self):
'''
test mine.get and mine.update using allow_tgt
'''
assert self.run_function('mine.update', minion_tgt='minion')
assert self.run_function('mine.update', minion_tgt='sub_minion')
# sub_minion should be able to view test.arg data
sub_min_ret = self.run_call('mine.get {0} test.arg'.format(self.tgt), config_dir=RUNTIME_VARS.TMP_SUB_MINION_CONF_DIR)
assert " - isn't" in sub_min_ret
# minion should not be able to view test.arg data
min_ret = self.run_call('mine.get {0} test.arg'.format(self.tgt))
assert " - isn't" not in min_ret
def test_send_allow_tgt(self):
'''
test mine.send with allow_tgt set
'''
mine_name = 'test_this'
for minion in ['sub_minion', 'minion']:
assert self.run_function('mine.send', [mine_name,
'mine_function=test.arg_clean', 'one'], allow_tgt='sub_minion',
minion_tgt=minion)
min_ret = self.run_call('mine.get {0} {1}'.format(self.tgt, mine_name))
sub_ret = self.run_call('mine.get {0} {1}'.format(self.tgt, mine_name),
config_dir=RUNTIME_VARS.TMP_SUB_MINION_CONF_DIR)
# ensure we did get the mine_name mine function for sub_minion
assert ' - one' in sub_ret
# ensure we did not get the mine_name mine function for minion
assert ' - one' not in min_ret
def test_send_allow_tgt_compound(self):
'''
test mine.send with allow_tgt set
and using compound targeting
'''
mine_name = 'test_this_comp'
for minion in ['sub_minion', 'minion']:
assert self.run_function('mine.send', [mine_name,
'mine_function=test.arg_clean', 'one'],
allow_tgt='L@minion,sub_minion',
allow_tgt_type='compound',
minion_tgt=minion)
min_ret = self.run_call('mine.get {0} {1}'.format(self.tgt, mine_name))
sub_ret = self.run_call('mine.get {0} {1}'.format(self.tgt, mine_name),
config_dir=RUNTIME_VARS.TMP_SUB_MINION_CONF_DIR)
# ensure we get the mine_name mine function for both minions
for ret in [min_ret, sub_ret]:
assert ' - one' in ret
def test_send_allow_tgt_doesnotexist(self):
'''
test mine.send with allow_tgt set when
the minion defined in allow_tgt does
not exist
'''
mine_name = 'mine_doesnotexist'
for minion in ['sub_minion', 'minion']:
assert self.run_function('mine.send', [mine_name,
'mine_function=test.arg_clean', 'one'], allow_tgt='doesnotexist',
minion_tgt=minion)
min_ret = self.run_call('mine.get {0} {1}'.format(self.tgt, mine_name))
sub_ret = self.run_call('mine.get {0} {1}'.format(self.tgt, mine_name),
config_dir=RUNTIME_VARS.TMP_SUB_MINION_CONF_DIR)
# ensure we did not get the mine_name mine function for both minions
for ret in [sub_ret, min_ret]:
assert ' - one' not in ret
def test_send(self):
'''
test mine.send

View file

@ -175,9 +175,12 @@ class ShellTestCase(TestCase, AdaptedConfigurationTestCaseMixin, ScriptPathMixin
arg_str = '--config-dir {0} {1}'.format(self.config_dir, arg_str)
return self.run_script('salt-cp', arg_str, with_retcode=with_retcode, catch_stderr=catch_stderr)
def run_call(self, arg_str, with_retcode=False, catch_stderr=False, local=False, timeout=15):
def run_call(self, arg_str, with_retcode=False, catch_stderr=False,
local=False, timeout=15, config_dir=None):
if not config_dir:
config_dir = self.config_dir
arg_str = '{0} --config-dir {1} {2}'.format('--local' if local else '',
self.config_dir, arg_str)
config_dir, arg_str)
return self.run_script('salt-call',
arg_str,
@ -582,12 +585,14 @@ class ShellCase(ShellTestCase, AdaptedConfigurationTestCaseMixin, ScriptPathMixi
timeout=timeout)
def run_call(self, arg_str, with_retcode=False, catch_stderr=False, # pylint: disable=W0221
local=False, timeout=RUN_TIMEOUT):
local=False, timeout=RUN_TIMEOUT, config_dir=None):
'''
Execute salt-call.
'''
if not config_dir:
config_dir = self.config_dir
arg_str = '{0} --config-dir {1} {2}'.format('--local' if local else '',
self.config_dir, arg_str)
config_dir, arg_str)
ret = self.run_script('salt-call',
arg_str,
with_retcode=with_retcode,
@ -772,8 +777,6 @@ class ModuleCase(TestCase, SaltClientTestCaseMixin):
'ssh.recv_known_host_entries',
'time.sleep'
)
if minion_tgt == 'sub_minion':
known_to_return_none += ('mine.update',)
if 'f_arg' in kwargs:
kwargs['arg'] = kwargs.pop('f_arg')
if 'f_timeout' in kwargs:

View file

@ -1485,3 +1485,19 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin):
self.assertIn('osfullname', os_grains)
self.assertEqual(os_grains.get('osfullname'), 'FreeBSD')
def test_saltversioninfo(self):
'''
test saltversioninfo core grain.
'''
ret = core.saltversioninfo()
info = ret['saltversioninfo']
assert isinstance(ret, dict)
assert isinstance(info, list)
try:
assert len(info) == 1
except AssertionError:
# We have a minor version we need to test
assert len(info) == 2
assert all([x is not None for x in info])
assert all([isinstance(x, int) for x in info])

View file

@ -43,6 +43,9 @@ class MineTestCase(TestCase, LoaderModuleMockMixin):
Test cases for salt.modules.mine
'''
def setUp(self):
self.kernel_ret = 'Linux!'
self.foo_ret = 'baz'
self.ip_ret = '2001:db8::1:3'
self.cache = FakeCache()
def setup_loader_modules(self):
@ -94,15 +97,16 @@ class MineTestCase(TestCase, LoaderModuleMockMixin):
'''
Tests sending an item to the mine in the minion's local cache,
and then immediately fetching it again (since tests are executed unordered).
Also verify that the stored mine cache has the correct structure (with ACL).
Also verify that the stored mine cache does not use ACL data structure
without allow_tgt passed.
'''
with patch.dict(mine.__opts__, {
'file_client': 'local',
'id': 'webserver',
}), \
patch.dict(mine.__salt__, {
'network.ip_addrs': MagicMock(return_value='2001:db8::1:3'),
'foo.bar': MagicMock(return_value='baz'),
'network.ip_addrs': MagicMock(return_value=self.ip_ret),
'foo.bar': MagicMock(return_value=self.foo_ret),
}):
ret = mine.send('ip_addr', mine_function='network.ip_addrs')
mine.send('foo.bar')
@ -110,14 +114,8 @@ class MineTestCase(TestCase, LoaderModuleMockMixin):
self.assertEqual(
self.cache.fetch('minions/webserver', 'mine_cache'),
{
'ip_addr': {
salt.utils.mine.MINE_ITEM_ACL_DATA: '2001:db8::1:3',
salt.utils.mine.MINE_ITEM_ACL_ID: salt.utils.mine.MINE_ITEM_ACL_VERSION,
},
'foo.bar': {
salt.utils.mine.MINE_ITEM_ACL_DATA: 'baz',
salt.utils.mine.MINE_ITEM_ACL_ID: salt.utils.mine.MINE_ITEM_ACL_VERSION,
},
'ip_addr': self.ip_ret,
'foo.bar': self.foo_ret,
}
)
with patch.dict(mine.__opts__, {
@ -128,9 +126,9 @@ class MineTestCase(TestCase, LoaderModuleMockMixin):
ret_single_dict = mine.get('*', ['ip_addr'])
ret_multi = mine.get('*', 'ip_addr,foo.bar')
ret_multi2 = mine.get('*', ['ip_addr', 'foo.bar'])
self.assertEqual(ret_single, {'webserver': '2001:db8::1:3'})
self.assertEqual(ret_single_dict, {'ip_addr': {'webserver': '2001:db8::1:3'}})
self.assertEqual(ret_multi, {'ip_addr': {'webserver': '2001:db8::1:3'}, 'foo.bar': {'webserver': 'baz'}})
self.assertEqual(ret_single, {'webserver': self.ip_ret})
self.assertEqual(ret_single_dict, {'ip_addr': {'webserver': self.ip_ret}})
self.assertEqual(ret_multi, {'ip_addr': {'webserver': self.ip_ret}, 'foo.bar': {'webserver': self.foo_ret}})
self.assertEqual(ret_multi, ret_multi2)
def test_send_get_acl_local(self):
@ -138,15 +136,16 @@ class MineTestCase(TestCase, LoaderModuleMockMixin):
Tests sending an item to the mine in the minion's local cache,
including ACL information (useless when only working locally, but hey),
and then immediately fetching it again (since tests are executed unordered).
Also verify that the stored mine cache has the correct structure (with ACL).
Also verify that the stored mine cache has the correct structure (with ACL)
when using allow_tgt and no ACL without allow_tgt.
'''
with patch.dict(mine.__opts__, {
'file_client': 'local',
'id': 'webserver',
}), \
patch.dict(mine.__salt__, {
'network.ip_addrs': MagicMock(return_value='2001:db8::1:3'),
'foo.bar': MagicMock(return_value='baz'),
'network.ip_addrs': MagicMock(return_value=self.ip_ret),
'foo.bar': MagicMock(return_value=self.foo_ret),
}):
ret = mine.send('ip_addr', mine_function='network.ip_addrs', allow_tgt='web*', allow_tgt_type='glob')
mine.send('foo.bar')
@ -155,15 +154,12 @@ class MineTestCase(TestCase, LoaderModuleMockMixin):
self.cache.fetch('minions/webserver', 'mine_cache'),
{
'ip_addr': {
salt.utils.mine.MINE_ITEM_ACL_DATA: '2001:db8::1:3',
salt.utils.mine.MINE_ITEM_ACL_DATA: self.ip_ret,
salt.utils.mine.MINE_ITEM_ACL_ID: salt.utils.mine.MINE_ITEM_ACL_VERSION,
'allow_tgt': 'web*',
'allow_tgt_type': 'glob',
},
'foo.bar': {
salt.utils.mine.MINE_ITEM_ACL_DATA: 'baz',
salt.utils.mine.MINE_ITEM_ACL_ID: salt.utils.mine.MINE_ITEM_ACL_VERSION,
},
'foo.bar': self.foo_ret,
}
)
with patch.dict(mine.__opts__, {
@ -171,7 +167,7 @@ class MineTestCase(TestCase, LoaderModuleMockMixin):
'id': 'webserver',
}):
ret_single = mine.get('*', 'ip_addr')
self.assertEqual(ret_single, {'webserver': '2001:db8::1:3'})
self.assertEqual(ret_single, {'webserver': self.ip_ret})
def test_send_master(self):
'''
@ -180,7 +176,7 @@ class MineTestCase(TestCase, LoaderModuleMockMixin):
'''
with patch.object(mine, '_mine_send', MagicMock(side_effect=lambda x, y: x)),\
patch.dict(mine.__salt__, {
'foo.bar': MagicMock(return_value='baz'),
'foo.bar': MagicMock(return_value=self.foo_ret),
}), \
patch.dict(mine.__opts__, {
'file_client': 'remote',
@ -192,12 +188,7 @@ class MineTestCase(TestCase, LoaderModuleMockMixin):
{
'id': 'foo',
'cmd': '_mine',
'data': {
'foo.bar': {
salt.utils.mine.MINE_ITEM_ACL_DATA: 'baz',
salt.utils.mine.MINE_ITEM_ACL_ID: salt.utils.mine.MINE_ITEM_ACL_VERSION,
},
},
'data': {'foo.bar': self.foo_ret},
'clear': False,
}
)
@ -209,7 +200,7 @@ class MineTestCase(TestCase, LoaderModuleMockMixin):
'''
with patch.object(mine, '_mine_send', MagicMock(side_effect=lambda x, y: x)),\
patch.dict(mine.__salt__, {
'foo.bar': MagicMock(return_value='baz'),
'foo.bar': MagicMock(return_value=self.foo_ret),
}), \
patch.dict(mine.__opts__, {
'file_client': 'remote',
@ -223,7 +214,7 @@ class MineTestCase(TestCase, LoaderModuleMockMixin):
'cmd': '_mine',
'data': {
'foo.bar': {
salt.utils.mine.MINE_ITEM_ACL_DATA: 'baz',
salt.utils.mine.MINE_ITEM_ACL_DATA: self.foo_ret,
salt.utils.mine.MINE_ITEM_ACL_ID: salt.utils.mine.MINE_ITEM_ACL_VERSION,
'allow_tgt': 'roles:web',
'allow_tgt_type': 'grains',
@ -239,7 +230,7 @@ class MineTestCase(TestCase, LoaderModuleMockMixin):
'''
mock_load = {
'tgt_type': 'qux',
'tgt': 'baz',
'tgt': self.foo_ret,
'cmd': '_mine_get',
'fun': 'foo.bar',
'id': 'foo'
@ -292,9 +283,9 @@ class MineTestCase(TestCase, LoaderModuleMockMixin):
}), \
patch.dict(mine.__salt__, {
'config.merge': MagicMock(return_value=config_mine_functions),
'grains.get': lambda x: 'Linux!',
'network.ip_addrs': MagicMock(return_value='2001:db8::1:3'),
'foo.bar': MagicMock(return_value='baz'),
'grains.get': lambda x: self.kernel_ret,
'network.ip_addrs': MagicMock(return_value=self.ip_ret),
'foo.bar': MagicMock(return_value=self.foo_ret),
}):
ret = mine.update()
self.assertEqual(ret, 'FakeCache:StoreSuccess!')
@ -302,22 +293,16 @@ class MineTestCase(TestCase, LoaderModuleMockMixin):
self.assertEqual(
self.cache.fetch('minions/webserver', 'mine_cache'),
{
'ip_addr': {
salt.utils.mine.MINE_ITEM_ACL_DATA: '2001:db8::1:3',
salt.utils.mine.MINE_ITEM_ACL_ID: salt.utils.mine.MINE_ITEM_ACL_VERSION,
},
'network.ip_addrs': {
salt.utils.mine.MINE_ITEM_ACL_DATA: '2001:db8::1:3',
salt.utils.mine.MINE_ITEM_ACL_ID: salt.utils.mine.MINE_ITEM_ACL_VERSION,
},
'ip_addr': self.ip_ret,
'network.ip_addrs': self.ip_ret,
'foo.bar': {
salt.utils.mine.MINE_ITEM_ACL_DATA: 'baz',
salt.utils.mine.MINE_ITEM_ACL_DATA: self.foo_ret,
salt.utils.mine.MINE_ITEM_ACL_ID: salt.utils.mine.MINE_ITEM_ACL_VERSION,
'allow_tgt': 'G@roles:webserver',
'allow_tgt_type': 'compound',
},
'kernel': {
salt.utils.mine.MINE_ITEM_ACL_DATA: 'Linux!',
salt.utils.mine.MINE_ITEM_ACL_DATA: self.kernel_ret,
salt.utils.mine.MINE_ITEM_ACL_ID: salt.utils.mine.MINE_ITEM_ACL_VERSION,
'allow_tgt': 'web*',
},
@ -343,8 +328,8 @@ class MineTestCase(TestCase, LoaderModuleMockMixin):
patch.dict(mine.__salt__, {
'config.merge': MagicMock(return_value={}),
'grains.get': lambda x: 'Linux!!',
'network.ip_addrs': MagicMock(return_value='2001:db8::1:4'),
'foo.bar': MagicMock(return_value='baz'),
'network.ip_addrs': MagicMock(return_value=self.ip_ret),
'foo.bar': MagicMock(return_value=self.foo_ret),
}):
ret = mine.update(mine_functions=manual_mine_functions)
self.assertEqual(ret, 'FakeCache:StoreSuccess!')
@ -352,16 +337,10 @@ class MineTestCase(TestCase, LoaderModuleMockMixin):
self.assertEqual(
self.cache.fetch('minions/webserver', 'mine_cache'),
{
'ip_addr': {
salt.utils.mine.MINE_ITEM_ACL_DATA: '2001:db8::1:4',
salt.utils.mine.MINE_ITEM_ACL_ID: salt.utils.mine.MINE_ITEM_ACL_VERSION,
},
'network.ip_addrs': {
salt.utils.mine.MINE_ITEM_ACL_DATA: '2001:db8::1:4',
salt.utils.mine.MINE_ITEM_ACL_ID: salt.utils.mine.MINE_ITEM_ACL_VERSION,
},
'ip_addr': self.ip_ret,
'network.ip_addrs': self.ip_ret,
'foo.bar': {
salt.utils.mine.MINE_ITEM_ACL_DATA: 'baz',
salt.utils.mine.MINE_ITEM_ACL_DATA: self.foo_ret,
salt.utils.mine.MINE_ITEM_ACL_ID: salt.utils.mine.MINE_ITEM_ACL_VERSION,
'allow_tgt': 'G@roles:webserver',
'allow_tgt_type': 'compound',
@ -388,22 +367,10 @@ class MineTestCase(TestCase, LoaderModuleMockMixin):
'id': 'webserver',
'cmd': '_mine',
'data': {
'ip_addr': {
salt.utils.mine.MINE_ITEM_ACL_DATA: '2001:db8::1:3',
salt.utils.mine.MINE_ITEM_ACL_ID: salt.utils.mine.MINE_ITEM_ACL_VERSION,
},
'network.ip_addrs': {
salt.utils.mine.MINE_ITEM_ACL_DATA: '2001:db8::1:3',
salt.utils.mine.MINE_ITEM_ACL_ID: salt.utils.mine.MINE_ITEM_ACL_VERSION,
},
'foo.bar': {
salt.utils.mine.MINE_ITEM_ACL_DATA: 'baz',
salt.utils.mine.MINE_ITEM_ACL_ID: salt.utils.mine.MINE_ITEM_ACL_VERSION,
},
'kernel': {
salt.utils.mine.MINE_ITEM_ACL_DATA: 'Linux!',
salt.utils.mine.MINE_ITEM_ACL_ID: salt.utils.mine.MINE_ITEM_ACL_VERSION,
},
'ip_addr': self.ip_ret,
'network.ip_addrs': self.ip_ret,
'foo.bar': self.foo_ret,
'kernel': self.kernel_ret,
},
'clear': False,
}
@ -415,9 +382,9 @@ class MineTestCase(TestCase, LoaderModuleMockMixin):
}), \
patch.dict(mine.__salt__, {
'config.merge': MagicMock(return_value=config_mine_functions),
'grains.get': lambda x: 'Linux!',
'network.ip_addrs': MagicMock(return_value='2001:db8::1:3'),
'foo.bar': MagicMock(return_value='baz'),
'grains.get': lambda x: self.kernel_ret,
'network.ip_addrs': MagicMock(return_value=self.ip_ret),
'foo.bar': MagicMock(return_value=self.foo_ret),
}):
# Verify the correct load
self.assertEqual(

View file

@ -14,6 +14,7 @@ from tests.support.runtests import RUNTIME_VARS
import tests.support.helpers
# Import Salt libs
import salt
import salt.ext.six
import salt.modules.cmdmod
import salt.utils.platform
@ -95,3 +96,10 @@ class VendorTornadoTest(TestCase):
log.error("Test found bad line: %s", line)
valid_lines.append(line)
assert valid_lines == [], len(valid_lines)
def test_regression_56063(self):
importer = salt.TornadoImporter()
try:
importer.find_module('tornado')
except TypeError:
assert False, 'TornadoImporter raised type error when one argument passed'

View file

@ -134,8 +134,9 @@ class BadTestModuleNamesTestCase(TestCase):
'integration.logging.handlers.test_logstash_mod',
'integration.master.test_event_return',
'integration.minion.test_blackout',
'integration.minion.test_pillar',
'integration.minion.test_executor',
'integration.minion.test_minion_cache',
'integration.minion.test_pillar',
'integration.minion.test_timeout',
'integration.modules.test_decorators',
'integration.modules.test_pkg',

View file

@ -37,8 +37,11 @@ class VersionTestCase(TestCase):
('v2014.1.4.1', (2014, 1, 4, 1, '', 0, 0, None), None),
('v2014.1.4.1rc3-n/a-abcdefff', (2014, 1, 4, 1, 'rc', 3, -1, 'abcdefff'), None),
('v3.4.1.1', (3, 4, 1, 1, '', 0, 0, None), None),
('v3000', (3000, None, None, 0, '', 0, 0, None), '3000'),
('v3000rc1', (3000, None, None, 0, 'rc', 1, 0, None), '3000rc1'),
('v3000', (3000, '', 0, 0, None), '3000'),
('v3000.0', (3000, '', 0, 0, None), '3000'),
('v4518.1', (4518, 1, '', 0, 0, None), '4518.1'),
('v3000rc1', (3000, 'rc', 1, 0, None), '3000rc1'),
('v3000rc1-n/a-abcdefff', (3000, 'rc', 1, -1, 'abcdefff'), None),
)
@ -76,6 +79,9 @@ class VersionTestCase(TestCase):
# version scheme in the future
# but still adding test for it
('v3000', 'v3000.0rc1'),
('v3000.1rc1', 'v3000.0rc1'),
('v3000', 'v2019.2.1rc1'),
('v3001rc1', 'v2019.2.1rc1'),
)
for higher_version, lower_version in examples:
self.assertTrue(SaltStackVersion.parse(higher_version) > lower_version)
@ -154,6 +160,45 @@ class VersionTestCase(TestCase):
assert ver.bugfix == 0
assert ver.string == '{0}.{1}.0'.format(maj_ver, min_ver)
def test_noc_info(self):
'''
Test noc_info property method
'''
expect = (
('v2014.1.4.1rc3-n/a-abcdefff', (2014, 1, 4, 1, 'rc', 3, -1)),
('v3.4.1.1', (3, 4, 1, 1, '', 0, 0)),
('v3000', (3000, '', 0, 0)),
('v3000.0', (3000, '', 0, 0)),
('v4518.1', (4518, 1, '', 0, 0)),
('v3000rc1', (3000, 'rc', 1, 0)),
('v3000rc1-n/a-abcdefff', (3000, 'rc', 1, -1)),
)
for vstr, noc_info in expect:
saltstack_version = SaltStackVersion.parse(vstr)
assert saltstack_version.noc_info, noc_info
assert len(saltstack_version.noc_info) == len(noc_info)
def test_full_info(self):
'''
Test full_Info property method
'''
expect = (
('v2014.1.4.1rc3-n/a-abcdefff', (2014, 1, 4, 1, 'rc', 3, -1, 'abcdefff')),
('v3.4.1.1', (3, 4, 1, 1, '', 0, 0, None)),
('v3000', (3000, '', 0, 0, None)),
('v3000.0', (3000, '', 0, 0, None)),
('v4518.1', (4518, 1, '', 0, 0, None)),
('v3000rc1', (3000, 'rc', 1, 0, None)),
('v3000rc1-n/a-abcdefff', (3000, 'rc', 1, -1, 'abcdefff')),
)
for vstr, full_info in expect:
saltstack_version = SaltStackVersion.parse(vstr)
assert saltstack_version.full_info, full_info
assert len(saltstack_version.full_info) == len(full_info)
def test_discover_version(self):
'''
Test call to __discover_version
@ -180,3 +225,31 @@ class VersionTestCase(TestCase):
with proc_mock, patch_os:
ret = getattr(salt.version, '__discover_version')(salt_ver)
assert ret == exp
def test_info_new_version(self):
'''
test info property method with new versioning scheme
'''
vers = ((3000, None, None),
(3000, 1, None),
(3001, 0, None))
for maj_ver, min_ver, bug_fix in vers:
ver = SaltStackVersion(major=maj_ver, minor=min_ver, bugfix=bug_fix)
if min_ver:
assert ver.info == (maj_ver, min_ver)
else:
assert ver.info == (maj_ver,)
def test_info_old_version(self):
'''
test info property method with old versioning scheme
'''
vers = ((2019, 2, 1),
(2018, 3, 0),
(2017, 7, None))
for maj_ver, min_ver, bug_fix in vers:
ver = SaltStackVersion(major=maj_ver, minor=min_ver, bugfix=bug_fix)
if bug_fix is None:
assert ver.info == (maj_ver, min_ver, 0, 0)
else:
assert ver.info == (maj_ver, min_ver, bug_fix, 0)