---
slug: cue
title: CUE
description: Render component manifests directly from CUE.
sidebar_position: 50
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# CUE

## Overview

This tutorial demonstrates mixing additional resources into a component using
CUE.  Holos components frequently mix in resources so we don't need to modify
existing charts or manifests.  We'll add an [ExternalSecret] resource to the
podinfo Helm chart we configured in the [Hello Holos] tutorial.

Key concepts:

1. Resources are validated against `#Resources` defined at the root.
2. Custom Resource Definitions need to be imported with timoni.
3. Helm, Kustomize, and CUE can be mixed in together in the same component.

## The Code

### Generating the structure

Use `holos` to generate a minimal platform directory structure.  First, create
and cd into a blank directory. Then use the `holos generate platform` command to
generate a minimal platform.

```shell
mkdir holos-cue-tutorial && cd holos-cue-tutorial
holos init platform v1alpha5
```

### Creating the component

Create the directory for the `podinfo` component.  Create an empty file and then
add the following CUE configuration to it.

```bash
mkdir -p components/podinfo
touch components/podinfo/podinfo.cue
```
```cue showLineNumbers
package holos

// export the component build plan to holos
holos: Component.BuildPlan

// Component is a Helm chart
Component: #Helm & {
	Name:      "podinfo"
	Namespace: "default"
	// Add metadata.namespace to all resources with kustomize.
	KustomizeConfig: Kustomization: namespace: Namespace
	Chart: {
		version: "6.6.2"
		repository: {
			name: "podinfo"
			url:  "https://stefanprodan.github.io/podinfo"
		}
	}
}
```

Integrate the component with the platform.

```bash
touch platform/podinfo.cue
```
```cue showLineNumbers
package holos

Platform: Components: podinfo: {
	name: "podinfo"
	path: "components/podinfo"
}
```

Render the platform.

<Tabs groupId="tutorial-hello-render-manifests">
  <TabItem value="command" label="Command">
```bash
holos render platform ./platform
```
  </TabItem>
  <TabItem value="output" label="Output">
```
cached podinfo 6.6.2
rendered podinfo in 1.938665041s
rendered platform in 1.938759417s
```
  </TabItem>
</Tabs>

Add and commit the initial configuration.

```bash
git init . && git add . && git commit -m initial
```

### Mixing in Resources

We use the [ComponentConfig] `Resources` field to mix in resources to any
component kind.  This field is a convenient wrapper around the core [BuildPlan]
[Resources] [Generator].

Create the mixins.cue file.

```bash
touch components/podinfo/mixins.cue
```
```cue showLineNumbers
package holos

// Component fields are unified with podinfo.cue
Component: {
	// Concrete values are defined in podinfo.cue
	Name:      string
	Namespace: string

	// Resources represents mix-in resources organized as a struct.
	Resources: ExternalSecret: (Name): {
		// Name is consistent with the component name.
		metadata: name: Name
		// Namespace is consistent with the component namespace.
		metadata: namespace: Namespace
		spec: {
			// Ensure the target secret name is consistent.
			target: name: metadata.name
			// Ensure the name in the SecretStore is consistent.
			dataFrom: [{extract: {key: metadata.name}}]
			refreshInterval: "30s"
			secretStoreRef: kind: "SecretStore"
			secretStoreRef: name: "default"
		}
	}
}
```

:::important
Holos uses CUE to validate mixed in resources against a schema.  The `Resources`
field validates against the `#Resources` definition in [resources.cue].
:::

### Importing CRDs

Holos includes CUE schema definitions of the ExternalSecret custom resource
definition (CRD).  These schemas are located in the `cue.mod` directory, written by
the `holos init platform` command we executed at the start of this tutorial.

Import your own custom resource definitions using [timoni].  We imported the
ExternalSecret CRDs embedded into `holos` with the following command.

<Tabs groupId="35B1A1A1-D7DF-4D27-A575-28556E182096">
  <TabItem value="command" label="Command">
```bash
timoni mod vendor crds -f https://raw.githubusercontent.com/external-secrets/external-secrets/v0.10.5/deploy/crds/bundle.yaml
```
  </TabItem>
  <TabItem value="output" label="Output">
```txt
2:22PM INF schemas vendored: external-secrets.io/clusterexternalsecret/v1beta1
2:22PM INF schemas vendored: external-secrets.io/clustersecretstore/v1alpha1
2:22PM INF schemas vendored: external-secrets.io/clustersecretstore/v1beta1
2:22PM INF schemas vendored: external-secrets.io/externalsecret/v1alpha1
2:22PM INF schemas vendored: external-secrets.io/externalsecret/v1beta1
2:22PM INF schemas vendored: external-secrets.io/pushsecret/v1alpha1
2:22PM INF schemas vendored: external-secrets.io/secretstore/v1alpha1
2:22PM INF schemas vendored: external-secrets.io/secretstore/v1beta1
2:22PM INF schemas vendored: generators.external-secrets.io/acraccesstoken/v1alpha1
2:22PM INF schemas vendored: generators.external-secrets.io/ecrauthorizationtoken/v1alpha1
2:22PM INF schemas vendored: generators.external-secrets.io/fake/v1alpha1
2:22PM INF schemas vendored: generators.external-secrets.io/gcraccesstoken/v1alpha1
2:22PM INF schemas vendored: generators.external-secrets.io/githubaccesstoken/v1alpha1
2:22PM INF schemas vendored: generators.external-secrets.io/password/v1alpha1
2:22PM INF schemas vendored: generators.external-secrets.io/uuid/v1alpha1
2:22PM INF schemas vendored: generators.external-secrets.io/vaultdynamicsecret/v1alpha1
2:22PM INF schemas vendored: generators.external-secrets.io/webhook/v1alpha1
```
  </TabItem>
</Tabs>

:::tip
Take a look at
[cue.mod/gen/external-secrets.io/externalsecret/v1beta1/types_gen.cue] to see
the imported definitions.
:::

Once imported, the last step is to add the resource kind to the `#Resources`
struct.  This is most often accomplished by adding a new file which cue unifies
with the existing [resources.cue] file.

## Reviewing Changes

Render the platform with the `ExternalSecret` mixed into the podinfo component.

```shell
holos render platform ./platform
```

Take a look at the diff to see the mixed in `ExternalSecret`.

```shell
git diff deploy
```

```diff
diff --git a/deploy/components/podinfo/podinfo.gen.yaml b/deploy/components/podinfo/podinfo.gen.yaml
index 6e4aec0..f79e9d0 100644
--- a/deploy/components/podinfo/podinfo.gen.yaml
+++ b/deploy/components/podinfo/podinfo.gen.yaml
@@ -112,3 +112,19 @@ spec:
       volumes:
       - emptyDir: {}
         name: data
+---
+apiVersion: external-secrets.io/v1beta1
+kind: ExternalSecret
+metadata:
+  name: podinfo
+  namespace: default
+spec:
+  dataFrom:
+  - extract:
+      key: podinfo
+  refreshInterval: 30s
+  secretStoreRef:
+    kind: SecretStore
+    name: default
+  target:
+    name: podinfo
```

We saw how to mix in resources using the `Resources` field of the
[ComponentConfig].  This technique approach works for every kind of component in
Holos.  We did this without needing to fork the upstream Helm chart so we can
easily update to new podinfo versions as they're released.

## Trying Locally

Optionally apply the manifests Holos rendered to a [Local Cluster].

## Next Steps

This tutorial uses the `#Resources` structure to map resource kinds to their
schema definitions in CUE.  This structure is defined in `resources.cue` at the
root of the tree.  Take a look at [resources.cue] to see this mapping structure.

Continue to the next tutorial to learn how to define your own data structures
similar to this `#Resources` structure.

[Local Cluster]: ../topics/local-cluster.mdx
[ExternalSecret]: https://external-secrets.io/latest/api/externalsecret/
[Artifact]: ../api/core.md#Artifact
[Resources]: ../api/core.md#Resources
[Generator]: ../api/core.md#Generator
[Hello Holos]: ./hello-holos.mdx
[cue.mod/gen/external-secrets.io/externalsecret/v1beta1/types_gen.cue]: https://github.com/holos-run/holos/blob/main/internal/generate/platforms/cue.mod/gen/external-secrets.io/externalsecret/v1beta1/types_gen.cue#L13
[ComponentConfig]: ../api/author.md#ComponentConfig
[timoni]: https://timoni.sh/install/
[resources.cue]: https://github.com/holos-run/holos/blob/main/internal/generate/platforms/v1alpha5/resources.cue#L33
