#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright: (c) 2021, Aubin Bikouo <@abikouo> # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function __metaclass__ = type DOCUMENTATION = r""" module: k8s_cp short_description: Copy files and directories to and from pod. version_added: "2.2.0" author: - Aubin Bikouo (@abikouo) description: - Use the Kubernetes Python client to copy files and directories to and from containers inside a pod. extends_documentation_fragment: - kubernetes.core.k8s_auth_options requirements: - "python >= 3.6" - "kubernetes >= 12.0.0" options: namespace: description: - The pod namespace name. type: str required: yes pod: description: - The pod name. type: str required: yes container: description: - The name of the container in the pod to copy files/directories from/to. - Defaults to the only container if there is only one container in the pod. type: str remote_path: description: - Path of the file or directory to copy. type: path required: yes local_path: description: - Path of the local file or directory. - Required when I(state) is set to C(from_pod). - Mutually exclusive with I(content). type: path content: description: - When used instead of I(local_path), sets the contents of a local file directly to the specified value. - Works only when I(remote_path) is a file. Creates the file if it does not exist. - For advanced formatting or if the content contains a variable, use the M(ansible.builtin.template) module. - Mutually exclusive with I(local_path). type: str state: description: - When set to C(to_pod), the local I(local_path) file or directory will be copied to I(remote_path) into the pod. - When set to C(from_pod), the remote file or directory I(remote_path) from pod will be copied locally to I(local_path). type: str default: to_pod choices: [ to_pod, from_pod ] no_preserve: description: - The copied file/directory's ownership and permissions will not be preserved in the container. - This option is ignored when I(content) is set or when I(state) is set to C(from_pod). type: bool default: False notes: - the tar binary is required on the container when copying from local filesystem to pod. """ EXAMPLES = r""" # kubectl cp /tmp/foo some-namespace/some-pod:/tmp/bar - name: Copy /tmp/foo local file to /tmp/bar in a remote pod kubernetes.core.k8s_cp: namespace: some-namespace pod: some-pod remote_path: /tmp/bar local_path: /tmp/foo # kubectl cp /tmp/foo_dir some-namespace/some-pod:/tmp/bar_dir - name: Copy /tmp/foo_dir local directory to /tmp/bar_dir in a remote pod kubernetes.core.k8s_cp: namespace: some-namespace pod: some-pod remote_path: /tmp/bar_dir local_path: /tmp/foo_dir # kubectl cp /tmp/foo some-namespace/some-pod:/tmp/bar -c some-container - name: Copy /tmp/foo local file to /tmp/bar in a remote pod in a specific container kubernetes.core.k8s_cp: namespace: some-namespace pod: some-pod container: some-container remote_path: /tmp/bar local_path: /tmp/foo no_preserve: True state: to_pod # kubectl cp some-namespace/some-pod:/tmp/foo /tmp/bar - name: Copy /tmp/foo from a remote pod to /tmp/bar locally kubernetes.core.k8s_cp: namespace: some-namespace pod: some-pod remote_path: /tmp/foo local_path: /tmp/bar state: from_pod # copy content into a file in the remote pod - name: Copy /tmp/foo from a remote pod to /tmp/bar locally kubernetes.core.k8s_cp: state: to_pod namespace: some-namespace pod: some-pod remote_path: /tmp/foo.txt content: "This content will be copied into remote file" """ RETURN = r""" result: description: - message describing the copy operation successfully done. returned: success type: str """ import copy from ansible_collections.kubernetes.core.plugins.module_utils.ansiblemodule import ( AnsibleModule, ) from ansible_collections.kubernetes.core.plugins.module_utils.k8s.client import ( get_api_client, ) from ansible_collections.kubernetes.core.plugins.module_utils.k8s.core import ( AnsibleK8SModule, ) from ansible_collections.kubernetes.core.plugins.module_utils.k8s.exceptions import ( CoreException, ) from ansible_collections.kubernetes.core.plugins.module_utils.k8s.service import ( K8sService, ) from ansible_collections.kubernetes.core.plugins.module_utils.args_common import ( AUTH_ARG_SPEC, ) from ansible_collections.kubernetes.core.plugins.module_utils.copy import ( K8SCopyFromPod, K8SCopyToPod, check_pod, ) from ansible.module_utils._text import to_native def argspec(): argument_spec = copy.deepcopy(AUTH_ARG_SPEC) argument_spec["namespace"] = {"type": "str", "required": True} argument_spec["pod"] = {"type": "str", "required": True} argument_spec["container"] = {} argument_spec["remote_path"] = {"type": "path", "required": True} argument_spec["local_path"] = {"type": "path"} argument_spec["content"] = {"type": "str"} argument_spec["state"] = { "type": "str", "default": "to_pod", "choices": ["to_pod", "from_pod"], } argument_spec["no_preserve"] = {"type": "bool", "default": False} return argument_spec def execute_module(module): client = get_api_client(module=module) svc = K8sService(client, module) containers = check_pod(svc) if len(containers) > 1 and module.params.get("container") is None: module.fail_json( msg="Pod contains more than 1 container, option 'container' should be set" ) state = module.params.get("state") if state == "to_pod": k8s_copy = K8SCopyToPod(module, client.client) else: k8s_copy = K8SCopyFromPod(module, client.client) try: k8s_copy.run() except Exception as e: module.fail_json("Failed to copy object due to: {0}".format(to_native(e))) def main(): module = AnsibleK8SModule( module_class=AnsibleModule, argument_spec=argspec(), check_pyyaml=False, mutually_exclusive=[("local_path", "content")], required_if=[("state", "from_pod", ["local_path"])], required_one_of=[["local_path", "content"]], supports_check_mode=True, ) try: execute_module(module) except CoreException as e: module.fail_from_exception(e) if __name__ == "__main__": main()