compshare-cli 0.3.4__tar.gz → 0.3.6__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.6/PKG-INFO +112 -0
- compshare_cli-0.3.6/README.md +87 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/__init__.py +1 -1
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/cli.py +33 -1
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/commands/feedback.py +1 -1
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/i18n.py +1 -3
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/insights.py +63 -56
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/location.py +2 -8
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/sdk.py +10 -2
- compshare_cli-0.3.6/src/compshare_cli.egg-info/PKG-INFO +112 -0
- compshare_cli-0.3.6/tests/test_feedback.py +202 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_location.py +1 -3
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_sdk.py +9 -0
- compshare_cli-0.3.4/PKG-INFO +0 -400
- compshare_cli-0.3.4/README.md +0 -375
- compshare_cli-0.3.4/src/compshare_cli.egg-info/PKG-INFO +0 -400
- compshare_cli-0.3.4/tests/test_feedback.py +0 -159
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/LICENSE +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/pyproject.toml +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/setup.cfg +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/__main__.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/actions.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/api.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/commands/__init__.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/commands/ask.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/commands/common.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/commands/doctor.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/commands/image.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/commands/instance.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/commands/storage.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/commands/team.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/config.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/errors.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/instance_templates.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/output.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/parsing.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/qa.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/remote_jobs.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/runtime.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/ssh.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/ssh_cache.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli.egg-info/SOURCES.txt +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli.egg-info/dependency_links.txt +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli.egg-info/entry_points.txt +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli.egg-info/requires.txt +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli.egg-info/top_level.txt +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_actions.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_api.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_cli.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_config.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_instance_templates.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_output.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_parsing.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_qa.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_release_version.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_remote_jobs.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_ssh.py +0 -0
- {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_ssh_cache.py +0 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: compshare-cli
|
|
3
|
+
Version: 0.3.6
|
|
4
|
+
Summary: Command-line client for CompShare GPU compute
|
|
5
|
+
Author: CompShare
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/BennielAllan/compshare-cli
|
|
8
|
+
Project-URL: Repository, https://github.com/BennielAllan/compshare-cli
|
|
9
|
+
Project-URL: Changelog, https://github.com/BennielAllan/compshare-cli/blob/master/CHANGELOG.md
|
|
10
|
+
Project-URL: Issues, https://github.com/BennielAllan/compshare-cli/issues
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: click<9,>=8.1
|
|
15
|
+
Requires-Dist: pexpect<5,>=4.9; platform_system != "Windows"
|
|
16
|
+
Requires-Dist: rich<15,>=13
|
|
17
|
+
Requires-Dist: typer<1,>=0.12
|
|
18
|
+
Requires-Dist: ucloud-sdk-python3<0.12,>=0.11.103
|
|
19
|
+
Requires-Dist: urllib3<2,>=1.26.18; python_version < "3.10" and platform_system == "Darwin"
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: pytest<10,>=8; extra == "dev"
|
|
22
|
+
Requires-Dist: pytest-cov<8,>=5; extra == "dev"
|
|
23
|
+
Requires-Dist: ruff<1,>=0.6; extra == "dev"
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# CompShare CLI
|
|
27
|
+
|
|
28
|
+
在终端管理优云智算 GPU 实例、镜像、云盘、US3 挂载和团队资源。
|
|
29
|
+
|
|
30
|
+
- 交互式创建实例,实时查询规格、库存和价格
|
|
31
|
+
- 支持批量生命周期操作、等待状态和跨地域查询
|
|
32
|
+
- 支持可断线恢复的远程任务、状态查询和增量日志读取
|
|
33
|
+
- 支持社区/自定义镜像、云盘、团队额度与账单
|
|
34
|
+
- 默认中文帮助,可切换英文;所有命令支持 JSON 输出
|
|
35
|
+
- 可通过 `compshare ask` 查询产品使用和计费知识
|
|
36
|
+
- 可通过 `compshare feedback` 反馈 CLI 问题和建议
|
|
37
|
+
|
|
38
|
+
## 安装
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install compshare-cli
|
|
42
|
+
pip install --upgrade compshare-cli
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 配置
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
compshare config --name default
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
凭证保存在 `~/.config/compshare/config.json`,支持多个配置:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
compshare config list
|
|
55
|
+
compshare config use production
|
|
56
|
+
compshare --profile production instance list
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
也可以使用环境变量:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
export COMPSHARE_PUBLIC_KEY='...'
|
|
63
|
+
export COMPSHARE_PRIVATE_KEY='...'
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
CLI 使用统计和反馈与业务 API 一样,通过当前 profile 的凭证签名后发送到
|
|
67
|
+
`https://api.compshare.cn/`;开发环境可使用 `COMPSHARE_INSIGHTS_URL` 覆盖网关地址。
|
|
68
|
+
|
|
69
|
+
## 快速开始
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# 查询、创建和查看实例
|
|
73
|
+
compshare instance search --region cn-sh2 --zone cn-sh2-02
|
|
74
|
+
compshare instance create
|
|
75
|
+
compshare instance list --all
|
|
76
|
+
|
|
77
|
+
# 连接实例
|
|
78
|
+
compshare instance ssh INSTANCE_ID
|
|
79
|
+
|
|
80
|
+
# 查看帮助
|
|
81
|
+
compshare -h
|
|
82
|
+
compshare instance -h
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## 命令概览
|
|
86
|
+
|
|
87
|
+
```text
|
|
88
|
+
compshare config API 凭证配置
|
|
89
|
+
compshare feedback 反馈 CLI 问题或建议
|
|
90
|
+
compshare doctor 配置、鉴权、网络与 SSH 环境诊断
|
|
91
|
+
compshare ask 产品使用和计费问答
|
|
92
|
+
compshare instance GPU 实例、规格、库存、价格和生命周期
|
|
93
|
+
compshare image 平台、自定义、社区及共享镜像
|
|
94
|
+
compshare storage 云盘和 US3 挂载
|
|
95
|
+
compshare team 团队、邀请、成员额度、账单和审计
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Skill
|
|
99
|
+
|
|
100
|
+
为 Codex、Claude Code、Cursor 等 AI Agent 安装 CompShare CLI Skill:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npx skills add compshare-cn/compshare-cli --skill compshare-cli
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
完整说明见 [CompShare CLI Skill](skills/compshare-cli/SKILL.md)。
|
|
107
|
+
|
|
108
|
+
## SDK
|
|
109
|
+
|
|
110
|
+
如需通过 SDK 集成 CompShare API,可参考独立的
|
|
111
|
+
[CompShare Developer Examples](https://github.com/ucloud/compshare-developer-examples) 仓库。
|
|
112
|
+
其中包含 Python、Go、Java、JavaScript 和 PHP 示例,覆盖 API 鉴权、GPU 实例创建、规格配置和状态查询。
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# CompShare CLI
|
|
2
|
+
|
|
3
|
+
在终端管理优云智算 GPU 实例、镜像、云盘、US3 挂载和团队资源。
|
|
4
|
+
|
|
5
|
+
- 交互式创建实例,实时查询规格、库存和价格
|
|
6
|
+
- 支持批量生命周期操作、等待状态和跨地域查询
|
|
7
|
+
- 支持可断线恢复的远程任务、状态查询和增量日志读取
|
|
8
|
+
- 支持社区/自定义镜像、云盘、团队额度与账单
|
|
9
|
+
- 默认中文帮助,可切换英文;所有命令支持 JSON 输出
|
|
10
|
+
- 可通过 `compshare ask` 查询产品使用和计费知识
|
|
11
|
+
- 可通过 `compshare feedback` 反馈 CLI 问题和建议
|
|
12
|
+
|
|
13
|
+
## 安装
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install compshare-cli
|
|
17
|
+
pip install --upgrade compshare-cli
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 配置
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
compshare config --name default
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
凭证保存在 `~/.config/compshare/config.json`,支持多个配置:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
compshare config list
|
|
30
|
+
compshare config use production
|
|
31
|
+
compshare --profile production instance list
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
也可以使用环境变量:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
export COMPSHARE_PUBLIC_KEY='...'
|
|
38
|
+
export COMPSHARE_PRIVATE_KEY='...'
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
CLI 使用统计和反馈与业务 API 一样,通过当前 profile 的凭证签名后发送到
|
|
42
|
+
`https://api.compshare.cn/`;开发环境可使用 `COMPSHARE_INSIGHTS_URL` 覆盖网关地址。
|
|
43
|
+
|
|
44
|
+
## 快速开始
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# 查询、创建和查看实例
|
|
48
|
+
compshare instance search --region cn-sh2 --zone cn-sh2-02
|
|
49
|
+
compshare instance create
|
|
50
|
+
compshare instance list --all
|
|
51
|
+
|
|
52
|
+
# 连接实例
|
|
53
|
+
compshare instance ssh INSTANCE_ID
|
|
54
|
+
|
|
55
|
+
# 查看帮助
|
|
56
|
+
compshare -h
|
|
57
|
+
compshare instance -h
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## 命令概览
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
compshare config API 凭证配置
|
|
64
|
+
compshare feedback 反馈 CLI 问题或建议
|
|
65
|
+
compshare doctor 配置、鉴权、网络与 SSH 环境诊断
|
|
66
|
+
compshare ask 产品使用和计费问答
|
|
67
|
+
compshare instance GPU 实例、规格、库存、价格和生命周期
|
|
68
|
+
compshare image 平台、自定义、社区及共享镜像
|
|
69
|
+
compshare storage 云盘和 US3 挂载
|
|
70
|
+
compshare team 团队、邀请、成员额度、账单和审计
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Skill
|
|
74
|
+
|
|
75
|
+
为 Codex、Claude Code、Cursor 等 AI Agent 安装 CompShare CLI Skill:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npx skills add compshare-cn/compshare-cli --skill compshare-cli
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
完整说明见 [CompShare CLI Skill](skills/compshare-cli/SKILL.md)。
|
|
82
|
+
|
|
83
|
+
## SDK
|
|
84
|
+
|
|
85
|
+
如需通过 SDK 集成 CompShare API,可参考独立的
|
|
86
|
+
[CompShare Developer Examples](https://github.com/ucloud/compshare-developer-examples) 仓库。
|
|
87
|
+
其中包含 Python、Go、Java、JavaScript 和 PHP 示例,覆盖 API 鉴权、GPU 实例创建、规格配置和状态查询。
|
|
@@ -506,16 +506,45 @@ def _requested_language(argv: List[str]) -> Optional[str]:
|
|
|
506
506
|
return requested
|
|
507
507
|
|
|
508
508
|
|
|
509
|
+
def _requested_profile(argv: List[str]) -> Optional[str]:
|
|
510
|
+
"""Return the root --profile value, if present."""
|
|
511
|
+
index = 0
|
|
512
|
+
while index < len(argv):
|
|
513
|
+
option = argv[index]
|
|
514
|
+
if option == "--profile":
|
|
515
|
+
return argv[index + 1] if index + 1 < len(argv) else None
|
|
516
|
+
if option.startswith("--profile="):
|
|
517
|
+
return option.split("=", 1)[1] or None
|
|
518
|
+
if option in {"--lang"}:
|
|
519
|
+
index += 2
|
|
520
|
+
continue
|
|
521
|
+
if option.startswith("--lang=") or option in {
|
|
522
|
+
"--json",
|
|
523
|
+
"--show-sensitive",
|
|
524
|
+
"--version",
|
|
525
|
+
"-h",
|
|
526
|
+
"--help",
|
|
527
|
+
}:
|
|
528
|
+
index += 1
|
|
529
|
+
continue
|
|
530
|
+
if not option.startswith("-"):
|
|
531
|
+
break
|
|
532
|
+
index += 1
|
|
533
|
+
return None
|
|
534
|
+
|
|
535
|
+
|
|
509
536
|
def main(args: Optional[List[str]] = None) -> None:
|
|
510
537
|
original_argv = list(sys.argv[1:] if args is None else args)
|
|
511
538
|
argv = list(original_argv)
|
|
512
539
|
if not argv:
|
|
513
540
|
argv = ["-h"]
|
|
514
541
|
telemetry_command: Optional[str] = None
|
|
542
|
+
telemetry_profile: Optional[str] = None
|
|
515
543
|
json_output = _global_flag_requested(argv, "--json")
|
|
516
544
|
show_sensitive = _global_flag_requested(argv, "--show-sensitive")
|
|
517
545
|
try:
|
|
518
546
|
argv = _normalize_global_options(argv)
|
|
547
|
+
telemetry_profile = _requested_profile(argv)
|
|
519
548
|
requested_language = _requested_language(argv)
|
|
520
549
|
if requested_language is None:
|
|
521
550
|
language = configured_language()
|
|
@@ -547,7 +576,10 @@ def main(args: Optional[List[str]] = None) -> None:
|
|
|
547
576
|
raise SystemExit(1) from error
|
|
548
577
|
finally:
|
|
549
578
|
if telemetry_command:
|
|
550
|
-
|
|
579
|
+
if telemetry_profile is None:
|
|
580
|
+
record_command(telemetry_command)
|
|
581
|
+
else:
|
|
582
|
+
record_command(telemetry_command, telemetry_profile)
|
|
551
583
|
if isinstance(result, int) and result:
|
|
552
584
|
raise SystemExit(result)
|
|
553
585
|
|
|
@@ -14,7 +14,7 @@ class FeedbackCategory(str, Enum):
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def run(state: Runtime, category: FeedbackCategory, message: str) -> None:
|
|
17
|
-
response = submit_feedback(category.value, message)
|
|
17
|
+
response = submit_feedback(state.profile, category.value, message)
|
|
18
18
|
Renderer(state.json_output, state.show_sensitive).success(
|
|
19
19
|
tr("Thank you for your feedback."), response
|
|
20
20
|
)
|
|
@@ -718,9 +718,7 @@ ZH_TRANSLATIONS: Dict[str, str] = {
|
|
|
718
718
|
"Feedback service is not configured; set {variable}.": (
|
|
719
719
|
"反馈服务尚未配置,请设置 {variable}。"
|
|
720
720
|
),
|
|
721
|
-
"Insights service rejected the request
|
|
722
|
-
"数据服务拒绝了请求,HTTP 状态码为 {status}。"
|
|
723
|
-
),
|
|
721
|
+
"Insights service rejected the request: {detail}": "数据服务拒绝了请求:{detail}",
|
|
724
722
|
"Unable to reach the insights service.": "无法连接数据服务。",
|
|
725
723
|
"Insights service returned an invalid response.": "数据服务返回了无效响应。",
|
|
726
724
|
"Thank you for your feedback.": "感谢反馈。",
|
|
@@ -7,16 +7,21 @@ import platform
|
|
|
7
7
|
import subprocess
|
|
8
8
|
import sys
|
|
9
9
|
from datetime import datetime, timezone
|
|
10
|
-
from typing import Any, Dict
|
|
11
|
-
from urllib import
|
|
12
|
-
|
|
10
|
+
from typing import Any, Dict, Optional
|
|
11
|
+
from urllib import parse
|
|
12
|
+
|
|
13
|
+
from ucloud.core import exc as ucloud_exc
|
|
13
14
|
|
|
14
15
|
from compshare_cli import __version__
|
|
16
|
+
from compshare_cli.config import ConfigStore, Profile
|
|
15
17
|
from compshare_cli.errors import CLIError
|
|
16
18
|
from compshare_cli.i18n import tr
|
|
19
|
+
from compshare_cli.sdk import CompShareSDK
|
|
17
20
|
|
|
18
21
|
ENDPOINT_ENV = "COMPSHARE_INSIGHTS_URL"
|
|
19
|
-
DEFAULT_ENDPOINT = "
|
|
22
|
+
DEFAULT_ENDPOINT = "https://api.compshare.cn"
|
|
23
|
+
EVENT_ACTION = "CreateCSCLIEvent"
|
|
24
|
+
FEEDBACK_ACTION = "CreateCSCLIFeedback"
|
|
20
25
|
|
|
21
26
|
|
|
22
27
|
def now() -> str:
|
|
@@ -28,18 +33,21 @@ def os_name() -> str:
|
|
|
28
33
|
return value or sys.platform.lower()
|
|
29
34
|
|
|
30
35
|
|
|
31
|
-
def record_command(command: str) -> None:
|
|
36
|
+
def record_command(command: str, profile_name: Optional[str] = None) -> None:
|
|
32
37
|
"""Report a command in a detached process without delaying or affecting the CLI."""
|
|
33
38
|
if not _base_url():
|
|
34
39
|
return
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
document = {
|
|
41
|
+
"profile_name": profile_name,
|
|
42
|
+
"payload": {
|
|
43
|
+
"Command": command,
|
|
44
|
+
"CLIVersion": __version__,
|
|
45
|
+
"OS": os_name(),
|
|
46
|
+
"OccurredAt": now(),
|
|
47
|
+
},
|
|
40
48
|
}
|
|
41
49
|
encoded = base64.urlsafe_b64encode(
|
|
42
|
-
json.dumps(
|
|
50
|
+
json.dumps(document, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
|
|
43
51
|
).decode("ascii")
|
|
44
52
|
kwargs: Dict[str, Any] = {
|
|
45
53
|
"stdin": subprocess.DEVNULL,
|
|
@@ -60,7 +68,11 @@ def record_command(command: str) -> None:
|
|
|
60
68
|
pass
|
|
61
69
|
|
|
62
70
|
|
|
63
|
-
def submit_feedback(
|
|
71
|
+
def submit_feedback(
|
|
72
|
+
profile: Profile,
|
|
73
|
+
category: str,
|
|
74
|
+
message: str,
|
|
75
|
+
) -> Dict[str, Any]:
|
|
64
76
|
if category not in {"bug", "suggest"}:
|
|
65
77
|
raise CLIError(tr("Feedback category must be bug or suggest."))
|
|
66
78
|
normalized = message.strip()
|
|
@@ -75,17 +87,33 @@ def submit_feedback(category: str, message: str) -> Dict[str, Any]:
|
|
|
75
87
|
variable=ENDPOINT_ENV,
|
|
76
88
|
)
|
|
77
89
|
)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
90
|
+
try:
|
|
91
|
+
response = _invoke(
|
|
92
|
+
profile,
|
|
93
|
+
FEEDBACK_ACTION,
|
|
94
|
+
{
|
|
95
|
+
"Category": category,
|
|
96
|
+
"Content": normalized,
|
|
97
|
+
"CLIVersion": __version__,
|
|
98
|
+
"OS": os_name(),
|
|
99
|
+
"OccurredAt": now(),
|
|
100
|
+
},
|
|
101
|
+
)
|
|
102
|
+
feedback_id = response.get("Id") if isinstance(response, dict) else None
|
|
103
|
+
if not feedback_id:
|
|
104
|
+
raise ValueError("missing feedback ID")
|
|
105
|
+
return {"ok": True, "id": feedback_id}
|
|
106
|
+
except ucloud_exc.RetCodeException as error:
|
|
107
|
+
raise CLIError(
|
|
108
|
+
tr(
|
|
109
|
+
"Insights service rejected the request: {detail}",
|
|
110
|
+
detail=error.message or str(error.code),
|
|
111
|
+
)
|
|
112
|
+
) from error
|
|
113
|
+
except (ucloud_exc.UCloudException, TimeoutError, OSError) as error:
|
|
114
|
+
raise CLIError(tr("Unable to reach the insights service.")) from error
|
|
115
|
+
except Exception as error:
|
|
116
|
+
raise CLIError(tr("Insights service returned an invalid response.")) from error
|
|
89
117
|
|
|
90
118
|
|
|
91
119
|
def _base_url() -> str:
|
|
@@ -96,43 +124,22 @@ def _base_url() -> str:
|
|
|
96
124
|
return value if parsed.scheme in {"http", "https"} and parsed.netloc else ""
|
|
97
125
|
|
|
98
126
|
|
|
99
|
-
def
|
|
100
|
-
|
|
101
|
-
req = request.Request(
|
|
102
|
-
f"{_base_url()}{path}",
|
|
103
|
-
data=body,
|
|
104
|
-
headers={
|
|
105
|
-
"Accept": "application/json",
|
|
106
|
-
"Content-Type": "application/json",
|
|
107
|
-
"User-Agent": f"compshare-cli/{__version__}",
|
|
108
|
-
},
|
|
109
|
-
method="POST",
|
|
110
|
-
)
|
|
111
|
-
try:
|
|
112
|
-
with request.urlopen(req, timeout=timeout) as response:
|
|
113
|
-
content = response.read()
|
|
114
|
-
except urlerror.HTTPError as error:
|
|
115
|
-
raise CLIError(
|
|
116
|
-
tr("Insights service rejected the request with HTTP {status}.", status=error.code)
|
|
117
|
-
) from error
|
|
118
|
-
except (urlerror.URLError, TimeoutError, OSError) as error:
|
|
119
|
-
raise CLIError(tr("Unable to reach the insights service.")) from error
|
|
120
|
-
if not content:
|
|
121
|
-
return {"ok": True}
|
|
122
|
-
try:
|
|
123
|
-
result = json.loads(content.decode("utf-8"))
|
|
124
|
-
except (UnicodeDecodeError, json.JSONDecodeError) as error:
|
|
125
|
-
raise CLIError(tr("Insights service returned an invalid response.")) from error
|
|
126
|
-
if not isinstance(result, dict):
|
|
127
|
-
raise CLIError(tr("Insights service returned an invalid response."))
|
|
128
|
-
return result
|
|
127
|
+
def _invoke(profile: Profile, action: str, payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
128
|
+
return CompShareSDK(profile, base_url=_base_url()).invoke(action, payload)
|
|
129
129
|
|
|
130
130
|
|
|
131
131
|
def _send_event(encoded: str) -> None:
|
|
132
132
|
try:
|
|
133
|
-
|
|
134
|
-
if isinstance(
|
|
135
|
-
|
|
133
|
+
document = json.loads(base64.urlsafe_b64decode(encoded.encode("ascii")).decode("utf-8"))
|
|
134
|
+
if not isinstance(document, dict) or not _base_url():
|
|
135
|
+
return
|
|
136
|
+
payload = document.get("payload")
|
|
137
|
+
if not isinstance(payload, dict):
|
|
138
|
+
return
|
|
139
|
+
raw_profile_name = document.get("profile_name")
|
|
140
|
+
profile_name = str(raw_profile_name) if raw_profile_name else None
|
|
141
|
+
profile = ConfigStore().load_profile(profile_name)
|
|
142
|
+
_invoke(profile, EVENT_ACTION, payload)
|
|
136
143
|
except Exception:
|
|
137
144
|
pass
|
|
138
145
|
|
|
@@ -77,11 +77,7 @@ def locate_disk(
|
|
|
77
77
|
zone = str(disk.get("Zone") or "")
|
|
78
78
|
locations = supported_locations(state, request_region=request_region)
|
|
79
79
|
location = next(
|
|
80
|
-
(
|
|
81
|
-
item
|
|
82
|
-
for item in locations
|
|
83
|
-
if str(item.get("Zone") or "") == zone and item.get("Region")
|
|
84
|
-
),
|
|
80
|
+
(item for item in locations if str(item.get("Zone") or "") == zone and item.get("Region")),
|
|
85
81
|
None,
|
|
86
82
|
)
|
|
87
83
|
if location is None:
|
|
@@ -95,8 +91,6 @@ def locate_disk(
|
|
|
95
91
|
region = str(location["Region"])
|
|
96
92
|
mount_instance = disk.get("MountInstance")
|
|
97
93
|
host = (
|
|
98
|
-
{"UHostId": str(mount_instance), "Region": region, "Zone": zone}
|
|
99
|
-
if mount_instance
|
|
100
|
-
else None
|
|
94
|
+
{"UHostId": str(mount_instance), "Region": region, "Zone": zone} if mount_instance else None
|
|
101
95
|
)
|
|
102
96
|
return region, zone, host, disk
|
|
@@ -17,13 +17,21 @@ class CompShareSDK:
|
|
|
17
17
|
lag behind the public API and silently discard newer fields.
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
|
-
def __init__(
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
profile: Profile,
|
|
23
|
+
region: Optional[str] = None,
|
|
24
|
+
base_url: Optional[str] = None,
|
|
25
|
+
) -> None:
|
|
21
26
|
logger = logging.getLogger("compshare_cli.ucloud")
|
|
22
27
|
logger.handlers.clear()
|
|
23
28
|
logger.addHandler(logging.NullHandler())
|
|
24
29
|
logger.setLevel(logging.CRITICAL)
|
|
25
30
|
logger.propagate = False
|
|
26
|
-
|
|
31
|
+
config = profile.sdk_config(region)
|
|
32
|
+
if base_url is not None:
|
|
33
|
+
config["base_url"] = base_url
|
|
34
|
+
self._service = Client(config, logger=logger).ucompshare()
|
|
27
35
|
|
|
28
36
|
def invoke(self, action: str, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
29
37
|
return self._service.invoke(action, params)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: compshare-cli
|
|
3
|
+
Version: 0.3.6
|
|
4
|
+
Summary: Command-line client for CompShare GPU compute
|
|
5
|
+
Author: CompShare
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/BennielAllan/compshare-cli
|
|
8
|
+
Project-URL: Repository, https://github.com/BennielAllan/compshare-cli
|
|
9
|
+
Project-URL: Changelog, https://github.com/BennielAllan/compshare-cli/blob/master/CHANGELOG.md
|
|
10
|
+
Project-URL: Issues, https://github.com/BennielAllan/compshare-cli/issues
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: click<9,>=8.1
|
|
15
|
+
Requires-Dist: pexpect<5,>=4.9; platform_system != "Windows"
|
|
16
|
+
Requires-Dist: rich<15,>=13
|
|
17
|
+
Requires-Dist: typer<1,>=0.12
|
|
18
|
+
Requires-Dist: ucloud-sdk-python3<0.12,>=0.11.103
|
|
19
|
+
Requires-Dist: urllib3<2,>=1.26.18; python_version < "3.10" and platform_system == "Darwin"
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: pytest<10,>=8; extra == "dev"
|
|
22
|
+
Requires-Dist: pytest-cov<8,>=5; extra == "dev"
|
|
23
|
+
Requires-Dist: ruff<1,>=0.6; extra == "dev"
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# CompShare CLI
|
|
27
|
+
|
|
28
|
+
在终端管理优云智算 GPU 实例、镜像、云盘、US3 挂载和团队资源。
|
|
29
|
+
|
|
30
|
+
- 交互式创建实例,实时查询规格、库存和价格
|
|
31
|
+
- 支持批量生命周期操作、等待状态和跨地域查询
|
|
32
|
+
- 支持可断线恢复的远程任务、状态查询和增量日志读取
|
|
33
|
+
- 支持社区/自定义镜像、云盘、团队额度与账单
|
|
34
|
+
- 默认中文帮助,可切换英文;所有命令支持 JSON 输出
|
|
35
|
+
- 可通过 `compshare ask` 查询产品使用和计费知识
|
|
36
|
+
- 可通过 `compshare feedback` 反馈 CLI 问题和建议
|
|
37
|
+
|
|
38
|
+
## 安装
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install compshare-cli
|
|
42
|
+
pip install --upgrade compshare-cli
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 配置
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
compshare config --name default
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
凭证保存在 `~/.config/compshare/config.json`,支持多个配置:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
compshare config list
|
|
55
|
+
compshare config use production
|
|
56
|
+
compshare --profile production instance list
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
也可以使用环境变量:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
export COMPSHARE_PUBLIC_KEY='...'
|
|
63
|
+
export COMPSHARE_PRIVATE_KEY='...'
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
CLI 使用统计和反馈与业务 API 一样,通过当前 profile 的凭证签名后发送到
|
|
67
|
+
`https://api.compshare.cn/`;开发环境可使用 `COMPSHARE_INSIGHTS_URL` 覆盖网关地址。
|
|
68
|
+
|
|
69
|
+
## 快速开始
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# 查询、创建和查看实例
|
|
73
|
+
compshare instance search --region cn-sh2 --zone cn-sh2-02
|
|
74
|
+
compshare instance create
|
|
75
|
+
compshare instance list --all
|
|
76
|
+
|
|
77
|
+
# 连接实例
|
|
78
|
+
compshare instance ssh INSTANCE_ID
|
|
79
|
+
|
|
80
|
+
# 查看帮助
|
|
81
|
+
compshare -h
|
|
82
|
+
compshare instance -h
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## 命令概览
|
|
86
|
+
|
|
87
|
+
```text
|
|
88
|
+
compshare config API 凭证配置
|
|
89
|
+
compshare feedback 反馈 CLI 问题或建议
|
|
90
|
+
compshare doctor 配置、鉴权、网络与 SSH 环境诊断
|
|
91
|
+
compshare ask 产品使用和计费问答
|
|
92
|
+
compshare instance GPU 实例、规格、库存、价格和生命周期
|
|
93
|
+
compshare image 平台、自定义、社区及共享镜像
|
|
94
|
+
compshare storage 云盘和 US3 挂载
|
|
95
|
+
compshare team 团队、邀请、成员额度、账单和审计
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Skill
|
|
99
|
+
|
|
100
|
+
为 Codex、Claude Code、Cursor 等 AI Agent 安装 CompShare CLI Skill:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npx skills add compshare-cn/compshare-cli --skill compshare-cli
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
完整说明见 [CompShare CLI Skill](skills/compshare-cli/SKILL.md)。
|
|
107
|
+
|
|
108
|
+
## SDK
|
|
109
|
+
|
|
110
|
+
如需通过 SDK 集成 CompShare API,可参考独立的
|
|
111
|
+
[CompShare Developer Examples](https://github.com/ucloud/compshare-developer-examples) 仓库。
|
|
112
|
+
其中包含 Python、Go、Java、JavaScript 和 PHP 示例,覆盖 API 鉴权、GPU 实例创建、规格配置和状态查询。
|