Update tech_docs/CUE.md
This commit is contained in:
310
tech_docs/CUE.md
310
tech_docs/CUE.md
@@ -1,3 +1,313 @@
|
|||||||
|
The CUE (Configure-Unify-Execute) lattice is a fundamental concept in the CUE language, which stands for Configure, Unify, and Execute. It is a powerful tool for managing configurations, validating data, and generating code. Here's a detailed explanation of the CUE lattice:
|
||||||
|
|
||||||
|
### Key Concepts
|
||||||
|
|
||||||
|
1. **Value Lattice**:
|
||||||
|
- The CUE lattice is a partially ordered set of values where every pair of values has a unique upper bound (join) and a greatest lower bound (meet). This structure allows CUE to unify different values and constraints in a consistent and predictable manner.
|
||||||
|
- The lattice starts from a singular root called **top** (`_`), which represents any value, and ends with a single leaf called **bottom** (`_|_`), which represents an error or void value.
|
||||||
|
|
||||||
|
2. **Operations**:
|
||||||
|
- **Unification (`&`)**: Combines two values in a conjunction ("and") to ensure the result is valid and correct. For example, `a: int & 5` results in `a: 5`.
|
||||||
|
- **Disjunction (`|`)**: Combines two values in a disjunction ("or"). For example, `a: int | "string"` allows `a` to be either an integer or a string.
|
||||||
|
|
||||||
|
3. **Types and Values**:
|
||||||
|
- In CUE, types, values, and constraints are all treated as values in the lattice. This means there is no distinction between the schema and the data, making it easier to define and validate configurations.
|
||||||
|
|
||||||
|
### Applications
|
||||||
|
|
||||||
|
1. **Data Validation**:
|
||||||
|
- CUE can validate data by unifying it with predefined schemas. Different departments or groups can define their own constraints, which can then be combined to validate the same set of data.
|
||||||
|
|
||||||
|
2. **Configuration Management**:
|
||||||
|
- CUE allows configurations to be combined from different sources without the need for imports. This makes it easier to manage complex configurations, especially in environments like Kubernetes.
|
||||||
|
|
||||||
|
3. **Code Generation**:
|
||||||
|
- CUE can generate code from configurations. For example, you can define a configuration in CUE and generate corresponding code in another language like Go or Python.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
Here's a simple example to illustrate the use of the CUE lattice:
|
||||||
|
|
||||||
|
```cue
|
||||||
|
#Schema: {
|
||||||
|
hello: string
|
||||||
|
life: int
|
||||||
|
pi: float
|
||||||
|
nums: [...int]
|
||||||
|
struct: {...}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Constrained: #Schema & {
|
||||||
|
hello: =~"[a-z]+"
|
||||||
|
life: >0
|
||||||
|
nums: list.MaxItems(10)
|
||||||
|
}
|
||||||
|
|
||||||
|
Value: #Constrained & {
|
||||||
|
hello: "world"
|
||||||
|
life: 42
|
||||||
|
pi: 3.14
|
||||||
|
nums: [1, 2, 3, 4, 5]
|
||||||
|
struct: {
|
||||||
|
a: "a"
|
||||||
|
b: "b"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example:
|
||||||
|
- `#Schema` defines the basic structure of the configuration.
|
||||||
|
- `#Constrained` adds constraints to the schema.
|
||||||
|
- `Value` provides a specific instance that must satisfy both the schema and the constraints.
|
||||||
|
|
||||||
|
### Conclusion
|
||||||
|
|
||||||
|
The CUE lattice provides a powerful and flexible way to manage configurations and validate data. By merging types and values into a single concept, CUE simplifies many tasks that are typically complex in other languages. This makes it particularly useful for configuration management, data validation, and code generation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
You’re right—let’s quit defending the “pipeline as a pile of YAML” and actually **collapse the whole thing into CUE itself**, so the **only** thing you commit is a single, self-contained CUE module that:
|
||||||
|
|
||||||
|
- *is* the application
|
||||||
|
- *is* the build recipe
|
||||||
|
- *is* the runbook
|
||||||
|
- *is* the troubleshooting checklist
|
||||||
|
- *is* the proven, vendor-neutral, byte-for-byte reproducible artifact that you hand to *any* runtime or teammate
|
||||||
|
|
||||||
|
Below is a concrete, working sketch that does exactly that.
|
||||||
|
You can `cue cmd plan`, `cue cmd build`, `cue cmd deploy`, `cue cmd break-glass`, or `cue cmd rollback`, and every byte—including the Dockerfile, the Cisco IOS snippet, and the step-by-step triage checklist—is **generated deterministically from one source of truth**.
|
||||||
|
No hidden YAML, no “oops the pipeline linter ate my leading space.”
|
||||||
|
|
||||||
|
────────────────────────────
|
||||||
|
1. Directory layout (one repo)
|
||||||
|
────────────────────────────
|
||||||
|
.
|
||||||
|
├── cue.mod
|
||||||
|
│ └── module.cue # declares: module acme.com/app
|
||||||
|
├── infra
|
||||||
|
│ ├── docker.cue # Dockerfile as CUE data
|
||||||
|
│ ├── k8s.cue # K8s manifests
|
||||||
|
│ └── cisco.cue # Switch configs
|
||||||
|
├── ops
|
||||||
|
│ ├── runbook.cue # live troubleshooting steps
|
||||||
|
│ └── rollback.cue # rollback recipe
|
||||||
|
└── app
|
||||||
|
├── src # real source code
|
||||||
|
└── app.cue # app-level params
|
||||||
|
|
||||||
|
All of these files are **pure CUE**; nothing else is allowed.
|
||||||
|
|
||||||
|
────────────────────────────
|
||||||
|
2. Single source of truth: app.cue
|
||||||
|
────────────────────────────
|
||||||
|
package app
|
||||||
|
|
||||||
|
// --- app identity -----------
|
||||||
|
name: "payments"
|
||||||
|
version: "1.4.2"
|
||||||
|
|
||||||
|
// --- golden signals ---------
|
||||||
|
golden: {
|
||||||
|
latencyP99: 120 * #ms
|
||||||
|
errorRate: 0.1 * #percent
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- infra knobs ------------
|
||||||
|
infra: {
|
||||||
|
image: "acme/\(name):\(version)"
|
||||||
|
port: 8080
|
||||||
|
cpu: "500m"
|
||||||
|
mem: "256Mi"
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- vendor-agnostic commands
|
||||||
|
command: {
|
||||||
|
plan: {
|
||||||
|
dockerfile: #Dockerfile
|
||||||
|
k8s: #K8s
|
||||||
|
cisco: #Cisco
|
||||||
|
}
|
||||||
|
runbook: #Runbook
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- unit definitions -------
|
||||||
|
#ms: *1 | number
|
||||||
|
#percent: *1 | number & >=0 & <=100
|
||||||
|
|
||||||
|
────────────────────────────
|
||||||
|
3. Dockerfile expressed as data
|
||||||
|
────────────────────────────
|
||||||
|
// infra/docker.cue
|
||||||
|
package infra
|
||||||
|
|
||||||
|
import "acme.com/app"
|
||||||
|
|
||||||
|
#Dockerfile: {
|
||||||
|
_syntax: "dockerfile.v1"
|
||||||
|
stages: [{
|
||||||
|
from: "alpine:3.19"
|
||||||
|
run: ["apk add --no-cache ca-certificates"]
|
||||||
|
copy: [{
|
||||||
|
src: ["./bin/payments"]
|
||||||
|
dest: "/usr/local/bin/payments"
|
||||||
|
}]
|
||||||
|
cmd: ["/usr/local/bin/payments"]
|
||||||
|
expose: [app.infra.port]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
A tiny cue-gen script (pure Go, reproducible) turns `#Dockerfile` into an actual Dockerfile at `docker build` time; no hand-edited text ever floats around.
|
||||||
|
|
||||||
|
────────────────────────────
|
||||||
|
4. K8s manifests
|
||||||
|
────────────────────────────
|
||||||
|
// infra/k8s.cue
|
||||||
|
package infra
|
||||||
|
|
||||||
|
import "acme.com/app"
|
||||||
|
|
||||||
|
#K8s: deployment: {
|
||||||
|
apiVersion: "apps/v1"
|
||||||
|
kind: "Deployment"
|
||||||
|
metadata: name: app.name
|
||||||
|
spec: {
|
||||||
|
replicas: 3
|
||||||
|
selector: matchLabels: app: app.name
|
||||||
|
template: {
|
||||||
|
metadata: labels: app: app.name
|
||||||
|
spec: containers: [{
|
||||||
|
name: app.name
|
||||||
|
image: app.infra.image
|
||||||
|
ports: [{containerPort: app.infra.port}]
|
||||||
|
resources: requests: {
|
||||||
|
cpu: app.infra.cpu
|
||||||
|
memory: app.infra.mem
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
────────────────────────────
|
||||||
|
5. Cisco IOS snippet (best-practice)
|
||||||
|
────────────────────────────
|
||||||
|
// infra/cisco.cue
|
||||||
|
package infra
|
||||||
|
|
||||||
|
import "acme.com/app"
|
||||||
|
|
||||||
|
#Cisco: {
|
||||||
|
hostname: "edge-sw-01"
|
||||||
|
iface: {
|
||||||
|
name: "GigabitEthernet1/0/1"
|
||||||
|
desc: "payments svc uplink"
|
||||||
|
ip: "10.0.0.1/30"
|
||||||
|
mtu: 9000
|
||||||
|
}
|
||||||
|
acl: [{
|
||||||
|
seq: 10
|
||||||
|
rule: "permit tcp any host 10.0.0.1 eq \(app.infra.port)"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
A second cue-gen pass translates `#Cisco` into the exact IOS commands, ready for `expect`/`ansible`/`napalm`.
|
||||||
|
|
||||||
|
────────────────────────────
|
||||||
|
6. Runbook + troubleshooting checklist
|
||||||
|
────────────────────────────
|
||||||
|
// ops/runbook.cue
|
||||||
|
package ops
|
||||||
|
|
||||||
|
import "acme.com/app"
|
||||||
|
|
||||||
|
#Runbook: {
|
||||||
|
checks: [{
|
||||||
|
name: "golden.latency"
|
||||||
|
cmd: "curl -w '%{time_total}' -s -o /dev/null http://\(_host)/health"
|
||||||
|
fail: "> \(app.golden.latencyP99)ms"
|
||||||
|
}, {
|
||||||
|
name: "golden.errors"
|
||||||
|
cmd: "curl -s http://\(_host)/metrics | grep 'http_errors_total'"
|
||||||
|
fail: "> \(app.golden.errorRate)%"
|
||||||
|
}]
|
||||||
|
escalations: [{
|
||||||
|
if: "latency > 2*threshold"
|
||||||
|
then: "kubectl rollout undo deployment/\(app.name)"
|
||||||
|
}]
|
||||||
|
_host: "payments.acme.internal"
|
||||||
|
}
|
||||||
|
|
||||||
|
────────────────────────────
|
||||||
|
7. Commands as first-class citizens
|
||||||
|
────────────────────────────
|
||||||
|
// cue.mod/pkg/tool/tool.cue
|
||||||
|
package tool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"tool/cli"
|
||||||
|
"tool/exec"
|
||||||
|
"tool/file"
|
||||||
|
"acme.com/app"
|
||||||
|
)
|
||||||
|
|
||||||
|
command: plan: {
|
||||||
|
task: dockerfile: file.Create & {
|
||||||
|
filename: "Dockerfile.gen"
|
||||||
|
contents: app.command.plan.dockerfile
|
||||||
|
}
|
||||||
|
task: k8s: file.Create & {
|
||||||
|
filename: "deploy.gen.yaml"
|
||||||
|
contents: yaml.Marshal(app.command.plan.k8s)
|
||||||
|
}
|
||||||
|
task: cisco: file.Create & {
|
||||||
|
filename: "switch.cfg"
|
||||||
|
contents: ios.Marshal(app.command.plan.cisco)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command: build: exec.Run & {
|
||||||
|
cmd: ["docker", "build", "-f", "Dockerfile.gen", "-t", app.infra.image, "."]
|
||||||
|
}
|
||||||
|
|
||||||
|
command: deploy: exec.Run & {
|
||||||
|
cmd: ["kubectl", "apply", "-f", "deploy.gen.yaml"]
|
||||||
|
}
|
||||||
|
|
||||||
|
command: breakGlass: cli.Print & {
|
||||||
|
text: """
|
||||||
|
1. kubectl logs -f deployment/\(app.name)
|
||||||
|
2. runbook checks: cue cmd runbook
|
||||||
|
3. rollback: cue cmd rollback
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
────────────────────────────
|
||||||
|
8. The workflow now
|
||||||
|
────────────────────────────
|
||||||
|
git push
|
||||||
|
↓ (GitHub Action triggers)
|
||||||
|
cue cmd plan → produces `Dockerfile.gen`, `deploy.gen.yaml`, `switch.cfg`
|
||||||
|
cue cmd build → image digest pinned in lockfile
|
||||||
|
cue cmd deploy → kubectl apply
|
||||||
|
cue cmd breakGlass → human runs only if alert fires; every step is auto-generated from the same CUE values
|
||||||
|
|
||||||
|
────────────────────────────
|
||||||
|
9. Why this ends the “YAML didn’t lint” nightmare
|
||||||
|
────────────────────────────
|
||||||
|
- There is **no YAML you can edit by hand**—only CUE.
|
||||||
|
- `cue vet` runs in CI; if the lattice is inconsistent, the push never even builds.
|
||||||
|
- The generated artefacts are byte-for-byte reproducible; you can `git bisect` straight to the offending configuration delta.
|
||||||
|
- Rollback is a cue command that re-emits the previous commit’s exact manifests; not a prayer that the right YAML blob is in git history.
|
||||||
|
|
||||||
|
────────────────────────────
|
||||||
|
10. Meta takeaway
|
||||||
|
────────────────────────────
|
||||||
|
Stop thinking “CUE is a config language.”
|
||||||
|
Start thinking: **the CUE module *is* the entire CI/CD pipeline, frozen at every commit.**
|
||||||
|
Everything else—Tekton, Argo, GitHub Actions, Cisco IOS, Dockerfiles—is just *materialised views* of that one lattice.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
Welcome to the world of **CUE** – *Configure-Unify-Execute* – a language that turns the usual “write YAML and pray” workflow into something that feels almost… serendipitous.
|
Welcome to the world of **CUE** – *Configure-Unify-Execute* – a language that turns the usual “write YAML and pray” workflow into something that feels almost… serendipitous.
|
||||||
|
|
||||||
In CUE you don’t *imperatively* build configs, websites, DB schemas, or API specs.
|
In CUE you don’t *imperatively* build configs, websites, DB schemas, or API specs.
|
||||||
|
|||||||
Reference in New Issue
Block a user