Merge pull request #52601 from Ch3LL/cp-52415

Cherry-Pick #52415 into 2019.2.1
This commit is contained in:
Daniel Wozniak 2019-04-21 12:33:03 -07:00 committed by GitHub
commit f7d823c8aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 600 additions and 518 deletions

View File

@ -259,10 +259,6 @@ A State Module must return a dict containing the following keys/values:
Prefer to keep line lengths short (use multiple lines as needed),
and end with punctuation (e.g. a period) to delimit multiple comments.
The return data can also, include the **pchanges** key, this stands for
`predictive changes`. The **pchanges** key informs the State system what
changes are predicted to occur.
.. note::
States should not return data which cannot be serialized such as frozensets.
@ -448,7 +444,6 @@ Example state module
'changes': {},
'result': False,
'comment': '',
'pchanges': {},
}
# Start with basic error-checking. Do all the passed parameters make sense
@ -469,7 +464,7 @@ Example state module
# in ``test=true`` mode.
if __opts__['test'] == True:
ret['comment'] = 'The state of "{0}" will be changed.'.format(name)
ret['pchanges'] = {
ret['changes'] = {
'old': current_state,
'new': 'Description, diff, whatever of the new state',
}

View File

@ -1436,25 +1436,19 @@ def extracted(name,
dir_result = __states__['file.directory'](full_path,
user=user,
group=group,
recurse=recurse,
test=__opts__['test'])
recurse=recurse)
log.debug('file.directory: %s', dir_result)
if __opts__['test']:
if dir_result.get('pchanges'):
ret['changes']['updated ownership'] = True
else:
try:
if dir_result['result']:
if dir_result['changes']:
ret['changes']['updated ownership'] = True
else:
enforce_failed.append(full_path)
except (KeyError, TypeError):
log.warning(
'Bad state return %s for file.directory state on %s',
dir_result, dirname
)
if dir_result.get('changes'):
ret['changes']['updated ownership'] = True
try:
if not dir_result['result']:
enforce_failed.append(full_path)
except (KeyError, TypeError):
log.warning(
'Bad state return %s for file.directory state on %s',
dir_result, dirname
)
for filename in enforce_files + enforce_links:
full_path = os.path.join(name, filename)

View File

@ -135,7 +135,7 @@ def present(
if __opts__['test']:
ret['result'] = None
ret['comment'] = 'Distribution {0} set for creation.'.format(name)
ret['pchanges'] = {'old': None, 'new': name}
ret['changes'] = {'old': None, 'new': name}
return ret
res = __salt__['boto_cloudfront.create_distribution'](
@ -203,7 +203,7 @@ def present(
'Distribution {0} set for new config:'.format(name),
changes_diff,
])
ret['pchanges'] = {'diff': changes_diff}
ret['changes'] = {'diff': changes_diff}
return ret
res = __salt__['boto_cloudfront.update_distribution'](

View File

@ -282,7 +282,7 @@ def object_present(
ret['result'] = None
ret['comment'] = 'S3 object {0} set to be {1}d.'.format(name, action)
ret['comment'] += '\nChanges:\n{0}'.format(changes_diff)
ret['pchanges'] = {'diff': changes_diff}
ret['changes'] = {'diff': changes_diff}
return ret
r = __salt__['boto_s3.upload_file'](

View File

@ -136,7 +136,7 @@ def present(
ret['comment'].append(
'SQS queue {0} is set to be created.'.format(name),
)
ret['pchanges'] = {'old': None, 'new': name}
ret['changes'] = {'old': None, 'new': name}
return ret
r = __salt__['boto_sqs.create'](
@ -225,7 +225,7 @@ def present(
attributes_diff,
)
)
ret['pchanges'] = {'attributes': {'diff': attributes_diff}}
ret['changes'] = {'attributes': {'diff': attributes_diff}}
return ret
r = __salt__['boto_sqs.set_attributes'](
@ -300,7 +300,7 @@ def absent(
if __opts__['test']:
ret['result'] = None
ret['comment'] = 'SQS queue {0} is set to be removed.'.format(name)
ret['pchanges'] = {'old': name, 'new': None}
ret['changes'] = {'old': name, 'new': None}
return ret
r = __salt__['boto_sqs.delete'](

View File

@ -336,7 +336,6 @@ def upgraded(name,
ret = {'name': name,
'result': True,
'changes': {},
'pchanges': {},
'comment': ''}
# Get list of currently installed packages
@ -346,12 +345,10 @@ def upgraded(name,
# Package not installed
if name.lower() not in [package.lower() for package in pre_install.keys()]:
if version:
ret['pchanges'] = {
name: 'Version {0} will be installed'.format(version)
}
ret['changes'][name] = 'Version {0} will be installed'.format(version)
ret['comment'] = 'Install version {0}'.format(version)
else:
ret['pchanges'] = {name: 'Latest version will be installed'}
ret['changes'][name] = 'Latest version will be installed'
ret['comment'] = 'Install latest version'
# Package installed
@ -378,8 +375,7 @@ def upgraded(name,
oper="==",
ver2=version):
if force:
ret['pchanges'] = {
name: 'Version {0} will be reinstalled'.format(version)}
ret['changes'][name] = 'Version {0} will be reinstalled'.format(version)
ret['comment'] = 'Reinstall {0} {1}'.format(full_name, version)
else:
ret['comment'] = '{0} {1} is already installed'.format(
@ -389,11 +385,9 @@ def upgraded(name,
# If installed version is older than new version
if salt.utils.versions.compare(
ver1=installed_version, oper="<", ver2=version):
ret['pchanges'] = {
name: 'Version {0} will be upgraded to Version {1}'.format(
installed_version, version
)
}
ret['changes'][name] = 'Version {0} will be upgraded to Version {1}'.format(
installed_version, version
)
ret['comment'] = 'Upgrade {0} {1} to {2}'.format(
full_name, installed_version, version
)
@ -409,13 +403,13 @@ def upgraded(name,
else:
ret['comment'] = 'No version found to install'
# Return if `test=True`
if __opts__['test']:
ret['result'] = None
# Return if there are no changes to be made
if not ret['changes']:
return ret
# Return if there are no changes to be made
if not ret['pchanges']:
# Return if running in test mode
if __opts__['test']:
ret['result'] = None
return ret
# Install the package
@ -439,6 +433,9 @@ def upgraded(name,
# Get list of installed packages after 'chocolatey.install'
post_install = __salt__['chocolatey.list'](local_only=True)
# Prior to this, ret['changes'] would have contained expected changes,
# replace them with the actual changes now that we have completed the
# installation.
ret['changes'] = salt.utils.data.compare_dicts(pre_install, post_install)
return ret

View File

@ -401,13 +401,11 @@ def dvs_configured(name, dvs):
''.format(dvs_name, datacenter_name)),
'result': True})
else:
ret.update({'comment': '\n'.join(comments)})
if __opts__['test']:
ret.update({'pchanges': changes,
'result': None})
else:
ret.update({'changes': changes,
'result': True})
ret.update({
'comment': '\n'.join(comments),
'changes': changes,
'result': None if __opts__['test'] else True,
})
return ret
@ -512,8 +510,10 @@ def portgroups_configured(name, dvs, portgroups):
log.info('Running state {0} on DVS \'{1}\', datacenter '
'\'{2}\''.format(name, dvs, datacenter))
changes_required = False
ret = {'name': name, 'changes': {}, 'result': None, 'comment': None,
'pchanges': {}}
ret = {'name': name,
'changes': {},
'result': None,
'comment': None}
comments = []
changes = {}
changes_required = False
@ -623,13 +623,11 @@ def portgroups_configured(name, dvs, portgroups):
'Nothing to be done.'.format(dvs, datacenter)),
'result': True})
else:
ret.update({'comment': '\n'.join(comments)})
if __opts__['test']:
ret.update({'pchanges': changes,
'result': None})
else:
ret.update({'changes': changes,
'result': True})
ret.update({
'comment': '\n'.join(comments),
'changes': changes,
'result': None if __opts__['test'] else True,
})
return ret
@ -649,8 +647,10 @@ def uplink_portgroup_configured(name, dvs, uplink_portgroup):
log.info('Running {0} on DVS \'{1}\', datacenter \'{2}\''
''.format(name, dvs, datacenter))
changes_required = False
ret = {'name': name, 'changes': {}, 'result': None, 'comment': None,
'pchanges': {}}
ret = {'name': name,
'changes': {},
'result': None,
'comment': None}
comments = []
changes = {}
changes_required = False
@ -708,11 +708,9 @@ def uplink_portgroup_configured(name, dvs, uplink_portgroup):
'Nothing to be done.'.format(dvs, datacenter)),
'result': True})
else:
ret.update({'comment': '\n'.join(comments)})
if __opts__['test']:
ret.update({'pchanges': changes,
'result': None})
else:
ret.update({'changes': changes,
'result': True})
ret.update({
'comment': '\n'.join(comments),
'changes': changes,
'result': None if __opts__['test'] else True,
})
return ret

View File

@ -89,11 +89,11 @@ def datacenter_configured(name):
dc_name = name
log.info('Running datacenter_configured for datacenter \'{0}\''
''.format(dc_name))
ret = {'name': name, 'changes': {}, 'pchanges': {},
'result': None, 'comment': 'Default'}
ret = {'name': name,
'changes': {},
'result': None,
'comment': 'Default'}
comments = []
changes = {}
pchanges = {}
si = None
try:
si = __salt__['vsphere.get_service_instance_via_proxy']()
@ -103,27 +103,19 @@ def datacenter_configured(name):
if __opts__['test']:
comments.append('State will create '
'datacenter \'{0}\'.'.format(dc_name))
log.info(comments[-1])
pchanges.update({'new': {'name': dc_name}})
else:
log.debug('Creating datacenter \'{0}\'. '.format(dc_name))
__salt__['vsphere.create_datacenter'](dc_name, si)
comments.append('Created datacenter \'{0}\'.'.format(dc_name))
log.info(comments[-1])
changes.update({'new': {'name': dc_name}})
log.info(comments[-1])
ret['changes'].update({'new': {'name': dc_name}})
else:
comments.append('Datacenter \'{0}\' already exists. Nothing to be '
'done.'.format(dc_name))
log.info(comments[-1])
__salt__['vsphere.disconnect'](si)
if __opts__['test'] and pchanges:
ret_status = None
else:
ret_status = True
ret.update({'result': ret_status,
'comment': '\n'.join(comments),
'changes': changes,
'pchanges': pchanges})
ret['comment'] = '\n'.join(comments)
ret['result'] = None if __opts__['test'] and ret['changes'] else True
return ret
except salt.exceptions.CommandExecutionError as exc:
log.error('Error: {}'.format(exc))

View File

@ -1070,8 +1070,10 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
else proxy_details['esxi_host']
log.info('Running state {0} for host \'{1}\''.format(name, hostname))
# Variable used to return the result of the invocation
ret = {'name': name, 'result': None, 'changes': {},
'pchanges': {}, 'comments': None}
ret = {'name': name,
'result': None,
'changes': {},
'comments': None}
# Signals if errors have been encountered
errors = False
# Signals if changes are required
@ -1294,12 +1296,8 @@ def diskgroups_configured(name, diskgroups, erase_disks=False):
None if __opts__['test'] else # running in test mode
False if errors else True) # found errors; defaults to True
ret.update({'result': result,
'comment': '\n'.join(comments)})
if changes:
if __opts__['test']:
ret['pchanges'] = diskgroup_changes
elif changes:
ret['changes'] = diskgroup_changes
'comment': '\n'.join(comments),
'changes': diskgroup_changes})
return ret
@ -1387,8 +1385,10 @@ def host_cache_configured(name, enabled, datastore, swap_size='100%',
else proxy_details['esxi_host']
log.trace('hostname = %s', hostname)
log.info('Running host_cache_swap_configured for host \'%s\'', hostname)
ret = {'name': hostname, 'comment': 'Default comments',
'result': None, 'changes': {}, 'pchanges': {}}
ret = {'name': hostname,
'comment': 'Default comments',
'result': None,
'changes': {}}
result = None if __opts__['test'] else True # We assume success
needs_setting = False
comments = []
@ -1582,11 +1582,8 @@ def host_cache_configured(name, enabled, datastore, swap_size='100%',
__salt__['vsphere.disconnect'](si)
log.info(comments[-1])
ret.update({'comment': '\n'.join(comments),
'result': result})
if __opts__['test']:
ret['pchanges'] = changes
else:
ret['changes'] = changes
'result': result,
'changes': changes})
return ret
except CommandExecutionError as err:
log.error('Error: %s.', err)

View File

@ -975,16 +975,25 @@ def _check_touch(name, atime, mtime):
'''
Check to see if a file needs to be updated or created
'''
ret = {
'result': None,
'comment': '',
'changes': {'new': name},
}
if not os.path.exists(name):
return None, 'File {0} is set to be created'.format(name)
stats = __salt__['file.stats'](name, follow_symlinks=False)
if atime is not None:
if six.text_type(atime) != six.text_type(stats['atime']):
return None, 'Times set to be updated on file {0}'.format(name)
if mtime is not None:
if six.text_type(mtime) != six.text_type(stats['mtime']):
return None, 'Times set to be updated on file {0}'.format(name)
return True, 'File {0} exists and has the correct times'.format(name)
ret['comment'] = 'File {0} is set to be created'.format(name)
else:
stats = __salt__['file.stats'](name, follow_symlinks=False)
if ((atime is not None
and six.text_type(atime) != six.text_type(stats['atime'])) or
(mtime is not None
and six.text_type(mtime) != six.text_type(stats['mtime']))):
ret['comment'] = 'Times set to be updated on file {0}'.format(name)
ret['changes'] = {'touched': name}
else:
ret['result'] = True
ret['comment'] = 'File {0} exists and has the correct times'.format(name)
return ret
def _get_symlink_ownership(path):
@ -1031,36 +1040,36 @@ def _symlink_check(name, target, force, user, group, win_owner):
'''
Check the symlink function
'''
pchanges = {}
changes = {}
if not os.path.exists(name) and not __salt__['file.is_link'](name):
pchanges['new'] = name
changes['new'] = name
return None, 'Symlink {0} to {1} is set for creation'.format(
name, target
), pchanges
), changes
if __salt__['file.is_link'](name):
if __salt__['file.readlink'](name) != target:
pchanges['change'] = name
changes['change'] = name
return None, 'Link {0} target is set to be changed to {1}'.format(
name, target
), pchanges
), changes
else:
result = True
msg = 'The symlink {0} is present'.format(name)
if not _check_symlink_ownership(name, user, group, win_owner):
result = None
pchanges['ownership'] = '{0}:{1}'.format(*_get_symlink_ownership(name))
changes['ownership'] = '{0}:{1}'.format(*_get_symlink_ownership(name))
msg += (
', but the ownership of the symlink would be changed '
'from {2}:{3} to {0}:{1}'
).format(user, group, *_get_symlink_ownership(name))
return result, msg, pchanges
return result, msg, changes
else:
if force:
return None, ('The file or directory {0} is set for removal to '
'make way for a new symlink targeting {1}'
.format(name, target)), pchanges
.format(name, target)), changes
return False, ('File or directory exists where the symlink {0} '
'should be. Did you mean to use force?'.format(name)), pchanges
'should be. Did you mean to use force?'.format(name)), changes
def _test_owner(kwargs, user=None):
@ -1222,12 +1231,12 @@ def _shortcut_check(name,
'''
Check the shortcut function
'''
pchanges = {}
changes = {}
if not os.path.exists(name):
pchanges['new'] = name
changes['new'] = name
return None, 'Shortcut "{0}" to "{1}" is set for creation'.format(
name, target
), pchanges
), changes
if os.path.isfile(name):
with salt.utils.winapi.Com():
@ -1248,28 +1257,28 @@ def _shortcut_check(name,
)
if not all(state_checks):
pchanges['change'] = name
changes['change'] = name
return None, 'Shortcut "{0}" target is set to be changed to "{1}"'.format(
name, target
), pchanges
), changes
else:
result = True
msg = 'The shortcut "{0}" is present'.format(name)
if not _check_shortcut_ownership(name, user):
result = None
pchanges['ownership'] = '{0}'.format(_get_shortcut_ownership(name))
changes['ownership'] = '{0}'.format(_get_shortcut_ownership(name))
msg += (
', but the ownership of the shortcut would be changed '
'from {1} to {0}'
).format(user, _get_shortcut_ownership(name))
return result, msg, pchanges
return result, msg, changes
else:
if force:
return None, ('The link or directory "{0}" is set for removal to '
'make way for a new shortcut targeting "{1}"'
.format(name, target)), pchanges
.format(name, target)), changes
return False, ('Link or directory exists where the shortcut "{0}" '
'should be. Did you mean to use force?'.format(name)), pchanges
'should be. Did you mean to use force?'.format(name)), changes
def _makedirs(name,
@ -1499,12 +1508,12 @@ def symlink(
msg += '.'
return _error(ret, msg)
presult, pcomment, ret['pchanges'] = _symlink_check(name,
target,
force,
user,
group,
win_owner)
presult, pcomment, pchanges = _symlink_check(name,
target,
force,
user,
group,
win_owner)
if not os.path.isdir(os.path.dirname(name)):
if makedirs:
@ -1537,6 +1546,7 @@ def symlink(
if __opts__['test']:
ret['result'] = presult
ret['comment'] = pcomment
ret['changes'] = pchanges
return ret
if __salt__['file.is_link'](name):
@ -1659,7 +1669,6 @@ def absent(name,
ret = {'name': name,
'changes': {},
'pchanges': {},
'result': True,
'comment': ''}
if not name:
@ -1671,9 +1680,9 @@ def absent(name,
if name == '/':
return _error(ret, 'Refusing to make "/" absent')
if os.path.isfile(name) or os.path.islink(name):
ret['pchanges']['removed'] = name
if __opts__['test']:
ret['result'] = None
ret['changes']['removed'] = name
ret['comment'] = 'File {0} is set for removal'.format(name)
return ret
try:
@ -1688,9 +1697,9 @@ def absent(name,
return _error(ret, '{0}'.format(exc))
elif os.path.isdir(name):
ret['pchanges']['removed'] = name
if __opts__['test']:
ret['result'] = None
ret['changes']['removed'] = name
ret['comment'] = 'Directory {0} is set for removal'.format(name)
return ret
try:
@ -1849,7 +1858,6 @@ def exists(name,
ret = {'name': name,
'changes': {},
'pchanges': {},
'result': True,
'comment': ''}
if not name:
@ -1874,7 +1882,6 @@ def missing(name,
ret = {'name': name,
'changes': {},
'pchanges': {},
'result': True,
'comment': ''}
if not name:
@ -2483,7 +2490,6 @@ def managed(name,
name = os.path.expanduser(name)
ret = {'changes': {},
'pchanges': {},
'comment': '',
'name': name,
'result': True}
@ -3226,7 +3232,6 @@ def directory(name,
name = os.path.expanduser(name)
ret = {'name': name,
'changes': {},
'pchanges': {},
'result': True,
'comment': ''}
if not name:
@ -3300,19 +3305,19 @@ def directory(name,
# Remove whatever is in the way
if os.path.isfile(name):
if __opts__['test']:
ret['pchanges']['forced'] = 'File was forcibly replaced'
ret['changes']['forced'] = 'File would be forcibly replaced'
else:
os.remove(name)
ret['changes']['forced'] = 'File was forcibly replaced'
elif __salt__['file.is_link'](name):
if __opts__['test']:
ret['pchanges']['forced'] = 'Symlink was forcibly replaced'
ret['changes']['forced'] = 'Symlink would be forcibly replaced'
else:
__salt__['file.remove'](name)
ret['changes']['forced'] = 'Symlink was forcibly replaced'
else:
if __opts__['test']:
ret['pchanges']['forced'] = 'Directory was forcibly replaced'
ret['changes']['forced'] = 'Directory would be forcibly replaced'
else:
__salt__['file.remove'](name)
ret['changes']['forced'] = 'Directory was forcibly replaced'
@ -3341,11 +3346,11 @@ def directory(name,
require, exclude_pat, max_depth, follow_symlinks)
if pchanges:
ret['pchanges'].update(pchanges)
ret['changes'].update(pchanges)
# Don't run through the reset of the function if there are no changes to be
# made
if not ret['pchanges'] or __opts__['test']:
if __opts__['test'] or not ret['changes']:
ret['result'] = presult
ret['comment'] = pcomment
return ret
@ -3764,7 +3769,6 @@ def recurse(name,
ret = {
'name': name,
'changes': {},
'pchanges': {},
'result': True,
'comment': {} # { path: [comment, ...] }
}
@ -4063,7 +4067,6 @@ def retention_schedule(name, retain, strptime_format=None, timezone=None):
name = os.path.expanduser(name)
ret = {'name': name,
'changes': {'retained': [], 'deleted': [], 'ignored': []},
'pchanges': {'retained': [], 'deleted': [], 'ignored': []},
'result': True,
'comment': ''}
if not name:
@ -4173,7 +4176,7 @@ def retention_schedule(name, retain, strptime_format=None, timezone=None):
'deleted': deletable_files,
'ignored': sorted(list(ignored_files), reverse=True),
}
ret['pchanges'] = changes
ret['changes'] = changes
# TODO: track and report how much space was / would be reclaimed
if __opts__['test']:
@ -4314,7 +4317,6 @@ def line(name, content=None, match=None, mode=None, location=None,
name = os.path.expanduser(name)
ret = {'name': name,
'changes': {},
'pchanges': {},
'result': True,
'comment': ''}
if not name:
@ -4348,14 +4350,13 @@ def line(name, content=None, match=None, mode=None, location=None,
before=before, after=after, show_changes=show_changes,
backup=backup, quiet=quiet, indent=indent)
if changes:
ret['pchanges']['diff'] = changes
ret['changes']['diff'] = changes
if __opts__['test']:
ret['result'] = None
ret['comment'] = 'Changes would be made:\ndiff:\n{0}'.format(changes)
ret['comment'] = 'Changes would be made'
else:
ret['result'] = True
ret['comment'] = 'Changes were made'
ret['changes'] = {'diff': changes}
else:
ret['result'] = True
ret['comment'] = 'No changes needed to be made'
@ -4505,7 +4506,6 @@ def replace(name,
ret = {'name': name,
'changes': {},
'pchanges': {},
'result': True,
'comment': ''}
if not name:
@ -4535,14 +4535,13 @@ def replace(name,
backslash_literal=backslash_literal)
if changes:
ret['pchanges']['diff'] = changes
ret['changes']['diff'] = changes
if __opts__['test']:
ret['result'] = None
ret['comment'] = 'Changes would have been made:\ndiff:\n{0}'.format(changes)
ret['comment'] = 'Changes would have been made'
else:
ret['result'] = True
ret['comment'] = 'Changes were made'
ret['changes'] = {'diff': changes}
else:
ret['result'] = True
ret['comment'] = 'No changes needed to be made'
@ -4764,7 +4763,6 @@ def blockreplace(
ret = {'name': name,
'changes': {},
'pchanges': {},
'result': False,
'comment': ''}
if not name:
@ -4837,13 +4835,11 @@ def blockreplace(
return ret
if changes:
ret['pchanges'] = {'diff': changes}
ret['changes']['diff'] = changes
if __opts__['test']:
ret['changes']['diff'] = ret['pchanges']['diff']
ret['result'] = None
ret['comment'] = 'Changes would be made'
else:
ret['changes']['diff'] = ret['pchanges']['diff']
ret['result'] = True
ret['comment'] = 'Changes were made'
else:
@ -4894,7 +4890,6 @@ def comment(name, regex, char='#', backup='.bak'):
ret = {'name': name,
'changes': {},
'pchanges': {},
'result': False,
'comment': ''}
if not name:
@ -4924,8 +4919,8 @@ def comment(name, regex, char='#', backup='.bak'):
else:
return _error(ret, '{0}: Pattern not found'.format(unanchor_regex))
ret['pchanges'][name] = 'updated'
if __opts__['test']:
ret['changes'][name] = 'updated'
ret['comment'] = 'File {0} is set to be updated'.format(name)
ret['result'] = None
return ret
@ -5004,7 +4999,6 @@ def uncomment(name, regex, char='#', backup='.bak'):
ret = {'name': name,
'changes': {},
'pchanges': {},
'result': False,
'comment': ''}
if not name:
@ -5031,26 +5025,20 @@ def uncomment(name, regex, char='#', backup='.bak'):
else:
return _error(ret, '{0}: Pattern not found'.format(regex))
ret['pchanges'][name] = 'updated'
if __opts__['test']:
ret['changes'][name] = 'updated'
ret['comment'] = 'File {0} is set to be updated'.format(name)
ret['result'] = None
return ret
with salt.utils.files.fopen(name, 'rb') as fp_:
slines = fp_.read()
if six.PY3:
slines = slines.decode(__salt_system_encoding__)
slines = slines.splitlines(True)
slines = salt.utils.data.decode(fp_.readlines())
# Perform the edit
__salt__['file.comment_line'](name, regex, char, False, backup)
with salt.utils.files.fopen(name, 'rb') as fp_:
nlines = fp_.read()
if six.PY3:
nlines = nlines.decode(__salt_system_encoding__)
nlines = nlines.splitlines(True)
nlines = salt.utils.data.decode(fp_.readlines())
# Check the result
ret['result'] = __salt__['file.search'](
@ -5214,10 +5202,9 @@ def append(name,
.. versionadded:: 0.9.5
'''
ret = {'name': name,
'changes': {},
'pchanges': {},
'result': False,
'comment': ''}
'changes': {},
'result': False,
'comment': ''}
if not name:
return _error(ret, 'Must provide name to file.append')
@ -5252,12 +5239,12 @@ def append(name,
except CommandExecutionError as exc:
return _error(ret, 'Drive {0} is not mapped'.format(exc.message))
if salt.utils.platform.is_windows():
check_res, check_msg, ret['pchanges'] = _check_directory_win(dirname)
else:
check_res, check_msg, ret['pchanges'] = _check_directory(dirname)
check_res, check_msg, check_changes = _check_directory_win(dirname) \
if salt.utils.platform.is_windows() \
else _check_directory(dirname)
if not check_res:
ret['changes'] = check_changes
return _error(ret, check_msg)
check_res, check_msg = _check_file(name)
@ -5506,7 +5493,6 @@ def prepend(name,
ret = {'name': name,
'changes': {},
'pchanges': {},
'result': False,
'comment': ''}
if not name:
@ -5536,11 +5522,12 @@ def prepend(name,
except CommandExecutionError as exc:
return _error(ret, 'Drive {0} is not mapped'.format(exc.message))
if salt.utils.platform.is_windows():
check_res, check_msg, ret['pchanges'] = _check_directory_win(dirname)
else:
check_res, check_msg, ret['pchanges'] = _check_directory(dirname)
check_res, check_msg, check_changes = _check_directory_win(dirname) \
if salt.utils.platform.is_windows() \
else _check_directory(dirname)
if not check_res:
ret['changes'] = check_changes
return _error(ret, check_msg)
check_res, check_msg = _check_file(name)
@ -6129,7 +6116,7 @@ def touch(name, atime=None, mtime=None, makedirs=False):
)
if __opts__['test']:
ret['result'], ret['comment'] = _check_touch(name, atime, mtime)
ret.update(_check_touch(name, atime, mtime))
return ret
if makedirs:
@ -7399,17 +7386,18 @@ def shortcut(
msg += '.'
return _error(ret, msg)
presult, pcomment, ret['pchanges'] = _shortcut_check(name,
target,
arguments,
working_dir,
description,
icon_location,
force,
user)
presult, pcomment, pchanges = _shortcut_check(name,
target,
arguments,
working_dir,
description,
icon_location,
force,
user)
if __opts__['test']:
ret['result'] = presult
ret['comment'] = pcomment
ret['changes'] = pchanges
return ret
if not os.path.isdir(os.path.dirname(name)):

View File

@ -52,15 +52,16 @@ def present(name, auth=None, **kwargs):
'result': True,
'comment': ''}
kwargs = __utils__['args.clean_kwargs'](**kwargs)
__salt__['glanceng.setup_clouds'](auth)
image = __salt__['glanceng.image_get'](name=name)
if not image:
if __opts__['test'] is True:
if __opts__['test']:
ret['result'] = None
ret['changes'] = kwargs
ret['pchanges'] = ret['changes']
ret['comment'] = 'Image {} will be created.'.format(name)
return ret
@ -91,10 +92,9 @@ def absent(name, auth=None):
image = __salt__['glanceng.image_get'](name=name)
if image:
if __opts__['test'] is True:
if __opts__['test']:
ret['result'] = None
ret['changes'] = {'name': name}
ret['pchanges'] = ret['changes']
ret['comment'] = 'Image {} will be deleted.'.format(name)
return ret

View File

@ -144,8 +144,7 @@ def latest_active(name, at_time=None, **kwargs): # pylint: disable=unused-argum
if __opts__['test']:
ret['result'] = None
ret['changes'] = {}
ret['pchanges'] = {'kernel': {
ret['changes'] = {'kernel': {
'old': active,
'new': latest
}}

View File

@ -56,15 +56,16 @@ def present(name, auth=None, **kwargs):
'result': True,
'comment': ''}
kwargs = __utils__['args.clean_kwargs'](**kwargs)
__salt__['keystoneng.setup_clouds'](auth)
domain = __salt__['keystoneng.domain_get'](name=name)
if not domain:
if __opts__['test'] is True:
if __opts__['test']:
ret['result'] = None
ret['changes'] = kwargs
ret['pchanges'] = ret['changes']
ret['comment'] = 'Domain {} will be created.'.format(name)
return ret
@ -76,10 +77,9 @@ def present(name, auth=None, **kwargs):
changes = __salt__['keystoneng.compare_changes'](domain, **kwargs)
if changes:
if __opts__['test'] is True:
if __opts__['test']:
ret['result'] = None
ret['changes'] = changes
ret['pchanges'] = ret['changes']
ret['comment'] = 'Domain {} will be updated.'.format(name)
return ret
@ -111,7 +111,6 @@ def absent(name, auth=None):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = {'name': name}
ret['pchanges'] = ret['changes']
ret['comment'] = 'Domain {} will be deleted.'.format(name)
return ret

View File

@ -101,6 +101,8 @@ def present(name, service_name, auth=None, **kwargs):
'result': True,
'comment': ''}
kwargs = __utils__['args.clean_kwargs'](**kwargs)
__salt__['keystoneng.setup_clouds'](auth)
success, val = _, endpoint = _common(ret, name, service_name, kwargs)
@ -111,7 +113,6 @@ def present(name, service_name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = kwargs
ret['pchanges'] = ret['changes']
ret['comment'] = 'Endpoint will be created.'
return ret
@ -131,7 +132,6 @@ def present(name, service_name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = changes
ret['pchanges'] = ret['changes']
ret['comment'] = 'Endpoint will be updated.'
return ret
@ -174,7 +174,6 @@ def absent(name, service_name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = {'id': endpoint.id}
ret['pchanges'] = ret['changes']
ret['comment'] = 'Endpoint will be deleted.'
return ret

View File

@ -73,6 +73,8 @@ def present(name, auth=None, **kwargs):
__salt__['keystoneng.setup_cloud'](auth)
kwargs = __utils__['args.clean_kwargs'](**kwargs)
kwargs['name'] = name
group = _common(kwargs)
@ -80,7 +82,6 @@ def present(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = kwargs
ret['pchanges'] = ret['changes']
ret['comment'] = 'Group will be created.'
return ret
@ -94,7 +95,6 @@ def present(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = changes
ret['pchanges'] = ret['changes']
ret['comment'] = 'Group will be updated.'
return ret
@ -120,6 +120,8 @@ def absent(name, auth=None, **kwargs):
'result': True,
'comment': ''}
kwargs = __utils__['args.clean_kwargs'](**kwargs)
__salt__['keystoneng.setup_cloud'](auth)
kwargs['name'] = name
@ -129,7 +131,6 @@ def absent(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = {'id': group.id}
ret['pchanges'] = ret['changes']
ret['comment'] = 'Group will be deleted.'
return ret

View File

@ -72,6 +72,8 @@ def present(name, auth=None, **kwargs):
'result': True,
'comment': ''}
kwargs = __utils__['args.clean_kwargs'](**kwargs)
__salt__['keystoneng.setup_clouds'](auth)
kwargs['name'] = name
@ -81,7 +83,6 @@ def present(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = kwargs
ret['pchanges'] = ret['changes']
ret['comment'] = 'Project will be created.'
return ret
@ -95,7 +96,6 @@ def present(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = changes
ret['pchanges'] = ret['changes']
ret['comment'] = 'Project will be updated.'
return ret
@ -121,6 +121,8 @@ def absent(name, auth=None, **kwargs):
'result': True,
'comment': ''}
kwargs = __utils__['args.clean_kwargs'](**kwargs)
__salt__['keystoneng.setup_clouds'](auth)
kwargs['name'] = name
@ -130,7 +132,6 @@ def absent(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = {'id': project.id}
ret['pchanges'] = ret['changes']
ret['comment'] = 'Project will be deleted.'
return ret

View File

@ -52,6 +52,8 @@ def present(name, auth=None, **kwargs):
'result': True,
'comment': ''}
kwargs = __utils__['args.clean_kwargs'](**kwargs)
__salt__['keystoneng.setup_clouds'](auth)
kwargs['name'] = name
@ -61,7 +63,6 @@ def present(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = kwargs
ret['pchanges'] = ret['changes']
ret['comment'] = 'Role will be created.'
return ret
@ -95,7 +96,6 @@ def absent(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = {'id': role.id}
ret['pchanges'] = ret['changes']
ret['comment'] = 'Role will be deleted.'
return ret

View File

@ -61,6 +61,8 @@ def present(name, auth=None, **kwargs):
'result': True,
'comment': ''}
kwargs = __utils__['args.clean_kwargs'](**kwargs)
__salt__['keystoneng.setup_clouds'](auth)
service = __salt__['keystoneng.service_get'](name=name)
@ -69,7 +71,6 @@ def present(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = kwargs
ret['pchanges'] = ret['changes']
ret['comment'] = 'Service will be created.'
return ret
@ -84,7 +85,6 @@ def present(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = changes
ret['pchanges'] = ret['changes']
ret['comment'] = 'Service will be updated.'
return ret
@ -117,7 +117,6 @@ def absent(name, auth=None):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = {'id': service.id}
ret['pchanges'] = ret['changes']
ret['comment'] = 'Service will be deleted.'
return ret

View File

@ -83,6 +83,8 @@ def present(name, auth=None, **kwargs):
'result': True,
'comment': ''}
kwargs = __utils__['args.clean_kwargs'](**kwargs)
__salt__['keystoneng.setup_clouds'](auth)
kwargs['name'] = name
@ -92,7 +94,6 @@ def present(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = kwargs
ret['pchanges'] = ret['changes']
ret['comment'] = 'User will be created.'
return ret
@ -106,7 +107,6 @@ def present(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = changes
ret['pchanges'] = ret['changes']
ret['comment'] = 'User will be updated.'
return ret
@ -133,6 +133,8 @@ def absent(name, auth=None, **kwargs):
'result': True,
'comment': ''}
kwargs = __utils__['args.clean_kwargs'](**kwargs)
__salt__['keystoneng.setup_clouds'](auth)
kwargs['name'] = name
@ -142,7 +144,6 @@ def absent(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = {'id': user.id}
ret['pchanges'] = ret['changes']
ret['comment'] = 'User will be deleted.'
return ret

View File

@ -103,7 +103,6 @@ def present(name, acl_type, acl_name='', perms='', recurse=False, force=False):
ret = {'name': name,
'result': True,
'changes': {},
'pchanges': {},
'comment': ''}
_octal = {'r': 4, 'w': 2, 'x': 1, '-': 0}
@ -176,7 +175,7 @@ def present(name, acl_type, acl_name='', perms='', recurse=False, force=False):
acl_name,
new_perms,
perms),
'result': None, 'pchanges': changes})
'result': None, 'changes': changes})
return ret
try:
if force:
@ -199,7 +198,7 @@ def present(name, acl_type, acl_name='', perms='', recurse=False, force=False):
if __opts__['test']:
ret.update({'comment': 'New permissions will be applied for '
'{0}: {1}'.format(acl_name, perms),
'result': None, 'pchanges': changes})
'result': None, 'changes': changes})
ret['result'] = None
return ret

View File

@ -94,8 +94,6 @@ def managed(name,
compliance_report: ``False``
Return the compliance report in the comment.
The compliance report structured object can be found however
in the ``pchanges`` field of the output (not displayed on the CLI).
.. versionadded:: 2017.7.3

View File

@ -72,6 +72,8 @@ def present(name, auth=None, **kwargs):
'result': True,
'comment': ''}
kwargs = __utils__['args.clean_kwargs'](**kwargs)
__salt__['neutronng.setup_clouds'](auth)
kwargs['name'] = name
@ -81,7 +83,6 @@ def present(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = kwargs
ret['pchanges'] = ret['changes']
ret['comment'] = 'Network will be created.'
return ret
@ -115,7 +116,6 @@ def present(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = changes
ret['pchanges'] = ret['changes']
ret['comment'] = 'Project will be updated.'
return ret
@ -140,6 +140,8 @@ def absent(name, auth=None, **kwargs):
'result': True,
'comment': ''}
kwargs = __utils__['args.clean_kwargs'](**kwargs)
__salt__['neutronng.setup_clouds'](auth)
kwargs['name'] = name
@ -149,7 +151,6 @@ def absent(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = {'id': network.id}
ret['pchanges'] = ret['changes']
ret['comment'] = 'Network will be deleted.'
return ret

View File

@ -74,6 +74,8 @@ def present(name, auth=None, **kwargs):
'result': True,
'comment': ''}
kwargs = __utils__['args.clean_kwargs'](**kwargs)
__salt__['neutronng.setup_clouds'](auth)
if 'project_name' in kwargs:
@ -95,7 +97,6 @@ def present(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = kwargs
ret['pchanges'] = ret['changes']
ret['comment'] = 'Security Group will be created.'
return ret
@ -109,7 +110,6 @@ def present(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = changes
ret['pchanges'] = ret['changes']
ret['comment'] = 'Security Group will be updated.'
return ret
@ -133,6 +133,8 @@ def absent(name, auth=None, **kwargs):
'result': True,
'comment': ''}
kwargs = __utils__['args.clean_kwargs'](**kwargs)
__salt__['neutronng.setup_clouds'](auth)
kwargs['project_id'] = __salt__['keystoneng.project_get'](
@ -147,7 +149,6 @@ def absent(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = {'id': secgroup.id}
ret['pchanges'] = ret['changes']
ret['comment'] = 'Security group will be deleted.'
return ret

View File

@ -77,6 +77,8 @@ def present(name, auth=None, **kwargs):
'result': True,
'comment': ''}
kwargs = __utils__['args.clean_kwargs'](**kwargs)
__salt__['neutronng.setup_clouds'](auth)
if 'project_name' in kwargs:
@ -112,7 +114,6 @@ def present(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = kwargs
ret['pchanges'] = ret['changes']
ret['comment'] = 'Security Group rule will be created.'
return ret
@ -166,10 +167,9 @@ def absent(name, auth=None, **kwargs):
rule_exists = True
if rule_exists:
if __opts__['test'] is True:
if __opts__['test']:
ret['result'] = None
ret['changes'] = {'id': kwargs['rule_id']}
ret['pchanges'] = ret['changes']
ret['comment'] = 'Security group rule will be deleted.'
return ret

View File

@ -96,16 +96,17 @@ def present(name, auth=None, **kwargs):
'result': True,
'comment': ''}
kwargs = __utils__['args.clean_kwargs'](**kwargs)
__salt__['neutronng.setup_clouds'](auth)
kwargs['subnet_name'] = name
subnet = __salt__['neutronng.subnet_get'](name=name)
if subnet is None:
if __opts__['test'] is True:
if __opts__['test']:
ret['result'] = None
ret['changes'] = kwargs
ret['pchanges'] = ret['changes']
ret['comment'] = 'Subnet will be created.'
return ret
@ -119,7 +120,6 @@ def present(name, auth=None, **kwargs):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = changes
ret['pchanges'] = ret['changes']
ret['comment'] = 'Project will be updated.'
return ret
@ -160,7 +160,6 @@ def absent(name, auth=None):
if __opts__['test'] is True:
ret['result'] = None
ret['changes'] = {'id': subnet.id}
ret['pchanges'] = ret['changes']
ret['comment'] = 'Project will be deleted.'
return ret

View File

@ -156,8 +156,10 @@ def default_vsan_policy_configured(name, policy):
'\'{1}\''.format(name, vcenter))
log.trace('policy = {0}'.format(policy))
changes_required = False
ret = {'name': name, 'changes': {}, 'result': None, 'comment': None,
'pchanges': {}}
ret = {'name': name,
'changes': {},
'result': None,
'comment': None}
comments = []
changes = {}
changes_required = False
@ -266,13 +268,11 @@ def default_vsan_policy_configured(name, policy):
'Nothing to be done.'.format(vcenter)),
'result': True})
else:
ret.update({'comment': '\n'.join(comments)})
if __opts__['test']:
ret.update({'pchanges': changes,
'result': None})
else:
ret.update({'changes': changes,
'result': True})
ret.update({
'comment': '\n'.join(comments),
'changes': changes,
'result': None if __opts__['test'] else True,
})
return ret
@ -286,8 +286,10 @@ def storage_policies_configured(name, policies):
comments = []
changes = []
changes_required = False
ret = {'name': name, 'changes': {}, 'result': None, 'comment': None,
'pchanges': {}}
ret = {'name': name,
'changes': {},
'result': None,
'comment': None}
log.trace('policies = {0}'.format(policies))
si = None
try:
@ -430,13 +432,11 @@ def storage_policies_configured(name, policies):
'Nothing to be done.'.format(vcenter)),
'result': True})
else:
ret.update({'comment': '\n'.join(comments)})
if __opts__['test']:
ret.update({'pchanges': {'storage_policies': changes},
'result': None})
else:
ret.update({'changes': {'storage_policies': changes},
'result': True})
ret.update({
'comment': '\n'.join(comments),
'changes': {'storage_policies': changes},
'result': None if __opts__['test'] else True,
})
return ret
@ -454,8 +454,10 @@ def default_storage_policy_assigned(name, policy, datastore):
''.format(name, policy, datastore))
changes = {}
changes_required = False
ret = {'name': name, 'changes': {}, 'result': None, 'comment': None,
'pchanges': {}}
ret = {'name': name,
'changes': {},
'result': None,
'comment': None}
si = None
try:
si = __salt__['vsphere.get_service_instance_via_proxy']()
@ -488,14 +490,13 @@ def default_storage_policy_assigned(name, policy, datastore):
ret.update({'comment': exc.strerror,
'result': False if not __opts__['test'] else None})
return ret
ret['comment'] = comment
if changes_required:
if __opts__['test']:
ret.update({'result': None,
'pchanges': changes})
else:
ret.update({'result': True,
'changes': changes})
ret.update({
'changes': changes,
'result': None if __opts__['test'] else True,
})
else:
ret['result'] = True
return ret

View File

@ -427,7 +427,8 @@ def function(
kwarg=None,
timeout=None,
batch=None,
subset=None):
subset=None,
**kwargs): # pylint: disable=unused-argument
'''
Execute a single module function on a remote minion via salt or salt-ssh
@ -478,15 +479,15 @@ def function(
'''
func_ret = {'name': name,
'changes': {},
'comment': '',
'result': True}
'changes': {},
'comment': '',
'result': True}
if kwarg is None:
kwarg = {}
if isinstance(arg, six.string_types):
func_ret['warnings'] = ['Please specify \'arg\' as a list, not a string. '
'Modifying in place, but please update SLS file '
'to remove this warning.']
func_ret['warnings'] = [
'Please specify \'arg\' as a list of arguments.'
]
arg = arg.split()
cmd_kw = {'arg': arg or [], 'kwarg': kwarg, 'ret': ret, 'timeout': timeout}
@ -509,9 +510,8 @@ def function(
fun = name
if __opts__['test'] is True:
func_ret['comment'] = (
'Function {0} will be executed on target {1} as test={2}'
).format(fun, tgt, six.text_type(False))
func_ret['comment'] = \
'Function {0} would be executed on target {1}'.format(fun, tgt)
func_ret['result'] = None
return func_ret
try:
@ -751,7 +751,7 @@ def runner(name, **kwargs):
return ret
def parallel_runners(name, runners):
def parallel_runners(name, runners, **kwargs): # pylint: disable=unused-argument
'''
Executes multiple runner modules on the master in parallel.

View File

@ -199,8 +199,7 @@ def baseline_snapshot(name, number=None, tag=None, include_diff=True, config='ro
filename=file).get(file, {}))
if __opts__['test'] and status:
ret['pchanges'] = status
ret['changes'] = ret['pchanges']
ret['changes'] = status
ret['comment'] = "{0} files changes are set to be undone".format(len(status.keys()))
ret['result'] = None
elif __opts__['test'] and not status:

View File

@ -34,10 +34,9 @@ def alias(name, collections, **kwargs):
'changes': {},
'result': False,
'comment': '',
'pchanges': {},
}
if __salt__["solrcloud.alias_exists"](name, **kwargs):
if __salt__['solrcloud.alias_exists'](name, **kwargs):
alias_content = __salt__['solrcloud.alias_get_collections'](name, **kwargs)
diff = set(alias_content).difference(set(collections))
@ -48,38 +47,31 @@ def alias(name, collections, **kwargs):
if __opts__['test']:
ret['comment'] = 'The alias "{0}" will be updated.'.format(name)
ret['pchanges'] = {
'old': ",".join(alias_content),
'new': ",".join(collections)
}
ret['result'] = None
else:
__salt__["solrcloud.alias_set_collections"](name, collections, **kwargs)
__salt__['solrcloud.alias_set_collections'](name, collections, **kwargs)
ret['comment'] = 'The alias "{0}" has been updated.'.format(name)
ret['changes'] = {
'old': ",".join(alias_content),
'new': ",".join(collections)
}
ret['result'] = True
ret['changes'] = {
'old': ','.join(alias_content),
'new': ','.join(collections),
}
else:
if __opts__['test']:
ret['comment'] = 'The alias "{0}" will be created.'.format(name)
ret['pchanges'] = {
'old': None,
'new': ",".join(collections)
}
ret['result'] = None
else:
__salt__["solrcloud.alias_set_collections"](name, collections, **kwargs)
__salt__['solrcloud.alias_set_collections'](name, collections, **kwargs)
ret['comment'] = 'The alias "{0}" has been created.'.format(name)
ret['changes'] = {
'old': None,
'new': ",".join(collections)
}
ret['result'] = True
ret['changes'] = {
'old': None,
'new': ','.join(collections),
}
return ret
@ -101,7 +93,6 @@ def collection(name, options=None, **kwargs):
'changes': {},
'result': False,
'comment': '',
'pchanges': {},
}
if options is None:
@ -137,42 +128,32 @@ def collection(name, options=None, **kwargs):
if __opts__['test']:
ret['comment'] = 'Collection options "{0}" will be changed.'.format(name)
ret['pchanges'] = {
'old': salt.utils.json.dumps(current_options, sort_keys=True, indent=4, separators=(',', ': ')),
'new': salt.utils.json.dumps(options, sort_keys=True, indent=4, separators=(',', ': '))
}
ret['result'] = None
return ret
else:
__salt__["solrcloud.collection_set_options"](name, diff, **kwargs)
__salt__['solrcloud.collection_set_options'](name, diff, **kwargs)
ret['comment'] = 'Parameters were updated for collection "{0}".'.format(name)
ret['result'] = True
ret['changes'] = {
'old': salt.utils.json.dumps(current_options, sort_keys=True, indent=4, separators=(',', ': ')),
'new': salt.utils.json.dumps(options, sort_keys=True, indent=4, separators=(',', ': '))
}
return ret
ret['changes'] = {
'old': salt.utils.json.dumps(current_options, sort_keys=True, indent=4, separators=(',', ': ')),
'new': salt.utils.json.dumps(options, sort_keys=True, indent=4, separators=(',', ': '))
}
return ret
else:
new_changes = salt.utils.json.dumps(options, sort_keys=True, indent=4, separators=(',', ': '))
if __opts__['test']:
ret['comment'] = 'The collection "{0}" will be created.'.format(name)
ret['pchanges'] = {
'old': None,
'new': str('options=') + new_changes # future lint: disable=blacklisted-function
}
ret['result'] = None
else:
__salt__["solrcloud.collection_create"](name, options, **kwargs)
ret['comment'] = 'The collection "{0}" has been created.'.format(name)
ret['changes'] = {
'old': None,
'new': str('options=') + new_changes # future lint: disable=blacklisted-function
}
ret['result'] = True
ret['changes'] = {
'old': None,
'new': str('options=') + new_changes # future lint: disable=blacklisted-function
}
return ret

View File

@ -67,7 +67,7 @@ def nop(name, **kwargs):
return succeed_without_changes(name)
def succeed_without_changes(name, **kwargs):
def succeed_without_changes(name, **kwargs): # pylint: disable=unused-argument
'''
Returns successful.
@ -85,7 +85,7 @@ def succeed_without_changes(name, **kwargs):
return ret
def fail_without_changes(name, **kwargs):
def fail_without_changes(name, **kwargs): # pylint: disable=unused-argument
'''
Returns failure.
@ -108,7 +108,7 @@ def fail_without_changes(name, **kwargs):
return ret
def succeed_with_changes(name, **kwargs):
def succeed_with_changes(name, **kwargs): # pylint: disable=unused-argument
'''
Returns successful and changes is not empty
@ -141,7 +141,7 @@ def succeed_with_changes(name, **kwargs):
return ret
def fail_with_changes(name, **kwargs):
def fail_with_changes(name, **kwargs): # pylint: disable=unused-argument
'''
Returns failure and changes is not empty.

View File

@ -492,7 +492,6 @@ def default_ret(name):
'''
ret = {
'name': name,
'pchanges': {},
'changes': {},
'result': False,
'comment': ''
@ -510,22 +509,16 @@ def loaded_ret(ret, loaded, test, debug, compliance_report=False, opts=None):
'''
# Always get the comment
changes = {}
pchanges = {}
ret['comment'] = loaded['comment']
if 'diff' in loaded:
changes['diff'] = loaded['diff']
pchanges['diff'] = loaded['diff']
if 'commit_id' in loaded:
changes['commit_id'] = loaded['commit_id']
pchanges['commit_id'] = loaded['commit_id']
if 'compliance_report' in loaded:
if compliance_report:
changes['compliance_report'] = loaded['compliance_report']
pchanges['compliance_report'] = loaded['compliance_report']
if debug and 'loaded_config' in loaded:
changes['loaded_config'] = loaded['loaded_config']
pchanges['loaded_config'] = loaded['loaded_config']
ret['pchanges'] = pchanges
if changes.get('diff'):
ret['comment'] = '{comment_base}\n\nConfiguration diff:\n\n{diff}'.format(comment_base=ret['comment'],
diff=changes['diff'])

View File

@ -212,10 +212,6 @@ def merge_subreturn(original_return, sub_return, subkey=None):
original_return.setdefault('changes', {})
original_return['changes'][subkey] = sub_return['changes']
if sub_return.get('pchanges'): # pchanges may or may not exist
original_return.setdefault('pchanges', {})
original_return['pchanges'][subkey] = sub_return['pchanges']
return original_return

View File

@ -2125,17 +2125,15 @@ def _check_perms(obj_name, obj_type, new_perms, cur_perms, access_mode, ret):
changes[user]['applies_to'] = applies_to
if changes:
if 'perms' not in ret['pchanges']:
ret['pchanges']['perms'] = {}
if 'perms' not in ret['changes']:
ret['changes']['perms'] = {}
for user in changes:
user_name = get_name(principal=user)
if __opts__['test'] is True:
if user not in ret['pchanges']['perms']:
ret['pchanges']['perms'][user] = {}
ret['pchanges']['perms'][user][access_mode] = changes[user][access_mode]
if user not in ret['changes']['perms']:
ret['changes']['perms'][user] = {}
ret['changes']['perms'][user][access_mode] = changes[user][access_mode]
else:
# Get applies_to
applies_to = None
@ -2291,7 +2289,6 @@ def check_perms(obj_name,
if not ret:
ret = {'name': obj_name,
'changes': {},
'pchanges': {},
'comment': [],
'result': True}
orig_comment = ''
@ -2305,7 +2302,7 @@ def check_perms(obj_name,
current_owner = get_owner(obj_name=obj_name, obj_type=obj_type)
if owner != current_owner:
if __opts__['test'] is True:
ret['pchanges']['owner'] = owner
ret['changes']['owner'] = owner
else:
try:
set_owner(obj_name=obj_name,
@ -2323,7 +2320,7 @@ def check_perms(obj_name,
if not inheritance == get_inheritance(obj_name=obj_name,
obj_type=obj_type):
if __opts__['test'] is True:
ret['pchanges']['inheritance'] = inheritance
ret['changes']['inheritance'] = inheritance
else:
try:
set_inheritance(
@ -2371,9 +2368,9 @@ def check_perms(obj_name,
user_name.lower() not in set(k.lower() for k in grant_perms):
if 'grant' in cur_perms['Not Inherited'][user_name]:
if __opts__['test'] is True:
if 'remove_perms' not in ret['pchanges']:
ret['pchanges']['remove_perms'] = {}
ret['pchanges']['remove_perms'].update(
if 'remove_perms' not in ret['changes']:
ret['changes']['remove_perms'] = {}
ret['changes']['remove_perms'].update(
{user_name: cur_perms['Not Inherited'][user_name]})
else:
if 'remove_perms' not in ret['changes']:
@ -2390,9 +2387,9 @@ def check_perms(obj_name,
user_name.lower() not in set(k.lower() for k in deny_perms):
if 'deny' in cur_perms['Not Inherited'][user_name]:
if __opts__['test'] is True:
if 'remove_perms' not in ret['pchanges']:
ret['pchanges']['remove_perms'] = {}
ret['pchanges']['remove_perms'].update(
if 'remove_perms' not in ret['changes']:
ret['changes']['remove_perms'] = {}
ret['changes']['remove_perms'].update(
{user_name: cur_perms['Not Inherited'][user_name]})
else:
if 'remove_perms' not in ret['changes']:
@ -2416,7 +2413,7 @@ def check_perms(obj_name,
ret['comment'] = '\n'.join(ret['comment'])
# Set result for test = True
if __opts__['test'] and (ret['changes'] or ret['pchanges']):
if __opts__['test'] and (ret['changes']):
ret['result'] = None
return ret

View File

@ -0,0 +1,22 @@
one:
file.managed:
- name: {{ pillar['file1'] }}
- source: {{ pillar['source'] }}
# This should run because there were changes
two:
test.succeed_without_changes:
- {{ pillar['req'] }}:
- file: one
# Run the same state as "one" again, this should not cause changes
three:
file.managed:
- name: {{ pillar['file2'] }}
- source: {{ pillar['source'] }}
# This should not run because there should be no changes
four:
test.succeed_without_changes:
- {{ pillar['req'] }}:
- file: three

View File

@ -0,0 +1,3 @@
{{ salt['runtests_helpers.get_salt_temp_dir_for_path']('orch.req_test') }}:
file.managed:
- contents: 'Hello world!'

View File

@ -643,3 +643,119 @@ class OrchEventTest(ShellCase):
self.assertTrue(received)
del listener
signal.alarm(0)
def test_orchestration_onchanges_and_prereq(self):
'''
Test to confirm that the parallel state requisite works in orch
we do this by running 10 test.sleep's of 10 seconds, and insure it only takes roughly 10s
'''
self.write_conf({
'fileserver_backend': ['roots'],
'file_roots': {
'base': [self.base_env],
},
})
orch_sls = os.path.join(self.base_env, 'orch.sls')
with salt.utils.files.fopen(orch_sls, 'w') as fp_:
fp_.write(textwrap.dedent('''
manage_a_file:
salt.state:
- tgt: minion
- sls:
- orch.req_test
do_onchanges:
salt.function:
- tgt: minion
- name: test.ping
- onchanges:
- salt: manage_a_file
do_prereq:
salt.function:
- tgt: minion
- name: test.ping
- prereq:
- salt: manage_a_file
'''))
listener = salt.utils.event.get_event(
'master',
sock_dir=self.master_opts['sock_dir'],
transport=self.master_opts['transport'],
opts=self.master_opts)
try:
jid1 = self.run_run_plus(
'state.orchestrate',
'orch',
test=True,
__reload_config=True).get('jid')
# Run for real to create the file
self.run_run_plus(
'state.orchestrate',
'orch',
__reload_config=True).get('jid')
# Run again in test mode. Since there were no changes, the
# requisites should not fire.
jid2 = self.run_run_plus(
'state.orchestrate',
'orch',
test=True,
__reload_config=True).get('jid')
finally:
try:
os.remove(os.path.join(TMP, 'orch.req_test'))
except OSError:
pass
assert jid1 is not None
assert jid2 is not None
tags = {'salt/run/{0}/ret'.format(x): x for x in (jid1, jid2)}
ret = {}
signal.signal(signal.SIGALRM, self.alarm_handler)
signal.alarm(self.timeout)
try:
while True:
event = listener.get_event(full=True)
if event is None:
continue
if event['tag'] in tags:
ret[tags.pop(event['tag'])] = self.repack_state_returns(
event['data']['return']['data']['master']
)
if not tags:
# If tags is empty, we've grabbed all the returns we
# wanted, so let's stop listening to the event bus.
break
finally:
del listener
signal.alarm(0)
for sls_id in ('manage_a_file', 'do_onchanges', 'do_prereq'):
# The first time through, all three states should have a None
# result, while the second time through, they should all have a
# True result.
assert ret[jid1][sls_id]['result'] is None, \
'result of {0} ({1}) is not None'.format(
sls_id,
ret[jid1][sls_id]['result'])
assert ret[jid2][sls_id]['result'] is True, \
'result of {0} ({1}) is not True'.format(
sls_id,
ret[jid2][sls_id]['result'])
# The file.managed state should have shown changes in the test mode
# return data.
assert ret[jid1]['manage_a_file']['changes']
# After the file was created, running again in test mode should have
# shown no changes.
assert not ret[jid2]['manage_a_file']['changes'], \
ret[jid2]['manage_a_file']['changes']

View File

@ -751,7 +751,6 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
source_hash=uppercase_hash
)
assert ret[state_name]['result'] is True
assert ret[state_name]['pchanges'] == {}
assert ret[state_name]['changes'] == {}
# Test uppercase source_hash using test=true
@ -764,7 +763,6 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
test=True
)
assert ret[state_name]['result'] is True
assert ret[state_name]['pchanges'] == {}
assert ret[state_name]['changes'] == {}
finally:
@ -818,6 +816,87 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
result = self.run_function('cp.is_cached', [source, saltenv])
assert result == '', 'File is still cached at {0}'.format(result)
@with_tempfile(create=False)
@with_tempfile(create=False)
def test_file_managed_onchanges(self, file1, file2):
'''
Test file.managed state with onchanges
'''
pillar = {'file1': file1,
'file2': file2,
'source': 'salt://testfile',
'req': 'onchanges'}
# Lay down the file used in the below SLS to ensure that when it is
# run, there are no changes.
self.run_state(
'file.managed',
name=pillar['file2'],
source=pillar['source'])
ret = self.repack_state_returns(
self.run_function(
'state.apply',
mods='onchanges_prereq',
pillar=pillar,
test=True,
)
)
# The file states should both exit with None
assert ret['one']['result'] is None, ret['one']['result']
assert ret['three']['result'] is True, ret['three']['result']
# The first file state should have changes, since a new file was
# created. The other one should not, since we already created that file
# before applying the SLS file.
assert ret['one']['changes']
assert not ret['three']['changes'], ret['three']['changes']
# The state watching 'one' should have been run due to changes
assert ret['two']['comment'] == 'Success!', ret['two']['comment']
# The state watching 'three' should not have been run
assert ret['four']['comment'] == \
'State was not run because none of the onchanges reqs changed', \
ret['four']['comment']
@with_tempfile(create=False)
@with_tempfile(create=False)
def test_file_managed_prereq(self, file1, file2):
'''
Test file.managed state with prereq
'''
pillar = {'file1': file1,
'file2': file2,
'source': 'salt://testfile',
'req': 'prereq'}
# Lay down the file used in the below SLS to ensure that when it is
# run, there are no changes.
self.run_state(
'file.managed',
name=pillar['file2'],
source=pillar['source'])
ret = self.repack_state_returns(
self.run_function(
'state.apply',
mods='onchanges_prereq',
pillar=pillar,
test=True,
)
)
# The file states should both exit with None
assert ret['one']['result'] is None, ret['one']['result']
assert ret['three']['result'] is True, ret['three']['result']
# The first file state should have changes, since a new file was
# created. The other one should not, since we already created that file
# before applying the SLS file.
assert ret['one']['changes']
assert not ret['three']['changes'], ret['three']['changes']
# The state watching 'one' should have been run due to changes
assert ret['two']['comment'] == 'Success!', ret['two']['comment']
# The state watching 'three' should not have been run
assert ret['four']['comment'] == 'No changes detected', \
ret['four']['comment']
def test_directory(self):
'''
file.directory

View File

@ -211,7 +211,10 @@ def flaky(caller=None, condition=True, attempts=4):
if attempt >= attempts -1:
raise exc
backoff_time = attempt ** 2
log.info('Found Exception. Waiting %s seconds to retry.', backoff_time)
log.info(
'Found Exception. Waiting %s seconds to retry.',
backoff_time
)
time.sleep(backoff_time)
return cls
return wrap

View File

@ -268,6 +268,19 @@ class TestCase(_TestCase):
)
# return _TestCase.assertNotAlmostEquals(self, *args, **kwargs)
def repack_state_returns(self, state_ret):
'''
Accepts a state return dict and returns it back with the top level key
names rewritten such that the ID declaration is the key instead of the
State's unique tag. For example: 'foo' instead of
'file_|-foo_|-/etc/foo.conf|-managed'
This makes it easier to work with state returns when crafting asserts
after running states.
'''
assert isinstance(state_ret, dict), state_ret
return {x.split('_|-')[1]: y for x, y in six.iteritems(state_ret)}
def failUnlessEqual(self, *args, **kwargs):
raise DeprecationWarning(
'The {0}() function is deprecated. Please start using {1}() '

View File

@ -91,7 +91,7 @@ class BotoCloudfrontTestCase(TestCase, LoaderModuleMockMixin):
self.base_ret_with({
'result': None,
'comment': comment,
'pchanges': {'old': None, 'new': self.name},
'changes': {'old': None, 'new': self.name},
}),
)
@ -191,7 +191,7 @@ class BotoCloudfrontTestCase(TestCase, LoaderModuleMockMixin):
self.base_ret_with({
'result': None,
'comment': '\n'.join([header, diff]),
'pchanges': {'diff': diff},
'changes': {'diff': diff},
}),
)

View File

@ -74,7 +74,7 @@ class BotoSqsTestCase(TestCase, LoaderModuleMockMixin):
ret.update({
'result': None,
'comment': comt,
'pchanges': {'old': None, 'new': 'mysqs'},
'changes': {'old': None, 'new': 'mysqs'},
})
self.assertDictEqual(boto_sqs.present(name), ret)
diff = textwrap.dedent('''\
@ -101,7 +101,7 @@ class BotoSqsTestCase(TestCase, LoaderModuleMockMixin):
]
ret.update({
'comment': comt,
'pchanges': {'attributes': {'diff': diff}},
'changes': {'attributes': {'diff': diff}},
})
self.assertDictEqual(boto_sqs.present(name, attributes), ret)
@ -133,6 +133,6 @@ class BotoSqsTestCase(TestCase, LoaderModuleMockMixin):
ret.update({
'result': None,
'comment': comt,
'pchanges': {'old': name, 'new': None},
'changes': {'old': name, 'new': None},
})
self.assertDictEqual(boto_sqs.absent(name), ret)

View File

@ -64,7 +64,6 @@ class DatacenterConfiguredTestCase(TestCase, LoaderModuleMockMixin):
res = esxdatacenter.datacenter_configured('fake_dc')
self.assertDictEqual(res, {'name': 'fake_dc',
'changes': {},
'pchanges': {},
'result': True,
'comment': 'Datacenter \'fake_dc\' already '
'exists. Nothing to be done.'})
@ -78,7 +77,6 @@ class DatacenterConfiguredTestCase(TestCase, LoaderModuleMockMixin):
res = esxdatacenter.datacenter_configured('fake_dc')
self.assertDictEqual(res, {'name': 'fake_dc',
'changes': {},
'pchanges': {},
'result': True,
'comment': 'Datacenter \'proxy_dc\' '
'already exists. Nothing to be done.'})
@ -112,7 +110,6 @@ class DatacenterConfiguredTestCase(TestCase, LoaderModuleMockMixin):
self.assertDictEqual(res,
{'name': 'fake_dc',
'changes': {'new': {'name': 'fake_dc'}},
'pchanges': {},
'result': True,
'comment': 'Created datacenter \'fake_dc\'.'})
@ -124,8 +121,7 @@ class DatacenterConfiguredTestCase(TestCase, LoaderModuleMockMixin):
res = esxdatacenter.datacenter_configured('fake_dc')
self.assertDictEqual(res,
{'name': 'fake_dc',
'changes': {},
'pchanges': {'new': {'name': 'fake_dc'}},
'changes': {'new': {'name': 'fake_dc'}},
'result': None,
'comment': 'State will create '
'datacenter \'fake_dc\'.'})
@ -138,7 +134,6 @@ class DatacenterConfiguredTestCase(TestCase, LoaderModuleMockMixin):
res = esxdatacenter.datacenter_configured('fake_dc')
self.assertDictEqual(res, {'name': 'fake_dc',
'changes': {},
'pchanges': {},
'result': True,
'comment': 'Datacenter \'fake_dc\' already '
'exists. Nothing to be done.'})
@ -154,7 +149,6 @@ class DatacenterConfiguredTestCase(TestCase, LoaderModuleMockMixin):
self.assertEqual(mock_disconnect.call_count, 0)
self.assertDictEqual(res, {'name': 'fake_dc',
'changes': {},
'pchanges': {},
'result': False,
'comment': 'Error'})
@ -169,7 +163,6 @@ class DatacenterConfiguredTestCase(TestCase, LoaderModuleMockMixin):
mock_disconnect.assert_called_once_with(self.mock_si)
self.assertDictEqual(res, {'name': 'fake_dc',
'changes': {},
'pchanges': {},
'result': False,
'comment': 'Error'})
@ -182,6 +175,5 @@ class DatacenterConfiguredTestCase(TestCase, LoaderModuleMockMixin):
res = esxdatacenter.datacenter_configured('fake_dc')
self.assertDictEqual(res, {'name': 'fake_dc',
'changes': {},
'pchanges': {},
'result': None,
'comment': 'Error'})

View File

@ -226,7 +226,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
comt = 'Symlink {0} to {1} is set for creation'.format(name, target)
ret = return_val({'comment': comt,
'result': None,
'pchanges': {'new': name}})
'changes': {'new': name}})
self.assertDictEqual(filestate.symlink(name, target, user=user,
group=group), ret)
@ -249,7 +249,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
comt = 'Directory {0} for symlink is not present'.format(test_dir)
ret = return_val({'comment': comt,
'result': False,
'pchanges': {'new': name}})
'changes': {}})
self.assertDictEqual(filestate.symlink(name, target,
user=user,
group=group), ret)
@ -271,7 +271,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
comt = 'Symlink {0} is present and owned by {1}:{2}'.format(name, user, group)
ret = return_val({'comment': comt,
'result': True,
'pchanges': {}})
'changes': {}})
self.assertDictEqual(filestate.symlink(name, target,
user=user,
group=group), ret)
@ -292,7 +292,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
'{1} - backup: {2}'.format(name, target, os.path.join(test_dir, 'SALT'))
ret.update({'comment': comt,
'result': False,
'pchanges': {'new': name}})
'changes': {}})
self.assertDictEqual(
filestate.symlink(name, target, user=user, group=group,
backupname='SALT'),
@ -312,7 +312,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
comt = 'Backupname must be an absolute path or a file name: {0}'.format('tmp/SALT')
ret.update({'comment': comt,
'result': False,
'pchanges': {'new': name}})
'changes': {}})
self.assertDictEqual(
filestate.symlink(name, target, user=user, group=group, backupname='tmp/SALT'),
ret)
@ -331,7 +331,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
patch('salt.utils.win_functions.get_sid_from_name', return_value='test-sid'):
comt = 'File exists where the symlink {0} should be'.format(name)
ret = return_val({'comment': comt,
'pchanges': {'new': name},
'changes': {},
'result': False})
self.assertDictEqual(
filestate.symlink(name, target, user=user, group=group),
@ -353,7 +353,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
comt = 'File exists where the symlink {0} should be'.format(name)
ret = return_val({'comment': comt,
'result': False,
'pchanges': {'new': name}})
'changes': {}})
self.assertDictEqual(
filestate.symlink(name, target, user=user, group=group),
ret)
@ -374,7 +374,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
comt = 'Directory exists where the symlink {0} should be'.format(name)
ret = return_val({'comment': comt,
'result': False,
'pchanges': {'new': name}})
'changes': {}})
self.assertDictEqual(
filestate.symlink(name, target, user=user, group=group),
ret)
@ -394,7 +394,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
comt = 'Unable to create new symlink {0} -> {1}: '.format(name, target)
ret = return_val({'comment': comt,
'result': False,
'pchanges': {'new': name}})
'changes': {}})
self.assertDictEqual(
filestate.symlink(name, target, user=user, group=group),
ret)
@ -417,7 +417,6 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
comt = 'Created new symlink {0} -> {1}'.format(name, target)
ret = return_val({'comment': comt,
'result': True,
'pchanges': {'new': name},
'changes': {'new': name}})
self.assertDictEqual(
filestate.symlink(name, target, user=user, group=group),
@ -443,7 +442,6 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
'ownership to {2}:{3}'.format(name, target, user, group)
ret = return_val({'comment': comt,
'result': False,
'pchanges': {'new': name},
'changes': {'new': name}})
self.assertDictEqual(
filestate.symlink(name, target, user=user, group=group),
@ -459,7 +457,6 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
ret = {'name': name,
'result': False,
'comment': '',
'pchanges': {},
'changes': {}}
mock_t = MagicMock(return_value=True)
@ -490,17 +487,15 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
ret.update({'comment': comt,
'name': name,
'result': None,
'pchanges': {'removed': '/fake/file.conf'}})
'changes': {'removed': '/fake/file.conf'}})
self.assertDictEqual(filestate.absent(name), ret)
ret.update({'pchanges': {}})
with patch.dict(filestate.__opts__, {'test': False}):
with patch.dict(filestate.__salt__,
{'file.remove': mock_file}):
comt = ('Removed file {0}'.format(name))
ret.update({'comment': comt, 'result': True,
'changes': {'removed': name},
'pchanges': {'removed': name}})
'changes': {'removed': name}})
self.assertDictEqual(filestate.absent(name), ret)
comt = ('Removed file {0}'.format(name))
@ -508,7 +503,6 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
'result': False,
'changes': {}})
self.assertDictEqual(filestate.absent(name), ret)
ret.update({'pchanges': {}})
with patch.object(os.path, 'isfile', mock_f):
with patch.object(os.path, 'isdir', mock_t):
@ -516,7 +510,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
comt = \
'Directory {0} is set for removal'.format(name)
ret.update({'comment': comt,
'pchanges': {'removed': name},
'changes': {'removed': name},
'result': None})
self.assertDictEqual(filestate.absent(name), ret)
@ -533,7 +527,6 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
ret.update({'comment': comt, 'result': False,
'changes': {}})
self.assertDictEqual(filestate.absent(name), ret)
ret.update({'pchanges': {}})
with patch.object(os.path, 'isdir', mock_f):
with patch.dict(filestate.__opts__, {'test': True}):
@ -552,8 +545,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
ret = {'name': name,
'result': False,
'comment': '',
'changes': {},
'pchanges': {}}
'changes': {}}
mock_t = MagicMock(return_value=True)
mock_f = MagicMock(return_value=False)
@ -589,7 +581,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
mock_f = MagicMock(return_value=False)
comt = ('Must provide name to file.missing')
ret.update({'comment': comt, 'name': '', 'pchanges': {}})
ret.update({'comment': comt, 'name': '', 'changes': {}})
self.assertDictEqual(filestate.missing(''), ret)
with patch.object(os.path, 'exists', mock_t):
@ -680,7 +672,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
'file.manage_file': mock_ex,
'cmd.run_all': mock_cmd_fail}):
comt = ('Destination file name is required')
ret.update({'comment': comt, 'name': '', 'pchanges': {}})
ret.update({'comment': comt, 'name': '', 'changes': {}})
self.assertDictEqual(filestate.managed(''), ret)
with patch.object(os.path, 'isfile', mock_f):
@ -785,13 +777,12 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
comt = ('check_cmd execution failed')
ret.update({'comment': comt, 'result': False, 'skip_watch': True})
ret.pop('pchanges')
self.assertDictEqual(filestate.managed
(name, user=user, group=group,
check_cmd='A'), ret)
comt = ('check_cmd execution failed')
ret.update({'comment': True, 'pchanges': {}})
ret.update({'comment': True, 'changes': {}})
ret.pop('skip_watch', None)
self.assertDictEqual(filestate.managed
(name, user=user, group=group),
@ -848,7 +839,6 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
ret = {'name': name,
'result': False,
'comment': '',
'pchanges': {},
'changes': {}}
comt = ('Must provide name to file.directory')
@ -940,12 +930,10 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
else:
comt = ('The following files will be changed:\n{0}:'
' directory - new\n'.format(name))
p_chg = {name: {'directory': 'new'}}
ret.update({
'comment': comt,
'result': None,
'pchanges': p_chg,
'changes': {}
'changes': {name: {'directory': 'new'}}
})
self.assertDictEqual(filestate.directory(name,
user=user,
@ -956,7 +944,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
with patch.object(os.path, 'isdir', mock_f):
comt = ('No directory to create {0} in'
.format(name))
ret.update({'comment': comt, 'result': False, 'changes': {}})
ret.update({'comment': comt, 'result': False})
self.assertDictEqual(filestate.directory
(name, user=user, group=group),
ret)
@ -975,7 +963,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
'options "ignore_files" and '
'"ignore_dirs" at the same '
'time.',
'pchanges': {}})
'changes': {}})
with patch.object(os.path, 'isdir', mock_t):
self.assertDictEqual(filestate.directory
(name, user=user,
@ -1003,7 +991,6 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
ret = {'name': name,
'result': False,
'comment': '',
'pchanges': {},
'changes': {}}
comt = ("'mode' is not allowed in 'file.recurse'."
@ -1092,7 +1079,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
'changes': {}}
comt = ('Must provide name to file.replace')
ret.update({'comment': comt, 'name': '', 'pchanges': {}})
ret.update({'comment': comt, 'name': '', 'changes': {}})
self.assertDictEqual(filestate.replace('', pattern, repl), ret)
mock_t = MagicMock(return_value=True)
@ -1126,7 +1113,6 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
ret = {'name': name,
'result': False,
'comment': '',
'pchanges': {},
'changes': {}}
comt = ('Must provide name to file.blockreplace')
@ -1146,8 +1132,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
with patch.dict(filestate.__opts__, {'test': True}):
comt = ('Changes would be made')
ret.update({'comment': comt, 'result': None,
'changes': {'diff': True},
'pchanges': {'diff': True}})
'changes': {'diff': True}})
self.assertDictEqual(filestate.blockreplace(name), ret)
# 'comment' function tests: 1
@ -1163,7 +1148,6 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
ret = {'name': name,
'result': False,
'comment': '',
'pchanges': {},
'changes': {}}
comt = ('Must provide name to file.comment')
@ -1194,14 +1178,15 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
'file.comment_line': mock_t}):
with patch.dict(filestate.__opts__, {'test': True}):
comt = ('File {0} is set to be updated'.format(name))
ret.update({'comment': comt, 'result': None, 'pchanges': {name: 'updated'}})
ret.update({'comment': comt, 'result': None, 'changes': {name: 'updated'}})
self.assertDictEqual(filestate.comment(name, regex), ret)
with patch.dict(filestate.__opts__, {'test': False}):
with patch.object(salt.utils.files, 'fopen',
MagicMock(mock_open())):
comt = ('Commented lines successfully')
ret.update({'comment': comt, 'result': True})
ret.update({'comment': comt, 'result': True,
'changes': {}})
self.assertDictEqual(filestate.comment(name, regex),
ret)
@ -1216,7 +1201,6 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
regex = 'bind 127.0.0.1'
ret = {'name': name,
'pchanges': {},
'result': False,
'comment': '',
'changes': {}}
@ -1249,14 +1233,16 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
with patch.dict(filestate.__opts__, {'test': True}):
comt = ('File {0} is set to be updated'.format(name))
ret.update({'comment': comt, 'result': None, 'pchanges': {name: 'updated'}, })
ret.update({'comment': comt, 'result': None,
'changes': {name: 'updated'}})
self.assertDictEqual(filestate.uncomment(name, regex), ret)
with patch.dict(filestate.__opts__, {'test': False}):
with patch.object(salt.utils.files, 'fopen',
MagicMock(mock_open())):
comt = ('Uncommented lines successfully')
ret.update({'comment': comt, 'result': True})
ret.update({'comment': comt, 'result': True,
'changes': {}})
self.assertDictEqual(filestate.uncomment(name, regex), ret)
# 'prepend' function tests: 1
@ -1276,7 +1262,6 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
ret = {'name': name,
'result': False,
'comment': '',
'pchanges': {},
'changes': {}}
comt = ('Must provide name to file.prepend')
@ -1299,24 +1284,23 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
'file.prepend': mock_t}):
comt = ('The following files will be changed:\n/tmp/etc:'
' directory - new\n')
pchanges = {'/tmp/etc': {'directory': 'new'}}
changes = {'/tmp/etc': {'directory': 'new'}}
if salt.utils.platform.is_windows():
comt = 'The directory "c:\\tmp\\etc" will be changed'
pchanges = {'c:\\tmp\\etc': {'directory': 'new'}}
ret.update({'comment': comt, 'name': name, 'pchanges': pchanges})
changes = {'c:\\tmp\\etc': {'directory': 'new'}}
ret.update({'comment': comt, 'name': name, 'changes': changes})
self.assertDictEqual(filestate.prepend(name, makedirs=True),
ret)
with patch.object(os.path, 'isabs', mock_f):
comt = ('Specified file {0} is not an absolute path'
.format(name))
ret.update({'comment': comt, 'pchanges': {}})
ret.update({'comment': comt, 'changes': {}})
self.assertDictEqual(filestate.prepend(name), ret)
with patch.object(os.path, 'isabs', mock_t):
with patch.object(os.path, 'exists', mock_t):
comt = ("Failed to load template file {0}".format(source))
ret.pop('pchanges')
ret.update({'comment': comt, 'name': source, 'data': []})
self.assertDictEqual(filestate.prepend(name, source=source),
ret)
@ -1330,8 +1314,9 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
change = {'diff': 'Replace binary file'}
comt = ('File {0} is set to be updated'
.format(name))
ret.update({'comment': comt, 'result': None,
'changes': change, 'pchanges': {}})
ret.update({'comment': comt,
'result': None,
'changes': change})
self.assertDictEqual(filestate.prepend
(name, text=text), ret)
@ -1372,14 +1357,18 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
with patch.object(os.path, 'exists', mock_f):
with patch.dict(filestate.__opts__, {'test': True}):
comt = ('File {0} is set to be created'.format(name))
ret.update({'comment': comt, 'result': None})
ret.update({'comment': comt,
'result': None,
'changes': {'new': name}})
self.assertDictEqual(filestate.touch(name), ret)
with patch.dict(filestate.__opts__, {'test': False}):
with patch.object(os.path, 'isdir', mock_f):
comt = ('Directory not present to touch file {0}'
.format(name))
ret.update({'comment': comt, 'result': False})
ret.update({'comment': comt,
'result': False,
'changes': {}})
self.assertDictEqual(filestate.touch(name), ret)
with patch.object(os.path, 'isdir', mock_t):
@ -1849,7 +1838,6 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
expected_ret = {
'name': fake_name,
'changes': {'retained': [], 'deleted': [], 'ignored': []},
'pchanges': {'retained': [], 'deleted': [], 'ignored': []},
'result': True,
'comment': 'Name provided to file.retention must be a directory',
}
@ -1895,8 +1883,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
deleted_files = sorted(list(set(fake_file_list) - retained_files - set(ignored_files)), reverse=True)
retained_files = sorted(list(retained_files), reverse=True)
changes = {'retained': retained_files, 'deleted': deleted_files, 'ignored': ignored_files}
expected_ret['pchanges'] = changes
expected_ret['changes'] = {'retained': retained_files, 'deleted': deleted_files, 'ignored': ignored_files}
if test:
expected_ret['result'] = None
expected_ret['comment'] = ('{0} backups would have been removed from {1}.\n'
@ -1904,7 +1891,6 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
else:
expected_ret['comment'] = ('{0} backups were removed from {1}.\n'
''.format(len(deleted_files), fake_name))
expected_ret['changes'] = changes
mock_remove.assert_has_calls(
[call(os.path.join(fake_name, x)) for x in deleted_files],
any_order=True

View File

@ -114,22 +114,28 @@ class KernelPkgTestCase(TestCase, LoaderModuleMockMixin):
Test - latest_active when a new kernel is available
'''
reboot = MagicMock(return_value=True)
with patch.dict(kernelpkg.__salt__, {'kernelpkg.needs_reboot': reboot}):
with patch.dict(kernelpkg.__opts__, {'test': False}):
kernelpkg.__salt__['system.reboot'].reset_mock()
ret = kernelpkg.latest_active(name=STATE_NAME)
self.assertEqual(ret['name'], STATE_NAME)
self.assertTrue(ret['result'])
self.assertIsInstance(ret['changes'], dict)
self.assertIsInstance(ret['comment'], six.text_type)
self.assert_called_once(kernelpkg.__salt__['system.reboot'])
latest = MagicMock(return_value=1)
with patch.dict(
kernelpkg.__salt__, {'kernelpkg.needs_reboot': reboot,
'kernelpkg.latest_installed': latest}), \
patch.dict(kernelpkg.__opts__, {'test': False}):
kernelpkg.__salt__['system.reboot'].reset_mock()
ret = kernelpkg.latest_active(name=STATE_NAME)
self.assertEqual(ret['name'], STATE_NAME)
self.assertTrue(ret['result'])
self.assertIsInstance(ret['changes'], dict)
self.assertIsInstance(ret['comment'], six.text_type)
self.assert_called_once(kernelpkg.__salt__['system.reboot'])
with patch.dict(kernelpkg.__opts__, {'test': True}):
kernelpkg.__salt__['system.reboot'].reset_mock()
ret = kernelpkg.latest_active(name=STATE_NAME)
self.assertEqual(ret['name'], STATE_NAME)
self.assertIsNone(ret['result'])
self.assertDictEqual(ret['changes'], {})
self.assertDictEqual(
ret['changes'],
{'kernel': {'new': 1, 'old': 0}}
)
self.assertIsInstance(ret['comment'], six.text_type)
kernelpkg.__salt__['system.reboot'].assert_not_called()

View File

@ -69,13 +69,12 @@ class LinuxAclTestCase(TestCase, LoaderModuleMockMixin):
''.format(acl_name, perms))
ret = {'name': name,
'comment': comt,
'changes': {},
'pchanges': {'new': {'acl_name': acl_name,
'changes': {'new': {'acl_name': acl_name,
'acl_type': acl_type,
'perms': perms},
'old': {'acl_name': acl_name,
'acl_type': acl_type,
'perms': 'r-x'}},
'old': {'acl_name': acl_name,
'acl_type': acl_type,
'perms': 'r-x'}},
'result': None}
self.assertDictEqual(linux_acl.present(name, acl_type, acl_name,
@ -92,7 +91,6 @@ class LinuxAclTestCase(TestCase, LoaderModuleMockMixin):
'old': {'acl_name': acl_name,
'acl_type': acl_type,
'perms': 'r-x'}},
'pchanges': {},
'result': True}
self.assertDictEqual(linux_acl.present(name, acl_type,
acl_name, perms),
@ -106,7 +104,6 @@ class LinuxAclTestCase(TestCase, LoaderModuleMockMixin):
ret = {'name': name,
'comment': comt,
'changes': {},
'pchanges': {},
'result': False}
self.assertDictEqual(linux_acl.present(name, acl_type,
acl_name, perms),
@ -118,10 +115,9 @@ class LinuxAclTestCase(TestCase, LoaderModuleMockMixin):
'for {0}: {1}'.format(acl_name, perms))
ret = {'name': name,
'comment': comt,
'changes': {},
'pchanges': {'new': {'acl_name': acl_name,
'acl_type': acl_type,
'perms': perms}},
'changes': {'new': {'acl_name': acl_name,
'acl_type': acl_type,
'perms': perms}},
'result': None}
self.assertDictEqual(linux_acl.present(name, acl_type,
acl_name, perms),
@ -135,7 +131,6 @@ class LinuxAclTestCase(TestCase, LoaderModuleMockMixin):
'changes': {'new': {'acl_name': acl_name,
'acl_type': acl_type,
'perms': perms}},
'pchanges': {},
'result': True}
self.assertDictEqual(linux_acl.present(name, acl_type,
acl_name, perms),
@ -149,7 +144,6 @@ class LinuxAclTestCase(TestCase, LoaderModuleMockMixin):
ret = {'name': name,
'comment': comt,
'changes': {},
'pchanges': {},
'result': False}
self.assertDictEqual(linux_acl.present(name, acl_type,
acl_name, perms),
@ -163,13 +157,12 @@ class LinuxAclTestCase(TestCase, LoaderModuleMockMixin):
''.format(acl_name, perms))
ret = {'name': name,
'comment': comt,
'changes': {},
'pchanges': {'new': {'acl_name': acl_name,
'changes': {'new': {'acl_name': acl_name,
'acl_type': acl_type,
'perms': perms},
'old': {'acl_name': acl_name,
'acl_type': acl_type,
'perms': 'rwx'}},
'old': {'acl_name': acl_name,
'acl_type': acl_type,
'perms': 'rwx'}},
'result': None}
self.assertDictEqual(linux_acl.present(name, acl_type, acl_name,
@ -183,7 +176,6 @@ class LinuxAclTestCase(TestCase, LoaderModuleMockMixin):
ret = {'name': name,
'comment': comt,
'changes': {},
'pchanges': {},
'result': True}
self.assertDictEqual(linux_acl.present(name, acl_type, acl_name,
@ -191,8 +183,7 @@ class LinuxAclTestCase(TestCase, LoaderModuleMockMixin):
# No acl type
comt = ('ACL Type does not exist')
ret = {'name': name, 'comment': comt, 'result': False,
'changes': {}, 'pchanges': {}}
ret = {'name': name, 'comment': comt, 'result': False, 'changes': {}}
self.assertDictEqual(linux_acl.present(name, acl_type, acl_name,
perms), ret)

View File

@ -30,8 +30,7 @@ class NetyangTestCase(TestCase, LoaderModuleMockMixin):
def test_managed(self):
ret = {'changes': {}, 'comment': 'Loaded.',
'name': 'test', 'result': False,
'pchanges': {'compliance_report': {'complies': False}}}
'name': 'test', 'result': False}
parse = MagicMock(return_value='abcdef')
temp_file = MagicMock(return_value='')
compliance_report = MagicMock(return_value={'complies': False})
@ -55,8 +54,7 @@ class NetyangTestCase(TestCase, LoaderModuleMockMixin):
def test_configured(self):
ret = {'changes': {}, 'comment': 'Loaded.',
'name': 'test', 'result': False,
'pchanges': {}}
'name': 'test', 'result': False}
load_config = MagicMock(return_value={'comment': 'Loaded.'})
with patch('salt.utils.files.fopen'):

View File

@ -175,13 +175,11 @@ class SaltmodTestCase(TestCase, LoaderModuleMockMixin):
name = 'state'
tgt = 'larry'
comt = ('Function state will be executed'
' on target {0} as test=False'.format(tgt))
ret = {'name': name,
'changes': {},
'result': None,
'comment': comt}
'comment': 'Function state would be executed '
'on target {0}'.format(tgt)}
with patch.dict(saltmod.__opts__, {'test': True}):
self.assertDictEqual(saltmod.function(name, tgt), ret)

View File

@ -527,56 +527,6 @@ class UtilStateMergeSubreturnTestcase(TestCase):
'alarms': secondary_changes,
})
def test_merge_pchanges(self):
primary_pchanges = {'old': None, 'new': 'my_resource'}
secondary_pchanges = {'old': None, 'new': ['alarm-1', 'alarm-2']}
# Neither main nor sub pchanges case
m = copy.deepcopy(self.main_ret)
s = copy.deepcopy(self.sub_ret)
res = salt.utils.state.merge_subreturn(m, s)
self.assertNotIn('pchanges', res)
# No main pchanges, sub pchanges
m = copy.deepcopy(self.main_ret)
s = copy.deepcopy(self.sub_ret)
s['pchanges'] = copy.deepcopy(secondary_pchanges)
res = salt.utils.state.merge_subreturn(m, s)
self.assertDictEqual(res['pchanges'], {
'secondary': secondary_pchanges
})
# Main pchanges, no sub pchanges
m = copy.deepcopy(self.main_ret)
m['pchanges'] = copy.deepcopy(primary_pchanges)
s = copy.deepcopy(self.sub_ret)
res = salt.utils.state.merge_subreturn(m, s)
self.assertDictEqual(res['pchanges'], primary_pchanges)
# Both main and sub pchanges, new pchanges don't affect existing ones
m = copy.deepcopy(self.main_ret)
m['pchanges'] = copy.deepcopy(primary_pchanges)
s = copy.deepcopy(self.sub_ret)
s['pchanges'] = copy.deepcopy(secondary_pchanges)
res = salt.utils.state.merge_subreturn(m, s)
self.assertDictEqual(res['pchanges'], {
'old': None,
'new': 'my_resource',
'secondary': secondary_pchanges,
})
# The subkey parameter is respected
m = copy.deepcopy(self.main_ret)
m['pchanges'] = copy.deepcopy(primary_pchanges)
s = copy.deepcopy(self.sub_ret)
s['pchanges'] = copy.deepcopy(secondary_pchanges)
res = salt.utils.state.merge_subreturn(m, s, subkey='alarms')
self.assertDictEqual(res['pchanges'], {
'old': None,
'new': 'my_resource',
'alarms': secondary_pchanges,
})
def test_merge_comments(self):
main_comment_1 = 'First primary comment.'
main_comment_2 = 'Second primary comment.'