k8s python API CRD资源接入

160 阅读3分钟
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date    : 2023-09-25 19:10:37
# @Author  : 792468193@qq.com
import datetime
import yaml
import time, arrow
from kubernetes import client, utils
from kubernetes.stream import stream
from functools import partialmethod


class SelfK8sError(Exception):
    pass


class MyK8s:
    def __init__(
        self,
        host,
        verify_ssl=True,
        ssl_ca_cert=None,
        cert_file=None,
        key_file=None,
        token=None,
    ):
        """
        参考 https://github.com/kubernetes-client/python/blob/master/kubernetes/README.md
        """
        aConfiguration = client.Configuration()
        aConfiguration.host = host
        aConfiguration.verify_ssl = verify_ssl

        if not token:
            aConfiguration.ssl_ca_cert = ssl_ca_cert
            aConfiguration.cert_file = cert_file
            aConfiguration.key_file = key_file
        else:
            aConfiguration.api_key = {"authorization": "Bearer " + token}
        self.api_client = client.ApiClient(aConfiguration)
        self.corev1 = client.CoreV1Api(self.api_client)
        self.appv1 = client.AppsV1Api(self.api_client)
        self.netv1 = client.NetworkingV1Api(self.api_client)
        self.co_api = client.CustomObjectsApi(self.api_client)
        self.batchv1 = client.BatchV1Api(self.api_client)
        self.autoscalingv2beta2 = None
        self.policyv1api = None
        self.inject_namesapced_object()
        self.inject_cluster_object()

    @staticmethod
    def inject_namesapced_object():
        # namespace级别的第三方对象在此处接入
        custom_objects = dict(
            cgroups=("resources.alibabacloud.com", "v1alpha1", "cgroups"),
            resource_policy=(
                "scheduling.alibabacloud.com",
                "v1alpha1",
                "resourcepolicies",
            ),
        )
        for object_name, object_attrs in custom_objects.items():
            for op in ["get", "create", "patch", "delete", "list"]:
                setattr(
                    CCK8s,
                    "{0}_{1}".format(op, object_name),
                    partialmethod(
                        getattr(CCK8s, "{}_custom_object".format(op)),
                        group=object_attrs[0],
                        api_version=object_attrs[1],
                        plural=object_attrs[2],
                    ),
                )

    @staticmethod
    def inject_cluster_object():
        # cluster级别的第三方对象在此处接入
        cluster_custom_objects = dict(
            sidecar_set=("apps.kruise.io", "v1alpha1", "sidecarsets")
        )
        for object_name, object_attrs in cluster_custom_objects.items():
            for op in ["get", "create", "patch", "delete", "list"]:
                setattr(
                    CCK8s,
                    "{0}_{1}".format(op, object_name),
                    partialmethod(
                        getattr(CCK8s, "{}_cluster_custom_object".format(op)),
                        group=object_attrs[0],
                        api_version=object_attrs[1],
                        plural=object_attrs[2],
                    ),
                )

    def _client_api(self, kind):
        if kind in (
            "controller_revision",
            "daemon_set",
            "deployment",
            "replica_set",
            "stateful_set",
        ):
            return self.appv1
        elif kind in ("pod", "service"):
            return self.corev1
        elif kind == "ingress":
            return self.netv1
        elif kind == "rollout":
            return self.co_api
        elif kind == "job":
            return self.batchv1
        elif kind == "hpa":
            if not self.autoscalingv2beta2:
                self.autoscalingv2beta2 = client.AutoscalingV2beta2Api(self.api_client)
            return self.autoscalingv2beta2
        elif kind == "pdb":
            if not self.policyv1api:
                self.policyv1api = client.PolicyV1Api(self.api_client)
            return self.policyv1api
        else:
            raise SelfK8sError("不支持操作类型为{}的对象".format(kind))

    def cli(self, kind):
        return self._client_api(kind)

    def get_custom_object(self, group, api_version, plural, namespace, name, **kw):
        func = getattr(self.co_api, "get_namespaced_custom_object")
        return func(group, api_version, namespace, plural, name, **kw)

    def delete_custom_object(self, group, api_version, plural, namespace, name, **kw):
        func = getattr(self.co_api, "delete_namespaced_custom_object")
        return func(group, api_version, namespace, plural, name, **kw)

    def list_custom_object(
        self, group, api_version, plural, namespace, name, null=False, **kw
    ):
        selector = "metadata.name={}".format(name)
        func = getattr(self.co_api, "list_namespaced_custom_object")
        items = func(
            group, api_version, namespace, plural, field_selector=selector, **kw
        )["items"]
        if not items:
            if null:
                return None
            else:
                raise SelfK8sError(
                    "{0} namespace has not found {1} {2}".format(
                        namespace, name, plural
                    )
                )
        if len(items) > 1:
            raise SelfK8sError(
                "{0} namespace has found multi {1} {2}".format(namespace, name, plural)
            )
        return items[0]

    def patch_custom_object(
        self, group, api_version, plural, namespace, name, json_data, **kw
    ):
        func = getattr(self.co_api, "patch_namespaced_custom_object")
        return func(group, api_version, namespace, plural, name, json_data, **kw)

    def create_custom_object(
        self, group, api_version, plural, namespace, json_data, **kw
    ):
        func = getattr(self.co_api, "create_namespaced_custom_object")
        return func(group, api_version, namespace, plural, json_data, **kw)

    #  cluster 级别的自定义对象
    def get_cluster_custom_object(self, group, api_version, plural, name, **kw):
        func = getattr(self.co_api, "get_cluster_custom_object")
        return func(group, api_version, plural, name, **kw)

    def delete_cluster_custom_object(self, group, api_version, plural, name, **kw):
        func = getattr(self.co_api, "delete_cluster_custom_object")
        return func(group, api_version, plural, name, **kw)

    def list_cluster_custom_object(
        self, group, api_version, plural, name, null=False, **kw
    ):
        selector = "metadata.name={}".format(name)
        func = getattr(self.co_api, "list_cluster_custom_object")
        items = func(group, api_version, plural, field_selector=selector, **kw)["items"]
        if not items:
            if null:
                return None
            else:
                raise SelfK8sError("cluster has not found {0} {1}".format(name, plural))
        if len(items) > 1:
            raise SelfK8sError("cluster has found multi {0} {1}".format(name, plural))
        return items[0]

    def patch_cluster_custom_object(
        self, group, api_version, plural, name, json_data, **kw
    ):
        func = getattr(self.co_api, "patch_cluster_custom_object")
        return func(group, api_version, plural, name, json_data, **kw)

    def create_cluster_custom_object(self, group, api_version, plural, json_data, **kw):
        func = getattr(self.co_api, "create_cluster_custom_object")
        return func(group, api_version, plural, json_data, **kw)

if __name__ == '__main__':
    cck8s = CCK8s(
        "https://xxxxxxx",
        ssl_ca_cert="/xxxxxxxxxxxxxxxxxx.ssl-ca",
        cert_file="/xxxxxxxxxxx.client-cert",
        key_file="/xxxxxxxxx.client-key",
    )
    data = {
        "apiVersion": "resources.alibabacloud.com/v1alpha1",
        "kind": "Cgroups",
        "metadata": {
            "name": object_name,
            "namespace": namespace,
        },
        "spec": {
            object_type: {
                "containers": [{"name": container_name}],
                "name": object_name,
                "namespace": namespace,
            }
        },
    }
    cck8s.create_cgroups(namespace=namespace, json_data=data)