Skip to content

Commit

Permalink
k8s_info - fix issue with kubernetes-client caching when api-server w…
Browse files Browse the repository at this point in the history
…as available (#571)

k8s_info - fix issue with kubernetes-client caching when api-server was available

SUMMARY
closes #508
ISSUE TYPE


Bugfix Pull Request

COMPONENT NAME

k8s_info
ADDITIONAL INFORMATION

Reviewed-by: Mike Graves <[email protected]>
  • Loading branch information
abikouo authored Jan 24, 2023
1 parent af7c24c commit 8ed4d4b
Show file tree
Hide file tree
Showing 7 changed files with 347 additions and 242 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
bugfixes:
- k8s_info - fix issue when module returns successful true after the resource cache has been established during periods where communication to the api-server is not possible (https://github.com/ansible-collections/kubernetes.core/issues/508).
10 changes: 7 additions & 3 deletions plugins/module_utils/k8s/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
)

from ansible.module_utils.common.dict_transformations import dict_merge
from ansible.module_utils._text import to_native

try:
from kubernetes.dynamic.exceptions import (
Expand Down Expand Up @@ -268,8 +267,13 @@ def find(
except BadRequestError:
return result
except CoreException as e:
result["msg"] = to_native(e)
return result
raise e
except Exception as e:
raise CoreException(
"Exception '{0}' raised while trying to get resource using (name={1}, namespace={2}, label_selectors={3}, field_selectors={4})".format(
e, name, namespace, label_selectors, field_selectors
)
)

# There is either no result or there is a List resource with no items
if (
Expand Down
4 changes: 3 additions & 1 deletion tests/integration/targets/k8s_info/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
---
test_namespace: "wait"
test_namespace:
- wait
- python-api-caching
k8s_wait_timeout: 400
91 changes: 91 additions & 0 deletions tests/integration/targets/k8s_info/tasks/api-server-caching.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
- name: create temporary directory for tests
tempfile:
state: directory
suffix: .test
register: _testdir

- block:
- name: Create kubernetes secret
k8s:
namespace: '{{ api_namespace }}'
definition:
apiVersion: v1
kind: Secret
metadata:
name: '{{ test_secret }}'
type: Opaque
stringData:
foo: bar

- name: save default kubeconfig
copy:
src: ~/.kube/config
dest: '{{ _testdir.path }}/config'

- name: create bad kubeconfig
copy:
src: '{{ _testdir.path }}/config'
dest: '{{ _testdir.path }}/badconfig'

- name: Remove certificate-data from badconfig
ansible.builtin.lineinfile:
path: '{{ _testdir.path }}/badconfig'
regexp: "(.*)certificate-authority-data(.*)"
state: absent

- name: Delete default config
file:
state: absent
path: ~/.kube/config

- name: Check for existing cluster namespace with good kubeconfig
k8s_info:
api_version: v1
kind: Secret
name: '{{ test_secret }}'
namespace: '{{ api_namespace }}'
kubeconfig: '{{ _testdir.path }}/config'
register: result_good_config

- name: Check for existing cluster namespace with bad kubeconfig
k8s_info:
api_version: v1
kind: Secret
name: '{{ test_secret }}'
namespace: '{{ api_namespace }}'
kubeconfig: '{{ _testdir.path }}/badconfig'
register: result_bad_config
ignore_errors: true

- name: Ensure task has failed with proper message
assert:
that:
- result_good_config is successful
- result_good_config.resources | length == 1
- result_bad_config is failed
- '"certificate verify failed" in result_bad_config.msg'

vars:
api_namespace: "{{ test_namespace[1] }}"
test_secret: "my-secret"

always:

- name: restore default kubeconfig
copy:
dest: ~/.kube/config
src: '{{ _testdir.path }}/config'

- name: Delete namespace
k8s:
kind: namespace
name: "{{ api_namespace }}"
state: absent
ignore_errors: true

- name: delete temporary directory
file:
state: absent
path: '{{ _testdir.path }}'
ignore_errors: true
241 changes: 4 additions & 237 deletions tests/integration/targets/k8s_info/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -1,238 +1,5 @@
---
- block:
- set_fact:
wait_namespace: "{{ test_namespace }}"
multi_pod_one: multi-pod-1
multi_pod_two: multi-pod-2

- name: Add a simple pod with initContainer
k8s:
definition:
apiVersion: v1
kind: Pod
metadata:
name: "{{ k8s_pod_name }}"
namespace: "{{ wait_namespace }}"
spec:
initContainers:
- name: init-01
image: python:3.7-alpine
command: ['sh', '-c', 'sleep 20']
containers:
- name: utilitypod-01
image: python:3.7-alpine
command: ['sh', '-c', 'sleep 360']

- name: Wait and gather information about new pod
k8s_info:
name: "{{ k8s_pod_name }}"
kind: Pod
namespace: "{{ wait_namespace }}"
wait: yes
wait_sleep: 5
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
register: wait_info

- name: Assert that pod creation succeeded
assert:
that:
- wait_info is successful
- not wait_info.changed
- wait_info.resources[0].status.phase == "Running"

- name: Remove Pod
k8s:
api_version: v1
kind: Pod
name: "{{ k8s_pod_name }}"
namespace: "{{ wait_namespace }}"
state: absent
wait: yes
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
ignore_errors: yes
register: short_wait_remove_pod

- name: Check if pod is removed
assert:
that:
- short_wait_remove_pod is successful
- short_wait_remove_pod.changed

- name: Create multiple pod with initContainer
k8s:
definition:
apiVersion: v1
kind: Pod
metadata:
labels:
run: multi-box
name: "{{ multi_pod_one }}"
namespace: "{{ wait_namespace }}"
spec:
initContainers:
- name: init-01
image: python:3.7-alpine
command: ['sh', '-c', 'sleep 25']
containers:
- name: multi-pod-01
image: python:3.7-alpine
command: ['sh', '-c', 'sleep 360']

- name: Create another pod with same label as previous pod
k8s:
definition:
apiVersion: v1
kind: Pod
metadata:
labels:
run: multi-box
name: "{{ multi_pod_two }}"
namespace: "{{ wait_namespace }}"
spec:
initContainers:
- name: init-02
image: python:3.7-alpine
command: ['sh', '-c', 'sleep 25']
containers:
- name: multi-pod-02
image: python:3.7-alpine
command: ['sh', '-c', 'sleep 360']

- name: Wait and gather information about new pods
k8s_info:
kind: Pod
namespace: "{{ wait_namespace }}"
wait: yes
wait_sleep: 5
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
label_selectors:
- run == multi-box
register: wait_info

- name: Assert that pod creation succeeded
assert:
that:
- wait_info is successful
- not wait_info.changed
- wait_info.resources[0].status.phase == "Running"
- wait_info.resources[1].status.phase == "Running"

- name: "Remove Pod {{ multi_pod_one }}"
k8s:
api_version: v1
kind: Pod
name: "{{ multi_pod_one }}"
namespace: "{{ wait_namespace }}"
state: absent
wait: yes
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
ignore_errors: yes
register: multi_pod_one_remove

- name: "Check if {{ multi_pod_one }} pod is removed"
assert:
that:
- multi_pod_one_remove is successful
- multi_pod_one_remove.changed

- name: "Remove Pod {{ multi_pod_two }}"
k8s:
api_version: v1
kind: Pod
name: "{{ multi_pod_two }}"
namespace: "{{ wait_namespace }}"
state: absent
wait: yes
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
ignore_errors: yes
register: multi_pod_two_remove

- name: "Check if {{ multi_pod_two }} pod is removed"
assert:
that:
- multi_pod_two_remove is successful
- multi_pod_two_remove.changed

- name: "Look for existing API"
k8s_info:
api_version: apps/v1
kind: Deployment
register: existing_api

- name: Check if we informed the user the api does exist
assert:
that:
- existing_api.api_found

- name: "Look for non-existent API"
k8s_info:
api_version: pleasedonotcreatethisresource.example.com/v7
kind: DoesNotExist
register: dne_api

- name: Check if we informed the user the api does not exist
assert:
that:
- not dne_api.resources
- not dne_api.api_found

- name: Start timer
set_fact:
start: "{{ lookup('pipe', 'date +%s') }}"

- name: Wait for non-existent pod to be created
k8s_info:
kind: Pod
name: does-not-exist
namespace: "{{ wait_namespace }}"
wait: yes
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
register: result

- name: Check that module waited
assert:
that:
- "{{ lookup('pipe', 'date +%s') }} - {{ start }} > 30"

- name: Create simple pod
k8s:
definition:
apiVersion: v1
kind: Pod
metadata:
name: wait-pod-1
namespace: "{{ wait_namespace }}"
spec:
containers:
- image: busybox
name: busybox
command:
- /bin/sh
- -c
- while true; do sleep 5; done

- name: Wait for multiple non-existent pods to be created
k8s_info:
kind: Pod
namespace: "{{ wait_namespace }}"
label_selectors:
- thislabel=doesnotexist
wait: yes
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
register: result

- name: Assert no pods were found
assert:
that:
- not result.resources

vars:
k8s_pod_name: pod-info-1

always:
- name: Remove namespace
k8s:
kind: Namespace
name: "{{ wait_namespace }}"
state: absent
ignore_errors: true
- include_tasks: "tasks/{{ item }}.yml"
with_items:
- wait
- api-server-caching
Loading

0 comments on commit 8ed4d4b

Please sign in to comment.