import time import yaml import traceback from kubernetes import client, config from kubernetes.client.exceptions import ApiException from appPublic.log import debug from .k8s_utils_public import format_source_labels def create_or_update_namespace(v1, namespace_name): """创建或更新命名空间""" try: v1.read_namespace(namespace_name) debug(f"namespace_name={namespace_name} 命名空间已存在,跳过创建。") except ApiException as e: if e.status == 404: body = { "apiVersion": "v1", "kind": "Namespace", "metadata": {"name": namespace_name} } v1.create_namespace(body=body) debug(f"namespace_name={namespace_name} 命名空间创建成功。") else: raise ValueError(f'{e}') def create_or_update_service_account(v1, namespace_name, service_account_name): """创建或更新服务账户""" try: v1.read_namespaced_service_account(name=service_account_name, namespace=namespace_name) debug(f"namespace_name={namespace_name} service_account_name={service_account_name} 服务账户已存在,跳过创建。") except ApiException as e: if e.status == 404: body = { "apiVersion": "v1", "kind": "ServiceAccount", "metadata": { "name": service_account_name, "namespace": namespace_name } } v1.create_namespaced_service_account(namespace=namespace_name, body=body) debug(f"namespace_name={namespace_name} service_account_name={service_account_name} 服务账户创建成功。") else: raise ValueError(f'{e}') def create_or_update_service(v1, namespace_name, service_name, port_mode, internal_port, selector, inside_port, outside_port): """创建或更新服务""" try: existing_service = v1.read_namespaced_service(name=service_name, namespace=namespace_name) update_info = [] need_update = False ports_config = [ { "name": f"podport{internal_port}", "protocol": "TCP", "port": internal_port, "targetPort": inside_port, "nodePort": outside_port if port_mode == "NodePort" else None } ] if existing_service.spec.type != port_mode: need_update = True update_info.append(f"服务类型从 {existing_service.spec.type} 更新为 {port_mode}") existing_service.spec.type = port_mode if existing_service.spec.selector != selector: need_update = True update_info.append(f"服务选择器从 {existing_service.spec.selector} 更新为 {selector}") existing_service.spec.selector = selector if existing_service.spec.ports != ports_config: need_update = True update_info.append(f"服务端口配置更新") existing_service.spec.ports = ports_config if need_update: v1.patch_namespaced_service(name=service_name, namespace=namespace_name, body=existing_service) debug(f"service_name={service_name} update_info={update_info} 服务已更新,更新内容: {update_info}") else: debug(f"service_name={service_name} 服务配置无变化,无需更新。") return existing_service except ApiException as e: if e.status == 404: ports_config = [ { "name": f"podport{internal_port}", "protocol": "TCP", "port": internal_port, "targetPort": inside_port, "nodePort": outside_port if port_mode == "NodePort" else None } ] body = { "apiVersion": "v1", "kind": "Service", "metadata": {"name": service_name, "namespace": namespace_name}, "spec": {"type": port_mode, "selector": selector, "ports": ports_config} } v1.create_namespaced_service(namespace=namespace_name, body=body) debug(f"service_name={service_name} 服务创建成功。") return v1.read_namespaced_service(name=service_name, namespace=namespace_name) else: raise ValueError(f'{e}') # def create_persistent_volume(v1, namespace_name, pv_name, capacity, access_modes, storage_class_name, nfs_server, nfs_path): # """创建PV""" # try: # v1.read_persistent_volume(name=pv_name) # debug(f"PersistentVolume {pv_name} 已存在,跳过创建。") # except ApiException as e: # if e.status == 404: # body = { # "apiVersion": "v1", # "kind": "PersistentVolume", # "metadata": { # "name": pv_name, # "namespace": namespace_name # }, # "spec": { # "capacity": { # "storage": capacity # }, # "accessModes": access_modes, # "persistentVolumeReclaimPolicy": "Retain", # "storageClassName": storage_class_name, # "nfs": { # "server": nfs_server, # "path": nfs_path # } # } # } # try: # v1.create_persistent_volume(body=body) # debug(f"PersistentVolume {pv_name} 创建成功。") # except ApiException as create_e: # raise Exception(f"创建 PersistentVolume {pv_name} 失败: {create_e.reason}") # else: # raise Exception(f"检查 PersistentVolume {pv_name} 是否存在时出错: {e.reason}") def create_persistent_volume_claim(v1, namespace_name, pvc_name, access_modes, storage_class_name, pvc_capacity, source_selflabel): """创建pvc""" try: v1.read_namespaced_persistent_volume_claim(name=pvc_name, namespace=namespace_name) debug(f"PersistentVolumeClaim {pvc_name} 已存在,跳过创建。") except ApiException as e: if e.status == 404: body = { "apiVersion": "v1", "kind": "PersistentVolumeClaim", "metadata": { "name": pvc_name, "namespace": namespace_name, "labels": source_selflabel }, "spec": { "accessModes": access_modes, "resources": {"requests": {"storage": pvc_capacity}}, "storageClassName": storage_class_name } } try: v1.create_namespaced_persistent_volume_claim(namespace=namespace_name, body=body) debug(f"PersistentVolumeClaim {pvc_name} 创建成功。") except ApiException as create_e: raise Exception(f"创建 PersistentVolumeClaim {pvc_name} 失败: {create_e.reason}") else: raise Exception(f"检查 PersistentVolumeClaim {pvc_name} 是否存在时出错: {e.reason}") def create_or_update_statefulset(apps_v1, v1, namespace_name, statefulset_name, service_account_name, image, replicas, cpu_limit, memory_limit, node_selector, container_name, initial_password, restart_policy, inside_port, volume_mount_path, pvc_name, env_vars, readiness_probe, liveness_probe, source_selflabel, ephemeral_storage, source_gpu): """创建或更新StatefulSet,共享单个pvc""" try: existing_statefulset = apps_v1.read_namespaced_stateful_set(name=statefulset_name, namespace=namespace_name) update_info = [] need_update = False template = existing_statefulset.spec.template container = template.spec.containers[0] # 更新副本数 if existing_statefulset.spec.replicas != replicas: need_update = True update_info.append(f"副本数从 {existing_statefulset.spec.replicas} 更新为 {replicas}") existing_statefulset.spec.replicas = replicas # 更新服务账户和重启策略 if template.spec.service_account_name != service_account_name: need_update = True update_info.append(f"服务账户从 {template.spec.service_account_name} 更新为 {service_account_name}") template.spec.service_account_name = service_account_name if template.spec.restart_policy != restart_policy: need_update = True update_info.append(f"重启策略从 {template.spec.restart_policy} 更新为 {restart_policy}") template.spec.restart_policy = restart_policy # 更新容器配置 if container.name != container_name: need_update = True update_info.append(f"容器名称从 {container.name} 更新为 {container_name}") container.name = container_name if container.image != image: need_update = True update_info.append(f"镜像从 {container.image} 更新为 {image}") container.image = image if container.env != env_vars: need_update = True update_info.append(f"环境变量更新为 {env_vars}") container.env = env_vars update_limits_info = { "cpu": cpu_limit, "memory": memory_limit, "ephemeral-storage": ephemeral_storage, "nvidia.com/gpu" : source_gpu } if container.resources.limits != update_limits_info: need_update = True update_info.append(f"资源实例消费上限更新为 {update_limits_info}") container.resources.limits = update_limits_info #update_requests_info = {"ephemeral-storage": ephemeral_storage} # if container.resources.requests != update_limits_info: # need_update = True # update_info.append(f"资源实例消费上限更新为 {update_limits_info}") container.resources.requests = update_limits_info if container.ports != [{"containerPort": inside_port}]: need_update = True update_info.append(f"容器端口从 {container.ports} 更新为 {inside_port}") container.ports = [{"containerPort": inside_port}] # 更新探针 if container.readiness_probe != readiness_probe: need_update = True update_info.append(f"就绪探针更新") container.readiness_probe = readiness_probe if container.liveness_probe != liveness_probe: need_update = True update_info.append(f"存活探针更新") container.liveness_probe = liveness_probe # 更新卷挂载 if container.volume_mounts != [{"name": pvc_name, "mountPath": volume_mount_path}]: need_update = True update_info.append(f"卷挂载从 {container.volume_mounts} 更新为 {volume_mount_path}") container.volume_mounts = [{"name": pvc_name, "mountPath": volume_mount_path}] if need_update: apps_v1.patch_namespaced_stateful_set(name=statefulset_name, namespace=namespace_name, body=existing_statefulset) debug(f"StatefulSet {statefulset_name} 更新成功: {update_info}") else: debug(f"StatefulSet {statefulset_name} 配置无变化") return existing_statefulset except ApiException as e: traceback.print_exc() limits_requests = { "cpu": cpu_limit, "memory": memory_limit, "ephemeral-storage": ephemeral_storage, "nvidia.com/gpu" : source_gpu } if e.status == 404: container_config = { "name": container_name, "image": image, "env": env_vars, "resources": { "limits": limits_requests, "requests": limits_requests #{"ephemeral-storage": ephemeral_storage} # 容器启动时请求 10GB 临时存储 }, "ports": [{"containerPort": inside_port}], "readinessProbe": readiness_probe, "livenessProbe": liveness_probe, "volumeMounts": [{"name": pvc_name, "mountPath": volume_mount_path}], "command": [ "/bin/bash", "-c", f"echo 'root:{initial_password}' | chpasswd && service ssh start && while true; do sleep 1; done" ] } body = { "apiVersion": "apps/v1", "kind": "StatefulSet", "metadata": {"name": statefulset_name, "namespace": namespace_name}, "spec": { "runtimeClassName": "nvidia", # 指定使用 nvidia runtime" "replicas": replicas, "selector": {"matchLabels": source_selflabel}, "serviceName": statefulset_name, "template": { "metadata": {"labels": source_selflabel}, "spec": { "serviceAccountName": service_account_name, "restartPolicy": restart_policy, "containers": [container_config], "nodeSelector": node_selector, # 基于客户端IP保持会话亲和性(可选):客户端请求始终到最开始pod; # 但也有弊端,假若某个Pod宕机或环境异常,客户端还是会一直请求该Pod,导致无法访问。 # "sessionAffinity": "ClientIP", "volumes": [{ "name": pvc_name, "persistentVolumeClaim": { "claimName": pvc_name } }] } } } } apps_v1.create_namespaced_stateful_set(namespace=namespace_name, body=body) debug(f"StatefulSet {statefulset_name} 创建成功,副本数: {replicas}") return apps_v1.read_namespaced_stateful_set(name=statefulset_name, namespace=namespace_name) else: raise ValueError(f'{e}') def delete_persistent_volume(v1, pv_name): """删除PV""" try: v1.delete_persistent_volume(name=pv_name) debug(f"PersistentVolume {pv_name} 删除成功") except ApiException as e: raise Exception(f"删除 PersistentVolume {pv_name} 失败: {e.reason}") def delete_persistent_volume_claim(v1, namespace_name, pvc_name): """删除pvc""" try: v1.delete_namespaced_persistent_volume_claim(name=pvc_name, namespace=namespace_name) debug(f"PersistentVolumeClaim {pvc_name} 删除成功") except ApiException as e: raise Exception(f"删除 PersistentVolumeClaim {pvc_name} 失败: {e.reason}") def delete_namespace(v1, namespace_name, root_namespace="default_namespace"): """删除命名空间""" if namespace_name != root_namespace: try: v1.delete_namespace(namespace_name, propagation_policy="Foreground") debug(f"命名空间 {namespace_name} 删除请求已提交") except ApiException as e: raise Exception(f"删除命名空间 {namespace_name} 失败: {e.reason}") else: debug(f"跳过删除根命名空间 {namespace_name}") def delete_service_account(v1, namespace_name, service_account_name, root_namespace="default_namespace"): """删除服务账户""" if namespace_name != root_namespace: try: v1.delete_namespaced_service_account(service_account_name, namespace_name) debug(f"服务账户 {service_account_name} 删除成功") except ApiException as e: raise Exception(f"删除服务账户 {service_account_name} 失败: {e.reason}") else: debug(f"跳过删除根命名空间中的服务账户 {service_account_name}") def delete_service(v1, namespace_name, service_name): """删除服务""" try: v1.delete_namespaced_service(service_name, namespace_name) debug(f"服务 {service_name} 删除成功") except ApiException as e: raise Exception(f"删除服务 {service_name} 失败: {e.reason}") def delete_statefulset(apps_v1, namespace_name, statefulset_name): """删除StatefulSet""" try: apps_v1.delete_namespaced_stateful_set( name=statefulset_name, namespace=namespace_name, propagation_policy="Foreground" ) debug(f"StatefulSet {statefulset_name} 删除请求已提交") except ApiException as e: raise Exception(f"删除 StatefulSet {statefulset_name} 失败: {e.reason}") def handle_k8s_operations(frontend_params): """ 处理Kubernetes资源操作 """ # 参数验证 required_params = [ "action", "namespace_name", "serviceaccount_name", "service_name", "podcd_name", "pod_imagepath", "source_replicasetnum", "source_cpurate", "source_memrate", "source_portmode", "source_apiport", "source_insideport", "source_outsideport", "source_name", "source_authpasswd", "source_restartpolicy", "source_mountpath", "host", # nfs_server "source_selflabel", # "source_nodeselector" ] for param in required_params: if not frontend_params.get(param): debug(f"param={param} 错误:缺少必要参数 {param}") raise ValueError(f"缺少必要参数: {param}") kubeconfig = yaml.safe_load(frontend_params.pop("kubeconfig")) config.load_kube_config_from_dict(kubeconfig) v1 = client.CoreV1Api() apps_v1 = client.AppsV1Api() action = frontend_params["action"] namespace_name = frontend_params["namespace_name"] service_account_name = frontend_params["serviceaccount_name"] service_name = frontend_params["service_name"] statefulset_name = frontend_params["podcd_name"] image = frontend_params["pod_imagepath"] replicas = int(frontend_params.get("source_replicasetnum")) cpu_limit = frontend_params["source_cpurate"] memory_limit = frontend_params["source_memrate"] port_mode = frontend_params["source_portmode"] internal_port = int(frontend_params["source_apiport"]) inside_port = int(frontend_params["source_insideport"]) outside_port = int(frontend_params["source_outsideport"]) container_name = frontend_params["source_name"] initial_password = frontend_params["source_authpasswd"] restart_policy = frontend_params["source_restartpolicy"] volume_mount_path = frontend_params["source_mountpath"] pvc_name = container_name.replace(" ", "").lower() + "-pvc" env_varsa = [{"name": "ENV_VAR_NAME", "value": "ENV_VAR_VALUE"}] env_vars = frontend_params.get("env_vars", env_varsa) readiness_probea = { "exec": { "command": ["/bin/bash", "-c", "ls /"] }, "initialDelaySeconds": 10, "periodSeconds": 5 } readiness_probe = frontend_params.get("readiness_probe", readiness_probea) liveness_probea = { "exec": { "command": ["service", "ssh", "status"] }, "initialDelaySeconds": 20, "periodSeconds": 10 } liveness_probe = frontend_params.get("liveness_probe", liveness_probea) access_modesa = ["ReadWriteMany"] #NFS 存储类通常需要 ReadWriteOnce 或 ReadOnlyMany,否则可能导致调度失败。 # access_modesa = ["ReadOnlyMany","ReadWriteOnce"] access_modes = frontend_params.get("access_modes",access_modesa) storage_class_name = frontend_params.get("storage_class_name", "nfs-storage-class") nfs_server = frontend_params.get("host") nfs_path = frontend_params.get("nfs_path","/d/k8s_nss") pv_name = f"{pvc_name}-pv" source_storagelimits = frontend_params.get("source_storagelimits", "50Gi") pv_capacity = frontend_params.get("pv_capacity", source_storagelimits) pvc_capacity = frontend_params.get("pvc_capacity",source_storagelimits) # 以下参数暂未开放----------------------------------------------------------------------------------- source_selflabel = format_source_labels(frontend_params.get("source_selflabel",":"),type="pod") node_selector = format_source_labels(frontend_params.get("source_nodeselector","="),type="node") # 限制容器最多使用 10GB 临时存储(包括根目录) ephemeral_storage = frontend_params.get("ephemeral_storage","10Gi") # 限制Pod占用GPU数量,默认为0 source_gpu = int(frontend_params.get("source_gpu", "0")) # ------------------------------------------------------------------------------------------------ # 删除选项控制 delete_options = { "pvc": frontend_params.get("delete_pvc", True), # "pv": frontend_params.get("delete_pv", True), "service": frontend_params.get("delete_service", True), "service_account": frontend_params.get("delete_service_account", False), "namespace": frontend_params.get("delete_namespace", False) } if action == "apply": # 创建资源(按依赖顺序) create_or_update_namespace(v1, namespace_name) create_or_update_service_account(v1, namespace_name, service_account_name) create_or_update_service(v1, namespace_name, service_name, port_mode, internal_port, source_selflabel, inside_port, outside_port) # create_persistent_volume(v1, namespace_name, pv_name, pv_capacity, access_modes, storage_class_name, nfs_server, nfs_path) create_persistent_volume_claim(v1, namespace_name, pvc_name, access_modes, storage_class_name, pvc_capacity, source_selflabel) create_or_update_statefulset( apps_v1, v1, namespace_name, statefulset_name, service_account_name, image, replicas, cpu_limit, memory_limit, node_selector, container_name, initial_password, restart_policy, inside_port, volume_mount_path, pvc_name, env_vars, readiness_probe, liveness_probe, source_selflabel, ephemeral_storage, source_gpu ) debug(f"成功申请 {replicas} 个副本的 {statefulset_name},共享pvc: {pvc_name}") elif action == "delete": # 删除资源(按逆序) delete_statefulset(apps_v1, namespace_name, statefulset_name) # 等待一段时间,确保Pod完全终止 debug(f'正在销毁资源实例,请稍等...') time.sleep(3) # 可根据实际情况调整) if delete_options["pvc"]: delete_persistent_volume_claim(v1, namespace_name, pvc_name) # if delete_options["pv"]: # delete_persistent_volume(v1, pv_name) if delete_options["service"]: delete_service(v1, namespace_name, service_name) if delete_options["service_account"]: delete_service_account(v1, namespace_name, service_account_name) if delete_options["namespace"]: delete_namespace(v1, namespace_name) debug(f"成功销毁 {statefulset_name} 及其相关资源") else: raise ValueError("action参数必须为'apply'或'delete'") if __name__ == "__main__": # Service 端口(port):客户端访问 Service 的端口(例如 2222)。 # Pod 端口(targetPort):后端 Pod 实际监听的端口(例如 22)。 # NodePort(nodePort):集群外访问的端口(例如 30060)。 kbc = "apiVersion: v1\nclusters:\n- cluster:\n certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURCVENDQWUyZ0F3SUJBZ0lJTGd4THlGMjM3QmN3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TlRBME1ETXdOelE1TXpWYUZ3MHpOVEEwTURFd056VTBNelZhTUJVeApFekFSQmdOVkJBTVRDbXQxWW1WeWJtVjBaWE13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLCkFvSUJBUURQUm5hdkZmNXBTWWUvVmJLc0s2SnhEazhyc2hsc2h5WnNNRk8xZDVhZG45Z055T0wwR2NtbEsrQ1EKVklKSnF3RklJeSsxUVlEd3VRMytzczEwYmV2Y2lqM1BRanluaXJRRkNhRlA0NHh2ZkEyK2thV1FYeTVncGwrMwpjSkI1K1MxVmx2Vi9aSHQ5SXgwNjFCdHB4dE5oMUkxNS9IYk4rWmVNNnEvd3lxUW93Y01ub2pyNDltYkxxOWNwCnFSem5LL2FwWXlBYnljUk9uWWlIZ0FjQWdsclFOTjBKUEJZd2dRd0pIUmlIcGhtVFBkdmY2ckxkNFR0dFl2OXgKdmZIRDNjVUdwZkVBUElaNUJBVi9ZM3p5V0pSbDQzSFV2Ri9jemNDQ01jOVlUd3VXaEpxb2doUUZUdnNuSVZzTwovNEtKQzRwQXFSenJlZFRWdExmMXgzQlRpVCt0QWdNQkFBR2pXVEJYTUE0R0ExVWREd0VCL3dRRUF3SUNwREFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUIwR0ExVWREZ1FXQkJUZjRZbzBpOVpIZC9ObzdkYWZrZVRTbzVzdzN6QVYKQmdOVkhSRUVEakFNZ2dwcmRXSmxjbTVsZEdWek1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRRERLalJWVVp1YwppckJ4QWdZWnBBeW5NSHdWQTF6YStVT09FM1U0MEMyVTN0VGgrK1BsN2o2ZGJZTWNWdEFvTXhxaDRiVjNQRW5SCmtWcWNaN2NjS3FGSXduZlhHK0ZGTVVwazVoTk0xLzc2UXBobi9OWk8zSStSVjFtV0VOU1BzM1FZdEVoWktXUlgKYWRXZ0krK0x1cUZyZVpTVzVjRXNnMWZDODFtd3dhTXdkRHZWcFJZMFEwWlBsMGFqTURsSlNDaDNOSXpQOS82bwpndXBrY1JSdWtvRGlscWVraXlrRWJ5OVJCWHZIbXo3Q0sxQ1ZnZXZJTDZrVnRPRFF2Rm10Qm1WemlRNWFDcXJOCmtZNmd6OUNGMkdKc2M4UkZrcWQxbzdMelhPakJsTkdzN2k2WmdEOE1Ca2tiank2RmZDZWVndmxOOGFCU2VmblEKZ2ZNOVptbnRpMVNDCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n server: https://192.168.0.3:6443\n name: kubernetes\ncontexts:\n- context:\n cluster: kubernetes\n user: kubernetes-admin\n name: kubernetes-admin@kubernetes\ncurrent-context: kubernetes-admin@kubernetes\nkind: Config\npreferences: {}\nusers:\n- name: kubernetes-admin\n user:\n client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURJRENDQWdpZ0F3SUJBZ0lIVGZPdmU4TzBJVEFOQmdrcWhraUc5dzBCQVFzRkFEQVZNUk13RVFZRFZRUUQKRXdwcmRXSmxjbTVsZEdWek1CNFhEVEkxTURRd016QTNORGt6TlZvWERUSTJNRFF3TXpBM05UUXpOMW93TkRFWApNQlVHQTFVRUNoTU9jM2x6ZEdWdE9tMWhjM1JsY25NeEdUQVhCZ05WQkFNVEVHdDFZbVZ5Ym1WMFpYTXRZV1J0CmFXNHdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFEWVJJT3h0TWFkOWs2T1JsL1UKZ2ZnZVJDQkpjZmMrc2ZFbzkxeW4vc05KZFVIbWRuamtMaC9wRjcwZkdoVWZ3R2t5dzR0WkdpTFFNR0xwclpyeAphVTdJT0R3a3I2ejl1SkQzaHlFZExhZGpZT0NOMHJhUFNpV05GV1QwSVN2UVBjZzNGQkQ2YmFHb2RtSmN5YnBPCk5qY1VZZmh5WEVqRXMwOU92QzhhZUJCbm9Na1RkRk53dlFaYXE2LzR3eTUyN0k3aUdIUVdvL21JS1VUVHhzRFgKMzJnVXErZmRVMEh5STJJeWhNMGdwT29uNURCVmRUbWsyMkZsVHk0ZWJ3Q3R4QmMvRCtpelhuZFpVd2tHMExMVwpqTEc4L3JkWTZ4WFJDVkhHM1BWNURRK0JvNEpnMTUwWWFSUnBKeDJYSGxad3N5OFBZcWVLcTM0b1pxczRTRndmCjJCY3JBZ01CQUFHalZqQlVNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0QKQWpBTUJnTlZIUk1CQWY4RUFqQUFNQjhHQTFVZEl3UVlNQmFBRk4vaGlqU0wxa2QzODJqdDFwK1I1TktqbXpEZgpNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUFTR0phc1EyQXpLdVNZWFdtMGlYOUhnWTNZQUJGMHpYRzRKZU5lCjREekxkOHF2TXlqRGMwUWFWSUtNbWswemhrV1ZIQzNKSEZWalRXcDBUNFE0TlVBMk8rOXFob1p0a25NL3dsQlUKS0Zab3ZHNFd6SU1sdVJwL21ZRUIzL3dHbkFPV01MdEtBSWJ3d3FRVWl4VW5KYkxCeG4xQ1k5ZERzb1o4VmZZMQp4N2R0WDBJWjJkbU1ETTVLV1lrbW5tQWJBR0tXazZBR3pVWEpWNmlTU3laYjlWLzNuN3hmZlpZRkVDQXBQNk91CjhmRGdIVjBCdEMxS3VmU0tsTitLMnF2aXAzMlRjRHdoTEVHQWQ2aU9qYzhBRXlHelJmOWY4M0xUSGJ2dGtibjYKR0VQQlBQSExSTFlQWEh0OE9LbHdNOThwQWxkSkIyWEJ6UEttc0JFeGFOSWRXd2FTCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBMkVTRHNiVEduZlpPamtaZjFJSDRIa1FnU1hIM1BySHhLUGRjcC83RFNYVkI1blo0CjVDNGY2UmU5SHhvVkg4QnBNc09MV1JvaTBEQmk2YTJhOFdsT3lEZzhKSytzL2JpUTk0Y2hIUzJuWTJEZ2pkSzIKajBvbGpSVms5Q0VyMEQzSU54UVErbTJocUhaaVhNbTZUalkzRkdINGNseEl4TE5QVHJ3dkduZ1FaNkRKRTNSVApjTDBHV3F1ditNTXVkdXlPNGhoMEZxUDVpQ2xFMDhiQTE5OW9GS3ZuM1ZOQjhpTmlNb1ROSUtUcUorUXdWWFU1CnBOdGhaVTh1SG04QXJjUVhQdy9vczE1M1dWTUpCdEN5MW95eHZQNjNXT3NWMFFsUnh0ejFlUTBQZ2FPQ1lOZWQKR0drVWFTY2RseDVXY0xNdkQyS25pcXQrS0dhck9FaGNIOWdYS3dJREFRQUJBb0lCQVFDQ1djRjZ3YmdaQzVWTApvZFV1MCt1RjZvLy9WS2F1YmpncDlmWXQ5NXNqVW42Vzl2OWtvUHh3MVBNVHBQZm9mR09yeWpyYVNLdUZDalVFCkhiUlBINmJ4ZlJ1YkRSdmFqWDByQkpLTDhMRjhiNjdKTEtFR2VxMXBmT1N0VkxVQXZjeElqbHF4WnBUU1loQmwKVnQxcE9MbzRHZGpTclJiYklDeUVDMTdrdUV0QytZV3lFb3E5MmlLNVdMTHdHM2hwVzhyVlVLVzZ2T0cyd0l4bAp0RWhMSGpOOWtnb1VVa2pORG9tK2FlcVVxeXhDeUZEdll4UmdhVTd0Y3pJSk52SUk3aDYxaExQbEZtMmxGQ0xlCjhjeTdKUDMyV1ZDSUpUMHhRNkJJRTdvVld4WWIvMzFVSHYrTHg0UHlBcFpiZ3piMjlvQm54VjhneUxnVjZDWW0Kd1psQlQ4S2hBb0dCQU9tMFZqTkVHVm5EaXNsTDFVVkNKYzFCVU1KcjNwalQvV0g4d2s0UzJYWmhwRWdVQmpQYgpDM3Y5czkxNHh6SjhXYWFtUFZPVGZMRmxzRWFLNnJpMFhjQkhXQi9ob1R1aDVKaDByS1RNWWFMTm9SdU00VCt6Ci9zUG1aY1ZMVXcxdHFmd3U5YlVpSTJCQURQNFM2MUFubk5hSnF1UmFWRk8vT1pqZUkvbHJzMVBSQW9HQkFPem0KVTNvcjNuSDh4WHI2WDNJUjRDM3l3TkZLaHNVVE44VmdWNWRVL0U5RmRHTldUVzRkWHdCK01jeUlQMlFLbjlycwpmcU9Cb0c3NlRKVHF0YzVobjY5Q014c1lVNVdPcDhOZW9oaXplY1luSTFjTk94TmZwdzZDdUZVb1pmTFFxU1dICmJ4dEVEaFkrcXJjR2FLZ3VzMk1uMkJ2cEg1bUhCTk5DL05pSVZ1WTdBb0dBZFlnVEhkOHVuSjBockJCdUpsR1kKN3p2YzRKb2RMV0RYZWpNQ2lQOGp6RXhZc1VNWXgzVnV0aUdtRmtpS2JWSnFSOHdzNVY0MEJJY3VlcHVjWmQyWApsSDZNekNQTjBVNmV4eWxPTmVidlowL2dxUmxWb3BMa0dpTkJwVkkzWjNaeVdYaElhNXJLamJwSWpuSjNVeTFJCnpBQWFLSk5nKzJrZEQwc1FibnlDaURFQ2dZQVFDZVA2OEg5bDdqd2NnRmozNnhmblpIa0RjbTAvYUhhdEtVR2sKNEQ4WXl0WC9aN2RrVGg3QmRNbkFWRFVlZTgyb3o3d2ZLOGFGM1BKVVhyT2lYbCttU1BBVzFJWE1LVlZZVjg3WApwMGNHVUY0SEpjRXJKWjIwME1yVUVTRWQyRnlyU3NrTjZvU2RvdTZCNTdBc09zVXdZR0UwT290R0pLc0I5cFlSCnZ1RkxRd0tCZ1FEZVFuRElPaUQ2SEpmc2loTC8xZ3dnS0hVeVc2WGYrNFhQODd3ZlVXT1N0SEpza29oTkZHdk8KSnpNdUFvc2V2UGFWdElCSXBZbFgycUlaaHlhdyt2VW9BUTZYRnR3WjM1QWo1T1VPbVFQQUJWbkVXZUJZRzdSaQpaZmhEU2NTek5xb3ozWFpjMnA4a2VMWE1XOWJsTDNNOTdOMFRLbExuZ0NrSTdoaXJMVGE2T0E9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=" action = 'delete' # 'apply' or 'delete' 删除的关键在于pod引擎名字 frontend_params = { "kubeconfig": kbc, "cluster_type": "", "host": "192.168.0.3", "port": 22, "user": "root", "password": "Yuanshenhong.1", "action": action, "namespace_name": "4hbm8atruisou2bs24t-n-0", "serviceaccount_name": "4hbm8atruisou2bs24t-n-0-serviceaccount", "podcd_name": "dkxuui1mvir6sf-uzf-ut-statefulset", "service_name": "dkxuui1mvir6sf-uzf-ut-service", "instance_type": "LinuxOS", "clusterid": "4hBm8atruISOU2bs24t_N", "source_name": "kyy-ubuntu", "source_authuser": "root", "source_authpasswd": "kyycloud", "source_podengine": "StatefulSet", "source_replicasetnum": "1", "pod_imagepath": "docker.io/library/ubuntu:22.04", "source_memrate": "512Mi", "source_cpurate": "300m", "source_selflabel": "app:ubuntu", "source_portmode": "NodePort", "source_restartpolicy": "Always", "source_apiport": "2222", "source_insideport": "22", "source_outsideport": "30060", "source_mountpath": "/mnt/data", "source_storagelimits": "100Gi", "source_nodeselector": "kyy-gpu: true", "source_gpu": "1", # 请求1个GPU } handle_k8s_operations(frontend_params)