o nnhf}@sddlmZdZdZdZddlZddlZddlZddlZddl Zddl Z ddl Z ddl Z ddl Z ddlZddlmZmZddlmZGdd d eZd d Zd d ZddZddZddZddZddZedkroedSdS)) annotationsa  --- module: copy version_added: historical short_description: Copy files to remote locations description: - The M(ansible.builtin.copy) module copies a file or a directory structure from the local or remote machine to a location on the remote machine. File system meta-information (permissions, ownership, etc.) may be set, even when the file or directory already exists on the target system. Some meta-information may be copied on request. - Get meta-information with the M(ansible.builtin.stat) module. - Set meta-information with the M(ansible.builtin.file) module. - Use the M(ansible.builtin.fetch) module to copy files from remote locations to the local box. - If you need variable interpolation in copied files, use the M(ansible.builtin.template) module. Using a variable with the O(content) parameter produces unpredictable results. - For Windows targets, use the M(ansible.windows.win_copy) module instead. options: src: description: - Local path to a file to copy to the remote server. - This can be absolute or relative. - If path is a directory, it is copied recursively. In this case, if path ends with "/", only inside contents of that directory are copied to destination. Otherwise, if it does not end with "/", the directory itself with all contents is copied. This behavior is similar to the C(rsync) command line tool. type: path content: description: - When used instead of O(src), sets the contents of a file directly to the specified value. - Works only when O(dest) is a file. Creates the file if it does not exist. - For advanced formatting or if O(content) contains a variable, use the M(ansible.builtin.template) module. type: str version_added: '1.1' dest: description: - Remote absolute path where the file should be copied to. - If O(src) is a directory, this must be a directory too. - If O(dest) is a non-existent path and if either O(dest) ends with "/" or O(src) is a directory, O(dest) is created. - If O(dest) is a relative path, the starting directory is determined by the remote host. - If O(src) and O(dest) are files, the parent directory of O(dest) is not created and the task fails if it does not already exist. type: path required: yes backup: description: - Create a backup file including the timestamp information so you can get the original file back if you somehow clobbered it incorrectly. type: bool default: no version_added: '0.7' force: description: - Influence whether the remote file must always be replaced. - If V(true), the remote file will be replaced when contents are different than the source. - If V(false), the file will only be transferred if the destination does not exist. type: bool default: yes version_added: '1.1' mode: description: - The permissions of the destination file or directory. - 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 (like V(0644) or V(01777)) or quote it (like V('644') or V('1777')) so Ansible receives a string and can do its own conversion from string into number. Giving Ansible a number without following one of these rules will end up with a decimal number which will have unexpected results. - As of Ansible 1.8, the mode may be specified as a symbolic mode (for example, V(u+rwx) or V(u=rw,g=r,o=r)). - As of Ansible 2.3, the mode may also be the special string V(preserve). - V(preserve) means that the file will be given the same permissions as the source file. - When doing a recursive copy, see also O(directory_mode). - If O(mode) is not specified and the destination file B(does not) exist, the default C(umask) on the system will be used when setting the mode for the newly created file. - If O(mode) is not specified and the destination file B(does) exist, the mode of the existing file will be used. - Specifying O(mode) is the best way to ensure files are created with the correct permissions. See CVE-2020-1736 for further details. directory_mode: description: - Set the access permissions of newly created directories to the given mode. Permissions on existing directories do not change. - See O(mode) for the syntax of accepted values. - The target system's defaults determine permissions when this parameter is not set. type: raw version_added: '1.5' remote_src: description: - Influence whether O(src) needs to be transferred or already is present remotely. - If V(false), it will search for O(src) on the controller node. - If V(true) it will search for O(src) on the managed (remote) node. - O(remote_src) supports recursive copying as of version 2.8. - O(remote_src) only works with O(mode=preserve) as of version 2.6. - Auto-decryption of files does not work when O(remote_src=yes). type: bool default: no version_added: '2.0' follow: description: - This flag indicates that filesystem links in the destination, if they exist, should be followed. type: bool default: no version_added: '1.8' local_follow: description: - This flag indicates that filesystem links in the source tree, if they exist, should be followed. type: bool default: yes version_added: '2.4' checksum: description: - SHA1 checksum of the file being transferred. - Used to validate that the copy of the file was successful. - If this is not provided, ansible will use the local calculated checksum of the src file. type: str version_added: '2.5' extends_documentation_fragment: - decrypt - files - validate - action_common_attributes - action_common_attributes.files - action_common_attributes.flow notes: - The M(ansible.builtin.copy) module recursively copy facility does not scale to lots (>hundreds) of files. seealso: - module: ansible.builtin.assemble - module: ansible.builtin.fetch - module: ansible.builtin.file - module: ansible.builtin.template - module: ansible.posix.synchronize - module: ansible.windows.win_copy author: - Ansible Core Team - Michael DeHaan attributes: action: support: full async: support: none bypass_host_loop: support: none check_mode: support: full diff_mode: support: full platform: platforms: posix safe_file_operations: support: full vault: support: full version_added: '2.2' a - name: Copy file with owner and permissions ansible.builtin.copy: src: /srv/myfiles/foo.conf dest: /etc/foo.conf owner: foo group: foo mode: '0644' - name: Copy file with owner and permission, using symbolic representation ansible.builtin.copy: src: /srv/myfiles/foo.conf dest: /etc/foo.conf owner: foo group: foo mode: u=rw,g=r,o=r - name: Another symbolic mode example, adding some permissions and removing others ansible.builtin.copy: src: /srv/myfiles/foo.conf dest: /etc/foo.conf owner: foo group: foo mode: u+rw,g-wx,o-rwx - name: Copy a new "ntp.conf" file into place, backing up the original if it differs from the copied version ansible.builtin.copy: src: /mine/ntp.conf dest: /etc/ntp.conf owner: root group: root mode: '0644' backup: yes - name: Copy a new "sudoers" file into place, after passing validation with visudo ansible.builtin.copy: src: /mine/sudoers dest: /etc/sudoers validate: /usr/sbin/visudo -csf %s - name: Copy a "sudoers" file on the remote machine for editing ansible.builtin.copy: src: /etc/sudoers dest: /etc/sudoers.edit remote_src: yes validate: /usr/sbin/visudo -csf %s - name: Copy using inline content ansible.builtin.copy: content: '# This file was moved to /etc/other.conf' dest: /etc/mine.conf - name: If follow=yes, /path/to/file will be overwritten by contents of foo.conf ansible.builtin.copy: src: /etc/foo.conf dest: /path/to/link # link to /path/to/file follow: yes - name: If follow=no, /path/to/link will become a file and be overwritten by contents of foo.conf ansible.builtin.copy: src: /etc/foo.conf dest: /path/to/link # link to /path/to/file follow: no a; dest: description: Destination file/path. returned: success type: str sample: /path/to/file.txt src: description: Source file used for the copy on the target machine. returned: changed type: str sample: /home/httpd/.ansible/tmp/ansible-tmp-1423796390.97-147729857856000/source md5sum: description: MD5 checksum of the file after running copy. returned: when supported type: str sample: 2a5aeecc61dc98c4d780b14b330e3282 checksum: description: SHA1 checksum of the file after running copy. returned: success type: str sample: 6e642bb8dd5c2e027bf21dd923337cbb4214f827 backup_file: description: Name of backup file created. returned: changed and if backup=yes type: str sample: /path/to/file.txt.2015-02-12@22:09~ gid: description: Group id of the file, after execution. returned: success type: int sample: 100 group: description: Group of the file, after execution. returned: success type: str sample: httpd owner: description: Owner of the file, after execution. returned: success type: str sample: httpd uid: description: Owner id of the file, after execution. returned: success type: int sample: 100 mode: description: Permissions of the target, after execution. returned: success type: str sample: '0644' size: description: Size of the target, after execution. returned: success type: int sample: 1220 state: description: State of the target, after execution. returned: success type: str sample: file N)to_bytes to_native) AnsibleModulec@seZdZddZdS)AnsibleModuleErrorcCs ||_dS)Nresults)selfrr ?/usr/local/lib/python3.10/dist-packages/ansible/modules/copy.py__init__0s zAnsibleModuleError.__init__N)__name__ __module__ __qualname__r r r r r r/s rcCsztj|\}}t|dd}|dkrd|gfStj|s/|dkr(tddidt|\}}n||gfS||||fS) zi Return the first pre-existing directory and a list of the new directories that will be created. surrogate_or_stricterrors./msgz0The '/' directory doesn't exist on this machine.r)ospathsplitrexistsrsplit_pre_existing_dirappend)dirnameheadtailb_headpre_existing_dirnew_directory_listr r r r4s     rcCs@|rtj||d}||d<|||}t|||||}|S)z] Walk the new directories list and make sure that permissions are as we would expect rr)rrjoinpopset_fs_attributes_if_different&adjust_recursive_directory_permissions)r!r"moduledirectory_argschanged working_dirr r r r&Fs  r&c sd}|jd}|jd}|dur|js^t|D]D\}}||d}|dur*|}fdd|DD]}|||d}|durB|}q3fdd|DD]} || |d}|dur[|}qLqnSt|j} t|D]G\}}tj | k}|dur||}fdd|DD]}t|j | k}|dur|}qfd d|DD]} t| j | k}|dur|}qqi|dur`|jst|D]E\}}| |d} | dur| }fd d|DD]}| ||d} | dur| }qڇfd d|DD]} | | |d} | dur| }qq|St |j } t|D]M\}}tj| k} | dur&| }fd d|DD]}t|j| k} | dur@| }q/fd d|DD]} t| j| k} | dur\| }qKq|S)NFownergroupTcg|] }tj|qSr rrr#.0ddirpathr r ^z#chown_recursive..cr-r r.r0fr2r r r4br5cr-r r.r/r2r r r4lr5cr-r r.r6r2r r r4pr5cr-r r.r/r2r r r4zr5cr-r r.r6r2r r r4~r5cr-r r.r/r2r r r4r5cr-r r.r6r2r r r4r5)params check_moderwalkset_owner_if_differentpwdgetpwnampw_uidstatst_uidset_group_if_differentgrpgetgrnamgr_gidst_gid) rr'r)r+r,dirnames filenames owner_changeddirfileuid group_changedgidr r2r chown_recursiveSs         rNcCsd}|jd}|jd}|jd}t||j}t|rd}|jsz|D]V}tj||} tj||} t | dd} t | dd} tj | rU|durUt | } t | | n t | | t | | |durl|| |d|durw|| |dd}q#|S) zKCopy files that are different between `src` directory and `dest` directory.Fr+r, local_followTrrN)r8filecmpdircmp diff_fileslenr9rrr#rislinkreadlinksymlinkshutilcopyfilecopymoder;rA)srcdestr'r)r+r,rOrRitem src_item_pathdest_item_pathb_src_item_pathb_dest_item_pathlinktor r r copy_diff_filess0        rbcCsd}|jd}|jd}|jd}t||j}t|rd}|js |D]}tj||} tj||} t | dd} t | dd} tj | r^tj | r^|dur^t j | | | dt| |tj | rytj | ry|duryt| } t| | tj | rtj| r|durt | | |d ur|| |d|d ur|| |dtj | rtj| r|durt| } t| | tj | stj| rt | | t | | |d ur|| |d|d ur|| |dtj | s tj | r t j | | | dt| |d}q$|S) zFCopy files that exist in `src` directory only to the `dest` directory.Fr+r,rOTrrsymlinksN)r8rPrQ left_onlyrSr9rrr#rrTisdirrWcopytreerNrUrVisfilerXr;rArY)rZr[r'r)r+r,rOrer\r]r^r_r`rar r r copy_left_onlysP                  ric Csd}t||j}|D]@}tj||}tj||}t|dd}t|dd} t|| |} t|| |} | s7| r9d}t tj||tj|||pJ|}q |S)NFrrT) rPrQ common_dirsrrr#rrbricopy_common_dirs) rZr[r'r)rjr\r]r^r_r`diff_files_changedleft_only_changedr r r rks    &rkc)Cs tttddtddtdddtdddtddd tddd tddtd dtddtddtddtddd d ddd }|jd }t|dd}|jd}tjj|vr\dtjj|}t|dd}|jd}|jd}|jdd}|jdd}|jd} |jd} |jd} |jd} |jd} |jd}|jd}tj |s|j d|dt |tj s|j d|d|jdd krd!t t |j|jd<|jd} d}d}d}d}tj|rz||}Wnttfy}z|d"t|WYd}~nd}~wwz||}WntyYnw|r.tj|s.| d#t||r>||kr>|j d$||d%|tjr|rOtj||}t|dd}tj|}t|dd}tj |szt|\}}Wn(ty}z|jd&d'|7<|j dCi|jWYd}~nd}~ww|j r|j!d(|d|d)t"|d}|#|j}|jd*}|dur||d<nd|d<t$|||||tj|rtj%|}|r|}tj||}t|dd}tj |r,tj&|r | r tj'|}t|dd}|s|j!d+||dd,t |tj r+tj|r+||}nKtj tj|swz t tj|Wn(tyj}zd-t|(vr`|j d.tj|dWYd}~nd}~ww|j d/tj|dt tj|tj)s|jd0s|j d1tj|dd}||kstj&|r|j sz|rtj |r|*|}tj&|rt+|t,|d2-|r| dur|.|| d| dur|/|| d| dur|0|| dd3|vr|j d4|d|1||\}}}|d5kr|j d6|||d7|} |rhtj|rht2j3tj|d8\}!} t45|| zt46|| Wn+tyg}z|j7t7j8kr\| d kr\|d9t|nWYd}~nd}~ww|j9| ||jd0| d:Wnttfy|j d;||ft:;d<Ynwd}|dur2|dur2|r2tj|jd r2t|jd dd}t|jddd}|tjjrtj|jdrt<|||}"t=|||}#t>|||}$t?||}%|"s|#s|$s|%rd}|tjjr;tj |jds;ttj%|dd}&ttj||&dd}ttj|jd d=dd}|j s4t4j@||| d>t?||d}|tjjstj|jdrttj%|dd}&ttj||&dd}ttj|jd d=dd}|j stj |st4j@||| d>d}t?|||j rtj |sd}tj |rt<|||}"t=|||}#t>|||}$t?||}%|"s|#s|$s|%rd}|tjjs2tj |jds2ttj%|jd dd}&ttj||&dd}|j s%tj |s%t"|d}ttj|jd d=dd}t<|||}"t=|||}#t>|||}$t?||}%|j r2tj |s2d}t|||||d?}'|rB||'d@<|j#|j|dA}(|A|(|'dB|'dB<|j!dCi|'dS)DNr)typestrT)rnno_log)rnrequiredboolF)rndefaultraw) rZ_original_basenamecontentr[backupforcevalidatedirectory_mode remote_srcrOchecksumfollow) argument_specadd_file_common_argssupports_check_moderZrrr[z.{0}{1}rwrxruryr}rOmoder+r,r{r|zSource %s not found)rzSource %s not readablepreservez0%03oz5Unable to calculate src checksum, assuming change: %sz+Cannot copy invalid source '%s': not a filezBCopied file does not match the expected checksum. Transfer failed.)rr|expected_checksumrz Could not copy to {0}z"dest directory %s would be created)rr)rZrzzfile already exists)rrZr[r)zpermission deniedz*Destination directory %s is not accessiblez'Destination directory %s does not exist unsafe_writeszDestination %s not writablewz%szvalidate must contain %%s: %srzfailed to validate)r exit_statusstdoutstderr)rIzUnable to copy stats {0})rkeep_dest_attrszfailed to copy: %s to %s)r tracebackrrc)r[rZmd5sumr|r) backup_file)rr)r )Brdictr8rrrsepformatgetr fail_jsonaccessR_OKr?S_IMODEst_moderhsha1OSErrorIOErrorwarnrmd5 ValueErrorrfendswithr#rrrresultrr9 exit_jsonmakedirsload_file_common_argumentsr&basenamerTrealpathlowerW_OK backup_localunlinkopencloseset_mode_if_differentr;rA run_commandtempfilemkstemprWrXcopystaterrnoENOSYS atomic_mover format_excrbrirkrNrgr%))r'rZb_srcr[b_destrwrxruryr}rOrr+r,r{r|r) checksum_dest checksum_src md5sum_srcer b_dirnamer!r"r(rzrrrcouterrb_mysrcdummyrlrmcommon_dirs_changedowner_group_changed b_basenameres_args file_argsr r r mains                                  $         $    $ $     $      r__main__) __future__r DOCUMENTATIONEXAMPLESRETURNrrPrBros.pathr<rWr?rr+ansible.module_utils.common.text.convertersrransible.module_utils.basicr Exceptionrrr&rNrbrirkrr r r r r s: A?  A5{