Merge branch '2017.7' into git-noexec-fix

This commit is contained in:
Nicole Thomas 2017-10-20 11:08:20 -04:00 committed by GitHub
commit a7a841d9d2
20 changed files with 395 additions and 202 deletions

View file

@ -12,4 +12,10 @@ Remove this section if not relevant
Yes/No
### Commits signed with GPG?
Yes/No
Please review [Salt's Contributing Guide](https://docs.saltstack.com/en/latest/topics/development/contributing.html) for best practices.
See GitHub's [page on GPG signing](https://help.github.com/articles/signing-commits-using-gpg/) for more information about signing commits with GPG.

View file

@ -3,6 +3,8 @@
Beacon to monitor temperature, humidity and pressure using the SenseHat
of a Raspberry Pi.
.. versionadded:: 2017.7.0
:maintainer: Benedikt Werner <1benediktwerner@gmail.com>
:maturity: new
:depends: sense_hat Python module

View file

@ -1582,7 +1582,10 @@ class LocalClient(object):
timeout=timeout,
tgt=tgt,
tgt_type=tgt_type,
expect_minions=(verbose or show_timeout),
# (gtmanfred) expect_minions is popped here incase it is passed from a client
# call. If this is not popped, then it would be passed twice to
# get_iter_returns.
expect_minions=(kwargs.pop('expect_minions', False) or verbose or show_timeout),
**kwargs
):
log.debug('return event: %s', ret)

View file

@ -4571,7 +4571,8 @@ def _list_nodes(full=False):
pass
vms[name]['id'] = vm.find('ID').text
vms[name]['image'] = vm.find('TEMPLATE').find('TEMPLATE_ID').text
if vm.find('TEMPLATE').find('TEMPLATE_ID'):
vms[name]['image'] = vm.find('TEMPLATE').find('TEMPLATE_ID').text
vms[name]['name'] = name
vms[name]['size'] = {'cpu': cpu_size, 'memory': memory_size}
vms[name]['state'] = vm.find('STATE').text

View file

@ -1367,7 +1367,10 @@ def os_data():
.format(' '.join(init_cmdline))
)
# Add lsb grains on any distro with lsb-release
# Add lsb grains on any distro with lsb-release. Note that this import
# can fail on systems with lsb-release installed if the system package
# does not install the python package for the python interpreter used by
# Salt (i.e. python2 or python3)
try:
import lsb_release # pylint: disable=import-error
release = lsb_release.get_distro_information()
@ -1416,7 +1419,13 @@ def os_data():
if 'VERSION_ID' in os_release:
grains['lsb_distrib_release'] = os_release['VERSION_ID']
if 'PRETTY_NAME' in os_release:
grains['lsb_distrib_codename'] = os_release['PRETTY_NAME']
codename = os_release['PRETTY_NAME']
# https://github.com/saltstack/salt/issues/44108
if os_release['ID'] == 'debian':
codename_match = re.search(r'\((\w+)\)$', codename)
if codename_match:
codename = codename_match.group(1)
grains['lsb_distrib_codename'] = codename
if 'CPE_NAME' in os_release:
if ":suse:" in os_release['CPE_NAME'] or ":opensuse:" in os_release['CPE_NAME']:
grains['os'] = "SUSE"

View file

