DAH-2589: lium describe — one pod manifest an agent can act on - #101
Conversation
|
Review pass after a second-model read of the diff. Three changes: SDK errors no longer borrow the pod-not-found code. The first cut classified failures by substring — Port keys are compared as strings, everywhere. Tests: 9 → 14. Also added Suite: 363 passed, same 11 pre-existing failures as on a clean Not taken, worth a separate change: |
| monkeypatch, [], error=LiumNotFoundError("Resource not found: /pods") | ||
| ) | ||
|
|
||
| assert result.exit_code == EXIT_GENERAL_ERROR |
There was a problem hiding this comment.
NIT: #104 remaps LiumError to exit 3, so this assert breaks once it lands. Safer to assert it is not EXIT_POD_NOT_FOUND.
There was a problem hiding this comment.
Right — #104 moves LiumError to exit 3. Changed to assert result.exit_code not in (0, EXIT_POD_NOT_FOUND), which pins what the test is actually about and survives either mapping.
| return round((datetime.now(timezone.utc) - dt_created).total_seconds() / 3600, 2) | ||
|
|
||
|
|
||
| def _port_number(port) -> object: |
There was a problem hiding this comment.
NIT: this returns int or str, never a bare object, and port has no type at all.
| def _port_number(port) -> object: | |
| def _port_number(port: str | int) -> int | str: |
There was a problem hiding this comment.
Applied your signature verbatim: def _port_number(port: str | int) -> int | str:.
| - `lium ls [GPU_TYPE]` - List available nodes | ||
| - `lium up [NODE_ID]` - Create a pod (use node ID or filters like `--gpu`, `--count`, `--country`) | ||
| - `lium ps` - List active pods | ||
| - `lium describe <POD>` - Full manifest of one pod: ports, GPU, template, billing (add `--json` for machine-readable output) |
There was a problem hiding this comment.
NIT: lium-docs has no describe.md yet and no row in the CLI reference index.
There was a problem hiding this comment.
Correct, and left as is on purpose. This row is the repo README CLI Reference — a plain bullet list, not a link into lium-docs, so it is accurate standalone. docs/ here is Sphinx SDK API only and has no CLI index. The docs.lium.io describe.md page plus the CLI reference row is a separate lium-docs PR.
Step A of DAH-2589 (machine layer, sub-task of DAH-1942). An agent that rents a pod has to piece together what it got from
ps, the dashboard and guesswork.lium describe <pod>answers it in one document.What the manifest carries
pod(id/huid/name/status/uptime),gpu(type, count, model and driver from the executor specs, max CUDA),machine(executor id, ip, location, tier, DinD),ports,access(ssh command, jupyter),template(name + docker image),storage(volume encryption),billing(price/h, spent so far, scheduled removal).The
portssection is the reason this command exists. The API returnsports_mappingkeyed by the port inside the container, and getting that direction wrong is the most common way an agent burns time on a pod. So the manifest states the direction explicitly, singles out the external port that reaches SSH, and lists the remaining ports a service can be published on:Decisions worth reviewing
API only, no SSH. The manifest is assembled from data the backend already returns, so it also answers for a pod that has stopped responding. Live in-pod state (free disk, is
nvccpresent, who is listening) is deliberately out of scope — that is step C of the task, alium-capabilitiescommand running inside the pod against this same schema.--json, not--format json. It follows the DAH-2556 contract:handle_errorskeys the JSON error envelope off ajson_outputkwarg, so--jsongets a machine-readable failure and a meaningful exit code for free. An unknown pod exitsEXIT_POD_NOT_FOUND(5) with{"ok": false, "error": {...}}on stderr and clean stdout.lsandpsstill use--format table|jsonand do not get that envelope — unifying the two spellings is its own change.ensure_config()runs only on the human path. A--jsoncaller is behind a pipe and cannot answer the interactive setup prompt, so a missing API key surfaces as the JSON envelope with the configuration exit code instead of hanging on a question nobody will read.Timestamp parsing and spend rounding are imported from
ps.displayrather than reimplemented, sodescribeandpscan never disagree about what a pod has cost.Tests
test/test_describe_cli.py— 9 tests: port direction and the SSH port, service ports excluding 22, GPU read from specs, a pod whose executor the API omitted, spend by uptime,--jsonparsing as-is, resolution by huid, and the not-found exit code. Full suite: 358 passed, 11 pre-existing failures unrelated to this change (provider, gpu splitting, release binary — same 11 fail on a cleanmain).Follow-ups, not in this PR
lium/SKILL.mdin the lium-skill repo needs a "working inside a pod" section pointing atdescribe— separate repo, separate PR.