mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-27 07:01:22 -07:00
file - allow touch on files not owned by user (#50964)
* file - allow touch on files not owned by user * use Sentinal value and preserved existing args * Do no instantiate the Sentinel object
This commit is contained in:
parent
8fd0fbe431
commit
419727a6da
3 changed files with 71 additions and 16 deletions
2
changelogs/fragments/file-touch-non-owner.yaml
Normal file
2
changelogs/fragments/file-touch-non-owner.yaml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
bugfixes:
|
||||||
|
- file - Allow state=touch on file the user does not own https://github.com/ansible/ansible/issues/50943
|
|
@ -211,6 +211,11 @@ class ParameterError(AnsibleModuleError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Sentinel(object):
|
||||||
|
def __new__(cls, *args, **kwargs):
|
||||||
|
return cls
|
||||||
|
|
||||||
|
|
||||||
def _ansible_excepthook(exc_type, exc_value, tb):
|
def _ansible_excepthook(exc_type, exc_value, tb):
|
||||||
# Using an exception allows us to catch it if the calling code knows it can recover
|
# Using an exception allows us to catch it if the calling code knows it can recover
|
||||||
if issubclass(exc_type, AnsibleModuleError):
|
if issubclass(exc_type, AnsibleModuleError):
|
||||||
|
@ -349,8 +354,7 @@ def get_timestamp_for_time(formatted_time, time_format):
|
||||||
if formatted_time == 'preserve':
|
if formatted_time == 'preserve':
|
||||||
return None
|
return None
|
||||||
elif formatted_time == 'now':
|
elif formatted_time == 'now':
|
||||||
current_time = time.time()
|
return Sentinel
|
||||||
return current_time
|
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
struct = time.strptime(formatted_time, time_format)
|
struct = time.strptime(formatted_time, time_format)
|
||||||
|
@ -363,25 +367,43 @@ def get_timestamp_for_time(formatted_time, time_format):
|
||||||
|
|
||||||
|
|
||||||
def update_timestamp_for_file(path, mtime, atime, diff=None):
|
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:
|
try:
|
||||||
previous_mtime = os.stat(path).st_mtime
|
# When mtime and atime are set to 'now', rely on utime(path, None) which does not require ownership of the file
|
||||||
previous_atime = os.stat(path).st_atime
|
# https://github.com/ansible/ansible/issues/50943
|
||||||
|
if mtime is Sentinel and atime is Sentinel:
|
||||||
|
# It's not exact but we can't rely on os.stat(path).st_mtime after setting os.utime(path, None) as it may
|
||||||
|
# not be updated. Just use the current time for the diff values
|
||||||
|
mtime = atime = time.time()
|
||||||
|
|
||||||
if mtime is None:
|
previous_mtime = os.stat(path).st_mtime
|
||||||
mtime = previous_mtime
|
previous_atime = os.stat(path).st_atime
|
||||||
|
|
||||||
if atime is None:
|
set_time = None
|
||||||
atime = previous_atime
|
else:
|
||||||
|
# If both parameters are None 'preserve', nothing to do
|
||||||
|
if mtime is None and atime is None:
|
||||||
|
return False
|
||||||
|
|
||||||
# If both timestamps are already ok, nothing to do
|
previous_mtime = os.stat(path).st_mtime
|
||||||
if mtime == previous_mtime and atime == previous_atime:
|
previous_atime = os.stat(path).st_atime
|
||||||
return False
|
|
||||||
|
|
||||||
os.utime(path, (atime, mtime))
|
if mtime is None:
|
||||||
|
mtime = previous_mtime
|
||||||
|
elif mtime is Sentinel:
|
||||||
|
mtime = time.time()
|
||||||
|
|
||||||
|
if atime is None:
|
||||||
|
atime = previous_atime
|
||||||
|
elif atime is Sentinel:
|
||||||
|
atime = time.time()
|
||||||
|
|
||||||
|
# If both timestamps are already ok, nothing to do
|
||||||
|
if mtime == previous_mtime and atime == previous_atime:
|
||||||
|
return False
|
||||||
|
|
||||||
|
set_time = (atime, mtime)
|
||||||
|
|
||||||
|
os.utime(path, set_time)
|
||||||
|
|
||||||
if diff is not None:
|
if diff is not None:
|
||||||
if 'before' not in diff:
|
if 'before' not in diff:
|
||||||
|
|
|
@ -488,6 +488,37 @@
|
||||||
that:
|
that:
|
||||||
- result.mode == '0444'
|
- result.mode == '0444'
|
||||||
|
|
||||||
|
# https://github.com/ansible/ansible/issues/50943
|
||||||
|
# Need to use /tmp as nobody can't access output_dir at all
|
||||||
|
- name: create file as root with all write permissions
|
||||||
|
file: dest=/tmp/write_utime state=touch mode=0666 owner={{ansible_user}}
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: get previous time
|
||||||
|
stat: path=/tmp/write_utime
|
||||||
|
register: previous_time
|
||||||
|
|
||||||
|
- name: touch file as nobody
|
||||||
|
file: dest=/tmp/write_utime state=touch
|
||||||
|
become: True
|
||||||
|
become_user: nobody
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: get new time
|
||||||
|
stat: path=/tmp/write_utime
|
||||||
|
register: current_time
|
||||||
|
|
||||||
|
always:
|
||||||
|
- name: remove test utime file
|
||||||
|
file: path=/tmp/write_utime state=absent
|
||||||
|
|
||||||
|
- name: assert touch file as nobody
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
- current_time.stat.atime > previous_time.stat.atime
|
||||||
|
- current_time.stat.mtime > previous_time.stat.mtime
|
||||||
|
|
||||||
# Follow + recursive tests
|
# Follow + recursive tests
|
||||||
- name: create a toplevel directory
|
- name: create a toplevel directory
|
||||||
file: path={{output_dir}}/test_follow_rec state=directory mode=0755
|
file: path={{output_dir}}/test_follow_rec state=directory mode=0755
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue