# Managing dependencies

[Links](../background/entities/link.md) express dependencies between Config Units. They indicate that configuration data should be propagated from the _upstream_ (target) unit to the _downstream_ (source) unit -- the Link direction is the opposite of the direction that data flows. Downstream units link to upstream units that they depend upon. Links also [sequence apply and destroy actions](#sequencing-apply-and-destroy-actions) based on these dependency relationships.

## Link types

The `UpdateType` field on a Link determines what kind of data propagation is performed:

| UpdateType | Purpose |
|------------|---------|
| `None` | Dependency sequencing only; no data propagation |
| `UpgradeUnit` | Merge upstream data and track upstream revision (for [variants](./variants.md)) |
| `MergeUnits` | Merge upstream data without revision tracking |
| `Insert` | Insert upstream data as a string value at a specific path |
| `NeedsProvides` | Match needed values to provided values (default) |

## Sequencing apply and destroy actions

All Links, regardless of UpdateType, affect apply and destroy order in [bulk actions](../background/concepts/bulk-operations.md). The Links create a DAG (directed acyclic graph) within the set of units being operated upon. Apply is performed in reverse topological order (upstream units first) and destroy is performed in topological order (downstream units first).

The `None` UpdateType is for Links that exist solely for this sequencing purpose. For example, you may want to ensure that units containing Kubernetes CustomResourceDefinitions are applied before units containing corresponding custom resources:

```
cub link create --space my-space - my-custom-resources my-crds --update-type None --no-auto-update
```

Here is a more complete example that links the `vote`, `worker`, and `result` components to `redis` and/or `db`, and links all of those units to the namespace, `appvote-ns`. When they are applied together, `appvote-ns` is applied first, followed by `redis` and `db`, and then `vote`, `result`, and `worker`:

```
cub link create --space appvote-dev - vote redis
cub link create --space appvote-dev - worker redis
cub link create --space appvote-dev - result db
cub link create --space appvote-dev - worker db
for slug in vote worker result redis db; do
    cub link create --space appvote-dev - "$slug" appvote-ns
done
cub unit apply --space appvote-dev
```

## Automatic vs manual resolution

For Link types that propagate data (all except None), resolution can be automatic or manual:

- **Automatic**: Set `AutoUpdate` to true on the Link. The downstream unit is updated asynchronously whenever the upstream unit changes. `AutoUpdate` must be false for UpdateType `None`.
- **Manual**: Leave `AutoUpdate` false (the default). Trigger resolution explicitly with the `--resolve` flag on `unit update`.

To resolve all non-auto-update Links on a unit:

```
cub unit update --space prod --patch --resolve "Link:*" backend
```

To resolve a specific Link by name:

```
cub unit update --space prod --patch --resolve "Link:prod/my-link-slug" backend
```

To preview what a resolve will do without committing the change, add `--dry-run`:

```
cub unit update --space prod --patch --resolve "Link:*" --dry-run backend
```

When resolving `Link:*`, Links with UpdateType `None` are automatically skipped.

## UpgradeUnit links

UpgradeUnit Links are used with [variants](./variants.md) (clones). When you clone a unit, ConfigHub automatically creates an UpgradeUnit Link from the clone (downstream) to the original (upstream). A unit can have at most one outgoing UpgradeUnit Link.

The Link records which upstream revision was last merged and includes a `WhereMutation` filter so that upgrade operations only overwrite changes that originated from the upstream, preserving local customizations.

Upgrade can be triggered in two ways:

```
# Using the --upgrade flag (uses the link's WhereMutation filter)
cub unit update --space prod --patch --upgrade backend-clone

# Using --resolve on the UpgradeUnit link
cub unit update --space prod --patch --resolve "Link:*" backend-clone
```

Both approaches produce the same result. For bulk upgrades across spaces:

```
cub unit update --space "*" --patch --upgrade --where "UpstreamUnit.Slug = 'backend' AND Space.Labels.Environment = 'prod'"
```

A unit's `UpstreamUnitID` is read-only. To establish, change, or remove the upstream relationship after a unit has been created, create, modify, or delete the unit's UpgradeUnit Link instead. See [creating and managing variants](./variants.md) for more details.

## MergeUnits links

MergeUnits Links merge all upstream configuration data into the downstream unit, with downstream changes treated as overrides. This is similar to UpgradeUnit but without updating the unit's `UpstreamUnitID` and `UpstreamRevisionNum`. More flexible: a unit can have any number of incoming and outgoing MergeUnits Links.

### Merging from live state

When `UseLiveState` is true, the merge pulls from the upstream unit's `LiveState` (the actual deployed state) rather than its `Data` (the desired state). The main use case is to receive data from a renderer bridge, such as ConfigMapRenderer (see [application configuration](./app-config.md)), ArgoCDRenderer (see [rendered manifests](./rendered-manifests.md)), or FluxRenderer. For example:

```
cub link create --space my-space - my-configmap my-config --use-live-state --auto-update --update-type MergeUnits
```

Because the rendered data is merged with the downstream unit's data, overrides can be applied to the merged result. Note that overrides are not recommended for ConfigMaps with ConfigMapFormat `File`, since the configuration data is represented as a single string.

### Splitting and combining units

With `WhereResource`, MergeUnits can be used to split one unit into multiple units. For example, separating CustomResourceDefinitions from other resources:

```
cub link create --space my-space - my-crds source-unit --update-type MergeUnits --where-resource "ResourceType LIKE '%CustomResourceDefinition'"
cub link create --space my-space - my-resources source-unit --update-type MergeUnits --where-resource "ResourceType !~~ '%CustomResourceDefinition'"
```

It can also combine resources from multiple upstream units into one downstream unit using multiple Links.

### WhereMutation filter

For both MergeUnits and UpgradeUnit Links, `WhereMutation` controls which downstream mutations can be overwritten during merge. This is how local customizations are preserved through upgrades.

## Insert links

Insert Links take the entire configuration data from the upstream unit and insert it as a string value at a specific path in the downstream unit. This is useful for embedding structured data from one format into a field of a resource in a different format.

For example, you might store a JSON IAM policy in an `AppConfig/JSON` unit and insert it into the `spec.policy` field of a Kubernetes custom resource:

```
# Create the Kubernetes unit with a placeholder
cub unit create --space my-space ecr-repository ecr-repository.yaml

# Create the JSON policy unit
cub unit create --space my-space ecr-policy ecr-policy.json --toolchain AppConfig/JSON

# Create an Insert link with a Binding identifying the target path
cat <<'EOF' | cub link create --space my-space - ecr-repository ecr-policy --update-type Insert --from-stdin
Bindings:
  - NeededResource:
      ResourceType: ecr.services.k8s.aws/v1alpha1/Repository
      ResourceName: customer-hosted-ns/customer-hosted-app
    NeededPath: spec.policy
    AutoUpdate: false
EOF

# Resolve the link to perform the insertion
cub unit update --space my-space --patch --resolve "Link:*" ecr-repository
```

Insert Links require exactly one Binding that specifies `NeededResource.ResourceName`, `NeededResource.ResourceType`, and `NeededPath` to identify the insertion point in the downstream unit. The `ProvidedResource` and `ProvidedPath` fields must not be specified in the Binding. Insert Links support both `AutoUpdate` true (for automatic propagation when the upstream unit changes) and false (for manual resolution). `WhereResource` can filter the upstream data before insertion.

## NeedsProvides links

NeedsProvides is the default Link type. It matches _needed_ values in the downstream unit with _provided_ values from the upstream unit, and propagates the provided values to the needed locations. See [needs/provides](../background/concepts/needsprovides.md) for the conceptual background.

[Placeholders](../background/concepts/placeholders.md) (see also [managing variants](./variants.md)) indicate values that need to be supplied. They can be replaced by various means, but most commonly by creating Links to dependencies or by mutating [triggers](../background/entities/trigger.md).

To create a NeedsProvides Link from a `backend` unit to a `ns` unit:

```
cub link create --space prod - backend ns
```

In this case, the name from a `Namespace` resource in the `ns` unit could be inserted into the `namespace` field of resources in the `backend` unit where the values are set to `confighubplaceholder`. ConfigHub discovers that Units containing `Namespace` resources _provide_ namespace names and that resources like Deployment and Service _need_ them. The identification and extraction of needed and provided values is performed by functions (`get-needed` and `get-provided`), and ConfigHub matches them and uses the `set-attributes` function to update the needed values.

Variants aren't required in order to use NeedsProvides Links, but in Kubernetes the main reason to use placeholder values is to leave them unbound until the configuration is linked to a providing unit.

### NeededPaths and ProvidedPaths

NeededPaths and ProvidedPaths are stored on each Unit and updated automatically when the unit's data changes. These stored paths enable efficient matching when Links are resolved.

### Bindings

After a NeedsProvides Link is resolved (either automatically or manually), Bindings are stored on the Link recording which values were propagated. For example, a namespace binding:

```json
{
  "AttributeName": "resource-name",
  "AutoUpdate": true,
  "DataType": "string",
  "NeededPath": "metadata.namespace",
  "NeededResource": {
    "ResourceCategory": "Resource",
    "ResourceName": "confighubplaceholder/mydep",
    "ResourceType": "apps/v1/Deployment"
  },
  "OriginalValue": "confighubplaceholder",
  "ProvidedPath": "metadata.name",
  "ProvidedResource": {
    "ResourceCategory": "Resource",
    "ResourceName": "/test-ns",
    "ResourceType": "v1/Namespace"
  }
}
```

Once established, Bindings enable updated values from the upstream unit to continue propagating to the corresponding downstream unit on subsequent resolutions.

### Manual bindings

Bindings can also be created manually, with `AutoUpdate` false in the Binding. This is useful for propagating values to or from non-standard locations or for resource types for which the built-in needs/provides identification hasn't been added yet:

```
cat <<'EOF' | cub link create --space my-space - subnet route-table --update-type NeedsProvides --auto-update --from-stdin
Bindings:
  - AttributeName: resource-name
    DataType: string
    ProvidedResource:
      ResourceType: example.services.k8s.aws/v1alpha1/RouteTable
      ResourceName: /my-route-table
    ProvidedPath: metadata.name
    NeededResource:
      ResourceType: example.services.k8s.aws/v1alpha1/Subnet
      ResourceName: /my-subnet
    NeededPath: spec.routeTableRefs.0.from.name
    AutoUpdate: false
EOF
```

Additionally, you can define [Attributes](../background/entities/attribute.md) in a Space to register additional paths for automated needs/provides binding with custom resource types.

## Using live state

Setting `UseLiveState` to true on a MergeUnits or Insert Link causes data propagation to use the upstream unit's `LiveState` (the actual deployed state) rather than its `Data` (the desired state). This is useful for propagating information that is only known after deployment, such as dynamically assigned addresses or rendered configuration.
