mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 08:58:59 +00:00
Merge pull request #47783 from rallytime/merge-2018.3
[2018.3] Merge forward from 2018.3.1 to 2018.3
This commit is contained in:
commit
4a6ca67883
@ -538,6 +538,10 @@
|
||||
# targeted with the normal -N argument to salt-ssh.
|
||||
#ssh_list_nodegroups: {}
|
||||
|
||||
# salt-ssh has the ability to update the flat roster file if a minion is not
|
||||
# found in the roster. Set this to True to enable it.
|
||||
#ssh_update_roster: False
|
||||
|
||||
##### Master Module Management #####
|
||||
##########################################
|
||||
# Manage how master side modules are loaded.
|
||||
|
@ -13,3 +13,13 @@ used as part of a salt-minion process running on the master. This will allow
|
||||
the minion to have pillars assigned to it, and will still allow the engine to
|
||||
create a LocalClient connection to the master ipc sockets to control
|
||||
environments.
|
||||
|
||||
Changes to Automatically Updating the Roster File
|
||||
-------------------------------------------------
|
||||
|
||||
In ``2018.3.0`` salt-ssh was configured to automatically update the flat roster
|
||||
file if a minion was not found for salt-ssh. This was decided to be
|
||||
undesireable as a default. The ``--skip-roster`` flag has been removed and
|
||||
replaced with ``--update-roster``, which will enable salt-ssh to add minions
|
||||
to the flat roster file. This behavior can also be enabled by setting
|
||||
``ssh_update_roster: True`` in the master config file.
|
||||
|
@ -5,6 +5,6 @@ msgpack>=0.5,!=0.5.5
|
||||
PyYAML
|
||||
MarkupSafe
|
||||
requests>=1.0.0
|
||||
tornado>=4.2.1,<5.0
|
||||
tornado>=4.2.1,<6.0
|
||||
# Required by Tornado to handle threads stuff.
|
||||
futures>=2.0
|
||||
|
@ -410,7 +410,7 @@ class SSH(object):
|
||||
'host': hostname,
|
||||
'user': user,
|
||||
}
|
||||
if not self.opts.get('ssh_skip_roster'):
|
||||
if self.opts.get('ssh_update_roster'):
|
||||
self._update_roster()
|
||||
|
||||
def get_pubkey(self):
|
||||
|
@ -1396,14 +1396,12 @@ class RemoteClient(Client):
|
||||
'''
|
||||
Return the metadata derived from the master_tops system
|
||||
'''
|
||||
salt.utils.versions.warn_until(
|
||||
'Magnesium',
|
||||
'The _ext_nodes master function has '
|
||||
'been renamed to _master_tops. To ensure '
|
||||
'compatibility when using older Salt masters '
|
||||
'we continue to pass the function as _ext_nodes.'
|
||||
log.debug(
|
||||
'The _ext_nodes master function has been renamed to _master_tops. '
|
||||
'To ensure compatibility when using older Salt masters we will '
|
||||
'continue to invoke the function as _ext_nodes until the '
|
||||
'Magnesium release.'
|
||||
)
|
||||
|
||||
# TODO: Change back to _master_tops
|
||||
# for Magnesium release
|
||||
load = {'cmd': '_ext_nodes',
|
||||
|
@ -850,7 +850,8 @@ class FSChan(object):
|
||||
self.opts['__fs_update'] = True
|
||||
else:
|
||||
self.fs.update()
|
||||
self.cmd_stub = {'master_tops': {}}
|
||||
self.cmd_stub = {'master_tops': {},
|
||||
'ext_nodes': {}}
|
||||
|
||||
def send(self, load, tries=None, timeout=None, raw=False): # pylint: disable=unused-argument
|
||||
'''
|
||||
|
@ -253,7 +253,7 @@ def file_hash(load, fnd):
|
||||
except OSError:
|
||||
pass
|
||||
return file_hash(load, fnd)
|
||||
if os.path.getmtime(path) == mtime:
|
||||
if str(os.path.getmtime(path)) == mtime:
|
||||
# check if mtime changed
|
||||
ret['hsum'] = hsum
|
||||
return ret
|
||||
|
@ -35,7 +35,7 @@ In case both are provided the `file` entry is preferred.
|
||||
|
||||
.. warning::
|
||||
|
||||
Configuration options will change in Flourine. All options above will be replaced by:
|
||||
Configuration options will change in Fluorine. All options above will be replaced by:
|
||||
|
||||
- kubernetes.kubeconfig or kubernetes.kubeconfig-data
|
||||
- kubernetes.context
|
||||
|
@ -14,7 +14,6 @@ import salt.utils.files
|
||||
import salt.utils.path
|
||||
import salt.utils.platform
|
||||
import salt.utils.stringutils
|
||||
import salt.utils.mac_utils
|
||||
from salt.exceptions import CommandExecutionError
|
||||
from salt.utils.versions import LooseVersion as _LooseVersion
|
||||
|
||||
@ -62,7 +61,7 @@ def _get_service(name):
|
||||
:return: The service information for the service, otherwise an Error
|
||||
:rtype: dict
|
||||
'''
|
||||
services = salt.utils.mac_utils.available_services()
|
||||
services = __utils__['mac_utils.available_services']()
|
||||
name = name.lower()
|
||||
|
||||
if name in services:
|
||||
@ -127,7 +126,7 @@ def launchctl(sub_cmd, *args, **kwargs):
|
||||
|
||||
salt '*' service.launchctl debug org.cups.cupsd
|
||||
'''
|
||||
return salt.utils.mac_utils.launchctl(sub_cmd, *args, **kwargs)
|
||||
return __utils__['mac_utils.launchctl'](sub_cmd, *args, **kwargs)
|
||||
|
||||
|
||||
def list_(name=None, runas=None):
|
||||
@ -158,13 +157,11 @@ def list_(name=None, runas=None):
|
||||
return launchctl('list',
|
||||
label,
|
||||
return_stdout=True,
|
||||
output_loglevel='trace',
|
||||
runas=runas)
|
||||
|
||||
# Collect information on all services: will raise an error if it fails
|
||||
return launchctl('list',
|
||||
return_stdout=True,
|
||||
output_loglevel='trace',
|
||||
runas=runas)
|
||||
|
||||
|
||||
@ -454,7 +451,7 @@ def get_all(runas=None):
|
||||
enabled = get_enabled(runas=runas)
|
||||
|
||||
# Get list of all services
|
||||
available = list(salt.utils.mac_utils.available_services().keys())
|
||||
available = list(__utils__['mac_utils.available_services']().keys())
|
||||
|
||||
# Return composite list
|
||||
return sorted(set(enabled + available))
|
||||
|
@ -627,7 +627,7 @@ def install(pkgs=None, # pylint: disable=R0912,R0913,R0914
|
||||
'''
|
||||
if 'no_chown' in kwargs:
|
||||
salt.utils.versions.warn_until(
|
||||
'Flourine',
|
||||
'Fluorine',
|
||||
'The no_chown argument has been deprecated and is no longer used. '
|
||||
'Its functionality was removed in Boron.')
|
||||
kwargs.pop('no_chown')
|
||||
|
@ -6,8 +6,10 @@ for managing outputters.
|
||||
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import errno
|
||||
import logging
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
@ -168,7 +170,7 @@ def get_printout(out, opts=None, **kwargs):
|
||||
'''
|
||||
try:
|
||||
fileno = sys.stdout.fileno()
|
||||
except AttributeError:
|
||||
except (AttributeError, io.UnsupportedOperation):
|
||||
fileno = -1 # sys.stdout is StringIO or fake
|
||||
return not os.isatty(fileno)
|
||||
|
||||
|
@ -8,7 +8,7 @@ salt.modules.kubernetes for more information.
|
||||
|
||||
.. warning::
|
||||
|
||||
Configuration options will change in Flourine.
|
||||
Configuration options will change in Fluorine.
|
||||
|
||||
The kubernetes module is used to manage different kubernetes resources.
|
||||
|
||||
|
@ -586,7 +586,7 @@ def installed(name,
|
||||
'''
|
||||
if 'no_chown' in kwargs:
|
||||
salt.utils.versions.warn_until(
|
||||
'Flourine',
|
||||
'Fluorine',
|
||||
'The no_chown argument has been deprecated and is no longer used. '
|
||||
'Its functionality was removed in Boron.')
|
||||
kwargs.pop('no_chown')
|
||||
|
@ -2512,13 +2512,21 @@ def latest(
|
||||
'result': None,
|
||||
'comment': '\n'.join(comments)}
|
||||
|
||||
# Build updated list of pkgs to exclude non-targeted ones
|
||||
targeted_pkgs = list(targets.keys()) if pkgs else None
|
||||
if salt.utils.platform.is_windows():
|
||||
# pkg.install execution module on windows ensures the software
|
||||
# package is installed when no version is specified, it does not
|
||||
# upgrade the software to the latest. This is per the design.
|
||||
# Build updated list of pkgs *with verion number*, exclude
|
||||
# non-targeted ones
|
||||
targeted_pkgs = [{x: targets[x]} for x in targets]
|
||||
else:
|
||||
# Build updated list of pkgs to exclude non-targeted ones
|
||||
targeted_pkgs = list(targets)
|
||||
|
||||
# No need to refresh, if a refresh was necessary it would have been
|
||||
# performed above when pkg.latest_version was run.
|
||||
try:
|
||||
# No need to refresh, if a refresh was necessary it would have been
|
||||
# performed above when pkg.latest_version was run.
|
||||
changes = __salt__['pkg.install'](name,
|
||||
changes = __salt__['pkg.install'](name=None,
|
||||
refresh=False,
|
||||
fromrepo=fromrepo,
|
||||
skip_verify=skip_verify,
|
||||
|
@ -137,7 +137,7 @@ def managed(name,
|
||||
'''
|
||||
if 'no_chown' in kwargs:
|
||||
salt.utils.versions.warn_until(
|
||||
'Flourine',
|
||||
'Fluorine',
|
||||
'The no_chown argument has been deprecated and is no longer used. '
|
||||
'Its functionality was removed in Boron.')
|
||||
kwargs.pop('no_chown')
|
||||
|
@ -115,10 +115,10 @@ def installed(name,
|
||||
'''
|
||||
if 'force' in kwargs:
|
||||
salt.utils.versions.warn_until(
|
||||
'Flourine',
|
||||
'Fluorine',
|
||||
'Parameter \'force\' has been detected in the argument list. This'
|
||||
'parameter is no longer used and has been replaced by \'recurse\''
|
||||
'as of Salt 2018.3.0. This warning will be removed in Salt Flourine.'
|
||||
'as of Salt 2018.3.0. This warning will be removed in Salt Fluorine.'
|
||||
)
|
||||
kwargs.pop('force')
|
||||
|
||||
|
@ -603,23 +603,22 @@ class TCPReqServerChannel(salt.transport.mixins.auth.AESReqServerMixin, salt.tra
|
||||
self.payload_handler = payload_handler
|
||||
self.io_loop = io_loop
|
||||
self.serial = salt.payload.Serial(self.opts)
|
||||
if USE_LOAD_BALANCER:
|
||||
self.req_server = LoadBalancerWorker(self.socket_queue,
|
||||
self.handle_message,
|
||||
io_loop=self.io_loop,
|
||||
ssl_options=self.opts.get('ssl'))
|
||||
else:
|
||||
if salt.utils.platform.is_windows():
|
||||
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
_set_tcp_keepalive(self._socket, self.opts)
|
||||
self._socket.setblocking(0)
|
||||
self._socket.bind((self.opts['interface'], int(self.opts['ret_port'])))
|
||||
self.req_server = SaltMessageServer(self.handle_message,
|
||||
io_loop=self.io_loop,
|
||||
ssl_options=self.opts.get('ssl'))
|
||||
self.req_server.add_socket(self._socket)
|
||||
self._socket.listen(self.backlog)
|
||||
with salt.utils.async.current_ioloop(self.io_loop):
|
||||
if USE_LOAD_BALANCER:
|
||||
self.req_server = LoadBalancerWorker(self.socket_queue,
|
||||
self.handle_message,
|
||||
ssl_options=self.opts.get('ssl'))
|
||||
else:
|
||||
if salt.utils.platform.is_windows():
|
||||
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
_set_tcp_keepalive(self._socket, self.opts)
|
||||
self._socket.setblocking(0)
|
||||
self._socket.bind((self.opts['interface'], int(self.opts['ret_port'])))
|
||||
self.req_server = SaltMessageServer(self.handle_message,
|
||||
ssl_options=self.opts.get('ssl'))
|
||||
self.req_server.add_socket(self._socket)
|
||||
self._socket.listen(self.backlog)
|
||||
salt.transport.mixins.auth.AESReqServerMixin.post_fork(self, payload_handler, io_loop)
|
||||
|
||||
@tornado.gen.coroutine
|
||||
@ -704,6 +703,7 @@ class SaltMessageServer(tornado.tcpserver.TCPServer, object):
|
||||
'''
|
||||
def __init__(self, message_handler, *args, **kwargs):
|
||||
super(SaltMessageServer, self).__init__(*args, **kwargs)
|
||||
self.io_loop = tornado.ioloop.IOLoop.current()
|
||||
|
||||
self.clients = []
|
||||
self.message_handler = message_handler
|
||||
@ -807,7 +807,9 @@ class TCPClientKeepAlive(tornado.tcpclient.TCPClient):
|
||||
stream = tornado.iostream.IOStream(
|
||||
sock,
|
||||
max_buffer_size=max_buffer_size)
|
||||
return stream.connect(addr)
|
||||
if tornado.version_info < (5,):
|
||||
return stream.connect(addr)
|
||||
return stream, stream.connect(addr)
|
||||
|
||||
|
||||
class SaltMessageClientPool(salt.transport.MessageClientPool):
|
||||
@ -891,33 +893,33 @@ class SaltMessageClient(object):
|
||||
return
|
||||
self._closing = True
|
||||
if hasattr(self, '_stream') and not self._stream.closed():
|
||||
self._stream.close()
|
||||
if self._read_until_future is not None:
|
||||
# This will prevent this message from showing up:
|
||||
# '[ERROR ] Future exception was never retrieved:
|
||||
# StreamClosedError'
|
||||
# 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.exception()
|
||||
if (not self._stream_return_future.done() and
|
||||
self.io_loop != tornado.ioloop.IOLoop.current(
|
||||
instance=False)):
|
||||
# If _stream_return() hasn't completed, it means the IO
|
||||
# Loop is stopped (such as when using
|
||||
# 'salt.utils.async.SyncWrapper'). Ensure that
|
||||
# _stream_return() completes by restarting the IO Loop.
|
||||
# This will prevent potential errors on shutdown.
|
||||
orig_loop = tornado.ioloop.IOLoop.current()
|
||||
self.io_loop.make_current()
|
||||
try:
|
||||
# If _stream_return() hasn't completed, it means the IO
|
||||
# Loop is stopped (such as when using
|
||||
# 'salt.utils.async.SyncWrapper'). Ensure that
|
||||
# _stream_return() completes by restarting the IO Loop.
|
||||
# This will prevent potential errors on shutdown.
|
||||
try:
|
||||
orig_loop = tornado.ioloop.IOLoop.current()
|
||||
self.io_loop.make_current()
|
||||
self._stream.close()
|
||||
if self._read_until_future is not None:
|
||||
# This will prevent this message from showing up:
|
||||
# '[ERROR ] Future exception was never retrieved:
|
||||
# StreamClosedError'
|
||||
# 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.exception()
|
||||
if (not self._stream_return_future.done() and
|
||||
self.io_loop != tornado.ioloop.IOLoop.current(
|
||||
instance=False)):
|
||||
self.io_loop.add_future(
|
||||
self._stream_return_future,
|
||||
lambda future: self.io_loop.stop()
|
||||
)
|
||||
self.io_loop.start()
|
||||
finally:
|
||||
orig_loop.make_current()
|
||||
finally:
|
||||
orig_loop.make_current()
|
||||
self._tcp_client.close()
|
||||
# Clear callback references to allow the object that they belong to
|
||||
# to be deleted.
|
||||
@ -970,7 +972,8 @@ class SaltMessageClient(object):
|
||||
with salt.utils.async.current_ioloop(self.io_loop):
|
||||
self._stream = yield self._tcp_client.connect(self.host,
|
||||
self.port,
|
||||
ssl_options=self.opts.get('ssl'))
|
||||
ssl_options=self.opts.get('ssl'),
|
||||
**kwargs)
|
||||
self._connecting_future.set_result(True)
|
||||
break
|
||||
except Exception as e:
|
||||
|
@ -2733,9 +2733,9 @@ def cache_nodes_ip(opts, base=None):
|
||||
addresses. Returns a dict.
|
||||
'''
|
||||
salt.utils.versions.warn_until(
|
||||
'Flourine',
|
||||
'Fluorine',
|
||||
'This function is incomplete and non-functional '
|
||||
'and will be removed in Salt Flourine.'
|
||||
'and will be removed in Salt Fluorine.'
|
||||
)
|
||||
if base is None:
|
||||
base = opts['cachedir']
|
||||
|
@ -36,6 +36,11 @@ log = logging.getLogger(__name__)
|
||||
|
||||
__virtualname__ = 'mac_utils'
|
||||
|
||||
__salt__ = {
|
||||
'cmd.run_all': salt.modules.cmdmod._run_all_quiet,
|
||||
'cmd.run': salt.modules.cmdmod._run_quiet,
|
||||
}
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
@ -267,7 +272,8 @@ def launchctl(sub_cmd, *args, **kwargs):
|
||||
|
||||
# Run command
|
||||
kwargs['python_shell'] = False
|
||||
ret = salt.modules.cmdmod.run_all(cmd, **kwargs)
|
||||
kwargs = salt.utils.args.clean_kwargs(**kwargs)
|
||||
ret = __salt__['cmd.run_all'](cmd, **kwargs)
|
||||
|
||||
# Raise an error or return successful result
|
||||
if ret['retcode']:
|
||||
@ -321,7 +327,7 @@ def _available_services():
|
||||
# the system provided plutil program to do the conversion
|
||||
cmd = '/usr/bin/plutil -convert xml1 -o - -- "{0}"'.format(
|
||||
true_path)
|
||||
plist_xml = salt.modules.cmdmod.run(cmd, output_loglevel='quiet')
|
||||
plist_xml = __salt__['cmd.run'](cmd)
|
||||
if six.PY2:
|
||||
plist = plistlib.readPlistFromString(plist_xml)
|
||||
else:
|
||||
|
@ -3078,11 +3078,11 @@ class SaltSSHOptionParser(six.with_metaclass(OptionParserMeta,
|
||||
help='Run command via sudo.'
|
||||
)
|
||||
auth_group.add_option(
|
||||
'--skip-roster',
|
||||
dest='ssh_skip_roster',
|
||||
'--update-roster',
|
||||
dest='ssh_update_roster',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help='If hostname is not found in the roster, do not store the information'
|
||||
help='If hostname is not found in the roster, store the information'
|
||||
'into the default roster file (flat).'
|
||||
)
|
||||
self.add_option_group(auth_group)
|
||||
|
@ -6,7 +6,7 @@ ec2-test:
|
||||
script_args: '-P -Z'
|
||||
ec2-win2012r2-test:
|
||||
provider: ec2-config
|
||||
size: t2.micro
|
||||
size: m1.small
|
||||
image: ami-eb1ecd96
|
||||
smb_port: 445
|
||||
win_installer: ''
|
||||
@ -20,7 +20,7 @@ ec2-win2012r2-test:
|
||||
deploy: True
|
||||
ec2-win2016-test:
|
||||
provider: ec2-config
|
||||
size: t2.micro
|
||||
size: m1.small
|
||||
image: ami-ed14c790
|
||||
smb_port: 445
|
||||
win_installer: ''
|
||||
|
@ -249,6 +249,7 @@ class CMDMODTestCase(TestCase, LoaderModuleMockMixin):
|
||||
self.assertRaises(CommandExecutionError, cmdmod._run, 'foo')
|
||||
|
||||
@skipIf(salt.utils.platform.is_windows(), 'Do not run on Windows')
|
||||
@skipIf(True, 'Test breaks unittests runs')
|
||||
def test_run(self):
|
||||
'''
|
||||
Tests end result when a command is not found
|
||||
|
@ -175,11 +175,8 @@ class MacUtilsTestCase(TestCase):
|
||||
mock_cmd = MagicMock(return_value={'retcode': 0,
|
||||
'stdout': 'success',
|
||||
'stderr': 'none'})
|
||||
with patch('salt.modules.cmdmod.run_all', mock_cmd) as m_run_all:
|
||||
with patch('salt.utils.mac_utils.__salt__', {'cmd.run_all': mock_cmd}):
|
||||
ret = mac_utils.launchctl('enable', 'org.salt.minion')
|
||||
m_run_all.assert_called_with(
|
||||
['launchctl', 'enable', 'org.salt.minion'],
|
||||
python_shell=False)
|
||||
self.assertEqual(ret, True)
|
||||
|
||||
def test_launchctl_return_stdout(self):
|
||||
@ -189,12 +186,10 @@ class MacUtilsTestCase(TestCase):
|
||||
mock_cmd = MagicMock(return_value={'retcode': 0,
|
||||
'stdout': 'success',
|
||||
'stderr': 'none'})
|
||||
with patch('salt.modules.cmdmod.run_all', mock_cmd) as m_run_all:
|
||||
with patch('salt.utils.mac_utils.__salt__', {'cmd.run_all': mock_cmd}):
|
||||
ret = mac_utils.launchctl('enable',
|
||||
'org.salt.minion',
|
||||
return_stdout=True)
|
||||
m_run_all.assert_called_with(['launchctl', 'enable', 'org.salt.minion'],
|
||||
python_shell=False)
|
||||
self.assertEqual(ret, 'success')
|
||||
|
||||
def test_launchctl_error(self):
|
||||
@ -208,13 +203,11 @@ class MacUtilsTestCase(TestCase):
|
||||
'stdout: failure\n' \
|
||||
'stderr: test failure\n' \
|
||||
'retcode: 1'
|
||||
with patch('salt.modules.cmdmod.run_all', mock_cmd) as m_run_all:
|
||||
with patch('salt.utils.mac_utils.__salt__', {'cmd.run_all': mock_cmd}):
|
||||
try:
|
||||
mac_utils.launchctl('enable', 'org.salt.minion')
|
||||
except CommandExecutionError as exc:
|
||||
self.assertEqual(exc.message, error)
|
||||
m_run_all.assert_called_with(['launchctl', 'enable', 'org.salt.minion'],
|
||||
python_shell=False)
|
||||
|
||||
@patch('salt.utils.path.os_walk')
|
||||
@patch('os.path.exists')
|
||||
@ -317,7 +310,7 @@ class MacUtilsTestCase(TestCase):
|
||||
@patch('salt.utils.path.os_walk')
|
||||
@patch('os.path.exists')
|
||||
@patch('plistlib.readPlist')
|
||||
@patch('salt.modules.cmdmod.run')
|
||||
@patch('salt.utils.mac_utils.__salt__')
|
||||
@patch('plistlib.readPlistFromString' if six.PY2 else 'plistlib.loads')
|
||||
def test_available_services_non_xml(self,
|
||||
mock_read_plist_from_string,
|
||||
@ -334,9 +327,15 @@ class MacUtilsTestCase(TestCase):
|
||||
[('/System/Library/LaunchAgents', [], ['com.apple.slla1.plist', 'com.apple.slla2.plist'])],
|
||||
[('/System/Library/LaunchDaemons', [], ['com.apple.slld1.plist', 'com.apple.slld2.plist'])],
|
||||
]
|
||||
attrs = {'cmd.run': MagicMock(return_value='<some xml>')}
|
||||
|
||||
def getitem(name):
|
||||
return attrs[name]
|
||||
|
||||
mock_run.__getitem__.side_effect = getitem
|
||||
mock_run.configure_mock(**attrs)
|
||||
mock_exists.return_value = True
|
||||
mock_read_plist.side_effect = Exception()
|
||||
mock_run.return_value = '<some xml>'
|
||||
mock_read_plist_from_string.side_effect = [
|
||||
MagicMock(Label='com.apple.lla1'),
|
||||
MagicMock(Label='com.apple.lla2'),
|
||||
@ -352,32 +351,24 @@ class MacUtilsTestCase(TestCase):
|
||||
|
||||
cmd = '/usr/bin/plutil -convert xml1 -o - -- "{0}"'
|
||||
calls = [
|
||||
call(cmd.format(os.path.realpath(os.path.join(
|
||||
'/Library/LaunchAgents', 'com.apple.lla1.plist'))),
|
||||
output_loglevel='quiet'),
|
||||
call(cmd.format(os.path.realpath(os.path.join(
|
||||
'/Library/LaunchAgents', 'com.apple.lla2.plist'))),
|
||||
output_loglevel='quiet'),
|
||||
call(cmd.format(os.path.realpath(os.path.join(
|
||||
'/Library/LaunchDaemons', 'com.apple.lld1.plist'))),
|
||||
output_loglevel='quiet'),
|
||||
call(cmd.format(os.path.realpath(os.path.join(
|
||||
'/Library/LaunchDaemons', 'com.apple.lld2.plist'))),
|
||||
output_loglevel='quiet'),
|
||||
call(cmd.format(os.path.realpath(os.path.join(
|
||||
'/System/Library/LaunchAgents', 'com.apple.slla1.plist'))),
|
||||
output_loglevel='quiet'),
|
||||
call(cmd.format(os.path.realpath(os.path.join(
|
||||
'/System/Library/LaunchAgents', 'com.apple.slla2.plist'))),
|
||||
output_loglevel='quiet'),
|
||||
call(cmd.format(os.path.realpath(os.path.join(
|
||||
'/System/Library/LaunchDaemons', 'com.apple.slld1.plist'))),
|
||||
output_loglevel='quiet'),
|
||||
call(cmd.format(os.path.realpath(os.path.join(
|
||||
'/System/Library/LaunchDaemons', 'com.apple.slld2.plist'))),
|
||||
output_loglevel='quiet'),
|
||||
call.cmd.run(cmd.format(os.path.realpath(os.path.join(
|
||||
'/Library/LaunchAgents', 'com.apple.lla1.plist'))),),
|
||||
call.cmd.run(cmd.format(os.path.realpath(os.path.join(
|
||||
'/Library/LaunchAgents', 'com.apple.lla2.plist'))),),
|
||||
call.cmd.run(cmd.format(os.path.realpath(os.path.join(
|
||||
'/Library/LaunchDaemons', 'com.apple.lld1.plist'))),),
|
||||
call.cmd.run(cmd.format(os.path.realpath(os.path.join(
|
||||
'/Library/LaunchDaemons', 'com.apple.lld2.plist'))),),
|
||||
call.cmd.run(cmd.format(os.path.realpath(os.path.join(
|
||||
'/System/Library/LaunchAgents', 'com.apple.slla1.plist'))),),
|
||||
call.cmd.run(cmd.format(os.path.realpath(os.path.join(
|
||||
'/System/Library/LaunchAgents', 'com.apple.slla2.plist'))),),
|
||||
call.cmd.run(cmd.format(os.path.realpath(os.path.join(
|
||||
'/System/Library/LaunchDaemons', 'com.apple.slld1.plist'))),),
|
||||
call.cmd.run(cmd.format(os.path.realpath(os.path.join(
|
||||
'/System/Library/LaunchDaemons', 'com.apple.slld2.plist'))),),
|
||||
]
|
||||
mock_run.assert_has_calls(calls)
|
||||
mock_run.assert_has_calls(calls, any_order=True)
|
||||
|
||||
# Make sure it's a dict with 8 items
|
||||
self.assertTrue(isinstance(ret, dict))
|
||||
@ -404,7 +395,7 @@ class MacUtilsTestCase(TestCase):
|
||||
@patch('salt.utils.path.os_walk')
|
||||
@patch('os.path.exists')
|
||||
@patch('plistlib.readPlist')
|
||||
@patch('salt.modules.cmdmod.run')
|
||||
@patch('salt.utils.mac_utils.__salt__')
|
||||
@patch('plistlib.readPlistFromString' if six.PY2 else 'plistlib.loads')
|
||||
def test_available_services_non_xml_malformed_plist(self,
|
||||
mock_read_plist_from_string,
|
||||
@ -421,41 +412,39 @@ class MacUtilsTestCase(TestCase):
|
||||
[('/System/Library/LaunchAgents', [], ['com.apple.slla1.plist', 'com.apple.slla2.plist'])],
|
||||
[('/System/Library/LaunchDaemons', [], ['com.apple.slld1.plist', 'com.apple.slld2.plist'])],
|
||||
]
|
||||
attrs = {'cmd.run': MagicMock(return_value='<some xml>')}
|
||||
|
||||
def getitem(name):
|
||||
return attrs[name]
|
||||
|
||||
mock_run.__getitem__.side_effect = getitem
|
||||
mock_run.configure_mock(**attrs)
|
||||
mock_exists.return_value = True
|
||||
mock_read_plist.side_effect = Exception()
|
||||
mock_run.return_value = '<some xml>'
|
||||
mock_read_plist_from_string.return_value = 'malformedness'
|
||||
|
||||
ret = mac_utils._available_services()
|
||||
|
||||
cmd = '/usr/bin/plutil -convert xml1 -o - -- "{0}"'
|
||||
calls = [
|
||||
call(cmd.format(os.path.realpath(os.path.join(
|
||||
'/Library/LaunchAgents', 'com.apple.lla1.plist'))),
|
||||
output_loglevel='quiet'),
|
||||
call(cmd.format(os.path.realpath(os.path.join(
|
||||
'/Library/LaunchAgents', 'com.apple.lla2.plist'))),
|
||||
output_loglevel='quiet'),
|
||||
call(cmd.format(os.path.realpath(os.path.join(
|
||||
'/Library/LaunchDaemons', 'com.apple.lld1.plist'))),
|
||||
output_loglevel='quiet'),
|
||||
call(cmd.format(os.path.realpath(os.path.join(
|
||||
'/Library/LaunchDaemons', 'com.apple.lld2.plist'))),
|
||||
output_loglevel='quiet'),
|
||||
call(cmd.format(os.path.realpath(os.path.join(
|
||||
'/System/Library/LaunchAgents', 'com.apple.slla1.plist'))),
|
||||
output_loglevel='quiet'),
|
||||
call(cmd.format(os.path.realpath(os.path.join(
|
||||
'/System/Library/LaunchAgents', 'com.apple.slla2.plist'))),
|
||||
output_loglevel='quiet'),
|
||||
call(cmd.format(os.path.realpath(os.path.join(
|
||||
'/System/Library/LaunchDaemons', 'com.apple.slld1.plist'))),
|
||||
output_loglevel='quiet'),
|
||||
call(cmd.format(os.path.realpath(os.path.join(
|
||||
'/System/Library/LaunchDaemons', 'com.apple.slld2.plist'))),
|
||||
output_loglevel='quiet'),
|
||||
call.cmd.run(cmd.format(os.path.realpath(os.path.join(
|
||||
'/Library/LaunchAgents', 'com.apple.lla1.plist'))),),
|
||||
call.cmd.run(cmd.format(os.path.realpath(os.path.join(
|
||||
'/Library/LaunchAgents', 'com.apple.lla2.plist'))),),
|
||||
call.cmd.run(cmd.format(os.path.realpath(os.path.join(
|
||||
'/Library/LaunchDaemons', 'com.apple.lld1.plist'))),),
|
||||
call.cmd.run(cmd.format(os.path.realpath(os.path.join(
|
||||
'/Library/LaunchDaemons', 'com.apple.lld2.plist'))),),
|
||||
call.cmd.run(cmd.format(os.path.realpath(os.path.join(
|
||||
'/System/Library/LaunchAgents', 'com.apple.slla1.plist'))),),
|
||||
call.cmd.run(cmd.format(os.path.realpath(os.path.join(
|
||||
'/System/Library/LaunchAgents', 'com.apple.slla2.plist'))),),
|
||||
call.cmd.run(cmd.format(os.path.realpath(os.path.join(
|
||||
'/System/Library/LaunchDaemons', 'com.apple.slld1.plist'))),),
|
||||
call.cmd.run(cmd.format(os.path.realpath(os.path.join(
|
||||
'/System/Library/LaunchDaemons', 'com.apple.slld2.plist'))),),
|
||||
]
|
||||
mock_run.assert_has_calls(calls)
|
||||
mock_run.assert_has_calls(calls, any_order=True)
|
||||
|
||||
# Make sure it's a dict with 8 items
|
||||
self.assertTrue(isinstance(ret, dict))
|
||||
|
@ -10,15 +10,19 @@
|
||||
|
||||
# Import python libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
# Import Salt Testing libs
|
||||
import tests.integration as integration
|
||||
from tests.support.unit import TestCase, skipIf
|
||||
from tests.support.mock import patch, NO_MOCK, NO_MOCK_REASON
|
||||
|
||||
# Import Salt libs
|
||||
import salt.modules.cmdmod
|
||||
import salt.version
|
||||
import salt.utils.platform
|
||||
import salt.utils.versions
|
||||
from salt.utils.versions import LooseVersion, StrictVersion
|
||||
|
||||
@ -95,6 +99,40 @@ class VersionTestCase(TestCase):
|
||||
'cmp(%s, %s) should be %s, got %s' %
|
||||
(v1, v2, wanted, res))
|
||||
|
||||
@skipIf(not salt.utils.platform.is_linux(), 'only need to run on linux')
|
||||
def test_spelling_version_name(self):
|
||||
'''
|
||||
check the spelling of the version name for the release
|
||||
names in the salt.utils.versions.warn_until call
|
||||
'''
|
||||
salt_dir = integration.CODE_DIR
|
||||
query = 'salt.utils.versions.warn_until'
|
||||
names = salt.version.SaltStackVersion.NAMES
|
||||
|
||||
salt_dir += '/salt/'
|
||||
cmd = 'grep -lr {0} -A 1 '.format(query) + salt_dir
|
||||
|
||||
grep_call = salt.modules.cmdmod.run_stdout(cmd=cmd).split(os.linesep)
|
||||
|
||||
for line in grep_call:
|
||||
num_cmd = salt.modules.cmdmod.run_stdout('grep -c {0} {1}'.format(query, line))
|
||||
ver_cmd = salt.modules.cmdmod.run_stdout('grep {0} {1} -A 1'.format(query, line))
|
||||
if 'pyc' in line:
|
||||
break
|
||||
|
||||
match = 0
|
||||
for key in names:
|
||||
if key in ver_cmd:
|
||||
match = match + (ver_cmd.count(key))
|
||||
if 'utils/__init__.py' in line:
|
||||
# work around for utils/__init__.py because
|
||||
# it includes the warn_utils function
|
||||
match = match + 1
|
||||
self.assertEqual(match, int(num_cmd), msg='The file: {0} has an '
|
||||
'incorrect spelling for the release name in the warn_utils '
|
||||
'call: {1}. Expecting one of these release names: '
|
||||
'{2}'.format(line, ver_cmd, names))
|
||||
|
||||
|
||||
class VersionFuncsTestCase(TestCase):
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user