diff --git a/openshift/dynamic/client.py b/openshift/dynamic/client.py index 154f291f..12b6e6ac 100644 --- a/openshift/dynamic/client.py +++ b/openshift/dynamic/client.py @@ -3,6 +3,7 @@ import json import hashlib import tempfile +from collections import defaultdict from functools import partial from abc import abstractmethod, abstractproperty @@ -642,7 +643,7 @@ def default_groups(self, request_resources=False): if request_resources else ResourceGroup(True)) }} groups[DISCOVERY_PREFIX] = {'': { - 'v1': ResourceGroup(True, resources = {"List": ResourceList(self.client)}) + 'v1': ResourceGroup(True, resources = {"List": [ResourceList(self.client)]}) }} return groups @@ -691,7 +692,7 @@ def _load_server_info(self): def get_resources_for_api_version(self, prefix, group, version, preferred): """ returns a dictionary of resources associated with provided (prefix, group, version)""" - resources = {} + resources = defaultdict(list) subresources = {} path = '/'.join(filter(None, [prefix, group, version])) @@ -710,7 +711,7 @@ def get_resources_for_api_version(self, prefix, group, version, preferred): for key in ('prefix', 'group', 'api_version', 'client', 'preferred'): resource.pop(key, None) - resources[resource['kind']] = Resource( + resourceobj = Resource( prefix=prefix, group=group, api_version=version, @@ -719,8 +720,10 @@ def get_resources_for_api_version(self, prefix, group, version, preferred): subresources=subresources.get(resource['name']), **resource ) + resources[resource['kind']].append(resourceobj) + resource_list = ResourceList(self.client, group=group, api_version=version, base_kind=resource['kind']) - resources[resource_list.kind] = resource_list + resources[resource_list.kind].append(resource_list) return resources def get(self, **kwargs): @@ -779,6 +782,7 @@ def search(self, **kwargs): def __search(self, parts, resources, reqParams): part = parts[0] if part != '*': + resourcePart = resources.get(part) if not resourcePart: return [] @@ -799,11 +803,14 @@ def __search(self, parts, resources, reqParams): return self.__search(parts[1:], resourcePart, reqParams + [part] ) else: if parts[1] != '*' and isinstance(parts[1], dict): - for term, value in parts[1].items(): - if getattr(resourcePart, term) == value: - return [resourcePart] + for _resource in resourcePart: + for term, value in parts[1].items(): + if getattr(_resource, term) == value: + return [_resource] + + return [] else: - return [resourcePart] + return resourcePart else: matches = [] for key in resources.keys(): @@ -889,11 +896,13 @@ def __search(self, parts, resources): return self.__search(parts[1:], resourcePart) else: if parts[1] != '*' and isinstance(parts[1], dict): - for term, value in parts[1].items(): - if getattr(resourcePart, term) == value: - return [resourcePart] + for _resource in resourcePart: + for term, value in parts[1].items(): + if getattr(_resource, term) == value: + return [_resource] + return [] else: - return [resourcePart] + return resourcePart elif part == '*': matches = [] for key in resources.keys(): diff --git a/test/unit/test_discoverer.py b/test/unit/test_discoverer.py index d3f046bb..c597bcee 100644 --- a/test/unit/test_discoverer.py +++ b/test/unit/test_discoverer.py @@ -26,6 +26,33 @@ def mock_namespace(): verbs=['create', 'delete', 'get', 'list', 'patch', 'update', 'watch'] ) +@pytest.fixture(scope='module') +def mock_templates(): + return Resource( + api_version='v1', + kind='Template', + name='templates', + namespaced=True, + preferred=True, + prefix='api', + shorter_names=[], + shortNames=[], + verbs=['create', 'delete', 'get', 'list', 'patch', 'update', 'watch'] + ) + +@pytest.fixture(scope='module') +def mock_processedtemplates(): + return Resource( + api_version='v1', + kind='Template', + name='processedtemplates', + namespaced=True, + preferred=True, + prefix='api', + shorter_names=[], + shortNames=[], + verbs=['create', 'delete', 'get', 'list', 'patch', 'update', 'watch'] + ) @pytest.fixture(scope='module') def mock_namespace_list(mock_namespace): @@ -35,7 +62,7 @@ def mock_namespace_list(mock_namespace): @pytest.fixture(scope='function', autouse=True) -def setup_client_monkeypatch(monkeypatch, mock_namespace, mock_namespace_list): +def setup_client_monkeypatch(monkeypatch, mock_namespace, mock_namespace_list, mock_templates, mock_processedtemplates): def mock_load_server_info(self): self.__version = {'kubernetes': 'mock-k8s-version'} @@ -45,8 +72,9 @@ def mock_parse_api_groups(self, request_resources=False): 'api': { '': { 'v1': { - 'Namespace': mock_namespace, - 'NamespaceList': mock_namespace_list + 'Namespace': [mock_namespace], + 'NamespaceList': [mock_namespace_list], + 'Template': [mock_templates, mock_processedtemplates], } } } @@ -92,3 +120,11 @@ def test_get_namespace_list_kind(client, mock_namespace_list): resource = client.resources.get(api_version='v1', kind='NamespaceList') assert resource == mock_namespace_list + + +def test_search_multiple_resources_for_template(client, mock_templates, mock_processedtemplates): + resources = client.resources.search(api_version='v1', kind='Template') + + assert len(resources) == 2 + assert mock_templates in resources + assert mock_processedtemplates in resources