mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge remote-tracking branch 'upstream/2015.5' into merge-forward-2015.8
Conflicts: salt/minion.py salt/modules/gpg.py salt/modules/keystone.py salt/modules/pw_user.py salt/states/reg.py setup.py
This commit is contained in:
commit
d3d0e004d9
37 changed files with 2967 additions and 476 deletions
|
@ -215,6 +215,48 @@ If you would like to log to the console instead of to the log file, remove the
|
|||
</topics/installation/osx>` instructions.
|
||||
|
||||
|
||||
Changing Default Paths
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Instead of updating your configuration files to point to the new root directory
|
||||
and having to pass the new configuration directory path to all of Salt's CLI
|
||||
tools, you can explicitly tweak the default system paths that Salt expects:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
GENERATE_SALT_SYSPATHS=1 pip --global-option='--salt-root-dir=/path/to/your/virtualenv/' \
|
||||
install -e ./salt # the path to the salt git clone from above
|
||||
|
||||
|
||||
You can now call all of Salt's CLI tools without explicitly passing the configuration directory.
|
||||
|
||||
Additional Options
|
||||
..................
|
||||
|
||||
In case you want to distribute your virtualenv, you probably don't want to
|
||||
include Salt's clone ``.git/`` directory, and, without it, Salt won't report
|
||||
the accurate version. You can tell ``setup.py`` to generate the hardcoded
|
||||
version information which is distributable:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
GENERATE_SALT_SYSPATHS=1 WRITE_SALT_VERSION=1 pip --global-option='--salt-root-dir=/path/to/your/virtualenv/' \
|
||||
install -e ./salt # the path to the salt git clone from above
|
||||
|
||||
|
||||
Instead of passing those two environmental variables, you can just pass a
|
||||
single one which will trigger the other two:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
MIMIC_SALT_INSTALL=1 pip --global-option='--salt-root-dir=/path/to/your/virtualenv/' \
|
||||
install -e ./salt # the path to the salt git clone from above
|
||||
|
||||
|
||||
This last one will grant you an edditable salt installation with hardcoded
|
||||
system paths and version information.
|
||||
|
||||
|
||||
Installing Salt from the Python Package Index
|
||||
---------------------------------------------
|
||||
|
||||
|
|
|
@ -139,8 +139,8 @@ Install the following software:
|
|||
Download the Prerequisite zip file for your CPU architecture from the
|
||||
SaltStack download site:
|
||||
|
||||
* `Salt32.zip <http://docs.saltstack.com/downloads/windows-deps/Salt32.zip/>`_
|
||||
* `Salt64.zip <http://docs.saltstack.com/downloads/windows-deps/Salt64.zip/>`_
|
||||
* `Salt32.zip <http://repo.saltstack.com/windows/dependencies/Salt32.zip/>`_
|
||||
* `Salt64.zip <http://repo.saltstack.com/windows/dependencies/Salt64.zip/>`_
|
||||
|
||||
These files contain all sofware required to build and develop salt. Unzip the
|
||||
contents of the file to ``C:\Salt-Dev\temp``.
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -73,7 +73,10 @@ start() {
|
|||
RETVAL=1
|
||||
else
|
||||
daemon --pidfile=$PID_FILE --check $SERVICE $SALTAPI $CONFIG_ARGS
|
||||
RETVAL=0
|
||||
RETVAL=$?
|
||||
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/$SERVICE
|
||||
echo
|
||||
return $RETVAL
|
||||
fi
|
||||
fi
|
||||
RETVAL=$?
|
||||
|
@ -97,6 +100,10 @@ stop() {
|
|||
fi
|
||||
else
|
||||
killproc $PROCESS
|
||||
RETVAL=$?
|
||||
echo
|
||||
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$SERVICE
|
||||
return $RETVAL
|
||||
fi
|
||||
RETVAL=$?
|
||||
echo
|
||||
|
|
|
@ -64,6 +64,10 @@ start() {
|
|||
fi
|
||||
else
|
||||
daemon --check $SERVICE $SALTMASTER -d $MASTER_ARGS
|
||||
RETVAL=$?
|
||||
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/$SERVICE
|
||||
echo
|
||||
return $RETVAL
|
||||
fi
|
||||
RETVAL=$?
|
||||
echo
|
||||
|
@ -86,6 +90,10 @@ stop() {
|
|||
fi
|
||||
else
|
||||
killproc $PROCESS
|
||||
RETVAL=$?
|
||||
echo
|
||||
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$SERVICE
|
||||
return $RETVAL
|
||||
fi
|
||||
RETVAL=$?
|
||||
echo
|
||||
|
|
|
@ -68,7 +68,11 @@ start() {
|
|||
RETVAL=$?
|
||||
echo -n "already running"
|
||||
else
|
||||
daemon --check $SERVICE $SALTMINION -d $MINION_ARGS
|
||||
daemon --check $SERVICE $SALTMINION -d $MINION_ARGS
|
||||
RETVAL=$?
|
||||
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/$SERVICE
|
||||
echo
|
||||
return $RETVAL
|
||||
fi
|
||||
fi
|
||||
RETVAL=$?
|
||||
|
@ -94,6 +98,7 @@ stop() {
|
|||
else
|
||||
killproc $PROCESS
|
||||
RETVAL=$?
|
||||
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$SERVICE
|
||||
# tidy up any rogue processes:
|
||||
PROCS=`ps -ef | grep "$SALTMINION" | grep -v grep | awk '{print $2}'`
|
||||
if [ -n "$PROCS" ]; then
|
||||
|
|
|
@ -65,6 +65,10 @@ start() {
|
|||
fi
|
||||
else
|
||||
daemon --check $SERVICE $SALTSYNDIC -d $SYNDIC_ARGS
|
||||
RETVAL=$?
|
||||
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/$SERVICE
|
||||
echo
|
||||
return $RETVAL
|
||||
fi
|
||||
RETVAL=$?
|
||||
echo
|
||||
|
@ -87,6 +91,10 @@ stop() {
|
|||
fi
|
||||
else
|
||||
killproc $PROCESS
|
||||
RETVAL=$?
|
||||
echo
|
||||
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$SERVICE
|
||||
return $RETVAL
|
||||
fi
|
||||
RETVAL=$?
|
||||
echo
|
||||
|
|
|
@ -954,10 +954,10 @@ ARGS = {9}\n'''.format(self.minion_config,
|
|||
pass
|
||||
|
||||
# Execute shim
|
||||
ret = self.shell.exec_cmd('/bin/sh $HOME/{0}'.format(target_shim_file))
|
||||
ret = self.shell.exec_cmd('/bin/sh \'$HOME/{0}\''.format(target_shim_file))
|
||||
|
||||
# Remove shim from target system
|
||||
self.shell.exec_cmd('rm $HOME/{0}'.format(target_shim_file))
|
||||
self.shell.exec_cmd('rm \'$HOME/{0}\''.format(target_shim_file))
|
||||
|
||||
return ret
|
||||
|
||||
|
|
|
@ -1654,7 +1654,6 @@ def request_instance(vm_=None, call=None):
|
|||
}
|
||||
try:
|
||||
rd_data = aws.query(rd_params,
|
||||
return_root=True,
|
||||
location=get_location(),
|
||||
provider=get_provider(),
|
||||
opts=__opts__,
|
||||
|
@ -2363,7 +2362,7 @@ def create(vm_=None, call=None):
|
|||
'volumes': volumes,
|
||||
'zone': ret['placement']['availabilityZone'],
|
||||
'instance_id': ret['instanceId'],
|
||||
'del_all_vols_on_destroy': vm_.get('set_del_all_vols_on_destroy', False)
|
||||
'del_all_vols_on_destroy': vm_.get('del_all_vols_on_destroy', False)
|
||||
},
|
||||
call='action'
|
||||
)
|
||||
|
@ -3780,38 +3779,52 @@ def delete_keypair(kwargs=None, call=None):
|
|||
|
||||
def create_snapshot(kwargs=None, call=None, wait_to_finish=False):
|
||||
'''
|
||||
Create a snapshot
|
||||
Create a snapshot.
|
||||
|
||||
volume_id
|
||||
The ID of the Volume from which to create a snapshot.
|
||||
|
||||
description
|
||||
The optional description of the snapshot.
|
||||
|
||||
CLI Exampe:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt-cloud -f create_snapshot my-ec2-config volume_id=vol-351d8826
|
||||
salt-cloud -f create_snapshot my-ec2-config volume_id=vol-351d8826 \\
|
||||
description="My Snapshot Description"
|
||||
'''
|
||||
if call != 'function':
|
||||
log.error(
|
||||
raise SaltCloudSystemExit(
|
||||
'The create_snapshot function must be called with -f '
|
||||
'or --function.'
|
||||
)
|
||||
return False
|
||||
|
||||
if 'volume_id' not in kwargs:
|
||||
log.error('A volume_id must be specified to create a snapshot.')
|
||||
return False
|
||||
if kwargs is None:
|
||||
kwargs = {}
|
||||
|
||||
if 'description' not in kwargs:
|
||||
kwargs['description'] = ''
|
||||
volume_id = kwargs.get('volume_id', None)
|
||||
description = kwargs.get('description', '')
|
||||
|
||||
params = {'Action': 'CreateSnapshot'}
|
||||
if volume_id is None:
|
||||
raise SaltCloudSystemExit(
|
||||
'A volume_id must be specified to create a snapshot.'
|
||||
)
|
||||
|
||||
if 'volume_id' in kwargs:
|
||||
params['VolumeId'] = kwargs['volume_id']
|
||||
|
||||
if 'description' in kwargs:
|
||||
params['Description'] = kwargs['description']
|
||||
params = {'Action': 'CreateSnapshot',
|
||||
'VolumeId': volume_id,
|
||||
'Description': description}
|
||||
|
||||
log.debug(params)
|
||||
|
||||
data = aws.query(params,
|
||||
return_url=True,
|
||||
return_root=True,
|
||||
location=get_location(),
|
||||
provider=get_provider(),
|
||||
opts=__opts__,
|
||||
sigver='4')
|
||||
sigver='4')[0]
|
||||
|
||||
r_data = {}
|
||||
for d in data:
|
||||
|
@ -3827,7 +3840,7 @@ def create_snapshot(kwargs=None, call=None, wait_to_finish=False):
|
|||
argument_being_watched='status',
|
||||
required_argument_response='completed')
|
||||
|
||||
return data
|
||||
return r_data
|
||||
|
||||
|
||||
def delete_snapshot(kwargs=None, call=None):
|
||||
|
|
|
@ -348,7 +348,7 @@ class AutoKey(object):
|
|||
autosign_dir = os.path.join(self.opts['pki_dir'], 'minions_autosign')
|
||||
|
||||
# cleanup expired files
|
||||
expire_minutes = self.opts.get('autosign_expire_minutes', 10)
|
||||
expire_minutes = self.opts.get('autosign_timeout', 120)
|
||||
if expire_minutes > 0:
|
||||
min_time = time.time() - (60 * int(expire_minutes))
|
||||
for root, dirs, filenames in os.walk(autosign_dir):
|
||||
|
|
|
@ -1558,6 +1558,7 @@ class Minion(MinionBase):
|
|||
del self.pub_channel
|
||||
self._connect_master_future = self.connect_master()
|
||||
self.block_until_connected() # TODO: remove
|
||||
self.functions, self.returners, self.function_errors = self._load_modules()
|
||||
self._fire_master_minion_start()
|
||||
log.info('Minion is ready to receive requests!')
|
||||
|
||||
|
|
|
@ -231,12 +231,25 @@ def create_or_update_alarm(
|
|||
if isinstance(ok_actions, string_types):
|
||||
ok_actions = ok_actions.split(",")
|
||||
|
||||
# convert action names into ARN's
|
||||
alarm_actions = convert_to_arn(alarm_actions, region, key, keyid, profile)
|
||||
insufficient_data_actions = convert_to_arn(
|
||||
insufficient_data_actions, region, key, keyid, profile
|
||||
)
|
||||
ok_actions = convert_to_arn(ok_actions, region, key, keyid, profile)
|
||||
# convert provided action names into ARN's
|
||||
if alarm_actions:
|
||||
alarm_actions = convert_to_arn(alarm_actions,
|
||||
region=region,
|
||||
key=key,
|
||||
keyid=keyid,
|
||||
profile=profile)
|
||||
if insufficient_data_actions:
|
||||
insufficient_data_actions = convert_to_arn(insufficient_data_actions,
|
||||
region=region,
|
||||
key=key,
|
||||
keyid=keyid,
|
||||
profile=profile)
|
||||
if ok_actions:
|
||||
ok_actions = convert_to_arn(ok_actions,
|
||||
region=region,
|
||||
key=key,
|
||||
keyid=keyid,
|
||||
profile=profile)
|
||||
|
||||
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
|
||||
|
||||
|
|
|
@ -276,14 +276,20 @@ def list_tab(user):
|
|||
ret['special'].append(dat)
|
||||
elif line.startswith('#'):
|
||||
# It's a comment! Catch it!
|
||||
comment = line.lstrip('# ')
|
||||
comment_line = line.lstrip('# ')
|
||||
|
||||
# load the identifier if any
|
||||
if SALT_CRON_IDENTIFIER in comment:
|
||||
parts = comment.split(SALT_CRON_IDENTIFIER)
|
||||
comment = parts[0].rstrip()
|
||||
if SALT_CRON_IDENTIFIER in comment_line:
|
||||
parts = comment_line.split(SALT_CRON_IDENTIFIER)
|
||||
comment_line = parts[0].rstrip()
|
||||
# skip leading :
|
||||
if len(parts[1]) > 1:
|
||||
identifier = parts[1][1:]
|
||||
|
||||
if comment is None:
|
||||
comment = comment_line
|
||||
else:
|
||||
comment += '\n' + comment_line
|
||||
elif len(line.split()) > 5:
|
||||
# Appears to be a standard cron line
|
||||
comps = line.split()
|
||||
|
|
|
@ -26,6 +26,14 @@ from salt.exceptions import SaltInvocationError
|
|||
|
||||
# Import 3rd-party libs
|
||||
import salt.ext.six as six
|
||||
try:
|
||||
from shlex import quote as _cmd_quote # pylint: disable=E0611
|
||||
except ImportError:
|
||||
from pipes import quote as _cmd_quote
|
||||
|
||||
from salt.exceptions import (
|
||||
SaltInvocationError
|
||||
)
|
||||
|
||||
# Set up logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
@ -826,15 +834,15 @@ def trust_key(keyid=None,
|
|||
if trust_level not in _VALID_TRUST_LEVELS:
|
||||
return 'ERROR: Valid trust levels - {0}'.format(','.join(_VALID_TRUST_LEVELS))
|
||||
|
||||
cmd = 'echo {0}:{1} | {2} --import-ownertrust'.format(fingerprint,
|
||||
NUM_TRUST_DICT[trust_level],
|
||||
_check_gpg())
|
||||
cmd = 'echo {0}:{1} | {2} --import-ownertrust'.format(_cmd_quote(fingerprint),
|
||||
_cmd_quote(NUM_TRUST_DICT[trust_level]),
|
||||
_cmd_quote(_check_gpg()))
|
||||
_user = user
|
||||
if user == 'salt':
|
||||
homeDir = os.path.join(salt.syspaths.CONFIG_DIR, 'gpgkeys')
|
||||
cmd = '{0} --homedir {1}'.format(cmd, homeDir)
|
||||
_user = 'root'
|
||||
res = __salt__['cmd.run_all'](cmd, runas=_user)
|
||||
res = __salt__['cmd.run_all'](cmd, runas=_user, python_shell=True)
|
||||
|
||||
if not res['retcode'] == 0:
|
||||
ret['res'] = False
|
||||
|
|
|
@ -51,6 +51,7 @@ Module for handling openstack keystone calls.
|
|||
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import
|
||||
import logging
|
||||
|
||||
# Import Salt Libs
|
||||
import salt.ext.six as six
|
||||
|
@ -66,6 +67,8 @@ try:
|
|||
except ImportError:
|
||||
pass
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
|
@ -707,7 +710,13 @@ def user_get(user_id=None, name=None, profile=None, **connection_args):
|
|||
break
|
||||
if not user_id:
|
||||
return {'Error': 'Unable to resolve user id'}
|
||||
user = kstone.users.get(user_id)
|
||||
try:
|
||||
user = kstone.users.get(user_id)
|
||||
except keystoneclient.exceptions.NotFound:
|
||||
msg = 'Could not find user \'{0}\''.format(user_id)
|
||||
log.error(msg)
|
||||
return {'Error': msg}
|
||||
|
||||
ret[user.name] = {'id': user.id,
|
||||
'name': user.name,
|
||||
'email': user.email,
|
||||
|
|
|
@ -391,7 +391,7 @@ def vgremove(vgname):
|
|||
salt mymachine lvm.vgremove vgname
|
||||
salt mymachine lvm.vgremove vgname force=True
|
||||
'''
|
||||
cmd = ['vgremove' '-f', vgname]
|
||||
cmd = ['vgremove', '-f', vgname]
|
||||
out = __salt__['cmd.run'](cmd, python_shell=False)
|
||||
return out.strip()
|
||||
|
||||
|
|
|
@ -130,3 +130,23 @@ def chgid(name, gid):
|
|||
if post_gid != pre_gid:
|
||||
return post_gid == gid
|
||||
return False
|
||||
|
||||
|
||||
def members(name, members_list):
|
||||
'''
|
||||
Replaces members of the group with a provided list.
|
||||
|
||||
.. versionadded:: 2015.5.4
|
||||
|
||||
CLI Example:
|
||||
|
||||
salt '*' group.members foo 'user1,user2,user3,...'
|
||||
|
||||
Replaces a membership list for a local group 'foo'.
|
||||
foo:x:1234:user1,user2,user3,...
|
||||
'''
|
||||
|
||||
retcode = __salt__['cmd.retcode']('pw groupmod {0} -M {1}'.format(
|
||||
name, members_list), python_shell=False)
|
||||
|
||||
return not retcode
|
||||
|
|
|
@ -9,8 +9,9 @@ import copy
|
|||
import logging
|
||||
try:
|
||||
import pwd
|
||||
HAS_PWD = True
|
||||
except ImportError:
|
||||
pass
|
||||
HAS_PWD = False
|
||||
|
||||
# Import 3rd party libs
|
||||
import salt.ext.six as six
|
||||
|
@ -29,7 +30,9 @@ def __virtual__():
|
|||
'''
|
||||
Set the user module if the kernel is FreeBSD
|
||||
'''
|
||||
return __virtualname__ if __grains__['kernel'] == 'FreeBSD' else False
|
||||
if HAS_PWD and __grains__['kernel'] == 'FreeBSD':
|
||||
return __virtualname__
|
||||
return False
|
||||
|
||||
|
||||
def _get_gecos(name):
|
||||
|
|
|
@ -1,29 +1,36 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Manage the registry on Windows.
|
||||
===========================
|
||||
Manage the Windows registry
|
||||
===========================
|
||||
|
||||
The read_key and set_key functions will be updated in Boron to reflect proper
|
||||
registry usage. The registry has three main components. Hives, Keys, and Values.
|
||||
|
||||
### Hives
|
||||
-----
|
||||
Hives
|
||||
-----
|
||||
Hives are the main sections of the registry and all begin with the word HKEY.
|
||||
- HKEY_LOCAL_MACHINE
|
||||
- HKEY_CURRENT_USER
|
||||
- HKEY_USER
|
||||
|
||||
### Keys
|
||||
----
|
||||
Keys
|
||||
----
|
||||
Keys are the folders in the registry. Keys can have many nested subkeys. Keys
|
||||
can have a value assigned to them under the (Default)
|
||||
|
||||
### Values
|
||||
Values are name/data pairs. There can be many values in a key. The (Default)
|
||||
value corresponds to the Key, the rest are their own value pairs.
|
||||
-----------------
|
||||
Values or Entries
|
||||
-----------------
|
||||
Values/Entries are name/data pairs. There can be many values in a key. The
|
||||
(Default) value corresponds to the Key, the rest are their own value pairs.
|
||||
|
||||
:depends: - winreg Python module
|
||||
'''
|
||||
|
||||
# TODO: Figure out the exceptions _winreg can raise and properly catch
|
||||
# them instead of a bare except that catches any exception at all
|
||||
# TODO: Figure out the exceptions _winreg can raise and properly catch them
|
||||
|
||||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
|
@ -142,44 +149,35 @@ def read_key(hkey, path, key=None):
|
|||
key=path,
|
||||
vname=key)
|
||||
|
||||
registry = Registry()
|
||||
hive = registry.hkeys[hkey]
|
||||
|
||||
try:
|
||||
value = _winreg.QueryValue(hive, path)
|
||||
if value:
|
||||
ret['vdata'] = value
|
||||
else:
|
||||
ret['vdata'] = None
|
||||
ret['comment'] = 'Empty Value'
|
||||
except WindowsError as exc: # pylint: disable=E0602
|
||||
log.debug(exc)
|
||||
ret['comment'] = '{0}'.format(exc)
|
||||
ret['success'] = False
|
||||
|
||||
return ret
|
||||
return read_value(hive=hkey, key=path)
|
||||
|
||||
|
||||
def read_value(hive, key, vname=None):
|
||||
r'''
|
||||
Reads a registry value or the default value for a key.
|
||||
Reads a registry value entry or the default value for a key.
|
||||
|
||||
:param hive: string
|
||||
The name of the hive. Can be one of the following
|
||||
- HKEY_LOCAL_MACHINE or HKLM
|
||||
- HKEY_CURRENT_USER or HKCU
|
||||
- HKEY_USER or HKU
|
||||
:param str hive:
|
||||
The name of the hive. Can be one of the following
|
||||
- HKEY_LOCAL_MACHINE or HKLM
|
||||
- HKEY_CURRENT_USER or HKCU
|
||||
- HKEY_USER or HKU
|
||||
|
||||
:param key: string
|
||||
The key (looks like a path) to the value name.
|
||||
:param str key:
|
||||
The key (looks like a path) to the value name.
|
||||
|
||||
:param vname: string
|
||||
The value name. These are the individual name/data pairs under the key. If
|
||||
not passed, the key (Default) value will be returned
|
||||
:param str vname:
|
||||
The value name. These are the individual name/data pairs under the key.
|
||||
If not passed, the key (Default) value will be returned
|
||||
|
||||
:return: dict
|
||||
A dictionary containing the passed settings as well as the value_data if
|
||||
successful. If unsuccessful, sets success to False
|
||||
:return:
|
||||
A dictionary containing the passed settings as well as the value_data if
|
||||
successful. If unsuccessful, sets success to False
|
||||
|
||||
If vname is not passed:
|
||||
- Returns the first unnamed value (Default) as a string.
|
||||
- Returns none if first unnamed value is empty.
|
||||
- Returns False if key not found.
|
||||
:rtype: dict
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -205,9 +203,9 @@ def read_value(hive, key, vname=None):
|
|||
|
||||
try:
|
||||
handle = _winreg.OpenKey(hive, key)
|
||||
value, vtype = _winreg.QueryValueEx(handle, vname)
|
||||
if value:
|
||||
ret['vdata'] = value
|
||||
vdata, vtype = _winreg.QueryValueEx(handle, vname)
|
||||
if vdata:
|
||||
ret['vdata'] = vdata
|
||||
ret['vtype'] = registry.vtype_reverse[vtype]
|
||||
else:
|
||||
ret['comment'] = 'Empty Value'
|
||||
|
@ -257,53 +255,45 @@ def set_key(hkey, path, value, key=None, vtype='REG_DWORD', reflection=True):
|
|||
vdata=value,
|
||||
vtype=vtype)
|
||||
|
||||
registry = Registry()
|
||||
hive = registry.hkeys[hkey]
|
||||
vtype = registry.vtype['REG_SZ']
|
||||
|
||||
try:
|
||||
_winreg.SetValue(hive, path, vtype, value)
|
||||
return True
|
||||
except WindowsError as exc: # pylint: disable=E0602
|
||||
log.error(exc)
|
||||
return False
|
||||
return set_value(hive=hkey, key=path, vdata=value, vtype=vtype)
|
||||
|
||||
|
||||
def set_value(hive, key, vname=None, vdata=None, vtype='REG_SZ', reflection=True):
|
||||
'''
|
||||
Sets a registry value.
|
||||
Sets a registry value entry or the default value for a key.
|
||||
|
||||
:param hive: string
|
||||
The name of the hive. Can be one of the following
|
||||
- HKEY_LOCAL_MACHINE or HKLM
|
||||
- HKEY_CURRENT_USER or HKCU
|
||||
- HKEY_USER or HKU
|
||||
:param str hive:
|
||||
The name of the hive. Can be one of the following
|
||||
- HKEY_LOCAL_MACHINE or HKLM
|
||||
- HKEY_CURRENT_USER or HKCU
|
||||
- HKEY_USER or HKU
|
||||
|
||||
:param key: string
|
||||
The key (looks like a path) to the value name.
|
||||
:param str key:
|
||||
The key (looks like a path) to the value name.
|
||||
|
||||
:param vname: string
|
||||
The value name. These are the individual name/data pairs under the key. If
|
||||
not passed, the key (Default) value will be set.
|
||||
:param str vname:
|
||||
The value name. These are the individual name/data pairs under the key.
|
||||
If not passed, the key (Default) value will be set.
|
||||
|
||||
:param vdata: string
|
||||
The value data to be set.
|
||||
:param str vdata:
|
||||
The value data to be set.
|
||||
|
||||
:param vtype: string
|
||||
The value type. Can be one of the following:
|
||||
- REG_BINARY
|
||||
- REG_DWORD
|
||||
- REG_EXPAND_SZ
|
||||
- REG_MULTI_SZ
|
||||
- REG_SZ
|
||||
:param str vtype:
|
||||
The value type. Can be one of the following:
|
||||
- REG_BINARY
|
||||
- REG_DWORD
|
||||
- REG_EXPAND_SZ
|
||||
- REG_MULTI_SZ
|
||||
- REG_SZ
|
||||
|
||||
:param reflection: boolean
|
||||
A boolean value indicating that the value should also be set in the
|
||||
Wow6432Node portion of the registry. Only applies to 64 bit Windows. This
|
||||
setting is ignored for 32 bit Windows.
|
||||
:param bool reflection:
|
||||
A boolean value indicating that the value should also be set in the
|
||||
Wow6432Node portion of the registry. Only applies to 64 bit Windows.
|
||||
This setting is ignored for 32 bit Windows.
|
||||
|
||||
:return: boolean
|
||||
Returns True if successful, False if not
|
||||
:return:
|
||||
Returns True if successful, False if not
|
||||
:rtype: bool
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -321,7 +311,7 @@ def set_value(hive, key, vname=None, vdata=None, vtype='REG_SZ', reflection=True
|
|||
_winreg.SetValueEx(handle, vname, 0, vtype, vdata)
|
||||
_winreg.CloseKey(handle)
|
||||
return True
|
||||
except WindowsError as exc: # pylint: disable=E0602
|
||||
except (WindowsError, ValueError) as exc: # pylint: disable=E0602
|
||||
log.error(exc)
|
||||
return False
|
||||
|
||||
|
@ -353,7 +343,7 @@ def create_key(hkey, path, key=None, value=None, reflection=True):
|
|||
salt '*' reg.create_key HKEY_CURRENT_USER 'SOFTWARE\\Salt' 'version' '0.97'
|
||||
'''
|
||||
if key: # This if statement will be removed in Boron
|
||||
salt.utils.warn_until('Boron', 'Use reg.set_value to set a registry '
|
||||
salt.utils.warn_until('Boron', 'Use reg.set_value to create a registry '
|
||||
'value. This functionality will be '
|
||||
'removed in Salt Boron')
|
||||
return set_value(hive=hkey,
|
||||
|
@ -362,21 +352,10 @@ def create_key(hkey, path, key=None, value=None, reflection=True):
|
|||
vdata=value,
|
||||
vtype='REG_SZ')
|
||||
|
||||
registry = Registry()
|
||||
hive = registry.hkeys[hkey]
|
||||
key = path
|
||||
access_mask = registry.reflection_mask[reflection]
|
||||
|
||||
try:
|
||||
handle = _winreg.CreateKeyEx(hive, key, 0, access_mask)
|
||||
_winreg.CloseKey(handle)
|
||||
return True
|
||||
except WindowsError as exc: # pylint: disable=E0602
|
||||
log.error(exc)
|
||||
return False
|
||||
return set_value(hive=hkey, key=path)
|
||||
|
||||
|
||||
def delete_key(hkey, path, key=None, reflection=True):
|
||||
def delete_key(hkey, path, key=None, reflection=True, force=False):
|
||||
'''
|
||||
*** Incorrect Usage ***
|
||||
The name of this function is misleading and will be changed to reflect
|
||||
|
@ -396,29 +375,62 @@ def delete_key(hkey, path, key=None, reflection=True):
|
|||
|
||||
Delete a registry key
|
||||
|
||||
Note: This cannot delete a key with subkeys
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' reg.delete_key HKEY_CURRENT_USER 'SOFTWARE\\Salt'
|
||||
|
||||
:param str hkey: (will be changed to hive)
|
||||
The name of the hive. Can be one of the following
|
||||
- HKEY_LOCAL_MACHINE or HKLM
|
||||
- HKEY_CURRENT_USER or HKCU
|
||||
- HKEY_USER or HKU
|
||||
|
||||
:param str path: (will be changed to key)
|
||||
The key (looks like a path) to remove.
|
||||
|
||||
:param str key: (used incorrectly)
|
||||
Will be removed in Boron
|
||||
|
||||
:param bool reflection:
|
||||
A boolean value indicating that the value should also be removed from
|
||||
the Wow6432Node portion of the registry. Only applies to 64 bit Windows.
|
||||
This setting is ignored for 32 bit Windows.
|
||||
|
||||
Only applies to delete value. If the key parameter is passed, this
|
||||
function calls delete_value instead. Will be changed in Boron.
|
||||
|
||||
:param bool force:
|
||||
A boolean value indicating that all subkeys should be removed as well.
|
||||
If this is set to False (default) and there are subkeys, the delete_key
|
||||
function will fail.
|
||||
|
||||
:return:
|
||||
Returns True if successful, False if not
|
||||
If force=True, the results of delete_key_recursive are returned.
|
||||
:rtype: bool
|
||||
'''
|
||||
|
||||
if key: # This if statement will be removed in Boron
|
||||
salt.utils.warn_until('Boron', 'Use reg.set_value to set a registry '
|
||||
'value. This functionality will be '
|
||||
'removed in Salt Boron')
|
||||
salt.utils.warn_until('Boron',
|
||||
'Variable names will be changed to match Windows '
|
||||
'Registry terminology. These changes will be '
|
||||
'made in Boron')
|
||||
return delete_value(hive=hkey,
|
||||
key=path,
|
||||
vname=key,
|
||||
reflection=reflection)
|
||||
|
||||
if force:
|
||||
return delete_key_recursive(hkey, path)
|
||||
|
||||
registry = Registry()
|
||||
hive = registry.hkeys[hkey]
|
||||
key = path
|
||||
|
||||
try:
|
||||
# Can't use delete_value to delete a key
|
||||
_winreg.DeleteKey(hive, key)
|
||||
return True
|
||||
except WindowsError as exc: # pylint: disable=E0602
|
||||
|
@ -426,30 +438,102 @@ def delete_key(hkey, path, key=None, reflection=True):
|
|||
return False
|
||||
|
||||
|
||||
def delete_key_recursive(hive, key):
|
||||
'''
|
||||
.. versionadded:: 2015.5.4
|
||||
|
||||
Delete a registry key to include all subkeys.
|
||||
|
||||
:param hive:
|
||||
The name of the hive. Can be one of the following
|
||||
- HKEY_LOCAL_MACHINE or HKLM
|
||||
- HKEY_CURRENT_USER or HKCU
|
||||
- HKEY_USER or HKU
|
||||
|
||||
:param key:
|
||||
The key to remove (looks like a path)
|
||||
|
||||
:return:
|
||||
A dictionary listing the keys that deleted successfully as well as those
|
||||
that failed to delete.
|
||||
:rtype: dict
|
||||
'''
|
||||
# Functions for traversing the registry tree
|
||||
def subkeys(key):
|
||||
i = 0
|
||||
while True:
|
||||
try:
|
||||
subkey = _winreg.EnumKey(key, i)
|
||||
yield subkey
|
||||
i += 1
|
||||
except WindowsError: # pylint: disable=E0602
|
||||
break
|
||||
|
||||
def traverse_registry_tree(hkey, keypath, ret):
|
||||
key = _winreg.OpenKey(hkey, keypath, 0, _winreg.KEY_READ)
|
||||
for subkeyname in subkeys(key):
|
||||
subkeypath = r'{0}\{1}'.format(keypath, subkeyname)
|
||||
ret = traverse_registry_tree(hkey, subkeypath, ret)
|
||||
ret.append('{0}'.format(subkeypath))
|
||||
return ret
|
||||
|
||||
# Instantiate the registry object
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[hive]
|
||||
keypath = key
|
||||
|
||||
# Get a reverse list of registry keys to be deleted
|
||||
key_list = []
|
||||
key_list = traverse_registry_tree(hkey, keypath, key_list)
|
||||
|
||||
ret = {'Deleted': [],
|
||||
'Failed': []}
|
||||
|
||||
# Delete all subkeys
|
||||
for keypath in key_list:
|
||||
try:
|
||||
_winreg.DeleteKey(hkey, keypath)
|
||||
ret['Deleted'].append(r'{0}\{1}'.format(hive, keypath))
|
||||
except WindowsError as exc: # pylint: disable=E0602
|
||||
log.error(exc)
|
||||
ret['Failed'].append(r'{0}\{1} {2}'.format(hive, key, exc))
|
||||
|
||||
# Delete the key now that all the subkeys are deleted
|
||||
try:
|
||||
_winreg.DeleteKey(hkey, key)
|
||||
ret['Deleted'].append(r'{0}\{1}'.format(hive, key))
|
||||
except WindowsError as exc: # pylint: disable=E0602
|
||||
log.error(exc)
|
||||
ret['Failed'].append(r'{0}\{1} {2}'.format(hive, key, exc))
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def delete_value(hive, key, vname=None, reflection=True):
|
||||
'''
|
||||
Deletes a registry value.
|
||||
Delete a registry value entry or the default value for a key.
|
||||
|
||||
:param hive: string
|
||||
The name of the hive. Can be one of the following
|
||||
- HKEY_LOCAL_MACHINE or HKLM
|
||||
- HKEY_CURRENT_USER or HKCU
|
||||
- HKEY_USER or HKU
|
||||
:param str hive:
|
||||
The name of the hive. Can be one of the following
|
||||
- HKEY_LOCAL_MACHINE or HKLM
|
||||
- HKEY_CURRENT_USER or HKCU
|
||||
- HKEY_USER or HKU
|
||||
|
||||
:param key: string
|
||||
The key (looks like a path) to the value name.
|
||||
:param str key:
|
||||
The key (looks like a path) to the value name.
|
||||
|
||||
:param vname: string
|
||||
The value name. These are the individual name/data pairs under the key. If
|
||||
not passed, the key (Default) value will be deleted.
|
||||
:param str vname:
|
||||
The value name. These are the individual name/data pairs under the key.
|
||||
If not passed, the key (Default) value will be deleted.
|
||||
|
||||
:param reflection: boolean
|
||||
A boolean value indicating that the value should also be set in the
|
||||
Wow6432Node portion of the registry. Only applies to 64 bit Windows. This
|
||||
setting is ignored for 32 bit Windows.
|
||||
:param bool reflection:
|
||||
A boolean value indicating that the value should also be set in the
|
||||
Wow6432Node portion of the registry. Only applies to 64 bit Windows.
|
||||
This setting is ignored for 32 bit Windows.
|
||||
|
||||
:return: boolean
|
||||
Returns True if successful, False if not
|
||||
:return:
|
||||
Returns True if successful, False if not
|
||||
:rtype: bool
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
|
|
@ -97,6 +97,11 @@ def list_(show_all=False, where=None, return_yaml=True):
|
|||
del schedule[job]
|
||||
continue
|
||||
|
||||
# if enabled is not included in the job,
|
||||
# assume job is enabled.
|
||||
if 'enabled' not in schedule[job]:
|
||||
schedule[job]['enabled'] = True
|
||||
|
||||
for item in pycopy.copy(schedule[job]):
|
||||
if item not in SCHEDULE_CONF:
|
||||
del schedule[job][item]
|
||||
|
|
|
@ -9,8 +9,9 @@ import re
|
|||
|
||||
try:
|
||||
import pwd
|
||||
HAS_PWD = True
|
||||
except ImportError:
|
||||
pass
|
||||
HAS_PWD = False
|
||||
import logging
|
||||
import copy
|
||||
|
||||
|
@ -32,10 +33,9 @@ __virtualname__ = 'user'
|
|||
def __virtual__():
|
||||
'''
|
||||
Set the user module if the kernel is Linux, OpenBSD or NetBSD
|
||||
and remove some of the functionality on OS X
|
||||
'''
|
||||
|
||||
if __grains__['kernel'] in ('Linux', 'OpenBSD', 'NetBSD'):
|
||||
if HAS_PWD and __grains__['kernel'] in ('Linux', 'OpenBSD', 'NetBSD'):
|
||||
return __virtualname__
|
||||
return False
|
||||
|
||||
|
|
|
@ -193,7 +193,11 @@ Overriding the alarm values on the resource:
|
|||
attributes:
|
||||
threshold: 2.0
|
||||
'''
|
||||
|
||||
# Import Python Libs
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Import Salt Libs
|
||||
import salt.utils.dictupdate as dictupdate
|
||||
from salt.exceptions import SaltInvocationError
|
||||
import salt.ext.six as six
|
||||
|
@ -307,13 +311,17 @@ def present(
|
|||
ret['result'] = _ret['result']
|
||||
if ret['result'] is False:
|
||||
return ret
|
||||
_ret = _attributes_present(name, attributes, region, key, keyid, profile)
|
||||
ret['changes'] = dictupdate.update(ret['changes'], _ret['changes'])
|
||||
ret['comment'] = ' '.join([ret['comment'], _ret['comment']])
|
||||
if not _ret['result']:
|
||||
ret['result'] = _ret['result']
|
||||
if ret['result'] is False:
|
||||
return ret
|
||||
|
||||
if attributes:
|
||||
_ret = _attributes_present(name, attributes, region, key, keyid, profile)
|
||||
ret['changes'] = dictupdate.update(ret['changes'], _ret['changes'])
|
||||
ret['comment'] = ' '.join([ret['comment'], _ret['comment']])
|
||||
|
||||
if not _ret['result']:
|
||||
ret['result'] = _ret['result']
|
||||
if ret['result'] is False:
|
||||
return ret
|
||||
|
||||
_ret = _health_check_present(name, health_check, region, key, keyid,
|
||||
profile)
|
||||
ret['changes'] = dictupdate.update(ret['changes'], _ret['changes'])
|
||||
|
|
|
@ -125,8 +125,7 @@ from salt.ext.six import string_types
|
|||
import salt.utils
|
||||
from salt.modules.cron import (
|
||||
_needs_change,
|
||||
_cron_matched,
|
||||
SALT_CRON_NO_IDENTIFIER
|
||||
_cron_matched
|
||||
)
|
||||
|
||||
|
||||
|
@ -217,7 +216,7 @@ def present(name,
|
|||
month='*',
|
||||
dayweek='*',
|
||||
comment=None,
|
||||
identifier=None):
|
||||
identifier=False):
|
||||
'''
|
||||
Verifies that the specified cron job is present for the specified user.
|
||||
For more advanced information about what exactly can be set in the cron
|
||||
|
@ -257,8 +256,8 @@ def present(name,
|
|||
edits. This defaults to the state id
|
||||
'''
|
||||
name = ' '.join(name.strip().split())
|
||||
if not identifier:
|
||||
identifier = SALT_CRON_NO_IDENTIFIER
|
||||
if identifier is False:
|
||||
identifier = name
|
||||
ret = {'changes': {},
|
||||
'comment': '',
|
||||
'name': name,
|
||||
|
@ -313,7 +312,7 @@ def present(name,
|
|||
|
||||
def absent(name,
|
||||
user='root',
|
||||
identifier=None,
|
||||
identifier=False,
|
||||
**kwargs):
|
||||
'''
|
||||
Verifies that the specified cron job is absent for the specified user; only
|
||||
|
@ -335,8 +334,8 @@ def absent(name,
|
|||
### of unsupported arguments will result in a traceback.
|
||||
|
||||
name = ' '.join(name.strip().split())
|
||||
if not identifier:
|
||||
identifier = SALT_CRON_NO_IDENTIFIER
|
||||
if identifier is False:
|
||||
identifier = name
|
||||
ret = {'name': name,
|
||||
'result': True,
|
||||
'changes': {},
|
||||
|
|
|
@ -220,8 +220,7 @@ def absent(name, destructive=False):
|
|||
'changes': {},
|
||||
'result': True,
|
||||
'comment': ''}
|
||||
grain = __grains__.get(name)
|
||||
if grain:
|
||||
if name in __grains__:
|
||||
if __opts__['test']:
|
||||
ret['result'] = None
|
||||
if destructive is True:
|
||||
|
|
|
@ -8,10 +8,12 @@ Manage OpenStack configuration file settings.
|
|||
:platform: linux
|
||||
|
||||
'''
|
||||
|
||||
# Import Python Libs
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Import salt libs
|
||||
import salt.exceptions
|
||||
# Import Salt Libs
|
||||
from salt.exceptions import CommandExecutionError
|
||||
|
||||
|
||||
def __virtual__():
|
||||
|
@ -48,18 +50,30 @@ def present(name, filename, section, value, parameter=None):
|
|||
if parameter is None:
|
||||
parameter = name
|
||||
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
'result': False,
|
||||
'comment': ''}
|
||||
|
||||
try:
|
||||
old_value = __salt__['openstack_config.get'](filename=filename,
|
||||
section=section,
|
||||
parameter=parameter)
|
||||
|
||||
if old_value == value:
|
||||
return {'name': name,
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': 'The value is already set to the correct value'}
|
||||
ret['result'] = True
|
||||
ret['comment'] = 'The value is already set to the correct value'
|
||||
return ret
|
||||
|
||||
except salt.exceptions.CommandExecutionError as e:
|
||||
if __opts__['test']:
|
||||
ret['result'] = None
|
||||
ret['comment'] = 'Value \'{0}\' is set to be changed to \'{1}\'.'.format(
|
||||
old_value,
|
||||
value
|
||||
)
|
||||
return ret
|
||||
|
||||
except CommandExecutionError as e:
|
||||
if not str(e).lower().startswith('parameter not found:'):
|
||||
raise
|
||||
|
||||
|
@ -68,10 +82,11 @@ def present(name, filename, section, value, parameter=None):
|
|||
parameter=parameter,
|
||||
value=value)
|
||||
|
||||
return {'name': name,
|
||||
'changes': {'Value': 'Updated'},
|
||||
'result': True,
|
||||
'comment': 'The value has been updated'}
|
||||
ret['changes'] = {'Value': 'Updated'}
|
||||
ret['result'] = True
|
||||
ret['comment'] = 'The value has been updated'
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def absent(name, filename, section, parameter=None):
|
||||
|
@ -92,23 +107,35 @@ def absent(name, filename, section, parameter=None):
|
|||
if parameter is None:
|
||||
parameter = name
|
||||
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
'result': False,
|
||||
'comment': ''}
|
||||
|
||||
try:
|
||||
old_value = __salt__['openstack_config.get'](filename=filename,
|
||||
section=section,
|
||||
parameter=parameter)
|
||||
except salt.exceptions.CommandExecutionError as e:
|
||||
except CommandExecutionError as e:
|
||||
if str(e).lower().startswith('parameter not found:'):
|
||||
return {'name': name,
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': 'The value is already absent'}
|
||||
ret['result'] = True
|
||||
ret['comment'] = 'The value is already absent'
|
||||
return ret
|
||||
raise
|
||||
|
||||
if __opts__['test']:
|
||||
ret['result'] = None
|
||||
ret['comment'] = 'Value \'{0}\' is set to be deleted.'.format(
|
||||
old_value
|
||||
)
|
||||
return ret
|
||||
|
||||
__salt__['openstack_config.delete'](filename=filename,
|
||||
section=section,
|
||||
parameter=parameter)
|
||||
|
||||
return {'name': name,
|
||||
'changes': {'Value': 'Deleted'},
|
||||
'result': True,
|
||||
'comment': 'The value has been deleted'}
|
||||
ret['changes'] = {'Value': 'Deleted'}
|
||||
ret['result'] = True
|
||||
ret['comment'] = 'The value has been deleted'
|
||||
|
||||
return ret
|
||||
|
|
|
@ -59,7 +59,7 @@ def __virtual__():
|
|||
'''
|
||||
Only load if the pip module is available in __salt__
|
||||
'''
|
||||
if HAS_PIP and 'pip.list' in __salt__:
|
||||
if 'pip.list' in __salt__:
|
||||
return __virtualname__
|
||||
return False
|
||||
|
||||
|
@ -100,6 +100,16 @@ def _check_pkg_version_format(pkg):
|
|||
|
||||
ret = {'result': False, 'comment': None,
|
||||
'prefix': None, 'version_spec': None}
|
||||
|
||||
if not HAS_PIP:
|
||||
ret['comment'] = (
|
||||
'An importable pip module is required but could not be found on '
|
||||
'your system. This usually means that the system''s pip package '
|
||||
'is not installed properly.'
|
||||
)
|
||||
|
||||
return ret
|
||||
|
||||
from_vcs = False
|
||||
try:
|
||||
# Get the requirement object from the pip library
|
||||
|
|
|
@ -42,14 +42,14 @@ def __virtual__():
|
|||
return salt.utils.which('rabbitmqctl') is not None
|
||||
|
||||
|
||||
def _check_perms_changes(name, newperms):
|
||||
def _check_perms_changes(name, newperms, runas=None):
|
||||
'''
|
||||
Whether Rabbitmq user's permissions need to be changed
|
||||
'''
|
||||
if not newperms:
|
||||
return False
|
||||
|
||||
existing_perms = __salt__['rabbitmq.list_user_permissions'](name)
|
||||
existing_perms = __salt__['rabbitmq.list_user_permissions'](name, runas=runas)
|
||||
|
||||
perm_need_change = False
|
||||
for vhost_perms in newperms:
|
||||
|
@ -63,14 +63,14 @@ def _check_perms_changes(name, newperms):
|
|||
return perm_need_change
|
||||
|
||||
|
||||
def _check_tags_changes(name, newtags):
|
||||
def _check_tags_changes(name, newtags, runas=None):
|
||||
'''
|
||||
Whether Rabbitmq user's tags need to be changed
|
||||
'''
|
||||
if newtags:
|
||||
if isinstance(newtags, str):
|
||||
newtags = newtags.split()
|
||||
return __salt__['rabbitmq.list_users']()[name] - set(newtags)
|
||||
return __salt__['rabbitmq.list_users'](runas=runas)[name] - set(newtags)
|
||||
else:
|
||||
return []
|
||||
|
||||
|
@ -147,7 +147,7 @@ def present(name,
|
|||
name, runas=runas)
|
||||
changes['old'] += 'Removed password.\n'
|
||||
|
||||
if _check_tags_changes(name, tags):
|
||||
if _check_tags_changes(name, tags, runas=runas):
|
||||
if __opts__['test']:
|
||||
ret['result'] = None
|
||||
ret['comment'] += ('Tags for user {0} '
|
||||
|
@ -158,7 +158,7 @@ def present(name,
|
|||
)
|
||||
changes['new'] += 'Set tags: {0}\n'.format(tags)
|
||||
|
||||
if _check_perms_changes(name, perms):
|
||||
if _check_perms_changes(name, perms, runas=runas):
|
||||
if __opts__['test']:
|
||||
ret['result'] = None
|
||||
ret['comment'] += ('Permissions for user {0} '
|
||||
|
@ -167,7 +167,7 @@ def present(name,
|
|||
for vhost_perm in perms:
|
||||
for vhost, perm in six.iteritems(vhost_perm):
|
||||
result.update(__salt__['rabbitmq.set_permissions'](
|
||||
vhost, name, perm[0], perm[1], perm[2], runas)
|
||||
vhost, name, perm[0], perm[1], perm[2], runas=runas)
|
||||
)
|
||||
changes['new'] += (
|
||||
'Set permissions {0} for vhost {1}'
|
||||
|
|
|
@ -1,11 +1,68 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Manage the registry on Windows
|
||||
r'''
|
||||
===========================
|
||||
Manage the Windows registry
|
||||
===========================
|
||||
Many python developers think of registry keys as if they were python keys in a
|
||||
dictionary which is not the case. The windows registry is broken down into the
|
||||
following components:
|
||||
|
||||
-----
|
||||
Hives
|
||||
-----
|
||||
|
||||
This is the top level of the registry. They all begin with HKEY.
|
||||
- HKEY_CLASSES_ROOT (HKCR)
|
||||
- HKEY_CURRENT_USER(HKCU)
|
||||
- HKEY_LOCAL MACHINE (HKLM)
|
||||
- HKEY_USER (HKU)
|
||||
- HKEY_CURRENT_CONFIG
|
||||
|
||||
----
|
||||
Keys
|
||||
----
|
||||
|
||||
Hives contain keys. These are basically the folders beneath the hives. They can
|
||||
contain any number of subkeys.
|
||||
|
||||
-----------------
|
||||
Values or Entries
|
||||
-----------------
|
||||
|
||||
Values or Entries are the name/data pairs beneath the keys and subkeys. All keys
|
||||
have a default name/data pair. It is usually "(Default)"="(value not set)". The
|
||||
actual value for the name and the date is Null. The registry editor will display
|
||||
"(Default)" and "(value not set)".
|
||||
|
||||
-------
|
||||
Example
|
||||
-------
|
||||
|
||||
The following example is taken from the windows startup portion of the registry:
|
||||
```
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]
|
||||
"RTHDVCPL"="\"C:\\Program Files\\Realtek\\Audio\\HDA\\RtkNGUI64.exe\" -s"
|
||||
"NvBackend"="\"C:\\Program Files (x86)\\NVIDIA Corporation\\Update Core\\NvBackend.exe\""
|
||||
"BTMTrayAgent"="rundll32.exe \"C:\\Program Files (x86)\\Intel\\Bluetooth\\btmshellex.dll\",TrayApp"
|
||||
```
|
||||
In this example these are the values for each:
|
||||
|
||||
Hive: `HKEY_LOCAL_MACHINE`
|
||||
|
||||
Key and subkeys: `SOFTWARE\Microsoft\Windows\CurrentVersion\Run`
|
||||
|
||||
Value:
|
||||
- There are 3 value names: `RTHDVCPL`, `NvBackend`, and `BTMTrayAgent`
|
||||
- Each value name has a corresponding value
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Import python libs
|
||||
import logging
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
@ -23,7 +80,7 @@ def _parse_key_value(key):
|
|||
splt = key.split("\\")
|
||||
hive = splt.pop(0)
|
||||
vname = splt.pop(-1)
|
||||
key = r'\\'.join(splt)
|
||||
key = '\\'.join(splt)
|
||||
return hive, key, vname
|
||||
|
||||
|
||||
|
@ -33,71 +90,149 @@ def _parse_key(key):
|
|||
'''
|
||||
splt = key.split("\\")
|
||||
hive = splt.pop(0)
|
||||
key = r'\\'.join(splt)
|
||||
key = '\\'.join(splt)
|
||||
return hive, key
|
||||
|
||||
|
||||
def present(name, value, vtype='REG_SZ', reflection=True):
|
||||
def present(name, value=None, vname=None, vdata=None, vtype='REG_SZ', reflection=True):
|
||||
'''
|
||||
Set a registry value
|
||||
Ensure a registry key or value is present.
|
||||
|
||||
Optionally set ``reflection`` to ``False`` to disable reflection.
|
||||
``reflection`` has no effect on a 32-bit OS.
|
||||
:param str name:
|
||||
A string value representing the full path of the key to include the
|
||||
HIVE, Key, and all Subkeys. For example:
|
||||
|
||||
In the example below, this will prevent Windows from silently creating
|
||||
the key in:
|
||||
``HKEY_CURRENT_USER\\SOFTWARE\\Wow6432Node\\Salt\\version``
|
||||
``HKEY_LOCAL_MACHINE\\SOFTWARE\\Salt``
|
||||
|
||||
Valid hive values include:
|
||||
- HKEY_CURRENT_USER or HKCU
|
||||
- HKEY_LOCAL_MACHINE or HKLM
|
||||
- HKEY_USERS or HKU
|
||||
|
||||
:param str value:
|
||||
Deprecated. Use vname and vdata instead. Included here for backwards
|
||||
compatability.
|
||||
|
||||
:param str vname:
|
||||
The name of the value you'd like to create beneath the Key. If this
|
||||
parameter is not passed it will assume you want to set the (Default)
|
||||
value
|
||||
|
||||
:param str vdata:
|
||||
The value you'd like to set for the Key. If a value name (vname) is
|
||||
passed, this will be the data for that value name. If not, this will be
|
||||
the (Default) value for the key.
|
||||
|
||||
The type for the (Default) value is always REG_SZ and cannot be changed.
|
||||
This parameter is optional. If not passed, the Key will be created with.
|
||||
|
||||
:param str vtype:
|
||||
The value type for the data you wish to store in the registry. Valid
|
||||
values are:
|
||||
|
||||
- REG_BINARY
|
||||
- REG_DWORD
|
||||
- REG_EXPAND_SZ
|
||||
- REG_MULTI_SZ
|
||||
- REG_SZ (Default)
|
||||
|
||||
:param bool reflection:
|
||||
On 64 bit machines a duplicate value will be created in the
|
||||
``Wow6432Node`` for 32bit programs. This only applies to the SOFTWARE
|
||||
key. This option is ignored on 32bit operating systems. This value
|
||||
defaults to True. Set it to False to disable reflection.
|
||||
|
||||
:return:
|
||||
Returns a dictionary showing the results of the registry operation.
|
||||
:rtype: dict
|
||||
|
||||
The following example will set the ``(Default)`` value for the
|
||||
``SOFTWARE\\Salt`` key in the ``HKEY_CURRENT_USER`` hive to ``0.15.3``. The
|
||||
value will not be reflected in ``Wow6432Node``:
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
HKEY_CURRENT_USER\\SOFTWARE\\Salt\\version:
|
||||
HKEY_CURRENT_USER\\SOFTWARE\\Salt:
|
||||
reg.present:
|
||||
- value: 0.15.3
|
||||
- vtype: REG_SZ
|
||||
- vdata: 0.15.3
|
||||
- reflection: False
|
||||
|
||||
The following example will set the value for the ``version`` entry under the
|
||||
``SOFTWARE\\Salt`` key in the ``HKEY_CURRENT_USER`` hive to ``0.15.3``. The
|
||||
value will be reflected in ``Wow6432Node``:
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
HKEY_CURRENT_USER\\SOFTWARE\\Salt:
|
||||
reg.present:
|
||||
- vname: version
|
||||
- vdata: 0.15.3
|
||||
|
||||
In the above example the path is interpreted as follows:
|
||||
- ``HKEY_CURRENT_USER`` is the hive
|
||||
- ``SOFTWARE\\Salt`` is the key
|
||||
- ``version`` is the value name
|
||||
So ``version`` will be created in the ``SOFTWARE\\Salt`` key in the
|
||||
``HKEY_CURRENT_USER`` hive and given the ``REG_SZ`` value of ``0.15.3``.
|
||||
- ``vname`` is the value name ('version') that will be created under the key
|
||||
- ``vdata`` is the data that will be assigned to 'version'
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'result': True,
|
||||
'changes': {},
|
||||
'comment': ''}
|
||||
|
||||
hive, key, vname = _parse_key_value(name)
|
||||
# This is for backwards compatibility
|
||||
# If 'value' is passed a value, vdata becomes value and the vname is
|
||||
# obtained from the key path
|
||||
if value:
|
||||
hive, key, vname = _parse_key_value(name)
|
||||
vdata = value
|
||||
ret['comment'] = 'State file is using deprecated syntax. Please update.'
|
||||
salt.utils.warn_until(
|
||||
'Boron',
|
||||
'The \'value\' argument has been deprecated. '
|
||||
'Please use vdata instead.'
|
||||
)
|
||||
else:
|
||||
hive, key = _parse_key(name)
|
||||
|
||||
# Determine what to do
|
||||
if value == __salt__['reg.read_value'](hive, key, vname)['vdata']:
|
||||
ret['comment'] = '{0} is already configured'.format(name)
|
||||
reg_current = __salt__['reg.read_value'](hive, key, vname)
|
||||
|
||||
if vdata == reg_current['vdata'] and reg_current['success']:
|
||||
ret['comment'] = '{0} in {1} is already configured'.\
|
||||
format(vname if vname else '(Default)', name)
|
||||
return ret
|
||||
else:
|
||||
ret['changes'] = {'reg': 'configured to {0}'.format(value)}
|
||||
|
||||
add_change = {'Key': r'{0}\{1}'.format(hive, key),
|
||||
'Entry': '{0}'.format(vname if vname else '(Default)'),
|
||||
'Value': '{0}'.format(vdata if vdata else '(Empty String)')}
|
||||
|
||||
# Check for test option
|
||||
if __opts__['test']:
|
||||
ret['result'] = None
|
||||
ret['changes'] = {'reg': {'Will add': add_change}}
|
||||
return ret
|
||||
|
||||
# Configure the value
|
||||
ret['result'] = __salt__['reg.set_value'](hive, key, vname, value, vtype,
|
||||
ret['result'] = __salt__['reg.set_value'](hive, key, vname, vdata, vtype,
|
||||
reflection)
|
||||
|
||||
if not ret:
|
||||
if not ret['result']:
|
||||
ret['changes'] = {}
|
||||
ret['comment'] = 'could not configure the registry key'
|
||||
ret['comment'] = r'Failed to add {0} to {1}\{2}'.format(name, hive, key)
|
||||
else:
|
||||
ret['changes'] = {'reg': {'Added': add_change}}
|
||||
ret['comment'] = r'Added {0} to {1}\{2}'.format(name, hive, key)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def absent(name):
|
||||
def absent(name, vname=None):
|
||||
'''
|
||||
Remove a registry value
|
||||
Ensure a registry value is removed. To remove a key use key_absent.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -118,14 +253,89 @@ def absent(name):
|
|||
'changes': {},
|
||||
'comment': ''}
|
||||
|
||||
hive, key, vname = _parse_key_value(name)
|
||||
hive, key = _parse_key(name)
|
||||
|
||||
# Determine what to do
|
||||
if not __salt__['reg.read_value'](hive, key, vname)['success']:
|
||||
hive, key, vname = _parse_key_value(name)
|
||||
if not __salt__['reg.read_value'](hive, key, vname)['success']:
|
||||
ret['comment'] = '{0} is already absent'.format(name)
|
||||
return ret
|
||||
|
||||
remove_change = {'Key': r'{0}\{1}'.format(hive, key),
|
||||
'Entry': '{0}'.format(vname if vname else '(Default)')}
|
||||
|
||||
# Check for test option
|
||||
if __opts__['test']:
|
||||
ret['result'] = None
|
||||
ret['changes'] = {'reg': {'Will remove': remove_change}}
|
||||
return ret
|
||||
|
||||
# Delete the value
|
||||
ret['result'] = __salt__['reg.delete_value'](hive, key, vname)
|
||||
if not ret['result']:
|
||||
ret['changes'] = {}
|
||||
ret['comment'] = r'Failed to remove {0} from {1}\{2}'.format(name, hive,
|
||||
key)
|
||||
else:
|
||||
ret['changes'] = {'reg': {'Removed': remove_change}}
|
||||
ret['comment'] = r'Removed {0} from {1}\{2}'.format(name, hive, key)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def key_absent(name, force=False):
|
||||
r'''
|
||||
.. versionadded:: 2015.5.4
|
||||
|
||||
Ensure a registry key is removed. This will remove a key and all value
|
||||
entries it contains. It will fail if the key contains subkeys.
|
||||
|
||||
:param str name:
|
||||
A string representing the full path to the key to be removed to include
|
||||
the hive and the keypath. The hive can be any of the following:
|
||||
- HKEY_LOCAL_MACHINE or HKLM
|
||||
- HKEY_CURRENT_USER or HKCU
|
||||
- HKEY_USER or HKU
|
||||
|
||||
:param bool force:
|
||||
A boolean value indicating that all subkeys should be deleted with the
|
||||
key. If force=False and subkeys exists beneath the key you want to
|
||||
delete, key_absent will fail. Use with caution. The default is False.
|
||||
|
||||
:return:
|
||||
Returns a dictionary showing the results of the registry operation.
|
||||
:rtype: dict
|
||||
|
||||
The following example will delete the ``SOFTWARE\Salt`` key and all subkeys
|
||||
under the ``HKEY_CURRENT_USER`` hive.
|
||||
|
||||
Example::
|
||||
|
||||
'HKEY_CURRENT_USER\SOFTWARE\Salt':
|
||||
reg.key_absent:
|
||||
- force: True
|
||||
|
||||
In the above example the path is interpreted as follows:
|
||||
- ``HKEY_CURRENT_USER`` is the hive
|
||||
- ``SOFTWARE\Salt`` is the key
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'result': True,
|
||||
'changes': {},
|
||||
'comment': ''}
|
||||
|
||||
hive, key = _parse_key(name)
|
||||
|
||||
# Determine what to do
|
||||
if not __salt__['reg.read_value'](hive, key)['success']:
|
||||
ret['comment'] = '{0} is already absent'.format(name)
|
||||
return ret
|
||||
else:
|
||||
ret['changes'] = {'reg': 'Removed {0}'.format(name)}
|
||||
|
||||
ret['changes'] = {'reg': {
|
||||
'Removed': {
|
||||
'Key': r'{0}\{1}'.format(hive, key)
|
||||
}}}
|
||||
|
||||
# Check for test option
|
||||
if __opts__['test']:
|
||||
|
@ -133,9 +343,10 @@ def absent(name):
|
|||
return ret
|
||||
|
||||
# Delete the value
|
||||
ret['result'] = __salt__['reg.delete_value'](hive, key, vname)
|
||||
if not ret['result']:
|
||||
__salt__['reg.delete_key'](hive, key, force=force)
|
||||
if __salt__['reg.read_value'](hive, key)['success']:
|
||||
ret['result'] = False
|
||||
ret['changes'] = {}
|
||||
ret['comment'] = 'failed to remove registry key {0}'.format(name)
|
||||
ret['comment'] = 'Failed to remove registry key {0}'.format(name)
|
||||
|
||||
return ret
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Manage Windows Package Repository
|
||||
|
||||
.. note::
|
||||
|
||||
This state only loads on minions that have the ``roles: salt-master`` grain
|
||||
set.
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
@ -21,15 +16,7 @@ import salt.config
|
|||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Load this state if this is the salt-master
|
||||
'''
|
||||
try:
|
||||
return ('winrepo'
|
||||
if 'salt-master' in __grains__.get('roles', [])
|
||||
else False)
|
||||
except TypeError:
|
||||
return False
|
||||
return 'winrepo'
|
||||
|
||||
|
||||
def genrepo(name, force=False, allow_empty=False):
|
||||
|
|
|
@ -68,7 +68,7 @@ def get_iam_region(version='latest', url='http://169.254.169.254',
|
|||
'''
|
||||
Gets instance identity document and returns region
|
||||
'''
|
||||
instance_identity_url = '{0}/{1}/latest/dynamic/instance-identity/document'.format(url, version)
|
||||
instance_identity_url = '{0}/{1}/dynamic/instance-identity/document'.format(url, version)
|
||||
|
||||
region = None
|
||||
try:
|
||||
|
|
|
@ -273,7 +273,7 @@ class SerializerExtension(Extension, object):
|
|||
{%- set json_src = "{'bar': 'for real'}"|load_json %}
|
||||
Dude, {{ yaml_src.foo }} {{ json_src.bar }}!
|
||||
|
||||
will be rendered has::
|
||||
will be rendered as::
|
||||
|
||||
Dude, it works for real!
|
||||
|
||||
|
@ -299,7 +299,7 @@ class SerializerExtension(Extension, object):
|
|||
{% endload %}
|
||||
Dude, {{ yaml_src.foo }} {{ json_src.bar }}!
|
||||
|
||||
will be rendered has::
|
||||
will be rendered as::
|
||||
|
||||
Dude, it works for real!
|
||||
|
||||
|
|
327
setup.py
327
setup.py
|
@ -5,7 +5,7 @@ The setup script for salt
|
|||
'''
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
# pylint: disable=file-perms
|
||||
# pylint: disable=C0111,E1101,E1103,F0401,W0611,W0201,W0232,R0201,R0902,R0903
|
||||
|
||||
# For Python 2.5. A no-op on 2.6 and above.
|
||||
|
@ -18,7 +18,7 @@ import time
|
|||
try:
|
||||
from urllib2 import urlopen
|
||||
except ImportError:
|
||||
from urllib.request import urlopen
|
||||
from urllib.request import urlopen # pylint: disable=no-name-in-module
|
||||
from datetime import datetime
|
||||
# pylint: disable=E0611
|
||||
import distutils.dist
|
||||
|
@ -71,6 +71,7 @@ WITH_SETUPTOOLS = False
|
|||
if 'USE_SETUPTOOLS' in os.environ or 'setuptools' in sys.modules:
|
||||
try:
|
||||
from setuptools import setup
|
||||
from setuptools.command.develop import develop
|
||||
from setuptools.command.install import install
|
||||
from setuptools.command.sdist import sdist
|
||||
from setuptools.command.egg_info import egg_info
|
||||
|
@ -103,6 +104,7 @@ except ImportError:
|
|||
|
||||
SALT_VERSION = os.path.join(os.path.abspath(SETUP_DIRNAME), 'salt', 'version.py')
|
||||
SALT_VERSION_HARDCODED = os.path.join(os.path.abspath(SETUP_DIRNAME), 'salt', '_version.py')
|
||||
SALT_SYSPATHS_HARDCODED = os.path.join(os.path.abspath(SETUP_DIRNAME), 'salt', '_syspaths.py')
|
||||
SALT_REQS = os.path.join(os.path.abspath(SETUP_DIRNAME), 'requirements', 'base.txt')
|
||||
SALT_ZEROMQ_REQS = os.path.join(os.path.abspath(SETUP_DIRNAME), 'requirements', 'zeromq.txt')
|
||||
SALT_RAET_REQS = os.path.join(os.path.abspath(SETUP_DIRNAME), 'requirements', 'raet.txt')
|
||||
|
@ -125,8 +127,16 @@ def _parse_requirements_file(requirements_file):
|
|||
line = line.strip()
|
||||
if not line or line.startswith(('#', '-r')):
|
||||
continue
|
||||
if IS_WINDOWS_PLATFORM and 'libcloud' in line:
|
||||
continue
|
||||
if IS_WINDOWS_PLATFORM:
|
||||
if 'libcloud' in line:
|
||||
continue
|
||||
if 'pycrypto' in line.lower():
|
||||
# On windows we install PyCrypto using python wheels
|
||||
continue
|
||||
if 'm2crypto' in line.lower() and __saltstack_version__.info < (2015, 8): # pylint: disable=undefined-variable
|
||||
# In Windows, we're installing M2CryptoWin{32,64} which comes
|
||||
# compiled
|
||||
continue
|
||||
parsed_requirements.append(line)
|
||||
return parsed_requirements
|
||||
# <---- Helper Functions ---------------------------------------------------------------------------------------------
|
||||
|
@ -139,10 +149,14 @@ class WriteSaltVersion(Command):
|
|||
user_options = []
|
||||
|
||||
def initialize_options(self):
|
||||
pass
|
||||
'''
|
||||
Abstract method that is required to be overwritten
|
||||
'''
|
||||
|
||||
def finalize_options(self):
|
||||
pass
|
||||
'''
|
||||
Abstract method that is required to be overwritten
|
||||
'''
|
||||
|
||||
def run(self):
|
||||
if not os.path.exists(SALT_VERSION_HARDCODED):
|
||||
|
@ -161,10 +175,9 @@ class WriteSaltVersion(Command):
|
|||
# pylint: enable=E0602
|
||||
|
||||
|
||||
class WriteSaltSshPackaingFile(Command):
|
||||
class GenerateSaltSyspaths(Command):
|
||||
|
||||
description = 'Write salt\'s ssh packaging file'
|
||||
user_options = []
|
||||
description = 'Generate salt\'s hardcoded syspaths file'
|
||||
|
||||
def initialize_options(self):
|
||||
pass
|
||||
|
@ -172,6 +185,45 @@ class WriteSaltSshPackaingFile(Command):
|
|||
def finalize_options(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
# Write the syspaths file
|
||||
if getattr(self.distribution, 'salt_syspaths_hardcoded_path', None) is None:
|
||||
print('This command is not meant to be called on it\'s own')
|
||||
exit(1)
|
||||
|
||||
# Write the system paths file
|
||||
open(self.distribution.salt_syspaths_hardcoded_path, 'w').write(
|
||||
INSTALL_SYSPATHS_TEMPLATE.format(
|
||||
date=datetime.utcnow(),
|
||||
root_dir=self.distribution.salt_root_dir,
|
||||
config_dir=self.distribution.salt_config_dir,
|
||||
cache_dir=self.distribution.salt_cache_dir,
|
||||
sock_dir=self.distribution.salt_sock_dir,
|
||||
srv_root_dir=self.distribution.salt_srv_root_dir,
|
||||
base_file_roots_dir=self.distribution.salt_base_file_roots_dir,
|
||||
base_pillar_roots_dir=self.distribution.salt_base_pillar_roots_dir,
|
||||
base_master_roots_dir=self.distribution.salt_base_master_roots_dir,
|
||||
logs_dir=self.distribution.salt_logs_dir,
|
||||
pidfile_dir=self.distribution.salt_pidfile_dir,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class WriteSaltSshPackaingFile(Command):
|
||||
|
||||
description = 'Write salt\'s ssh packaging file'
|
||||
user_options = []
|
||||
|
||||
def initialize_options(self):
|
||||
'''
|
||||
Abstract method that is required to be overwritten
|
||||
'''
|
||||
|
||||
def finalize_options(self):
|
||||
'''
|
||||
Abstract method that is required to be overwritten
|
||||
'''
|
||||
|
||||
def run(self):
|
||||
if not os.path.exists(PACKAGED_FOR_SALT_SSH_FILE):
|
||||
# Write the salt-ssh packaging file
|
||||
|
@ -184,6 +236,198 @@ class WriteSaltSshPackaingFile(Command):
|
|||
# pylint: enable=E0602
|
||||
|
||||
|
||||
if WITH_SETUPTOOLS:
|
||||
class Develop(develop):
|
||||
user_options = develop.user_options + [
|
||||
('write_salt_version', None,
|
||||
'Generate Salt\'s _version.py file which allows proper version '
|
||||
'reporting. This defaults to False on develop/editable setups. '
|
||||
'If WRITE_SALT_VERSION is found in the environment this flag is '
|
||||
'switched to True.'),
|
||||
('generate_salt_syspaths', None,
|
||||
'Generate Salt\'s _syspaths.py file which allows tweaking some '
|
||||
'common paths that salt uses. This defaults to False on '
|
||||
'develop/editable setups. If GENERATE_SALT_SYSPATHS is found in '
|
||||
'the environment this flag is switched to True.'),
|
||||
('mimic_salt_install', None,
|
||||
'Mimmic the install command when running the develop command. '
|
||||
'This will generate salt\'s _version.py and _syspaths.py files. '
|
||||
'Generate Salt\'s _syspaths.py file which allows tweaking some '
|
||||
'This defaults to False on develop/editable setups. '
|
||||
'If MIMIC_INSTALL is found in the environment this flag is '
|
||||
'switched to True.')
|
||||
]
|
||||
boolean_options = develop.boolean_options + [
|
||||
'write_salt_version',
|
||||
'generate_salt_syspaths',
|
||||
'mimic_salt_install'
|
||||
]
|
||||
|
||||
def initialize_options(self):
|
||||
develop.initialize_options(self)
|
||||
self.write_salt_version = False
|
||||
self.generate_salt_syspaths = False
|
||||
self.mimic_salt_install = False
|
||||
|
||||
def finalize_options(self):
|
||||
develop.finalize_options(self)
|
||||
if 'WRITE_SALT_VERSION' in os.environ:
|
||||
self.write_salt_version = True
|
||||
if 'GENERATE_SALT_SYSPATHS' in os.environ:
|
||||
self.generate_salt_syspaths = True
|
||||
if 'MIMIC_SALT_INSTALL' in os.environ:
|
||||
self.mimic_salt_install = True
|
||||
|
||||
if self.mimic_salt_install:
|
||||
self.write_salt_version = True
|
||||
self.generate_salt_syspaths = True
|
||||
|
||||
def run(self):
|
||||
if IS_WINDOWS_PLATFORM:
|
||||
if __saltstack_version__.info < (2015, 8): # pylint: disable=undefined-variable
|
||||
# Install M2Crypto first
|
||||
self.distribution.salt_installing_m2crypto_windows = True
|
||||
self.run_command('install-m2crypto-windows')
|
||||
self.distribution.salt_installing_m2crypto_windows = None
|
||||
|
||||
# Install PyCrypto
|
||||
self.distribution.salt_installing_pycrypto_windows = True
|
||||
self.run_command('install-pycrypto-windows')
|
||||
self.distribution.salt_installing_pycrypto_windows = None
|
||||
|
||||
# Download the required DLLs
|
||||
self.distribution.salt_download_windows_dlls = True
|
||||
self.run_command('download-windows-dlls')
|
||||
self.distribution.salt_download_windows_dlls = None
|
||||
|
||||
if self.write_salt_version is True:
|
||||
self.distribution.running_salt_install = True
|
||||
self.distribution.salt_version_hardcoded_path = SALT_VERSION_HARDCODED
|
||||
self.run_command('write_salt_version')
|
||||
|
||||
if self.generate_salt_syspaths:
|
||||
self.distribution.salt_syspaths_hardcoded_path = SALT_SYSPATHS_HARDCODED
|
||||
self.run_command('generate_salt_syspaths')
|
||||
|
||||
# Resume normal execution
|
||||
develop.run(self)
|
||||
|
||||
|
||||
class InstallM2CryptoWindows(Command):
|
||||
|
||||
description = 'Install M2CryptoWindows'
|
||||
|
||||
def initialize_options(self):
|
||||
pass
|
||||
|
||||
def finalize_options(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
if getattr(self.distribution, 'salt_installing_m2crypto_windows', None) is None:
|
||||
print('This command is not meant to be called on it\'s own')
|
||||
exit(1)
|
||||
import platform
|
||||
from pip.utils import call_subprocess
|
||||
from pip.utils.logging import indent_log
|
||||
platform_bits, _ = platform.architecture()
|
||||
with indent_log():
|
||||
call_subprocess(
|
||||
['pip', 'install', '--egg', 'M2CryptoWin{0}'.format(platform_bits[:2])]
|
||||
)
|
||||
|
||||
|
||||
class InstallPyCryptoWindowsWheel(Command):
|
||||
|
||||
description = 'Install PyCrypto on Windows'
|
||||
|
||||
def initialize_options(self):
|
||||
pass
|
||||
|
||||
def finalize_options(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
if getattr(self.distribution, 'salt_installing_pycrypto_windows', None) is None:
|
||||
print('This command is not meant to be called on it\'s own')
|
||||
exit(1)
|
||||
import platform
|
||||
from pip.utils import call_subprocess
|
||||
from pip.utils.logging import indent_log
|
||||
platform_bits, _ = platform.architecture()
|
||||
call_arguments = ['pip', 'install', 'wheel']
|
||||
if platform_bits == '64bit':
|
||||
call_arguments.append(
|
||||
'http://repo.saltstack.com/windows/dependencies/64/pycrypto-2.6.1-cp27-none-win_amd64.whl'
|
||||
)
|
||||
else:
|
||||
call_arguments.append(
|
||||
'http://repo.saltstack.com/windows/dependencies/32/pycrypto-2.6.1-cp27-none-win32.whl'
|
||||
)
|
||||
with indent_log():
|
||||
call_subprocess(call_arguments)
|
||||
|
||||
|
||||
class DownloadWindowsDlls(Command):
|
||||
|
||||
description = 'Download required DLL\'s for windows'
|
||||
|
||||
def initialize_options(self):
|
||||
pass
|
||||
|
||||
def finalize_options(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
if getattr(self.distribution, 'salt_download_windows_dlls', None) is None:
|
||||
print('This command is not meant to be called on it\'s own')
|
||||
exit(1)
|
||||
import platform
|
||||
from pip.utils.logging import indent_log
|
||||
platform_bits, _ = platform.architecture()
|
||||
url = 'https://repo.saltstack.com/windows/dependencies/{bits}/{fname}32.dll'
|
||||
dest = os.path.join(os.path.dirname(sys.executable), '{fname}32.dll')
|
||||
with indent_log():
|
||||
for fname in ('libeay', 'ssleay'):
|
||||
furl = url.format(bits=platform_bits[:2], fname=fname)
|
||||
fdest = dest.format(fname=fname)
|
||||
if not os.path.exists(fdest):
|
||||
log.info('Downloading {0}32.dll to {1} from {2}'.format(fname, fdest, furl))
|
||||
try:
|
||||
import requests
|
||||
from contextlib import closing
|
||||
with closing(requests.get(furl, stream=True)) as req:
|
||||
if req.status_code == 200:
|
||||
with open(fdest, 'w') as wfh:
|
||||
for chunk in req.iter_content(chunk_size=4096):
|
||||
if chunk: # filter out keep-alive new chunks
|
||||
wfh.write(chunk)
|
||||
wfh.flush()
|
||||
else:
|
||||
log.error(
|
||||
'Failed to download {0}32.dll to {1} from {2}'.format(
|
||||
fname, fdest, furl
|
||||
)
|
||||
)
|
||||
except ImportError:
|
||||
req = urlopen(furl)
|
||||
|
||||
if req.getcode() == 200:
|
||||
with open(fdest, 'w') as wfh:
|
||||
while True:
|
||||
for chunk in req.read(4096):
|
||||
if not chunk:
|
||||
break
|
||||
wfh.write(chunk)
|
||||
wfh.flush()
|
||||
else:
|
||||
log.error(
|
||||
'Failed to download {0}32.dll to {1} from {2}'.format(
|
||||
fname, fdest, furl
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class Sdist(sdist):
|
||||
|
||||
def make_release_tree(self, base_dir, files):
|
||||
|
@ -318,7 +562,9 @@ class TestCommand(Command):
|
|||
self.runtests_opts = None
|
||||
|
||||
def finalize_options(self):
|
||||
pass
|
||||
'''
|
||||
Abstract method that is required to be overwritten
|
||||
'''
|
||||
|
||||
def run(self):
|
||||
from subprocess import Popen
|
||||
|
@ -389,24 +635,10 @@ class Build(build):
|
|||
self.run_command('write_salt_version')
|
||||
|
||||
# Write the system paths file
|
||||
system_paths_file_path = os.path.join(
|
||||
self.distribution.salt_syspaths_hardcoded_path = os.path.join(
|
||||
self.build_lib, 'salt', '_syspaths.py'
|
||||
)
|
||||
open(system_paths_file_path, 'w').write(
|
||||
INSTALL_SYSPATHS_TEMPLATE.format(
|
||||
date=datetime.utcnow(),
|
||||
root_dir=self.distribution.salt_root_dir,
|
||||
config_dir=self.distribution.salt_config_dir,
|
||||
cache_dir=self.distribution.salt_cache_dir,
|
||||
sock_dir=self.distribution.salt_sock_dir,
|
||||
srv_root_dir=self.distribution.salt_srv_root_dir,
|
||||
base_file_roots_dir=self.distribution.salt_base_file_roots_dir,
|
||||
base_pillar_roots_dir=self.distribution.salt_base_pillar_roots_dir,
|
||||
base_master_roots_dir=self.distribution.salt_base_master_roots_dir,
|
||||
logs_dir=self.distribution.salt_logs_dir,
|
||||
pidfile_dir=self.distribution.salt_pidfile_dir,
|
||||
)
|
||||
)
|
||||
self.run_command('generate_salt_syspaths')
|
||||
|
||||
|
||||
class Install(install):
|
||||
|
@ -499,6 +731,20 @@ class Install(install):
|
|||
self.distribution.salt_version_hardcoded_path = os.path.join(
|
||||
self.build_lib, 'salt', '_version.py'
|
||||
)
|
||||
if IS_WINDOWS_PLATFORM:
|
||||
if __saltstack_version__.info < (2015, 8): # pylint: disable=undefined-variable
|
||||
# Install M2Crypto first
|
||||
self.distribution.salt_installing_m2crypto_windows = True
|
||||
self.run_command('install-m2crypto-windows')
|
||||
self.distribution.salt_installing_m2crypto_windows = None
|
||||
# Install PyCrypto
|
||||
self.distribution.salt_installing_pycrypto_windows = True
|
||||
self.run_command('install-pycrypto-windows')
|
||||
self.distribution.salt_installing_pycrypto_windows = None
|
||||
# Download the required DLLs
|
||||
self.distribution.salt_download_windows_dlls = True
|
||||
self.run_command('download-windows-dlls')
|
||||
self.distribution.salt_download_windows_dlls = None
|
||||
# Run install.run
|
||||
install.run(self)
|
||||
|
||||
|
@ -597,7 +843,6 @@ class SaltDistribution(distutils.dist.Distribution):
|
|||
self.salt_logs_dir = None
|
||||
self.salt_pidfile_dir = None
|
||||
|
||||
|
||||
self.name = 'salt-ssh' if PACKAGED_FOR_SALT_SSH else 'salt'
|
||||
self.salt_version = __version__ # pylint: disable=undefined-variable
|
||||
self.description = 'Portable, distributed, remote execution and configuration management system'
|
||||
|
@ -610,10 +855,19 @@ class SaltDistribution(distutils.dist.Distribution):
|
|||
'sdist': Sdist,
|
||||
'install': Install,
|
||||
'write_salt_version': WriteSaltVersion,
|
||||
'generate_salt_syspaths': GenerateSaltSyspaths,
|
||||
'write_salt_ssh_packaging_file': WriteSaltSshPackaingFile})
|
||||
if not IS_WINDOWS_PLATFORM:
|
||||
self.cmdclass.update({'sdist': CloudSdist,
|
||||
'install_lib': InstallLib})
|
||||
if IS_WINDOWS_PLATFORM:
|
||||
self.cmdclass.update({'install-pycrypto-windows': InstallPyCryptoWindowsWheel,
|
||||
'download-windows-dlls': DownloadWindowsDlls})
|
||||
if __saltstack_version__.info < (2015, 8): # pylint: disable=undefined-variable
|
||||
self.cmdclass.update({'install-m2crypto-windows': InstallM2CryptoWindows})
|
||||
|
||||
if WITH_SETUPTOOLS:
|
||||
self.cmdclass.update({'develop': Develop})
|
||||
|
||||
self.license = 'Apache Software License 2.0'
|
||||
self.packages = self.discover_packages()
|
||||
|
@ -731,6 +985,7 @@ class SaltDistribution(distutils.dist.Distribution):
|
|||
|
||||
if IS_WINDOWS_PLATFORM:
|
||||
install_requires.append('WMI')
|
||||
install_requires.append('pypiwin32 >= 219')
|
||||
|
||||
if self.salt_transport == 'zeromq':
|
||||
install_requires += _parse_requirements_file(SALT_ZEROMQ_REQS)
|
||||
|
@ -911,14 +1166,6 @@ class SaltDistribution(distutils.dist.Distribution):
|
|||
def parse_command_line(self):
|
||||
args = distutils.dist.Distribution.parse_command_line(self)
|
||||
|
||||
# Setup our property functions after class initialization and
|
||||
# after parsing the command line since most are set to None
|
||||
for funcname in dir(self):
|
||||
if not funcname.startswith('_property_'):
|
||||
continue
|
||||
property_name = funcname.split('_property_', 1)[-1]
|
||||
setattr(self, property_name, getattr(self, funcname))
|
||||
|
||||
if not self.ssh_packaging and PACKAGED_FOR_SALT_SSH:
|
||||
self.ssh_packaging = 1
|
||||
|
||||
|
@ -936,6 +1183,16 @@ class SaltDistribution(distutils.dist.Distribution):
|
|||
)
|
||||
)
|
||||
|
||||
# Setup our property functions after class initialization and
|
||||
# after parsing the command line since most are set to None
|
||||
# ATTENTION: This should be the last step before returning the args or
|
||||
# some of the requirements won't be correctly set
|
||||
for funcname in dir(self):
|
||||
if not funcname.startswith('_property_'):
|
||||
continue
|
||||
property_name = funcname.split('_property_', 1)[-1]
|
||||
setattr(self, property_name, getattr(self, funcname))
|
||||
|
||||
return args
|
||||
# <---- Overridden Methods ---------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -18,7 +18,11 @@ from salttesting.mock import (
|
|||
# Import Salt Libs
|
||||
from salt.modules import pw_user
|
||||
from salt.exceptions import CommandExecutionError
|
||||
import pwd
|
||||
try:
|
||||
import pwd
|
||||
HAS_PWD = True
|
||||
except ImportError:
|
||||
HAS_PWD = False
|
||||
|
||||
|
||||
# Globals
|
||||
|
@ -27,6 +31,7 @@ pw_user.__salt__ = {}
|
|||
pw_user.__context__ = {}
|
||||
|
||||
|
||||
@skipIf(not HAS_PWD, 'These tests can only run on systems with the python pwd module')
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class PwUserTestCase(TestCase):
|
||||
'''
|
||||
|
@ -49,16 +54,21 @@ class PwUserTestCase(TestCase):
|
|||
with patch.dict(pw_user.__salt__, {'cmd.run_all': mock}):
|
||||
self.assertTrue(pw_user.delete('A'), 1)
|
||||
|
||||
@patch('salt.modules.pw_user.__context__', MagicMock(return_value='A'))
|
||||
def test_getent(self):
|
||||
'''
|
||||
Test if user.getent already have a value
|
||||
'''
|
||||
self.assertTrue(pw_user.getent())
|
||||
mock_user = 'saltdude'
|
||||
|
||||
mock = MagicMock(return_value='A')
|
||||
with patch.object(pw_user, 'info', mock):
|
||||
self.assertEqual(pw_user.getent(True)[0], 'A')
|
||||
class MockData(object):
|
||||
pw_name = mock_user
|
||||
|
||||
with patch('pwd.getpwall', MagicMock(return_value=[MockData()])):
|
||||
with patch.dict(pw_user.__context__, {'user.getent': mock_user}):
|
||||
self.assertEqual(pw_user.getent(), mock_user)
|
||||
|
||||
with patch.object(pw_user, 'info', MagicMock(return_value=mock_user)):
|
||||
self.assertEqual(pw_user.getent(True)[0], mock_user)
|
||||
|
||||
def test_chuid(self):
|
||||
'''
|
||||
|
@ -291,13 +301,22 @@ class PwUserTestCase(TestCase):
|
|||
'''
|
||||
Return a list of groups the named user belongs to
|
||||
'''
|
||||
self.assertEqual(pw_user.list_groups('name'), 'A')
|
||||
mock_group = 'saltgroup'
|
||||
|
||||
with patch('salt.utils.get_group_list', MagicMock(return_value=[mock_group])):
|
||||
self.assertEqual(pw_user.list_groups('name'), [mock_group])
|
||||
|
||||
def test_list_users(self):
|
||||
'''
|
||||
Return a list of all users
|
||||
'''
|
||||
self.assertTrue(pw_user.list_users())
|
||||
mock_user = 'saltdude'
|
||||
|
||||
class MockData(object):
|
||||
pw_name = mock_user
|
||||
|
||||
with patch('pwd.getpwall', MagicMock(return_value=[MockData()])):
|
||||
self.assertEqual(pw_user.list_users(), [mock_user])
|
||||
|
||||
def test_rename(self):
|
||||
'''
|
||||
|
|
|
@ -98,7 +98,7 @@ class BotoElbTestCase(TestCase):
|
|||
self.assertTrue(boto_elb.__salt__['boto_elb.exists'].called)
|
||||
self.assertTrue(boto_elb.__salt__['boto_elb.create'].called)
|
||||
self.assertTrue(boto_elb.__salt__['state.single'].called)
|
||||
self.assertTrue(
|
||||
self.assertFalse(
|
||||
boto_elb.__salt__['boto_elb.get_attributes'].called
|
||||
)
|
||||
self.assertTrue(
|
||||
|
|
|
@ -139,7 +139,8 @@ class CronTestCase(TestCase):
|
|||
cron.present(
|
||||
name='foo',
|
||||
hour='2',
|
||||
user='root')
|
||||
user='root',
|
||||
identifier=None)
|
||||
self.assertEqual(
|
||||
get_crontab(),
|
||||
('# Lines below here are managed by Salt, do not edit\n'
|
||||
|
@ -147,7 +148,7 @@ class CronTestCase(TestCase):
|
|||
'* 2 * * * foo\n'
|
||||
'# SALT_CRON_IDENTIFIER:2\n'
|
||||
'* 2 * * * foo\n'
|
||||
'* 2 * * * foo\n'))
|
||||
'* 2 * * * foo'))
|
||||
|
||||
@patch('salt.modules.cron.raw_cron',
|
||||
new=MagicMock(side_effect=get_crontab))
|
||||
|
@ -196,214 +197,107 @@ class CronTestCase(TestCase):
|
|||
new=MagicMock(side_effect=get_crontab))
|
||||
@patch('salt.modules.cron._write_cron_lines',
|
||||
new=MagicMock(side_effect=write_crontab))
|
||||
def test_aissue_1072(self):
|
||||
def test_multiline_comments_are_updated(self):
|
||||
set_crontab(
|
||||
'# Lines below here are managed by Salt, do not edit\n'
|
||||
'# I have a multi-line comment SALT_CRON_IDENTIFIER:1\n'
|
||||
'# First crontab - single line comment SALT_CRON_IDENTIFIER:1\n'
|
||||
'* 1 * * * foo'
|
||||
)
|
||||
cron.present(
|
||||
name='foo',
|
||||
hour='1',
|
||||
comment='1I have a multi-line comment\n2about my script here.\n',
|
||||
comment='First crontab\nfirst multi-line comment\n',
|
||||
identifier='1',
|
||||
user='root')
|
||||
cron.present(
|
||||
name='foo',
|
||||
hour='1',
|
||||
comment='3I have a multi-line comment\n3about my script here.\n',
|
||||
comment='First crontab\nsecond multi-line comment\n',
|
||||
identifier='1',
|
||||
user='root')
|
||||
cron.present(
|
||||
name='foo',
|
||||
hour='1',
|
||||
comment='I have a multi-line comment\nabout my script here.\n',
|
||||
comment='Second crontab\nmulti-line comment\n',
|
||||
identifier='2',
|
||||
user='root')
|
||||
self.assertEqual(
|
||||
get_crontab(),
|
||||
'# Lines below here are managed by Salt, do not edit\n'
|
||||
'# 2about my script here. SALT_CRON_IDENTIFIER:1\n'
|
||||
'# First crontab\n'
|
||||
'# second multi-line comment SALT_CRON_IDENTIFIER:1\n'
|
||||
'* 1 * * * foo\n'
|
||||
'# I have a multi-line comment\n'
|
||||
'# about my script here. SALT_CRON_IDENTIFIER:2\n'
|
||||
'# Second crontab\n'
|
||||
'# multi-line comment SALT_CRON_IDENTIFIER:2\n'
|
||||
'* 1 * * * foo')
|
||||
|
||||
@patch('salt.modules.cron.raw_cron',
|
||||
new=MagicMock(side_effect=get_crontab))
|
||||
@patch('salt.modules.cron._write_cron_lines',
|
||||
new=MagicMock(side_effect=write_crontab))
|
||||
def test_issue_11935(self):
|
||||
def test_existing_unmanaged_jobs_are_made_managed(self):
|
||||
set_crontab(
|
||||
'# Lines below here are managed by Salt, do not edit\n'
|
||||
'0 2 * * * find /var/www -type f '
|
||||
'-mtime -7 -print0 | xargs -0 '
|
||||
'clamscan -i --no-summary 2>/dev/null'
|
||||
'0 2 * * * foo'
|
||||
)
|
||||
cmd = (
|
||||
'find /var/www -type f -mtime -7 -print0 '
|
||||
'| xargs -0 clamscan -i --no-summary 2>/dev/null'
|
||||
)
|
||||
self.assertEqual(cron._check_cron('root', cmd, hour='2', minute='0'),
|
||||
'present')
|
||||
ret = cron.present(cmd, 'root', minute='0', hour='2')
|
||||
self.assertEqual(ret['changes'], {})
|
||||
self.assertEqual(
|
||||
ret['comment'],
|
||||
'Cron find /var/www -type f -mtime -7 -print0 '
|
||||
'| xargs -0 clamscan -i --no-summary 2>/dev/null already present')
|
||||
self.assertEqual(cron._check_cron('root', cmd, hour='3', minute='0'),
|
||||
'update')
|
||||
ret = cron.present(cmd, 'root', minute='0', hour='3')
|
||||
self.assertEqual(ret['changes'],
|
||||
{'root': 'find /var/www -type f -mtime -7 -print0 | '
|
||||
'xargs -0 clamscan -i --no-summary 2>/dev/null'})
|
||||
self.assertEqual(
|
||||
ret['comment'],
|
||||
'Cron find /var/www -type f -mtime -7 -print0 '
|
||||
'| xargs -0 clamscan -i --no-summary 2>/dev/null updated')
|
||||
ret = cron._check_cron('root', 'foo', hour='2', minute='0')
|
||||
self.assertEqual(ret, 'present')
|
||||
ret = cron.present('foo', 'root', minute='0', hour='2')
|
||||
self.assertEqual(ret['changes'], {'root': 'foo'})
|
||||
self.assertEqual(ret['comment'], 'Cron foo updated')
|
||||
self.assertEqual(
|
||||
get_crontab(),
|
||||
'# Lines below here are managed by Salt, do not edit\n'
|
||||
'0 3 * * * find /var/www -type f -mtime -7 -print0 |'
|
||||
' xargs -0 clamscan -i --no-summary 2>/dev/null')
|
||||
'# SALT_CRON_IDENTIFIER:foo\n'
|
||||
'0 2 * * * foo')
|
||||
ret = cron.present('foo', 'root', minute='0', hour='2')
|
||||
self.assertEqual(ret['changes'], {})
|
||||
self.assertEqual(ret['comment'], 'Cron foo already present')
|
||||
|
||||
@patch('salt.modules.cron.raw_cron',
|
||||
new=MagicMock(side_effect=get_crontab))
|
||||
@patch('salt.modules.cron._write_cron_lines',
|
||||
new=MagicMock(side_effect=write_crontab))
|
||||
def test_issue_11935_with_id(self):
|
||||
def test_existing_noid_jobs_are_updated_with_identifier(self):
|
||||
set_crontab(
|
||||
'# Lines below here are managed by Salt, do not edit\n'
|
||||
'# SALT_CRON_IDENTIFIER:1\n'
|
||||
'0 2 * * * find /var/www -type f '
|
||||
'-mtime -7 -print0 | xargs -0 '
|
||||
'clamscan -i --no-summary 2>/dev/null'
|
||||
'# SALT_CRON_IDENTIFIER:NO ID SET\n'
|
||||
'1 * * * * foo'
|
||||
)
|
||||
cmd = (
|
||||
'find /var/www -type f -mtime -7 -print0 '
|
||||
'| xargs -0 clamscan -i --no-summary 2>/dev/null'
|
||||
)
|
||||
self.assertEqual(cron._check_cron(
|
||||
'root', cmd, hour='2', minute='0', identifier=1), 'present')
|
||||
ret = cron.present(cmd, 'root', minute='0', hour='2', identifier='1')
|
||||
self.assertEqual(ret['changes'], {})
|
||||
self.assertEqual(
|
||||
ret['comment'],
|
||||
'Cron find /var/www -type f -mtime -7 -print0 '
|
||||
'| xargs -0 clamscan -i --no-summary 2>/dev/null already present')
|
||||
self.assertEqual(cron._check_cron(
|
||||
'root', cmd, hour='3', minute='0', identifier='1'), 'update')
|
||||
ret = cron.present(cmd, 'root', minute='0', hour='3', identifier='1')
|
||||
self.assertEqual(ret['changes'],
|
||||
{'root': 'find /var/www -type f -mtime -7 -print0 | '
|
||||
'xargs -0 clamscan -i --no-summary 2>/dev/null'})
|
||||
self.assertEqual(
|
||||
ret['comment'],
|
||||
'Cron find /var/www -type f -mtime -7 -print0 '
|
||||
'| xargs -0 clamscan -i --no-summary 2>/dev/null updated')
|
||||
ret = cron._check_cron('root', 'foo', minute=1)
|
||||
self.assertEqual(ret, 'present')
|
||||
ret = cron.present('foo', 'root', minute=1)
|
||||
self.assertEqual(ret['changes'], {'root': 'foo'})
|
||||
self.assertEqual(ret['comment'], 'Cron foo updated')
|
||||
self.assertEqual(
|
||||
get_crontab(),
|
||||
'# Lines below here are managed by Salt, do not edit\n'
|
||||
'# SALT_CRON_IDENTIFIER:1\n'
|
||||
'0 3 * * * find /var/www -type f -mtime -7 -print0 |'
|
||||
' xargs -0 clamscan -i --no-summary 2>/dev/null')
|
||||
'# SALT_CRON_IDENTIFIER:foo\n'
|
||||
'1 * * * * foo')
|
||||
|
||||
@patch('salt.modules.cron.raw_cron',
|
||||
new=MagicMock(side_effect=get_crontab))
|
||||
@patch('salt.modules.cron._write_cron_lines',
|
||||
new=MagicMock(side_effect=write_crontab))
|
||||
def test_issue_11935_mixed(self):
|
||||
def test_existing_duplicate_unmanaged_jobs_are_merged_and_given_id(self):
|
||||
set_crontab(
|
||||
'# Lines below here are managed by Salt, do not edit\n'
|
||||
'0 2 * * * find /var/www -type f '
|
||||
'-mtime -7 -print0 | xargs -0 '
|
||||
'clamscan -i --no-summary 2>/dev/null'
|
||||
'0 2 * * * foo\n'
|
||||
'0 2 * * * foo'
|
||||
)
|
||||
cmd = (
|
||||
'find /var/www -type f -mtime -7 -print0 '
|
||||
'| xargs -0 clamscan -i --no-summary 2>/dev/null'
|
||||
)
|
||||
self.assertEqual(cron._check_cron('root', cmd, hour='2', minute='0'),
|
||||
'present')
|
||||
ret = cron.present(cmd, 'root', minute='0', hour='2')
|
||||
ret = cron._check_cron('root', 'foo', hour='2', minute='0')
|
||||
self.assertEqual(ret, 'present')
|
||||
ret = cron.present('foo', 'root', minute='0', hour='2')
|
||||
self.assertEqual(ret['changes'], {'root': 'foo'})
|
||||
self.assertEqual(ret['comment'], 'Cron foo updated')
|
||||
self.assertEqual(
|
||||
get_crontab(),
|
||||
'# Lines below here are managed by Salt, do not edit\n'
|
||||
'# SALT_CRON_IDENTIFIER:foo\n'
|
||||
'0 2 * * * foo')
|
||||
ret = cron.present('foo', 'root', minute='0', hour='2')
|
||||
self.assertEqual(ret['changes'], {})
|
||||
self.assertEqual(
|
||||
ret['comment'],
|
||||
'Cron find /var/www -type f -mtime -7 -print0 '
|
||||
'| xargs -0 clamscan -i --no-summary 2>/dev/null already present')
|
||||
self.assertEqual(cron._check_cron('root', cmd, hour='3', minute='0'),
|
||||
'update')
|
||||
ret = cron.present(cmd, 'root', minute='0', hour='3')
|
||||
self.assertEqual(ret['changes'],
|
||||
{'root': 'find /var/www -type f -mtime -7 -print0 | '
|
||||
'xargs -0 clamscan -i --no-summary 2>/dev/null'})
|
||||
self.assertEqual(
|
||||
ret['comment'],
|
||||
'Cron find /var/www -type f -mtime -7 -print0 '
|
||||
'| xargs -0 clamscan -i --no-summary 2>/dev/null updated')
|
||||
self.assertEqual(
|
||||
get_crontab(),
|
||||
'# Lines below here are managed by Salt, do not edit\n'
|
||||
'0 3 * * * find /var/www -type f -mtime -7 -print0 |'
|
||||
' xargs -0 clamscan -i --no-summary 2>/dev/null')
|
||||
self.assertEqual(cron._check_cron(
|
||||
'root', cmd, hour='2', minute='0', identifier='1'), 'update')
|
||||
ret = cron.present(cmd, 'root', minute='0', hour='2', identifier='1')
|
||||
self.assertEqual(
|
||||
ret['changes'],
|
||||
{'root': 'find /var/www -type f -mtime -7 -print0 | '
|
||||
'xargs -0 clamscan -i --no-summary 2>/dev/null'})
|
||||
self.assertEqual(
|
||||
ret['comment'],
|
||||
'Cron find /var/www -type f -mtime -7 -print0 '
|
||||
'| xargs -0 clamscan -i --no-summary 2>/dev/null updated')
|
||||
self.assertEqual(cron._check_cron(
|
||||
'root', cmd, hour='3', minute='0', identifier='1'), 'update')
|
||||
ret = cron.present(cmd, 'root', minute='0', hour='3', identifier='1')
|
||||
self.assertEqual(ret['changes'],
|
||||
{'root': 'find /var/www -type f -mtime -7 -print0 | '
|
||||
'xargs -0 clamscan -i --no-summary 2>/dev/null'})
|
||||
self.assertEqual(
|
||||
ret['comment'],
|
||||
'Cron find /var/www -type f -mtime -7 -print0 '
|
||||
'| xargs -0 clamscan -i --no-summary 2>/dev/null updated')
|
||||
self.assertEqual(
|
||||
get_crontab(),
|
||||
'# Lines below here are managed by Salt, do not edit\n'
|
||||
'# SALT_CRON_IDENTIFIER:1\n'
|
||||
'0 3 * * * find /var/www -type f -mtime -7 -print0 |'
|
||||
' xargs -0 clamscan -i --no-summary 2>/dev/null')
|
||||
|
||||
set_crontab(
|
||||
'# Lines below here are managed by Salt, do not edit\n'
|
||||
'0 2 * * * find /var/www -type f '
|
||||
'-mtime -7 -print0 | xargs -0 '
|
||||
'clamscan -i --no-summary 2>/dev/null'
|
||||
)
|
||||
self.assertEqual(cron._check_cron(
|
||||
'root', cmd + "a", hour='2', minute='0', identifier='1'), 'absent')
|
||||
ret = cron.present(
|
||||
cmd + "a", 'root', minute='0', hour='2', identifier='1')
|
||||
self.assertEqual(
|
||||
ret['changes'],
|
||||
{'root': 'find /var/www -type f -mtime -7 -print0 | '
|
||||
'xargs -0 clamscan -i --no-summary 2>/dev/nulla'})
|
||||
self.assertEqual(
|
||||
ret['comment'],
|
||||
'Cron find /var/www -type f -mtime -7 -print0 | '
|
||||
'xargs -0 clamscan -i --no-summary 2>/dev/nulla added '
|
||||
'to root\'s crontab')
|
||||
self.assertEqual(
|
||||
get_crontab(),
|
||||
'# Lines below here are managed by Salt, do not edit\n'
|
||||
'0 2 * * *'
|
||||
' find /var/www -type f -mtime -7 -print0'
|
||||
' | xargs -0 clamscan -i --no-summary 2>/dev/null\n'
|
||||
'# SALT_CRON_IDENTIFIER:1\n'
|
||||
'0 2 * * *'
|
||||
' find /var/www -type f -mtime -7 -print0'
|
||||
' | xargs -0 clamscan -i --no-summary 2>/dev/nulla')
|
||||
|
||||
self.assertEqual(ret['comment'], 'Cron foo already present')
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
|
|
|
@ -22,7 +22,7 @@ ensure_in_syspath('../../')
|
|||
from salt.states import openstack_config
|
||||
|
||||
openstack_config.__salt__ = {}
|
||||
openstack_config.__opts__ = {}
|
||||
openstack_config.__opts__ = {'test': False}
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
|
|
|
@ -36,28 +36,43 @@ class RegTestCase(TestCase):
|
|||
'''
|
||||
Test to set a registry entry.
|
||||
'''
|
||||
name = 'HKEY_CURRENT_USER\\SOFTWARE\\Salt\\version'
|
||||
value = '0.15.3'
|
||||
name = 'HKEY_CURRENT_USER\\SOFTWARE\\Salt'
|
||||
vname = 'version'
|
||||
vdata = '0.15.3'
|
||||
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': '{0} is already configured'.format(name)}
|
||||
'comment': '{0} in {1} is already configured'.format(vname, name)}
|
||||
|
||||
mock = MagicMock(side_effect=[{'vdata': value}, {'vdata': 'a'}, {'vdata': 'a'}])
|
||||
mock_read = MagicMock(side_effect=[{'vdata': vdata, 'success': True},
|
||||
{'vdata': 'a', 'success': True},
|
||||
{'vdata': 'a', 'success': True}])
|
||||
mock_t = MagicMock(return_value=True)
|
||||
with patch.dict(reg.__salt__, {'reg.read_value': mock,
|
||||
with patch.dict(reg.__salt__, {'reg.read_value': mock_read,
|
||||
'reg.set_value': mock_t}):
|
||||
self.assertDictEqual(reg.present(name, value), ret)
|
||||
self.assertDictEqual(reg.present(name,
|
||||
vname=vname,
|
||||
vdata=vdata), ret)
|
||||
|
||||
with patch.dict(reg.__opts__, {'test': True}):
|
||||
ret.update({'comment': '', 'result': None,
|
||||
'changes': {'reg': 'configured to 0.15.3'}})
|
||||
self.assertDictEqual(reg.present(name, value), ret)
|
||||
'changes': {'reg': {'Will add': {'Key': name,
|
||||
'Entry': vname,
|
||||
'Value': vdata}}}})
|
||||
self.assertDictEqual(reg.present(name,
|
||||
vname=vname,
|
||||
vdata=vdata), ret)
|
||||
|
||||
with patch.dict(reg.__opts__, {'test': False}):
|
||||
ret.update({'result': True})
|
||||
self.assertDictEqual(reg.present(name, value), ret)
|
||||
ret.update({'comment': 'Added {0} to {0}'.format(name),
|
||||
'result': True,
|
||||
'changes': {'reg': {'Added': {'Key': name,
|
||||
'Entry': vname,
|
||||
'Value': vdata}}}})
|
||||
self.assertDictEqual(reg.present(name,
|
||||
vname=vname,
|
||||
vdata=vdata), ret)
|
||||
|
||||
# 'absent' function tests: 1
|
||||
|
||||
|
@ -65,27 +80,35 @@ class RegTestCase(TestCase):
|
|||
'''
|
||||
Test to remove a registry entry.
|
||||
'''
|
||||
name = 'HKEY_CURRENT_USER\\SOFTWARE\\Salt\\version'
|
||||
name = 'HKEY_CURRENT_USER\\SOFTWARE\\Salt'
|
||||
vname = 'version'
|
||||
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': '{0} is already absent'.format(name)}
|
||||
|
||||
mock = MagicMock(side_effect=[{'success': False}, {'success': True}, {'success': True}])
|
||||
mock_read = MagicMock(side_effect=[{'success': False},
|
||||
{'success': False},
|
||||
{'success': True},
|
||||
{'success': True}])
|
||||
mock_t = MagicMock(return_value=True)
|
||||
with patch.dict(reg.__salt__, {'reg.read_value': mock,
|
||||
with patch.dict(reg.__salt__, {'reg.read_value': mock_read,
|
||||
'reg.delete_value': mock_t}):
|
||||
self.assertDictEqual(reg.absent(name), ret)
|
||||
self.assertDictEqual(reg.absent(name, vname), ret)
|
||||
|
||||
with patch.dict(reg.__opts__, {'test': True}):
|
||||
ret.update({'comment': '', 'result': None,
|
||||
'changes': {'reg': 'Removed {0}'.format(name)}})
|
||||
self.assertDictEqual(reg.absent(name), ret)
|
||||
'changes': {'reg': {'Will remove': {'Entry': vname,
|
||||
'Key': name}}}})
|
||||
self.assertDictEqual(reg.absent(name, vname), ret)
|
||||
|
||||
with patch.dict(reg.__opts__, {'test': False}):
|
||||
ret.update({'result': True})
|
||||
self.assertDictEqual(reg.absent(name), ret)
|
||||
ret.update({'result': True,
|
||||
'changes': {'reg': {'Removed': {'Entry': vname,
|
||||
'Key': name}}},
|
||||
'comment': 'Removed {0} from {0}'.format(name)})
|
||||
self.assertDictEqual(reg.absent(name, vname), ret)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
Loading…
Add table
Reference in a new issue