mirror of
https://github.com/valitydev/salt.git
synced 2024-11-06 16:45:27 +00:00
Merge branch '2016.3' into 'develop'
Conflicts: - salt/beacons/memusage.py
This commit is contained in:
commit
7476076ea3
@ -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
|
||||
-----------------
|
||||
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
||||
|
@ -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 ----------------------------------->
|
||||
|
@ -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
|
||||
|
@ -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():
|
||||
|
@ -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():
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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' \
|
||||
|
@ -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()
|
||||
|
@ -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,
|
||||
|
21
salt/modules/rest_sample_utils.py
Normal file
21
salt/modules/rest_sample_utils.py
Normal 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']()
|
@ -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():
|
||||
|
@ -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):
|
||||
|
@ -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():
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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):
|
||||
|
||||
'''
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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'])
|
||||
|
@ -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
|
||||
|
84
tests/unit/modules/mac_power_test.py
Normal file
84
tests/unit/modules/mac_power_test.py
Normal 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)
|
170
tests/unit/utils/mac_utils_test.py
Normal file
170
tests/unit/utils/mac_utils_test.py
Normal 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)
|
Loading…
Reference in New Issue
Block a user