mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
allow atomic_move to not be atomic ...
just 'cause people build bad systems that insist on not allowing updates in an atomic manner and force us to do them in a very unsafe way that has race conditions and can lead to many issues. if using this option you should really be opening a bug report with the system that only allows for this type of update. and now i shower though i doubt i'll feel clean
This commit is contained in:
parent
f30d5b1d94
commit
70ac47ae61
1 changed files with 20 additions and 4 deletions
|
@ -1668,7 +1668,7 @@ class AnsibleModule(object):
|
|||
e = get_exception()
|
||||
sys.stderr.write("could not cleanup %s: %s" % (tmpfile, e))
|
||||
|
||||
def atomic_move(self, src, dest):
|
||||
def atomic_move(self, src, dest, unsafe_writes=False):
|
||||
'''atomically move src to dest, copying attributes from dest, returns true on success
|
||||
it uses os.rename to ensure this as it is an atomic operation, rest of the function is
|
||||
to work around limitations, corner cases and ensure selinux context is saved if possible'''
|
||||
|
@ -1708,9 +1708,25 @@ class AnsibleModule(object):
|
|||
os.rename(src, dest)
|
||||
except (IOError, OSError):
|
||||
e = get_exception()
|
||||
# sadly there are some situations where we cannot ensure atomicity, but only if
|
||||
# the user insists and we get the appropriate error we update the file unsafely
|
||||
if unsafe_writes and e.errno == errno.EBUSY:
|
||||
#TODO: issue warning that this is an unsafe operation, but doing it cause user insists
|
||||
try:
|
||||
try:
|
||||
out_dest = open(dest, 'wb')
|
||||
in_src = open(src, 'rb')
|
||||
shutil.copyfileobj(in_src, out_dest)
|
||||
finally: # assuring closed files in 2.4 compatible way
|
||||
if out_dest:
|
||||
out_dest.close()
|
||||
if in_src:
|
||||
in_src.close()
|
||||
except (shutil.Error, OSError, IOError), e:
|
||||
self.fail_json(msg='Could not write data to file (%s) from (%s): %s' % (dest, src, e))
|
||||
elif e.errno not in [errno.EPERM, errno.EXDEV, errno.EACCES, errno.ETXTBSY]:
|
||||
# only try workarounds for errno 18 (cross device), 1 (not permitted), 13 (permission denied)
|
||||
# and 26 (text file busy) which happens on vagrant synced folders
|
||||
if e.errno not in [errno.EPERM, errno.EXDEV, errno.EACCES, errno.ETXTBSY]:
|
||||
# and 26 (text file busy) which happens on vagrant synced folders and other 'exotic' non posix file systems
|
||||
self.fail_json(msg='Could not replace file: %s to %s: %s' % (src, dest, e))
|
||||
|
||||
dest_dir = os.path.dirname(dest)
|
||||
|
|
Loading…
Reference in a new issue