Skip to content

feat(cli): add datumctl-inventory plugin#41

Closed
ecv wants to merge 3 commits into
mainfrom
feat/datumctl-inventory-plugin
Closed

feat(cli): add datumctl-inventory plugin#41
ecv wants to merge 3 commits into
mainfrom
feat/datumctl-inventory-plugin

Conversation

@ecv

@ecv ecv commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

What

Adds cmd/datumctl-inventory — a datumctl plugin providing a read view over the inventory this operator serves (inventory.miloapis.com/v1alpha1). Invoked as datumctl inventory ... once installed.

This supersedes datum-cloud/datumctl#212, which baked the command into datumctl core. Per @scotwells' review there, the CLI should live with the service that owns the API — so it lives here as a plugin, using this repo's own typed API.

Commands

Command Does
inventory providers|regions|sites|clusters|nodes List per kind, curated columns, -o table/json/yaml
inventory tree [--region] region → site → node hierarchy + per-region clusters
inventory summary totals per kind, sites/nodes per region, sites per provider

Design

  • Typed client: imports api/v1alpha1 + controller-runtime client = compile-safe field access (the upside of living in this repo vs unstructured in datumctl core).
  • Platform-root scope: inventory objects are cluster-scoped on the Datum Cloud platform root, so the plugin talks to the platform API directly via DATUM_API_HOST; no org/project scope.
  • Filters: --region/--site/--cluster resolve server-side via the topology.inventory.miloapis.com/* labels the controllers propagate; --provider matches the site providerRef client-side.
  • Plugin contract: --plugin-manifest, DATUM_* env context, on-demand token via the credentials helper — using the go.datum.net/datumctl/plugin SDK. No datumctl core changes.

Tests

go test ./cmd/datumctl-inventory/ — covers ready-condition mapping, table rendering, tree hierarchy + --region scoping, and summary tallies.

Verified against prod (read-only)

Built the binary, injected the same DATUM_* context datumctl sets, ran against prod:

  • lists: 4 providers / 19 regions / 20 sites / 20 clusters / 110 nodes, columns + cross-refs + Ready populated
  • sites --region us-central-1 → 2 (server-side label) ✓
  • sites --provider gcpgcp-us-east4 (client-side providerRef) ✓
  • nodes --cluster us-central-1-lab → cluster label filter ✓
  • tree --region, summary, -o yaml, invalid-format error path all ✓

(Fleet now includes freshly-loaded GKE/GCP inventory — gcp-us-east4, 20 nodes — rendered correctly.)

Follow-ups (not in this PR)

  • Release wiring: add goreleaser + checksums.txt so datumctl plugin install milo-os/datumctl-inventory works, and list it in datum-cloud/datumctl-plugins. Until then it installs as an unmanaged/trusted plugin.

Closes datum-cloud/enhancements#713 (datumctl view portion) — tracked via datum-cloud/datumctl#211.

Add a datumctl plugin that provides a read view over the inventory
served by this operator. Invoked as `datumctl inventory ...` once
installed. Replaces the approach of baking the command into datumctl
core (datum-cloud/datumctl#212) — per review, the CLI lives with the
service that owns the API.

Key features:
- List subcommands per kind (providers, regions, sites, clusters,
  nodes) with curated columns and -o table/json/yaml
- Filter flags --region/--site/--cluster resolve server-side via the
  topology.inventory.miloapis.com/* labels the operator propagates;
  --provider matches the site providerRef client-side
- `inventory tree` prints the region -> site -> node hierarchy with
  per-region clusters; `inventory summary` prints fleet-wide counts
- Uses this repo's typed api/v1alpha1 client against the platform root,
  with credentials fetched on demand via the datumctl SDK helper
- Implements the datumctl plugin contract (--plugin-manifest, DATUM_*
  context, go.datum.net/datumctl/plugin SDK)
Add goreleaser config + workflow to publish datumctl-inventory release
archives so it installs via `datumctl plugin install milo-os/datumctl-inventory`.

Plugin releases are decoupled from the operator: they trigger on a
`datumctl-inventory/vX.Y.Z` tag prefix and build only the plugin binary.
The operator's publish.yaml is guarded so plugin tags and the plugin's
GitHub release do not rebuild the operator image.

Key changes:
- .goreleaser.datumctl-inventory.yaml: builds ./cmd/datumctl-inventory for
  linux/darwin/windows x amd64/arm64; archives named
  datumctl-inventory_{OS}_{Arch}; checksums.txt; version via -X main.version
- release-datumctl-inventory.yaml: triggers on datumctl-inventory/v* tags;
  GORELEASER_CURRENT_TAG strips the prefix so the plugin gets its own version
- publish.yaml: tags-ignore datumctl-inventory/** on push, and skip the
  release-published jobs when the release tag carries the plugin prefix

Closes #42
@ecv ecv marked this pull request as draft June 11, 2026 16:06
@ecv

ecv commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

Added release wiring (closes #42) and set this back to draft pending the operator/plugin separation discussion.

Release wiring added:

  • .goreleaser.datumctl-inventory.yaml — builds only ./cmd/datumctl-inventory (linux/darwin/windows × amd64/arm64), archives datumctl-inventory_{OS}_{Arch}, checksums.txt, version via -X main.version. Validated with goreleaser check + a snapshot build (archives + checksums + in-archive binary name + manifest all confirmed).
  • .github/workflows/release-datumctl-inventory.yaml — triggers on datumctl-inventory/vX.Y.Z tags; builds the plugin only.
  • publish.yaml guarded so plugin tags (push) and the plugin's GitHub release (release: published) don't rebuild the operator image.

Open design point for the separation discussion (why it's draft): OSS goreleaser has no monorepo/tag-prefix support (Pro-only). I worked around it with a datumctl-inventory/v* tag prefix + GORELEASER_CURRENT_TAG to give the plugin its own version line. The cleaner alternative is a dedicated milo-os/datumctl-inventory repo (matches datumctl's owner/repo install convention). Want your call on same-repo-with-prefix vs separate-repo before this merges.

@ecv

ecv commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

@scotwells — need your call on packaging before this leaves draft.

You asked for the CLI to live with the service that owns the API, so I put it here as cmd/datumctl-inventory using this repo's typed api/v1alpha1. The snag is release packaging: OSS goreleaser has no monorepo / tag-prefix support (Pro-only), so co-releasing a plugin alongside the operator in one repo needs a workaround.

Two honest options:

Option A — same repo + tag prefix (what this PR does)

  • Plugin releases on datumctl-inventory/vX.Y.Z tags; GORELEASER_CURRENT_TAG strips the prefix so the plugin gets its own version line.
  • publish.yaml guarded so plugin tags/releases don't rebuild the operator image.
  • ✅ CLI + API definition stay together; plugin imports the typed API directly (no schema drift); one PR touches both.
  • ❌ Non-standard tag scheme in a repo that also tags v0.0.x; leans on the env-var workaround; release config + operator-CI guards add coupling to a shared workflow.

Option B — dedicated repo milo-os/datumctl-inventory

  • Matches datumctl's native install convention (datumctl plugin install milo-os/datumctl-inventory); clean independent versioning; vanilla goreleaser; no edits to the operator's publish.yaml.
  • ❌ Splits CLI from the API it reads; the plugin depends on go.miloapis.com/inventory/api as an external module and tracks its releases — the coupling you wanted to avoid, re-introduced as a version dependency.

A third option if you have Pro: real goreleaser monorepo support makes Option A clean (no GORELEASER_CURRENT_TAG hack, first-class tag prefixes).

My lean: A if we value API+CLI living together (your original steer) and accept the tag-prefix quirk; B if you'd rather the plugin version and release flow be fully independent of the operator. Which do you prefer?

@scotwells

Copy link
Copy Markdown
Contributor

Can't we use the same tag between the operator and the CLI plugin?

Per review, the plugin shares the operator's version and tag instead of
using a separate tag prefix. On `release: published`, goreleaser builds the
plugin and appends datumctl-inventory_{OS}_{Arch} archives + checksums.txt
to the same GitHub release as the operator image.

Removes the tag-prefix trigger, the GORELEASER_CURRENT_TAG workaround, and
the publish.yaml guards (no longer needed — both build on the same tag).
@ecv

ecv commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

Reworked release wiring per @scotwellsplugin shares the operator's tag/version (no separate tag prefix).

  • On release: published, release-datumctl-inventory.yaml runs goreleaser with release: { mode: append } → appends datumctl-inventory_{OS}_{Arch} archives + checksums.txt to the same GitHub release as the operator image. Plugin vX.Y.Z == operator vX.Y.Z.
  • Dropped the datumctl-inventory/* tag prefix + GORELEASER_CURRENT_TAG workaround.
  • Reverted the publish.yaml guards — both artifacts build on the same tag now, so no need to fence them off. publish.yaml is back to its original form (zero diff vs main).

goreleaser check passes; earlier snapshot build confirmed archive names + checksums.txt two-column format + in-archive binary name.

Note for the curated-index follow-on: since archives live on milo-os/inventory releases (not a datumctl-inventory repo), the datumctl-plugins entry should point its platform URIs straight at the inventory release assets. Still draft — ready for your review of the same-tag approach.

@ecv ecv marked this pull request as ready for review June 11, 2026 16:28
@ecv ecv enabled auto-merge (squash) June 11, 2026 19:48
@ecv

ecv commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

I'm thinking it's weird that milo-os/inventory contain any reference to datum at all. Reviewing pattern.

@ecv ecv disabled auto-merge June 12, 2026 14:39
@ecv

ecv commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

Reconsidering where this plugin lives (org separation)

Surveyed where existing datumctl plugins live:

Plugin Source repo Org
datumctl (core CLI) datum-cloud/datumctl datum-cloud
plugin index datum-cloud/datumctl-plugins datum-cloud
datumctl-compute datum-cloud/compute (kubebuilder operator + co-located plugin) datum-cloud
connect datum-cloud/connect (service + co-located plugin) datum-cloud
datumctl-inventory (this PR) milo-os/inventory milo-os

Two principles in tension

  1. Co-locate the plugin with the service that owns the API. This PR follows it, and so does compute (operator + plugin in one repo) — so the approach itself has precedent.
  2. Keep datum and milo separate. datumctl is a Datum CLI surface; milo-os is the upstream/open platform. Every other datumctl plugin lives under datum-cloud. This PR is the only one in milo-os, so it couples a Datum DX surface into a milo repo.

These collide here specifically because the inventory service itself is milo (go.miloapis.com/inventory), whereas compute/connect are Datum's own services. So "co-locate with the service" and "keep datum out of milo" can't both hold in-repo.

Resolution

Moving the plugin to a dedicated datum-cloud/datumctl-inventory repo:

  • Matches datumctl's native install convention (datumctl plugin install datum-cloud/datumctl-inventory) and the datum-cloud home of every other plugin.
  • Depends on go.miloapis.com/inventory/api as an external module — which expresses the datum→milo boundary correctly (Datum consumes milo's published API types) instead of hiding it inside a milo repo.
  • Independent versioning/release (no shared-tag coupling to the operator).

This PR will be closed once the new repo is up. cc @scotwells — this supersedes the same-repo approach you steered earlier; flagging since it reverses that call on org-separation grounds.

@ecv

ecv commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

Proceeding but naming my plugin's repository datum-cloud/inventory.

@ecv

ecv commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by datum-cloud/inventory (new repo): https://github.com/datum-cloud/inventory

Moved the plugin out of the milo repo to honor datum/milo separation — datumctl plugins live under datum-cloud (cf. datum-cloud/computedatumctl-compute). The new repo depends on go.miloapis.com/inventory/api as an external module, so it consumes milo's published types instead of vendoring a Datum CLI surface into this repo. Install: datumctl plugin install datum-cloud/inventory.

Closing; nothing merges here.

@ecv ecv closed this Jun 12, 2026
@ecv ecv deleted the feat/datumctl-inventory-plugin branch June 12, 2026 14:53
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.

Physical inventory for Milo

2 participants