mirror of
https://github.com/ansible-collections/kubernetes.core.git
synced 2026-05-06 21:12:37 +00:00
k8s_cp - a new module for copying files to/from a Pod (#127)
* k8s_cp module * add documentation for k8s_cp module * add doc for the new module * pods should be running * support for binary, archive and zip file * sanity * Delete file.txt * remove unused * set back * Update collection.txt * Update test_copy_errors.yml * Update plugins/modules/k8s_cp.py Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com> * Update k8s_cp.py * Update k8s_cp.py * tar binary requirements * Update common.py * Update k8s_cp.py * Update k8s_cp.py * replace kind with binary file * Update test_copy_large_file.yml * Update plugins/action/k8s_info.py Co-authored-by: Mike Graves <mgraves@redhat.com> * Update k8s_info.py * Update k8s_info.py * Update k8s_cp.py Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com> Co-authored-by: Mike Graves <mgraves@redhat.com>
This commit is contained in:
@@ -177,6 +177,11 @@
|
||||
tags:
|
||||
- helm
|
||||
|
||||
- role: k8scopy
|
||||
tags:
|
||||
- copy
|
||||
- k8s
|
||||
|
||||
post_tasks:
|
||||
- name: Ensure namespace exists
|
||||
k8s:
|
||||
|
||||
15
molecule/default/roles/k8scopy/defaults/main.yml
Normal file
15
molecule/default/roles/k8scopy/defaults/main.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
# defaults file for k8copy
|
||||
copy_namespace: copy
|
||||
|
||||
pod_with_one_container:
|
||||
name: pod-copy-0
|
||||
container: container-00
|
||||
|
||||
pod_with_two_container:
|
||||
name: pod-copy-1
|
||||
container:
|
||||
- container-10
|
||||
- container-11
|
||||
|
||||
kubectl_path: /tmp/kubectl
|
||||
BIN
molecule/default/roles/k8scopy/files/archive.tar
Normal file
BIN
molecule/default/roles/k8scopy/files/archive.tar
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
||||
kubernetes.core
|
||||
@@ -0,0 +1 @@
|
||||
k8s_cp
|
||||
1
molecule/default/roles/k8scopy/files/data/file.txt
Normal file
1
molecule/default/roles/k8scopy/files/data/file.txt
Normal file
@@ -0,0 +1 @@
|
||||
This is a simple file used to test k8s_cp module on ansible.
|
||||
@@ -0,0 +1,2 @@
|
||||
cloud team
|
||||
content team
|
||||
BIN
molecule/default/roles/k8scopy/files/hello
Executable file
BIN
molecule/default/roles/k8scopy/files/hello
Executable file
Binary file not shown.
1
molecule/default/roles/k8scopy/files/simple_file.txt
Normal file
1
molecule/default/roles/k8scopy/files/simple_file.txt
Normal file
@@ -0,0 +1 @@
|
||||
This content will be copied into remote Pod.
|
||||
BIN
molecule/default/roles/k8scopy/files/simple_zip_file.txt.gz
Normal file
BIN
molecule/default/roles/k8scopy/files/simple_zip_file.txt.gz
Normal file
Binary file not shown.
91
molecule/default/roles/k8scopy/library/k8s_create_file.py
Normal file
91
molecule/default/roles/k8scopy/library/k8s_create_file.py
Normal file
@@ -0,0 +1,91 @@
|
||||
#!/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_diff
|
||||
|
||||
short_description: Create large file with a defined size.
|
||||
|
||||
author:
|
||||
- Aubin Bikouo (@abikouo)
|
||||
|
||||
description:
|
||||
- This module is used to validate k8s_cp module.
|
||||
|
||||
options:
|
||||
path:
|
||||
description:
|
||||
- The destination path for the file to create.
|
||||
type: path
|
||||
required: yes
|
||||
size:
|
||||
description:
|
||||
- The size of the output file in MB.
|
||||
type: int
|
||||
default: 400
|
||||
binary:
|
||||
description:
|
||||
- If this flag is set to yes, the generated file content binary data.
|
||||
type: bool
|
||||
default: False
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: create 150MB file
|
||||
k8s_diff:
|
||||
path: large_file.txt
|
||||
size: 150
|
||||
'''
|
||||
|
||||
|
||||
RETURN = r'''
|
||||
'''
|
||||
|
||||
import os
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
|
||||
def execute_module(module):
|
||||
try:
|
||||
size = module.params.get('size') * 1024 * 1024
|
||||
path = module.params.get('path')
|
||||
write_mode = "w"
|
||||
if module.params.get('binary'):
|
||||
content = os.urandom(size)
|
||||
write_mode = "wb"
|
||||
else:
|
||||
content = ""
|
||||
count = 0
|
||||
while len(content) < size:
|
||||
content += f"This file has been generated using ansible: {count}\n"
|
||||
count += 1
|
||||
|
||||
with open(path, write_mode) as f:
|
||||
f.write(content)
|
||||
module.exit_json(changed=True, size=len(content))
|
||||
except Exception as e:
|
||||
module.fail_json(msg="failed to create file due to: {0}".format(to_native(e)))
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = {}
|
||||
argument_spec['size'] = {'type': 'int', 'default': 400}
|
||||
argument_spec['path'] = {'type': 'path', 'required': True}
|
||||
argument_spec['binary'] = {'type': 'bool', 'default': False}
|
||||
module = AnsibleModule(argument_spec=argument_spec)
|
||||
|
||||
execute_module(module)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
215
molecule/default/roles/k8scopy/library/kubectl_file_compare.py
Normal file
215
molecule/default/roles/k8scopy/library/kubectl_file_compare.py
Normal file
@@ -0,0 +1,215 @@
|
||||
#!/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: kubectl_file_compare
|
||||
|
||||
short_description: Compare file and directory using kubectl
|
||||
|
||||
author:
|
||||
- Aubin Bikouo (@abikouo)
|
||||
|
||||
description:
|
||||
- This module is used to validate k8s_cp module.
|
||||
- Compare the local file/directory with the remote pod version
|
||||
|
||||
notes:
|
||||
- This module authenticates on kubernetes cluster using default kubeconfig only.
|
||||
|
||||
options:
|
||||
namespace:
|
||||
description:
|
||||
- The pod namespace name
|
||||
type: str
|
||||
required: yes
|
||||
pod:
|
||||
description:
|
||||
- The pod name
|
||||
type: str
|
||||
required: yes
|
||||
container:
|
||||
description:
|
||||
- The container to retrieve files from.
|
||||
type: str
|
||||
remote_path:
|
||||
description:
|
||||
- Path of the file or directory on Pod.
|
||||
type: path
|
||||
required: yes
|
||||
local_path:
|
||||
description:
|
||||
- Path of the local file or directory.
|
||||
type: path
|
||||
content:
|
||||
description:
|
||||
- local content to compare with remote file from pod.
|
||||
- mutually exclusive with option I(local_path).
|
||||
type: path
|
||||
required: yes
|
||||
args:
|
||||
description:
|
||||
- The file is considered to be an executable.
|
||||
- The tool will be run locally and on pod and compare result from output and stderr.
|
||||
type: list
|
||||
kubectl_path:
|
||||
description:
|
||||
- Path to the kubectl executable, if not specified it will be download.
|
||||
type: path
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: compare local /tmp/foo with /tmp/bar in a remote pod
|
||||
kubectl_file_compare:
|
||||
namespace: some-namespace
|
||||
pod: some-pod
|
||||
remote_path: /tmp/bar
|
||||
local_path: /tmp/foo
|
||||
kubectl_path: /tmp/test/kubectl
|
||||
|
||||
- name: Compare executable running help command
|
||||
kubectl_file_compare:
|
||||
namespace: some-namespace
|
||||
pod: some-pod
|
||||
remote_path: /tmp/test/kubectl
|
||||
local_path: kubectl
|
||||
kubectl_path: /tmp/test/kubectl
|
||||
args:
|
||||
- "--help"
|
||||
'''
|
||||
|
||||
|
||||
RETURN = r'''
|
||||
'''
|
||||
|
||||
import os
|
||||
import filecmp
|
||||
|
||||
from tempfile import NamedTemporaryFile, TemporaryDirectory
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
def kubectl_get_content(module, dest_dir):
|
||||
kubectl_path = module.params.get('kubectl_path')
|
||||
if kubectl_path is None:
|
||||
kubectl_path = module.get_bin_path('kubectl', required=True)
|
||||
|
||||
namespace = module.params.get('namespace')
|
||||
pod = module.params.get('pod')
|
||||
file = module.params.get('remote_path')
|
||||
|
||||
cmd = [
|
||||
kubectl_path,
|
||||
'cp',
|
||||
"{0}/{1}:{2}".format(namespace, pod, file)
|
||||
]
|
||||
container = module.params.get('container')
|
||||
if container:
|
||||
cmd += ['-c', container]
|
||||
local_file = os.path.join(dest_dir, os.path.basename(module.params.get('remote_path')))
|
||||
cmd.append(local_file)
|
||||
rc, out, err = module.run_command(cmd)
|
||||
return local_file, err, rc, out
|
||||
|
||||
|
||||
def kubectl_run_from_pod(module):
|
||||
kubectl_path = module.params.get('kubectl_path')
|
||||
if kubectl_path is None:
|
||||
kubectl_path = module.get_bin_path('kubectl', required=True)
|
||||
|
||||
cmd = [
|
||||
kubectl_path,
|
||||
'exec',
|
||||
module.params.get('pod'),
|
||||
'-n',
|
||||
module.params.get('namespace')
|
||||
]
|
||||
container = module.params.get('container')
|
||||
if container:
|
||||
cmd += ['-c', container]
|
||||
cmd += ['--', module.params.get('remote_path')]
|
||||
cmd += module.params.get('args')
|
||||
return module.run_command(cmd)
|
||||
|
||||
|
||||
def compare_directories(dir1, dir2):
|
||||
test = filecmp.dircmp(dir1, dir2)
|
||||
if any([len(test.left_only) > 0, len(test.right_only) > 0, len(test.funny_files) > 0]):
|
||||
return False
|
||||
(t, mismatch, errors) = filecmp.cmpfiles(dir1, dir2, test.common_files, shallow=False)
|
||||
if len(mismatch) > 0 or len(errors) > 0:
|
||||
return False
|
||||
for common_dir in test.common_dirs:
|
||||
new_dir1 = os.path.join(dir1, common_dir)
|
||||
new_dir2 = os.path.join(dir2, common_dir)
|
||||
if not compare_directories(new_dir1, new_dir2):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def execute_module(module):
|
||||
|
||||
args = module.params.get('args')
|
||||
local_path = module.params.get('local_path')
|
||||
namespace = module.params.get('namespace')
|
||||
pod = module.params.get('pod')
|
||||
file = module.params.get('remote_path')
|
||||
content = module.params.get('content')
|
||||
if args:
|
||||
pod_rc, pod_out, pod_err = kubectl_run_from_pod(module)
|
||||
rc, out, err = module.run_command([module.params.get('local_path')] + args)
|
||||
if rc == pod_rc and out == pod_out:
|
||||
module.exit_json(msg=f"{local_path} and {namespace}/{pod}:{file} are same.", rc=rc, stderr=err, stdout=out)
|
||||
result = dict(local=dict(rc=rc, out=out, err=err), remote=dict(rc=pod_rc, out=pod_out, err=pod_err))
|
||||
module.fail_json(msg=f"{local_path} and {namespace}/{pod}:{file} are same.", **result)
|
||||
else:
|
||||
with TemporaryDirectory() as tmpdirname:
|
||||
file_from_pod, err, rc, out = kubectl_get_content(module=module, dest_dir=tmpdirname)
|
||||
if not os.path.exists(file_from_pod):
|
||||
module.fail_json(msg="failed to copy content from pod", error=err, output=out)
|
||||
|
||||
if content is not None:
|
||||
with NamedTemporaryFile(mode="w") as tmp_file:
|
||||
tmp_file.write(content)
|
||||
tmp_file.flush()
|
||||
if filecmp.cmp(file_from_pod, tmp_file.name):
|
||||
module.exit_json(msg=f"defined content and {namespace}/{pod}:{file} are same.")
|
||||
module.fail_json(msg=f"defined content and {namespace}/{pod}:{file} are same.")
|
||||
|
||||
if os.path.isfile(local_path):
|
||||
if filecmp.cmp(file_from_pod, local_path):
|
||||
module.exit_json(msg=f"{local_path} and {namespace}/{pod}:{file} are same.")
|
||||
module.fail_json(msg=f"{local_path} and {namespace}/{pod}:{file} are same.")
|
||||
|
||||
if os.path.isdir(local_path):
|
||||
if compare_directories(file_from_pod, local_path):
|
||||
module.exit_json(msg=f"{local_path} and {namespace}/{pod}:{file} are same.")
|
||||
module.fail_json(msg=f"{local_path} and {namespace}/{pod}:{file} are same.")
|
||||
|
||||
|
||||
def main():
|
||||
argument_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['kubectl_path'] = {'type': 'path'}
|
||||
argument_spec['args'] = {'type': 'list'}
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
mutually_exclusive=[('local_path', 'content')],
|
||||
required_one_of=[['local_path', 'content']])
|
||||
|
||||
execute_module(module)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
3
molecule/default/roles/k8scopy/meta/main.yml
Normal file
3
molecule/default/roles/k8scopy/meta/main.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
---
|
||||
collections:
|
||||
- kubernetes.core
|
||||
46
molecule/default/roles/k8scopy/tasks/main.yml
Normal file
46
molecule/default/roles/k8scopy/tasks/main.yml
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
- block:
|
||||
- name: Download kubeclt executable used to compare results
|
||||
get_url:
|
||||
url: https://dl.k8s.io/release/v1.21.3/bin/linux/amd64/kubectl
|
||||
dest: "{{ kubectl_path }}"
|
||||
|
||||
- name: make kubectl executable
|
||||
ansible.builtin.file:
|
||||
path: "{{ kubectl_path }}"
|
||||
mode: "+x"
|
||||
|
||||
# Ensure namespace and create pod to perform tests on
|
||||
- name: Ensure namespace exists
|
||||
k8s:
|
||||
definition:
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: "{{ copy_namespace }}"
|
||||
|
||||
- name: Create Pods
|
||||
k8s:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
wait: yes
|
||||
template: pods_definition.j2
|
||||
|
||||
- include_tasks: test_copy_errors.yml
|
||||
- include_tasks: test_copy_file.yml
|
||||
- include_tasks: test_multi_container_pod.yml
|
||||
- include_tasks: test_copy_directory.yml
|
||||
- include_tasks: test_copy_large_file.yml
|
||||
|
||||
always:
|
||||
- name: Remove kubectl executable
|
||||
ansible.builtin.file:
|
||||
path: "{{ kubectl_path }}"
|
||||
state: absent
|
||||
ignore_errors: true
|
||||
|
||||
- name: Remove namespace
|
||||
k8s:
|
||||
kind: Namespace
|
||||
name: "{{ copy_namespace }}"
|
||||
state: absent
|
||||
ignore_errors: true
|
||||
85
molecule/default/roles/k8scopy/tasks/test_copy_directory.yml
Normal file
85
molecule/default/roles/k8scopy/tasks/test_copy_directory.yml
Normal file
@@ -0,0 +1,85 @@
|
||||
---
|
||||
- block:
|
||||
- name: copy directory into remote Pod (create new directory)
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /dest_data
|
||||
local_path: files/data
|
||||
state: to_pod
|
||||
|
||||
- name: compare directories
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /dest_data
|
||||
local_path: '{{ role_path }}/files/data'
|
||||
kubectl_path: "{{ kubectl_path }}"
|
||||
|
||||
- name: copy directory into remote Pod (existing directory)
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp
|
||||
local_path: files/data
|
||||
state: to_pod
|
||||
|
||||
- name: compare directories
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp/data
|
||||
local_path: '{{ role_path }}/files/data'
|
||||
kubectl_path: "{{ kubectl_path }}"
|
||||
|
||||
- name: copy directory from Pod into local filesystem (new directory to create)
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp/data
|
||||
local_path: /tmp/test
|
||||
state: from_pod
|
||||
|
||||
- name: compare directories
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp/data
|
||||
local_path: /tmp/test
|
||||
kubectl_path: "{{ kubectl_path }}"
|
||||
|
||||
- name: copy directory from Pod into local filesystem (existing directory)
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp/data
|
||||
local_path: /tmp
|
||||
state: from_pod
|
||||
|
||||
- name: compare directories
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp/data
|
||||
local_path: /tmp/data
|
||||
kubectl_path: "{{ kubectl_path }}"
|
||||
|
||||
always:
|
||||
- name: Remove directories created into remote Pod
|
||||
k8s_exec:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
command: 'rm -rf {{ item }}'
|
||||
ignore_errors: true
|
||||
with_items:
|
||||
- /dest_data
|
||||
- /tmp/data
|
||||
|
||||
- name: Remove local directories
|
||||
file:
|
||||
path: '{{ item }}'
|
||||
state: absent
|
||||
ignore_errors: true
|
||||
with_items:
|
||||
- /tmp/data
|
||||
- /tmp/test
|
||||
69
molecule/default/roles/k8scopy/tasks/test_copy_errors.yml
Normal file
69
molecule/default/roles/k8scopy/tasks/test_copy_errors.yml
Normal file
@@ -0,0 +1,69 @@
|
||||
---
|
||||
# copy non-existent local file should fail
|
||||
- name: copy non-existent file into remote Pod
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp
|
||||
local_path: this_file_does_not_exist
|
||||
state: to_pod
|
||||
ignore_errors: true
|
||||
register: copy_non_existent
|
||||
|
||||
- name: check that error message is as expected
|
||||
assert:
|
||||
that:
|
||||
- copy_non_existent is failed
|
||||
- copy_non_existent.msg == "this_file_does_not_exist does not exist in local filesystem"
|
||||
|
||||
# copy non-existent pod file should fail
|
||||
- name: copy of non-existent file from remote pod should fail
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /this_file_does_not_exist
|
||||
local_path: /tmp
|
||||
state: from_pod
|
||||
ignore_errors: true
|
||||
register: copy_non_existent
|
||||
|
||||
- name: check that error message is as expected
|
||||
assert:
|
||||
that:
|
||||
- copy_non_existent is failed
|
||||
- copy_non_existent.msg == "/this_file_does_not_exist does not exist in remote pod filesystem"
|
||||
|
||||
# copy file into multiple container pod without specifying the container should fail
|
||||
- name: copy file into multiple container pod
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_two_container.name }}'
|
||||
remote_path: /tmp
|
||||
local_path: files/simple_file.txt
|
||||
state: to_pod
|
||||
ignore_errors: true
|
||||
register: copy_multi_container
|
||||
|
||||
- name: check that error message is as expected
|
||||
assert:
|
||||
that:
|
||||
- copy_multi_container is failed
|
||||
- copy_multi_container.msg == "Pod contains more than 1 container, option 'container' should be set"
|
||||
|
||||
# copy using non-existent container from pod should failed
|
||||
- name: copy file into multiple container pod
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_two_container.name }}'
|
||||
remote_path: /tmp
|
||||
local_path: files/simple_file.txt
|
||||
state: to_pod
|
||||
container: this_is_a_fake_container
|
||||
ignore_errors: true
|
||||
register: copy_fake_container
|
||||
|
||||
- name: check that error message is as expected
|
||||
assert:
|
||||
that:
|
||||
- copy_fake_container is failed
|
||||
- copy_fake_container.msg == "Pod has no container this_is_a_fake_container"
|
||||
191
molecule/default/roles/k8scopy/tasks/test_copy_file.yml
Normal file
191
molecule/default/roles/k8scopy/tasks/test_copy_file.yml
Normal file
@@ -0,0 +1,191 @@
|
||||
---
|
||||
- block:
|
||||
# Text file
|
||||
- name: copy text file into remote pod
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp
|
||||
local_path: files/simple_file.txt
|
||||
state: to_pod
|
||||
|
||||
- name: Compare files
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp/simple_file.txt
|
||||
content: "{{ lookup('file', 'simple_file.txt')}}"
|
||||
kubectl_path: "{{ kubectl_path }}"
|
||||
|
||||
- name: Copy simple text file from Pod
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp/simple_file.txt
|
||||
local_path: /tmp/copy_from_pod.txt
|
||||
state: from_pod
|
||||
|
||||
- name: Compare files
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp/simple_file.txt
|
||||
local_path: /tmp/copy_from_pod.txt
|
||||
kubectl_path: "{{ kubectl_path }}"
|
||||
|
||||
# Binary file
|
||||
- name: Generate random content
|
||||
set_fact:
|
||||
hello_arg: "{{ lookup('password', '/dev/null chars=ascii_lowercase,digits length=16') }}"
|
||||
|
||||
- name: Copy executable into Pod
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp/hello.exe
|
||||
local_path: files/hello
|
||||
state: to_pod
|
||||
|
||||
- name: Compare executable
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp/hello.exe
|
||||
local_path: "{{ role_path }}/files/hello"
|
||||
kubectl_path: "{{ kubectl_path }}"
|
||||
args:
|
||||
- "{{ hello_arg }}"
|
||||
|
||||
- name: Copy executable from Pod
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp/hello.exe
|
||||
local_path: /tmp/hello
|
||||
state: from_pod
|
||||
|
||||
- name: update executable permission
|
||||
file:
|
||||
path: /tmp/hello
|
||||
mode: '0755'
|
||||
|
||||
- name: Compare executable
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp/hello.exe
|
||||
local_path: /tmp/hello
|
||||
kubectl_path: "{{ kubectl_path }}"
|
||||
args:
|
||||
- "{{ hello_arg }}"
|
||||
|
||||
# zip files
|
||||
- name: copy zip file into remote pod
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp
|
||||
local_path: files/simple_zip_file.txt.gz
|
||||
state: to_pod
|
||||
|
||||
- name: compare zip files
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp/simple_zip_file.txt.gz
|
||||
local_path: '{{ role_path }}/files/simple_zip_file.txt.gz'
|
||||
kubectl_path: "{{ kubectl_path }}"
|
||||
|
||||
- name: copy zip file from pod into local filesystem
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp/simple_zip_file.txt.gz
|
||||
local_path: /tmp/copied_from_pod.txt.gz
|
||||
state: from_pod
|
||||
|
||||
- name: compare zip files
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp/simple_zip_file.txt.gz
|
||||
local_path: /tmp/copied_from_pod.txt.gz
|
||||
kubectl_path: "{{ kubectl_path }}"
|
||||
|
||||
# tar files
|
||||
- name: copy archive into remote pod
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp
|
||||
local_path: files/archive.tar
|
||||
state: to_pod
|
||||
|
||||
- name: compare archive
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp/archive.tar
|
||||
local_path: '{{ role_path }}/files/archive.tar'
|
||||
kubectl_path: "{{ kubectl_path }}"
|
||||
|
||||
- name: copy archive from remote pod into local filesystem
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp/archive.tar
|
||||
local_path: /tmp/local_archive.tar
|
||||
state: from_pod
|
||||
|
||||
- name: compare archive
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /tmp/archive.tar
|
||||
local_path: /tmp/local_archive.tar
|
||||
kubectl_path: "{{ kubectl_path }}"
|
||||
|
||||
# Copy into Pod using content option
|
||||
- name: set content to be copied into Pod
|
||||
set_fact:
|
||||
pod_content: "{{ lookup('password', '/dev/null chars=ascii_lowercase,digits,punctuation length=128') }}"
|
||||
|
||||
- name: copy archive into remote pod
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /this_content.txt
|
||||
content: '{{ pod_content }}'
|
||||
state: to_pod
|
||||
|
||||
- name: Assert that content is as expected into Pod
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /this_content.txt
|
||||
content: '{{ pod_content }}'
|
||||
kubectl_path: "{{ kubectl_path }}"
|
||||
|
||||
always:
|
||||
- name: Delete file created on Pod
|
||||
k8s_exec:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
command: 'rm {{ item }}'
|
||||
ignore_errors: true
|
||||
with_items:
|
||||
- /tmp/simple_file.txt
|
||||
- /tmp/hello.exe
|
||||
- /tmp/simple_zip_file.txt.gz
|
||||
- /tmp/archive.tar
|
||||
- /this_content.txt
|
||||
|
||||
- name: Delete file created locally
|
||||
file:
|
||||
path: '{{ item }}'
|
||||
state: absent
|
||||
with_items:
|
||||
- /tmp/copy_from_pod.txt
|
||||
- /tmp/hello
|
||||
- /tmp/copied_from_pod.txt.gz
|
||||
- /tmp/local_archive.tar
|
||||
103
molecule/default/roles/k8scopy/tasks/test_copy_large_file.yml
Normal file
103
molecule/default/roles/k8scopy/tasks/test_copy_large_file.yml
Normal file
@@ -0,0 +1,103 @@
|
||||
---
|
||||
- name: test copy of large binary and text files
|
||||
block:
|
||||
- set_fact:
|
||||
test_directory: "/tmp/test_k8scp_large_files"
|
||||
no_log: true
|
||||
|
||||
- name: create temporary directory for local files
|
||||
ansible.builtin.file:
|
||||
path: "{{ test_directory }}"
|
||||
state: directory
|
||||
|
||||
- name: create large text file
|
||||
k8s_create_file:
|
||||
path: "{{ test_directory }}/large_text_file.txt"
|
||||
size: 150
|
||||
|
||||
- name: create large binary file
|
||||
k8s_create_file:
|
||||
path: "{{ test_directory }}/large_bin_file.bin"
|
||||
size: 200
|
||||
binary: true
|
||||
|
||||
# Copy large text file from/to local filesystem to Pod
|
||||
- name: copy large file into remote Pod
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /large_text_file.txt
|
||||
local_path: "{{ test_directory }}/large_text_file.txt"
|
||||
state: to_pod
|
||||
|
||||
- name: Compare files
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /large_text_file.txt
|
||||
local_path: "{{ test_directory }}/large_text_file.txt"
|
||||
kubectl_path: "{{ kubectl_path }}"
|
||||
|
||||
- name: copy large file from Pod into local filesystem
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /large_text_file.txt
|
||||
local_path: "{{ test_directory }}/large_text_file_from_pod.txt"
|
||||
state: from_pod
|
||||
|
||||
- name: Compare files
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /large_text_file.txt
|
||||
local_path: "{{ test_directory }}/large_text_file_from_pod.txt"
|
||||
kubectl_path: "{{ kubectl_path }}"
|
||||
|
||||
# Copy large binary file from/to local filesystem to Pod
|
||||
- name: copy large file into remote Pod
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /large_bin_file.bin
|
||||
local_path: "{{ test_directory }}/large_bin_file.bin"
|
||||
state: to_pod
|
||||
|
||||
- name: Compare executable, local vs remote
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /large_bin_file.bin
|
||||
local_path: "{{ test_directory }}/large_bin_file.bin"
|
||||
|
||||
- name: copy executable from pod into local filesystem
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /large_bin_file.bin
|
||||
local_path: "{{ test_directory }}/large_bin_file_from_pod.bin"
|
||||
state: from_pod
|
||||
|
||||
- name: Compare executable, local vs remote
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
remote_path: /large_bin_file.bin
|
||||
local_path: "{{ test_directory }}/large_bin_file_from_pod.bin"
|
||||
|
||||
always:
|
||||
- name: Delete temporary directory created for the test
|
||||
ansible.builtin.file:
|
||||
path: "{{ test_directory }}"
|
||||
state: absent
|
||||
ignore_errors: true
|
||||
|
||||
- name: Delete file created on Pod
|
||||
k8s_exec:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_one_container.name }}'
|
||||
command: 'rm {{ item }}'
|
||||
ignore_errors: true
|
||||
with_items:
|
||||
- /large_text_file.txt
|
||||
- /large_bin_file.bin
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
- set_fact:
|
||||
random_content: "{{ lookup('password', '/dev/null chars=ascii_lowercase,digits,punctuation length=128') }}"
|
||||
|
||||
- name: Copy content into first pod's container
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_two_container.name }}'
|
||||
remote_path: /file_from_localhost.txt
|
||||
content: '{{ random_content }}'
|
||||
container: '{{ pod_with_two_container.container[0] }}'
|
||||
state: to_pod
|
||||
|
||||
- name: Assert that content has been copied into first container
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_two_container.name }}'
|
||||
remote_path: /file_from_localhost.txt
|
||||
container: '{{ pod_with_two_container.container[0] }}'
|
||||
content: '{{ random_content }}'
|
||||
kubectl_path: "{{ kubectl_path }}"
|
||||
|
||||
- name: Assert that content has not been copied into second container
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_two_container.name }}'
|
||||
remote_path: /file_from_localhost.txt
|
||||
container: '{{ pod_with_two_container.container[1] }}'
|
||||
content: '{{ random_content }}'
|
||||
kubectl_path: "{{ kubectl_path }}"
|
||||
register: diff
|
||||
ignore_errors: true
|
||||
|
||||
- name: check that diff failed
|
||||
assert:
|
||||
that:
|
||||
- diff is failed
|
||||
|
||||
- name: Copy content into second's pod container
|
||||
k8s_cp:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_two_container.name }}'
|
||||
remote_path: /file_from_localhost_01.txt
|
||||
content: '{{ random_content }}-secondpod'
|
||||
container: '{{ pod_with_two_container.container[1] }}'
|
||||
state: to_pod
|
||||
|
||||
- name: Assert that content has not been copied into first container
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_two_container.name }}'
|
||||
remote_path: /file_from_localhost_01.txt
|
||||
container: '{{ pod_with_two_container.container[0] }}'
|
||||
content: '{{ random_content }}-secondpod'
|
||||
kubectl_path: "{{ kubectl_path }}"
|
||||
ignore_errors: true
|
||||
register: diff_1
|
||||
|
||||
- name: check that diff failed
|
||||
assert:
|
||||
that:
|
||||
- diff_1 is failed
|
||||
|
||||
- name: Assert that content has been copied into second container
|
||||
kubectl_file_compare:
|
||||
namespace: '{{ copy_namespace }}'
|
||||
pod: '{{ pod_with_two_container.name }}'
|
||||
remote_path: /file_from_localhost_01.txt
|
||||
container: '{{ pod_with_two_container.container[1] }}'
|
||||
content: '{{ random_content }}-secondpod'
|
||||
kubectl_path: "{{ kubectl_path }}"
|
||||
33
molecule/default/roles/k8scopy/templates/pods_definition.j2
Normal file
33
molecule/default/roles/k8scopy/templates/pods_definition.j2
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: '{{ pod_with_one_container.name }}'
|
||||
spec:
|
||||
containers:
|
||||
- name: '{{ pod_with_one_container.container }}'
|
||||
image: busybox
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- while true;do date;sleep 5; done
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: '{{ pod_with_two_container.name }}'
|
||||
spec:
|
||||
containers:
|
||||
- name: '{{ pod_with_two_container.container[0] }}'
|
||||
image: busybox:1.32.0
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- while true;do date;sleep 5; done
|
||||
- name: '{{ pod_with_two_container.container[1] }}'
|
||||
image: busybox:1.33.0
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- while true;do date;sleep 5; done
|
||||
|
||||
Reference in New Issue
Block a user