mirror of
https://github.com/ansible-collections/kubernetes.core.git
synced 2026-05-13 21:12:05 +00:00
This reverts commit 4ccb15d4ad.
This commit is contained in:
@@ -1,3 +0,0 @@
|
|||||||
---
|
|
||||||
minor_changes:
|
|
||||||
- k8s - add new option ``wait_property`` to support ability to wait on arbitrary property (https://github.com/ansible-collections/kubernetes.core/pull/105).
|
|
||||||
@@ -364,93 +364,6 @@
|
|||||||
that:
|
that:
|
||||||
- short_wait_remove_pod is failed
|
- short_wait_remove_pod is failed
|
||||||
|
|
||||||
- name: add a simple crashing pod and wait until container is running
|
|
||||||
k8s:
|
|
||||||
definition:
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Pod
|
|
||||||
metadata:
|
|
||||||
name: pod-crash-0
|
|
||||||
namespace: "{{ wait_namespace }}"
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: crashing-container
|
|
||||||
image: busybox
|
|
||||||
command: ['/dummy/dummy-shell', '-c', 'sleep 2000']
|
|
||||||
wait: yes
|
|
||||||
wait_timeout: 10
|
|
||||||
wait_property:
|
|
||||||
property: status.containerStatuses[*].state.running
|
|
||||||
ignore_errors: true
|
|
||||||
register: crash_pod
|
|
||||||
|
|
||||||
- name: assert that task failed
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- crash_pod is failed
|
|
||||||
- crash_pod is changed
|
|
||||||
- '"Resource creation timed out" in crash_pod.msg'
|
|
||||||
|
|
||||||
- name: add a valid pod and wait until container is running
|
|
||||||
k8s:
|
|
||||||
definition:
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Pod
|
|
||||||
metadata:
|
|
||||||
name: pod-valid-0
|
|
||||||
namespace: "{{ wait_namespace }}"
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: crashing-container
|
|
||||||
image: busybox
|
|
||||||
command: ['/bin/sh', '-c', 'sleep 10000']
|
|
||||||
wait: yes
|
|
||||||
wait_timeout: 10
|
|
||||||
wait_property:
|
|
||||||
property: status.containerStatuses[*].state.running
|
|
||||||
ignore_errors: true
|
|
||||||
register: valid_pod
|
|
||||||
|
|
||||||
- name: assert that task failed
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- valid_pod is successful
|
|
||||||
- valid_pod.changed
|
|
||||||
- valid_pod.result.status.containerStatuses[0].state.running is defined
|
|
||||||
|
|
||||||
- name: create pod (waiting for container.ready set to false)
|
|
||||||
k8s:
|
|
||||||
definition:
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Pod
|
|
||||||
metadata:
|
|
||||||
name: redis-pod
|
|
||||||
namespace: "{{ wait_namespace }}"
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: redis-container
|
|
||||||
image: redis
|
|
||||||
volumeMounts:
|
|
||||||
- name: test
|
|
||||||
mountPath: "/etc/test"
|
|
||||||
readOnly: true
|
|
||||||
volumes:
|
|
||||||
- name: test
|
|
||||||
configMap:
|
|
||||||
name: redis-config
|
|
||||||
wait: yes
|
|
||||||
wait_timeout: 10
|
|
||||||
wait_property:
|
|
||||||
property: status.containerStatuses[0].ready
|
|
||||||
value: "false"
|
|
||||||
register: wait_boolean
|
|
||||||
|
|
||||||
- name: assert that pod was created but not running
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- wait_boolean.changed
|
|
||||||
- wait_boolean.result.status.phase == 'Pending'
|
|
||||||
|
|
||||||
always:
|
always:
|
||||||
- name: Remove namespace
|
- name: Remove namespace
|
||||||
k8s:
|
k8s:
|
||||||
|
|||||||
@@ -64,22 +64,4 @@ options:
|
|||||||
- The possible reasons in a condition are specific to each resource type in Kubernetes.
|
- The possible reasons in a condition are specific to each resource type in Kubernetes.
|
||||||
- See the API documentation of the status field for a given resource to see possible choices.
|
- See the API documentation of the status field for a given resource to see possible choices.
|
||||||
type: dict
|
type: dict
|
||||||
wait_property:
|
|
||||||
description:
|
|
||||||
- Specifies a property on the resource to wait for.
|
|
||||||
- Ignored if C(wait) is not set or is set to I(False).
|
|
||||||
type: dict
|
|
||||||
version_added: '2.1.0'
|
|
||||||
suboptions:
|
|
||||||
property:
|
|
||||||
type: str
|
|
||||||
required: True
|
|
||||||
description:
|
|
||||||
- The property name to wait for.
|
|
||||||
value:
|
|
||||||
type: str
|
|
||||||
description:
|
|
||||||
- The expected value of the C(property).
|
|
||||||
- The value is not case-sensitive.
|
|
||||||
- If this is missing, we will check only that the attribute C(property) is present.
|
|
||||||
'''
|
'''
|
||||||
|
|||||||
@@ -70,14 +70,6 @@ WAIT_ARG_SPEC = dict(
|
|||||||
status=dict(default=True, choices=[True, False, "Unknown"]),
|
status=dict(default=True, choices=[True, False, "Unknown"]),
|
||||||
reason=dict()
|
reason=dict()
|
||||||
)
|
)
|
||||||
),
|
|
||||||
wait_property=dict(
|
|
||||||
type='dict',
|
|
||||||
default=None,
|
|
||||||
options=dict(
|
|
||||||
property=dict(required=True),
|
|
||||||
value=dict()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ from distutils.version import LooseVersion
|
|||||||
|
|
||||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (AUTH_ARG_MAP, AUTH_ARG_SPEC, AUTH_PROXY_HEADERS_SPEC)
|
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (AUTH_ARG_MAP, AUTH_ARG_SPEC, AUTH_PROXY_HEADERS_SPEC)
|
||||||
from ansible_collections.kubernetes.core.plugins.module_utils.hashes import generate_hash
|
from ansible_collections.kubernetes.core.plugins.module_utils.hashes import generate_hash
|
||||||
from ansible_collections.kubernetes.core.plugins.module_utils.jsonpath_extractor import validate_with_jsonpath
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import missing_required_lib
|
from ansible.module_utils.basic import missing_required_lib
|
||||||
from ansible.module_utils.six import iteritems, string_types
|
from ansible.module_utils.six import iteritems, string_types
|
||||||
@@ -37,7 +36,6 @@ from ansible.module_utils._text import to_native, to_bytes, to_text
|
|||||||
from ansible.module_utils.common.dict_transformations import dict_merge
|
from ansible.module_utils.common.dict_transformations import dict_merge
|
||||||
from ansible.module_utils.parsing.convert_bool import boolean
|
from ansible.module_utils.parsing.convert_bool import boolean
|
||||||
|
|
||||||
|
|
||||||
K8S_IMP_ERR = None
|
K8S_IMP_ERR = None
|
||||||
try:
|
try:
|
||||||
import kubernetes
|
import kubernetes
|
||||||
@@ -232,7 +230,7 @@ class K8sAnsibleMixin(object):
|
|||||||
self.fail(msg='Failed to find exact match for {0}.{1} by [kind, name, singularName, shortNames]'.format(api_version, kind))
|
self.fail(msg='Failed to find exact match for {0}.{1} by [kind, name, singularName, shortNames]'.format(api_version, kind))
|
||||||
|
|
||||||
def kubernetes_facts(self, kind, api_version, name=None, namespace=None, label_selectors=None, field_selectors=None,
|
def kubernetes_facts(self, kind, api_version, name=None, namespace=None, label_selectors=None, field_selectors=None,
|
||||||
wait=False, wait_sleep=5, wait_timeout=120, state='present', condition=None, property=None):
|
wait=False, wait_sleep=5, wait_timeout=120, state='present', condition=None):
|
||||||
resource = self.find_resource(kind, api_version)
|
resource = self.find_resource(kind, api_version)
|
||||||
api_found = bool(resource)
|
api_found = bool(resource)
|
||||||
if not api_found:
|
if not api_found:
|
||||||
@@ -288,7 +286,7 @@ class K8sAnsibleMixin(object):
|
|||||||
for resource_instance in resource_list:
|
for resource_instance in resource_list:
|
||||||
success, res, duration = self.wait(resource, resource_instance,
|
success, res, duration = self.wait(resource, resource_instance,
|
||||||
sleep=wait_sleep, timeout=wait_timeout,
|
sleep=wait_sleep, timeout=wait_timeout,
|
||||||
state=state, condition=condition, property=property)
|
state=state, condition=condition)
|
||||||
if not success:
|
if not success:
|
||||||
self.fail(msg="Failed to gather information about %s(s) even"
|
self.fail(msg="Failed to gather information about %s(s) even"
|
||||||
" after waiting for %s seconds" % (res.get('kind'), duration))
|
" after waiting for %s seconds" % (res.get('kind'), duration))
|
||||||
@@ -351,7 +349,7 @@ class K8sAnsibleMixin(object):
|
|||||||
def fail(self, msg=None):
|
def fail(self, msg=None):
|
||||||
self.fail_json(msg=msg)
|
self.fail_json(msg=msg)
|
||||||
|
|
||||||
def _wait_for(self, resource, name, namespace, predicates, sleep, timeout, state):
|
def _wait_for(self, resource, name, namespace, predicate, sleep, timeout, state):
|
||||||
start = datetime.now()
|
start = datetime.now()
|
||||||
|
|
||||||
def _wait_for_elapsed():
|
def _wait_for_elapsed():
|
||||||
@@ -361,7 +359,7 @@ class K8sAnsibleMixin(object):
|
|||||||
while _wait_for_elapsed() < timeout:
|
while _wait_for_elapsed() < timeout:
|
||||||
try:
|
try:
|
||||||
response = resource.get(name=name, namespace=namespace)
|
response = resource.get(name=name, namespace=namespace)
|
||||||
if all([predicate(response) for predicate in predicates]):
|
if predicate(response):
|
||||||
if response:
|
if response:
|
||||||
return True, response.to_dict(), _wait_for_elapsed()
|
return True, response.to_dict(), _wait_for_elapsed()
|
||||||
return True, {}, _wait_for_elapsed()
|
return True, {}, _wait_for_elapsed()
|
||||||
@@ -373,7 +371,7 @@ class K8sAnsibleMixin(object):
|
|||||||
response = response.to_dict()
|
response = response.to_dict()
|
||||||
return False, response, _wait_for_elapsed()
|
return False, response, _wait_for_elapsed()
|
||||||
|
|
||||||
def wait(self, resource, definition, sleep, timeout, state='present', condition=None, property=None):
|
def wait(self, resource, definition, sleep, timeout, state='present', condition=None):
|
||||||
|
|
||||||
def _deployment_ready(deployment):
|
def _deployment_ready(deployment):
|
||||||
# FIXME: frustratingly bool(deployment.status) is True even if status is empty
|
# FIXME: frustratingly bool(deployment.status) is True even if status is empty
|
||||||
@@ -424,29 +422,19 @@ class K8sAnsibleMixin(object):
|
|||||||
def _resource_absent(resource):
|
def _resource_absent(resource):
|
||||||
return not resource
|
return not resource
|
||||||
|
|
||||||
def _wait_for_property(resource):
|
|
||||||
return validate_with_jsonpath(self, resource.to_dict(), property.get('property'), property.get('value', None))
|
|
||||||
|
|
||||||
waiter = dict(
|
waiter = dict(
|
||||||
Deployment=_deployment_ready,
|
Deployment=_deployment_ready,
|
||||||
DaemonSet=_daemonset_ready,
|
DaemonSet=_daemonset_ready,
|
||||||
Pod=_pod_ready
|
Pod=_pod_ready
|
||||||
)
|
)
|
||||||
kind = definition['kind']
|
kind = definition['kind']
|
||||||
predicates = []
|
if state == 'present' and not condition:
|
||||||
if state == 'present':
|
predicate = waiter.get(kind, lambda x: x)
|
||||||
if condition is None and property is None:
|
elif state == 'present' and condition:
|
||||||
predicates.append(waiter.get(kind, lambda x: x))
|
predicate = _custom_condition
|
||||||
else:
|
|
||||||
if condition:
|
|
||||||
# add waiter on custom condition
|
|
||||||
predicates.append(_custom_condition)
|
|
||||||
if property:
|
|
||||||
# json path predicate
|
|
||||||
predicates.append(_wait_for_property)
|
|
||||||
else:
|
else:
|
||||||
predicates = [_resource_absent]
|
predicate = _resource_absent
|
||||||
return self._wait_for(resource, definition['metadata']['name'], definition['metadata'].get('namespace'), predicates, sleep, timeout, state)
|
return self._wait_for(resource, definition['metadata']['name'], definition['metadata'].get('namespace'), predicate, sleep, timeout, state)
|
||||||
|
|
||||||
def set_resource_definitions(self, module):
|
def set_resource_definitions(self, module):
|
||||||
resource_definition = module.params.get('resource_definition')
|
resource_definition = module.params.get('resource_definition')
|
||||||
@@ -589,7 +577,6 @@ class K8sAnsibleMixin(object):
|
|||||||
continue_on_error = self.params.get('continue_on_error')
|
continue_on_error = self.params.get('continue_on_error')
|
||||||
if self.params.get('wait_condition') and self.params['wait_condition'].get('type'):
|
if self.params.get('wait_condition') and self.params['wait_condition'].get('type'):
|
||||||
wait_condition = self.params['wait_condition']
|
wait_condition = self.params['wait_condition']
|
||||||
wait_property = self.params.get('wait_property')
|
|
||||||
|
|
||||||
def build_error_msg(kind, name, msg):
|
def build_error_msg(kind, name, msg):
|
||||||
return "%s %s: %s" % (kind, name, msg)
|
return "%s %s: %s" % (kind, name, msg)
|
||||||
@@ -699,8 +686,7 @@ class K8sAnsibleMixin(object):
|
|||||||
success = True
|
success = True
|
||||||
result['result'] = k8s_obj
|
result['result'] = k8s_obj
|
||||||
if wait and not self.check_mode:
|
if wait and not self.check_mode:
|
||||||
success, result['result'], result['duration'] = self.wait(resource, definition, wait_sleep, wait_timeout,
|
success, result['result'], result['duration'] = self.wait(resource, definition, wait_sleep, wait_timeout, condition=wait_condition)
|
||||||
condition=wait_condition, property=wait_property)
|
|
||||||
if existing:
|
if existing:
|
||||||
existing = existing.to_dict()
|
existing = existing.to_dict()
|
||||||
else:
|
else:
|
||||||
@@ -760,8 +746,7 @@ class K8sAnsibleMixin(object):
|
|||||||
success = True
|
success = True
|
||||||
result['result'] = k8s_obj
|
result['result'] = k8s_obj
|
||||||
if wait and not self.check_mode:
|
if wait and not self.check_mode:
|
||||||
success, result['result'], result['duration'] = self.wait(resource, definition, wait_sleep, wait_timeout,
|
success, result['result'], result['duration'] = self.wait(resource, definition, wait_sleep, wait_timeout, condition=wait_condition)
|
||||||
condition=wait_condition, property=wait_property)
|
|
||||||
result['changed'] = True
|
result['changed'] = True
|
||||||
result['method'] = 'create'
|
result['method'] = 'create'
|
||||||
if not success:
|
if not success:
|
||||||
@@ -796,8 +781,7 @@ class K8sAnsibleMixin(object):
|
|||||||
success = True
|
success = True
|
||||||
result['result'] = k8s_obj
|
result['result'] = k8s_obj
|
||||||
if wait and not self.check_mode:
|
if wait and not self.check_mode:
|
||||||
success, result['result'], result['duration'] = self.wait(resource, definition, wait_sleep, wait_timeout,
|
success, result['result'], result['duration'] = self.wait(resource, definition, wait_sleep, wait_timeout, condition=wait_condition)
|
||||||
condition=wait_condition, property=wait_property)
|
|
||||||
match, diffs = self.diff_objects(existing.to_dict(), result['result'])
|
match, diffs = self.diff_objects(existing.to_dict(), result['result'])
|
||||||
result['changed'] = not match
|
result['changed'] = not match
|
||||||
result['method'] = 'replace'
|
result['method'] = 'replace'
|
||||||
@@ -831,8 +815,7 @@ class K8sAnsibleMixin(object):
|
|||||||
success = True
|
success = True
|
||||||
result['result'] = k8s_obj
|
result['result'] = k8s_obj
|
||||||
if wait and not self.check_mode:
|
if wait and not self.check_mode:
|
||||||
success, result['result'], result['duration'] = self.wait(resource, definition, wait_sleep, wait_timeout,
|
success, result['result'], result['duration'] = self.wait(resource, definition, wait_sleep, wait_timeout, condition=wait_condition)
|
||||||
condition=wait_condition, property=wait_property)
|
|
||||||
match, diffs = self.diff_objects(existing.to_dict(), result['result'])
|
match, diffs = self.diff_objects(existing.to_dict(), result['result'])
|
||||||
result['changed'] = not match
|
result['changed'] = not match
|
||||||
result['method'] = 'patch'
|
result['method'] = 'patch'
|
||||||
|
|||||||
@@ -1,142 +0,0 @@
|
|||||||
# Copyright [2021] [Red Hat, Inc.]
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
|
|
||||||
from __future__ import absolute_import, division, print_function
|
|
||||||
__metaclass__ = type
|
|
||||||
|
|
||||||
from ansible.module_utils._text import to_native
|
|
||||||
|
|
||||||
|
|
||||||
class JsonPathException(Exception):
|
|
||||||
""" Error while parsing Json path structure """
|
|
||||||
|
|
||||||
|
|
||||||
def find_element(value, start):
|
|
||||||
dot_idx = value.find(".", start)
|
|
||||||
end = dot_idx if dot_idx != -1 else len(value)
|
|
||||||
arr_idx = value.find("[", start, end)
|
|
||||||
|
|
||||||
if dot_idx == -1 and arr_idx == -1:
|
|
||||||
# last element of the json path
|
|
||||||
if value[start] == '[':
|
|
||||||
raise JsonPathException("unable to find array end string for array starting at index {0} '{1}'".format(start, value[start:]))
|
|
||||||
return value[start:], None
|
|
||||||
|
|
||||||
elif arr_idx != -1:
|
|
||||||
if arr_idx == start:
|
|
||||||
# array element (ex: "[0]" or "[*].ready" or "[*][0].ready" )
|
|
||||||
arr_end = value.find("]", arr_idx)
|
|
||||||
if arr_end == -1:
|
|
||||||
raise JsonPathException("unable to find array end string for array starting at index {0} '{1}'".format(arr_idx, value[arr_idx:]))
|
|
||||||
data = value[arr_idx + 1:arr_end]
|
|
||||||
if data != "*" and not data.isnumeric():
|
|
||||||
raise JsonPathException("wrong value specified into array starting at index {0} => '{1}'".format(arr_idx, data))
|
|
||||||
return int(data) if data != "*" else -1, arr_end + 1 if arr_end < len(value) - 1 else None
|
|
||||||
elif arr_idx > start:
|
|
||||||
# single value found (ex: "containers[0]")
|
|
||||||
return value[start:arr_idx], arr_idx
|
|
||||||
|
|
||||||
else: # dot_idx != -1
|
|
||||||
return value[start:dot_idx], dot_idx + 1
|
|
||||||
|
|
||||||
|
|
||||||
def parse(expr):
|
|
||||||
result = []
|
|
||||||
if expr[0] == ".":
|
|
||||||
expr = expr[1:]
|
|
||||||
start = 0
|
|
||||||
while start is not None:
|
|
||||||
elt, next = find_element(expr, start)
|
|
||||||
if elt == '':
|
|
||||||
if not isinstance(result[-1], int):
|
|
||||||
raise JsonPathException("empty element following non array element at index {0} '{1}'".format(start, expr[start:]))
|
|
||||||
else:
|
|
||||||
result.append(elt)
|
|
||||||
start = next
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def search_json_item(jsonpath_expr, json_doc):
|
|
||||||
json_idx = 0
|
|
||||||
json_item = jsonpath_expr[json_idx]
|
|
||||||
if isinstance(json_item, int):
|
|
||||||
if not isinstance(json_doc, list):
|
|
||||||
# trying to parse list items, but current document is not a list
|
|
||||||
return None
|
|
||||||
elements = json_doc
|
|
||||||
if json_item != -1:
|
|
||||||
# looking for specific index from the list
|
|
||||||
if json_item >= len(json_doc):
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
elements = json_doc[json_item]
|
|
||||||
|
|
||||||
# when we reach the end of the json path
|
|
||||||
if len(jsonpath_expr) == 1:
|
|
||||||
return elements
|
|
||||||
elif json_item != -1 and (isinstance(elements, dict) or isinstance(elements, list)):
|
|
||||||
return search_json_item(jsonpath_expr[1:], elements)
|
|
||||||
elif json_item == -1:
|
|
||||||
result = []
|
|
||||||
for elt in elements:
|
|
||||||
ret = search_json_item(jsonpath_expr[1:], elt)
|
|
||||||
if ret is not None:
|
|
||||||
result.append(ret)
|
|
||||||
return result if result != [] else None
|
|
||||||
else:
|
|
||||||
# looking for a specific field into the json document
|
|
||||||
if not isinstance(json_doc, dict):
|
|
||||||
return None
|
|
||||||
if json_item not in json_doc:
|
|
||||||
return None
|
|
||||||
if len(jsonpath_expr) == 1:
|
|
||||||
return json_doc.get(json_item)
|
|
||||||
else:
|
|
||||||
return search_json_item(jsonpath_expr[1:], json_doc.get(json_item))
|
|
||||||
|
|
||||||
|
|
||||||
def search(expr, data):
|
|
||||||
jsonpath_expr = parse(expr)
|
|
||||||
return search_json_item(jsonpath_expr, data)
|
|
||||||
|
|
||||||
|
|
||||||
def validate_with_jsonpath(module, data, expr, value=None):
|
|
||||||
def _raise_or_fail(err, **kwargs):
|
|
||||||
if module and hasattr(module, "fail_json"):
|
|
||||||
module.fail_json(error=to_native(err), **kwargs)
|
|
||||||
raise err
|
|
||||||
|
|
||||||
def _match_value(buf, v):
|
|
||||||
if isinstance(buf, list):
|
|
||||||
# convert all values from bool to str and lowercase them
|
|
||||||
return all([str(i).lower() == v.lower() for i in buf])
|
|
||||||
elif isinstance(buf, str) or isinstance(buf, int) or isinstance(buf, float):
|
|
||||||
return v.lower() == str(buf).lower()
|
|
||||||
elif isinstance(buf, bool):
|
|
||||||
return v.lower() == str(buf).lower()
|
|
||||||
else:
|
|
||||||
# unable to test single value against dict
|
|
||||||
return False
|
|
||||||
|
|
||||||
try:
|
|
||||||
content = search(expr, data)
|
|
||||||
if content is None or content == []:
|
|
||||||
return False
|
|
||||||
if value is None or _match_value(content, value):
|
|
||||||
# looking for state present
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
except Exception as err:
|
|
||||||
_raise_or_fail(err, msg="Failed to extract path from Json: {0}".format(expr))
|
|
||||||
@@ -252,32 +252,6 @@ EXAMPLES = r'''
|
|||||||
status: Unknown
|
status: Unknown
|
||||||
reason: DeploymentPaused
|
reason: DeploymentPaused
|
||||||
|
|
||||||
# Wait for this service to have acquired an External IP
|
|
||||||
- name: Create ingress and wait for ip to be assigned
|
|
||||||
kubernetes.core.k8s:
|
|
||||||
template: dash-service.yaml
|
|
||||||
wait: yes
|
|
||||||
wait_property:
|
|
||||||
property: status.loadBalancer.ingress[*].ip
|
|
||||||
|
|
||||||
# Wait for container inside a pod to be ready
|
|
||||||
- name: Create Pod and wait for containers to be ready
|
|
||||||
kubernetes.core.k8s:
|
|
||||||
template: pod.yaml
|
|
||||||
wait: yes
|
|
||||||
wait_property:
|
|
||||||
property: status.containerStatuses[*].ready
|
|
||||||
value: "true"
|
|
||||||
|
|
||||||
# Wait for first container inside a pod to be ready
|
|
||||||
- name: Create Pod and wait for first containers to be ready
|
|
||||||
kubernetes.core.k8s:
|
|
||||||
template: pod.yaml
|
|
||||||
wait: yes
|
|
||||||
wait_property:
|
|
||||||
property: status.containerStatuses[0].ready
|
|
||||||
value: "true"
|
|
||||||
|
|
||||||
# Patch existing namespace : add label
|
# Patch existing namespace : add label
|
||||||
- name: add label to existing namespace
|
- name: add label to existing namespace
|
||||||
kubernetes.core.k8s:
|
kubernetes.core.k8s:
|
||||||
|
|||||||
@@ -164,7 +164,6 @@ def execute_module(module, k8s_ansible_mixin):
|
|||||||
wait_sleep=module.params["wait_sleep"],
|
wait_sleep=module.params["wait_sleep"],
|
||||||
wait_timeout=module.params["wait_timeout"],
|
wait_timeout=module.params["wait_timeout"],
|
||||||
condition=module.params["wait_condition"],
|
condition=module.params["wait_condition"],
|
||||||
property=module.params["wait_property"]
|
|
||||||
)
|
)
|
||||||
module.exit_json(changed=False, **facts)
|
module.exit_json(changed=False, **facts)
|
||||||
|
|
||||||
|
|||||||
@@ -1,76 +0,0 @@
|
|||||||
# Copyright [2021] [Red Hat, Inc.]
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
|
|
||||||
from __future__ import absolute_import, division, print_function
|
|
||||||
__metaclass__ = type
|
|
||||||
|
|
||||||
from ansible_collections.kubernetes.core.plugins.module_utils.jsonpath_extractor import validate_with_jsonpath
|
|
||||||
|
|
||||||
|
|
||||||
def test_property_present():
|
|
||||||
data = {
|
|
||||||
"containers": [
|
|
||||||
{"name": "t0", "image": "nginx"},
|
|
||||||
{"name": "t1", "image": "python"},
|
|
||||||
{"name": "t2", "image": "mongo", "state": "running"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
assert validate_with_jsonpath(None, data, "containers[*].state")
|
|
||||||
assert not validate_with_jsonpath(None, data, "containers[*].status")
|
|
||||||
|
|
||||||
|
|
||||||
def test_property_value():
|
|
||||||
data = {
|
|
||||||
"containers": [
|
|
||||||
{"name": "t0", "image": "nginx"},
|
|
||||||
{"name": "t1", "image": "python"},
|
|
||||||
{"name": "t2", "image": "mongo", "state": "running"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
assert validate_with_jsonpath(None, data, "containers[*].state", "running")
|
|
||||||
assert validate_with_jsonpath(None, data, "containers[*].state", "Running")
|
|
||||||
assert not validate_with_jsonpath(None, data, "containers[*].state", "off")
|
|
||||||
|
|
||||||
|
|
||||||
def test_boolean_value():
|
|
||||||
data = {
|
|
||||||
"containers": [
|
|
||||||
{"image": "nginx", "poweron": False},
|
|
||||||
{"image": "python"},
|
|
||||||
{"image": "mongo", "connected": True}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
assert validate_with_jsonpath(None, data, "containers[*].connected", "true")
|
|
||||||
assert validate_with_jsonpath(None, data, "containers[*].connected", "True")
|
|
||||||
assert validate_with_jsonpath(None, data, "containers[*].connected", "TRUE")
|
|
||||||
assert validate_with_jsonpath(None, data, "containers[0].poweron", "false")
|
|
||||||
|
|
||||||
data = {
|
|
||||||
"containers": [
|
|
||||||
{"image": "nginx", "ready": False},
|
|
||||||
{"image": "python", "ready": False},
|
|
||||||
{"image": "mongo", "ready": True}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
assert not validate_with_jsonpath(None, data, "containers[*].ready", "true")
|
|
||||||
|
|
||||||
data = {
|
|
||||||
"containers": [
|
|
||||||
{"image": "nginx", "ready": True},
|
|
||||||
{"image": "python", "ready": True},
|
|
||||||
{"image": "mongo", "ready": True}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
assert validate_with_jsonpath(None, data, "containers[*].ready", "true")
|
|
||||||
Reference in New Issue
Block a user