k8s-aiops 0.1.0__tar.gz

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.
Files changed (48) hide show
  1. k8s_aiops-0.1.0/.gitignore +22 -0
  2. k8s_aiops-0.1.0/LICENSE +21 -0
  3. k8s_aiops-0.1.0/PKG-INFO +99 -0
  4. k8s_aiops-0.1.0/README.md +84 -0
  5. k8s_aiops-0.1.0/SECURITY.md +78 -0
  6. k8s_aiops-0.1.0/k8s_aiops/__init__.py +10 -0
  7. k8s_aiops-0.1.0/k8s_aiops/cli/__init__.py +9 -0
  8. k8s_aiops-0.1.0/k8s_aiops/cli/_common.py +81 -0
  9. k8s_aiops-0.1.0/k8s_aiops/cli/_root.py +78 -0
  10. k8s_aiops-0.1.0/k8s_aiops/cli/deployment.py +95 -0
  11. k8s_aiops-0.1.0/k8s_aiops/cli/doctor.py +21 -0
  12. k8s_aiops-0.1.0/k8s_aiops/cli/namespace.py +27 -0
  13. k8s_aiops-0.1.0/k8s_aiops/cli/node.py +61 -0
  14. k8s_aiops-0.1.0/k8s_aiops/cli/pod.py +80 -0
  15. k8s_aiops-0.1.0/k8s_aiops/cli/service.py +32 -0
  16. k8s_aiops-0.1.0/k8s_aiops/config.py +113 -0
  17. k8s_aiops-0.1.0/k8s_aiops/connection.py +169 -0
  18. k8s_aiops-0.1.0/k8s_aiops/doctor.py +54 -0
  19. k8s_aiops-0.1.0/k8s_aiops/governance/__init__.py +40 -0
  20. k8s_aiops-0.1.0/k8s_aiops/governance/audit.py +377 -0
  21. k8s_aiops-0.1.0/k8s_aiops/governance/budget.py +225 -0
  22. k8s_aiops-0.1.0/k8s_aiops/governance/decorators.py +474 -0
  23. k8s_aiops-0.1.0/k8s_aiops/governance/paths.py +23 -0
  24. k8s_aiops-0.1.0/k8s_aiops/governance/patterns.py +378 -0
  25. k8s_aiops-0.1.0/k8s_aiops/governance/policy.py +411 -0
  26. k8s_aiops-0.1.0/k8s_aiops/governance/sanitize.py +39 -0
  27. k8s_aiops-0.1.0/k8s_aiops/governance/undo.py +218 -0
  28. k8s_aiops-0.1.0/k8s_aiops/ops/__init__.py +1 -0
  29. k8s_aiops-0.1.0/k8s_aiops/ops/_shared.py +48 -0
  30. k8s_aiops-0.1.0/k8s_aiops/ops/lifecycle.py +128 -0
  31. k8s_aiops-0.1.0/k8s_aiops/ops/namespaces.py +26 -0
  32. k8s_aiops-0.1.0/k8s_aiops/ops/nodes.py +49 -0
  33. k8s_aiops-0.1.0/k8s_aiops/ops/workloads.py +185 -0
  34. k8s_aiops-0.1.0/mcp_server/__init__.py +1 -0
  35. k8s_aiops-0.1.0/mcp_server/_shared.py +98 -0
  36. k8s_aiops-0.1.0/mcp_server/server.py +33 -0
  37. k8s_aiops-0.1.0/mcp_server/tools/__init__.py +1 -0
  38. k8s_aiops-0.1.0/mcp_server/tools/lifecycle.py +99 -0
  39. k8s_aiops-0.1.0/mcp_server/tools/namespaces.py +19 -0
  40. k8s_aiops-0.1.0/mcp_server/tools/nodes.py +66 -0
  41. k8s_aiops-0.1.0/mcp_server/tools/workloads.py +134 -0
  42. k8s_aiops-0.1.0/pyproject.toml +58 -0
  43. k8s_aiops-0.1.0/server.json +21 -0
  44. k8s_aiops-0.1.0/skills/k8s-aiops/SKILL.md +164 -0
  45. k8s_aiops-0.1.0/skills/k8s-aiops/references/capabilities.md +46 -0
  46. k8s_aiops-0.1.0/skills/k8s-aiops/references/cli-reference.md +63 -0
  47. k8s_aiops-0.1.0/skills/k8s-aiops/references/setup-guide.md +102 -0
  48. k8s_aiops-0.1.0/tests/test_smoke.py +243 -0
