ceph-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.
- ceph_aiops-0.1.0/.gitignore +7 -0
- ceph_aiops-0.1.0/CHANGELOG.md +61 -0
- ceph_aiops-0.1.0/LICENSE +21 -0
- ceph_aiops-0.1.0/PKG-INFO +137 -0
- ceph_aiops-0.1.0/README.md +121 -0
- ceph_aiops-0.1.0/RELEASE_NOTES.md +57 -0
- ceph_aiops-0.1.0/SECURITY.md +79 -0
- ceph_aiops-0.1.0/ceph_aiops/__init__.py +9 -0
- ceph_aiops-0.1.0/ceph_aiops/cli/__init__.py +9 -0
- ceph_aiops-0.1.0/ceph_aiops/cli/_common.py +78 -0
- ceph_aiops-0.1.0/ceph_aiops/cli/_root.py +57 -0
- ceph_aiops-0.1.0/ceph_aiops/cli/doctor.py +21 -0
- ceph_aiops-0.1.0/ceph_aiops/cli/health.py +35 -0
- ceph_aiops-0.1.0/ceph_aiops/cli/init.py +103 -0
- ceph_aiops-0.1.0/ceph_aiops/cli/osd.py +95 -0
- ceph_aiops-0.1.0/ceph_aiops/cli/overview.py +16 -0
- ceph_aiops-0.1.0/ceph_aiops/cli/secret.py +103 -0
- ceph_aiops-0.1.0/ceph_aiops/config.py +139 -0
- ceph_aiops-0.1.0/ceph_aiops/connection.py +205 -0
- ceph_aiops-0.1.0/ceph_aiops/doctor.py +86 -0
- ceph_aiops-0.1.0/ceph_aiops/governance/__init__.py +40 -0
- ceph_aiops-0.1.0/ceph_aiops/governance/audit.py +377 -0
- ceph_aiops-0.1.0/ceph_aiops/governance/budget.py +225 -0
- ceph_aiops-0.1.0/ceph_aiops/governance/decorators.py +474 -0
- ceph_aiops-0.1.0/ceph_aiops/governance/paths.py +23 -0
- ceph_aiops-0.1.0/ceph_aiops/governance/patterns.py +378 -0
- ceph_aiops-0.1.0/ceph_aiops/governance/policy.py +411 -0
- ceph_aiops-0.1.0/ceph_aiops/governance/sanitize.py +39 -0
- ceph_aiops-0.1.0/ceph_aiops/governance/undo.py +218 -0
- ceph_aiops-0.1.0/ceph_aiops/ops/__init__.py +1 -0
- ceph_aiops-0.1.0/ceph_aiops/ops/_util.py +44 -0
- ceph_aiops-0.1.0/ceph_aiops/ops/clusterops.py +192 -0
- ceph_aiops-0.1.0/ceph_aiops/ops/filesystem.py +107 -0
- ceph_aiops-0.1.0/ceph_aiops/ops/health.py +177 -0
- ceph_aiops-0.1.0/ceph_aiops/ops/osd.py +119 -0
- ceph_aiops-0.1.0/ceph_aiops/ops/overview.py +38 -0
- ceph_aiops-0.1.0/ceph_aiops/ops/pg.py +155 -0
- ceph_aiops-0.1.0/ceph_aiops/ops/pool.py +179 -0
- ceph_aiops-0.1.0/ceph_aiops/ops/rbd.py +77 -0
- ceph_aiops-0.1.0/ceph_aiops/secretstore.py +302 -0
- ceph_aiops-0.1.0/mcp_server/__init__.py +1 -0
- ceph_aiops-0.1.0/mcp_server/_shared.py +102 -0
- ceph_aiops-0.1.0/mcp_server/server.py +36 -0
- ceph_aiops-0.1.0/mcp_server/tools/__init__.py +1 -0
- ceph_aiops-0.1.0/mcp_server/tools/clusterops.py +121 -0
- ceph_aiops-0.1.0/mcp_server/tools/filesystem.py +37 -0
- ceph_aiops-0.1.0/mcp_server/tools/health.py +35 -0
- ceph_aiops-0.1.0/mcp_server/tools/osd.py +168 -0
- ceph_aiops-0.1.0/mcp_server/tools/pg.py +84 -0
- ceph_aiops-0.1.0/mcp_server/tools/pool.py +195 -0
- ceph_aiops-0.1.0/mcp_server/tools/rbd.py +106 -0
- ceph_aiops-0.1.0/pyproject.toml +59 -0
- ceph_aiops-0.1.0/server.json +21 -0
- ceph_aiops-0.1.0/skills/ceph-aiops/SKILL.md +114 -0
- ceph_aiops-0.1.0/skills/ceph-aiops/references/capabilities.md +61 -0
- ceph_aiops-0.1.0/skills/ceph-aiops/references/cli-reference.md +59 -0
- ceph_aiops-0.1.0/skills/ceph-aiops/references/setup-guide.md +125 -0
- ceph_aiops-0.1.0/smithery.yaml +9 -0
- ceph_aiops-0.1.0/tests/test_clusterops.py +101 -0
- ceph_aiops-0.1.0/tests/test_filesystem.py +91 -0
- ceph_aiops-0.1.0/tests/test_pg.py +65 -0
- ceph_aiops-0.1.0/tests/test_pool.py +107 -0
- ceph_aiops-0.1.0/tests/test_rbd.py +78 -0
- ceph_aiops-0.1.0/tests/test_secretstore.py +99 -0
- ceph_aiops-0.1.0/tests/test_smoke.py +264 -0
- ceph_aiops-0.1.0/uv.lock +962 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to ceph-aiops are documented here. This project adheres
|
|
4
|
+
to [Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
## [0.1.0] — preview
|
|
7
|
+
|
|
8
|
+
Initial preview release: governed AI-ops for **Ceph** via the ceph-mgr Dashboard
|
|
9
|
+
REST API, with a bundled governance harness. Works against vanilla ceph-mgr
|
|
10
|
+
(cephadm / Proxmox-hosted / MicroCeph) — no croit, no Kubernetes.
|
|
11
|
+
**Mock-validated only — not yet verified against a live cluster.**
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **35 MCP tools** (17 read, 18 write), every one wrapped with the bundled
|
|
16
|
+
`@governed_tool` harness (audit, policy, token/runaway budget, undo,
|
|
17
|
+
risk-tiers):
|
|
18
|
+
- **Health** — `cluster_health` (flagship RCA: per active HEALTH_WARN/ERR
|
|
19
|
+
check → plain-language cause + suggested action), `cluster_status`
|
|
20
|
+
(`ceph -s` summary).
|
|
21
|
+
- **OSD** — `osd_tree`, `osd_df` (most-full first + near/backfill-full flags),
|
|
22
|
+
`osd_perf` (slowest first); `cluster_flag_set` (low, undo — noout/noscrub/
|
|
23
|
+
nobackfill/norecover), `osd_reweight` (med, undo → prior weight; 0.0=drain),
|
|
24
|
+
`osd_mark_in` (med, undo), `osd_mark_out` (high, dry-run — drains data),
|
|
25
|
+
`osd_purge` (high, dry-run — irreversible).
|
|
26
|
+
- **PG** — `pg_summary` (state histogram + non-active+clean), `pg_dump_stuck`
|
|
27
|
+
(stuck PGs + implicated OSDs), `scrub_status` (overdue scrub/deep-scrub);
|
|
28
|
+
`trigger_scrub` (low), `trigger_deep_scrub` (low).
|
|
29
|
+
- **Pool** — `pool_ls`, `pool_df` (usable capacity = raw ÷ size);
|
|
30
|
+
`set_pool_quota` (med, undo), `set_pool_pg_num` (med, undo),
|
|
31
|
+
`set_pool_autoscale` (med, undo), `pool_create` (med), `set_pool_size`
|
|
32
|
+
(high, dry-run — replica change forces data movement), `pool_delete`
|
|
33
|
+
(high, dry-run — destroys all data).
|
|
34
|
+
- **RBD** — `rbd_ls`; `rbd_image_create` (med), `rbd_snapshot_create` (low),
|
|
35
|
+
`rbd_image_delete` (high, dry-run), `rbd_snapshot_delete` (high, dry-run).
|
|
36
|
+
- **CephFS / RGW** — `cephfs_status` (MDS ranks + "behind on trimming" +
|
|
37
|
+
client count), `rgw_status` (daemons + buckets + LARGE_OMAP /
|
|
38
|
+
unsharded-index findings).
|
|
39
|
+
- **Cluster-ops** — `mon_status` (quorum / out-of-quorum), `mgr_status`
|
|
40
|
+
(active/standbys/modules), `slow_ops` (blocked requests by OSD),
|
|
41
|
+
`capacity_forecast` (days-to-nearfull); `throttle_recovery` (med, undo —
|
|
42
|
+
`osd_max_backfills` / `osd_recovery_max_active`).
|
|
43
|
+
- **JWT authentication** — username + password exchanged for a short-lived JWT
|
|
44
|
+
at `POST /api/auth` against the mgr Dashboard (`https://<host>:8443`); the mgr
|
|
45
|
+
**dashboard** module must be enabled.
|
|
46
|
+
- **Encrypted secret store** — the Dashboard password is stored encrypted in
|
|
47
|
+
`~/.ceph-aiops/secrets.enc` (Fernet + scrypt); never plaintext on disk. Legacy
|
|
48
|
+
`CEPH_<TARGET>_PASSWORD` env var honoured as a fallback.
|
|
49
|
+
- **CLI** (`ceph-aiops`) — `init` wizard, `secret` management, `doctor`,
|
|
50
|
+
`overview`, and the `health` / `osd` sub-commands.
|
|
51
|
+
- **Teaching connection layer** — JWT login with centralised, human-readable
|
|
52
|
+
error translation (e.g. dashboard-module-not-enabled, auth failure).
|
|
53
|
+
|
|
54
|
+
### Known limitations
|
|
55
|
+
|
|
56
|
+
- Preview / mock-only: multi-node rebalance behaviour and the write ops are
|
|
57
|
+
unverified against a real Ceph cluster. Fastest live check: a single-node
|
|
58
|
+
MicroCeph running `ceph-aiops doctor`.
|
|
59
|
+
- The ceph-mgr Dashboard API has no ETag / pagination, so this tool exposes none.
|
|
60
|
+
- Out of scope by design (v0.1.0): RGW multisite, NFS-Ganesha exports, and
|
|
61
|
+
cephadm orchestrator host management.
|
ceph_aiops-0.1.0/LICENSE
ADDED
|
@@ -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,137 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ceph-aiops
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Governed AI-ops for Ceph (ceph-mgr Dashboard REST): HEALTH_WARN root-cause analysis, OSD/PG/pool/RBD/CephFS/RGW operations, and destructive-op guardrails 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: cryptography>=42.0
|
|
10
|
+
Requires-Dist: httpx<1.0,>=0.27
|
|
11
|
+
Requires-Dist: mcp[cli]<2.0,>=1.10
|
|
12
|
+
Requires-Dist: pyyaml<7.0,>=6.0
|
|
13
|
+
Requires-Dist: rich<16.0,>=13.0
|
|
14
|
+
Requires-Dist: typer<1.0,>=0.12
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
<!-- mcp-name: io.github.AIops-tools/ceph-aiops -->
|
|
18
|
+
|
|
19
|
+
# Ceph AIops (preview)
|
|
20
|
+
|
|
21
|
+
> **Disclaimer**: Community-maintained open-source project. **Not affiliated with, endorsed by, or sponsored by the Ceph project or any storage vendor.** Product and trademark names belong to their owners. MIT licensed.
|
|
22
|
+
|
|
23
|
+
Governed AI-ops for **Ceph** — talks to a vanilla **ceph-mgr Dashboard REST API**
|
|
24
|
+
(HTTPS `:8443`, username + password exchanged for a short-lived JWT at
|
|
25
|
+
`POST /api/auth`) with a **built-in governance harness**: unified audit log,
|
|
26
|
+
policy engine, token/runaway budget guard, undo-token recording, and
|
|
27
|
+
graduated-autonomy risk tiers. Works against stock ceph-mgr — **cephadm**,
|
|
28
|
+
**Proxmox-hosted Ceph**, or **MicroCeph** — with **no croit and no Kubernetes
|
|
29
|
+
dependency**. Self-contained: no external skill-family dependency.
|
|
30
|
+
**Preview — mock-validated only, not yet verified against a live cluster.**
|
|
31
|
+
|
|
32
|
+
## What it does
|
|
33
|
+
|
|
34
|
+
The flagship analysis, plus the guarded reads and writes around it:
|
|
35
|
+
|
|
36
|
+
- **`cluster_health` — HEALTH_WARN/ERR root-cause analysis.** Instead of echoing
|
|
37
|
+
raw check codes (`PG_DEGRADED`, `OSD_NEARFULL`, `SLOW_OPS`, `MON_DOWN`,
|
|
38
|
+
`LARGE_OMAP_OBJECTS`, …), it turns each *active* check into plain language:
|
|
39
|
+
**what it means, the likely cause, and the suggested next action**. This is the
|
|
40
|
+
differentiator vs the hobby Ceph MCPs that just proxy `ceph -s`.
|
|
41
|
+
- **Governed destructive ops.** The operations operators actually fear —
|
|
42
|
+
`osd_purge`, `pool_delete`, `set_pool_size`, `rbd_image_delete` — carry
|
|
43
|
+
**dry-run + double-confirm** and a **high** risk tier; reversible tuning
|
|
44
|
+
(`osd_reweight`, `throttle_recovery`, `cluster_flag_set`, pool quota/pg_num/
|
|
45
|
+
autoscale) records an **undo descriptor** capturing the prior state.
|
|
46
|
+
|
|
47
|
+
## What works
|
|
48
|
+
|
|
49
|
+
- **CLI** (`ceph-aiops ...`): `init`, `overview`, `health detail`/`health status`,
|
|
50
|
+
`osd tree/df/reweight/out/purge`, `secret set/list/rm/migrate/rotate-password`,
|
|
51
|
+
`doctor`, `mcp`. `osd out` and `osd purge` require `--dry-run` + double confirm.
|
|
52
|
+
- **MCP server** (`ceph-aiops mcp` or `ceph-aiops-mcp`): the full **35 tools**
|
|
53
|
+
(17 read, 18 write), every one wrapped with the bundled `@governed_tool`
|
|
54
|
+
harness. The CLI is a convenience subset; the MCP surface is the whole tool.
|
|
55
|
+
- **Encrypted credentials**: the Dashboard password lives in an encrypted store
|
|
56
|
+
`~/.ceph-aiops/secrets.enc` (Fernet + scrypt) — **never plaintext on disk**.
|
|
57
|
+
Unlock with a master password from `CEPH_AIOPS_MASTER_PASSWORD` (MCP/CI) or an
|
|
58
|
+
interactive prompt (CLI).
|
|
59
|
+
- **Reversibility**: reversible writes capture the prior state and record an
|
|
60
|
+
inverse undo descriptor (e.g. `osd_reweight` → prior weight, `set_pool_quota`
|
|
61
|
+
→ prior quota, `throttle_recovery` → prior backfill/recovery settings).
|
|
62
|
+
- **Safety**: destructive ops (`osd_purge`, `osd_mark_out`, `pool_delete`,
|
|
63
|
+
`set_pool_size`, `rbd_image_delete`, `rbd_snapshot_delete`) are `high` risk
|
|
64
|
+
with `dry_run` and CLI double confirmation.
|
|
65
|
+
|
|
66
|
+
## Capability matrix (35 MCP tools)
|
|
67
|
+
|
|
68
|
+
| Group | Tools | Count | R/W |
|
|
69
|
+
|-------|-------|:-----:|:---:|
|
|
70
|
+
| **Health** | `cluster_health` (flagship RCA), `cluster_status` | 2 | read |
|
|
71
|
+
| **OSD** | `osd_tree`, `osd_df`, `osd_perf` | 3 | read |
|
|
72
|
+
| | `cluster_flag_set` (low, undo), `osd_reweight` (med, undo), `osd_mark_in` (med, undo) | 3 | write |
|
|
73
|
+
| | `osd_mark_out` (high, dry-run), `osd_purge` (high, dry-run) | 2 | write |
|
|
74
|
+
| **PG** | `pg_summary`, `pg_dump_stuck`, `scrub_status` | 3 | read |
|
|
75
|
+
| | `trigger_scrub` (low), `trigger_deep_scrub` (low) | 2 | write |
|
|
76
|
+
| **Pool** | `pool_ls`, `pool_df` | 2 | read |
|
|
77
|
+
| | `set_pool_quota` (med, undo), `set_pool_pg_num` (med, undo), `set_pool_autoscale` (med, undo), `pool_create` (med) | 4 | write |
|
|
78
|
+
| | `set_pool_size` (high, dry-run), `pool_delete` (high, dry-run) | 2 | write |
|
|
79
|
+
| **RBD** | `rbd_ls` | 1 | read |
|
|
80
|
+
| | `rbd_image_create` (med), `rbd_snapshot_create` (low) | 2 | write |
|
|
81
|
+
| | `rbd_image_delete` (high, dry-run), `rbd_snapshot_delete` (high, dry-run) | 2 | write |
|
|
82
|
+
| **CephFS / RGW** | `cephfs_status`, `rgw_status` | 2 | read |
|
|
83
|
+
| **Cluster-ops** | `mon_status`, `mgr_status`, `slow_ops`, `capacity_forecast` | 4 | read |
|
|
84
|
+
| | `throttle_recovery` (med, undo) | 1 | write |
|
|
85
|
+
|
|
86
|
+
Totals: **35 tools — 17 read, 18 write.**
|
|
87
|
+
|
|
88
|
+
## Quick start
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
uv tool install ceph-aiops # or: pipx install ceph-aiops
|
|
92
|
+
ceph-aiops init # wizard: add a mgr target + store the Dashboard password (encrypted)
|
|
93
|
+
ceph-aiops doctor # JWT login + mgr-dashboard reachability
|
|
94
|
+
ceph-aiops overview # HEALTH status + active checks + OSD up/in
|
|
95
|
+
ceph-aiops health detail # decode the active HEALTH_WARN/ERR checks (RCA)
|
|
96
|
+
ceph-aiops osd df # per-OSD utilization, most-full first, near/backfill-full flags
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Run as an MCP server (stdio):
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
export CEPH_AIOPS_MASTER_PASSWORD=... # unlock secrets non-interactively
|
|
103
|
+
ceph-aiops-mcp
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Governance
|
|
107
|
+
|
|
108
|
+
Every MCP tool passes through the bundled `@governed_tool` harness:
|
|
109
|
+
|
|
110
|
+
- **Audit** — every call (params, result, status, duration, risk tier,
|
|
111
|
+
approver, rationale) is logged to `~/.ceph-aiops/audit.db` (relocatable
|
|
112
|
+
via `CEPH_AIOPS_HOME`).
|
|
113
|
+
- **Budget / runaway guard** — token and call budgets trip a circuit breaker.
|
|
114
|
+
- **Risk tiers** — graduated autonomy; high-risk ops (purge/delete/replica
|
|
115
|
+
change) can require a named approver
|
|
116
|
+
(`CEPH_AUDIT_APPROVED_BY` / `CEPH_AUDIT_RATIONALE`).
|
|
117
|
+
- **Undo recording** — reversible writes record an inverse descriptor.
|
|
118
|
+
|
|
119
|
+
## Supported scope & limitations
|
|
120
|
+
|
|
121
|
+
- **Deployments**: vanilla ceph-mgr with the **dashboard** module enabled —
|
|
122
|
+
cephadm, Proxmox-hosted Ceph, or MicroCeph. **No croit, no Kubernetes
|
|
123
|
+
dependency.**
|
|
124
|
+
- **Ceph has no ETag / pagination** on the Dashboard API, so this tool exposes
|
|
125
|
+
none — nothing is missing, the upstream API simply doesn't offer them.
|
|
126
|
+
- **Preview / mock-only.** Behaviour is validated against mocked Dashboard
|
|
127
|
+
responses. The cheapest **live** check is a single-node **MicroCeph**
|
|
128
|
+
(`snap install microceph` → bootstrap → loop-file OSDs) running
|
|
129
|
+
`ceph-aiops doctor`; a 3-node Vagrant cluster exercises real rebalance
|
|
130
|
+
behaviour. Multi-node rebalance and the write ops are **unverified against a
|
|
131
|
+
real cluster**.
|
|
132
|
+
|
|
133
|
+
## Missing a capability?
|
|
134
|
+
|
|
135
|
+
RGW multisite, per-daemon config sprawl, NFS-Ganesha exports, orchestrator
|
|
136
|
+
(cephadm) host management — not here yet. **Open an issue or send a PR** — feedback
|
|
137
|
+
and contributions are welcome.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<!-- mcp-name: io.github.AIops-tools/ceph-aiops -->
|
|
2
|
+
|
|
3
|
+
# Ceph AIops (preview)
|
|
4
|
+
|
|
5
|
+
> **Disclaimer**: Community-maintained open-source project. **Not affiliated with, endorsed by, or sponsored by the Ceph project or any storage vendor.** Product and trademark names belong to their owners. MIT licensed.
|
|
6
|
+
|
|
7
|
+
Governed AI-ops for **Ceph** — talks to a vanilla **ceph-mgr Dashboard REST API**
|
|
8
|
+
(HTTPS `:8443`, username + password exchanged for a short-lived JWT at
|
|
9
|
+
`POST /api/auth`) with a **built-in governance harness**: unified audit log,
|
|
10
|
+
policy engine, token/runaway budget guard, undo-token recording, and
|
|
11
|
+
graduated-autonomy risk tiers. Works against stock ceph-mgr — **cephadm**,
|
|
12
|
+
**Proxmox-hosted Ceph**, or **MicroCeph** — with **no croit and no Kubernetes
|
|
13
|
+
dependency**. Self-contained: no external skill-family dependency.
|
|
14
|
+
**Preview — mock-validated only, not yet verified against a live cluster.**
|
|
15
|
+
|
|
16
|
+
## What it does
|
|
17
|
+
|
|
18
|
+
The flagship analysis, plus the guarded reads and writes around it:
|
|
19
|
+
|
|
20
|
+
- **`cluster_health` — HEALTH_WARN/ERR root-cause analysis.** Instead of echoing
|
|
21
|
+
raw check codes (`PG_DEGRADED`, `OSD_NEARFULL`, `SLOW_OPS`, `MON_DOWN`,
|
|
22
|
+
`LARGE_OMAP_OBJECTS`, …), it turns each *active* check into plain language:
|
|
23
|
+
**what it means, the likely cause, and the suggested next action**. This is the
|
|
24
|
+
differentiator vs the hobby Ceph MCPs that just proxy `ceph -s`.
|
|
25
|
+
- **Governed destructive ops.** The operations operators actually fear —
|
|
26
|
+
`osd_purge`, `pool_delete`, `set_pool_size`, `rbd_image_delete` — carry
|
|
27
|
+
**dry-run + double-confirm** and a **high** risk tier; reversible tuning
|
|
28
|
+
(`osd_reweight`, `throttle_recovery`, `cluster_flag_set`, pool quota/pg_num/
|
|
29
|
+
autoscale) records an **undo descriptor** capturing the prior state.
|
|
30
|
+
|
|
31
|
+
## What works
|
|
32
|
+
|
|
33
|
+
- **CLI** (`ceph-aiops ...`): `init`, `overview`, `health detail`/`health status`,
|
|
34
|
+
`osd tree/df/reweight/out/purge`, `secret set/list/rm/migrate/rotate-password`,
|
|
35
|
+
`doctor`, `mcp`. `osd out` and `osd purge` require `--dry-run` + double confirm.
|
|
36
|
+
- **MCP server** (`ceph-aiops mcp` or `ceph-aiops-mcp`): the full **35 tools**
|
|
37
|
+
(17 read, 18 write), every one wrapped with the bundled `@governed_tool`
|
|
38
|
+
harness. The CLI is a convenience subset; the MCP surface is the whole tool.
|
|
39
|
+
- **Encrypted credentials**: the Dashboard password lives in an encrypted store
|
|
40
|
+
`~/.ceph-aiops/secrets.enc` (Fernet + scrypt) — **never plaintext on disk**.
|
|
41
|
+
Unlock with a master password from `CEPH_AIOPS_MASTER_PASSWORD` (MCP/CI) or an
|
|
42
|
+
interactive prompt (CLI).
|
|
43
|
+
- **Reversibility**: reversible writes capture the prior state and record an
|
|
44
|
+
inverse undo descriptor (e.g. `osd_reweight` → prior weight, `set_pool_quota`
|
|
45
|
+
→ prior quota, `throttle_recovery` → prior backfill/recovery settings).
|
|
46
|
+
- **Safety**: destructive ops (`osd_purge`, `osd_mark_out`, `pool_delete`,
|
|
47
|
+
`set_pool_size`, `rbd_image_delete`, `rbd_snapshot_delete`) are `high` risk
|
|
48
|
+
with `dry_run` and CLI double confirmation.
|
|
49
|
+
|
|
50
|
+
## Capability matrix (35 MCP tools)
|
|
51
|
+
|
|
52
|
+
| Group | Tools | Count | R/W |
|
|
53
|
+
|-------|-------|:-----:|:---:|
|
|
54
|
+
| **Health** | `cluster_health` (flagship RCA), `cluster_status` | 2 | read |
|
|
55
|
+
| **OSD** | `osd_tree`, `osd_df`, `osd_perf` | 3 | read |
|
|
56
|
+
| | `cluster_flag_set` (low, undo), `osd_reweight` (med, undo), `osd_mark_in` (med, undo) | 3 | write |
|
|
57
|
+
| | `osd_mark_out` (high, dry-run), `osd_purge` (high, dry-run) | 2 | write |
|
|
58
|
+
| **PG** | `pg_summary`, `pg_dump_stuck`, `scrub_status` | 3 | read |
|
|
59
|
+
| | `trigger_scrub` (low), `trigger_deep_scrub` (low) | 2 | write |
|
|
60
|
+
| **Pool** | `pool_ls`, `pool_df` | 2 | read |
|
|
61
|
+
| | `set_pool_quota` (med, undo), `set_pool_pg_num` (med, undo), `set_pool_autoscale` (med, undo), `pool_create` (med) | 4 | write |
|
|
62
|
+
| | `set_pool_size` (high, dry-run), `pool_delete` (high, dry-run) | 2 | write |
|
|
63
|
+
| **RBD** | `rbd_ls` | 1 | read |
|
|
64
|
+
| | `rbd_image_create` (med), `rbd_snapshot_create` (low) | 2 | write |
|
|
65
|
+
| | `rbd_image_delete` (high, dry-run), `rbd_snapshot_delete` (high, dry-run) | 2 | write |
|
|
66
|
+
| **CephFS / RGW** | `cephfs_status`, `rgw_status` | 2 | read |
|
|
67
|
+
| **Cluster-ops** | `mon_status`, `mgr_status`, `slow_ops`, `capacity_forecast` | 4 | read |
|
|
68
|
+
| | `throttle_recovery` (med, undo) | 1 | write |
|
|
69
|
+
|
|
70
|
+
Totals: **35 tools — 17 read, 18 write.**
|
|
71
|
+
|
|
72
|
+
## Quick start
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
uv tool install ceph-aiops # or: pipx install ceph-aiops
|
|
76
|
+
ceph-aiops init # wizard: add a mgr target + store the Dashboard password (encrypted)
|
|
77
|
+
ceph-aiops doctor # JWT login + mgr-dashboard reachability
|
|
78
|
+
ceph-aiops overview # HEALTH status + active checks + OSD up/in
|
|
79
|
+
ceph-aiops health detail # decode the active HEALTH_WARN/ERR checks (RCA)
|
|
80
|
+
ceph-aiops osd df # per-OSD utilization, most-full first, near/backfill-full flags
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Run as an MCP server (stdio):
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
export CEPH_AIOPS_MASTER_PASSWORD=... # unlock secrets non-interactively
|
|
87
|
+
ceph-aiops-mcp
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Governance
|
|
91
|
+
|
|
92
|
+
Every MCP tool passes through the bundled `@governed_tool` harness:
|
|
93
|
+
|
|
94
|
+
- **Audit** — every call (params, result, status, duration, risk tier,
|
|
95
|
+
approver, rationale) is logged to `~/.ceph-aiops/audit.db` (relocatable
|
|
96
|
+
via `CEPH_AIOPS_HOME`).
|
|
97
|
+
- **Budget / runaway guard** — token and call budgets trip a circuit breaker.
|
|
98
|
+
- **Risk tiers** — graduated autonomy; high-risk ops (purge/delete/replica
|
|
99
|
+
change) can require a named approver
|
|
100
|
+
(`CEPH_AUDIT_APPROVED_BY` / `CEPH_AUDIT_RATIONALE`).
|
|
101
|
+
- **Undo recording** — reversible writes record an inverse descriptor.
|
|
102
|
+
|
|
103
|
+
## Supported scope & limitations
|
|
104
|
+
|
|
105
|
+
- **Deployments**: vanilla ceph-mgr with the **dashboard** module enabled —
|
|
106
|
+
cephadm, Proxmox-hosted Ceph, or MicroCeph. **No croit, no Kubernetes
|
|
107
|
+
dependency.**
|
|
108
|
+
- **Ceph has no ETag / pagination** on the Dashboard API, so this tool exposes
|
|
109
|
+
none — nothing is missing, the upstream API simply doesn't offer them.
|
|
110
|
+
- **Preview / mock-only.** Behaviour is validated against mocked Dashboard
|
|
111
|
+
responses. The cheapest **live** check is a single-node **MicroCeph**
|
|
112
|
+
(`snap install microceph` → bootstrap → loop-file OSDs) running
|
|
113
|
+
`ceph-aiops doctor`; a 3-node Vagrant cluster exercises real rebalance
|
|
114
|
+
behaviour. Multi-node rebalance and the write ops are **unverified against a
|
|
115
|
+
real cluster**.
|
|
116
|
+
|
|
117
|
+
## Missing a capability?
|
|
118
|
+
|
|
119
|
+
RGW multisite, per-daemon config sprawl, NFS-Ganesha exports, orchestrator
|
|
120
|
+
(cephadm) host management — not here yet. **Open an issue or send a PR** — feedback
|
|
121
|
+
and contributions are welcome.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Ceph AIops v0.1.0 — preview
|
|
2
|
+
|
|
3
|
+
Governed AI-ops for **Ceph** via the **ceph-mgr Dashboard REST API** for AI
|
|
4
|
+
agents, with a built-in governance harness (audit, policy, token/runaway
|
|
5
|
+
budget, undo-token recording, graduated risk tiers) and an encrypted credential
|
|
6
|
+
store. Standalone — no external skill-family dependency. Works against vanilla
|
|
7
|
+
ceph-mgr (cephadm / Proxmox-hosted / MicroCeph) — no croit, no Kubernetes.
|
|
8
|
+
|
|
9
|
+
> **Preview / mock-only.** All behaviour is validated against mocked Dashboard
|
|
10
|
+
> REST responses; it has not been run against a live Ceph cluster. The fastest
|
|
11
|
+
> live check is a single-node MicroCeph running `ceph-aiops doctor`.
|
|
12
|
+
|
|
13
|
+
## Highlights
|
|
14
|
+
|
|
15
|
+
- **35 MCP tools** (17 read, 18 write), every one wrapped with `@governed_tool`:
|
|
16
|
+
- **Health** — `cluster_health` (flagship: per active HEALTH_WARN/ERR check →
|
|
17
|
+
plain-language cause + suggested action), `cluster_status`.
|
|
18
|
+
- **OSD** — `osd_tree`, `osd_df` (most-full first + near/backfill-full flags),
|
|
19
|
+
`osd_perf`; writes `cluster_flag_set`, `osd_reweight`, `osd_mark_in`,
|
|
20
|
+
`osd_mark_out` (high), `osd_purge` (high).
|
|
21
|
+
- **PG** — `pg_summary`, `pg_dump_stuck`, `scrub_status`; `trigger_scrub`,
|
|
22
|
+
`trigger_deep_scrub`.
|
|
23
|
+
- **Pool** — `pool_ls`, `pool_df` (usable capacity = raw ÷ size); writes
|
|
24
|
+
`set_pool_quota`, `set_pool_pg_num`, `set_pool_autoscale`, `pool_create`,
|
|
25
|
+
`set_pool_size` (high), `pool_delete` (high).
|
|
26
|
+
- **RBD** — `rbd_ls`; `rbd_image_create`, `rbd_snapshot_create`,
|
|
27
|
+
`rbd_image_delete` (high), `rbd_snapshot_delete` (high).
|
|
28
|
+
- **CephFS / RGW** — `cephfs_status`, `rgw_status`.
|
|
29
|
+
- **Cluster-ops** — `mon_status`, `mgr_status`, `slow_ops`,
|
|
30
|
+
`capacity_forecast`; `throttle_recovery` (the #1 tuning ask —
|
|
31
|
+
`osd_max_backfills` / `osd_recovery_max_active`).
|
|
32
|
+
- **HEALTH_WARN root-cause analysis** — `cluster_health` decodes each active
|
|
33
|
+
check code into cause + action, the differentiator vs raw `ceph -s` proxies.
|
|
34
|
+
- **JWT auth** — username + password exchanged for a short-lived JWT at
|
|
35
|
+
`POST /api/auth`; the mgr **dashboard** module must be enabled.
|
|
36
|
+
- **Encrypted secret store** (`~/.ceph-aiops/secrets.enc`, Fernet + scrypt) —
|
|
37
|
+
never plaintext on disk; legacy `CEPH_<TARGET>_PASSWORD` env fallback.
|
|
38
|
+
- **CLI** with an `init` onboarding wizard, `secret` management, and `doctor`.
|
|
39
|
+
- **Dry-run + double-confirm** on the destructive ops operators fear
|
|
40
|
+
(`osd_purge`, `osd_mark_out`, `pool_delete`, `set_pool_size`,
|
|
41
|
+
`rbd_image_delete`); reversible writes record an undo descriptor.
|
|
42
|
+
|
|
43
|
+
## Install
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
uv tool install ceph-aiops
|
|
47
|
+
ceph-aiops init
|
|
48
|
+
ceph-aiops doctor
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Caveats
|
|
52
|
+
|
|
53
|
+
- Preview / mock-only: multi-node rebalance behaviour and the write ops are
|
|
54
|
+
unverified against a real cluster.
|
|
55
|
+
- The Dashboard API has no ETag / pagination, so this tool exposes none.
|
|
56
|
+
- Out of scope for v0.1.0: RGW multisite, NFS-Ganesha exports, and cephadm
|
|
57
|
+
orchestrator host management.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Disclaimer
|
|
4
|
+
|
|
5
|
+
Community-maintained open-source project. **Not affiliated with, endorsed by, or
|
|
6
|
+
sponsored by the Ceph project or the Ceph Foundation.** Product and trademark
|
|
7
|
+
names belong to their owners. Source is publicly auditable under the MIT license.
|
|
8
|
+
|
|
9
|
+
## Reporting Vulnerabilities
|
|
10
|
+
|
|
11
|
+
Report privately via a GitHub Security Advisory on
|
|
12
|
+
[github.com/AIops-tools/Ceph-AIops](https://github.com/AIops-tools/Ceph-AIops/security/advisories)
|
|
13
|
+
or email zhouwei008@gmail.com. Please do not open public issues for security
|
|
14
|
+
reports.
|
|
15
|
+
|
|
16
|
+
## Security Design
|
|
17
|
+
|
|
18
|
+
### Credential Management
|
|
19
|
+
- Per-target ceph-mgr Dashboard passwords live **encrypted** in
|
|
20
|
+
`~/.ceph-aiops/secrets.enc` (Fernet/AES-128 + scrypt-derived key; chmod
|
|
21
|
+
600), never in `config.yaml` and never in source. The master password is
|
|
22
|
+
never stored — only a per-store random salt and the ciphertext are on disk.
|
|
23
|
+
- A legacy plaintext env var `CEPH_<TARGET_NAME_UPPER>_PASSWORD` is still
|
|
24
|
+
honoured as a fallback with a deprecation warning (migrate with
|
|
25
|
+
`ceph-aiops secret migrate`).
|
|
26
|
+
- The password is exchanged for a short-lived **JWT** at `POST /api/auth`; only
|
|
27
|
+
the token is sent on subsequent requests (Bearer), and it is refreshed once on
|
|
28
|
+
a 401. The password is held only in memory, never logged or echoed; the config
|
|
29
|
+
file holds only host, port, username, and TLS settings.
|
|
30
|
+
|
|
31
|
+
### Governed Operations
|
|
32
|
+
Every MCP tool runs through the bundled `@governed_tool` harness
|
|
33
|
+
(`ceph_aiops.governance`):
|
|
34
|
+
- **Audit** — every call logged to a local SQLite DB under `~/.ceph-aiops/`
|
|
35
|
+
(relocatable via `CEPH_AIOPS_HOME`), agent-attributed, secret-redacted.
|
|
36
|
+
- **Token/runaway budget** — hard ceilings (`CEPH_MAX_TOOL_CALLS` /
|
|
37
|
+
`CEPH_MAX_TOOL_SECONDS`) plus an on-by-default guard that trips a tight
|
|
38
|
+
poll/retry loop, preventing unbounded API consumption (e.g. polling a slow
|
|
39
|
+
session).
|
|
40
|
+
- **Graduated risk tiers** — `~/.ceph-aiops/rules.yaml` `risk_tiers` gate
|
|
41
|
+
writes by environment/tag; the highest tiers require a recorded approver.
|
|
42
|
+
- **Undo-token recording** — reversible writes capture the BEFORE state and
|
|
43
|
+
record an inverse descriptor (e.g. `osd_reweight`→restore prior weight,
|
|
44
|
+
`cluster_flag_set`→toggle the flag back, `throttle_recovery`→restore prior
|
|
45
|
+
backfill/recovery limits) so the change can be rolled back.
|
|
46
|
+
|
|
47
|
+
### State-Changing Operations
|
|
48
|
+
Destructive writes — `osd_mark_out`, `osd_purge`, `set_pool_size`, `pool_delete`,
|
|
49
|
+
`rbd_image_delete`, `rbd_snapshot_delete` — are `risk_level=high`, accept a
|
|
50
|
+
`dry_run` preview, and (under `risk_tiers`) require a recorded approver
|
|
51
|
+
(`CEPH_AUDIT_APPROVED_BY` + `CEPH_AUDIT_RATIONALE`). The CLI additionally
|
|
52
|
+
double-confirms `osd out` and `osd purge` and supports `--dry-run`. Reversible
|
|
53
|
+
medium/low writes capture before-state and, where a safe inverse exists, record
|
|
54
|
+
an undo token. Ceph has no ETag/If-Match and its list endpoints return full
|
|
55
|
+
arrays, so there is no optimistic-concurrency token to manage.
|
|
56
|
+
|
|
57
|
+
### SSL/TLS Verification
|
|
58
|
+
`verify_ssl` defaults to true; disable only for self-signed lab certificates.
|
|
59
|
+
|
|
60
|
+
### Prompt-Injection Protection
|
|
61
|
+
All server-returned text (pool/OSD names, PG ids, health check messages, RGW
|
|
62
|
+
bucket names) is passed through a `sanitize()` truncate + control-character strip
|
|
63
|
+
before reaching the agent.
|
|
64
|
+
|
|
65
|
+
### Network Scope
|
|
66
|
+
No webhooks, no telemetry, no outbound calls beyond the configured ceph-mgr
|
|
67
|
+
Dashboard REST API endpoint. No post-install scripts or background services.
|
|
68
|
+
|
|
69
|
+
## Static Analysis
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
uvx bandit -r ceph_aiops/ mcp_server/
|
|
73
|
+
uv run ruff check .
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Supported Versions
|
|
77
|
+
|
|
78
|
+
The latest released version receives security fixes. This is a preview (0.x);
|
|
79
|
+
pin a version in production.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""ceph-aiops — governed Ceph SCALE 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 ``ceph_aiops.governance`` — this package has no external
|
|
6
|
+
skill-family dependency. Preview: not yet full-coverage.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Shared helpers for ceph-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
|
+
DryRunOption = Annotated[
|
|
21
|
+
bool, typer.Option("--dry-run", help="Print the API call without executing")
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _cli_error_types() -> tuple[type[BaseException], ...]:
|
|
26
|
+
"""Exceptions translated to a one-line teaching error instead of a traceback."""
|
|
27
|
+
from ceph_aiops.connection import CephApiError
|
|
28
|
+
|
|
29
|
+
return (CephApiError, KeyError, OSError, ValueError)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def cli_errors(fn: Callable) -> Callable:
|
|
33
|
+
"""Translate known exceptions into one red line + exit code 1."""
|
|
34
|
+
|
|
35
|
+
@functools.wraps(fn)
|
|
36
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
37
|
+
try:
|
|
38
|
+
return fn(*args, **kwargs)
|
|
39
|
+
except (typer.Exit, typer.Abort):
|
|
40
|
+
raise
|
|
41
|
+
except _cli_error_types() as e:
|
|
42
|
+
message = str(e)
|
|
43
|
+
if isinstance(e, KeyError):
|
|
44
|
+
message = f"Missing required key or environment variable: {message}"
|
|
45
|
+
console.print(f"[red]Error: {message}[/]")
|
|
46
|
+
raise typer.Exit(1) from e
|
|
47
|
+
|
|
48
|
+
return wrapper
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def get_connection(target: str | None, config_path: Path | None = None):
|
|
52
|
+
"""Return a (conn, config) tuple for the given target."""
|
|
53
|
+
from ceph_aiops.config import load_config
|
|
54
|
+
from ceph_aiops.connection import ConnectionManager
|
|
55
|
+
|
|
56
|
+
cfg = load_config(config_path)
|
|
57
|
+
mgr = ConnectionManager(cfg)
|
|
58
|
+
return mgr.connect(target), cfg
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def dry_run_print(*, operation: str, api_call: str, parameters: dict | None = None) -> None:
|
|
62
|
+
"""Print a dry-run preview of the API call that would be made."""
|
|
63
|
+
console.print("\n[bold magenta][DRY-RUN] No changes will be made.[/]")
|
|
64
|
+
console.print(f"[magenta] Operation: {operation}[/]")
|
|
65
|
+
console.print(f"[magenta] API Call: {api_call}[/]")
|
|
66
|
+
for k, v in (parameters or {}).items():
|
|
67
|
+
console.print(f"[magenta] Param: {k} = {v}[/]")
|
|
68
|
+
console.print("[magenta] Run without --dry-run to execute.[/]\n")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def double_confirm(action: str, resource: str) -> None:
|
|
72
|
+
"""Require two confirmations for a destructive operation."""
|
|
73
|
+
console.print(f"[bold yellow]⚠️ About to: {action} '{resource}'[/]")
|
|
74
|
+
typer.confirm(f"Confirm 1/2: {action} '{resource}'?", abort=True)
|
|
75
|
+
typer.confirm(
|
|
76
|
+
f"Confirm 2/2: really {action} '{resource}'? This may be irreversible.",
|
|
77
|
+
abort=True,
|
|
78
|
+
)
|
|
@@ -0,0 +1,57 @@
|
|
|
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 ceph_aiops.cli._common import cli_errors
|
|
8
|
+
from ceph_aiops.cli.doctor import doctor_cmd
|
|
9
|
+
from ceph_aiops.cli.health import health_app
|
|
10
|
+
from ceph_aiops.cli.init import init_cmd
|
|
11
|
+
from ceph_aiops.cli.osd import osd_app
|
|
12
|
+
from ceph_aiops.cli.overview import overview_cmd
|
|
13
|
+
from ceph_aiops.cli.secret import secret_app
|
|
14
|
+
|
|
15
|
+
app = typer.Typer(
|
|
16
|
+
name="ceph-aiops",
|
|
17
|
+
help="Governed AI-ops for Ceph (mgr Dashboard REST): health RCA, OSD/PG/pool, "
|
|
18
|
+
"RBD/CephFS/RGW, recovery, capacity.",
|
|
19
|
+
no_args_is_help=True,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
app.add_typer(health_app, name="health")
|
|
23
|
+
app.add_typer(osd_app, name="osd")
|
|
24
|
+
app.add_typer(secret_app, name="secret")
|
|
25
|
+
app.command("init")(init_cmd)
|
|
26
|
+
app.command("overview")(overview_cmd)
|
|
27
|
+
app.command("doctor")(doctor_cmd)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@app.command("mcp")
|
|
31
|
+
@cli_errors
|
|
32
|
+
def mcp_cmd() -> None:
|
|
33
|
+
"""Start the MCP server (stdio transport).
|
|
34
|
+
|
|
35
|
+
Single-command entry point for MCP clients (does not go through uvx/PyPI
|
|
36
|
+
resolution at launch):
|
|
37
|
+
ceph-aiops mcp
|
|
38
|
+
"""
|
|
39
|
+
import sys
|
|
40
|
+
|
|
41
|
+
if sys.version_info < (3, 11):
|
|
42
|
+
typer.echo(
|
|
43
|
+
f"ERROR: ceph-aiops requires Python >= 3.11 "
|
|
44
|
+
f"(got {sys.version_info.major}.{sys.version_info.minor}).\n"
|
|
45
|
+
f"Fix: uv python install 3.12 && "
|
|
46
|
+
f"uv tool install --python 3.12 --force ceph-aiops",
|
|
47
|
+
err=True,
|
|
48
|
+
)
|
|
49
|
+
raise typer.Exit(2)
|
|
50
|
+
|
|
51
|
+
from mcp_server.server import main as _mcp_main
|
|
52
|
+
|
|
53
|
+
_mcp_main()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
if __name__ == "__main__":
|
|
57
|
+
app()
|
|
@@ -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 ceph_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 environment, config, secrets, and connectivity."""
|
|
19
|
+
from ceph_aiops.doctor import run_doctor
|
|
20
|
+
|
|
21
|
+
raise typer.Exit(run_doctor(skip_auth=skip_auth))
|