compshare-cli 0.3.3__tar.gz → 0.3.4__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.
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/PKG-INFO +103 -15
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/README.md +102 -14
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/pyproject.toml +4 -1
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/__init__.py +1 -1
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/api.py +28 -13
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/cli.py +202 -22
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/commands/doctor.py +5 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/commands/image.py +9 -1
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/commands/instance.py +630 -2
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/commands/storage.py +1 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/commands/team.py +25 -3
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/config.py +46 -2
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/i18n.py +119 -7
- compshare_cli-0.3.4/src/compshare_cli/output.py +362 -0
- compshare_cli-0.3.4/src/compshare_cli/remote_jobs.py +670 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli.egg-info/PKG-INFO +103 -15
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli.egg-info/SOURCES.txt +3 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/tests/test_api.py +42 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/tests/test_cli.py +789 -94
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/tests/test_config.py +29 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/tests/test_feedback.py +5 -1
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/tests/test_output.py +50 -2
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/tests/test_qa.py +7 -2
- compshare_cli-0.3.4/tests/test_release_version.py +19 -0
- compshare_cli-0.3.4/tests/test_remote_jobs.py +230 -0
- compshare_cli-0.3.3/src/compshare_cli/output.py +0 -190
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/LICENSE +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/setup.cfg +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/__main__.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/actions.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/commands/__init__.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/commands/ask.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/commands/common.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/commands/feedback.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/errors.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/insights.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/instance_templates.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/location.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/parsing.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/qa.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/runtime.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/sdk.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/ssh.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli/ssh_cache.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli.egg-info/dependency_links.txt +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli.egg-info/entry_points.txt +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli.egg-info/requires.txt +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/src/compshare_cli.egg-info/top_level.txt +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/tests/test_actions.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/tests/test_instance_templates.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/tests/test_location.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/tests/test_parsing.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/tests/test_sdk.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/tests/test_ssh.py +0 -0
- {compshare_cli-0.3.3 → compshare_cli-0.3.4}/tests/test_ssh_cache.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: compshare-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: Command-line client for CompShare GPU compute
|
|
5
5
|
Author: CompShare
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -29,13 +29,14 @@ Dynamic: license-file
|
|
|
29
29
|
|
|
30
30
|
- 交互式创建实例,实时查询规格、库存和价格
|
|
31
31
|
- 支持批量生命周期操作、等待状态和跨地域查询
|
|
32
|
+
- 支持可断线恢复的远程任务、状态查询和增量日志读取
|
|
32
33
|
- 支持社区/自定义镜像、云盘、团队额度与账单
|
|
33
34
|
- 默认中文帮助,可切换英文;所有命令支持 JSON 输出
|
|
34
35
|
- 可通过 `compshare ask` 查询产品使用和计费知识
|
|
35
36
|
- 可通过 `compshare feedback` 反馈 CLI 问题和建议
|
|
36
37
|
- 基于官方 [`ucloud-sdk-python3`](https://github.com/ucloud/ucloud-sdk-python3)
|
|
37
38
|
|
|
38
|
-
当前版本:`0.3.
|
|
39
|
+
当前版本:`0.3.4`,要求 Python 3.9 或更高版本。
|
|
39
40
|
|
|
40
41
|
## 安装
|
|
41
42
|
|
|
@@ -86,6 +87,9 @@ compshare config use production
|
|
|
86
87
|
compshare --profile production instance list
|
|
87
88
|
```
|
|
88
89
|
|
|
90
|
+
`config list` 会明确标注当前凭证来自配置文件、环境变量或两者混合;JSON 输出还会分别说明
|
|
91
|
+
公钥和私钥的来源,但不会显示凭证内容。
|
|
92
|
+
|
|
89
93
|
也可以使用环境变量:
|
|
90
94
|
|
|
91
95
|
```bash
|
|
@@ -115,6 +119,11 @@ compshare instance stop INSTANCE_1 INSTANCE_2
|
|
|
115
119
|
compshare instance start INSTANCE_1 INSTANCE_2
|
|
116
120
|
compshare instance wait INSTANCE_1 INSTANCE_2 --state Running
|
|
117
121
|
|
|
122
|
+
# 设置、查询和延期定时关机
|
|
123
|
+
compshare instance schedule set INSTANCE_ID --at 2h
|
|
124
|
+
compshare instance schedule show INSTANCE_ID
|
|
125
|
+
compshare instance schedule extend INSTANCE_ID --by 1h
|
|
126
|
+
|
|
118
127
|
# SSH
|
|
119
128
|
compshare instance ssh INSTANCE_ID
|
|
120
129
|
# 默认自动填写 API 返回的密码;需要手动输入时可关闭
|
|
@@ -122,7 +131,7 @@ compshare instance ssh INSTANCE_ID --no-auto-password
|
|
|
122
131
|
# 自动登录后执行远程命令;远程参数用 -- 与 CLI 选项分隔
|
|
123
132
|
compshare instance ssh INSTANCE_ID -- nvidia-smi --query-gpu=name
|
|
124
133
|
compshare instance ssh INSTANCE_ID -- 'cd /workspace && python train.py'
|
|
125
|
-
# Agent
|
|
134
|
+
# Agent/脚本:在统一 JSON 契约的 data 中返回 phase、exit_code、stdout、stderr
|
|
126
135
|
compshare --json instance ssh INSTANCE_ID -- nvidia-smi
|
|
127
136
|
# 强制刷新或禁用本地 SSH 连接缓存
|
|
128
137
|
compshare instance ssh INSTANCE_ID --refresh
|
|
@@ -132,6 +141,12 @@ compshare instance cp INSTANCE_ID ./model.bin :/workspace/model.bin
|
|
|
132
141
|
compshare instance cp INSTANCE_ID ./dataset :/workspace/dataset
|
|
133
142
|
compshare instance cp INSTANCE_ID :/workspace/result ./result
|
|
134
143
|
|
|
144
|
+
# 长时间运行的远程任务;提交后立即返回 Job ID
|
|
145
|
+
compshare instance job submit INSTANCE_ID --name build --cwd /workspace/project -- make -j8
|
|
146
|
+
compshare instance job show INSTANCE_ID JOB_ID
|
|
147
|
+
compshare instance job logs INSTANCE_ID JOB_ID --follow
|
|
148
|
+
compshare instance job wait INSTANCE_ID JOB_ID --timeout 300
|
|
149
|
+
|
|
135
150
|
# 产品问答
|
|
136
151
|
compshare ask "按量实例关机以后,云硬盘还收费吗?"
|
|
137
152
|
```
|
|
@@ -182,6 +197,44 @@ compshare instance create --template training-4090 --cpu 32 --memory 128GiB --ye
|
|
|
182
197
|
`compshare instance template path` 查看实际路径。模板只保存实例创建参数,不保存 API
|
|
183
198
|
凭证、`--yes`、`--show-sensitive` 或其他执行控制选项。
|
|
184
199
|
|
|
200
|
+
## 远程任务
|
|
201
|
+
|
|
202
|
+
`instance ssh INSTANCE_ID -- COMMAND` 适合需要同步获取结果的短命令。安装、编译和计算等
|
|
203
|
+
长任务可通过 `instance job` 在实例上脱离 SSH 运行,本地终端关闭或网络中断不会终止任务:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
# 普通命令及参数会被安全转义
|
|
207
|
+
compshare instance job submit INSTANCE_ID \
|
|
208
|
+
--name training \
|
|
209
|
+
--cwd /workspace/project \
|
|
210
|
+
-- python train.py --epochs 100
|
|
211
|
+
|
|
212
|
+
# 管道、重定向等 Shell 语法应显式使用 sh -lc
|
|
213
|
+
compshare instance job submit INSTANCE_ID --name install -- \
|
|
214
|
+
sh -lc 'apt-get update && apt-get install -y ffmpeg'
|
|
215
|
+
|
|
216
|
+
compshare instance job list INSTANCE_ID
|
|
217
|
+
compshare instance job show INSTANCE_ID JOB_ID
|
|
218
|
+
compshare instance job logs INSTANCE_ID JOB_ID --tail 200
|
|
219
|
+
compshare instance job logs INSTANCE_ID JOB_ID --follow
|
|
220
|
+
compshare instance job wait INSTANCE_ID JOB_ID --timeout 300
|
|
221
|
+
compshare instance job cancel INSTANCE_ID JOB_ID --yes
|
|
222
|
+
compshare instance job prune INSTANCE_ID --older-than 7d --yes
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Agent 可按字节偏移增量读取 stdout 和 stderr;响应中的 `StdoutNextOffset`、
|
|
226
|
+
`StderrNextOffset` 可直接用于下一次请求:
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
compshare --json instance job logs INSTANCE_ID JOB_ID \
|
|
230
|
+
--stdout-offset 0 --stderr-offset 0 --limit 65536
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
任务记录遵循 XDG Base Directory 规范,保存在实例 SSH 用户的
|
|
234
|
+
`${XDG_STATE_HOME:-$HOME/.local/state}/compshare/jobs/JOB_ID/`。目录权限为 `0700`,文件权限为
|
|
235
|
+
`0600`。任务可以抵抗本地断线,但实例关机或重启会将未完成任务标记为 `Interrupted`;实例重装
|
|
236
|
+
或删除会移除系统盘上的任务记录和日志,重要产物应写入数据盘或共享存储。
|
|
237
|
+
|
|
185
238
|
## 功能入口
|
|
186
239
|
|
|
187
240
|
```text
|
|
@@ -234,20 +287,15 @@ CLI 支持 Bash、Zsh、Fish 和 PowerShell 命令补全。为当前 Shell 自
|
|
|
234
287
|
compshare --install-completion
|
|
235
288
|
```
|
|
236
289
|
|
|
237
|
-
如需检查、复制或自行加载补全脚本:
|
|
238
|
-
|
|
239
|
-
```bash
|
|
240
|
-
compshare --show-completion
|
|
241
|
-
```
|
|
242
|
-
|
|
243
290
|
## 脚本调用
|
|
244
291
|
|
|
245
|
-
`--json`、`--profile` 和 `--show-sensitive`
|
|
292
|
+
`--json`、`--profile` 和 `--show-sensitive` 可以放在命令前,也可以放在常见的子命令参数位置;
|
|
293
|
+
`--` 之后的同名参数始终原样传给远程命令:
|
|
246
294
|
|
|
247
295
|
```bash
|
|
248
296
|
compshare --json instance list --status Running --all
|
|
249
|
-
compshare
|
|
250
|
-
compshare --json --show-sensitive
|
|
297
|
+
compshare image list --source community --profile production
|
|
298
|
+
compshare instance show uhost-xxxxxxxx --json --show-sensitive
|
|
251
299
|
```
|
|
252
300
|
|
|
253
301
|
JSON 模式不会启动交互向导。生命周期操作可使用 `--wait`、`--no-wait` 和
|
|
@@ -256,6 +304,44 @@ JSON 模式不会启动交互向导。生命周期操作可使用 `--wait`、`--
|
|
|
256
304
|
`instance show` 可使用 `--ip`、`--softwares`、`--spec`、`--disks`、`--billing`、
|
|
257
305
|
`--image` 和 `--status` 聚焦输出一个或多个信息分组;不传这些选项时保持完整摘要。
|
|
258
306
|
|
|
307
|
+
所有 JSON 命令只输出一个 UTF-8 文档,并使用相同的顶层契约。成功响应如下:
|
|
308
|
+
|
|
309
|
+
```json
|
|
310
|
+
{
|
|
311
|
+
"ok": true,
|
|
312
|
+
"schema_version": "1",
|
|
313
|
+
"data": {"version": "0.3.4"}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
错误响应中的 `code` 稳定且不受语言设置影响,适合 Agent 分支判断;`message` 用于显示,
|
|
318
|
+
接口错误的 Action、RetCode 和请求 ID 放在 `details` 中:
|
|
319
|
+
|
|
320
|
+
```json
|
|
321
|
+
{
|
|
322
|
+
"ok": false,
|
|
323
|
+
"schema_version": "1",
|
|
324
|
+
"error": {
|
|
325
|
+
"code": "api_error",
|
|
326
|
+
"message": "...",
|
|
327
|
+
"details": {
|
|
328
|
+
"action": "DescribeCompShareInstance",
|
|
329
|
+
"ret_code": 171,
|
|
330
|
+
"request_uuid": "..."
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
列表响应使用 `data.items`,总数、过滤数、偏移量和是否返回全部结果位于 `meta`;列表只返回
|
|
337
|
+
表格对应的摘要字段,完整 README、镜像详情和实例详情应通过相应的 `show` 命令读取。
|
|
338
|
+
API 的 Action、RetCode 和请求 ID 也会移到 `meta`。发生默认脱敏时,
|
|
339
|
+
`meta.redacted_fields` 会列出被替换为 `***` 的 JSON 路径。业务字段本身仍沿用 API 返回的名称、
|
|
340
|
+
类型和单位,本版本不做语义转换。
|
|
341
|
+
|
|
342
|
+
`--json --version` 和 `--json --help` 同样遵循上述契约;JSON 帮助直接返回命令、参数和子命令
|
|
343
|
+
结构,不输出 Rich 终端表格。
|
|
344
|
+
|
|
259
345
|
Region 和 Zone 是资源参数,放在对应子命令后:
|
|
260
346
|
|
|
261
347
|
```bash
|
|
@@ -288,14 +374,16 @@ compshare --lang zh --help
|
|
|
288
374
|
- `instance ssh` 在支持的交互式终端中通过伪终端自动填写登录密码,不会打印密码或将其放入进程参数。
|
|
289
375
|
- 自动登录会接受首次出现的 SSH 主机密钥;已记录主机的密钥发生变化时仍会拒绝连接。
|
|
290
376
|
- `instance ssh INSTANCE_ID -- COMMAND` 可非交互执行远程命令,透传命令输出和退出码。
|
|
291
|
-
-
|
|
377
|
+
- `instance job submit` 使用 `nohup` 和独立进程会话在远端运行长任务,任务状态和日志不依赖
|
|
378
|
+
本地 CLI 进程;取消任务和清理历史记录需要显式确认。
|
|
379
|
+
- `--json instance ssh INSTANCE_ID -- COMMAND` 会真实执行命令;成功信息位于 `data`,连接或认证失败使用统一的 `error` 对象。
|
|
292
380
|
- `--json` 始终以 UTF-8 字节输出,不依赖 Windows 活动代码页或终端编码。
|
|
293
381
|
- `instance ssh` 默认将 API 返回的 SSH 命令和密码按 profile/实例缓存 1 小时;Windows 使用当前用户的 DPAPI 加密密码,其他平台将缓存文件权限限制为当前用户。可用 `--refresh` 强制更新、`--no-cache` 禁用;重置密码和重装实例会清除对应缓存。
|
|
294
382
|
- 实例创建是异步操作;`instance create` 默认等待到 `Running`,显式使用 `--no-wait` 才会在创建接口返回后立即退出。`instance ssh` 也会默认等待实例运行后再连接。
|
|
295
383
|
- `instance cp INSTANCE_ID SOURCE DESTINATION` 可自动认证并双向复制文件或目录;实例侧路径
|
|
296
384
|
使用 `:/path` 表示。旧的 `instance scp INSTANCE_ID LOCAL_PATH REMOTE_PATH` 上传语法继续兼容。
|
|
297
|
-
- `--json instance cp ...`
|
|
298
|
-
`stdout
|
|
385
|
+
- `--json instance cp ...` 会真实执行复制,并在统一契约中返回 `phase`、`exit_code`、
|
|
386
|
+
`stdout` 和 `stderr`;只有显式使用 `--print` 才仅输出命令。
|
|
299
387
|
- `--show-sensitive` 会恢复这些字段的原始值;请勿在共享终端、CI 日志或 Agent 会话中使用。
|
|
300
388
|
- 删除、关机、重启、重装和改配等操作默认要求输入 `y` 或 `n` 确认;空输入或无效输入
|
|
301
389
|
最多重试三次。JSON 模式不启动确认提示,执行这类操作必须显式使用 `--yes`。
|
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
- 交互式创建实例,实时查询规格、库存和价格
|
|
6
6
|
- 支持批量生命周期操作、等待状态和跨地域查询
|
|
7
|
+
- 支持可断线恢复的远程任务、状态查询和增量日志读取
|
|
7
8
|
- 支持社区/自定义镜像、云盘、团队额度与账单
|
|
8
9
|
- 默认中文帮助,可切换英文;所有命令支持 JSON 输出
|
|
9
10
|
- 可通过 `compshare ask` 查询产品使用和计费知识
|
|
10
11
|
- 可通过 `compshare feedback` 反馈 CLI 问题和建议
|
|
11
12
|
- 基于官方 [`ucloud-sdk-python3`](https://github.com/ucloud/ucloud-sdk-python3)
|
|
12
13
|
|
|
13
|
-
当前版本:`0.3.
|
|
14
|
+
当前版本:`0.3.4`,要求 Python 3.9 或更高版本。
|
|
14
15
|
|
|
15
16
|
## 安装
|
|
16
17
|
|
|
@@ -61,6 +62,9 @@ compshare config use production
|
|
|
61
62
|
compshare --profile production instance list
|
|
62
63
|
```
|
|
63
64
|
|
|
65
|
+
`config list` 会明确标注当前凭证来自配置文件、环境变量或两者混合;JSON 输出还会分别说明
|
|
66
|
+
公钥和私钥的来源,但不会显示凭证内容。
|
|
67
|
+
|
|
64
68
|
也可以使用环境变量:
|
|
65
69
|
|
|
66
70
|
```bash
|
|
@@ -90,6 +94,11 @@ compshare instance stop INSTANCE_1 INSTANCE_2
|
|
|
90
94
|
compshare instance start INSTANCE_1 INSTANCE_2
|
|
91
95
|
compshare instance wait INSTANCE_1 INSTANCE_2 --state Running
|
|
92
96
|
|
|
97
|
+
# 设置、查询和延期定时关机
|
|
98
|
+
compshare instance schedule set INSTANCE_ID --at 2h
|
|
99
|
+
compshare instance schedule show INSTANCE_ID
|
|
100
|
+
compshare instance schedule extend INSTANCE_ID --by 1h
|
|
101
|
+
|
|
93
102
|
# SSH
|
|
94
103
|
compshare instance ssh INSTANCE_ID
|
|
95
104
|
# 默认自动填写 API 返回的密码;需要手动输入时可关闭
|
|
@@ -97,7 +106,7 @@ compshare instance ssh INSTANCE_ID --no-auto-password
|
|
|
97
106
|
# 自动登录后执行远程命令;远程参数用 -- 与 CLI 选项分隔
|
|
98
107
|
compshare instance ssh INSTANCE_ID -- nvidia-smi --query-gpu=name
|
|
99
108
|
compshare instance ssh INSTANCE_ID -- 'cd /workspace && python train.py'
|
|
100
|
-
# Agent
|
|
109
|
+
# Agent/脚本:在统一 JSON 契约的 data 中返回 phase、exit_code、stdout、stderr
|
|
101
110
|
compshare --json instance ssh INSTANCE_ID -- nvidia-smi
|
|
102
111
|
# 强制刷新或禁用本地 SSH 连接缓存
|
|
103
112
|
compshare instance ssh INSTANCE_ID --refresh
|
|
@@ -107,6 +116,12 @@ compshare instance cp INSTANCE_ID ./model.bin :/workspace/model.bin
|
|
|
107
116
|
compshare instance cp INSTANCE_ID ./dataset :/workspace/dataset
|
|
108
117
|
compshare instance cp INSTANCE_ID :/workspace/result ./result
|
|
109
118
|
|
|
119
|
+
# 长时间运行的远程任务;提交后立即返回 Job ID
|
|
120
|
+
compshare instance job submit INSTANCE_ID --name build --cwd /workspace/project -- make -j8
|
|
121
|
+
compshare instance job show INSTANCE_ID JOB_ID
|
|
122
|
+
compshare instance job logs INSTANCE_ID JOB_ID --follow
|
|
123
|
+
compshare instance job wait INSTANCE_ID JOB_ID --timeout 300
|
|
124
|
+
|
|
110
125
|
# 产品问答
|
|
111
126
|
compshare ask "按量实例关机以后,云硬盘还收费吗?"
|
|
112
127
|
```
|
|
@@ -157,6 +172,44 @@ compshare instance create --template training-4090 --cpu 32 --memory 128GiB --ye
|
|
|
157
172
|
`compshare instance template path` 查看实际路径。模板只保存实例创建参数,不保存 API
|
|
158
173
|
凭证、`--yes`、`--show-sensitive` 或其他执行控制选项。
|
|
159
174
|
|
|
175
|
+
## 远程任务
|
|
176
|
+
|
|
177
|
+
`instance ssh INSTANCE_ID -- COMMAND` 适合需要同步获取结果的短命令。安装、编译和计算等
|
|
178
|
+
长任务可通过 `instance job` 在实例上脱离 SSH 运行,本地终端关闭或网络中断不会终止任务:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
# 普通命令及参数会被安全转义
|
|
182
|
+
compshare instance job submit INSTANCE_ID \
|
|
183
|
+
--name training \
|
|
184
|
+
--cwd /workspace/project \
|
|
185
|
+
-- python train.py --epochs 100
|
|
186
|
+
|
|
187
|
+
# 管道、重定向等 Shell 语法应显式使用 sh -lc
|
|
188
|
+
compshare instance job submit INSTANCE_ID --name install -- \
|
|
189
|
+
sh -lc 'apt-get update && apt-get install -y ffmpeg'
|
|
190
|
+
|
|
191
|
+
compshare instance job list INSTANCE_ID
|
|
192
|
+
compshare instance job show INSTANCE_ID JOB_ID
|
|
193
|
+
compshare instance job logs INSTANCE_ID JOB_ID --tail 200
|
|
194
|
+
compshare instance job logs INSTANCE_ID JOB_ID --follow
|
|
195
|
+
compshare instance job wait INSTANCE_ID JOB_ID --timeout 300
|
|
196
|
+
compshare instance job cancel INSTANCE_ID JOB_ID --yes
|
|
197
|
+
compshare instance job prune INSTANCE_ID --older-than 7d --yes
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Agent 可按字节偏移增量读取 stdout 和 stderr;响应中的 `StdoutNextOffset`、
|
|
201
|
+
`StderrNextOffset` 可直接用于下一次请求:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
compshare --json instance job logs INSTANCE_ID JOB_ID \
|
|
205
|
+
--stdout-offset 0 --stderr-offset 0 --limit 65536
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
任务记录遵循 XDG Base Directory 规范,保存在实例 SSH 用户的
|
|
209
|
+
`${XDG_STATE_HOME:-$HOME/.local/state}/compshare/jobs/JOB_ID/`。目录权限为 `0700`,文件权限为
|
|
210
|
+
`0600`。任务可以抵抗本地断线,但实例关机或重启会将未完成任务标记为 `Interrupted`;实例重装
|
|
211
|
+
或删除会移除系统盘上的任务记录和日志,重要产物应写入数据盘或共享存储。
|
|
212
|
+
|
|
160
213
|
## 功能入口
|
|
161
214
|
|
|
162
215
|
```text
|
|
@@ -209,20 +262,15 @@ CLI 支持 Bash、Zsh、Fish 和 PowerShell 命令补全。为当前 Shell 自
|
|
|
209
262
|
compshare --install-completion
|
|
210
263
|
```
|
|
211
264
|
|
|
212
|
-
如需检查、复制或自行加载补全脚本:
|
|
213
|
-
|
|
214
|
-
```bash
|
|
215
|
-
compshare --show-completion
|
|
216
|
-
```
|
|
217
|
-
|
|
218
265
|
## 脚本调用
|
|
219
266
|
|
|
220
|
-
`--json`、`--profile` 和 `--show-sensitive`
|
|
267
|
+
`--json`、`--profile` 和 `--show-sensitive` 可以放在命令前,也可以放在常见的子命令参数位置;
|
|
268
|
+
`--` 之后的同名参数始终原样传给远程命令:
|
|
221
269
|
|
|
222
270
|
```bash
|
|
223
271
|
compshare --json instance list --status Running --all
|
|
224
|
-
compshare
|
|
225
|
-
compshare --json --show-sensitive
|
|
272
|
+
compshare image list --source community --profile production
|
|
273
|
+
compshare instance show uhost-xxxxxxxx --json --show-sensitive
|
|
226
274
|
```
|
|
227
275
|
|
|
228
276
|
JSON 模式不会启动交互向导。生命周期操作可使用 `--wait`、`--no-wait` 和
|
|
@@ -231,6 +279,44 @@ JSON 模式不会启动交互向导。生命周期操作可使用 `--wait`、`--
|
|
|
231
279
|
`instance show` 可使用 `--ip`、`--softwares`、`--spec`、`--disks`、`--billing`、
|
|
232
280
|
`--image` 和 `--status` 聚焦输出一个或多个信息分组;不传这些选项时保持完整摘要。
|
|
233
281
|
|
|
282
|
+
所有 JSON 命令只输出一个 UTF-8 文档,并使用相同的顶层契约。成功响应如下:
|
|
283
|
+
|
|
284
|
+
```json
|
|
285
|
+
{
|
|
286
|
+
"ok": true,
|
|
287
|
+
"schema_version": "1",
|
|
288
|
+
"data": {"version": "0.3.4"}
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
错误响应中的 `code` 稳定且不受语言设置影响,适合 Agent 分支判断;`message` 用于显示,
|
|
293
|
+
接口错误的 Action、RetCode 和请求 ID 放在 `details` 中:
|
|
294
|
+
|
|
295
|
+
```json
|
|
296
|
+
{
|
|
297
|
+
"ok": false,
|
|
298
|
+
"schema_version": "1",
|
|
299
|
+
"error": {
|
|
300
|
+
"code": "api_error",
|
|
301
|
+
"message": "...",
|
|
302
|
+
"details": {
|
|
303
|
+
"action": "DescribeCompShareInstance",
|
|
304
|
+
"ret_code": 171,
|
|
305
|
+
"request_uuid": "..."
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
列表响应使用 `data.items`,总数、过滤数、偏移量和是否返回全部结果位于 `meta`;列表只返回
|
|
312
|
+
表格对应的摘要字段,完整 README、镜像详情和实例详情应通过相应的 `show` 命令读取。
|
|
313
|
+
API 的 Action、RetCode 和请求 ID 也会移到 `meta`。发生默认脱敏时,
|
|
314
|
+
`meta.redacted_fields` 会列出被替换为 `***` 的 JSON 路径。业务字段本身仍沿用 API 返回的名称、
|
|
315
|
+
类型和单位,本版本不做语义转换。
|
|
316
|
+
|
|
317
|
+
`--json --version` 和 `--json --help` 同样遵循上述契约;JSON 帮助直接返回命令、参数和子命令
|
|
318
|
+
结构,不输出 Rich 终端表格。
|
|
319
|
+
|
|
234
320
|
Region 和 Zone 是资源参数,放在对应子命令后:
|
|
235
321
|
|
|
236
322
|
```bash
|
|
@@ -263,14 +349,16 @@ compshare --lang zh --help
|
|
|
263
349
|
- `instance ssh` 在支持的交互式终端中通过伪终端自动填写登录密码,不会打印密码或将其放入进程参数。
|
|
264
350
|
- 自动登录会接受首次出现的 SSH 主机密钥;已记录主机的密钥发生变化时仍会拒绝连接。
|
|
265
351
|
- `instance ssh INSTANCE_ID -- COMMAND` 可非交互执行远程命令,透传命令输出和退出码。
|
|
266
|
-
-
|
|
352
|
+
- `instance job submit` 使用 `nohup` 和独立进程会话在远端运行长任务,任务状态和日志不依赖
|
|
353
|
+
本地 CLI 进程;取消任务和清理历史记录需要显式确认。
|
|
354
|
+
- `--json instance ssh INSTANCE_ID -- COMMAND` 会真实执行命令;成功信息位于 `data`,连接或认证失败使用统一的 `error` 对象。
|
|
267
355
|
- `--json` 始终以 UTF-8 字节输出,不依赖 Windows 活动代码页或终端编码。
|
|
268
356
|
- `instance ssh` 默认将 API 返回的 SSH 命令和密码按 profile/实例缓存 1 小时;Windows 使用当前用户的 DPAPI 加密密码,其他平台将缓存文件权限限制为当前用户。可用 `--refresh` 强制更新、`--no-cache` 禁用;重置密码和重装实例会清除对应缓存。
|
|
269
357
|
- 实例创建是异步操作;`instance create` 默认等待到 `Running`,显式使用 `--no-wait` 才会在创建接口返回后立即退出。`instance ssh` 也会默认等待实例运行后再连接。
|
|
270
358
|
- `instance cp INSTANCE_ID SOURCE DESTINATION` 可自动认证并双向复制文件或目录;实例侧路径
|
|
271
359
|
使用 `:/path` 表示。旧的 `instance scp INSTANCE_ID LOCAL_PATH REMOTE_PATH` 上传语法继续兼容。
|
|
272
|
-
- `--json instance cp ...`
|
|
273
|
-
`stdout
|
|
360
|
+
- `--json instance cp ...` 会真实执行复制,并在统一契约中返回 `phase`、`exit_code`、
|
|
361
|
+
`stdout` 和 `stderr`;只有显式使用 `--print` 才仅输出命令。
|
|
274
362
|
- `--show-sensitive` 会恢复这些字段的原始值;请勿在共享终端、CI 日志或 Agent 会话中使用。
|
|
275
363
|
- 删除、关机、重启、重装和改配等操作默认要求输入 `y` 或 `n` 确认;空输入或无效输入
|
|
276
364
|
最多重试三次。JSON 模式不启动确认提示,执行这类操作必须显式使用 `--yes`。
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "compshare-cli"
|
|
7
|
-
|
|
7
|
+
dynamic = ["version"]
|
|
8
8
|
description = "Command-line client for CompShare GPU compute"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -39,6 +39,9 @@ dev = [
|
|
|
39
39
|
compshare = "compshare_cli.cli:main"
|
|
40
40
|
compshare-ssh-askpass = "compshare_cli.ssh:askpass"
|
|
41
41
|
|
|
42
|
+
[tool.setuptools.dynamic]
|
|
43
|
+
version = { attr = "compshare_cli.__version__" }
|
|
44
|
+
|
|
42
45
|
[tool.setuptools.packages.find]
|
|
43
46
|
where = ["src"]
|
|
44
47
|
|
|
@@ -52,11 +52,12 @@ def invoke(
|
|
|
52
52
|
continue
|
|
53
53
|
raise
|
|
54
54
|
except CLIError as error:
|
|
55
|
-
renderer.
|
|
55
|
+
renderer.coded_error("configuration_error", str(error))
|
|
56
56
|
raise typer.Exit(1) from error
|
|
57
57
|
except ucloud_exc.RetCodeException as error:
|
|
58
58
|
hint = error_hint(error.action or action, error.code)
|
|
59
|
-
renderer.
|
|
59
|
+
renderer.coded_error(
|
|
60
|
+
"api_error",
|
|
60
61
|
_with_hint(error.message or str(error), hint),
|
|
61
62
|
details={
|
|
62
63
|
"action": error.action,
|
|
@@ -67,10 +68,10 @@ def invoke(
|
|
|
67
68
|
)
|
|
68
69
|
raise typer.Exit(1) from error
|
|
69
70
|
except ucloud_exc.UCloudException as error:
|
|
70
|
-
renderer.
|
|
71
|
+
renderer.coded_error("transport_error", str(error))
|
|
71
72
|
raise typer.Exit(1) from error
|
|
72
73
|
except Exception as error: # SDK transport exceptions are not all UCloudException subclasses.
|
|
73
|
-
renderer.
|
|
74
|
+
renderer.coded_error("transport_error", str(error))
|
|
74
75
|
raise typer.Exit(1) from error
|
|
75
76
|
|
|
76
77
|
if success:
|
|
@@ -79,7 +80,7 @@ def invoke(
|
|
|
79
80
|
renderer.data(response)
|
|
80
81
|
else:
|
|
81
82
|
rows = row_builder(response) if row_builder else response.get(list_key or "") or []
|
|
82
|
-
renderer.data(response, rows=rows, columns=columns)
|
|
83
|
+
renderer.data(response, rows=rows, columns=columns, json_list=True)
|
|
83
84
|
return response
|
|
84
85
|
|
|
85
86
|
|
|
@@ -88,11 +89,14 @@ def call(runtime: Runtime, action: str, params: Dict[str, Any]) -> Dict[str, Any
|
|
|
88
89
|
try:
|
|
89
90
|
return _sdk(runtime, params).invoke(action, params)
|
|
90
91
|
except CLIError as error:
|
|
91
|
-
Renderer(runtime.json_output, runtime.show_sensitive).
|
|
92
|
+
Renderer(runtime.json_output, runtime.show_sensitive).coded_error(
|
|
93
|
+
"configuration_error", str(error)
|
|
94
|
+
)
|
|
92
95
|
raise typer.Exit(1) from error
|
|
93
96
|
except ucloud_exc.RetCodeException as error:
|
|
94
97
|
hint = error_hint(error.action or action, error.code)
|
|
95
|
-
Renderer(runtime.json_output, runtime.show_sensitive).
|
|
98
|
+
Renderer(runtime.json_output, runtime.show_sensitive).coded_error(
|
|
99
|
+
"api_error",
|
|
96
100
|
_with_hint(error.message or str(error), hint),
|
|
97
101
|
details={
|
|
98
102
|
"action": error.action,
|
|
@@ -103,10 +107,14 @@ def call(runtime: Runtime, action: str, params: Dict[str, Any]) -> Dict[str, Any
|
|
|
103
107
|
)
|
|
104
108
|
raise typer.Exit(1) from error
|
|
105
109
|
except ucloud_exc.UCloudException as error:
|
|
106
|
-
Renderer(runtime.json_output, runtime.show_sensitive).
|
|
110
|
+
Renderer(runtime.json_output, runtime.show_sensitive).coded_error(
|
|
111
|
+
"transport_error", str(error)
|
|
112
|
+
)
|
|
107
113
|
raise typer.Exit(1) from error
|
|
108
114
|
except Exception as error:
|
|
109
|
-
Renderer(runtime.json_output, runtime.show_sensitive).
|
|
115
|
+
Renderer(runtime.json_output, runtime.show_sensitive).coded_error(
|
|
116
|
+
"transport_error", str(error)
|
|
117
|
+
)
|
|
110
118
|
raise typer.Exit(1) from error
|
|
111
119
|
|
|
112
120
|
|
|
@@ -195,11 +203,14 @@ def download_file(
|
|
|
195
203
|
try:
|
|
196
204
|
return _sdk(runtime, params).download(action, params)
|
|
197
205
|
except CLIError as error:
|
|
198
|
-
Renderer(runtime.json_output, runtime.show_sensitive).
|
|
206
|
+
Renderer(runtime.json_output, runtime.show_sensitive).coded_error(
|
|
207
|
+
"configuration_error", str(error)
|
|
208
|
+
)
|
|
199
209
|
raise typer.Exit(1) from error
|
|
200
210
|
except ucloud_exc.RetCodeException as error:
|
|
201
211
|
hint = error_hint(error.action or action, error.code)
|
|
202
|
-
Renderer(runtime.json_output, runtime.show_sensitive).
|
|
212
|
+
Renderer(runtime.json_output, runtime.show_sensitive).coded_error(
|
|
213
|
+
"api_error",
|
|
203
214
|
_with_hint(error.message or str(error), hint),
|
|
204
215
|
details={
|
|
205
216
|
"action": error.action or action,
|
|
@@ -210,10 +221,14 @@ def download_file(
|
|
|
210
221
|
)
|
|
211
222
|
raise typer.Exit(1) from error
|
|
212
223
|
except ucloud_exc.UCloudException as error:
|
|
213
|
-
Renderer(runtime.json_output, runtime.show_sensitive).
|
|
224
|
+
Renderer(runtime.json_output, runtime.show_sensitive).coded_error(
|
|
225
|
+
"transport_error", str(error)
|
|
226
|
+
)
|
|
214
227
|
raise typer.Exit(1) from error
|
|
215
228
|
except Exception as error:
|
|
216
|
-
Renderer(runtime.json_output, runtime.show_sensitive).
|
|
229
|
+
Renderer(runtime.json_output, runtime.show_sensitive).coded_error(
|
|
230
|
+
"transport_error", str(error)
|
|
231
|
+
)
|
|
217
232
|
raise typer.Exit(1) from error
|
|
218
233
|
|
|
219
234
|
|