Skip to content

feat: add pulse stats and pulse diff commands - #1

Merged
ipedrazas merged 2 commits into
mainfrom
feat/stats-and-diff
Jul 29, 2026
Merged

feat: add pulse stats and pulse diff commands#1
ipedrazas merged 2 commits into
mainfrom
feat/stats-and-diff

Conversation

@ipedrazas

Copy link
Copy Markdown
Owner

Summary

  • pulse stats --node X --since 24h [--json] — per-container restart counts, status transitions, and uptime resets over a lookback window.
  • pulse diff --since 2h [--node X] [--json] — compares current container state against a point in the past: appeared, disappeared, changed-image, and restarted containers.
  • Both are backed by two new CLIService RPCs, GetContainerStats and DiffContainers, computed entirely from data Pulse already persists — no agent (Rust) changes or DB migrations required:
    • containers.created_at / removed_at give the "was this container alive at time T" signal used for the diff's before/after snapshots.
    • The container_events hypertable's status/uptime_seconds history gives status transitions and uptime resets (a drop in uptime_seconds between consecutive samples = a restart).
  • Introduces a "default node" concept so --node can be omitted: resolution order is --node flag → PULSE_DEFAULT_NODE env var → default-node in ~/.pulse/config.yaml → the sole registered node if there's exactly one → a clear error otherwise.
  • --since uses time.ParseDuration (24h, 2h, 30m, ...) with a helpful error on invalid input; diff requires it, stats defaults to 24h.
  • No data in the window, or an unregistered node, returns empty results rather than an error; an unreachable API/node surfaces the underlying gRPC error.

Design note: "changed image digest"

Pulse doesn't currently track image digests anywhere (agent, proto, or DB) — only the image reference string (e.g. nginx:latest). Docker containers are also immutable with respect to their image: changing a container's image always means recreating it (a new container ID), never an in-place field update. So changed_image is detected by matching containers by name across the window and comparing the image reference on the container that's actually running now vs. what was running before — the same mechanism that also flags a same-name container recreation as restarted. This matches the spec's intent ("still running, but different image") without inventing digest telemetry that doesn't exist in the system today.

Test plan

  • buf lint / buf generate — proto changes are lint-clean and generate without error
  • go build for API and CLI
  • go test — API unit tests, CLI tests, and new Testcontainers-backed integration tests (TestListContainersAt, TestListContainerEvents, TestGetContainerStats, TestDiffContainers) all pass against real TimescaleDB
  • govulncheck — no new findings vs. main (5 pre-existing dependency vulnerabilities on main unrelated to this change, from a vuln DB update since main's last CI run)
  • Manual end-to-end smoke test: real API server + real TimescaleDB + a scripted gRPC agent client + the built pulse binary — verified pulse ps, pulse stats, pulse diff (table and --json), default-node auto-resolution, and error paths (invalid --since, missing --since, unreachable node, empty window)

Adds `pulse stats --since <window>` (per-container restart counts, status
transitions, and uptime resets) and `pulse diff --since <window>` (appeared/
disappeared/changed-image/restarted containers vs. a point in the past).

Both are backed by two new CLIService RPCs (GetContainerStats,
DiffContainers) computed from data Pulse already tracks: the containers
table's created_at/removed_at lifecycle timestamps and the container_events
hypertable's status/uptime history. No agent or schema changes needed.

Also introduces a "default node" concept (PULSE_DEFAULT_NODE env var or
default-node in ~/.pulse/config.yaml, falling back to auto-selecting the
sole registered node) so --node can be omitted on these commands.
Signed-off-by: ipedrazas <ipedrazas@gmail.com>
@ipedrazas
ipedrazas merged commit 8715b48 into main Jul 29, 2026
5 of 6 checks passed
@ipedrazas
ipedrazas deleted the feat/stats-and-diff branch July 30, 2026 09:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant