@sema-agent/server 7.103.1 → 7.104.0
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.
- package/MIGRATION.md +362 -3
- package/README.md +6 -1
- package/README.zh-CN.md +5 -1
- package/USAGE.md +279 -18
- package/deploy/sema-up/README.md +57 -7
- package/deploy/sema-up/cluster-up.sh +18 -4
- package/deploy/sema-up/kube-up.sh +16 -0
- package/deploy/sema-up/lib/dataroot.sh +142 -0
- package/deploy/sema-up/lib/flagshape.sh +69 -0
- package/deploy/sema-up/lib/lanes.py +14 -4
- package/deploy/sema-up/lib/shell-access.sh +41 -0
- package/deploy/sema-up/preflight.sh +14 -1
- package/deploy/sema-up/sema-up.sh +134 -37
- package/deploy/sema-up/smoke.sh +5 -0
- package/dist/auto-mode-face.js +3 -4
- package/dist/boot/budget-tracing.js +1 -1
- package/dist/boot/config-center.d.ts +6 -2
- package/dist/boot/config-center.js +5 -59
- package/dist/boot/execution-env.d.ts +11 -0
- package/dist/boot/execution-env.js +14 -0
- package/dist/boot/execution-lane.d.ts +25 -0
- package/dist/boot/execution-lane.js +95 -0
- package/dist/boot/memory-consolidation.d.ts +185 -9
- package/dist/boot/memory-consolidation.js +192 -32
- package/dist/boot/resolve-spec.d.ts +2 -0
- package/dist/boot/resolve-spec.js +28 -24
- package/dist/boot/runner-deps.d.ts +6 -2
- package/dist/boot/runner-deps.js +4 -0
- package/dist/boot/session-faces.d.ts +5 -0
- package/dist/boot/session-faces.js +18 -2
- package/dist/boot/session-incarnation-seat.d.ts +41 -0
- package/dist/boot/session-incarnation-seat.js +69 -0
- package/dist/boot/stage-01-config.js +2 -2
- package/dist/boot/stage-02-registry-pull.js +3 -1
- package/dist/boot/stage-04-stores.d.ts +2 -0
- package/dist/boot/stage-04-stores.js +3 -1
- package/dist/boot/stage-05-execution-env.d.ts +4 -0
- package/dist/boot/stage-05-execution-env.js +2 -2
- package/dist/boot/stage-06-runners.d.ts +4 -1
- package/dist/boot/stage-06-runners.js +7 -14
- package/dist/boot/stage-07-capability-layer.d.ts +4 -1
- package/dist/boot/stage-08-reapers.d.ts +4 -1
- package/dist/boot/stage-09-leader.d.ts +6 -1
- package/dist/boot/stage-09-leader.js +2 -1
- package/dist/boot/stage-10-http-server.d.ts +6 -1
- package/dist/boot/stage-10-http-server.js +4 -1
- package/dist/brain.d.ts +1 -1
- package/dist/config-catalog.d.ts +16 -1
- package/dist/config-catalog.js +9 -9
- package/dist/config-center/restart-signal.d.ts +4 -4
- package/dist/config-invariants.d.ts +7 -1
- package/dist/config-invariants.js +37 -6
- package/dist/config-provider.d.ts +42 -10
- package/dist/config-provider.js +18 -16
- package/dist/config-types.d.ts +37 -16
- package/dist/config-types.js +1 -0
- package/dist/config.d.ts +13 -28
- package/dist/config.js +53 -70
- package/dist/env-facts.d.ts +13 -3
- package/dist/env-facts.js +15 -3
- package/dist/execution-lane-caps.d.ts +15 -0
- package/dist/execution-lane-caps.js +8 -0
- package/dist/file-history-capture.d.ts +42 -35
- package/dist/file-history-capture.js +15 -10
- package/dist/host-lsp-manager.d.ts +1 -1
- package/dist/http/admission.d.ts +11 -4
- package/dist/http/admission.js +5 -1
- package/dist/http/dispatch.js +3 -3
- package/dist/http/principal-gate.d.ts +22 -0
- package/dist/http/principal-gate.js +20 -0
- package/dist/http/resume-legs.js +9 -5
- package/dist/http/routes/agents-roster.d.ts +7 -0
- package/dist/http/routes/agents-roster.js +6 -2
- package/dist/http/routes/approvals-assistant.d.ts +48 -19
- package/dist/http/routes/approvals-assistant.js +117 -50
- package/dist/http/routes/capabilities.js +3 -2
- package/dist/http/routes/config-catalog.js +1 -0
- package/dist/http/routes/memory-consolidation.d.ts +3 -2
- package/dist/http/routes/memory-policy.js +3 -3
- package/dist/http/routes/rules.js +2 -2
- package/dist/http/routes/runs.js +27 -2
- package/dist/http/routes/session-sync.js +8 -14
- package/dist/http/routes/sessions-list.js +3 -2
- package/dist/http/routes/sessions.js +44 -23
- package/dist/http/routes/shared-memory.js +2 -2
- package/dist/http/routes/tasks.js +22 -19
- package/dist/http/routes/trace-usage.js +4 -4
- package/dist/http/send.d.ts +12 -0
- package/dist/http/send.js +12 -1
- package/dist/http/server.d.ts +21 -4
- package/dist/http/server.js +7 -4
- package/dist/http/sync-submit-body.d.ts +43 -0
- package/dist/http/sync-submit-body.js +4 -0
- package/dist/http/wire-types.d.ts +23 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/leader/merge.d.ts +8 -3
- package/dist/memory-incident-sink.js +2 -1
- package/dist/model-select.d.ts +9 -0
- package/dist/model-select.js +5 -1
- package/dist/observability/corrupt-read-seat.d.ts +151 -16
- package/dist/observability/corrupt-read-seat.js +158 -15
- package/dist/observability/fail-open.d.ts +12 -0
- package/dist/observability/fail-open.js +12 -0
- package/dist/observability/run-terminal.d.ts +15 -1
- package/dist/observability/run-terminal.js +4 -0
- package/dist/parked-decide.d.ts +8 -3
- package/dist/parked-decide.js +56 -20
- package/dist/parked-revive-surface.d.ts +14 -7
- package/dist/parked-revive-surface.js +5 -1
- package/dist/plugins/approval-ask-store-file.d.ts +4 -1
- package/dist/plugins/approval-ask-store-file.js +9 -12
- package/dist/plugins/approval-ask-store-sql.d.ts +4 -0
- package/dist/plugins/approval-ask-store-sql.js +4 -1
- package/dist/plugins/approval-exemption-store.d.ts +21 -1
- package/dist/plugins/approval-exemption-store.js +36 -7
- package/dist/plugins/approval-nonce-store.d.ts +16 -2
- package/dist/plugins/approval-nonce-store.js +17 -7
- package/dist/plugins/caching-session-store.d.ts +5 -0
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/file-resume-anchor-store.d.ts +7 -2
- package/dist/plugins/file-resume-anchor-store.js +19 -5
- package/dist/plugins/file-run-store.d.ts +21 -8
- package/dist/plugins/file-run-store.js +60 -38
- package/dist/plugins/local-session-store.d.ts +22 -0
- package/dist/plugins/local-session-store.js +74 -11
- package/dist/plugins/memory-run-store.d.ts +7 -5
- package/dist/plugins/memory-run-store.js +11 -4
- package/dist/plugins/one-time-migrations.d.ts +38 -1
- package/dist/plugins/one-time-migrations.js +143 -15
- package/dist/plugins/permission-rule-store-file.d.ts +9 -2
- package/dist/plugins/permission-rule-store-file.js +37 -51
- package/dist/plugins/pg-session-storage.d.ts +3 -0
- package/dist/plugins/pg-session-storage.js +19 -10
- package/dist/plugins/run-store-sql.d.ts +12 -4
- package/dist/plugins/run-store-sql.js +15 -13
- package/dist/plugins/send-file-ledger.d.ts +5 -1
- package/dist/plugins/send-file-ledger.js +11 -6
- package/dist/plugins/session-event-payload.d.ts +14 -4
- package/dist/plugins/session-event-payload.js +5 -2
- package/dist/plugins/store-backend.d.ts +7 -3
- package/dist/plugins/store-backend.js +10 -6
- package/dist/plugins/store-contracts.d.ts +7 -2
- package/dist/plugins/tidb-pool.js +8 -2
- package/dist/plugins/tidb-session-store.d.ts +6 -1
- package/dist/plugins/tidb-session-store.js +17 -10
- package/dist/project-identity.d.ts +4 -6
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +72 -3
- package/dist/request-value-closure.js +12 -4
- package/dist/roster-bound-http-status.d.ts +6 -0
- package/dist/roster-bound-http-status.js +6 -0
- package/dist/run-local.js +22 -27
- package/dist/runs.d.ts +22 -2
- package/dist/runs.js +29 -7
- package/dist/sealed-key.d.ts +31 -4
- package/dist/sealed-key.js +9 -0
- package/dist/security.d.ts +5 -1
- package/dist/server-secret-env.d.ts +2 -2
- package/dist/session-children-retire.d.ts +92 -0
- package/dist/session-children-retire.js +85 -0
- package/dist/session-error-wire.d.ts +58 -0
- package/dist/session-error-wire.js +38 -0
- package/dist/session-incarnation.d.ts +61 -0
- package/dist/session-incarnation.js +43 -0
- package/dist/session-records-skipped-notice.d.ts +20 -0
- package/dist/session-records-skipped-notice.js +27 -0
- package/dist/tool-approval.d.ts +65 -0
- package/dist/tool-approval.js +36 -9
- package/dist/trace/core-keyset-guard.d.ts +8 -7
- package/dist/trace/engine-notice-wire.d.ts +3 -1
- package/dist/trace/engine-notice-wire.js +2 -0
- package/dist/trace/project.d.ts +1 -1
- package/dist/trace/project.js +9 -0
- package/dist/trace/wire-projection-faces.d.ts +10 -3
- package/dist/trace/wire-projection-faces.js +8 -2
- package/package.json +3 -3
package/deploy/sema-up/README.md
CHANGED
|
@@ -53,23 +53,23 @@ summary 会打印手动接法。
|
|
|
53
53
|
| `--profile=P` | 交互问 | `full-single`/`data-center`/`local-plus`/`full-cluster` |
|
|
54
54
|
| `--users=U` | `single` | `single`(超管 turnkey)/`multi`(身份隔离 REQUIRE_PRINCIPAL=true) |
|
|
55
55
|
| `--region=R` | `auto` | `cn`/`global`;auto=对 aliyun/npmjs 探测延迟 |
|
|
56
|
-
| `--project=NAME` | `sema` | compose project
|
|
56
|
+
| `--project=NAME` | `sema` | compose project 名;并行试验/多套共存用。也是工作目录 `~/.sema-up/<名>` 与自动数据根 `<盘>/sema-data/<名>` 的一段 ⇒ 只收小写字母 / 数字 / `-` / `_`,首字符是字母或数字(别的写法在建任何目录之前拒) |
|
|
57
57
|
| `--dry-run` | — | 只打印执行计划,不写 .env、不起容器 |
|
|
58
58
|
| `--yes` | — | 无人值守(全默认;缺必填 fail-loud) |
|
|
59
59
|
| `--interactive=json` | — | 机器可读交互协议 |
|
|
60
60
|
| `-f FILE` | — | site 配置(env 形式;`machines.yaml` 走固定形状 mini-parser) |
|
|
61
|
-
| `--port=N` | 8090 | 引擎端口;`--pg-port`(5432)/`--minio-port`(9000)/`--minio-console-port`(9001)
|
|
61
|
+
| `--port=N` | 8090 | 引擎端口;`--pg-port`(5432)/`--minio-port`(9000)/`--minio-console-port`(9001)同理。端口旗只收 1–65535 的十进制整数 |
|
|
62
62
|
| `--gateway=URL` | — | 模型网关 baseURL(OpenAI 兼容);带 agent 的档必需 |
|
|
63
63
|
| `--model=ID` | `deepseek-v4-flash` | 模型 id |
|
|
64
64
|
| `--model-key=K` | — | 模型 API key(也可 -f 里 MODEL_API_KEY) |
|
|
65
65
|
| `--sandbox=LANE` | single→`host`;multi→`e2b-cloud` | `host`/`e2b-cloud`(full-single / local-plus)。**执行车道**=agent 的手落在哪里,不点名就是没有手;词表与必需键的单一属主=`lib/lanes.json`。`kata`/`runc`/`e2b-self` 已退役(compose 路径对它们零接线),收到即非零退出并指路。kube 路径(full-cluster)**不选词**:runtime 按 runtimeClass `kata-qemu` 在不在自动定,车道恒 `REMOTE_EXEC=k8s` |
|
|
66
|
-
| `--registry=
|
|
66
|
+
| `--registry=true\|false` | `true`(local-plus `false`) | 配置中心网站开关;**只收 `true` / `false`**(`yes` / `1` / `on` 在建任何目录之前拒 —— 7.104.0 之前它们被静默当成关) |
|
|
67
67
|
| `--registry-image=REF` | — | sema-registry 镜像(registry=true 必需) |
|
|
68
68
|
| `--git=MODE` | `none` | `none`/`provision`/`connect` |
|
|
69
69
|
| `--git-url=URL --git-token=T` | — | connect 态的已有服务(Gitea/GitHub/任意三方 git,自动识别;证书不校验) |
|
|
70
70
|
| `--pg-url=URL` | — | 外接第三方 PG(`postgres://user:pass@host:port/db`);给了就不部署本地 PG,装配前真连检 |
|
|
71
71
|
| `--s3-endpoint=URL --s3-access-key= --s3-secret-key=` | — | 外接第三方 S3(兼容协议:MinIO/OSS/COS/R2…);不部署本地 MinIO,装配前 ls+建桶检(`--insecure`) |
|
|
72
|
-
| `--data-root=DIR` | 多盘机自动选大盘 | 数据卷 bind
|
|
72
|
+
| `--data-root=DIR` | 多盘机自动选大盘 `<盘>/sema-data/<project>` | 数据卷 bind 到指定目录;首装落定不漂移(换盘 = `--teardown-volumes` 后迁数据、删掉 `.env` 的 `DATA_ROOT_DIR` 行、带新 `--data-root` 重装)。**一条数据根只归一个项目**,见下「数据根归属」 |
|
|
73
73
|
| `--git-http-port=N` | 3300 | 自建 Gitea HTTP 口;`--git-ssh-port`(2222)同理 |
|
|
74
74
|
| `--gitea-image=REF` | `gitea/gitea:1.24` | 自建 Gitea 镜像 |
|
|
75
75
|
| `--pg-host= --pg-password= --minio-endpoint= --minio-password=` | — | local-plus 的远端数据面(data-center summary 里有) |
|
|
@@ -78,6 +78,21 @@ summary 会打印手动接法。
|
|
|
78
78
|
| `--teardown` / `--teardown-volumes` | — | 卸载(留数据 / 连卷删) |
|
|
79
79
|
| `--skip-preflight` | — | 跳过预检(不建议) |
|
|
80
80
|
|
|
81
|
+
### 取值旗的形(7.104.0,S-621)
|
|
82
|
+
|
|
83
|
+
一条规则:**每只取值旗都过形判**,不合 ⇒ 在建任何目录、写任何文件之前非零退出,拒句点名旗、收到的值、合法形。
|
|
84
|
+
判据与闭集词表只在 `lib/flagshape.sh` 定义一次(sema-up / kube-up / cluster-up / preflight / smoke 同读;`--help` 的词表从它渲)。
|
|
85
|
+
判的是**生效值**(命令行 ∪ `-f` 配置里的同名变量),所以拒句同时报旗名与变量名(如 `--registry(REGISTRY_ENABLED)`)。
|
|
86
|
+
命令行上写了 `--旗=` 却没给值 ⇒ 照判(空串不在任何闭集里);交互答案(TTY / `--interactive=json`)必须是那道题的选项之一。
|
|
87
|
+
|
|
88
|
+
| 形 | 旗 |
|
|
89
|
+
|---|---|
|
|
90
|
+
| 布尔(闭集 `true` / `false`) | `--registry`;无值旗 `--dry-run` / `--teardown` / `--teardown-volumes` / `--skip-preflight` 落成的变量(`-f` 里写同名变量会覆盖它们,同判);kube-up 的 `DRY_RUN` |
|
|
91
|
+
| 端口(1–65535 十进制整数,不带前导 0 / 正负号 / 空白) | `--port` `--pg-port` `--minio-port` `--minio-console-port` `--git-http-port` `--git-ssh-port`;`-f` / 环境的 `REGISTRY_PORT`;preflight `--ports` 的每一项 |
|
|
92
|
+
| 枚举(列全词) | `--profile` `--users` `--region` `--git` `--kube`;交互形 `MODE_INTERACTIVE`(`tty` / `json` / `none`,由 `--interactive=json` / `--yes` 落成)(kube-up 单独跑只收 `existing` / `k3s`);cluster-up 的 `STACK_ENGINE`(`render` / `helm`);preflight `--profile`(另收 `full`);`--sandbox`(词表属 `lib/lanes.json`,形判用 `lanes.py check`) |
|
|
93
|
+
| 项目名形(compose 项目名,也是路径的一段) | `--project`(sema-up / preflight / smoke) |
|
|
94
|
+
| 自由文本(不判:合法形不是闭集) | `--gateway` `--git-url` `--minio-endpoint` `--pg-url` `--s3-endpoint`(URL);`--registry-image` `--gitea-image`(镜像引用);`--data-root` `--kubeconfig` `-f`(路径;数据根另有归属判);`--pg-host`(主机);`--model`(模型 id);`--model-key` `--git-token` `--pg-password` `--minio-password` `--s3-access-key` `--s3-secret-key`(凭据);smoke 的 `--url` / `--token`。落 `.env` 的值另过 `lib/envf.sh` 的写口 |
|
|
95
|
+
|
|
81
96
|
site.env 词表 = 上表的 env 形式(`PROFILE`/`SEMA_SERVER_IMAGE`/`SEMA_REGISTRY_IMAGE`/
|
|
82
97
|
`GIT_MODE`/`GIT_URL`/`GIT_TOKEN`/`MODEL_API_KEY`/`E2B_API_KEY`/`IMAGE_PULL_USER`/`IMAGE_PULL_TOKEN` …);
|
|
83
98
|
命令行显式参数赢过文件。k8s 路径额外:`STORAGE_CLASS`(缺省用集群默认 SC)、`NAMESPACE`(sema)。
|
|
@@ -92,10 +107,29 @@ data-center:2c/2G/20G)以下 BLOCK——确实无法稳定部署,提前警告不
|
|
|
92
107
|
单节点 allocatable <1c/2G 才拦。凡带 URL 的外接面(PG/S3/git)装配前都做真连接检测,
|
|
93
108
|
一律忽略证书(内网自签是常态),验的是协议兼容与可达。
|
|
94
109
|
|
|
110
|
+
### 数据根归属(7.104.0 起)
|
|
111
|
+
|
|
112
|
+
多盘机不给 `--data-root` 时,数据根 = `<大盘>/sema-data/<project>`(**按项目分**;7.104.0 之前是 `<大盘>/sema-data`,同机第二个项目
|
|
113
|
+
会自动落进同一份目录)。任何来源的数据根(自动 / `--data-root` / `.env` 首装值)首次使用时,sema-up 在根里落一只项目标记
|
|
114
|
+
`.sema-up-project`(`project=<名>` + `work=<工作目录 ~/.sema-up/<名>>`),之后每次装 / 重跑核对,`--dry-run` 同样判(只报、不写):
|
|
115
|
+
|
|
116
|
+
- 标记在、但记的是**别的项目**(或同名项目的另一个工作目录 = 另一个用户)⇒ **拒**,拒句点名两边,出路 = 换 `--project` 或显式 `--data-root=<别处>`;
|
|
117
|
+
- 标记缺席而目录**非空**(7.104.0 之前的存量安装)⇒ 只有本项目 `.env` 的首装值 `DATA_ROOT_DIR` 正是这条根时认作本项目、照起并补写标记,否则同拒;
|
|
118
|
+
- 一条根**嵌在另一个数据根里**(祖先目录有标记,或有 `pgdata` / `miniodata` / `registrydata` / `gitdata`)⇒ 拒 —— 例如 `<盘>/sema-data`
|
|
119
|
+
本身是 7.104.0 之前某个项目的根,新项目的自动根 `<盘>/sema-data/<project>` 就落在它里面;出路是显式 `--data-root=<不在任何数据根里的目录>`;
|
|
120
|
+
- 已装的项目照 `.env` 首装值不动(不漂移、不搬数据)。`--teardown-volumes` 之后只有标记是本项目时才提示「确认不要了再 rm -rf」。
|
|
121
|
+
|
|
122
|
+
**两个项目可能已经共用一份数据目录**(7.104.0 之前同机装过两个项目、都没给 `--data-root`):先重跑其中一个(它会补写标记认领这条根),另一个
|
|
123
|
+
重跑时被拒,拒句里给出核对命令 —— `docker volume inspect <项目A>_pgdata <项目B>_pgdata --format '{{.Name}} {{index .Options "device"}}'`,
|
|
124
|
+
两行 `device` 相同 = 两套栈挂着同一目录。拆:被拒的那个项目 `--teardown-volumes`(删的是 bind 卷**对象**,盘上文件不动;只 `--teardown`
|
|
125
|
+
会留下仍指着旧目录的卷对象,compose 重起时照旧复用它、接着写共用目录)→ 删掉它 `.env` 里 `DATA_ROOT_DIR` 那一行 → 带
|
|
126
|
+
`--data-root=<新的空目录>` 重跑 → `docker volume inspect <它>_pgdata --format '{{index .Options "device"}}'` 核对已指到新目录(新目录从空库起;
|
|
127
|
+
原先写进共用目录的数据要人工核对归属)。另:shell / `-f` 导出的 `DATA_ROOT_DIR` 是 compose 真正插值的那一个,它与 `.env` / `--data-root` 不一致 ⇒ 拒。
|
|
128
|
+
|
|
95
129
|
## 镜像从哪来
|
|
96
130
|
|
|
97
|
-
- **server**:`SEMA_SERVER_IMAGE`(`ghcr.io/sema-agent/sema-server
|
|
98
|
-
CN 兜底=自建镜像 registry。SWR 已弃用)。
|
|
131
|
+
- **server**:`SEMA_SERVER_IMAGE`(`ghcr.io/sema-agent/sema-server:v<版本>`,public 匿名可拉;**tag 带 `v`** —— 发布镜像
|
|
132
|
+
按 git tag `v<版本>` 打,不带 `v` 的 `:7.104.0` 拉不到(未给镜像时的拒句直接给出本包版本对应的那一个);CN 兜底=自建镜像 registry。SWR 已弃用)。
|
|
99
133
|
- **registry**:`SEMA_REGISTRY_IMAGE`(GHCR/Hub 的 `sema-registry` 镜像,迁移中,公开仓匿名可拉;
|
|
100
134
|
SWR 已弃用;仅换 private 仓时才需 k8s 路径凭据=env `IMAGE_PULL_USER`/`IMAGE_PULL_TOKEN`)。
|
|
101
135
|
- 公共镜像(postgres/minio/gitea)直接拉;国内网络不通时配 dockerd `registry-mirrors`。
|
|
@@ -112,6 +146,18 @@ summary 里管理员密码只显示一次(新生成那次),不进日志不进 gi
|
|
|
112
146
|
**规范形**:一行、行首顶格 `K=<值>`,值是一个词或一对同型引号包住的一个词;`export ` 前缀、键旁空格、`K: v`、
|
|
113
147
|
行内注释、重复行 ⇒ 非零退出并点名行号(不去猜 compose 会怎么读那一行)。`REQUIRE_PRINCIPAL` 只认 `true` / `false`。
|
|
114
148
|
|
|
149
|
+
## 壳(sema CLI)接入
|
|
150
|
+
|
|
151
|
+
sema-up 装完的汇总里有一段「壳接入」(`--interactive=json` 的 summary 行对应 `shellAccess` 对象),**不打印令牌值**:
|
|
152
|
+
|
|
153
|
+
- **连哪个地址**:壳对非回环地址只收 https、回环地址才收 http(判据在 sema CLI 的 connect 检查里),而汇总里「引擎」那一行是局域网的
|
|
154
|
+
http 地址 —— 壳按设计拒连它。所以:引擎这台机上 `sema cloud engine connect http://127.0.0.1:<引擎口>`;别的机器上先开隧道
|
|
155
|
+
`ssh -L <本地口>:127.0.0.1:<引擎口> <用户>@<引擎机>`,再 `sema cloud engine connect http://127.0.0.1:<本地口>`(kube 路径换成
|
|
156
|
+
`kubectl -n <ns> port-forward svc/sema-server 8090:8090`)。
|
|
157
|
+
- **令牌怎么交给壳**:sema-up 起的引擎只认部署令牌 `SERVICE_AUTH_TOKEN`(在 `~/.sema-up/<project>/.env`,0600)。在启动 sema 的那个
|
|
158
|
+
shell 里 `export SEMA_LIVE_TOKEN=<那一行的值>` 再启动 sema;壳里 `/status` 看当前带没带令牌。(这个变量旧版壳就认;cli ≥ 1.0.138
|
|
159
|
+
起,壳在连上后第一句撞 401 时自己说出这句。)registry 登录令牌 sema-up 的引擎不验,不要拿它当出路。
|
|
160
|
+
|
|
115
161
|
## 验收
|
|
116
162
|
|
|
117
163
|
```bash
|
|
@@ -134,7 +180,9 @@ deploy/sema-up/smoke.sh --url=http://host:8090 --token=$SERVICE_AUTH_TOKEN #
|
|
|
134
180
|
| k8s:server `CreateContainerConfigError` | runner-token 复制晚于 pod 创建 | 重跑 kube-up(幂等);已内置先复制后等待 |
|
|
135
181
|
| Gitea OAuth app 创建失败 | token 缺 `write:user` scope | summary 的待人工项有手动接法 |
|
|
136
182
|
| smoke `auth 门` FAIL | SERVICE_AUTH_TOKEN 未生效=公网裸奔 | 立刻查 .env 与容器 env |
|
|
137
|
-
|
|
|
183
|
+
| 引擎面 `401 auth.unauthorized`(壳里是 `API Error: 401 auth.unauthorized`,体里有一句出路) | 调用方没带部署令牌,或带的不是这台的(两种同一个回答) | 令牌 = `~/.sema-up/<project>/.env` 的 `SERVICE_AUTH_TOKEN`。壳:在启动 sema 的 shell 里 `export SEMA_LIVE_TOKEN=<该值>` 再启动 sema(`/status` 连远端时有「Engine token」一行、`sema cloud engine status` 有 `token:` 行,只说设没设不显示值;见上「壳接入」);cli ≥ 1.0.138 的壳在「带了令牌但引擎不认」时自己说出两句之一(逐字):带的是 SEMA_LIVE_TOKEN ⇒ 「This engine did not accept the service token that was sent (from SEMA_LIVE_TOKEN). Check the value with whoever runs the engine (for a sema-up deployment: SERVICE_AUTH_TOKEN in the deployment's .env), then run `export SEMA_LIVE_TOKEN=<token>` with the right value in the shell you start sema from and start sema again. `/status` shows whether a token is attached.」;带的是登录令牌(没设 SEMA_LIVE_TOKEN)⇒ 「This engine did not accept your registry sign-in token (sent because SEMA_LIVE_TOKEN is not set). If the engine expects a service token, get it from whoever runs the engine (for a sema-up deployment: SERVICE_AUTH_TOKEN in the deployment's .env), then run `export SEMA_LIVE_TOKEN=<token>` in the shell you start sema from and start sema again. `/status` shows whether a token is attached.」。引擎自己的 401 体对「没带」与「带错」逐字同(不区分,防探测),分辨面只在壳侧这两句;其它 HTTP 调用方:`Authorization: Bearer <该值>` |
|
|
184
|
+
| 模型面 402/401(模型网关回的,不是引擎的门) | 模型网关:余额耗尽/key 无效 | 充值/换 key(`.env` 的 `MODEL_API_KEY`)后重跑 smoke |
|
|
185
|
+
| `⛔ 数据根 … 已归另一个 sema-up 项目` / `… 嵌在另一个数据根里` | 这条数据目录属于别的项目(见上「数据根归属」) | 换 `--project` 或显式 `--data-root=<别处>`;存量共用按拒句里的核对命令查、按上文拆 |
|
|
138
186
|
| NodePort 不可达(kind/远程) | kind 节点是容器,宿主到 NodePort 不通 | `kubectl -n sema port-forward svc/sema-server 8090:8090` |
|
|
139
187
|
|
|
140
188
|
## 文件地图
|
|
@@ -149,4 +197,6 @@ chart/ helm chart(server/CNPG PG/MinIO/registry/gitea/沙箱 RBAC
|
|
|
149
197
|
stack/compose.yaml 单机 Layer 1(profiles: data/agent/registry/git)
|
|
150
198
|
machines.example.yaml 多机清单模板
|
|
151
199
|
lib/parse-machines.py machines.yaml mini-parser(标准库零依赖,fail-loud)
|
|
200
|
+
lib/dataroot.sh 数据根归属规则(自动根按项目分 / 项目标记 / 拒 / 卸载提示;sema-up 与 preflight 同读)
|
|
201
|
+
lib/shell-access.sh 汇总里「壳接入」一段的唯一渲染(sema-up / kube-up / cluster-up 同读;只给位置不给值)
|
|
152
202
|
```
|
|
@@ -15,6 +15,10 @@ set -euo pipefail
|
|
|
15
15
|
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
16
16
|
# `.env` 的文法与全部读写原语只在 lib/envf.sh 定义(S-618 续):本脚本不再有自己的 setk / `. "$ENVF"`。
|
|
17
17
|
. "$HERE/lib/envf.sh"
|
|
18
|
+
# 「壳怎么接这台引擎」的渲染(S-850;sema-up.sh / kube-up.sh 同一只)。
|
|
19
|
+
. "$HERE/lib/shell-access.sh"
|
|
20
|
+
# 取值旗的形(S-621):判据与词表同 sema-up.sh 一处定义。
|
|
21
|
+
. "$HERE/lib/flagshape.sh"
|
|
18
22
|
log() { printf '[cluster-up] %s\n' "$*" >&2; }
|
|
19
23
|
die() { log "⛔ $*"; exit 1; }
|
|
20
24
|
|
|
@@ -25,8 +29,13 @@ K3S_CHANNEL="${K3S_CHANNEL:-stable}"
|
|
|
25
29
|
CNPG_VERSION="${CNPG_VERSION:-1.30.0}" # ⚠ in-tree barman 1.31 移除;升版前先迁 barman-cloud plugin
|
|
26
30
|
LONGHORN_VERSION="${LONGHORN_VERSION:-1.10.0}"
|
|
27
31
|
KATA_VERSION="${KATA_VERSION:-3.21.0}"
|
|
32
|
+
STACK_ENGINE="${STACK_ENGINE:-render}" # sema-stack 装配引擎:render(as-built 渲染 apply,缺省)| helm
|
|
28
33
|
NODEPORT=30890
|
|
29
34
|
|
|
35
|
+
# 取值旗的形(S-621)——在对任何一台机器发起 ssh 之前。修前:REGION=eu 当成「非 cn 非 global」、STACK_ENGINE=x 当成 render。
|
|
36
|
+
flag_enum "--region(REGION)" "$REGION" $FLAG_WORDS_REGION
|
|
37
|
+
flag_enum "STACK_ENGINE" "$STACK_ENGINE" $FLAG_WORDS_STACK_ENGINE
|
|
38
|
+
|
|
30
39
|
# <3 机=建议不强求(clay 2026-07-12:有建议的 3 节点配置,仍能处理;某台机器过小才拦——
|
|
31
40
|
# 那个由 0/8 每机预检的 8G/40G 硬底线负责)。ALLOW_SMALL_CLUSTER 保留兼容,不再必需。
|
|
32
41
|
if [ "$MACHINE_COUNT" -lt 3 ]; then
|
|
@@ -267,7 +276,7 @@ if [ -n "${IMAGE_PULL_USER:-}" ] && [ -n "${IMAGE_PULL_TOKEN:-}" ]; then
|
|
|
267
276
|
rrun 0 k3s kubectl create namespace "$ns" --dry-run=client -o yaml | rrun 0 k3s kubectl apply -f - >/dev/null
|
|
268
277
|
# helm adoption:chart 声明 Namespace/sema-sandbox——6b 先建了它,不打 helm 属主标记
|
|
269
278
|
# 的话 `helm upgrade --install` 拒绝接管(fresh helm 装直接失败)。render 路径不受影响(仅 helm 时打)。
|
|
270
|
-
if [ "$ns" = sema-sandbox ] && [ "$
|
|
279
|
+
if [ "$ns" = sema-sandbox ] && [ "$STACK_ENGINE" = "helm" ]; then
|
|
271
280
|
rrun 0 k3s kubectl label ns "$ns" app.kubernetes.io/managed-by=Helm --overwrite >/dev/null
|
|
272
281
|
rrun 0 k3s kubectl annotate ns "$ns" meta.helm.sh/release-name=sema-stack meta.helm.sh/release-namespace=sema --overwrite >/dev/null
|
|
273
282
|
fi
|
|
@@ -296,7 +305,7 @@ fi
|
|
|
296
305
|
# ── 7. sema-stack 装配:helm chart(STACK_ENGINE=helm)或渲染 apply(默认,as-built)──
|
|
297
306
|
# chart/ 与 stack/sema-stack-cluster.yaml 同构(对象名一致,可从存量 adoption);helm 路径
|
|
298
307
|
# 验收等价后再翻默认。
|
|
299
|
-
log "7/8 sema-stack 渲染+apply(engine=$
|
|
308
|
+
log "7/8 sema-stack 渲染+apply(engine=$STACK_ENGINE)"
|
|
300
309
|
: "${MODEL_GATEWAY_BASEURL:?模型面必需(--gateway)}"; : "${MODEL_ID:?模型面必需(--model)}"
|
|
301
310
|
ENVF="$WORK/.env"; touch "$ENVF"; chmod 600 "$ENVF"
|
|
302
311
|
setk MINIO_PASSWORD "$(openssl rand -hex 24)"
|
|
@@ -314,7 +323,7 @@ envf_load MINIO_PASSWORD SERVICE_AUTH_TOKEN
|
|
|
314
323
|
PG_INSTANCES=$(( MACHINE_COUNT >= 3 ? 3 : MACHINE_COUNT ))
|
|
315
324
|
PG_AA=$([ "$MACHINE_COUNT" -ge 3 ] && echo required || echo preferred)
|
|
316
325
|
SERVER_REPLICAS=$(( MACHINE_COUNT >= 3 ? 3 : 2 ))
|
|
317
|
-
if [ "$
|
|
326
|
+
if [ "$STACK_ENGINE" = "helm" ]; then
|
|
318
327
|
# ── helm 路径:chart tar 经 stdin 上载(不落敏感值;chart 本身无凭据),values 本地生成
|
|
319
328
|
# (umask 077)经 stdin 给 helm -f -(凭据不进 argv、不落远端盘——与渲染路径同纪律)──
|
|
320
329
|
tar -C "$HERE" -czf - chart | mssh 0 'rm -rf /tmp/sema-stack-chart && mkdir -p /tmp/sema-stack-chart && tar xzf - -C /tmp/sema-stack-chart'
|
|
@@ -432,5 +441,10 @@ cat >&2 <<EOF
|
|
|
432
441
|
沙箱 kata-qemu runtimeclass(ns sema-sandbox,SA sema-runner)
|
|
433
442
|
凭据 $ENVF(0600;SERVICE_AUTH_TOKEN=API 门)
|
|
434
443
|
管理 ssh 隧道 6443(kubeconfig 在首节点 /etc/rancher/k3s/k3s.yaml,server 改 127.0.0.1)
|
|
435
|
-
═══════════════════════════════════════════════════════════
|
|
436
444
|
EOF
|
|
445
|
+
# 壳对 NodePort / LB 的明文 http 按设计拒连(非回环要 https)⇒ 经 ssh 隧道把首节点的 NodePort 带到本机回环再 connect
|
|
446
|
+
# (NodePort 钉在节点网段、不在节点自己的回环上 —— **转发目标**写节点私网 IP,见上面 smoke 的同一条注;**ssh 目标**是本次部署
|
|
447
|
+
# 连得上的那一台 = machines.yaml 的 HOST / USER / SSH_KEY,与 mssh 同一组,私网 IP 与 HOST 可以不同 —— 车内 codex r1-F4)。
|
|
448
|
+
_k0_key="$(mvar 0 SSH_KEY)"
|
|
449
|
+
shell_access_text "$ENVF" "能 ssh 到首节点的机器上(比如跑这次部署的这台):" "ssh ${_k0_key:+-i $_k0_key }-L <本地口>:$K3S0_IP:$NODEPORT $(mvar 0 USER)@$(mvar 0 HOST)" "http://127.0.0.1:<本地口>" >&2
|
|
450
|
+
echo "═══════════════════════════════════════════════════════════" >&2
|
|
@@ -17,6 +17,10 @@ HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
|
17
17
|
# `.env` 的文法与全部读写原语(envf_get / envf_has / envf_load / envf_put / setk / setk_new / resetk)只在这一处
|
|
18
18
|
# 定义,sema-up.sh / cluster-up.sh / smoke.sh 同源(S-618 续):本脚本不再有自己的 setk / has_env / `. "$ENVF"`。
|
|
19
19
|
. "$HERE/lib/envf.sh"
|
|
20
|
+
# 「壳怎么接这台引擎」的渲染(S-850;sema-up.sh / cluster-up.sh 同一只)。
|
|
21
|
+
. "$HERE/lib/shell-access.sh"
|
|
22
|
+
# 取值旗的形(S-621):判据与词表同 sema-up.sh 一处定义。
|
|
23
|
+
. "$HERE/lib/flagshape.sh"
|
|
20
24
|
log() { printf '[kube-up] %s\n' "$*" >&2; }
|
|
21
25
|
die() { log "⛔ $*"; exit 1; }
|
|
22
26
|
|
|
@@ -32,6 +36,16 @@ NAMESPACE="${NAMESPACE:-sema}"
|
|
|
32
36
|
CNPG_VERSION="${CNPG_VERSION:-1.30.0}" # ⚠ in-tree barman 1.31 移除;升版前先迁 barman-cloud plugin
|
|
33
37
|
K3S_CHANNEL="${K3S_CHANNEL:-stable}"
|
|
34
38
|
|
|
39
|
+
# ── 取值旗的形(S-621)——在装 k3s / 动集群 / 建 WORK 之前 ─────────────────────────────────────────
|
|
40
|
+
# 单独跑时这些环境变量就是本脚本的旗;经 sema-up 进来的值那边已判过,这里同一只再判一次(本脚本自己也是入口)。
|
|
41
|
+
# 修前:DRY_RUN=1 ≠ true ⇒ 当成真装;REGISTRY_ENABLED=yes 当关;USERS=team 当 single;KUBE_MODE=foo 走 existing 那一臂。
|
|
42
|
+
flag_enum "--kube(KUBE_MODE)" "$KUBE_MODE" $FLAG_WORDS_KUBE_SINGLE # machines 走 cluster-up.sh,不进本脚本
|
|
43
|
+
flag_bool "DRY_RUN(--dry-run)" "$DRY_RUN"
|
|
44
|
+
flag_enum "--users(USERS)" "$USERS" $FLAG_WORDS_USERS
|
|
45
|
+
flag_bool "--registry(REGISTRY_ENABLED)" "$REGISTRY_ENABLED"
|
|
46
|
+
flag_enum "--git(GIT_MODE)" "$GIT_MODE" $FLAG_WORDS_GIT
|
|
47
|
+
flag_enum "--region(REGION)" "$REGION" $FLAG_WORDS_REGION
|
|
48
|
+
|
|
35
49
|
# ── 0. kubeconfig / 工具解析 ─────────────────────────────────────────────────────
|
|
36
50
|
if [ "$KUBE_MODE" = "k3s" ]; then
|
|
37
51
|
[ "$(uname -s)" = "Linux" ] || die "--kube=k3s 只支持 Linux(本机装 k3s)。macOS 下一步:用 kind/k3d 起集群后 --kube=existing"
|
|
@@ -381,6 +395,8 @@ log "6/6 完成"
|
|
|
381
395
|
echo "══════════════ kube-up 完成($NODES 节点,mode=$KUBE_MODE)══════════════"
|
|
382
396
|
echo " 引擎 NodePort 30890 → http://$NODE_IP:30890(API 凭据=SERVICE_AUTH_TOKEN)"
|
|
383
397
|
echo " 本机不可达 NodePort 时(kind/远程):kubectl -n $NAMESPACE port-forward svc/sema-server 8090:8090"
|
|
398
|
+
# 壳对 NodePort 的明文 http 按设计拒连(非回环要 https)⇒ 经 port-forward 带到本机回环再 connect。
|
|
399
|
+
shell_access_text "$ENVF" "装了 kubectl、能连这个集群的机器上:" "kubectl -n $NAMESPACE port-forward svc/sema-server 8090:8090" "http://127.0.0.1:8090"
|
|
384
400
|
echo " 数据 CNPG sema-pg×$PG_INSTANCES($PG_AA)+ MinIO(桶:workspaces/blobs/backups/sema-pg-backup)"
|
|
385
401
|
if [ "$REGISTRY_ENABLED" = "true" ]; then
|
|
386
402
|
echo " 配置中心 NodePort 30300 → http://$NODE_IP:30300"
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# lib/dataroot.sh — 数据根归属的唯一规则(S-851,7.104.0)。sema-up.sh(判定 / 落定 / 卸载提示)与 preflight.sh(多盘机
|
|
2
|
+
# 建议句)都从这里取,不各写一份。
|
|
3
|
+
#
|
|
4
|
+
# 规则:一条数据根归**一个**项目所有 ——
|
|
5
|
+
# · 自动选盘的根 = <盘>/sema-data/<project>(dataroot_for_disk;修前是 <盘>/sema-data,同机第二个项目会自动落进同一份目录);
|
|
6
|
+
# · 首次使用时在根里落一只项目标记 <根>/.sema-up-project,内容 = `project=<名>` + `work=<工作目录>`(dataroot_marker_body);
|
|
7
|
+
# · 每次装 / 重跑核对(dataroot_judge):标记在而不是本项目 ⇒ 拒;标记缺席而目录非空(7.104.0 之前的存量安装,那时还没有
|
|
8
|
+
# 标记)⇒ 只有 .env 首装值正是这条根时认作本项目、落定时补写标记,否则拒;一条根也不许嵌在另一个数据根里(祖先目录有标记,
|
|
9
|
+
# 或有 sema-up 建的卷目录 —— 7.104.0 之前自动选盘的根就是 <盘>/sema-data 本身);
|
|
10
|
+
# · 已装的项目照 .env 首装值不动 —— 调用方先按首装值定根,再来判(本文件不决定根取哪条,只判这条根能不能归本项目)。
|
|
11
|
+
# 调用方先定义:log(打到 stderr)、PROJECT、WORK、ENVF。拒 = 响亮一段 + exit 1(不静默另选一条根:替运维挑目录是替他做决定)。
|
|
12
|
+
|
|
13
|
+
DATAROOT_MARKER=".sema-up-project"
|
|
14
|
+
# sema-up 在数据根下建的四只卷目录(compose.dataroot.yaml 的 bind 源)= 存量数据根的指纹。
|
|
15
|
+
DATAROOT_LAYOUT="pgdata miniodata registrydata gitdata"
|
|
16
|
+
|
|
17
|
+
# dataroot_for_disk <挂载点> <项目> —— 自动选盘的根。preflight 的建议句也用它(同一条规则,不另拼路径)。
|
|
18
|
+
dataroot_for_disk() { printf '%s/sema-data/%s' "${1%/}" "$2"; }
|
|
19
|
+
|
|
20
|
+
# 本项目的标记内容(工作目录 = ~/.sema-up/<project>:同名项目在另一个用户 / 另一个 HOME 下是另一套部署)。工作目录按**物理**
|
|
21
|
+
# 路径记(HOME 经符号链接换一种写法仍是同一套部署;WORK 在脚本开头就已建好,解析得到)。
|
|
22
|
+
dataroot_work_phys() { (cd "$WORK" 2>/dev/null && pwd -P) || printf '%s' "$WORK"; }
|
|
23
|
+
dataroot_marker_body() { printf 'project=%s\nwork=%s\n' "$PROJECT" "$(dataroot_work_phys)"; }
|
|
24
|
+
|
|
25
|
+
# dataroot_physical <路径> —— 物理绝对路径:已存在的前缀逐段解析符号链接,不存在的尾段按字面规整后接上;不建任何目录。
|
|
26
|
+
# 归属判定(祖先有没有别的项目的根 / 标记在不在 / 是不是首装值)一律按它比 —— 按字面逐级 dirname 会被一条符号链接绕过
|
|
27
|
+
# (`--data-root=/alias/beta` 而 /alias → 别的项目的 pgdata:字面祖先里看不见那个项目的标记)。
|
|
28
|
+
dataroot_physical() { python3 -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$1"; }
|
|
29
|
+
|
|
30
|
+
# dataroot_marker_field <标记文件> <project|work> —— 读标记里的一项(读不到 ⇒ 空)。
|
|
31
|
+
dataroot_marker_field() { sed -n "s/^$2=//p" "$1" 2>/dev/null | head -n 1; }
|
|
32
|
+
|
|
33
|
+
# dataroot_is_ours <根> —— 标记在且逐字是本项目。
|
|
34
|
+
dataroot_is_ours() {
|
|
35
|
+
[ -f "$1/$DATAROOT_MARKER" ] || return 1
|
|
36
|
+
[ "$(cat "$1/$DATAROOT_MARKER" 2>/dev/null)" = "$(dataroot_marker_body)" ]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# dataroot_looks_owned <目录> —— 这是(某个项目的)数据根吗:有标记,或有存量布局里的任一只卷目录。一只叫 pgdata 等名字、
|
|
40
|
+
# 自己带标记的子目录是**项目根**(项目恰好叫这个名字:<盘>/sema-data/pgdata),不算上一级的存量布局。
|
|
41
|
+
dataroot_looks_owned() {
|
|
42
|
+
local v
|
|
43
|
+
[ -e "$1/$DATAROOT_MARKER" ] && return 0
|
|
44
|
+
for v in $DATAROOT_LAYOUT; do [ -d "$1/$v" ] && [ ! -e "$1/$v/$DATAROOT_MARKER" ] && return 0; done
|
|
45
|
+
return 1
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# dataroot_judge <根> <.env 首装值(可空)> <这条根从哪来的一句话>
|
|
49
|
+
# 设 DATAROOT_CLAIM:owned(标记已是本项目)| new(新根 / 空目录:落定时写标记)| backfill(存量:落定时补写标记);
|
|
50
|
+
# 设 DATAROOT_PHYS = 这条根的物理路径(落定也落在它上面:根是一条悬空符号链接时,建的是链接那头)。
|
|
51
|
+
# 只读:不建目录、不写标记 —— dry-run 与真跑判的是同一只函数,写只在 dataroot_settle 里。
|
|
52
|
+
dataroot_judge() {
|
|
53
|
+
local root="$1" stored="$2" src="$3" phys marker d mp mw entries stored_phys=""
|
|
54
|
+
DATAROOT_CLAIM="" DATAROOT_PHYS=""
|
|
55
|
+
phys="$(dataroot_physical "$root")" || { log "⛔ 数据根 $root 解析不了物理路径(python3?)—— 判不出它属于谁,不往里写"; exit 1; }
|
|
56
|
+
DATAROOT_PHYS="$phys"
|
|
57
|
+
marker="$phys/$DATAROOT_MARKER"
|
|
58
|
+
if [ -n "$stored" ]; then stored_phys="$(dataroot_physical "$stored")" || exit 1; fi
|
|
59
|
+
# ① 祖先(物理路径):这条根不许嵌在另一个数据根里(那个项目卸载后照提示删目录,会连本项目一起删)。
|
|
60
|
+
d="$(dirname "$phys")"
|
|
61
|
+
while [ -n "$d" ] && [ "$d" != "/" ] && [ "$d" != "." ]; do
|
|
62
|
+
if dataroot_looks_owned "$d"; then
|
|
63
|
+
log "⛔ 数据根 $root 嵌在另一个数据根 $d 里面($d 下有项目标记或 sema-up 的卷目录 $(echo "$DATAROOT_LAYOUT" | tr ' ' '/');7.104.0 之前自动选盘的根就是 <盘>/sema-data 本身)。数据根取自:$src"
|
|
64
|
+
log " ↳ 为什么拒:那个项目卸载后照提示删 $d,会连本项目的数据一起删;两套栈的卷目录也会混在一棵树里"
|
|
65
|
+
log " ↳ 下一步:显式 --data-root=<不在任何数据根里的目录>(例如 $(dirname "$d")/sema-data-$PROJECT)。$d 是谁的:看 $d/$DATAROOT_MARKER,或 docker volume ls 找 bind 到它的卷"
|
|
66
|
+
exit 1
|
|
67
|
+
fi
|
|
68
|
+
d="$(dirname "$d")"
|
|
69
|
+
done
|
|
70
|
+
# ② 自己:标记在 ⇒ 必须是本项目。
|
|
71
|
+
if [ -e "$marker" ]; then
|
|
72
|
+
if dataroot_is_ours "$phys"; then DATAROOT_CLAIM=owned; return 0; fi
|
|
73
|
+
mp="$(dataroot_marker_field "$marker" project)"; mw="$(dataroot_marker_field "$marker" work)"
|
|
74
|
+
log "⛔ 数据根 $root 已归另一个 sema-up 项目:标记 $marker 记的是 project=${mp:-?}(工作目录 ${mw:-?});本次是 project=$PROJECT(工作目录 $(dataroot_work_phys))。数据根取自:$src"
|
|
75
|
+
log " ↳ 为什么拒:两个项目共用一份数据目录 = 两套 PG / MinIO 写同一批文件;其中一个卸载时照提示删目录,会连另一个的数据一起删"
|
|
76
|
+
log " ↳ 下一步(按你的意图二选一):① 要一套独立的部署:换一个 --project=<新名>(自动数据根按项目分),或显式 --data-root=<另一条空目录>;② 你要操作的就是那个项目:用它自己的 --project=${mp:-<它的名字>},在工作目录 ${mw:-<它的工作目录>} 所属的用户下跑"
|
|
77
|
+
if [ -n "$stored_phys" ] && [ "$stored_phys" = "$phys" ]; then
|
|
78
|
+
log " ↳ 这一条是 $ENVF 登记的首装值 —— 7.104.0 之前自动选盘不带项目名,两个项目可能早已共用它。先查两套栈是不是挂着同一目录:docker volume inspect ${mp:-<它的项目>}_pgdata ${PROJECT}_pgdata --format '{{.Name}} {{index .Options \"device\"}}'(两行 device 相同 = 共用)"
|
|
79
|
+
log " ↳ 拆(本项目这一侧):$0 --project=$PROJECT --teardown-volumes(删的是 bind 卷**对象**,盘上文件不动;只 --teardown 会留下仍指着这条旧目录的卷对象,compose 重起时照旧复用它)→ 删掉 $ENVF 里 DATA_ROOT_DIR 那一行 → 带 --data-root=<新的空目录> 重跑 → docker volume inspect ${PROJECT}_pgdata --format '{{index .Options \"device\"}}' 核对它已指到新目录(新目录从空库起;原先写进共用目录的数据要人工核对归属)"
|
|
80
|
+
fi
|
|
81
|
+
exit 1
|
|
82
|
+
fi
|
|
83
|
+
# ③ 没有标记:不在 / 空目录 = 新根;非空 = 只认 .env 登记过的存量根(补写),别的一律认不出主人 ⇒ 拒。
|
|
84
|
+
if [ ! -e "$phys" ]; then DATAROOT_CLAIM=new; return 0; fi
|
|
85
|
+
if [ ! -d "$phys" ]; then
|
|
86
|
+
log "⛔ 数据根 $root 已存在但不是目录。数据根取自:$src"
|
|
87
|
+
log " ↳ 下一步:换一条 --data-root=<目录>"
|
|
88
|
+
exit 1
|
|
89
|
+
fi
|
|
90
|
+
if ! entries="$(ls -A "$phys" 2>/dev/null)"; then
|
|
91
|
+
log "⛔ 数据根 $root 读不了(权限?),判不出它是不是空的、属于谁 —— 不往里写。数据根取自:$src"
|
|
92
|
+
log " ↳ 下一步:用对这条目录有读写权的用户跑,或换一条 --data-root=<目录>"
|
|
93
|
+
exit 1
|
|
94
|
+
fi
|
|
95
|
+
if [ -z "$entries" ]; then DATAROOT_CLAIM=new; return 0; fi
|
|
96
|
+
if [ -n "$stored_phys" ] && [ "$stored_phys" = "$phys" ]; then DATAROOT_CLAIM=backfill; return 0; fi
|
|
97
|
+
log "⛔ 数据根 $root 不是空目录,也没有 sema-up 的项目标记($marker 缺席),而 $ENVF 没把它登记成本项目的首装数据根 —— 认不出它属于谁,不往里写。数据根取自:$src"
|
|
98
|
+
log " ↳ 下一步:① 换一条空目录或新目录:--data-root=<别处>;② 它确实是本项目的数据(比如 .env 重建过):确认后手工写标记 printf 'project=%s\\nwork=%s\\n' $PROJECT $(dataroot_work_phys) > $marker,再重跑"
|
|
99
|
+
exit 1
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# dataroot_plan_line <根> —— dry-run 计划里报这条根的归属判定(判而不写)。
|
|
103
|
+
dataroot_plan_line() {
|
|
104
|
+
case "$DATAROOT_CLAIM" in
|
|
105
|
+
owned) printf ' 数据根: %s(项目标记已是本项目)\n' "$1" ;;
|
|
106
|
+
new) printf ' 数据根: %s(首次使用:将落项目标记 %s;本次 dry-run 不写)\n' "$1" "$1/$DATAROOT_MARKER" ;;
|
|
107
|
+
backfill) printf ' 数据根: %s(存量安装、没有标记,.env 首装值就是它:将补写项目标记 %s;本次 dry-run 不写)\n' "$1" "$1/$DATAROOT_MARKER" ;;
|
|
108
|
+
*) log "⛔ 内部:数据根 $1 未经判定"; exit 1 ;;
|
|
109
|
+
esac
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
# dataroot_settle <根> —— 落定(只在真跑、判定之后调):建根与四只卷目录,new / backfill 时写标记。
|
|
113
|
+
# 写标记用 noclobber(O_EXCL):两次 sema-up 同时认领同一条新根时,后到的那次读到对方的标记 ⇒ 拒,不互相覆盖。
|
|
114
|
+
dataroot_settle() {
|
|
115
|
+
local root="${DATAROOT_PHYS:-$1}" v
|
|
116
|
+
case "$DATAROOT_CLAIM" in
|
|
117
|
+
owned) : ;;
|
|
118
|
+
new|backfill)
|
|
119
|
+
mkdir -p "$root"
|
|
120
|
+
if ! ( set -C; dataroot_marker_body > "$root/$DATAROOT_MARKER" ) 2>/dev/null && ! dataroot_is_ours "$root"; then
|
|
121
|
+
log "⛔ 数据根 $root 的项目标记落不下,或刚被别的项目抢先落了($root/$DATAROOT_MARKER)—— 不往里写"
|
|
122
|
+
log " ↳ 下一步:看 $root/$DATAROOT_MARKER 记的是谁;不是本项目就换一条 --data-root=<目录>"
|
|
123
|
+
exit 1
|
|
124
|
+
fi
|
|
125
|
+
;;
|
|
126
|
+
*) log "⛔ 内部:数据根 $root 未经判定就落定"; exit 1 ;;
|
|
127
|
+
esac
|
|
128
|
+
for v in $DATAROOT_LAYOUT; do mkdir -p "$root/$v"; done
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
# dataroot_teardown_hint <根> —— `--teardown-volumes` 之后,盘上文件还在;删不删要看这条根是不是本项目的。
|
|
132
|
+
dataroot_teardown_hint() {
|
|
133
|
+
local root="$1" marker="$1/$DATAROOT_MARKER" mp mw
|
|
134
|
+
if dataroot_is_ours "$root"; then
|
|
135
|
+
log "⚠ 数据根在大盘 bind 目录 ${root}——卷对象已删,盘上文件还在;确认不要了再手动 rm -rf"
|
|
136
|
+
elif [ -e "$marker" ]; then
|
|
137
|
+
mp="$(dataroot_marker_field "$marker" project)"; mw="$(dataroot_marker_field "$marker" work)"
|
|
138
|
+
log "⚠ 数据根 bind 目录 ${root} 的卷对象已删、盘上文件还在;但它的项目标记记的是 project=${mp:-?}(工作目录 ${mw:-?}),不是本项目 —— 那是另一个项目的数据,不要整目录删"
|
|
139
|
+
else
|
|
140
|
+
log "⚠ 数据根 bind 目录 ${root} 的卷对象已删、盘上文件还在;它没有项目标记(7.104.0 之前的安装),删之前先确认没有别的项目也 bind 在这里:docker volume ls 逐个 docker volume inspect 看 device"
|
|
141
|
+
fi
|
|
142
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# lib/flagshape.sh — 取值旗的形(S-621,7.104.0):一条规则、一处定义(判据 + 词表)。sema-up.sh(参数解析之后、建任何目录之前)、
|
|
2
|
+
# kube-up.sh / cluster-up.sh(单独跑时环境变量就是它们的旗)、preflight.sh / smoke.sh 都从这里判,不各写一份。
|
|
3
|
+
#
|
|
4
|
+
# 规则:每只取值旗都过形判;不合 ⇒ 拒句点名旗、收到的值、合法形,非零退出 —— 调用方把判放在任何建目录 / 写文件 / 动集群 /
|
|
5
|
+
# 连远端之前。四种形:
|
|
6
|
+
# · bool —— 闭集 true / false。修前 --registry 只与字面 true 比:yes / 1 / on 被静默当成「关」,且原样落进 .env;
|
|
7
|
+
# · port —— 1–65535 的十进制整数,不带前导 0 / 正负号 / 空白(前导 0 在 bash 算术里读成八进制);
|
|
8
|
+
# · enum —— 列全词(词表就在下面:--help、拒句、交互选项的对拍钉都从这里取,不手抄);
|
|
9
|
+
# · project —— compose 项目名形(小写字母 / 数字 / - / _,首字符字母或数字):它也是工作目录 ~/.sema-up/<名> 与自动数据根
|
|
10
|
+
# <盘>/sema-data/<名> 的一段路径(S-851)—— `..` / `/` / 空串会把两者指到别处。
|
|
11
|
+
# 自由文本(URL / 镜像引用 / 路径 / 主机名 / 模型 id / 凭据)不在这里判:合法形不是闭集,各有自己的消费点(落 .env 的值
|
|
12
|
+
# 另过 lib/envf.sh 的写口)。盘点见 deploy/sema-up/README.md「取值旗的形」。
|
|
13
|
+
#
|
|
14
|
+
# 字符判据一律用**逐个列出**的字符集(`[!0123456789]`),不用区间(`[0-9]` / `[a-z]` 的含义随 locale 变)。
|
|
15
|
+
# 调用方先定义:log(打到 stderr)。调用形:flag_<形> <称呼> <值> [<词…>];称呼 = 旗名,值可能来自 -f 配置 / 环境时
|
|
16
|
+
# 连变量名一起写(如 `--registry(REGISTRY_ENABLED)`)。拒 = log 两行 + exit 1。
|
|
17
|
+
|
|
18
|
+
# ── 词表(单一属主)──────────────────────────────────────────────────────────────────────────────
|
|
19
|
+
FLAG_WORDS_PROFILE="full-single data-center local-plus full-cluster"
|
|
20
|
+
FLAG_WORDS_USERS="single multi"
|
|
21
|
+
FLAG_WORDS_REGION="auto cn global"
|
|
22
|
+
FLAG_WORDS_GIT="none provision connect"
|
|
23
|
+
# kube 路径:单机两态走 kube-up.sh,machines(多机 ssh 装配)走 cluster-up.sh。
|
|
24
|
+
FLAG_WORDS_KUBE_SINGLE="existing k3s"
|
|
25
|
+
FLAG_WORDS_KUBE="$FLAG_WORDS_KUBE_SINGLE machines"
|
|
26
|
+
# cluster-up.sh 的 sema-stack 装配引擎(缺省 render = as-built 渲染 apply)。
|
|
27
|
+
FLAG_WORDS_STACK_ENGINE="render helm"
|
|
28
|
+
# sema-up.sh 的交互形(缺省 tty;--interactive=json ⇒ json;--yes ⇒ none)。
|
|
29
|
+
FLAG_WORDS_INTERACTIVE="tty json none"
|
|
30
|
+
|
|
31
|
+
# flag_show <值> —— 拒句里回显收到的值:单行可见形(换行 / 控制字符按 bash 的 %q 转义),一个值伪造不出日志里的第二行。
|
|
32
|
+
flag_show() { printf '%q' "$1"; }
|
|
33
|
+
|
|
34
|
+
# flag_words <词…> —— 「a / b / c」。
|
|
35
|
+
flag_words() { local out="" w; for w in "$@"; do out="${out:+$out / }$w"; done; printf '%s' "$out"; }
|
|
36
|
+
|
|
37
|
+
# flag_refuse <称呼> <值> <合法形>
|
|
38
|
+
flag_refuse() {
|
|
39
|
+
log "⛔ $1 收到 $(flag_show "$2") —— 合法形:$3"
|
|
40
|
+
log " ↳ 下一步:按合法形改了再跑(不在形里的值一律拒,不会被当成缺省或别的词)"
|
|
41
|
+
exit 1
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
flag_bool() {
|
|
45
|
+
case "$2" in true|false) return 0 ;; esac
|
|
46
|
+
flag_refuse "$1" "$2" "true / false(只收这两个词;yes / 1 / on 这类写法不认)"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
flag_port() {
|
|
50
|
+
case "$2" in
|
|
51
|
+
''|0*|*[!0123456789]*) ;;
|
|
52
|
+
*) if [ "${#2}" -le 5 ] && [ "$2" -le 65535 ]; then return 0; fi ;;
|
|
53
|
+
esac
|
|
54
|
+
flag_refuse "$1" "$2" "1–65535 的十进制整数(不带前导 0、正负号、空白)"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
flag_enum() {
|
|
58
|
+
local label="$1" v="$2" w; shift 2
|
|
59
|
+
for w in "$@"; do [ "$v" = "$w" ] && return 0; done
|
|
60
|
+
flag_refuse "$label" "$v" "$(flag_words "$@")"
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
flag_project() {
|
|
64
|
+
case "$2" in
|
|
65
|
+
''|[-_]*|*[!abcdefghijklmnopqrstuvwxyz0123456789_-]*) ;;
|
|
66
|
+
*) return 0 ;;
|
|
67
|
+
esac
|
|
68
|
+
flag_refuse "$1" "$2" "小写字母 / 数字 / - / _,首字符是字母或数字(compose 项目名;也是工作目录 ~/.sema-up/<名> 与自动数据根 <盘>/sema-data/<名> 的一段)"
|
|
69
|
+
}
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
choices 打印 compose 路径的在役词(每行一个;--help / README 的词表渲它)
|
|
14
14
|
default <users> 打印该租户形下的缺省 choice
|
|
15
15
|
options <users> 每行一个 `ask` 选项串 `value:label[:infeasible=原因|建议]`
|
|
16
|
+
check <choice> 只判「是不是 compose 路径上的在役词」(退役词 / 表外词 ⇒ 拒,与 resolve 同一只判据),
|
|
17
|
+
不打印;sema-up 在建工作目录之前拿它判 --sandbox 的形(S-621),租户形那一半留给 resolve
|
|
16
18
|
resolve <users> <choice> 校验并打印该车道要落 .env 的 `KEY=VALUE` 行(仅有值的键);
|
|
17
19
|
必需但由运维自备的键名打印成 `#REQUIRED <NAME>` 注释行(「选了却没给」的早拒读它)
|
|
18
20
|
choice-of <REMOTE_EXEC 值> 部署事实 → `--sandbox` 词的反查(决策 = 显式旗 ∨ 部署事实 ∨ 表缺省):上一次落下的 `REMOTE_EXEC=<值>`
|
|
@@ -125,8 +127,8 @@ def cmd_choice_of(remote_exec):
|
|
|
125
127
|
)
|
|
126
128
|
|
|
127
129
|
|
|
128
|
-
def
|
|
129
|
-
|
|
130
|
+
def row_of(t, choice):
|
|
131
|
+
"""`--sandbox` 词 → compose 表行;退役词 / 表外词 ⇒ 拒。`check` 与 `resolve` 同一只判据。"""
|
|
130
132
|
gone = retired_of(t, choice)
|
|
131
133
|
if gone is not None:
|
|
132
134
|
die(
|
|
@@ -140,6 +142,12 @@ def cmd_resolve(users, choice):
|
|
|
140
142
|
" ↳ kube 路径(--profile=full-cluster)**不选词**:runtime 按 runtimeClass 自动定"
|
|
141
143
|
% (choice, " / ".join(r["choice"] for r in compose_rows(t)))
|
|
142
144
|
)
|
|
145
|
+
return row
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def cmd_resolve(users, choice):
|
|
149
|
+
t = table()
|
|
150
|
+
row = row_of(t, choice)
|
|
143
151
|
if users not in row["users"]:
|
|
144
152
|
die(
|
|
145
153
|
"--sandbox=%s 不能用在 --users=%s 上(该车道隔离性 %s)—— 改选:%s,或走 kube 路径 "
|
|
@@ -159,7 +167,7 @@ def cmd_resolve(users, choice):
|
|
|
159
167
|
|
|
160
168
|
def main(argv):
|
|
161
169
|
if len(argv) < 2:
|
|
162
|
-
die("用法: lanes.py choices|default|options|resolve|choice-of …")
|
|
170
|
+
die("用法: lanes.py choices|default|options|check|resolve|choice-of …")
|
|
163
171
|
verb = argv[1]
|
|
164
172
|
if verb == "choices" and len(argv) == 2:
|
|
165
173
|
print(cmd_choices())
|
|
@@ -169,10 +177,12 @@ def main(argv):
|
|
|
169
177
|
print(cmd_options(argv[2]))
|
|
170
178
|
elif verb == "choice-of" and len(argv) == 3:
|
|
171
179
|
print(cmd_choice_of(argv[2]))
|
|
180
|
+
elif verb == "check" and len(argv) == 3:
|
|
181
|
+
row_of(table(), argv[2])
|
|
172
182
|
elif verb == "resolve" and len(argv) == 4:
|
|
173
183
|
print(cmd_resolve(argv[2], argv[3]))
|
|
174
184
|
else:
|
|
175
|
-
die("用法: lanes.py choices | default <users> | options <users> | resolve <users> <choice> | choice-of <REMOTE_EXEC 值>")
|
|
185
|
+
die("用法: lanes.py choices | default <users> | options <users> | check <choice> | resolve <users> <choice> | choice-of <REMOTE_EXEC 值>")
|
|
176
186
|
|
|
177
187
|
|
|
178
188
|
if __name__ == "__main__":
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# lib/shell-access.sh — 「壳(sema CLI)怎么接这台引擎」的唯一渲染(S-850,7.104.0)。sema-up.sh(汇总 / dry-run 计划 /
|
|
2
|
+
# `--interactive=json` 的 summary)、kube-up.sh、cluster-up.sh 三条部署路径都调它,不各写一份。
|
|
3
|
+
# 只给**位置**、不给值:令牌在哪只文件的哪个键、在壳里放进哪个变量 —— 本文件的函数不读任何凭据。
|
|
4
|
+
#
|
|
5
|
+
# 句子里的两条事实(出处是壳的源码,不是推测):
|
|
6
|
+
# · 壳对非回环地址只收 https,回环地址才收 http —— sema-cli `src/sema/engineTarget.ts` 的 `validateEngineUrlTransport`(connect 时判);
|
|
7
|
+
# 所以汇总里「引擎」那一行的局域网 http 地址壳按设计拒连,要先把引擎口带到本机回环(本机直连 / ssh 隧道 /
|
|
8
|
+
# kubectl port-forward);
|
|
9
|
+
# · 壳经环境变量 `SEMA_LIVE_TOKEN` 把令牌作 Bearer 带给回环引擎(sema-cli `src/sema/engineTarget.ts` 的 `resolveLiveAuthToken`);
|
|
10
|
+
# sema-up 三条路径起的引擎只认 SERVICE_AUTH_TOKEN(都没配 AUTH_BRIDGE_ISSUER,registry 登录令牌它不验)。
|
|
11
|
+
SHELL_TOKEN_KEY="SERVICE_AUTH_TOKEN"
|
|
12
|
+
SHELL_TOKEN_ENV="SEMA_LIVE_TOKEN"
|
|
13
|
+
|
|
14
|
+
# shell_connect_sentence <场合> <前置一步(空 = 不需要)> <回环 URL>
|
|
15
|
+
shell_connect_sentence() {
|
|
16
|
+
if [ -n "$2" ]; then printf '%s先 %s,再 sema cloud engine connect %s' "$1" "$2" "$3"
|
|
17
|
+
else printf '%ssema cloud engine connect %s' "$1" "$3"; fi
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
# shell_access_text <凭据文件> <场合> <前置一步> <回环 URL> [<场合> <前置一步> <回环 URL> …]
|
|
21
|
+
# 汇总里的一段(首行 ` 壳接入 `,续行缩进与汇总其它段同宽)。
|
|
22
|
+
shell_access_text() {
|
|
23
|
+
local envf="$1" lead=" 壳接入 "
|
|
24
|
+
shift
|
|
25
|
+
while [ "$#" -ge 3 ]; do
|
|
26
|
+
printf '%s%s\n' "$lead" "$(shell_connect_sentence "$1" "$2" "$3")"
|
|
27
|
+
lead=" "
|
|
28
|
+
shift 3
|
|
29
|
+
done
|
|
30
|
+
printf ' 令牌:在启动 sema 的那个 shell 里 export %s=<值> 再启动 sema;<值> = %s 里 %s 那一行的值(本段不打印它)\n' "$SHELL_TOKEN_ENV" "$envf" "$SHELL_TOKEN_KEY"
|
|
31
|
+
printf ' 为什么不直接连汇总里「引擎」那一行的地址:壳对非回环地址只收 https(令牌不走明文网络),回环地址(本机 / 隧道 / port-forward)才收 http\n'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# shell_access_json <凭据文件> <回环 URL> <隧道命令> <隧道后的回环 URL> —— summary 行的 `shellAccess` 对象(json.dumps:路径里的引号 /
|
|
35
|
+
# 反斜杠照转义)。
|
|
36
|
+
shell_access_json() {
|
|
37
|
+
python3 -c 'import json, sys
|
|
38
|
+
a = sys.argv
|
|
39
|
+
print(json.dumps({"connectUrl": a[2], "tunnel": a[3], "tunnelConnectUrl": a[4], "tokenFile": a[1], "tokenKey": a[5], "tokenEnv": a[6]}, ensure_ascii=False))' \
|
|
40
|
+
"$1" "$2" "$3" "$4" "$SHELL_TOKEN_KEY" "$SHELL_TOKEN_ENV"
|
|
41
|
+
}
|
|
@@ -4,8 +4,15 @@
|
|
|
4
4
|
# (sema cloud deploy 渲染用,同一交互协议的 infeasible:{reason,suggestion} 字段)。
|
|
5
5
|
# 只读探测,零改动,幂等。退出码:0=可部署(可能有 WARN),1=存在 BLOCK 项。
|
|
6
6
|
set -u
|
|
7
|
+
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
8
|
+
# 自动数据根的路径形只在 lib/dataroot.sh 定义一次(S-851):下面「多盘机」建议句与 sema-up 自动选的根同一条规则。
|
|
9
|
+
. "$HERE/lib/dataroot.sh"
|
|
10
|
+
# 取值旗的形(S-621):判据与词表同 sema-up.sh 一处定义。
|
|
11
|
+
. "$HERE/lib/flagshape.sh"
|
|
12
|
+
log() { printf '[preflight] %s\n' "$*" >&2; }
|
|
7
13
|
|
|
8
14
|
JSON=false
|
|
15
|
+
PROJECT="sema" # --project=NAME:建议句里的自动数据根 <盘>/sema-data/<project>(sema-up 传它自己的项目名)
|
|
9
16
|
PROFILE="full" # full | data-center — data-center 档降低 RAM/盘要求
|
|
10
17
|
PORTS="" # --ports=8090,5432,… 显式端口面(调用方按 profile+改口传;缺省按 profile 取默认)
|
|
11
18
|
PORTS_SET=false # 显式给了 --ports(即使空串=「一个都不用检」,重入场景自己的口已剔除)——与「没给」区分
|
|
@@ -14,8 +21,14 @@ for a in "$@"; do
|
|
|
14
21
|
--json) JSON=true ;;
|
|
15
22
|
--profile=*) PROFILE="${a#--profile=}" ;;
|
|
16
23
|
--ports=*) PORTS="${a#--ports=}"; PORTS_SET=true ;;
|
|
24
|
+
--project=*) PROJECT="${a#--project=}" ;;
|
|
17
25
|
esac
|
|
18
26
|
done
|
|
27
|
+
# 取值旗的形(S-621)——在任何探测之前(本脚本只读,但 --json 的 profile 原样进协议行、端口原样进 ss / lsof 的参数)。
|
|
28
|
+
# profile:sema-up 传它自己的档位词;单独跑的缺省是 full(= 非 data-center 的阈值)。
|
|
29
|
+
flag_enum "--profile" "$PROFILE" full $FLAG_WORDS_PROFILE
|
|
30
|
+
flag_project "--project" "$PROJECT"
|
|
31
|
+
set -f; for _p in $(printf '%s' "$PORTS" | tr ',' ' '); do flag_port "--ports 里的一项" "$_p"; done; set +f # 空项(前导逗号)照旧忽略;set -f:值里的 * 不许按文件名展开
|
|
19
32
|
if [ -z "$PORTS" ] && ! $PORTS_SET; then
|
|
20
33
|
# 只检本 profile 真会占的端口(data-center 检 8090/6443 会被无关服务误 BLOCK——真踩)
|
|
21
34
|
case "$PROFILE" in
|
|
@@ -94,7 +107,7 @@ done <<EOF_DF
|
|
|
94
107
|
$DF_OUT
|
|
95
108
|
EOF_DF
|
|
96
109
|
if [ -n "$BEST_MNT" ] && [ "$BEST_MNT" != "/" ] && [ "$BEST_GB" -gt "${DISK_GB:-0}" ]; then
|
|
97
|
-
add WARN disk-alt "$BEST_MNT ${BEST_GB}G avail" "存在比 / 更大的数据盘(多盘机)" "--data-root=$BEST_MNT
|
|
110
|
+
add WARN disk-alt "$BEST_MNT ${BEST_GB}G avail" "存在比 / 更大的数据盘(多盘机)" "--data-root=$(dataroot_for_disk "$BEST_MNT" "$PROJECT")(sema-up 未显式指定时会自动选它;数据根按项目分)"
|
|
98
111
|
fi
|
|
99
112
|
|
|
100
113
|
# ── KVM(**kube 路径**的 kata runtimeClass 前提;compose 路径已无需要 KVM 的车道,S-599)────────
|