Merge branch '2016.3' into 'develop'

Conflicts:
  - salt/beacons/memusage.py
This commit is contained in:
rallytime 2016-03-07 14:13:14 -07:00
commit 7476076ea3
26 changed files with 575 additions and 158 deletions

View File

@ -77,6 +77,51 @@ Platform Changes
.. _`#30555`: https://github.com/saltstack/salt/pull/30555
.. _`#30552`: https://github.com/saltstack/salt/pull/30552
Proxy Minion Changes
====================
As mentioned in earlier documentation, the ``add_proxymodule_to_opts``
configuration variable defaults to ``False`` in this release. This means if you
have proxymodules or other code looking in ``__opts__['proxymodule']`` you
will need to set this variable in your ``/etc/salt/proxy`` file, or
modify your code to use the `__proxy__` injected variable.
The ``__proxyenabled__`` directive now only applies to grains and proxy modules
themselves. Standard execution modules and state modules are not prevented
from loading for proxy minions.
Support has been added to Salt's loader allowing custom proxymodules
to be placed in ``salt://_proxy``. Proxy minions that need these modules
will need to be restarted to pick up any changes. A corresponding runner,
``saltutil.sync_proxymodules``, has been added to sync these modules to minions.
Enhancements in grains processing have made the ``__proxyenabled__`` directive
somewhat redundant in dynamic grains code. It is still required, but best
practices for the ``__virtual__`` function in grains files have changed. It
is now recommended that the ``__virtual__`` functions check to make sure
they are being loaded for the correct proxytype, example below:
.. code-block:: python
def __virtual__():
'''
Only work on proxy
'''
try:
if salt.utils.is_proxy() and \
__opts__['proxy']['proxytype'] == 'ssh_sample':
return __virtualname__
except KeyError:
pass
return False
The try/except block above exists because grains are processed very early
in the proxy minion startup process, sometimes earlier than the proxy
key in the ``__opts__`` dictionary is populated.
New Features
============
@ -102,6 +147,22 @@ Simplified Custom Module Deployment
Improved Mac OS Support
-----------------------
Improved Solarish Support
-------------------------
A lot of work was done to improve support for SmartOS. This work also
resulted in improvements for Solaris and illumos as SmartOS.
- rewrite of :mod:`vmadm module <salt.modules.smartos_vmadm>` (SmartOS)
- rewrite of :mod:`imgadm module <salt.modules.smartos_imgadm>` (SmartOS)
- deprecation of :mod:`virt module <salt.modules.smartos_virt>` in favor of vmadm (SmartOS)
- implemented :mod:`smartos state <salt.states.smartos>` (SmartOS)
- improved :mod:`zpool module <salt.modules.zpool>` add SmartOS, illumos and Solaris support
- improved :mod:`zfs module <salt.modules.zfs>` add SmartOS, illumos and Solaris support
- implemented :mod:`zpool state <salt.states.zpool>`
- implemented :mod:`zfs state <salt.states.zfs>`
- other minor fixes to grains, localmod, ...
Tornado Transport
-----------------

View File

@ -1,7 +1,6 @@
# Need to set a specific version of pyzmq, so can't use the main project's requirements file... have to copy it in and modify...
#-r ../../../requirements/zeromq.txt
-r ../../../requirements/base.txt
M2Crypto
pycrypto
pycrypto>=2.6.1
pyzmq == 13.1.0
-r requirements.txt

View File

