sdu-ucloud-cli 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sdu_ucloud_cli-0.1.0/.gitignore +22 -0
- sdu_ucloud_cli-0.1.0/LICENSE +21 -0
- sdu_ucloud_cli-0.1.0/PKG-INFO +306 -0
- sdu_ucloud_cli-0.1.0/README.md +258 -0
- sdu_ucloud_cli-0.1.0/pyproject.toml +72 -0
- sdu_ucloud_cli-0.1.0/ucloud_cli/__init__.py +5 -0
- sdu_ucloud_cli-0.1.0/ucloud_cli/__main__.py +5 -0
- sdu_ucloud_cli-0.1.0/ucloud_cli/auth.py +213 -0
- sdu_ucloud_cli-0.1.0/ucloud_cli/cli.py +4661 -0
- sdu_ucloud_cli-0.1.0/ucloud_cli/client.py +22 -0
- sdu_ucloud_cli-0.1.0/ucloud_cli/config.py +80 -0
- sdu_ucloud_cli-0.1.0/ucloud_cli/discovery.py +103 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
dist_pypi/
|
|
7
|
+
wheels/
|
|
8
|
+
*.egg-info
|
|
9
|
+
.pytest_cache/
|
|
10
|
+
.ruff_cache/
|
|
11
|
+
.mypy_cache/
|
|
12
|
+
.DS_Store
|
|
13
|
+
|
|
14
|
+
# Virtual environments
|
|
15
|
+
.venv
|
|
16
|
+
|
|
17
|
+
# Local traffic captures may include auth tokens
|
|
18
|
+
*.curl
|
|
19
|
+
captures/
|
|
20
|
+
|
|
21
|
+
# Local cloned backend source (not part of this CLI package)
|
|
22
|
+
ucloud/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rasmus Larsen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sdu-ucloud-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Unofficial CLI for SDU UCloud web service
|
|
5
|
+
Author-email: Rasmus Larsen <rasmus.larsen@alexandra.dk>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Rasmus Larsen
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Keywords: cli,hpc,sdu,ucloud
|
|
29
|
+
Classifier: Development Status :: 3 - Alpha
|
|
30
|
+
Classifier: Environment :: Console
|
|
31
|
+
Classifier: Intended Audience :: Developers
|
|
32
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
33
|
+
Classifier: Operating System :: OS Independent
|
|
34
|
+
Classifier: Programming Language :: Python :: 3
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
38
|
+
Classifier: Topic :: Utilities
|
|
39
|
+
Requires-Python: >=3.10.13
|
|
40
|
+
Requires-Dist: httpx<1.0,>=0.27
|
|
41
|
+
Requires-Dist: platformdirs<5.0,>=4.2
|
|
42
|
+
Requires-Dist: rich<14.0,>=13.7
|
|
43
|
+
Requires-Dist: typer<1.0,>=0.12
|
|
44
|
+
Provides-Extra: dev
|
|
45
|
+
Requires-Dist: pytest<9.0,>=8.2; extra == 'dev'
|
|
46
|
+
Requires-Dist: ruff<1.0,>=0.6.5; extra == 'dev'
|
|
47
|
+
Description-Content-Type: text/markdown
|
|
48
|
+
|
|
49
|
+
# ucloud-cli
|
|
50
|
+
|
|
51
|
+
`ucloud-cli` is an unofficial command-line client for SDU UCloud (`https://cloud.sdu.dk`).
|
|
52
|
+
It lets you manage common workflows from a terminal: projects, jobs, job submission, status checks, accounting, and SSH access.
|
|
53
|
+
It is published on PyPI as `sdu-ucloud-cli` and installs the `ucloud` command.
|
|
54
|
+
|
|
55
|
+
This tool uses the same web endpoints as the UCloud dashboard.
|
|
56
|
+
There is no stable public API contract for these endpoints, so behavior can change over time.
|
|
57
|
+
|
|
58
|
+
## Install
|
|
59
|
+
|
|
60
|
+
Install from PyPI:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
uv tool install sdu-ucloud-cli
|
|
64
|
+
ucloud --help
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Install from a local checkout:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
uv tool install .
|
|
71
|
+
ucloud --help
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Run directly from source:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
uv sync
|
|
78
|
+
uv run ucloud --help
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Install from Git without cloning:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
uv tool install "git+https://github.com/rlrs/ucloud-cli.git"
|
|
85
|
+
ucloud --help
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## First login flow
|
|
89
|
+
|
|
90
|
+
Login directly with username/password (supports MFA challenge):
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
uv run ucloud auth login --username <username>
|
|
94
|
+
uv run ucloud auth status
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Refresh the access token from the stored `refreshToken` cookie:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
uv run ucloud auth refresh
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
If you already have a browser session in Firefox, import it automatically:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
uv run ucloud auth import-firefox
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Fallbacks (manual browser capture):
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
uv run ucloud auth import-curl capture.curl
|
|
113
|
+
uv run ucloud auth login-cookie --cookie-header "name=value; other=value"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Probe endpoints
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
uv run ucloud request GET /api/projects
|
|
120
|
+
uv run ucloud request GET /api/projects --output json
|
|
121
|
+
uv run ucloud request POST /api/example --json '{"id":"123"}'
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
You can attach a project context header to any request:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
uv run ucloud request GET /api/jobs/browse --project <project-id>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Project context
|
|
131
|
+
|
|
132
|
+
Set a default project once and reuse it across commands:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
uv run ucloud projects browse --limit 20
|
|
136
|
+
uv run ucloud projects use --project <project-id>
|
|
137
|
+
uv run ucloud projects current
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
You can also run `uv run ucloud projects use` without `--project` to pick from an interactive list.
|
|
141
|
+
|
|
142
|
+
## Drives and files (read-only)
|
|
143
|
+
|
|
144
|
+
Browse drives in the active project:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
uv run ucloud files drives
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
List files in a directory:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
uv run ucloud files ls /
|
|
154
|
+
uv run ucloud files ls /1081839/DFM
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Inspect a single path:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
uv run ucloud files stat /1081839/DFM/readme.txt
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Show storage usage/quota from drives + wallets:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
uv run ucloud files df
|
|
167
|
+
uv run ucloud files df --project all
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Render a recursive tree (read-only crawl):
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
uv run ucloud files tree /1093173
|
|
174
|
+
uv run ucloud files tree /1093173/eval-service --dirs-only
|
|
175
|
+
uv run ucloud files tree / --crawl-drives --max-depth 2
|
|
176
|
+
uv run ucloud files tree /1093173/eval-service --sort-by size --reverse --no-dirs-first
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
`--max-depth` limits tree display depth only; size aggregation still uses crawl results.
|
|
180
|
+
|
|
181
|
+
## Browse jobs
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
uv run ucloud jobs browse
|
|
185
|
+
uv run ucloud jobs browse --filter-state RUNNING --items-per-page 100
|
|
186
|
+
uv run ucloud jobs browse --all --items-per-page 100
|
|
187
|
+
uv run ucloud jobs browse --project all
|
|
188
|
+
uv run ucloud jobs browse --output json --limit 20
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
`jobs browse` uses the active project context and prints it above the result.
|
|
192
|
+
Set one with `ucloud projects use --project <project-id>` or override with `--project`.
|
|
193
|
+
Use `--project all` to browse across all visible projects.
|
|
194
|
+
When available, the project line includes both title and id.
|
|
195
|
+
Browse output includes remaining time until expiry (`remaining`).
|
|
196
|
+
|
|
197
|
+
## Job status and stop
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
uv run ucloud jobs status <job-id>
|
|
201
|
+
uv run ucloud jobs status <job-id> --poll --interval 2
|
|
202
|
+
uv run ucloud jobs stop <job-id>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## SSH into a job
|
|
206
|
+
|
|
207
|
+
Open SSH directly from the latest `jobs/retrieve` SSH update:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
uv run ucloud jobs ssh <job-id>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Print the resolved command without executing:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
uv run ucloud jobs ssh <job-id> --print-only
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Submit jobs (safe default)
|
|
220
|
+
|
|
221
|
+
`jobs submit` is dry-run by default and does not send anything to UCloud unless `--execute` is present.
|
|
222
|
+
The selected project controls the `Project` request header (job ownership context), while mounted drive paths can still point to other projects.
|
|
223
|
+
Project-scoped commands print the active project and allow `--project` override.
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
uv run ucloud jobs submit --from-curl job-submit.curl
|
|
227
|
+
uv run ucloud jobs submit --from-curl job-submit.curl --execute
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Copy a previous job as a template:
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
uv run ucloud jobs submit --from <job-id>
|
|
234
|
+
uv run ucloud jobs submit --from <job-id> --execute
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Useful overrides (without editing raw JSON):
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
uv run ucloud jobs submit --from-curl job-submit.curl \
|
|
241
|
+
--name "debug-run" \
|
|
242
|
+
--app-version Aug2026 \
|
|
243
|
+
--product-id u3-gpu-4 \
|
|
244
|
+
--replicas 1 \
|
|
245
|
+
--time 12:00 \
|
|
246
|
+
--mount /<id>/<dir> \
|
|
247
|
+
--mount-ro /<id>/<dir>
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
This prints a readable summary first. Add `--show-payload` to inspect full JSON and `--write-payload job.json` to save it.
|
|
251
|
+
|
|
252
|
+
Other payload input modes:
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
uv run ucloud jobs submit --payload-file job.json
|
|
256
|
+
uv run ucloud jobs submit --json '{"type":"bulk","items":[]}'
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Browse accounting wallets
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
uv run ucloud accounting wallets
|
|
263
|
+
uv run ucloud accounting wallets --items-per-page 250
|
|
264
|
+
uv run ucloud accounting wallets --output json --limit 20
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
`accounting wallets` is project-scoped and uses the active project (or `--project`).
|
|
268
|
+
|
|
269
|
+
## Per-user job accounting
|
|
270
|
+
|
|
271
|
+
Aggregate historical job usage per user inside the active project:
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
uv run ucloud accounting jobs
|
|
275
|
+
uv run ucloud accounting jobs --max-pages 10
|
|
276
|
+
uv run ucloud accounting jobs --output json
|
|
277
|
+
uv run ucloud accounting jobs --project all
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
`accounting jobs` uses `jobs/browse` with pagination and sums estimated GPU-hours by owner.
|
|
281
|
+
By default it includes all job states; use `--filter-state` to narrow scope.
|
|
282
|
+
Pass `--project all` to aggregate across all visible projects.
|
|
283
|
+
Running jobs are counted only up to the current time (not full allocation).
|
|
284
|
+
Accounting tables include one column per machine family (for example `u3-gpu`, `u1-dfm`, `u1-standard-h`).
|
|
285
|
+
GPU families are shown in `gpuh`; non-GPU families are shown in `h`.
|
|
286
|
+
|
|
287
|
+
## Project helper
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
uv run ucloud projects browse
|
|
291
|
+
uv run ucloud projects browse --items-per-page 250 --sort-by favorite
|
|
292
|
+
uv run ucloud projects browse --output json --limit 20
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## Auto-discover endpoints from source
|
|
296
|
+
|
|
297
|
+
If you have the UCloud source repository cloned as `ucloud/`, you can parse the generated endpoint map:
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
uv run ucloud discover endpoints
|
|
301
|
+
uv run ucloud discover endpoints --contains jobs --contains browse
|
|
302
|
+
uv run ucloud discover endpoints --method GET --output json --write endpoints.json
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
By default this reads:
|
|
306
|
+
`ucloud/frontend-web/webclient/app/Authentication/RpcNameTable.ts`
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# ucloud-cli
|
|
2
|
+
|
|
3
|
+
`ucloud-cli` is an unofficial command-line client for SDU UCloud (`https://cloud.sdu.dk`).
|
|
4
|
+
It lets you manage common workflows from a terminal: projects, jobs, job submission, status checks, accounting, and SSH access.
|
|
5
|
+
It is published on PyPI as `sdu-ucloud-cli` and installs the `ucloud` command.
|
|
6
|
+
|
|
7
|
+
This tool uses the same web endpoints as the UCloud dashboard.
|
|
8
|
+
There is no stable public API contract for these endpoints, so behavior can change over time.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
Install from PyPI:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
uv tool install sdu-ucloud-cli
|
|
16
|
+
ucloud --help
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Install from a local checkout:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
uv tool install .
|
|
23
|
+
ucloud --help
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Run directly from source:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
uv sync
|
|
30
|
+
uv run ucloud --help
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Install from Git without cloning:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
uv tool install "git+https://github.com/rlrs/ucloud-cli.git"
|
|
37
|
+
ucloud --help
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## First login flow
|
|
41
|
+
|
|
42
|
+
Login directly with username/password (supports MFA challenge):
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
uv run ucloud auth login --username <username>
|
|
46
|
+
uv run ucloud auth status
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Refresh the access token from the stored `refreshToken` cookie:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
uv run ucloud auth refresh
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
If you already have a browser session in Firefox, import it automatically:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
uv run ucloud auth import-firefox
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Fallbacks (manual browser capture):
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
uv run ucloud auth import-curl capture.curl
|
|
65
|
+
uv run ucloud auth login-cookie --cookie-header "name=value; other=value"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Probe endpoints
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
uv run ucloud request GET /api/projects
|
|
72
|
+
uv run ucloud request GET /api/projects --output json
|
|
73
|
+
uv run ucloud request POST /api/example --json '{"id":"123"}'
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
You can attach a project context header to any request:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
uv run ucloud request GET /api/jobs/browse --project <project-id>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Project context
|
|
83
|
+
|
|
84
|
+
Set a default project once and reuse it across commands:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
uv run ucloud projects browse --limit 20
|
|
88
|
+
uv run ucloud projects use --project <project-id>
|
|
89
|
+
uv run ucloud projects current
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
You can also run `uv run ucloud projects use` without `--project` to pick from an interactive list.
|
|
93
|
+
|
|
94
|
+
## Drives and files (read-only)
|
|
95
|
+
|
|
96
|
+
Browse drives in the active project:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
uv run ucloud files drives
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
List files in a directory:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
uv run ucloud files ls /
|
|
106
|
+
uv run ucloud files ls /1081839/DFM
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Inspect a single path:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
uv run ucloud files stat /1081839/DFM/readme.txt
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Show storage usage/quota from drives + wallets:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
uv run ucloud files df
|
|
119
|
+
uv run ucloud files df --project all
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Render a recursive tree (read-only crawl):
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
uv run ucloud files tree /1093173
|
|
126
|
+
uv run ucloud files tree /1093173/eval-service --dirs-only
|
|
127
|
+
uv run ucloud files tree / --crawl-drives --max-depth 2
|
|
128
|
+
uv run ucloud files tree /1093173/eval-service --sort-by size --reverse --no-dirs-first
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`--max-depth` limits tree display depth only; size aggregation still uses crawl results.
|
|
132
|
+
|
|
133
|
+
## Browse jobs
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
uv run ucloud jobs browse
|
|
137
|
+
uv run ucloud jobs browse --filter-state RUNNING --items-per-page 100
|
|
138
|
+
uv run ucloud jobs browse --all --items-per-page 100
|
|
139
|
+
uv run ucloud jobs browse --project all
|
|
140
|
+
uv run ucloud jobs browse --output json --limit 20
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`jobs browse` uses the active project context and prints it above the result.
|
|
144
|
+
Set one with `ucloud projects use --project <project-id>` or override with `--project`.
|
|
145
|
+
Use `--project all` to browse across all visible projects.
|
|
146
|
+
When available, the project line includes both title and id.
|
|
147
|
+
Browse output includes remaining time until expiry (`remaining`).
|
|
148
|
+
|
|
149
|
+
## Job status and stop
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
uv run ucloud jobs status <job-id>
|
|
153
|
+
uv run ucloud jobs status <job-id> --poll --interval 2
|
|
154
|
+
uv run ucloud jobs stop <job-id>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## SSH into a job
|
|
158
|
+
|
|
159
|
+
Open SSH directly from the latest `jobs/retrieve` SSH update:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
uv run ucloud jobs ssh <job-id>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Print the resolved command without executing:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
uv run ucloud jobs ssh <job-id> --print-only
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Submit jobs (safe default)
|
|
172
|
+
|
|
173
|
+
`jobs submit` is dry-run by default and does not send anything to UCloud unless `--execute` is present.
|
|
174
|
+
The selected project controls the `Project` request header (job ownership context), while mounted drive paths can still point to other projects.
|
|
175
|
+
Project-scoped commands print the active project and allow `--project` override.
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
uv run ucloud jobs submit --from-curl job-submit.curl
|
|
179
|
+
uv run ucloud jobs submit --from-curl job-submit.curl --execute
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Copy a previous job as a template:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
uv run ucloud jobs submit --from <job-id>
|
|
186
|
+
uv run ucloud jobs submit --from <job-id> --execute
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Useful overrides (without editing raw JSON):
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
uv run ucloud jobs submit --from-curl job-submit.curl \
|
|
193
|
+
--name "debug-run" \
|
|
194
|
+
--app-version Aug2026 \
|
|
195
|
+
--product-id u3-gpu-4 \
|
|
196
|
+
--replicas 1 \
|
|
197
|
+
--time 12:00 \
|
|
198
|
+
--mount /<id>/<dir> \
|
|
199
|
+
--mount-ro /<id>/<dir>
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
This prints a readable summary first. Add `--show-payload` to inspect full JSON and `--write-payload job.json` to save it.
|
|
203
|
+
|
|
204
|
+
Other payload input modes:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
uv run ucloud jobs submit --payload-file job.json
|
|
208
|
+
uv run ucloud jobs submit --json '{"type":"bulk","items":[]}'
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Browse accounting wallets
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
uv run ucloud accounting wallets
|
|
215
|
+
uv run ucloud accounting wallets --items-per-page 250
|
|
216
|
+
uv run ucloud accounting wallets --output json --limit 20
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
`accounting wallets` is project-scoped and uses the active project (or `--project`).
|
|
220
|
+
|
|
221
|
+
## Per-user job accounting
|
|
222
|
+
|
|
223
|
+
Aggregate historical job usage per user inside the active project:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
uv run ucloud accounting jobs
|
|
227
|
+
uv run ucloud accounting jobs --max-pages 10
|
|
228
|
+
uv run ucloud accounting jobs --output json
|
|
229
|
+
uv run ucloud accounting jobs --project all
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
`accounting jobs` uses `jobs/browse` with pagination and sums estimated GPU-hours by owner.
|
|
233
|
+
By default it includes all job states; use `--filter-state` to narrow scope.
|
|
234
|
+
Pass `--project all` to aggregate across all visible projects.
|
|
235
|
+
Running jobs are counted only up to the current time (not full allocation).
|
|
236
|
+
Accounting tables include one column per machine family (for example `u3-gpu`, `u1-dfm`, `u1-standard-h`).
|
|
237
|
+
GPU families are shown in `gpuh`; non-GPU families are shown in `h`.
|
|
238
|
+
|
|
239
|
+
## Project helper
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
uv run ucloud projects browse
|
|
243
|
+
uv run ucloud projects browse --items-per-page 250 --sort-by favorite
|
|
244
|
+
uv run ucloud projects browse --output json --limit 20
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Auto-discover endpoints from source
|
|
248
|
+
|
|
249
|
+
If you have the UCloud source repository cloned as `ucloud/`, you can parse the generated endpoint map:
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
uv run ucloud discover endpoints
|
|
253
|
+
uv run ucloud discover endpoints --contains jobs --contains browse
|
|
254
|
+
uv run ucloud discover endpoints --method GET --output json --write endpoints.json
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
By default this reads:
|
|
258
|
+
`ucloud/frontend-web/webclient/app/Authentication/RpcNameTable.ts`
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.25"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "sdu-ucloud-cli"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Unofficial CLI for SDU UCloud web service"
|
|
9
|
+
authors = [
|
|
10
|
+
{ name = "Rasmus Larsen", email = "rasmus.larsen@alexandra.dk" },
|
|
11
|
+
]
|
|
12
|
+
license = { file = "LICENSE" }
|
|
13
|
+
readme = "README.md"
|
|
14
|
+
requires-python = ">=3.10.13"
|
|
15
|
+
keywords = ["ucloud", "sdu", "cli", "hpc"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Environment :: Console",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Topic :: Utilities",
|
|
27
|
+
]
|
|
28
|
+
dependencies = [
|
|
29
|
+
"httpx>=0.27,<1.0",
|
|
30
|
+
"platformdirs>=4.2,<5.0",
|
|
31
|
+
"rich>=13.7,<14.0",
|
|
32
|
+
"typer>=0.12,<1.0",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.optional-dependencies]
|
|
36
|
+
dev = [
|
|
37
|
+
"pytest>=8.2,<9.0",
|
|
38
|
+
"ruff>=0.6.5,<1.0",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
[project.scripts]
|
|
42
|
+
ucloud = "ucloud_cli.cli:main"
|
|
43
|
+
|
|
44
|
+
[tool.hatch.version]
|
|
45
|
+
path = "ucloud_cli/__init__.py"
|
|
46
|
+
|
|
47
|
+
[tool.hatch.build.targets.wheel]
|
|
48
|
+
packages = ["ucloud_cli"]
|
|
49
|
+
|
|
50
|
+
[tool.hatch.build.targets.sdist]
|
|
51
|
+
only-include = [
|
|
52
|
+
"LICENSE",
|
|
53
|
+
"README.md",
|
|
54
|
+
"pyproject.toml",
|
|
55
|
+
"ucloud_cli",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[tool.pytest.ini_options]
|
|
59
|
+
pythonpath = ["."]
|
|
60
|
+
markers = [
|
|
61
|
+
"live: tests that talk to a live UCloud environment (opt-in with UCLOUD_LIVE_TESTS=1).",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
[tool.ruff]
|
|
65
|
+
target-version = "py310"
|
|
66
|
+
extend-exclude = ["ucloud"]
|
|
67
|
+
|
|
68
|
+
[dependency-groups]
|
|
69
|
+
dev = [
|
|
70
|
+
"build>=1.4.0",
|
|
71
|
+
"twine>=6.2.0",
|
|
72
|
+
]
|