Compare commits

21 Commits
6.0.0 ... 6.2.0

Author SHA1 Message Date
Bianca Henderson
6dadd06252 Add missing changelog fragments from 5.4.0 and 5.4.1 releases (#1015)
Reviewed-by: Mandar Kulkarni <mandar242@gmail.com>
Reviewed-by: Yuriy Novostavskiy <yuriy@novostavskiy.kyiv.ua>
2025-10-07 20:38:26 +00:00
Bianca Henderson
69dc7d5c5d Prep 6.2.0 release (#1011)
SUMMARY

Prep kubernetes.core 6.2.0 release

COMPONENT NAME
Multiple

Reviewed-by: Bikouo Aubin
Reviewed-by: Yuriy Novostavskiy <yuriy@novostavskiy.kyiv.ua>
Reviewed-by: Alina Buzachis
Reviewed-by: Bianca Henderson <beeankha@gmail.com>
Reviewed-by: Mandar Kulkarni <mandar242@gmail.com>
2025-10-07 18:18:54 +00:00
patchback[bot]
2fa1c2c6e5 Add support of local environment variables in kustomize lookup plugin (#786) (#1010)
This is a backport of PR #786 as merged into main (87344b9).
SUMMARY
kustomize doesn't support an environment that makes it impossible to use HTTP_PROXY or provide some templatized parameters.
This PR is the result of the issue #783
ISSUE TYPE

Feature Pull Request

COMPONENT NAME
kubernetes.core.kustomize lookup plugin

Reviewed-by: Bikouo Aubin
Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2025-10-03 14:34:41 +00:00
patchback[bot]
f2623dd3cf update doc following #971 (#1006) (#1008)
This is a backport of PR #1006 as merged into main (200d64f).
SUMMARY
In the PR #971, support for copying files to initContainers, and this change includes a minor update for DOCUMENTATION for the k8s_cp module; however, docs/kubernetes.core.k8s_cp_module.rst wasn't updated, and it's a trivial change following the Updating documentation section of the CONTRIBUTING.md
ISSUE TYPE

Docs Pull Request

COMPONENT NAME
docs/kubernetes.core.k8s_cp_module.rst
ADDITIONAL INFORMATION
As it is a trivial change and related to #971, I didn't created a chnagelog fragment and suggest adding skip-changelog label.
To be backported to stable-5 and stable-6

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2025-10-02 20:11:20 +00:00
patchback[bot]
8772d8c997 Add the PR head as reference to the checkout action of the splitter job. (#981) (#1005)
This is a backport of PR #981 as merged into main (ec35c74).
SUMMARY
During the workflow checks of one of my previous pull requests, I ran into an error as result of a new integration test that was added in the main branch but which was not present in my pull request (https://github.com/ansible-collections/kubernetes.core/actions/runs/16787189478/job/47540604109). I'd find out that the reference for the repository checkout for the splitter job was not set and therefor it referenced to the main branch.
With this change, the head of the pull request is used as reference for the repository checkout action, in the splitter job. This way it will not fail when someone creates a PR that doesn't have newly added integration tests that were added to the main branch in the meantime. It also adds that newly added integration tests will be tested during the PR workflow checks already.
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME
bugfix in the workflow
ADDITIONAL INFORMATION
n/a

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2025-10-02 19:12:05 +00:00
patchback[bot]
a32108f64f Added support for copying files to init Containers. (#971) (#1003)
This is a backport of PR #971 as merged into main (027700c).
SUMMARY
Was going trough the list with issues and found 958; which seemed a quick fix.
What I fixed with with this PR:

Added support for copying files to init containers.
Fixed the format message when an exec is failing for a pod (the order was wrong).
Added a check if the container that you try to run copy for is started.

ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME
copy.py module
ADDITIONAL INFORMATION
Some testing.
Verify that the pod does not exist:
kubectl -n default get pod/yorick
Output:
Error from server (NotFound): pods "yorick" not found

Run the playbook to create the file, create the deployment, wait for the init container to be ready, copy the created file to the init container, cat the copied file (using kubernetes.core.k8s_exec) that is now in the init container and try to copy the created file to the (not started) container (which fails - to see the new error message for it):
cat << EOF | ansible-playbook /dev/stdin
- hosts: localhost
  gather_facts: False
  tasks:

  - ansible.builtin.copy:
      content: |
        Hi there
      dest: /tmp/yorick.txt

  - name: Deploy pod with initContainer with an unlimited while loop
    kubernetes.core.k8s:
      kubeconfig: "~/.kube/config"
      definition:
        apiVersion: v1
        kind: Pod
        metadata:
          name: "yorick"
          namespace: "default"
        spec:
          initContainers:
            - name: "yorick-init"
              image: busybox:latest
              command: ["/bin/sh"]
              args:
                - "-c"
                - |
                  echo "Init container started, waiting for file..."
                  # Wait for the file to be copied
                  while :;do
                    echo "Waiting for file"
                    sleep 5
                  done
                  echo "File received! Init container completing..."
          containers:
            - name: "yorick-container"
              image: busybox:latest
              command: ["/bin/sh"]
              args:
                - "-c"
                - |
                  # Keep container running for testing
                  sleep 300

  - kubernetes.core.k8s_info:
      kubeconfig: "~/.kube/config"
      api_version: v1
      kind: Pod
      name: "yorick"
      namespace: "default"
    register: pod_status
    until: >-
      pod_status.resources|length > 0
      and 'initContainerStatuses' in pod_status.resources.0.status
      and pod_status.resources.0.status.initContainerStatuses|length > 0
      and pod_status.resources.0.status.initContainerStatuses.0.started|bool

  - name: Copy /tmp/yorick.txt to the yorick-init init container
    kubernetes.core.k8s_cp:
      kubeconfig: "~/.kube/config"
      namespace: default
      pod: yorick
      remote_path: /tmp/yorick.txt
      local_path: /tmp/yorick.txt
      container: yorick-init

  - name: Execute a command
    kubernetes.core.k8s_exec:
      kubeconfig: "~/.kube/config"
      namespace: default
      pod: yorick
      container: yorick-init
      command: cat /tmp/yorick.txt
    register: exec_out

  - ansible.builtin.debug:
      var: exec_out.stdout

  - name: Try to copy /tmp/yorick.txt to the yorick-container container
    kubernetes.core.k8s_cp:
      kubeconfig: "~/.kube/config"
      namespace: default
      pod: yorick
      remote_path: /tmp/yorick.txt
      local_path: /tmp/yorick.txt
      container: yorick-container
EOF
Output:
PLAY [localhost] ********************************************************************************************************************************************************************

TASK [ansible.builtin.copy] *********************************************************************************************************************************************************
Thursday 31 July 2025  02:01:21 +0200 (0:00:00.016)       0:00:00.016 *********
ok: [localhost]

TASK [Deploy pod with initContainer with an unlimited while loop] *******************************************************************************************************************
Thursday 31 July 2025  02:01:21 +0200 (0:00:00.788)       0:00:00.804 *********
changed: [localhost]

TASK [kubernetes.core.k8s_info] *****************************************************************************************************************************************************
Thursday 31 July 2025  02:01:25 +0200 (0:00:03.963)       0:00:04.768 *********
FAILED - RETRYING: [localhost]: kubernetes.core.k8s_info (3 retries left).
ok: [localhost]

TASK [Copy /tmp/yorick.txt to the yorick-init init container] ***********************************************************************************************************************
Thursday 31 July 2025  02:01:32 +0200 (0:00:06.598)       0:00:11.366 *********
changed: [localhost]

TASK [Execute a command] ************************************************************************************************************************************************************
Thursday 31 July 2025  02:01:39 +0200 (0:00:07.017)       0:00:18.383 *********
changed: [localhost]

TASK [ansible.builtin.debug] ********************************************************************************************************************************************************
Thursday 31 July 2025  02:01:40 +0200 (0:00:00.644)       0:00:19.028 *********
ok: [localhost] => {
    "exec_out.stdout": "Hi there\n"
}

TASK [Try to copy /tmp/yorick.txt to the yorick-container container] ****************************************************************************************************************
Thursday 31 July 2025  02:01:40 +0200 (0:00:00.021)       0:00:19.050 *********
fatal: [localhost]: FAILED! => {
    "changed": false
}

MSG:

Pod container yorick-container is not started

PLAY RECAP **************************************************************************************************************************************************************************
localhost                  : ok=6    changed=3    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

Playbook run took 0 days, 0 hours, 0 minutes, 21 seconds

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2025-09-25 15:07:52 +00:00
patchback[bot]
365e5e9159 Add support for skip-schema-validation in helm module (#995) (#1001)
This is a backport of PR #995 as merged into main (da93cce).
SUMMARY
This pull request adds support for a new skip_schema_validation option to the helm module, allowing users to disable JSON schema validation for Helm charts and values (requires helm >= 3.16.0).
ISSUE TYPE

Feature Pull Request

COMPONENT NAME
helm
ADDITIONAL INFORMATION
Added the skip_schema_validation boolean parameter to the helm module, allowing users to disable JSON schema validation for charts and values. This option is only available with Helm versions >= 3.16.0, and an appropriate error is raised for older versions.
Added integration tests to verify the behavior of the skip_schema_validation option, including cases for both supported and unsupported Helm versions.
Closes #994

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2025-09-24 20:29:07 +00:00
patchback[bot]
448a68da3d Changelog fixes (#989) (#990)
This is a backport of PR #989 as merged into main (6158300).
SUMMARY

Changelog fixes

ISSUE TYPE


Docs Pull Request

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
Reviewed-by: Chyna Sanders
2025-09-22 20:14:29 +00:00
patchback[bot]
46acab9c4c [CI Fix] Remove ansible.module_utils.six imports (#998) (#1000)
This is a backport of PR #998 as merged into main (448d3fe).
SUMMARY
This PR is essentially attempting Option B from issue #996 (Option A is implemented here); this code update accounts for the recent merge of sanity: warn on ansible.module_utils.six imports #85651.

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
Reviewed-by: Mandar Kulkarni <mandar242@gmail.com>
2025-09-22 16:49:02 +00:00
Bianca Henderson
fdb77182c8 Update/correct stable-6 changelog (#987)
SUMMARY
A part of the changelog referring to reverted changes was left in; this PR updates the changelog files to accurately reflect the state of stable-6/6.1.0 release.

Reviewed-by: Yuriy Novostavskiy
Reviewed-by: Alina Buzachis
2025-08-13 08:34:52 +00:00
Alina Buzachis
fa3d94f793 Prep kubernetes.core 6.1.0 (#977)
SUMMARY


ISSUE TYPE


Bugfix Pull Request
Docs Pull Request
Feature Pull Request
New Module Pull Request

COMPONENT NAME

ADDITIONAL INFORMATION

Reviewed-by: Yuriy Novostavskiy
Reviewed-by: Bianca Henderson <beeankha@gmail.com>
Reviewed-by: GomathiselviS <gomathiselvi@gmail.com>
2025-08-12 18:25:31 +00:00
patchback[bot]
9ec27cf37c CI fix for 976 (#982) (#985)
This is a backport of PR #982 as merged into main (a861079).
SUMMARY
Exclude plugins/connection/kubectl.py from ansible-lint, as this file contains only examples that is simplificated and may not be accordingally to linter rules.
resolves #976
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME
CI
ADDITIONAL INFORMATION

Reviewed-by: Alina Buzachis
Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2025-08-12 15:59:34 +00:00
Bianca Henderson
10cb241256 Reapply "Remove kubeconfig value from module invocation log (#826)" (#899) (#966) (#979)
This reverts commit 1d962fb from stable-6 (i.e., reapplies the changes from #966); this is a temporary fix for #782 as it will re-introduce #870.

Reviewed-by: Alina Buzachis
Reviewed-by: GomathiselviS <gomathiselvi@gmail.com>
2025-08-11 16:48:04 +00:00
patchback[bot]
92e1f581fe fix(k8s,service): Hide fields first before creating diffs (#915) (#963)
This is a backport of PR #915 as merged into main (6a0635a).
SUMMARY

By hiding fields first before creating a diff hidden fields will not be shown in the resulting diffs and therefore will also not trigger the changed condition.
The issue can only be reproduced when a mutating webhook changes the object while the kubernetes.core.k8s module is working with it.

kubevirt/kubevirt.core#145
ISSUE TYPE


Bugfix Pull Request

COMPONENT NAME

kubernetes.core.module_utils.k8s.service
ADDITIONAL INFORMATION


Run kubernetes.core.k8s and create object with hidden fields. After run kubernetes.core.k8s again and let a webhook mutate the object that the module is working with. The module should return with changed: no.

Reviewed-by: Alina Buzachis
2025-08-04 18:03:21 +00:00
patchback[bot]
7f69aff0d6 k8s_json_patch: support the hidden_fields param (#964) (#972)
This is a backport of PR #964 as merged into main (c48778d).
SUMMARY
Add support for hidden_fields on k8s_json_patch

ISSUE TYPE

Feature Pull Request

COMPONENT NAME
k8s_json_patch
ADDITIONAL INFORMATION
Works exactly the same as k8s
Haven't pushed the doc yet, because of many changes. Will do it on a separate commit if the tests pass.
1st commit here, sorry if I forget some things.
Thanks!

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2025-08-01 18:24:39 +00:00
patchback[bot]
8c65ac066d Add support for take-ownership Helm flag (#957) (#969)
This is a backport of PR #957 as merged into main (cf3c3a9).
SUMMARY
Add support for take-ownership Helm flag added in Helm 3.17.0
ISSUE TYPE

Feature Pull Request

COMPONENT NAME

kubernetes.core.helm

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2025-07-28 15:48:39 +00:00
patchback[bot]
1d962fb932 Revert "Remove kubeconfig value from module invocation log (#826)" (#899) (#966)
This is a backport of PR #899 as merged into main (1705ced).
This reverts commit 6efabd3.
SUMMARY

Fixes #870
A better solution is necessary to address #782. The current code makes getting manifests practically unusable. We need to revert this commit until a better solution is found.

ISSUE TYPE


Bugfix Pull Request

COMPONENT NAME

kubeconfig

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2025-07-22 21:29:21 +00:00
patchback[bot]
27ce23aa72 Fix integration test with ansibe-core 2.20 (#951) (#960)
This is a backport of PR #951 as merged into main (f568c9d).
SUMMARY
Now that ansible-core 2.19.0rc1 has been released, ansible-core’s devel branch has been bumped from 2.19.0.dev0 to 2.20.0.dev0. This potentially requires collection CIs to be updated which rely on devel using tests/sanity/ignore-2.19.txt, for example. Also it’s now time to add stable-2.19 to CI if you relied on devel to cover 2.19 so far. Note that milestone has also been updated to 2.20.0dev0.
During testing, I noticed that the failed test tasks/test_helm_not_installed.yml due to the new error message with ansible 2.20, please find here and following comments.
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME
test/CI (tasks/test_helm_not_installed.yml)
ADDITIONAL INFORMATION
to be cherry-picked to the stable-6 and stable-5

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2025-07-15 15:34:33 +00:00
patchback[bot]
993652b581 Add more functionality coverage to k8s_rollback integration test (#950) (#956)
This is a backport of PR #950 as merged into main (94e4235).
SUMMARY

Resolves #344

This revision adds the following test coverage:

Label Selectors: Tests rollback using label selectors to target specific deployments.
No Rollout History: Tests the warning scenario when attempting to rollback a deployment with only one revision.
Unsupported Resource Types: Tests error handling when trying to rollback unsupported resources like Services.
Non-existent Resources: Tests behavior when attempting to rollback resources that don't exist.
Multiple Resource Rollback: Tests bulk rollback operations using label selectors on multiple deployments.
Return Value Validation: Comprehensive validation of the rollback_info structure and content.
Field Selectors: Tests rollback using field selectors to target specific resources.
Check Mode Validation: Additional validation of check mode behavior and return values.

COMPONENT NAME

tests/integration/targets/k8s_rollback/tasks/main.yml

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2025-07-14 14:36:29 +00:00
patchback[bot]
9bd9d22db3 Fix the integration test for helm_registry_auth with helm >= 3.18.0 and clarify idempotency. (#946) (#953)
This is a backport of PR #946 as merged into main (642eb93).
SUMMARY
Fix the integration test for helm_registry_auth with helm >= 3.18.0 and clarify idempotency.
Fixes #944
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME
helm_registry_auth
ADDITIONAL INFORMATION
Caused by the changes in helm starting from 3.18.0

Reviewed-by: Bikouo Aubin
Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2025-07-08 15:56:48 +00:00
patchback[bot]
0593426918 Add plain_http parameter to helm, helm_pull and helm_template (#934) (#949)
This is a backport of PR #934 as merged into main (775959c).
SUMMARY

This change introduces the plain_http parameter to modules that can interact with OCI registries. This in needed in cases where the OCI registry does not use SSL encryption, forcing Helm to send HTTP requests instead of HTTPS

ISSUE TYPE


Feature Pull Request

COMPONENT NAME

helm, helm_pull and helm_template
ADDITIONAL INFORMATION


This is the output when trying to use an OCI registry that is not configured to use SSL certs.

fatal: [localhost]: FAILED! => {"changed": false, "command": "/usr/local/bin/helm show chart 'oci://<http-registry>/charts/foo'", "msg": "Failure when executing Helm command. Exited 1.\nstdout: \nstderr: Error: Get \"https://<http-registry>/v2/charts/foo/tags/list\": http: server gave HTTP response to HTTPS client\n", "stderr": "Error: Get \"https://<http-registry>/v2/charts/foo/tags/list\": http: server gave HTTP response to HTTPS client\n", "stderr_lines": ["Error: Get \"https://<http-registry>/v2/charts/foo/tags/list\": http: server gave HTTP response to HTTPS client"], "stdout": "", "stdout_lines": []}

Reviewed-by: Bikouo Aubin
2025-06-12 10:53:42 +00:00
60 changed files with 1407 additions and 219 deletions

View File

@@ -3,6 +3,7 @@ profile: production
exclude_paths: exclude_paths:
- .ansible/ - .ansible/
- .github/
- tests/integration - tests/integration
- tests/unit - tests/unit
- tests/sanity - tests/sanity

View File

@@ -3,3 +3,4 @@
plugins/connection/kubectl.py no-changed-when plugins/connection/kubectl.py no-changed-when
# false positive result # false positive result
plugins/connection/kubectl.py var-naming[no-reserved] plugins/connection/kubectl.py var-naming[no-reserved]
plugins/connection/kubectl.py jinja[invalid]

View File

@@ -26,6 +26,7 @@ jobs:
with: with:
path: ${{ env.source_dir }} path: ${{ env.source_dir }}
fetch-depth: "0" fetch-depth: "0"
ref: ${{ github.event.pull_request.head.sha }}
- name: list changes for pull request - name: list changes for pull request
id: splitter id: splitter

View File

@@ -20,4 +20,6 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: run-ansible-lint - name: run-ansible-lint
uses: ansible/ansible-lint@v25.1.2 uses: ansible/ansible-lint@main
with:
gh_action_ref: "v25.5.0"

3
.gitignore vendored
View File

@@ -21,3 +21,6 @@ tests/integration/*-chart-*.tgz
# ansible-test generated file # ansible-test generated file
tests/integration/inventory tests/integration/inventory
tests/integration/*-*.yml tests/integration/*-*.yml
# VS Code settings
.vscode/

View File

@@ -26,3 +26,4 @@ ignore: |
.tox .tox
.ansible .ansible
tests/output tests/output
plugins/connection/kubectl.py

View File

@@ -4,13 +4,51 @@ Kubernetes Collection Release Notes
.. contents:: Topics .. contents:: Topics
v6.0.0 v6.2.0
====== ======
Release Summary Release Summary
--------------- ---------------
This major release removes the deprecated ``k8s`` inventory plugin and also removes ``ansible-core<2.16`` support. This release adds minor changes and bugfixes, including support of skip-schema-validation in ``helm`` module and removing deprecated ``ansible.module_utils.six`` imports.
Minor Changes
-------------
- Add support of skip-schema-validation in ``helm`` module (https://github.com/ansible-collections/kubernetes.core/pull/995)
- kustomize - Add support of local environ (https://github.com/ansible-collections/kubernetes.core/pull/786).
Bugfixes
--------
- Remove ``ansible.module_utils.six`` imports to avoid warnings (https://github.com/ansible-collections/kubernetes.core/pull/998).
- Update the ``k8s_cp`` module to also work for init containers (https://github.com/ansible-collections/kubernetes.core/pull/971).
v6.1.0
======
Release Summary
---------------
This release adds ``plain_http`` and ``take_ownership`` parameters for helm modules, support for ``hidden_fields`` in ``k8s_json_patch``, documented lack of idempotency support in ``helm_registry_auth`` with ``helm ≥ 3.18.0``, and improved ``k8s_rollback`` test coverage.
Minor Changes
-------------
- Module helm_registry_auth do not support idempotency with `helm >= 3.18.0` (https://github.com/ansible-collections/kubernetes.core/pull/946)
- Module k8s_json_patch - Add support for `hidden_fields` (https://github.com/ansible-collections/kubernetes.core/pull/964).
- helm - Parameter plain_http added for working with insecure OCI registries (https://github.com/ansible-collections/kubernetes.core/pull/934).
- helm - Parameter take_ownership added (https://github.com/ansible-collections/kubernetes.core/pull/957).
- helm_pull - Parameter plain_http added for working with insecure OCI registries (https://github.com/ansible-collections/kubernetes.core/pull/934).
- helm_template - Parameter plain_http added for working with insecure OCI registries (https://github.com/ansible-collections/kubernetes.core/pull/934).
Bugfixes
--------
- module_utils/k8s/service - hide fields first before creating diffs (https://github.com/ansible-collections/kubernetes.core/pull/915).
v6.0.0
======
Breaking Changes / Porting Guide Breaking Changes / Porting Guide
-------------------------------- --------------------------------
@@ -18,6 +56,34 @@ Breaking Changes / Porting Guide
- Remove deprecated ``k8s`` invetory plugin (https://github.com/ansible-collections/kubernetes.core/pull/867). - 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). - Remove support for ``ansible-core<2.16`` (https://github.com/ansible-collections/kubernetes.core/pull/867).
v5.4.1
======
Release Summary
---------------
This release includes bugfixes for k8s service field handling, k8s_cp init containers support, and removes deprecated ansible.module_utils.six imports.
Bugfixes
--------
- Remove ``ansible.module_utils.six`` imports to avoid warnings (https://github.com/ansible-collections/kubernetes.core/pull/998).
- Update the `k8s_cp` module to also work for init containers (https://github.com/ansible-collections/kubernetes.core/pull/971).
- module_utils/k8s/service - hide fields first before creating diffs (https://github.com/ansible-collections/kubernetes.core/pull/915).
v5.4.0
======
Release Summary
---------------
This release updates the ``helm_registry_auth`` module to match the behavior of ``helm >= 3.18.0`` which reports a successful logout regardless of the current state (i.e., no idempotency).
Minor Changes
-------------
- Module ``helm_registry_auth`` does not support idempotency with ``helm >= 3.18.0`` (https://github.com/ansible-collections/kubernetes.core/pull/946)
v5.3.0 v5.3.0
====== ======
@@ -29,15 +95,15 @@ This release includes minor changes, bug fixes and also bumps ``ansible-lint`` v
Minor Changes Minor Changes
------------- -------------
- kubernetes.core - Bump version of ``ansible-lint`` to ``25.1.2`` (https://github.com/ansible-collections/kubernetes.core/pull/919). - 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). - 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 ``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). - helm - add support for ``insecure_skip_tls_verify`` option to helm and helm_repository(https://github.com/ansible-collections/kubernetes.core/issues/694).
Bugfixes 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). - 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 v5.2.0
====== ======
@@ -65,7 +131,7 @@ This release came with new module ``helm_registry_auth``, improvements to the er
Minor Changes Minor Changes
------------- -------------
- Bump version of ansible-lint to minimum 24.7.0 (https://github.com/ansible-collections/kubernetes.core/pull/765). - 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). - Parameter insecure_registry added to helm_template as equivalent of insecure-skip-tls-verify (https://github.com/ansible-collections/kubernetes.core/pull/805).
- k8s_drain - Improve error message for pod disruption budget when draining a node (https://github.com/ansible-collections/kubernetes.core/issues/797). - k8s_drain - Improve error message for pod disruption budget when draining a node (https://github.com/ansible-collections/kubernetes.core/issues/797).

View File

@@ -1,5 +1,5 @@
# Also needs to be updated in galaxy.yml # Also needs to be updated in galaxy.yml
VERSION = 6.0.0 VERSION = 6.2.0
TEST_ARGS ?= "" TEST_ARGS ?= ""
PYTHON_VERSION ?= `python -c 'import platform; print(".".join(platform.python_version_tuple()[0:2]))'` PYTHON_VERSION ?= `python -c 'import platform; print(".".join(platform.python_version_tuple()[0:2]))'`

View File

@@ -21,12 +21,10 @@ For more information about communication, see the [Ansible communication guide](
## Requirements ## Requirements
<!--start requires_ansible--> <!--start requires_ansible-->
### Ansible Version Compatibility ## Ansible version compatibility
This collection has been tested against following Ansible versions: **>=2.16.0**. This collection has been tested against the 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`).
Plugins and modules within a collection may be tested with only specific Ansible versions. Plugins and modules within a collection may be tested with only specific Ansible versions.
A collection may contain metadata that identifies these versions. A collection may contain metadata that identifies these versions.
PEP440 is the schema used to describe the versions of Ansible. PEP440 is the schema used to describe the versions of Ansible.
@@ -47,17 +45,17 @@ This collection supports Kubernetes versions >= 1.24.
Click on the name of a plugin or module to view that content's documentation: Click on the name of a plugin or module to view that content's documentation:
<!--start collection content--> <!--start collection content-->
### Connection Plugins ### Connection plugins
Name | Description 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. [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 Name | Description
--- | --- --- | ---
kubernetes.core.k8s_config_resource_name|Generate resource name for the given resource of type ConfigMap, Secret kubernetes.core.k8s_config_resource_name|Generate resource name for the given resource of type ConfigMap, Secret
### Lookup Plugins ### Lookup plugins
Name | Description Name | Description
--- | --- --- | ---
[kubernetes.core.k8s](https://github.com/ansible-collections/kubernetes.core/blob/main/docs/kubernetes.core.k8s_lookup.rst)|Query the K8s API [kubernetes.core.k8s](https://github.com/ansible-collections/kubernetes.core/blob/main/docs/kubernetes.core.k8s_lookup.rst)|Query the K8s API
@@ -101,7 +99,7 @@ You can also include it in a `requirements.yml` file and install it via `ansible
--- ---
collections: collections:
- name: kubernetes.core - name: kubernetes.core
version: 6.0.0 version: 6.2.0
``` ```
### Installing the Kubernetes Python Library ### Installing the Kubernetes Python Library

View File

@@ -977,7 +977,7 @@ releases:
- kustomize - kustomize plugin fails with deprecation warnings (https://github.com/ansible-collections/kubernetes.core/issues/639). - kustomize - kustomize plugin fails with deprecation warnings (https://github.com/ansible-collections/kubernetes.core/issues/639).
- waiter - Fix waiting for daemonset when desired number of pods is 0. (https://github.com/ansible-collections/kubernetes.core/pull/756). - waiter - Fix waiting for daemonset when desired number of pods is 0. (https://github.com/ansible-collections/kubernetes.core/pull/756).
minor_changes: minor_changes:
- Bump version of ansible-lint to minimum 24.7.0 (https://github.com/ansible-collections/kubernetes.core/pull/765). - 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 - Parameter insecure_registry added to helm_template as equivalent of insecure-skip-tls-verify
(https://github.com/ansible-collections/kubernetes.core/pull/805). (https://github.com/ansible-collections/kubernetes.core/pull/805).
- k8s_drain - Improve error message for pod disruption budget when draining - k8s_drain - Improve error message for pod disruption budget when draining
@@ -1044,6 +1044,33 @@ releases:
- 898-k8s-dont-delete-in-check-mode.yaml - 898-k8s-dont-delete-in-check-mode.yaml
- 919-update-ansible-lint-version.yaml - 919-update-ansible-lint-version.yaml
release_date: '2025-05-16' release_date: '2025-05-16'
5.4.0:
changes:
minor_changes:
- Module ``helm_registry_auth`` does not support idempotency with ``helm >= 3.18.0``
(https://github.com/ansible-collections/kubernetes.core/pull/946).
release_summary: This release updates the ``helm_registry_auth`` module to match the behavior of ``helm >= 3.18.0`` which reports a successful logout regardless of the current state (i.e., no idempotency).
fragments:
- 20250411-kubeconfig-no_log-revert.yaml
- 20250503-fix-unit-tests.yml
- 20250605-fix-helm_registry_auth-integration_test.yaml
- 5.4.0.yml
release_date: '2025-08-12'
5.4.1:
changes:
bugfixes:
- Remove ``ansible.module_utils.six`` imports to avoid warnings (https://github.com/ansible-collections/kubernetes.core/pull/998).
- Update the `k8s_cp` module to also work for init containers (https://github.com/ansible-collections/kubernetes.core/pull/971).
- module_utils/k8s/service - hide fields first before creating diffs (https://github.com/ansible-collections/kubernetes.core/pull/915).
release_summary: This release includes bugfixes for k8s service field handling,
k8s_cp init containers support, and removes deprecated ansible.module_utils.six
imports.
fragments:
- 20250428-k8s-service-hide-fields-first.yaml
- 20250731-fix-k8s_cp-initcontainers.yaml
- 20250922-remove-ansible-six-imports.yaml
- 5.4.1.yml
release_date: '2025-10-07'
6.0.0: 6.0.0:
changes: changes:
breaking_changes: breaking_changes:
@@ -1052,3 +1079,51 @@ releases:
fragments: fragments:
- 20250121-breaking-changes-6.0.0.yml - 20250121-breaking-changes-6.0.0.yml
release_date: '2025-05-19' release_date: '2025-05-19'
6.1.0:
changes:
bugfixes:
- module_utils/k8s/service - hide fields first before creating diffs (https://github.com/ansible-collections/kubernetes.core/pull/915).
minor_changes:
- Module helm_registry_auth do not support idempotency with `helm >= 3.18.0`
(https://github.com/ansible-collections/kubernetes.core/pull/946)
- Module k8s_json_patch - Add support for `hidden_fields` (https://github.com/ansible-collections/kubernetes.core/pull/964).
- helm - Parameter plain_http added for working with insecure OCI registries
(https://github.com/ansible-collections/kubernetes.core/pull/934).
- helm - Parameter take_ownership added (https://github.com/ansible-collections/kubernetes.core/pull/957).
- helm_pull - Parameter plain_http added for working with insecure OCI registries
(https://github.com/ansible-collections/kubernetes.core/pull/934).
- helm_template - Parameter plain_http added for working with insecure OCI registries
(https://github.com/ansible-collections/kubernetes.core/pull/934).
release_summary: "This release adds ``plain_http`` and ``take_ownership`` parameters
for helm modules, support for ``hidden_fields`` in ``k8s_json_patch``, documented
lack of idempotency support in ``helm_registry_auth`` with ``helm \u2265 3.18.0``,
and improved ``k8s_rollback`` test coverage."
fragments:
- 20250411-kubeconfig-no_log-revert.yaml
- 20250428-k8s-service-hide-fields-first.yaml
- 20250522-add-plain-http-for-oci-registries.yaml
- 20250605-fix-helm_registry_auth-integration_test.yaml
- 20250704-k8s-rollback-integration-test-coverage.yaml
- 20250720-k8s-patch-add-hidden-fields.yaml
- 20250911-add-support-helm-take-ownership.yaml
- release_summary.yml
release_date: '2025-08-12'
6.2.0:
changes:
bugfixes:
- Remove ``ansible.module_utils.six`` imports to avoid warnings (https://github.com/ansible-collections/kubernetes.core/pull/998).
- Update the `k8s_cp` module to also work for init containers (https://github.com/ansible-collections/kubernetes.core/pull/971).
minor_changes:
- Add support of skip-schema-validation in ``helm`` module (https://github.com/ansible-collections/kubernetes.core/pull/995)
- kustomize - Add support of local environ (https://github.com/ansible-collections/kubernetes.core/pull/786).
release_summary: This release adds minor changes and bugfixes, including support
of skip-schema-validation in ``helm`` module and removing deprecated
``ansible.module_utils.six`` imports.
fragments:
- 20241030-support-of-evrion-for-kustomize-lookup-plugin.yaml
- 20250731-fix-k8s_cp-initcontainers.yaml
- 20250916-skip-schema-validation.yaml
- 20250922-remove-ansible-six-imports.yaml
- 6_2_0.yml
release_date: '2025-10-07'

View File

@@ -1,147 +0,0 @@
.. _ansible_turbo_mode:
******************
Ansible Turbo mode
******************
Following document provides overview of Ansible Turbo mode in ``kubernetes.core`` collection.
.. contents::
:local:
:depth: 1
Synopsis
--------
- A brief introduction about Ansible Turbo mode in ``kuberentes.core`` collection.
- Ansible Turbo mode is an optional performance optimization. It can be enabled by installing the cloud.common collection and setting the ``ENABLE_TURBO_MODE`` environment variable.
Requirements
------------
The following requirement is needed on the host that executes this module.
- The ``cloud.common`` collection (https://github.com/ansible-collections/cloud.common)
You will also need to set the environment variable ``ENABLE_TURBO_MODE=1`` on the managed host. This can be done in the same ways you would usually do so, for example::
---
- hosts: remote
environment:
ENABLE_TURBO_MODE: 1
tasks:
...
Installation
------------
You can install ``cloud.common`` collection using following command::
# ansible-galaxy collection install cloud.common
Current situation without Ansible Turbo mode
============================================
The traditional execution flow of an Ansible module includes the following steps:
- Upload of a ZIP archive with the module and its dependencies
- Execution of the module
- Ansible collects the results once the script is finished
These steps happen for each task of a playbook, and on every host.
Most of the time, the execution of a module is fast enough for
the user. However, sometime the module requires significant amount of time,
just to initialize itself. This is a common situation with the API based modules.
A classic initialization involves the following steps:
- Load a Python library to access the remote resource (via SDK)
- Open a client
- Load a bunch of Python modules.
- Request a new TCP connection.
- Create a session.
- Authenticate the client.
All these steps are time consuming and the same operations will be running again and again.
For instance, here:
- ``import openstack``: takes 0.569s
- ``client = openstack.connect()``: takes 0.065s
- ``client.authorize()``: takes 1.360s,
These numbers are from test running against VexxHost public cloud.
In this case, it's a 2s-ish overhead per task. If the playbook
comes with 10 tasks, the execution time cannot go below 20s.
How Ansible Turbo Module improve the situation
==============================================
``AnsibleTurboModule`` is actually a class that inherites from
the standard ``AnsibleModule`` class that your modules probably
already use.
The big difference is that when a module starts, it also spawns
a little Python daemon. If a daemon already exists, it will just
reuse it.
All the module logic is run inside this Python daemon. This means:
- Python modules are actually loaded one time
- Ansible module can reuse an existing authenticated session.
The background service
======================
The daemon kills itself after 15s, and communication are done
through an Unix socket.
It runs in one single process and uses ``asyncio`` internally.
Consequently you can use the ``async`` keyword in your Ansible module.
This will be handy if you interact with a lot of remote systems
at the same time.
Security impact
===============
``ansible_module.turbo`` open an Unix socket to interact with the background service.
We use this service to open the connection toward the different target systems.
This is similar to what SSH does with the sockets.
Keep in mind that:
- All the modules can access the same cache. Soon an isolation will be done at the collection level (https://github.com/ansible-collections/cloud.common/pull/17)
- A task can load a different version of a library and impact the next tasks.
- If the same user runs two ``ansible-playbook`` at the same time, they will have access to the same cache.
When a module stores a session in a cache, it's a good idea to use a hash of the authentication information to identify the session.
Error management
================
``ansible_module.turbo`` uses exceptions to communicate a result back to the module.
- ``EmbeddedModuleFailure`` is raised when ``json_fail()`` is called.
- ``EmbeddedModuleSuccess`` is raised in case of success and returns the result to the origin module process.
These exceptions are defined in ``ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions``.
You can raise ``EmbeddedModuleFailure`` exception yourself, for instance from a module in ``module_utils``.
.. note:: Be careful with the ``except Exception:`` blocks.
Not only they are bad practice, but also may interface with this
mechanism.
Troubleshooting
===============
You may want to manually start the server. This can be done with the following command:
.. code-block:: shell
PYTHONPATH=$HOME/.ansible/collections python -m ansible_collections.cloud.common.plugins.module_utils.turbo.server --socket-path $HOME/.ansible/tmp/turbo_mode.kubernetes.core.socket
You can use the ``--help`` argument to get a list of the optional parameters.

View File

@@ -330,6 +330,27 @@ Parameters
<div style="font-size: small; color: darkgreen"><br/>aliases: kubeconfig_path</div> <div style="font-size: small; color: darkgreen"><br/>aliases: kubeconfig_path</div>
</td> </td>
</tr> </tr>
<tr>
<td colspan="2">
<div class="ansibleOptionAnchor" id="parameter-"></div>
<b>plain_http</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.1.0</div>
</td>
<td>
<ul style="margin: 0; padding: 0"><b>Choices:</b>
<li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
<li>yes</li>
</ul>
</td>
<td>
<div>Use HTTP instead of HTTPS when working with OCI registries</div>
<div>Requires Helm &gt;= 3.13.0</div>
</td>
</tr>
<tr> <tr>
<td colspan="2"> <td colspan="2">
<div class="ansibleOptionAnchor" id="parameter-"></div> <div class="ansibleOptionAnchor" id="parameter-"></div>
@@ -601,6 +622,48 @@ Parameters
<div>Skip custom resource definitions when installing or upgrading.</div> <div>Skip custom resource definitions when installing or upgrading.</div>
</td> </td>
</tr> </tr>
<tr>
<td colspan="2">
<div class="ansibleOptionAnchor" id="parameter-"></div>
<b>skip_schema_validation</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.2.0</div>
</td>
<td>
<ul style="margin: 0; padding: 0"><b>Choices:</b>
<li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
<li>yes</li>
</ul>
</td>
<td>
<div>Disables JSON schema validation for Chart and values.</div>
<div>This feature requires helm &gt;= 3.16.0</div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="ansibleOptionAnchor" id="parameter-"></div>
<b>take_ownership</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.1.0</div>
</td>
<td>
<ul style="margin: 0; padding: 0"><b>Choices:</b>
<li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
<li>yes</li>
</ul>
</td>
<td>
<div>When upgrading, Helm will ignore the check for helm annotations and take ownership of the existing resources</div>
<div>This feature requires helm &gt;= 3.17.0</div>
</td>
</tr>
<tr> <tr>
<td colspan="2"> <td colspan="2">
<div class="ansibleOptionAnchor" id="parameter-"></div> <div class="ansibleOptionAnchor" id="parameter-"></div>
@@ -810,6 +873,12 @@ Examples
chart_ref: "https://github.com/grafana/helm-charts/releases/download/grafana-5.6.0/grafana-5.6.0.tgz" chart_ref: "https://github.com/grafana/helm-charts/releases/download/grafana-5.6.0/grafana-5.6.0.tgz"
release_namespace: monitoring release_namespace: monitoring
- name: Deploy Bitnami's MongoDB latest chart from OCI registry
kubernetes.core.helm:
name: test
chart_ref: "oci://registry-1.docker.io/bitnamicharts/mongodb"
release_namespace: database
# Using complex Values # Using complex Values
- name: Deploy new-relic client chart - name: Deploy new-relic client chart
kubernetes.core.helm: kubernetes.core.helm:

View File

@@ -193,6 +193,27 @@ Parameters
<div>Pass credentials to all domains.</div> <div>Pass credentials to all domains.</div>
</td> </td>
</tr> </tr>
<tr>
<td colspan="1">
<div class="ansibleOptionAnchor" id="parameter-"></div>
<b>plain_http</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.1.0</div>
</td>
<td>
<ul style="margin: 0; padding: 0"><b>Choices:</b>
<li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
<li>yes</li>
</ul>
</td>
<td>
<div>Use HTTP instead of HTTPS when working with OCI registries</div>
<div>Requires Helm &gt;= 3.13.0</div>
</td>
</tr>
<tr> <tr>
<td colspan="1"> <td colspan="1">
<div class="ansibleOptionAnchor" id="parameter-"></div> <div class="ansibleOptionAnchor" id="parameter-"></div>

View File

@@ -170,6 +170,7 @@ Parameters
<div>Desired state of the registry.</div> <div>Desired state of the registry.</div>
<div>If set to V(present) attempt to log in to the remote registry server using the URL specified in O(host).</div> <div>If set to V(present) attempt to log in to the remote registry server using the URL specified in O(host).</div>
<div>If set to V(absent) attempt to log out from the remote registry server using the URL specified in O(host).</div> <div>If set to V(absent) attempt to log out from the remote registry server using the URL specified in O(host).</div>
<div>As helm &gt;= 3.18.0 reports successful logout even if the user is not logged in, this module will report a change regardless of the current state.</div>
</td> </td>
</tr> </tr>
<tr> <tr>

View File

@@ -194,6 +194,27 @@ Parameters
<div>If the directory already exists, it will be overwritten.</div> <div>If the directory already exists, it will be overwritten.</div>
</td> </td>
</tr> </tr>
<tr>
<td colspan="2">
<div class="ansibleOptionAnchor" id="parameter-"></div>
<b>plain_http</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.1.0</div>
</td>
<td>
<ul style="margin: 0; padding: 0"><b>Choices:</b>
<li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
<li>yes</li>
</ul>
</td>
<td>
<div>Use HTTP instead of HTTPS when working with OCI registries</div>
<div>Requires Helm &gt;= 3.13.0</div>
</td>
</tr>
<tr> <tr>
<td colspan="2"> <td colspan="2">
<div class="ansibleOptionAnchor" id="parameter-"></div> <div class="ansibleOptionAnchor" id="parameter-"></div>

View File

@@ -512,6 +512,7 @@ Notes
.. note:: .. note::
- the tar binary is required on the container when copying from local filesystem to pod. - the tar binary is required on the container when copying from local filesystem to pod.
- the (init) container has to be started before you copy files or directories to it.
- To avoid SSL certificate validation errors when ``validate_certs`` is *True*, the full certificate chain for the API server must be provided via ``ca_cert`` or in the kubeconfig file. - To avoid SSL certificate validation errors when ``validate_certs`` is *True*, the full certificate chain for the API server must be provided via ``ca_cert`` or in the kubeconfig file.

View File

@@ -140,6 +140,25 @@ Parameters
<div>The name of a context found in the config file. Can also be specified via K8S_AUTH_CONTEXT environment variable.</div> <div>The name of a context found in the config file. Can also be specified via K8S_AUTH_CONTEXT environment variable.</div>
</td> </td>
</tr> </tr>
<tr>
<td colspan="2">
<div class="ansibleOptionAnchor" id="parameter-"></div>
<b>hidden_fields</b>
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
<div style="font-size: small">
<span style="color: purple">list</span>
/ <span style="color: purple">elements=string</span>
</div>
<div style="font-style: italic; font-size: small; color: darkgreen">added in 6.1.0</div>
</td>
<td>
<b>Default:</b><br/><div style="color: blue">[]</div>
</td>
<td>
<div>List of fields to hide from the diff output.</div>
<div>This is useful for fields that are not relevant to the patch operation, such as `metadata.managedFields`.</div>
</td>
</tr>
<tr> <tr>
<td colspan="2"> <td colspan="2">
<div class="ansibleOptionAnchor" id="parameter-"></div> <div class="ansibleOptionAnchor" id="parameter-"></div>

View File

@@ -95,6 +95,26 @@ Parameters
<div>Enable the helm chart inflation generator</div> <div>Enable the helm chart inflation generator</div>
</td> </td>
</tr> </tr>
<tr>
<td colspan="1">
<div class="ansibleOptionAnchor" id="parameter-"></div>
<b>environment</b>
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
<div style="font-size: small">
<span style="color: purple">raw</span>
</div>
<div style="font-style: italic; font-size: small; color: darkgreen">added in 6.2.0</div>
</td>
<td>
<b>Default:</b><br/><div style="color: blue">{}</div>
</td>
<td>
</td>
<td>
<div>The environment variables to pass to the kustomize or kubectl command.</div>
<div>This can be a dictionary or a string in the format key=value, multiple pairs separated by space.</div>
</td>
</tr>
<tr> <tr>
<td colspan="1"> <td colspan="1">
<div class="ansibleOptionAnchor" id="parameter-"></div> <div class="ansibleOptionAnchor" id="parameter-"></div>
@@ -145,6 +165,14 @@ Examples
kubernetes.core.k8s: kubernetes.core.k8s:
definition: "{{ lookup('kubernetes.core.kustomize', dir='/path/to/kustomization', enable_helm=True) }}" definition: "{{ lookup('kubernetes.core.kustomize', dir='/path/to/kustomization', enable_helm=True) }}"
- name: Create kubernetes resources for lookup output with environment variables in string format
kubernetes.core.k8s:
definition: "{{ lookup('kubernetes.core.kustomize', binary_path='/path/to/kubectl', environment='HTTP_PROXY=http://proxy.example.com:3128') }}"
- name: Create kubernetes resources for lookup output with environment variables in dict format
kubernetes.core.k8s:
definition: "{{ lookup('kubernetes.core.kustomize', binary_path='/path/to/kubectl', environment={'HTTP_PROXY': 'http://proxy.example.com:3128'}) }}"
Return Values Return Values

View File

@@ -25,7 +25,7 @@ tags:
- openshift - openshift
- okd - okd
- cluster - cluster
version: 6.0.0 version: 6.2.0
build_ignore: build_ignore:
- .DS_Store - .DS_Store
- "*.tar.gz" - "*.tar.gz"

View File

@@ -22,7 +22,6 @@ from ansible.errors import (
) )
from ansible.module_utils._text import to_bytes, to_native, to_text from ansible.module_utils._text import to_bytes, to_native, to_text
from ansible.module_utils.parsing.convert_bool import boolean from ansible.module_utils.parsing.convert_bool import boolean
from ansible.module_utils.six import iteritems, string_types
from ansible.plugins.action import ActionBase from ansible.plugins.action import ActionBase
try: try:
@@ -100,7 +99,7 @@ class ActionModule(ActionBase):
"trim_blocks": True, "trim_blocks": True,
"lstrip_blocks": False, "lstrip_blocks": False,
} }
if isinstance(template, string_types): if isinstance(template, str):
# treat this as raw_params # treat this as raw_params
template_param["path"] = template template_param["path"] = template
elif isinstance(template, dict): elif isinstance(template, dict):
@@ -120,7 +119,7 @@ class ActionModule(ActionBase):
): ):
if s_type in template_args: if s_type in template_args:
value = ensure_type(template_args[s_type], "string") value = ensure_type(template_args[s_type], "string")
if value is not None and not isinstance(value, string_types): if value is not None and not isinstance(value, str):
raise AnsibleActionFail( raise AnsibleActionFail(
"%s is expected to be a string, but got %s instead" "%s is expected to be a string, but got %s instead"
% (s_type, type(value)) % (s_type, type(value))
@@ -196,7 +195,7 @@ class ActionModule(ActionBase):
) )
template_params = [] template_params = []
if isinstance(template, string_types) or isinstance(template, dict): if isinstance(template, str) or isinstance(template, dict):
template_params.append(self.get_template_args(template)) template_params.append(self.get_template_args(template))
elif isinstance(template, list): elif isinstance(template, list):
for element in template: for element in template:
@@ -246,7 +245,7 @@ class ActionModule(ActionBase):
# add ansible 'template' vars # add ansible 'template' vars
temp_vars = copy.deepcopy(task_vars) temp_vars = copy.deepcopy(task_vars)
overrides = {} overrides = {}
for key, value in iteritems(template_item): for key, value in template_item.items():
if hasattr(self._templar.environment, key): if hasattr(self._templar.environment, key):
if value is not None: if value is not None:
overrides[key] = value overrides[key] = value
@@ -303,7 +302,7 @@ class ActionModule(ActionBase):
) )
def get_kubeconfig(self, kubeconfig, remote_transport, new_module_args): def get_kubeconfig(self, kubeconfig, remote_transport, new_module_args):
if isinstance(kubeconfig, string_types): if isinstance(kubeconfig, str):
# find the kubeconfig in the expected search path # find the kubeconfig in the expected search path
if not remote_transport: if not remote_transport:
# kubeconfig is local # kubeconfig is local

View File

@@ -34,6 +34,13 @@ DOCUMENTATION = """
description: description:
- Enable the helm chart inflation generator - Enable the helm chart inflation generator
default: "False" default: "False"
environment:
description:
- The environment variables to pass to the kustomize or kubectl command.
- This can be a dictionary or a string in the format key=value, multiple pairs separated by space.
type: raw
default: {}
version_added: 6.2.0
requirements: requirements:
- "python >= 3.6" - "python >= 3.6"
@@ -55,6 +62,14 @@ EXAMPLES = """
- name: Create kubernetes resources for lookup output with `--enable-helm` set - name: Create kubernetes resources for lookup output with `--enable-helm` set
kubernetes.core.k8s: kubernetes.core.k8s:
definition: "{{ lookup('kubernetes.core.kustomize', dir='/path/to/kustomization', enable_helm=True) }}" definition: "{{ lookup('kubernetes.core.kustomize', dir='/path/to/kustomization', enable_helm=True) }}"
- name: Create kubernetes resources for lookup output with environment variables in string format
kubernetes.core.k8s:
definition: "{{ lookup('kubernetes.core.kustomize', binary_path='/path/to/kubectl', environment='HTTP_PROXY=http://proxy.example.com:3128') }}"
- name: Create kubernetes resources for lookup output with environment variables in dict format
kubernetes.core.k8s:
definition: "{{ lookup('kubernetes.core.kustomize', binary_path='/path/to/kubectl', environment={'HTTP_PROXY': 'http://proxy.example.com:3128'}) }}"
""" """
RETURN = """ RETURN = """
@@ -72,6 +87,7 @@ RETURN = """
key1: val1 key1: val1
""" """
import os
import subprocess import subprocess
from ansible.errors import AnsibleLookupError from ansible.errors import AnsibleLookupError
@@ -92,8 +108,10 @@ def get_binary_from_path(name, opt_dirs=None):
return None return None
def run_command(command): def run_command(command, environ=None):
cmd = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) cmd = subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=environ
)
stdout, stderr = cmd.communicate() stdout, stderr = cmd.communicate()
return cmd.returncode, stdout, stderr return cmd.returncode, stdout, stderr
@@ -107,6 +125,7 @@ class LookupModule(LookupBase):
binary_path=None, binary_path=None,
opt_dirs=None, opt_dirs=None,
enable_helm=False, enable_helm=False,
environment=None,
**kwargs **kwargs
): ):
executable_path = binary_path executable_path = binary_path
@@ -141,7 +160,21 @@ class LookupModule(LookupBase):
if enable_helm: if enable_helm:
command += ["--enable-helm"] command += ["--enable-helm"]
(ret, out, err) = run_command(command) environ = None
if environment:
environ = os.environ.copy()
if isinstance(environment, str):
if not all(env.count("=") == 1 for env in environment.split(" ")):
raise AnsibleLookupError(
"environment should be dict or string in the format key=value, multiple pairs separated by space"
)
for env in environment.split(" "):
key, value = env.split("=")
environ[key] = value
if isinstance(environment, dict):
environ.update(environment)
(ret, out, err) = run_command(command, environ=environ)
if ret != 0: if ret != 0:
if err: if err:
raise AnsibleLookupError( raise AnsibleLookupError(

View File

@@ -1,12 +1,10 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
from ansible.module_utils.six import string_types
__metaclass__ = type __metaclass__ = type
def list_dict_str(value): def list_dict_str(value):
if isinstance(value, (list, dict, string_types)): if isinstance(value, (list, dict, str)):
return value return value
raise TypeError raise TypeError

View File

@@ -96,7 +96,7 @@ class K8SCopy(metaclass=ABCMeta):
return error, stdout, stderr return error, stdout, stderr
except Exception as e: except Exception as e:
self.module.fail_json( self.module.fail_json(
msg="Error while running/parsing from pod {1}/{2} command='{0}' : {3}".format( msg="Error while running/parsing from pod {0}/{1} command='{2}' : {3}".format(
self.namespace, self.name, cmd, to_native(e) self.namespace, self.name, cmd, to_native(e)
) )
) )
@@ -435,11 +435,21 @@ def check_pod(svc):
try: try:
result = svc.client.get(resource, name=name, namespace=namespace) result = svc.client.get(resource, name=name, namespace=namespace)
containers = [ containers = dict(
c["name"] for c in result.to_dict()["status"]["containerStatuses"] {
] c["name"]: c
if container and container not in containers: for cl in ["initContainerStatuses", "containerStatuses"]
for c in result.to_dict()["status"].get(cl, [])
}
)
if container and container not in containers.keys():
module.fail_json(msg="Pod has no container {0}".format(container)) module.fail_json(msg="Pod has no container {0}".format(container))
return containers if (
container
and container in containers
and not bool(containers[container].get("started", False))
):
module.fail_json(msg="Pod container {0} is not started".format(container))
return containers.keys()
except Exception as exc: except Exception as exc:
_fail(exc) _fail(exc)

View File

@@ -15,7 +15,6 @@ import tempfile
import traceback import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.six import string_types
from ansible_collections.kubernetes.core.plugins.module_utils.version import ( from ansible_collections.kubernetes.core.plugins.module_utils.version import (
LooseVersion, LooseVersion,
) )
@@ -113,7 +112,7 @@ class AnsibleHelmModule(object):
kubeconfig_content = None kubeconfig_content = None
kubeconfig = self.params.get("kubeconfig") kubeconfig = self.params.get("kubeconfig")
if kubeconfig: if kubeconfig:
if isinstance(kubeconfig, string_types): if isinstance(kubeconfig, str):
with open(os.path.expanduser(kubeconfig)) as fd: with open(os.path.expanduser(kubeconfig)) as fd:
kubeconfig_content = yaml.safe_load(fd) kubeconfig_content = yaml.safe_load(fd)
elif isinstance(kubeconfig, dict): elif isinstance(kubeconfig, dict):

View File

@@ -5,7 +5,6 @@ import hashlib
import os import os
from typing import Any, Dict, List, Optional from typing import Any, Dict, List, Optional
from ansible.module_utils.six import iteritems, string_types
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import ( from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
AUTH_ARG_MAP, AUTH_ARG_MAP,
AUTH_ARG_SPEC, AUTH_ARG_SPEC,
@@ -115,7 +114,7 @@ def _load_config(auth: Dict) -> None:
"persist_config": auth.get("persist_config"), "persist_config": auth.get("persist_config"),
} }
if kubeconfig: if kubeconfig:
if isinstance(kubeconfig, string_types): if isinstance(kubeconfig, str):
kubernetes.config.load_kube_config(config_file=kubeconfig, **optional_arg) kubernetes.config.load_kube_config(config_file=kubeconfig, **optional_arg)
elif isinstance(kubeconfig, dict): elif isinstance(kubeconfig, dict):
kubernetes.config.load_kube_config_from_dict( kubernetes.config.load_kube_config_from_dict(
@@ -163,7 +162,7 @@ def _create_configuration(auth: Dict):
except AttributeError: except AttributeError:
configuration = kubernetes.client.Configuration() configuration = kubernetes.client.Configuration()
for key, value in iteritems(auth): for key, value in auth.items():
if key in AUTH_ARG_MAP.keys() and value is not None: if key in AUTH_ARG_MAP.keys() and value is not None:
if key == "api_key": if key == "api_key":
setattr( setattr(

View File

@@ -4,7 +4,6 @@
import os import os
from typing import Dict, Iterable, List, Optional, Union, cast from typing import Dict, Iterable, List, Optional, Union, cast
from ansible.module_utils.six import string_types
from ansible.module_utils.urls import Request from ansible.module_utils.urls import Request
try: try:
@@ -78,11 +77,11 @@ def create_definitions(params: Dict) -> List[ResourceDefinition]:
def from_yaml(definition: Union[str, List, Dict]) -> Iterable[Dict]: def from_yaml(definition: Union[str, List, Dict]) -> Iterable[Dict]:
"""Load resource definitions from a yaml definition.""" """Load resource definitions from a yaml definition."""
definitions: List[Dict] = [] definitions: List[Dict] = []
if isinstance(definition, string_types): if isinstance(definition, str):
definitions += yaml.safe_load_all(definition) definitions += yaml.safe_load_all(definition)
elif isinstance(definition, list): elif isinstance(definition, list):
for item in definition: for item in definition:
if isinstance(item, string_types): if isinstance(item, str):
definitions += yaml.safe_load_all(item) definitions += yaml.safe_load_all(item)
else: else:
definitions.append(item) definitions.append(item)

View File

@@ -498,8 +498,8 @@ def diff_objects(
if not diff: if not diff:
return True, result return True, result
result["before"] = diff[0] result["before"] = hide_fields(diff[0], hidden_fields)
result["after"] = diff[1] result["after"] = hide_fields(diff[1], hidden_fields)
if list(result["after"].keys()) == ["metadata"] and list( if list(result["after"].keys()) == ["metadata"] and list(
result["before"].keys() result["before"].keys()
@@ -512,9 +512,6 @@ def diff_objects(
).issubset(ignored_keys): ).issubset(ignored_keys):
return True, result return True, result
result["before"] = hide_fields(result["before"], hidden_fields)
result["after"] = hide_fields(result["after"], hidden_fields)
return False, result return False, result

View File

@@ -237,6 +237,27 @@ options:
default: False default: False
aliases: [ skip_tls_certs_check ] aliases: [ skip_tls_certs_check ]
version_added: 5.3.0 version_added: 5.3.0
plain_http:
description:
- Use HTTP instead of HTTPS when working with OCI registries
- Requires Helm >= 3.13.0
type: bool
default: False
version_added: 6.1.0
take_ownership:
description:
- When upgrading, Helm will ignore the check for helm annotations and take ownership of the existing resources
- This feature requires helm >= 3.17.0
type: bool
default: False
version_added: 6.1.0
skip_schema_validation:
description:
- Disables JSON schema validation for Chart and values.
- This feature requires helm >= 3.16.0
type: bool
default: False
version_added: 6.2.0
extends_documentation_fragment: extends_documentation_fragment:
- kubernetes.core.helm_common_options - kubernetes.core.helm_common_options
""" """
@@ -319,6 +340,12 @@ EXAMPLES = r"""
chart_ref: "https://github.com/grafana/helm-charts/releases/download/grafana-5.6.0/grafana-5.6.0.tgz" chart_ref: "https://github.com/grafana/helm-charts/releases/download/grafana-5.6.0/grafana-5.6.0.tgz"
release_namespace: monitoring release_namespace: monitoring
- name: Deploy Bitnami's MongoDB latest chart from OCI registry
kubernetes.core.helm:
name: test
chart_ref: "oci://registry-1.docker.io/bitnamicharts/mongodb"
release_namespace: database
# Using complex Values # Using complex Values
- name: Deploy new-relic client chart - name: Deploy new-relic client chart
kubernetes.core.helm: kubernetes.core.helm:
@@ -495,7 +522,9 @@ def run_dep_update(module, chart_ref):
rc, out, err = module.run_helm_command(dep_update) rc, out, err = module.run_helm_command(dep_update)
def fetch_chart_info(module, command, chart_ref, insecure_skip_tls_verify=False): def fetch_chart_info(
module, command, chart_ref, insecure_skip_tls_verify=False, plain_http=False
):
""" """
Get chart info Get chart info
""" """
@@ -504,6 +533,17 @@ def fetch_chart_info(module, command, chart_ref, insecure_skip_tls_verify=False)
if insecure_skip_tls_verify: if insecure_skip_tls_verify:
inspect_command += " --insecure-skip-tls-verify" inspect_command += " --insecure-skip-tls-verify"
if plain_http:
helm_version = module.get_helm_version()
if LooseVersion(helm_version) < LooseVersion("3.13.0"):
module.fail_json(
msg="plain_http requires helm >= 3.13.0, current version is {0}".format(
helm_version
)
)
else:
inspect_command += " --plain-http"
rc, out, err = module.run_helm_command(inspect_command) rc, out, err = module.run_helm_command(inspect_command)
return yaml.safe_load(out) return yaml.safe_load(out)
@@ -533,6 +573,9 @@ def deploy(
reset_values=True, reset_values=True,
reset_then_reuse_values=False, reset_then_reuse_values=False,
insecure_skip_tls_verify=False, insecure_skip_tls_verify=False,
plain_http=False,
take_ownership=False,
skip_schema_validation=False,
): ):
""" """
Install/upgrade/rollback release chart Install/upgrade/rollback release chart
@@ -546,6 +589,8 @@ def deploy(
deploy_command = command + " upgrade -i" # install/upgrade deploy_command = command + " upgrade -i" # install/upgrade
if reset_values: if reset_values:
deploy_command += " --reset-values" deploy_command += " --reset-values"
if take_ownership:
deploy_command += " --take-ownership"
if reuse_values is not None: if reuse_values is not None:
deploy_command += " --reuse-values=" + str(reuse_values) deploy_command += " --reuse-values=" + str(reuse_values)
@@ -595,6 +640,9 @@ def deploy(
else: else:
deploy_command += " --insecure-skip-tls-verify" deploy_command += " --insecure-skip-tls-verify"
if plain_http:
deploy_command += " --plain-http"
if values_files: if values_files:
for value_file in values_files: for value_file in values_files:
deploy_command += " --values=" + value_file deploy_command += " --values=" + value_file
@@ -618,6 +666,17 @@ def deploy(
if set_value_args: if set_value_args:
deploy_command += " " + set_value_args deploy_command += " " + set_value_args
if skip_schema_validation:
helm_version = module.get_helm_version()
if LooseVersion(helm_version) < LooseVersion("3.16.0"):
module.fail_json(
msg="skip_schema_validation requires helm >= 3.16.0, current version is {0}".format(
helm_version
)
)
else:
deploy_command += " --skip-schema-validation"
deploy_command += " " + release_name + f" '{chart_name}'" deploy_command += " " + release_name + f" '{chart_name}'"
return deploy_command return deploy_command
@@ -690,6 +749,8 @@ def helmdiff_check(
reset_values=True, reset_values=True,
reset_then_reuse_values=False, reset_then_reuse_values=False,
insecure_skip_tls_verify=False, insecure_skip_tls_verify=False,
plain_http=False,
skip_schema_validation=False,
): ):
""" """
Use helm diff to determine if a release would change by upgrading a chart. Use helm diff to determine if a release would change by upgrading a chart.
@@ -745,6 +806,28 @@ def helmdiff_check(
if insecure_skip_tls_verify: if insecure_skip_tls_verify:
cmd += " --insecure-skip-tls-verify" cmd += " --insecure-skip-tls-verify"
if skip_schema_validation:
helm_version = module.get_helm_version()
if LooseVersion(helm_version) < LooseVersion("3.16.0"):
module.fail_json(
msg="skip_schema_validation requires helm >= 3.16.0, current version is {0}".format(
helm_version
)
)
else:
cmd += " --skip-schema-validation"
if plain_http:
helm_version = module.get_helm_version()
if LooseVersion(helm_version) < LooseVersion("3.13.0"):
module.fail_json(
msg="plain_http requires helm >= 3.13.0, current version is {0}".format(
helm_version
)
)
else:
cmd += " --plain-http"
rc, out, err = module.run_helm_command(cmd) rc, out, err = module.run_helm_command(cmd)
return (len(out.strip()) > 0, out.strip()) return (len(out.strip()) > 0, out.strip())
@@ -808,6 +891,9 @@ def argument_spec():
insecure_skip_tls_verify=dict( insecure_skip_tls_verify=dict(
type="bool", default=False, aliases=["skip_tls_certs_check"] type="bool", default=False, aliases=["skip_tls_certs_check"]
), ),
plain_http=dict(type="bool", default=False),
take_ownership=dict(type="bool", default=False),
skip_schema_validation=dict(type="bool", default=False),
) )
) )
return arg_spec return arg_spec
@@ -862,6 +948,9 @@ def main():
reset_values = module.params.get("reset_values") reset_values = module.params.get("reset_values")
reset_then_reuse_values = module.params.get("reset_then_reuse_values") reset_then_reuse_values = module.params.get("reset_then_reuse_values")
insecure_skip_tls_verify = module.params.get("insecure_skip_tls_verify") insecure_skip_tls_verify = module.params.get("insecure_skip_tls_verify")
plain_http = module.params.get("plain_http")
take_ownership = module.params.get("take_ownership")
skip_schema_validation = module.params.get("skip_schema_validation")
if update_repo_cache: if update_repo_cache:
run_repo_update(module) run_repo_update(module)
@@ -871,6 +960,33 @@ def main():
release_status = get_release_status(module, release_name, all_status=all_status) release_status = get_release_status(module, release_name, all_status=all_status)
helm_cmd = module.get_helm_binary() helm_cmd = module.get_helm_binary()
if plain_http:
helm_version = module.get_helm_version()
if LooseVersion(helm_version) < LooseVersion("3.13.0"):
module.fail_json(
msg="plain_http requires helm >= 3.13.0, current version is {0}".format(
helm_version
)
)
if take_ownership:
helm_version = module.get_helm_version()
if LooseVersion(helm_version) < LooseVersion("3.17.0"):
module.fail_json(
msg="take_ownership requires helm >= 3.17.0, current version is {0}".format(
helm_version
)
)
if skip_schema_validation:
helm_version = module.get_helm_version()
if LooseVersion(helm_version) < LooseVersion("3.16.0"):
module.fail_json(
msg="skip_schema_validation requires helm >= 3.16.0, current version is {0}".format(
helm_version
)
)
opt_result = {} opt_result = {}
if release_state == "absent" and release_status is not None: if release_state == "absent" and release_status is not None:
# skip release statuses 'uninstalled' and 'uninstalling' # skip release statuses 'uninstalled' and 'uninstalling'
@@ -900,7 +1016,7 @@ def main():
# Fetch chart info to have real version and real name for chart_ref from archive, folder or url # Fetch chart info to have real version and real name for chart_ref from archive, folder or url
chart_info = fetch_chart_info( chart_info = fetch_chart_info(
module, helm_cmd, chart_ref, insecure_skip_tls_verify module, helm_cmd, chart_ref, insecure_skip_tls_verify, plain_http
) )
if dependency_update: if dependency_update:
@@ -962,6 +1078,8 @@ def main():
reset_values=reset_values, reset_values=reset_values,
reset_then_reuse_values=reset_then_reuse_values, reset_then_reuse_values=reset_then_reuse_values,
insecure_skip_tls_verify=insecure_skip_tls_verify, insecure_skip_tls_verify=insecure_skip_tls_verify,
plain_http=plain_http,
skip_schema_validation=skip_schema_validation,
) )
changed = True changed = True
@@ -989,6 +1107,8 @@ def main():
reset_values=reset_values, reset_values=reset_values,
reset_then_reuse_values=reset_then_reuse_values, reset_then_reuse_values=reset_then_reuse_values,
insecure_skip_tls_verify=insecure_skip_tls_verify, insecure_skip_tls_verify=insecure_skip_tls_verify,
plain_http=plain_http,
skip_schema_validation=skip_schema_validation,
) )
if would_change and module._diff: if would_change and module._diff:
opt_result["diff"] = {"prepared": prepared} opt_result["diff"] = {"prepared": prepared}
@@ -1026,6 +1146,9 @@ def main():
reset_values=reset_values, reset_values=reset_values,
reset_then_reuse_values=reset_then_reuse_values, reset_then_reuse_values=reset_then_reuse_values,
insecure_skip_tls_verify=insecure_skip_tls_verify, insecure_skip_tls_verify=insecure_skip_tls_verify,
plain_http=plain_http,
take_ownership=take_ownership,
skip_schema_validation=skip_schema_validation,
) )
changed = True changed = True

View File

@@ -114,6 +114,13 @@ options:
- The path of a helm binary to use. - The path of a helm binary to use.
required: false required: false
type: path type: path
plain_http:
description:
- Use HTTP instead of HTTPS when working with OCI registries
- Requires Helm >= 3.13.0
type: bool
default: False
version_added: 6.1.0
""" """
EXAMPLES = r""" EXAMPLES = r"""
@@ -201,6 +208,7 @@ def main():
chart_ssl_cert_file=dict(type="path"), chart_ssl_cert_file=dict(type="path"),
chart_ssl_key_file=dict(type="path"), chart_ssl_key_file=dict(type="path"),
binary_path=dict(type="path"), binary_path=dict(type="path"),
plain_http=dict(type="bool", default=False),
) )
module = AnsibleHelmModule( module = AnsibleHelmModule(
argument_spec=argspec, argument_spec=argspec,
@@ -225,6 +233,7 @@ def main():
chart_ca_cert="3.1.0", chart_ca_cert="3.1.0",
chart_ssl_cert_file="3.1.0", chart_ssl_cert_file="3.1.0",
chart_ssl_key_file="3.1.0", chart_ssl_key_file="3.1.0",
plain_http="3.13.0",
) )
def test_version_requirement(opt): def test_version_requirement(opt):
@@ -264,6 +273,7 @@ def main():
skip_tls_certs_check=dict(key="insecure-skip-tls-verify"), skip_tls_certs_check=dict(key="insecure-skip-tls-verify"),
chart_devel=dict(key="devel"), chart_devel=dict(key="devel"),
untar_chart=dict(key="untar"), untar_chart=dict(key="untar"),
plain_http=dict(key="plain-http"),
) )
for k, v in helm_flag_args.items(): for k, v in helm_flag_args.items():

View File

@@ -31,6 +31,7 @@ options:
- Desired state of the registry. - Desired state of the registry.
- If set to V(present) attempt to log in to the remote registry server using the URL specified in O(host). - If set to V(present) attempt to log in to the remote registry server using the URL specified in O(host).
- If set to V(absent) attempt to log out from the remote registry server using the URL specified in O(host). - If set to V(absent) attempt to log out from the remote registry server using the URL specified in O(host).
- As helm >= 3.18.0 reports successful logout even if the user is not logged in, this module will report a change regardless of the current state.
required: false required: false
default: present default: present
choices: ['present', 'absent'] choices: ['present', 'absent']
@@ -129,6 +130,9 @@ failed:
from ansible_collections.kubernetes.core.plugins.module_utils.helm import ( from ansible_collections.kubernetes.core.plugins.module_utils.helm import (
AnsibleHelmModule, AnsibleHelmModule,
) )
from ansible_collections.kubernetes.core.plugins.module_utils.version import (
LooseVersion,
)
def arg_spec(): def arg_spec():
@@ -231,6 +235,13 @@ def main():
command=helm_cmd, command=helm_cmd,
) )
helm_version = module.get_helm_version()
if LooseVersion(helm_version) >= LooseVersion("3.18.0") and state == "absent":
# https://github.com/ansible-collections/kubernetes.core/issues/944
module.warn(
"The helm_registry_auth is not idempotent with helm >= 3.18.0, always report a change."
)
module.exit_json(changed=changed, stdout=out, stderr=err, command=helm_cmd) module.exit_json(changed=changed, stdout=out, stderr=err, command=helm_cmd)

View File

@@ -147,6 +147,13 @@ options:
- json - json
- file - file
version_added: 2.4.0 version_added: 2.4.0
plain_http:
description:
- Use HTTP instead of HTTPS when working with OCI registries
- Requires Helm >= 3.13.0
type: bool
default: False
version_added: 6.1.0
""" """
EXAMPLES = r""" EXAMPLES = r"""
@@ -218,6 +225,9 @@ from ansible.module_utils.basic import missing_required_lib
from ansible_collections.kubernetes.core.plugins.module_utils.helm import ( from ansible_collections.kubernetes.core.plugins.module_utils.helm import (
AnsibleHelmModule, AnsibleHelmModule,
) )
from ansible_collections.kubernetes.core.plugins.module_utils.version import (
LooseVersion,
)
def template( def template(
@@ -236,6 +246,7 @@ def template(
values_files=None, values_files=None,
include_crds=False, include_crds=False,
set_values=None, set_values=None,
plain_http=False,
): ):
cmd += " template " cmd += " template "
@@ -262,6 +273,9 @@ def template(
if insecure_registry: if insecure_registry:
cmd += " --insecure-skip-tls-verify" cmd += " --insecure-skip-tls-verify"
if plain_http:
cmd += " --plain-http"
if show_only: if show_only:
for template in show_only: for template in show_only:
cmd += " -s " + template cmd += " -s " + template
@@ -307,6 +321,7 @@ def main():
values_files=dict(type="list", default=[], elements="str"), values_files=dict(type="list", default=[], elements="str"),
update_repo_cache=dict(type="bool", default=False), update_repo_cache=dict(type="bool", default=False),
set_values=dict(type="list", elements="dict"), set_values=dict(type="list", elements="dict"),
plain_http=dict(type="bool", default=False),
), ),
supports_check_mode=True, supports_check_mode=True,
) )
@@ -327,12 +342,22 @@ def main():
values_files = module.params.get("values_files") values_files = module.params.get("values_files")
update_repo_cache = module.params.get("update_repo_cache") update_repo_cache = module.params.get("update_repo_cache")
set_values = module.params.get("set_values") set_values = module.params.get("set_values")
plain_http = module.params.get("plain_http")
if not IMP_YAML: if not IMP_YAML:
module.fail_json(msg=missing_required_lib("yaml"), exception=IMP_YAML_ERR) module.fail_json(msg=missing_required_lib("yaml"), exception=IMP_YAML_ERR)
helm_cmd = module.get_helm_binary() helm_cmd = module.get_helm_binary()
if plain_http:
helm_version = module.get_helm_version()
if LooseVersion(helm_version) < LooseVersion("3.13.0"):
module.fail_json(
msg="plain_http requires helm >= 3.13.0, current version is {0}".format(
helm_version
)
)
if update_repo_cache: if update_repo_cache:
update_cmd = helm_cmd + " repo update" update_cmd = helm_cmd + " repo update"
module.run_helm_command(update_cmd) module.run_helm_command(update_cmd)
@@ -357,6 +382,7 @@ def main():
values_files=values_files, values_files=values_files,
include_crds=include_crds, include_crds=include_crds,
set_values=set_values_args, set_values=set_values_args,
plain_http=plain_http,
) )
if not check_mode: if not check_mode:

View File

@@ -79,6 +79,7 @@ options:
notes: notes:
- the tar binary is required on the container when copying from local filesystem to pod. - the tar binary is required on the container when copying from local filesystem to pod.
- the (init) container has to be started before you copy files or directories to it.
""" """
EXAMPLES = r""" EXAMPLES = r"""

View File

@@ -33,6 +33,14 @@ options:
aliases: aliases:
- api - api
- version - version
hidden_fields:
description:
- List of fields to hide from the diff output.
- This is useful for fields that are not relevant to the patch operation, such as `metadata.managedFields`.
type: list
elements: str
default: []
version_added: 6.1.0
kind: kind:
description: description:
- Use to specify an object model. - Use to specify an object model.
@@ -147,6 +155,7 @@ from ansible_collections.kubernetes.core.plugins.module_utils.k8s.exceptions imp
) )
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.service import ( from ansible_collections.kubernetes.core.plugins.module_utils.k8s.service import (
diff_objects, diff_objects,
hide_fields,
) )
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.waiter import ( from ansible_collections.kubernetes.core.plugins.module_utils.k8s.waiter import (
get_waiter, get_waiter,
@@ -174,6 +183,7 @@ JSON_PATCH_ARGS = {
"namespace": {"type": "str"}, "namespace": {"type": "str"},
"name": {"type": "str", "required": True}, "name": {"type": "str", "required": True},
"patch": {"type": "list", "required": True, "elements": "dict"}, "patch": {"type": "list", "required": True, "elements": "dict"},
"hidden_fields": {"type": "list", "elements": "str", "default": []},
} }
@@ -203,6 +213,7 @@ def execute_module(module, client):
namespace = module.params.get("namespace") namespace = module.params.get("namespace")
patch = module.params.get("patch") patch = module.params.get("patch")
hidden_fields = module.params.get("hidden_fields")
wait = module.params.get("wait") wait = module.params.get("wait")
wait_sleep = module.params.get("wait_sleep") wait_sleep = module.params.get("wait_sleep")
wait_timeout = module.params.get("wait_timeout") wait_timeout = module.params.get("wait_timeout")
@@ -260,13 +271,13 @@ def execute_module(module, client):
module.fail_json(msg=msg, error=to_native(exc), status="", reason="") module.fail_json(msg=msg, error=to_native(exc), status="", reason="")
success = True success = True
result = {"result": obj} result = {"result": hide_fields(obj, hidden_fields)}
if wait and not module.check_mode: if wait and not module.check_mode:
waiter = get_waiter(client, resource, condition=wait_condition) waiter = get_waiter(client, resource, condition=wait_condition)
success, result["result"], result["duration"] = waiter.wait( success, result["result"], result["duration"] = waiter.wait(
wait_timeout, wait_sleep, name, namespace wait_timeout, wait_sleep, name, namespace
) )
match, diffs = diff_objects(existing.to_dict(), obj) match, diffs = diff_objects(existing.to_dict(), obj, hidden_fields)
result["changed"] = not match result["changed"] = not match
if module._diff: if module._diff:
result["diff"] = diffs result["diff"] = diffs

View File

@@ -29,3 +29,5 @@ test_namespace:
- "helm-chart-with-space-into-name" - "helm-chart-with-space-into-name"
- "helm-reset-then-reuse-values" - "helm-reset-then-reuse-values"
- "helm-insecure" - "helm-insecure"
- "helm-test-take-ownership"
- "helm-skip-schema-validation"

View File

@@ -6,3 +6,4 @@
with_items: with_items:
- "v3.15.4" - "v3.15.4"
- "v3.16.0" - "v3.16.0"
- "v3.17.0"

View File

@@ -47,6 +47,12 @@
- name: Test insecure registry flag feature - name: Test insecure registry flag feature
include_tasks: test_helm_insecure.yml include_tasks: test_helm_insecure.yml
- name: Test take ownership flag feature
include_tasks: test_helm_take_ownership.yml
- name: Test helm skip_schema_validation
include_tasks: test_skip_schema_validation.yml
- name: Clean helm install - name: Clean helm install
file: file:
path: "{{ item }}" path: "{{ item }}"

View File

@@ -13,3 +13,11 @@
that: that:
- helm_missing_binary is failed - helm_missing_binary is failed
- "'No such file or directory' in helm_missing_binary.msg" - "'No such file or directory' in helm_missing_binary.msg"
when: ansible_version.full is version('2.20', '<')
- name: Assert that helm is not installed (ansible 2.20+)
assert:
that:
- helm_missing_binary is failed
- "'Error executing command' in helm_missing_binary.msg"
when: ansible_version.full is version('2.20', '>=')

View File

@@ -0,0 +1,81 @@
---
- name: Test helm take ownership
vars:
helm_namespace: "{{ test_namespace[13] }}"
block:
- name: Initial chart installation (no flag set)
helm:
binary_path: "{{ helm_binary }}"
chart_ref: "{{ chart_test_oci }}"
release_name: test-take-ownership
release_namespace: "{{ helm_namespace }}"
create_namespace: true
register: install
- name: Validate that take-ownership flag is not set
assert:
that:
- install is changed
- '"--take-ownership" not in install.command'
- name: Upgrade chart (take-onwership flag set)
helm:
binary_path: "{{ helm_binary }}"
chart_ref: "{{ chart_test_oci }}"
release_name: test-take-ownership
release_namespace: "{{ helm_namespace }}"
take_ownership: true
values:
commonLabels:
take-onwership: "set"
register: upgrade
ignore_errors: true
- name: Validate that take-ownership flag IS set if helm version is >= 3.17.0
assert:
that:
- upgrade is changed
- '"--take-ownership" in upgrade.command'
when: '"v3.17.0" <= helm_version'
- name: Validate that feature fails for helm < 3.17.0
assert:
that:
- upgrade is failed
- '"take_ownership requires helm >= 3.17.0" in upgrade.msg'
when: 'helm_version < "v3.17.0"'
- name: Upgrade chart (take-onwership flag not set)
helm:
binary_path: "{{ helm_binary }}"
chart_ref: "{{ chart_test_oci }}"
release_name: test-take-ownership
release_namespace: "{{ helm_namespace }}"
values:
commonLabels:
take-onwership: "not-set"
register: upgrade
ignore_errors: true
- name: Validate that take-ownership flag IS set if helm version is >= 3.17.0
assert:
that:
- upgrade is changed
- '"--take-ownership" not in upgrade.command'
when: '"v3.17.0" <= helm_version'
- name: Validate that feature fails for helm < 3.17.0
assert:
that:
- upgrade is changed
- upgrade.msg is not defined
when: 'helm_version < "v3.17.0"'
always:
- name: Remove helm namespace
k8s:
api_version: v1
kind: Namespace
name: "{{ helm_namespace }}"
state: absent

View File

@@ -0,0 +1,48 @@
---
- name: Test helm skip_schema_validation
vars:
helm_namespace: "{{ test_namespace[14] }}"
chart_release_values:
replica:
replicaCount: 3
master:
count: 1
kind: Deployment
block:
- name: 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 }}"
skip_schema_validation: true
register: install
ignore_errors: true
- name: Debug install result
debug:
var: install
- name: Validate skip_schema_validation with helm >= 3.16.0 works
assert:
that:
- install is changed
- "'--skip-schema-validation' in install.command"
when: "helm_version is ansible.builtin.version('v3.16.0', '>=')"
- name: Validate skip_schema_validation with helm < 3.16.0 fails
assert:
that:
- install is failed
- "'skip_schema_validation requires helm >= 3.16.0' in install.msg"
when: "helm_version is ansible.builtin.version('v3.16.0', '<')"
always:
- name: Remove helm namespace
k8s:
api_version: v1
kind: Namespace
name: "{{ helm_namespace }}"
state: absent

View File

@@ -0,0 +1,3 @@
helm_template
helm_pull
helm

View File

@@ -0,0 +1,3 @@
[all]
helm-3.12.3 helm_version=v3.12.3 test_namespace=helm-plain-http-v3-12-3 tests_should_failed=true
helm-3.18.2 helm_version=v3.18.2 test_namespace=helm-plain-http-v3-18-2 tests_should_failed=false

View File

@@ -0,0 +1,14 @@
- name: Run test for helm plain http option
hosts: all
gather_facts: true
vars:
ansible_connection: local
ansible_python_interpreter: "{{ ansible_playbook_python }}"
chart_test_oci: "oci://registry-1.docker.io/bitnamicharts/redis"
roles:
- setup_namespace
tasks:
- ansible.builtin.include_tasks: tasks/test.yaml

View File

@@ -0,0 +1,99 @@
---
- name: Run test for helm
block:
- name: Create temporary directory to install chart In
ansible.builtin.tempfile:
state: directory
suffix: .helm
register: install_path
- name: Install required helm version
ansible.builtin.include_role:
name: install_helm
vars:
helm_install_path: "{{ install_path.path }}"
- name: Set helm binary path
ansible.builtin.set_fact:
helm_binary: "{{ install_path.path }}/{{ ansible_system | lower }}-amd64/helm"
# helm
- name: Run helm with plain_http
kubernetes.core.helm:
binary_path: "{{ helm_binary }}"
chart_ref: "{{ chart_test_oci }}"
release_name: test-secure
release_namespace: "{{ test_namespace }}"
create_namespace: true
plain_http: true
register: install_chart
ignore_errors: true
- name: Ensure module failed as expected
ansible.builtin.assert:
that:
- install_chart is failed
- '"plain_http requires helm >= 3.13.0" in install_chart.msg'
when: tests_should_failed | bool
- name: Ensure the result command contains the expected option
ansible.builtin.assert:
that:
- install_chart is not failed
- '"--plain-http" in install_chart.command'
when: not (tests_should_failed | bool)
# helm_pull
- name: Trying to download helm chart with option plain_http
kubernetes.core.helm_pull:
chart_ref: "{{ chart_test_oci }}"
destination: "{{ playbook_dir }}"
binary_path: "{{ helm_binary }}"
plain_http: true
register: pull_chart
ignore_errors: true
- name: Ensure module failed as expected
ansible.builtin.assert:
that:
- pull_chart is failed
- '"plain_http requires helm >= 3.13.0" in pull_chart.msg'
when: tests_should_failed | bool
- name: Ensure the result command contains the expected option
ansible.builtin.assert:
that:
- pull_chart is not failed
- '"--plain-http" in pull_chart.command'
when: not (tests_should_failed | bool)
# helm_template
- name: Test helm render template
kubernetes.core.helm_template:
binary_path: "{{ helm_binary }}"
chart_ref: "{{ chart_test_oci }}"
output_dir: "{{ playbook_dir }}"
plain_http: true
register: template
ignore_errors: true
- name: Ensure module failed as expected
ansible.builtin.assert:
that:
- template is failed
- '"plain_http requires helm >= 3.13.0" in template.msg'
when: tests_should_failed | bool
- name: Ensure the result command contains the expected option
ansible.builtin.assert:
that:
- template is not failed
- '"--plain-http" in template.command'
when: not (tests_should_failed | bool)
always:
- name: Delete temporary file
ansible.builtin.file:
path: "{{ install_path.path }}"
state: absent
ignore_errors: true

View File

@@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -eux
export ANSIBLE_ROLES_PATH=../
ansible-playbook playbooks/play.yaml -i inventory.ini "$@"

View File

@@ -108,15 +108,19 @@
assert: assert:
that: "'Removing login credentials' in _helm_registry_auth_logout.stderr" that: "'Removing login credentials' in _helm_registry_auth_logout.stderr"
- name: Test logout idempotency - name: Test idempotency of logout with helm < 3.18.0
helm_registry_auth: when: _helm_version.stdout is ansible.builtin.version('v3.18.0', '<')
host: localhost:{{ registry_port }} block:
state: absent
register: _helm_registry_auth_logout_idempotency
- name: Assert logout operation did not report change - name: Test logout idempotency
ansible.builtin.assert: helm_registry_auth:
that: _helm_registry_auth_logout_idempotency is not changed host: localhost:{{ registry_port }}
state: absent
register: _helm_registry_auth_logout_idempotency
- name: Assert logout operation did not report change
ansible.builtin.assert:
that: _helm_registry_auth_logout_idempotency is not changed
- name: Ensure that not able to push to the registry - name: Ensure that not able to push to the registry
ansible.builtin.shell: >- ansible.builtin.shell: >-
@@ -133,8 +137,7 @@
# Helm binary prints the message to stderr # Helm binary prints the message to stderr
ansible.builtin.assert: ansible.builtin.assert:
that: that:
- "'push access denied' in _save_chart.stderr" - "'push access denied' in _save_chart.stderr or 'basic credential not found' in _save_chart.stderr"
- "'authorization failed' in _save_chart.stderr"
- "_save_chart.rc != 0" - "_save_chart.rc != 0"
- "'localhost:{{ registry_port }}' not in _config_json.content | b64decode" - "'localhost:{{ registry_port }}' not in _config_json.content | b64decode"
@@ -155,7 +158,8 @@
- name: Assert that the registry is not logged in and auth data is not saved - name: Assert that the registry is not logged in and auth data is not saved
ansible.builtin.assert: ansible.builtin.assert:
that: that:
- "'401 Unauthorized' in _helm_registry_auth_wrong.stderr" - "'401' in _helm_registry_auth_wrong.stderr"
- "'unauthorized' in _helm_registry_auth_wrong.stderr | lower"
- "'{{ wrong_password }}' not in _helm_registry_auth_correct.command" - "'{{ wrong_password }}' not in _helm_registry_auth_correct.command"
- "'{{ wrong_password }}' not in _helm_registry_auth_correct.stdout" - "'{{ wrong_password }}' not in _helm_registry_auth_correct.stdout"
- "'{{ wrong_password }}' not in _helm_registry_auth_correct.stderr" - "'{{ wrong_password }}' not in _helm_registry_auth_correct.stderr"

View File

@@ -14,3 +14,9 @@ pod_with_two_container:
pod_without_executable_find: pod_without_executable_find:
name: openjdk-pod name: openjdk-pod
pod_with_initcontainer_and_container:
name: pod-copy-2
container:
- container-20
- container-21

View File

@@ -18,6 +18,23 @@
wait: yes wait: yes
template: pods_definition.j2 template: pods_definition.j2
- name: Create Init Pod
k8s:
namespace: '{{ copy_namespace }}'
template: pods_definition_init.j2
- kubernetes.core.k8s_info:
api_version: v1
kind: Pod
name: '{{ pod_with_initcontainer_and_container.name }}'
namespace: '{{ copy_namespace }}'
register: init_pod_status
until: >-
init_pod_status.resources|length > 0
and 'initContainerStatuses' in init_pod_status.resources.0.status
and init_pod_status.resources.0.status.initContainerStatuses|length > 0
and init_pod_status.resources.0.status.initContainerStatuses.0.started|bool
- include_tasks: test_copy_errors.yml - include_tasks: test_copy_errors.yml
- include_tasks: test_check_mode.yml - include_tasks: test_check_mode.yml
- include_tasks: test_copy_file.yml - include_tasks: test_copy_file.yml
@@ -25,6 +42,7 @@
- include_tasks: test_copy_directory.yml - include_tasks: test_copy_directory.yml
- include_tasks: test_copy_large_file.yml - include_tasks: test_copy_large_file.yml
- include_tasks: test_copy_item_with_space_in_its_name.yml - include_tasks: test_copy_item_with_space_in_its_name.yml
- include_tasks: test_init_container_pod.yml
always: always:

View File

@@ -67,3 +67,21 @@
that: that:
- copy_fake_container is failed - copy_fake_container is failed
- copy_fake_container.msg == "Pod has no container this_is_a_fake_container" - copy_fake_container.msg == "Pod has no container this_is_a_fake_container"
# copy file to not started container in pod should fail
- name: copy file to not started container in pod should fail
k8s_cp:
namespace: '{{ copy_namespace }}'
pod: '{{ pod_with_initcontainer_and_container.name }}'
remote_path: /tmp
local_path: files/simple_file.txt
state: to_pod
container: '{{ pod_with_initcontainer_and_container.container[1] }}'
ignore_errors: true
register: copy_not_started_container
- name: check that error message is as expected
assert:
that:
- copy_not_started_container is failed
- copy_not_started_container.msg == "Pod container {{ pod_with_initcontainer_and_container.container[1] }} is not started"

View File

@@ -0,0 +1,25 @@
---
- set_fact:
random_content: "{{ lookup('password', '/dev/null chars=ascii_lowercase,digits,punctuation length=128') }}"
- name: Copy content into init container
k8s_cp:
namespace: '{{ copy_namespace }}'
pod: '{{ pod_with_initcontainer_and_container.name }}'
remote_path: /file_from_localhost.txt
content: '{{ random_content }}'
container: '{{ pod_with_initcontainer_and_container.container[0] }}'
state: to_pod
- name: Get the content from copied file
kubernetes.core.k8s_exec:
namespace: '{{ copy_namespace }}'
pod: '{{ pod_with_initcontainer_and_container.name }}'
container: '{{ pod_with_initcontainer_and_container.container[0] }}'
command: cat /file_from_localhost.txt
register: exec_out
- name: check that content is found and the same as generated earlier
assert:
that:
- exec_out.stdout == random_content

View File

@@ -0,0 +1,20 @@
---
apiVersion: v1
kind: Pod
metadata:
name: '{{ pod_with_initcontainer_and_container.name }}'
spec:
initContainers:
- name: '{{ pod_with_initcontainer_and_container.container[0] }}'
image: busybox
command:
- /bin/sh
- -c
- while true;do date;sleep 5; done
containers:
- name: '{{ pod_with_initcontainer_and_container.container[1] }}'
image: busybox
command:
- /bin/sh
- -c
- while true;do date;sleep 5; done

View File

@@ -58,7 +58,7 @@
- "'managedFields' not in hf4.resources[0]['metadata']" - "'managedFields' not in hf4.resources[0]['metadata']"
- name: Hiding a changed field should still result in a change - name: Hiding a changed field should not result in a change
k8s: k8s:
definition: "{{ hide_fields_base_configmap | combine({'data':{'hello':'different'}}) }}" definition: "{{ hide_fields_base_configmap | combine({'data':{'hello':'different'}}) }}"
hidden_fields: hidden_fields:
@@ -67,10 +67,10 @@
register: hf5 register: hf5
diff: true diff: true
- name: Ensure that hidden changed field changed - name: Ensure that hidden changed field not changed
assert: assert:
that: that:
- hf5.changed - not hf5.changed
- name: Apply works with hidden fields - name: Apply works with hidden fields
k8s: k8s:

View File

@@ -0,0 +1,3 @@
k8s_json_patch
k8s
time=33

View File

@@ -0,0 +1,2 @@
---
test_namespace: "k8s-hide-fields"

View File

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

View File

@@ -0,0 +1,6 @@
---
- connection: local
gather_facts: false
hosts: localhost
roles:
- k8s_json_patch_hide_fields

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -eux
export ANSIBLE_CALLBACKS_ENABLED=profile_tasks
export ANSIBLE_ROLES_PATH=../
ansible-playbook playbook.yaml "$@"

View File

@@ -0,0 +1,91 @@
- vars:
pod: json-patch
k8s_wait_timeout: 400
block:
- name: Create a simple pod
kubernetes.core.k8s:
definition:
apiVersion: v1
kind: Pod
metadata:
namespace: "{{ test_namespace }}"
name: "{{ pod }}"
labels:
label1: foo
spec:
containers:
- image: busybox:musl
name: busybox
command:
- sh
- -c
- while true; do echo $(date); sleep 10; done
wait: yes
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
- name: Add a label, and hide some fields
kubernetes.core.k8s_json_patch:
kind: Pod
namespace: "{{ test_namespace }}"
name: "{{ pod }}"
patch:
- op: add
path: /metadata/labels/label2
value: bar
hidden_fields:
- metadata.managedFields
register: hf1
- name: Ensure hidden fields are not present
assert:
that:
- "'managedFields' not in hf1.result['metadata']"
- name: Add a label, without hiding our fields
kubernetes.core.k8s_json_patch:
kind: Pod
namespace: "{{ test_namespace }}"
name: "{{ pod }}"
patch:
- op: add
path: /metadata/labels/label3
value: bar
hidden_fields:
- something.else
register: hf2
- name: Ensure hidden fields are present
assert:
that:
- "'managedFields' in hf2.result['metadata']"
- name: Patching the same resource with missing hidden fields should have no effect
kubernetes.core.k8s_json_patch:
kind: Pod
namespace: "{{ test_namespace }}"
name: "{{ pod }}"
patch:
- op: add
path: /metadata/labels/label2
value: bar
hidden_fields:
- does.not.exist
register: hf2
- name: Ensure no change with missing hidden fields
assert:
that:
- not hf2.changed
always:
- name: Remove namespace
k8s:
kind: Namespace
name: "{{ test_namespace }}"
state: absent
ignore_errors: true

View File

@@ -33,7 +33,6 @@
ports: ports:
- containerPort: 80 - containerPort: 80
- name: Crash the existing deployment - name: Crash the existing deployment
k8s: k8s:
state: present state: present
@@ -228,7 +227,7 @@
hostPath: hostPath:
path: /var/lib/docker/containers path: /var/lib/docker/containers
register: crash register: crash
ignore_errors: true ignore_errors: yes
- name: Assert that the Daemonset failed - name: Assert that the Daemonset failed
assert: assert:
@@ -291,6 +290,297 @@
that: that:
- failed_version | int + 1 == result.resources[0].metadata.annotations['deprecated.daemonset.template.generation'] | int - failed_version | int + 1 == result.resources[0].metadata.annotations['deprecated.daemonset.template.generation'] | int
- name: Create deployment with specific labels for selector testing
k8s:
state: present
wait: yes
wait_timeout: "{{ k8s_wait_timeout }}"
definition:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-labeled
namespace: "{{ namespace }}"
labels:
app: nginx
test-group: label-selector-test
spec:
replicas: 2
selector:
matchLabels:
app: nginx-labeled
template:
metadata:
labels:
app: nginx-labeled
spec:
containers:
- name: nginx
image: nginx:1.17
ports:
- containerPort: 80
- name: Update deployment to create second revision
k8s:
state: present
wait: yes
wait_timeout: 30
definition:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-labeled
namespace: "{{ namespace }}"
labels:
app: nginx
test-group: label-selector-test
spec:
replicas: 2
selector:
matchLabels:
app: nginx-labeled
template:
metadata:
labels:
app: nginx-labeled
spec:
containers:
- name: nginx
image: nginx:1.18
ports:
- containerPort: 80
- name: Test rollback with label selectors
k8s_rollback:
api_version: apps/v1
kind: Deployment
name: nginx-labeled
namespace: "{{ namespace }}"
label_selectors:
- "test-group=label-selector-test"
register: result
- name: Assert label selector rollback worked
assert:
that:
- result is changed
- result.rollback_info | length == 1
- result.rollback_info[0].method == "patch"
- name: Create deployment with single revision
k8s:
state: present
wait: yes
wait_timeout: 30
definition:
apiVersion: apps/v1
kind: Deployment
metadata:
name: single-revision
namespace: "{{ namespace }}"
spec:
replicas: 1
selector:
matchLabels:
app: single-revision
template:
metadata:
labels:
app: single-revision
spec:
containers:
- name: nginx
image: nginx:1.17
ports:
- containerPort: 80
- name: Try to rollback deployment with no previous revisions
k8s_rollback:
api_version: apps/v1
kind: Deployment
name: single-revision
namespace: "{{ namespace }}"
register: result
- name: Assert warning is returned for no rollout history
assert:
that:
- not result.changed
- result.rollback_info[0].warnings is defined
- "'No rollout history found' in result.rollback_info[0].warnings[0]"
- name: Create a service for unsupported resource test
k8s:
state: present
definition:
apiVersion: v1
kind: Service
metadata:
name: test-service
namespace: "{{ namespace }}"
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
- name: Test rollback on unsupported resource type
k8s_rollback:
api_version: v1
kind: Service
name: test-service
namespace: "{{ namespace }}"
register: result
ignore_errors: yes
- name: Assert error message for unsupported resource
assert:
that:
- not result.changed
- "'Cannot perform rollback on resource of kind Service' in result.msg"
- name: Test rollback on non-existent deployment
k8s_rollback:
api_version: apps/v1
kind: Deployment
name: non-existent
namespace: "{{ namespace }}"
register: result
- name: Assert no resources found
assert:
that:
- not result.changed
- result.rollback_info | length == 0
- name: Create multiple deployments with same label
k8s:
state: present
wait: yes
wait_timeout: 30
definition:
apiVersion: apps/v1
kind: Deployment
metadata:
name: "multi-{{ item }}"
namespace: "{{ namespace }}"
labels:
group: multi-test
app: multi
spec:
replicas: 1
selector:
matchLabels:
app: "multi-{{ item }}"
template:
metadata:
labels:
app: "multi-{{ item }}"
spec:
containers:
- name: nginx
image: nginx:1.17
ports:
- containerPort: 80
loop: [1, 2, 3]
- name: Update multiple deployments to create second revisions
k8s:
state: present
wait: yes
wait_timeout: 30
definition:
apiVersion: apps/v1
kind: Deployment
metadata:
name: "multi-{{ item }}"
namespace: "{{ namespace }}"
labels:
group: multi-test
app: multi
spec:
replicas: 1
selector:
matchLabels:
app: "multi-{{ item }}"
template:
metadata:
labels:
app: "multi-{{ item }}"
spec:
containers:
- name: nginx
image: nginx:1.18
ports:
- containerPort: 80
loop: [1, 2, 3]
- name: Rollback multiple deployments using label selector
k8s_rollback:
api_version: apps/v1
kind: Deployment
name: "multi-{{ item }}"
namespace: "{{ namespace }}"
label_selectors:
- "group=multi-test"
register: result
loop: [1, 2, 3]
- name: Assert multiple resources were rolled back
assert:
that:
- result.results | length == 3
- result.results | selectattr('changed', 'equalto', true) | list | length == 3
- result.results | selectattr('rollback_info', 'defined') | list | length == 3
- result.results | map(attribute='rollback_info') | map('first') | map(attribute='method') | select('equalto', 'patch') | list | length == 3
- name: Validate rollback_info structure for deployment
assert:
that:
- result.results is defined
- result.results[0].rollback_info is defined
- result.results[0].rollback_info | length > 0
- result.results[0].rollback_info[0].method == "patch"
- result.results[0].rollback_info[0].body is defined
- result.results[0].rollback_info[0].resources is defined
- result.results[0].rollback_info[0].resources.metadata is defined
- result.results[0].rollback_info[0].resources.spec is defined
- name: Test rollback with field selectors
k8s_rollback:
api_version: apps/v1
kind: Deployment
name: multi-1
namespace: "{{ namespace }}"
field_selectors:
- "metadata.name=multi-1"
register: result
- name: Assert field selector rollback worked
assert:
that:
- result is changed
- result.rollback_info | length == 1
- result.rollback_info[0].resources.metadata.name == "multi-1"
- name: Test check mode return values
k8s_rollback:
api_version: apps/v1
kind: Deployment
name: multi-2
namespace: "{{ namespace }}"
register: result
check_mode: yes
- name: Validate check mode returns expected structure
assert:
that:
- result is changed
- result.rollback_info is defined
- result.rollback_info[0].method == "patch"
- result.rollback_info[0].body is defined
always: always:
- name: Delete {{ namespace }} namespace - name: Delete {{ namespace }} namespace
k8s: k8s:

View File

@@ -94,6 +94,52 @@
namespace: "{{ kustomize_ns }}" namespace: "{{ kustomize_ns }}"
definition: "{{ lookup('kubernetes.core.kustomize', dir=kustomize_dir, opt_dirs=tmp_dir_path) }}" definition: "{{ lookup('kubernetes.core.kustomize', dir=kustomize_dir, opt_dirs=tmp_dir_path) }}"
- name: Create temporarly directory for test
ansible.builtin.tempfile:
state: directory
suffix: .testkustomize
register: _tmp_dir_kustomize
- name: Download helloWorld example
ansible.builtin.get_url:
url: "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/refs/heads/master/examples/loadHttp/kustomization.yaml"
dest: "{{ _tmp_dir_kustomize.path }}"
- name: Run tinyproxy in docker
# Replace the 'app: hello' with 'app: ${TEST_APP}'
ansible.builtin.command: "docker run --rm -d -p 8888:8888 --name=tinyproxy dannydirect/tinyproxy ANY"
- name: Ensure that tinyproxy is running
ansible.builtin.wait_for:
host: localhost
port: 8888
state: started
- name: Test kustomize lookup plugin with environment variables in the string format
set_fact:
resource_kustomize: "{{ lookup('kubernetes.core.kustomize', dir=_tmp_dir_kustomize.path, environment='HTTPS_PROXY=http://localhost:8888 VAR2=Flase') }}"
- name: Test kustomize lookup plugin with environment variables in the dict format
set_fact:
resource_kustomize: "{{ lookup('kubernetes.core.kustomize', dir=_tmp_dir_kustomize.path, environment={'HTTPS_PROXY': 'http://localhost:8888', 'VAR2': 'Flase'}) }}"
- name: Stop tinyproxy
ansible.builtin.command: "docker stop tinyproxy"
- name: Ensure kustomize lookup plugin fail with proxy down
set_fact:
resource_kustomize: "{{ lookup('kubernetes.core.kustomize', dir=_tmp_dir_kustomize.path, environment='HTTPS_PROXY=http://localhost:8888 VAR2=Flase') }}"
register: result
ignore_errors: true
- name: Assert that kustomize lookup plugin failed
ansible.builtin.assert:
that:
- result.failed
- "'proxyconnect tcp: dial' in result.msg"
- "'connection refused' in result.msg"
always: always:
- name: Delete namespace - name: Delete namespace
k8s: k8s:
@@ -105,4 +151,11 @@
- name: Delete temporary directory - name: Delete temporary directory
file: file:
state: absent state: absent
path: "{{ tmp_dir_path }}" path: "{{ item }}"
with_items:
- "{{ tmp_dir_path }}"
- "{{ _tmp_dir_kustomize.path }}"
- name: Stop tinyproxy
ansible.builtin.command: "docker stop tinyproxy"
ignore_errors: true

View File

@@ -10,7 +10,6 @@ import ansible.module_utils.basic
import pytest import pytest
from ansible.module_utils._text import to_bytes from ansible.module_utils._text import to_bytes
from ansible.module_utils.common._collections_compat import MutableMapping from ansible.module_utils.common._collections_compat import MutableMapping
from ansible.module_utils.six import string_types
@pytest.fixture @pytest.fixture
@@ -20,7 +19,7 @@ def stdin(mocker, request):
old_argv = sys.argv old_argv = sys.argv
sys.argv = ["ansible_unittest"] sys.argv = ["ansible_unittest"]
if isinstance(request.param, string_types): if isinstance(request.param, str):
args = request.param args = request.param
elif isinstance(request.param, MutableMapping): elif isinstance(request.param, MutableMapping):
if "ANSIBLE_MODULE_ARGS" not in request.param: if "ANSIBLE_MODULE_ARGS" not in request.param: