From 791175daefebfc215ef5caf0d6a6ddbba9f6cdd3 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Thu, 10 Feb 2022 08:11:52 +0530 Subject: [PATCH] Use resource prefix when apiVersion is v1 (#371) Use resource prefix when apiVersion is v1 SUMMARY When getting a resource from the core api group, the prefix was not passed, leading the lookup to happen in all api groups. This broad search is not really necessary and leads to problems in some corner cases, for example, when an api is deleted after the api group list is cached. This fix uses the 'api' prefix when the apiVersion is 'v1', as this is almost certainly what the user wants. As a fallback, to retain backwards compatibility, the old behavior is used if the first lookup failed to find a resource. Given that the module defaults to 'v1' for the apiVersion, there are likely many cases where a resource, such as StatefulSet, is used while failing to provide an apiVersion. While technically incorrect, this has worked in most cases, so we probably shouldn't break this behavior. Fixes #351 ISSUE TYPE Bugfix Pull Request COMPONENT NAME changelogs/fragments/364-use-resource-prefix.yaml plugins/module_utils/common.py --- .../fragments/364-use-resource-prefix.yaml | 3 ++ plugins/module_utils/common.py | 36 +++++++++++++------ 2 files changed, 29 insertions(+), 10 deletions(-) create mode 100644 changelogs/fragments/364-use-resource-prefix.yaml diff --git a/changelogs/fragments/364-use-resource-prefix.yaml b/changelogs/fragments/364-use-resource-prefix.yaml new file mode 100644 index 00000000..4785d925 --- /dev/null +++ b/changelogs/fragments/364-use-resource-prefix.yaml @@ -0,0 +1,3 @@ +--- +bugfixes: + - use resource prefix when finding resource and apiVersion is v1 (https://github.com/ansible-collections/kubernetes.core/issues/351). diff --git a/plugins/module_utils/common.py b/plugins/module_utils/common.py index e77fdabb..9fec2f77 100644 --- a/plugins/module_utils/common.py +++ b/plugins/module_utils/common.py @@ -354,25 +354,41 @@ class K8sAnsibleMixin(object): if pyyaml_required and not HAS_YAML: module.fail_json(msg=missing_required_lib("PyYAML"), exception=YAML_IMP_ERR) - def find_resource(self, kind, api_version, fail=False): + def _find_resource_with_prefix(self, prefix, kind, api_version): for attribute in ["kind", "name", "singular_name"]: try: return self.client.resources.get( - **{"api_version": api_version, attribute: kind} + **{"prefix": prefix, "api_version": api_version, attribute: kind} ) except (ResourceNotFoundError, ResourceNotUniqueError): pass + return self.client.resources.get( + prefix=prefix, api_version=api_version, short_names=[kind] + ) + + def find_resource(self, kind, api_version, fail=False): + msg = "Failed to find exact match for {0}.{1} by [kind, name, singularName, shortNames]".format( + api_version, kind + ) try: - return self.client.resources.get( - api_version=api_version, short_names=[kind] - ) + if api_version == "v1": + return self._find_resource_with_prefix("api", kind, api_version) + except ResourceNotUniqueError: + # No point trying again as we'll just get the same error + if fail: + self.fail(msg=msg) + else: + return None + except ResourceNotFoundError: + pass + # The second check without a prefix is maintained for backwards compatibility. + # If we are here, it's probably because the resource really doesn't exist or + # the wrong api_version has been specified, for example, v1.DaemonSet. + try: + return self._find_resource_with_prefix(None, kind, api_version) except (ResourceNotFoundError, ResourceNotUniqueError): if fail: - self.fail( - msg="Failed to find exact match for {0}.{1} by [kind, name, singularName, shortNames]".format( - api_version, kind - ) - ) + self.fail(msg=msg) def kubernetes_facts( self,