Honor wait_timeout in k8s_info for missing resource (#360)

* Honor wait in k8s_info for missing resource

The wait logic in the k8s_info module immediately returns when no
resources are found, regardless whether a wait_timeout has been
specified. This expands the logic to wait when a name has been provided.
The case this is specifically meant to address is when querying for a
resource that is indirectly created by another resource, for example, a
pod created by a deployment or an operator.

The existing logic in every other case should remain as it was before.
This means if a query might return more than one resource--all pods with
some label, for example--the module will return immediately if no pods
are found, even if a wait_timeout has been provided.

* Add changelog fragment
This commit is contained in:
Mike Graves
2021-02-16 12:19:22 -05:00
committed by GitHub
parent 80b914021f
commit 9f7b6fb3ff
3 changed files with 68 additions and 21 deletions

View File

@@ -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).

View File

@@ -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:

View File

@@ -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)