Link
Infrastructure resources often have dependencies on other resources in the sense that information about one resource is necessary in order to configure another resource. For example an AWS load balancer needs to know the subnet IDs of the VPC it should route traffic to. When dependent resources are kept together in a single Config Unit, the infrastructure can usually resolve these dependencies by itself. But sometimes you want to modularize and keep them separate. ConfigHub supports this by using multiple Config Units and you use Links to express these dependencies between Config Units.
In general, Links indicate that configuration data should be propagated from the target of the Link, called the upstream unit, to the source of the Link, called the downstream unit -- the Link direction is the opposite of the direction that data flows. Downstream units link to upstream units that they depend upon. The dependency also sequences apply and destroy actions.
In Kubernetes, data propagation manifests mainly in the form of static resource references. For example, for Units containing Kubernetes Namespace-scoped resources such as Deployment and Service, the metadata.namespace fields of those resources can be set via the needs/provides mechanism by linking their Unit to a Unit containing a Kubernetes Namespace.
Link types
The UpdateType field determines the operation performed using the Link:
- None: No data propagation is performed. Used solely to express a dependency for sequencing apply and destroy actions.
AutoUpdatemust be false. - UpgradeUnit: Merges upstream configuration data into the downstream unit and keeps the downstream unit's
UpstreamUnitIDandUpstreamRevisionNumin sync with the Link. This type is automatically created when cloning a unit and is used by the upgrade mechanism. A unit may have at most one outgoing UpgradeUnit Link. - MergeUnits: Like UpgradeUnit, but without updating the unit's
UpstreamUnitIDandUpstreamRevisionNum. More flexible: a unit may have any number of incoming and outgoing MergeUnits Links. Can pull fromLiveStatewhenUseLiveStateis true. - Insert: Inserts the entire configuration data of the upstream unit as a string value at a specific path in the downstream unit, identified by a single Binding. Useful for embedding structured data (such as JSON policies) into a field of a resource in a different format.
- Upsert: Pulls one or more resources produced by the upstream unit (optionally first transformed by a
TransformInvocation) and inserts or replaces each of them in the downstream unit. Used to render configuration produced by one unit (e.g. anAppConfig/*file) into resources of a different toolchain (e.g. a Kubernetes ConfigMap).Bindingsmust be empty; the downstream unit must currently beKubernetes/YAML. - TransformPaths: Reads named values from specified paths in the upstream unit (and optionally from
UpstreamGettersfunction invocations) and writes Go template or CEL expression results to specified paths in the downstream unit (and optionally viaDownstreamSettersfunction invocations). Useful when you want to compute downstream values from one or more upstream values combined with Space/Unit metadata, or to drive a mutating function with templated arguments. See UpstreamPaths, UpstreamGetters, DownstreamPaths, and DownstreamSetters. - NeedsProvides (default): Needed values in the downstream unit are matched with provided values from the upstream unit. See needs/provides for details. If
UpdateTypeis empty, it defaults to NeedsProvides.
Automatic creation
When a unit is cloned, ConfigHub automatically creates an UpgradeUnit Link from the new clone (downstream) to the original unit (upstream). This Link records which upstream revision was last merged and includes a WhereMutation filter so that upgrade operations only overwrite mutations that originated from the upstream, preserving local customizations.
Resolution
For all Link types that propagate data (all except None), configuration data can be updated in two ways:
- Automatic: When
AutoUpdateis true, the downstream unit is automatically updated when the upstream unit changes.AutoUpdatemust be false for UpdateType None. - Manual: The downstream unit is updated with a
resolveparameter specifying the Link or Links to resolve. When resolving all Links (Link:*), None Links are skipped.
For UpgradeUnit Links, resolution can also be triggered via the --upgrade flag, which uses the Link's WhereMutation filter if one is present.
To preview what a resolve operation will do before committing the change, use --dry-run.
Bindings
Bindings record which values are propagated by a Link. Their structure and requirements vary by Link type:
- NeedsProvides: After resolution (automatic or manual), Bindings are stored on the Link recording which needed attributes in the downstream unit were matched to provided attributes in the upstream unit. Bindings can also be specified manually with
AutoUpdatefalse to propagate values to or from non-standard locations. Each Binding specifiesDataType(string, int, or bool),ProvidedResource,ProvidedPath,NeededResource, andNeededPath. - Insert: Requires exactly one Binding specifying
NeededResource.ResourceName,NeededResource.ResourceType, andNeededPathto identify where the upstream data is inserted.ProvidedResourceandProvidedPathmust not be specified.AutoUpdatein the Binding must be false. - MergeUnits, UpgradeUnit, Upsert, TransformPaths, None: Must not have Bindings.
UpstreamPaths, UpstreamGetters, DownstreamPaths, and DownstreamSetters
For TransformPaths Links, four lists on the Link declare what to read from the upstream unit and what to write to the downstream unit.
Upstream phase: read named values
- UpstreamPaths is a list of
NamedPath. Each entry has aName(a legal Go and CEL identifier, used to reference the value from expressions), aResourceidentifying a resource in the upstream unit, and aPathwithin that resource. Values are read via theget-pathsfunction and are filtered by the Link'sWhereResourcebefore lookup. - UpstreamGetters is a list of
NamedFunctionResult. Each entry has aName(same identifier rules asUpstreamPaths) and aFunctionInvocationfor a non-mutating ConfigHub function whoseOutputTypeisAttributeValueList. TheValueof the first returnedAttributeValueis bound toName. Use a getter when the upstream value cannot be addressed by a single literal path — for example, when it has to be derived via a CEL expression over the upstream resources.FunctionInvocation.WhereResourceis AND-combined with the Link'sWhereResourceto give each getter its own resource scope. Worker functions are not supported.
UpstreamPaths and UpstreamGetters Names share a single namespace and must all be unique. All upstream reads — get-paths plus the getter functions — run in one invocation on the upstream unit.
Downstream phase: write values and run mutating functions
- DownstreamPaths is a list of
PathExpression. Each entry has aResourceandPathidentifying where to write in the downstream unit; anExpression(a Go template or CEL expression, perEvaluator); aParameterslist naming the upstream values the expression references (matchingUpstreamPathsorUpstreamGettersNames); and aDataType(string,int, orbool). The expression renders to a string and is coerced toDataType(strconv.Atoiforint,strconv.ParseBoolforbool). Values are written via theset-attributesfunction in a single call. - DownstreamSetters is a list of
ParameterizedFunction. Each entry has aParameterslist (matching upstream Names that the setter is allowed to reference) and aFunctionInvocationof a mutating ConfigHub function. String arguments whoseEvaluatoris set are template-expanded client-side using the same scope asDownstreamPathsexpressions, narrowed to the setter'sParameterslist. Non-string arguments and arguments withoutEvaluatorare passed through unchanged.FunctionInvocation.WhereResourceis AND-combined with the Link'sWhereResource. Worker functions are not supported.
DownstreamSetters run first (in one invocation on the downstream unit), then DownstreamPaths run via set-attributes (in one invocation). The two mutation summaries are merged into the resolve's FunctionMutationSummary.
Expression scope
| Evaluator | FunctionContext fields | Upstream values |
|---|---|---|
template (Go templates) |
Top-level (e.g. {{.UnitSlug}}, {{.SpaceSlug}}) |
{{.Params.<name>}} |
cel (Common Expression Language) |
functionContext.UnitSlug, functionContext.SpaceSlug, … |
params.<name> |
The FunctionContext fields are those of the downstream unit. Field names match the function handler: Go template field names for templates, JSON-shaped names for CEL.
Abort semantics
If any UpstreamPath or UpstreamGetter produces no value (e.g. the path does not exist in any matching resource, or the getter function returns an empty list), the resolve is aborted: no values are written, and the explicit (manual) resolve path returns an error. The auto-update path logs the failure and continues with subsequent Links.
Link fields
In addition to common metadata fields (DisplayName, Slug, Labels, Annotations), Links have the following fields:
| Field | Description |
|---|---|
FromUnitID |
The downstream (consumer) unit. The Link must be in the same space as this unit. |
ToUnitID |
The upstream (producer) unit. |
ToSpaceID |
The space of the upstream unit. May differ from the Link's space for cross-space links. |
UpdateType |
The operation type: None, UpgradeUnit, MergeUnits, Insert, Upsert, TransformPaths, or NeedsProvides. Defaults to NeedsProvides if empty. |
AutoUpdate |
If true, automatically update the downstream unit when the upstream unit changes. Must be false for None. |
UseLiveState |
If true, use the LiveState of the upstream unit rather than Data as the source. |
UpstreamLastMergedRevisionNum |
The revision (or UnitAction) number of the last merged upstream change. |
DownstreamLastMergedRevisionNum |
The revision number of the downstream unit created by the last merge. |
WhereMutation |
A filter expression that controls which downstream mutations can be overwritten during merge operations. Only for MergeUnits and UpgradeUnit. |
WhereResource |
A filter expression that selects which upstream resources are eligible for propagation. |
Bindings |
The attribute bindings for NeedsProvides and Insert Links. See Bindings. |
TransformInvocationID |
Identifier of an Invocation whose function runs on the upstream data before being upserted into the downstream Unit. Only valid when UpdateType is Upsert. The Invocation's ToolchainType must match the upstream Unit, the function must be non-mutating, and its OutputType must match the downstream Unit's toolchain (currently only Kubernetes/YAML / YAML output). |
UpstreamPaths |
List of NamedPath declaring the values to read from the upstream unit via get-paths. Only valid when UpdateType is TransformPaths. See UpstreamPaths, UpstreamGetters, DownstreamPaths, and DownstreamSetters. |
UpstreamGetters |
List of NamedFunctionResult declaring non-mutating function invocations whose first AttributeValue value is bound to a Name and exposed to expressions alongside UpstreamPaths. Only valid when UpdateType is TransformPaths. |
DownstreamPaths |
List of PathExpression declaring the values to write to the downstream unit via set-attributes. Only valid when UpdateType is TransformPaths. |
DownstreamSetters |
List of ParameterizedFunction declaring mutating function invocations to run on the downstream unit. String arguments are template-expanded using the upstream values listed in Parameters. Only valid when UpdateType is TransformPaths. |