diff options
author | jctanner <tanner.jc@gmail.com> | 2017-08-02 10:04:09 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-02 10:04:09 -0400 |
commit | baf1ed9100803b0962554d5bbf30e0e531af9b34 (patch) | |
tree | 7f3398b5fe30fbb9ab551f21775a93aa6b8aa311 /lib/ansible/module_utils | |
parent | b266204afa3722c77bd1d4d816f32b9ed7443685 (diff) | |
download | ansible-baf1ed9100803b0962554d5bbf30e0e531af9b34.tar.gz |
[WIP] Create preserved_copy function in basic.py to perserve file ownership. (#27344)
Create preserved_copy function in basic.py to perserve file ownership.
* Add a test for template preserved backup
* Use a script to get the random names
* bytes to strings
* Remove dump of hostvars
* Stop being fancy and create a testuser instead
* Fix pep8
* set file attributes
* Pass the correct data to set_attributes_if_different
* Use -j instead -b and pass the attributes as a string instead of a list
* remove debugging message
* Use shell to softly set the attr
Fixes #24408
Diffstat (limited to 'lib/ansible/module_utils')
-rw-r--r-- | lib/ansible/module_utils/basic.py | 38 |
1 files changed, 37 insertions, 1 deletions
diff --git a/lib/ansible/module_utils/basic.py b/lib/ansible/module_utils/basic.py index 94aec93974..e4cbc6c8c3 100644 --- a/lib/ansible/module_utils/basic.py +++ b/lib/ansible/module_utils/basic.py @@ -2355,7 +2355,7 @@ class AnsibleModule(object): backupdest = '%s.%s.%s' % (fn, os.getpid(), ext) try: - shutil.copy2(fn, backupdest) + self.preserved_copy(fn, backupdest) except (shutil.Error, IOError): e = get_exception() self.fail_json(msg='Could not make backup of %s to %s: %s' % (fn, backupdest, e)) @@ -2370,6 +2370,42 @@ class AnsibleModule(object): e = get_exception() sys.stderr.write("could not cleanup %s: %s" % (tmpfile, e)) + def preserved_copy(self, src, dest): + """Copy a file with preserved ownership, permissions and context""" + + # shutil.copy2(src, dst) + # Similar to shutil.copy(), but metadata is copied as well - in fact, + # this is just shutil.copy() followed by copystat(). This is similar + # to the Unix command cp -p. + # + # shutil.copystat(src, dst) + # Copy the permission bits, last access time, last modification time, + # and flags from src to dst. The file contents, owner, and group are + # unaffected. src and dst are path names given as strings. + + shutil.copy2(src, dest) + + # Set the context + if self.selinux_enabled(): + context = self.selinux_context(src) + self.set_context_if_different(dest, context, False) + + # chown it + try: + dest_stat = os.stat(src) + tmp_stat = os.stat(dest) + if dest_stat and (tmp_stat.st_uid != dest_stat.st_uid or tmp_stat.st_gid != dest_stat.st_gid): + os.chown(dest, dest_stat.st_uid, dest_stat.st_gid) + except OSError as e: + if e.errno != errno.EPERM: + raise + + # Set the attributes + current_attribs = self.get_file_attributes(src) + current_attribs = current_attribs.get('attr_flags', []) + current_attribs = ''.join(current_attribs) + self.set_attributes_if_different(dest, current_attribs, True) + 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 |