Skip to content

cub variant upload

cub variant upload

Upload rendered Kubernetes resources into a Space as Units

Synopsis

Upload already-rendered Kubernetes manifests into a ConfigHub Space.

The input is a stream of rendered resources — from the installer, "kustomize build", or "helm template" — supplied as files, directories (walked for .yaml/.yml), "-" for stdin, or an "oci://" reference to a manifest bundle. This command does not render anything; it ingests what you give it.

An oci:// input is pulled and its YAML extracted before ingestion. The bundle is a standard OCI image artifact (a tar or tar+gzip layer of YAML, as "cub release publish" and Flux produce, or individual file layers as "oras push" produces); registry credentials are reused from your Docker config.

Every input is recorded on the Space as a "confighub.com/external-source" annotation (a JSON array), together with the --granularity and --namespace the upload ran with, so the plan can be reproduced from the Space alone. For an oci:// input the resolved digest is recorded too, making the exact bundle installed auditable.

An upload into a Space recorded with a different --granularity or --namespace is refused. Granularity decides the Unit slugs, so changing it would replace that Space's Units rather than update them; namespace decides the synthesized Namespace resource and what AppConfig placeholders carry, so changing it would rewrite those resources. Both have to be repeated on a re-upload — --granularity has a default, so omitting it is itself a change. Re-run with the recorded values, or use --space to upload elsewhere.

Resources become Units in one of three granularities (--granularity): minimal one Unit for everything, with CRDs split into their own Unit and each AppConfig file split into its own Unit set (the default). per-resource one Unit per resource. per-file one Unit per source file, named from the file's stem — so the input's file layout defines the Unit set (matches how "cub helm" groups a chart's template files). Useful with an oci:// bundle of named files.

In minimal mode the resources in the combined Unit are ordered by install priority (Namespaces, RBAC, config, then workloads) and by their references to one another. A Namespace resource is synthesized if --namespace is given and none is present. AppConfig ConfigMaps (carrying installer.confighub.com annotations) are expanded into an AppConfig data Unit, a render-configmap Invocation, a placeholder Unit, and an Upsert link. Rendered Secrets are never uploaded — apply them out-of-band.

Links between Units are inferred from references, label selectors, and custom-resource → CRD relationships. Because ConfigHub does not break dependency cycles, any cycle found in the ordering or the links is broken here — the weakest edge is dropped (a selector before a reference; a cross-scope reference before a same-namespace one) and the broken edge is reported.

The Space is created if missing and stamped with the well-known labels from --component, --variant, --stage, --environment, --region, --layer, and --owner. --component and --variant are required. The Space slug comes from --space-pattern (a Go template over .Labels), or from --space to set it explicitly.

Each created Unit records the input it came from — the oci:// ref, file, or directory as named on the command line — as its external source, so its change description reads "from oci://ghcr.io/org/bundle". Use --change-desc to prefix your own description.

Re-uploading: Running this command again against a Space it already populated is a re-upload, not a second create. Each Unit is merged rather than replaced: the new content is 3-way merged against the last upload, so changes made in ConfigHub after the first upload — a set- function, a hand edit, a needs/provides binding — survive, while everything the source actually changed lands. Resources new to the input become new Units. A re-upload whose input has not changed does nothing.

The updates are recorded in a ChangeSet, so an entire re-upload can be rolled back with the "cub unit update --restore Before:ChangeSet:" command printed at the end.

Units in the Space that the input no longer produces are left alone and reported. Pass --prune to empty them instead: that merges empty content, withdrawing only the resources this source contributed and leaving post-upload additions in place, so their deployed resources are removed by the next apply. Units guarded by a DestroyGate refuse. Nothing is ever deleted — the Unit record, its target binding, and its metadata survive.

Use --dry-run to see what would be created, updated, or emptied, including the per-field merge as the server would resolve it, without changing anything.

Examples:

  # Minimal upload of a kustomize build into a derived Space slug "web-base".
  kustomize build overlays/base | cub variant upload --component web --variant base -

  # One Unit per resource, into an explicit Space, bound to a target.
  cub variant upload --component web --variant prod --space web-prod \
    --granularity per-resource --target web-prod/cluster ./rendered/

  # Helm output, ensuring a namespace and a regional label.
  helm template myapp ./chart | cub variant upload --component myapp --variant prod \
    --environment Prod --region us-east1 --namespace myapp -

  # Seed a base from a published OCI manifest bundle, one Unit per bundled file.
  cub variant upload --component cubbychat --variant base --granularity per-file \
    oci://ghcr.io/confighub/configs/cubbychat

  # Re-upload: same command, newer bundle. Changed Units are merged, preserving
  # edits made in ConfigHub since the first upload.
  cub variant upload --component cubbychat --variant base --granularity per-file \
    oci://ghcr.io/confighub/configs/cubbychat:v2

  # Preview that re-upload first, including the per-field merge.
  cub variant upload --dry-run --component cubbychat --variant base \
    --granularity per-file oci://ghcr.io/confighub/configs/cubbychat:v2

  # Re-upload and withdraw the resources the new render no longer contains.
  cub variant upload --prune --component web --variant base ./rendered/
cub variant upload [flags] <file|dir|oci://ref|-> [<file|dir|oci://ref> ...]

Options

      --allow-exists           tolerate Spaces, Units, Invocations, and Links that already exist (retry a partial upload)
      --annotation strings     annotation key=value to set on every created Unit (repeatable)
      --change-desc string     change description recorded on each created Unit
      --component string       value for the well-known "Component" Space label (required)
      --dry-run                report what the upload would create, update, or empty, and exit without changing anything
      --environment string     value for the well-known "Environment" Space label (e.g. Prod)
      --granularity string     how resources map to Units: minimal, per-resource, or per-file (default "minimal")
  -h, --help                   help for upload
      --label strings          label key=value to set on every created Unit (repeatable)
      --layer string           value for the well-known "Layer" Space label (e.g. App)
      --namespace string       ensure a Namespace resource with this name exists (unless "default")
      --owner string           value for the well-known "Owner" Space label (e.g. Engineering)
      --prune                  on a re-upload, empty Units in the Space that this input no longer produces
      --region string          value for the well-known "Region" Space label (e.g. us-east1)
      --space string           explicit Space slug; overrides --space-pattern
      --space-pattern string   Go template (prefix 'template:') for the Space slug, evaluated over .Labels (default "template:{{.Labels.Component}}-{{.Labels.Variant}}")
      --stage string           value for the well-known "Stage" Space label (e.g. Canary)
      --target string          target for the created Units, in <target-slug> or <space-slug>/<target-slug> form
      --variant string         value for the well-known "Variant" Space label (required)

Options inherited from parent commands

      --context string   The context to use for this command
      --debug            Debug output

SEE ALSO