CUE
Overview
This tutorial demonstrates how to add additional resources to a component using CUE. Holos components often mix in resources, eliminating the need to modify existing charts or manifests. In this tutorial, we'll add an ExternalSecret resource to the podinfo Helm chart configured in the Hello Holos tutorial.
Key concepts:
- Resources are validated against
#Resources
defined at the root. - Custom Resource Definitions need to be imported using Timoni.
- Helm, Kustomize, and CUE can be mixed together within the same component.
The Code
Generating the Structure
Use holos
to generate a minimal platform directory structure. First, create
and navigate into a blank directory. Then, use the holos generate platform
command to generate a minimal platform.
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, then add
the following CUE configuration to it.
mkdir -p components/podinfo
cat <<EOF > components/podinfo/podinfo.cue
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"
}
}
}
EOF
Register the component with the platform.
cat <<EOF > platform/podinfo.cue
package holos
Platform: Components: podinfo: {
name: "podinfo"
path: "components/podinfo"
}
EOF
Render the platform.
- Command
- Output
holos render platform
cached podinfo 6.6.2
rendered podinfo in 1.938665041s
rendered platform in 1.938759417s
Add and commit the initial configuration.
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.
cat <<EOF > components/podinfo/mixins.cue
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"
}
}
}
EOF
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 for the ExternalSecret Custom Resource
Definition (CRD). These schemas are located in the cue.mod
directory,
generated by the holos init platform
command executed at the start of this
tutorial.
To import your own custom resource definitions, use Timoni. We imported the
ExternalSecret CRDs embedded in holos
using the following command.
- Command
- Output
timoni mod vendor crds -f https://raw.githubusercontent.com/external-secrets/external-secrets/v0.10.5/deploy/crds/bundle.yaml
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
Take a look at cue.mod/gen/external-secrets.io/externalsecret/v1beta1/types_gen.cue to see the imported definitions.
Once imported, the final step is to add the resource kind to the #Resources
struct. Typically, this is done by creating a new file that CUE unifies with the
existing resources.cue file.
Reviewing Changes
Render the platform with the ExternalSecret
mixed into the podinfo component.
holos render platform
Take a look at the diff to see the mixed in ExternalSecret
.
git diff deploy
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 approach works for every kind of component in Holos,
allowing seamless integration without needing to fork the upstream Helm chart.
This way, we can easily update to new podinfo versions as they're released.
Trying Locally
Optionally, apply the manifests rendered by Holos to a Local Cluster for testing.
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.