mirror of
https://github.com/ansible-collections/kubernetes.core.git
synced 2026-05-12 12:32:05 +00:00
Compare commits
20 Commits
stable-5
...
stable-2.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0de560df27 | ||
|
|
243bc00599 | ||
|
|
7e00e1ef87 | ||
|
|
1b412e06ab | ||
|
|
11c800d6ed | ||
|
|
0d9c4d3459 | ||
|
|
3645c1c16c | ||
|
|
5fdd70cbc3 | ||
|
|
1c02fe3443 | ||
|
|
eaffde63bb | ||
|
|
d8538ffed3 | ||
|
|
bc168a5727 | ||
|
|
dc5a1e6dd1 | ||
|
|
72536fe286 | ||
|
|
f2d899b939 | ||
|
|
bc391218a4 | ||
|
|
83b3a1aa39 | ||
|
|
aa41055503 | ||
|
|
256fa58ca8 | ||
|
|
70db517265 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -15,4 +15,8 @@ tests/integration/cloud-config-*
|
|||||||
.cache
|
.cache
|
||||||
|
|
||||||
# Helm charts
|
# Helm charts
|
||||||
molecule/default/*-chart-*.tgz
|
tests/integration/*-chart-*.tgz
|
||||||
|
|
||||||
|
# ansible-test generated file
|
||||||
|
tests/integration/inventory
|
||||||
|
tests/integration/*-*.yml
|
||||||
|
|||||||
10
.zuul.d/network-ee-sanity-tests_non-voting.yaml
Normal file
10
.zuul.d/network-ee-sanity-tests_non-voting.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
- project:
|
||||||
|
name: github.com/ansible-collections/kubernetes.core
|
||||||
|
check:
|
||||||
|
jobs:
|
||||||
|
- network-ee-sanity-tests:
|
||||||
|
voting: false
|
||||||
|
gate:
|
||||||
|
jobs:
|
||||||
|
- network-ee-sanity-tests:
|
||||||
|
voting: false
|
||||||
@@ -5,6 +5,37 @@ Kubernetes Collection Release Notes
|
|||||||
.. contents:: Topics
|
.. contents:: Topics
|
||||||
|
|
||||||
|
|
||||||
|
v2.2.3
|
||||||
|
======
|
||||||
|
|
||||||
|
Bugfixes
|
||||||
|
--------
|
||||||
|
|
||||||
|
- k8s_drain - fix error caused by accessing an undefined variable when pods have local storage (https://github.com/ansible-collections/kubernetes.core/issues/292).
|
||||||
|
- k8s_info - don't wait on empty List resources (https://github.com/ansible-collections/kubernetes.core/pull/253).
|
||||||
|
- module_utils.common - change default opening mode to read-bytes to avoid bad interpretation of non ascii characters and strings, often present in 3rd party manifests.
|
||||||
|
|
||||||
|
Minor Changes
|
||||||
|
-------------
|
||||||
|
|
||||||
|
- Add integration test to check handling of module_defaults (https://github.com/ansible-collections/kubernetes.core/pull/296).
|
||||||
|
|
||||||
|
v2.2.2
|
||||||
|
======
|
||||||
|
|
||||||
|
Bugfixes
|
||||||
|
--------
|
||||||
|
|
||||||
|
- remove binary file from k8s_cp test suite (https://github.com/ansible-collections/kubernetes.core/pull/298).
|
||||||
|
|
||||||
|
v2.2.1
|
||||||
|
======
|
||||||
|
|
||||||
|
Bugfixes
|
||||||
|
--------
|
||||||
|
|
||||||
|
- common - Ensure the label_selectors parameter of _wait_for method is optional.
|
||||||
|
|
||||||
v2.2.0
|
v2.2.0
|
||||||
======
|
======
|
||||||
|
|
||||||
|
|||||||
7
Makefile
7
Makefile
@@ -1,5 +1,5 @@
|
|||||||
# Also needs to be updated in galaxy.yml
|
# Also needs to be updated in galaxy.yml
|
||||||
VERSION = 2.2.0
|
VERSION = 2.2.3
|
||||||
|
|
||||||
TEST_ARGS ?= ""
|
TEST_ARGS ?= ""
|
||||||
PYTHON_VERSION ?= `python -c 'import platform; print(".".join(platform.python_version_tuple()[0:2]))'`
|
PYTHON_VERSION ?= `python -c 'import platform; print(".".join(platform.python_version_tuple()[0:2]))'`
|
||||||
@@ -22,10 +22,7 @@ test-sanity:
|
|||||||
ansible-test sanity --docker -v --color --python $(PYTHON_VERSION) $(?TEST_ARGS)
|
ansible-test sanity --docker -v --color --python $(PYTHON_VERSION) $(?TEST_ARGS)
|
||||||
|
|
||||||
test-integration:
|
test-integration:
|
||||||
ansible-test integration --docker -v --color --retry-on-error --python $(PYTHON_VERSION) --continue-on-error --diff --coverage $(?TEST_ARGS)
|
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-molecule:
|
|
||||||
molecule test
|
|
||||||
|
|
||||||
test-unit:
|
test-unit:
|
||||||
ansible-test units --docker -v --color --python $(PYTHON_VERSION) $(?TEST_ARGS)
|
ansible-test units --docker -v --color --python $(PYTHON_VERSION) $(?TEST_ARGS)
|
||||||
|
|||||||
48
PSF-license.txt
Normal file
48
PSF-license.txt
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
1. This LICENSE AGREEMENT is between the Python Software Foundation
|
||||||
|
("PSF"), and the Individual or Organization ("Licensee") accessing and
|
||||||
|
otherwise using this software ("Python") in source or binary form and
|
||||||
|
its associated documentation.
|
||||||
|
|
||||||
|
2. Subject to the terms and conditions of this License Agreement, PSF hereby
|
||||||
|
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
|
||||||
|
analyze, test, perform and/or display publicly, prepare derivative works,
|
||||||
|
distribute, and otherwise use Python alone or in any derivative version,
|
||||||
|
provided, however, that PSF's License Agreement and PSF's notice of copyright,
|
||||||
|
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||||
|
2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Python Software Foundation;
|
||||||
|
All Rights Reserved" are retained in Python alone or in any derivative version
|
||||||
|
prepared by Licensee.
|
||||||
|
|
||||||
|
3. In the event Licensee prepares a derivative work that is based on
|
||||||
|
or incorporates Python or any part thereof, and wants to make
|
||||||
|
the derivative work available to others as provided herein, then
|
||||||
|
Licensee hereby agrees to include in any such work a brief summary of
|
||||||
|
the changes made to Python.
|
||||||
|
|
||||||
|
4. PSF is making Python available to Licensee on an "AS IS"
|
||||||
|
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||||
|
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
|
||||||
|
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||||
|
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
|
||||||
|
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||||
|
|
||||||
|
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
||||||
|
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
||||||
|
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
|
||||||
|
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||||
|
|
||||||
|
6. This License Agreement will automatically terminate upon a material
|
||||||
|
breach of its terms and conditions.
|
||||||
|
|
||||||
|
7. Nothing in this License Agreement shall be deemed to create any
|
||||||
|
relationship of agency, partnership, or joint venture between PSF and
|
||||||
|
Licensee. This License Agreement does not grant permission to use PSF
|
||||||
|
trademarks or trade name in a trademark sense to endorse or promote
|
||||||
|
products or services of Licensee, or any third party.
|
||||||
|
|
||||||
|
8. By copying, installing or otherwise using Python, Licensee
|
||||||
|
agrees to be bound by the terms and conditions of this License
|
||||||
|
Agreement.
|
||||||
@@ -85,7 +85,7 @@ You can also include it in a `requirements.yml` file and install it via `ansible
|
|||||||
---
|
---
|
||||||
collections:
|
collections:
|
||||||
- name: kubernetes.core
|
- name: kubernetes.core
|
||||||
version: 2.2.0
|
version: 2.2.3
|
||||||
```
|
```
|
||||||
|
|
||||||
### Installing the Kubernetes Python Library
|
### Installing the Kubernetes Python Library
|
||||||
|
|||||||
@@ -486,3 +486,35 @@ releases:
|
|||||||
name: kustomize
|
name: kustomize
|
||||||
namespace: null
|
namespace: null
|
||||||
release_date: '2021-09-15'
|
release_date: '2021-09-15'
|
||||||
|
2.2.1:
|
||||||
|
changes:
|
||||||
|
bugfixes:
|
||||||
|
- common - Ensure the label_selectors parameter of _wait_for method is optional.
|
||||||
|
fragments:
|
||||||
|
- 0-copy_ignore_txt.yml
|
||||||
|
- _wait_for_label_selector_optional.yaml
|
||||||
|
release_date: '2021-10-18'
|
||||||
|
2.2.2:
|
||||||
|
changes:
|
||||||
|
bugfixes:
|
||||||
|
- remove binary file from k8s_cp test suite (https://github.com/ansible-collections/kubernetes.core/pull/298).
|
||||||
|
fragments:
|
||||||
|
- 298-remove-binary-file.yaml
|
||||||
|
release_date: '2021-12-07'
|
||||||
|
2.2.3:
|
||||||
|
changes:
|
||||||
|
bugfixes:
|
||||||
|
- k8s_drain - fix error caused by accessing an undefined variable when pods
|
||||||
|
have local storage (https://github.com/ansible-collections/kubernetes.core/issues/292).
|
||||||
|
- k8s_info - don't wait on empty List resources (https://github.com/ansible-collections/kubernetes.core/pull/253).
|
||||||
|
- module_utils.common - change default opening mode to read-bytes to avoid bad
|
||||||
|
interpretation of non ascii characters and strings, often present in 3rd party
|
||||||
|
manifests.
|
||||||
|
minor_changes:
|
||||||
|
- Add integration test to check handling of module_defaults
|
||||||
|
(https://github.com/ansible-collections/kubernetes.core/pull/296).
|
||||||
|
fragments:
|
||||||
|
- 253-dont-wait-on-list-resources.yaml
|
||||||
|
- 295-fix-k8s-drain-variable-declaration.yaml
|
||||||
|
- 308-fix-for-common-non-ascii-characters-in-resources.yaml
|
||||||
|
release_date: '2022-01-18'
|
||||||
|
|||||||
2
changelogs/fragments/456-replace-distutils.yml
Normal file
2
changelogs/fragments/456-replace-distutils.yml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
minor_changes:
|
||||||
|
- kubectl.py - replace distutils.spawn.find_executable with shutil.which in the kubectl connection plugin (https://github.com/ansible-collections/kubernetes.core/pull/456).
|
||||||
2
changelogs/fragments/disutils.version.yml
Normal file
2
changelogs/fragments/disutils.version.yml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
bugfixes:
|
||||||
|
- "Various modules and plugins - use vendored version of ``distutils.version`` instead of the deprecated Python standard library ``distutils`` (https://github.com/ansible-collections/kubernetes.core/pull/314)."
|
||||||
3
changelogs/fragments/exception.yml
Normal file
3
changelogs/fragments/exception.yml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
bugfixes:
|
||||||
|
- import exception from ``kubernetes.client.rest``.
|
||||||
@@ -25,7 +25,7 @@ tags:
|
|||||||
- openshift
|
- openshift
|
||||||
- okd
|
- okd
|
||||||
- cluster
|
- cluster
|
||||||
version: 2.2.0
|
version: 2.2.3
|
||||||
build_ignore:
|
build_ignore:
|
||||||
- .DS_Store
|
- .DS_Store
|
||||||
- '*.tar.gz'
|
- '*.tar.gz'
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ action_groups:
|
|||||||
k8s:
|
k8s:
|
||||||
- k8s
|
- k8s
|
||||||
- k8s_exec
|
- k8s_exec
|
||||||
- k8s_facts
|
|
||||||
- k8s_info
|
- k8s_info
|
||||||
- k8s_log
|
- k8s_log
|
||||||
- k8s_scale
|
- k8s_scale
|
||||||
|
|||||||
@@ -1,292 +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
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,39 +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
|
|
||||||
dependency:
|
|
||||||
name: galaxy
|
|
||||||
options:
|
|
||||||
requirements-file: requirements.yml
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Prepare
|
|
||||||
hosts: localhost
|
|
||||||
connection: local
|
|
||||||
|
|
||||||
collections:
|
|
||||||
- kubernetes.core
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Include drain.yml
|
|
||||||
include_tasks:
|
|
||||||
file: tasks/drain.yml
|
|
||||||
Binary file not shown.
@@ -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()
|
|
||||||
@@ -22,9 +22,9 @@ __metaclass__ = type
|
|||||||
|
|
||||||
DOCUMENTATION = r"""
|
DOCUMENTATION = r"""
|
||||||
author:
|
author:
|
||||||
- xuxinkun
|
- xuxinkun (@xuxinkun)
|
||||||
|
|
||||||
connection: kubectl
|
name: kubectl
|
||||||
|
|
||||||
short_description: Execute tasks in pods running on Kubernetes.
|
short_description: Execute tasks in pods running on Kubernetes.
|
||||||
|
|
||||||
@@ -170,9 +170,9 @@ DOCUMENTATION = r"""
|
|||||||
aliases: [ kubectl_verify_ssl ]
|
aliases: [ kubectl_verify_ssl ]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import distutils.spawn
|
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from ansible.parsing.yaml.loader import AnsibleLoader
|
from ansible.parsing.yaml.loader import AnsibleLoader
|
||||||
@@ -217,13 +217,10 @@ class Connection(ConnectionBase):
|
|||||||
|
|
||||||
# Note: kubectl runs commands as the user that started the container.
|
# Note: kubectl runs commands as the user that started the container.
|
||||||
# It is impossible to set the remote user for a kubectl connection.
|
# It is impossible to set the remote user for a kubectl connection.
|
||||||
cmd_arg = '{0}_command'.format(self.transport)
|
cmd_arg = "{0}_command".format(self.transport)
|
||||||
if cmd_arg in kwargs:
|
self.transport_cmd = kwargs.get(cmd_arg, shutil.which(self.transport))
|
||||||
self.transport_cmd = kwargs[cmd_arg]
|
if not self.transport_cmd:
|
||||||
else:
|
raise AnsibleError("{0} command not found in PATH".format(self.transport))
|
||||||
self.transport_cmd = distutils.spawn.find_executable(self.transport)
|
|
||||||
if not self.transport_cmd:
|
|
||||||
raise AnsibleError("{0} command not found in PATH".format(self.transport))
|
|
||||||
|
|
||||||
def _build_exec_cmd(self, cmd):
|
def _build_exec_cmd(self, cmd):
|
||||||
""" Build the local kubectl exec command to run cmd on remote_host
|
""" Build the local kubectl exec command to run cmd on remote_host
|
||||||
|
|||||||
@@ -28,6 +28,6 @@ options:
|
|||||||
- Reads from the local file system. To read from the Ansible controller's file system, including vaulted files, use the file lookup
|
- Reads from the local file system. To read from the Ansible controller's file system, including vaulted files, use the file lookup
|
||||||
plugin or template lookup plugin, combined with the from_yaml filter, and pass the result to
|
plugin or template lookup plugin, combined with the from_yaml filter, and pass the result to
|
||||||
I(resource_definition). See Examples below.
|
I(resource_definition). See Examples below.
|
||||||
- Mutually exclusive with I(template) in case of M(k8s) module.
|
- Mutually exclusive with I(template) in case of M(kubernetes.core.k8s) module.
|
||||||
type: path
|
type: path
|
||||||
'''
|
'''
|
||||||
|
|||||||
@@ -6,10 +6,9 @@ __metaclass__ = type
|
|||||||
|
|
||||||
DOCUMENTATION = '''
|
DOCUMENTATION = '''
|
||||||
name: k8s
|
name: k8s
|
||||||
plugin_type: inventory
|
|
||||||
author:
|
author:
|
||||||
- Chris Houseknecht <@chouseknecht>
|
- Chris Houseknecht (@chouseknecht)
|
||||||
- Fabian von Feilitzsch <@fabianvf>
|
- Fabian von Feilitzsch (@fabianvf)
|
||||||
|
|
||||||
short_description: Kubernetes (K8s) inventory source
|
short_description: Kubernetes (K8s) inventory source
|
||||||
|
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ from __future__ import (absolute_import, division, print_function)
|
|||||||
|
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
DOCUMENTATION = """
|
||||||
lookup: k8s
|
name: k8s
|
||||||
|
|
||||||
short_description: Query the K8s API
|
short_description: Query the K8s API
|
||||||
|
|
||||||
author:
|
author:
|
||||||
- Chris Houseknecht <@chouseknecht>
|
- Chris Houseknecht (@chouseknecht)
|
||||||
- Fabian von Feilitzsch <@fabianvf>
|
- Fabian von Feilitzsch (@fabianvf)
|
||||||
|
|
||||||
description:
|
description:
|
||||||
- Uses the Kubernetes Python client to fetch a specific object by name, all matching objects within a
|
- Uses the Kubernetes Python client to fetch a specific object by name, all matching objects within a
|
||||||
@@ -117,7 +117,7 @@ DOCUMENTATION = '''
|
|||||||
- "python >= 3.6"
|
- "python >= 3.6"
|
||||||
- "kubernetes >= 12.0.0"
|
- "kubernetes >= 12.0.0"
|
||||||
- "PyYAML >= 3.11"
|
- "PyYAML >= 3.11"
|
||||||
'''
|
"""
|
||||||
|
|
||||||
EXAMPLES = """
|
EXAMPLES = """
|
||||||
- name: Fetch a list of namespaces
|
- name: Fetch a list of namespaces
|
||||||
@@ -159,28 +159,19 @@ RETURN = """
|
|||||||
_list:
|
_list:
|
||||||
description:
|
description:
|
||||||
- One ore more object definitions returned from the API.
|
- One ore more object definitions returned from the API.
|
||||||
type: complex
|
type: list
|
||||||
contains:
|
elements: dict
|
||||||
api_version:
|
sample:
|
||||||
description: The versioned schema of this representation of an object.
|
- kind: ConfigMap
|
||||||
returned: success
|
apiVersion: v1
|
||||||
type: str
|
metadata:
|
||||||
kind:
|
creationTimestamp: "2022-03-04T13:59:49Z"
|
||||||
description: Represents the REST resource this object represents.
|
name: my-config-map
|
||||||
returned: success
|
namespace: default
|
||||||
type: str
|
resourceVersion: "418"
|
||||||
metadata:
|
uid: 5714b011-d090-4eac-8272-a0ea82ec0abd
|
||||||
description: Standard object metadata. Includes name, namespace, annotations, labels, etc.
|
data:
|
||||||
returned: success
|
key1: val1
|
||||||
type: complex
|
|
||||||
spec:
|
|
||||||
description: Specific attributes of the object. Will vary based on the I(api_version) and I(kind).
|
|
||||||
returned: success
|
|
||||||
type: complex
|
|
||||||
status:
|
|
||||||
description: Current status details for the object.
|
|
||||||
returned: success
|
|
||||||
type: complex
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
|
|||||||
@@ -3,15 +3,15 @@
|
|||||||
#
|
#
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
DOCUMENTATION = """
|
||||||
lookup: kustomize
|
name: kustomize
|
||||||
|
|
||||||
short_description: Build a set of kubernetes resources using a 'kustomization.yaml' file.
|
short_description: Build a set of kubernetes resources using a 'kustomization.yaml' file.
|
||||||
|
|
||||||
version_added: "2.2.0"
|
version_added: "2.2.0"
|
||||||
|
|
||||||
author:
|
author:
|
||||||
- Aubin Bikouo <@abikouo>
|
- Aubin Bikouo (@abikouo)
|
||||||
notes:
|
notes:
|
||||||
- If both kustomize and kubectl are part of the PATH, kustomize will be used by the plugin.
|
- If both kustomize and kubectl are part of the PATH, kustomize will be used by the plugin.
|
||||||
description:
|
description:
|
||||||
@@ -33,7 +33,7 @@ DOCUMENTATION = '''
|
|||||||
|
|
||||||
requirements:
|
requirements:
|
||||||
- "python >= 3.6"
|
- "python >= 3.6"
|
||||||
'''
|
"""
|
||||||
|
|
||||||
EXAMPLES = """
|
EXAMPLES = """
|
||||||
- name: Run lookup using kustomize
|
- name: Run lookup using kustomize
|
||||||
@@ -52,29 +52,16 @@ EXAMPLES = """
|
|||||||
RETURN = """
|
RETURN = """
|
||||||
_list:
|
_list:
|
||||||
description:
|
description:
|
||||||
- One ore more object definitions returned from the tool execution.
|
- YAML string for the object definitions returned from the tool execution.
|
||||||
type: complex
|
type: str
|
||||||
contains:
|
sample:
|
||||||
api_version:
|
kind: ConfigMap
|
||||||
description: The versioned schema of this representation of an object.
|
apiVersion: v1
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
kind:
|
|
||||||
description: Represents the REST resource this object represents.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
metadata:
|
metadata:
|
||||||
description: Standard object metadata. Includes name, namespace, annotations, labels, etc.
|
name: my-config-map
|
||||||
returned: success
|
namespace: default
|
||||||
type: complex
|
data:
|
||||||
spec:
|
key1: val1
|
||||||
description: Specific attributes of the object. Will vary based on the I(api_version) and I(kind).
|
|
||||||
returned: success
|
|
||||||
type: complex
|
|
||||||
status:
|
|
||||||
description: Current status details for the object.
|
|
||||||
returned: success
|
|
||||||
type: complex
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from ansible.errors import AnsibleLookupError
|
from ansible.errors import AnsibleLookupError
|
||||||
|
|||||||
344
plugins/module_utils/_version.py
Normal file
344
plugins/module_utils/_version.py
Normal file
@@ -0,0 +1,344 @@
|
|||||||
|
# Vendored copy of distutils/version.py from CPython 3.9.5
|
||||||
|
#
|
||||||
|
# Implements multiple version numbering conventions for the
|
||||||
|
# Python Module Distribution Utilities.
|
||||||
|
#
|
||||||
|
# PSF License (see PSF-license.txt or https://opensource.org/licenses/Python-2.0)
|
||||||
|
#
|
||||||
|
|
||||||
|
"""Provides classes to represent module version numbers (one class for
|
||||||
|
each style of version numbering). There are currently two such classes
|
||||||
|
implemented: StrictVersion and LooseVersion.
|
||||||
|
|
||||||
|
Every version number class implements the following interface:
|
||||||
|
* the 'parse' method takes a string and parses it to some internal
|
||||||
|
representation; if the string is an invalid version number,
|
||||||
|
'parse' raises a ValueError exception
|
||||||
|
* the class constructor takes an optional string argument which,
|
||||||
|
if supplied, is passed to 'parse'
|
||||||
|
* __str__ reconstructs the string that was passed to 'parse' (or
|
||||||
|
an equivalent string -- ie. one that will generate an equivalent
|
||||||
|
version number instance)
|
||||||
|
* __repr__ generates Python code to recreate the version number instance
|
||||||
|
* _cmp compares the current instance with either another instance
|
||||||
|
of the same class or a string (which will be parsed to an instance
|
||||||
|
of the same class, thus must follow the same rules)
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
try:
|
||||||
|
RE_FLAGS = re.VERBOSE | re.ASCII
|
||||||
|
except AttributeError:
|
||||||
|
RE_FLAGS = re.VERBOSE
|
||||||
|
|
||||||
|
|
||||||
|
class Version:
|
||||||
|
"""Abstract base class for version numbering classes. Just provides
|
||||||
|
constructor (__init__) and reproducer (__repr__), because those
|
||||||
|
seem to be the same for all version numbering classes; and route
|
||||||
|
rich comparisons to _cmp.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, vstring=None):
|
||||||
|
if vstring:
|
||||||
|
self.parse(vstring)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "%s ('%s')" % (self.__class__.__name__, str(self))
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
c = self._cmp(other)
|
||||||
|
if c is NotImplemented:
|
||||||
|
return c
|
||||||
|
return c == 0
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
c = self._cmp(other)
|
||||||
|
if c is NotImplemented:
|
||||||
|
return c
|
||||||
|
return c < 0
|
||||||
|
|
||||||
|
def __le__(self, other):
|
||||||
|
c = self._cmp(other)
|
||||||
|
if c is NotImplemented:
|
||||||
|
return c
|
||||||
|
return c <= 0
|
||||||
|
|
||||||
|
def __gt__(self, other):
|
||||||
|
c = self._cmp(other)
|
||||||
|
if c is NotImplemented:
|
||||||
|
return c
|
||||||
|
return c > 0
|
||||||
|
|
||||||
|
def __ge__(self, other):
|
||||||
|
c = self._cmp(other)
|
||||||
|
if c is NotImplemented:
|
||||||
|
return c
|
||||||
|
return c >= 0
|
||||||
|
|
||||||
|
|
||||||
|
# Interface for version-number classes -- must be implemented
|
||||||
|
# by the following classes (the concrete ones -- Version should
|
||||||
|
# be treated as an abstract class).
|
||||||
|
# __init__ (string) - create and take same action as 'parse'
|
||||||
|
# (string parameter is optional)
|
||||||
|
# parse (string) - convert a string representation to whatever
|
||||||
|
# internal representation is appropriate for
|
||||||
|
# this style of version numbering
|
||||||
|
# __str__ (self) - convert back to a string; should be very similar
|
||||||
|
# (if not identical to) the string supplied to parse
|
||||||
|
# __repr__ (self) - generate Python code to recreate
|
||||||
|
# the instance
|
||||||
|
# _cmp (self, other) - compare two version numbers ('other' may
|
||||||
|
# be an unparsed version string, or another
|
||||||
|
# instance of your version class)
|
||||||
|
|
||||||
|
|
||||||
|
class StrictVersion(Version):
|
||||||
|
"""Version numbering for anal retentives and software idealists.
|
||||||
|
Implements the standard interface for version number classes as
|
||||||
|
described above. A version number consists of two or three
|
||||||
|
dot-separated numeric components, with an optional "pre-release" tag
|
||||||
|
on the end. The pre-release tag consists of the letter 'a' or 'b'
|
||||||
|
followed by a number. If the numeric components of two version
|
||||||
|
numbers are equal, then one with a pre-release tag will always
|
||||||
|
be deemed earlier (lesser) than one without.
|
||||||
|
|
||||||
|
The following are valid version numbers (shown in the order that
|
||||||
|
would be obtained by sorting according to the supplied cmp function):
|
||||||
|
|
||||||
|
0.4 0.4.0 (these two are equivalent)
|
||||||
|
0.4.1
|
||||||
|
0.5a1
|
||||||
|
0.5b3
|
||||||
|
0.5
|
||||||
|
0.9.6
|
||||||
|
1.0
|
||||||
|
1.0.4a3
|
||||||
|
1.0.4b1
|
||||||
|
1.0.4
|
||||||
|
|
||||||
|
The following are examples of invalid version numbers:
|
||||||
|
|
||||||
|
1
|
||||||
|
2.7.2.2
|
||||||
|
1.3.a4
|
||||||
|
1.3pl1
|
||||||
|
1.3c4
|
||||||
|
|
||||||
|
The rationale for this version numbering system will be explained
|
||||||
|
in the distutils documentation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
version_re = re.compile(r"^(\d+) \. (\d+) (\. (\d+))? ([ab](\d+))?$", RE_FLAGS)
|
||||||
|
|
||||||
|
def parse(self, vstring):
|
||||||
|
match = self.version_re.match(vstring)
|
||||||
|
if not match:
|
||||||
|
raise ValueError("invalid version number '%s'" % vstring)
|
||||||
|
|
||||||
|
(major, minor, patch, prerelease, prerelease_num) = match.group(1, 2, 4, 5, 6)
|
||||||
|
|
||||||
|
if patch:
|
||||||
|
self.version = tuple(map(int, [major, minor, patch]))
|
||||||
|
else:
|
||||||
|
self.version = tuple(map(int, [major, minor])) + (0,)
|
||||||
|
|
||||||
|
if prerelease:
|
||||||
|
self.prerelease = (prerelease[0], int(prerelease_num))
|
||||||
|
else:
|
||||||
|
self.prerelease = None
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.version[2] == 0:
|
||||||
|
vstring = ".".join(map(str, self.version[0:2]))
|
||||||
|
else:
|
||||||
|
vstring = ".".join(map(str, self.version))
|
||||||
|
|
||||||
|
if self.prerelease:
|
||||||
|
vstring = vstring + self.prerelease[0] + str(self.prerelease[1])
|
||||||
|
|
||||||
|
return vstring
|
||||||
|
|
||||||
|
def _cmp(self, other):
|
||||||
|
if isinstance(other, str):
|
||||||
|
other = StrictVersion(other)
|
||||||
|
elif not isinstance(other, StrictVersion):
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
if self.version != other.version:
|
||||||
|
# numeric versions don't match
|
||||||
|
# prerelease stuff doesn't matter
|
||||||
|
if self.version < other.version:
|
||||||
|
return -1
|
||||||
|
else:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# have to compare prerelease
|
||||||
|
# case 1: neither has prerelease; they're equal
|
||||||
|
# case 2: self has prerelease, other doesn't; other is greater
|
||||||
|
# case 3: self doesn't have prerelease, other does: self is greater
|
||||||
|
# case 4: both have prerelease: must compare them!
|
||||||
|
|
||||||
|
if not self.prerelease and not other.prerelease:
|
||||||
|
return 0
|
||||||
|
elif self.prerelease and not other.prerelease:
|
||||||
|
return -1
|
||||||
|
elif not self.prerelease and other.prerelease:
|
||||||
|
return 1
|
||||||
|
elif self.prerelease and other.prerelease:
|
||||||
|
if self.prerelease == other.prerelease:
|
||||||
|
return 0
|
||||||
|
elif self.prerelease < other.prerelease:
|
||||||
|
return -1
|
||||||
|
else:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
raise AssertionError("never get here")
|
||||||
|
|
||||||
|
|
||||||
|
# end class StrictVersion
|
||||||
|
|
||||||
|
# The rules according to Greg Stein:
|
||||||
|
# 1) a version number has 1 or more numbers separated by a period or by
|
||||||
|
# sequences of letters. If only periods, then these are compared
|
||||||
|
# left-to-right to determine an ordering.
|
||||||
|
# 2) sequences of letters are part of the tuple for comparison and are
|
||||||
|
# compared lexicographically
|
||||||
|
# 3) recognize the numeric components may have leading zeroes
|
||||||
|
#
|
||||||
|
# The LooseVersion class below implements these rules: a version number
|
||||||
|
# string is split up into a tuple of integer and string components, and
|
||||||
|
# comparison is a simple tuple comparison. This means that version
|
||||||
|
# numbers behave in a predictable and obvious way, but a way that might
|
||||||
|
# not necessarily be how people *want* version numbers to behave. There
|
||||||
|
# wouldn't be a problem if people could stick to purely numeric version
|
||||||
|
# numbers: just split on period and compare the numbers as tuples.
|
||||||
|
# However, people insist on putting letters into their version numbers;
|
||||||
|
# the most common purpose seems to be:
|
||||||
|
# - indicating a "pre-release" version
|
||||||
|
# ('alpha', 'beta', 'a', 'b', 'pre', 'p')
|
||||||
|
# - indicating a post-release patch ('p', 'pl', 'patch')
|
||||||
|
# but of course this can't cover all version number schemes, and there's
|
||||||
|
# no way to know what a programmer means without asking him.
|
||||||
|
#
|
||||||
|
# The problem is what to do with letters (and other non-numeric
|
||||||
|
# characters) in a version number. The current implementation does the
|
||||||
|
# obvious and predictable thing: keep them as strings and compare
|
||||||
|
# lexically within a tuple comparison. This has the desired effect if
|
||||||
|
# an appended letter sequence implies something "post-release":
|
||||||
|
# eg. "0.99" < "0.99pl14" < "1.0", and "5.001" < "5.001m" < "5.002".
|
||||||
|
#
|
||||||
|
# However, if letters in a version number imply a pre-release version,
|
||||||
|
# the "obvious" thing isn't correct. Eg. you would expect that
|
||||||
|
# "1.5.1" < "1.5.2a2" < "1.5.2", but under the tuple/lexical comparison
|
||||||
|
# implemented here, this just isn't so.
|
||||||
|
#
|
||||||
|
# Two possible solutions come to mind. The first is to tie the
|
||||||
|
# comparison algorithm to a particular set of semantic rules, as has
|
||||||
|
# been done in the StrictVersion class above. This works great as long
|
||||||
|
# as everyone can go along with bondage and discipline. Hopefully a
|
||||||
|
# (large) subset of Python module programmers will agree that the
|
||||||
|
# particular flavour of bondage and discipline provided by StrictVersion
|
||||||
|
# provides enough benefit to be worth using, and will submit their
|
||||||
|
# version numbering scheme to its domination. The free-thinking
|
||||||
|
# anarchists in the lot will never give in, though, and something needs
|
||||||
|
# to be done to accommodate them.
|
||||||
|
#
|
||||||
|
# Perhaps a "moderately strict" version class could be implemented that
|
||||||
|
# lets almost anything slide (syntactically), and makes some heuristic
|
||||||
|
# assumptions about non-digits in version number strings. This could
|
||||||
|
# sink into special-case-hell, though; if I was as talented and
|
||||||
|
# idiosyncratic as Larry Wall, I'd go ahead and implement a class that
|
||||||
|
# somehow knows that "1.2.1" < "1.2.2a2" < "1.2.2" < "1.2.2pl3", and is
|
||||||
|
# just as happy dealing with things like "2g6" and "1.13++". I don't
|
||||||
|
# think I'm smart enough to do it right though.
|
||||||
|
#
|
||||||
|
# In any case, I've coded the test suite for this module (see
|
||||||
|
# ../test/test_version.py) specifically to fail on things like comparing
|
||||||
|
# "1.2a2" and "1.2". That's not because the *code* is doing anything
|
||||||
|
# wrong, it's because the simple, obvious design doesn't match my
|
||||||
|
# complicated, hairy expectations for real-world version numbers. It
|
||||||
|
# would be a snap to fix the test suite to say, "Yep, LooseVersion does
|
||||||
|
# the Right Thing" (ie. the code matches the conception). But I'd rather
|
||||||
|
# have a conception that matches common notions about version numbers.
|
||||||
|
|
||||||
|
|
||||||
|
class LooseVersion(Version):
|
||||||
|
"""Version numbering for anarchists and software realists.
|
||||||
|
Implements the standard interface for version number classes as
|
||||||
|
described above. A version number consists of a series of numbers,
|
||||||
|
separated by either periods or strings of letters. When comparing
|
||||||
|
version numbers, the numeric components will be compared
|
||||||
|
numerically, and the alphabetic components lexically. The following
|
||||||
|
are all valid version numbers, in no particular order:
|
||||||
|
|
||||||
|
1.5.1
|
||||||
|
1.5.2b2
|
||||||
|
161
|
||||||
|
3.10a
|
||||||
|
8.02
|
||||||
|
3.4j
|
||||||
|
1996.07.12
|
||||||
|
3.2.pl0
|
||||||
|
3.1.1.6
|
||||||
|
2g6
|
||||||
|
11g
|
||||||
|
0.960923
|
||||||
|
2.2beta29
|
||||||
|
1.13++
|
||||||
|
5.5.kw
|
||||||
|
2.0b1pl0
|
||||||
|
|
||||||
|
In fact, there is no such thing as an invalid version number under
|
||||||
|
this scheme; the rules for comparison are simple and predictable,
|
||||||
|
but may not always give the results you want (for some definition
|
||||||
|
of "want").
|
||||||
|
"""
|
||||||
|
|
||||||
|
component_re = re.compile(r"(\d+ | [a-z]+ | \.)", re.VERBOSE)
|
||||||
|
|
||||||
|
def __init__(self, vstring=None):
|
||||||
|
if vstring:
|
||||||
|
self.parse(vstring)
|
||||||
|
|
||||||
|
def parse(self, vstring):
|
||||||
|
# I've given up on thinking I can reconstruct the version string
|
||||||
|
# from the parsed tuple -- so I just store the string here for
|
||||||
|
# use by __str__
|
||||||
|
self.vstring = vstring
|
||||||
|
components = [x for x in self.component_re.split(vstring) if x and x != "."]
|
||||||
|
for i, obj in enumerate(components):
|
||||||
|
try:
|
||||||
|
components[i] = int(obj)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.version = components
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.vstring
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "LooseVersion ('%s')" % str(self)
|
||||||
|
|
||||||
|
def _cmp(self, other):
|
||||||
|
if isinstance(other, str):
|
||||||
|
other = LooseVersion(other)
|
||||||
|
elif not isinstance(other, LooseVersion):
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
if self.version == other.version:
|
||||||
|
return 0
|
||||||
|
if self.version < other.version:
|
||||||
|
return -1
|
||||||
|
if self.version > other.version:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
# end class LooseVersion
|
||||||
@@ -25,11 +25,21 @@ import traceback
|
|||||||
import sys
|
import sys
|
||||||
import hashlib
|
import hashlib
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from distutils.version import LooseVersion
|
|
||||||
|
|
||||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (AUTH_ARG_MAP, AUTH_ARG_SPEC, AUTH_PROXY_HEADERS_SPEC)
|
from ansible_collections.kubernetes.core.plugins.module_utils.version import (
|
||||||
from ansible_collections.kubernetes.core.plugins.module_utils.hashes import generate_hash
|
LooseVersion,
|
||||||
from ansible_collections.kubernetes.core.plugins.module_utils.selector import LabelSelectorFilter
|
)
|
||||||
|
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
|
||||||
|
AUTH_ARG_MAP,
|
||||||
|
AUTH_ARG_SPEC,
|
||||||
|
AUTH_PROXY_HEADERS_SPEC,
|
||||||
|
)
|
||||||
|
from ansible_collections.kubernetes.core.plugins.module_utils.hashes import (
|
||||||
|
generate_hash,
|
||||||
|
)
|
||||||
|
from ansible_collections.kubernetes.core.plugins.module_utils.selector import (
|
||||||
|
LabelSelectorFilter,
|
||||||
|
)
|
||||||
|
|
||||||
from ansible.module_utils.basic import missing_required_lib
|
from ansible.module_utils.basic import missing_required_lib
|
||||||
from ansible.module_utils.six import iteritems, string_types
|
from ansible.module_utils.six import iteritems, string_types
|
||||||
@@ -279,18 +289,28 @@ class K8sAnsibleMixin(object):
|
|||||||
def _elapsed():
|
def _elapsed():
|
||||||
return (datetime.now() - start).seconds
|
return (datetime.now() - start).seconds
|
||||||
|
|
||||||
if result is None:
|
def result_empty(result):
|
||||||
while _elapsed() < wait_timeout:
|
return (
|
||||||
try:
|
result is None
|
||||||
result = resource.get(name=name, namespace=namespace,
|
or result.kind.endswith("List")
|
||||||
label_selector=','.join(label_selectors),
|
and not result.get("items")
|
||||||
field_selector=','.join(field_selectors))
|
)
|
||||||
break
|
|
||||||
except NotFoundError:
|
while result_empty(result) and _elapsed() < wait_timeout:
|
||||||
pass
|
try:
|
||||||
time.sleep(wait_sleep)
|
result = resource.get(
|
||||||
if result is None:
|
name=name,
|
||||||
return dict(resources=[], api_found=True)
|
namespace=namespace,
|
||||||
|
label_selector=",".join(label_selectors),
|
||||||
|
field_selector=",".join(field_selectors),
|
||||||
|
)
|
||||||
|
except NotFoundError:
|
||||||
|
pass
|
||||||
|
if not result_empty(result):
|
||||||
|
break
|
||||||
|
time.sleep(wait_sleep)
|
||||||
|
if result_empty(result):
|
||||||
|
return dict(resources=[], api_found=True)
|
||||||
|
|
||||||
if isinstance(result, ResourceInstance):
|
if isinstance(result, ResourceInstance):
|
||||||
satisfied_by = []
|
satisfied_by = []
|
||||||
@@ -331,7 +351,7 @@ class K8sAnsibleMixin(object):
|
|||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
self.fail(msg="Error accessing {0}. Does the file exist?".format(path))
|
self.fail(msg="Error accessing {0}. Does the file exist?".format(path))
|
||||||
try:
|
try:
|
||||||
with open(path, 'r') as f:
|
with open(path, "rb") as f:
|
||||||
result = list(yaml.safe_load_all(f))
|
result = list(yaml.safe_load_all(f))
|
||||||
except (IOError, yaml.YAMLError) as exc:
|
except (IOError, yaml.YAMLError) as exc:
|
||||||
self.fail(msg="Error loading resource_definition: {0}".format(exc))
|
self.fail(msg="Error loading resource_definition: {0}".format(exc))
|
||||||
@@ -365,7 +385,7 @@ class K8sAnsibleMixin(object):
|
|||||||
def fail(self, msg=None):
|
def fail(self, msg=None):
|
||||||
self.fail_json(msg=msg)
|
self.fail_json(msg=msg)
|
||||||
|
|
||||||
def _wait_for(self, resource, name, namespace, predicate, sleep, timeout, state, label_selectors):
|
def _wait_for(self, resource, name, namespace, predicate, sleep, timeout, state, label_selectors=None):
|
||||||
start = datetime.now()
|
start = datetime.now()
|
||||||
|
|
||||||
def _wait_for_elapsed():
|
def _wait_for_elapsed():
|
||||||
|
|||||||
18
plugins/module_utils/version.py
Normal file
18
plugins/module_utils/version.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright: (c) 2021, Felix Fontein <felix@fontein.de>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
"""Provide version object to compare version numbers."""
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
# Once we drop support for Ansible 2.9, ansible-base 2.10, and ansible-core 2.11, we can
|
||||||
|
# remove the _version.py file, and replace the following import by
|
||||||
|
#
|
||||||
|
# from ansible.module_utils.compat.version import LooseVersion
|
||||||
|
|
||||||
|
from ._version import LooseVersion # noqa: F401
|
||||||
@@ -119,20 +119,40 @@ result:
|
|||||||
type: str
|
type: str
|
||||||
'''
|
'''
|
||||||
import copy
|
import copy
|
||||||
from datetime import datetime
|
|
||||||
import time
|
import time
|
||||||
from ansible_collections.kubernetes.core.plugins.module_utils.ansiblemodule import AnsibleModule
|
import traceback
|
||||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import AUTH_ARG_SPEC
|
|
||||||
|
from datetime import datetime
|
||||||
|
from ansible_collections.kubernetes.core.plugins.module_utils.ansiblemodule import (
|
||||||
|
AnsibleModule,
|
||||||
|
)
|
||||||
|
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
|
||||||
|
AUTH_ARG_SPEC,
|
||||||
|
)
|
||||||
from ansible.module_utils._text import to_native
|
from ansible.module_utils._text import to_native
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from kubernetes.client.api import core_v1_api
|
from kubernetes.client.api import core_v1_api
|
||||||
from kubernetes.client.models import V1beta1Eviction, V1DeleteOptions
|
from kubernetes.client.models import V1DeleteOptions
|
||||||
from kubernetes.client.exceptions import ApiException
|
from kubernetes.client.exceptions import ApiException
|
||||||
except ImportError:
|
except ImportError:
|
||||||
# ImportError are managed by the common module already.
|
# ImportError are managed by the common module already.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
HAS_EVICTION_API = True
|
||||||
|
k8s_import_exception = None
|
||||||
|
K8S_IMP_ERR = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
from kubernetes.client.models import V1beta1Eviction as v1_eviction
|
||||||
|
except ImportError:
|
||||||
|
try:
|
||||||
|
from kubernetes.client.models import V1Eviction as v1_eviction
|
||||||
|
except ImportError as e:
|
||||||
|
k8s_import_exception = e
|
||||||
|
K8S_IMP_ERR = traceback.format_exc()
|
||||||
|
HAS_EVICTION_API = False
|
||||||
|
|
||||||
|
|
||||||
def filter_pods(pods, force, ignore_daemonset):
|
def filter_pods(pods, force, ignore_daemonset):
|
||||||
k8s_kind_mirror = "kubernetes.io/config.mirror"
|
k8s_kind_mirror = "kubernetes.io/config.mirror"
|
||||||
@@ -183,6 +203,7 @@ def filter_pods(pods, force, ignore_daemonset):
|
|||||||
|
|
||||||
# local storage
|
# local storage
|
||||||
if localStorage:
|
if localStorage:
|
||||||
|
pod_names = ",".join([pod[0] + "/" + pod[1] for pod in localStorage])
|
||||||
errors.append("cannot delete Pods with local storage: {0}.".format(pod_names))
|
errors.append("cannot delete Pods with local storage: {0}.".format(pod_names))
|
||||||
|
|
||||||
# DaemonSet managed Pods
|
# DaemonSet managed Pods
|
||||||
@@ -270,8 +291,10 @@ class K8sDrainAnsible(object):
|
|||||||
body = V1DeleteOptions(**definition)
|
body = V1DeleteOptions(**definition)
|
||||||
self._api_instance.delete_namespaced_pod(name=name, namespace=namespace, body=body)
|
self._api_instance.delete_namespaced_pod(name=name, namespace=namespace, body=body)
|
||||||
else:
|
else:
|
||||||
body = V1beta1Eviction(**definition)
|
body = v1_eviction(**definition)
|
||||||
self._api_instance.create_namespaced_pod_eviction(name=name, namespace=namespace, body=body)
|
self._api_instance.create_namespaced_pod_eviction(
|
||||||
|
name=name, namespace=namespace, body=body
|
||||||
|
)
|
||||||
self._changed = True
|
self._changed = True
|
||||||
except ApiException as exc:
|
except ApiException as exc:
|
||||||
if exc.reason != "Not Found":
|
if exc.reason != "Not Found":
|
||||||
@@ -403,6 +426,13 @@ def argspec():
|
|||||||
def main():
|
def main():
|
||||||
module = AnsibleModule(argument_spec=argspec())
|
module = AnsibleModule(argument_spec=argspec())
|
||||||
|
|
||||||
|
if not HAS_EVICTION_API:
|
||||||
|
module.fail_json(
|
||||||
|
msg="The kubernetes Python library missing with V1Eviction API",
|
||||||
|
exception=K8S_IMP_ERR,
|
||||||
|
error=to_native(k8s_import_exception),
|
||||||
|
)
|
||||||
|
|
||||||
k8s_drain = K8sDrainAnsible(module)
|
k8s_drain = K8sDrainAnsible(module)
|
||||||
k8s_drain.execute_module()
|
k8s_drain.execute_module()
|
||||||
|
|
||||||
|
|||||||
@@ -191,6 +191,10 @@ def main():
|
|||||||
|
|
||||||
k8s_ansible_mixin = K8sAnsibleMixin(module)
|
k8s_ansible_mixin = K8sAnsibleMixin(module)
|
||||||
k8s_ansible_mixin.client = get_api_client(module=module)
|
k8s_ansible_mixin.client = get_api_client(module=module)
|
||||||
|
k8s_ansible_mixin.fail_json = module.fail_json
|
||||||
|
k8s_ansible_mixin.fail = module.fail_json
|
||||||
|
k8s_ansible_mixin.exit_json = module.exit_json
|
||||||
|
k8s_ansible_mixin.warn = module.warn
|
||||||
execute_module(module, k8s_ansible_mixin)
|
execute_module(module, k8s_ansible_mixin)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
collections:
|
|
||||||
- name: cloud.common
|
|
||||||
version: ">=2.0.4"
|
|
||||||
8
tests/integration/targets/helm/aliases
Normal file
8
tests/integration/targets/helm/aliases
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# slow - 11min
|
||||||
|
slow
|
||||||
|
time=313
|
||||||
|
helm_info
|
||||||
|
helm_plugin
|
||||||
|
helm_plugin_info
|
||||||
|
helm_repository
|
||||||
|
helm_template
|
||||||
@@ -1,10 +1,6 @@
|
|||||||
---
|
---
|
||||||
helm_archive_name: "helm-{{ helm_version }}-{{ ansible_system | lower }}-amd64.tar.gz"
|
helm_archive_name: "helm-{{ helm_version }}-{{ ansible_system | lower }}-amd64.tar.gz"
|
||||||
helm_binary: "/tmp/helm/{{ ansible_system | lower }}-amd64/helm"
|
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: "ingress-nginx"
|
||||||
chart_test_local_path: "nginx-ingress"
|
chart_test_local_path: "nginx-ingress"
|
||||||
@@ -17,3 +13,15 @@ chart_test_git_repo: "http://github.com/helm/charts.git"
|
|||||||
chart_test_values:
|
chart_test_values:
|
||||||
revisionHistoryLimit: 0
|
revisionHistoryLimit: 0
|
||||||
myValue: "changed"
|
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"
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
apiVersion: apiextensions.k8s.io/v1
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
name: foos.example.com
|
name: foos.ansible.com
|
||||||
spec:
|
spec:
|
||||||
group: example.com
|
group: ansible.com
|
||||||
versions:
|
versions:
|
||||||
- name: v1
|
- name: v1
|
||||||
served: true
|
served: true
|
||||||
95
tests/integration/targets/helm/library/helm_test_version.py
Normal file
95
tests/integration/targets/helm/library/helm_test_version.py
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# 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"""
|
||||||
|
---
|
||||||
|
module: helm_test_version
|
||||||
|
short_description: check helm executable version
|
||||||
|
author:
|
||||||
|
- Aubin Bikouo (@abikouo)
|
||||||
|
requirements:
|
||||||
|
- "helm (https://github.com/helm/helm/releases)"
|
||||||
|
description:
|
||||||
|
- validate version of helm binary is lower than the specified version.
|
||||||
|
options:
|
||||||
|
binary_path:
|
||||||
|
description:
|
||||||
|
- The path of a helm binary to use.
|
||||||
|
required: false
|
||||||
|
type: path
|
||||||
|
version:
|
||||||
|
description:
|
||||||
|
- version to test against helm binary.
|
||||||
|
type: str
|
||||||
|
default: 3.7.0
|
||||||
|
"""
|
||||||
|
|
||||||
|
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"""
|
||||||
|
message:
|
||||||
|
type: str
|
||||||
|
description: Text message describing the test result.
|
||||||
|
returned: always
|
||||||
|
sample: 'version installed: 3.4.5 is lower than version 3.5.0'
|
||||||
|
result:
|
||||||
|
type: bool
|
||||||
|
description: Test result.
|
||||||
|
returned: always
|
||||||
|
sample: 1
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
from ansible_collections.kubernetes.core.plugins.module_utils.version import (
|
||||||
|
LooseVersion,
|
||||||
|
)
|
||||||
|
|
||||||
|
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"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
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 = module.get_bin_path(helm_cmd_common, required=True)
|
||||||
|
rc, out, err = module.run_command([helm_cmd_common, "version"])
|
||||||
|
if rc != 0:
|
||||||
|
module.fail_json(msg="helm version failed.", err=err, out=out, rc=rc)
|
||||||
|
|
||||||
|
m = re.match(r'version.BuildInfo{Version:"v([0-9\.]*)",', out)
|
||||||
|
installed_version = m.group(1)
|
||||||
|
|
||||||
|
message = "version installed: %s" % installed_version
|
||||||
|
if LooseVersion(installed_version) < LooseVersion(version):
|
||||||
|
message += " is lower than version %s" % version
|
||||||
|
module.exit_json(changed=False, result=True, message=message)
|
||||||
|
else:
|
||||||
|
message += " is greater than version %s" % version
|
||||||
|
module.exit_json(changed=False, result=False, message=message)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
---
|
---
|
||||||
collections:
|
collections:
|
||||||
- kubernetes.core
|
- kubernetes.core
|
||||||
|
dependencies:
|
||||||
|
- remove_namespace
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
- name: Create namespace
|
- name: Create namespace
|
||||||
k8s:
|
k8s:
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
name: "{{ helm_namespace }}"
|
name: "{{ test_namespace[4] }}"
|
||||||
|
|
||||||
- name: Copy test chart
|
- name: Copy test chart
|
||||||
copy:
|
copy:
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
chart_ref: "/tmp/helm_test_crds/{{ test_chart }}"
|
chart_ref: "/tmp/helm_test_crds/{{ test_chart }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ test_namespace[4] }}"
|
||||||
name: test-crds
|
name: test-crds
|
||||||
skip_crds: true
|
skip_crds: true
|
||||||
register: install
|
register: install
|
||||||
@@ -30,10 +30,10 @@
|
|||||||
- name: Fail to create custom resource
|
- name: Fail to create custom resource
|
||||||
k8s:
|
k8s:
|
||||||
definition:
|
definition:
|
||||||
apiVersion: example.com/v1
|
apiVersion: ansible.com/v1
|
||||||
kind: Foo
|
kind: Foo
|
||||||
metadata:
|
metadata:
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ test_namespace[4] }}"
|
||||||
name: test-foo
|
name: test-foo
|
||||||
foobar: footest
|
foobar: footest
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
@@ -42,13 +42,13 @@
|
|||||||
- assert:
|
- assert:
|
||||||
that:
|
that:
|
||||||
- result is failed
|
- 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
|
# Helm won't install CRDs into an existing release, so we need to delete this, first
|
||||||
- name: Uninstall chart
|
- name: Uninstall chart
|
||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ test_namespace[4] }}"
|
||||||
name: test-crds
|
name: test-crds
|
||||||
state: absent
|
state: absent
|
||||||
|
|
||||||
@@ -56,16 +56,16 @@
|
|||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
chart_ref: "/tmp/helm_test_crds/{{ test_chart }}"
|
chart_ref: "/tmp/helm_test_crds/{{ test_chart }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ test_namespace[4] }}"
|
||||||
name: test-crds
|
name: test-crds
|
||||||
|
|
||||||
- name: Create custom resource
|
- name: Create custom resource
|
||||||
k8s:
|
k8s:
|
||||||
definition:
|
definition:
|
||||||
apiVersion: example.com/v1
|
apiVersion: ansible.com/v1
|
||||||
kind: Foo
|
kind: Foo
|
||||||
metadata:
|
metadata:
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ test_namespace[4] }}"
|
||||||
name: test-foo
|
name: test-foo
|
||||||
foobar: footest
|
foobar: footest
|
||||||
register: result
|
register: result
|
||||||
@@ -85,16 +85,14 @@
|
|||||||
- name: Remove namespace
|
- name: Remove namespace
|
||||||
k8s:
|
k8s:
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
name: "{{ helm_namespace }}"
|
name: "{{ test_namespace[4] }}"
|
||||||
state: absent
|
state: absent
|
||||||
wait: true
|
|
||||||
wait_timeout: 180
|
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
|
|
||||||
# CRDs aren't deleted with a namespace, so we need to manually delete it
|
# CRDs aren't deleted with a namespace, so we need to manually delete it
|
||||||
- name: Remove CRD
|
- name: Remove CRD
|
||||||
k8s:
|
k8s:
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
name: foos.example.com
|
name: foos.ansible.com
|
||||||
state: absent
|
state: absent
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
binary_path: "{{ helm_binary}}_fake"
|
binary_path: "{{ helm_binary}}_fake"
|
||||||
name: test
|
name: test
|
||||||
chart_ref: "{{ chart_test }}"
|
chart_ref: "{{ chart_test }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ test_namespace[3] }}"
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
register: helm_missing_binary
|
register: helm_missing_binary
|
||||||
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: does-not-exist
|
name: does-not-exist
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ test_namespace[1] }}"
|
||||||
environment:
|
environment:
|
||||||
K8S_AUTH_HOST: somewhere
|
K8S_AUTH_HOST: somewhere
|
||||||
register: _helm_result
|
register: _helm_result
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
---
|
---
|
||||||
- name: Chart tests
|
- name: Chart tests
|
||||||
|
vars:
|
||||||
|
chart_release_name: "test-{{ chart_name | default(source) }}"
|
||||||
|
chart_release_replaced_name: "test-{{ chart_name | default(source) }}-001"
|
||||||
block:
|
block:
|
||||||
- name: Create temp directory
|
- name: Create temp directory
|
||||||
tempfile:
|
tempfile:
|
||||||
@@ -13,7 +16,7 @@
|
|||||||
- name: Check helm_info empty
|
- name: Check helm_info empty
|
||||||
helm_info:
|
helm_info:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
name: test
|
name: "{{ chart_release_name }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
register: empty_info
|
register: empty_info
|
||||||
|
|
||||||
@@ -25,7 +28,7 @@
|
|||||||
- name: "Install fail {{ chart_test }} from {{ source }}"
|
- name: "Install fail {{ chart_test }} from {{ source }}"
|
||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
name: test
|
name: "{{ chart_release_name }}"
|
||||||
chart_ref: "{{ chart_source }}"
|
chart_ref: "{{ chart_source }}"
|
||||||
chart_version: "{{ chart_source_version | default(omit) }}"
|
chart_version: "{{ chart_source_version | default(omit) }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
@@ -41,7 +44,7 @@
|
|||||||
- name: "Install {{ chart_test }} from {{ source }} in check mode"
|
- name: "Install {{ chart_test }} from {{ source }} in check mode"
|
||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
name: test
|
name: "{{ chart_release_name }}"
|
||||||
chart_ref: "{{ chart_source }}"
|
chart_ref: "{{ chart_source }}"
|
||||||
chart_version: "{{ chart_source_version | default(omit) }}"
|
chart_version: "{{ chart_source_version | default(omit) }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
@@ -59,7 +62,7 @@
|
|||||||
- name: "Install {{ chart_test }} from {{ source }}"
|
- name: "Install {{ chart_test }} from {{ source }}"
|
||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
name: test
|
name: "{{ chart_release_name }}"
|
||||||
chart_ref: "{{ chart_source }}"
|
chart_ref: "{{ chart_source }}"
|
||||||
chart_version: "{{ chart_source_version | default(omit) }}"
|
chart_version: "{{ chart_source_version | default(omit) }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
@@ -76,7 +79,7 @@
|
|||||||
- name: Check helm_info content
|
- name: Check helm_info content
|
||||||
helm_info:
|
helm_info:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
name: test
|
name: "{{ chart_release_name }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
register: content_info
|
register: content_info
|
||||||
|
|
||||||
@@ -89,7 +92,7 @@
|
|||||||
- name: Check idempotency
|
- name: Check idempotency
|
||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
name: test
|
name: "{{ chart_release_name }}"
|
||||||
chart_ref: "{{ chart_source }}"
|
chart_ref: "{{ chart_source }}"
|
||||||
chart_version: "{{ chart_source_version | default(omit) }}"
|
chart_version: "{{ chart_source_version | default(omit) }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
@@ -105,7 +108,7 @@
|
|||||||
- name: "Add vars to {{ chart_test }} from {{ source }}"
|
- name: "Add vars to {{ chart_test }} from {{ source }}"
|
||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
name: test
|
name: "{{ chart_release_name }}"
|
||||||
chart_ref: "{{ chart_source }}"
|
chart_ref: "{{ chart_source }}"
|
||||||
chart_version: "{{ chart_source_version | default(omit) }}"
|
chart_version: "{{ chart_source_version | default(omit) }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
@@ -123,7 +126,7 @@
|
|||||||
- name: Check idempotency after adding vars
|
- name: Check idempotency after adding vars
|
||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
name: test
|
name: "{{ chart_release_name }}"
|
||||||
chart_ref: "{{ chart_source }}"
|
chart_ref: "{{ chart_source }}"
|
||||||
chart_version: "{{ chart_source_version | default(omit) }}"
|
chart_version: "{{ chart_source_version | default(omit) }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
@@ -141,7 +144,7 @@
|
|||||||
- name: "Remove Vars to {{ chart_test }} from {{ source }}"
|
- name: "Remove Vars to {{ chart_test }} from {{ source }}"
|
||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
name: test
|
name: "{{ chart_release_name }}"
|
||||||
chart_ref: "{{ chart_source }}"
|
chart_ref: "{{ chart_source }}"
|
||||||
chart_version: "{{ chart_source_version | default(omit) }}"
|
chart_version: "{{ chart_source_version | default(omit) }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
@@ -158,7 +161,7 @@
|
|||||||
- name: Check idempotency after removing vars
|
- name: Check idempotency after removing vars
|
||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
name: test
|
name: "{{ chart_release_name }}"
|
||||||
chart_ref: "{{ chart_source }}"
|
chart_ref: "{{ chart_source }}"
|
||||||
chart_version: "{{ chart_source_version | default(omit) }}"
|
chart_version: "{{ chart_source_version | default(omit) }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
@@ -175,7 +178,7 @@
|
|||||||
- name: "Upgrade {{ chart_test }} from {{ source }}"
|
- name: "Upgrade {{ chart_test }} from {{ source }}"
|
||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
name: test
|
name: "{{ chart_release_name }}"
|
||||||
chart_ref: "{{ chart_source_upgrade | default(chart_source) }}"
|
chart_ref: "{{ chart_source_upgrade | default(chart_source) }}"
|
||||||
chart_version: "{{ chart_source_version_upgrade | default(omit) }}"
|
chart_version: "{{ chart_source_version_upgrade | default(omit) }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
@@ -191,7 +194,7 @@
|
|||||||
- name: Check idempotency after upgrade
|
- name: Check idempotency after upgrade
|
||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
name: test
|
name: "{{ chart_release_name }}"
|
||||||
chart_ref: "{{ chart_source_upgrade | default(chart_source) }}"
|
chart_ref: "{{ chart_source_upgrade | default(chart_source) }}"
|
||||||
chart_version: "{{ chart_source_version_upgrade | default(omit) }}"
|
chart_version: "{{ chart_source_version_upgrade | default(omit) }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
@@ -208,7 +211,7 @@
|
|||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: test
|
name: "{{ chart_release_name }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
register: install
|
register: install
|
||||||
|
|
||||||
@@ -221,7 +224,7 @@
|
|||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: test
|
name: "{{ chart_release_name }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
register: install
|
register: install
|
||||||
|
|
||||||
@@ -234,7 +237,7 @@
|
|||||||
- name: Install chart for replace option
|
- name: Install chart for replace option
|
||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
name: test-0001
|
name: "{{ chart_release_replaced_name }}"
|
||||||
chart_ref: "{{ chart_source }}"
|
chart_ref: "{{ chart_source }}"
|
||||||
chart_version: "{{ chart_source_version | default(omit) }}"
|
chart_version: "{{ chart_source_version | default(omit) }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
@@ -245,11 +248,11 @@
|
|||||||
that:
|
that:
|
||||||
- install is changed
|
- install is changed
|
||||||
|
|
||||||
- name: Remove {{ chart_test }} with --purge
|
- name: "Remove {{ chart_release_replaced_name }} with --purge"
|
||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: test-0001
|
name: "{{ chart_release_replaced_name }}"
|
||||||
purge: False
|
purge: False
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
register: install
|
register: install
|
||||||
@@ -259,10 +262,10 @@
|
|||||||
that:
|
that:
|
||||||
- install is changed
|
- install is changed
|
||||||
|
|
||||||
- name: Install chart again with same name test-0001
|
- name: "Install chart again with same name {{ chart_release_replaced_name }}"
|
||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
name: test-0001
|
name: "{{ chart_release_replaced_name }}"
|
||||||
chart_ref: "{{ chart_source }}"
|
chart_ref: "{{ chart_source }}"
|
||||||
chart_version: "{{ chart_source_version | default(omit) }}"
|
chart_version: "{{ chart_source_version | default(omit) }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
@@ -278,7 +281,7 @@
|
|||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: test-0001
|
name: "{{ chart_release_replaced_name }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
register: install
|
register: install
|
||||||
|
|
||||||
@@ -290,7 +293,7 @@
|
|||||||
- name: "Install {{ chart_test }} from {{ source }} with values_files"
|
- name: "Install {{ chart_test }} from {{ source }} with values_files"
|
||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
name: test
|
name: "{{ chart_release_name }}"
|
||||||
chart_ref: "{{ chart_source }}"
|
chart_ref: "{{ chart_source }}"
|
||||||
chart_version: "{{ chart_source_version | default(omit) }}"
|
chart_version: "{{ chart_source_version | default(omit) }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
@@ -309,7 +312,7 @@
|
|||||||
- name: "Install {{ chart_test }} from {{ source }} with values_files (again)"
|
- name: "Install {{ chart_test }} from {{ source }} with values_files (again)"
|
||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
name: test
|
name: "{{ chart_release_name }}"
|
||||||
chart_ref: "{{ chart_source }}"
|
chart_ref: "{{ chart_source }}"
|
||||||
chart_version: "{{ chart_source_version | default(omit) }}"
|
chart_version: "{{ chart_source_version | default(omit) }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
@@ -351,7 +354,7 @@
|
|||||||
- name: Release using non-existent context
|
- name: Release using non-existent context
|
||||||
helm:
|
helm:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
name: test
|
name: "{{ chart_release_name }}"
|
||||||
chart_ref: "{{ chart_source }}"
|
chart_ref: "{{ chart_source }}"
|
||||||
chart_version: "{{ chart_source_version | default(omit) }}"
|
chart_version: "{{ chart_source_version | default(omit) }}"
|
||||||
namespace: "{{ helm_namespace }}"
|
namespace: "{{ helm_namespace }}"
|
||||||
@@ -379,5 +382,3 @@
|
|||||||
kind: Namespace
|
kind: Namespace
|
||||||
name: "{{ helm_namespace }}"
|
name: "{{ helm_namespace }}"
|
||||||
state: absent
|
state: absent
|
||||||
wait: true
|
|
||||||
wait_timeout: 180
|
|
||||||
@@ -22,6 +22,8 @@
|
|||||||
chart_source_upgrade: "/tmp/helm_test_repo_upgrade/stable/{{ chart_test_local_path }}/"
|
chart_source_upgrade: "/tmp/helm_test_repo_upgrade/stable/{{ chart_test_local_path }}/"
|
||||||
chart_test_version: "{{ chart_test_version_local_path }}"
|
chart_test_version: "{{ chart_test_version_local_path }}"
|
||||||
chart_test_version_upgrade: "{{ chart_test_version_upgrade_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
|
- name: Test appVersion idempotence
|
||||||
vars:
|
vars:
|
||||||
@@ -66,6 +68,8 @@
|
|||||||
source: local_path
|
source: local_path
|
||||||
chart_source: "/tmp/helm_test_appversion/test-chart/{{ chart_test }}-{{ chart_test_app_version }}-{{ chart_test_version }}.tgz"
|
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_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
|
- name: Test appVersion handling when null
|
||||||
vars:
|
vars:
|
||||||
@@ -94,6 +98,8 @@
|
|||||||
source: local_path
|
source: local_path
|
||||||
chart_source: "/tmp/helm_test_appversion/test-null/{{ chart_test }}/"
|
chart_source: "/tmp/helm_test_appversion/test-null/{{ chart_test }}/"
|
||||||
chart_source_upgrade: "{{ chart_test }}-{{ chart_test_version_upgrade }}.tgz"
|
chart_source_upgrade: "{{ chart_test }}-{{ chart_test_version_upgrade }}.tgz"
|
||||||
|
chart_name: "local-path-003"
|
||||||
|
helm_namespace: "{{ test_namespace[9] }}"
|
||||||
|
|
||||||
- name: Remove clone repos
|
- name: Remove clone repos
|
||||||
file:
|
file:
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
chart_source: "test_helm/{{ chart_test }}"
|
chart_source: "test_helm/{{ chart_test }}"
|
||||||
chart_source_version: "{{ chart_test_version }}"
|
chart_source_version: "{{ chart_test_version }}"
|
||||||
chart_source_version_upgrade: "{{ chart_test_version_upgrade }}"
|
chart_source_version_upgrade: "{{ chart_test_version_upgrade }}"
|
||||||
|
helm_namespace: "{{ test_namespace[6] }}"
|
||||||
|
|
||||||
- name: Add chart repo
|
- name: Add chart repo
|
||||||
helm_repository:
|
helm_repository:
|
||||||
@@ -5,3 +5,4 @@
|
|||||||
source: url
|
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: "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"
|
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] }}"
|
||||||
@@ -4,6 +4,9 @@
|
|||||||
test_chart_ref: "/tmp/test-chart"
|
test_chart_ref: "/tmp/test-chart"
|
||||||
|
|
||||||
block:
|
block:
|
||||||
|
- set_fact:
|
||||||
|
helm_namespace: "{{ test_namespace[0] }}"
|
||||||
|
|
||||||
- name: Install helm diff
|
- name: Install helm diff
|
||||||
helm_plugin:
|
helm_plugin:
|
||||||
binary_path: "{{ helm_binary }}"
|
binary_path: "{{ helm_binary }}"
|
||||||
@@ -148,6 +151,4 @@
|
|||||||
kind: Namespace
|
kind: Namespace
|
||||||
name: "{{ helm_namespace }}"
|
name: "{{ helm_namespace }}"
|
||||||
state: absent
|
state: absent
|
||||||
wait: yes
|
|
||||||
wait_timeout: 180
|
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
3
tests/integration/targets/inventory_k8s/aliases
Normal file
3
tests/integration/targets/inventory_k8s/aliases
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
context/target
|
||||||
|
time=42
|
||||||
|
k8s
|
||||||
102
tests/integration/targets/inventory_k8s/playbooks/play.yml
Normal file
102
tests/integration/targets/inventory_k8s/playbooks/play.yml
Normal 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
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
plugin: kubernetes.core.k8s
|
||||||
@@ -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 }}"
|
||||||
8
tests/integration/targets/inventory_k8s/runme.sh
Executable file
8
tests/integration/targets/inventory_k8s/runme.sh
Executable 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 "$@"
|
||||||
2
tests/integration/targets/k8s_access_review/aliases
Normal file
2
tests/integration/targets/k8s_access_review/aliases
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
time=7
|
||||||
|
k8s
|
||||||
2
tests/integration/targets/k8s_append_hash/aliases
Normal file
2
tests/integration/targets/k8s_append_hash/aliases
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
time=14
|
||||||
|
k8s
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
test_namespace: "append-hash"
|
||||||
2
tests/integration/targets/k8s_append_hash/meta/main.yml
Normal file
2
tests/integration/targets/k8s_append_hash/meta/main.yml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
dependencies:
|
||||||
|
- setup_namespace
|
||||||
@@ -3,14 +3,14 @@
|
|||||||
- name: Ensure that append_hash namespace exists
|
- name: Ensure that append_hash namespace exists
|
||||||
k8s:
|
k8s:
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
name: append-hash
|
name: "{{ test_namespace }}"
|
||||||
|
|
||||||
- name: Create k8s_resource variable
|
- name: Create k8s_resource variable
|
||||||
set_fact:
|
set_fact:
|
||||||
k8s_resource:
|
k8s_resource:
|
||||||
metadata:
|
metadata:
|
||||||
name: config-map-test
|
name: config-map-test
|
||||||
namespace: append-hash
|
namespace: "{{ test_namespace }}"
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
data:
|
data:
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
definition:
|
definition:
|
||||||
metadata:
|
metadata:
|
||||||
name: config-map-test
|
name: config-map-test
|
||||||
namespace: append-hash
|
namespace: "{{ test_namespace }}"
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
data:
|
data:
|
||||||
@@ -65,5 +65,5 @@
|
|||||||
- name: Ensure that namespace is removed
|
- name: Ensure that namespace is removed
|
||||||
k8s:
|
k8s:
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
name: append-hash
|
name: "{{ test_namespace }}"
|
||||||
state: absent
|
state: absent
|
||||||
5
tests/integration/targets/k8s_apply/aliases
Normal file
5
tests/integration/targets/k8s_apply/aliases
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# duration 9min
|
||||||
|
slow
|
||||||
|
k8s_service
|
||||||
|
k8s
|
||||||
|
time=192
|
||||||
@@ -37,4 +37,6 @@ k8s_pod_template:
|
|||||||
metadata: "{{ k8s_pod_metadata }}"
|
metadata: "{{ k8s_pod_metadata }}"
|
||||||
spec: "{{ k8s_pod_spec }}"
|
spec: "{{ k8s_pod_spec }}"
|
||||||
|
|
||||||
kubernetes_role_path: ../../tests/integration/targets/kubernetes
|
test_namespace: "apply"
|
||||||
|
|
||||||
|
k8s_wait_timeout: 240
|
||||||
2
tests/integration/targets/k8s_apply/meta/main.yml
Normal file
2
tests/integration/targets/k8s_apply/meta/main.yml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
dependencies:
|
||||||
|
- setup_namespace
|
||||||
@@ -1,20 +1,17 @@
|
|||||||
---
|
---
|
||||||
- block:
|
- block:
|
||||||
- set_fact:
|
|
||||||
apply_namespace: apply
|
|
||||||
|
|
||||||
- name: Ensure namespace exists
|
- name: Ensure namespace exists
|
||||||
k8s:
|
k8s:
|
||||||
definition:
|
definition:
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
metadata:
|
metadata:
|
||||||
name: "{{ apply_namespace }}"
|
name: "{{ test_namespace }}"
|
||||||
|
|
||||||
- name: Add a configmap
|
- name: Add a configmap
|
||||||
k8s:
|
k8s:
|
||||||
name: "apply-configmap"
|
name: "apply-configmap"
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
definition:
|
definition:
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
@@ -38,7 +35,7 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
metadata:
|
metadata:
|
||||||
name: "apply-configmap"
|
name: "apply-configmap"
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
data:
|
data:
|
||||||
one: "1"
|
one: "1"
|
||||||
two: "2"
|
two: "2"
|
||||||
@@ -58,7 +55,7 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
metadata:
|
metadata:
|
||||||
name: "apply-configmap"
|
name: "apply-configmap"
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
data:
|
data:
|
||||||
one: "1"
|
one: "1"
|
||||||
two: "2"
|
two: "2"
|
||||||
@@ -75,7 +72,7 @@
|
|||||||
- name: Add same configmap again but using name and namespace args
|
- name: Add same configmap again but using name and namespace args
|
||||||
k8s:
|
k8s:
|
||||||
name: "apply-configmap"
|
name: "apply-configmap"
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
definition:
|
definition:
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
@@ -98,7 +95,7 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
metadata:
|
metadata:
|
||||||
name: "apply-configmap"
|
name: "apply-configmap"
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
data:
|
data:
|
||||||
one: "1"
|
one: "1"
|
||||||
three: "3"
|
three: "3"
|
||||||
@@ -120,7 +117,7 @@
|
|||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: apply-svc
|
name: apply-svc
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: whatever
|
app: whatever
|
||||||
@@ -138,7 +135,7 @@
|
|||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: apply-svc
|
name: apply-svc
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: whatever
|
app: whatever
|
||||||
@@ -161,7 +158,7 @@
|
|||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: apply-svc
|
name: apply-svc
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: whatever
|
app: whatever
|
||||||
@@ -185,7 +182,7 @@
|
|||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: apply-svc
|
name: apply-svc
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: whatever
|
app: whatever
|
||||||
@@ -210,7 +207,7 @@
|
|||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: apply-svc
|
name: apply-svc
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: whatever
|
app: whatever
|
||||||
@@ -239,7 +236,7 @@
|
|||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: apply-svc
|
name: apply-svc
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: whatever
|
app: whatever
|
||||||
@@ -265,7 +262,7 @@
|
|||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: apply-svc
|
name: apply-svc
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: whatever
|
app: whatever
|
||||||
@@ -290,7 +287,7 @@
|
|||||||
kind: ServiceAccount
|
kind: ServiceAccount
|
||||||
metadata:
|
metadata:
|
||||||
name: apply-deploy
|
name: apply-deploy
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
|
|
||||||
- name: Add a deployment
|
- name: Add a deployment
|
||||||
k8s:
|
k8s:
|
||||||
@@ -299,7 +296,7 @@
|
|||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: apply-deploy
|
name: apply-deploy
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
@@ -307,6 +304,7 @@
|
|||||||
app: "{{ k8s_pod_name }}"
|
app: "{{ k8s_pod_name }}"
|
||||||
template: "{{ k8s_pod_template }}"
|
template: "{{ k8s_pod_template }}"
|
||||||
wait: yes
|
wait: yes
|
||||||
|
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
|
||||||
apply: yes
|
apply: yes
|
||||||
vars:
|
vars:
|
||||||
k8s_pod_name: apply-deploy
|
k8s_pod_name: apply-deploy
|
||||||
@@ -331,7 +329,7 @@
|
|||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: apply-deploy
|
name: apply-deploy
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
@@ -339,6 +337,7 @@
|
|||||||
app: "{{ k8s_pod_name }}"
|
app: "{{ k8s_pod_name }}"
|
||||||
template: "{{ k8s_pod_template }}"
|
template: "{{ k8s_pod_template }}"
|
||||||
wait: yes
|
wait: yes
|
||||||
|
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
|
||||||
apply: yes
|
apply: yes
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
vars:
|
vars:
|
||||||
@@ -370,7 +369,7 @@
|
|||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: apply-deploy
|
name: apply-deploy
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
@@ -378,6 +377,7 @@
|
|||||||
app: "{{ k8s_pod_name }}"
|
app: "{{ k8s_pod_name }}"
|
||||||
template: "{{ k8s_pod_template }}"
|
template: "{{ k8s_pod_template }}"
|
||||||
wait: yes
|
wait: yes
|
||||||
|
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
|
||||||
apply: yes
|
apply: yes
|
||||||
vars:
|
vars:
|
||||||
k8s_pod_name: apply-deploy
|
k8s_pod_name: apply-deploy
|
||||||
@@ -409,7 +409,7 @@
|
|||||||
kind: ServiceAccount
|
kind: ServiceAccount
|
||||||
metadata:
|
metadata:
|
||||||
name: apply-deploy
|
name: apply-deploy
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
|
|
||||||
- name: Apply deployment after service account removed
|
- name: Apply deployment after service account removed
|
||||||
k8s:
|
k8s:
|
||||||
@@ -418,7 +418,7 @@
|
|||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: apply-deploy
|
name: apply-deploy
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
@@ -426,6 +426,7 @@
|
|||||||
app: "{{ k8s_pod_name }}"
|
app: "{{ k8s_pod_name }}"
|
||||||
template: "{{ k8s_pod_template }}"
|
template: "{{ k8s_pod_template }}"
|
||||||
wait: yes
|
wait: yes
|
||||||
|
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
|
||||||
apply: yes
|
apply: yes
|
||||||
vars:
|
vars:
|
||||||
k8s_pod_name: apply-deploy
|
k8s_pod_name: apply-deploy
|
||||||
@@ -449,318 +450,6 @@
|
|||||||
that:
|
that:
|
||||||
- deploy_after_serviceaccount_removal is failed
|
- 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
|
- name: Add a secret
|
||||||
k8s:
|
k8s:
|
||||||
definition:
|
definition:
|
||||||
@@ -768,7 +457,7 @@
|
|||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: apply-secret
|
name: apply-secret
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
type: Opaque
|
type: Opaque
|
||||||
stringData:
|
stringData:
|
||||||
foo: bar
|
foo: bar
|
||||||
@@ -787,7 +476,7 @@
|
|||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: apply-secret
|
name: apply-secret
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
type: Opaque
|
type: Opaque
|
||||||
stringData:
|
stringData:
|
||||||
foo: bar
|
foo: bar
|
||||||
@@ -805,7 +494,7 @@
|
|||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: apply-secret
|
name: apply-secret
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
type: Opaque
|
type: Opaque
|
||||||
stringData:
|
stringData:
|
||||||
foo: bar
|
foo: bar
|
||||||
@@ -824,7 +513,7 @@
|
|||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: apply-secret
|
name: apply-secret
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
type: Opaque
|
type: Opaque
|
||||||
data:
|
data:
|
||||||
foo: YmFy
|
foo: YmFy
|
||||||
@@ -838,7 +527,7 @@
|
|||||||
|
|
||||||
- name: Create network policy (egress array with empty dict)
|
- name: Create network policy (egress array with empty dict)
|
||||||
k8s:
|
k8s:
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
apply: true
|
apply: true
|
||||||
definition:
|
definition:
|
||||||
kind: NetworkPolicy
|
kind: NetworkPolicy
|
||||||
@@ -865,7 +554,7 @@
|
|||||||
|
|
||||||
- name: Apply network policy
|
- name: Apply network policy
|
||||||
k8s:
|
k8s:
|
||||||
namespace: "{{ apply_namespace }}"
|
namespace: "{{ test_namespace }}"
|
||||||
definition:
|
definition:
|
||||||
kind: NetworkPolicy
|
kind: NetworkPolicy
|
||||||
apiVersion: networking.k8s.io/v1
|
apiVersion: networking.k8s.io/v1
|
||||||
@@ -900,5 +589,5 @@
|
|||||||
- name: Remove namespace
|
- name: Remove namespace
|
||||||
k8s:
|
k8s:
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
name: "{{ apply_namespace }}"
|
name: "{{ test_namespace }}"
|
||||||
state: absent
|
state: absent
|
||||||
2
tests/integration/targets/k8s_cluster_info/aliases
Normal file
2
tests/integration/targets/k8s_cluster_info/aliases
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
k8s_cluster_info
|
||||||
|
time=9
|
||||||
4
tests/integration/targets/k8s_copy/aliases
Normal file
4
tests/integration/targets/k8s_copy/aliases
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
k8s_exec
|
||||||
|
k8s_cp
|
||||||
|
k8s
|
||||||
|
time=101
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
# defaults file for k8copy
|
# defaults file for k8copy
|
||||||
copy_namespace: copy
|
test_namespace: copy
|
||||||
|
|
||||||
pod_with_one_container:
|
pod_with_one_container:
|
||||||
name: pod-copy-0
|
name: pod-copy-0
|
||||||
@@ -8,9 +8,9 @@ from __future__ import absolute_import, division, print_function
|
|||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = r'''
|
DOCUMENTATION = r"""
|
||||||
|
|
||||||
module: k8s_diff
|
module: k8s_create_file
|
||||||
|
|
||||||
short_description: Create large file with a defined size.
|
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.
|
- If this flag is set to yes, the generated file content binary data.
|
||||||
type: bool
|
type: bool
|
||||||
default: False
|
default: False
|
||||||
'''
|
"""
|
||||||
|
|
||||||
EXAMPLES = r'''
|
EXAMPLES = r"""
|
||||||
- name: create 150MB file
|
- name: create 150MB file
|
||||||
k8s_diff:
|
k8s_diff:
|
||||||
path: large_file.txt
|
path: large_file.txt
|
||||||
size: 150
|
size: 150
|
||||||
'''
|
"""
|
||||||
|
|
||||||
|
|
||||||
RETURN = r'''
|
RETURN = r"""
|
||||||
'''
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
@@ -57,17 +57,19 @@ from ansible.module_utils._text import to_native
|
|||||||
|
|
||||||
def execute_module(module):
|
def execute_module(module):
|
||||||
try:
|
try:
|
||||||
size = module.params.get('size') * 1024 * 1024
|
size = module.params.get("size") * 1024 * 1024
|
||||||
path = module.params.get('path')
|
path = module.params.get("path")
|
||||||
write_mode = "w"
|
write_mode = "w"
|
||||||
if module.params.get('binary'):
|
if module.params.get("binary"):
|
||||||
content = os.urandom(size)
|
content = os.urandom(size)
|
||||||
write_mode = "wb"
|
write_mode = "wb"
|
||||||
else:
|
else:
|
||||||
content = ""
|
content = ""
|
||||||
count = 0
|
count = 0
|
||||||
while len(content) < size:
|
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
|
count += 1
|
||||||
|
|
||||||
with open(path, write_mode) as f:
|
with open(path, write_mode) as f:
|
||||||
@@ -79,13 +81,13 @@ def execute_module(module):
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
argument_spec = {}
|
argument_spec = {}
|
||||||
argument_spec['size'] = {'type': 'int', 'default': 400}
|
argument_spec["size"] = {"type": "int", "default": 400}
|
||||||
argument_spec['path'] = {'type': 'path', 'required': True}
|
argument_spec["path"] = {"type": "path", "required": True}
|
||||||
argument_spec['binary'] = {'type': 'bool', 'default': False}
|
argument_spec["binary"] = {"type": "bool", "default": False}
|
||||||
module = AnsibleModule(argument_spec=argument_spec)
|
module = AnsibleModule(argument_spec=argument_spec)
|
||||||
|
|
||||||
execute_module(module)
|
execute_module(module)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
@@ -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()
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
---
|
---
|
||||||
collections:
|
collections:
|
||||||
- kubernetes.core
|
- kubernetes.core
|
||||||
|
dependencies:
|
||||||
|
- setup_namespace
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
---
|
---
|
||||||
|
- set_fact:
|
||||||
|
copy_namespace: "{{ test_namespace }}"
|
||||||
|
|
||||||
- block:
|
- block:
|
||||||
- name: Download kubeclt executable used to compare results
|
- name: Download kubeclt executable used to compare results
|
||||||
get_url:
|
get_url:
|
||||||
@@ -34,50 +34,65 @@
|
|||||||
kubectl_path: "{{ kubectl_path }}"
|
kubectl_path: "{{ kubectl_path }}"
|
||||||
|
|
||||||
# Binary file
|
# Binary file
|
||||||
- name: Generate random content
|
|
||||||
set_fact:
|
- name: Create temp binary file
|
||||||
hello_arg: "{{ lookup('password', '/dev/null chars=ascii_lowercase,digits length=16') }}"
|
tempfile:
|
||||||
|
state: file
|
||||||
|
register: binfile
|
||||||
|
|
||||||
|
- name: Generate random binary content
|
||||||
|
command: dd if=/dev/urandom of={{ binfile.path }} bs=1M count=1
|
||||||
|
|
||||||
- name: Copy executable into Pod
|
- name: Copy executable into Pod
|
||||||
k8s_cp:
|
k8s_cp:
|
||||||
namespace: '{{ copy_namespace }}'
|
namespace: '{{ copy_namespace }}'
|
||||||
pod: '{{ pod_with_one_container.name }}'
|
pod: '{{ pod_with_one_container.name }}'
|
||||||
remote_path: /tmp/hello.exe
|
remote_path: /tmp/hello.exe
|
||||||
local_path: files/hello
|
local_path: "{{ binfile.path }}"
|
||||||
state: to_pod
|
state: to_pod
|
||||||
|
|
||||||
- name: Compare executable
|
- name: Get remote hash
|
||||||
kubectl_file_compare:
|
kubernetes.core.k8s_exec:
|
||||||
namespace: '{{ copy_namespace }}'
|
namespace: "{{ copy_namespace }}"
|
||||||
pod: '{{ pod_with_one_container.name }}'
|
pod: "{{ pod_with_one_container.name }}"
|
||||||
remote_path: /tmp/hello.exe
|
command: sha256sum -b /tmp/hello.exe
|
||||||
local_path: "{{ role_path }}/files/hello"
|
register: remote_hash
|
||||||
kubectl_path: "{{ kubectl_path }}"
|
|
||||||
args:
|
- name: Get local hash
|
||||||
- "{{ hello_arg }}"
|
command: sha256sum -b {{ binfile.path }}
|
||||||
|
register: local_hash
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- remote_hash.stdout.split()[0] == local_hash.stdout.split()[0]
|
||||||
|
|
||||||
|
- name: Generate tempfile
|
||||||
|
tempfile:
|
||||||
|
state: file
|
||||||
|
register: binfile
|
||||||
|
|
||||||
- name: Copy executable from Pod
|
- name: Copy executable from Pod
|
||||||
k8s_cp:
|
k8s_cp:
|
||||||
namespace: '{{ copy_namespace }}'
|
namespace: '{{ copy_namespace }}'
|
||||||
pod: '{{ pod_with_one_container.name }}'
|
pod: '{{ pod_with_one_container.name }}'
|
||||||
remote_path: /tmp/hello.exe
|
remote_path: /tmp/hello.exe
|
||||||
local_path: /tmp/hello
|
local_path: "{{ binfile.path }}"
|
||||||
state: from_pod
|
state: from_pod
|
||||||
|
|
||||||
- name: update executable permission
|
- name: Get remote hash
|
||||||
file:
|
kubernetes.core.k8s_exec:
|
||||||
path: /tmp/hello
|
namespace: "{{ copy_namespace }}"
|
||||||
mode: '0755'
|
pod: "{{ pod_with_one_container.name }}"
|
||||||
|
command: sha256sum -b /tmp/hello.exe
|
||||||
|
register: remote_hash
|
||||||
|
|
||||||
- name: Compare executable
|
- name: Get local hash
|
||||||
kubectl_file_compare:
|
command: sha256sum -b {{ binfile.path }}
|
||||||
namespace: '{{ copy_namespace }}'
|
register: local_hash
|
||||||
pod: '{{ pod_with_one_container.name }}'
|
|
||||||
remote_path: /tmp/hello.exe
|
- assert:
|
||||||
local_path: /tmp/hello
|
that:
|
||||||
kubectl_path: "{{ kubectl_path }}"
|
- remote_hash.stdout.split()[0] == local_hash.stdout.split()[0]
|
||||||
args:
|
|
||||||
- "{{ hello_arg }}"
|
|
||||||
|
|
||||||
# zip files
|
# zip files
|
||||||
- name: copy zip file into remote pod
|
- name: copy zip file into remote pod
|
||||||
2
tests/integration/targets/k8s_crd/aliases
Normal file
2
tests/integration/targets/k8s_crd/aliases
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
time=22
|
||||||
|
k8s
|
||||||
2
tests/integration/targets/k8s_crd/defaults/main.yml
Normal file
2
tests/integration/targets/k8s_crd/defaults/main.yml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
test_namespace: "crd"
|
||||||
3
tests/integration/targets/k8s_crd/meta/main.yml
Normal file
3
tests/integration/targets/k8s_crd/meta/main.yml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
dependencies:
|
||||||
|
- setup_namespace
|
||||||
@@ -1,13 +1,8 @@
|
|||||||
---
|
---
|
||||||
- block:
|
- block:
|
||||||
- name: Create a namespace
|
|
||||||
k8s:
|
|
||||||
name: crd
|
|
||||||
kind: Namespace
|
|
||||||
|
|
||||||
- name: Install custom resource definitions
|
- name: Install custom resource definitions
|
||||||
k8s:
|
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
|
- name: Pause 5 seconds to avoid race condition
|
||||||
pause:
|
pause:
|
||||||
@@ -15,15 +10,15 @@
|
|||||||
|
|
||||||
- name: Create custom resource definition
|
- name: Create custom resource definition
|
||||||
k8s:
|
k8s:
|
||||||
definition: "{{ lookup('file', kubernetes_role_path + '/files/crd-resource.yml') }}"
|
definition: "{{ lookup('file', 'crd-resource.yml') }}"
|
||||||
namespace: crd
|
namespace: "{{ test_namespace }}"
|
||||||
apply: "{{ create_crd_with_apply | default(omit) }}"
|
apply: "{{ create_crd_with_apply | default(omit) }}"
|
||||||
register: create_crd
|
register: create_crd
|
||||||
|
|
||||||
- name: Patch custom resource definition
|
- name: Patch custom resource definition
|
||||||
k8s:
|
k8s:
|
||||||
definition: "{{ lookup('file', kubernetes_role_path + '/files/crd-resource.yml') }}"
|
definition: "{{ lookup('file', 'crd-resource.yml') }}"
|
||||||
namespace: crd
|
namespace: "{{ test_namespace }}"
|
||||||
register: recreate_crd
|
register: recreate_crd
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
|
|
||||||
@@ -35,33 +30,32 @@
|
|||||||
- block:
|
- block:
|
||||||
- name: Recreate custom resource definition with merge_type
|
- name: Recreate custom resource definition with merge_type
|
||||||
k8s:
|
k8s:
|
||||||
definition: "{{ lookup('file', kubernetes_role_path + '/files/crd-resource.yml') }}"
|
definition: "{{ lookup('file', 'crd-resource.yml') }}"
|
||||||
merge_type:
|
merge_type:
|
||||||
- merge
|
- merge
|
||||||
namespace: crd
|
namespace: "{{ test_namespace }}"
|
||||||
register: recreate_crd_with_merge
|
register: recreate_crd_with_merge
|
||||||
|
|
||||||
- name: Recreate custom resource definition with merge_type list
|
- name: Recreate custom resource definition with merge_type list
|
||||||
k8s:
|
k8s:
|
||||||
definition: "{{ lookup('file', kubernetes_role_path + '/files/crd-resource.yml') }}"
|
definition: "{{ lookup('file', 'crd-resource.yml') }}"
|
||||||
merge_type:
|
merge_type:
|
||||||
- strategic-merge
|
- strategic-merge
|
||||||
- merge
|
- merge
|
||||||
namespace: crd
|
namespace: "{{ test_namespace }}"
|
||||||
register: recreate_crd_with_merge_list
|
register: recreate_crd_with_merge_list
|
||||||
when: recreate_crd is successful
|
when: recreate_crd is successful
|
||||||
|
|
||||||
|
|
||||||
- name: Remove crd
|
- name: Remove crd
|
||||||
k8s:
|
k8s:
|
||||||
definition: "{{ lookup('file', kubernetes_role_path + '/files/crd-resource.yml') }}"
|
definition: "{{ lookup('file', 'crd-resource.yml') }}"
|
||||||
namespace: crd
|
namespace: "{{ test_namespace }}"
|
||||||
state: absent
|
state: absent
|
||||||
|
|
||||||
always:
|
always:
|
||||||
- name: Remove crd namespace
|
- name: Remove crd namespace
|
||||||
k8s:
|
k8s:
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
name: crd
|
name: "{{ test_namespace }}"
|
||||||
state: absent
|
state: absent
|
||||||
ignore_errors: yes
|
|
||||||
3
tests/integration/targets/k8s_delete/aliases
Normal file
3
tests/integration/targets/k8s_delete/aliases
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
time=70
|
||||||
|
k8s_info
|
||||||
|
k8s
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user