Metadata-Version: 2.5
Name: noc-ops
Version: 0.1.2
Summary: 多云运维 ops CLI —— 9 朵云（AWS / 阿里云 / 腾讯云 / 火山引擎 / GCP / Azure / Oracle / Cloudflare / Supabase）+ 本地网络机器：清单同步、运维看板、定时重启、Claude Code / Codex skill；可选 MCP
Project-URL: Homepage, https://github.com/pholex/noc-ops
Project-URL: Repository, https://github.com/pholex/noc-ops
Project-URL: Skill, https://github.com/pholex/multicloud-ops
Author: Fenghuang
License-Expression: Apache-2.0
License-File: LICENSE
License-File: NOTICE
Keywords: aliyun,aws,azure,claude-code,devops,gcp,multicloud,noc,oci,ops,skill,tencent-cloud
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: System :: Systems Administration
Requires-Python: >=3.10
Provides-Extra: all
Requires-Dist: mcp<3,>=2.2.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: mcp<3,>=2.2.0; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: pyyaml; extra == 'dev'
Provides-Extra: mcp
Requires-Dist: mcp<3,>=2.2.0; extra == 'mcp'
Provides-Extra: sangfor
Requires-Dist: pycryptodome; extra == 'sangfor'
Description-Content-Type: text/markdown

# NOC — 多云运维 ops CLI

用自然语言运维多云机群（AWS / 阿里云 / 腾讯云 / 火山引擎 / Google Cloud / Azure / Oracle，另只读纳管 Cloudflare / Supabase）的 `ops` CLI：核心只用 Python 标准库，负责清单同步、运维看板、定时重启、读写闸门；**agent 入口是一份 skill**（[pholex/multicloud-ops](https://github.com/pholex/multicloud-ops)），装进 Claude Code / Codex / Cursor / Gemini CLI / Kiro / Cline 等任何带 shell 的 agent 客户端即可用，模型由客户端自带。
可选组件：`[mcp]` 给没有 shell 的 GUI 客户端（Claude Desktop）接 MCP。终端内的自然语言入口 `ops "<指令>"` 不在公开包里，由扩展包经 entry point `noc_ops.default_command` 提供。各入口共享 `providers + sync + aws_safety + schedule_ops` 这套底座。
能力随日常运维不断**沉淀**：每做一项新运维，就存成一个 runbook，攒一段时间后接管大部分日常工作。

## 代码与工作区（分离）

**代码**（pip/uv 装进 venv，只读）：
```
src/noc_ops/
├── cli.py            # `ops` 入口：分发 sync/noc/doctor/setup，默认走 agent
├── sync.py           # 扫实例/域名/RDS/S3/Lambda/CloudFront/IAM/AI 密钥(Bedrock key)/SQS·SNS·SES·EventBridge/成本/账务额度，生成 inventory+data.json+ssh config
├── mcp_server.py     # MCP server（`ops-mcp` 入口，给 Codex 等）
├── schedule_ops.py   # 计划任务（定时重启，EventBridge + Lambda 派发）
├── aws_safety.py     # 读/写操作分类器（权限闸门）
├── ops_log.py        # 操作日志（写操作审计流水）
├── paths.py          # 工作区路径解析（代码↔数据分离）
├── doctor.py / setup_clients.py   # 体检 / 多客户端一键安装
├── providers/        # 多云驱动：base + aws/aliyun/tencent/volcengine/gcp/azure/oracle/cloudflare/supabase/synology/vmware/sangfor/local
├── dashboard/        # 看板前端（server.py + index.html + 自托管 ag-Grid/字体）
├── skill/SKILL.md.tmpl            # Claude Code skill 模板（setup 时渲染安装）
└── assets/runbooks/  # 全新安装的种子 runbook
```

**工作区**（可变数据，默认 `~/.noc`，可用 `NOC_HOME` 或 `ops setup --workspace` 指定）：
```
<workspace>/
├── inventory.md      # 实例+域名+账务额度清单（人读，sync 生成）
├── data.json         # 机读数据（sync 生成，看板/MCP 用）
├── runbooks/*.md     # 能力库（用户沉淀，随用增长；升级不丢）
└── .state/           # 运行时状态（ssh 用户缓存 / 快照 / 操作日志）
```

## 安装与运行

支持 macOS / Linux（纯 Python 包）。一行装（推荐）：`curl -fsSL https://<host>/install.sh | sh`（自动装 uv + 从 PyPI 装 + 接入客户端）。或手动：

```bash
uv tool install noc-ops                     # 或 pipx install noc-ops；开发者：uv tool install <本仓路径>
uv tool install --force 'noc-ops[mcp]'      # 可选：ops-mcp，仅无 shell 的 GUI 客户端（Claude Desktop）需要
ops setup [--workspace ~/Developer/noc]    # 记工作区 + 经 `skills` CLI 把 skill 扇出到所有已装客户端（skill 优先）
ops init                                    # 交互式生成配置（发现账号/区域/SSH key，免手编 TOML）
ops doctor --fix                            # 体检：云 CLI 依赖 / 凭证 / 工作区 / 客户端；--fix 自动修

ops "宁夏有几台 EC2 在运行"                 # 一次性指令（任意目录可跑）
ops                                         # 进入交互模式（推荐：边做边沉淀）
ops sync                                    # 同步实例清单 + SSH 配置（新增实例后跑）
ops sync --account=<账号>                   # 只刷某一个云账号（AWS 账号 ID / 阿里云 profile 名）
ops noc                                     # 启动 NOC 运维看板（默认后台；status/stop/restart 管理）
```

前置：用到哪朵云就装好对应 CLI 并配好凭证（`aws` / `aliyun` / `tccli` / `ve` / `gcloud` / `az` / `oci`；`ops doctor` 会逐项检查，没装 CLI 的云 `ops sync` 自动跳过）。
渠道 **skill 优先**；无 shell 的 GUI 客户端（如 Claude Desktop）才需 `ops setup --with-mcp`（外包 `npx add-mcp`，含 Claude Desktop）。

## ops noc — NOC 运维看板

`ops noc` 启动本地服务（默认 `http://127.0.0.1:8765`），用 **ag-Grid**（社区版，MIT）密集表格
呈现全部实例：状态灯、账号、区域（旗帜）、类型、IP、实例 ID（点击复制）、登录用户、直连/跳板/SSM（无密钥对的 AWS 实例视为仅 SSM Session Manager 可达，不配 SSH）。
顶部标签页分类展示 **实例 / 域名 / 数据库 / 存储 / 函数 / CDN / IAM / AI 密钥 / 消息·事件 / 成本 / 计划任务 / 剧本 / 操作日志** 十三类；「剧本」页列出 `runbooks/` 全部剧本（标题/沉淀时间/是否写操作/触发意图），点剧本名即在新页打开其 markdown（`/runbook?name=<名>`，限定在 runbooks 目录内）。
支持按账号/区域/状态筛选、关键字搜索、点表头排序、列宽拖拽/重排、每列筛选菜单、**导出 CSV**。
Quartz 主题跟随系统明暗。右上「刷新」触发一次 `ops sync`（重扫 AWS + 探测新机器）再重载。
数据来自 `<workspace>/data.json`（由 `ops sync` 生成）。

> 账号级的**账务/额度**（`credits` 键：信用余额、免费额度到期、超额保护、预算告警）没有独立 tab——它是账号状态而非资源清单，渲染在 `inventory.md` 的「💳 云账务 / 额度」节，刷新用 `ops sync --kind=credits`。与「成本」tab 的分工：credits 是「还剩多少、超额会怎样」，billing 是「花了多少」的流水。

> 「AI 密钥」tab 只盘点**元数据**（限定到哪个 API、绑定的服务账号、客户端限制、创建时间），**永远不取密钥串**（不调 `get-key-string`，data.json / inventory 里不会出现 key 本体）。目前接了两朵云：GCP 的 Cloud API Keys（AI Studio 的 Gemini key 与 Vertex AI Express key 本质都是它，按 `apiTargets` 标成「Gemini API」/「Vertex AI」，只盘 AI 用途；无限制 key 标红，Google 已在封禁闲置的无限制 key；项目需启用 `apikeys.googleapis.com`）和 AWS 的 Bedrock 长期 API key（IAM 服务专用凭证，含 Claude Platform on AWS key；只盘全球区（`--all-users` 一次列全；中国区不支持该参数，直接跳过）；短期 12h key 本地签出、不可列）。阿里云百炼 key 没有列表 OpenAPI，暂未纳管。刷新 `ops sync --kind=apikeys`。

ag-Grid 的 JS、Inter 字体均**本地自托管在 `src/noc_ops/dashboard/vendor/`、不走第三方 CDN**（遵全局规则）；
看板服务用 Python stdlib 起、运行期不拉外部包。
（注：这里说的是「看板运行期」的取舍——不是全工程教条。`ops setup` 装 skill 时会按需调用
`skills` CLI（`npx skills`，节点级工具）做多客户端扇出；用对的成熟工具优先于死守零依赖。）

**生命周期**：`ops noc` **默认后台守护启动**（detach，关终端不死，日志写 `<workspace>/.state/noc.log`），立即返回。
- `ops noc status` — 看在不在跑（PID / URL）
- `ops noc stop` — 停掉（只杀 noc 自己的监听进程，非 noc 占用仅告警）
- `ops noc restart` — 停旧启新
- `ops noc -f` — 前台跑（占终端、Ctrl+C 退出，调试用）

选项：`ops noc --port 9000 --no-open`（可与上面组合）。

## ops sync — 实例清单/SSH 配置同步

新增或变更 EC2 后跑 `ops sync`，它会全量扫描、对比快照、报告 新增/变更/删除，并重新生成
`inventory.md` 与 `~/.ssh/config`（marker 段）。私钥按约定 `~/.ssh/<profile>/<KeyName>.pem`
自动推导；登录用户名（ec2-user / ubuntu / centos）对未缓存实例自动探测一次并缓存（幂等，日常只探新机器）。

不必每次都全量重扫，可按两个维度收窄（都是 patch 式合并写回 `data.json`，不整份覆盖）：

```bash
ops sync --kind=instances                          # 按资源类型收窄（看板「按 tab 单刷」），扫所有账号
ops sync --account=123456789012                    # 按 AWS 账号收窄：只扫该账号（~25s vs 全量一两分钟）
ops sync --account=123456789012 --kind=instances   # 两者组合：只刷该账号的实例（~3s）
ops sync --account=<aliyun-profile>                          # 阿里云账号也认（profile 名或账号 ID，~2s）
ops sync --probe=<实例名|ID>                       # 只探这一台 AWS 实例的 SSH 登录用户名并回写 config（零云 API，几秒）
```

`--account=` 只重扫指定账号，同云其它账号 / 其它云的行原样沿用；`~/.ssh/config` 的托管段虽是整段
重写，但沿用账号的 Host 会一并还原写回（产出与全账号刷新逐字节一致）。`inventory.md` 与实例快照
是全量产物、两条收窄路径都不动它们。

账号名按云解析：**AWS** 用账号 ID，**阿里云**用 CLI profile 名（如 `<profile>`）或账号 ID 都行。
各云能按账号刷的资源类型不同（AWS 九类；阿里云 = 实例/存储/域名，即 provider 真会产出的），
点名了该云没有的类型会直接拒绝并列出可用值。

非公网机器（VMware / Sangfor HCI / 群晖 / 本地物理机）**不参与全量 sync**（连不上时不该被误判
"已删除"），按**网络域**分两条命令单刷，各有各的门控，互不覆盖：

```bash
ops sync --local        # 只刷内网机器（network=lan）；门控 = local_net.probe 内网探针
ops sync --tailscale    # 只刷 Tailscale 组网上的机器；门控 = `tailscale status`
ops sync --index        # 只刷 runbooks/操作日志索引进 data.json（零网络，秒级）
```

网络域按端点地址自动推导（`100.64.0.0/10` 或 `*.ts.net` → tailscale，其余 → lan），
账号里显式写 `network = "tailscale"` 可覆盖。两个域**故意不合并**——"连不上"的含义不同：
内网看人在不在内网，Tailscale 看 tailscaled 跑没跑、对端节点是否 Online。详见
`runbooks/sync-inventory.md` 与 `src/noc_ops/netprobe.py`。
账号在 `src/noc_ops/providers/aws.py` 的 `ACCOUNTS` 维护；别名前缀/跳板在 `src/noc_ops/sync.py` 的 `ALIAS_PREFIX`/`JUMPS`。详见 `runbooks/sync-inventory.md`。

可选环境变量：`OPS_MODEL`（默认 `claude-sonnet-4-6`）。

## ops reboot — 重启一台实例（公有云 + 本地 HCI 同一入口）

```bash
ops reboot <实例名|ID>            # 重启：按 cloud 自动选通道
ops reboot <实例名|ID> --status   # 只查实时状态（只读），重启后隔 ~40 秒用它复查
ops reboot <实例名|ID> --dry-run  # 只打印将要执行的命令
```

通道按 `cloud` 走 `Provider.reboot_argv`：AWS `aws ec2 reboot-instances`、腾讯 `RebootInstances`、
阿里 `RebootInstance`、火山 `ecs RebootInstance`（优雅）、GCP `instances reset`（硬）、Azure `vm restart`、Oracle `SOFTRESET`，
**VMware 走 vCenter REST、深信服 HCI 走 SCP 管控 API**（两者都是 Token 认证 + Keychain 取密码，
CLI 拼不出来——这也是本命令存在的理由：以前只有 MCP server 接了这条通道，走 skill 的
Claude Code / Codex 够不着）。群晖 / ESXi 宿主 / Cloudflare / Supabase 没有管控 API，
会**如实拒绝并给出该走哪条路**（DSM、SSH 别名、控制台），不抛异常。

> ⚠️ **深信服目前只有 `--status` 可用**：这版 SCP 不认现有重启端点（实测 404），命令会如实报错
> 并指向替代路径（Linux 走 SSH、Windows 去控制台）。端点考古与下一步见「待办」。

目标解析由严到宽：精确 ID → 精确名 → 忽略大小写 → 唯一子串；**匹配到多台一律列出来让你挑**
（`srv07/srv08`、`泛微OA 应用/数据库` 这类同前缀名太多，猜错就是重启错生产机）。
重启属低风险可逆，按安全模型**免二次确认**直接执行，并自动记一条操作日志（`--source` 声明调用方）。

## 安全模型

| 操作类型 | 行为 |
|---|---|
| 只读（describe/list/get、df/状态查询等） | **自动执行**，不打扰 |
| 实例重启（`ops reboot`、各云 reboot API） | **自动执行**，低风险可逆；自动记审计日志 |
| 其它写操作（启停/销毁/改配置、远程改动、写文件） | **先弹确认**，y 才执行 |

分类逻辑在 `src/noc_ops/aws_safety.py`，保守原则：**拿不准一律当写操作、要确认**。

> ⚠️ 关键实现点：写操作工具**不能**放进 `ClaudeAgentOptions.allowed_tools`——那会被 SDK 自动批准、绕过确认回调。只有纯只读内置工具（Read/Glob/Grep）放 allowed_tools，其余都走 `can_use_tool` 闸门。

## 怎么加一项新能力（沉淀 runbook）

1. 在交互模式里和 Agent 一起把某项运维做完。
2. Agent 会主动问要不要沉淀；同意后它按 `_TEMPLATE.md` 在 `runbooks/` 生成剧本。
3. 下次遇到同类需求，Agent 会先 Glob 到这个剧本、照着执行。

**加能力 ≈ 写一个 markdown，不用改代码。**

## 开发 / 测试

改本仓代码时的约定（代码与工作区分离、改完必须重装、同步清单、提交规范）见 `CLAUDE.md`，这里只列最常用的三条。

**测试**

```bash
uv run --extra dev pytest -m unit -q     # Tier 1：离线、零 LLM、秒级，改完就跑

```

公开仓只有离线单元测试（Tier 1）。单测读的是匿名化夹具 `tests/fixtures/workspace/ops-config.toml`，不读任何真实工作区。

**改完 `src/` 要重装全局 `ops`**：全局 `ops` 是 `uv tool` 装的 wheel 拷贝，不跟随 `src/`。`uv tool install --force --no-cache <本仓路径>`，否则「代码改好了、跑起来还是旧行为」。

**新增 provider / 资源种类 / 看板 tab 的同步清单**：`providers/<cloud>.py` + `sync.py` → `dashboard/index.html` → `skill/SKILL.md.tmpl`（公开 skill 仓 pholex/multicloud-ops 同步）→ 本 README → `ops setup` 重扇出 skill 再重装。漏一处就出现「看板有、agent 不知道」。

**数据文件不入库**：仓根目录同时就是工作区，`data.json` / `inventory.md` / `.state/` / `local-servers.toml` / `ops-config.toml` / `runbooks/` 都是工作区数据，已在 `.gitignore`。秘密（token / PAT / 密码）走系统 Keychain 或 Parameter Store，不进仓库、也不进 `ops-config.toml`。

## 插件子命令（entry point）

公司 / 团队专属的子命令不进公开 wheel，放在自己的私有包里，经 entry point 组 `noc_ops.commands` 挂回 `ops`：

```toml
# 私有包的 pyproject.toml
[project]
dependencies = ["noc-ops"]
[project.entry-points."noc_ops.commands"]

acme = "acme_ops.skill_fragment:fragment"            # 无参返回 markdown；ops setup 渲染 skill 时拼在末尾
```

装法：`uv tool install 'noc-ops[all]' --with <你的插件包>`。`ops help` 末尾会列出已装的插件命令；内建命令名不可被插件覆盖；插件加载失败只报该命令、不影响 `ops` 其余功能。插件读自己的配置段用 `deploy_config.section("<段名>")`；插件专属的 agent 使用规则经 `noc_ops.skill_fragments` 随包提供，`ops setup` 自动拼进完整版 skill，不必改公开模板。

## 许可

Apache License 2.0，见 `LICENSE` 与 `NOTICE`。看板自托管的第三方前端组件（AG Grid Community / Inter 字体）各随其原许可（MIT / OFL 1.1）。
