diff --git a/lib/ansible/module_utils/basic.py b/lib/ansible/module_utils/basic.py index 61f68a3965..dda62155ba 100644 --- a/lib/ansible/module_utils/basic.py +++ b/lib/ansible/module_utils/basic.py @@ -1941,7 +1941,7 @@ class AnsibleModule(object): os.rename(b_src, b_dest) except (IOError, OSError): e = get_exception() - if e.errno not in [errno.EPERM, errno.EXDEV, errno.EACCES, errno.ETXTBSY]: + if e.errno not in [errno.EPERM, errno.EXDEV, errno.EACCES, errno.ETXTBSY, errno.EBUSY]: # 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 and other 'exotic' non posix file systems self.fail_json(msg='Could not replace file: %s to %s: %s' % (src, dest, e)) @@ -1983,29 +1983,15 @@ class AnsibleModule(object): e = get_exception() if e.errno != errno.EPERM: raise - os.rename(b_tmp_dest_name, b_dest) + try: + os.rename(b_tmp_dest_name, b_dest) + except (shutil.Error, OSError, IOError): + if unsafe_writes: + self._unsafe_writes(b_tmp_dest_name, b_dest, get_exception()) + else: + self.fail_json(msg='Could not replace file: %s to %s: %s' % (src, dest, exception)) except (shutil.Error, OSError, IOError): - 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(b_dest, 'wb') - in_src = open(b_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 = get_exception() - self.fail_json(msg='Could not write data to file (%s) from (%s): %s' % (dest, src, e)) - - else: - self.fail_json(msg='Could not replace file: %s to %s: %s' % (src, dest, e)) + self.fail_json(msg='Could not replace file: %s to %s: %s' % (src, dest, exception)) finally: self.cleanup(b_tmp_dest_name) @@ -2022,6 +2008,28 @@ class AnsibleModule(object): # rename might not preserve context self.set_context_if_different(dest, context, False) + def _unsafe_writes(self, src, dest, 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 exception.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 = get_exception() + self.fail_json(msg='Could not write data to file (%s) from (%s): %s' % (dest, src, e)) + + else: + self.fail_json(msg='Could not replace file: %s to %s: %s' % (src, dest, exception)) + def run_command(self, args, check_rc=False, close_fds=True, executable=None, data=None, binary_data=False, path_prefix=None, cwd=None, use_unsafe_shell=False, prompt_regex=None, environ_update=None): ''' Execute a command, returns rc, stdout, and stderr.