diff --git a/changelogs/fragments/360-k8s_info-wait-timeout.yaml b/changelogs/fragments/360-k8s_info-wait-timeout.yaml new file mode 100644 index 00000000..a26a78ac --- /dev/null +++ b/changelogs/fragments/360-k8s_info-wait-timeout.yaml @@ -0,0 +1,2 @@ +bugfixes: + - respect the ``wait_timeout`` parameter in the ``k8s`` and ``k8s_info`` modules when a resource does not exist (https://github.com/ansible-collections/community.kubernetes/issues/344). diff --git a/molecule/default/tasks/info.yml b/molecule/default/tasks/info.yml index 891f3dcc..f1061a86 100644 --- a/molecule/default/tasks/info.yml +++ b/molecule/default/tasks/info.yml @@ -182,6 +182,24 @@ - 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: 45 + register: result + + - name: Check that module waited + assert: + that: + - "{{ lookup('pipe', 'date +%s') }} - {{ start }} > 30" + always: - name: Remove namespace k8s: diff --git a/plugins/module_utils/common.py b/plugins/module_utils/common.py index 2e2bc6ed..3c44f5c9 100644 --- a/plugins/module_utils/common.py +++ b/plugins/module_utils/common.py @@ -319,31 +319,58 @@ class K8sAnsibleMixin(object): if not field_selectors: field_selectors = [] + result = None try: - result = resource.get(name=name, - namespace=namespace, + result = resource.get(name=name, namespace=namespace, label_selector=','.join(label_selectors), field_selector=','.join(field_selectors)) - if wait: - satisfied_by = [] - if isinstance(result, ResourceInstance): - # We have a list of ResourceInstance - resource_list = result.get('items', []) - if not resource_list: - resource_list = [result] - - for resource_instance in resource_list: - success, res, duration = self.wait(resource, resource_instance, - sleep=wait_sleep, timeout=wait_timeout, - state=state, condition=condition) - if not success: - self.fail(msg="Failed to gather information about %s(s) even" - " after waiting for %s seconds" % (res.get('kind'), duration)) - satisfied_by.append(res) - return dict(resources=satisfied_by, api_found=True) - result = result.to_dict() - except (openshift.dynamic.exceptions.BadRequestError, openshift.dynamic.exceptions.NotFoundError): + except openshift.dynamic.exceptions.BadRequestError: return dict(resources=[], api_found=True) + except openshift.dynamic.exceptions.NotFoundError: + if not wait or name is None: + return dict(resources=[], api_found=True) + + if not wait: + result = result.to_dict() + if 'items' in result: + return dict(resources=result['items'], api_found=True) + return dict(resources=[result], api_found=True) + + start = datetime.now() + + def _elapsed(): + return (datetime.now() - start).seconds + + if result is None: + while _elapsed() < wait_timeout: + try: + result = resource.get(name=name, namespace=namespace, + label_selector=','.join(label_selectors), + field_selector=','.join(field_selectors)) + break + except NotFoundError: + pass + time.sleep(wait_sleep) + if result is None: + return dict(resources=[], api_found=True) + + if isinstance(result, ResourceInstance): + satisfied_by = [] + # We have a list of ResourceInstance + resource_list = result.get('items', []) + if not resource_list: + resource_list = [result] + + for resource_instance in resource_list: + success, res, duration = self.wait(resource, resource_instance, + sleep=wait_sleep, timeout=wait_timeout, + state=state, condition=condition) + if not success: + self.fail(msg="Failed to gather information about %s(s) even" + " after waiting for %s seconds" % (res.get('kind'), duration)) + satisfied_by.append(res) + return dict(resources=satisfied_by, api_found=True) + result = result.to_dict() if 'items' in result: return dict(resources=result['items'], api_found=True)