Move integration test suite from molecule to ansible-test (#392)

Move integration test suite from molecule to ansible-test

SUMMARY

molecule has been replaced with ansible-test
some test cases have been updated

k8s_apply : remove duplicated tasks increasing the running time of the test
helm: use different namespaces for different test cases in order to wait for the namespace deletion before moving to the next test.
all: remove wait: yes at the end of each test when deleting namespace, the role used to create namespace will ensure that it is deleted before if existing.


ISSUE TYPE


Feature Pull Request

COMPONENT NAME

integration testing

Reviewed-by: Mike Graves <mgraves@redhat.com>
Reviewed-by: Gonéri Le Bouder <goneri@lebouder.net>
Reviewed-by: None <None>
This commit is contained in:
abikouo
2022-03-11 09:03:00 +01:00
committed by GitHub
parent db78d3a505
commit fd61f8b15d
199 changed files with 1172 additions and 1835 deletions

6
.gitignore vendored
View File

@@ -15,4 +15,8 @@ tests/integration/cloud-config-*
.cache
# Helm charts
molecule/default/*-chart-*.tgz
tests/integration/*-chart-*.tgz
# ansible-test generated file
tests/integration/inventory
tests/integration/*-*.yml

View File

@@ -22,10 +22,7 @@ test-sanity:
ansible-test sanity --docker -v --color --python $(PYTHON_VERSION) $(?TEST_ARGS)
test-integration:
ansible-test integration --docker -v --color --retry-on-error --python $(PYTHON_VERSION) --continue-on-error --diff --coverage $(?TEST_ARGS)
test-molecule:
molecule test
ansible-test integration --diff --no-temp-workdir --color --skip-tags False --retry-on-error --continue-on-error --python $(PYTHON_VERSION) -v --coverage $(?TEST_ARGS)
test-unit:
ansible-test units --docker -v --color --python $(PYTHON_VERSION) $(?TEST_ARGS)

View File

@@ -1,308 +0,0 @@
---
- name: Converge
hosts: localhost
connection: local
collections:
- kubernetes.core
vars_files:
- vars/main.yml
tasks:
- name: Verify cluster is working.
k8s_info:
namespace: kube-system
kind: Pod
register: pod_list
- name: Verify cluster has more than 5 pods running.
assert:
that: (pod_list.resources | count) > 5
- name: Include access_review.yml
include_tasks:
file: tasks/access_review.yml
apply:
tags: [ access_review, k8s ]
tags:
- always
- name: Include append_hash.yml
include_tasks:
file: tasks/append_hash.yml
apply:
tags: [ append_hash, k8s ]
tags:
- always
- name: Include apply.yml
include_tasks:
file: tasks/apply.yml
apply:
tags: [ apply, k8s ]
tags:
- always
- name: Include cluster_info.yml
include_tasks:
file: tasks/cluster_info.yml
apply:
tags: [ cluster_info, k8s ]
tags:
- always
- name: Include crd.yml
include_tasks:
file: tasks/crd.yml
apply:
tags: [ crd, k8s ]
tags:
- always
- name: Include delete.yml
include_tasks:
file: tasks/delete.yml
apply:
tags: [ delete, k8s ]
tags:
- always
- name: Include exec.yml
include_tasks:
file: tasks/exec.yml
apply:
tags: [ exec, k8s ]
tags:
- always
- name: Include full.yml
include_tasks:
file: tasks/full.yml
apply:
tags: [ full, k8s ]
tags:
- always
- name: Include gc.yml
include_tasks:
file: tasks/gc.yml
apply:
tags: [ gc, k8s ]
tags:
- always
- name: Include info.yml
include_tasks:
file: tasks/info.yml
apply:
tags: [ info, k8s ]
tags:
- always
- name: Include json_patch.yml
include_tasks:
file: tasks/json_patch.yml
apply:
tags: [ json_patch, k8s ]
tags:
- always
- name: Include lists.yml
include_tasks:
file: tasks/lists.yml
apply:
tags: [ lists, k8s ]
tags:
- always
- name: Include log.yml
include_tasks:
file: tasks/log.yml
apply:
tags: [ log, k8s ]
tags:
- always
- name: Include rollback.yml
include_tasks:
file: tasks/rollback.yml
apply:
tags: [ rollback, k8s ]
tags:
- always
- name: Include scale.yml
include_tasks:
file: tasks/scale.yml
apply:
tags: [ scale, k8s ]
tags:
- always
- name: Include template.yml
include_tasks:
file: tasks/template.yml
apply:
tags: [ template, k8s ]
tags:
- always
- name: Include validate.yml
include_tasks:
file: tasks/validate.yml
apply:
tags: [ validate, k8s ]
tags:
- always
- name: Include waiter.yml
include_tasks:
file: tasks/waiter.yml
apply:
tags: [ waiter, k8s ]
tags:
- always
- name: Include merge_type.yml
include_tasks:
file: tasks/merge_type.yml
apply:
tags: [ merge_type, k8s ]
tags:
- always
- name: Include patched.yml
include_tasks:
file: tasks/patched.yml
apply:
tags: [ patched, k8s ]
tags:
- always
- name: Include lookup_k8s.yml
include_tasks:
file: tasks/lookup_k8s.yml
apply:
tags: [ lookup_k8s, k8s ]
tags:
- always
- name: Include label_selectors.yml
include_tasks:
file: tasks/label_selectors.yml
apply:
tags: [ label_selectors, k8s ]
tags:
- always
- name: Include diff.yml
include_tasks:
file: tasks/diff.yml
apply:
tags: [ diff, k8s ]
tags:
- always
- name: Include lookup_kustomize.yml
include_tasks:
file: tasks/lookup_kustomize.yml
apply:
tags: [ lookup_kustomize, k8s ]
tags:
- always
- name: Include generate_name.yml
include_tasks:
file: tasks/generate_name.yml
apply:
tags: [ generate_name, k8s ]
tags:
- always
- name: Include user_impersonation.yml
include_tasks:
file: tasks/user_impersonation.yml
apply:
tags: [ user_impersonation, k8s ]
tags:
- always
roles:
- role: helm
tags:
- helm
- role: k8scopy
tags:
- copy
- k8s
post_tasks:
- name: Ensure namespace exists
k8s:
api_version: v1
kind: Namespace
name: inventory
- name: Add a deployment
k8s:
definition:
apiVersion: apps/v1
kind: Deployment
metadata:
name: inventory
namespace: inventory
spec:
replicas: 1
selector:
matchLabels:
app: "{{ k8s_pod_name }}"
template: "{{ k8s_pod_template }}"
wait: yes
wait_timeout: 120
vars:
k8s_pod_name: inventory
k8s_pod_image: python
k8s_pod_command:
- python
- '-m'
- http.server
k8s_pod_env:
- name: TEST
value: test
- meta: refresh_inventory
- name: Verify inventory and connection plugins
hosts: namespace_inventory_pods
gather_facts: no
vars:
file_content: |
Hello world
tasks:
- name: End play if host not running (TODO should we not add these to the inventory?)
meta: end_host
when: pod_phase != "Running"
- debug: var=hostvars
- setup:
- debug: var=ansible_facts
- name: Assert the TEST environment variable was retrieved
assert:
that: ansible_facts.env.TEST == 'test'
- name: Copy a file into the host
copy:
content: '{{ file_content }}'
dest: /tmp/test_file
- name: Retrieve the file from the host
slurp:
src: /tmp/test_file
register: slurped_file
- name: Assert the file content matches expectations
assert:
that: (slurped_file.content|b64decode) == file_content
- name: Delete inventory namespace
hosts: localhost
connection: local
gather_facts: no
tasks:
- name: Remove inventory namespace
k8s:
api_version: v1
kind: Namespace
name: inventory
state: absent

View File

@@ -1,35 +0,0 @@
---
driver:
name: delegated
options:
managed: false
login_cmd_template: 'docker exec -ti {instance} bash'
ansible_connection_options:
ansible_connection: docker
platforms:
- name: instance-kind
provisioner:
name: ansible
log: true
config_options:
inventory:
enable_plugins: kubernetes.core.k8s,yaml
lint: {}
inventory:
hosts:
plugin: kubernetes.core.k8s
host_vars:
localhost:
ansible_python_interpreter: '{{ ansible_playbook_python }}'
env:
ANSIBLE_FORCE_COLOR: 'true'
options:
vvv: True
scenario:
name: default
test_sequence:
- dependency
- syntax
- prepare
- converge
- verify

View File

@@ -1,16 +0,0 @@
---
- name: Prepare
hosts: localhost
connection: local
collections:
- kubernetes.core
tasks:
- name: Include drain.yml
include_tasks:
file: tasks/drain.yml
- name: Include taint.yml
include_tasks:
file: tasks/taint.yml

View File

@@ -1,217 +0,0 @@
#!/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="{0} and {1}/{2}:{3} are same.".format(
local_path, namespace, pod, file
), 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()

View File

@@ -0,0 +1,8 @@
# slow - 11min
slow
time=313
helm_info
helm_plugin
helm_plugin_info
helm_repository
helm_template

View File

@@ -1,10 +1,6 @@
---
helm_archive_name: "helm-{{ helm_version }}-{{ ansible_system | lower }}-amd64.tar.gz"
helm_binary: "/tmp/helm/{{ ansible_system | lower }}-amd64/helm"
helm_namespace: helm
tiller_namespace: tiller
tiller_cluster_role: cluster-admin
chart_test: "ingress-nginx"
chart_test_local_path: "nginx-ingress"
@@ -17,3 +13,15 @@ chart_test_git_repo: "http://github.com/helm/charts.git"
chart_test_values:
revisionHistoryLimit: 0
myValue: "changed"
test_namespace:
- "helm-diff"
- "helm-envvars"
- "helm-uninstall"
- "helm-not-installed"
- "helm-crd"
- "helm-url"
- "helm-repository"
- "helm-local-path-001"
- "helm-local-path-002"
- "helm-local-path-003"

View File

@@ -1,9 +1,9 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: foos.example.com
name: foos.ansible.com
spec:
group: example.com
group: ansible.com
versions:
- name: v1
served: true

View File

@@ -4,10 +4,11 @@
# Copyright: (c) 2021, Ansible Project
# 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'''
DOCUMENTATION = r"""
---
module: helm_test_version
short_description: check helm executable version
@@ -28,16 +29,16 @@ options:
- version to test against helm binary.
type: str
default: 3.7.0
'''
"""
EXAMPLES = r'''
EXAMPLES = r"""
- name: validate helm binary version is lower than 3.5.0
helm_test_version:
binary_path: path/to/helm
version: "3.5.0"
'''
"""
RETURN = r'''
RETURN = r"""
message:
type: str
description: Text message describing the test result.
@@ -48,10 +49,12 @@ result:
description: Test result.
returned: always
sample: 1
'''
"""
import re
from ansible_collections.kubernetes.core.plugins.module_utils.version import LooseVersion
from ansible_collections.kubernetes.core.plugins.module_utils.version import (
LooseVersion,
)
from ansible.module_utils.basic import AnsibleModule
@@ -59,18 +62,17 @@ from ansible.module_utils.basic import AnsibleModule
def main():
module = AnsibleModule(
argument_spec=dict(
binary_path=dict(type='path'),
version=dict(type='str', default='3.7.0'),
binary_path=dict(type="path"), version=dict(type="str", default="3.7.0"),
),
)
bin_path = module.params.get('binary_path')
version = module.params.get('version')
bin_path = module.params.get("binary_path")
version = module.params.get("version")
if bin_path is not None:
helm_cmd_common = bin_path
else:
helm_cmd_common = 'helm'
helm_cmd_common = "helm"
helm_cmd_common = module.get_bin_path(helm_cmd_common, required=True)
rc, out, err = module.run_command([helm_cmd_common, "version"])
@@ -89,5 +91,5 @@ def main():
module.exit_json(changed=False, result=False, message=message)
if __name__ == '__main__':
if __name__ == "__main__":
main()

View File

@@ -1,3 +1,5 @@
---
collections:
- kubernetes.core
dependencies:
- remove_namespace

View File

@@ -6,7 +6,7 @@
- name: Create namespace
k8s:
kind: Namespace
name: "{{ helm_namespace }}"
name: "{{ test_namespace[4] }}"
- name: Copy test chart
copy:
@@ -17,7 +17,7 @@
helm:
binary_path: "{{ helm_binary }}"
chart_ref: "/tmp/helm_test_crds/{{ test_chart }}"
namespace: "{{ helm_namespace }}"
namespace: "{{ test_namespace[4] }}"
name: test-crds
skip_crds: true
register: install
@@ -30,10 +30,10 @@
- name: Fail to create custom resource
k8s:
definition:
apiVersion: example.com/v1
apiVersion: ansible.com/v1
kind: Foo
metadata:
namespace: "{{ helm_namespace }}"
namespace: "{{ test_namespace[4] }}"
name: test-foo
foobar: footest
ignore_errors: true
@@ -42,13 +42,13 @@
- assert:
that:
- result is failed
- "result.msg.startswith('Failed to find exact match for example.com/v1.Foo')"
- "result.msg.startswith('Failed to find exact match for ansible.com/v1.Foo')"
# Helm won't install CRDs into an existing release, so we need to delete this, first
- name: Uninstall chart
helm:
binary_path: "{{ helm_binary }}"
namespace: "{{ helm_namespace }}"
namespace: "{{ test_namespace[4] }}"
name: test-crds
state: absent
@@ -56,16 +56,16 @@
helm:
binary_path: "{{ helm_binary }}"
chart_ref: "/tmp/helm_test_crds/{{ test_chart }}"
namespace: "{{ helm_namespace }}"
namespace: "{{ test_namespace[4] }}"
name: test-crds
- name: Create custom resource
k8s:
definition:
apiVersion: example.com/v1
apiVersion: ansible.com/v1
kind: Foo
metadata:
namespace: "{{ helm_namespace }}"
namespace: "{{ test_namespace[4] }}"
name: test-foo
foobar: footest
register: result
@@ -85,16 +85,14 @@
- name: Remove namespace
k8s:
kind: Namespace
name: "{{ helm_namespace }}"
name: "{{ test_namespace[4] }}"
state: absent
wait: true
wait_timeout: 180
ignore_errors: true
# CRDs aren't deleted with a namespace, so we need to manually delete it
- name: Remove CRD
k8s:
kind: CustomResourceDefinition
name: foos.example.com
name: foos.ansible.com
state: absent
ignore_errors: true

View File

@@ -4,7 +4,7 @@
binary_path: "{{ helm_binary}}_fake"
name: test
chart_ref: "{{ chart_test }}"
namespace: "{{ helm_namespace }}"
namespace: "{{ test_namespace[3] }}"
ignore_errors: yes
register: helm_missing_binary

View File

@@ -8,6 +8,7 @@
- set_fact:
chart_source: "https://github.com/kubernetes/kube-state-metrics/releases/download/kube-state-metrics-helm-chart-2.13.3/kube-state-metrics-2.13.3.tgz"
chart_name: "test-wait-uninstall"
helm_namespace: "{{ test_namespace[2] }}"
- name: Install chart
helm:
@@ -75,7 +76,5 @@
kind: Namespace
name: "{{ helm_namespace }}"
state: absent
wait: true
wait_timeout: 180
ignore_errors: true
when: test_version.result

View File

@@ -3,7 +3,7 @@
binary_path: "{{ helm_binary }}"
state: absent
name: does-not-exist
namespace: "{{ helm_namespace }}"
namespace: "{{ test_namespace[1] }}"
environment:
K8S_AUTH_HOST: somewhere
register: _helm_result

View File

@@ -1,5 +1,8 @@
---
- name: Chart tests
vars:
chart_release_name: "test-{{ chart_name | default(source) }}"
chart_release_replaced_name: "test-{{ chart_name | default(source) }}-001"
block:
- name: Create temp directory
tempfile:
@@ -13,7 +16,7 @@
- name: Check helm_info empty
helm_info:
binary_path: "{{ helm_binary }}"
name: test
name: "{{ chart_release_name }}"
namespace: "{{ helm_namespace }}"
register: empty_info
@@ -25,7 +28,7 @@
- name: "Install fail {{ chart_test }} from {{ source }}"
helm:
binary_path: "{{ helm_binary }}"
name: test
name: "{{ chart_release_name }}"
chart_ref: "{{ chart_source }}"
chart_version: "{{ chart_source_version | default(omit) }}"
namespace: "{{ helm_namespace }}"
@@ -41,7 +44,7 @@
- name: "Install {{ chart_test }} from {{ source }} in check mode"
helm:
binary_path: "{{ helm_binary }}"
name: test
name: "{{ chart_release_name }}"
chart_ref: "{{ chart_source }}"
chart_version: "{{ chart_source_version | default(omit) }}"
namespace: "{{ helm_namespace }}"
@@ -59,7 +62,7 @@
- name: "Install {{ chart_test }} from {{ source }}"
helm:
binary_path: "{{ helm_binary }}"
name: test
name: "{{ chart_release_name }}"
chart_ref: "{{ chart_source }}"
chart_version: "{{ chart_source_version | default(omit) }}"
namespace: "{{ helm_namespace }}"
@@ -76,14 +79,14 @@
- name: Check helm_info content
helm_info:
binary_path: "{{ helm_binary }}"
name: test
name: "{{ chart_release_name }}"
namespace: "{{ helm_namespace }}"
register: content_info
- name: Check helm_info content using release_state
helm_info:
binary_path: "{{ helm_binary }}"
name: test
name: "{{ chart_release_name }}"
namespace: "{{ helm_namespace }}"
release_state:
- deployed
@@ -99,7 +102,7 @@
- name: Check idempotency
helm:
binary_path: "{{ helm_binary }}"
name: test
name: "{{ chart_release_name }}"
chart_ref: "{{ chart_source }}"
chart_version: "{{ chart_source_version | default(omit) }}"
namespace: "{{ helm_namespace }}"
@@ -115,7 +118,7 @@
- name: "Add vars to {{ chart_test }} from {{ source }}"
helm:
binary_path: "{{ helm_binary }}"
name: test
name: "{{ chart_release_name }}"
chart_ref: "{{ chart_source }}"
chart_version: "{{ chart_source_version | default(omit) }}"
namespace: "{{ helm_namespace }}"
@@ -133,7 +136,7 @@
- name: Check idempotency after adding vars
helm:
binary_path: "{{ helm_binary }}"
name: test
name: "{{ chart_release_name }}"
chart_ref: "{{ chart_source }}"
chart_version: "{{ chart_source_version | default(omit) }}"
namespace: "{{ helm_namespace }}"
@@ -151,7 +154,7 @@
- name: "Remove Vars to {{ chart_test }} from {{ source }}"
helm:
binary_path: "{{ helm_binary }}"
name: test
name: "{{ chart_release_name }}"
chart_ref: "{{ chart_source }}"
chart_version: "{{ chart_source_version | default(omit) }}"
namespace: "{{ helm_namespace }}"
@@ -168,7 +171,7 @@
- name: Check idempotency after removing vars
helm:
binary_path: "{{ helm_binary }}"
name: test
name: "{{ chart_release_name }}"
chart_ref: "{{ chart_source }}"
chart_version: "{{ chart_source_version | default(omit) }}"
namespace: "{{ helm_namespace }}"
@@ -185,7 +188,7 @@
- name: "Upgrade {{ chart_test }} from {{ source }}"
helm:
binary_path: "{{ helm_binary }}"
name: test
name: "{{ chart_release_name }}"
chart_ref: "{{ chart_source_upgrade | default(chart_source) }}"
chart_version: "{{ chart_source_version_upgrade | default(omit) }}"
namespace: "{{ helm_namespace }}"
@@ -201,7 +204,7 @@
- name: Check idempotency after upgrade
helm:
binary_path: "{{ helm_binary }}"
name: test
name: "{{ chart_release_name }}"
chart_ref: "{{ chart_source_upgrade | default(chart_source) }}"
chart_version: "{{ chart_source_version_upgrade | default(omit) }}"
namespace: "{{ helm_namespace }}"
@@ -218,7 +221,7 @@
helm:
binary_path: "{{ helm_binary }}"
state: absent
name: test
name: "{{ chart_release_name }}"
namespace: "{{ helm_namespace }}"
register: install
@@ -231,7 +234,7 @@
helm:
binary_path: "{{ helm_binary }}"
state: absent
name: test
name: "{{ chart_release_name }}"
namespace: "{{ helm_namespace }}"
register: install
@@ -244,7 +247,7 @@
- name: Install chart for replace option
helm:
binary_path: "{{ helm_binary }}"
name: test-0001
name: "{{ chart_release_replaced_name }}"
chart_ref: "{{ chart_source }}"
chart_version: "{{ chart_source_version | default(omit) }}"
namespace: "{{ helm_namespace }}"
@@ -255,11 +258,11 @@
that:
- install is changed
- name: Remove {{ chart_test }} with --purge
- name: "Remove {{ chart_release_replaced_name }} with --purge"
helm:
binary_path: "{{ helm_binary }}"
state: absent
name: test-0001
name: "{{ chart_release_replaced_name }}"
purge: False
namespace: "{{ helm_namespace }}"
register: install
@@ -269,10 +272,10 @@
that:
- install is changed
- name: Install chart again with same name test-0001
- name: "Install chart again with same name {{ chart_release_replaced_name }}"
helm:
binary_path: "{{ helm_binary }}"
name: test-0001
name: "{{ chart_release_replaced_name }}"
chart_ref: "{{ chart_source }}"
chart_version: "{{ chart_source_version | default(omit) }}"
namespace: "{{ helm_namespace }}"
@@ -288,7 +291,7 @@
helm:
binary_path: "{{ helm_binary }}"
state: absent
name: test-0001
name: "{{ chart_release_replaced_name }}"
namespace: "{{ helm_namespace }}"
register: install
@@ -300,7 +303,7 @@
- name: "Install {{ chart_test }} from {{ source }} with values_files"
helm:
binary_path: "{{ helm_binary }}"
name: test
name: "{{ chart_release_name }}"
chart_ref: "{{ chart_source }}"
chart_version: "{{ chart_source_version | default(omit) }}"
namespace: "{{ helm_namespace }}"
@@ -319,7 +322,7 @@
- name: "Install {{ chart_test }} from {{ source }} with values_files (again)"
helm:
binary_path: "{{ helm_binary }}"
name: test
name: "{{ chart_release_name }}"
chart_ref: "{{ chart_source }}"
chart_version: "{{ chart_source_version | default(omit) }}"
namespace: "{{ helm_namespace }}"
@@ -361,7 +364,7 @@
- name: Release using non-existent context
helm:
binary_path: "{{ helm_binary }}"
name: test
name: "{{ chart_release_name }}"
chart_ref: "{{ chart_source }}"
chart_version: "{{ chart_source_version | default(omit) }}"
namespace: "{{ helm_namespace }}"
@@ -389,5 +392,3 @@
kind: Namespace
name: "{{ helm_namespace }}"
state: absent
wait: true
wait_timeout: 180

View File

@@ -22,6 +22,8 @@
chart_source_upgrade: "/tmp/helm_test_repo_upgrade/stable/{{ chart_test_local_path }}/"
chart_test_version: "{{ chart_test_version_local_path }}"
chart_test_version_upgrade: "{{ chart_test_version_upgrade_local_path }}"
chart_name: "local-path-001"
helm_namespace: "{{ test_namespace[7] }}"
- name: Test appVersion idempotence
vars:
@@ -66,6 +68,8 @@
source: local_path
chart_source: "/tmp/helm_test_appversion/test-chart/{{ chart_test }}-{{ chart_test_app_version }}-{{ chart_test_version }}.tgz"
chart_source_upgrade: "/tmp/helm_test_appversion/test-chart/{{ chart_test }}-{{ chart_test_upgrade_app_version }}-{{ chart_test_version_upgrade }}.tgz"
chart_name: "local-path-002"
helm_namespace: "{{ test_namespace[8] }}"
- name: Test appVersion handling when null
vars:
@@ -94,6 +98,8 @@
source: local_path
chart_source: "/tmp/helm_test_appversion/test-null/{{ chart_test }}/"
chart_source_upgrade: "{{ chart_test }}-{{ chart_test_version_upgrade }}.tgz"
chart_name: "local-path-003"
helm_namespace: "{{ test_namespace[9] }}"
- name: Remove clone repos
file:

View File

@@ -12,6 +12,7 @@
chart_source: "test_helm/{{ chart_test }}"
chart_source_version: "{{ chart_test_version }}"
chart_source_version_upgrade: "{{ chart_test_version_upgrade }}"
helm_namespace: "{{ test_namespace[6] }}"
- name: Add chart repo
helm_repository:

View File

@@ -5,3 +5,4 @@
source: url
chart_source: "https://github.com/kubernetes/ingress-nginx/releases/download/{{ chart_test }}-{{ chart_test_version }}/{{ chart_test }}-{{ chart_test_version }}.tgz"
chart_source_upgrade: "https://github.com/kubernetes/ingress-nginx/releases/download/{{ chart_test }}-{{ chart_test_version_upgrade }}/{{ chart_test }}-{{ chart_test_version_upgrade }}.tgz"
helm_namespace: "{{ test_namespace[5] }}"

View File

@@ -4,6 +4,9 @@
test_chart_ref: "/tmp/test-chart"
block:
- set_fact:
helm_namespace: "{{ test_namespace[0] }}"
- name: Install helm diff
helm_plugin:
binary_path: "{{ helm_binary }}"
@@ -254,6 +257,4 @@
kind: Namespace
name: "{{ helm_namespace }}"
state: absent
wait: yes
wait_timeout: 180
ignore_errors: yes

View File

@@ -0,0 +1,3 @@
context/target
time=42
k8s

View File

@@ -0,0 +1,102 @@
---
- name: Converge
hosts: localhost
connection: local
collections:
- kubernetes.core
vars_files:
- vars/main.yml
tasks:
- name: Delete existing namespace
k8s:
api_version: v1
kind: Namespace
name: inventory
wait: yes
state: absent
- name: Ensure namespace exists
k8s:
api_version: v1
kind: Namespace
name: inventory
- name: Add a deployment
k8s:
definition:
apiVersion: apps/v1
kind: Deployment
metadata:
name: inventory
namespace: inventory
spec:
replicas: 1
selector:
matchLabels:
app: "{{ k8s_pod_name }}"
template: "{{ k8s_pod_template }}"
wait: yes
wait_timeout: 400
vars:
k8s_pod_name: inventory
k8s_pod_image: python
k8s_pod_command:
- python
- '-m'
- http.server
k8s_pod_env:
- name: TEST
value: test
- meta: refresh_inventory
- name: Verify inventory and connection plugins
hosts: namespace_inventory_pods
gather_facts: no
vars:
file_content: |
Hello world
tasks:
- name: End play if host not running (TODO should we not add these to the inventory?)
meta: end_host
when: pod_phase != "Running"
- debug: var=hostvars
- setup:
- debug: var=ansible_facts
- name: Assert the TEST environment variable was retrieved
assert:
that: ansible_facts.env.TEST == 'test'
- name: Copy a file into the host
copy:
content: '{{ file_content }}'
dest: /tmp/test_file
- name: Retrieve the file from the host
slurp:
src: /tmp/test_file
register: slurped_file
- name: Assert the file content matches expectations
assert:
that: (slurped_file.content|b64decode) == file_content
- name: Delete inventory namespace
hosts: localhost
connection: local
gather_facts: no
tasks:
- name: Remove inventory namespace
k8s:
api_version: v1
kind: Namespace
name: inventory
state: absent

View File

@@ -0,0 +1,2 @@
---
plugin: kubernetes.core.k8s

View File

@@ -0,0 +1,38 @@
---
k8s_pod_metadata:
labels:
app: "{{ k8s_pod_name }}"
k8s_pod_spec:
serviceAccount: "{{ k8s_pod_service_account }}"
containers:
- image: "{{ k8s_pod_image }}"
imagePullPolicy: Always
name: "{{ k8s_pod_name }}"
command: "{{ k8s_pod_command }}"
readinessProbe:
initialDelaySeconds: 15
exec:
command:
- /bin/true
resources: "{{ k8s_pod_resources }}"
ports: "{{ k8s_pod_ports }}"
env: "{{ k8s_pod_env }}"
k8s_pod_service_account: default
k8s_pod_resources:
limits:
cpu: "100m"
memory: "100Mi"
k8s_pod_command: []
k8s_pod_ports: []
k8s_pod_env: []
k8s_pod_template:
metadata: "{{ k8s_pod_metadata }}"
spec: "{{ k8s_pod_spec }}"

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -eux
export ANSIBLE_INVENTORY_ENABLED=kubernetes.core.k8s,yaml
export ANSIBLE_PYTHON_INTERPRETER=auto_silent
ansible-playbook playbooks/play.yml -i playbooks/test.inventory_k8s.yml "$@"

View File

@@ -0,0 +1,2 @@
time=7
k8s

View File

@@ -0,0 +1,2 @@
time=14
k8s

View File

@@ -0,0 +1,2 @@
---
test_namespace: "append-hash"

View File

@@ -0,0 +1,2 @@
dependencies:
- setup_namespace

View File

@@ -3,14 +3,14 @@
- name: Ensure that append_hash namespace exists
k8s:
kind: Namespace
name: append-hash
name: "{{ test_namespace }}"
- name: Create k8s_resource variable
set_fact:
k8s_resource:
metadata:
name: config-map-test
namespace: append-hash
namespace: "{{ test_namespace }}"
apiVersion: v1
kind: ConfigMap
data:
@@ -46,7 +46,7 @@
definition:
metadata:
name: config-map-test
namespace: append-hash
namespace: "{{ test_namespace }}"
apiVersion: v1
kind: ConfigMap
data:
@@ -65,5 +65,5 @@
- name: Ensure that namespace is removed
k8s:
kind: Namespace
name: append-hash
name: "{{ test_namespace }}"
state: absent

View File

@@ -0,0 +1,5 @@
# duration 9min
slow
k8s_service
k8s
time=192

View File

@@ -37,4 +37,6 @@ k8s_pod_template:
metadata: "{{ k8s_pod_metadata }}"
spec: "{{ k8s_pod_spec }}"
kubernetes_role_path: ../../tests/integration/targets/kubernetes
test_namespace: "apply"
k8s_wait_timeout: 240

View File

@@ -0,0 +1,2 @@
dependencies:
- setup_namespace

View File

@@ -1,20 +1,17 @@
---
- block:
- set_fact:
apply_namespace: apply
- name: Ensure namespace exists
k8s:
definition:
apiVersion: v1
kind: Namespace
metadata:
name: "{{ apply_namespace }}"
name: "{{ test_namespace }}"
- name: Add a configmap
k8s:
name: "apply-configmap"
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
definition:
kind: ConfigMap
apiVersion: v1
@@ -38,7 +35,7 @@
apiVersion: v1
metadata:
name: "apply-configmap"
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
data:
one: "1"
two: "2"
@@ -58,7 +55,7 @@
apiVersion: v1
metadata:
name: "apply-configmap"
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
data:
one: "1"
two: "2"
@@ -75,7 +72,7 @@
- name: Add same configmap again but using name and namespace args
k8s:
name: "apply-configmap"
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
definition:
kind: ConfigMap
apiVersion: v1
@@ -98,7 +95,7 @@
apiVersion: v1
metadata:
name: "apply-configmap"
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
data:
one: "1"
three: "3"
@@ -120,7 +117,7 @@
kind: Service
metadata:
name: apply-svc
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
spec:
selector:
app: whatever
@@ -138,7 +135,7 @@
kind: Service
metadata:
name: apply-svc
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
spec:
selector:
app: whatever
@@ -161,7 +158,7 @@
kind: Service
metadata:
name: apply-svc
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
spec:
selector:
app: whatever
@@ -185,7 +182,7 @@
kind: Service
metadata:
name: apply-svc
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
spec:
selector:
app: whatever
@@ -210,7 +207,7 @@
kind: Service
metadata:
name: apply-svc
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
spec:
selector:
app: whatever
@@ -239,7 +236,7 @@
kind: Service
metadata:
name: apply-svc
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
spec:
selector:
app: whatever
@@ -265,7 +262,7 @@
kind: Service
metadata:
name: apply-svc
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
spec:
selector:
app: whatever
@@ -290,7 +287,7 @@
kind: ServiceAccount
metadata:
name: apply-deploy
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
- name: Add a deployment
k8s:
@@ -299,7 +296,7 @@
kind: Deployment
metadata:
name: apply-deploy
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
spec:
replicas: 1
selector:
@@ -307,6 +304,7 @@
app: "{{ k8s_pod_name }}"
template: "{{ k8s_pod_template }}"
wait: yes
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
apply: yes
vars:
k8s_pod_name: apply-deploy
@@ -331,7 +329,7 @@
kind: Deployment
metadata:
name: apply-deploy
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
spec:
replicas: 1
selector:
@@ -339,6 +337,7 @@
app: "{{ k8s_pod_name }}"
template: "{{ k8s_pod_template }}"
wait: yes
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
apply: yes
check_mode: yes
vars:
@@ -370,7 +369,7 @@
kind: Deployment
metadata:
name: apply-deploy
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
spec:
replicas: 1
selector:
@@ -378,6 +377,7 @@
app: "{{ k8s_pod_name }}"
template: "{{ k8s_pod_template }}"
wait: yes
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
apply: yes
vars:
k8s_pod_name: apply-deploy
@@ -409,7 +409,7 @@
kind: ServiceAccount
metadata:
name: apply-deploy
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
- name: Apply deployment after service account removed
k8s:
@@ -418,7 +418,7 @@
kind: Deployment
metadata:
name: apply-deploy
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
spec:
replicas: 1
selector:
@@ -426,6 +426,7 @@
app: "{{ k8s_pod_name }}"
template: "{{ k8s_pod_template }}"
wait: yes
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
apply: yes
vars:
k8s_pod_name: apply-deploy
@@ -449,318 +450,6 @@
that:
- deploy_after_serviceaccount_removal is failed
- name: Insert new service port
k8s:
definition:
apiVersion: v1
kind: Service
metadata:
name: apply-svc
namespace: "{{ apply_namespace }}"
spec:
selector:
app: whatever
ports:
- name: mesh
port: 8080
targetPort: 8080
- name: http
port: 8081
targetPort: 8081
apply: yes
register: k8s_service_4
- name: Check ports are correct
assert:
that:
- k8s_service_4 is changed
- k8s_service_4.result.spec.ports | length == 2
- k8s_service_4.result.spec.ports[0].port == 8080
- k8s_service_4.result.spec.ports[1].port == 8081
- name: Remove new service port (check mode)
k8s:
definition:
apiVersion: v1
kind: Service
metadata:
name: apply-svc
namespace: "{{ apply_namespace }}"
spec:
selector:
app: whatever
ports:
- name: http
port: 8081
targetPort: 8081
apply: yes
check_mode: yes
register: k8s_service_check
- name: Check ports are correct
assert:
that:
- k8s_service_check is changed
- k8s_service_check.result.spec.ports | length == 1
- k8s_service_check.result.spec.ports[0].port == 8081
- name: Remove new service port
k8s:
definition:
apiVersion: v1
kind: Service
metadata:
name: apply-svc
namespace: "{{ apply_namespace }}"
spec:
selector:
app: whatever
ports:
- name: http
port: 8081
targetPort: 8081
apply: yes
register: k8s_service_5
- name: Check ports are correct
assert:
that:
- k8s_service_5 is changed
- k8s_service_5.result.spec.ports | length == 1
- k8s_service_5.result.spec.ports[0].port == 8081
- name: Add a serviceaccount
k8s:
definition:
apiVersion: v1
kind: ServiceAccount
metadata:
name: apply-deploy
namespace: "{{ apply_namespace }}"
- name: Add a deployment
k8s:
definition:
apiVersion: apps/v1
kind: Deployment
metadata:
name: apply-deploy
namespace: "{{ apply_namespace }}"
spec:
replicas: 1
selector:
matchLabels:
app: "{{ k8s_pod_name }}"
template: "{{ k8s_pod_template }}"
wait: yes
apply: yes
vars:
k8s_pod_name: apply-deploy
k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:v0.10.0-green
k8s_pod_service_account: apply-deploy
k8s_pod_ports:
- containerPort: 8080
name: http
protocol: TCP
- name: Remove the serviceaccount
k8s:
state: absent
definition:
apiVersion: v1
kind: ServiceAccount
metadata:
name: apply-deploy
namespace: "{{ apply_namespace }}"
- name: Update the earlier deployment
k8s:
definition:
apiVersion: apps/v1
kind: Deployment
metadata:
name: apply-deploy
namespace: "{{ apply_namespace }}"
spec:
replicas: 2
selector:
matchLabels:
app: "{{ k8s_pod_name }}"
template: "{{ k8s_pod_template }}"
wait: yes
apply: yes
vars:
k8s_pod_name: apply-deploy
k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:v0.10.0-purple
k8s_pod_service_account: apply-deploy
k8s_pod_ports:
- containerPort: 8080
name: http
protocol: TCP
register: deploy_after_serviceaccount_removal
ignore_errors: yes
- name: Ensure that updating deployment after service account removal failed
assert:
that:
- deploy_after_serviceaccount_removal is failed
- name: Insert new service port
k8s:
definition:
apiVersion: v1
kind: Service
metadata:
name: apply-svc
namespace: "{{ apply_namespace }}"
spec:
selector:
app: whatever
ports:
- name: mesh
port: 8080
targetPort: 8080
- name: http
port: 8081
targetPort: 8081
apply: yes
register: k8s_service_4
- name: Check ports are correct
assert:
that:
- k8s_service_4 is changed
- k8s_service_4.result.spec.ports | length == 2
- k8s_service_4.result.spec.ports[0].port == 8080
- k8s_service_4.result.spec.ports[1].port == 8081
- name: Remove new service port (check mode)
k8s:
definition:
apiVersion: v1
kind: Service
metadata:
name: apply-svc
namespace: "{{ apply_namespace }}"
spec:
selector:
app: whatever
ports:
- name: http
port: 8081
targetPort: 8081
apply: yes
check_mode: yes
register: k8s_service_check
- name: Check ports are correct
assert:
that:
- k8s_service_check is changed
- k8s_service_check.result.spec.ports | length == 1
- k8s_service_check.result.spec.ports[0].port == 8081
- name: Remove new service port
k8s:
definition:
apiVersion: v1
kind: Service
metadata:
name: apply-svc
namespace: "{{ apply_namespace }}"
spec:
selector:
app: whatever
ports:
- name: http
port: 8081
targetPort: 8081
apply: yes
register: k8s_service_5
- name: Check ports are correct
assert:
that:
- k8s_service_5 is changed
- k8s_service_5.result.spec.ports | length == 1
- k8s_service_5.result.spec.ports[0].port == 8081
- name: Add a serviceaccount
k8s:
definition:
apiVersion: v1
kind: ServiceAccount
metadata:
name: apply-deploy
namespace: "{{ apply_namespace }}"
- name: Add a deployment
k8s:
definition:
apiVersion: apps/v1
kind: Deployment
metadata:
name: apply-deploy
namespace: "{{ apply_namespace }}"
spec:
replicas: 1
selector:
matchLabels:
app: "{{ k8s_pod_name }}"
template: "{{ k8s_pod_template }}"
wait: yes
apply: yes
vars:
k8s_pod_name: apply-deploy
k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:v0.10.0-green
k8s_pod_service_account: apply-deploy
k8s_pod_ports:
- containerPort: 8080
name: http
protocol: TCP
- name: Remove the serviceaccount
k8s:
state: absent
definition:
apiVersion: v1
kind: ServiceAccount
metadata:
name: apply-deploy
namespace: "{{ apply_namespace }}"
- name: Update the earlier deployment
k8s:
definition:
apiVersion: apps/v1
kind: Deployment
metadata:
name: apply-deploy
namespace: "{{ apply_namespace }}"
spec:
replicas: 2
selector:
matchLabels:
app: "{{ k8s_pod_name }}"
template: "{{ k8s_pod_template }}"
wait: yes
apply: yes
vars:
k8s_pod_name: apply-deploy
k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:v0.10.0-purple
k8s_pod_service_account: apply-deploy
k8s_pod_ports:
- containerPort: 8080
name: http
protocol: TCP
register: deploy_after_serviceaccount_removal
ignore_errors: yes
- name: Ensure that updating deployment after service account removal failed
assert:
that:
- deploy_after_serviceaccount_removal is failed
- name: Add a secret
k8s:
definition:
@@ -768,7 +457,7 @@
kind: Secret
metadata:
name: apply-secret
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
type: Opaque
stringData:
foo: bar
@@ -787,7 +476,7 @@
kind: Secret
metadata:
name: apply-secret
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
type: Opaque
stringData:
foo: bar
@@ -805,7 +494,7 @@
kind: Secret
metadata:
name: apply-secret
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
type: Opaque
stringData:
foo: bar
@@ -824,7 +513,7 @@
kind: Secret
metadata:
name: apply-secret
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
type: Opaque
data:
foo: YmFy
@@ -838,7 +527,7 @@
- name: Create network policy (egress array with empty dict)
k8s:
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
apply: true
definition:
kind: NetworkPolicy
@@ -865,7 +554,7 @@
- name: Apply network policy
k8s:
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
definition:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
@@ -899,7 +588,7 @@
# Server Side Apply
- name: Create Configmap using server side apply - field_manager not specified
k8s:
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
definition:
apiVersion: v1
kind: ConfigMap
@@ -921,7 +610,7 @@
- name: Create Configmap using server side apply
k8s:
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
definition:
apiVersion: v1
kind: ConfigMap
@@ -943,7 +632,7 @@
- name: Apply ConfigMap using same parameters
k8s:
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
definition:
apiVersion: v1
kind: ConfigMap
@@ -963,7 +652,7 @@
- name: Apply ConfigMap adding new manager
k8s:
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
definition:
apiVersion: v1
kind: ConfigMap
@@ -984,7 +673,7 @@
- name: Apply changes to Configmap using new field_manager
k8s:
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
definition:
apiVersion: v1
kind: ConfigMap
@@ -1006,7 +695,7 @@
- name: Apply changes to Configmap using new field_manager and force_conflicts
k8s:
namespace: "{{ apply_namespace }}"
namespace: "{{ test_namespace }}"
definition:
apiVersion: v1
kind: ConfigMap
@@ -1028,10 +717,9 @@
- result.result.metadata.managedFields[0].manager == 'manager-02'
- result.result.data.key == 'value-1'
always:
- name: Remove namespace
k8s:
kind: Namespace
name: "{{ apply_namespace }}"
name: "{{ test_namespace }}"
state: absent

View File

@@ -0,0 +1,2 @@
k8s_cluster_info
time=9

View File

@@ -0,0 +1,4 @@
k8s_exec
k8s_cp
k8s
time=101

View File

@@ -1,6 +1,6 @@
---
# defaults file for k8copy
copy_namespace: copy
test_namespace: copy
pod_with_one_container:
name: pod-copy-0

View File

@@ -8,9 +8,9 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = r'''
DOCUMENTATION = r"""
module: k8s_diff
module: k8s_create_file
short_description: Create large file with a defined size.
@@ -36,18 +36,18 @@ options:
- If this flag is set to yes, the generated file content binary data.
type: bool
default: False
'''
"""
EXAMPLES = r'''
EXAMPLES = r"""
- name: create 150MB file
k8s_diff:
path: large_file.txt
size: 150
'''
"""
RETURN = r'''
'''
RETURN = r"""
"""
import os
@@ -57,17 +57,19 @@ 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')
size = module.params.get("size") * 1024 * 1024
path = module.params.get("path")
write_mode = "w"
if module.params.get('binary'):
if module.params.get("binary"):
content = os.urandom(size)
write_mode = "wb"
else:
content = ""
count = 0
while len(content) < size:
content += "This file has been generated using ansible: {0}\n".format(count)
content += "This file has been generated using ansible: {0}\n".format(
count
)
count += 1
with open(path, write_mode) as f:
@@ -79,13 +81,13 @@ def execute_module(module):
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}
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__':
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,247 @@
#!/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="{0} and {1}/{2}:{3} are same.".format(
local_path, namespace, pod, file
),
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()

View File

@@ -1,3 +1,5 @@
---
collections:
- kubernetes.core
dependencies:
- setup_namespace

View File

@@ -1,4 +1,7 @@
---
- set_fact:
copy_namespace: "{{ test_namespace }}"
- block:
# Ensure namespace and create pod to perform tests on
- name: Ensure namespace exists

View File

@@ -0,0 +1,2 @@
time=22
k8s

View File

@@ -0,0 +1,2 @@
---
test_namespace: "crd"

View File

@@ -0,0 +1,3 @@
---
dependencies:
- setup_namespace

View File

@@ -1,13 +1,8 @@
---
- block:
- name: Create a namespace
k8s:
name: crd
kind: Namespace
- name: Install custom resource definitions
k8s:
definition: "{{ lookup('file', kubernetes_role_path + '/files/setup-crd.yml') }}"
definition: "{{ lookup('file', 'setup-crd.yml') }}"
- name: Pause 5 seconds to avoid race condition
pause:
@@ -15,15 +10,15 @@
- name: Create custom resource definition
k8s:
definition: "{{ lookup('file', kubernetes_role_path + '/files/crd-resource.yml') }}"
namespace: crd
definition: "{{ lookup('file', 'crd-resource.yml') }}"
namespace: "{{ test_namespace }}"
apply: "{{ create_crd_with_apply | default(omit) }}"
register: create_crd
- name: Patch custom resource definition
k8s:
definition: "{{ lookup('file', kubernetes_role_path + '/files/crd-resource.yml') }}"
namespace: crd
definition: "{{ lookup('file', 'crd-resource.yml') }}"
namespace: "{{ test_namespace }}"
register: recreate_crd
ignore_errors: yes
@@ -35,33 +30,32 @@
- block:
- name: Recreate custom resource definition with merge_type
k8s:
definition: "{{ lookup('file', kubernetes_role_path + '/files/crd-resource.yml') }}"
definition: "{{ lookup('file', 'crd-resource.yml') }}"
merge_type:
- merge
namespace: crd
namespace: "{{ test_namespace }}"
register: recreate_crd_with_merge
- name: Recreate custom resource definition with merge_type list
k8s:
definition: "{{ lookup('file', kubernetes_role_path + '/files/crd-resource.yml') }}"
definition: "{{ lookup('file', 'crd-resource.yml') }}"
merge_type:
- strategic-merge
- merge
namespace: crd
namespace: "{{ test_namespace }}"
register: recreate_crd_with_merge_list
when: recreate_crd is successful
- name: Remove crd
k8s:
definition: "{{ lookup('file', kubernetes_role_path + '/files/crd-resource.yml') }}"
namespace: crd
definition: "{{ lookup('file', 'crd-resource.yml') }}"
namespace: "{{ test_namespace }}"
state: absent
always:
- name: Remove crd namespace
k8s:
kind: Namespace
name: crd
name: "{{ test_namespace }}"
state: absent
ignore_errors: yes

View File

@@ -0,0 +1,3 @@
time=70
k8s_info
k8s

View File

@@ -0,0 +1,25 @@
---
k8s_pod_template:
metadata:
labels:
app: "{{ k8s_pod_name }}"
spec:
serviceAccount: "default"
containers:
- image: "{{ k8s_pod_image }}"
imagePullPolicy: Always
name: "{{ k8s_pod_name }}"
command: []
readinessProbe:
initialDelaySeconds: 15
exec:
command:
- /bin/true
resources:
limits:
cpu: "100m"
memory: "100Mi"
ports: []
env: []
test_namespace: "delete"

View File

@@ -0,0 +1,3 @@
---
dependencies:
- setup_namespace

View File

@@ -1,16 +1,5 @@
---
- block:
- set_fact:
delete_namespace: delete
- name: Ensure namespace exists
k8s:
definition:
apiVersion: v1
kind: Namespace
metadata:
name: "{{ delete_namespace }}"
- name: Add a daemonset
k8s:
definition:
@@ -18,14 +7,14 @@
kind: DaemonSet
metadata:
name: delete-daemonset
namespace: "{{ delete_namespace }}"
namespace: "{{ test_namespace }}"
spec:
selector:
matchLabels:
app: "{{ k8s_pod_name }}"
template: "{{ k8s_pod_template }}"
wait: yes
wait_timeout: 180
wait_timeout: 400
vars:
k8s_pod_name: delete-ds
k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:1
@@ -38,7 +27,7 @@
- name: Check if pods exist
k8s_info:
namespace: "{{ delete_namespace }}"
namespace: "{{ test_namespace }}"
kind: Pod
label_selectors:
- "app={{ k8s_pod_name }}"
@@ -55,13 +44,13 @@
k8s:
kind: DaemonSet
name: delete-daemonset
namespace: "{{ delete_namespace }}"
namespace: "{{ test_namespace }}"
state: absent
wait: yes
- name: Show status of pods
k8s_info:
namespace: "{{ delete_namespace }}"
namespace: "{{ test_namespace }}"
kind: Pod
label_selectors:
- "app={{ k8s_pod_name }}"
@@ -74,7 +63,7 @@
- name: Check if pods still exist
k8s_info:
namespace: "{{ delete_namespace }}"
namespace: "{{ test_namespace }}"
kind: Pod
label_selectors:
- "app={{ k8s_pod_name }}"
@@ -91,5 +80,5 @@
- name: Remove namespace
k8s:
kind: Namespace
name: "{{ delete_namespace }}"
name: "{{ test_namespace }}"
state: absent

View File

@@ -0,0 +1,2 @@
time=20
k8s

View File

@@ -0,0 +1,3 @@
---
test_namespace: "diff"
diff_configmap: "diff-configmap"

View File

@@ -0,0 +1,2 @@
dependencies:
- setup_namespace

View File

@@ -1,20 +1,14 @@
---
- set_fact:
diff_namespace: "diff"
diff_configmap: "diff-configmap"
- block:
- name: Ensure namespace
k8s:
kind: Namespace
name: '{{ diff_namespace }}'
- set_fact:
diff_namespace: "{{ test_namespace }}"
# Using option 'apply' set to 'yes'
- name: Create Pod using apply and diff set to yes
k8s:
namespace: '{{ diff_namespace }}'
apply: yes
template: "pod_diff.j2"
template: "pod.j2"
diff: yes
vars:
pod_name: "pod-apply"
@@ -31,7 +25,7 @@
k8s:
namespace: '{{ diff_namespace }}'
apply: yes
template: "pod_diff.j2"
template: "pod.j2"
diff: no
vars:
pod_name: "pod-apply"
@@ -49,7 +43,7 @@
k8s:
namespace: '{{ diff_namespace }}'
state: present
template: "pod_diff.j2"
template: "pod.j2"
vars:
pod_name: "pod-patch"
pod_image: "busybox:1.32.0"
@@ -59,7 +53,7 @@
k8s:
namespace: '{{ diff_namespace }}'
state: patched
template: "pod_diff.j2"
template: "pod.j2"
diff: no
vars:
pod_name: "pod-patch"
@@ -77,7 +71,7 @@
k8s:
namespace: '{{ diff_namespace }}'
state: patched
template: "pod_diff.j2"
template: "pod.j2"
diff: yes
vars:
pod_name: "pod-patch"
@@ -151,3 +145,4 @@
state: absent
kind: Namespace
name: '{{ diff_namespace }}'
ignore_errors: true

View File

@@ -0,0 +1,4 @@
k8s_drain
k8s
k8s_info
time=78

View File

@@ -0,0 +1,3 @@
---
test_namespace: "drain"
k8s_wait_timeout: 400

View File

@@ -0,0 +1,3 @@
---
dependencies:
- setup_namespace

View File

@@ -2,16 +2,10 @@
- block:
- name: Set common facts
set_fact:
drain_namespace: "drain"
drain_daemonset_name: "promotheus-dset"
drain_pod_name: "pod-drain"
drain_deployment_emptydir_name: "deployment-emptydir-drain"
- name: Create {{ drain_namespace }} namespace
k8s:
kind: Namespace
name: '{{ drain_namespace }}'
# It seems that the default ServiceAccount can take a bit to be created
# right after a cluster is brought up. This can lead to the ServiceAccount
# admission controller rejecting a Pod creation request because the
@@ -20,7 +14,7 @@
k8s_info:
kind: ServiceAccount
name: default
namespace: "{{ drain_namespace }}"
namespace: "{{ test_namespace }}"
wait: yes
- name: list cluster nodes
@@ -43,7 +37,7 @@
- name: Deploy daemonset on cluster
k8s:
namespace: '{{ drain_namespace }}'
namespace: '{{ test_namespace }}'
definition:
apiVersion: apps/v1
kind: DaemonSet
@@ -75,8 +69,9 @@
- name: Create Pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet.
k8s:
namespace: '{{ drain_namespace }}'
namespace: '{{ test_namespace }}'
wait: yes
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
definition:
apiVersion: v1
kind: Pod
@@ -102,8 +97,9 @@
- name: Create Deployment with an emptyDir volume.
k8s:
namespace: '{{ drain_namespace }}'
namespace: '{{ test_namespace }}'
wait: yes
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
definition:
apiVersion: apps/v1
kind: Deployment
@@ -147,7 +143,7 @@
- name: Register emptyDir Pod name
k8s_info:
namespace: '{{ drain_namespace }}'
namespace: '{{ test_namespace }}'
kind: Pod
label_selectors:
- "drain = emptyDir"
@@ -180,7 +176,7 @@
- name: Get pods
k8s_info:
kind: Pod
namespace: '{{ drain_namespace }}'
namespace: '{{ test_namespace }}'
register: Pod
- name: assert that pods are running on cordoned node
@@ -244,7 +240,7 @@
- name: assert that unmanaged pod were deleted
k8s_info:
namespace: '{{ drain_namespace }}'
namespace: '{{ test_namespace }}'
kind: Pod
name: '{{ drain_pod_name }}'
register: _result
@@ -252,7 +248,7 @@
- name: assert that emptyDir pod was deleted
k8s_info:
namespace: '{{ drain_namespace }}'
namespace: '{{ test_namespace }}'
kind: Pod
name: "{{ emptydir_pod_result.resources[0].metadata.name }}"
register: _result
@@ -276,7 +272,7 @@
- name: Get DaemonSet
k8s_info:
kind: DaemonSet
namespace: '{{ drain_namespace }}'
namespace: '{{ test_namespace }}'
name: '{{ drain_daemonset_name }}'
register: dset_result
@@ -302,4 +298,4 @@
k8s:
state: absent
kind: namespace
name: '{{ drain_namespace }}'
name: '{{ test_namespace }}'

View File

@@ -0,0 +1,3 @@
k8s_exec
k8s
time=23

View File

@@ -0,0 +1,2 @@
---
test_namespace: "k8s-exec"

View File

@@ -0,0 +1,3 @@
---
dependencies:
- setup_namespace

View File

@@ -1,13 +1,13 @@
---
- vars:
exec_namespace: k8s-exec
k8s_wait_timeout: 400
pod: sleep-pod
exec_pod_definition:
apiVersion: v1
kind: Pod
metadata:
name: "{{ pod }}"
namespace: "{{ exec_namespace }}"
namespace: "{{ test_namespace }}"
spec:
containers:
- name: sleeper
@@ -19,7 +19,7 @@
kind: Pod
metadata:
name: "{{ multi_container_pod_name }}"
namespace: "{{ exec_namespace }}"
namespace: "{{ test_namespace }}"
spec:
containers:
- name: sleeper-1
@@ -30,22 +30,17 @@
command: ["sleep", "infinity"]
block:
- name: "Ensure that {{ exec_namespace }} namespace exists"
k8s:
kind: Namespace
name: "{{ exec_namespace }}"
- name: "Create a pod"
k8s:
definition: "{{ exec_pod_definition }}"
wait: yes
wait_sleep: 1
wait_timeout: 30
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
- name: "Execute a command"
k8s_exec:
pod: "{{ pod }}"
namespace: "{{ exec_namespace }}"
namespace: "{{ test_namespace }}"
command: cat /etc/resolv.conf
register: output
@@ -60,7 +55,7 @@
- name: Check if rc is returned for the given command
k8s_exec:
namespace: "{{ exec_namespace }}"
namespace: "{{ test_namespace }}"
pod: "{{ pod }}"
command: 'false'
register: command_status
@@ -77,12 +72,12 @@
definition: "{{ multi_container_pod_definition }}"
wait: yes
wait_sleep: 1
wait_timeout: 30
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
- name: Execute command on the first container of the pod
k8s_exec:
pod: "{{ multi_container_pod_name }}"
namespace: "{{ exec_namespace }}"
namespace: "{{ test_namespace }}"
command: echo hello
register: output
@@ -95,5 +90,5 @@
- name: "Cleanup namespace"
k8s:
kind: Namespace
name: "{{ exec_namespace }}"
name: "{{ test_namespace }}"
state: absent

View File

@@ -0,0 +1,3 @@
time=57
k8s
k8s_info

View File

@@ -0,0 +1,10 @@
---
test_namespace:
- testing
- testing1
- testing2
- testing3
- testing4
- testing5
- testing6
- test-namespace-module-defaults

View File

@@ -0,0 +1,3 @@
---
dependencies:
- remove_namespace

View File

@@ -0,0 +1 @@
time=142

Some files were not shown because too many files have changed in this diff Show More