diff --git a/lib/charms/kubernetes_charm_libraries/v0/multus.py b/lib/charms/kubernetes_charm_libraries/v0/multus.py index 8ee02b9..c425619 100644 --- a/lib/charms/kubernetes_charm_libraries/v0/multus.py +++ b/lib/charms/kubernetes_charm_libraries/v0/multus.py @@ -123,7 +123,7 @@ def _on_config_changed(self, event: EventBase): # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 9 +LIBPATCH = 10 logger = logging.getLogger(__name__) @@ -384,6 +384,54 @@ def patch_statefulset( raise KubernetesMultusError(f"Could not patch statefulset {name}") logger.info("Multus annotation added to %s statefulset", name) + def unpatch_statefulset( + self, + name: str, + container_name: str, + ) -> None: + """Removes annotations, security privilege and NET_ADMIN capability from stateful set. + + Args: + name: Statefulset name + container_name: Container name + """ + try: + statefulset = self.client.get(res=StatefulSet, name=name, namespace=self.namespace) + except ApiError: + raise KubernetesMultusError(f"Could not get statefulset {name}") + + container = Container(name=container_name) + container.securityContext = SecurityContext( + capabilities=Capabilities( + drop=[ + "NET_ADMIN", + ] + ) + ) + container.securityContext.privileged = False + statefulset_delta = StatefulSet( + spec=StatefulSetSpec( + selector=statefulset.spec.selector, # type: ignore[attr-defined] + serviceName=statefulset.spec.serviceName, # type: ignore[attr-defined] + template=PodTemplateSpec( + metadata=ObjectMeta(annotations={"k8s.v1.cni.cncf.io/networks": "[]"}), + spec=PodSpec(containers=[container]), + ), + ) + ) + try: + self.client.patch( + res=StatefulSet, + name=name, + obj=statefulset_delta, + patch_type=PatchType.APPLY, + namespace=self.namespace, + field_manager=self.__class__.__name__, + ) + except ApiError: + raise KubernetesMultusError(f"Could not remove patches from statefulset {name}") + logger.info("Multus annotation removed from %s statefulset", name) + def statefulset_is_patched( self, name: str, @@ -658,11 +706,15 @@ def _pod(self) -> str: return "-".join(self.model.unit.name.rsplit("/", 1)) def _on_remove(self, event: RemoveEvent) -> None: - """Deletes network attachment definitions. + """Deletes network attachment definitions and removes patch. Args: event: RemoveEvent """ + self.kubernetes.unpatch_statefulset( + name=self.model.app.name, + container_name=self.container_name, + ) for network_attachment_definition in self.network_attachment_definitions_func(): if self.kubernetes.network_attachment_definition_is_created( network_attachment_definition=network_attachment_definition diff --git a/tests/unit/lib/charms/kubernetes_charm_libraries/v0/test_multus.py b/tests/unit/lib/charms/kubernetes_charm_libraries/v0/test_multus.py index 46920fc..ab74db1 100644 --- a/tests/unit/lib/charms/kubernetes_charm_libraries/v0/test_multus.py +++ b/tests/unit/lib/charms/kubernetes_charm_libraries/v0/test_multus.py @@ -1169,6 +1169,16 @@ def test_given_nads_not_created_when_nad_config_changed_then_patch_statefulset_i privileged=False, ) + @patch("lightkube.core.client.GenericSyncClient", new=Mock) + @patch(f"{MULTUS_LIBRARY_PATH}.KubernetesClient.unpatch_statefulset") + def test_given_when_removed_then_statefulset_unpatched(self, patch_unpatch_statefulset): + harness = Harness(_TestCharmMultipleNAD) + self.addCleanup(harness.cleanup) + harness.begin() + harness.charm.on.remove.emit() + + patch_unpatch_statefulset.assert_called() + @patch("lightkube.core.client.GenericSyncClient", new=Mock) @patch(f"{MULTUS_LIBRARY_PATH}.KubernetesClient.delete_network_attachment_definition") @patch(f"{MULTUS_LIBRARY_PATH}.KubernetesClient.network_attachment_definition_is_created")