raphaelauv commented on code in PR #29930: URL: https://github.com/apache/airflow/pull/29930#discussion_r1163344192
########## airflow/providers/cncf/kubernetes/utils/delete_from.py: ########## @@ -0,0 +1,141 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# from https://github.com/tomplus/kubernetes_asyncio/pull/239/files + +from __future__ import annotations + +import re + +from kubernetes import client + +DEFAULT_DELETION_BODY = client.V1DeleteOptions( + propagation_policy="Background", + grace_period_seconds=5, +) + + +def delete_from_dict( + k8s_client, + yml_document, + verbose=False, + namespace="default", + body=None, + **kwargs, +): + + if body is None: + body = DEFAULT_DELETION_BODY + + api_exceptions = [] + if "List" in yml_document["kind"]: + kind = yml_document["kind"].replace("List", "") + for yml_doc in yml_document["items"]: + if kind != "": + yml_doc["apiVersion"] = yml_document["apiVersion"] + yml_doc["kind"] = kind + try: + _delete_from_yaml_single_item( + k8s_client, + yml_doc, + verbose, + namespace=namespace, + body=body, + **kwargs, + ) + except client.rest.ApiException as api_exception: + api_exceptions.append(api_exception) + else: + + try: + _delete_from_yaml_single_item( + k8s_client, + yml_document, + verbose, + namespace=namespace, + body=body, + **kwargs, + ) + except client.rest.ApiException as api_exception: + api_exceptions.append(api_exception) + + if api_exceptions: + raise FailToDeleteError(api_exceptions) + + +def _delete_from_yaml_single_item( + k8s_client, + yml_document, + verbose=False, + namespace="default", + body=None, + **kwargs, +): + if body is None: + body = DEFAULT_DELETION_BODY + + # get group and version from apiVersion + group, _, version = yml_document["apiVersion"].partition("/") + if version == "": + version = group + group = "core" + # Take care for the case e.g. api_type is "apiextensions.k8s.io" + # Only replace the last instance + group = "".join(group.rsplit(".k8s.io", 1)) + # convert group name from DNS subdomain format to + # python class name convention + group = "".join(word.capitalize() for word in group.split(".")) + fcn_to_call = f"{group}{version.capitalize()}Api" + k8s_api = getattr(client, fcn_to_call)(k8s_client) + # Replace CamelCased action_type into snake_case + kind = yml_document["kind"] + kind = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", kind) + kind = re.sub("([a-z0-9])([A-Z])", r"\1_\2", kind).lower() + + # Decide which namespace we are going to use for deleting the object + # IMPORTANT: Its ignore namespace in args: + # create_from_yaml_single_item have same behaviour + if "namespace" in yml_document["metadata"]: + namespace = yml_document["metadata"]["namespace"] + name = yml_document["metadata"]["name"] + + # Expect the user to delete namespaced objects more often + if hasattr(k8s_api, f"delete_namespaced_{kind}"): + resp: client.V1Status = getattr(k8s_api, f"delete_namespaced_{kind}")( + name=name, namespace=namespace, body=body, **kwargs + ) + else: + resp: client.V1Status = getattr(k8s_api, f"delete_{kind}")(name=name, body=body, **kwargs) + if verbose: + print(f"{kind} deleted. status='{str(resp.status)}'") + return resp + + +class FailToDeleteError(Exception): + """ + An exception class for handling error if an error occurred when + handling a yaml file during deletion of the resource. + """ + + def __init__(self, api_exceptions): + self.api_exceptions = api_exceptions + + def __str__(self): + msg = "" + for api_exception in self.api_exceptions: + msg += f"Error from server ({api_exception.reason}):{api_exception.body}" Review Comment: if there is a list of multiple resource, each deletion is try. if an error occur then it will fail at the end and log the error -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