@@ -0,0 +1,22 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+
8
+ # Virtual envs / build
9
+ .venv/
10
+ dist/
11
+ build/
12
+
13
+ # uv
14
+ uv.lock
15
+
16
+ # Local config / secrets (never commit)
17
+ *.env
18
+ .env
19
+ config.yaml
20
+
21
+ # OS
22
+ .DS_Store
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wei <zhouwei008@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,99 @@
1
+ Metadata-Version: 2.4
2
+ Name: k8s-aiops
3
+ Version: 0.1.0
4
+ Summary: Governed Kubernetes operations for AI agents with a built-in governance harness (audit, budget, undo, risk tiers)
5
+ Author-email: wei <zhouwei008@gmail.com>
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Requires-Python: >=3.11
9
+ Requires-Dist: kubernetes<32,>=29
10
+ Requires-Dist: mcp[cli]<2.0,>=1.10
11
+ Requires-Dist: pyyaml<7.0,>=6.0
12
+ Requires-Dist: rich<16.0,>=13.0
13
+ Requires-Dist: typer<1.0,>=0.12
14
+ Description-Content-Type: text/markdown
15
+
16
+ <!-- mcp-name: io.github.AIops-tools/k8s-aiops -->
17
+ # k8s-aiops (preview)
18
+
19
+ > **Disclaimer**: This is a community-maintained open-source project and is **not
20
+ > affiliated with, endorsed by, or sponsored by the Cloud Native Computing
21
+ > Foundation, the Kubernetes project, or k3s/Rancher.** "Kubernetes" and "k3s" are
22
+ > trademarks of their respective owners. Source code is publicly auditable at
23
+ > [github.com/AIops-tools/K8s-AIops](https://github.com/AIops-tools/K8s-AIops) under
24
+ > the MIT license.
25
+
26
+ Governed Kubernetes operations for AI agents — **15 MCP tools**, every one wrapped
27
+ with the bundled `@governed_tool` harness: a local unified audit log under
28
+ `~/.k8s-aiops/`, policy engine, token/runaway budget guard, undo-token recording, and
29
+ graduated-autonomy risk tiers.
30
+
31
+ > **Standalone**: the governance harness is bundled in the package
32
+ > (`k8s_aiops.governance`) — k8s-aiops has no external skill-family dependency.
33
+ > Preview: common cluster operations, not yet exhaustive.
34
+
35
+ ## What works
36
+
37
+ Any cluster a kubeconfig can reach: standard Kubernetes, **k3s**, **EKS**, **GKE**,
38
+ **AKS**, kind, minikube. Authentication (client certs, tokens, EKS/GKE/AKS exec
39
+ plugins) is delegated entirely to the kubeconfig.
40
+
41
+ ## Quick Start
42
+
43
+ ```bash
44
+ uv tool install k8s-aiops
45
+
46
+ # Uses your current kube-context out of the box:
47
+ k8s-aiops doctor
48
+ k8s-aiops pod list
49
+ k8s-aiops deployment list -n default
50
+ ```
51
+
52
+ To define named targets (multiple clusters/contexts), create
53
+ `~/.k8s-aiops/config.yaml`:
54
+
55
+ ```yaml
56
+ targets:
57
+ - name: prod # used as -t prod
58
+ context: prod-eks # a context in your kubeconfig (omit for current-context)
59
+ namespace: default # optional default namespace
60
+ # kubeconfig: /path/to/alt/kubeconfig # optional explicit path
61
+ - name: lab
62
+ context: k3s-lab
63
+ ```
64
+
65
+ No secrets live in this file — credentials come from the kubeconfig.
66
+
67
+ ## MCP
68
+
69
+ ```jsonc
70
+ {
71
+ "command": "k8s-aiops",
72
+ "args": ["mcp"],
73
+ "env": { "K8S_AIOPS_CONFIG": "~/.k8s-aiops/config.yaml" }
74
+ }
75
+ ```
76
+
77
+ ## Audit & Safety
78
+
79
+ - Every tool call is logged to `~/.k8s-aiops/audit.db` (local SQLite; relocate with
80
+ `K8S_AIOPS_HOME`).
81
+ - Reversible writes record an inverse undo descriptor (`scale_deployment` →
82
+ scale-back to previous; `cordon_node` ↔ `uncordon_node`).
83
+ - `delete_deployment` is `risk_level=high`; CLI destructive commands require double
84
+ confirmation and support `--dry-run`.
85
+ - All API text passes through `sanitize()` (prompt-injection defense).
86
+
87
+ See `skills/k8s-aiops/SKILL.md` and `SECURITY.md` for details.
88
+
89
+ ## Companion Skills
90
+
91
+ | If you want… | Use |
92
+ |--------------|-----|
93
+ | Kubernetes pods / deployments / nodes | **k8s-aiops** (this) |
94
+ | Hypervisor VM lifecycle | a hypervisor ops skill |
95
+ | Backup & restore | a backup ops skill |
96
+
97
+ ## License
98
+
99
+ MIT — [github.com/AIops-tools/K8s-AIops](https://github.com/AIops-tools/K8s-AIops)
@@ -0,0 +1,84 @@
1
+ <!-- mcp-name: io.github.AIops-tools/k8s-aiops -->
2
+ # k8s-aiops (preview)
3
+
4
+ > **Disclaimer**: This is a community-maintained open-source project and is **not
5
+ > affiliated with, endorsed by, or sponsored by the Cloud Native Computing
6
+ > Foundation, the Kubernetes project, or k3s/Rancher.** "Kubernetes" and "k3s" are
7
+ > trademarks of their respective owners. Source code is publicly auditable at
8
+ > [github.com/AIops-tools/K8s-AIops](https://github.com/AIops-tools/K8s-AIops) under
9
+ > the MIT license.
10
+
11
+ Governed Kubernetes operations for AI agents — **15 MCP tools**, every one wrapped
12
+ with the bundled `@governed_tool` harness: a local unified audit log under
13
+ `~/.k8s-aiops/`, policy engine, token/runaway budget guard, undo-token recording, and
14
+ graduated-autonomy risk tiers.
15
+
16
+ > **Standalone**: the governance harness is bundled in the package
17
+ > (`k8s_aiops.governance`) — k8s-aiops has no external skill-family dependency.
18
+ > Preview: common cluster operations, not yet exhaustive.
19
+
20
+ ## What works
21
+
22
+ Any cluster a kubeconfig can reach: standard Kubernetes, **k3s**, **EKS**, **GKE**,
23
+ **AKS**, kind, minikube. Authentication (client certs, tokens, EKS/GKE/AKS exec
24
+ plugins) is delegated entirely to the kubeconfig.
25
+
26
+ ## Quick Start
27
+
28
+ ```bash
29
+ uv tool install k8s-aiops
30
+
31
+ # Uses your current kube-context out of the box:
32
+ k8s-aiops doctor
33
+ k8s-aiops pod list
34
+ k8s-aiops deployment list -n default
35
+ ```
36
+
37
+ To define named targets (multiple clusters/contexts), create
38
+ `~/.k8s-aiops/config.yaml`:
39
+
40
+ ```yaml
41
+ targets:
42
+ - name: prod # used as -t prod
43
+ context: prod-eks # a context in your kubeconfig (omit for current-context)
44
+ namespace: default # optional default namespace
45
+ # kubeconfig: /path/to/alt/kubeconfig # optional explicit path
46
+ - name: lab
47
+ context: k3s-lab
48
+ ```
49
+
50
+ No secrets live in this file — credentials come from the kubeconfig.
51
+
52
+ ## MCP
53
+
54
+ ```jsonc
55
+ {
56
+ "command": "k8s-aiops",
57
+ "args": ["mcp"],
58
+ "env": { "K8S_AIOPS_CONFIG": "~/.k8s-aiops/config.yaml" }
59
+ }
60
+ ```
61
+
62
+ ## Audit & Safety
63
+
64
+ - Every tool call is logged to `~/.k8s-aiops/audit.db` (local SQLite; relocate with
65
+ `K8S_AIOPS_HOME`).
66
+ - Reversible writes record an inverse undo descriptor (`scale_deployment` →
67
+ scale-back to previous; `cordon_node` ↔ `uncordon_node`).
68
+ - `delete_deployment` is `risk_level=high`; CLI destructive commands require double
69
+ confirmation and support `--dry-run`.
70
+ - All API text passes through `sanitize()` (prompt-injection defense).
71
+
72
+ See `skills/k8s-aiops/SKILL.md` and `SECURITY.md` for details.
73
+
74
+ ## Companion Skills
75
+
76
+ | If you want… | Use |
77
+ |--------------|-----|
78
+ | Kubernetes pods / deployments / nodes | **k8s-aiops** (this) |
79
+ | Hypervisor VM lifecycle | a hypervisor ops skill |
80
+ | Backup & restore | a backup ops skill |
81
+
82
+ ## License
83
+
84
+ MIT — [github.com/AIops-tools/K8s-AIops](https://github.com/AIops-tools/K8s-AIops)
@@ -0,0 +1,78 @@
1
+ # Security Policy
2
+
3
+ ## Disclaimer
4
+
5
+ This is a community-maintained open-source project and is **not affiliated with,
6
+ endorsed by, or sponsored by the Cloud Native Computing Foundation, the Kubernetes
7
+ project, or k3s/Rancher.** "Kubernetes" and "k3s" are trademarks of their respective
8
+ owners. Source code is publicly auditable at
9
+ [github.com/AIops-tools/K8s-AIops](https://github.com/AIops-tools/K8s-AIops) under
10
+ the MIT license.
11
+
12
+ ## Reporting Vulnerabilities
13
+
14
+ Report security issues privately to **zhouwei008@gmail.com** or via a GitHub
15
+ private security advisory on the repository. Please do not open public issues for
16
+ undisclosed vulnerabilities.
17
+
18
+ ## Security Design
19
+
20
+ ### Credential Management
21
+
22
+ k8s-aiops does **not** store or handle cluster credentials directly. All
23
+ authentication is delegated to the kubeconfig (`KUBECONFIG` env or `~/.kube/config`),
24
+ which may hold client certificates, bearer tokens, or exec plugins (for EKS/GKE/AKS).
25
+ The skill loads a kube context via the official `kubernetes` client and never reads,
26
+ logs, or echoes the underlying credentials. The state directory `~/.k8s-aiops` should
27
+ be owner-only (`chmod 700`); the skill warns if it is more permissive.
28
+
29
+ ### Destructive Operation Safety
30
+
31
+ Write operations (scale, rollout restart, delete pod, delete deployment, cordon)
32
+ all pass through the bundled `@governed_tool` decorator: policy pre-check, token /
33
+ runaway budget guard, graduated-autonomy risk-tier gate, and audit logging. The CLI
34
+ layer additionally requires double confirmation and supports `--dry-run` for the
35
+ most destructive commands (deployment delete, pod delete, node cordon). Reversible
36
+ writes record an inverse undo descriptor — `scale_deployment` records a scale-back to
37
+ the previous replica count; `cordon_node` ↔ `uncordon_node` are mutual inverses.
38
+ `delete_pod`, `delete_deployment`, and `rollout_restart_deployment` declare no undo;
39
+ `delete_deployment` is tagged `risk_level=high`.
40
+
41
+ ### Least Privilege
42
+
43
+ Use a kube context bound to a ServiceAccount or user with only the RBAC verbs you
44
+ need. Read-only use requires only `get`/`list`/`watch`; the write tools additionally
45
+ need `patch`/`delete` on the relevant resources.
46
+
47
+ ### Webhooks / Outbound Network
48
+
49
+ None. The skill makes no outbound network calls beyond the configured Kubernetes API
50
+ server. There are no background services or post-install scripts.
51
+
52
+ ### TLS Verification
53
+
54
+ TLS verification follows the kubeconfig (`certificate-authority` / `insecure-skip-tls-verify`).
55
+ The skill does not weaken it; disable verification only in the kubeconfig itself and
56
+ only for self-signed lab clusters.
57
+
58
+ ### Prompt Injection Protection
59
+
60
+ All text returned from the Kubernetes API (names, log lines, event messages) is run
61
+ through `sanitize()` — truncation plus C0/C1 control-character stripping — before
62
+ reaching the agent.
63
+
64
+ ### Transitive Dependencies
65
+
66
+ `kubernetes` (official Python client), `typer`/`rich` (CLI), `pyyaml` (config), and
67
+ the MCP SDK. No external skill-family dependency — the governance harness is vendored
68
+ under `k8s_aiops.governance`.
69
+
70
+ ## Static Analysis
71
+
72
+ ```bash
73
+ uvx bandit -r k8s_aiops/ mcp_server/
74
+ ```
75
+
76
+ ## Supported Versions
77
+
78
+ The latest released version (currently 0.1.0, preview) receives security fixes.
@@ -0,0 +1,10 @@
1
+ """k8s-aiops — governed Kubernetes operations for AI agents.
2
+
3
+ Standalone and self-contained: the governance harness (audit, token budget,
4
+ undo-token recording, graduated risk tiers, prompt-injection sanitize) is
5
+ bundled under ``k8s_aiops.governance`` — this package has no external
6
+ skill-family dependency. Works with any kubeconfig-reachable cluster
7
+ (standard Kubernetes, k3s, EKS, GKE, AKS). Preview: not yet full-coverage.
8
+ """
9
+
10
+ __version__ = "0.1.0"
@@ -0,0 +1,9 @@
1
+ """CLI package for k8s-aiops.
2
+
3
+ Re-exports ``app`` so the pyproject entry point
4
+ ``k8s-aiops = "k8s_aiops.cli:app"`` works unchanged.
5
+ """
6
+
7
+ from k8s_aiops.cli._root import app
8
+
9
+ __all__ = ["app"]
@@ -0,0 +1,81 @@
1
+ """Shared helpers for k8s-aiops CLI sub-modules."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import functools
6
+ from collections.abc import Callable
7
+ from pathlib import Path
8
+ from typing import Annotated, Any
9
+
10
+ import typer
11
+ from rich.console import Console
12
+
13
+ console = Console()
14
+
15
+ # ─── Shared Option types ───────────────────────────────────────────────────
16
+
17
+ TargetOption = Annotated[
18
+ str | None, typer.Option("--target", "-t", help="Target name from config")
19
+ ]
20
+ NamespaceOption = Annotated[
21
+ str | None, typer.Option("--namespace", "-n", help="Namespace (omit for all/default)")
22
+ ]
23
+ DryRunOption = Annotated[
24
+ bool, typer.Option("--dry-run", help="Print the operation without executing")
25
+ ]
26
+
27
+
28
+ def _cli_error_types() -> tuple[type[BaseException], ...]:
29
+ """Exceptions translated to a one-line teaching error instead of a traceback."""
30
+ from k8s_aiops.connection import K8sApiError
31
+
32
+ return (K8sApiError, KeyError, OSError, ValueError)
33
+
34
+
35
+ def cli_errors(fn: Callable) -> Callable:
36
+ """Translate known exceptions into one red line + exit code 1."""
37
+
38
+ @functools.wraps(fn)
39
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
40
+ try:
41
+ return fn(*args, **kwargs)
42
+ except (typer.Exit, typer.Abort):
43
+ raise
44
+ except _cli_error_types() as e:
45
+ message = str(e)
46
+ if isinstance(e, KeyError):
47
+ message = f"Missing required key: {message}"
48
+ console.print(f"[red]Error: {message}[/]")
49
+ raise typer.Exit(1) from e
50
+
51
+ return wrapper
52
+
53
+
54
+ def get_connection(target: str | None, config_path: Path | None = None):
55
+ """Return a (conn, config) tuple for the given target."""
56
+ from k8s_aiops.config import load_config
57
+ from k8s_aiops.connection import ConnectionManager
58
+
59
+ cfg = load_config(config_path)
60
+ mgr = ConnectionManager(cfg)
61
+ return mgr.connect(target), cfg
62
+
63
+
64
+ def dry_run_print(*, operation: str, detail: str, parameters: dict | None = None) -> None:
65
+ """Print a dry-run preview of the operation that would be performed."""
66
+ console.print("\n[bold magenta][DRY-RUN] No changes will be made.[/]")
67
+ console.print(f"[magenta] Operation: {operation}[/]")
68
+ console.print(f"[magenta] Detail: {detail}[/]")
69
+ for k, v in (parameters or {}).items():
70
+ console.print(f"[magenta] Param: {k} = {v}[/]")
71
+ console.print("[magenta] Run without --dry-run to execute.[/]\n")
72
+
73
+
74
+ def double_confirm(action: str, resource: str) -> None:
75
+ """Require two confirmations for a destructive operation."""
76
+ console.print(f"[bold yellow]⚠️ About to: {action} '{resource}'[/]")
77
+ typer.confirm(f"Confirm 1/2: {action} '{resource}'?", abort=True)
78
+ typer.confirm(
79
+ f"Confirm 2/2: really {action} '{resource}'? This may be irreversible.",
80
+ abort=True,
81
+ )
@@ -0,0 +1,78 @@
1
+ """Top-level Typer app: assembles sub-apps and top-level commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import typer
6
+
7
+ from k8s_aiops.cli._common import NamespaceOption, TargetOption, cli_errors
8
+ from k8s_aiops.cli.deployment import deployment_app
9
+ from k8s_aiops.cli.doctor import doctor_cmd
10
+ from k8s_aiops.cli.namespace import namespace_app
11
+ from k8s_aiops.cli.node import node_app
12
+ from k8s_aiops.cli.pod import pod_app
13
+ from k8s_aiops.cli.service import service_app
14
+
15
+ app = typer.Typer(
16
+ name="k8s-aiops",
17
+ help="Governed Kubernetes operations for AI agents (works with k3s/EKS/GKE/AKS).",
18
+ no_args_is_help=True,
19
+ )
20
+
21
+ app.add_typer(pod_app, name="pod")
22
+ app.add_typer(deployment_app, name="deployment")
23
+ app.add_typer(service_app, name="service")
24
+ app.add_typer(node_app, name="node")
25
+ app.add_typer(namespace_app, name="namespace")
26
+ app.command("doctor")(doctor_cmd)
27
+
28
+
29
+ @app.command("events")
30
+ @cli_errors
31
+ def events_cmd(target: TargetOption = None, namespace: NamespaceOption = None) -> None:
32
+ """List recent cluster events (namespace-scoped or all-namespaces)."""
33
+ from rich.console import Console
34
+ from rich.table import Table
35
+
36
+ from k8s_aiops.cli._common import get_connection
37
+ from k8s_aiops.ops import workloads
38
+
39
+ conn, _ = get_connection(target)
40
+ rows = workloads.list_events(conn, namespace)
41
+ table = Table(title="Kubernetes Events")
42
+ for col in ("type", "reason", "object", "namespace", "message", "age"):
43
+ table.add_column(col)
44
+ for r in rows:
45
+ table.add_row(
46
+ r["type"], r["reason"], r["object"], r["namespace"], r["message"], r["age"]
47
+ )
48
+ Console().print(table)
49
+
50
+
51
+ @app.command("mcp")
52
+ @cli_errors
53
+ def mcp_cmd() -> None:
54
+ """Start the MCP server (stdio transport).
55
+
56
+ Single-command entry point for MCP clients (does not go through uvx/PyPI
57
+ resolution at launch):
58
+ k8s-aiops mcp
59
+ """
60
+ import sys
61
+
62
+ if sys.version_info < (3, 11):
63
+ typer.echo(
64
+ f"ERROR: k8s-aiops requires Python >= 3.11 "
65
+ f"(got {sys.version_info.major}.{sys.version_info.minor}).\n"
66
+ f"Fix: uv python install 3.12 && "
67
+ f"uv tool install --python 3.12 --force k8s-aiops",
68
+ err=True,
69
+ )
70
+ raise typer.Exit(2)
71
+
72
+ from mcp_server.server import main as _mcp_main
73
+
74
+ _mcp_main()
75
+
76
+
77
+ if __name__ == "__main__":
78
+ app()
@@ -0,0 +1,95 @@
1
+ """``k8s-aiops deployment ...`` sub-commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import typer
6
+ from rich.console import Console
7
+ from rich.table import Table
8
+
9
+ from k8s_aiops.cli._common import (
10
+ DryRunOption,
11
+ NamespaceOption,
12
+ TargetOption,
13
+ cli_errors,
14
+ double_confirm,
15
+ dry_run_print,
16
+ get_connection,
17
+ )
18
+ from k8s_aiops.ops import lifecycle, workloads
19
+
20
+ deployment_app = typer.Typer(help="Deployment operations.", no_args_is_help=True)
21
+ console = Console()
22
+
23
+
24
+ @deployment_app.command("list")
25
+ @cli_errors
26
+ def deployment_list(target: TargetOption = None, namespace: NamespaceOption = None) -> None:
27
+ """List deployments (name, namespace, desired/ready/available, age)."""
28
+ conn, _ = get_connection(target)
29
+ rows = workloads.list_deployments(conn, namespace)
30
+ table = Table(title="Deployments")
31
+ for col in ("name", "namespace", "desired", "ready", "available", "age"):
32
+ table.add_column(col)
33
+ for r in rows:
34
+ table.add_row(
35
+ r["name"], r["namespace"], str(r["desired"]),
36
+ str(r["ready"]), str(r["available"]), r["age"],
37
+ )
38
+ console.print(table)
39
+
40
+
41
+ @deployment_app.command("get")
42
+ @cli_errors
43
+ def deployment_get(
44
+ name: str, target: TargetOption = None, namespace: NamespaceOption = None
45
+ ) -> None:
46
+ """Show detail for one deployment."""
47
+ conn, _ = get_connection(target)
48
+ for k, v in workloads.get_deployment(conn, name, namespace).items():
49
+ console.print(f" [cyan]{k}:[/] {v}")
50
+
51
+
52
+ @deployment_app.command("scale")
53
+ @cli_errors
54
+ def deployment_scale(
55
+ name: str,
56
+ replicas: int,
57
+ target: TargetOption = None,
58
+ namespace: NamespaceOption = None,
59
+ ) -> None:
60
+ """Scale a deployment to a replica count."""
61
+ conn, _ = get_connection(target)
62
+ result = lifecycle.scale_deployment(conn, name, replicas, namespace)
63
+ console.print(
64
+ f"[green]Scaled {name} -> {replicas}[/] "
65
+ f"(was {result['previous_replicas']})"
66
+ )
67
+
68
+
69
+ @deployment_app.command("restart")
70
+ @cli_errors
71
+ def deployment_restart(
72
+ name: str, target: TargetOption = None, namespace: NamespaceOption = None
73
+ ) -> None:
74
+ """Trigger a rolling restart of a deployment."""
75
+ conn, _ = get_connection(target)
76
+ lifecycle.rollout_restart_deployment(conn, name, namespace)
77
+ console.print(f"[green]Rollout restart triggered for {name}[/]")
78
+
79
+
80
+ @deployment_app.command("delete")
81
+ @cli_errors
82
+ def deployment_delete(
83
+ name: str,
84
+ target: TargetOption = None,
85
+ namespace: NamespaceOption = None,
86
+ dry_run: DryRunOption = False,
87
+ ) -> None:
88
+ """Delete a deployment and its pods (HIGH RISK — double confirm)."""
89
+ if dry_run:
90
+ dry_run_print(operation="delete_deployment", detail=f"delete deployment {name}")
91
+ return
92
+ double_confirm("delete", f"deployment {name}")
93
+ conn, _ = get_connection(target)
94
+ lifecycle.delete_deployment(conn, name, namespace)
95
+ console.print(f"[green]Deleted deployment {name}[/]")
@@ -0,0 +1,21 @@
1
+ """Doctor top-level command: environment and connectivity check."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Annotated
6
+
7
+ import typer
8
+
9
+ from k8s_aiops.cli._common import cli_errors
10
+
11
+
12
+ @cli_errors
13
+ def doctor_cmd(
14
+ skip_auth: Annotated[
15
+ bool, typer.Option("--skip-auth", help="Skip connectivity check (faster)")
16
+ ] = False,
17
+ ) -> None:
18
+ """Check config and cluster reachability."""
19
+ from k8s_aiops.doctor import run_doctor
20
+
21
+ raise typer.Exit(run_doctor(skip_auth=skip_auth))
@@ -0,0 +1,27 @@
1
+ """``k8s-aiops namespace ...`` sub-commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import typer
6
+ from rich.console import Console
7
+ from rich.table import Table
8
+
9
+ from k8s_aiops.cli._common import TargetOption, cli_errors, get_connection
10
+ from k8s_aiops.ops import namespaces
11
+
12
+ namespace_app = typer.Typer(help="Namespace operations.", no_args_is_help=True)
13
+ console = Console()
14
+
15
+
16
+ @namespace_app.command("list")
17
+ @cli_errors
18
+ def namespace_list(target: TargetOption = None) -> None:
19
+ """List namespaces (name, phase, age)."""
20
+ conn, _ = get_connection(target)
21
+ rows = namespaces.list_namespaces(conn)
22
+ table = Table(title="Namespaces")
23
+ for col in ("name", "phase", "age"):
24
+ table.add_column(col)
25
+ for r in rows:
26
+ table.add_row(r["name"], r["phase"], r["age"])
27
+ console.print(table)