@ -40,9 +40,9 @@ def validate(config):
'''
Validate the beacon configuration
'''
# Configuration for diskusage beacon should be a list of dicts
# Configuration for memusage beacon should be a list of dicts
if not isinstance(config, dict):
return False, ('Configuration for diskusage '
return False, ('Configuration for memusage '
'beacon must be a dictionary.')
return True, 'Valid beacon configuration'

View File

@ -1264,13 +1264,7 @@ DEFAULT_MASTER_OPTS = {
DEFAULT_PROXY_MINION_OPTS = {
'conf_file': os.path.join(salt.syspaths.CONFIG_DIR, 'proxy'),
'log_file': os.path.join(salt.syspaths.LOGS_DIR, 'proxy'),
'add_proxymodule_to_opts': True,
# Default multiprocessing to False since anything that needs
# salt.vt will have trouble with our forking model.
# Proxies with non-persistent (mostly REST API) connections
# can change this back to True
'multiprocessing': True
'add_proxymodule_to_opts': False,
}
# ----- Salt Cloud Configuration Defaults ----------------------------------->

View File

@ -24,10 +24,14 @@ GRAINS_CACHE = {}
def __virtual__():
if not salt.utils.is_proxy():
return False
else:
return __virtualname__
try:
if salt.utils.is_proxy() and __opts__['proxy']['proxytype'] == 'esxi':
return __virtualname__
except KeyError:
pass
return False
def esxi():
@ -80,14 +84,19 @@ def _grains():
'''
Get the grains from the proxied device.
'''
host = __pillar__['proxy']['host']
username, password = _find_credentials(host)
protocol = __pillar__['proxy'].get('protocol')
port = __pillar__['proxy'].get('port')
ret = salt.modules.vsphere.system_info(host=host,
username=username,
password=password,
protocol=protocol,
port=port)
GRAINS_CACHE.update(ret)
try:
host = __pillar__['proxy']['host']
if host:
username, password = _find_credentials(host)
protocol = __pillar__['proxy'].get('protocol')
port = __pillar__['proxy'].get('port')
ret = salt.modules.vsphere.system_info(host=host,
username=username,
password=password,
protocol=protocol,
port=port)
GRAINS_CACHE.update(ret)
except KeyError:
pass
return GRAINS_CACHE

View File

@ -24,10 +24,12 @@ GRAINS_CACHE = {}
def __virtual__():
if not salt.utils.is_proxy():
return False
else:
return __virtualname__
try:
if salt.utils.is_proxy() and __opts__['proxy']['proxytype'] == 'fx2':
return __virtualname__
except KeyError:
pass
return False
def _find_credentials():

View File

@ -11,10 +11,13 @@ __virtualname__ = 'rest_sample'
def __virtual__():
if not salt.utils.is_proxy():
return False
else:
return __virtualname__
try:
if salt.utils.is_proxy() and __opts__['proxy']['proxytype'] == 'rest_sample':
return __virtualname__
except KeyError:
pass
return False
def kernel():

View File

@ -14,6 +14,7 @@ import sys
import time
import errno
import signal
import stat
import logging
import multiprocessing
import tempfile
@ -260,7 +261,13 @@ class Maintenance(SignalHandlingMultiprocessingProcess):
dfn = os.path.join(self.opts['cachedir'], '.dfn')
try:
stats = os.stat(dfn)
if stats.st_mode == 0o100400:
# Basic Windows permissions don't distinguish between
# user/group/all. Check for read-only state instead.
if salt.utils.is_windows() and not os.access(dfn, os.W_OK):
to_rotate = True
# Cannot delete read-only files on Windows.
os.chmod(dfn, stat.S_IRUSR | stat.S_IWUSR)
elif stats.st_mode == 0o100400:
to_rotate = True
else:
log.error('Found dropfile with incorrect permissions, ignoring...')
@ -668,6 +675,9 @@ class ReqServer(SignalHandlingMultiprocessingProcess):
dfn = os.path.join(self.opts['cachedir'], '.dfn')
if os.path.isfile(dfn):
try:
if salt.utils.is_windows() and not os.access(dfn, os.W_OK):
# Cannot delete read-only files on Windows.
os.chmod(dfn, stat.S_IRUSR | stat.S_IWUSR)
os.remove(dfn)
except os.error:
pass

View File

@ -533,7 +533,7 @@ class SMinion(MinionBase):
or self.opts.get('use_master_when_local', False)):
if HAS_ZMQ:
zmq.eventloop.ioloop.install()
io_loop = LOOP_CLASS()
io_loop = LOOP_CLASS.current()
io_loop.run_sync(
lambda: self.eval_master(self.opts, failed=True)
)
@ -654,7 +654,7 @@ class MultiMinion(MinionBase):
if HAS_ZMQ:
zmq.eventloop.ioloop.install()
self.io_loop = LOOP_CLASS()
self.io_loop = LOOP_CLASS.current()
def _spawn_minions(self):
'''
@ -756,7 +756,7 @@ class Minion(MinionBase):
if io_loop is None:
if HAS_ZMQ:
zmq.eventloop.ioloop.install()
self.io_loop = LOOP_CLASS()
self.io_loop = LOOP_CLASS.current()
else:
self.io_loop = io_loop

View File

@ -1062,6 +1062,7 @@ def comment_line(path,
:param backup: string
The file extension to give the backup file. Default is ``.bak``
Set to False/None to not keep a backup.
:return: boolean
Returns True if successful, False if not
@ -1191,16 +1192,19 @@ def comment_line(path,
except (OSError, IOError) as exc:
raise CommandExecutionError("Exception: {0}".format(exc))
# Move the backup file to the original directory
backup_name = '{0}{1}'.format(path, backup)
try:
shutil.move(temp_file, backup_name)
except (OSError, IOError) as exc:
raise CommandExecutionError(
"Unable to move the temp file '{0}' to the "
"backup file '{1}'. "
"Exception: {2}".format(path, temp_file, exc)
)
if backup:
# Move the backup file to the original directory
backup_name = '{0}{1}'.format(path, backup)
try:
shutil.move(temp_file, backup_name)
except (OSError, IOError) as exc:
raise CommandExecutionError(
"Unable to move the temp file '{0}' to the "
"backup file '{1}'. "
"Exception: {2}".format(path, temp_file, exc)
)
else:
os.remove(temp_file)
if not salt.utils.is_windows():
check_perms(path, None, pre_user, pre_group, pre_mode)

View File

@ -39,7 +39,7 @@ def _validate_sleep(minutes):
'''
# Must be a value between 1 and 180 or Never/Off
if isinstance(minutes, str):
if minutes.lower() in ['never']:
if minutes.lower() in ['never', 'off']:
return minutes.lower()
else:
msg = '\nMac Power: Invalid String Value for Minutes.\n' \

View File

@ -11,6 +11,7 @@ from datetime import datetime
# Import salt libs
import salt.utils
import salt.utils.mac_utils
from salt.exceptions import CommandExecutionError
__virtualname__ = 'timezone'
@ -55,48 +56,6 @@ def _get_date_time_format(dt_string):
raise CommandExecutionError(msg)
def _execute_return_success(cmd):
'''
Helper function to execute the command
Returns: bool
'''
ret = __salt__['cmd.run_all'](cmd)
if ret['retcode'] != 0:
msg = 'Command failed: {0}'.format(ret['stderr'])
raise CommandExecutionError(msg)
return True
def _execute_return_result(cmd):
ret = __salt__['cmd.run_all'](cmd)
if ret['retcode'] != 0:
msg = 'Command failed: {0}'.format(ret['stderr'])
raise CommandExecutionError(msg)
return ret['stdout']
def _parse_return(data):
'''
Parse a return in the format:
``Time Zone: America/Denver``
to return only:
``America/Denver``
Returns: The value portion of a return
'''
if ': ' in data:
return data.split(': ')[1]
if ':\n' in data:
return data.split(':\n')[1]
else:
return data
def get_date():
'''
Displays the current date
@ -109,8 +68,8 @@ def get_date():
salt '*' timezone.get_date
'''
ret = _execute_return_result('systemsetup -getdate')
return _parse_return(ret)
ret = salt.utils.mac_utils.execute_return_result('systemsetup -getdate')
return salt.utils.mac_utils.parse_return(ret)
def set_date(date):
@ -136,7 +95,7 @@ def set_date(date):
dt_obj = datetime.strptime(date, date_format)
cmd = 'systemsetup -setdate {0}'.format(dt_obj.strftime('%m:%d:%Y'))
_execute_return_success(cmd)
salt.utils.mac_utils.execute_return_success(cmd)
new_date = get_date()
date_format = _get_date_time_format(new_date)
@ -158,8 +117,8 @@ def get_time():
salt '*' timezone.get_time
'''
ret = _execute_return_result('systemsetup -gettime')
return _parse_return(ret)
ret = salt.utils.mac_utils.execute_return_result('systemsetup -gettime')
return salt.utils.mac_utils.parse_return(ret)
def set_time(time):
@ -183,7 +142,7 @@ def set_time(time):
dt_obj = datetime.strptime(time, time_format)
cmd = 'systemsetup -settime {0}'.format(dt_obj.strftime('%H:%M:%S'))
_execute_return_success(cmd)
salt.utils.mac_utils.execute_return_success(cmd)
new_time = get_time()
time_format = _get_date_time_format(new_time)
@ -205,8 +164,8 @@ def get_zone():
salt '*' timezone.get_zone
'''
ret = _execute_return_result('systemsetup -gettimezone')
return _parse_return(ret)
ret = salt.utils.mac_utils.execute_return_result('systemsetup -gettimezone')
return salt.utils.mac_utils.parse_return(ret)
def get_zonecode():
@ -222,7 +181,7 @@ def get_zonecode():
salt '*' timezone.get_zonecode
'''
return _execute_return_result('date +%Z')
return salt.utils.mac_utils.execute_return_result('date +%Z')
def get_offset():
@ -238,7 +197,7 @@ def get_offset():
salt '*' timezone.get_offset
'''
return _execute_return_result('date +%z')
return salt.utils.mac_utils.execute_return_result('date +%z')
def list_zones():
@ -255,8 +214,8 @@ def list_zones():
salt '*' timezone.list_zones
'''
ret = _execute_return_result('systemsetup -listtimezones')
return _parse_return(ret)
ret = salt.utils.mac_utils.execute_return_result('systemsetup -listtimezones')
return salt.utils.mac_utils.parse_return(ret)
def set_zone(time_zone):
@ -279,7 +238,7 @@ def set_zone(time_zone):
return (False, 'Not a valid timezone. '
'Use list_time_zones to find a valid time zone.')
_execute_return_success('systemsetup -settimezone {0}'.format(time_zone))
salt.utils.mac_utils.execute_return_success('systemsetup -settimezone {0}'.format(time_zone))
return time_zone in get_zone()
@ -318,12 +277,8 @@ def get_using_network_time():
salt '*' timezone.get_using_network_time
'''
ret = _execute_return_result('systemsetup -getusingnetworktime')
if _parse_return(ret) == 'On':
return True
else:
return False
ret = salt.utils.mac_utils.execute_return_result('systemsetup -getusingnetworktime')
return salt.utils.mac_utils.validate_enabled(salt.utils.mac_utils.parse_return(ret)) == 'on'
def set_using_network_time(enable):
@ -342,21 +297,12 @@ def set_using_network_time(enable):
salt '*' timezone.set_using_network_time True
'''
if enable not in ['On', 'on', 'Off', 'off', True, False]:
msg = 'Must pass a boolean value. Passed: {0}'.format(enable)
raise CommandExecutionError(msg)
state = salt.utils.mac_utils.validate_enabled(enable)
if enable in ['On', 'on', True]:
enable = 'on'
expect = True
else:
enable = 'off'
expect = False
cmd = 'systemsetup -setusingnetworktime {0}'.format(enable)
cmd = 'systemsetup -setusingnetworktime {0}'.format(state)
salt.utils.mac_utils.execute_return_success(cmd)
_execute_return_success(cmd)
return expect == get_using_network_time()
return state == salt.utils.mac_utils.validate_enabled(get_using_network_time())
def get_time_server():
@ -372,8 +318,8 @@ def get_time_server():
salt '*' timezone.get_time_server
'''
ret = _execute_return_result('systemsetup -getnetworktimeserver')
return _parse_return(ret)
ret = salt.utils.mac_utils.execute_return_result('systemsetup -getnetworktimeserver')
return salt.utils.mac_utils.parse_return(ret)
def set_time_server(time_server='time.apple.com'):
@ -395,6 +341,6 @@ def set_time_server(time_server='time.apple.com'):
salt '*' timezone.set_time_server time.acme.com
'''
cmd = 'systemsetup -setnetworktimeserver {0}'.format(time_server)
_execute_return_success(cmd)
salt.utils.mac_utils.execute_return_success(cmd)
return time_server in get_time_server()

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
'''
Service support for the REST example
Package support for the REST example
'''
from __future__ import absolute_import
@ -11,18 +11,21 @@ import salt.utils
log = logging.getLogger(__name__)
__proxyenabled__ = ['rest_sample']
# Define the module's virtual name
__virtualname__ = 'pkg'
def __virtual__():
'''
Only work on proxy
Only work on systems that are a proxy minion
'''
if salt.utils.is_proxy():
return __virtualname__
return (False, 'The rest_package execution module failed to load: only available on proxy minions.')
try:
if salt.utils.is_proxy() and __opts__['proxy']['proxytype'] == 'rest_sample':
return __virtualname__
except KeyError:
return (False, 'The rest_package execution module failed to load. Check the proxy key in pillar.')
return (False, 'The rest_package execution module failed to load: only works on a rest_sample proxy minion.')
def list_pkgs(versions_as_list=False, **kwargs):
@ -55,6 +58,14 @@ def version(*names, **kwargs):
return str(__proxy__['rest_sample.package_status'](names[0]))
def upgrade(refresh=True, skip_verify=True, **kwargs):
old = __proxy__['rest_sample.package_list']()
new = __proxy__['rest_sample.uptodate']()
pkg_installed = __proxy__['rest_sample.upgrade']()
ret = salt.utils.compare_dicts(old, pkg_installed)
return ret
def installed(
name,
version=None,

View File

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
'''
Utility functions for the rest_sample
'''
from __future__ import absolute_import
__proxyenabled__ = ['rest_sample']
def fix_outage():
'''
"Fix" the outage
CLI Example:
.. code-block:: bash
salt 'rest-sample-proxy' rest_sample.fix_outage
'''
return __proxy__['rest_sample.fix_outage']()

View File

@ -4,9 +4,9 @@ Provide the service module for the proxy-minion REST sample
'''
# Import python libs
from __future__ import absolute_import
import logging
import salt.utils
__proxyenabled__ = ['rest_sample']
import logging
log = logging.getLogger(__name__)
@ -23,9 +23,13 @@ def __virtual__():
'''
Only work on systems that are a proxy minion
'''
if __grains__['os'] == 'proxy':
return __virtualname__
return (False, 'The rest_service execution module failed to load: only available on proxy minions.')
try:
if salt.utils.is_proxy() and __opts__['proxy']['proxytype'] == 'rest_sample':
return __virtualname__
except KeyError:
return (False, 'The rest_service execution module failed to load. Check the proxy key in pillar.')
return (False, 'The rest_service execution module failed to load: only works on a rest_sample proxy minion.')
def get_all():

View File

@ -13,7 +13,6 @@ import salt.utils
log = logging.getLogger(__name__)
__proxyenabled__ = ['ssh_sample']
# Define the module's virtual name
__virtualname__ = 'pkg'
@ -22,9 +21,13 @@ def __virtual__():
'''
Only work on proxy
'''
if salt.utils.is_proxy():
return __virtualname__
return (False, 'THe ssh_service execution module failed to load: only works on a proxy minion.')
try:
if salt.utils.is_proxy() and __opts__['proxy']['proxytype'] == 'ssh_sample':
return __virtualname__
except KeyError:
return (False, 'The ssh_package execution module failed to load. Check the proxy key in pillar.')
return (False, 'The ssh_package execution module failed to load: only works on an ssh_sample proxy minion.')
def list_pkgs(versions_as_list=False, **kwargs):

View File

@ -6,8 +6,7 @@ Provide the service module for the proxy-minion SSH sample
# Import python libs
from __future__ import absolute_import
import logging
__proxyenabled__ = ['ssh_sample']
import salt.utils
log = logging.getLogger(__name__)
@ -15,7 +14,6 @@ __func_alias__ = {
'list_': 'list'
}
# Define the module's virtual name
__virtualname__ = 'service'
@ -24,9 +22,13 @@ def __virtual__():
'''
Only work on systems that are a proxy minion
'''
if __grains__['os'] == 'proxy':
return __virtualname__
return (False, 'ssh_service module cannot be loaded: only available on proxy minions.')
try:
if salt.utils.is_proxy() and __opts__['proxy']['proxytype'] == 'ssh_sample':
return __virtualname__
except KeyError:
return (False, 'The ssh_service execution module failed to load. Check the proxy key in pillar.')
return (False, 'The ssh_service execution module failed to load: only works on an ssh_sample proxy minion.')
def get_all():

View File

@ -624,8 +624,10 @@ def write_pem(text, path, pem_type=None):
salt '*' x509.write_pem "-----BEGIN CERTIFICATE-----MIIGMzCCBBugA..." path=/etc/pki/mycert.crt
'''
old_umask = os.umask(0o77)
text = get_pem_entry(text, pem_type=pem_type)
salt.utils.fopen(path, 'w').write(text)
os.umask(old_umask)
return 'PEM written to {0}'.format(path)

View File

@ -129,7 +129,7 @@ def package_install(name, **kwargs):
Install a "package" on the REST server
'''
cmd = DETAILS['url']+'package/install/'+name
if 'version' in kwargs:
if kwargs.get('version', False):
cmd += '/'+kwargs['version']
else:
cmd += '/1.0'
@ -137,6 +137,20 @@ def package_install(name, **kwargs):
return r['dict']
def fix_outage():
r = salt.utils.http.query(DETAILS['url']+'fix_outage')
return r
def uptodate(name):
'''
Call the REST endpoint to see if the packages on the "server" are up to date.
'''
r = salt.utils.http.query(DETAILS['url']+'package/remove/'+name, decode_type='json', decode=True)
return r['dict']
def package_remove(name):
'''

View File

@ -101,7 +101,7 @@ def package_list():
'''
# Send the command to execute
out, err = DETAILS['server'].sendline('pkg_list')
out, err = DETAILS['server'].sendline('pkg_list\n')
# "scrape" the output and return the right fields as a dict
return parse(out)
@ -112,7 +112,7 @@ def package_install(name, **kwargs):
Install a "package" on the ssh server
'''
cmd = 'pkg_install ' + name
if 'version' in kwargs:
if kwargs.get('version', False):
cmd += ' ' + kwargs['version']
# Send the command to execute

View File

@ -3162,6 +3162,8 @@ def comment(name, regex, char='#', backup='.bak'):
``uncomment`` is called. Meaning the backup will only be useful
after the first invocation.
Set to False/None to not keep a backup.
Usage:
.. code-block:: yaml
@ -3255,6 +3257,8 @@ def uncomment(name, regex, char='#', backup='.bak'):
``uncomment`` is called. Meaning the backup will only be useful
after the first invocation.
Set to False/None to not keep a backup.
Usage:
.. code-block:: yaml

View File

@ -57,7 +57,8 @@ def state(
allow_fail=0,
concurrent=False,
timeout=None,
batch=None):
batch=None,
queue=False):
'''
Invoke a state run on a given target
@ -118,6 +119,9 @@ def state(
for use when multiple state runs can safely be run at the same
Do not use this flag for performance optimization.
queue
Pass ``queue=true`` through to the state function
Examples:
Run a list of sls files via :py:func:`state.sls <salt.state.sls>` on target
@ -195,6 +199,7 @@ def state(
cmd_kw['kwarg']['pillar'] = pillar
cmd_kw['kwarg']['saltenv'] = __env__
cmd_kw['kwarg']['queue'] = queue
if isinstance(concurrent, bool):
cmd_kw['kwarg']['concurrent'] = concurrent

View File

@ -7,12 +7,19 @@ from __future__ import absolute_import
# Import Python Libraries
import logging
import subprocess
import os
# Import Third Party Libs
# Import Salt Libs
import salt.utils
from salt.exceptions import CommandExecutionError, SaltInvocationError
import salt.utils.timed_subprocess
import salt.grains.extra
from salt.exceptions import CommandExecutionError, SaltInvocationError,\
TimedProcTimeoutError
DEFAULT_SHELL = salt.grains.extra.shell()['shell']
# Set up logging
log = logging.getLogger(__name__)
@ -31,6 +38,64 @@ def __virtual__():
return __virtualname__
def _run_all(cmd):
'''
Args:
cmd:
Returns:
'''
run_env = os.environ.copy()
kwargs = {'cwd': None,
'shell': DEFAULT_SHELL,
'env': run_env,
'stdin': None,
'stdout': subprocess.PIPE,
'stderr': subprocess.PIPE,
'with_communicate': True,
'timeout': None,
'bg': False,
}
try:
proc = salt.utils.timed_subprocess.TimedProc(cmd, **kwargs)
except (OSError, IOError) as exc:
raise CommandExecutionError(
'Unable to run command \'{0}\' with the context \'{1}\', '
'reason: {2}'.format(cmd, kwargs, exc)
)
ret = {}
try:
proc.run()
except TimedProcTimeoutError as exc:
ret['stdout'] = str(exc)
ret['stderr'] = ''
ret['retcode'] = 1
ret['pid'] = proc.process.pid
return ret
out, err = proc.stdout, proc.stderr
if out is not None:
out = salt.utils.to_str(out).rstrip()
if err is not None:
err = salt.utils.to_str(err).rstrip()
ret['pid'] = proc.process.pid
ret['retcode'] = proc.process.returncode
ret['stdout'] = out
ret['stderr'] = err
return ret
def execute_return_success(cmd):
'''
Executes the passed command. Returns True if successful
@ -40,7 +105,8 @@ def execute_return_success(cmd):
:return: True if successful, otherwise False
:rtype: bool
'''
ret = __salt__['cmd.run_all'](cmd)
ret = _run_all(cmd)
if 'not supported' in ret['stdout'].lower():
return 'Not supported on this machine'
@ -64,7 +130,7 @@ def execute_return_result(cmd):
an error
:rtype: str
'''
ret = __salt__['cmd.run_all'](cmd)
ret = _run_all(cmd)
if ret['retcode'] != 0:
msg = 'Command failed: {0}'.format(ret['stderr'])

View File

@ -603,20 +603,23 @@ def system_information():
if lin_ver[0]:
return ' '.join(lin_ver)
elif mac_ver[0]:
return ' '.join([mac_ver[0], '-'.join(mac_ver[1]), mac_ver[2]])
if isinstance(mac_ver[1], (tuple, list)) and ''.join(mac_ver[1]):
return ' '.join([mac_ver[0], '.'.join(mac_ver[1]), mac_ver[2]])
else:
return ' '.join([mac_ver[0], mac_ver[2]])
elif win_ver[0]:
return ' '.join(win_ver)
else:
return ''
system = [
('system', platform.system()),
('dist', ' '.join(platform.dist())),
('release', platform.release()),
('machine', platform.machine()),
('version', system_version()),
]
sys_ver = system_version()
if sys_ver:
system.append(('system', sys_ver))
for name, attr in system:
yield name, attr
continue

View File

@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
'''
mac_power tests
'''
# Import python libs
from __future__ import absolute_import
# Import Salt Testing Libs
from salttesting import TestCase, skipIf
from salttesting.helpers import ensure_in_syspath
from salttesting.mock import NO_MOCK, NO_MOCK_REASON
ensure_in_syspath('../../')
# Import Salt Libs
from salt.modules import mac_power
from salt.exceptions import SaltInvocationError
@skipIf(NO_MOCK, NO_MOCK_REASON)
class MacPowerTestCase(TestCase):
'''
test mac_power execution module
'''
def test_validate_sleep_valid_number(self):
'''
test _validate_sleep function with valid number
'''
self.assertEqual(mac_power._validate_sleep(179),
179)
def test_validate_sleep_invalid_number(self):
'''
test _validate_sleep function with invalid number
'''
self.assertRaises(SaltInvocationError,
mac_power._validate_sleep,
181)
def test_validate_sleep_valid_string(self):
'''
test _validate_sleep function with valid string
'''
self.assertEqual(mac_power._validate_sleep('never'),
'never')
self.assertEqual(mac_power._validate_sleep('off'),
'off')
def test_validate_sleep_invalid_string(self):
'''
test _validate_sleep function with invalid string
'''
self.assertRaises(SaltInvocationError,
mac_power._validate_sleep,
'bob')
def test_validate_sleep_bool_true(self):
'''
test _validate_sleep function with True
'''
self.assertRaises(SaltInvocationError,
mac_power._validate_sleep,
True)
def test_validate_sleep_bool_false(self):
'''
test _validate_sleep function with False
'''
self.assertEqual(mac_power._validate_sleep(False),
'never')
def test_validate_sleep_unexpected(self):
'''
test _validate_sleep function with True
'''
self.assertRaises(SaltInvocationError,
mac_power._validate_sleep,
172.7)
if __name__ == '__main__':
from integration import run_tests
run_tests(MacPowerTestCase, needs_daemon=False)

View File

@ -0,0 +1,170 @@
# -*- coding: utf-8 -*-
'''
mac_utils tests
'''
# Import python libs
from __future__ import absolute_import
# Import Salt Testing Libs
from salttesting import TestCase, skipIf
from salttesting.helpers import ensure_in_syspath
from salttesting.mock import MagicMock, patch, NO_MOCK, NO_MOCK_REASON
from salt.ext.six.moves import range
ensure_in_syspath('../../')
# Import Salt Libs
from salt.utils import mac_utils
from salt.exceptions import SaltInvocationError, CommandExecutionError
@skipIf(NO_MOCK, NO_MOCK_REASON)
class MacUtilsTestCase(TestCase):
'''
test mac_utils salt utility
'''
def test_execute_return_success_not_supported(self):
'''
test execute_return_success function
command not supported
'''
mock_cmd = MagicMock(return_value={'retcode': 0,
'stdout': 'not supported'})
with patch.object(mac_utils, '_run_all', mock_cmd):
ret = mac_utils.execute_return_success('dir c:\\')
self.assertEqual(ret, 'Not supported on this machine')
def test_execute_return_success_command_failed(self):
'''
test execute_return_success function
command failed
'''
mock_cmd = MagicMock(return_value={'retcode': 1,
'stdout': 'spongebob'})
with patch.object(mac_utils, '_run_all', mock_cmd):
self.assertRaises(CommandExecutionError,
mac_utils.execute_return_success,
'dir c:\\')
def test_execute_return_success_command_succeeded(self):
'''
test execute_return_success function
command succeeded
'''
mock_cmd = MagicMock(return_value={'retcode': 0,
'stdout': 'spongebob'})
with patch.object(mac_utils, '_run_all', mock_cmd):
ret = mac_utils.execute_return_success('dir c:\\')
self.assertEqual(ret, True)
def test_execute_return_result_command_failed(self):
'''
test execute_return_result function
command failed
'''
mock_cmd = MagicMock(return_value={'retcode': 1,
'stdout': 'spongebob',
'stderr': 'squarepants'})
with patch.object(mac_utils, '_run_all', mock_cmd):
self.assertRaises(CommandExecutionError,
mac_utils.execute_return_result,
'dir c:\\')
def test_execute_return_result_command_succeeded(self):
'''
test execute_return_result function
command succeeded
'''
mock_cmd = MagicMock(return_value={'retcode': 0,
'stdout': 'spongebob'})
with patch.object(mac_utils, '_run_all', mock_cmd):
ret = mac_utils.execute_return_result('dir c:\\')
self.assertEqual(ret, 'spongebob')
def test_parse_return_space(self):
'''
test parse_return function
space after colon
'''
self.assertEqual(mac_utils.parse_return('spongebob: squarepants'),
'squarepants')
def test_parse_return_new_line(self):
'''
test parse_return function
new line after colon
'''
self.assertEqual(mac_utils.parse_return('spongebob:\nsquarepants'),
'squarepants')
def test_parse_return_no_delimiter(self):
'''
test parse_return function
no delimiter
'''
self.assertEqual(mac_utils.parse_return('squarepants'),
'squarepants')
def test_validate_enabled_on(self):
'''
test validate_enabled function
test on
'''
self.assertEqual(mac_utils.validate_enabled('On'),
'on')
def test_validate_enabled_off(self):
'''
test validate_enabled function
test off
'''
self.assertEqual(mac_utils.validate_enabled('Off'),
'off')
def test_validate_enabled_bad_string(self):
'''
test validate_enabled function
test bad string
'''
self.assertRaises(SaltInvocationError,
mac_utils.validate_enabled,
'bad string')
def test_validate_enabled_non_zero(self):
'''
test validate_enabled function
test non zero
'''
for x in range(1, 179, 3):
self.assertEqual(mac_utils.validate_enabled(x),
'on')
def test_validate_enabled_0(self):
'''
test validate_enabled function
test 0
'''
self.assertEqual(mac_utils.validate_enabled(0),
'off')
def test_validate_enabled_true(self):
'''
test validate_enabled function
test True
'''
self.assertEqual(mac_utils.validate_enabled(True),
'on')
def test_validate_enabled_false(self):
'''
test validate_enabled function
test False
'''
self.assertEqual(mac_utils.validate_enabled(False),
'off')
if __name__ == '__main__':
from integration import run_tests
run_tests(MacUtilsTestCase, needs_daemon=False)