@ -2,6 +2,8 @@
'''
Module for controlling the LED matrix or reading environment data on the SenseHat of a Raspberry Pi.
.. versionadded:: 2017.7.0
:maintainer: Benedikt Werner <1benediktwerner@gmail.com>, Joachim Werner <joe@suse.com>
:maturity: new
:depends: sense_hat Python module

View file

@ -893,8 +893,8 @@ def highstate(test=None, queue=False, **kwargs):
finally:
st_.pop_active()
if __salt__['config.option']('state_data', '') == 'terse' or \
kwargs.get('terse'):
if isinstance(ret, dict) and (__salt__['config.option']('state_data', '') == 'terse' or
kwargs.get('terse')):
ret = _filter_running(ret)
serial = salt.payload.Serial(__opts__)

View file

@ -250,7 +250,7 @@ def adduser(name, username, **kwargs):
'/', '\\').encode('ascii', 'backslashreplace').lower())
try:
if salt.utils.win_functions.get_sam_name(username) not in existingMembers:
if salt.utils.win_functions.get_sam_name(username).lower() not in existingMembers:
if not __opts__['test']:
groupObj.Add('WinNT://' + username.replace('\\', '/'))
@ -309,7 +309,7 @@ def deluser(name, username, **kwargs):
'/', '\\').encode('ascii', 'backslashreplace').lower())
try:
if salt.utils.win_functions.get_sam_name(username) in existingMembers:
if salt.utils.win_functions.get_sam_name(username).lower() in existingMembers:
if not __opts__['test']:
groupObj.Remove('WinNT://' + username.replace('\\', '/'))

View file

@ -34,16 +34,19 @@ Current known limitations
- pywin32 Python module
- lxml
- uuid
- codecs
- struct
- salt.modules.reg
'''
# Import python libs
from __future__ import absolute_import
import io
import os
import logging
import re
import locale
import ctypes
import time
# Import salt libs
import salt.utils
@ -90,7 +93,6 @@ try:
import win32net
import win32security
import uuid
import codecs
import lxml
import struct
from lxml import etree
@ -117,6 +119,16 @@ try:
ADMX_DISPLAYNAME_SEARCH_XPATH = etree.XPath('//*[local-name() = "policy" and @*[local-name() = "displayName"] = $display_name and (@*[local-name() = "class"] = "Both" or @*[local-name() = "class"] = $registry_class) ]')
PRESENTATION_ANCESTOR_XPATH = etree.XPath('ancestor::*[local-name() = "presentation"]')
TEXT_ELEMENT_XPATH = etree.XPath('.//*[local-name() = "text"]')
# Get the System Install Language
# https://msdn.microsoft.com/en-us/library/dd318123(VS.85).aspx
# local.windows_locale is a dict
# GetSystemDefaultUILanguage() returns a 4 digit language code that
# corresponds to an entry in the dict
# Not available in win32api, so we have to use ctypes
# Default to `en-US` (1033)
windll = ctypes.windll.kernel32
INSTALL_LANGUAGE = locale.windows_locale.get(
windll.GetSystemDefaultUILanguage(), 1033).replace('_', '-')
except ImportError:
HAS_WINDOWS_MODULES = False
@ -2709,7 +2721,8 @@ def _processPolicyDefinitions(policy_def_path='c:\\Windows\\PolicyDefinitions',
helper function to process all ADMX files in the specified policy_def_path
and build a single XML doc that we can search/use for ADMX policy processing
'''
display_language_fallback = 'en-US'
# Fallback to the System Install Language
display_language_fallback = INSTALL_LANGUAGE
t_policy_definitions = lxml.etree.Element('policyDefinitions')
t_policy_definitions.append(lxml.etree.Element('categories'))
t_policy_definitions.append(lxml.etree.Element('policies'))
@ -2773,22 +2786,44 @@ def _processPolicyDefinitions(policy_def_path='c:\\Windows\\PolicyDefinitions',
temp_ns = policy_ns
temp_ns = _updateNamespace(temp_ns, this_namespace)
policydefs_policyns_xpath(t_policy_definitions)[0].append(temp_ns)
adml_file = os.path.join(root, display_language, os.path.splitext(t_admfile)[0] + '.adml')
# We need to make sure the adml file exists. First we'll check
# the passed display_language (eg: en-US). Then we'll try the
# abbreviated version (en) to account for alternate locations.
# We'll do the same for the display_language_fallback (en_US).
adml_file = os.path.join(root, display_language,
os.path.splitext(t_admfile)[0] + '.adml')
if not __salt__['file.file_exists'](adml_file):
msg = ('An ADML file in the specified ADML language "{0}" '
'does not exist for the ADMX "{1}", the fallback '
'language will be tried.')
'does not exist for the ADMX "{1}", the abbreviated '
'language code will be tried.')
log.info(msg.format(display_language, t_admfile))
adml_file = os.path.join(root,
display_language_fallback,
os.path.splitext(t_admfile)[0] + '.adml')
adml_file = os.path.join(root, display_language.split('-')[0],
os.path.splitext(t_admfile)[0] + '.adml')
if not __salt__['file.file_exists'](adml_file):
msg = ('An ADML file in the specified ADML language '
'"{0}" and the fallback language "{1}" do not '
'exist for the ADMX "{2}".')
raise SaltInvocationError(msg.format(display_language,
display_language_fallback,
t_admfile))
msg = ('An ADML file in the specified ADML language code "{0}" '
'does not exist for the ADMX "{1}", the fallback '
'language will be tried.')
log.info(msg.format(display_language[:2], t_admfile))
adml_file = os.path.join(root, display_language_fallback,
os.path.splitext(t_admfile)[0] + '.adml')
if not __salt__['file.file_exists'](adml_file):
msg = ('An ADML file in the specified ADML fallback language "{0}" '
'does not exist for the ADMX "{1}", the abbreviated'
'fallback language code will be tried.')
log.info(msg.format(display_language_fallback, t_admfile))
adml_file = os.path.join(root, display_language_fallback.split('-')[0],
os.path.splitext(t_admfile)[0] + '.adml')
if not __salt__['file.file_exists'](adml_file):
msg = ('An ADML file in the specified ADML language '
'"{0}" and the fallback language "{1}" do not '
'exist for the ADMX "{2}".')
raise SaltInvocationError(msg.format(display_language,
display_language_fallback,
t_admfile))
try:
xmltree = lxml.etree.parse(adml_file)
except lxml.etree.XMLSyntaxError:
@ -2796,8 +2831,8 @@ def _processPolicyDefinitions(policy_def_path='c:\\Windows\\PolicyDefinitions',
try:
xmltree = _remove_unicode_encoding(adml_file)
except Exception:
msg = ('An error was found while processing adml file {0}, all policy'
' languange data from this file will be unavailable via this module')
msg = ('An error was found while processing adml file {0}, all policy '
'language data from this file will be unavailable via this module')
log.error(msg.format(adml_file))
continue
if None in namespaces:
@ -2828,15 +2863,23 @@ def _findOptionValueInSeceditFile(option):
'''
try:
_d = uuid.uuid4().hex
_tfile = '{0}\\{1}'.format(__salt__['config.get']('cachedir'),
_tfile = '{0}\\{1}'.format(__opts__['cachedir'],
'salt-secedit-dump-{0}.txt'.format(_d))
_ret = __salt__['cmd.run']('secedit /export /cfg {0}'.format(_tfile))
if _ret:
_reader = codecs.open(_tfile, 'r', encoding='utf-16')
_secdata = _reader.readlines()
_reader.close()
with io.open(_tfile, encoding='utf-16') as _reader:
_secdata = _reader.readlines()
if __salt__['file.file_exists'](_tfile):
_ret = __salt__['file.remove'](_tfile)
for _ in range(5):
try:
__salt__['file.remove'](_tfile)
except CommandExecutionError:
time.sleep(.1)
continue
else:
break
else:
log.error('error occurred removing {0}'.format(_tfile))
for _line in _secdata:
if _line.startswith(option):
return True, _line.split('=')[1].strip()
@ -2852,9 +2895,9 @@ def _importSeceditConfig(infdata):
'''
try:
_d = uuid.uuid4().hex
_tSdbfile = '{0}\\{1}'.format(__salt__['config.get']('cachedir'),
_tSdbfile = '{0}\\{1}'.format(__opts__['cachedir'],
'salt-secedit-import-{0}.sdb'.format(_d))
_tInfFile = '{0}\\{1}'.format(__salt__['config.get']('cachedir'),
_tInfFile = '{0}\\{1}'.format(__opts__['cachedir'],
'salt-secedit-config-{0}.inf'.format(_d))
# make sure our temp files don't already exist
if __salt__['file.file_exists'](_tSdbfile):

View file

@ -3,7 +3,9 @@
The local returner is used to test the returner interface, it just prints the
return data to the console to verify that it is being passed properly
To use the local returner, append '--return local' to the salt command. ex:
To use the local returner, append '--return local' to the salt command. ex:
.. code-block:: bash
salt '*' test.ping --return local
'''

View file

@ -1853,7 +1853,7 @@ def stopped(name=None,
.. code-block:: yaml
stopped_containers:
docker.stopped:
docker_container.stopped:
- names:
- foo
- bar
@ -1862,7 +1862,7 @@ def stopped(name=None,
.. code-block:: yaml
stopped_containers:
docker.stopped:
docker_container.stopped:
- containers:
- foo
- bar
@ -1998,10 +1998,10 @@ def absent(name, force=False):
.. code-block:: yaml
mycontainer:
docker.absent
docker_container.absent
multiple_containers:
docker.absent:
docker_container.absent:
- names:
- foo
- bar

View file

@ -65,11 +65,11 @@ def _changes(name,
if lgrp['members']:
lgrp['members'] = [user.lower() for user in lgrp['members']]
if members:
members = [salt.utils.win_functions.get_sam_name(user) for user in members]
members = [salt.utils.win_functions.get_sam_name(user).lower() for user in members]
if addusers:
addusers = [salt.utils.win_functions.get_sam_name(user) for user in addusers]
addusers = [salt.utils.win_functions.get_sam_name(user).lower() for user in addusers]
if delusers:
delusers = [salt.utils.win_functions.get_sam_name(user) for user in delusers]
delusers = [salt.utils.win_functions.get_sam_name(user).lower() for user in delusers]
change = {}
if gid:
@ -244,9 +244,7 @@ def present(name,
return ret
# Group is not present, make it.
if __salt__['group.add'](name,
gid,
system=system):
if __salt__['group.add'](name, gid=gid, system=system):
# if members to be added
grp_members = None
if members:
@ -269,7 +267,7 @@ def present(name,
ret['result'] = False
ret['comment'] = (
'Group {0} has been created but, some changes could not'
' be applied')
' be applied'.format(name))
ret['changes'] = {'Failed': changes}
else:
ret['result'] = False

View file

@ -1139,7 +1139,8 @@ class Schedule(object):
# Sort the list of "whens" from earlier to later schedules
_when.sort()
for i in _when:
# Copy the list so we can loop through it
for i in copy.deepcopy(_when):
if i < now and len(_when) > 1:
# Remove all missed schedules except the latest one.
# We need it to detect if it was triggered previously.

View file

@ -111,7 +111,7 @@ def get_sid_from_name(name):
sid = win32security.LookupAccountName(None, name)[0]
except pywintypes.error as exc:
raise CommandExecutionError(
'User {0} found: {1}'.format(name, exc.strerror))
'User {0} not found: {1}'.format(name, exc.strerror))
return win32security.ConvertSidToStringSid(sid)
@ -146,14 +146,16 @@ def get_current_user():
def get_sam_name(username):
'''
Gets the SAM name for a user. It basically prefixes a username without a
backslash with the computer name. If the username contains a backslash, it
is returned as is.
backslash with the computer name. If the user does not exist, a SAM
compatible name will be returned using the local hostname as the domain.
Everything is returned lower case
i.e. salt.utils.get_same_name('Administrator') would return 'DOMAIN.COM\Administrator'
i.e. salt.utils.fix_local_user('Administrator') would return 'computername\administrator'
.. note:: Long computer names are truncated to 15 characters
'''
if '\\' not in username:
username = '{0}\\{1}'.format(platform.node(), username)
return username.lower()
try:
sid_obj = win32security.LookupAccountName(None, username)[0]
except pywintypes.error:
return '\\'.join([platform.node()[:15].upper(), username])
username, domain, _ = win32security.LookupAccountSid(None, sid_obj)
return '\\'.join([domain, username])

View file

@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View file

@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
'''
Tests for the spm build utility
'''
# Import python libs
from __future__ import absolute_import
import os
import shutil
import textwrap
# Import Salt Testing libs
from tests.support.case import SPMCase
from tests.support.helpers import destructiveTest
# Import Salt Libraries
import salt.utils
@destructiveTest
class SPMBuildTest(SPMCase):
'''
Validate the spm build command
'''
def setUp(self):
self.config = self._spm_config()
self.formula_dir = os.path.join(' '.join(self.config['file_roots']['base']), 'formulas')
self.formula_sls_dir = os.path.join(self.formula_dir, 'apache')
self.formula_sls = os.path.join(self.formula_sls_dir, 'apache.sls')
self.formula_file = os.path.join(self.formula_dir, 'FORMULA')
dirs = [self.formula_dir, self.formula_sls_dir]
for formula_dir in dirs:
os.makedirs(formula_dir)
with salt.utils.fopen(self.formula_sls, 'w') as fp:
fp.write(textwrap.dedent('''\
install-apache:
pkg.installed:
- name: apache2
'''))
with salt.utils.fopen(self.formula_file, 'w') as fp:
fp.write(textwrap.dedent('''\
name: apache
os: RedHat, Debian, Ubuntu, Suse, FreeBSD
os_family: RedHat, Debian, Suse, FreeBSD
version: 201506
release: 2
summary: Formula for installing Apache
description: Formula for installing Apache
'''))
def test_spm_build(self):
'''
test spm build
'''
build_spm = self.run_spm('build', self.config, self.formula_dir)
spm_file = os.path.join(self.config['spm_build_dir'], 'apache-201506-2.spm')
# Make sure .spm file gets created
self.assertTrue(os.path.exists(spm_file))
# Make sure formula path dir is created
self.assertTrue(os.path.isdir(self.config['formula_path']))
def tearDown(self):
shutil.rmtree(self._tmp_spm)

View file

@ -564,6 +564,49 @@ class ShellCase(ShellTestCase, AdaptedConfigurationTestCaseMixin, ScriptPathMixi
timeout=timeout)
class SPMCase(TestCase, AdaptedConfigurationTestCaseMixin):
'''
Class for handling spm commands
'''
def _spm_config(self):
self._tmp_spm = tempfile.mkdtemp()
config = self.get_temp_config('minion', **{
'spm_logfile': os.path.join(self._tmp_spm, 'log'),
'spm_repos_config': os.path.join(self._tmp_spm, 'etc', 'spm.repos'),
'spm_cache_dir': os.path.join(self._tmp_spm, 'cache'),
'spm_build_dir': os.path.join(self._tmp_spm, 'build'),
'spm_build_exclude': ['.git'],
'spm_db_provider': 'sqlite3',
'spm_files_provider': 'local',
'spm_db': os.path.join(self._tmp_spm, 'packages.db'),
'extension_modules': os.path.join(self._tmp_spm, 'modules'),
'file_roots': {'base': [self._tmp_spm, ]},
'formula_path': os.path.join(self._tmp_spm, 'spm'),
'pillar_path': os.path.join(self._tmp_spm, 'pillar'),
'reactor_path': os.path.join(self._tmp_spm, 'reactor'),
'assume_yes': True,
'force': False,
'verbose': False,
'cache': 'localfs',
'cachedir': os.path.join(self._tmp_spm, 'cache'),
'spm_repo_dups': 'ignore',
'spm_share_dir': os.path.join(self._tmp_spm, 'share'),
})
return config
def _spm_client(self, config):
import salt.spm
ui = salt.spm.SPMCmdlineInterface()
client = salt.spm.SPMClient(ui, config)
return client
def run_spm(self, cmd, config, arg=()):
client = self._spm_client(config)
spm_cmd = client.run([cmd, arg])
return spm_cmd
class ModuleCase(TestCase, SaltClientTestCaseMixin):
'''
Execute a module function

View file

@ -33,11 +33,11 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
'''
Test to verify that a device is mounted.
'''
name = '/mnt/sdb'
device = '/dev/sdb5'
name = os.path.realpath('/mnt/sdb')
device = os.path.realpath('/dev/sdb5')
fstype = 'xfs'
name2 = '/mnt/cifs'
name2 = os.path.realpath('/mnt/cifs')
device2 = '//SERVER/SHARE/'
fstype2 = 'cifs'
opts2 = ['noowners']
@ -62,12 +62,11 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
mock_str = MagicMock(return_value='salt')
mock_user = MagicMock(return_value={'uid': 510})
mock_group = MagicMock(return_value={'gid': 100})
umount1 = ("Forced unmount because devices don't match. "
"Wanted: /dev/sdb6, current: /dev/sdb5, /dev/sdb5")
with patch.dict(mount.__grains__, {'os': 'Darwin'}):
with patch.dict(mount.__salt__, {'mount.active': mock_mnt,
'cmd.run_all': mock_ret,
'mount.umount': mock_f}):
'mount.umount': mock_f}), \
patch('os.path.exists', MagicMock(return_value=True)):
comt = ('Unable to find device with label /dev/sdb5.')
ret.update({'comment': comt})
self.assertDictEqual(mount.mounted(name, 'LABEL=/dev/sdb5',
@ -81,7 +80,7 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
ret)
with patch.dict(mount.__opts__, {'test': False}):
comt = ('Unable to unmount /mnt/sdb: False.')
comt = ('Unable to unmount {0}: False.'.format(name))
umount = ('Forced unmount and mount because'
' options (noowners) changed')
ret.update({'comment': comt, 'result': False,
@ -89,16 +88,19 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
self.assertDictEqual(mount.mounted(name, device, 'nfs'),
ret)
umount1 = ("Forced unmount because devices don't match. "
"Wanted: {0}, current: {1}, {1}".format(os.path.realpath('/dev/sdb6'), device))
comt = ('Unable to unmount')
ret.update({'comment': comt, 'result': None,
'changes': {'umount': umount1}})
self.assertDictEqual(mount.mounted(name, '/dev/sdb6',
self.assertDictEqual(mount.mounted(name, os.path.realpath('/dev/sdb6'),
fstype, opts=[]), ret)
with patch.dict(mount.__salt__, {'mount.active': mock_emt,
'mount.mount': mock_str,
'mount.set_automaster': mock}):
with patch.dict(mount.__opts__, {'test': True}):
with patch.dict(mount.__opts__, {'test': True}), \
patch('os.path.exists', MagicMock(return_value=False)):
comt = ('{0} does not exist and would not be created'.format(name))
ret.update({'comment': comt, 'changes': {}})
self.assertDictEqual(mount.mounted(name, device,
@ -117,14 +119,16 @@ class MountTestCase(TestCase, LoaderModuleMockMixin):
self.assertDictEqual(mount.mounted(name, device,
fstype), ret)
with patch.dict(mount.__opts__, {'test': True}):
with patch.dict(mount.__opts__, {'test': True}), \
patch('os.path.exists', MagicMock(return_value=False)):
comt = ('{0} does not exist and would neither be created nor mounted. '
'{0} needs to be written to the fstab in order to be made persistent.'.format(name))
ret.update({'comment': comt, 'result': None})
self.assertDictEqual(mount.mounted(name, device, fstype,
mount=False), ret)
with patch.dict(mount.__opts__, {'test': False}):
with patch.dict(mount.__opts__, {'test': False}), \
patch('os.path.exists', MagicMock(return_value=False)):
comt = ('{0} not present and not mounted. '
'Entry already exists in the fstab.'.format(name))
ret.update({'comment': comt, 'result': True})

View file

@ -14,6 +14,7 @@ from tests.support.mock import patch, call, NO_MOCK, NO_MOCK_REASON, MagicMock
import salt.master
from tests.support.case import ModuleCase
from salt import auth
import salt.utils
@skipIf(NO_MOCK, NO_MOCK_REASON)
@ -146,6 +147,7 @@ class MasterACLTestCase(ModuleCase):
}
self.addCleanup(delattr, self, 'valid_clear_load')
@skipIf(salt.utils.is_windows(), 'PAM eauth not available on Windows')
def test_master_publish_name(self):
'''
Test to ensure a simple name can auth against a given function.
@ -214,6 +216,7 @@ class MasterACLTestCase(ModuleCase):
self.clear.publish(self.valid_clear_load)
self.assertEqual(self.fire_event_mock.mock_calls, [])
@skipIf(salt.utils.is_windows(), 'PAM eauth not available on Windows')
def test_master_minion_glob(self):
'''
Test to ensure we can allow access to a given
@ -250,6 +253,7 @@ class MasterACLTestCase(ModuleCase):
# Unimplemented
pass
@skipIf(salt.utils.is_windows(), 'PAM eauth not available on Windows')
def test_args_empty_spec(self):
'''
Test simple arg restriction allowed.
@ -267,6 +271,7 @@ class MasterACLTestCase(ModuleCase):
self.clear.publish(self.valid_clear_load)
self.assertEqual(self.fire_event_mock.call_args[0][0]['fun'], 'test.empty')
@skipIf(salt.utils.is_windows(), 'PAM eauth not available on Windows')
def test_args_simple_match(self):
'''
Test simple arg restriction allowed.
@ -287,6 +292,7 @@ class MasterACLTestCase(ModuleCase):
self.clear.publish(self.valid_clear_load)
self.assertEqual(self.fire_event_mock.call_args[0][0]['fun'], 'test.echo')
@skipIf(salt.utils.is_windows(), 'PAM eauth not available on Windows')
def test_args_more_args(self):
'''
Test simple arg restriction allowed to pass unlisted args.
@ -345,6 +351,7 @@ class MasterACLTestCase(ModuleCase):
self.clear.publish(self.valid_clear_load)
self.assertEqual(self.fire_event_mock.mock_calls, [])
@skipIf(salt.utils.is_windows(), 'PAM eauth not available on Windows')
def test_args_kwargs_match(self):
'''
Test simple kwargs restriction allowed.
@ -416,6 +423,7 @@ class MasterACLTestCase(ModuleCase):
self.clear.publish(self.valid_clear_load)
self.assertEqual(self.fire_event_mock.mock_calls, [])
@skipIf(salt.utils.is_windows(), 'PAM eauth not available on Windows')
def test_args_mixed_match(self):
'''
Test mixed args and kwargs restriction allowed.
@ -559,6 +567,7 @@ class AuthACLTestCase(ModuleCase):
}
self.addCleanup(delattr, self, 'valid_clear_load')
@skipIf(salt.utils.is_windows(), 'PAM eauth not available on Windows')
def test_acl_simple_allow(self):
self.clear.publish(self.valid_clear_load)
self.assertEqual(self.auth_check_mock.call_args[0][0],

View file

@ -68,6 +68,141 @@ class LoggerMock(object):
return False
def _master_exec_test(child_pipe):
def _create_master():
'''
Create master instance
:return:
'''
obj = daemons.Master()
obj.config = {'user': 'dummy', 'hash_type': alg}
for attr in ['start_log_info', 'prepare', 'shutdown', 'master']:
setattr(obj, attr, MagicMock())
return obj
_logger = LoggerMock()
ret = True
with patch('salt.cli.daemons.check_user', MagicMock(return_value=True)):
with patch('salt.cli.daemons.log', _logger):
for alg in ['md5', 'sha1']:
_create_master().start()
ret = ret and _logger.messages \
and _logger.has_message('Do not use {alg}'.format(alg=alg),
log_type='warning')
_logger.reset()
for alg in ['sha224', 'sha256', 'sha384', 'sha512']:
_create_master().start()
ret = ret and _logger.messages \
and not _logger.has_message('Do not use ')
child_pipe.send(ret)
child_pipe.close()
def _minion_exec_test(child_pipe):
def _create_minion():
'''
Create minion instance
:return:
'''
obj = daemons.Minion()
obj.config = {'user': 'dummy', 'hash_type': alg}
for attr in ['start_log_info', 'prepare', 'shutdown']:
setattr(obj, attr, MagicMock())
setattr(obj, 'minion', MagicMock(restart=False))
return obj
ret = True
_logger = LoggerMock()
with patch('salt.cli.daemons.check_user', MagicMock(return_value=True)):
with patch('salt.cli.daemons.log', _logger):
for alg in ['md5', 'sha1']:
_create_minion().start()
ret = ret and _logger.messages \
and _logger.has_message('Do not use {alg}'.format(alg=alg),
log_type='warning')
_logger.reset()
for alg in ['sha224', 'sha256', 'sha384', 'sha512']:
_create_minion().start()
ret = ret and _logger.messages \
and not _logger.has_message('Do not use ')
child_pipe.send(ret)
child_pipe.close()
def _proxy_exec_test(child_pipe):
def _create_proxy_minion():
'''
Create proxy minion instance
:return:
'''
obj = daemons.ProxyMinion()
obj.config = {'user': 'dummy', 'hash_type': alg}
for attr in ['minion', 'start_log_info', 'prepare', 'shutdown', 'tune_in']:
setattr(obj, attr, MagicMock())
obj.minion.restart = False
return obj
ret = True
_logger = LoggerMock()
with patch('salt.cli.daemons.check_user', MagicMock(return_value=True)):
with patch('salt.cli.daemons.log', _logger):
for alg in ['md5', 'sha1']:
_create_proxy_minion().start()
ret = ret and _logger.messages \
and _logger.has_message('Do not use {alg}'.format(alg=alg),
log_type='warning')
_logger.reset()
for alg in ['sha224', 'sha256', 'sha384', 'sha512']:
_create_proxy_minion().start()
ret = ret and _logger.messages \
and not _logger.has_message('Do not use ')
child_pipe.send(ret)
child_pipe.close()
def _syndic_exec_test(child_pipe):
def _create_syndic():
'''
Create syndic instance
:return:
'''
obj = daemons.Syndic()
obj.config = {'user': 'dummy', 'hash_type': alg}
for attr in ['syndic', 'start_log_info', 'prepare', 'shutdown']:
setattr(obj, attr, MagicMock())
return obj
ret = True
_logger = LoggerMock()
with patch('salt.cli.daemons.check_user', MagicMock(return_value=True)):
with patch('salt.cli.daemons.log', _logger):
for alg in ['md5', 'sha1']:
_create_syndic().start()
ret = ret and _logger.messages \
and _logger.has_message('Do not use {alg}'.format(alg=alg),
log_type='warning')
_logger.reset()
for alg in ['sha224', 'sha256', 'sha384', 'sha512']:
_create_syndic().start()
ret = ret and _logger.messages \
and not _logger.has_message('Do not use ')
child_pipe.send(ret)
child_pipe.close()
@skipIf(NO_MOCK, NO_MOCK_REASON)
class DaemonsStarterTestCase(TestCase, SaltClientTestCaseMixin):
'''
@ -87,38 +222,7 @@ class DaemonsStarterTestCase(TestCase, SaltClientTestCaseMixin):
:return:
'''
def exec_test(child_pipe):
def _create_master():
'''
Create master instance
:return:
'''
obj = daemons.Master()
obj.config = {'user': 'dummy', 'hash_type': alg}
for attr in ['start_log_info', 'prepare', 'shutdown', 'master']:
setattr(obj, attr, MagicMock())
return obj
_logger = LoggerMock()
ret = True
with patch('salt.cli.daemons.check_user', MagicMock(return_value=True)):
with patch('salt.cli.daemons.log', _logger):
for alg in ['md5', 'sha1']:
_create_master().start()
ret = ret and _logger.messages \
and _logger.has_message('Do not use {alg}'.format(alg=alg),
log_type='warning')
_logger.reset()
for alg in ['sha224', 'sha256', 'sha384', 'sha512']:
_create_master().start()
ret = ret and _logger.messages \
and not _logger.has_message('Do not use ')
child_pipe.send(ret)
child_pipe.close()
self._multiproc_exec_test(exec_test)
self._multiproc_exec_test(_master_exec_test)
def test_minion_daemon_hash_type_verified(self):
'''
@ -126,41 +230,7 @@ class DaemonsStarterTestCase(TestCase, SaltClientTestCaseMixin):
:return:
'''
def exec_test(child_pipe):
def _create_minion():
'''
Create minion instance
:return:
'''
obj = daemons.Minion()
obj.config = {'user': 'dummy', 'hash_type': alg}
for attr in ['start_log_info', 'prepare', 'shutdown']:
setattr(obj, attr, MagicMock())
setattr(obj, 'minion', MagicMock(restart=False))
return obj
ret = True
_logger = LoggerMock()
with patch('salt.cli.daemons.check_user', MagicMock(return_value=True)):
with patch('salt.cli.daemons.log', _logger):
for alg in ['md5', 'sha1']:
_create_minion().start()
ret = ret and _logger.messages \
and _logger.has_message('Do not use {alg}'.format(alg=alg),
log_type='warning')
_logger.reset()
for alg in ['sha224', 'sha256', 'sha384', 'sha512']:
_create_minion().start()
ret = ret and _logger.messages \
and not _logger.has_message('Do not use ')
child_pipe.send(ret)
child_pipe.close()
self._multiproc_exec_test(exec_test)
self._multiproc_exec_test(_minion_exec_test)
def test_proxy_minion_daemon_hash_type_verified(self):
'''
@ -168,41 +238,7 @@ class DaemonsStarterTestCase(TestCase, SaltClientTestCaseMixin):
:return:
'''
def exec_test(child_pipe):
def _create_proxy_minion():
'''
Create proxy minion instance
:return:
'''
obj = daemons.ProxyMinion()
obj.config = {'user': 'dummy', 'hash_type': alg}
for attr in ['minion', 'start_log_info', 'prepare', 'shutdown', 'tune_in']:
setattr(obj, attr, MagicMock())
obj.minion.restart = False
return obj
ret = True
_logger = LoggerMock()
with patch('salt.cli.daemons.check_user', MagicMock(return_value=True)):
with patch('salt.cli.daemons.log', _logger):
for alg in ['md5', 'sha1']:
_create_proxy_minion().start()
ret = ret and _logger.messages \
and _logger.has_message('Do not use {alg}'.format(alg=alg),
log_type='warning')
_logger.reset()
for alg in ['sha224', 'sha256', 'sha384', 'sha512']:
_create_proxy_minion().start()
ret = ret and _logger.messages \
and not _logger.has_message('Do not use ')
child_pipe.send(ret)
child_pipe.close()
self._multiproc_exec_test(exec_test)
self._multiproc_exec_test(_proxy_exec_test)
def test_syndic_daemon_hash_type_verified(self):
'''
@ -210,38 +246,4 @@ class DaemonsStarterTestCase(TestCase, SaltClientTestCaseMixin):
:return:
'''
def exec_test(child_pipe):
def _create_syndic():
'''
Create syndic instance
:return:
'''
obj = daemons.Syndic()
obj.config = {'user': 'dummy', 'hash_type': alg}
for attr in ['syndic', 'start_log_info', 'prepare', 'shutdown']:
setattr(obj, attr, MagicMock())
return obj
ret = True
_logger = LoggerMock()
with patch('salt.cli.daemons.check_user', MagicMock(return_value=True)):
with patch('salt.cli.daemons.log', _logger):
for alg in ['md5', 'sha1']:
_create_syndic().start()
ret = ret and _logger.messages \
and _logger.has_message('Do not use {alg}'.format(alg=alg),
log_type='warning')
_logger.reset()
for alg in ['sha224', 'sha256', 'sha384', 'sha512']:
_create_syndic().start()
ret = ret and _logger.messages \
and not _logger.has_message('Do not use ')
child_pipe.send(ret)
child_pipe.close()
self._multiproc_exec_test(exec_test)
self._multiproc_exec_test(_syndic_exec_test)