mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
* Add new parameters related to mtime and atime for file module, fixes #30226
This commit is contained in:
parent
1b3f074ec6
commit
a78cc15099
3 changed files with 203 additions and 42 deletions
|
@ -76,6 +76,30 @@ options:
|
||||||
type: bool
|
type: bool
|
||||||
default: 'yes'
|
default: 'yes'
|
||||||
version_added: "1.8"
|
version_added: "1.8"
|
||||||
|
modification_time:
|
||||||
|
description:
|
||||||
|
- This parameter indicates the time the file's modification time should be set to
|
||||||
|
- 'Should be C(preserve) when no modification is required, C(YYYYMMDDHHMM.SS) when using default time format, or C(now)'
|
||||||
|
- 'Default is None meaning that C(preserve) is the default for C(state=[file,directory,link,hard]) and C(now) is default for C(state=touch)'
|
||||||
|
version_added: "2.7"
|
||||||
|
modification_time_format:
|
||||||
|
description:
|
||||||
|
- 'When used with C(modification_time), indicates the time format that must be used.'
|
||||||
|
- 'Based on default Python format (see time.strftime doc)'
|
||||||
|
default: "%Y%m%d%H%M.%S"
|
||||||
|
version_added: "2.7"
|
||||||
|
access_time:
|
||||||
|
description:
|
||||||
|
- This parameter indicates the time the file's access time should be set to
|
||||||
|
- 'Should be C(preserve) when no modification is required, C(YYYYMMDDHHMM.SS) when using default time format, or C(now)'
|
||||||
|
- 'Default is None meaning that C(preserve) is the default for C(state=[file,directory,link,hard]) and C(now) is default for C(state=touch)'
|
||||||
|
version_added: "2.7"
|
||||||
|
access_time_format:
|
||||||
|
description:
|
||||||
|
- 'When used with C(access_time), indicates the time format that must be used.'
|
||||||
|
- 'Based on default Python format (see time.strftime doc)'
|
||||||
|
default: "%Y%m%d%H%M.%S"
|
||||||
|
version_added: "2.7"
|
||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES = '''
|
EXAMPLES = '''
|
||||||
|
@ -116,11 +140,31 @@ EXAMPLES = '''
|
||||||
state: touch
|
state: touch
|
||||||
mode: "u+rw,g-wx,o-rwx"
|
mode: "u+rw,g-wx,o-rwx"
|
||||||
|
|
||||||
|
# touch again the same file, but dont change times
|
||||||
|
# this makes the task idempotents
|
||||||
|
- file:
|
||||||
|
path: /etc/foo.conf
|
||||||
|
state: touch
|
||||||
|
mode: "u+rw,g-wx,o-rwx"
|
||||||
|
modification_time: "preserve"
|
||||||
|
access_time: "preserve"
|
||||||
|
|
||||||
# create a directory if it doesn't exist
|
# create a directory if it doesn't exist
|
||||||
- file:
|
- file:
|
||||||
path: /etc/some_directory
|
path: /etc/some_directory
|
||||||
state: directory
|
state: directory
|
||||||
mode: 0755
|
mode: 0755
|
||||||
|
|
||||||
|
# updates modification and access time of given file
|
||||||
|
- file:
|
||||||
|
path: /etc/some_file
|
||||||
|
state: file
|
||||||
|
mode: 0755
|
||||||
|
modification_time: now
|
||||||
|
access_time: now
|
||||||
|
'''
|
||||||
|
RETURN = '''
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import errno
|
import errno
|
||||||
|
@ -233,7 +277,7 @@ def get_state(path):
|
||||||
|
|
||||||
|
|
||||||
# This should be moved into the common file utilities
|
# This should be moved into the common file utilities
|
||||||
def recursive_set_attributes(b_path, follow, file_args):
|
def recursive_set_attributes(b_path, follow, file_args, mtime, atime):
|
||||||
changed = False
|
changed = False
|
||||||
for b_root, b_dirs, b_files in os.walk(b_path):
|
for b_root, b_dirs, b_files in os.walk(b_path):
|
||||||
for b_fsobj in b_dirs + b_files:
|
for b_fsobj in b_dirs + b_files:
|
||||||
|
@ -242,11 +286,14 @@ def recursive_set_attributes(b_path, follow, file_args):
|
||||||
tmp_file_args = file_args.copy()
|
tmp_file_args = file_args.copy()
|
||||||
tmp_file_args['path'] = to_native(b_fsname, errors='surrogate_or_strict')
|
tmp_file_args['path'] = to_native(b_fsname, errors='surrogate_or_strict')
|
||||||
changed |= module.set_fs_attributes_if_different(tmp_file_args, changed, expand=False)
|
changed |= module.set_fs_attributes_if_different(tmp_file_args, changed, expand=False)
|
||||||
|
changed |= update_timestamp_for_file(tmp_file_args['path'], mtime, atime)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Change perms on the link
|
# Change perms on the link
|
||||||
tmp_file_args = file_args.copy()
|
tmp_file_args = file_args.copy()
|
||||||
tmp_file_args['path'] = to_native(b_fsname, errors='surrogate_or_strict')
|
tmp_file_args['path'] = to_native(b_fsname, errors='surrogate_or_strict')
|
||||||
changed |= module.set_fs_attributes_if_different(tmp_file_args, changed, expand=False)
|
changed |= module.set_fs_attributes_if_different(tmp_file_args, changed, expand=False)
|
||||||
|
changed |= update_timestamp_for_file(tmp_file_args['path'], mtime, atime)
|
||||||
|
|
||||||
if follow:
|
if follow:
|
||||||
b_fsname = os.path.join(b_root, os.readlink(b_fsname))
|
b_fsname = os.path.join(b_root, os.readlink(b_fsname))
|
||||||
|
@ -254,12 +301,13 @@ def recursive_set_attributes(b_path, follow, file_args):
|
||||||
if os.path.exists(b_fsname):
|
if os.path.exists(b_fsname):
|
||||||
if os.path.isdir(b_fsname):
|
if os.path.isdir(b_fsname):
|
||||||
# Link is a directory so change perms on the directory's contents
|
# Link is a directory so change perms on the directory's contents
|
||||||
changed |= recursive_set_attributes(b_fsname, follow, file_args)
|
changed |= recursive_set_attributes(b_fsname, follow, file_args, mtime, atime)
|
||||||
|
|
||||||
# Change perms on the file pointed to by the link
|
# Change perms on the file pointed to by the link
|
||||||
tmp_file_args = file_args.copy()
|
tmp_file_args = file_args.copy()
|
||||||
tmp_file_args['path'] = to_native(b_fsname, errors='surrogate_or_strict')
|
tmp_file_args['path'] = to_native(b_fsname, errors='surrogate_or_strict')
|
||||||
changed |= module.set_fs_attributes_if_different(tmp_file_args, changed, expand=False)
|
changed |= module.set_fs_attributes_if_different(tmp_file_args, changed, expand=False)
|
||||||
|
changed |= update_timestamp_for_file(tmp_file_args['path'], mtime, atime)
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
|
|
||||||
|
@ -279,6 +327,70 @@ def initial_diff(path, state, prev_state):
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
|
def get_timestamp_for_time(formatted_time, time_format):
|
||||||
|
if formatted_time == 'preserve':
|
||||||
|
return None
|
||||||
|
elif formatted_time == 'now':
|
||||||
|
current_time = time.time()
|
||||||
|
return current_time
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
struct = time.strptime(formatted_time, time_format)
|
||||||
|
struct_time = time.mktime(struct)
|
||||||
|
except (ValueError, OverflowError) as e:
|
||||||
|
raise AnsibleModuleError(results={'msg': 'Error while obtaining timestamp for time %s using format %s: %s'
|
||||||
|
% (formatted_time, time_format, to_native(e, nonstring='simplerepr'))})
|
||||||
|
|
||||||
|
return struct_time
|
||||||
|
|
||||||
|
|
||||||
|
def update_timestamp_for_file(path, mtime, atime, diff=None):
|
||||||
|
# If both parameters are None, nothing to do
|
||||||
|
if mtime is None and atime is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
previous_mtime = os.stat(path).st_mtime
|
||||||
|
previous_atime = os.stat(path).st_atime
|
||||||
|
|
||||||
|
if mtime is None:
|
||||||
|
mtime = previous_mtime
|
||||||
|
|
||||||
|
if atime is None:
|
||||||
|
atime = previous_atime
|
||||||
|
|
||||||
|
# If both timestamps are already ok, nothing to do
|
||||||
|
if mtime == previous_mtime and atime == previous_atime:
|
||||||
|
return False
|
||||||
|
|
||||||
|
os.utime(path, (atime, mtime))
|
||||||
|
|
||||||
|
if diff is not None:
|
||||||
|
if 'before' not in diff:
|
||||||
|
diff['before'] = {}
|
||||||
|
if 'after' not in diff:
|
||||||
|
diff['after'] = {}
|
||||||
|
if mtime != previous_mtime:
|
||||||
|
diff['before']['mtime'] = previous_mtime
|
||||||
|
diff['after']['mtime'] = mtime
|
||||||
|
if atime != previous_atime:
|
||||||
|
diff['before']['atime'] = previous_atime
|
||||||
|
diff['after']['atime'] = atime
|
||||||
|
except OSError as e:
|
||||||
|
raise AnsibleModuleError(results={'msg': 'Error while updating modification or access time: %s'
|
||||||
|
% to_native(e, nonstring='simplerepr'), 'path': path})
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def keep_backward_compatibility_on_timestamps(parameter, state):
|
||||||
|
if state in ['file', 'hard', 'directory', 'link'] and parameter is None:
|
||||||
|
return 'preserve'
|
||||||
|
elif state == 'touch' and parameter is None:
|
||||||
|
return 'now'
|
||||||
|
else:
|
||||||
|
return parameter
|
||||||
|
|
||||||
|
|
||||||
def execute_diff_peek(path):
|
def execute_diff_peek(path):
|
||||||
"""Take a guess as to whether a file is a binary file"""
|
"""Take a guess as to whether a file is a binary file"""
|
||||||
b_path = to_bytes(path, errors='surrogate_or_strict')
|
b_path = to_bytes(path, errors='surrogate_or_strict')
|
||||||
|
@ -324,51 +436,31 @@ def ensure_absent(path):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def execute_touch(path, follow):
|
def execute_touch(path, follow, timestamps):
|
||||||
b_path = to_bytes(path, errors='surrogate_or_strict')
|
b_path = to_bytes(path, errors='surrogate_or_strict')
|
||||||
prev_state = get_state(b_path)
|
prev_state = get_state(b_path)
|
||||||
|
changed = False
|
||||||
# Unfortunately, touch always changes the file because it updates file's timestamp
|
result = {'dest': path}
|
||||||
result = {'dest': path, 'changed': True}
|
mtime = get_timestamp_for_time(timestamps['modification_time'], timestamps['modification_time_format'])
|
||||||
|
atime = get_timestamp_for_time(timestamps['access_time'], timestamps['access_time_format'])
|
||||||
|
|
||||||
if not module.check_mode:
|
if not module.check_mode:
|
||||||
if prev_state == 'absent':
|
if prev_state == 'absent':
|
||||||
# Create an empty file if the filename did not already exist
|
# Create an empty file if the filename did not already exist
|
||||||
try:
|
try:
|
||||||
open(b_path, 'wb').close()
|
open(b_path, 'wb').close()
|
||||||
|
changed = True
|
||||||
except (OSError, IOError) as e:
|
except (OSError, IOError) as e:
|
||||||
raise AnsibleModuleError(results={'msg': 'Error, could not touch target: %s'
|
raise AnsibleModuleError(results={'msg': 'Error, could not touch target: %s'
|
||||||
% to_native(e, nonstring='simplerepr'),
|
% to_native(e, nonstring='simplerepr'),
|
||||||
'path': path})
|
'path': path})
|
||||||
|
|
||||||
elif prev_state in ('file', 'directory', 'hard'):
|
|
||||||
# Update the timestamp if the file already existed
|
|
||||||
try:
|
|
||||||
os.utime(b_path, None)
|
|
||||||
except OSError as e:
|
|
||||||
raise AnsibleModuleError(results={'msg': 'Error while touching existing target: %s'
|
|
||||||
% to_native(e, nonstring='simplerepr'),
|
|
||||||
'path': path})
|
|
||||||
|
|
||||||
elif prev_state == 'link' and follow:
|
|
||||||
# Update the timestamp of the pointed to file
|
|
||||||
b_link_target = os.readlink(b_path)
|
|
||||||
try:
|
|
||||||
os.utime(b_link_target, None)
|
|
||||||
except OSError as e:
|
|
||||||
raise AnsibleModuleError(results={'msg': 'Error while touching existing target: %s'
|
|
||||||
% to_native(e, nonstring='simplerepr'),
|
|
||||||
'path': path})
|
|
||||||
|
|
||||||
else:
|
|
||||||
raise AnsibleModuleError(results={'msg': 'Can only touch files, directories, and'
|
|
||||||
' hardlinks (%s is %s)' % (path, prev_state)})
|
|
||||||
|
|
||||||
# Update the attributes on the file
|
# Update the attributes on the file
|
||||||
diff = initial_diff(path, 'touch', prev_state)
|
diff = initial_diff(path, 'touch', prev_state)
|
||||||
file_args = module.load_file_common_arguments(module.params)
|
file_args = module.load_file_common_arguments(module.params)
|
||||||
try:
|
try:
|
||||||
module.set_fs_attributes_if_different(file_args, True, diff, expand=False)
|
changed = module.set_fs_attributes_if_different(file_args, changed, diff, expand=False)
|
||||||
|
changed |= update_timestamp_for_file(file_args['path'], mtime, atime, diff)
|
||||||
except SystemExit as e:
|
except SystemExit as e:
|
||||||
if e.code:
|
if e.code:
|
||||||
# We take this to mean that fail_json() was called from
|
# We take this to mean that fail_json() was called from
|
||||||
|
@ -378,14 +470,17 @@ def execute_touch(path, follow):
|
||||||
os.remove(b_path)
|
os.remove(b_path)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
result['changed'] = changed
|
||||||
result['diff'] = diff
|
result['diff'] = diff
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def ensure_file_attributes(path, follow):
|
def ensure_file_attributes(path, follow, timestamps):
|
||||||
b_path = to_bytes(path, errors='surrogate_or_strict')
|
b_path = to_bytes(path, errors='surrogate_or_strict')
|
||||||
prev_state = get_state(b_path)
|
prev_state = get_state(b_path)
|
||||||
file_args = module.load_file_common_arguments(module.params)
|
file_args = module.load_file_common_arguments(module.params)
|
||||||
|
mtime = get_timestamp_for_time(timestamps['modification_time'], timestamps['modification_time_format'])
|
||||||
|
atime = get_timestamp_for_time(timestamps['access_time'], timestamps['access_time_format'])
|
||||||
|
|
||||||
if prev_state != 'file':
|
if prev_state != 'file':
|
||||||
if follow and prev_state == 'link':
|
if follow and prev_state == 'link':
|
||||||
|
@ -402,13 +497,16 @@ def ensure_file_attributes(path, follow):
|
||||||
|
|
||||||
diff = initial_diff(path, 'file', prev_state)
|
diff = initial_diff(path, 'file', prev_state)
|
||||||
changed = module.set_fs_attributes_if_different(file_args, False, diff, expand=False)
|
changed = module.set_fs_attributes_if_different(file_args, False, diff, expand=False)
|
||||||
|
changed |= update_timestamp_for_file(file_args['path'], mtime, atime, diff)
|
||||||
return {'path': path, 'changed': changed, 'diff': diff}
|
return {'path': path, 'changed': changed, 'diff': diff}
|
||||||
|
|
||||||
|
|
||||||
def ensure_directory(path, follow, recurse):
|
def ensure_directory(path, follow, recurse, timestamps):
|
||||||
b_path = to_bytes(path, errors='surrogate_or_strict')
|
b_path = to_bytes(path, errors='surrogate_or_strict')
|
||||||
prev_state = get_state(b_path)
|
prev_state = get_state(b_path)
|
||||||
file_args = module.load_file_common_arguments(module.params)
|
file_args = module.load_file_common_arguments(module.params)
|
||||||
|
mtime = get_timestamp_for_time(timestamps['modification_time'], timestamps['modification_time_format'])
|
||||||
|
atime = get_timestamp_for_time(timestamps['access_time'], timestamps['access_time_format'])
|
||||||
|
|
||||||
# For followed symlinks, we need to operate on the target of the link
|
# For followed symlinks, we need to operate on the target of the link
|
||||||
if follow and prev_state == 'link':
|
if follow and prev_state == 'link':
|
||||||
|
@ -450,6 +548,7 @@ def ensure_directory(path, follow, recurse):
|
||||||
tmp_file_args = file_args.copy()
|
tmp_file_args = file_args.copy()
|
||||||
tmp_file_args['path'] = curpath
|
tmp_file_args['path'] = curpath
|
||||||
changed = module.set_fs_attributes_if_different(tmp_file_args, changed, diff, expand=False)
|
changed = module.set_fs_attributes_if_different(tmp_file_args, changed, diff, expand=False)
|
||||||
|
changed |= update_timestamp_for_file(file_args['path'], mtime, atime, diff)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise AnsibleModuleError(results={'msg': 'There was an issue creating %s as requested:'
|
raise AnsibleModuleError(results={'msg': 'There was an issue creating %s as requested:'
|
||||||
' %s' % (curpath, to_native(e)),
|
' %s' % (curpath, to_native(e)),
|
||||||
|
@ -466,19 +565,20 @@ def ensure_directory(path, follow, recurse):
|
||||||
#
|
#
|
||||||
|
|
||||||
changed = module.set_fs_attributes_if_different(file_args, changed, diff, expand=False)
|
changed = module.set_fs_attributes_if_different(file_args, changed, diff, expand=False)
|
||||||
|
changed |= update_timestamp_for_file(file_args['path'], mtime, atime, diff)
|
||||||
if recurse:
|
if recurse:
|
||||||
changed |= recursive_set_attributes(b_path, follow, file_args)
|
changed |= recursive_set_attributes(b_path, follow, file_args, mtime, atime)
|
||||||
|
|
||||||
return {'path': path, 'changed': changed, 'diff': diff}
|
return {'path': path, 'changed': changed, 'diff': diff}
|
||||||
|
|
||||||
|
|
||||||
def ensure_symlink(path, src, follow, force):
|
def ensure_symlink(path, src, follow, force, timestamps):
|
||||||
b_path = to_bytes(path, errors='surrogate_or_strict')
|
b_path = to_bytes(path, errors='surrogate_or_strict')
|
||||||
b_src = to_bytes(src, errors='surrogate_or_strict')
|
b_src = to_bytes(src, errors='surrogate_or_strict')
|
||||||
prev_state = get_state(b_path)
|
prev_state = get_state(b_path)
|
||||||
file_args = module.load_file_common_arguments(module.params)
|
file_args = module.load_file_common_arguments(module.params)
|
||||||
|
mtime = get_timestamp_for_time(timestamps['modification_time'], timestamps['modification_time_format'])
|
||||||
|
atime = get_timestamp_for_time(timestamps['access_time'], timestamps['access_time_format'])
|
||||||
# source is both the source of a symlink or an informational passing of the src for a template module
|
# source is both the source of a symlink or an informational passing of the src for a template module
|
||||||
# or copy module, even if this module never uses it, it is needed to key off some things
|
# or copy module, even if this module never uses it, it is needed to key off some things
|
||||||
if src is None:
|
if src is None:
|
||||||
|
@ -581,15 +681,18 @@ def ensure_symlink(path, src, follow, force):
|
||||||
' set to False to avoid this.')
|
' set to False to avoid this.')
|
||||||
else:
|
else:
|
||||||
changed = module.set_fs_attributes_if_different(file_args, changed, diff, expand=False)
|
changed = module.set_fs_attributes_if_different(file_args, changed, diff, expand=False)
|
||||||
|
changed |= update_timestamp_for_file(file_args['path'], mtime, atime, diff)
|
||||||
|
|
||||||
return {'dest': path, 'src': src, 'changed': changed, 'diff': diff}
|
return {'dest': path, 'src': src, 'changed': changed, 'diff': diff}
|
||||||
|
|
||||||
|
|
||||||
def ensure_hardlink(path, src, follow, force):
|
def ensure_hardlink(path, src, follow, force, timestamps):
|
||||||
b_path = to_bytes(path, errors='surrogate_or_strict')
|
b_path = to_bytes(path, errors='surrogate_or_strict')
|
||||||
b_src = to_bytes(src, errors='surrogate_or_strict')
|
b_src = to_bytes(src, errors='surrogate_or_strict')
|
||||||
prev_state = get_state(b_path)
|
prev_state = get_state(b_path)
|
||||||
file_args = module.load_file_common_arguments(module.params)
|
file_args = module.load_file_common_arguments(module.params)
|
||||||
|
mtime = get_timestamp_for_time(timestamps['modification_time'], timestamps['modification_time_format'])
|
||||||
|
atime = get_timestamp_for_time(timestamps['access_time'], timestamps['access_time_format'])
|
||||||
|
|
||||||
# src is the source of a hardlink. We require it if we are creating a new hardlink
|
# src is the source of a hardlink. We require it if we are creating a new hardlink
|
||||||
if src is None and not os.path.exists(b_path):
|
if src is None and not os.path.exists(b_path):
|
||||||
|
@ -688,6 +791,7 @@ def ensure_hardlink(path, src, follow, force):
|
||||||
return {'dest': path, 'src': src, 'changed': changed, 'diff': diff}
|
return {'dest': path, 'src': src, 'changed': changed, 'diff': diff}
|
||||||
|
|
||||||
changed = module.set_fs_attributes_if_different(file_args, changed, diff, expand=False)
|
changed = module.set_fs_attributes_if_different(file_args, changed, diff, expand=False)
|
||||||
|
changed |= update_timestamp_for_file(file_args['path'], mtime, atime, diff)
|
||||||
|
|
||||||
return {'dest': path, 'src': src, 'changed': changed, 'diff': diff}
|
return {'dest': path, 'src': src, 'changed': changed, 'diff': diff}
|
||||||
|
|
||||||
|
@ -706,6 +810,10 @@ def main():
|
||||||
follow=dict(required=False, default=True, type='bool'), # Note: Different default than file_common_args
|
follow=dict(required=False, default=True, type='bool'), # Note: Different default than file_common_args
|
||||||
_diff_peek=dict(default=None), # Internal use only, for internal checks in the action plugins
|
_diff_peek=dict(default=None), # Internal use only, for internal checks in the action plugins
|
||||||
src=dict(required=False, default=None, type='path'), # Note: Should not be in file_common_args in future
|
src=dict(required=False, default=None, type='path'), # Note: Should not be in file_common_args in future
|
||||||
|
modification_time=dict(required=False, default=None),
|
||||||
|
modification_time_format=dict(required=False, default='%Y%m%d%H%M.%S'),
|
||||||
|
access_time=dict(required=False, default=None),
|
||||||
|
access_time_format=dict(required=False, default='%Y%m%d%H%M.%S'),
|
||||||
),
|
),
|
||||||
add_file_common_args=True,
|
add_file_common_args=True,
|
||||||
supports_check_mode=True
|
supports_check_mode=True
|
||||||
|
@ -723,21 +831,27 @@ def main():
|
||||||
path = params['path']
|
path = params['path']
|
||||||
src = params['src']
|
src = params['src']
|
||||||
|
|
||||||
|
timestamps = {}
|
||||||
|
timestamps['modification_time'] = keep_backward_compatibility_on_timestamps(params['modification_time'], state)
|
||||||
|
timestamps['modification_time_format'] = params['modification_time_format']
|
||||||
|
timestamps['access_time'] = keep_backward_compatibility_on_timestamps(params['access_time'], state)
|
||||||
|
timestamps['access_time_format'] = params['access_time_format']
|
||||||
|
|
||||||
# short-circuit for diff_peek
|
# short-circuit for diff_peek
|
||||||
if params['_diff_peek'] is not None:
|
if params['_diff_peek'] is not None:
|
||||||
appears_binary = execute_diff_peek(to_bytes(path, errors='surrogate_or_strict'))
|
appears_binary = execute_diff_peek(to_bytes(path, errors='surrogate_or_strict'))
|
||||||
module.exit_json(path=path, changed=False, appears_binary=appears_binary)
|
module.exit_json(path=path, changed=False, appears_binary=appears_binary)
|
||||||
|
|
||||||
if state == 'file':
|
if state == 'file':
|
||||||
result = ensure_file_attributes(path, follow)
|
result = ensure_file_attributes(path, follow, timestamps)
|
||||||
elif state == 'directory':
|
elif state == 'directory':
|
||||||
result = ensure_directory(path, follow, recurse)
|
result = ensure_directory(path, follow, recurse, timestamps)
|
||||||
elif state == 'link':
|
elif state == 'link':
|
||||||
result = ensure_symlink(path, src, follow, force)
|
result = ensure_symlink(path, src, follow, force, timestamps)
|
||||||
elif state == 'hard':
|
elif state == 'hard':
|
||||||
result = ensure_hardlink(path, src, follow, force)
|
result = ensure_hardlink(path, src, follow, force, timestamps)
|
||||||
elif state == 'touch':
|
elif state == 'touch':
|
||||||
result = execute_touch(path, follow)
|
result = execute_touch(path, follow, timestamps)
|
||||||
elif state == 'absent':
|
elif state == 'absent':
|
||||||
result = ensure_absent(path)
|
result = ensure_absent(path)
|
||||||
|
|
||||||
|
|
|
@ -262,6 +262,35 @@
|
||||||
- 'file8_dir_stat["stat"].isdir'
|
- 'file8_dir_stat["stat"].isdir'
|
||||||
- 'file8_dir_stat["stat"]["mtime"] != file8_initial_dir_stat["stat"]["mtime"]'
|
- 'file8_dir_stat["stat"]["mtime"] != file8_initial_dir_stat["stat"]["mtime"]'
|
||||||
|
|
||||||
|
- name: Get initial stat info to compare with later
|
||||||
|
stat:
|
||||||
|
path: '{{ output_dir }}/sub1'
|
||||||
|
follow: False
|
||||||
|
register: file11_initial_dir_stat
|
||||||
|
|
||||||
|
- name: Use touch with directory as dest and keep mtime and atime
|
||||||
|
file:
|
||||||
|
dest: '{{output_dir}}/sub1'
|
||||||
|
state: touch
|
||||||
|
force: False
|
||||||
|
modification_time: preserve
|
||||||
|
access_time: preserve
|
||||||
|
register: file11_result
|
||||||
|
|
||||||
|
- name: Get stat info to show the directory has not been changed
|
||||||
|
stat:
|
||||||
|
path: '{{ output_dir }}/sub1'
|
||||||
|
follow: False
|
||||||
|
register: file11_dir_stat
|
||||||
|
|
||||||
|
- name: verify that the directory has not been updated
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- 'file11_result is not changed'
|
||||||
|
- 'file11_dir_stat["stat"].isdir'
|
||||||
|
- 'file11_dir_stat["stat"]["mtime"] == file11_initial_dir_stat["stat"]["mtime"]'
|
||||||
|
- 'file11_dir_stat["stat"]["atime"] == file11_initial_dir_stat["stat"]["atime"]'
|
||||||
|
|
||||||
#
|
#
|
||||||
# State=directory realizes that the directory already exists and does nothing
|
# State=directory realizes that the directory already exists and does nothing
|
||||||
#
|
#
|
||||||
|
|
|
@ -117,6 +117,24 @@
|
||||||
- name: change ownership and group
|
- name: change ownership and group
|
||||||
file: path={{output_dir}}/baz.txt owner=1234 group=1234
|
file: path={{output_dir}}/baz.txt owner=1234 group=1234
|
||||||
|
|
||||||
|
- name: Get stat info to check atime later
|
||||||
|
stat: path={{output_dir}}/baz.txt
|
||||||
|
register: file_attributes_result_5_before
|
||||||
|
|
||||||
|
- name: updates access time
|
||||||
|
file: path={{output_dir}}/baz.txt access_time=now
|
||||||
|
register: file_attributes_result_5
|
||||||
|
|
||||||
|
- name: Get stat info to check atime later
|
||||||
|
stat: path={{output_dir}}/baz.txt
|
||||||
|
register: file_attributes_result_5_after
|
||||||
|
|
||||||
|
- name: verify that the file was marked as changed and atime changed
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "file_attributes_result_5 is changed"
|
||||||
|
- "file_attributes_result_5_after['stat']['atime'] != file_attributes_result_5_before['stat']['atime']"
|
||||||
|
|
||||||
- name: setup a tmp-like directory for ownership test
|
- name: setup a tmp-like directory for ownership test
|
||||||
file: path=/tmp/worldwritable mode=1777 state=directory
|
file: path=/tmp/worldwritable mode=1777 state=directory
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue