copy.py (ansible-2.14.0) | : | copy.py (ansible-2.14.1rc1) | ||
---|---|---|---|---|
skipping to change at line 57 | skipping to change at line 57 | |||
required: yes | required: yes | |||
backup: | backup: | |||
description: | description: | |||
- Create a backup file including the timestamp information so you can get th e original file back if you somehow clobbered it incorrectly. | - Create a backup file including the timestamp information so you can get th e original file back if you somehow clobbered it incorrectly. | |||
type: bool | type: bool | |||
default: no | default: no | |||
version_added: '0.7' | version_added: '0.7' | |||
force: | force: | |||
description: | description: | |||
- Influence whether the remote file must always be replaced. | - Influence whether the remote file must always be replaced. | |||
- If C(yes), the remote file will be replaced when contents are different th | - If C(true), the remote file will be replaced when contents are different t | |||
an the source. | han the source. | |||
- If C(no), the file will only be transferred if the destination does not ex | - If C(false), the file will only be transferred if the destination does not | |||
ist. | exist. | |||
type: bool | type: bool | |||
default: yes | default: yes | |||
version_added: '1.1' | version_added: '1.1' | |||
mode: | mode: | |||
description: | description: | |||
- The permissions of the destination file or directory. | - The permissions of the destination file or directory. | |||
- For those used to C(/usr/bin/chmod) remember that modes are actually octal numbers. | - For those used to C(/usr/bin/chmod) remember that modes are actually octal numbers. | |||
You must either add a leading zero so that Ansible's YAML parser knows it is an octal number | You must either add a leading zero so that Ansible's YAML parser knows it is an octal number | |||
(like C(0644) or C(01777)) or quote it (like C('644') or C('1777')) so Ans ible receives a string | (like C(0644) or C(01777)) or quote it (like C('644') or C('1777')) so Ans ible receives a string | |||
and can do its own conversion from string into number. Giving Ansible a nu mber without following | and can do its own conversion from string into number. Giving Ansible a nu mber without following | |||
skipping to change at line 89 | skipping to change at line 89 | |||
directory_mode: | directory_mode: | |||
description: | description: | |||
- When doing a recursive copy set the mode for the directories. | - When doing a recursive copy set the mode for the directories. | |||
- If this is not set we will use the system defaults. | - If this is not set we will use the system defaults. | |||
- The mode is only set on directories which are newly created, and will not affect those that already existed. | - The mode is only set on directories which are newly created, and will not affect those that already existed. | |||
type: raw | type: raw | |||
version_added: '1.5' | version_added: '1.5' | |||
remote_src: | remote_src: | |||
description: | description: | |||
- Influence whether C(src) needs to be transferred or already is present rem otely. | - Influence whether C(src) needs to be transferred or already is present rem otely. | |||
- If C(no), it will search for C(src) on the controller node. | - If C(false), it will search for C(src) on the controller node. | |||
- If C(yes) it will search for C(src) on the managed (remote) node. | - If C(true) it will search for C(src) on the managed (remote) node. | |||
- C(remote_src) supports recursive copying as of version 2.8. | - C(remote_src) supports recursive copying as of version 2.8. | |||
- C(remote_src) only works with C(mode=preserve) as of version 2.6. | - C(remote_src) only works with C(mode=preserve) as of version 2.6. | |||
- Autodecryption of files does not work when C(remote_src=yes). | - Autodecryption of files does not work when C(remote_src=yes). | |||
type: bool | type: bool | |||
default: no | default: no | |||
version_added: '2.0' | version_added: '2.0' | |||
follow: | follow: | |||
description: | description: | |||
- This flag indicates that filesystem links in the destination, if they exis t, should be followed. | - This flag indicates that filesystem links in the destination, if they exis t, should be followed. | |||
type: bool | type: bool | |||
skipping to change at line 568 | skipping to change at line 568 | |||
module.fail_json(msg="Source %s not found" % (src)) | module.fail_json(msg="Source %s not found" % (src)) | |||
if not os.access(b_src, os.R_OK): | if not os.access(b_src, os.R_OK): | |||
module.fail_json(msg="Source %s not readable" % (src)) | module.fail_json(msg="Source %s not readable" % (src)) | |||
# Preserve is usually handled in the action plugin but mode + remote_src has to be done on the | # Preserve is usually handled in the action plugin but mode + remote_src has to be done on the | |||
# remote host | # remote host | |||
if module.params['mode'] == 'preserve': | if module.params['mode'] == 'preserve': | |||
module.params['mode'] = '0%03o' % stat.S_IMODE(os.stat(b_src).st_mode) | module.params['mode'] = '0%03o' % stat.S_IMODE(os.stat(b_src).st_mode) | |||
mode = module.params['mode'] | mode = module.params['mode'] | |||
changed = False | ||||
checksum_dest = None | checksum_dest = None | |||
checksum_src = None | ||||
md5sum_src = None | ||||
if os.path.isfile(src): | if os.path.isfile(src): | |||
checksum_src = module.sha1(src) | try: | |||
else: | checksum_src = module.sha1(src) | |||
checksum_src = None | except (OSError, IOError) as e: | |||
module.warn("Unable to calculate src checksum, assuming change: %s" | ||||
# Backwards compat only. This will be None in FIPS mode | % to_native(e)) | |||
try: | try: | |||
if os.path.isfile(src): | # Backwards compat only. This will be None in FIPS mode | |||
md5sum_src = module.md5(src) | md5sum_src = module.md5(src) | |||
else: | except ValueError: | |||
md5sum_src = None | pass | |||
except ValueError: | elif remote_src and not os.path.isdir(src): | |||
md5sum_src = None | module.fail_json("Cannot copy invalid source '%s': not a file" % to_nati | |||
ve(src)) | ||||
changed = False | ||||
if checksum and checksum_src != checksum: | if checksum and checksum_src != checksum: | |||
module.fail_json( | module.fail_json( | |||
msg='Copied file does not match the expected checksum. Transfer fail ed.', | msg='Copied file does not match the expected checksum. Transfer fail ed.', | |||
checksum=checksum_src, | checksum=checksum_src, | |||
expected_checksum=checksum | expected_checksum=checksum | |||
) | ) | |||
# Special handling for recursive copy - create intermediate dirs | # Special handling for recursive copy - create intermediate dirs | |||
if dest.endswith(os.sep): | if dest.endswith(os.sep): | |||
skipping to change at line 649 | skipping to change at line 650 | |||
except OSError as e: | except OSError as e: | |||
if "permission denied" in to_native(e).lower(): | if "permission denied" in to_native(e).lower(): | |||
module.fail_json(msg="Destination directory %s is not access ible" % (os.path.dirname(dest))) | module.fail_json(msg="Destination directory %s is not access ible" % (os.path.dirname(dest))) | |||
module.fail_json(msg="Destination directory %s does not exist" % (os .path.dirname(dest))) | module.fail_json(msg="Destination directory %s does not exist" % (os .path.dirname(dest))) | |||
if not os.access(os.path.dirname(b_dest), os.W_OK) and not module.params['un safe_writes']: | if not os.access(os.path.dirname(b_dest), os.W_OK) and not module.params['un safe_writes']: | |||
module.fail_json(msg="Destination %s not writable" % (os.path.dirname(de st))) | module.fail_json(msg="Destination %s not writable" % (os.path.dirname(de st))) | |||
backup_file = None | backup_file = None | |||
if checksum_src != checksum_dest or os.path.islink(b_dest): | if checksum_src != checksum_dest or os.path.islink(b_dest): | |||
if not module.check_mode: | if not module.check_mode: | |||
try: | try: | |||
if backup: | if backup: | |||
if os.path.exists(b_dest): | if os.path.exists(b_dest): | |||
backup_file = module.backup_local(dest) | backup_file = module.backup_local(dest) | |||
# allow for conversion from symlink. | # allow for conversion from symlink. | |||
if os.path.islink(b_dest): | if os.path.islink(b_dest): | |||
os.unlink(b_dest) | os.unlink(b_dest) | |||
open(b_dest, 'w').close() | open(b_dest, 'w').close() | |||
if validate: | if validate: | |||
skipping to change at line 672 | skipping to change at line 674 | |||
module.set_mode_if_different(src, mode, False) | module.set_mode_if_different(src, mode, False) | |||
if owner is not None: | if owner is not None: | |||
module.set_owner_if_different(src, owner, False) | module.set_owner_if_different(src, owner, False) | |||
if group is not None: | if group is not None: | |||
module.set_group_if_different(src, group, False) | module.set_group_if_different(src, group, False) | |||
if "%s" not in validate: | if "%s" not in validate: | |||
module.fail_json(msg="validate must contain %%s: %s" % ( validate)) | module.fail_json(msg="validate must contain %%s: %s" % ( validate)) | |||
(rc, out, err) = module.run_command(validate % src) | (rc, out, err) = module.run_command(validate % src) | |||
if rc != 0: | if rc != 0: | |||
module.fail_json(msg="failed to validate", exit_status=r c, stdout=out, stderr=err) | module.fail_json(msg="failed to validate", exit_status=r c, stdout=out, stderr=err) | |||
b_mysrc = b_src | b_mysrc = b_src | |||
if remote_src and os.path.isfile(b_src): | if remote_src and os.path.isfile(b_src): | |||
_, b_mysrc = tempfile.mkstemp(dir=os.path.dirname(b_dest)) | _, b_mysrc = tempfile.mkstemp(dir=os.path.dirname(b_dest)) | |||
shutil.copyfile(b_src, b_mysrc) | shutil.copyfile(b_src, b_mysrc) | |||
try: | try: | |||
shutil.copystat(b_src, b_mysrc) | shutil.copystat(b_src, b_mysrc) | |||
except OSError as err: | except OSError as err: | |||
if err.errno == errno.ENOSYS and mode == "preserve": | if err.errno == errno.ENOSYS and mode == "preserve": | |||
module.warn("Unable to copy stats {0}".format(to_nat ive(b_src))) | module.warn("Unable to copy stats {0}".format(to_nat ive(b_src))) | |||
else: | else: | |||
raise | raise | |||
# might be needed below | # might be needed below | |||
if PY3 and hasattr(os, 'listxattr'): | if PY3 and hasattr(os, 'listxattr'): | |||
try: | try: | |||
src_has_acls = 'system.posix_acl_access' in os.listxattr (src) | src_has_acls = 'system.posix_acl_access' in os.listxattr (src) | |||
except Exception as e: | except Exception as e: | |||
# assume unwanted ACLs by default | # assume unwanted ACLs by default | |||
src_has_acls = True | src_has_acls = True | |||
# at this point we should always have tmp file | ||||
module.atomic_move(b_mysrc, dest, unsafe_writes=module.params['u nsafe_writes']) | module.atomic_move(b_mysrc, dest, unsafe_writes=module.params['u nsafe_writes']) | |||
if PY3 and hasattr(os, 'listxattr') and platform.system() == 'Li nux' and not remote_src: | if PY3 and hasattr(os, 'listxattr') and platform.system() == 'Li nux' and not remote_src: | |||
# atomic_move used above to copy src into dest might, in som e cases, | # atomic_move used above to copy src into dest might, in som e cases, | |||
# use shutil.copy2 which in turn uses shutil.copystat. | # use shutil.copy2 which in turn uses shutil.copystat. | |||
# Since Python 3.3, shutil.copystat copies file extended att ributes: | # Since Python 3.3, shutil.copystat copies file extended att ributes: | |||
# https://docs.python.org/3/library/shutil.html#shutil.copys tat | # https://docs.python.org/3/library/shutil.html#shutil.copys tat | |||
# os.listxattr (along with others) was added to handle the o peration. | # os.listxattr (along with others) was added to handle the o peration. | |||
# This means that on Python 3 we are copying the extended at tributes which includes | # This means that on Python 3 we are copying the extended at tributes which includes | |||
End of changes. 10 change blocks. | ||||
19 lines changed or deleted | 26 lines changed or added |