diff --git a/kubernetes/base/dynamic/client.py b/kubernetes/base/dynamic/client.py index 352e11a809..d3ea2a80f7 100644 --- a/kubernetes/base/dynamic/client.py +++ b/kubernetes/base/dynamic/client.py @@ -119,6 +119,8 @@ def create(self, resource, body=None, namespace=None, **kwargs): return self.request('post', path, body=body, **kwargs) def delete(self, resource, name=None, namespace=None, body=None, label_selector=None, field_selector=None, **kwargs): + _body = self.serialize_body(body) + name = name or _body.get('metadata', {}).get('name') if not (name or label_selector or field_selector): raise ValueError("At least one of name|label_selector|field_selector is required") if resource.namespaced and not (label_selector or field_selector or namespace): diff --git a/kubernetes/utils/__init__.py b/kubernetes/utils/__init__.py index 217d9ccbc4..d8f004f0c7 100644 --- a/kubernetes/utils/__init__.py +++ b/kubernetes/utils/__init__.py @@ -15,5 +15,5 @@ from __future__ import absolute_import from .create_from_yaml import (FailToCreateError, create_from_dict, - create_from_yaml, create_from_directory) + action_from_yaml, create_from_directory) from .quantity import parse_quantity diff --git a/kubernetes/utils/create_from_yaml.py b/kubernetes/utils/create_from_yaml.py index 562c0edb7e..32bbc7986f 100644 --- a/kubernetes/utils/create_from_yaml.py +++ b/kubernetes/utils/create_from_yaml.py @@ -96,13 +96,13 @@ def create_from_directory( return k8s_objects_all -def create_from_yaml( +def action_from_yaml( k8s_client, yaml_file=None, yaml_objects=None, verbose=False, namespace="default", - apply=False, + action="apply", **kwargs, ): """ @@ -141,7 +141,7 @@ def create_from_yaml( instances for each object that failed to create. """ - def create_with(objects, apply=apply): + def create_with(objects): failures = [] k8s_objects = [] for yml_document in objects: @@ -153,7 +153,7 @@ def create_with(objects, apply=apply): yml_document, verbose, namespace=namespace, - apply=apply, + action=action, **kwargs, ) k8s_objects.append(created) @@ -174,7 +174,7 @@ class Loader(yaml.loader.SafeLoader): elif yaml_file: with open(os.path.abspath(yaml_file)) as f: yml_document_all = yaml.load_all(f, Loader=Loader) - return create_with(yml_document_all, apply) + return create_with(yml_document_all) else: raise ValueError( "One of `yaml_file` or `yaml_objects` arguments must be provided" @@ -182,7 +182,7 @@ class Loader(yaml.loader.SafeLoader): def create_from_dict( - k8s_client, data, verbose=False, namespace="default", apply=False, **kwargs + k8s_client, data, verbose=False, namespace="default", action="apply", **kwargs ): """ Perform an action from a dictionary containing valid kubernetes @@ -227,7 +227,7 @@ def create_from_dict( yml_object, verbose, namespace=namespace, - apply=apply, + action=action, **kwargs, ) k8s_objects.append(created) @@ -237,7 +237,7 @@ def create_from_dict( # This is a single object. Call the single item method try: created = create_from_yaml_single_item( - k8s_client, data, verbose, namespace=namespace, apply=apply, **kwargs + k8s_client, data, verbose, namespace=namespace, action=action, **kwargs ) k8s_objects.append(created) except client.rest.ApiException as api_exception: @@ -251,11 +251,12 @@ def create_from_dict( def create_from_yaml_single_item( - k8s_client, yml_object, verbose=False, apply=False, **kwargs + k8s_client, yml_object, verbose=False, action="apply", **kwargs ): kind = yml_object["kind"] - if apply is True: + if action == "apply": + # 允许重复应用资源 apply_client = DynamicClient(k8s_client).resources.get( api_version=yml_object["apiVersion"], kind=kind ) @@ -268,42 +269,51 @@ def create_from_yaml_single_item( msg += " status='{0}'".format(str(resp.status)) print(msg) return resp - group, _, version = yml_object["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 = "{0}{1}Api".format(group, version.capitalize()) - k8s_api = getattr(client, fcn_to_call)(k8s_client) - # Replace CamelCased action_type into snake_case - kind = UPPER_FOLLOWED_BY_LOWER_RE.sub(r"\1_\2", kind) - kind = LOWER_OR_NUM_FOLLOWED_BY_UPPER_RE.sub(r"\1_\2", kind).lower() - # Expect the user to create namespaced objects more often - if hasattr(k8s_api, "create_namespaced_{0}".format(kind)): - # Decide which namespace we are going to put the object in, - # if any - if "namespace" in yml_object["metadata"]: - namespace = yml_object["metadata"]["namespace"] - kwargs["namespace"] = namespace - resp = getattr(k8s_api, "create_namespaced_{0}".format(kind))( - body=yml_object, **kwargs - ) + elif action == "delete": + # 由pig2014修改 + # 增加了按yaml删除资源的功能 + group, _, version = yml_object["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 = "{0}{1}Api".format(group, version.capitalize()) + k8s_api = getattr(client, fcn_to_call)(k8s_client) + # Replace CamelCased action_type into snake_case + kind = UPPER_FOLLOWED_BY_LOWER_RE.sub(r"\1_\2", kind) + kind = LOWER_OR_NUM_FOLLOWED_BY_UPPER_RE.sub(r"\1_\2", kind).lower() + # kind = "deployment" + name = yml_object["metadata"]["name"] + # Expect the user to delete namespaced objects more often + if hasattr(k8s_api, "delete_namespaced_{0}".format(kind)): + # Decide which namespace we are going to put the object in, + # if any + if "namespace" in yml_object["metadata"]: + namespace = yml_object["metadata"]["namespace"] + kwargs["namespace"] = namespace + resp = getattr(k8s_api, "delete_namespaced_{0}".format(kind))( + # body=yml_object, name=name, **kwargs + body=None, name=name, **kwargs # 我只能说这玩意填个None就完事了真是太敷衍了 + ) + else: + kwargs.pop("namespace", None) + resp = getattr(k8s_api, "delete_{0}".format(kind))( + # body=yml_object, name=name, **kwargs + body=None, name=name, **kwargs # 同上 + ) + if verbose: + msg = "{0} deleted.".format(kind) + if hasattr(resp, "status"): + msg += " status='{0}'".format(str(resp.status)) + print(msg) + return resp else: - kwargs.pop("namespace", None) - resp = getattr(k8s_api, "create_{0}".format(kind))( - body=yml_object, **kwargs - ) - if verbose: - msg = "{0} created.".format(kind) - if hasattr(resp, "status"): - msg += " status='{0}'".format(str(resp.status)) - print(msg) - return resp + raise ValueError(f"Unsupported action {action}, only 'apply' and 'delete' is supported!") class FailToCreateError(Exception):