Documentation
¶
Overview ¶
Package upload turns a rendered work-dir into the inputs the cub CLI needs to materialize ConfigHub Spaces, Units, and Links — without itself shelling out. The CLI layer in internal/cli/upload.go orchestrates the cub calls.
Phase 6 wires this up:
- One Space per package (parent + each locked dep).
- One untargeted installer-record Unit per Space, holding installer.yaml plus every file in that package's out/<pkg>/spec/ (plus the lock for the parent).
- Cross-Space NeedsProvides links from the parent's record Unit to each dep's record Unit, derived from the lock.
Index ¶
- Constants
- func BuildInstallerRecord(pkg Package) ([]byte, error)
- func IsBuiltInClusterRole(name string) bool
- func ReconcileLinks(ctx context.Context, space, pkgName string, skipUnmatched map[string]struct{}) error
- func RefreshInstallerRecord(ctx context.Context, pkg Package) error
- func RenderSpaceSlug(pattern string, vars Vars) (string, error)
- func UnmatchedKey(targetType, targetName string) string
- func WriteUploadDoc(ctx context.Context, workDir, spacePattern string, packages []Package) error
- type AppConfigManifest
- type CrossSpaceLink
- type DiscoverInput
- type LinkEdge
- type Package
- type RecordContents
- type UnmatchedReference
- type Vars
Constants ¶
const ( // AppConfigToolchainEnv is the only AppConfig toolchain where the // as-key-value rendering option is meaningful (envFrom injection). AppConfigToolchainEnv = "AppConfig/Env" )
AppConfig annotation keys — duplicated from internal/cli/appconfig.go to avoid pulling the CLI package into upload (which would invert the dependency direction). Keep the values in sync; both files document the same author contract.
const InstallerRecordSlug = "installer-record"
InstallerRecordSlug is the conventional name for the per-Space Unit that carries installer.yaml + spec docs (no Target). One per Space.
const UploadDocFilename = "upload.yaml"
UploadDocFilename is the basename of the persisted Upload doc inside the parent's spec dir.
Variables ¶
This section is empty.
Functions ¶
func BuildInstallerRecord ¶
BuildInstallerRecord builds the multi-doc YAML body for the per-Space installer-record Unit. The result is `installer.yaml` followed by every YAML doc in pkg.SpecDir (in lexicographic order), separated by `---`. Files outside spec/ are not included. upload.yaml (if present) is included so a freshly cloned work-dir can re-derive everything, including where it was uploaded, from ConfigHub alone.
func IsBuiltInClusterRole ¶
IsBuiltInClusterRole reports whether name is a Kubernetes built-in ClusterRole — either one of the four user-facing roles (cluster-admin, admin, edit, view) or any role under the `system:` prefix Kubernetes reserves for its core-component roles (system:node, system:kube-*, system:controller:*, etc.). See https://kubernetes.io/docs/reference/access-authn-authz/rbac/.
Duplicated here pending the next SDK release; once a canonical copy lives in k8skit, drop this file and import from there.
func ReconcileLinks ¶
func ReconcileLinks(ctx context.Context, space, pkgName string, skipUnmatched map[string]struct{}) error
ReconcileLinks runs the standard installer intra-Space link inference (references, label-selectors, custom-resource → CRD pairs) against the Units in space, then creates only the links that are missing. Idempotent: existing links matching (FromUnit.Slug, ToUnit.Slug, ToSpace == space) are left alone.
Each new link is labeled Package=<pkgName> so it can be filtered alongside the package's units.
skipUnmatched suppresses entries from the unmatched-references reminder for resources the caller already accounts for elsewhere (e.g., rendered Secrets the operator will apply out-of-band). Keys are produced by UnmatchedKey(targetType, targetName). Pass nil to report every unmatched reference. Built-in Kubernetes ClusterRoles are always filtered out — they pre-exist in every cluster and would otherwise dominate the reminder for any package that ships a RoleBinding.
Used by `installer upload` (after the per-package Unit creation loop) and by `installer update` (after Apply mutates the Unit set). The two paths share an implementation so behavior cannot drift.
func RefreshInstallerRecord ¶
RefreshInstallerRecord rebuilds the installer-record Unit body from pkg's local files and uploads it to ConfigHub. Used after `installer update` / `installer upgrade-apply` mutates the local spec so the cub-side record stays in sync — without this refresh, a subsequent upgrade reads stale inputs (notably ImageOverrides) from ConfigHub via wizard.LoadPriorState.
Idempotent: cub unit update --merge-external-source upserts against the prior MergeExternal recorded under the same source name (installer-record).
func RenderSpaceSlug ¶
RenderSpaceSlug expands pattern using vars. Templates have access to PackageName, PackageVersion, and Variant. Returns the expanded slug, stripped of whitespace.
func UnmatchedKey ¶
UnmatchedKey produces the canonical key for the skipUnmatched set passed to ReconcileLinks. The shape matches what reportUnmatchedReferences computes per row internally.
func WriteUploadDoc ¶
WriteUploadDoc writes <work-dir>/out/spec/upload.yaml from the discovered package set. Reads the active cub context to record the organization ID and server URL alongside the resolved Space slugs.
Called by the CLI at the end of a successful `installer upload`. Safe to call when packages contains only the parent (no deps).
Types ¶
type AppConfigManifest ¶
type AppConfigManifest struct {
// ManifestPath is the absolute path to the rendered ConfigMap YAML.
// The file itself is not uploaded as a Kubernetes/YAML Unit — the
// renderer Target re-derives the ConfigMap at apply time.
ManifestPath string
// CarrierName is metadata.name of the rendered ConfigMap.
CarrierName string
// CarrierNamespace is metadata.namespace (may be empty for
// cluster-scope ConfigMaps, but the kustomize default sets it).
CarrierNamespace string
// Toolchain is the value of installer.confighub.com/toolchain on
// the ConfigMap (e.g., AppConfig/Properties, AppConfig/Env).
Toolchain string
// Mode is appconfig-mode (file|env). Set by the transformer's
// pre-pass; this code reads it verbatim.
Mode string
// SourceKey is the data: key whose value is the raw file body
// (file mode only). Empty in env mode.
SourceKey string
// Mutable reflects appconfig-mutable: when true, the render-configmap
// Invocation is created with `--immutable=false`, producing a single
// mutable ConfigMap with a stable name (updates in place; workloads
// roll via the hash annotation on the pod template). When false (the
// kustomize default for configMapGenerator), `--immutable=true`
// produces immutable ConfigMaps with hashed names.
Mutable bool
// Content is the raw AppConfig file body. file mode reads
// data[SourceKey] verbatim; env mode emits a `.env`-shaped doc
// from data: in sorted key order.
Content []byte
}
AppConfigManifest describes one annotated ConfigMap discovered in a rendered manifests directory. DetectAppConfigManifest fills it in; callers use it to drive renderer-Target + AppConfig-Unit creation and to know which files to skip in the normal Kubernetes/YAML upload path.
func DetectAppConfigManifest ¶
func DetectAppConfigManifest(path string) (*AppConfigManifest, error)
DetectAppConfigManifest reads path as a YAML document and returns an AppConfigManifest only when the document is a ConfigMap carrying installer.confighub.com/toolchain (with mode + source-key already injected by the transformer's pre-pass). Returns nil for every other manifest type so callers can branch with `if appCfg != nil`.
func (*AppConfigManifest) InvocationSlug ¶
func (m *AppConfigManifest) InvocationSlug() string
InvocationSlug returns the slug for the render-configmap Invocation that the Upsert link references as its TransformInvocation. One Invocation per AppConfig Unit, named for symmetry with UnitSlug.
func (*AppConfigManifest) PlaceholderSlug ¶
func (m *AppConfigManifest) PlaceholderSlug() string
PlaceholderSlug returns the slug for the placeholder Kubernetes/YAML ConfigMap Unit that the Upsert link populates with the rendered ConfigMap. It carries a "-rendered" suffix so it doesn't collide with UnitSlug in the same Space; the slug is not user-facing (workloads still resolve by the ConfigMap's metadata.name, which equals UnitSlug after the render).
func (*AppConfigManifest) RenderConfigMapArgs ¶
func (m *AppConfigManifest) RenderConfigMapArgs() []string
RenderConfigMapArgs returns the function-argument tokens to pass to `cub invocation create … -- render-configmap …`. Each token already includes its `--<name>=<value>` form so the caller can append them directly to its arg list.
- --immutable=true (kustomize default for configMapGenerator) or --immutable=false when the carrier was generated with disableNameSuffixHash: true.
- --as-key-value=true only when the carrier was generated from `envs:` AND the toolchain is AppConfig/Env. The function silently ignores it for other toolchains; we set it only where it's meaningful.
func (*AppConfigManifest) UnitSlug ¶
func (m *AppConfigManifest) UnitSlug() string
UnitSlug returns the slug for the AppConfig Unit. It matches the carrier ConfigMap's name with no suffix because the rendered ConfigMap uses the Unit slug as its metadata.name (the render-configmap function emits `<UnitSlug>-<hash>` in immutable mode and `<UnitSlug>` in mutable mode), so the Unit slug must equal the name workloads use (envFrom, configMapRef, etc.) for refs to resolve at apply time.
type CrossSpaceLink ¶
type CrossSpaceLink struct {
// Slug is the link's deterministic slug, derived from the dep name.
Slug string
// Package is the parent package name, used as the value of the
// "Package" label on the created link.
Package string
// FromSpace is the parent's Space; FromUnit is the parent's
// installer-record Unit slug.
FromSpace string
FromUnit string
// ToSpace is the dep's Space; ToUnit is the dep's installer-record
// Unit slug.
ToSpace string
ToUnit string
// Reason is the human-readable why (the dep's Name from the lock).
Reason string
}
CrossSpaceLink describes one parent-to-dep edge to materialize as a ConfigHub Link spanning two Spaces. Both ends point at each Space's installer-record Unit.
func PlanCrossSpaceLinks ¶
func PlanCrossSpaceLinks(packages []Package) []CrossSpaceLink
PlanCrossSpaceLinks builds the list of links to create from a discovered package set. Packages must include the parent first; deps are matched by LocalHandle.
type DiscoverInput ¶
type DiscoverInput struct {
WorkDir string
SpacePattern string
ParentPackage *api.Package
Lock *api.Lock // nil when the parent declares no Dependencies
}
DiscoverInput is what Discover needs to do its job. Caller supplies the parent's already-loaded Package and Lock, plus the workDir and pattern.
type LinkEdge ¶
type LinkEdge struct {
FromUnit string
ToUnit string
// Reason is human-readable; surfaced in upload/update logs.
Reason string
}
LinkEdge is one inferred edge between two Units in the same Space. Exposed so callers (e.g., a future installer plan extension) can inspect the inference output without re-creating the links.
type Package ¶
type Package struct {
// Name is metadata.name from installer.yaml.
Name string
// Version is installerMetadata.version from installer.yaml.
Version string
// LocalHandle is the name the parent used for this dep in its
// installer.yaml + lock. Empty for the parent itself. Used to derive
// link slugs and to match dep packages back to lock entries.
LocalHandle string
// PackageDir is the directory containing installer.yaml.
PackageDir string
// ManifestsDir is where rendered per-resource YAML lives.
ManifestsDir string
// SpecDir is where this package's spec docs live (selection.yaml etc.).
SpecDir string
// SecretsDir is where rendered Secret YAML lives (never uploaded).
SecretsDir string
// SpaceSlug is the ConfigHub Space this package's Units land in.
SpaceSlug string
// IsParent is true for the root package; false for every dep.
IsParent bool
}
Package is one unit-of-upload — the parent or a locked dep.
func Discover ¶
func Discover(in DiscoverInput) ([]Package, error)
Discover walks the work-dir layout produced by Render and returns one Package per source — the parent first, then each locked dep in lock order. Each dep's installer.yaml is read from the vendor cache the renderer populated at out/vendor/<name>@<version>/package/.
type RecordContents ¶
type RecordContents struct {
Package *api.Package
Selection *api.Selection
Inputs *api.Inputs
Facts *api.Facts
Lock *api.Lock
Upload *api.Upload
}
SplitInstallerRecord is the inverse of BuildInstallerRecord: it splits a multi-doc body into one decoded value per kind. Unknown kinds are silently skipped — the body is forward-compatible with future spec docs. installer.yaml is parsed as Package; everything else is keyed by Kind.
func SplitInstallerRecord ¶
func SplitInstallerRecord(body []byte) (*RecordContents, error)
SplitInstallerRecord parses a multi-doc YAML stream produced by BuildInstallerRecord. It is tolerant of new kinds being added later.
type UnmatchedReference ¶
UnmatchedReference is a `get-references` result that didn't match any Unit in the Space — workload Unit FromUnit references a resource of type TargetType named TargetName, but no Unit holds that target. Typically a sign that the target lives in the cluster (out-of-band Secret, platform-team Namespace, etc.) rather than a bug.