diff --git a/kr8s/_api.py b/kr8s/_api.py index 8d917b00..efa42a85 100644 --- a/kr8s/_api.py +++ b/kr8s/_api.py @@ -288,7 +288,7 @@ async def async_whoami(self): [name] = cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME) return name.value - async def async_lookup_kind(self, kind) -> tuple[str, bool]: + async def async_lookup_kind(self, kind) -> tuple[str, str, bool]: """Lookup a Kubernetes resource kind.""" from ._objects import parse_kind @@ -306,15 +306,17 @@ async def async_lookup_kind(self, kind) -> tuple[str, bool]: if "/" in resource["version"]: return ( f"{resource['singularName']}.{resource['version']}", + resource["name"], resource["namespaced"], ) return ( f"{resource['singularName']}/{resource['version']}", + resource["name"], resource["namespaced"], ) raise ValueError(f"Kind {kind} not found.") - async def lookup_kind(self, kind) -> tuple[str, bool]: + async def lookup_kind(self, kind) -> tuple[str, str, bool]: """Lookup a Kubernetes resource kind. Check whether a resource kind exists on the remote server. @@ -323,7 +325,7 @@ async def lookup_kind(self, kind) -> tuple[str, bool]: kind: The kind of resource to lookup. Returns: - The kind of resource and whether the resource is namespaced + The kind of resource, the plural form and whether the resource is namespaced Raises: ValueError: If the kind is not found. @@ -367,7 +369,7 @@ async def async_get_kind( else: namespaced: bool | None = None try: - kind, namespaced = await self.async_lookup_kind(kind) + kind, plural, namespaced = await self.async_lookup_kind(kind) except ServerError as e: warnings.warn(str(e), stacklevel=1) if isinstance(kind, str): @@ -377,10 +379,15 @@ async def async_get_kind( if allow_unknown_type: if namespaced is not None: obj_cls = new_class( - kind, namespaced=namespaced, asyncio=self._asyncio + kind, + namespaced=namespaced, + asyncio=self._asyncio, + plural=plural, ) else: - obj_cls = new_class(kind, asyncio=self._asyncio) + obj_cls = new_class( + kind, asyncio=self._asyncio, plural=plural + ) else: raise e params = params or None diff --git a/kr8s/tests/test_api.py b/kr8s/tests/test_api.py index b94f1de7..f8c0e49b 100644 --- a/kr8s/tests/test_api.py +++ b/kr8s/tests/test_api.py @@ -317,18 +317,33 @@ async def test_api_timeout() -> None: async def test_lookup_kind(): api = await kr8s.asyncio.api() - assert await api.lookup_kind("no") == ("node/v1", False) - assert await api.lookup_kind("nodes") == ("node/v1", False) - assert await api.lookup_kind("po") == ("pod/v1", True) - assert await api.lookup_kind("pods/v1") == ("pod/v1", True) - assert await api.lookup_kind("role") == ("role.rbac.authorization.k8s.io/v1", True) - assert await api.lookup_kind("roles") == ("role.rbac.authorization.k8s.io/v1", True) + assert await api.lookup_kind("no") == ("node/v1", "nodes", False) + assert await api.lookup_kind("nodes") == ("node/v1", "nodes", False) + assert await api.lookup_kind("po") == ("pod/v1", "pods", True) + assert await api.lookup_kind("pods/v1") == ("pod/v1", "pods", True) + assert await api.lookup_kind("CSIStorageCapacity") == ( + "csistoragecapacity.storage.k8s.io/v1", + "csistoragecapacities", + True, + ) + assert await api.lookup_kind("role") == ( + "role.rbac.authorization.k8s.io/v1", + "roles", + True, + ) + assert await api.lookup_kind("roles") == ( + "role.rbac.authorization.k8s.io/v1", + "roles", + True, + ) assert await api.lookup_kind("roles.v1.rbac.authorization.k8s.io") == ( "role.rbac.authorization.k8s.io/v1", + "roles", True, ) assert await api.lookup_kind("roles.rbac.authorization.k8s.io") == ( "role.rbac.authorization.k8s.io/v1", + "roles", True, ) @@ -366,3 +381,17 @@ async def test_dynamic_classes(kind, ensure_gc): await api.get(kind, allow_unknown_type=False) await api.get(kind) + + +@pytest.mark.parametrize( + "kind", + [ + "ingress.networking.k8s.io", + "networkpolicies.networking.k8s.io", + "csistoragecapacities.storage.k8s.io", + "CSIStorageCapacity", + ], +) +async def test_get_dynamic_plurals(kind, ensure_gc): + api = await kr8s.asyncio.api() + assert isinstance(await api.get(kind), list)