kubectl-mcp-server 1.12.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kubectl_mcp_server-1.12.0.dist-info/METADATA +711 -0
- kubectl_mcp_server-1.12.0.dist-info/RECORD +45 -0
- kubectl_mcp_server-1.12.0.dist-info/WHEEL +5 -0
- kubectl_mcp_server-1.12.0.dist-info/entry_points.txt +3 -0
- kubectl_mcp_server-1.12.0.dist-info/licenses/LICENSE +21 -0
- kubectl_mcp_server-1.12.0.dist-info/top_level.txt +2 -0
- kubectl_mcp_tool/__init__.py +21 -0
- kubectl_mcp_tool/__main__.py +46 -0
- kubectl_mcp_tool/auth/__init__.py +13 -0
- kubectl_mcp_tool/auth/config.py +71 -0
- kubectl_mcp_tool/auth/scopes.py +148 -0
- kubectl_mcp_tool/auth/verifier.py +82 -0
- kubectl_mcp_tool/cli/__init__.py +9 -0
- kubectl_mcp_tool/cli/__main__.py +10 -0
- kubectl_mcp_tool/cli/cli.py +111 -0
- kubectl_mcp_tool/diagnostics.py +355 -0
- kubectl_mcp_tool/k8s_config.py +289 -0
- kubectl_mcp_tool/mcp_server.py +530 -0
- kubectl_mcp_tool/prompts/__init__.py +5 -0
- kubectl_mcp_tool/prompts/prompts.py +823 -0
- kubectl_mcp_tool/resources/__init__.py +5 -0
- kubectl_mcp_tool/resources/resources.py +305 -0
- kubectl_mcp_tool/tools/__init__.py +28 -0
- kubectl_mcp_tool/tools/browser.py +371 -0
- kubectl_mcp_tool/tools/cluster.py +315 -0
- kubectl_mcp_tool/tools/core.py +421 -0
- kubectl_mcp_tool/tools/cost.py +680 -0
- kubectl_mcp_tool/tools/deployments.py +381 -0
- kubectl_mcp_tool/tools/diagnostics.py +174 -0
- kubectl_mcp_tool/tools/helm.py +1561 -0
- kubectl_mcp_tool/tools/networking.py +296 -0
- kubectl_mcp_tool/tools/operations.py +501 -0
- kubectl_mcp_tool/tools/pods.py +582 -0
- kubectl_mcp_tool/tools/security.py +333 -0
- kubectl_mcp_tool/tools/storage.py +133 -0
- kubectl_mcp_tool/utils/__init__.py +17 -0
- kubectl_mcp_tool/utils/helpers.py +80 -0
- tests/__init__.py +9 -0
- tests/conftest.py +379 -0
- tests/test_auth.py +256 -0
- tests/test_browser.py +349 -0
- tests/test_prompts.py +536 -0
- tests/test_resources.py +343 -0
- tests/test_server.py +384 -0
- tests/test_tools.py +659 -0
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Kubernetes diagnostics and monitoring module for kubectl-mcp-tool.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Dict, List, Any, Optional
|
|
9
|
+
import subprocess
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
class KubernetesDiagnostics:
|
|
14
|
+
"""Kubernetes diagnostics and monitoring tools."""
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def run_command(cmd: List[str]) -> str:
|
|
18
|
+
"""Run a kubectl command and return the output."""
|
|
19
|
+
try:
|
|
20
|
+
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
|
21
|
+
return result.stdout.strip()
|
|
22
|
+
except subprocess.CalledProcessError as e:
|
|
23
|
+
logger.error(f"Command failed: {' '.join(cmd)}")
|
|
24
|
+
logger.error(f"Error output: {e.stderr}")
|
|
25
|
+
return f"Error: {e.stderr}"
|
|
26
|
+
|
|
27
|
+
def get_logs(self, pod_name: str, namespace: Optional[str] = None,
|
|
28
|
+
container: Optional[str] = None, tail: Optional[int] = None,
|
|
29
|
+
previous: bool = False) -> Dict[str, Any]:
|
|
30
|
+
"""Get logs from a pod."""
|
|
31
|
+
cmd = ["kubectl", "logs"]
|
|
32
|
+
|
|
33
|
+
if namespace:
|
|
34
|
+
cmd.extend(["-n", namespace])
|
|
35
|
+
|
|
36
|
+
if container:
|
|
37
|
+
cmd.extend(["-c", container])
|
|
38
|
+
|
|
39
|
+
if tail:
|
|
40
|
+
cmd.extend(["--tail", str(tail)])
|
|
41
|
+
|
|
42
|
+
if previous:
|
|
43
|
+
cmd.append("-p")
|
|
44
|
+
|
|
45
|
+
cmd.append(pod_name)
|
|
46
|
+
|
|
47
|
+
logs = self.run_command(cmd)
|
|
48
|
+
return {
|
|
49
|
+
"pod_name": pod_name,
|
|
50
|
+
"namespace": namespace or "default",
|
|
51
|
+
"container": container,
|
|
52
|
+
"logs": logs
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
def get_events(self, namespace: Optional[str] = None,
|
|
56
|
+
resource_name: Optional[str] = None) -> Dict[str, Any]:
|
|
57
|
+
"""Get Kubernetes events."""
|
|
58
|
+
cmd = ["kubectl", "get", "events"]
|
|
59
|
+
|
|
60
|
+
if namespace:
|
|
61
|
+
cmd.extend(["-n", namespace])
|
|
62
|
+
|
|
63
|
+
if resource_name:
|
|
64
|
+
cmd.extend([f"--field-selector=involvedObject.name={resource_name}"])
|
|
65
|
+
|
|
66
|
+
cmd.extend(["--sort-by=.metadata.creationTimestamp"])
|
|
67
|
+
|
|
68
|
+
events = self.run_command(cmd)
|
|
69
|
+
return {
|
|
70
|
+
"namespace": namespace or "default",
|
|
71
|
+
"resource_name": resource_name,
|
|
72
|
+
"events": events
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
def check_pod_health(self, pod_name: str, namespace: str = "default") -> Dict[str, Any]:
|
|
76
|
+
"""Check pod health and detect common issues."""
|
|
77
|
+
# Get pod details
|
|
78
|
+
cmd = ["kubectl", "get", "pod", pod_name, "-n", namespace, "-o", "json"]
|
|
79
|
+
pod_json_str = self.run_command(cmd)
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
pod_json = json.loads(pod_json_str)
|
|
83
|
+
except json.JSONDecodeError:
|
|
84
|
+
return {"error": "Failed to get pod details", "raw_output": pod_json_str}
|
|
85
|
+
|
|
86
|
+
issues = []
|
|
87
|
+
|
|
88
|
+
# Check pod status
|
|
89
|
+
status = pod_json.get("status", {})
|
|
90
|
+
phase = status.get("phase")
|
|
91
|
+
if phase != "Running":
|
|
92
|
+
issues.append(f"Pod is not running (Status: {phase})")
|
|
93
|
+
|
|
94
|
+
# Check container statuses
|
|
95
|
+
for container in status.get("containerStatuses", []):
|
|
96
|
+
if not container.get("ready"):
|
|
97
|
+
waiting = container.get("state", {}).get("waiting", {})
|
|
98
|
+
if waiting:
|
|
99
|
+
issues.append(
|
|
100
|
+
f"Container {container['name']} is waiting: "
|
|
101
|
+
f"{waiting.get('reason')} - {waiting.get('message')}"
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# Get recent events
|
|
105
|
+
events = self.get_events(namespace, pod_name)
|
|
106
|
+
|
|
107
|
+
# Check resource usage
|
|
108
|
+
usage = self.get_resource_usage("pods", namespace, pod_name)
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
"pod_name": pod_name,
|
|
112
|
+
"namespace": namespace,
|
|
113
|
+
"status": phase,
|
|
114
|
+
"issues": issues,
|
|
115
|
+
"events": events.get("events"),
|
|
116
|
+
"resource_usage": usage.get("usage")
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
def get_resource_usage(self, resource_type: str = "pods",
|
|
120
|
+
namespace: Optional[str] = None,
|
|
121
|
+
resource_name: Optional[str] = None) -> Dict[str, Any]:
|
|
122
|
+
"""Get resource usage statistics."""
|
|
123
|
+
cmd = ["kubectl", "top", resource_type]
|
|
124
|
+
|
|
125
|
+
if namespace:
|
|
126
|
+
cmd.extend(["-n", namespace])
|
|
127
|
+
|
|
128
|
+
if resource_name:
|
|
129
|
+
cmd.append(resource_name)
|
|
130
|
+
|
|
131
|
+
usage = self.run_command(cmd)
|
|
132
|
+
return {
|
|
133
|
+
"resource_type": resource_type,
|
|
134
|
+
"namespace": namespace,
|
|
135
|
+
"resource_name": resource_name,
|
|
136
|
+
"usage": usage
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
def validate_resources(self, namespace: str = "default") -> Dict[str, Any]:
|
|
140
|
+
"""Validate Kubernetes resources for common misconfigurations."""
|
|
141
|
+
validations = []
|
|
142
|
+
|
|
143
|
+
# Get all pods
|
|
144
|
+
cmd = ["kubectl", "get", "pods", "-n", namespace, "-o", "json"]
|
|
145
|
+
pods_json_str = self.run_command(cmd)
|
|
146
|
+
|
|
147
|
+
try:
|
|
148
|
+
pods = json.loads(pods_json_str)
|
|
149
|
+
except json.JSONDecodeError:
|
|
150
|
+
return {"error": "Failed to get pods", "raw_output": pods_json_str}
|
|
151
|
+
|
|
152
|
+
for pod in pods.get("items", []):
|
|
153
|
+
pod_name = pod["metadata"]["name"]
|
|
154
|
+
|
|
155
|
+
# Check resource limits
|
|
156
|
+
for container in pod["spec"]["containers"]:
|
|
157
|
+
if not container.get("resources", {}).get("limits"):
|
|
158
|
+
validations.append({
|
|
159
|
+
"level": "warning",
|
|
160
|
+
"type": "no_resource_limits",
|
|
161
|
+
"message": f"Container {container['name']} in pod {pod_name} has no resource limits"
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
# Check probes
|
|
165
|
+
if not container.get("livenessProbe"):
|
|
166
|
+
validations.append({
|
|
167
|
+
"level": "warning",
|
|
168
|
+
"type": "no_liveness_probe",
|
|
169
|
+
"message": f"Container {container['name']} in pod {pod_name} has no liveness probe"
|
|
170
|
+
})
|
|
171
|
+
if not container.get("readinessProbe"):
|
|
172
|
+
validations.append({
|
|
173
|
+
"level": "warning",
|
|
174
|
+
"type": "no_readiness_probe",
|
|
175
|
+
"message": f"Container {container['name']} in pod {pod_name} has no readiness probe"
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
"namespace": namespace,
|
|
180
|
+
"validations": validations,
|
|
181
|
+
"summary": {
|
|
182
|
+
"total_validations": len(validations),
|
|
183
|
+
"warnings": len([v for v in validations if v["level"] == "warning"]),
|
|
184
|
+
"errors": len([v for v in validations if v["level"] == "error"])
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
def analyze_pod_logs(self, pod_name: str, namespace: str = "default",
|
|
189
|
+
container: Optional[str] = None, tail: int = 1000) -> Dict[str, Any]:
|
|
190
|
+
"""Analyze pod logs for common issues and patterns."""
|
|
191
|
+
# Get logs
|
|
192
|
+
logs_data = self.get_logs(pod_name, namespace, container, tail)
|
|
193
|
+
logs = logs_data.get("logs", "")
|
|
194
|
+
|
|
195
|
+
analysis = {
|
|
196
|
+
"error_count": 0,
|
|
197
|
+
"warning_count": 0,
|
|
198
|
+
"errors": [],
|
|
199
|
+
"warnings": [],
|
|
200
|
+
"patterns": {}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
# Common error patterns to look for
|
|
204
|
+
error_patterns = [
|
|
205
|
+
"error", "exception", "failed", "failure", "fatal",
|
|
206
|
+
"OOMKilled", "CrashLoopBackOff"
|
|
207
|
+
]
|
|
208
|
+
|
|
209
|
+
warning_patterns = [
|
|
210
|
+
"warning", "warn", "deprecated"
|
|
211
|
+
]
|
|
212
|
+
|
|
213
|
+
# Analyze logs
|
|
214
|
+
for line in logs.split("\n"):
|
|
215
|
+
line_lower = line.lower()
|
|
216
|
+
|
|
217
|
+
# Check for errors
|
|
218
|
+
for pattern in error_patterns:
|
|
219
|
+
if pattern in line_lower:
|
|
220
|
+
analysis["error_count"] += 1
|
|
221
|
+
analysis["errors"].append(line)
|
|
222
|
+
break
|
|
223
|
+
|
|
224
|
+
# Check for warnings
|
|
225
|
+
for pattern in warning_patterns:
|
|
226
|
+
if pattern in line_lower:
|
|
227
|
+
analysis["warning_count"] += 1
|
|
228
|
+
analysis["warnings"].append(line)
|
|
229
|
+
break
|
|
230
|
+
|
|
231
|
+
return {
|
|
232
|
+
"pod_name": pod_name,
|
|
233
|
+
"namespace": namespace,
|
|
234
|
+
"container": container,
|
|
235
|
+
"analysis": analysis
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
# Convenience functions for direct import
|
|
240
|
+
_diagnostics = KubernetesDiagnostics()
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def check_kubectl_installation() -> Dict[str, Any]:
|
|
244
|
+
"""Check if kubectl is installed and accessible."""
|
|
245
|
+
try:
|
|
246
|
+
import shutil
|
|
247
|
+
kubectl_path = shutil.which("kubectl")
|
|
248
|
+
if not kubectl_path:
|
|
249
|
+
return {
|
|
250
|
+
"installed": False,
|
|
251
|
+
"error": "kubectl not found in PATH"
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
import subprocess
|
|
255
|
+
result = subprocess.run(
|
|
256
|
+
["kubectl", "version", "--client", "-o", "json"],
|
|
257
|
+
capture_output=True,
|
|
258
|
+
text=True,
|
|
259
|
+
timeout=10
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
if result.returncode != 0:
|
|
263
|
+
return {
|
|
264
|
+
"installed": True,
|
|
265
|
+
"path": kubectl_path,
|
|
266
|
+
"error": result.stderr
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
import json
|
|
270
|
+
version_info = json.loads(result.stdout)
|
|
271
|
+
return {
|
|
272
|
+
"installed": True,
|
|
273
|
+
"path": kubectl_path,
|
|
274
|
+
"version": version_info.get("clientVersion", {})
|
|
275
|
+
}
|
|
276
|
+
except Exception as e:
|
|
277
|
+
return {
|
|
278
|
+
"installed": False,
|
|
279
|
+
"error": str(e)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def check_cluster_connection() -> Dict[str, Any]:
|
|
284
|
+
"""Check if we can connect to a Kubernetes cluster."""
|
|
285
|
+
try:
|
|
286
|
+
import subprocess
|
|
287
|
+
result = subprocess.run(
|
|
288
|
+
["kubectl", "cluster-info"],
|
|
289
|
+
capture_output=True,
|
|
290
|
+
text=True,
|
|
291
|
+
timeout=10
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
if result.returncode != 0:
|
|
295
|
+
return {
|
|
296
|
+
"connected": False,
|
|
297
|
+
"error": result.stderr
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return {
|
|
301
|
+
"connected": True,
|
|
302
|
+
"cluster_info": result.stdout.strip()
|
|
303
|
+
}
|
|
304
|
+
except Exception as e:
|
|
305
|
+
return {
|
|
306
|
+
"connected": False,
|
|
307
|
+
"error": str(e)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def run_diagnostics() -> Dict[str, Any]:
|
|
312
|
+
"""Run comprehensive diagnostics."""
|
|
313
|
+
kubectl_check = check_kubectl_installation()
|
|
314
|
+
cluster_check = check_cluster_connection()
|
|
315
|
+
|
|
316
|
+
diagnostics = {
|
|
317
|
+
"kubectl": kubectl_check,
|
|
318
|
+
"cluster": cluster_check,
|
|
319
|
+
"overall_status": "healthy" if (
|
|
320
|
+
kubectl_check.get("installed") and
|
|
321
|
+
cluster_check.get("connected")
|
|
322
|
+
) else "unhealthy"
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if diagnostics["overall_status"] == "healthy":
|
|
326
|
+
# Additional checks
|
|
327
|
+
try:
|
|
328
|
+
import subprocess
|
|
329
|
+
|
|
330
|
+
# Check nodes
|
|
331
|
+
nodes_result = subprocess.run(
|
|
332
|
+
["kubectl", "get", "nodes", "-o", "json"],
|
|
333
|
+
capture_output=True,
|
|
334
|
+
text=True,
|
|
335
|
+
timeout=10
|
|
336
|
+
)
|
|
337
|
+
if nodes_result.returncode == 0:
|
|
338
|
+
import json
|
|
339
|
+
nodes_data = json.loads(nodes_result.stdout)
|
|
340
|
+
nodes_count = len(nodes_data.get("items", []))
|
|
341
|
+
ready_nodes = sum(
|
|
342
|
+
1 for node in nodes_data.get("items", [])
|
|
343
|
+
if any(
|
|
344
|
+
c.get("type") == "Ready" and c.get("status") == "True"
|
|
345
|
+
for c in node.get("status", {}).get("conditions", [])
|
|
346
|
+
)
|
|
347
|
+
)
|
|
348
|
+
diagnostics["nodes"] = {
|
|
349
|
+
"total": nodes_count,
|
|
350
|
+
"ready": ready_nodes
|
|
351
|
+
}
|
|
352
|
+
except Exception as e:
|
|
353
|
+
diagnostics["nodes_error"] = str(e)
|
|
354
|
+
|
|
355
|
+
return diagnostics
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Kubernetes configuration loader utility.
|
|
3
|
+
|
|
4
|
+
Handles both in-cluster and out-of-cluster (kubeconfig) configurations.
|
|
5
|
+
|
|
6
|
+
This module patches the kubernetes.config.load_kube_config function to
|
|
7
|
+
automatically try in-cluster config first when running inside a pod.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import logging
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger("mcp-server")
|
|
14
|
+
|
|
15
|
+
_config_loaded = False
|
|
16
|
+
_original_load_kube_config = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def load_kubernetes_config():
|
|
20
|
+
"""Load Kubernetes configuration.
|
|
21
|
+
|
|
22
|
+
Tries in-cluster config first (when running inside a pod),
|
|
23
|
+
then falls back to kubeconfig file.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
bool: True if config loaded successfully, False otherwise
|
|
27
|
+
"""
|
|
28
|
+
global _config_loaded
|
|
29
|
+
|
|
30
|
+
if _config_loaded:
|
|
31
|
+
return True
|
|
32
|
+
|
|
33
|
+
from kubernetes import config
|
|
34
|
+
from kubernetes.config.config_exception import ConfigException
|
|
35
|
+
|
|
36
|
+
# Try in-cluster config first (for pods running in Kubernetes)
|
|
37
|
+
try:
|
|
38
|
+
config.load_incluster_config()
|
|
39
|
+
logger.info("Loaded in-cluster Kubernetes configuration")
|
|
40
|
+
_config_loaded = True
|
|
41
|
+
return True
|
|
42
|
+
except ConfigException:
|
|
43
|
+
logger.debug("Not running in-cluster, trying kubeconfig...")
|
|
44
|
+
|
|
45
|
+
# Fall back to kubeconfig file
|
|
46
|
+
try:
|
|
47
|
+
kubeconfig_path = os.environ.get('KUBECONFIG', '~/.kube/config')
|
|
48
|
+
kubeconfig_path = os.path.expanduser(kubeconfig_path)
|
|
49
|
+
config.load_kube_config(config_file=kubeconfig_path)
|
|
50
|
+
logger.info(f"Loaded kubeconfig from {kubeconfig_path}")
|
|
51
|
+
_config_loaded = True
|
|
52
|
+
return True
|
|
53
|
+
except ConfigException as e:
|
|
54
|
+
logger.error(f"Failed to load Kubernetes config: {e}")
|
|
55
|
+
return False
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _patched_load_kube_config(*args, **kwargs):
|
|
59
|
+
"""Patched version of load_kube_config that tries in-cluster first."""
|
|
60
|
+
global _config_loaded, _original_load_kube_config
|
|
61
|
+
|
|
62
|
+
if _config_loaded:
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
from kubernetes.config.config_exception import ConfigException
|
|
66
|
+
|
|
67
|
+
# Try in-cluster config first
|
|
68
|
+
try:
|
|
69
|
+
from kubernetes import config
|
|
70
|
+
config.load_incluster_config()
|
|
71
|
+
logger.info("Loaded in-cluster Kubernetes configuration")
|
|
72
|
+
_config_loaded = True
|
|
73
|
+
return
|
|
74
|
+
except ConfigException:
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
# Fall back to original behavior
|
|
78
|
+
if _original_load_kube_config:
|
|
79
|
+
_original_load_kube_config(*args, **kwargs)
|
|
80
|
+
_config_loaded = True
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def patch_kubernetes_config():
|
|
84
|
+
"""Patch the kubernetes config module to support in-cluster config.
|
|
85
|
+
|
|
86
|
+
This should be called early in the application startup.
|
|
87
|
+
"""
|
|
88
|
+
global _original_load_kube_config
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
from kubernetes import config
|
|
92
|
+
|
|
93
|
+
if _original_load_kube_config is None:
|
|
94
|
+
_original_load_kube_config = config.load_kube_config
|
|
95
|
+
config.load_kube_config = _patched_load_kube_config
|
|
96
|
+
logger.debug("Patched kubernetes.config.load_kube_config for in-cluster support")
|
|
97
|
+
except ImportError:
|
|
98
|
+
logger.debug("kubernetes package not available for patching")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
# Auto-patch when this module is imported
|
|
102
|
+
patch_kubernetes_config()
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def get_k8s_client():
|
|
106
|
+
"""Get a configured Kubernetes API client.
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
kubernetes.client.CoreV1Api: Configured Kubernetes client
|
|
110
|
+
|
|
111
|
+
Raises:
|
|
112
|
+
RuntimeError: If Kubernetes config cannot be loaded
|
|
113
|
+
"""
|
|
114
|
+
from kubernetes import client
|
|
115
|
+
|
|
116
|
+
if not load_kubernetes_config():
|
|
117
|
+
raise RuntimeError("Invalid kube-config file. No configuration found.")
|
|
118
|
+
|
|
119
|
+
return client.CoreV1Api()
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def get_apps_client():
|
|
123
|
+
"""Get a configured Kubernetes Apps API client.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
kubernetes.client.AppsV1Api: Configured Apps API client
|
|
127
|
+
|
|
128
|
+
Raises:
|
|
129
|
+
RuntimeError: If Kubernetes config cannot be loaded
|
|
130
|
+
"""
|
|
131
|
+
from kubernetes import client
|
|
132
|
+
|
|
133
|
+
if not load_kubernetes_config():
|
|
134
|
+
raise RuntimeError("Invalid kube-config file. No configuration found.")
|
|
135
|
+
|
|
136
|
+
return client.AppsV1Api()
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def get_rbac_client():
|
|
140
|
+
"""Get a configured Kubernetes RBAC API client.
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
kubernetes.client.RbacAuthorizationV1Api: Configured RBAC client
|
|
144
|
+
|
|
145
|
+
Raises:
|
|
146
|
+
RuntimeError: If Kubernetes config cannot be loaded
|
|
147
|
+
"""
|
|
148
|
+
from kubernetes import client
|
|
149
|
+
|
|
150
|
+
if not load_kubernetes_config():
|
|
151
|
+
raise RuntimeError("Invalid kube-config file. No configuration found.")
|
|
152
|
+
|
|
153
|
+
return client.RbacAuthorizationV1Api()
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def get_networking_client():
|
|
157
|
+
"""Get a configured Kubernetes Networking API client.
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
kubernetes.client.NetworkingV1Api: Configured Networking client
|
|
161
|
+
|
|
162
|
+
Raises:
|
|
163
|
+
RuntimeError: If Kubernetes config cannot be loaded
|
|
164
|
+
"""
|
|
165
|
+
from kubernetes import client
|
|
166
|
+
|
|
167
|
+
if not load_kubernetes_config():
|
|
168
|
+
raise RuntimeError("Invalid kube-config file. No configuration found.")
|
|
169
|
+
|
|
170
|
+
return client.NetworkingV1Api()
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def get_storage_client():
|
|
174
|
+
"""Get a configured Kubernetes Storage API client.
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
kubernetes.client.StorageV1Api: Configured Storage client
|
|
178
|
+
|
|
179
|
+
Raises:
|
|
180
|
+
RuntimeError: If Kubernetes config cannot be loaded
|
|
181
|
+
"""
|
|
182
|
+
from kubernetes import client
|
|
183
|
+
|
|
184
|
+
if not load_kubernetes_config():
|
|
185
|
+
raise RuntimeError("Invalid kube-config file. No configuration found.")
|
|
186
|
+
|
|
187
|
+
return client.StorageV1Api()
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def get_batch_client():
|
|
191
|
+
"""Get a configured Kubernetes Batch API client.
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
kubernetes.client.BatchV1Api: Configured Batch client
|
|
195
|
+
|
|
196
|
+
Raises:
|
|
197
|
+
RuntimeError: If Kubernetes config cannot be loaded
|
|
198
|
+
"""
|
|
199
|
+
from kubernetes import client
|
|
200
|
+
|
|
201
|
+
if not load_kubernetes_config():
|
|
202
|
+
raise RuntimeError("Invalid kube-config file. No configuration found.")
|
|
203
|
+
|
|
204
|
+
return client.BatchV1Api()
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def get_autoscaling_client():
|
|
208
|
+
"""Get a configured Kubernetes Autoscaling API client.
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
kubernetes.client.AutoscalingV1Api: Configured Autoscaling client
|
|
212
|
+
|
|
213
|
+
Raises:
|
|
214
|
+
RuntimeError: If Kubernetes config cannot be loaded
|
|
215
|
+
"""
|
|
216
|
+
from kubernetes import client
|
|
217
|
+
|
|
218
|
+
if not load_kubernetes_config():
|
|
219
|
+
raise RuntimeError("Invalid kube-config file. No configuration found.")
|
|
220
|
+
|
|
221
|
+
return client.AutoscalingV1Api()
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def get_policy_client():
|
|
225
|
+
"""Get a configured Kubernetes Policy API client.
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
kubernetes.client.PolicyV1Api: Configured Policy client
|
|
229
|
+
|
|
230
|
+
Raises:
|
|
231
|
+
RuntimeError: If Kubernetes config cannot be loaded
|
|
232
|
+
"""
|
|
233
|
+
from kubernetes import client
|
|
234
|
+
|
|
235
|
+
if not load_kubernetes_config():
|
|
236
|
+
raise RuntimeError("Invalid kube-config file. No configuration found.")
|
|
237
|
+
|
|
238
|
+
return client.PolicyV1Api()
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def get_custom_objects_client():
|
|
242
|
+
"""Get a configured Kubernetes Custom Objects API client.
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
kubernetes.client.CustomObjectsApi: Configured Custom Objects client
|
|
246
|
+
|
|
247
|
+
Raises:
|
|
248
|
+
RuntimeError: If Kubernetes config cannot be loaded
|
|
249
|
+
"""
|
|
250
|
+
from kubernetes import client
|
|
251
|
+
|
|
252
|
+
if not load_kubernetes_config():
|
|
253
|
+
raise RuntimeError("Invalid kube-config file. No configuration found.")
|
|
254
|
+
|
|
255
|
+
return client.CustomObjectsApi()
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def get_version_client():
|
|
259
|
+
"""Get a configured Kubernetes Version API client.
|
|
260
|
+
|
|
261
|
+
Returns:
|
|
262
|
+
kubernetes.client.VersionApi: Configured Version client
|
|
263
|
+
|
|
264
|
+
Raises:
|
|
265
|
+
RuntimeError: If Kubernetes config cannot be loaded
|
|
266
|
+
"""
|
|
267
|
+
from kubernetes import client
|
|
268
|
+
|
|
269
|
+
if not load_kubernetes_config():
|
|
270
|
+
raise RuntimeError("Invalid kube-config file. No configuration found.")
|
|
271
|
+
|
|
272
|
+
return client.VersionApi()
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def get_admissionregistration_client():
|
|
276
|
+
"""Get a configured Kubernetes Admission Registration API client.
|
|
277
|
+
|
|
278
|
+
Returns:
|
|
279
|
+
kubernetes.client.AdmissionregistrationV1Api: Configured Admission client
|
|
280
|
+
|
|
281
|
+
Raises:
|
|
282
|
+
RuntimeError: If Kubernetes config cannot be loaded
|
|
283
|
+
"""
|
|
284
|
+
from kubernetes import client
|
|
285
|
+
|
|
286
|
+
if not load_kubernetes_config():
|
|
287
|
+
raise RuntimeError("Invalid kube-config file. No configuration found.")
|
|
288
|
+
|
|
289
|
+
return client.AdmissionregistrationV1Api()
|