pyvolt-cli 0.3.0__tar.gz → 0.3.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyvolt-cli
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: The command-line companion to Pyvolt: managed Python deployments on infrastructure you actually own.
5
5
  Project-URL: Homepage, https://pyvolt.com
6
6
  Project-URL: Repository, https://github.com/pyvolt-hq/pyvolt-cli
@@ -45,9 +45,10 @@ pyvolt deploy myapp --follow
45
45
  | `pyvolt servers` / `pyvolt apps` | Inventory with live status |
46
46
  | `pyvolt deploy DOMAIN [--follow]` | Trigger a deployment, optionally streaming the log |
47
47
  | `pyvolt deployments DOMAIN` | Recent deployment history |
48
- | `pyvolt env DOMAIN list\|set K=V…\|rm K` | Environment variables — pushed and app restarted |
48
+ | `pyvolt env DOMAIN list\|get K\|set K=V…\|rm K` | Environment variables — pushed and app restarted |
49
49
  | `pyvolt ps DOMAIN [restart NAME]` | Background processes with live systemd state |
50
50
  | `pyvolt logs DOMAIN [-p NAME] [-n N]` | Tail the app's journal |
51
+ | `pyvolt metrics SERVER` | Latest CPU / memory / disk / network snapshot |
51
52
  | `pyvolt bans SERVER` | IPs banned by fail2ban, your own flagged |
52
53
  | `pyvolt unban SERVER [IP] [--me]` | Lift a ban — `--me` unbans your own IP, even while it's banned |
53
54
  | `pyvolt ssh SERVER [--app DOMAIN]` | Open a shell on the server (as the `pyvolt` user); `--app` cds into the app dir |
@@ -15,9 +15,10 @@ pyvolt deploy myapp --follow
15
15
  | `pyvolt servers` / `pyvolt apps` | Inventory with live status |
16
16
  | `pyvolt deploy DOMAIN [--follow]` | Trigger a deployment, optionally streaming the log |
17
17
  | `pyvolt deployments DOMAIN` | Recent deployment history |
18
- | `pyvolt env DOMAIN list\|set K=V…\|rm K` | Environment variables — pushed and app restarted |
18
+ | `pyvolt env DOMAIN list\|get K\|set K=V…\|rm K` | Environment variables — pushed and app restarted |
19
19
  | `pyvolt ps DOMAIN [restart NAME]` | Background processes with live systemd state |
20
20
  | `pyvolt logs DOMAIN [-p NAME] [-n N]` | Tail the app's journal |
21
+ | `pyvolt metrics SERVER` | Latest CPU / memory / disk / network snapshot |
21
22
  | `pyvolt bans SERVER` | IPs banned by fail2ban, your own flagged |
22
23
  | `pyvolt unban SERVER [IP] [--me]` | Lift a ban — `--me` unbans your own IP, even while it's banned |
23
24
  | `pyvolt ssh SERVER [--app DOMAIN]` | Open a shell on the server (as the `pyvolt` user); `--app` cds into the app dir |
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pyvolt-cli"
7
- version = "0.3.0"
7
+ version = "0.3.2"
8
8
  description = "The command-line companion to Pyvolt: managed Python deployments on infrastructure you actually own."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -282,6 +282,17 @@ def env_list(ctx: typer.Context):
282
282
  console.print(t)
283
283
 
284
284
 
285
+ @env_app.command("get")
286
+ def env_get(ctx: typer.Context, key: str):
287
+ """Show one variable's value — unmasked, since it's your own secret."""
288
+ api = Api()
289
+ site = api.resolve_app(ctx.obj)
290
+ row = api.get(f"/v1/apps/{site['id']}/env/{key}")
291
+ if _emit(row):
292
+ return
293
+ console.print(row["value"])
294
+
295
+
285
296
  @env_app.command("set")
286
297
  def env_set(ctx: typer.Context, pairs: list[str] = typer.Argument(..., metavar="KEY=VALUE...")):
287
298
  """Set one or more variables — pushes the .env and restarts the app."""
@@ -358,6 +369,28 @@ def logs(
358
369
  console.out(line, highlight=False)
359
370
 
360
371
 
372
+ @app.command()
373
+ def metrics(server: str = typer.Argument(..., metavar="SERVER")):
374
+ """Latest CPU / memory / disk / network snapshot for a server."""
375
+ api = Api()
376
+ srv = api.resolve_server(server)
377
+ m = api.get(f"/v1/servers/{srv['id']}/metrics")
378
+ if _emit(m):
379
+ return
380
+ if m["at"] is None:
381
+ console.print("[yellow]No metrics collected yet[/yellow] — they land a few minutes after provisioning.")
382
+ return
383
+ pct = lambda v: f"{v:.0f}%" if v is not None else "-" # noqa: E731
384
+ t = _table("METRIC", "VALUE")
385
+ t.add_row("CPU", pct(m["cpu_percent"]))
386
+ t.add_row("Memory", pct(m["memory_percent"]))
387
+ t.add_row("Disk", pct(m["disk_percent"]))
388
+ t.add_row("Net in", f"{m['net_in_bytes'] / 1e6:.1f} MB")
389
+ t.add_row("Net out", f"{m['net_out_bytes'] / 1e6:.1f} MB")
390
+ console.print(t)
391
+ console.print(f"[dim]as of {m['at']}[/dim]")
392
+
393
+
361
394
  # ---- fail2ban -------------------------------------------------------------------
362
395
 
363
396
  @app.command()
File without changes
File without changes