mirror of
https://github.com/ansible-collections/kubernetes.core.git
synced 2026-05-11 20:12:18 +00:00
Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8fa5b201a4 | ||
|
|
94c1f57f36 | ||
|
|
d0b97319a5 | ||
|
|
38d5c81051 | ||
|
|
914a16ec5c | ||
|
|
cb2070c93f | ||
|
|
b594d35931 | ||
|
|
00699ac3e5 | ||
|
|
d329e7ee42 | ||
|
|
d4fc22c74e | ||
|
|
b648f45e90 | ||
|
|
2cb5d6c316 | ||
|
|
0e7229cf8d | ||
|
|
9ec6912325 | ||
|
|
7cdf0d03f5 | ||
|
|
91df2f10bc | ||
|
|
1943dfc3d9 | ||
|
|
eb731cd3a5 | ||
|
|
ecc64cace1 | ||
|
|
bc0de24cba | ||
|
|
9f60b151ba | ||
|
|
159a63af97 | ||
|
|
6efabd3418 | ||
|
|
aee847431a | ||
|
|
6609abdd5a | ||
|
|
219c747a24 | ||
|
|
7559b65946 | ||
|
|
c8a33c7180 | ||
|
|
52f2cb5587 | ||
|
|
513ff66fcf | ||
|
|
fca0dc0485 | ||
|
|
cd686316e9 | ||
|
|
b8e9873f64 | ||
|
|
4c305e73f0 | ||
|
|
c8a9326306 | ||
|
|
445d367059 | ||
|
|
fdb8af7ca9 | ||
|
|
a89f19b4e5 | ||
|
|
5bc53dba7c | ||
|
|
b07fbd6271 | ||
|
|
44a2fc392a | ||
|
|
6265a3e7ce | ||
|
|
0afd257dd0 | ||
|
|
d192157ed8 | ||
|
|
6a04f42d0b | ||
|
|
5064d722c3 | ||
|
|
fb80d973c4 | ||
|
|
8363a4debf | ||
|
|
0c5233a650 | ||
|
|
c0666a5137 |
5
.ansible-lint-ignore
Normal file
5
.ansible-lint-ignore
Normal file
@@ -0,0 +1,5 @@
|
||||
# https://docs.ansible.com/ansible-lint/docs/rules/
|
||||
# no-changed-when is not requried for examples
|
||||
plugins/connection/kubectl.py no-changed-when
|
||||
# false positive result
|
||||
plugins/connection/kubectl.py var-naming[no-reserved]
|
||||
@@ -1,2 +0,0 @@
|
||||
# no-changed-when is not requried for examples
|
||||
plugins/connection/kubectl.py no-changed-when
|
||||
16
.github/workflows/integration-tests.yaml
vendored
16
.github/workflows/integration-tests.yaml
vendored
@@ -50,6 +50,7 @@ jobs:
|
||||
source: "./source"
|
||||
cloud_common: "./cloudcommon"
|
||||
ansible_posix: "./ansible_posix"
|
||||
community_general: "./community_general"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -61,7 +62,7 @@ jobs:
|
||||
- true
|
||||
- false
|
||||
workflow-id: ${{ fromJson(needs.splitter.outputs.test_jobs) }}
|
||||
name: "integration-py${{ matrix.python-version }}-${{ matrix.ansible-version }}-${{ matrix.workflow-id }}"
|
||||
name: "integration-py${{ matrix.python-version }}-${{ matrix.ansible-version }}-${{ matrix.workflow-id }}-enable_turbo=${{ matrix.enable-turbo-mode }}"
|
||||
steps:
|
||||
- name: Read target
|
||||
id: read-targets
|
||||
@@ -118,6 +119,13 @@ jobs:
|
||||
path: ${{ env.ansible_posix }}
|
||||
ref: main
|
||||
|
||||
- name: checkout ansible-collections/community.general
|
||||
uses: ansible-network/github_actions/.github/actions/checkout_dependency@main
|
||||
with:
|
||||
repository: ansible-collections/community.general
|
||||
path: ${{ env.community_general }}
|
||||
ref: main
|
||||
|
||||
- name: install cloud.common collection
|
||||
uses: ansible-network/github_actions/.github/actions/build_install_collection@main
|
||||
with:
|
||||
@@ -130,6 +138,12 @@ jobs:
|
||||
install_python_dependencies: true
|
||||
source_path: ${{ env.ansible_posix }}
|
||||
|
||||
- name: install community.general collection
|
||||
uses: ansible-network/github_actions/.github/actions/build_install_collection@main
|
||||
with:
|
||||
install_python_dependencies: false
|
||||
source_path: ${{ env.community_general }}
|
||||
|
||||
- name: create kubernetes cluster
|
||||
uses: helm/kind-action@v1.8.0
|
||||
with:
|
||||
|
||||
2
.github/workflows/linters.yaml
vendored
2
.github/workflows/linters.yaml
vendored
@@ -20,4 +20,4 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: run-ansible-lint
|
||||
uses: ansible/ansible-lint@v24.12.2
|
||||
uses: ansible/ansible-lint@v25.1.2
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -13,6 +13,7 @@ changelogs/.plugin-cache.yaml
|
||||
tests/output
|
||||
tests/integration/cloud-config-*
|
||||
.cache
|
||||
.ansible
|
||||
|
||||
# Helm charts
|
||||
tests/integration/*-chart-*.tgz
|
||||
|
||||
@@ -5,16 +5,24 @@ rules:
|
||||
braces:
|
||||
max-spaces-inside: 1
|
||||
level: error
|
||||
|
||||
brackets:
|
||||
max-spaces-inside: 1
|
||||
level: error
|
||||
comments:
|
||||
min-spaces-from-content: 1
|
||||
comments-indentation: false
|
||||
document-start: disable
|
||||
line-length: disable
|
||||
truthy: disable
|
||||
indentation:
|
||||
spaces: 2
|
||||
indent-sequences: consistent
|
||||
octal-values:
|
||||
forbid-implicit-octal: true
|
||||
forbid-explicit-octal: true
|
||||
ignore: |
|
||||
.cache
|
||||
.tox
|
||||
.ansible
|
||||
tests/output
|
||||
|
||||
@@ -4,22 +4,76 @@ Kubernetes Collection Release Notes
|
||||
|
||||
.. contents:: Topics
|
||||
|
||||
v6.0.0
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
This major release removes the deprecated ``k8s`` inventory plugin and also removes ``ansible-core<2.16`` support.
|
||||
|
||||
Breaking Changes / Porting Guide
|
||||
--------------------------------
|
||||
|
||||
- Remove deprecated ``k8s`` invetory plugin (https://github.com/ansible-collections/kubernetes.core/pull/867).
|
||||
- Remove support for ``ansible-core<2.16`` (https://github.com/ansible-collections/kubernetes.core/pull/867).
|
||||
|
||||
v5.3.0
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
This release includes minor changes, bug fixes and also bumps ``ansible-lint`` version to ``25.1.2``.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- kubernetes.core - Bump version of ``ansible-lint`` to ``25.1.2`` (https://github.com/ansible-collections/kubernetes.core/pull/919).
|
||||
- action/k8s_info - update templating mechanism with changes from ``ansible-core 2.19`` (https://github.com/ansible-collections/kubernetes.core/pull/888).
|
||||
- helm - add ``reset_then_reuse_values`` support to helm module (https://github.com/ansible-collections/kubernetes.core/issues/803).
|
||||
- helm - add support for ``insecure_skip_tls_verify`` option to helm and ``helm_repository`` (https://github.com/ansible-collections/kubernetes.core/issues/694).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- module_utils/k8s/service - Fix issue when trying to delete resource using ``delete_options`` and ``check_mode=true`` (https://github.com/ansible-collections/kubernetes.core/issues/892).
|
||||
|
||||
v5.2.0
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
This release adds more functionality to the hidden_fields option and support for waiting on ClusterOperators to reach a ready state.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- k8s - Extend hidden_fields to allow the expression of more complex field types to be hidden (https://github.com/ansible-collections/kubernetes.core/pull/872)
|
||||
- k8s_info - Extend hidden_fields to allow the expression of more complex field types to be hidden (https://github.com/ansible-collections/kubernetes.core/pull/872)
|
||||
- waiter.py - add ClusterOperator support. The module can now check OpenShift cluster health by verifying ClusterOperator status requiring 'Available: True', 'Degraded: False', and 'Progressing: False' for success. (https://github.com/ansible-collections/kubernetes.core/issues/869)
|
||||
|
||||
v5.1.0
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
This release came with new module ``helm_registry_auth``, improvements to the error messages in the k8s_drain module, new parameter ``insecure_registry`` for ``helm_template`` module and several bug fixes.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- Bump version of ansible-lint to minimum 24.7.0 (https://github.com/ansible-collections/kubernetes.core/pull/765).
|
||||
- Parameter insecure_registry added to helm_template as equivalent of insecure-skip-tls-verify (https://github.com/ansible-collections/kubernetes.core/pull/805).
|
||||
- connection/kubectl.py - Added an example of using the kubectl connection plugin to the documentation (https://github.com/ansible-collections/kubernetes.core/pull/741).
|
||||
- k8s_drain - Improve error message for pod disruption budget when draining a node (https://github.com/ansible-collections/kubernetes.core/issues/797).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- helm - Helm version checks did not support RC versions. They now accept any version tags. (https://github.com/ansible-collections/kubernetes.core/pull/745).
|
||||
- helm_pull - Apply no_log=True to pass_credentials to silence false positive warning.. (https://github.com/ansible-collections/kubernetes.core/pull/796).
|
||||
- helm_pull - Apply no_log=True to pass_credentials to silence false positive warning. (https://github.com/ansible-collections/kubernetes.core/pull/796).
|
||||
- k8s_drain - Fix k8s_drain does not wait for single pod (https://github.com/ansible-collections/kubernetes.core/issues/769).
|
||||
- k8s_drain - Fix k8s_drain runs into a timeout when evicting a pod which is part of a stateful set (https://github.com/ansible-collections/kubernetes.core/issues/792).
|
||||
- kubeconfig option should not appear in module invocation log (https://github.com/ansible-collections/kubernetes.core/issues/782).
|
||||
@@ -42,6 +96,7 @@ This major release drops support for ``ansible-core<2.15``.
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- connection/kubectl.py - Added an example of using the kubectl connection plugin to the documentation (https://github.com/ansible-collections/kubernetes.core/pull/741).
|
||||
- inventory/k8s.py - Defer removal of k8s inventory plugin to version 6.0.0 (https://github.com/ansible-collections/kubernetes.core/pull/734).
|
||||
|
||||
Breaking Changes / Porting Guide
|
||||
@@ -82,17 +137,32 @@ Bugfixes
|
||||
- helm - use ``reuse-values`` when running ``helm diff`` command (https://github.com/ansible-collections/kubernetes.core/issues/680).
|
||||
- integrations test helm_kubeconfig - set helm version to v3.10.3 to avoid incompatability with new bitnami charts (https://github.com/ansible-collections/kubernetes.core/pull/670).
|
||||
|
||||
v3.3.1
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
This release fixes the CI issues with the ``linters`` workflow.
|
||||
|
||||
v3.3.0
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
This release comes with improvements to the error messages in the k8s_drain module and several bug fixes.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
- inventory/k8s.py - Defer removal of k8s inventory plugin to version 5.0 (https://github.com/ansible-collections/kubernetes.core/pull/723).
|
||||
- inventory/k8s.py - Defer removal of k8s inventory plugin to version 6.0.0 (https://github.com/ansible-collections/kubernetes.core/pull/734).
|
||||
|
||||
- k8s_drain - Improve error message for pod disruption budget when draining a node (https://github.com/ansible-collections/kubernetes.core/issues/797).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- helm - Helm version checks did not support RC versions. They now accept any version tags. (https://github.com/ansible-collections/kubernetes.core/pull/745).
|
||||
- helm_pull - Apply no_log=True to pass_credentials to silence false positive warning.. (https://github.com/ansible-collections/kubernetes.core/pull/796).
|
||||
- helm_pull - Apply no_log=True to pass_credentials to silence false positive warning. (https://github.com/ansible-collections/kubernetes.core/pull/796).
|
||||
- k8s_drain - Fix k8s_drain does not wait for single pod (https://github.com/ansible-collections/kubernetes.core/issues/769).
|
||||
- k8s_drain - Fix k8s_drain runs into a timeout when evicting a pod which is part of a stateful set (https://github.com/ansible-collections/kubernetes.core/issues/792).
|
||||
- kubeconfig option should not appear in module invocation log (https://github.com/ansible-collections/kubernetes.core/issues/782).
|
||||
@@ -104,13 +174,15 @@ v3.2.0
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
This release comes with documentation updates.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- inventory/k8s.py - Defer removal of k8s inventory plugin to version 6.0.0 (https://github.com/ansible-collections/kubernetes.core/pull/734).
|
||||
- connection/kubectl.py - Added an example of using the kubectl connection plugin to the documentation (https://github.com/ansible-collections/kubernetes.core/pull/741).
|
||||
- inventory/k8s.py - Defer removal of k8s inventory plugin to version 5.0 (https://github.com/ansible-collections/kubernetes.core/pull/723).
|
||||
- inventory/k8s.py - Defer removal of k8s inventory plugin to version 6.0.0 (https://github.com/ansible-collections/kubernetes.core/pull/734).
|
||||
|
||||
v3.1.0
|
||||
======
|
||||
|
||||
2
Makefile
2
Makefile
@@ -1,5 +1,5 @@
|
||||
# Also needs to be updated in galaxy.yml
|
||||
VERSION = 5.1.0
|
||||
VERSION = 6.0.0
|
||||
|
||||
TEST_ARGS ?= ""
|
||||
PYTHON_VERSION ?= `python -c 'import platform; print(".".join(platform.python_version_tuple()[0:2]))'`
|
||||
|
||||
27
README.md
27
README.md
@@ -21,9 +21,9 @@ For more information about communication, see the [Ansible communication guide](
|
||||
## Requirements
|
||||
|
||||
<!--start requires_ansible-->
|
||||
## Ansible version compatibility
|
||||
### Ansible Version Compatibility
|
||||
|
||||
This collection has been tested against following Ansible versions: **>=2.15.0**.
|
||||
This collection has been tested against following Ansible versions: **>=2.16.0**.
|
||||
|
||||
For collections that support Ansible 2.9, please ensure you update your `network_os` to use the
|
||||
fully qualified collection name (for example, `cisco.ios.ios`).
|
||||
@@ -42,27 +42,22 @@ Note: Python2 is deprecated from [1st January 2020](https://www.python.org/doc/s
|
||||
|
||||
This collection supports Kubernetes versions >= 1.24.
|
||||
|
||||
### Included content
|
||||
### Included Content
|
||||
|
||||
Click on the name of a plugin or module to view that content's documentation:
|
||||
|
||||
<!--start collection content-->
|
||||
### Connection plugins
|
||||
### Connection Plugins
|
||||
Name | Description
|
||||
--- | ---
|
||||
[kubernetes.core.kubectl](https://github.com/ansible-collections/kubernetes.core/blob/main/docs/kubernetes.core.kubectl_connection.rst)|Execute tasks in pods running on Kubernetes.
|
||||
|
||||
### K8s filter plugins
|
||||
### K8s Filter Plugins
|
||||
Name | Description
|
||||
--- | ---
|
||||
kubernetes.core.k8s_config_resource_name|Generate resource name for the given resource of type ConfigMap, Secret
|
||||
|
||||
### Inventory plugins
|
||||
Name | Description
|
||||
--- | ---
|
||||
[kubernetes.core.k8s](https://github.com/ansible-collections/kubernetes.core/blob/main/docs/kubernetes.core.k8s_inventory.rst)|Kubernetes (K8s) inventory source
|
||||
|
||||
### Lookup plugins
|
||||
### Lookup Plugins
|
||||
Name | Description
|
||||
--- | ---
|
||||
[kubernetes.core.k8s](https://github.com/ansible-collections/kubernetes.core/blob/main/docs/kubernetes.core.k8s_lookup.rst)|Query the K8s API
|
||||
@@ -106,7 +101,7 @@ You can also include it in a `requirements.yml` file and install it via `ansible
|
||||
---
|
||||
collections:
|
||||
- name: kubernetes.core
|
||||
version: 5.1.0
|
||||
version: 6.0.0
|
||||
```
|
||||
|
||||
### Installing the Kubernetes Python Library
|
||||
@@ -183,7 +178,7 @@ If upgrading older playbooks which were built prior to Ansible 2.10 and this col
|
||||
|
||||
For documentation on how to use individual modules and other content included in this collection, please see the links in the 'Included content' section earlier in this README.
|
||||
|
||||
## Ansible Turbo mode Tech Preview
|
||||
## Ansible Turbo Mode Tech Preview
|
||||
|
||||
|
||||
The ``kubernetes.core`` collection supports Ansible Turbo mode as a tech preview via the ``cloud.common`` collection. By default, this feature is disabled. To enable Turbo mode for modules, set the environment variable `ENABLE_TURBO_MODE=1` on the managed node. For example:
|
||||
@@ -202,7 +197,7 @@ defined in the playbook using `environment` keyword as above, you must set it us
|
||||
|
||||
Please read more about Ansible Turbo mode - [here](https://github.com/ansible-collections/kubernetes.core/blob/main/docs/ansible_turbo_mode.rst).
|
||||
|
||||
## Contributing to this collection
|
||||
## Contributing to this Collection
|
||||
|
||||
If you want to develop new content for this collection or improve what's already here, the easiest way to work on the collection is to clone it into one of the configured [`COLLECTIONS_PATHS`](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#collections-paths), and work on it there.
|
||||
|
||||
@@ -252,6 +247,8 @@ The process for uploading a supported release to Automation Hub is documented se
|
||||
|
||||
<!--List available communication channels. In addition to channels specific to your collection, we also recommend to use the following ones.-->
|
||||
|
||||
> **Note:** The `stable-4` branch, which handles all `4.x.y` releases of this collection, is no longer supported. This means that no backports nor releases will be performed on the `stable-4` branch.
|
||||
|
||||
We announce releases and important changes through Ansible's [The Bullhorn newsletter](https://github.com/ansible/community/wiki/News#the-bullhorn). Be sure you are [subscribed](https://eepurl.com/gZmiEP).
|
||||
|
||||
We take part in the global quarterly [Ansible Contributor Summit](https://github.com/ansible/community/wiki/Contributor-Summit) virtually or in-person. Track [The Bullhorn newsletter](https://eepurl.com/gZmiEP) and join us.
|
||||
@@ -263,7 +260,7 @@ For the latest supported versions, refer to the release notes below.
|
||||
If you encounter issues or have questions, you can submit a support request through the following channels:
|
||||
- GitHub Issues: Report bugs, request features, or ask questions by opening an issue in the [GitHub repository]((https://github.com/ansible-collections/kubernetes.core/).
|
||||
|
||||
## Release notes
|
||||
## Release Notes
|
||||
|
||||
See the [raw generated changelog](https://github.com/ansible-collections/kubernetes.core/blob/main/CHANGELOG.rst).
|
||||
|
||||
|
||||
@@ -859,15 +859,15 @@ releases:
|
||||
minor_changes:
|
||||
- connection/kubectl.py - Added an example of using the kubectl connection plugin
|
||||
to the documentation (https://github.com/ansible-collections/kubernetes.core/pull/741).
|
||||
- inventory/k8s.py - Defer removal of k8s inventory plugin to version 5.0 (https://github.com/ansible-collections/kubernetes.core/pull/723).
|
||||
- inventory/k8s.py - Defer removal of k8s inventory plugin to version 6.0.0
|
||||
(https://github.com/ansible-collections/kubernetes.core/pull/734).
|
||||
- inventory/k8s.py - Defer removal of k8s inventory plugin to version 5.0 (https://github.com/ansible-collections/kubernetes.core/pull/723).
|
||||
release_summary: This release comes with documentation updates.
|
||||
fragments:
|
||||
- 20240530-defer-removal-and-ansible-core-support-update.yaml
|
||||
- 20240601-doc-example-of-using-kubectl.yaml
|
||||
- inventory-update_removal_date.yml
|
||||
- 3.2.0.yml
|
||||
- inventory-update_removal_date.yml
|
||||
release_date: '2024-06-14'
|
||||
3.3.0:
|
||||
changes:
|
||||
@@ -885,7 +885,8 @@ releases:
|
||||
minor_changes:
|
||||
- k8s_drain - Improve error message for pod disruption budget when draining
|
||||
a node (https://github.com/ansible-collections/kubernetes.core/issues/797).
|
||||
release_summary: This release comes with improvements to the error messages in the k8s_drain module and several bug fixes.
|
||||
release_summary: This release comes with improvements to the error messages
|
||||
in the k8s_drain module and several bug fixes.
|
||||
fragments:
|
||||
- 20240530-ansible-core-support-update.yaml
|
||||
- 20240611-helm-rc-version.yaml
|
||||
@@ -899,6 +900,12 @@ releases:
|
||||
- 798-drain-pdb-error-message.yaml
|
||||
- readme_template_update.yml
|
||||
release_date: '2025-01-20'
|
||||
3.3.1:
|
||||
changes:
|
||||
release_summary: This release fixes the CI issues with the ``linters`` workflow.
|
||||
fragments:
|
||||
- release_summary.yml
|
||||
release_date: '2025-03-26'
|
||||
4.0.0:
|
||||
changes:
|
||||
bugfixes:
|
||||
@@ -946,10 +953,10 @@ releases:
|
||||
breaking_changes:
|
||||
- Remove support for ``ansible-core<2.15`` (https://github.com/ansible-collections/kubernetes.core/pull/737).
|
||||
minor_changes:
|
||||
- inventory/k8s.py - Defer removal of k8s inventory plugin to version 6.0.0
|
||||
(https://github.com/ansible-collections/kubernetes.core/pull/734).
|
||||
- connection/kubectl.py - Added an example of using the kubectl connection plugin
|
||||
to the documentation (https://github.com/ansible-collections/kubernetes.core/pull/741).
|
||||
- inventory/k8s.py - Defer removal of k8s inventory plugin to version 6.0.0
|
||||
(https://github.com/ansible-collections/kubernetes.core/pull/734).
|
||||
release_summary: This major release drops support for ``ansible-core<2.15``.
|
||||
fragments:
|
||||
- 20240530-ansible-core-support-update.yaml
|
||||
@@ -976,8 +983,8 @@ releases:
|
||||
- k8s_drain - Improve error message for pod disruption budget when draining
|
||||
a node (https://github.com/ansible-collections/kubernetes.core/issues/797).
|
||||
release_summary: This release came with new module ``helm_registry_auth``, improvements
|
||||
to the error messages in the k8s_drain module, new parameter ``insecure_registry`` for
|
||||
``helm_template`` module and several bug fixes.
|
||||
to the error messages in the k8s_drain module, new parameter ``insecure_registry``
|
||||
for ``helm_template`` module and several bug fixes.
|
||||
fragments:
|
||||
- 0-readme.yml
|
||||
- 20240601-doc-example-of-using-kubectl.yaml
|
||||
@@ -999,3 +1006,49 @@ releases:
|
||||
name: helm_registry_auth
|
||||
namespace: ''
|
||||
release_date: '2025-01-20'
|
||||
5.2.0:
|
||||
changes:
|
||||
minor_changes:
|
||||
- k8s - Extend hidden_fields to allow the expression of more complex field types
|
||||
to be hidden (https://github.com/ansible-collections/kubernetes.core/pull/872)
|
||||
- k8s_info - Extend hidden_fields to allow the expression of more complex field
|
||||
types to be hidden (https://github.com/ansible-collections/kubernetes.core/pull/872)
|
||||
- 'waiter.py - add ClusterOperator support. The module can now check OpenShift
|
||||
cluster health by verifying ClusterOperator status requiring ''Available:
|
||||
True'', ''Degraded: False'', and ''Progressing: False'' for success. (https://github.com/ansible-collections/kubernetes.core/issues/869)'
|
||||
release_summary: This release adds more functionality to the hidden_fields option
|
||||
and support for waiting on ClusterOperators to reach a ready state.
|
||||
fragments:
|
||||
- 5.2.0.yml
|
||||
- 643-extend-hidden-fields.yaml
|
||||
- 879-clusteroperator-waiter.py.yaml
|
||||
release_date: '2025-03-27'
|
||||
5.3.0:
|
||||
changes:
|
||||
bugfixes:
|
||||
- module_utils/k8s/service - fix issue when trying to delete resource using
|
||||
`delete_options` and `check_mode=true` (https://github.com/ansible-collections/kubernetes.core/issues/892).
|
||||
minor_changes:
|
||||
- Bump version of ansible-lint to 25.1.2 (https://github.com/ansible-collections/kubernetes.core/pull/919).
|
||||
- action/k8s_info - update templating mechanism with changes from ``ansible-core
|
||||
2.19`` (https://github.com/ansible-collections/kubernetes.core/pull/888).
|
||||
- helm - add reset_then_reuse_values support to helm module (https://github.com/ansible-collections/kubernetes.core/issues/803).
|
||||
- helm - add support for ``insecure_skip_tls_verify`` option to helm and helm_repository(https://github.com/ansible-collections/kubernetes.core/issues/694).
|
||||
release_summary: This release includes minor changes, bug fixes and also bumps
|
||||
ansible-lint version to ``25.1.2``.
|
||||
fragments:
|
||||
- 20250324-k8s_info-templating.yaml
|
||||
- 5.3.0.yml
|
||||
- 694-add-insecure-skip-tls-verify.yml
|
||||
- 800-helm-add-reset_then_reuse_values-support.yml
|
||||
- 898-k8s-dont-delete-in-check-mode.yaml
|
||||
- 919-update-ansible-lint-version.yaml
|
||||
release_date: '2025-05-16'
|
||||
6.0.0:
|
||||
changes:
|
||||
breaking_changes:
|
||||
- Remove deprecated ``k8s`` invetory plugin (https://github.com/ansible-collections/kubernetes.core/pull/867).
|
||||
- Remove support for ``ansible-core<2.16`` (https://github.com/ansible-collections/kubernetes.core/pull/867).
|
||||
fragments:
|
||||
- 20250121-breaking-changes-6.0.0.yml
|
||||
release_date: '2025-05-19'
|
||||
|
||||
@@ -17,7 +17,7 @@ Requirements
|
||||
|
||||
To use the modules, you'll need the following:
|
||||
|
||||
- Ansible 2.9.17 or latest installed
|
||||
- Ansible 2.16.0 or latest installed
|
||||
- `Kubernetes Python client <https://pypi.org/project/kubernetes/>`_ installed on the host that will execute the modules.
|
||||
|
||||
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
.. _ansible_collections.kubernetes.core.docsite.k8s_ansible_inventory:
|
||||
|
||||
*****************************************
|
||||
Using Kubernetes dynamic inventory plugin
|
||||
*****************************************
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Kubernetes dynamic inventory plugin
|
||||
===================================
|
||||
|
||||
|
||||
The best way to interact with your Pods is to use the Kubernetes dynamic inventory plugin, which queries Kubernetes APIs using ``kubectl`` command line available on controller node and tells Ansible what Pods can be managed.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
To use the Kubernetes dynamic inventory plugins, you must install `Kubernetes Python client <https://github.com/kubernetes-client/python>`_, `kubectl <https://github.com/kubernetes/kubectl>`_ on your control node (the host running Ansible).
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pip install kubernetes
|
||||
|
||||
Please refer to Kubernetes official documentation for `installing kubectl <https://kubernetes.io/docs/tasks/tools/install-kubectl/>`_ on the given operating systems.
|
||||
|
||||
To use this Kubernetes dynamic inventory plugin, you need to enable it first by specifying the following in the ``ansible.cfg`` file:
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[inventory]
|
||||
enable_plugins = kubernetes.core.k8s
|
||||
|
||||
Then, create a file that ends in ``.k8s.yml`` or ``.k8s.yaml`` in your working directory.
|
||||
|
||||
The ``kubernetes.core.k8s`` inventory plugin takes in the same authentication information as any other Kubernetes modules.
|
||||
|
||||
Here's an example of a valid inventory file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
plugin: kubernetes.core.k8s
|
||||
|
||||
Executing ``ansible-inventory --list -i <filename>.k8s.yml`` will create a list of Pods that are ready to be configured using Ansible.
|
||||
|
||||
You can also provide the namespace to gather information about specific pods from the given namespace. For example, to gather information about Pods under the ``test`` namespace you will specify the ``namespaces`` parameter:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
plugin: kubernetes.core.k8s
|
||||
connections:
|
||||
- namespaces:
|
||||
- test
|
||||
|
||||
Using vaulted configuration files
|
||||
=================================
|
||||
|
||||
Since the inventory configuration file contains Kubernetes related sensitive information in plain text, a security risk, you may want to
|
||||
encrypt your entire inventory configuration file.
|
||||
|
||||
You can encrypt a valid inventory configuration file as follows:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ ansible-vault encrypt <filename>.k8s.yml
|
||||
New Vault password:
|
||||
Confirm New Vault password:
|
||||
Encryption successful
|
||||
|
||||
$ echo "MySuperSecretPassw0rd!" > /path/to/vault_password_file
|
||||
|
||||
And you can use this vaulted inventory configuration file using:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ ansible-inventory -i <filename>.k8s.yml --list --vault-password-file=/path/to/vault_password_file
|
||||
|
||||
|
||||
.. seealso::
|
||||
|
||||
`Kubernetes Python client - Issue Tracker <https://github.com/kubernetes-client/python/issues>`_
|
||||
The issue tracker for Kubernetes Python client
|
||||
`Kubectl installation <https://kubernetes.io/docs/tasks/tools/install-kubectl/>`_
|
||||
Installation guide for installing Kubectl
|
||||
:ref:`working_with_playbooks`
|
||||
An introduction to playbooks
|
||||
:ref:`playbooks_vault`
|
||||
Using Vault in playbooks
|
||||
@@ -13,6 +13,5 @@ To get started, please select one of the following topics.
|
||||
:maxdepth: 1
|
||||
|
||||
kubernetes_scenarios/k8s_intro
|
||||
kubernetes_scenarios/k8s_inventory
|
||||
kubernetes_scenarios/k8s_scenarios
|
||||
|
||||
|
||||
@@ -289,6 +289,29 @@ Parameters
|
||||
<div>Provide a URL for accessing the API. Can also be specified via <code>K8S_AUTH_HOST</code> environment variable.</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>insecure_skip_tls_verify</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">boolean</span>
|
||||
</div>
|
||||
<div style="font-style: italic; font-size: small; color: darkgreen">added in 5.3.0</div>
|
||||
</td>
|
||||
<td>
|
||||
<ul style="margin: 0; padding: 0"><b>Choices:</b>
|
||||
<li><div style="color: blue"><b>no</b> ←</div></li>
|
||||
<li>yes</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<div>Skip tls certificate checks for the chart download.</div>
|
||||
<div>Do not confuse with the <code>validate_certs</code> option.</div>
|
||||
<div>This option is only available for helm >= 3.16.0.</div>
|
||||
<div style="font-size: small; color: darkgreen"><br/>aliases: skip_tls_certs_check</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
@@ -435,6 +458,28 @@ Parameters
|
||||
<div>mutually exclusive with with <code>history_max</code>.</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>reset_then_reuse_values</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">boolean</span>
|
||||
</div>
|
||||
<div style="font-style: italic; font-size: small; color: darkgreen">added in 6.0.0</div>
|
||||
</td>
|
||||
<td>
|
||||
<ul style="margin: 0; padding: 0"><b>Choices:</b>
|
||||
<li><div style="color: blue"><b>no</b> ←</div></li>
|
||||
<li>yes</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<div>When upgrading package, reset the values to the ones built into the chart, apply the last release's values and merge in any overrides from parameters O(release_values), O(values_files) or O(set_values).</div>
|
||||
<div>If O(reset_values) or O(reuse_values) is set to V(True), this is ignored.</div>
|
||||
<div>This feature requires helm diff >= 3.9.12.</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
|
||||
@@ -279,7 +279,8 @@ Parameters
|
||||
</td>
|
||||
<td>
|
||||
<div>Whether or not to check tls certificate for the chart download.</div>
|
||||
<div>Requires helm >= 3.3.0.</div>
|
||||
<div>Requires helm >= 3.3.0. Alias <code>insecure_skip_tls_verify</code> added in 5.3.0.</div>
|
||||
<div style="font-size: small; color: darkgreen"><br/>aliases: insecure_skip_tls_verify</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -143,6 +143,27 @@ Parameters
|
||||
<div>Provide a URL for accessing the API. Can also be specified via <code>K8S_AUTH_HOST</code> environment variable.</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>insecure_skip_tls_verify</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">boolean</span>
|
||||
</div>
|
||||
<div style="font-style: italic; font-size: small; color: darkgreen">added in 5.3.0</div>
|
||||
</td>
|
||||
<td>
|
||||
<ul style="margin: 0; padding: 0"><b>Choices:</b>
|
||||
<li><div style="color: blue"><b>no</b> ←</div></li>
|
||||
<li>yes</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<div>Skip tls certificate checks for the repository url.</div>
|
||||
<div style="font-size: small; color: darkgreen"><br/>aliases: skip_tls_certs_check</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
|
||||
@@ -595,7 +595,8 @@ Examples
|
||||
kubernetes.core.k8s_drain:
|
||||
state: drain
|
||||
name: foo
|
||||
force: yes
|
||||
delete_options:
|
||||
force: yes
|
||||
|
||||
- name: Drain node "foo", but abort if there are pods not managed by a ReplicationController, Job, or DaemonSet, and use a grace period of 15 minutes.
|
||||
kubernetes.core.k8s_drain:
|
||||
|
||||
@@ -174,8 +174,7 @@ Parameters
|
||||
</td>
|
||||
<td>
|
||||
<div>Hide fields matching any of the field definitions in the result</div>
|
||||
<div>An example might be <code>hidden_fields=[metadata.managedFields]</code></div>
|
||||
<div>Only field definitions that don't reference list items are supported (so V(spec.containers[0]) would not work)</div>
|
||||
<div>An example might be <code>hidden_fields=[metadata.managedFields]</code> or V(hidden_fields=[spec.containers[0].env[3].value]) or V(hidden_fields=[metadata.annotations[kubectl.kubernetes.io/last-applied-configuration]])</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -1,372 +0,0 @@
|
||||
.. _kubernetes.core.k8s_inventory:
|
||||
|
||||
|
||||
*******************
|
||||
kubernetes.core.k8s
|
||||
*******************
|
||||
|
||||
**Kubernetes (K8s) inventory source**
|
||||
|
||||
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 1
|
||||
|
||||
DEPRECATED
|
||||
----------
|
||||
:Removed in collection release after
|
||||
:Why: As discussed in https://github.com/ansible-collections/kubernetes.core/issues/31, we decided to
|
||||
remove the k8s inventory plugin in release 6.0.0.
|
||||
|
||||
:Alternative: Use :ref:`kubernetes.core.k8s_info <kubernetes.core.k8s_info_module>` and :ref:`ansible.builtin.add_host <ansible.builtin.add_host_module>` instead.
|
||||
|
||||
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
- Fetch containers and services for one or more clusters.
|
||||
- Groups by cluster name, namespace, namespace_services, namespace_pods, and labels.
|
||||
- Uses the kubectl connection plugin to access the Kubernetes cluster.
|
||||
- Uses k8s.(yml|yaml) YAML configuration file to set parameter values.
|
||||
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
The below requirements are needed on the local Ansible controller node that executes this inventory.
|
||||
|
||||
- python >= 3.9
|
||||
- kubernetes >= 24.2.0
|
||||
- PyYAML >= 3.11
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<table border=0 cellpadding=0 class="documentation-table">
|
||||
<tr>
|
||||
<th colspan="2">Parameter</th>
|
||||
<th>Choices/<font color="blue">Defaults</font></th>
|
||||
<th>Configuration</th>
|
||||
<th width="100%">Comments</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>connections</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">-</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>Optional list of cluster connection settings. If no connections are provided, the default <em>~/.kube/config</em> and active context will be used, and objects will be returned for all namespaces the active user is authorized to access.</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="elbow-placeholder"></td>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>api_key</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">-</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>Token used to authenticate with the API. Can also be specified via K8S_AUTH_API_KEY environment variable.</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="elbow-placeholder"></td>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>ca_cert</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">-</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>Path to a CA certificate used to authenticate with the API. Can also be specified via K8S_AUTH_SSL_CA_CERT environment variable.</div>
|
||||
<div style="font-size: small; color: darkgreen"><br/>aliases: ssl_ca_cert</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="elbow-placeholder"></td>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>client_cert</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">-</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>Path to a certificate used to authenticate with the API. Can also be specified via K8S_AUTH_CERT_FILE environment variable.</div>
|
||||
<div style="font-size: small; color: darkgreen"><br/>aliases: cert_file</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="elbow-placeholder"></td>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>client_key</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">-</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>Path to a key file used to authenticate with the API. Can also be specified via K8S_AUTH_KEY_FILE environment variable.</div>
|
||||
<div style="font-size: small; color: darkgreen"><br/>aliases: key_file</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="elbow-placeholder"></td>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>context</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">-</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>The name of a context found in the config file. Can also be specified via K8S_AUTH_CONTEXT environment variable.</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="elbow-placeholder"></td>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>host</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">-</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>Provide a URL for accessing the API. Can also be specified via K8S_AUTH_HOST environment variable.</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="elbow-placeholder"></td>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>kubeconfig</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">-</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>Path to an existing Kubernetes config file. If not provided, and no other connection options are provided, the Kubernetes client will attempt to load the default configuration file from <em>~/.kube/config</em>. Can also be specified via K8S_AUTH_KUBECONFIG environment variable.</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="elbow-placeholder"></td>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>name</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">-</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>Optional name to assign to the cluster. If not provided, a name is constructed from the server and port.</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="elbow-placeholder"></td>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>namespaces</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">-</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>List of namespaces. If not specified, will fetch all containers for all namespaces user is authorized to access.</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="elbow-placeholder"></td>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>password</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">-</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>Provide a password for authenticating with the API. Can also be specified via K8S_AUTH_PASSWORD environment variable.</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="elbow-placeholder"></td>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>username</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">-</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>Provide a username for authenticating with the API. Can also be specified via K8S_AUTH_USERNAME environment variable.</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="elbow-placeholder"></td>
|
||||
<td colspan="1">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>validate_certs</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">boolean</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<ul style="margin: 0; padding: 0"><b>Choices:</b>
|
||||
<li>no</li>
|
||||
<li>yes</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>Whether or not to verify the API server's SSL certificates. Can also be specified via K8S_AUTH_VERIFY_SSL environment variable.</div>
|
||||
<div style="font-size: small; color: darkgreen"><br/>aliases: verify_ssl</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||
<b>plugin</b>
|
||||
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">-</span>
|
||||
/ <span style="color: red">required</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<ul style="margin: 0; padding: 0"><b>Choices:</b>
|
||||
<li>kubernetes.core.k8s</li>
|
||||
<li>k8s</li>
|
||||
<li>community.kubernetes.k8s</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<div>token that ensures this is a source file for the 'k8s' plugin.</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
|
||||
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# File must be named k8s.yaml or k8s.yml
|
||||
|
||||
- name: Authenticate with token, and return all pods and services for all namespaces
|
||||
plugin: kubernetes.core.k8s
|
||||
connections:
|
||||
- host: https://192.168.64.4:8443
|
||||
api_key: xxxxxxxxxxxxxxxx
|
||||
validate_certs: false
|
||||
|
||||
- name: Use default config (~/.kube/config) file and active context, and return objects for a specific namespace
|
||||
plugin: kubernetes.core.k8s
|
||||
connections:
|
||||
- namespaces:
|
||||
- testing
|
||||
|
||||
- name: Use a custom config file, and a specific context.
|
||||
plugin: kubernetes.core.k8s
|
||||
connections:
|
||||
- kubeconfig: /path/to/config
|
||||
context: 'awx/192-168-64-4:8443/developer'
|
||||
|
||||
|
||||
|
||||
|
||||
Status
|
||||
------
|
||||
|
||||
|
||||
- This inventory will be removed in version 6.0.0. *[deprecated]*
|
||||
- For more information see `DEPRECATED`_.
|
||||
|
||||
|
||||
Authors
|
||||
~~~~~~~
|
||||
|
||||
- Chris Houseknecht (@chouseknecht)
|
||||
- Fabian von Feilitzsch (@fabianvf)
|
||||
|
||||
|
||||
.. hint::
|
||||
Configuration entries for each entry type have a low to high priority order. For example, a variable that is lower in the list will override a variable that is higher up.
|
||||
@@ -395,8 +395,7 @@ Parameters
|
||||
</td>
|
||||
<td>
|
||||
<div>Hide fields matching this option in the result</div>
|
||||
<div>An example might be <code>hidden_fields=[metadata.managedFields]</code></div>
|
||||
<div>Only field definitions that don't reference list items are supported (so V(spec.containers[0]) would not work)</div>
|
||||
<div>An example might be <code>hidden_fields=[metadata.managedFields]</code> or V(hidden_fields=[spec.containers[0].env[3].value]) or V(hidden_fields=[metadata.annotations[kubectl.kubernetes.io/last-applied-configuration]])</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -25,7 +25,7 @@ tags:
|
||||
- openshift
|
||||
- okd
|
||||
- cluster
|
||||
version: 5.1.0
|
||||
version: 6.0.0
|
||||
build_ignore:
|
||||
- .DS_Store
|
||||
- "*.tar.gz"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
requires_ansible: '>=2.15.0'
|
||||
requires_ansible: '>=2.16.0'
|
||||
|
||||
action_groups:
|
||||
helm:
|
||||
@@ -21,11 +21,10 @@ plugin_routing:
|
||||
openshift:
|
||||
redirect: community.okd.openshift
|
||||
k8s:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 6.0.0
|
||||
warning_text: >-
|
||||
The k8s inventory plugin has been deprecated and
|
||||
will be removed in release 6.0.0.
|
||||
The k8s inventory plugin was slated for deprecation in 3.3.0 and has been removed in release 6.0.0. Use kubernetes.core.k8s_info and ansible.builtin.add_host instead.
|
||||
modules:
|
||||
k8s_auth:
|
||||
redirect: community.okd.k8s_auth
|
||||
|
||||
@@ -25,30 +25,18 @@ from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.module_utils.six import iteritems, string_types
|
||||
from ansible.plugins.action import ActionBase
|
||||
|
||||
try:
|
||||
from ansible.template import trust_as_template
|
||||
except ImportError:
|
||||
trust_as_template = None
|
||||
|
||||
class RemoveOmit(object):
|
||||
def __init__(self, buffer, omit_value):
|
||||
try:
|
||||
import yaml
|
||||
except ImportError:
|
||||
raise AnsibleError("Failed to import the required Python library (PyYAML).")
|
||||
self.data = yaml.safe_load_all(buffer)
|
||||
self.omit = omit_value
|
||||
|
||||
def remove_omit(self, data):
|
||||
if isinstance(data, dict):
|
||||
result = dict()
|
||||
for key, value in iteritems(data):
|
||||
if value == self.omit:
|
||||
continue
|
||||
result[key] = self.remove_omit(value)
|
||||
return result
|
||||
if isinstance(data, list):
|
||||
return [self.remove_omit(v) for v in data if v != self.omit]
|
||||
return data
|
||||
|
||||
def output(self):
|
||||
return [self.remove_omit(d) for d in self.data]
|
||||
def _from_yaml_to_definition(buffer):
|
||||
try:
|
||||
import yaml
|
||||
except ImportError:
|
||||
raise AnsibleError("Failed to import the required Python library (PyYAML).")
|
||||
return list(yaml.safe_load_all(buffer))
|
||||
|
||||
|
||||
ENV_KUBECONFIG_PATH_SEPARATOR = ";" if platform.system() == "Windows" else ":"
|
||||
@@ -207,7 +195,6 @@ class ActionModule(ActionBase):
|
||||
"'template' is only a supported parameter for the 'k8s' module."
|
||||
)
|
||||
|
||||
omit_value = task_vars.get("omit")
|
||||
template_params = []
|
||||
if isinstance(template, string_types) or isinstance(template, dict):
|
||||
template_params.append(self.get_template_args(template))
|
||||
@@ -230,17 +217,18 @@ class ActionModule(ActionBase):
|
||||
old_vars = self._templar.available_variables
|
||||
|
||||
default_environment = {}
|
||||
for key in (
|
||||
"newline_sequence",
|
||||
"variable_start_string",
|
||||
"variable_end_string",
|
||||
"block_start_string",
|
||||
"block_end_string",
|
||||
"trim_blocks",
|
||||
"lstrip_blocks",
|
||||
):
|
||||
if hasattr(self._templar.environment, key):
|
||||
default_environment[key] = getattr(self._templar.environment, key)
|
||||
if trust_as_template is None:
|
||||
for key in (
|
||||
"newline_sequence",
|
||||
"variable_start_string",
|
||||
"variable_end_string",
|
||||
"block_start_string",
|
||||
"block_end_string",
|
||||
"trim_blocks",
|
||||
"lstrip_blocks",
|
||||
):
|
||||
if hasattr(self._templar.environment, key):
|
||||
default_environment[key] = getattr(self._templar.environment, key)
|
||||
for template_item in template_params:
|
||||
# We need to convert unescaped sequences to proper escaped sequences for Jinja2
|
||||
newline_sequence = template_item["newline_sequence"]
|
||||
@@ -257,26 +245,35 @@ class ActionModule(ActionBase):
|
||||
with self.get_template_data(template_item["path"]) as template_data:
|
||||
# add ansible 'template' vars
|
||||
temp_vars = copy.deepcopy(task_vars)
|
||||
overrides = {}
|
||||
for key, value in iteritems(template_item):
|
||||
if hasattr(self._templar.environment, key):
|
||||
if value is not None:
|
||||
setattr(self._templar.environment, key, value)
|
||||
else:
|
||||
overrides[key] = value
|
||||
if trust_as_template is None:
|
||||
setattr(self._templar.environment, key, value)
|
||||
elif trust_as_template is None:
|
||||
setattr(
|
||||
self._templar.environment,
|
||||
key,
|
||||
default_environment.get(key),
|
||||
)
|
||||
self._templar.available_variables = temp_vars
|
||||
result = self._templar.do_template(
|
||||
template_data,
|
||||
preserve_trailing_newlines=True,
|
||||
escape_backslashes=False,
|
||||
)
|
||||
if omit_value is not None:
|
||||
result_template.extend(RemoveOmit(result, omit_value).output())
|
||||
if trust_as_template:
|
||||
template_data = trust_as_template(template_data)
|
||||
result = self._templar.template(
|
||||
template_data,
|
||||
preserve_trailing_newlines=True,
|
||||
escape_backslashes=False,
|
||||
overrides=overrides,
|
||||
)
|
||||
else:
|
||||
result_template.append(result)
|
||||
result = self._templar.do_template(
|
||||
template_data,
|
||||
preserve_trailing_newlines=True,
|
||||
escape_backslashes=False,
|
||||
)
|
||||
result_template.extend(_from_yaml_to_definition(result))
|
||||
self._templar.available_variables = old_vars
|
||||
resource_definition = self._task.args.get("definition", None)
|
||||
if not resource_definition:
|
||||
|
||||
@@ -1,476 +0,0 @@
|
||||
# Copyright (c) 2018 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 = """
|
||||
name: k8s
|
||||
author:
|
||||
- Chris Houseknecht (@chouseknecht)
|
||||
- Fabian von Feilitzsch (@fabianvf)
|
||||
|
||||
short_description: Kubernetes (K8s) inventory source
|
||||
|
||||
description:
|
||||
- Fetch containers and services for one or more clusters.
|
||||
- Groups by cluster name, namespace, namespace_services, namespace_pods, and labels.
|
||||
- Uses the kubectl connection plugin to access the Kubernetes cluster.
|
||||
- Uses k8s.(yml|yaml) YAML configuration file to set parameter values.
|
||||
|
||||
deprecated:
|
||||
removed_in: 6.0.0
|
||||
why: |
|
||||
As discussed in U(https://github.com/ansible-collections/kubernetes.core/issues/31), we decided to
|
||||
remove the k8s inventory plugin in release 6.0.0.
|
||||
alternative: "Use M(kubernetes.core.k8s_info) and M(ansible.builtin.add_host) instead."
|
||||
|
||||
options:
|
||||
plugin:
|
||||
description: token that ensures this is a source file for the 'k8s' plugin.
|
||||
required: True
|
||||
choices: ['kubernetes.core.k8s', 'k8s', 'community.kubernetes.k8s']
|
||||
connections:
|
||||
description:
|
||||
- Optional list of cluster connection settings. If no connections are provided, the default
|
||||
I(~/.kube/config) and active context will be used, and objects will be returned for all namespaces
|
||||
the active user is authorized to access.
|
||||
suboptions:
|
||||
name:
|
||||
description:
|
||||
- Optional name to assign to the cluster. If not provided, a name is constructed from the server
|
||||
and port.
|
||||
kubeconfig:
|
||||
description:
|
||||
- Path to an existing Kubernetes config file. If not provided, and no other connection
|
||||
options are provided, the Kubernetes client will attempt to load the default
|
||||
configuration file from I(~/.kube/config). Can also be specified via K8S_AUTH_KUBECONFIG
|
||||
environment variable.
|
||||
context:
|
||||
description:
|
||||
- The name of a context found in the config file. Can also be specified via K8S_AUTH_CONTEXT environment
|
||||
variable.
|
||||
host:
|
||||
description:
|
||||
- Provide a URL for accessing the API. Can also be specified via K8S_AUTH_HOST environment variable.
|
||||
api_key:
|
||||
description:
|
||||
- Token used to authenticate with the API. Can also be specified via K8S_AUTH_API_KEY environment
|
||||
variable.
|
||||
username:
|
||||
description:
|
||||
- Provide a username for authenticating with the API. Can also be specified via K8S_AUTH_USERNAME
|
||||
environment variable.
|
||||
password:
|
||||
description:
|
||||
- Provide a password for authenticating with the API. Can also be specified via K8S_AUTH_PASSWORD
|
||||
environment variable.
|
||||
client_cert:
|
||||
description:
|
||||
- Path to a certificate used to authenticate with the API. Can also be specified via K8S_AUTH_CERT_FILE
|
||||
environment variable.
|
||||
aliases: [ cert_file ]
|
||||
client_key:
|
||||
description:
|
||||
- Path to a key file used to authenticate with the API. Can also be specified via K8S_AUTH_KEY_FILE
|
||||
environment variable.
|
||||
aliases: [ key_file ]
|
||||
ca_cert:
|
||||
description:
|
||||
- Path to a CA certificate used to authenticate with the API. Can also be specified via
|
||||
K8S_AUTH_SSL_CA_CERT environment variable.
|
||||
aliases: [ ssl_ca_cert ]
|
||||
validate_certs:
|
||||
description:
|
||||
- "Whether or not to verify the API server's SSL certificates. Can also be specified via
|
||||
K8S_AUTH_VERIFY_SSL environment variable."
|
||||
type: bool
|
||||
aliases: [ verify_ssl ]
|
||||
namespaces:
|
||||
description:
|
||||
- List of namespaces. If not specified, will fetch all containers for all namespaces user is authorized
|
||||
to access.
|
||||
|
||||
requirements:
|
||||
- "python >= 3.9"
|
||||
- "kubernetes >= 24.2.0"
|
||||
- "PyYAML >= 3.11"
|
||||
"""
|
||||
|
||||
EXAMPLES = r"""
|
||||
# File must be named k8s.yaml or k8s.yml
|
||||
|
||||
- name: Authenticate with token, and return all pods and services for all namespaces
|
||||
plugin: kubernetes.core.k8s
|
||||
connections:
|
||||
- host: https://192.168.64.4:8443
|
||||
api_key: xxxxxxxxxxxxxxxx
|
||||
validate_certs: false
|
||||
|
||||
- name: Use default config (~/.kube/config) file and active context, and return objects for a specific namespace
|
||||
plugin: kubernetes.core.k8s
|
||||
connections:
|
||||
- namespaces:
|
||||
- testing
|
||||
|
||||
- name: Use a custom config file, and a specific context.
|
||||
plugin: kubernetes.core.k8s
|
||||
connections:
|
||||
- kubeconfig: /path/to/config
|
||||
context: 'awx/192-168-64-4:8443/developer'
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.plugins.inventory import BaseInventoryPlugin, Cacheable, Constructable
|
||||
|
||||
try:
|
||||
from kubernetes.dynamic.exceptions import DynamicApiError
|
||||
|
||||
HAS_K8S_MODULE_HELPER = True
|
||||
k8s_import_exception = None
|
||||
except ImportError as e:
|
||||
HAS_K8S_MODULE_HELPER = False
|
||||
k8s_import_exception = e
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.client import (
|
||||
get_api_client,
|
||||
)
|
||||
|
||||
|
||||
def format_dynamic_api_exc(exc):
|
||||
if exc.body:
|
||||
if exc.headers and exc.headers.get("Content-Type") == "application/json":
|
||||
message = json.loads(exc.body).get("message")
|
||||
if message:
|
||||
return message
|
||||
return exc.body
|
||||
else:
|
||||
return "%s Reason: %s" % (exc.status, exc.reason)
|
||||
|
||||
|
||||
class K8sInventoryException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
NAME = "kubernetes.core.k8s"
|
||||
|
||||
connection_plugin = "kubernetes.core.kubectl"
|
||||
transport = "kubectl"
|
||||
|
||||
def parse(self, inventory, loader, path, cache=True):
|
||||
super(InventoryModule, self).parse(inventory, loader, path)
|
||||
|
||||
self.display.deprecated(
|
||||
"The 'k8s' inventory plugin has been deprecated and will be removed in release 6.0.0",
|
||||
version="6.0.0",
|
||||
collection_name="kubernetes.core",
|
||||
)
|
||||
cache_key = self._get_cache_prefix(path)
|
||||
config_data = self._read_config_data(path)
|
||||
self.setup(config_data, cache, cache_key)
|
||||
|
||||
def setup(self, config_data, cache, cache_key):
|
||||
connections = config_data.get("connections")
|
||||
|
||||
if not HAS_K8S_MODULE_HELPER:
|
||||
raise K8sInventoryException(
|
||||
"This module requires the Kubernetes Python client. Try `pip install kubernetes`. Detail: {0}".format(
|
||||
k8s_import_exception
|
||||
)
|
||||
)
|
||||
|
||||
source_data = None
|
||||
if cache and cache_key in self._cache:
|
||||
try:
|
||||
source_data = self._cache[cache_key]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if not source_data:
|
||||
self.fetch_objects(connections)
|
||||
|
||||
def fetch_objects(self, connections):
|
||||
if connections:
|
||||
if not isinstance(connections, list):
|
||||
raise K8sInventoryException("Expecting connections to be a list.")
|
||||
|
||||
for connection in connections:
|
||||
if not isinstance(connection, dict):
|
||||
raise K8sInventoryException(
|
||||
"Expecting connection to be a dictionary."
|
||||
)
|
||||
client = get_api_client(**connection)
|
||||
name = connection.get(
|
||||
"name", self.get_default_host_name(client.configuration.host)
|
||||
)
|
||||
if connection.get("namespaces"):
|
||||
namespaces = connection["namespaces"]
|
||||
else:
|
||||
namespaces = self.get_available_namespaces(client)
|
||||
for namespace in namespaces:
|
||||
self.get_pods_for_namespace(client, name, namespace)
|
||||
self.get_services_for_namespace(client, name, namespace)
|
||||
else:
|
||||
client = get_api_client()
|
||||
name = self.get_default_host_name(client.configuration.host)
|
||||
namespaces = self.get_available_namespaces(client)
|
||||
for namespace in namespaces:
|
||||
self.get_pods_for_namespace(client, name, namespace)
|
||||
self.get_services_for_namespace(client, name, namespace)
|
||||
|
||||
@staticmethod
|
||||
def get_default_host_name(host):
|
||||
return (
|
||||
host.replace("https://", "")
|
||||
.replace("http://", "")
|
||||
.replace(".", "-")
|
||||
.replace(":", "_")
|
||||
)
|
||||
|
||||
def get_available_namespaces(self, client):
|
||||
v1_namespace = client.resources.get(api_version="v1", kind="Namespace")
|
||||
try:
|
||||
obj = v1_namespace.get()
|
||||
except DynamicApiError as exc:
|
||||
self.display.debug(exc)
|
||||
raise K8sInventoryException(
|
||||
"Error fetching Namespace list: %s" % format_dynamic_api_exc(exc)
|
||||
)
|
||||
return [namespace.metadata.name for namespace in obj.items]
|
||||
|
||||
def get_pods_for_namespace(self, client, name, namespace):
|
||||
v1_pod = client.resources.get(api_version="v1", kind="Pod")
|
||||
try:
|
||||
obj = v1_pod.get(namespace=namespace)
|
||||
except DynamicApiError as exc:
|
||||
self.display.debug(exc)
|
||||
raise K8sInventoryException(
|
||||
"Error fetching Pod list: %s" % format_dynamic_api_exc(exc)
|
||||
)
|
||||
|
||||
namespace_group = "namespace_{0}".format(namespace)
|
||||
namespace_pods_group = "{0}_pods".format(namespace_group)
|
||||
|
||||
self.inventory.add_group(name)
|
||||
self.inventory.add_group(namespace_group)
|
||||
self.inventory.add_child(name, namespace_group)
|
||||
self.inventory.add_group(namespace_pods_group)
|
||||
self.inventory.add_child(namespace_group, namespace_pods_group)
|
||||
|
||||
for pod in obj.items:
|
||||
pod_name = pod.metadata.name
|
||||
pod_groups = []
|
||||
pod_annotations = (
|
||||
{} if not pod.metadata.annotations else dict(pod.metadata.annotations)
|
||||
)
|
||||
|
||||
if pod.metadata.labels:
|
||||
# create a group for each label_value
|
||||
for key, value in pod.metadata.labels:
|
||||
group_name = "label_{0}_{1}".format(key, value)
|
||||
if group_name not in pod_groups:
|
||||
pod_groups.append(group_name)
|
||||
self.inventory.add_group(group_name)
|
||||
pod_labels = dict(pod.metadata.labels)
|
||||
else:
|
||||
pod_labels = {}
|
||||
|
||||
if not pod.status.containerStatuses:
|
||||
continue
|
||||
|
||||
for container in pod.status.containerStatuses:
|
||||
# add each pod_container to the namespace group, and to each label_value group
|
||||
container_name = "{0}_{1}".format(pod.metadata.name, container.name)
|
||||
self.inventory.add_host(container_name)
|
||||
self.inventory.add_child(namespace_pods_group, container_name)
|
||||
if pod_groups:
|
||||
for group in pod_groups:
|
||||
self.inventory.add_child(group, container_name)
|
||||
|
||||
# Add hostvars
|
||||
self.inventory.set_variable(container_name, "object_type", "pod")
|
||||
self.inventory.set_variable(container_name, "labels", pod_labels)
|
||||
self.inventory.set_variable(
|
||||
container_name, "annotations", pod_annotations
|
||||
)
|
||||
self.inventory.set_variable(
|
||||
container_name, "cluster_name", pod.metadata.clusterName
|
||||
)
|
||||
self.inventory.set_variable(
|
||||
container_name, "pod_node_name", pod.spec.nodeName
|
||||
)
|
||||
self.inventory.set_variable(container_name, "pod_name", pod.spec.name)
|
||||
self.inventory.set_variable(
|
||||
container_name, "pod_host_ip", pod.status.hostIP
|
||||
)
|
||||
self.inventory.set_variable(
|
||||
container_name, "pod_phase", pod.status.phase
|
||||
)
|
||||
self.inventory.set_variable(container_name, "pod_ip", pod.status.podIP)
|
||||
self.inventory.set_variable(
|
||||
container_name, "pod_self_link", pod.metadata.selfLink
|
||||
)
|
||||
self.inventory.set_variable(
|
||||
container_name, "pod_resource_version", pod.metadata.resourceVersion
|
||||
)
|
||||
self.inventory.set_variable(container_name, "pod_uid", pod.metadata.uid)
|
||||
self.inventory.set_variable(
|
||||
container_name, "container_name", container.image
|
||||
)
|
||||
self.inventory.set_variable(
|
||||
container_name, "container_image", container.image
|
||||
)
|
||||
if container.state.running:
|
||||
self.inventory.set_variable(
|
||||
container_name, "container_state", "Running"
|
||||
)
|
||||
if container.state.terminated:
|
||||
self.inventory.set_variable(
|
||||
container_name, "container_state", "Terminated"
|
||||
)
|
||||
if container.state.waiting:
|
||||
self.inventory.set_variable(
|
||||
container_name, "container_state", "Waiting"
|
||||
)
|
||||
self.inventory.set_variable(
|
||||
container_name, "container_ready", container.ready
|
||||
)
|
||||
self.inventory.set_variable(
|
||||
container_name, "ansible_remote_tmp", "/tmp/"
|
||||
)
|
||||
self.inventory.set_variable(
|
||||
container_name, "ansible_connection", self.connection_plugin
|
||||
)
|
||||
self.inventory.set_variable(
|
||||
container_name, "ansible_{0}_pod".format(self.transport), pod_name
|
||||
)
|
||||
self.inventory.set_variable(
|
||||
container_name,
|
||||
"ansible_{0}_container".format(self.transport),
|
||||
container.name,
|
||||
)
|
||||
self.inventory.set_variable(
|
||||
container_name,
|
||||
"ansible_{0}_namespace".format(self.transport),
|
||||
namespace,
|
||||
)
|
||||
|
||||
def get_services_for_namespace(self, client, name, namespace):
|
||||
v1_service = client.resources.get(api_version="v1", kind="Service")
|
||||
try:
|
||||
obj = v1_service.get(namespace=namespace)
|
||||
except DynamicApiError as exc:
|
||||
self.display.debug(exc)
|
||||
raise K8sInventoryException(
|
||||
"Error fetching Service list: %s" % format_dynamic_api_exc(exc)
|
||||
)
|
||||
|
||||
namespace_group = "namespace_{0}".format(namespace)
|
||||
namespace_services_group = "{0}_services".format(namespace_group)
|
||||
|
||||
self.inventory.add_group(name)
|
||||
self.inventory.add_group(namespace_group)
|
||||
self.inventory.add_child(name, namespace_group)
|
||||
self.inventory.add_group(namespace_services_group)
|
||||
self.inventory.add_child(namespace_group, namespace_services_group)
|
||||
|
||||
for service in obj.items:
|
||||
service_name = service.metadata.name
|
||||
service_labels = (
|
||||
{} if not service.metadata.labels else dict(service.metadata.labels)
|
||||
)
|
||||
service_annotations = (
|
||||
{}
|
||||
if not service.metadata.annotations
|
||||
else dict(service.metadata.annotations)
|
||||
)
|
||||
|
||||
self.inventory.add_host(service_name)
|
||||
|
||||
if service.metadata.labels:
|
||||
# create a group for each label_value
|
||||
for key, value in service.metadata.labels:
|
||||
group_name = "label_{0}_{1}".format(key, value)
|
||||
self.inventory.add_group(group_name)
|
||||
self.inventory.add_child(group_name, service_name)
|
||||
|
||||
try:
|
||||
self.inventory.add_child(namespace_services_group, service_name)
|
||||
except AnsibleError:
|
||||
raise
|
||||
|
||||
ports = [
|
||||
{
|
||||
"name": port.name,
|
||||
"port": port.port,
|
||||
"protocol": port.protocol,
|
||||
"targetPort": port.targetPort,
|
||||
"nodePort": port.nodePort,
|
||||
}
|
||||
for port in service.spec.ports or []
|
||||
]
|
||||
|
||||
# add hostvars
|
||||
self.inventory.set_variable(service_name, "object_type", "service")
|
||||
self.inventory.set_variable(service_name, "labels", service_labels)
|
||||
self.inventory.set_variable(
|
||||
service_name, "annotations", service_annotations
|
||||
)
|
||||
self.inventory.set_variable(
|
||||
service_name, "cluster_name", service.metadata.clusterName
|
||||
)
|
||||
self.inventory.set_variable(service_name, "ports", ports)
|
||||
self.inventory.set_variable(service_name, "type", service.spec.type)
|
||||
self.inventory.set_variable(
|
||||
service_name, "self_link", service.metadata.selfLink
|
||||
)
|
||||
self.inventory.set_variable(
|
||||
service_name, "resource_version", service.metadata.resourceVersion
|
||||
)
|
||||
self.inventory.set_variable(service_name, "uid", service.metadata.uid)
|
||||
|
||||
if service.spec.externalTrafficPolicy:
|
||||
self.inventory.set_variable(
|
||||
service_name,
|
||||
"external_traffic_policy",
|
||||
service.spec.externalTrafficPolicy,
|
||||
)
|
||||
if service.spec.externalIPs:
|
||||
self.inventory.set_variable(
|
||||
service_name, "external_ips", service.spec.externalIPs
|
||||
)
|
||||
|
||||
if service.spec.externalName:
|
||||
self.inventory.set_variable(
|
||||
service_name, "external_name", service.spec.externalName
|
||||
)
|
||||
|
||||
if service.spec.healthCheckNodePort:
|
||||
self.inventory.set_variable(
|
||||
service_name,
|
||||
"health_check_node_port",
|
||||
service.spec.healthCheckNodePort,
|
||||
)
|
||||
if service.spec.loadBalancerIP:
|
||||
self.inventory.set_variable(
|
||||
service_name, "load_balancer_ip", service.spec.loadBalancerIP
|
||||
)
|
||||
if service.spec.selector:
|
||||
self.inventory.set_variable(
|
||||
service_name, "selector", dict(service.spec.selector)
|
||||
)
|
||||
|
||||
if (
|
||||
hasattr(service.status.loadBalancer, "ingress")
|
||||
and service.status.loadBalancer.ingress
|
||||
):
|
||||
load_balancer = [
|
||||
{"hostname": ingress.hostname, "ip": ingress.ip}
|
||||
for ingress in service.status.loadBalancer.ingress
|
||||
]
|
||||
self.inventory.set_variable(
|
||||
service_name, "load_balancer", load_balancer
|
||||
)
|
||||
@@ -4,7 +4,7 @@
|
||||
import copy
|
||||
from json import loads
|
||||
from re import compile
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
|
||||
from ansible.module_utils.common.dict_transformations import dict_merge
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.hashes import (
|
||||
@@ -473,7 +473,7 @@ class K8sService:
|
||||
if label_selectors:
|
||||
params["label_selector"] = ",".join(label_selectors)
|
||||
|
||||
if delete_options:
|
||||
if delete_options and not self.module.check_mode:
|
||||
body = {
|
||||
"apiVersion": "v1",
|
||||
"kind": "DeleteOptions",
|
||||
@@ -501,47 +501,107 @@ def diff_objects(
|
||||
result["before"] = diff[0]
|
||||
result["after"] = diff[1]
|
||||
|
||||
if list(result["after"].keys()) != ["metadata"] or list(
|
||||
if list(result["after"].keys()) == ["metadata"] and list(
|
||||
result["before"].keys()
|
||||
) != ["metadata"]:
|
||||
return False, result
|
||||
) == ["metadata"]:
|
||||
# If only metadata.generation and metadata.resourceVersion changed, ignore it
|
||||
ignored_keys = set(["generation", "resourceVersion"])
|
||||
|
||||
# If only metadata.generation and metadata.resourceVersion changed, ignore it
|
||||
ignored_keys = set(["generation", "resourceVersion"])
|
||||
|
||||
if not set(result["after"]["metadata"].keys()).issubset(ignored_keys):
|
||||
return False, result
|
||||
if not set(result["before"]["metadata"].keys()).issubset(ignored_keys):
|
||||
return False, result
|
||||
if set(result["after"]["metadata"].keys()).issubset(ignored_keys) and set(
|
||||
result["before"]["metadata"].keys()
|
||||
).issubset(ignored_keys):
|
||||
return True, result
|
||||
|
||||
result["before"] = hide_fields(result["before"], hidden_fields)
|
||||
result["after"] = hide_fields(result["after"], hidden_fields)
|
||||
|
||||
return True, result
|
||||
return False, result
|
||||
|
||||
|
||||
def hide_fields(definition: dict, hidden_fields: Optional[list]) -> dict:
|
||||
if not hidden_fields:
|
||||
return definition
|
||||
result = copy.deepcopy(definition)
|
||||
for hidden_field in hidden_fields:
|
||||
result = hide_field(result, hidden_field)
|
||||
def hide_field_tree(hidden_field: str) -> List[str]:
|
||||
result = []
|
||||
key, rest = hide_field_split2(hidden_field)
|
||||
result.append(key)
|
||||
while rest:
|
||||
key, rest = hide_field_split2(rest)
|
||||
result.append(key)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# hide_field is not hugely sophisticated and designed to cope
|
||||
# with e.g. status or metadata.managedFields rather than e.g.
|
||||
# spec.template.spec.containers[0].env[3].value
|
||||
def hide_field(definition: dict, hidden_field: str) -> dict:
|
||||
split = hidden_field.split(".", 1)
|
||||
if split[0] in definition:
|
||||
if len(split) == 2:
|
||||
definition[split[0]] = hide_field(definition[split[0]], split[1])
|
||||
else:
|
||||
del definition[split[0]]
|
||||
def build_hidden_field_tree(hidden_fields: List[str]) -> Dict[str, Any]:
|
||||
"""Group hidden field targeting the same json key
|
||||
Example:
|
||||
Input: ['env[3]', 'env[0]']
|
||||
Output: {'env': [0, 3]}
|
||||
"""
|
||||
output = {}
|
||||
for hidden_field in hidden_fields:
|
||||
current = output
|
||||
tree = hide_field_tree(hidden_field)
|
||||
for idx, key in enumerate(tree):
|
||||
if current.get(key, "") is None:
|
||||
break
|
||||
if idx == (len(tree) - 1):
|
||||
current[key] = None
|
||||
elif key not in current:
|
||||
current[key] = {}
|
||||
current = current[key]
|
||||
return output
|
||||
|
||||
|
||||
# hide_field should be able to cope with simple or more complicated
|
||||
# field definitions
|
||||
# e.g. status or metadata.managedFields or
|
||||
# spec.template.spec.containers[0].env[3].value or
|
||||
# metadata.annotations[kubectl.kubernetes.io/last-applied-configuration]
|
||||
def hide_field(
|
||||
definition: Union[Dict[str, Any], List[Any]], hidden_field: Dict[str, Any]
|
||||
) -> Dict[str, Any]:
|
||||
def dict_contains_key(obj: Dict[str, Any], key: str) -> bool:
|
||||
return key in obj
|
||||
|
||||
def list_contains_key(obj: List[Any], key: str) -> bool:
|
||||
return int(key) < len(obj)
|
||||
|
||||
hidden_keys = list(hidden_field.keys())
|
||||
field_contains_key = dict_contains_key
|
||||
field_get_key = str
|
||||
if isinstance(definition, list):
|
||||
# Sort with reverse=true so that when we delete an item from the list, the order is not changed
|
||||
hidden_keys = sorted(
|
||||
[k for k in hidden_field.keys() if k.isdecimal()], reverse=True
|
||||
)
|
||||
field_contains_key = list_contains_key
|
||||
field_get_key = int
|
||||
|
||||
for key in hidden_keys:
|
||||
if field_contains_key(definition, key):
|
||||
value = hidden_field.get(key)
|
||||
convert_key = field_get_key(key)
|
||||
if value is None:
|
||||
del definition[convert_key]
|
||||
else:
|
||||
definition[convert_key] = hide_field(definition[convert_key], value)
|
||||
if (
|
||||
definition[convert_key] == dict()
|
||||
or definition[convert_key] == list()
|
||||
):
|
||||
del definition[convert_key]
|
||||
|
||||
return definition
|
||||
|
||||
|
||||
def hide_fields(
|
||||
definition: Dict[str, Any], hidden_fields: Optional[List[str]]
|
||||
) -> Dict[str, Any]:
|
||||
if not hidden_fields:
|
||||
return definition
|
||||
result = copy.deepcopy(definition)
|
||||
hidden_field_tree = build_hidden_field_tree(hidden_fields)
|
||||
return hide_field(result, hidden_field_tree)
|
||||
|
||||
|
||||
def decode_response(resp) -> Tuple[Dict, List[str]]:
|
||||
"""
|
||||
This function decodes unserialized responses from the Kubernetes python
|
||||
@@ -620,3 +680,35 @@ def parse_quoted_string(quoted_string: str) -> Tuple[str, str]:
|
||||
raise ValueError("invalid quoted string: missing closing quote")
|
||||
|
||||
return "".join(result), remainder
|
||||
|
||||
|
||||
# hide_field_split2 returns the first key in hidden_field and the rest of the hidden_field
|
||||
# We expect the first key to either be in brackets, to be terminated by the start of a left
|
||||
# bracket, or to be terminated by a dot.
|
||||
|
||||
# examples would be:
|
||||
# field.another.next -> (field, another.next)
|
||||
# field[key].value -> (field, [key].value)
|
||||
# [key].value -> (key, value)
|
||||
# [one][two] -> (one, [two])
|
||||
|
||||
|
||||
def hide_field_split2(hidden_field: str) -> Tuple[str, str]:
|
||||
lbracket = hidden_field.find("[")
|
||||
rbracket = hidden_field.find("]")
|
||||
dot = hidden_field.find(".")
|
||||
|
||||
if lbracket == 0:
|
||||
# skip past right bracket and any following dot
|
||||
rest = hidden_field[rbracket + 1 :] # noqa: E203
|
||||
if rest and rest[0] == ".":
|
||||
rest = rest[1:]
|
||||
return (hidden_field[lbracket + 1 : rbracket], rest) # noqa: E203
|
||||
|
||||
if lbracket != -1 and (dot == -1 or lbracket < dot):
|
||||
return (hidden_field[:lbracket], hidden_field[lbracket:])
|
||||
|
||||
split = hidden_field.split(".", 1)
|
||||
if len(split) == 1:
|
||||
return split[0], ""
|
||||
return split
|
||||
|
||||
@@ -117,11 +117,34 @@ def exists(resource: Optional[ResourceInstance]) -> bool:
|
||||
return bool(resource) and not empty_list(resource)
|
||||
|
||||
|
||||
def cluster_operator_ready(resource: ResourceInstance) -> bool:
|
||||
"""
|
||||
Predicate to check if a single ClusterOperator is healthy.
|
||||
Returns True if:
|
||||
- "Available" is True
|
||||
- "Degraded" is False
|
||||
- "Progressing" is False
|
||||
"""
|
||||
if not resource:
|
||||
return False
|
||||
|
||||
# Extract conditions from the resource's status
|
||||
conditions = resource.get("status", {}).get("conditions", [])
|
||||
|
||||
status = {x.get("type", ""): x.get("status") for x in conditions}
|
||||
return (
|
||||
(status.get("Degraded") == "False")
|
||||
and (status.get("Progressing") == "False")
|
||||
and (status.get("Available") == "True")
|
||||
)
|
||||
|
||||
|
||||
RESOURCE_PREDICATES = {
|
||||
"DaemonSet": daemonset_ready,
|
||||
"Deployment": deployment_ready,
|
||||
"Pod": pod_ready,
|
||||
"StatefulSet": statefulset_ready,
|
||||
"ClusterOperator": cluster_operator_ready,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -145,6 +145,16 @@ options:
|
||||
required: false
|
||||
default: True
|
||||
version_added: 3.0.0
|
||||
reset_then_reuse_values:
|
||||
description:
|
||||
- When upgrading package, reset the values to the ones built into the chart, apply the last release's values and merge in any overrides from
|
||||
parameters O(release_values), O(values_files) or O(set_values).
|
||||
- If O(reset_values) or O(reuse_values) is set to V(True), this is ignored.
|
||||
- This feature requires helm diff >= 3.9.12.
|
||||
type: bool
|
||||
required: false
|
||||
default: False
|
||||
version_added: 6.0.0
|
||||
|
||||
#Helm options
|
||||
disable_hook:
|
||||
@@ -218,6 +228,15 @@ options:
|
||||
- mutually exclusive with with C(replace).
|
||||
type: int
|
||||
version_added: 2.2.0
|
||||
insecure_skip_tls_verify:
|
||||
description:
|
||||
- Skip tls certificate checks for the chart download.
|
||||
- Do not confuse with the C(validate_certs) option.
|
||||
- This option is only available for helm >= 3.16.0.
|
||||
type: bool
|
||||
default: False
|
||||
aliases: [ skip_tls_certs_check ]
|
||||
version_added: 5.3.0
|
||||
extends_documentation_fragment:
|
||||
- kubernetes.core.helm_common_options
|
||||
"""
|
||||
@@ -476,12 +495,15 @@ def run_dep_update(module, chart_ref):
|
||||
rc, out, err = module.run_helm_command(dep_update)
|
||||
|
||||
|
||||
def fetch_chart_info(module, command, chart_ref):
|
||||
def fetch_chart_info(module, command, chart_ref, insecure_skip_tls_verify=False):
|
||||
"""
|
||||
Get chart info
|
||||
"""
|
||||
inspect_command = command + f" show chart '{chart_ref}'"
|
||||
|
||||
if insecure_skip_tls_verify:
|
||||
inspect_command += " --insecure-skip-tls-verify"
|
||||
|
||||
rc, out, err = module.run_helm_command(inspect_command)
|
||||
|
||||
return yaml.safe_load(out)
|
||||
@@ -509,6 +531,8 @@ def deploy(
|
||||
set_value_args=None,
|
||||
reuse_values=None,
|
||||
reset_values=True,
|
||||
reset_then_reuse_values=False,
|
||||
insecure_skip_tls_verify=False,
|
||||
):
|
||||
"""
|
||||
Install/upgrade/rollback release chart
|
||||
@@ -526,6 +550,17 @@ def deploy(
|
||||
if reuse_values is not None:
|
||||
deploy_command += " --reuse-values=" + str(reuse_values)
|
||||
|
||||
if reset_then_reuse_values:
|
||||
helm_version = module.get_helm_version()
|
||||
if LooseVersion(helm_version) < LooseVersion("3.14.0"):
|
||||
module.fail_json(
|
||||
msg="reset_then_reuse_values requires helm >= 3.14.0, current version is {0}".format(
|
||||
helm_version
|
||||
)
|
||||
)
|
||||
else:
|
||||
deploy_command += " --reset-then-reuse-values"
|
||||
|
||||
if wait:
|
||||
deploy_command += " --wait"
|
||||
if wait_timeout is not None:
|
||||
@@ -549,6 +584,17 @@ def deploy(
|
||||
if create_namespace:
|
||||
deploy_command += " --create-namespace"
|
||||
|
||||
if insecure_skip_tls_verify:
|
||||
helm_version = module.get_helm_version()
|
||||
if LooseVersion(helm_version) < LooseVersion("3.16.0"):
|
||||
module.fail_json(
|
||||
msg="insecure_skip_tls_verify requires helm >= 3.16.0, current version is {0}".format(
|
||||
helm_version
|
||||
)
|
||||
)
|
||||
else:
|
||||
deploy_command += " --insecure-skip-tls-verify"
|
||||
|
||||
if values_files:
|
||||
for value_file in values_files:
|
||||
deploy_command += " --values=" + value_file
|
||||
@@ -642,6 +688,8 @@ def helmdiff_check(
|
||||
set_value_args=None,
|
||||
reuse_values=None,
|
||||
reset_values=True,
|
||||
reset_then_reuse_values=False,
|
||||
insecure_skip_tls_verify=False,
|
||||
):
|
||||
"""
|
||||
Use helm diff to determine if a release would change by upgrading a chart.
|
||||
@@ -676,6 +724,27 @@ def helmdiff_check(
|
||||
if reuse_values:
|
||||
cmd += " --reuse-values"
|
||||
|
||||
if reset_then_reuse_values:
|
||||
helm_diff_version = get_plugin_version("diff")
|
||||
helm_version = module.get_helm_version()
|
||||
fail_msg = ""
|
||||
if LooseVersion(helm_diff_version) < LooseVersion("3.9.12"):
|
||||
fail_msg = "reset_then_reuse_values requires helm diff >= 3.9.12, current version is {0}\n".format(
|
||||
helm_diff_version
|
||||
)
|
||||
if LooseVersion(helm_version) < LooseVersion("3.14.0"):
|
||||
fail_msg += "reset_then_reuse_values requires helm >= 3.14.0, current version is {0}\n".format(
|
||||
helm_version
|
||||
)
|
||||
|
||||
if fail_msg:
|
||||
module.fail_json(msg=fail_msg)
|
||||
else:
|
||||
cmd += " --reset-then-reuse-values"
|
||||
|
||||
if insecure_skip_tls_verify:
|
||||
cmd += " --insecure-skip-tls-verify"
|
||||
|
||||
rc, out, err = module.run_helm_command(cmd)
|
||||
return (len(out.strip()) > 0, out.strip())
|
||||
|
||||
@@ -735,6 +804,10 @@ def argument_spec():
|
||||
set_values=dict(type="list", elements="dict"),
|
||||
reuse_values=dict(type="bool"),
|
||||
reset_values=dict(type="bool", default=True),
|
||||
reset_then_reuse_values=dict(type="bool", default=False),
|
||||
insecure_skip_tls_verify=dict(
|
||||
type="bool", default=False, aliases=["skip_tls_certs_check"]
|
||||
),
|
||||
)
|
||||
)
|
||||
return arg_spec
|
||||
@@ -787,6 +860,8 @@ def main():
|
||||
set_values = module.params.get("set_values")
|
||||
reuse_values = module.params.get("reuse_values")
|
||||
reset_values = module.params.get("reset_values")
|
||||
reset_then_reuse_values = module.params.get("reset_then_reuse_values")
|
||||
insecure_skip_tls_verify = module.params.get("insecure_skip_tls_verify")
|
||||
|
||||
if update_repo_cache:
|
||||
run_repo_update(module)
|
||||
@@ -824,7 +899,9 @@ def main():
|
||||
helm_cmd += " --repo=" + chart_repo_url
|
||||
|
||||
# Fetch chart info to have real version and real name for chart_ref from archive, folder or url
|
||||
chart_info = fetch_chart_info(module, helm_cmd, chart_ref)
|
||||
chart_info = fetch_chart_info(
|
||||
module, helm_cmd, chart_ref, insecure_skip_tls_verify
|
||||
)
|
||||
|
||||
if dependency_update:
|
||||
if chart_info.get("dependencies"):
|
||||
@@ -883,6 +960,8 @@ def main():
|
||||
set_value_args=set_value_args,
|
||||
reuse_values=reuse_values,
|
||||
reset_values=reset_values,
|
||||
reset_then_reuse_values=reset_then_reuse_values,
|
||||
insecure_skip_tls_verify=insecure_skip_tls_verify,
|
||||
)
|
||||
changed = True
|
||||
|
||||
@@ -908,6 +987,8 @@ def main():
|
||||
set_value_args,
|
||||
reuse_values=reuse_values,
|
||||
reset_values=reset_values,
|
||||
reset_then_reuse_values=reset_then_reuse_values,
|
||||
insecure_skip_tls_verify=insecure_skip_tls_verify,
|
||||
)
|
||||
if would_change and module._diff:
|
||||
opt_result["diff"] = {"prepared": prepared}
|
||||
@@ -943,6 +1024,8 @@ def main():
|
||||
set_value_args=set_value_args,
|
||||
reuse_values=reuse_values,
|
||||
reset_values=reset_values,
|
||||
reset_then_reuse_values=reset_then_reuse_values,
|
||||
insecure_skip_tls_verify=insecure_skip_tls_verify,
|
||||
)
|
||||
changed = True
|
||||
|
||||
|
||||
@@ -75,9 +75,10 @@ options:
|
||||
skip_tls_certs_check:
|
||||
description:
|
||||
- Whether or not to check tls certificate for the chart download.
|
||||
- Requires helm >= 3.3.0.
|
||||
- Requires helm >= 3.3.0. Alias C(insecure_skip_tls_verify) added in 5.3.0.
|
||||
type: bool
|
||||
default: False
|
||||
aliases: [ insecure_skip_tls_verify ]
|
||||
chart_devel:
|
||||
description:
|
||||
- Use development versions, too. Equivalent to version '>0.0.0-0'.
|
||||
@@ -190,7 +191,9 @@ def main():
|
||||
type="str", no_log=True, aliases=["password", "chart_repo_password"]
|
||||
),
|
||||
pass_credentials=dict(type="bool", default=False, no_log=False),
|
||||
skip_tls_certs_check=dict(type="bool", default=False),
|
||||
skip_tls_certs_check=dict(
|
||||
type="bool", default=False, aliases=["insecure_skip_tls_verify"]
|
||||
),
|
||||
chart_devel=dict(type="bool"),
|
||||
untar_chart=dict(type="bool", default=False),
|
||||
destination=dict(type="path", required=True),
|
||||
|
||||
@@ -119,6 +119,13 @@ options:
|
||||
aliases: [ force ]
|
||||
default: False
|
||||
version_added: 2.4.0
|
||||
insecure_skip_tls_verify:
|
||||
description:
|
||||
- Skip tls certificate checks for the repository url.
|
||||
type: bool
|
||||
default: False
|
||||
aliases: [ skip_tls_certs_check ]
|
||||
version_added: "5.3.0"
|
||||
"""
|
||||
|
||||
EXAMPLES = r"""
|
||||
@@ -226,6 +233,7 @@ def install_repository(
|
||||
repository_password,
|
||||
pass_credentials,
|
||||
force_update,
|
||||
insecure_skip_tls_verify,
|
||||
):
|
||||
install_command = command + " repo add " + repository_name + " " + repository_url
|
||||
|
||||
@@ -239,6 +247,9 @@ def install_repository(
|
||||
if force_update:
|
||||
install_command += " --force-update"
|
||||
|
||||
if insecure_skip_tls_verify:
|
||||
install_command += " --insecure-skip-tls-verify"
|
||||
|
||||
return install_command
|
||||
|
||||
|
||||
@@ -262,6 +273,9 @@ def argument_spec():
|
||||
),
|
||||
pass_credentials=dict(type="bool", default=False, no_log=True),
|
||||
force_update=dict(type="bool", default=False, aliases=["force"]),
|
||||
insecure_skip_tls_verify=dict(
|
||||
type="bool", default=False, aliases=["skip_tls_certs_check"]
|
||||
),
|
||||
)
|
||||
)
|
||||
return arg_spec
|
||||
@@ -290,6 +304,7 @@ def main():
|
||||
repo_state = module.params.get("repo_state")
|
||||
pass_credentials = module.params.get("pass_credentials")
|
||||
force_update = module.params.get("force_update")
|
||||
insecure_skip_tls_verify = module.params.get("insecure_skip_tls_verify")
|
||||
|
||||
helm_cmd = module.get_helm_binary()
|
||||
|
||||
@@ -308,6 +323,7 @@ def main():
|
||||
repo_password,
|
||||
pass_credentials,
|
||||
force_update,
|
||||
insecure_skip_tls_verify,
|
||||
)
|
||||
changed = True
|
||||
elif repository_status["url"] != repo_url:
|
||||
|
||||
@@ -188,7 +188,8 @@ options:
|
||||
description:
|
||||
- Hide fields matching this option in the result
|
||||
- An example might be C(hidden_fields=[metadata.managedFields])
|
||||
- Only field definitions that don't reference list items are supported (so V(spec.containers[0]) would not work)
|
||||
or V(hidden_fields=[spec.containers[0].env[3].value])
|
||||
or V(hidden_fields=[metadata.annotations[kubectl.kubernetes.io/last-applied-configuration]])
|
||||
type: list
|
||||
elements: str
|
||||
version_added: 3.0.0
|
||||
|
||||
@@ -48,7 +48,8 @@ options:
|
||||
description:
|
||||
- Hide fields matching any of the field definitions in the result
|
||||
- An example might be C(hidden_fields=[metadata.managedFields])
|
||||
- Only field definitions that don't reference list items are supported (so V(spec.containers[0]) would not work)
|
||||
or V(hidden_fields=[spec.containers[0].env[3].value])
|
||||
or V(hidden_fields=[metadata.annotations[kubectl.kubernetes.io/last-applied-configuration]])
|
||||
type: list
|
||||
elements: str
|
||||
version_added: 3.0.0
|
||||
|
||||
@@ -3,6 +3,7 @@ helm_default_archive_name: "helm-{{ helm_version }}-{{ ansible_system | lower }}
|
||||
helm_binary: "/tmp/helm/{{ ansible_system | lower }}-amd64/helm"
|
||||
|
||||
chart_test: "ingress-nginx"
|
||||
chart_test_oci: "oci://registry-1.docker.io/bitnamicharts/redis"
|
||||
chart_test_local_path: "nginx-ingress"
|
||||
chart_test_version: 4.2.4
|
||||
chart_test_version_local_path: 1.32.0
|
||||
@@ -26,3 +27,5 @@ test_namespace:
|
||||
- "helm-from-url"
|
||||
- "helm-reuse-values"
|
||||
- "helm-chart-with-space-into-name"
|
||||
- "helm-reset-then-reuse-values"
|
||||
- "helm-insecure"
|
||||
|
||||
@@ -4,4 +4,5 @@
|
||||
loop_control:
|
||||
loop_var: helm_version
|
||||
with_items:
|
||||
- "v3.8.0"
|
||||
- "v3.15.4"
|
||||
- "v3.16.0"
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
- name: test helm upgrade with reuse_values
|
||||
include_tasks: test_helm_reuse_values.yml
|
||||
|
||||
- name: test helm upgrade with reset_then_reuse_values
|
||||
include_tasks: test_helm_reset_then_reuse_values.yml
|
||||
|
||||
- name: test helm dependency update
|
||||
include_tasks: test_up_dep.yml
|
||||
|
||||
@@ -41,6 +44,9 @@
|
||||
- name: Test Skip CRDS feature in helm chart install
|
||||
include_tasks: test_crds.yml
|
||||
|
||||
- name: Test insecure registry flag feature
|
||||
include_tasks: test_helm_insecure.yml
|
||||
|
||||
- name: Clean helm install
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
|
||||
@@ -3,78 +3,89 @@
|
||||
vars:
|
||||
test_chart: "test-crds"
|
||||
helm_namespace: "{{ test_namespace[0] }}"
|
||||
helm_binary: helm
|
||||
block:
|
||||
- name: Create namespace
|
||||
k8s:
|
||||
kind: Namespace
|
||||
name: "{{ helm_namespace }}"
|
||||
|
||||
- name: Copy test chart
|
||||
copy:
|
||||
src: "{{ test_chart }}"
|
||||
dest: "/tmp/helm_test_crds/"
|
||||
|
||||
- name: Install chart while skipping CRDs
|
||||
helm:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
chart_ref: "/tmp/helm_test_crds/{{ test_chart }}"
|
||||
namespace: "{{ helm_namespace }}"
|
||||
name: test-crds
|
||||
skip_crds: true
|
||||
register: install
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- install is changed
|
||||
- install.status.name == "test-crds"
|
||||
|
||||
- name: Fail to create custom resource
|
||||
k8s:
|
||||
definition:
|
||||
apiVersion: ansible.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
namespace: "{{ helm_namespace }}"
|
||||
name: test-foo
|
||||
foobar: footest
|
||||
- name: Check if CRD resource is already present
|
||||
k8s_info:
|
||||
namespace: default
|
||||
kind: Foo
|
||||
api_version: ansible.com/v1
|
||||
ignore_errors: true
|
||||
register: result
|
||||
register: crd_check
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is failed
|
||||
- "result.msg.startswith('Failed to find exact match for ansible.com/v1.Foo')"
|
||||
- when: crd_check is failed
|
||||
block:
|
||||
- name: Copy test chart
|
||||
copy:
|
||||
src: "{{ test_chart }}"
|
||||
dest: "/tmp/helm_test_crds/"
|
||||
|
||||
# Helm won't install CRDs into an existing release, so we need to delete this, first
|
||||
- name: Uninstall chart
|
||||
helm:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
namespace: "{{ helm_namespace }}"
|
||||
name: test-crds
|
||||
state: absent
|
||||
|
||||
- name: Install chart with CRDs
|
||||
helm:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
chart_ref: "/tmp/helm_test_crds/{{ test_chart }}"
|
||||
namespace: "{{ helm_namespace }}"
|
||||
name: test-crds
|
||||
|
||||
- name: Create custom resource
|
||||
k8s:
|
||||
definition:
|
||||
apiVersion: ansible.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
- name: Install chart while skipping CRDs
|
||||
helm:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
chart_ref: "/tmp/helm_test_crds/{{ test_chart }}"
|
||||
namespace: "{{ helm_namespace }}"
|
||||
name: test-foo
|
||||
foobar: footest
|
||||
register: result
|
||||
name: test-crds
|
||||
skip_crds: true
|
||||
register: install
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.result.foobar == "footest"
|
||||
- assert:
|
||||
that:
|
||||
- install is changed
|
||||
- install.status.name == "test-crds"
|
||||
|
||||
- name: Fail to create custom resource
|
||||
k8s:
|
||||
definition:
|
||||
apiVersion: ansible.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
namespace: "{{ helm_namespace }}"
|
||||
name: test-foo
|
||||
foobar: footest
|
||||
ignore_errors: true
|
||||
register: result
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is failed
|
||||
- "result.msg.startswith('Failed to find exact match for ansible.com/v1.Foo')"
|
||||
|
||||
# Helm won't install CRDs into an existing release, so we need to delete this, first
|
||||
- name: Uninstall chart
|
||||
helm:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
namespace: "{{ helm_namespace }}"
|
||||
name: test-crds
|
||||
state: absent
|
||||
|
||||
- name: Install chart with CRDs
|
||||
helm:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
chart_ref: "/tmp/helm_test_crds/{{ test_chart }}"
|
||||
namespace: "{{ helm_namespace }}"
|
||||
name: test-crds
|
||||
|
||||
- name: Create custom resource
|
||||
k8s:
|
||||
definition:
|
||||
apiVersion: ansible.com/v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
namespace: "{{ helm_namespace }}"
|
||||
name: test-foo
|
||||
foobar: footest
|
||||
register: result
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.result.foobar == "footest"
|
||||
|
||||
always:
|
||||
- name: Remove chart
|
||||
|
||||
52
tests/integration/targets/helm/tasks/test_helm_insecure.yml
Normal file
52
tests/integration/targets/helm/tasks/test_helm_insecure.yml
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
- name: Test helm insecure
|
||||
vars:
|
||||
helm_namespace: "{{ test_namespace[12] }}"
|
||||
block:
|
||||
|
||||
- name: Initial chart installation (no flag set)
|
||||
helm:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
chart_ref: "{{ chart_test_oci }}"
|
||||
release_name: test-secure
|
||||
release_namespace: "{{ helm_namespace }}"
|
||||
create_namespace: true
|
||||
register: install
|
||||
|
||||
- name: Validate that insecure flag is not set
|
||||
assert:
|
||||
that:
|
||||
- install is changed
|
||||
- '"--insecure-skip-tls-verify" not in install.command'
|
||||
|
||||
- name: Initial chart installation (insecure flag set)
|
||||
helm:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
chart_ref: "{{ chart_test_oci }}"
|
||||
release_name: test-insecure
|
||||
release_namespace: "{{ helm_namespace }}"
|
||||
insecure_skip_tls_verify: true
|
||||
register: install
|
||||
ignore_errors: true
|
||||
|
||||
- name: Validate that insecure flag IS set if helm version is >= 3.16.0
|
||||
assert:
|
||||
that:
|
||||
- install is changed
|
||||
- '"--insecure-skip-tls-verify" in install.command'
|
||||
when: '"v3.16.0" <= helm_version'
|
||||
|
||||
- name: Validate that feature fails for helm < 3.16.0
|
||||
assert:
|
||||
that:
|
||||
- install is failed
|
||||
- '"insecure_skip_tls_verify requires helm >= 3.16.0" in install.msg'
|
||||
when: 'helm_version < "v3.16.0"'
|
||||
|
||||
always:
|
||||
- name: Remove helm namespace
|
||||
k8s:
|
||||
api_version: v1
|
||||
kind: Namespace
|
||||
name: "{{ helm_namespace }}"
|
||||
state: absent
|
||||
@@ -0,0 +1,75 @@
|
||||
---
|
||||
- name: Test helm reset_then_reuse_values
|
||||
vars:
|
||||
helm_namespace: "{{ test_namespace[11] }}"
|
||||
chart_release_values:
|
||||
replica:
|
||||
replicaCount: 3
|
||||
master:
|
||||
count: 1
|
||||
kind: Deployment
|
||||
chart_reset_then_reuse_values:
|
||||
replica:
|
||||
replicaCount: 1
|
||||
master:
|
||||
count: 3
|
||||
block:
|
||||
- name: Initial chart installation
|
||||
helm:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
chart_ref: oci://registry-1.docker.io/bitnamicharts/redis
|
||||
release_name: test-redis
|
||||
release_namespace: "{{ helm_namespace }}"
|
||||
create_namespace: true
|
||||
release_values: "{{ chart_release_values }}"
|
||||
register: install
|
||||
|
||||
- name: Get value set as string
|
||||
helm_info:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
release_name: test-redis
|
||||
release_namespace: "{{ helm_namespace }}"
|
||||
register: release_value
|
||||
|
||||
- name: Validate that chart values are as expected
|
||||
assert:
|
||||
that:
|
||||
- install is changed
|
||||
- '"--reset-then-reuse-values" not in install.command'
|
||||
- release_value["status"]["values"] == chart_release_values
|
||||
|
||||
- name: Upgrade chart using reset_then_reuse_values=true
|
||||
helm:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
chart_ref: oci://registry-1.docker.io/bitnamicharts/redis
|
||||
release_name: test-redis
|
||||
release_namespace: "{{ helm_namespace }}"
|
||||
reuse_values: false
|
||||
reset_values: false
|
||||
reset_then_reuse_values: true
|
||||
release_values: "{{ chart_reset_then_reuse_values }}"
|
||||
register: upgrade
|
||||
|
||||
- name: Get value set as string
|
||||
helm_info:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
release_name: test-redis
|
||||
release_namespace: "{{ helm_namespace }}"
|
||||
register: release_value
|
||||
|
||||
- name: Validate that chart values are as expected
|
||||
assert:
|
||||
that:
|
||||
- upgrade is changed
|
||||
- '"--reset-then-reuse-values" in upgrade.command'
|
||||
- '"--reuse-values " not in upgrade.command'
|
||||
- '"--reset-values" not in upgrade.command'
|
||||
- release_value["status"]["values"] == chart_release_values | combine(chart_reset_then_reuse_values, recursive=true)
|
||||
|
||||
always:
|
||||
- name: Remove helm namespace
|
||||
k8s:
|
||||
api_version: v1
|
||||
kind: Namespace
|
||||
name: "{{ helm_namespace }}"
|
||||
state: absent
|
||||
@@ -10,7 +10,7 @@
|
||||
binary_path: "{{ helm_binary }}"
|
||||
state: present
|
||||
plugin_path: https://github.com/databus23/helm-diff
|
||||
plugin_version: 3.4.0
|
||||
plugin_version: 3.9.13
|
||||
|
||||
- name: Copy test chart
|
||||
copy:
|
||||
@@ -324,3 +324,5 @@
|
||||
ignore_errors: true
|
||||
|
||||
- include_tasks: reuse_values.yml
|
||||
|
||||
- include_tasks: reset_then_reuse_values.yml
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
---
|
||||
- name: Create temporary directory for helm chart
|
||||
tempfile:
|
||||
suffix: .helm
|
||||
state: directory
|
||||
register: helm_dir
|
||||
|
||||
- name: Test helm diff functionality
|
||||
vars:
|
||||
test_chart_path: "{{ helm_dir.path }}/test-chart-reuse-values"
|
||||
test_release_name: "myrelease"
|
||||
|
||||
block:
|
||||
- name: Install helm diff
|
||||
kubernetes.core.helm_plugin:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
state: present
|
||||
plugin_path: https://github.com/databus23/helm-diff
|
||||
plugin_version: 3.9.14
|
||||
|
||||
- name: Copy test chart
|
||||
ansible.builtin.copy:
|
||||
src: "test-chart-reuse-values"
|
||||
dest: "{{ helm_dir.path }}"
|
||||
|
||||
- name: Delete existing namespace
|
||||
kubernetes.core.k8s:
|
||||
state: absent
|
||||
wait: true
|
||||
kind: Namespace
|
||||
name: "{{ helm_namespace }}"
|
||||
ignore_errors: true
|
||||
|
||||
- name: Create helm release
|
||||
kubernetes.core.helm:
|
||||
state: present
|
||||
binary_path: "{{ helm_binary }}"
|
||||
chart_ref: "{{ test_chart_path }}"
|
||||
release_name: "{{ test_release_name }}"
|
||||
release_namespace: "{{ helm_namespace }}"
|
||||
create_namespace: true
|
||||
release_values:
|
||||
ansible_version: devel
|
||||
phase: ci
|
||||
wait: true
|
||||
|
||||
- name: Upgrade helm release (reset_values=false and reuse_values=false and reset_then_reuse_values=true)
|
||||
kubernetes.core.helm:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
chart_ref: "{{ test_chart_path }}"
|
||||
reset_values: false
|
||||
reuse_values: false
|
||||
reset_then_reuse_values: true
|
||||
release_name: "{{ test_release_name }}"
|
||||
release_namespace: "{{ helm_namespace }}"
|
||||
values:
|
||||
ansible_version: devel
|
||||
register: helm_upgrade
|
||||
|
||||
- name: Ensure task did not reported change
|
||||
assert:
|
||||
that:
|
||||
- helm_upgrade is not changed
|
||||
|
||||
- name: Upgrade helm release (reset_then_reuse_values=true with default value for reset_values and reuse_values=false)
|
||||
kubernetes.core.helm:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
chart_ref: "{{ test_chart_path }}"
|
||||
reuse_values: false
|
||||
reset_then_reuse_values: true
|
||||
release_name: "{{ test_release_name }}"
|
||||
release_namespace: "{{ helm_namespace }}"
|
||||
values:
|
||||
ansible_version: devel
|
||||
register: helm_upgrade
|
||||
|
||||
- name: Ensure task reported change
|
||||
assert:
|
||||
that:
|
||||
- helm_upgrade is changed
|
||||
|
||||
# Delete helm and helm diff to install older version
|
||||
- name: Uninstall helm diff
|
||||
helm_plugin:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
state: absent
|
||||
plugin_name: diff
|
||||
ignore_errors: true
|
||||
|
||||
- name: Delete Helm folders
|
||||
file:
|
||||
path: /tmp/helm/
|
||||
state: absent
|
||||
|
||||
- name: Init Helm folders
|
||||
file:
|
||||
path: /tmp/helm
|
||||
state: directory
|
||||
|
||||
- name: Set Helm old version
|
||||
set_fact:
|
||||
helm_archive_name: "helm-v3.8.0-linux-amd64.tar.gz"
|
||||
helm_diff_old_version: "3.8.0"
|
||||
|
||||
- name: Unarchive Helm binary
|
||||
unarchive:
|
||||
src: "https://get.helm.sh/{{ helm_archive_name | default(helm_default_archive_name) }}"
|
||||
dest: /tmp/helm/
|
||||
remote_src: yes
|
||||
retries: 10
|
||||
delay: 5
|
||||
register: result
|
||||
until: result is not failed
|
||||
|
||||
- name: Upgrade helm release (with reset_then_reuse_values=true)
|
||||
kubernetes.core.helm:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
chart_ref: "{{ test_chart_path }}"
|
||||
reuse_values: false
|
||||
reset_then_reuse_values: true
|
||||
release_name: "{{ test_release_name }}"
|
||||
release_namespace: "{{ helm_namespace }}"
|
||||
values:
|
||||
ansible_version: test
|
||||
register: helm_upgrade
|
||||
ignore_errors: true
|
||||
|
||||
- name: Debug
|
||||
debug:
|
||||
var: helm_upgrade
|
||||
|
||||
- name: Ensure warning for Helm version
|
||||
assert:
|
||||
that:
|
||||
- helm_upgrade is failed
|
||||
- '"reset_then_reuse_values requires helm >= 3.14.0, current version is" in helm_upgrade.msg'
|
||||
|
||||
- name: Install helm diff
|
||||
helm_plugin:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
state: present
|
||||
plugin_path: https://github.com/databus23/helm-diff
|
||||
plugin_version: "{{ helm_diff_old_version }}"
|
||||
|
||||
- name: Upgrade helm release (with reset_then_reuse_values=true)
|
||||
kubernetes.core.helm:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
chart_ref: "{{ test_chart_path }}"
|
||||
reuse_values: false
|
||||
reset_then_reuse_values: true
|
||||
release_name: "{{ test_release_name }}"
|
||||
release_namespace: "{{ helm_namespace }}"
|
||||
values:
|
||||
ansible_version: devel
|
||||
register: helm_upgrade
|
||||
ignore_errors: true
|
||||
|
||||
- name: Debug
|
||||
debug:
|
||||
var: helm_upgrade
|
||||
|
||||
- name: Ensure warning for Helm Diff version
|
||||
assert:
|
||||
that:
|
||||
- helm_upgrade is failed
|
||||
- '"reset_then_reuse_values requires helm diff >= 3.9.12, current version is" in helm_upgrade.msg'
|
||||
|
||||
always:
|
||||
- name: Remove temporary directory
|
||||
file:
|
||||
path: "{{ helm_dir.path }}"
|
||||
state: absent
|
||||
ignore_errors: true
|
||||
|
||||
- name: Uninstall helm diff
|
||||
kubernetes.core.helm_plugin:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
state: absent
|
||||
plugin_name: diff
|
||||
ignore_errors: true
|
||||
|
||||
- name: Remove helm namespace
|
||||
kubernetes.core.k8s:
|
||||
api_version: v1
|
||||
kind: Namespace
|
||||
name: "{{ helm_namespace }}"
|
||||
state: absent
|
||||
wait: true
|
||||
ignore_errors: true
|
||||
@@ -90,4 +90,5 @@
|
||||
kind: Namespace
|
||||
name: "{{ helm_namespace }}"
|
||||
state: absent
|
||||
wait: true
|
||||
ignore_errors: true
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
---
|
||||
collections:
|
||||
- kubernetes.core
|
||||
dependencies:
|
||||
- install_helm
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
assert:
|
||||
that:
|
||||
- repository is changed
|
||||
- '"--insecure-skip-tls-verify" not in repository.command'
|
||||
|
||||
- name: Check idempotency
|
||||
helm_repository:
|
||||
@@ -78,3 +79,23 @@
|
||||
assert:
|
||||
that:
|
||||
- repository is not changed
|
||||
|
||||
- name: Add test_helm_repo chart repository as insecure
|
||||
helm_repository:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
name: test_helm_repo
|
||||
repo_url: "{{ chart_test_repo }}"
|
||||
insecure_skip_tls_verify: true
|
||||
register: repository
|
||||
|
||||
- name: Assert that repository added and flag set
|
||||
assert:
|
||||
that:
|
||||
- repository is changed
|
||||
- '"--insecure-skip-tls-verify" in repository.command'
|
||||
|
||||
- name: Clean test_helm_repo chart repository
|
||||
helm_repository:
|
||||
binary_path: "{{ helm_binary }}"
|
||||
name: test_helm_repo
|
||||
state: absent
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
---
|
||||
helm_version: v3.8.0
|
||||
helm_version: v3.16.4
|
||||
helm_install_path: /tmp/helm
|
||||
helm_default_archive_name: "helm-{{ helm_version }}-{{ ansible_system | lower }}-amd64.tar.gz"
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
context/target
|
||||
time=42
|
||||
k8s
|
||||
@@ -1,46 +0,0 @@
|
||||
---
|
||||
- name: Create inventory files
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
|
||||
collections:
|
||||
- kubernetes.core
|
||||
|
||||
roles:
|
||||
- role: setup_kubeconfig
|
||||
kubeconfig_operation: 'save'
|
||||
|
||||
tasks:
|
||||
- name: Create inventory files
|
||||
copy:
|
||||
content: "{{ item.content }}"
|
||||
dest: "{{ item.path }}"
|
||||
vars:
|
||||
hostname: "{{ lookup('file', user_credentials_dir + '/host_data.txt') }}"
|
||||
test_cert_file: "{{ user_credentials_dir | realpath + '/cert_file_data.txt' }}"
|
||||
test_key_file: "{{ user_credentials_dir | realpath + '/key_file_data.txt' }}"
|
||||
test_ca_cert: "{{ user_credentials_dir | realpath + '/ssl_ca_cert_data.txt' }}"
|
||||
with_items:
|
||||
- path: "test_inventory_aliases_with_ssl_k8s.yml"
|
||||
content: |
|
||||
---
|
||||
plugin: kubernetes.core.k8s
|
||||
connections:
|
||||
- namespaces:
|
||||
- inventory
|
||||
host: "{{ hostname }}"
|
||||
cert_file: "{{ test_cert_file }}"
|
||||
key_file: "{{ test_key_file }}"
|
||||
verify_ssl: true
|
||||
ssl_ca_cert: "{{ test_ca_cert }}"
|
||||
- path: "test_inventory_aliases_no_ssl_k8s.yml"
|
||||
content: |
|
||||
---
|
||||
plugin: kubernetes.core.k8s
|
||||
connections:
|
||||
- namespaces:
|
||||
- inventory
|
||||
host: "{{ hostname }}"
|
||||
cert_file: "{{ test_cert_file }}"
|
||||
key_file: "{{ test_key_file }}"
|
||||
verify_ssl: false
|
||||
@@ -1,30 +0,0 @@
|
||||
---
|
||||
- name: Delete inventory namespace
|
||||
hosts: localhost
|
||||
connection: local
|
||||
gather_facts: true
|
||||
|
||||
roles:
|
||||
- role: setup_kubeconfig
|
||||
kubeconfig_operation: 'revert'
|
||||
|
||||
tasks:
|
||||
- name: Delete temporary files
|
||||
file:
|
||||
state: absent
|
||||
path: "{{ user_credentials_dir ~ '/' ~ item }}"
|
||||
ignore_errors: true
|
||||
with_items:
|
||||
- test_inventory_aliases_with_ssl_k8s.yml
|
||||
- test_inventory_aliases_no_ssl_k8s.yml
|
||||
- ssl_ca_cert_data.txt
|
||||
- key_file_data.txt
|
||||
- cert_file_data.txt
|
||||
- host_data.txt
|
||||
|
||||
- name: Remove inventory namespace
|
||||
k8s:
|
||||
api_version: v1
|
||||
kind: Namespace
|
||||
name: inventory
|
||||
state: absent
|
||||
@@ -1,90 +0,0 @@
|
||||
---
|
||||
- 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
|
||||
@@ -1,2 +0,0 @@
|
||||
---
|
||||
plugin: kubernetes.core.k8s
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
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 }}"
|
||||
@@ -1,30 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eux
|
||||
|
||||
export ANSIBLE_ROLES_PATH="../"
|
||||
USER_CREDENTIALS_DIR=$(pwd)
|
||||
|
||||
ansible-playbook playbooks/delete_resources.yml -e "user_credentials_dir=${USER_CREDENTIALS_DIR}" "$@"
|
||||
|
||||
{
|
||||
export ANSIBLE_CALLBACKS_ENABLED=profile_tasks
|
||||
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 "$@" &&
|
||||
|
||||
ansible-playbook playbooks/create_resources.yml -e "user_credentials_dir=${USER_CREDENTIALS_DIR}" "$@" &&
|
||||
|
||||
ansible-inventory -i playbooks/test_inventory_aliases_with_ssl_k8s.yml --list "$@" &&
|
||||
|
||||
ansible-inventory -i playbooks/test_inventory_aliases_no_ssl_k8s.yml --list "$@" &&
|
||||
|
||||
unset ANSIBLE_INVENTORY_ENABLED &&
|
||||
|
||||
ansible-playbook playbooks/delete_resources.yml -e "user_credentials_dir=${USER_CREDENTIALS_DIR}" "$@"
|
||||
|
||||
} || {
|
||||
ansible-playbook playbooks/delete_resources.yml -e "user_credentials_dir=${USER_CREDENTIALS_DIR}" "$@"
|
||||
exit 1
|
||||
}
|
||||
@@ -26,7 +26,8 @@
|
||||
assert:
|
||||
that:
|
||||
- k8s_configmap is changed
|
||||
- k8s_configmap.result.metadata.annotations|default(False)
|
||||
- '"annotations" in k8s_configmap.result.metadata'
|
||||
- k8s_configmap.result.metadata.annotations != {}
|
||||
|
||||
- name: Add same configmap again
|
||||
k8s:
|
||||
@@ -467,7 +468,7 @@
|
||||
assert:
|
||||
that:
|
||||
- k8s_secret is changed
|
||||
- k8s_secret.result.data.foo
|
||||
- k8s_secret.result.data.foo != ""
|
||||
|
||||
- name: Add same secret
|
||||
k8s:
|
||||
@@ -748,7 +749,7 @@
|
||||
assert:
|
||||
that:
|
||||
- _create is changed
|
||||
- not _info.resources
|
||||
- _info.resources | length == 0
|
||||
|
||||
# server side apply over kubernetes client releases
|
||||
- name: Create temporary directory
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
- name: Assert that there are pods
|
||||
assert:
|
||||
that:
|
||||
- pods_create.resources
|
||||
- pods_create.resources | length > 0
|
||||
|
||||
- name: Remove the daemonset
|
||||
k8s:
|
||||
@@ -74,7 +74,7 @@
|
||||
- name: Assert that deleting the daemonset deleted the pods
|
||||
assert:
|
||||
that:
|
||||
- not pods_delete.resources
|
||||
- pods_delete.resources | length == 0
|
||||
|
||||
# test deletion using label selector
|
||||
- name: Deploy load balancer
|
||||
@@ -152,6 +152,27 @@
|
||||
register: _deployment
|
||||
failed_when: _deployment.resources | length == 0
|
||||
|
||||
- name: Trying to delete nginx deployment in check mode and with deleteOptions set
|
||||
k8s:
|
||||
kind: Deployment
|
||||
api_version: apps/v1
|
||||
namespace: "{{ test_namespace }}"
|
||||
name: nginx-d
|
||||
state: absent
|
||||
delete_options:
|
||||
propagationPolicy: Foreground
|
||||
check_mode: true
|
||||
register: _delete
|
||||
|
||||
- name: Validate that Deployment nginx-d still exists
|
||||
k8s_info:
|
||||
kind: Deployment
|
||||
api_version: apps/v1
|
||||
namespace: "{{ test_namespace }}"
|
||||
name: nginx-d
|
||||
register: _deployment
|
||||
failed_when: _deployment.resources | length != 1
|
||||
|
||||
- name: Trying to delete using delete_all=true but missing kind option
|
||||
k8s:
|
||||
api_version: apps/v1
|
||||
|
||||
@@ -244,7 +244,7 @@
|
||||
kind: Pod
|
||||
name: '{{ drain_pod_name }}'
|
||||
register: _result
|
||||
failed_when: _result.resources
|
||||
failed_when: _result.resources | length > 0
|
||||
|
||||
- name: assert that emptyDir pod was deleted
|
||||
k8s_info:
|
||||
@@ -346,7 +346,7 @@
|
||||
kind: Pod
|
||||
name: '{{ drain_pod_name }}-01'
|
||||
register: _result
|
||||
failed_when: _result.resources
|
||||
failed_when: _result.resources | length > 0
|
||||
|
||||
# test: drain using pod_selectors
|
||||
- name: Uncordon node
|
||||
|
||||
@@ -394,9 +394,11 @@
|
||||
register: k8s_info_testing6
|
||||
failed_when: not k8s_info_testing6.resources or k8s_info_testing6.resources[0].status.phase != "Active"
|
||||
|
||||
- name: Create large configmap data
|
||||
command: dd if=/dev/urandom bs=500K count=1
|
||||
register: cmap_data
|
||||
- name: Create a file with specific size and attributes, to be used as swap space
|
||||
community.general.filesize:
|
||||
path: /tmp/configmap.bin
|
||||
size: 500K
|
||||
source: /dev/urandom
|
||||
|
||||
- name: Create configmap with large value
|
||||
k8s:
|
||||
@@ -407,7 +409,7 @@
|
||||
name: testmap
|
||||
namespace: testing
|
||||
data:
|
||||
testkey: "{{ cmap_data.stdout | b64encode }}"
|
||||
testkey: "{{ lookup('file', '/tmp/configmap.bin') | b64encode }}"
|
||||
wait: true
|
||||
register: result
|
||||
|
||||
@@ -424,7 +426,7 @@
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result.resources[0].data.testkey == (cmap_data.stdout | b64encode)
|
||||
- result.resources[0].data.testkey == (lookup('file', '/tmp/configmap.bin') | b64encode)
|
||||
|
||||
# test setting module defaults for kubernetes.core.k8s_info
|
||||
- block:
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
label_selectors:
|
||||
- "job=gc"
|
||||
register: wait_job
|
||||
until: wait_job.resources
|
||||
until: wait_job.resources | length > 0
|
||||
retries: 5
|
||||
delay: 10
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
label_selectors:
|
||||
- "job=gc"
|
||||
register: wait_job
|
||||
until: wait_job.resources
|
||||
until: wait_job.resources | length > 0
|
||||
retries: 5
|
||||
delay: 10
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
label_selectors:
|
||||
- "job=gc"
|
||||
register: wait_job
|
||||
until: wait_job.resources
|
||||
until: wait_job.resources | length > 0
|
||||
retries: 5
|
||||
delay: 10
|
||||
|
||||
@@ -225,7 +225,7 @@
|
||||
|
||||
- name: Assert job is deleted
|
||||
assert:
|
||||
that: not job.resources
|
||||
that: job.resources | length == 0
|
||||
|
||||
always:
|
||||
- name: Delete namespace
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
definition: "{{ hide_fields_base_configmap | combine({'data':{'anew':'value'}}) }}"
|
||||
hidden_fields:
|
||||
- data
|
||||
- metadata.annotations[kubectl.kubernetes.io/last-applied-configuration]
|
||||
apply: true
|
||||
register: hf6
|
||||
diff: true
|
||||
@@ -86,6 +87,22 @@
|
||||
that:
|
||||
- hf6.changed
|
||||
|
||||
- name: Ensure hidden fields are not present
|
||||
assert:
|
||||
that:
|
||||
- >-
|
||||
'annotations' not in hf6.result.metadata or
|
||||
'kubectl.kubernetes.io/last-applied-configuration'
|
||||
not in hf6.result.metadata.annotations
|
||||
- >-
|
||||
'annotations' not in hf6.diff.before.metadata or
|
||||
'kubectl.kubernetes.io/last-applied-configuration'
|
||||
not in hf6.diff.before.metadata.annotations
|
||||
- >-
|
||||
'annotations' not in hf6.diff.after.metadata or
|
||||
'kubectl.kubernetes.io/last-applied-configuration'
|
||||
not in hf6.diff.after.metadata.annotations
|
||||
|
||||
- name: Hidden field should not show up in deletion
|
||||
k8s:
|
||||
definition: "{{ hide_fields_base_configmap}}"
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
- result.changed
|
||||
- result.result.metadata.labels.label2 == "bar"
|
||||
- result.result.spec.containers[0].image == "busybox:glibc"
|
||||
- result.diff
|
||||
- result.diff != {}
|
||||
|
||||
- name: Describe pod
|
||||
kubernetes.core.k8s_info:
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
- name: Update directory permissions
|
||||
file:
|
||||
path: "{{ manifests_dir.path }}"
|
||||
mode: 0755
|
||||
mode: '0755'
|
||||
|
||||
- name: Create manifests files
|
||||
copy:
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
that:
|
||||
- scale_down is changed
|
||||
- '"duration" in scale_down'
|
||||
- scale_down.diff
|
||||
- scale_down.diff != {}
|
||||
|
||||
- name: Scale the deployment once again (idempotency)
|
||||
k8s_scale:
|
||||
@@ -274,7 +274,7 @@
|
||||
assert:
|
||||
that:
|
||||
- scale_down_no_wait is changed
|
||||
- scale_down_no_wait.diff
|
||||
- scale_down_no_wait.diff != {}
|
||||
- scale_down_no_wait_pods.resources | length == 1
|
||||
|
||||
# scale multiple resource using label selectors
|
||||
|
||||
@@ -421,7 +421,7 @@
|
||||
- name: Assert that taints have been removed
|
||||
assert:
|
||||
that:
|
||||
- _result.resources | selectattr('spec.taints', 'undefined')
|
||||
- _result.resources | selectattr('spec.taints', 'undefined') | list | length > 0
|
||||
|
||||
always:
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
kubernetes.core.k8s_service:
|
||||
template: "pod_one.j2"
|
||||
state: present
|
||||
ignore_errors: yes
|
||||
ignore_errors: true
|
||||
register: r
|
||||
|
||||
- name: Check for expected failures in last tasks
|
||||
@@ -35,7 +35,7 @@
|
||||
k8s_pod_name_one: pod
|
||||
k8s_pod_namespace: "{{ template_namespace }}"
|
||||
register: r
|
||||
ignore_errors: yes
|
||||
ignore_errors: true
|
||||
|
||||
- name: Check if definition and template are mutually exclusive
|
||||
assert:
|
||||
@@ -52,7 +52,7 @@
|
||||
k8s_pod_name_one: pod
|
||||
k8s_pod_namespace: "{{ template_namespace }}"
|
||||
register: r
|
||||
ignore_errors: yes
|
||||
ignore_errors: true
|
||||
|
||||
- name: Check if src and template are mutually exclusive
|
||||
assert:
|
||||
@@ -63,7 +63,7 @@
|
||||
- name: Create pod using template (direct specification)
|
||||
kubernetes.core.k8s:
|
||||
template: "pod_one.j2"
|
||||
wait: yes
|
||||
wait: true
|
||||
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
|
||||
vars:
|
||||
k8s_pod_name_one: pod-1
|
||||
@@ -79,7 +79,7 @@
|
||||
kubernetes.core.k8s:
|
||||
template:
|
||||
- default
|
||||
wait: yes
|
||||
wait: true
|
||||
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
|
||||
vars:
|
||||
k8s_pod_name_one: pod-2
|
||||
@@ -96,7 +96,7 @@
|
||||
kubernetes.core.k8s:
|
||||
template:
|
||||
path: "pod_one.j2"
|
||||
wait: yes
|
||||
wait: true
|
||||
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
|
||||
vars:
|
||||
k8s_pod_name_one: pod-3
|
||||
@@ -114,12 +114,11 @@
|
||||
path: "pod_two.j2"
|
||||
variable_start_string: '[['
|
||||
variable_end_string: ']]'
|
||||
wait: yes
|
||||
wait: true
|
||||
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
|
||||
vars:
|
||||
k8s_pod_name_two: pod-4
|
||||
k8s_pod_namespace: "[[ template_namespace ]]"
|
||||
ansible_python_interpreter: "[[ ansible_playbook_python ]]"
|
||||
k8s_pod_namespace: "template-test"
|
||||
register: r
|
||||
|
||||
- name: Assert that pod creation succeeded using template
|
||||
@@ -131,7 +130,7 @@
|
||||
kubernetes.core.k8s:
|
||||
template:
|
||||
path: "pod_three.j2"
|
||||
wait: yes
|
||||
wait: true
|
||||
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
|
||||
vars:
|
||||
k8s_pod_name_three_one: pod-5
|
||||
@@ -152,7 +151,7 @@
|
||||
variable_start_string: '[['
|
||||
variable_end_string: ']]'
|
||||
- path: "pod_three.j2"
|
||||
wait: yes
|
||||
wait: true
|
||||
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
|
||||
vars:
|
||||
k8s_pod_name_one: pod-7
|
||||
@@ -239,63 +238,6 @@
|
||||
- resource.result.results | selectattr('changed') | list | length == 1
|
||||
- resource.result.results | selectattr('error', 'defined') | list | length == 1
|
||||
|
||||
# Test resource definition using template with 'omit'
|
||||
- name: Deploy configmap using template
|
||||
k8s:
|
||||
namespace: "{{ template_namespace }}"
|
||||
name: test-data
|
||||
template: configmap.yml.j2
|
||||
|
||||
- name: Read configmap created
|
||||
k8s_info:
|
||||
kind: configmap
|
||||
namespace: "{{ template_namespace }}"
|
||||
name: test-data
|
||||
register: _configmap
|
||||
|
||||
- name: Validate that the configmap does not contains annotations
|
||||
assert:
|
||||
that:
|
||||
- '"annotations" not in _configmap.resources.0.metadata'
|
||||
|
||||
- name: Create resource once again
|
||||
k8s:
|
||||
namespace: "{{ template_namespace }}"
|
||||
name: test-data
|
||||
template: configmap.yml.j2
|
||||
register: _configmap
|
||||
|
||||
- name: assert that nothing changed
|
||||
assert:
|
||||
that:
|
||||
- _configmap is not changed
|
||||
|
||||
- name: Create resource once again (using description)
|
||||
k8s:
|
||||
namespace: "{{ template_namespace }}"
|
||||
name: test-data
|
||||
template: configmap.yml.j2
|
||||
register: _configmap
|
||||
vars:
|
||||
k8s_configmap_desc: "This is a simple configmap used to test ansible k8s collection"
|
||||
|
||||
- name: assert that configmap was changed
|
||||
assert:
|
||||
that:
|
||||
- _configmap is changed
|
||||
|
||||
- name: Read configmap created
|
||||
k8s_info:
|
||||
kind: configmap
|
||||
namespace: "{{ template_namespace }}"
|
||||
name: test-data
|
||||
register: _configmap
|
||||
|
||||
- name: Validate that the configmap does not contains annotations
|
||||
assert:
|
||||
that:
|
||||
- _configmap.resources.0.metadata.annotations.description == "This is a simple configmap used to test ansible k8s collection"
|
||||
|
||||
always:
|
||||
- name: Remove namespace (Cleanup)
|
||||
kubernetes.core.k8s:
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
annotations:
|
||||
description: "{{ k8s_configmap_desc | default(omit) }}"
|
||||
data:
|
||||
key: "testing-template"
|
||||
@@ -56,8 +56,8 @@
|
||||
# Without wantlist=True lookup should return mapping
|
||||
- test5 is mapping
|
||||
- test6 is mapping
|
||||
# errors='ignore'
|
||||
- test7 is string
|
||||
# errors='ignore' (return null with ansible-core 2.19)
|
||||
- test7 is string or not test7
|
||||
- test8 is not defined
|
||||
|
||||
- name: Create another namespace with label
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
- name: make script as executable
|
||||
file:
|
||||
path: "{{ tmp_dir_path }}/install_kustomize.sh"
|
||||
mode: 0755
|
||||
mode: '0755'
|
||||
|
||||
- name: Install kustomize
|
||||
command: "{{ tmp_dir_path }}/install_kustomize.sh"
|
||||
|
||||
@@ -4,10 +4,17 @@
|
||||
namespace_to_create: "{{ item.name | default(item) }}"
|
||||
namespace_labels: "{{ item.labels | default(omit) }}"
|
||||
with_items: "{{ test_namespace }}"
|
||||
when: test_namespace | type_debug == "list"
|
||||
when:
|
||||
- test_namespace is not string
|
||||
- test_namespace is not mapping
|
||||
- test_namespace is iterable
|
||||
|
||||
- include_tasks: tasks/create.yml
|
||||
vars:
|
||||
namespace_to_create: "{{ test_namespace }}"
|
||||
namespace_labels: "{{ test_namespace_labels | default(omit) }}"
|
||||
when: test_namespace | type_debug == "AnsibleUnicode"
|
||||
when:
|
||||
- test_namespace is string
|
||||
- test_namespace is iterable
|
||||
- test_namespace is sequence
|
||||
- test_namespace is not mapping
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
plugins/module_utils/client/discovery.py import-3.9!skip
|
||||
plugins/module_utils/client/discovery.py import-3.10!skip
|
||||
plugins/module_utils/client/discovery.py import-3.11!skip
|
||||
plugins/module_utils/client/resource.py import-3.9!skip
|
||||
plugins/module_utils/client/resource.py import-3.10!skip
|
||||
plugins/module_utils/client/resource.py import-3.11!skip
|
||||
plugins/module_utils/k8sdynamicclient.py import-3.9!skip
|
||||
plugins/module_utils/k8sdynamicclient.py import-3.10!skip
|
||||
plugins/module_utils/k8sdynamicclient.py import-3.11!skip
|
||||
plugins/modules/k8s.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/k8s_scale.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/k8s_service.py validate-modules:parameter-type-not-in-doc
|
||||
tests/unit/module_utils/fixtures/definitions.yml yamllint!skip
|
||||
tests/unit/module_utils/fixtures/deployments.yml yamllint!skip
|
||||
tests/unit/module_utils/fixtures/pods.yml yamllint!skip
|
||||
tests/integration/targets/helm/files/appversionless-chart-v2/templates/configmap.yaml yamllint!skip
|
||||
tests/integration/targets/helm/files/appversionless-chart/templates/configmap.yaml yamllint!skip
|
||||
tests/integration/targets/helm/files/test-chart-v2/templates/configmap.yaml yamllint!skip
|
||||
tests/integration/targets/helm/files/test-chart/templates/configmap.yaml yamllint!skip
|
||||
tests/integration/targets/helm_diff/files/test-chart/templates/configmap.yaml yamllint!skip
|
||||
tests/integration/targets/k8s_scale/files/deployment.yaml yamllint!skip
|
||||
plugins/modules/k8s.py validate-modules:return-syntax-error
|
||||
plugins/modules/k8s_scale.py validate-modules:return-syntax-error
|
||||
plugins/modules/k8s_service.py validate-modules:return-syntax-error
|
||||
plugins/modules/k8s_taint.py validate-modules:return-syntax-error
|
||||
tests/integration/targets/k8s_delete/files/deployments.yaml yamllint!skip
|
||||
tests/integration/targets/helm_diff/files/test-chart-reuse-values/templates/configmap.yaml yamllint!skip
|
||||
tests/integration/targets/helm_registry_auth/tasks/main.yaml yamllint!skip
|
||||
tests/integration/targets/helm_diff/files/test-chart-deployment-time/templates/configmap.yaml yamllint!skip
|
||||
|
||||
@@ -14,6 +14,7 @@ plugins/module_utils/version.py pylint!skip
|
||||
plugins/modules/k8s.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/k8s_scale.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/k8s_service.py validate-modules:parameter-type-not-in-doc
|
||||
tests/unit/module_utils/fixtures/clusteroperator.yml yamllint!skip
|
||||
tests/unit/module_utils/fixtures/definitions.yml yamllint!skip
|
||||
tests/unit/module_utils/fixtures/deployments.yml yamllint!skip
|
||||
tests/integration/targets/k8s_delete/files/deployments.yaml yamllint!skip
|
||||
|
||||
@@ -14,6 +14,7 @@ plugins/module_utils/version.py pylint!skip
|
||||
plugins/modules/k8s.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/k8s_scale.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/k8s_service.py validate-modules:parameter-type-not-in-doc
|
||||
tests/unit/module_utils/fixtures/clusteroperator.yml yamllint!skip
|
||||
tests/unit/module_utils/fixtures/definitions.yml yamllint!skip
|
||||
tests/unit/module_utils/fixtures/deployments.yml yamllint!skip
|
||||
tests/integration/targets/k8s_delete/files/deployments.yaml yamllint!skip
|
||||
|
||||
@@ -11,6 +11,7 @@ plugins/module_utils/version.py pylint!skip
|
||||
plugins/modules/k8s.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/k8s_scale.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/k8s_service.py validate-modules:parameter-type-not-in-doc
|
||||
tests/unit/module_utils/fixtures/clusteroperator.yml yamllint!skip
|
||||
tests/unit/module_utils/fixtures/definitions.yml yamllint!skip
|
||||
tests/unit/module_utils/fixtures/deployments.yml yamllint!skip
|
||||
tests/integration/targets/k8s_delete/files/deployments.yaml yamllint!skip
|
||||
|
||||
@@ -11,6 +11,7 @@ plugins/module_utils/version.py pylint!skip
|
||||
plugins/modules/k8s.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/k8s_scale.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/k8s_service.py validate-modules:parameter-type-not-in-doc
|
||||
tests/unit/module_utils/fixtures/clusteroperator.yml yamllint!skip
|
||||
tests/unit/module_utils/fixtures/definitions.yml yamllint!skip
|
||||
tests/unit/module_utils/fixtures/deployments.yml yamllint!skip
|
||||
tests/integration/targets/k8s_delete/files/deployments.yaml yamllint!skip
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
plugins/module_utils/client/discovery.py import-3.9!skip
|
||||
plugins/module_utils/client/discovery.py import-3.10!skip
|
||||
plugins/module_utils/client/discovery.py import-3.11!skip
|
||||
plugins/module_utils/client/resource.py import-3.9!skip
|
||||
plugins/module_utils/client/resource.py import-3.10!skip
|
||||
plugins/module_utils/client/discovery.py import-3.12!skip
|
||||
plugins/module_utils/client/discovery.py import-3.13!skip
|
||||
plugins/module_utils/client/resource.py import-3.11!skip
|
||||
plugins/module_utils/k8sdynamicclient.py import-3.9!skip
|
||||
plugins/module_utils/k8sdynamicclient.py import-3.10!skip
|
||||
plugins/module_utils/client/resource.py import-3.12!skip
|
||||
plugins/module_utils/client/resource.py import-3.13!skip
|
||||
plugins/module_utils/k8sdynamicclient.py import-3.11!skip
|
||||
plugins/module_utils/k8sdynamicclient.py import-3.12!skip
|
||||
plugins/module_utils/k8sdynamicclient.py import-3.13!skip
|
||||
plugins/module_utils/version.py pylint!skip
|
||||
plugins/modules/k8s.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/k8s_scale.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/k8s_service.py validate-modules:parameter-type-not-in-doc
|
||||
tests/unit/module_utils/fixtures/clusteroperator.yml yamllint!skip
|
||||
tests/unit/module_utils/fixtures/definitions.yml yamllint!skip
|
||||
tests/unit/module_utils/fixtures/deployments.yml yamllint!skip
|
||||
tests/integration/targets/k8s_delete/files/deployments.yaml yamllint!skip
|
||||
@@ -1,105 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright: (c) 2022, 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
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from ansible_collections.kubernetes.core.plugins.action.k8s_info import RemoveOmit
|
||||
|
||||
|
||||
def get_omit_token():
|
||||
return "__omit_place_holder__%s" % datetime.now().strftime("%Y%m%d%H%M%S")
|
||||
|
||||
|
||||
def test_remove_omit_from_str():
|
||||
omit_token = get_omit_token()
|
||||
src = """
|
||||
project: ansible
|
||||
collection: {omit}
|
||||
""".format(
|
||||
omit=omit_token
|
||||
)
|
||||
result = RemoveOmit(src, omit_value=omit_token).output()
|
||||
assert len(result) == 1
|
||||
assert result[0] == dict(project="ansible")
|
||||
|
||||
|
||||
def test_remove_omit_from_list():
|
||||
omit_token = get_omit_token()
|
||||
src = """
|
||||
items:
|
||||
- {omit}
|
||||
""".format(
|
||||
omit=omit_token
|
||||
)
|
||||
result = RemoveOmit(src, omit_value=omit_token).output()
|
||||
assert len(result) == 1
|
||||
assert result[0] == dict(items=[])
|
||||
|
||||
|
||||
def test_remove_omit_from_list_of_dict():
|
||||
omit_token = get_omit_token()
|
||||
src = """
|
||||
items:
|
||||
- owner: ansible
|
||||
team: {omit}
|
||||
- simple_list_item
|
||||
""".format(
|
||||
omit=omit_token
|
||||
)
|
||||
result = RemoveOmit(src, omit_value=omit_token).output()
|
||||
assert len(result) == 1
|
||||
assert result[0] == dict(items=[dict(owner="ansible"), "simple_list_item"])
|
||||
|
||||
|
||||
def test_remove_omit_combined():
|
||||
omit_token = get_omit_token()
|
||||
src = """
|
||||
items:
|
||||
- {omit}
|
||||
- list_item_a
|
||||
- list_item_b
|
||||
parent:
|
||||
child:
|
||||
subchilda: {omit}
|
||||
subchildb:
|
||||
name: {omit}
|
||||
age: 3
|
||||
""".format(
|
||||
omit=omit_token
|
||||
)
|
||||
result = RemoveOmit(src, omit_value=omit_token).output()
|
||||
assert len(result) == 1
|
||||
assert result[0] == dict(
|
||||
items=["list_item_a", "list_item_b"],
|
||||
parent=dict(child=dict(subchildb=dict(age=3))),
|
||||
)
|
||||
|
||||
|
||||
def test_remove_omit_mutiple_documents():
|
||||
omit_token = get_omit_token()
|
||||
src = [
|
||||
"""
|
||||
project: ansible
|
||||
collection: {omit}
|
||||
""".format(
|
||||
omit=omit_token
|
||||
),
|
||||
"---",
|
||||
"""
|
||||
project: kubernetes
|
||||
environment: production
|
||||
collection: {omit}""".format(
|
||||
omit=omit_token
|
||||
),
|
||||
]
|
||||
src = "\n".join(src)
|
||||
print(src)
|
||||
result = RemoveOmit(src, omit_value=omit_token).output()
|
||||
assert len(result) == 2
|
||||
assert result[0] == dict(project="ansible")
|
||||
assert result[1] == dict(project="kubernetes", environment="production")
|
||||
99
tests/unit/module_utils/fixtures/clusteroperator.yml
Normal file
99
tests/unit/module_utils/fixtures/clusteroperator.yml
Normal file
@@ -0,0 +1,99 @@
|
||||
---
|
||||
apiVersion: config.openshift.io/v1
|
||||
kind: ClusterOperator
|
||||
metadata:
|
||||
name: authentication
|
||||
spec: {}
|
||||
status:
|
||||
conditions:
|
||||
- message: All is well
|
||||
reason: AsExpected
|
||||
status: 'False'
|
||||
type: Degraded
|
||||
- message: 'AuthenticatorCertKeyProgressing: All is well'
|
||||
reason: AsExpected
|
||||
status: 'False'
|
||||
type: Progressing
|
||||
- message: All is well
|
||||
reason: AsExpected
|
||||
status: 'True'
|
||||
type: Available
|
||||
- message: All is well
|
||||
reason: AsExpected
|
||||
status: 'True'
|
||||
type: Upgradeable
|
||||
- reason: NoData
|
||||
status: Unknown
|
||||
type: EvaluationConditionsDetected
|
||||
---
|
||||
apiVersion: config.openshift.io/v1
|
||||
kind: ClusterOperator
|
||||
metadata:
|
||||
name: dns
|
||||
spec: {}
|
||||
status:
|
||||
conditions:
|
||||
- message: DNS "default" is available.
|
||||
reason: AsExpected
|
||||
status: 'True'
|
||||
type: Available
|
||||
- message: 'DNS "default" reports Progressing=True: "Have 2 available node-resolver
|
||||
pods, want 3."'
|
||||
reason: DNSReportsProgressingIsTrue
|
||||
status: 'True'
|
||||
type: Progressing
|
||||
- reason: DNSNotDegraded
|
||||
status: 'False'
|
||||
type: Degraded
|
||||
- message: 'DNS default is upgradeable: DNS Operator can be upgraded'
|
||||
reason: DNSUpgradeable
|
||||
status: 'True'
|
||||
type: Upgradeable
|
||||
---
|
||||
apiVersion: config.openshift.io/v1
|
||||
kind: ClusterOperator
|
||||
metadata:
|
||||
name: dns
|
||||
spec: {}
|
||||
status:
|
||||
conditions:
|
||||
- message: DNS "default" is available.
|
||||
reason: AsExpected
|
||||
status: 'True'
|
||||
type: Available
|
||||
- message: 'DNS "default" reports Progressing=True: "Have 2 available node-resolver
|
||||
pods, want 3."'
|
||||
reason: DNSReportsProgressingIsTrue
|
||||
status: 'False'
|
||||
type: Progressing
|
||||
- reason: DNSNotDegraded
|
||||
status: 'True'
|
||||
type: Degraded
|
||||
- message: 'DNS default is upgradeable: DNS Operator can be upgraded'
|
||||
reason: DNSUpgradeable
|
||||
status: 'False'
|
||||
type: Upgradeable
|
||||
---
|
||||
apiVersion: config.openshift.io/v1
|
||||
kind: ClusterOperator
|
||||
metadata:
|
||||
name: dns
|
||||
spec: {}
|
||||
status:
|
||||
conditions:
|
||||
- message: DNS "default" is available.
|
||||
reason: AsExpected
|
||||
status: 'False'
|
||||
type: Available
|
||||
- message: 'DNS "default" reports Progressing=True: "Have 2 available node-resolver
|
||||
pods, want 3."'
|
||||
reason: DNSReportsProgressingIsTrue
|
||||
status: 'True'
|
||||
type: Progressing
|
||||
- reason: DNSNotDegraded
|
||||
status: 'True'
|
||||
type: Degraded
|
||||
- message: 'DNS default is upgradeable: DNS Operator can be upgraded'
|
||||
reason: DNSUpgradeable
|
||||
status: 'False'
|
||||
type: Upgradeable
|
||||
@@ -2,50 +2,57 @@ from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import json
|
||||
import re
|
||||
|
||||
import kubernetes
|
||||
import pytest
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.core import (
|
||||
AnsibleK8SModule,
|
||||
)
|
||||
from mock import MagicMock, patch
|
||||
|
||||
MINIMAL_K8S_VERSION = "24.2.0"
|
||||
UNSUPPORTED_K8S_VERSION = "11.0.0"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("stdin", [{}], indirect=["stdin"])
|
||||
def test_no_warn(monkeypatch, stdin, capfd):
|
||||
class FakeAnsibleModule:
|
||||
def __init__(self, **kwargs):
|
||||
pass
|
||||
|
||||
def exit_json(self):
|
||||
raise SystemExit(0)
|
||||
|
||||
|
||||
@patch.object(AnsibleK8SModule, "warn")
|
||||
def test_no_warn(m_ansible_k8s_module_warn, monkeypatch, capfd):
|
||||
monkeypatch.setattr(kubernetes, "__version__", MINIMAL_K8S_VERSION)
|
||||
|
||||
module = AnsibleK8SModule(argument_spec={})
|
||||
m_ansible_k8s_module_warn.side_effect = print
|
||||
module = AnsibleK8SModule(argument_spec={}, module_class=FakeAnsibleModule)
|
||||
with pytest.raises(SystemExit):
|
||||
module.exit_json()
|
||||
out, err = capfd.readouterr()
|
||||
|
||||
return_value = json.loads(out)
|
||||
|
||||
assert return_value.get("exception") is None
|
||||
assert return_value.get("warnings") is None
|
||||
assert return_value.get("failed") is None
|
||||
m_ansible_k8s_module_warn.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("stdin", [{}], indirect=["stdin"])
|
||||
def test_warn_on_k8s_version(monkeypatch, stdin, capfd):
|
||||
@patch.object(AnsibleK8SModule, "warn")
|
||||
def test_warn_on_k8s_version(m_ansible_k8s_module_warn, monkeypatch, capfd):
|
||||
monkeypatch.setattr(kubernetes, "__version__", UNSUPPORTED_K8S_VERSION)
|
||||
|
||||
module = AnsibleK8SModule(argument_spec={})
|
||||
m_ansible_k8s_module_warn.side_effect = print
|
||||
module = AnsibleK8SModule(argument_spec={}, module_class=FakeAnsibleModule)
|
||||
with pytest.raises(SystemExit):
|
||||
module.exit_json()
|
||||
|
||||
m_ansible_k8s_module_warn.assert_called_once()
|
||||
out, err = capfd.readouterr()
|
||||
|
||||
return_value = json.loads(out)
|
||||
|
||||
assert return_value.get("warnings") is not None
|
||||
warnings = return_value["warnings"]
|
||||
assert len(warnings) == 1
|
||||
assert "kubernetes" in warnings[0]
|
||||
assert MINIMAL_K8S_VERSION in warnings[0]
|
||||
assert (
|
||||
re.search(
|
||||
r"kubernetes<([0-9]+\.[0-9]+\.[0-9]+) is not supported or tested. Some features may not work.",
|
||||
out,
|
||||
)
|
||||
is not None
|
||||
)
|
||||
|
||||
|
||||
dependencies = [
|
||||
@@ -58,9 +65,17 @@ dependencies = [
|
||||
@pytest.mark.parametrize(
|
||||
"stdin,desired,actual,result", [({}, *d) for d in dependencies], indirect=["stdin"]
|
||||
)
|
||||
def test_has_at_least(monkeypatch, stdin, desired, actual, result, capfd):
|
||||
@patch.object(AnsibleK8SModule, "warn")
|
||||
def test_has_at_least(
|
||||
m_ansible_k8s_module_warn, monkeypatch, stdin, desired, actual, result, capfd
|
||||
):
|
||||
monkeypatch.setattr(kubernetes, "__version__", actual)
|
||||
|
||||
def fake_warn(x):
|
||||
print(x)
|
||||
raise SystemExit(1)
|
||||
|
||||
m_ansible_k8s_module_warn.side_effect = fake_warn
|
||||
module = AnsibleK8SModule(argument_spec={})
|
||||
|
||||
assert module.has_at_least("kubernetes", desired) is result
|
||||
@@ -80,11 +95,18 @@ def test_requires_fails_with_message(
|
||||
monkeypatch, stdin, dependency, version, msg, capfd
|
||||
):
|
||||
monkeypatch.setattr(kubernetes, "__version__", "24.2.0")
|
||||
module = AnsibleK8SModule(argument_spec={})
|
||||
module = AnsibleK8SModule(argument_spec={}, module_class=FakeAnsibleModule)
|
||||
|
||||
def fake_fail_json(**kwargs):
|
||||
print(f"Printing message => {kwargs}")
|
||||
print(kwargs.get("msg"))
|
||||
raise SystemExit(1)
|
||||
|
||||
module.fail_json = MagicMock()
|
||||
module.fail_json.side_effect = fake_fail_json
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
module.requires(dependency, version)
|
||||
module.fail_json.assert_called_once()
|
||||
out, err = capfd.readouterr()
|
||||
return_value = json.loads(out)
|
||||
|
||||
assert return_value.get("failed")
|
||||
assert msg in return_value.get("msg")
|
||||
assert msg in out
|
||||
|
||||
264
tests/unit/module_utils/test_hide_fields.py
Normal file
264
tests/unit/module_utils/test_hide_fields.py
Normal file
@@ -0,0 +1,264 @@
|
||||
# Copyright [2025] [Red Hat, Inc.]
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import pytest
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.service import (
|
||||
build_hidden_field_tree,
|
||||
hide_fields,
|
||||
)
|
||||
|
||||
|
||||
def test_hiding_missing_field_does_nothing():
|
||||
output = dict(
|
||||
kind="ConfigMap", metadata=dict(name="foo"), data=dict(one="1", two="2")
|
||||
)
|
||||
hidden_fields = ["doesnotexist"]
|
||||
assert hide_fields(output, hidden_fields) == output
|
||||
|
||||
|
||||
def test_hiding_simple_field():
|
||||
output = dict(
|
||||
kind="ConfigMap", metadata=dict(name="foo"), data=dict(one="1", two="2")
|
||||
)
|
||||
hidden_fields = ["metadata"]
|
||||
expected = dict(kind="ConfigMap", data=dict(one="1", two="2"))
|
||||
assert hide_fields(output, hidden_fields) == expected
|
||||
|
||||
|
||||
def test_hiding_only_key_in_dict_removes_dict():
|
||||
output = dict(kind="ConfigMap", metadata=dict(name="foo"), data=dict(one="1"))
|
||||
hidden_fields = ["data.one"]
|
||||
expected = dict(kind="ConfigMap", metadata=dict(name="foo"))
|
||||
assert hide_fields(output, hidden_fields) == expected
|
||||
|
||||
|
||||
def test_hiding_all_keys_in_dict_removes_dict():
|
||||
output = dict(
|
||||
kind="ConfigMap", metadata=dict(name="foo"), data=dict(one="1", two="2")
|
||||
)
|
||||
hidden_fields = ["data.one", "data.two"]
|
||||
expected = dict(kind="ConfigMap", metadata=dict(name="foo"))
|
||||
assert hide_fields(output, hidden_fields) == expected
|
||||
|
||||
|
||||
def test_hiding_multiple_fields():
|
||||
output = dict(
|
||||
kind="ConfigMap", metadata=dict(name="foo"), data=dict(one="1", two="2")
|
||||
)
|
||||
hidden_fields = ["metadata", "data.one"]
|
||||
expected = dict(kind="ConfigMap", data=dict(two="2"))
|
||||
assert hide_fields(output, hidden_fields) == expected
|
||||
|
||||
|
||||
def test_hiding_dict_key():
|
||||
output = dict(
|
||||
kind="ConfigMap",
|
||||
metadata=dict(
|
||||
name="foo",
|
||||
annotations={
|
||||
"kubectl.kubernetes.io/last-applied-configuration": '{"testvalue"}'
|
||||
},
|
||||
),
|
||||
data=dict(one="1", two="2"),
|
||||
)
|
||||
hidden_fields = [
|
||||
"metadata.annotations[kubectl.kubernetes.io/last-applied-configuration]",
|
||||
]
|
||||
expected = dict(
|
||||
kind="ConfigMap", metadata=dict(name="foo"), data=dict(one="1", two="2")
|
||||
)
|
||||
assert hide_fields(output, hidden_fields) == expected
|
||||
|
||||
|
||||
def test_hiding_list_value_key():
|
||||
output = dict(
|
||||
kind="Pod",
|
||||
metadata=dict(name="foo"),
|
||||
spec=dict(
|
||||
containers=[
|
||||
dict(
|
||||
name="containers",
|
||||
image="busybox",
|
||||
env=[
|
||||
dict(name="ENV1", value="env1"),
|
||||
dict(name="ENV2", value="env2"),
|
||||
dict(name="ENV3", value="env3"),
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
hidden_fields = ["spec.containers[0].env[1].value"]
|
||||
expected = dict(
|
||||
kind="Pod",
|
||||
metadata=dict(name="foo"),
|
||||
spec=dict(
|
||||
containers=[
|
||||
dict(
|
||||
name="containers",
|
||||
image="busybox",
|
||||
env=[
|
||||
dict(name="ENV1", value="env1"),
|
||||
dict(name="ENV2"),
|
||||
dict(name="ENV3", value="env3"),
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
assert hide_fields(output, hidden_fields) == expected
|
||||
|
||||
|
||||
def test_hiding_last_list_item():
|
||||
output = dict(
|
||||
kind="Pod",
|
||||
metadata=dict(name="foo"),
|
||||
spec=dict(
|
||||
containers=[
|
||||
dict(
|
||||
name="containers",
|
||||
image="busybox",
|
||||
env=[
|
||||
dict(name="ENV1", value="env1"),
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
hidden_fields = ["spec.containers[0].env[0]"]
|
||||
expected = dict(
|
||||
kind="Pod",
|
||||
metadata=dict(name="foo"),
|
||||
spec=dict(
|
||||
containers=[
|
||||
dict(
|
||||
name="containers",
|
||||
image="busybox",
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
assert hide_fields(output, hidden_fields) == expected
|
||||
|
||||
|
||||
def test_hiding_nested_dicts_using_brackets():
|
||||
output = dict(
|
||||
kind="Pod",
|
||||
metadata=dict(name="foo"),
|
||||
spec=dict(
|
||||
containers=[
|
||||
dict(
|
||||
name="containers",
|
||||
image="busybox",
|
||||
securityContext=dict(runAsUser=101),
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
hidden_fields = ["spec.containers[0][securityContext][runAsUser]"]
|
||||
expected = dict(
|
||||
kind="Pod",
|
||||
metadata=dict(name="foo"),
|
||||
spec=dict(
|
||||
containers=[
|
||||
dict(
|
||||
name="containers",
|
||||
image="busybox",
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
assert hide_fields(output, hidden_fields) == expected
|
||||
|
||||
|
||||
def test_using_jinja_syntax():
|
||||
output = dict(
|
||||
kind="ConfigMap", metadata=dict(name="foo"), data=["0", "1", "2", "3"]
|
||||
)
|
||||
hidden_fields = ["data.2"]
|
||||
expected = dict(kind="ConfigMap", metadata=dict(name="foo"), data=["0", "1", "3"])
|
||||
assert hide_fields(output, hidden_fields) == expected
|
||||
|
||||
|
||||
def test_remove_multiple_items_from_list():
|
||||
output = dict(
|
||||
kind="ConfigMap", metadata=dict(name="foo"), data=["0", "1", "2", "3"]
|
||||
)
|
||||
hidden_fields = ["data[0]", "data[2]"]
|
||||
expected = dict(kind="ConfigMap", metadata=dict(name="foo"), data=["1", "3"])
|
||||
assert hide_fields(output, hidden_fields) == expected
|
||||
|
||||
|
||||
def test_hide_dict_and_nested_dict():
|
||||
output = {
|
||||
"kind": "Pod",
|
||||
"metadata": {
|
||||
"labels": {
|
||||
"control-plane": "controller-manager",
|
||||
"pod-template-hash": "687b856498",
|
||||
},
|
||||
"annotations": {
|
||||
"kubectl.kubernetes.io/default-container": "awx-manager",
|
||||
"creationTimestamp": "2025-01-16T12:40:43Z",
|
||||
},
|
||||
},
|
||||
}
|
||||
hidden_fields = ["metadata.labels.pod-template-hash", "metadata.labels"]
|
||||
expected = {
|
||||
"kind": "Pod",
|
||||
"metadata": {
|
||||
"annotations": {
|
||||
"kubectl.kubernetes.io/default-container": "awx-manager",
|
||||
"creationTimestamp": "2025-01-16T12:40:43Z",
|
||||
}
|
||||
},
|
||||
}
|
||||
assert hide_fields(output, hidden_fields) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"hidden_fields,expected",
|
||||
[
|
||||
(
|
||||
[
|
||||
"data[0]",
|
||||
"data[1]",
|
||||
"metadata.annotation",
|
||||
"metadata.annotation[0].name",
|
||||
],
|
||||
{"data": {"0": None, "1": None}, "metadata": {"annotation": None}},
|
||||
),
|
||||
(
|
||||
[
|
||||
"data[0]",
|
||||
"data[1]",
|
||||
"metadata.annotation[0].name",
|
||||
"metadata.annotation",
|
||||
],
|
||||
{"data": {"0": None, "1": None}, "metadata": {"annotation": None}},
|
||||
),
|
||||
(
|
||||
[
|
||||
"data[0]",
|
||||
"data[1]",
|
||||
"data",
|
||||
"metadata.annotation[0].name",
|
||||
"metadata.annotation",
|
||||
],
|
||||
{"data": None, "metadata": {"annotation": None}},
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_build_hidden_field_tree(hidden_fields, expected):
|
||||
assert build_hidden_field_tree(hidden_fields) == expected
|
||||
@@ -202,8 +202,8 @@ def test_service_create_resource_warnings(
|
||||
result, warnings = svc.create(Mock(), pod_definition)
|
||||
|
||||
assert result == mock_pod_resource_instance.to_dict()
|
||||
assert warnings[0] == "test warning 1"
|
||||
assert warnings[1] == "test warning 2"
|
||||
assert str(warnings[0]) == "test warning 1"
|
||||
assert str(warnings[1]) == "test warning 2"
|
||||
|
||||
|
||||
def test_service_create_resource_check_mode():
|
||||
@@ -289,8 +289,8 @@ def test_service_apply_existing_resource_warnings(
|
||||
)
|
||||
|
||||
assert result == mock_pod_resource_instance.to_dict()
|
||||
assert warnings[0] == "test warning 1"
|
||||
assert warnings[1] == "test warning 2"
|
||||
assert str(warnings[0]) == "test warning 1"
|
||||
assert str(warnings[1]) == "test warning 2"
|
||||
|
||||
|
||||
def test_service_replace_existing_resource(
|
||||
|
||||
@@ -9,6 +9,7 @@ from ansible_collections.kubernetes.core.plugins.module_utils.k8s.waiter import
|
||||
DummyWaiter,
|
||||
Waiter,
|
||||
clock,
|
||||
cluster_operator_ready,
|
||||
custom_condition,
|
||||
deployment_ready,
|
||||
exists,
|
||||
@@ -29,6 +30,7 @@ def resources(filepath):
|
||||
RESOURCES = resources("fixtures/definitions.yml")
|
||||
PODS = resources("fixtures/pods.yml")
|
||||
DEPLOYMENTS = resources("fixtures/deployments.yml")
|
||||
CLUSTER_OPERATOR = resources("fixtures/clusteroperator.yml")
|
||||
|
||||
|
||||
def test_clock_times_out():
|
||||
@@ -119,3 +121,10 @@ def test_get_waiter_returns_correct_waiter():
|
||||
).predicate.func
|
||||
== custom_condition
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"clusteroperator,expected", zip(CLUSTER_OPERATOR, [True, False, False, False])
|
||||
)
|
||||
def test_cluster_operator(clusteroperator, expected):
|
||||
assert cluster_operator_ready(clusteroperator) is expected
|
||||
|
||||
Reference in New Issue
Block a user