From ef82b78a2f10682c11eaeb79492bde5657bcd6f8 Mon Sep 17 00:00:00 2001 From: Mike Graves Date: Fri, 4 Jun 2021 13:19:02 -0400 Subject: [PATCH] Support multiple resources with same GVK (#119) In replicating the openshift client functionality we forgot to bring over a fix for multiple resources with the same group version and kind. This is specifically a problem for openshift templates. --- plugins/module_utils/client/discovery.py | 29 +++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/plugins/module_utils/client/discovery.py b/plugins/module_utils/client/discovery.py index ec01f195..8abdf759 100644 --- a/plugins/module_utils/client/discovery.py +++ b/plugins/module_utils/client/discovery.py @@ -22,7 +22,8 @@ import tempfile import kubernetes.dynamic import kubernetes.dynamic.discovery from kubernetes import __version__ -from kubernetes.dynamic.exceptions import ServiceUnavailableError +from kubernetes.dynamic.exceptions import (ResourceNotFoundError, ResourceNotUniqueError, + ServiceUnavailableError) from ansible_collections.kubernetes.core.plugins.module_utils.client.resource import ResourceList @@ -129,6 +130,32 @@ class Discoverer(kubernetes.dynamic.discovery.Discoverer): resources[resource_list.kind].append(resource_list) return resources + def get(self, **kwargs): + """ + Same as search, but will throw an error if there are multiple or no + results. If there are multiple results and only one is an exact match + on api_version, that resource will be returned. + """ + results = self.search(**kwargs) + # If there are multiple matches, prefer exact matches on api_version + if len(results) > 1 and kwargs.get('api_version'): + results = [ + result for result in results if result.group_version == kwargs['api_version'] + ] + # If there are multiple matches, prefer non-List kinds + if len(results) > 1 and not all([isinstance(x, ResourceList) for x in results]): + results = [result for result in results if not isinstance(result, ResourceList)] + # if multiple resources are found that share a GVK, prefer the one with the most supported verbs + if len(results) > 1 and len(set((x.group_version, x.kind) for x in results)) == 1: + if len(set(len(x.verbs) for x in results)) != 1: + results = [max(results, key=lambda x: len(x.verbs))] + if len(results) == 1: + return results[0] + elif not results: + raise ResourceNotFoundError('No matches found for {0}'.format(kwargs)) + else: + raise ResourceNotUniqueError('Multiple matches found for {0}: {1}'.format(kwargs, results)) + class LazyDiscoverer(Discoverer, kubernetes.dynamic.LazyDiscoverer): def __init__(self, client, cache_file):