@@ -66,7 +66,116 @@ def _get_k8s_server_version(self) -> str:
66
66
print (f"获取 Kubernetes 版本信息失败: { e } " )
67
67
# 默认假设为较新版本
68
68
return "1.25"
69
-
69
+ def _infer_kind_from_resource_type (self , resource_type : str ) -> str :
70
+ """
71
+ 根据资源类型(复数形式)推断对应的 Kind(单数形式)。
72
+
73
+ Args:
74
+ resource_type (str): 资源类型的复数形式,如 "pods", "deployments" 等
75
+
76
+ Returns:
77
+ str: 推断出的 Kind
78
+ """
79
+ # 常见的复数到单数的映射
80
+ resource_kind_mapping = {
81
+ # Core API resources
82
+ 'pods' : 'Pod' ,
83
+ 'services' : 'Service' ,
84
+ 'configmaps' : 'ConfigMap' ,
85
+ 'secrets' : 'Secret' ,
86
+ 'serviceaccounts' : 'ServiceAccount' ,
87
+ 'events' : 'Event' ,
88
+ 'nodes' : 'Node' ,
89
+ 'persistentvolumes' : 'PersistentVolume' ,
90
+ 'persistentvolumeclaims' : 'PersistentVolumeClaim' ,
91
+ 'namespaces' : 'Namespace' ,
92
+ 'endpoints' : 'Endpoints' ,
93
+ 'limitranges' : 'LimitRange' ,
94
+ 'resourcequotas' : 'ResourceQuota' ,
95
+ 'replicationcontrollers' : 'ReplicationController' ,
96
+ 'bindings' : 'Binding' ,
97
+ 'componentstatuses' : 'ComponentStatus' ,
98
+
99
+ # Apps API resources
100
+ 'deployments' : 'Deployment' ,
101
+ 'replicasets' : 'ReplicaSet' ,
102
+ 'daemonsets' : 'DaemonSet' ,
103
+ 'statefulsets' : 'StatefulSet' ,
104
+
105
+ # Networking API resources
106
+ 'ingresses' : 'Ingress' ,
107
+ 'networkpolicies' : 'NetworkPolicy' ,
108
+ 'ingressclasses' : 'IngressClass' ,
109
+
110
+ # RBAC API resources
111
+ 'roles' : 'Role' ,
112
+ 'rolebindings' : 'RoleBinding' ,
113
+ 'clusterroles' : 'ClusterRole' ,
114
+ 'clusterrolebindings' : 'ClusterRoleBinding' ,
115
+
116
+ # Batch API resources
117
+ 'jobs' : 'Job' ,
118
+ 'cronjobs' : 'CronJob' ,
119
+
120
+ # Autoscaling API resources
121
+ 'horizontalpodautoscalers' : 'HorizontalPodAutoscaler' ,
122
+
123
+ # Policy API resources
124
+ 'poddisruptionbudgets' : 'PodDisruptionBudget' ,
125
+ 'podsecuritypolicies' : 'PodSecurityPolicy' ,
126
+
127
+ # Storage API resources
128
+ 'storageclasses' : 'StorageClass' ,
129
+ 'volumeattachments' : 'VolumeAttachment' ,
130
+ 'csinodes' : 'CSINode' ,
131
+ 'csidrivers' : 'CSIDriver' ,
132
+ 'csistoragecapacities' : 'CSIStorageCapacity' ,
133
+
134
+ # Node API resources
135
+ 'runtimeclasses' : 'RuntimeClass' ,
136
+
137
+ # API extensions resources
138
+ 'customresourcedefinitions' : 'CustomResourceDefinition' ,
139
+
140
+ # Admission registration resources
141
+ 'mutatingwebhookconfigurations' : 'MutatingWebhookConfiguration' ,
142
+ 'validatingwebhookconfigurations' : 'ValidatingWebhookConfiguration' ,
143
+
144
+ # Certificates API resources
145
+ 'certificatesigningrequests' : 'CertificateSigningRequest' ,
146
+
147
+ # Coordination API resources
148
+ 'leases' : 'Lease' ,
149
+
150
+ # Discovery API resources
151
+ 'endpointslices' : 'EndpointSlice' ,
152
+ }
153
+
154
+ # 先查找直接映射
155
+ if resource_type .lower () in resource_kind_mapping :
156
+ return resource_kind_mapping [resource_type .lower ()]
157
+
158
+ # 如果没有直接映射,尝试通过 dynamic client 发现
159
+ try :
160
+ for api_resource in self ._dynamic_client .resources .search (name = resource_type ):
161
+ return api_resource .kind
162
+ except Exception :
163
+ pass
164
+
165
+ # 如果还是找不到,使用简单的规则转换
166
+ # 去掉末尾的 's',然后首字母大写
167
+ if resource_type .endswith ('s' ) and len (resource_type ) > 1 :
168
+ kind = resource_type [:- 1 ].capitalize ()
169
+ # 处理一些特殊情况
170
+ if kind .endswith ('ie' ):
171
+ kind = kind [:- 2 ] + 'y' # policies -> policy -> Policy
172
+ elif kind .endswith ('sse' ):
173
+ kind = kind [:- 1 ] # classes -> classe -> class -> Class
174
+ return kind
175
+ else :
176
+ # 如果没有找到合适的映射,返回原始资源类型的大写形式
177
+ return resource_type .capitalize ()
178
+
70
179
def _infer_api_version (self , resource_type : str ) -> str :
71
180
"""
72
181
根据资源类型和 Kubernetes 版本推断 API 版本。
@@ -183,7 +292,7 @@ def _infer_api_version(self, resource_type: str) -> str:
183
292
# 对于未知的资源类型,尝试使用 dynamic client 的发现功能
184
293
try :
185
294
# 尝试通过 API 发现找到资源
186
- for api_resource in self ._dynamic_client .resources .search (kind = resource_type ):
295
+ for api_resource in self ._dynamic_client .resources .search (kind = self . _infer_kind_from_resource_type ( resource_type ) ):
187
296
return api_resource .group_version
188
297
# 如果没有找到,抛出错误
189
298
raise ValueError (f"无法推断资源 '{ resource_type } ' 的 API 版本,请明确提供 'api_version' 参数。" )
@@ -305,7 +414,7 @@ def _get_resource(
305
414
if not api_version :
306
415
api_version = self ._infer_api_version (resource_type )
307
416
308
- resource_client = self ._dynamic_client .resources .get (api_version = api_version , kind = resource_type )
417
+ resource_client = self ._dynamic_client .resources .get (api_version = api_version , kind = self . _infer_kind_from_resource_type ( resource_type ) )
309
418
310
419
# 构建查询参数
311
420
params = {
@@ -360,7 +469,7 @@ def get_resource(
360
469
if not api_version :
361
470
api_version = self ._infer_api_version (resource_type )
362
471
363
- resource_client = self ._dynamic_client .resources .get (api_version = api_version , kind = resource_type )
472
+ resource_client = self ._dynamic_client .resources .get (api_version = api_version , kind = self . _infer_kind_from_resource_type ( resource_type ) )
364
473
365
474
# 检查资源是否为命名空间级别
366
475
if resource_client .namespaced and not namespace :
@@ -549,7 +658,7 @@ def list_resource(
549
658
if not api_version :
550
659
api_version = self ._infer_api_version (resource_type )
551
660
552
- resource_client = self ._dynamic_client .resources .get (api_version = api_version , kind = resource_type )
661
+ resource_client = self ._dynamic_client .resources .get (api_version = api_version , kind = self . _infer_kind_from_resource_type ( resource_type ) )
553
662
554
663
# 构建查询参数
555
664
params = {
@@ -670,7 +779,7 @@ def create_resource(
670
779
try :
671
780
# 获取 dynamic client resource
672
781
# 获取 resource 对象
673
- resource = self ._dynamic_client .resources .get (api_version = resolved_api_version , kind = resource_type )
782
+ resource = self ._dynamic_client .resources .get (api_version = resolved_api_version , kind = self . _infer_kind_from_resource_type ( resource_type ) )
674
783
675
784
#resource_client = self._dynamic_client.resources.get(api_version=resolved_api_version, kind=resource_type)
676
785
res = self ._dynamic_client .create (resource , body = resource_body , namespace = namespace )
@@ -743,7 +852,7 @@ def find_resource_api_version(self, resource_type: str) -> Optional[str]:
743
852
"""
744
853
try :
745
854
# 搜索匹配的资源
746
- for api_resource in self ._dynamic_client .resources .search (kind = resource_type ):
855
+ for api_resource in self ._dynamic_client .resources .search (kind = self . _infer_kind_from_resource_type ( resource_type ) ):
747
856
return api_resource .group_version
748
857
return None
749
858
except Exception as e :
@@ -763,7 +872,7 @@ def validate_resource_and_api_version(self, resource_type: str, api_version: str
763
872
"""
764
873
try :
765
874
# 尝试获取资源客户端
766
- self ._dynamic_client .resources .get (api_version = api_version , kind = resource_type )
875
+ self ._dynamic_client .resources .get (api_version = api_version , kind = self . _infer_kind_from_resource_type ( resource_type ) )
767
876
return True
768
877
except Exception :
769
878
return False
@@ -783,7 +892,7 @@ def get_resource_info(self, resource_type: str, api_version: Optional[str] = Non
783
892
if not api_version :
784
893
api_version = self ._infer_api_version (resource_type )
785
894
786
- resource_client = self ._dynamic_client .resources .get (api_version = api_version , kind = resource_type )
895
+ resource_client = self ._dynamic_client .resources .get (api_version = api_version , kind = self . _infer_kind_from_resource_type ( resource_type ) )
787
896
788
897
return {
789
898
"name" : resource_client .name ,
@@ -831,7 +940,7 @@ def delete_resource(
831
940
if not api_version :
832
941
api_version = self ._infer_api_version (resource_type )
833
942
834
- resource_client = self ._dynamic_client .resources .get (api_version = api_version , kind = resource_type )
943
+ resource_client = self ._dynamic_client .resources .get (api_version = api_version , kind = self . _infer_kind_from_resource_type ( resource_type ) )
835
944
836
945
# 检查资源是否为命名空间级别
837
946
if resource_client .namespaced and not namespace :
@@ -987,7 +1096,7 @@ def update_resource(
987
1096
try :
988
1097
# 获取 dynamic client resource
989
1098
# 获取 resource 对象
990
- resource = self ._dynamic_client .resources .get (api_version = resolved_api_version , kind = resource_type )
1099
+ resource = self ._dynamic_client .resources .get (api_version = resolved_api_version , kind = self . _infer_kind_from_resource_type ( resource_type ) )
991
1100
992
1101
#resource_client = self._dynamic_client.resources.get(api_version=resolved_api_version, kind=resource_type)
993
1102
res = self ._dynamic_client .replace (resource , body = resource_body , namespace = namespace )
0 commit comments