mirror of
https://github.com/valitydev/salt.git
synced 2024-11-06 08:35:21 +00:00
Merge branch '2017.7' into '2018.3'
Conflicts: - requirements/base.txt - salt/states/archive.py - salt/states/file.py - tests/integration/runners/test_state.py - tests/unit/daemons/test_masterapi.py
This commit is contained in:
commit
3d2ea16c3a
@ -1,10 +1,6 @@
|
||||
-r base.txt
|
||||
|
||||
mock>=2.0.0
|
||||
apache-libcloud>=0.14.0
|
||||
boto>=2.32.1
|
||||
boto3>=1.2.1
|
||||
moto>=0.3.6
|
||||
SaltPyLint>=v2017.3.6
|
||||
pytest>=3.5.0
|
||||
git+https://github.com/saltstack/pytest-salt.git@master#egg=pytest-salt
|
||||
|
36
requirements/tests.txt
Normal file
36
requirements/tests.txt
Normal file
@ -0,0 +1,36 @@
|
||||
-r zeromq.txt
|
||||
-r dev.txt
|
||||
-r pytest.txt
|
||||
apache-libcloud>=1.0.0
|
||||
boto>=2.32.1
|
||||
boto3>=1.2.1
|
||||
moto>=0.3.6
|
||||
docker; sys.platform != 'win32'
|
||||
docker==2.7.0; sys.platform == 'win32'
|
||||
virtualenv
|
||||
setuptools>=30
|
||||
six>=1.10.0
|
||||
timelib
|
||||
coverage
|
||||
keyring==5.7.1
|
||||
python-gnupg
|
||||
python-etcd==0.4.2
|
||||
GitPython
|
||||
supervisor; python_version < '3'
|
||||
kubernetes<4.0
|
||||
psutil
|
||||
pyvmomi
|
||||
setproctitle
|
||||
cherrypy; sys.platform != 'win32' and sys.platform != 'darwin'
|
||||
pyinotify; sys.platform != 'win32' and sys.platform != 'darwin'
|
||||
PyMySQL; sys.platform != 'win32' and sys.platform != 'darwin'
|
||||
jsonschema
|
||||
strict_rfc3339
|
||||
rfc3987
|
||||
jinja2
|
||||
pyOpenSSL
|
||||
ioflo
|
||||
dnspython
|
||||
SaltTesting==2017.6.1
|
||||
junos-eznc
|
||||
jxmlease
|
@ -66,14 +66,28 @@ def _gen_checksum(path):
|
||||
|
||||
|
||||
def _checksum_file_path(path):
|
||||
relpath = '.'.join((os.path.relpath(path, __opts__['cachedir']), 'hash'))
|
||||
if re.match(r'..[/\\]', relpath):
|
||||
# path is a local file
|
||||
relpath = salt.utils.path.join(
|
||||
'local',
|
||||
os.path.splitdrive(path)[-1].lstrip('/\\'),
|
||||
)
|
||||
return salt.utils.path.join(__opts__['cachedir'], 'archive_hash', relpath)
|
||||
try:
|
||||
relpath = '.'.join((os.path.relpath(path, __opts__['cachedir']), 'hash'))
|
||||
if re.match(r'..[/\\]', relpath):
|
||||
# path is a local file
|
||||
relpath = salt.utils.path.join(
|
||||
'local',
|
||||
os.path.splitdrive(path)[-1].lstrip('/\\'),
|
||||
)
|
||||
except ValueError as exc:
|
||||
# The path is on a different drive (Windows)
|
||||
if six.text_type(exc).startswith('path is on'):
|
||||
drive, path = os.path.splitdrive(path)
|
||||
relpath = salt.utils.path.join(
|
||||
'local',
|
||||
drive.rstrip(':'),
|
||||
path.lstrip('/\\'),
|
||||
)
|
||||
else:
|
||||
raise
|
||||
ret = salt.utils.path.join(__opts__['cachedir'], 'archive_hash', relpath)
|
||||
log.debug('Using checksum file %s for cached archive file %s', ret, path)
|
||||
return ret
|
||||
|
||||
|
||||
def _update_checksum(path):
|
||||
|
@ -673,13 +673,13 @@ def _error(ret, err_msg):
|
||||
|
||||
|
||||
def _check_directory(name,
|
||||
user,
|
||||
group,
|
||||
recurse,
|
||||
mode,
|
||||
clean,
|
||||
require,
|
||||
exclude_pat,
|
||||
user=None,
|
||||
group=None,
|
||||
recurse=False,
|
||||
mode=None,
|
||||
clean=False,
|
||||
require=False,
|
||||
exclude_pat=None,
|
||||
max_depth=None,
|
||||
follow_symlinks=False):
|
||||
'''
|
||||
@ -764,7 +764,7 @@ def _check_directory(name,
|
||||
|
||||
|
||||
def _check_directory_win(name,
|
||||
win_owner,
|
||||
win_owner=None,
|
||||
win_perms=None,
|
||||
win_deny_perms=None,
|
||||
win_inheritance=None,
|
||||
@ -778,9 +778,10 @@ def _check_directory_win(name,
|
||||
changes = {name: {'directory': 'new'}}
|
||||
else:
|
||||
# Check owner
|
||||
owner = salt.utils.win_dacl.get_owner(name)
|
||||
if not owner.lower() == win_owner.lower():
|
||||
changes['owner'] = win_owner
|
||||
if win_owner is not None:
|
||||
owner = salt.utils.win_dacl.get_owner(name)
|
||||
if not owner.lower() == win_owner.lower():
|
||||
changes['owner'] = win_owner
|
||||
|
||||
# Check perms
|
||||
perms = salt.utils.win_dacl.get_permissions(name)
|
||||
@ -956,33 +957,46 @@ def _check_touch(name, atime, mtime):
|
||||
|
||||
|
||||
def _get_symlink_ownership(path):
|
||||
return (
|
||||
__salt__['file.get_user'](path, follow_symlinks=False),
|
||||
__salt__['file.get_group'](path, follow_symlinks=False)
|
||||
)
|
||||
if salt.utils.is_windows():
|
||||
owner = salt.utils.win_dacl.get_owner(path)
|
||||
return owner, owner
|
||||
else:
|
||||
return (
|
||||
__salt__['file.get_user'](path, follow_symlinks=False),
|
||||
__salt__['file.get_group'](path, follow_symlinks=False)
|
||||
)
|
||||
|
||||
|
||||
def _check_symlink_ownership(path, user, group):
|
||||
def _check_symlink_ownership(path, user, group, win_owner):
|
||||
'''
|
||||
Check if the symlink ownership matches the specified user and group
|
||||
'''
|
||||
cur_user, cur_group = _get_symlink_ownership(path)
|
||||
return (cur_user == user) and (cur_group == group)
|
||||
if salt.utils.is_windows():
|
||||
return win_owner == cur_user
|
||||
else:
|
||||
return (cur_user == user) and (cur_group == group)
|
||||
|
||||
|
||||
def _set_symlink_ownership(path, user, group):
|
||||
def _set_symlink_ownership(path, user, group, win_owner):
|
||||
'''
|
||||
Set the ownership of a symlink and return a boolean indicating
|
||||
success/failure
|
||||
'''
|
||||
try:
|
||||
__salt__['file.lchown'](path, user, group)
|
||||
except OSError:
|
||||
pass
|
||||
return _check_symlink_ownership(path, user, group)
|
||||
if salt.utils.is_windows():
|
||||
try:
|
||||
salt.utils.win_dacl.set_owner(path, win_owner)
|
||||
except CommandExecutionError:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
__salt__['file.lchown'](path, user, group)
|
||||
except OSError:
|
||||
pass
|
||||
return _check_symlink_ownership(path, user, group, win_owner)
|
||||
|
||||
|
||||
def _symlink_check(name, target, force, user, group):
|
||||
def _symlink_check(name, target, force, user, group, win_owner):
|
||||
'''
|
||||
Check the symlink function
|
||||
'''
|
||||
@ -1001,7 +1015,7 @@ def _symlink_check(name, target, force, user, group):
|
||||
else:
|
||||
result = True
|
||||
msg = 'The symlink {0} is present'.format(name)
|
||||
if not _check_symlink_ownership(name, user, group):
|
||||
if not _check_symlink_ownership(name, user, group, win_owner):
|
||||
result = None
|
||||
pchanges['ownership'] = '{0}:{1}'.format(*_get_symlink_ownership(name))
|
||||
msg += (
|
||||
@ -1225,6 +1239,57 @@ def _shortcut_check(name,
|
||||
'should be. Did you mean to use force?'.format(name)), pchanges
|
||||
|
||||
|
||||
def _makedirs(name,
|
||||
user=None,
|
||||
group=None,
|
||||
dir_mode=None,
|
||||
win_owner=None,
|
||||
win_perms=None,
|
||||
win_deny_perms=None,
|
||||
win_inheritance=None):
|
||||
'''
|
||||
Helper function for creating directories when the ``makedirs`` option is set
|
||||
to ``True``. Handles Unix and Windows based systems
|
||||
|
||||
.. versionadded:: 2017.7.7
|
||||
|
||||
Args:
|
||||
name (str): The directory path to create
|
||||
user (str): The linux user to own the directory
|
||||
group (str): The linux group to own the directory
|
||||
dir_mode (str): The linux mode to apply to the directory
|
||||
win_owner (str): The Windows user to own the directory
|
||||
win_perms (dict): A dictionary of grant permissions for Windows
|
||||
win_deny_perms (dict): A dictionary of deny permissions for Windows
|
||||
win_inheritance (bool): True to inherit permissions on Windows
|
||||
|
||||
Returns:
|
||||
bool: True if successful, otherwise False on Windows
|
||||
str: Error messages on failure on Linux
|
||||
None: On successful creation on Linux
|
||||
|
||||
Raises:
|
||||
CommandExecutionError: If the drive is not mounted on Windows
|
||||
'''
|
||||
if salt.utils.is_windows():
|
||||
# Make sure the drive is mapped before trying to create the
|
||||
# path in windows
|
||||
drive, path = os.path.splitdrive(name)
|
||||
if not os.path.isdir(drive):
|
||||
raise CommandExecutionError(drive)
|
||||
win_owner = win_owner if win_owner else user
|
||||
return __salt__['file.makedirs'](path=name,
|
||||
owner=win_owner,
|
||||
grant_perms=win_perms,
|
||||
deny_perms=win_deny_perms,
|
||||
inheritance=win_inheritance)
|
||||
else:
|
||||
return __salt__['file.makedirs'](path=name,
|
||||
user=user,
|
||||
group=group,
|
||||
mode=dir_mode)
|
||||
|
||||
|
||||
def symlink(
|
||||
name,
|
||||
target,
|
||||
@ -1234,6 +1299,10 @@ def symlink(
|
||||
user=None,
|
||||
group=None,
|
||||
mode=None,
|
||||
win_owner=None,
|
||||
win_perms=None,
|
||||
win_deny_perms=None,
|
||||
win_inheritance=None,
|
||||
**kwargs):
|
||||
'''
|
||||
Create a symbolic link (symlink, soft link)
|
||||
@ -1282,6 +1351,28 @@ def symlink(
|
||||
|
||||
The default mode for new files and directories corresponds umask of salt
|
||||
process. For existing files and directories it's not enforced.
|
||||
|
||||
win_owner : None
|
||||
The owner of the symlink and directories if ``makedirs`` is True. If
|
||||
this is not passed, ``user`` will be used. If ``user`` is not passed,
|
||||
the account under which Salt is running will be used.
|
||||
|
||||
.. versionadded:: 2017.7.7
|
||||
|
||||
win_perms : None
|
||||
A dictionary containing permissions to grant
|
||||
|
||||
.. versionadded:: 2017.7.7
|
||||
|
||||
win_deny_perms : None
|
||||
A dictionary containing permissions to deny
|
||||
|
||||
.. versionadded:: 2017.7.7
|
||||
|
||||
win_inheritance : None
|
||||
True to inherit permissions from parent, otherwise False
|
||||
|
||||
.. versionadded:: 2017.7.7
|
||||
'''
|
||||
name = os.path.expanduser(name)
|
||||
|
||||
@ -1310,10 +1401,16 @@ def symlink(
|
||||
if not user:
|
||||
user = 'SYSTEM'
|
||||
|
||||
# If win_owner is not passed, use user
|
||||
if win_owner is None:
|
||||
win_owner = user if user else None
|
||||
|
||||
# Group isn't relevant to Windows, use win_perms/win_deny_perms
|
||||
if group is not None:
|
||||
log.warning(
|
||||
'The group argument for {0} has been ignored as this '
|
||||
'is a Windows system.'.format(name)
|
||||
'is a Windows system. Please use the `win_*` parameters to set '
|
||||
'permissions in Windows.'.format(name)
|
||||
)
|
||||
group = user
|
||||
|
||||
@ -1323,14 +1420,31 @@ def symlink(
|
||||
)
|
||||
|
||||
preflight_errors = []
|
||||
uid = __salt__['file.user_to_uid'](user)
|
||||
gid = __salt__['file.group_to_gid'](group)
|
||||
if salt.utils.is_windows():
|
||||
# Make sure the passed owner exists
|
||||
if not salt.utils.win_functions.get_sid_from_name(win_owner):
|
||||
preflight_errors.append('User {0} does not exist'.format(win_owner))
|
||||
|
||||
if uid == '':
|
||||
preflight_errors.append('User {0} does not exist'.format(user))
|
||||
# Make sure users passed in win_perms exist
|
||||
if win_perms:
|
||||
for name_check in win_perms:
|
||||
if not salt.utils.win_functions.get_sid_from_name(name_check):
|
||||
preflight_errors.append('User {0} does not exist'.format(name_check))
|
||||
|
||||
if gid == '':
|
||||
preflight_errors.append('Group {0} does not exist'.format(group))
|
||||
# Make sure users passed in win_deny_perms exist
|
||||
if win_deny_perms:
|
||||
for name_check in win_deny_perms:
|
||||
if not salt.utils.win_functions.get_sid_from_name(name_check):
|
||||
preflight_errors.append('User {0} does not exist'.format(name_check))
|
||||
else:
|
||||
uid = __salt__['file.user_to_uid'](user)
|
||||
gid = __salt__['file.group_to_gid'](group)
|
||||
|
||||
if uid == '':
|
||||
preflight_errors.append('User {0} does not exist'.format(user))
|
||||
|
||||
if gid == '':
|
||||
preflight_errors.append('Group {0} does not exist'.format(group))
|
||||
|
||||
if not os.path.isabs(name):
|
||||
preflight_errors.append(
|
||||
@ -1347,47 +1461,77 @@ def symlink(
|
||||
target,
|
||||
force,
|
||||
user,
|
||||
group)
|
||||
group,
|
||||
win_owner)
|
||||
|
||||
if not os.path.isdir(os.path.dirname(name)):
|
||||
if makedirs:
|
||||
if __opts__['test']:
|
||||
pcomment += '\n{0} will be created'.format(os.path.dirname(name))
|
||||
else:
|
||||
try:
|
||||
_makedirs(name=name,
|
||||
user=user,
|
||||
group=group,
|
||||
dir_mode=mode,
|
||||
win_owner=win_owner,
|
||||
win_perms=win_perms,
|
||||
win_deny_perms=win_deny_perms,
|
||||
win_inheritance=win_inheritance)
|
||||
except CommandExecutionError as exc:
|
||||
return _error(ret, 'Drive {0} is not mapped'.format(exc.message))
|
||||
else:
|
||||
if __opts__['test']:
|
||||
pcomment += '\nDirectory {0} for symlink is not present' \
|
||||
''.format(os.path.dirname(name))
|
||||
else:
|
||||
return _error(
|
||||
ret,
|
||||
'Directory {0} for symlink is not present'.format(
|
||||
os.path.dirname(name)
|
||||
)
|
||||
)
|
||||
|
||||
if __opts__['test']:
|
||||
ret['result'] = presult
|
||||
ret['comment'] = pcomment
|
||||
return ret
|
||||
|
||||
if not os.path.isdir(os.path.dirname(name)):
|
||||
if makedirs:
|
||||
__salt__['file.makedirs'](
|
||||
name,
|
||||
user=user,
|
||||
group=group,
|
||||
mode=mode)
|
||||
else:
|
||||
return _error(
|
||||
ret,
|
||||
'Directory {0} for symlink is not present'.format(
|
||||
os.path.dirname(name)
|
||||
)
|
||||
)
|
||||
if __salt__['file.is_link'](name):
|
||||
# The link exists, verify that it matches the target
|
||||
if os.path.normpath(__salt__['file.readlink'](name)) != os.path.normpath(target):
|
||||
# The target is wrong, delete the link
|
||||
os.remove(name)
|
||||
else:
|
||||
if _check_symlink_ownership(name, user, group):
|
||||
if _check_symlink_ownership(name, user, group, win_owner):
|
||||
# The link looks good!
|
||||
ret['comment'] = ('Symlink {0} is present and owned by '
|
||||
'{1}:{2}'.format(name, user, group))
|
||||
else:
|
||||
if _set_symlink_ownership(name, user, group):
|
||||
ret['comment'] = ('Set ownership of symlink {0} to '
|
||||
if salt.utils.is_windows():
|
||||
ret['comment'] = ('Symlink {0} is present and owned by {1}'
|
||||
''.format(name, win_owner))
|
||||
else:
|
||||
ret['comment'] = ('Symlink {0} is present and owned by '
|
||||
'{1}:{2}'.format(name, user, group))
|
||||
ret['changes']['ownership'] = '{0}:{1}'.format(user, group)
|
||||
else:
|
||||
if _set_symlink_ownership(name, user, group, win_owner):
|
||||
if salt.utils.is_windows():
|
||||
ret['comment'] = ('Set ownership of symlink {0} to '
|
||||
'{1}'.format(name, win_owner))
|
||||
ret['changes']['ownership'] = win_owner
|
||||
else:
|
||||
ret['comment'] = ('Set ownership of symlink {0} to '
|
||||
'{1}:{2}'.format(name, user, group))
|
||||
ret['changes']['ownership'] = '{0}:{1}'.format(user,
|
||||
group)
|
||||
else:
|
||||
ret['result'] = False
|
||||
ret['comment'] += (
|
||||
'Failed to set ownership of symlink {0} to '
|
||||
'{1}:{2}'.format(name, user, group)
|
||||
)
|
||||
if salt.utils.is_windows():
|
||||
ret['comment'] += (
|
||||
'Failed to set ownership of symlink '
|
||||
'{0} to {1}'.format(name, win_owner))
|
||||
else:
|
||||
ret['comment'] += (
|
||||
'Failed to set ownership of symlink {0} to '
|
||||
'{1}:{2}'.format(name, user, group))
|
||||
return ret
|
||||
|
||||
elif os.path.isfile(name) or os.path.isdir(name):
|
||||
@ -1434,8 +1578,8 @@ def symlink(
|
||||
'{1}'.format(name, target))
|
||||
ret['changes']['new'] = name
|
||||
|
||||
if not _check_symlink_ownership(name, user, group):
|
||||
if not _set_symlink_ownership(name, user, group):
|
||||
if not _check_symlink_ownership(name, user, group, win_owner):
|
||||
if not _set_symlink_ownership(name, user, group, win_owner):
|
||||
ret['result'] = False
|
||||
ret['comment'] += (', but was unable to set ownership to '
|
||||
'{0}:{1}'.format(user, group))
|
||||
@ -2971,23 +3115,17 @@ def directory(name,
|
||||
# The parent directory does not exist, create them
|
||||
if makedirs:
|
||||
# Everything's good, create the parent Dirs
|
||||
if salt.utils.platform.is_windows():
|
||||
# Make sure the drive is mapped before trying to create the
|
||||
# path in windows
|
||||
drive, path = os.path.splitdrive(name)
|
||||
if not os.path.isdir(drive):
|
||||
return _error(
|
||||
ret, 'Drive {0} is not mapped'.format(drive))
|
||||
__salt__['file.makedirs'](
|
||||
path=name,
|
||||
owner=win_owner,
|
||||
grant_perms=win_perms,
|
||||
deny_perms=win_deny_perms,
|
||||
inheritance=win_inheritance,
|
||||
reset=win_perms_reset)
|
||||
else:
|
||||
__salt__['file.makedirs'](name, user=user, group=group,
|
||||
mode=dir_mode)
|
||||
try:
|
||||
_makedirs(name=name,
|
||||
user=user,
|
||||
group=group,
|
||||
dir_mode=dir_mode,
|
||||
win_owner=win_owner,
|
||||
win_perms=win_perms,
|
||||
win_deny_perms=win_deny_perms,
|
||||
win_inheritance=win_inheritance)
|
||||
except CommandExecutionError as exc:
|
||||
return _error(ret, 'Drive {0} is not mapped'.format(exc.message))
|
||||
else:
|
||||
return _error(
|
||||
ret, 'No directory to create {0} in'.format(name))
|
||||
@ -3182,6 +3320,10 @@ def recurse(name,
|
||||
maxdepth=None,
|
||||
keep_symlinks=False,
|
||||
force_symlinks=False,
|
||||
win_owner=None,
|
||||
win_perms=None,
|
||||
win_deny_perms=None,
|
||||
win_inheritance=True,
|
||||
**kwargs):
|
||||
'''
|
||||
Recurse through a subdirectory on the master and copy said subdirectory
|
||||
@ -3341,6 +3483,28 @@ def recurse(name,
|
||||
If a file or directory is obstructing symlink creation it will be
|
||||
recursively removed so that symlink creation can proceed. This
|
||||
option is usually not needed except in special circumstances.
|
||||
|
||||
win_owner : None
|
||||
The owner of the symlink and directories if ``makedirs`` is True. If
|
||||
this is not passed, ``user`` will be used. If ``user`` is not passed,
|
||||
the account under which Salt is running will be used.
|
||||
|
||||
.. versionadded:: 2017.7.7
|
||||
|
||||
win_perms : None
|
||||
A dictionary containing permissions to grant
|
||||
|
||||
.. versionadded:: 2017.7.7
|
||||
|
||||
win_deny_perms : None
|
||||
A dictionary containing permissions to deny
|
||||
|
||||
.. versionadded:: 2017.7.7
|
||||
|
||||
win_inheritance : None
|
||||
True to inherit permissions from parent, otherwise False
|
||||
|
||||
.. versionadded:: 2017.7.7
|
||||
'''
|
||||
if 'env' in kwargs:
|
||||
# "env" is not supported; Use "saltenv".
|
||||
@ -3439,7 +3603,18 @@ def recurse(name,
|
||||
return _error(
|
||||
ret, 'The path {0} exists and is not a directory'.format(name))
|
||||
if not __opts__['test']:
|
||||
__salt__['file.makedirs_perms'](name, user, group, dir_mode)
|
||||
if salt.utils.is_windows():
|
||||
win_owner = win_owner if win_owner else user
|
||||
__salt__['file.makedirs_perms'](path=name,
|
||||
owner=win_owner,
|
||||
grant_perms=win_perms,
|
||||
deny_perms=win_deny_perms,
|
||||
inheritance=win_inheritance)
|
||||
else:
|
||||
__salt__['file.makedirs_perms'](name=name,
|
||||
user=user,
|
||||
group=group,
|
||||
mode=dir_mode)
|
||||
|
||||
def add_comment(path, comment):
|
||||
comments = ret['comment'].setdefault(path, [])
|
||||
@ -4821,10 +4996,16 @@ def append(name,
|
||||
if makedirs is True:
|
||||
dirname = os.path.dirname(name)
|
||||
if not __salt__['file.directory_exists'](dirname):
|
||||
__salt__['file.makedirs'](name)
|
||||
check_res, check_msg, ret['pchanges'] = _check_directory(
|
||||
dirname, None, None, False, None, False, False, None
|
||||
)
|
||||
try:
|
||||
_makedirs(name=name)
|
||||
except CommandExecutionError as exc:
|
||||
return _error(ret, 'Drive {0} is not mapped'.format(exc.message))
|
||||
|
||||
if salt.utils.is_windows():
|
||||
check_res, check_msg, ret['pchanges'] = _check_directory_win(dirname)
|
||||
else:
|
||||
check_res, check_msg, ret['pchanges'] = _check_directory(dirname)
|
||||
|
||||
if not check_res:
|
||||
return _error(ret, check_msg)
|
||||
|
||||
@ -4935,6 +5116,90 @@ def prepend(name,
|
||||
The text will not be prepended again if it already exists in the file. You
|
||||
may specify a single line of text or a list of lines to append.
|
||||
|
||||
name
|
||||
The location of the file to append to.
|
||||
|
||||
text
|
||||
The text to be appended, which can be a single string or a list
|
||||
of strings.
|
||||
|
||||
makedirs
|
||||
If the file is located in a path without a parent directory,
|
||||
then the state will fail. If makedirs is set to True, then
|
||||
the parent directories will be created to facilitate the
|
||||
creation of the named file. Defaults to False.
|
||||
|
||||
source
|
||||
A single source file to append. This source file can be hosted on either
|
||||
the salt master server, or on an HTTP or FTP server. Both HTTPS and
|
||||
HTTP are supported as well as downloading directly from Amazon S3
|
||||
compatible URLs with both pre-configured and automatic IAM credentials
|
||||
(see s3.get state documentation). File retrieval from Openstack Swift
|
||||
object storage is supported via swift://container/object_path URLs
|
||||
(see swift.get documentation).
|
||||
|
||||
For files hosted on the salt file server, if the file is located on
|
||||
the master in the directory named spam, and is called eggs, the source
|
||||
string is salt://spam/eggs.
|
||||
|
||||
If the file is hosted on an HTTP or FTP server, the source_hash argument
|
||||
is also required.
|
||||
|
||||
source_hash
|
||||
This can be one of the following:
|
||||
1. a source hash string
|
||||
2. the URI of a file that contains source hash strings
|
||||
|
||||
The function accepts the first encountered long unbroken alphanumeric
|
||||
string of correct length as a valid hash, in order from most secure to
|
||||
least secure:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
Type Length
|
||||
====== ======
|
||||
sha512 128
|
||||
sha384 96
|
||||
sha256 64
|
||||
sha224 56
|
||||
sha1 40
|
||||
md5 32
|
||||
|
||||
See the ``source_hash`` parameter description for :mod:`file.managed
|
||||
<salt.states.file.managed>` function for more details and examples.
|
||||
|
||||
template
|
||||
The named templating engine will be used to render the appended-to file.
|
||||
Defaults to ``jinja``. The following templates are supported:
|
||||
|
||||
- :mod:`cheetah<salt.renderers.cheetah>`
|
||||
- :mod:`genshi<salt.renderers.genshi>`
|
||||
- :mod:`jinja<salt.renderers.jinja>`
|
||||
- :mod:`mako<salt.renderers.mako>`
|
||||
- :mod:`py<salt.renderers.py>`
|
||||
- :mod:`wempy<salt.renderers.wempy>`
|
||||
|
||||
sources
|
||||
A list of source files to append. If the files are hosted on an HTTP or
|
||||
FTP server, the source_hashes argument is also required.
|
||||
|
||||
source_hashes
|
||||
A list of source_hashes corresponding to the sources list specified in
|
||||
the sources argument.
|
||||
|
||||
defaults
|
||||
Default context passed to the template.
|
||||
|
||||
context
|
||||
Overrides default context variables passed to the template.
|
||||
|
||||
ignore_whitespace
|
||||
.. versionadded:: 2015.8.4
|
||||
|
||||
Spaces and Tabs in text are ignored by default, when searching for the
|
||||
appending content, one space or multiple tabs are the same for salt.
|
||||
Set this option to ``False`` if you want to change this behavior.
|
||||
|
||||
Multi-line example:
|
||||
|
||||
.. code-block:: yaml
|
||||
@ -5013,10 +5278,15 @@ def prepend(name,
|
||||
if makedirs is True:
|
||||
dirname = os.path.dirname(name)
|
||||
if not __salt__['file.directory_exists'](dirname):
|
||||
__salt__['file.makedirs'](name)
|
||||
check_res, check_msg, ret['pchanges'] = _check_directory(
|
||||
dirname, None, None, False, None, False, False, None
|
||||
)
|
||||
try:
|
||||
_makedirs(name=name)
|
||||
except CommandExecutionError as exc:
|
||||
return _error(ret, 'Drive {0} is not mapped'.format(exc.message))
|
||||
|
||||
if salt.utils.is_windows():
|
||||
check_res, check_msg, ret['pchanges'] = _check_directory_win(dirname)
|
||||
else:
|
||||
check_res, check_msg, ret['pchanges'] = _check_directory(dirname)
|
||||
if not check_res:
|
||||
return _error(ret, check_msg)
|
||||
|
||||
@ -5302,7 +5572,10 @@ def touch(name, atime=None, mtime=None, makedirs=False):
|
||||
return ret
|
||||
|
||||
if makedirs:
|
||||
__salt__['file.makedirs'](name)
|
||||
try:
|
||||
_makedirs(name=name)
|
||||
except CommandExecutionError as exc:
|
||||
return _error(ret, 'Drive {0} is not mapped'.format(exc.message))
|
||||
if not os.path.isdir(os.path.dirname(name)):
|
||||
return _error(
|
||||
ret, 'Directory not present to touch file {0}'.format(name)
|
||||
@ -5499,7 +5772,10 @@ def copy(
|
||||
dname = os.path.dirname(name)
|
||||
if not os.path.isdir(dname):
|
||||
if makedirs:
|
||||
__salt__['file.makedirs'](name)
|
||||
try:
|
||||
_makedirs(name=name)
|
||||
except CommandExecutionError as exc:
|
||||
return _error(ret, 'Drive {0} is not mapped'.format(exc.message))
|
||||
else:
|
||||
return _error(
|
||||
ret,
|
||||
@ -5596,7 +5872,10 @@ def rename(name, source, force=False, makedirs=False):
|
||||
dname = os.path.dirname(name)
|
||||
if not os.path.isdir(dname):
|
||||
if makedirs:
|
||||
__salt__['file.makedirs'](name)
|
||||
try:
|
||||
_makedirs(name=name)
|
||||
except CommandExecutionError as exc:
|
||||
return _error(ret, 'Drive {0} is not mapped'.format(exc.message))
|
||||
else:
|
||||
return _error(
|
||||
ret,
|
||||
@ -6470,9 +6749,10 @@ def shortcut(
|
||||
|
||||
if not os.path.isdir(os.path.dirname(name)):
|
||||
if makedirs:
|
||||
__salt__['file.makedirs'](
|
||||
name,
|
||||
user=user)
|
||||
try:
|
||||
_makedirs(name=name, user=user)
|
||||
except CommandExecutionError as exc:
|
||||
return _error(ret, 'Drive {0} is not mapped'.format(exc.message))
|
||||
else:
|
||||
return _error(
|
||||
ret,
|
||||
@ -6495,7 +6775,10 @@ def shortcut(
|
||||
time.sleep(1) # wait for asynchronous deletion
|
||||
if not os.path.isdir(os.path.dirname(backupname)):
|
||||
if makedirs:
|
||||
os.makedirs(backupname)
|
||||
try:
|
||||
_makedirs(name=backupname)
|
||||
except CommandExecutionError as exc:
|
||||
return _error(ret, 'Drive {0} is not mapped'.format(exc.message))
|
||||
else:
|
||||
return _error(ret, (
|
||||
'Directory does not exist for'
|
||||
|
@ -239,7 +239,8 @@ class WindowsUpdateAgent(object):
|
||||
# Error codes found at the following site:
|
||||
# https://msdn.microsoft.com/en-us/library/windows/desktop/hh968413(v=vs.85).aspx
|
||||
# https://technet.microsoft.com/en-us/library/cc720442(v=ws.10).aspx
|
||||
fail_codes = {-2145124300: 'Download failed: 0x80240034',
|
||||
fail_codes = {-2145107924: 'WinHTTP Send/Receive failed: 0x8024402C',
|
||||
-2145124300: 'Download failed: 0x80240034',
|
||||
-2145124302: 'Invalid search criteria: 0x80240032',
|
||||
-2145124305: 'Cancelled by policy: 0x8024002F',
|
||||
-2145124307: 'Missing source: 0x8024002D',
|
||||
|
@ -254,11 +254,13 @@ def pytest_runtest_setup(item):
|
||||
if destructive_tests_marker is not None:
|
||||
if item.config.getoption('--run-destructive') is False:
|
||||
pytest.skip('Destructive tests are disabled')
|
||||
os.environ['DESTRUCTIVE_TESTS'] = six.text_type(item.config.getoption('--run-destructive'))
|
||||
|
||||
expensive_tests_marker = item.get_marker('expensive_test')
|
||||
if expensive_tests_marker is not None:
|
||||
if item.config.getoption('--run-expensive') is False:
|
||||
pytest.skip('Expensive tests are disabled')
|
||||
os.environ['EXPENSIVE_TESTS'] = six.text_type(item.config.getoption('--run-expensive'))
|
||||
|
||||
skip_if_not_root_marker = item.get_marker('skip_if_not_root')
|
||||
if skip_if_not_root_marker is not None:
|
||||
|
@ -1,6 +1,6 @@
|
||||
{% set versions = {'18':['05', '03', '01'], '16':['04', '03', '02', '00'], '9':['20']} %}
|
||||
|
||||
Zzip:
|
||||
7zip:
|
||||
{% for major, subversions in versions.items() %}
|
||||
{% for minor in subversions %}
|
||||
'{{major}}.{{minor}}.00.0':
|
||||
|
@ -127,7 +127,11 @@ class ServiceModuleTest(ModuleCase):
|
||||
# currently upstart does not have a mechanism to report if disabling a service fails if does not exist
|
||||
self.assertTrue(self.run_function('service.disable', [srv_name]))
|
||||
else:
|
||||
self.assertFalse(self.run_function('service.disable', [srv_name]))
|
||||
if salt.utils.is_windows():
|
||||
disable = self.run_function('service.disable', [srv_name])
|
||||
self.assertTrue('error' in disable.lower())
|
||||
else:
|
||||
self.assertFalse(self.run_function('service.disable', [srv_name]))
|
||||
|
||||
if salt.utils.platform.is_darwin():
|
||||
self.assertFalse(self.run_function('service.disabled', [srv_name]))
|
||||
|
@ -270,13 +270,15 @@ class PkgTest(ModuleCase, SaltReturnAssertsMixin):
|
||||
except AssertionError:
|
||||
self.assertSaltTrueReturn(self.run_state('pkg.removed', name=None, pkgs=pkg_targets))
|
||||
|
||||
ret = self.run_state('pkg.installed',
|
||||
name=None,
|
||||
pkgs=pkg_targets,
|
||||
refresh=False)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
ret = self.run_state('pkg.removed', name=None, pkgs=pkg_targets)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
try:
|
||||
ret = self.run_state('pkg.installed',
|
||||
name=None,
|
||||
pkgs=pkg_targets,
|
||||
refresh=False)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
finally:
|
||||
ret = self.run_state('pkg.removed', name=None, pkgs=pkg_targets)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
@requires_system_grains
|
||||
def test_pkg_004_installed_multipkg_with_version(self, grains=None):
|
||||
@ -318,13 +320,15 @@ class PkgTest(ModuleCase, SaltReturnAssertsMixin):
|
||||
|
||||
pkgs = [{pkg_targets[0]: version}, pkg_targets[1]]
|
||||
|
||||
ret = self.run_state('pkg.installed',
|
||||
name=None,
|
||||
pkgs=pkgs,
|
||||
refresh=False)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
ret = self.run_state('pkg.removed', name=None, pkgs=pkg_targets)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
try:
|
||||
ret = self.run_state('pkg.installed',
|
||||
name=None,
|
||||
pkgs=pkgs,
|
||||
refresh=False)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
finally:
|
||||
ret = self.run_state('pkg.removed', name=None, pkgs=pkg_targets)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
@requires_system_grains
|
||||
def test_pkg_005_installed_32bit(self, grains=None):
|
||||
|
@ -9,7 +9,6 @@ on a single system to test scale capabilities
|
||||
# Import Python Libs
|
||||
from __future__ import absolute_import, print_function
|
||||
import os
|
||||
import pwd
|
||||
import time
|
||||
import signal
|
||||
import optparse
|
||||
@ -29,6 +28,7 @@ import salt.utils.yaml
|
||||
# Import third party libs
|
||||
from salt.ext import six
|
||||
from salt.ext.six.moves import range # pylint: disable=import-error,redefined-builtin
|
||||
import tests.support.helpers
|
||||
|
||||
|
||||
OSES = [
|
||||
@ -148,7 +148,7 @@ def parse():
|
||||
'-c', '--config-dir', default='',
|
||||
help=('Pass in a configuration directory containing base configuration.')
|
||||
)
|
||||
parser.add_option('-u', '--user', default=pwd.getpwuid(os.getuid()).pw_name)
|
||||
parser.add_option('-u', '--user', default=tests.support.helpers.this_user())
|
||||
|
||||
options, _args = parser.parse_args()
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
from functools import wraps
|
||||
import os
|
||||
import io
|
||||
import stat
|
||||
|
||||
@ -12,6 +13,7 @@ import salt.daemons.masterapi as masterapi
|
||||
import salt.utils.platform
|
||||
|
||||
# Import Salt Testing Libs
|
||||
from tests.support.paths import TMP_CONF_DIR
|
||||
from tests.support.unit import TestCase, skipIf
|
||||
from tests.support.mock import (
|
||||
patch,
|
||||
@ -568,7 +570,7 @@ class RemoteFuncsTestCase(TestCase):
|
||||
'''
|
||||
|
||||
def setUp(self):
|
||||
opts = salt.config.master_config(None)
|
||||
opts = salt.config.master_config(os.path.join(TMP_CONF_DIR, 'master'))
|
||||
self.funcs = masterapi.RemoteFuncs(opts)
|
||||
self.funcs.cache = FakeCache()
|
||||
|
||||
|
@ -59,9 +59,11 @@ class DocTestCase(TestCase):
|
||||
key, val = regex.split(line, 1)
|
||||
|
||||
# Don't test man pages, this file,
|
||||
# the page that documents to not use ":doc:", or
|
||||
# the doc/conf.py file
|
||||
# the tox virtualenv files, the page
|
||||
# that documents to not use ":doc:",
|
||||
# or the doc/conf.py file
|
||||
if 'man' in key \
|
||||
or '.tox/' in key \
|
||||
or key.endswith('test_doc.py') \
|
||||
or key.endswith(os.sep.join(['doc', 'conf.py'])) \
|
||||
or key.endswith(os.sep.join(['conventions', 'documentation.rst'])) \
|
||||
|
15
tox.ini
15
tox.ini
@ -2,15 +2,6 @@
|
||||
envlist = py27,py34,py35,py36
|
||||
|
||||
[testenv]
|
||||
sitepackages = True
|
||||
deps =
|
||||
py27,pylint: -r{toxinidir}/requirements/dev_python27.txt
|
||||
py34,py35,py36: -r{toxinidir}/requirements/dev_python34.txt
|
||||
commands =
|
||||
py27: python2 {toxinidir}/tests/runtests.py {posargs:-v --run-destructive}
|
||||
py34,py35,py36: python3 {toxinidir}/tests/runtests.py {posargs:-v --run-destructive}
|
||||
|
||||
[testenv:pylint]
|
||||
basepython = python2.7
|
||||
commands = pylint --rcfile={toxinidir}/.testing.pylintrc --disable=W1307 {posargs:setup.py salt/}
|
||||
pylint --rcfile={toxinidir}/.testing.pylintrc --disable=W0232,E1002,W1307 {posargs:tests/}
|
||||
deps = -r{toxinidir}/requirements/tests.txt
|
||||
commands = pytest --rootdir {toxinidir} {posargs:--no-print-logs --run-destructive}
|
||||
passenv = LANG HOME
|
||||
|
Loading…
Reference in New Issue
Block a user