mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
states.file.patch/modules.file.check_hash: use hash length to determine type
This brings the file.patch state and file.check_hash function to parity with the source_hash handling changes made in the 2016.11 branch, by using the hash length to determine the type. It also fixes a shadowed builtin in the file.patch state.
This commit is contained in:
parent
b492f7094c
commit
650dbaca4e
2 changed files with 71 additions and 37 deletions
|
@ -687,31 +687,54 @@ def check_hash(path, file_hash):
|
|||
'''
|
||||
Check if a file matches the given hash string
|
||||
|
||||
Returns true if the hash matched, otherwise false. Raises ValueError if
|
||||
the hash was not formatted correctly.
|
||||
Returns ``True`` if the hash matches, otherwise ``False``.
|
||||
|
||||
path
|
||||
A file path
|
||||
Path to a file local to the minion.
|
||||
|
||||
hash
|
||||
A string in the form <hash_type>:<hash_value>. For example:
|
||||
``md5:e138491e9d5b97023cea823fe17bac22``
|
||||
The hash to check against the file specified in the ``path`` argument.
|
||||
For versions 2016.11.4 and newer, the hash can be specified without an
|
||||
accompanying hash type (e.g. ``e138491e9d5b97023cea823fe17bac22``),
|
||||
but for earlier releases it is necessary to also specify the hash type
|
||||
in the format ``<hash_type>:<hash_value>`` (e.g.
|
||||
``md5:e138491e9d5b97023cea823fe17bac22``).
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' file.check_hash /etc/fstab md5:<md5sum>
|
||||
salt '*' file.check_hash /etc/fstab e138491e9d5b97023cea823fe17bac22
|
||||
salt '*' file.check_hash /etc/fstab md5:e138491e9d5b97023cea823fe17bac22
|
||||
'''
|
||||
path = os.path.expanduser(path)
|
||||
|
||||
hash_parts = file_hash.split(':', 1)
|
||||
if len(hash_parts) != 2:
|
||||
# Support "=" for backward compatibility.
|
||||
hash_parts = file_hash.split('=', 1)
|
||||
if len(hash_parts) != 2:
|
||||
raise ValueError('Bad hash format: \'{0}\''.format(file_hash))
|
||||
hash_form, hash_value = hash_parts
|
||||
return get_hash(path, hash_form) == hash_value
|
||||
if not isinstance(file_hash, six.string_types):
|
||||
raise SaltInvocationError('hash must be a string')
|
||||
|
||||
for sep in (':', '='):
|
||||
if sep in file_hash:
|
||||
hash_type, hash_value = file_hash.split(sep, 1)
|
||||
break
|
||||
else:
|
||||
hash_value = file_hash
|
||||
hash_len = len(file_hash)
|
||||
hash_type = HASHES_REVMAP.get(hash_len)
|
||||
if hash_type is None:
|
||||
raise SaltInvocationError(
|
||||
'Hash {0} (length: {1}) could not be matched to a supported '
|
||||
'hash type. The supported hash types and lengths are: '
|
||||
'{2}'.format(
|
||||
file_hash,
|
||||
hash_len,
|
||||
', '.join(
|
||||
['{0} ({1})'.format(HASHES_REVMAP[x], x)
|
||||
for x in sorted(HASHES_REVMAP)]
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
return get_hash(path, hash_type) == hash_value
|
||||
|
||||
|
||||
def find(path, *args, **kwargs):
|
||||
|
|
|
@ -281,7 +281,7 @@ import salt.utils.dictupdate
|
|||
import salt.utils.templates
|
||||
import salt.utils.url
|
||||
from salt.utils.locales import sdecode
|
||||
from salt.exceptions import CommandExecutionError
|
||||
from salt.exceptions import CommandExecutionError, SaltInvocationError
|
||||
|
||||
# Import 3rd-party libs
|
||||
import salt.ext.six as six
|
||||
|
@ -4372,7 +4372,6 @@ def prepend(name,
|
|||
|
||||
def patch(name,
|
||||
source=None,
|
||||
hash=None,
|
||||
options='',
|
||||
dry_run_first=True,
|
||||
**kwargs):
|
||||
|
@ -4394,10 +4393,13 @@ def patch(name,
|
|||
salt://spam/eggs. A source is required.
|
||||
|
||||
hash
|
||||
Hash of the patched file. If the hash of the target file matches this
|
||||
value then the patch is assumed to have been applied. The hash string
|
||||
is the hash algorithm followed by the hash of the file:
|
||||
md5=e138491e9d5b97023cea823fe17bac22
|
||||
The hash of the patched file. If the hash of the target file matches
|
||||
this value then the patch is assumed to have been applied. For versions
|
||||
2016.11.4 and newer, the hash can be specified without an accompanying
|
||||
hash type (e.g. ``e138491e9d5b97023cea823fe17bac22``), but for earlier
|
||||
releases it is necessary to also specify the hash type in the format
|
||||
``<hash_type>:<hash_value>`` (e.g.
|
||||
``md5:e138491e9d5b97023cea823fe17bac22``).
|
||||
|
||||
options
|
||||
Extra options to pass to patch.
|
||||
|
@ -4410,7 +4412,7 @@ def patch(name,
|
|||
by the ``source`` parameter. If not provided, this defaults to the
|
||||
environment from which the state is being executed.
|
||||
|
||||
Usage:
|
||||
**Usage:**
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -4418,8 +4420,15 @@ def patch(name,
|
|||
/opt/file.txt:
|
||||
file.patch:
|
||||
- source: salt://file.patch
|
||||
- hash: md5=e138491e9d5b97023cea823fe17bac22
|
||||
- hash: e138491e9d5b97023cea823fe17bac22
|
||||
|
||||
.. note::
|
||||
For minions running version 2016.11.3 or older, the hash in the example
|
||||
above would need to be specified with the hash type (i.e.
|
||||
``md5:e138491e9d5b97023cea823fe17bac22``).
|
||||
'''
|
||||
hash_ = kwargs.pop('hash', None)
|
||||
|
||||
if 'env' in kwargs:
|
||||
salt.utils.warn_until(
|
||||
'Oxygen',
|
||||
|
@ -4439,11 +4448,16 @@ def patch(name,
|
|||
return _error(ret, check_msg)
|
||||
if not source:
|
||||
return _error(ret, 'Source is required')
|
||||
if hash is None:
|
||||
if hash_ is None:
|
||||
return _error(ret, 'Hash is required')
|
||||
|
||||
if hash and __salt__['file.check_hash'](name, hash):
|
||||
ret.update(result=True, comment='Patch is already applied')
|
||||
try:
|
||||
if hash_ and __salt__['file.check_hash'](name, hash_):
|
||||
ret['result'] = True
|
||||
ret['comment'] = 'Patch is already applied'
|
||||
return ret
|
||||
except (SaltInvocationError, ValueError) as exc:
|
||||
ret['comment'] = exc.__str__()
|
||||
return ret
|
||||
|
||||
# get cached file or copy it to cache
|
||||
|
@ -4454,9 +4468,8 @@ def patch(name,
|
|||
return ret
|
||||
|
||||
log.debug(
|
||||
'State patch.applied cached source {0} -> {1}'.format(
|
||||
source, cached_source_path
|
||||
)
|
||||
'State patch.applied cached source %s -> %s',
|
||||
source, cached_source_path
|
||||
)
|
||||
|
||||
if dry_run_first or __opts__['test']:
|
||||
|
@ -4467,20 +4480,18 @@ def patch(name,
|
|||
ret['comment'] = 'File {0} will be patched'.format(name)
|
||||
ret['result'] = None
|
||||
return ret
|
||||
if ret['changes']['retcode']:
|
||||
if ret['changes']['retcode'] != 0:
|
||||
return ret
|
||||
|
||||
ret['changes'] = __salt__['file.patch'](
|
||||
name, cached_source_path, options=options
|
||||
)
|
||||
ret['result'] = not ret['changes']['retcode']
|
||||
if ret['result'] and hash and not __salt__['file.check_hash'](name, hash):
|
||||
ret.update(
|
||||
result=False,
|
||||
comment='File {0} hash mismatch after patch was applied'.format(
|
||||
name
|
||||
)
|
||||
)
|
||||
ret['result'] = ret['changes']['retcode'] == 0
|
||||
# No need to check for SaltInvocationError or ValueError this time, since
|
||||
# these exceptions would have been caught above.
|
||||
if ret['result'] and hash_ and not __salt__['file.check_hash'](name, hash_):
|
||||
ret['result'] = False
|
||||
ret['comment'] = 'Hash mismatch after patch was applied'
|
||||
return ret
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue