Skip to content
This repository has been archived by the owner on Jun 13, 2024. It is now read-only.

k8s Secret check_mode issue #282

Closed
eMCeee89 opened this issue Oct 22, 2020 · 5 comments · Fixed by #343
Closed

k8s Secret check_mode issue #282

eMCeee89 opened this issue Oct 22, 2020 · 5 comments · Fixed by #343
Assignees
Labels
has_pr This issue has a related PR that may close it. priority/medium type/bug Something isn't working

Comments

@eMCeee89
Copy link

SUMMARY

When k8s module is used for Kubernetes Secret (state=present) with a check_mode enabled, then it always returns changed: True. Without check_mode, the very same manifest returns changed: False. Please note this issue only applies to Secret resource type, ConfigMap resource returns expected results.

ISSUE TYPE
  • Bug Report
COMPONENT NAME

community.kubernetes.k8s

ANSIBLE VERSION
ansible 2.9.14
  config file = /kubernetes/ansible.cfg
  configured module search path = ['/home/bambus/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.6/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 3.6.8 (default, Apr 16 2020, 01:36:27) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)]
CONFIGURATION
ANSIBLE_SSH_ARGS(/kubernetes/ansible.cfg) = -C -o ControlMaster=auto -o ControlPersist=60s -o PubkeyAuthentication=no
COLOR_CHANGED(/kubernetes/ansible.cfg) = yellow
COLOR_DEBUG(/kubernetes/ansible.cfg) = dark gray
COLOR_DEPRECATE(/kubernetes/ansible.cfg) = purple
COLOR_DIFF_ADD(/kubernetes/ansible.cfg) = green
COLOR_DIFF_LINES(/kubernetes/ansible.cfg) = cyan
COLOR_DIFF_REMOVE(/kubernetes/ansible.cfg) = red
COLOR_ERROR(/kubernetes/ansible.cfg) = red
COLOR_HIGHLIGHT(/kubernetes/ansible.cfg) = white
COLOR_OK(/kubernetes/ansible.cfg) = green
COLOR_SKIP(/kubernetes/ansible.cfg) = cyan
COLOR_UNREACHABLE(/kubernetes/ansible.cfg) = red
COLOR_VERBOSE(/kubernetes/ansible.cfg) = blue
COLOR_WARN(/kubernetes/ansible.cfg) = bright purple
DEFAULT_LOAD_CALLBACK_PLUGINS(/kubernetes/ansible.cfg) = True
DEFAULT_STDOUT_CALLBACK(/kubernetes/ansible.cfg) = yaml
HOST_KEY_CHECKING(/kubernetes/ansible.cfg) = False
OS / ENVIRONMENT

Centos 8.2.2004

STEPS TO REPRODUCE
---
- hosts: "127.0.0.1"
  connection: local
  gather_facts: False
  vars:
    _definition:
      apiVersion: v1
      kind: Secret
      metadata:
        name: test
        namespace: default
      type: Opaque
      stringData:
        foo: "bar"
  tasks:
    - name: dry run
      k8s:
        state: present
        definition: "{{ _definition }}"
      check_mode: yes

    - name: real run
      k8s:
        state: present
        definition: "{{ _definition }}"
EXPECTED RESULTS

Having check_mode enabled, it should return empty diff when there is no change to be applied and change result set to False.

ACTUAL RESULTS

When check_mode is enabled, it always returns changed: True result even though there is no change to be applied.

$ ansible-playbook -i inventory/localhost.yml playbooks/playbook.yml -vvvv
ansible-playbook 2.9.14
  config file = /kubernetes/ansible.cfg
  configured module search path = ['/home/bambus/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.6/site-packages/ansible
  executable location = /usr/bin/ansible-playbook
  python version = 3.6.8 (default, Apr 16 2020, 01:36:27) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)]
Using /kubernetes/ansible.cfg as config file
setting up inventory plugins
host_list declined parsing /kubernetes/inventory/localhost.yml as it did not pass its verify_file() method
script declined parsing /kubernetes/inventory/localhost.yml as it did not pass its verify_file() method
Parsed /kubernetes/inventory/localhost.yml inventory source with yaml plugin
Loading callback plugin yaml of type stdout, v2.0 from /usr/lib/python3.6/site-packages/ansible/plugins/callback/yaml.py

PLAYBOOK: playbook.yml ******************************************************************************************************************************************************
Positional arguments: playbooks/playbook.yml
verbosity: 4
connection: smart
timeout: 10
become_method: sudo
tags: ('all',)
inventory: ('/kubernetes/inventory/localhost.yml',)
forks: 5
1 plays in playbooks/playbook.yml

PLAY [127.0.0.1] ************************************************************************************************************************************************************
META: ran handlers

TASK [dry run] **************************************************************************************************************************************************************
task path: /kubernetes/playbooks/playbook.yml:16
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: bambus
<127.0.0.1> EXEC /bin/sh -c 'echo ~bambus && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/bambus/.ansible/tmp `"&& mkdir "` echo /home/bambus/.ansible/tmp/ansible-tmp-1603373084.7558267-273572-266149592071148 `" && echo ansible-tmp-1603373084.7558267-273572-266149592071148="` echo /home/bambus/.ansible/tmp/ansible-tmp-1603373084.7558267-273572-266149592071148 `" ) && sleep 0'
Using module file /usr/lib/python3.6/site-packages/ansible/modules/clustering/k8s/k8s.py
<127.0.0.1> PUT /home/bambus/.ansible/tmp/ansible-local-273555e76twcw7/tmpuulrd53s TO /home/bambus/.ansible/tmp/ansible-tmp-1603373084.7558267-273572-266149592071148/AnsiballZ_k8s.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /home/bambus/.ansible/tmp/ansible-tmp-1603373084.7558267-273572-266149592071148/ /home/bambus/.ansible/tmp/ansible-tmp-1603373084.7558267-273572-266149592071148/AnsiballZ_k8s.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '/usr/bin/python3.6 /home/bambus/.ansible/tmp/ansible-tmp-1603373084.7558267-273572-266149592071148/AnsiballZ_k8s.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /home/bambus/.ansible/tmp/ansible-tmp-1603373084.7558267-273572-266149592071148/ > /dev/null 2>&1 && sleep 0'
changed: [127.0.0.1] => changed=true 
  diff:
    after:
      stringData:
        foo: bar
    before: {}
  invocation:
    module_args:
      api_key: null
      api_version: v1
      append_hash: false
      apply: false
      ca_cert: null
      client_cert: null
      client_key: null
      context: null
      force: false
      host: null
      kind: null
      kubeconfig: null
      merge_type: null
      name: null
      namespace: null
      password: null
      proxy: null
      resource_definition:
        apiVersion: v1
        kind: Secret
        metadata:
          name: test
          namespace: default
        stringData:
          foo: bar
        type: Opaque
      src: null
      state: present
      username: null
      validate: null
      validate_certs: null
      wait: false
      wait_condition: null
      wait_sleep: 5
      wait_timeout: 120
  method: patch
  result:
    apiVersion: v1
    data:
      foo: YmFy
    kind: Secret
    metadata:
      creationTimestamp: '2020-10-22T13:22:26Z'
      name: test
      namespace: default
      resourceVersion: '491215'
      selfLink: /api/v1/namespaces/default/secrets/test
      uid: b8cdc934-521e-469d-a06a-4cffe10ef05e
    stringData:
      foo: bar
    type: Opaque

