urun-cli 0.7.6__tar.gz → 0.7.8__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.
- {urun_cli-0.7.6 → urun_cli-0.7.8}/CHANGELOG.md +25 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/PKG-INFO +33 -1
- {urun_cli-0.7.6 → urun_cli-0.7.8}/README.md +32 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/pyproject.toml +2 -1
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/api.py +12 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/catalog.py +4 -4
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/cli.py +288 -50
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/deps.py +203 -22
- urun_cli-0.7.8/src/urun/hub_builds.py +328 -0
- urun_cli-0.7.8/src/urun/kubectl_plugin.py +688 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/rust.py +1 -1
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/serve.py +73 -1
- {urun_cli-0.7.6 → urun_cli-0.7.8}/.gitignore +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/LICENSE +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/SECURITY.md +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/hatch_build.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/__init__.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/_bin/README.md +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/buildlogs.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/client_tokens.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/config.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/dev.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/devconsole.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/devstream.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/discovery.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/errors.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/fleet.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/frontend_launch.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/launch_auth.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/manifest.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/nodes.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/openai_proxy_bin.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/repo_deps.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/reserve.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/retry.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/runtime_health.py +0 -0
- {urun_cli-0.7.6 → urun_cli-0.7.8}/src/urun/scratch.py +0 -0
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
## Unreleased
|
|
2
2
|
|
|
3
|
+
- `urun release promote <release_id> [--environment main]` — make an existing
|
|
4
|
+
release current again (clean rollback, no marker commits). Server side it
|
|
5
|
+
takes the same path as a same-content `urun deploy`: the control plane
|
|
6
|
+
re-registers the release and republishes the release pointer.
|
|
7
|
+
- Deploy deps collector: `@app.function(deps=...)` may now reference a
|
|
8
|
+
module-level `Dependencies(...)` constant imported from a file shipped with
|
|
9
|
+
the app (`from sense_deploy import SENSE_DEPS`) — resolved statically by the
|
|
10
|
+
same side-effect-free evaluator, including re-export chains and the
|
|
11
|
+
`import mod` + `mod.SYM` attribute form. An attached `deps=` that cannot be
|
|
12
|
+
statically resolved now FAILS THE DEPLOY LOUDLY naming `file:line`, the
|
|
13
|
+
import it came through, and the fix — previously it silently shipped an
|
|
14
|
+
EMPTY manifest (no python pins, no files) and the app's boot self-test died
|
|
15
|
+
with `No module named ...` after fleet rollout (sense, 2026-10-27/28).
|
|
16
|
+
- `kubectl urun` — a kubectl plugin (`kubectl-urun`, installed alongside
|
|
17
|
+
`urun`) with four verbs over the `gpu.urun.sh/v1alpha1` GPUWorker surface:
|
|
18
|
+
`logs` (the `logs.urun.sh/v1` log subresource, with `-f` follow
|
|
19
|
+
passthrough, `--since`, `--tail`, `-s <service>`), `cordon`/`uncordon`
|
|
20
|
+
(`spec.unschedulable`), `drain` (cordon, then wait for the `Draining`
|
|
21
|
+
condition to reach `False`/`Drained`, nonzero on `--timeout`), and
|
|
22
|
+
`describe` (node block, services, conditions, events, liveness lease,
|
|
23
|
+
claim summary). Claim-owned workers are cordoned through their OWNING
|
|
24
|
+
GPUWorkerClaim (resolved via `spec.claimRef`) because the claim
|
|
25
|
+
reconciler re-renders the worker's spec; the patched object is printed.
|
|
26
|
+
All verbs ride a bounded `kubectl proxy --port=0` child, so
|
|
27
|
+
`--kubeconfig`/`--context`/`-n` resolve exactly as kubectl resolves them.
|
|
3
28
|
- Security (ENG-570 / pentest urun-cli-01, mirrored in urun-python
|
|
4
29
|
`urun/core/store/repo.py`): `store.repo(...)` specs parsed from untrusted
|
|
5
30
|
app source are validated before any git call. The `@<ref>` pin must be a
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: urun-cli
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.8
|
|
4
4
|
Summary: End-user CLI for deploying apps to urun
|
|
5
5
|
Project-URL: Homepage, https://urun.sh
|
|
6
6
|
Project-URL: Repository, https://github.com/urun-sh/urun-cli
|
|
@@ -534,6 +534,33 @@ What it does:
|
|
|
534
534
|
sooner. `--no-logs` skips streaming the occupant's log after creation
|
|
535
535
|
(Ctrl-C also detaches without tearing the occupant down).
|
|
536
536
|
|
|
537
|
+
## Operator: GPUWorker nodes (`kubectl urun`)
|
|
538
|
+
|
|
539
|
+
Installing `urun-cli` also installs the `kubectl-urun` binary; with it on
|
|
540
|
+
`PATH`, kubectl dispatches `kubectl urun` to it as a standard kubectl plugin.
|
|
541
|
+
These verbs are the operator surface over the `gpu.urun.sh/v1alpha1`
|
|
542
|
+
GPUWorker custom resources (the cluster must have the urun controller
|
|
543
|
+
installed); they resolve kubeconfig/context through kubectl itself, so
|
|
544
|
+
`--kubeconfig`, `--context`, and `-n` behave like any other kubectl command:
|
|
545
|
+
|
|
546
|
+
```bash
|
|
547
|
+
kubectl urun logs <worker> -n urun # one-shot aggregated log
|
|
548
|
+
kubectl urun logs <worker> -n urun -s vineyard --tail 200 --since 30m
|
|
549
|
+
kubectl urun logs <worker> -n urun -f # follow; Ctrl-C detaches
|
|
550
|
+
kubectl urun cordon <worker> -n urun # mark unschedulable
|
|
551
|
+
kubectl urun uncordon <worker> -n urun
|
|
552
|
+
kubectl urun drain <worker> -n urun --timeout 300 # cordon + wait for Drained
|
|
553
|
+
kubectl urun describe <worker> -n urun # node/services/conditions/events/lease
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
`cordon` sets `spec.unschedulable`. Claim-owned workers (workers with a
|
|
557
|
+
`spec.claimRef`) are re-rendered from their claim by the claim reconciler, so
|
|
558
|
+
`cordon`/`uncordon`/`drain` patch the OWNING CLAIM's `spec.unschedulable`
|
|
559
|
+
instead and print which object they patched; workers without a claim are
|
|
560
|
+
patched directly. `drain` cordons and then watches the worker's `Draining`
|
|
561
|
+
condition until it flips to `False`/`Drained` (no sessions left), exiting
|
|
562
|
+
nonzero on `--timeout` (default 300s).
|
|
563
|
+
|
|
537
564
|
## What gets deployed
|
|
538
565
|
|
|
539
566
|
`urun deploy` creates a source manifest from your Python entrypoint:
|
|
@@ -579,6 +606,11 @@ def superres(): ...
|
|
|
579
606
|
- `files=` is **purely additive**. With no `files=`, collection is exactly what
|
|
580
607
|
it was before.
|
|
581
608
|
- Entries are **individual files**, not directories or globs. List each file.
|
|
609
|
+
- `deps=` may be a module-level `Dependencies(...)` constant imported from a
|
|
610
|
+
file shipped with the app (`from deps_mod import APP_DEPS`) — the deploy
|
|
611
|
+
collector resolves it statically. Anything it cannot resolve (an import
|
|
612
|
+
outside the app directory, a non-literal) **fails the deploy loudly**, naming
|
|
613
|
+
`file:line` and the fix — it never ships an empty manifest.
|
|
582
614
|
- A declared path that does not exist, escapes the app directory (`..`, a
|
|
583
615
|
symlink pointing outside), or is absolute **fails the deploy immediately**,
|
|
584
616
|
naming the path and the directory it was looked up under. A declared file is
|
|
@@ -509,6 +509,33 @@ What it does:
|
|
|
509
509
|
sooner. `--no-logs` skips streaming the occupant's log after creation
|
|
510
510
|
(Ctrl-C also detaches without tearing the occupant down).
|
|
511
511
|
|
|
512
|
+
## Operator: GPUWorker nodes (`kubectl urun`)
|
|
513
|
+
|
|
514
|
+
Installing `urun-cli` also installs the `kubectl-urun` binary; with it on
|
|
515
|
+
`PATH`, kubectl dispatches `kubectl urun` to it as a standard kubectl plugin.
|
|
516
|
+
These verbs are the operator surface over the `gpu.urun.sh/v1alpha1`
|
|
517
|
+
GPUWorker custom resources (the cluster must have the urun controller
|
|
518
|
+
installed); they resolve kubeconfig/context through kubectl itself, so
|
|
519
|
+
`--kubeconfig`, `--context`, and `-n` behave like any other kubectl command:
|
|
520
|
+
|
|
521
|
+
```bash
|
|
522
|
+
kubectl urun logs <worker> -n urun # one-shot aggregated log
|
|
523
|
+
kubectl urun logs <worker> -n urun -s vineyard --tail 200 --since 30m
|
|
524
|
+
kubectl urun logs <worker> -n urun -f # follow; Ctrl-C detaches
|
|
525
|
+
kubectl urun cordon <worker> -n urun # mark unschedulable
|
|
526
|
+
kubectl urun uncordon <worker> -n urun
|
|
527
|
+
kubectl urun drain <worker> -n urun --timeout 300 # cordon + wait for Drained
|
|
528
|
+
kubectl urun describe <worker> -n urun # node/services/conditions/events/lease
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
`cordon` sets `spec.unschedulable`. Claim-owned workers (workers with a
|
|
532
|
+
`spec.claimRef`) are re-rendered from their claim by the claim reconciler, so
|
|
533
|
+
`cordon`/`uncordon`/`drain` patch the OWNING CLAIM's `spec.unschedulable`
|
|
534
|
+
instead and print which object they patched; workers without a claim are
|
|
535
|
+
patched directly. `drain` cordons and then watches the worker's `Draining`
|
|
536
|
+
condition until it flips to `False`/`Drained` (no sessions left), exiting
|
|
537
|
+
nonzero on `--timeout` (default 300s).
|
|
538
|
+
|
|
512
539
|
## What gets deployed
|
|
513
540
|
|
|
514
541
|
`urun deploy` creates a source manifest from your Python entrypoint:
|
|
@@ -554,6 +581,11 @@ def superres(): ...
|
|
|
554
581
|
- `files=` is **purely additive**. With no `files=`, collection is exactly what
|
|
555
582
|
it was before.
|
|
556
583
|
- Entries are **individual files**, not directories or globs. List each file.
|
|
584
|
+
- `deps=` may be a module-level `Dependencies(...)` constant imported from a
|
|
585
|
+
file shipped with the app (`from deps_mod import APP_DEPS`) — the deploy
|
|
586
|
+
collector resolves it statically. Anything it cannot resolve (an import
|
|
587
|
+
outside the app directory, a non-literal) **fails the deploy loudly**, naming
|
|
588
|
+
`file:line` and the fix — it never ships an empty manifest.
|
|
557
589
|
- A declared path that does not exist, escapes the app directory (`..`, a
|
|
558
590
|
symlink pointing outside), or is absolute **fails the deploy immediately**,
|
|
559
591
|
naming the path and the directory it was looked up under. A declared file is
|
|
@@ -20,7 +20,7 @@ name = "urun-cli"
|
|
|
20
20
|
# so every merge remains on the already-published version until this value is
|
|
21
21
|
# advanced. Wiring semantic-release into CI remains separate work; this patch
|
|
22
22
|
# bump is the minimal release unblock (post-v0.6.3 fixes + the Rust feature minor).
|
|
23
|
-
version = "0.7.
|
|
23
|
+
version = "0.7.8"
|
|
24
24
|
description = "End-user CLI for deploying apps to urun"
|
|
25
25
|
readme = "README.md"
|
|
26
26
|
requires-python = ">=3.11"
|
|
@@ -48,6 +48,7 @@ Issues = "https://github.com/urun-sh/urun-cli/issues"
|
|
|
48
48
|
[project.scripts]
|
|
49
49
|
urun = "urun.cli:main"
|
|
50
50
|
urun-cli = "urun.cli:main"
|
|
51
|
+
kubectl-urun = "urun.kubectl_plugin:main"
|
|
51
52
|
|
|
52
53
|
[project.optional-dependencies]
|
|
53
54
|
# Rust app discovery (urun/rust.py) parses with the pinned native
|
|
@@ -461,6 +461,18 @@ class ApiClient:
|
|
|
461
461
|
def get_release(self, release_id: str) -> dict[str, Any]:
|
|
462
462
|
return self._get(f"/cli/releases/{urllib.parse.quote(release_id, safe='')}")
|
|
463
463
|
|
|
464
|
+
def promote_release(self, release_id: str, environment: str) -> dict[str, Any]:
|
|
465
|
+
"""Make an EXISTING release current for ``environment`` (rollback).
|
|
466
|
+
|
|
467
|
+
``POST /cli/releases/<id>/promote`` re-fires the release's deploy event —
|
|
468
|
+
the same path a same-content ``urun deploy`` takes — so the control plane
|
|
469
|
+
re-registers it and republishes the release pointer.
|
|
470
|
+
"""
|
|
471
|
+
return self._post(
|
|
472
|
+
f"/cli/releases/{urllib.parse.quote(release_id, safe='')}/promote",
|
|
473
|
+
{"environment": environment},
|
|
474
|
+
)
|
|
475
|
+
|
|
464
476
|
def query_logs(self, params: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
465
477
|
return self._get("/cli/logs", params)
|
|
466
478
|
|
|
@@ -120,7 +120,7 @@ ENGINE_DEPS: dict[str, list[str]] = {
|
|
|
120
120
|
"nvidia-cuda-crt==13.0.88",
|
|
121
121
|
"nvidia-cuda-cccl==13.0.85",
|
|
122
122
|
"nvidia-nvvm==13.0.88",
|
|
123
|
-
"nvidia-cuda-runtime==13.0
|
|
123
|
+
"nvidia-cuda-runtime==13.0.*",
|
|
124
124
|
"numpy<2",
|
|
125
125
|
"pillow>=10.0.0",
|
|
126
126
|
"orjson",
|
|
@@ -162,7 +162,7 @@ ENGINE_DEPS: dict[str, list[str]] = {
|
|
|
162
162
|
"nvidia-cuda-crt==13.0.88",
|
|
163
163
|
"nvidia-cuda-cccl==13.0.85",
|
|
164
164
|
"nvidia-nvvm==13.0.88",
|
|
165
|
-
"nvidia-cuda-runtime==13.0
|
|
165
|
+
"nvidia-cuda-runtime==13.0.*",
|
|
166
166
|
"numpy<2",
|
|
167
167
|
"pillow>=10.0.0",
|
|
168
168
|
"orjson",
|
|
@@ -368,7 +368,7 @@ ENGINE_DEPS: dict[str, list[str]] = {
|
|
|
368
368
|
"nvidia-cuda-crt==13.0.88",
|
|
369
369
|
"nvidia-cuda-cccl==13.0.85",
|
|
370
370
|
"nvidia-nvvm==13.0.88",
|
|
371
|
-
"nvidia-cuda-runtime==13.0
|
|
371
|
+
"nvidia-cuda-runtime==13.0.*",
|
|
372
372
|
"numpy<2",
|
|
373
373
|
"pillow>=10.0.0",
|
|
374
374
|
"orjson",
|
|
@@ -446,7 +446,7 @@ ENGINE_DEPS: dict[str, list[str]] = {
|
|
|
446
446
|
"nvidia-cuda-crt==13.0.88",
|
|
447
447
|
"nvidia-cuda-cccl==13.0.85",
|
|
448
448
|
"nvidia-nvvm==13.0.88",
|
|
449
|
-
"nvidia-cuda-runtime==13.0
|
|
449
|
+
"nvidia-cuda-runtime==13.0.*",
|
|
450
450
|
"ninja",
|
|
451
451
|
"pip",
|
|
452
452
|
"nvidia-cutlass-dsl>=4.6.0.dev0,<5",
|