TASK [real run] *************************************************************************************************************************************************************
task path: /kubernetes/playbooks/playbook.yml:22
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: bambus
<127.0.0.1> EXEC /bin/sh -c 'echo ~bambus && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/bambus/.ansible/tmp `"&& mkdir "` echo /home/bambus/.ansible/tmp/ansible-tmp-1603373087.9914718-273624-167314503481206 `" && echo ansible-tmp-1603373087.9914718-273624-167314503481206="` echo /home/bambus/.ansible/tmp/ansible-tmp-1603373087.9914718-273624-167314503481206 `" ) && sleep 0'
Using module file /usr/lib/python3.6/site-packages/ansible/modules/clustering/k8s/k8s.py
<127.0.0.1> PUT /home/bambus/.ansible/tmp/ansible-local-273555e76twcw7/tmp9we0qr90 TO /home/bambus/.ansible/tmp/ansible-tmp-1603373087.9914718-273624-167314503481206/AnsiballZ_k8s.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /home/bambus/.ansible/tmp/ansible-tmp-1603373087.9914718-273624-167314503481206/ /home/bambus/.ansible/tmp/ansible-tmp-1603373087.9914718-273624-167314503481206/AnsiballZ_k8s.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '/usr/bin/python3.6 /home/bambus/.ansible/tmp/ansible-tmp-1603373087.9914718-273624-167314503481206/AnsiballZ_k8s.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /home/bambus/.ansible/tmp/ansible-tmp-1603373087.9914718-273624-167314503481206/ > /dev/null 2>&1 && sleep 0'
ok: [127.0.0.1] => changed=false 
  diff: {}
  invocation:
    module_args:
      api_key: null
      api_version: v1
      append_hash: false
      apply: false
      ca_cert: null
      client_cert: null
      client_key: null
      context: null
      force: false
      host: null
      kind: null
      kubeconfig: null
      merge_type: null
      name: null
      namespace: null
      password: null
      proxy: null
      resource_definition:
        apiVersion: v1
        kind: Secret
        metadata:
          name: test
          namespace: default
        stringData:
          foo: bar
        type: Opaque
      src: null
      state: present
      username: null
      validate: null
      validate_certs: null
      wait: false
      wait_condition: null
      wait_sleep: 5
      wait_timeout: 120
  method: patch
  result:
    apiVersion: v1
    data:
      foo: YmFy
    kind: Secret
    metadata:
      creationTimestamp: '2020-10-22T13:22:26Z'
      name: test
      namespace: default
      resourceVersion: '491215'
      selfLink: /api/v1/namespaces/default/secrets/test
      uid: b8cdc934-521e-469d-a06a-4cffe10ef05e
    type: Opaque
META: ran handlers
META: ran handlers

PLAY RECAP ******************************************************************************************************************************************************************
127.0.0.1                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
@eMCeee89
Copy link
Author

One finding regarding the issue:

  • if you use data instead of stringData and you encode values using b64encode filter, then the issue will not appear hence module behaves as expected

@fabianvf
Copy link
Collaborator

Since the k8s module is generic, in check mode it sees that what the user wants is stringData with content, and what is there is data with different content, and so it assumes that this is a real change and reports that the resource will change (which should be correct for pretty much any other resource).

We can just special case secrets in check mode here to make it work correctly, we just need to change stringData to data and base64 encode the values before running the diff

@tima tima added planned This issue is planned to be taken up in a feature release priority/medium labels Oct 22, 2020
@gravesm gravesm self-assigned this Jan 8, 2021
gravesm added a commit to gravesm/community.kubernetes that referenced this issue Jan 12, 2021
When adding a Secret and using stringData, check_mode will always show
changes. An existing resource fetched from Kubernetes will have the
stringData already base64 encoded and merged into the data attribute.
This change performs the base64 encoding and merging with the provided
definition to more accurately represent the current state of the
cluster.

This change only affects check_mode. When making any changes to the
cluster the stringData is passed along as provided in the definition.

Closes ansible-collections#282.
@Akasurde
Copy link
Member

@eMCeee89 Could you please check if #343 works for you and let us know? Thanks.

needs_info

@Akasurde
Copy link
Member

resolved_by_pr #343

@Akasurde Akasurde added has_pr This issue has a related PR that may close it. type/bug Something isn't working and removed planned This issue is planned to be taken up in a feature release labels Jan 13, 2021
@eMCeee89
Copy link
Author

@Akasurde I can confirm it works well using a version from #343, thank you.

goneri pushed a commit that referenced this issue Jan 14, 2021
When adding a Secret and using stringData, check_mode will always show
changes. An existing resource fetched from Kubernetes will have the
stringData already base64 encoded and merged into the data attribute.
This change performs the base64 encoding and merging with the provided
definition to more accurately represent the current state of the
cluster.

This change only affects check_mode. When making any changes to the
cluster the stringData is passed along as provided in the definition.

Closes #282.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
has_pr This issue has a related PR that may close it. priority/medium type/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants