Compare commits

..

7 Commits

Author SHA1 Message Date
Jeff McCune
f7e0470c48 version 0.104.0 with cue 0.12.0 2025-02-06 14:37:50 -08:00
Jeff McCune
d5c7b82684 go mod tidy 2025-02-06 14:33:14 -08:00
Jeff McCune
7d0392e596 update to cue 0.12.0
Most relevant for us: lots of fixes to the evaluator, enables the embed
and toposort experiments.
2025-02-06 14:31:39 -08:00
Gary Larizza
410b882d1d Merge pull request #403 from holos-run/gl/hello-holos-testscript
docs: Update Hello Holos tutorial to use testscript
2025-01-22 14:43:47 -08:00
Gary Larizza
e2648202dc Merge pull request #404 from holos-run/gl/kustomize-testscript
docs: Update Kustomize tutorial to use testscript
2025-01-22 14:43:33 -08:00
Gary Larizza
8fbee1cbd9 docs: Update Kustomize tutorial to use testscript
PROBLEM:

The "Kustomize" tutorial has hardcoded code blocks and hasn't been
updated to use the automated testscript workflow.

SOLUTION:

Create a test for the Kustomize tutorial.
Create a testscript for the Kustomize test.
Update the Kustomize MDX file to load in data from the testscript directory.

OUTCOME:

The code content in the Kustomize tutorial now comes directly from the
testscript workflow.
2025-01-16 14:24:24 -08:00
Gary Larizza
982db2cccc docs: Update Hello Holos tutorial to use testscript
PROBLEM:

The "Hello Holos" tutorial has hardcoded code blocks and hasn't been
updated to use the automated testscript workflow.

SOLUTION:

* Create a test for the Hello Holos tutorial.
* Create a testscript for the Hello Holos test.
* Update the Hello Holos MDX file to load in data from the testscript directory.

OUTCOME:

The code content in the Hello Holos tutorial now comes directly from the
testscript workflow.
2025-01-16 10:12:17 -08:00
128 changed files with 1831 additions and 5151 deletions

View File

@@ -0,0 +1,7 @@
exec bash -c 'bash -euo pipefail $WORK/command.sh 2>&1'
cmp stdout $WORK/output.txt
-- command.sh --
holos --version
-- output.txt --
0.103.0

View File

@@ -0,0 +1,126 @@
# Set $HOME because:
# - Helm uses it for temporary files
# - Git requires it for setting author name/email globally
env HOME=$WORK/.tmp
chmod 0755 $WORK/update.sh
# Configure git author for testscript execution
exec git config --global user.name 'Holos Docs'
exec git config --global user.email 'hello@holos.run'
exec git config --global init.defaultBranch main
# Remove the tutorial directory if it already exists
exec rm -rf holos-tutorial
# Create and change to the tutorial directory, and then initialize the Holos platform
exec bash -c 'bash -euo pipefail $WORK/mkdir-and-init.sh'
cd holos-tutorial
# Create the components directory
exec bash -c 'bash -euo pipefail $WORK/mkdir-components.sh'
# Combine and execute the multiline podinfo component header/body/trailer files
exec cat $WORK/podinfo-component-header.sh ../podinfo-component-body.cue ../eof-trailer.sh
stdin stdout
exec bash -xeuo pipefail
# Combine and execute the multiline platform registration header/body/trailer files
exec cat $WORK/register-podinfo-header.sh ../register-podinfo-body.cue ../eof-trailer.sh
stdin stdout
exec bash -xeuo pipefail
# Render the platform, capture stdout, and use update.sh to gate whether the
# output file should be updated.
#
# NOTE: The [net] condition will test whether external network access is available
[net] exec bash -c 'bash -euo pipefail $WORK/render.sh 2>&1'
[net] stdin stdout
exec $WORK/update.sh $WORK/register-components-output.txt
# Generate and update the tree of the tutorial directory (omitting the cue.mod directory)
exec bash -c 'bash -euo pipefail $WORK/tree.sh'
stdin stdout
exec $WORK/update.sh $WORK/tree.txt
# Split the rendered manifest into two separate files to display separately
exec bash -c 'bash -euo pipefail $WORK/split-rendered-manifest.sh $WORK/holos-tutorial/deploy/components/podinfo/podinfo.gen.yaml $WORK'
# Grep for the Hello Holos message and write the output file
exec bash -c 'bash -euo pipefail $WORK/grep-for-message.sh'
stdin stdout
exec $WORK/update.sh $WORK/grepped-output.txt
# Clean up the tutorial directory and tmp $HOME directory
cd $WORK
exec rm -rf holos-tutorial
exec rm -rf $HOME
-- update.sh --
#! /bin/bash
set -euo pipefail
[[ -s "$1" ]] && [[ -z "${HOLOS_UPDATE_SCRIPTS:-}" ]] && exit 0
cat > "$1"
-- mkdir-and-init.sh --
mkdir holos-tutorial && cd holos-tutorial
holos init platform v1alpha5
-- tree.sh --
tree -L 3 -I cue.mod .
-- mkdir-components.sh --
mkdir -p components/podinfo
-- podinfo-component-header.sh --
cat <<EOF > components/podinfo/podinfo.cue
-- podinfo-component-body.cue --
package holos
// Produce a helm chart build plan.
holos: HelmChart.BuildPlan
HelmChart: #Helm & {
Name: "podinfo"
Chart: {
version: "6.6.2"
repository: {
name: "podinfo"
url: "https://stefanprodan.github.io/podinfo"
}
}
// Holos marshals Values into values.yaml for Helm.
Values: {
// message is a string with a default value. @tag indicates a value may
// be injected from the platform spec component parameters.
ui: {
message: string | *"Hello World" @tag(greeting, type=string)
}
}
}
-- eof-trailer.sh --
EOF
-- register-podinfo-header.sh --
cat <<EOF > platform/podinfo.cue
-- register-podinfo-body.cue --
package holos
Platform: Components: podinfo: {
name: "podinfo"
path: "components/podinfo"
// Inject a value into the component.
parameters: greeting: "Hello Holos!"
}
-- render.sh --
holos render platform
-- register-components-output.txt --
cached podinfo 6.6.2
rendered podinfo in 1.938665041s
rendered platform in 1.938759417s
-- podinfo-rendered-path.sh --
deploy/components/podinfo/podinfo.gen.yaml
-- split-rendered-manifest.sh --
awk 'BEGIN {RS="---"} NR==1 {print > "service.yaml"} NR==2 {print > "deployment.yaml"}' $1
mv service.yaml $2/rendered-service.yaml
mv deployment.yaml $2/rendered-deployment.yaml
-- grep-for-message.sh --
grep -B2 Hello deploy/components/podinfo/podinfo.gen.yaml
-- grepped-output.txt --
env:
- name: PODINFO_UI_MESSAGE
value: Hello Holos!

View File

@@ -0,0 +1 @@
holos --version

View File

@@ -0,0 +1 @@
0.103.0

View File

@@ -0,0 +1 @@
grep -B2 Hello deploy/components/podinfo/podinfo.gen.yaml

View File

@@ -0,0 +1,3 @@
env:
- name: PODINFO_UI_MESSAGE
value: Hello Holos!

View File

@@ -0,0 +1,2 @@
mkdir holos-tutorial && cd holos-tutorial
holos init platform v1alpha5

View File

@@ -0,0 +1 @@
mkdir -p components/podinfo

View File

@@ -0,0 +1,23 @@
package holos
// Produce a helm chart build plan.
holos: HelmChart.BuildPlan
HelmChart: #Helm & {
Name: "podinfo"
Chart: {
version: "6.6.2"
repository: {
name: "podinfo"
url: "https://stefanprodan.github.io/podinfo"
}
}
// Holos marshals Values into values.yaml for Helm.
Values: {
// message is a string with a default value. @tag indicates a value may
// be injected from the platform spec component parameters.
ui: {
message: string | *"Hello World" @tag(greeting, type=string)
}
}
}

View File

@@ -0,0 +1 @@
cat <<EOF > components/podinfo/podinfo.cue

View File

@@ -0,0 +1 @@
deploy/components/podinfo/podinfo.gen.yaml

View File

@@ -0,0 +1,2 @@
rendered podinfo in 544.501875ms
rendered platform in 544.608125ms

View File

@@ -0,0 +1,8 @@
package holos
Platform: Components: podinfo: {
name: "podinfo"
path: "components/podinfo"
// Inject a value into the component.
parameters: greeting: "Hello Holos!"
}

View File

@@ -0,0 +1 @@
cat <<EOF > platform/podinfo.cue

View File

@@ -0,0 +1,93 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: podinfo
app.kubernetes.io/version: 6.6.2
helm.sh/chart: podinfo-6.6.2
name: podinfo
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: podinfo
strategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
annotations:
prometheus.io/port: "9898"
prometheus.io/scrape: "true"
labels:
app.kubernetes.io/name: podinfo
spec:
containers:
- command:
- ./podinfo
- --port=9898
- --cert-path=/data/cert
- --port-metrics=9797
- --grpc-port=9999
- --grpc-service-name=podinfo
- --level=info
- --random-delay=false
- --random-error=false
env:
- name: PODINFO_UI_MESSAGE
value: Hello Holos!
- name: PODINFO_UI_COLOR
value: '#34577c'
image: ghcr.io/stefanprodan/podinfo:6.6.2
imagePullPolicy: IfNotPresent
livenessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/healthz
failureThreshold: 3
initialDelaySeconds: 1
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
name: podinfo
ports:
- containerPort: 9898
name: http
protocol: TCP
- containerPort: 9797
name: http-metrics
protocol: TCP
- containerPort: 9999
name: grpc
protocol: TCP
readinessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/readyz
failureThreshold: 3
initialDelaySeconds: 1
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
resources:
limits: null
requests:
cpu: 1m
memory: 16Mi
volumeMounts:
- mountPath: /data
name: data
terminationGracePeriodSeconds: 30
volumes:
- emptyDir: {}
name: data

View File

@@ -0,0 +1,23 @@
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: podinfo
app.kubernetes.io/version: 6.6.2
helm.sh/chart: podinfo-6.6.2
name: podinfo
spec:
ports:
- name: http
port: 9898
protocol: TCP
targetPort: http
- name: grpc
port: 9999
protocol: TCP
targetPort: grpc
selector:
app.kubernetes.io/name: podinfo
type: ClusterIP

View File

@@ -0,0 +1,3 @@
awk 'BEGIN {RS="---"} NR==1 {print > "service.yaml"} NR==2 {print > "deployment.yaml"}' $1
mv service.yaml $2/rendered-service.yaml
mv deployment.yaml $2/rendered-deployment.yaml

View File

@@ -0,0 +1 @@
tree -L 3 -I cue.mod .

View File

@@ -0,0 +1,17 @@
.
|-- components
| `-- podinfo
| |-- podinfo.cue
| `-- vendor
|-- deploy
| `-- components
| `-- podinfo
|-- platform
| |-- platform.gen.cue
| `-- podinfo.cue
|-- platform.metadata.json
|-- resources.cue
|-- schema.cue
`-- tags.cue
8 directories, 7 files

View File

@@ -0,0 +1,7 @@
exec bash -c 'bash -euo pipefail $WORK/command.sh 2>&1'
cmp stdout $WORK/output.txt
-- command.sh --
holos --version
-- output.txt --
0.103.0

View File

@@ -0,0 +1,226 @@
# Set $HOME because:
# - Helm uses it for temporary files
# - Git requires it for setting author name/email globally
env HOME=$WORK/.tmp
chmod 0755 $WORK/update.sh
# Configure git author for testscript execution
exec git config --global user.name 'Holos Docs'
exec git config --global user.email 'hello@holos.run'
exec git config --global init.defaultBranch main
# Remove the tutorial directory if it already exists
exec rm -rf holos-kustomize-tutorial
# Create and change to the tutorial directory, and then initialize the Holos platform
exec bash -c 'bash -euo pipefail $WORK/mkdir-and-init.sh'
cd holos-kustomize-tutorial
# Initialize git
exec bash -c 'bash -euo pipefail $WORK/git-init.sh'
# Create the component directory
exec bash -c 'bash -euo pipefail $WORK/mkdir-component.sh'
# Combine and execute the multiline httpbin component header/body/trailer files
exec cat $WORK/httpbin-component-header.sh $WORK/httpbin-component-body.cue $WORK/eof-trailer.sh
stdin stdout
exec bash -xeuo pipefail
# Combine and execute the multiline httpbin yaml header/body/trailer files
exec cat $WORK/httpbin-yaml-header.sh $WORK/httpbin-yaml-body.yaml $WORK/eof-trailer.sh
stdin stdout
exec bash -xeuo pipefail
# Combine and execute the multiline registration header/body/trailer files
exec cat $WORK/register-component-header.sh $WORK/register-component-body.cue $WORK/eof-trailer.sh
stdin stdout
exec bash -xeuo pipefail
# Render the platform, capture stdout, and use update.sh to gate whether the
# output file should be updated.
#
# NOTE: The [net] condition will test whether external network access is available
[net] exec bash -c 'bash -euo pipefail $WORK/render.sh 2>&1'
[net] stdin stdout
exec $WORK/update.sh $WORK/register-component-output.txt
# Git commit and capture output
exec bash -c 'bash -euo pipefail $WORK/git-commit-component.sh'
stdin stdout
exec $WORK/update.sh $WORK/git-commit-component-output.txt
# Export Build Plan and capture output
exec bash -c 'bash -euo pipefail $WORK/cue-export.sh'
stdin stdout
exec $WORK/update.sh $WORK/buildplan-output.cue
# Combine and execute the multiline kustomize patch header/body/trailer files
exec cat $WORK/httpbin-patch-header.sh $WORK/httpbin-patch-body.cue $WORK/eof-trailer.sh
stdin stdout
exec bash -xeuo pipefail
# Render the platform and capture output
[net] exec bash -c 'bash -euo pipefail $WORK/render.sh 2>&1'
[net] stdin stdout
exec $WORK/update.sh $WORK/kustomize-patch-render-output.txt
# Git diff and capture output
exec bash -c 'bash -euo pipefail $WORK/git-diff.sh'
stdin stdout
exec $WORK/update.sh $WORK/git.diff
# Git commit and capture output
exec bash -c 'bash -euo pipefail $WORK/git-commit-final.sh'
stdin stdout
exec $WORK/update.sh $WORK/git-commit-final-output.txt
# Clean up the tutorial directory and tmp $HOME directory
cd $WORK
exec rm -rf holos-kustomize-tutorial
exec rm -rf $HOME
-- update.sh --
#! /bin/bash
set -euo pipefail
[[ -s "$1" ]] && [[ -z "${HOLOS_UPDATE_SCRIPTS:-}" ]] && exit 0
cat > "$1"
-- mkdir-and-init.sh --
mkdir holos-kustomize-tutorial
cd holos-kustomize-tutorial
holos init platform v1alpha5
-- git-init.sh --
git init . && git add . && git commit -m initial
-- mkdir-component.sh --
mkdir -p components/httpbin
-- httpbin-component-header.sh --
cat <<EOF > components/httpbin/httpbin.cue
-- httpbin-component-body.cue --
package holos
// Produce a Kustomize BuildPlan for Holos
holos: Kustomize.BuildPlan
// https://github.com/mccutchen/go-httpbin/blob/v2.15.0/kustomize/README.md
Kustomize: #Kustomize & {
KustomizeConfig: {
// Files tells Holos to copy the file from the component path to the
// temporary directory Holos uses for BuildPlan execution.
Files: {
"httpbin.yaml": _
}
CommonLabels: {
"app.kubernetes.io/name": "httpbin"
}
// Kustomization represents a kustomization.yaml file in CUE. Holos
// marshals this field into a `kustomization.yaml` while processing a
// BuildPlan. See
// https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/
Kustomization: {
images: [{name: "mccutchen/go-httpbin"}]
// Use a hidden field to compose patches easily with a struct. Hidden
// fields are not included in exported structures.
_patches: {}
// Convert the hidden struct to a list.
patches: [for x in _patches {x}]
}
}
}
-- eof-trailer.sh --
EOF
-- httpbin-yaml-header.sh --
cat <<EOF > components/httpbin/httpbin.yaml
-- httpbin-yaml-body.yaml --
# https://github.com/mccutchen/go-httpbin/blob/v2.15.0/kustomize/resources.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
spec:
template:
spec:
containers:
- name: httpbin
image: mccutchen/go-httpbin
ports:
- name: http
containerPort: 8080
protocol: TCP
livenessProbe:
httpGet:
path: /status/200
port: http
readinessProbe:
httpGet:
path: /status/200
port: http
resources: {}
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
spec:
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
appProtocol: http
-- register-component-header.sh --
cat <<EOF > platform/httpbin.cue
-- register-component-body.cue --
package holos
Platform: Components: {
httpbin: {
name: "httpbin"
path: "components/httpbin"
}
}
-- git-commit-component.sh --
git add . && git commit -m 'add httpbin'
-- cue-export.sh --
holos cue export --expression holos --out=yaml ./components/httpbin
-- httpbin-patch-header.sh --
cat <<EOF > components/httpbin/patches.cue
-- httpbin-patch-body.cue --
package holos
import "encoding/yaml"
// Mix in a Kustomize patch to the configuration.
Kustomize: KustomizeConfig: Kustomization: _patches: {
probe: {
target: kind: "Service"
target: name: "httpbin"
patch: yaml.Marshal([{
op: "add"
path: "/metadata/annotations/prometheus.io~1probe"
value: "true"
}])
}
}
-- httpbin-component-output.txt --
rendered httpbin in 197.030208ms
rendered platform in 197.416416ms
-- render.sh --
holos render platform
-- git-diff.sh --
git diff
-- git.diff --
diff --git a/deploy/components/httpbin/httpbin.gen.yaml b/deploy/components/httpbin/httpbin.gen.yaml
index 298b9a8..a16bd1a 100644
--- a/deploy/components/httpbin/httpbin.gen.yaml
+++ b/deploy/components/httpbin/httpbin.gen.yaml
@@ -1,6 +1,8 @@
apiVersion: v1
kind: Service
metadata:
+ annotations:
+ prometheus.io/probe: "true"
labels:
app.kubernetes.io/name: httpbin
name: httpbin
-- git-commit-final.sh --
git add . && git commit -m 'annotate httpbin for prometheus probes'

View File

@@ -0,0 +1 @@
holos --version

View File

@@ -0,0 +1 @@
0.103.0

View File

@@ -0,0 +1,36 @@
kind: BuildPlan
apiVersion: v1alpha5
metadata:
name: no-name
spec:
artifacts:
- artifact: components/no-name/no-name.gen.yaml
generators:
- kind: Resources
output: resources.gen.yaml
resources: {}
- kind: File
output: httpbin.yaml
file:
source: httpbin.yaml
validators: []
transformers:
- kind: Kustomize
inputs:
- resources.gen.yaml
- httpbin.yaml
output: components/no-name/no-name.gen.yaml
kustomize:
kustomization:
labels:
- includeSelectors: false
pairs:
app.kubernetes.io/name: httpbin
patches: []
images:
- name: mccutchen/go-httpbin
resources:
- resources.gen.yaml
- httpbin.yaml
kind: Kustomization
apiVersion: kustomize.config.k8s.io/v1beta1

View File

@@ -0,0 +1 @@
holos cue export --expression holos --out=yaml ./components/httpbin

View File

@@ -0,0 +1,6 @@
[main f0dd632] add httpbin
4 files changed, 113 insertions(+)
create mode 100644 components/httpbin/httpbin.cue
create mode 100644 components/httpbin/httpbin.yaml
create mode 100644 deploy/components/httpbin/httpbin.gen.yaml
create mode 100644 platform/httpbin.cue

View File

@@ -0,0 +1 @@
git add . && git commit -m 'add httpbin'

View File

@@ -0,0 +1,3 @@
[main b120712] annotate httpbin for prometheus probes
2 files changed, 18 insertions(+)
create mode 100644 components/httpbin/patches.cue

View File

@@ -0,0 +1 @@
git add . && git commit -m 'annotate httpbin for prometheus probes'

View File

@@ -0,0 +1 @@
git diff

View File

@@ -0,0 +1 @@
git init . && git add . && git commit -m initial

View File

@@ -0,0 +1,13 @@
diff --git a/deploy/components/httpbin/httpbin.gen.yaml b/deploy/components/httpbin/httpbin.gen.yaml
index 298b9a8..a16bd1a 100644
--- a/deploy/components/httpbin/httpbin.gen.yaml
+++ b/deploy/components/httpbin/httpbin.gen.yaml
@@ -1,6 +1,8 @@
apiVersion: v1
kind: Service
metadata:
+ annotations:
+ prometheus.io/probe: "true"
labels:
app.kubernetes.io/name: httpbin
name: httpbin

View File

@@ -0,0 +1,30 @@
package holos
// Produce a Kustomize BuildPlan for Holos
holos: Kustomize.BuildPlan
// https://github.com/mccutchen/go-httpbin/blob/v2.15.0/kustomize/README.md
Kustomize: #Kustomize & {
KustomizeConfig: {
// Files tells Holos to copy the file from the component path to the
// temporary directory Holos uses for BuildPlan execution.
Files: {
"httpbin.yaml": _
}
CommonLabels: {
"app.kubernetes.io/name": "httpbin"
}
// Kustomization represents a kustomization.yaml file in CUE. Holos
// marshals this field into a `kustomization.yaml` while processing a
// BuildPlan. See
// https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/
Kustomization: {
images: [{name: "mccutchen/go-httpbin"}]
// Use a hidden field to compose patches easily with a struct. Hidden
// fields are not included in exported structures.
_patches: {}
// Convert the hidden struct to a list.
patches: [for x in _patches {x}]
}
}
}

View File

@@ -0,0 +1 @@
cat <<EOF > components/httpbin/httpbin.cue

View File

@@ -0,0 +1,2 @@
rendered httpbin in 197.030208ms
rendered platform in 197.416416ms

View File

@@ -0,0 +1,16 @@
package holos
import "encoding/yaml"
// Mix in a Kustomize patch to the configuration.
Kustomize: KustomizeConfig: Kustomization: _patches: {
probe: {
target: kind: "Service"
target: name: "httpbin"
patch: yaml.Marshal([{
op: "add"
path: "/metadata/annotations/prometheus.io~1probe"
value: "true"
}])
}
}

View File

@@ -0,0 +1 @@
cat <<EOF > components/httpbin/patches.cue

View File

@@ -0,0 +1,36 @@
# https://github.com/mccutchen/go-httpbin/blob/v2.15.0/kustomize/resources.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
spec:
template:
spec:
containers:
- name: httpbin
image: mccutchen/go-httpbin
ports:
- name: http
containerPort: 8080
protocol: TCP
livenessProbe:
httpGet:
path: /status/200
port: http
readinessProbe:
httpGet:
path: /status/200
port: http
resources: {}
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
spec:
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
appProtocol: http

View File

@@ -0,0 +1 @@
cat <<EOF > components/httpbin/httpbin.yaml

View File

@@ -0,0 +1,2 @@
rendered httpbin in 132.00525ms
rendered platform in 132.124042ms

View File

@@ -0,0 +1,3 @@
mkdir holos-kustomize-tutorial
cd holos-kustomize-tutorial
holos init platform v1alpha5

View File

@@ -0,0 +1 @@
mkdir -p components/httpbin

View File

@@ -0,0 +1,8 @@
package holos
Platform: Components: {
httpbin: {
name: "httpbin"
path: "components/httpbin"
}
}

View File

@@ -0,0 +1 @@
cat <<EOF > platform/httpbin.cue

View File

@@ -0,0 +1,2 @@
rendered httpbin in 175.057083ms
rendered platform in 175.145292ms

View File

@@ -10,6 +10,7 @@ import TabItem from '@theme/TabItem';
import RenderingOverview from '@site/src/diagrams/rendering-overview.mdx';
import PlatformSequence from '@site/src/diagrams/render-platform-sequence.mdx';
import ComponentSequence from '@site/src/diagrams/render-component-sequence.mdx';
import CodeBlock from '@theme/CodeBlock';
# Hello Holos
@@ -21,49 +22,37 @@ This introduces the core concept of wrapping Helm charts as Holos Components.
## Implementation
### Holos Version
Ensure you have a current version of `holos` installed. This document was
tested with the following version.
import HolosVersionCommand from '!!raw-loader!./_hello-holos/script-01-holos-version/command.sh';
import HolosVersionOutput from '!!raw-loader!./_hello-holos/script-01-holos-version/output.txt';
<CodeBlock language="bash">{HolosVersionCommand}</CodeBlock>
<CodeBlock language="txt">{HolosVersionOutput}</CodeBlock>
### Initialize Platform Structure
Create and initialize a minimal platform:
```shell
mkdir holos-tutorial && cd holos-tutorial
holos init platform v1alpha5
```
import MkdirAndInit from '!!raw-loader!./_hello-holos/script-02-hello-holos/mkdir-and-init.sh';
import TreeOutput from '!!raw-loader!./_hello-holos/script-02-hello-holos/tree.txt';
The resulting directory structure:
<CodeBlock language="bash">{MkdirAndInit}</CodeBlock>
For reference, the directory structure you will attain by the end of this tutorial
is listed below (NOTE: we have omitted the `cue.mod` directory for brevity):
<Tabs groupId="80D04C6A-BC83-44D0-95CC-CE01B439B159">
<TabItem value="tree" label="Tree">
```text showLineNumbers
holos-tutorial/
├── components/
│   └── podinfo/
│   └── podinfo.cue
├── cue.mod/
├── platform/
│   ├── platform.gen.cue
│   └── podinfo.cue
├── resources.cue
├── schema.cue
└── tags.cue
```
<CodeBlock language="txt" showLineNumbers>{TreeOutput}</CodeBlock>
</TabItem>
<TabItem value="details" label="Details">
<div style={{display: "flex"}}>
<div>
```text showLineNumbers
holos-tutorial/
├── components/
│   └── podinfo/
│   └── podinfo.cue
├── cue.mod/
├── platform/
│   ├── platform.gen.cue
│   └── podinfo.cue
├── resources.cue
├── schema.cue
└── tags.cue
```
<CodeBlock language="txt" showLineNumbers>{TreeOutput}</CodeBlock>
</div>
<div>
- **Line 1** The platform root is the `holos-tutorial` directory we created.
@@ -72,22 +61,24 @@ anywhere.
- **Line 3** A component is a collection of `*.cue` files at a path.
- **Line 4** We'll create this file and configure the podinfo helm chart in the
next section.
- **Line 5** The CUE module directory. Schema definitions for Kubernetes and
Holos resources reside within the `cue.mod` directory.
- **Line 6** The platform directory is the **main entrypoint** for the `holos
- **Line 5** The `vendor` directory contains a cached copy of the Helm chart that
was fetched for the component.
- **Line 6** Rendered manifests are placed within the `deploy` directory following
the structure of the `components/` directory.
- **Line 9** The platform directory is the **main entrypoint** for the `holos
render platform` command.
- **Line 7** `platform.gen.cue` is initialized by `holos init platform` and
- **Line 10** `platform.gen.cue` is initialized by `holos init platform` and
contains the Platform spec.
- **Line 8** `podinfo.cue` integrates podinfo with the platform by adding the
- **Line 11** `podinfo.cue` integrates podinfo with the platform by adding the
component to the platform spec. We'll add ths file after the next section.
- **Line 9** `resources.cue` Defines the Kubernetes resources available to
- **Line 13** `resources.cue` Defines the Kubernetes resources available to
manage in CUE.
- **Line 10** `schema.cue` Defines the configuration common to all component
- **Line 14** `schema.cue` Defines the configuration common to all component
kinds.
- **Line 11** `tags.cue` Defines where component parameter values are injected
- **Line 15** `tags.cue` Defines where component parameter values are injected
into the overall platform configuration. We don't need to be concerned with
this file until we cover component parameters.
- **Lines 9-11** Initialized by `holos init platform`, user editable after
- **Lines 9-15** Initialized by `holos init platform`, user editable after
initialization.
</div>
</div>
@@ -98,40 +89,15 @@ initialization.
Configure the `podinfo` component:
```bash
mkdir -p components/podinfo
```
```bash
cat <<EOF > components/podinfo/podinfo.cue
```
```cue showLineNumbers
package holos
import MkdirComponents from '!!raw-loader!./_hello-holos/script-02-hello-holos/mkdir-components.sh';
import PodinfoHeader from '!!raw-loader!./_hello-holos/script-02-hello-holos/podinfo-component-header.sh';
import PodinfoBody from '!!raw-loader!./_hello-holos/script-02-hello-holos/podinfo-component-body.cue';
import EofTrailer from '!!raw-loader!./_hello-holos/script-02-hello-holos/eof-trailer.sh';
// Produce a helm chart build plan.
holos: HelmChart.BuildPlan
HelmChart: #Helm & {
Name: "podinfo"
Chart: {
version: "6.6.2"
repository: {
name: "podinfo"
url: "https://stefanprodan.github.io/podinfo"
}
}
// Holos marshals Values into values.yaml for Helm.
Values: {
// message is a string with a default value. @tag indicates a value may
// be injected from the platform spec component parameters.
ui: {
message: string | *"Hello World" @tag(greeting, type=string)
}
}
}
```
```bash
EOF
```
<CodeBlock language="bash">{MkdirComponents}</CodeBlock>
<CodeBlock language="bash">{PodinfoHeader}</CodeBlock>
<CodeBlock language="cue" showLineNumbers>{PodinfoBody}</CodeBlock>
<CodeBlock language="bash">{EofTrailer}</CodeBlock>
:::important
Like Go packages, CUE loads all `*.cue` files in the component directory to
@@ -148,22 +114,12 @@ root-level `schema.cue`.
Register the `podinfo` component in `platform/podinfo.cue`:
```bash
cat <<EOF > platform/podinfo.cue
```
```cue showLineNumbers
package holos
import RegisterPodinfoHeader from '!!raw-loader!./_hello-holos/script-02-hello-holos/register-podinfo-header.sh';
import RegisterPodinfoBody from '!!raw-loader!./_hello-holos/script-02-hello-holos/register-podinfo-body.cue';
Platform: Components: podinfo: {
name: "podinfo"
path: "components/podinfo"
// Inject a value into the component.
parameters: greeting: "Hello Holos!"
}
```
```bash
EOF
```
<CodeBlock language="bash">{RegisterPodinfoHeader}</CodeBlock>
<CodeBlock language="cue" showLineNumbers>{RegisterPodinfoBody}</CodeBlock>
<CodeBlock language="bash">{EofTrailer}</CodeBlock>
:::tip
Parameter names are unrestricted, except for the reserved `holos_` prefix.
@@ -173,161 +129,42 @@ Parameter names are unrestricted, except for the reserved `holos_` prefix.
Render the `podinfo` configuration:
import RenderCommand from '!!raw-loader!./_hello-holos/script-02-hello-holos/render.sh';
import RegisterComponentsOutput from '!!raw-loader!./_hello-holos/script-02-hello-holos/register-components-output.txt';
<Tabs groupId="E150C802-7162-4FBF-82A7-77D9ADAEE847">
<TabItem value="command" label="Command">
```bash
holos render platform
```
<CodeBlock language="bash">{RenderCommand}</CodeBlock>
</TabItem>
<TabItem value="output" label="Output">
```
cached podinfo 6.6.2
rendered podinfo in 1.938665041s
rendered platform in 1.938759417s
```
<CodeBlock language="txt">{RegisterComponentsOutput}</CodeBlock>
</TabItem>
</Tabs>
Holos executes `helm template` with locally cached charts to generate:
```txt
deploy/components/podinfo/podinfo.gen.yaml
```
import PodinfoRenderedPath from '!!raw-loader!./_hello-holos/script-02-hello-holos/podinfo-rendered-path.sh';
import RenderedService from '!!raw-loader!./_hello-holos/script-02-hello-holos/rendered-service.yaml';
import RenderedDeployment from '!!raw-loader!./_hello-holos/script-02-hello-holos/rendered-deployment.yaml';
<CodeBlock language="txt">{PodinfoRenderedPath}</CodeBlock>
<Tabs groupId="0E9C231D-D0E8-410A-A4A0-601842A086A6">
<TabItem value="service" label="Service">
```yaml showLineNumbers
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: podinfo
app.kubernetes.io/version: 6.6.2
helm.sh/chart: podinfo-6.6.2
name: podinfo
spec:
ports:
- name: http
port: 9898
protocol: TCP
targetPort: http
- name: grpc
port: 9999
protocol: TCP
targetPort: grpc
selector:
app.kubernetes.io/name: podinfo
type: ClusterIP
```
<CodeBlock language="yaml" showLineNumbers>{RenderedService}</CodeBlock>
</TabItem>
<TabItem value="deployment" label="Deployment">
```yaml showLineNumbers
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: podinfo
app.kubernetes.io/version: 6.6.2
helm.sh/chart: podinfo-6.6.2
name: podinfo
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: podinfo
strategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
annotations:
prometheus.io/port: "9898"
prometheus.io/scrape: "true"
labels:
app.kubernetes.io/name: podinfo
spec:
containers:
- command:
- ./podinfo
- --port=9898
- --cert-path=/data/cert
- --port-metrics=9797
- --grpc-port=9999
- --grpc-service-name=podinfo
- --level=info
- --random-delay=false
- --random-error=false
env:
- name: PODINFO_UI_MESSAGE
value: Hello Holos!
- name: PODINFO_UI_COLOR
value: '#34577c'
image: ghcr.io/stefanprodan/podinfo:6.6.2
imagePullPolicy: IfNotPresent
livenessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/healthz
failureThreshold: 3
initialDelaySeconds: 1
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
name: podinfo
ports:
- containerPort: 9898
name: http
protocol: TCP
- containerPort: 9797
name: http-metrics
protocol: TCP
- containerPort: 9999
name: grpc
protocol: TCP
readinessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/readyz
failureThreshold: 3
initialDelaySeconds: 1
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
resources:
limits: null
requests:
cpu: 1m
memory: 16Mi
volumeMounts:
- mountPath: /data
name: data
terminationGracePeriodSeconds: 30
volumes:
- emptyDir: {}
name: data
```
<CodeBlock language="yaml" showLineNumbers>{RenderedDeployment}</CodeBlock>
</TabItem>
</Tabs>
Holos renders the component with the greeting injected from the platform spec.
```shell
grep -B2 Hello deploy/components/podinfo/podinfo.gen.yaml
```
```yaml
env:
- name: PODINFO_UI_MESSAGE
value: Hello Holos!
```
import GrepForMessage from '!!raw-loader!./_hello-holos/script-02-hello-holos/grep-for-message.sh';
import GreppedOutput from '!!raw-loader!./_hello-holos/script-02-hello-holos/grepped-output.txt';
<CodeBlock language="bash">{GrepForMessage}</CodeBlock>
<CodeBlock language="yaml">{GreppedOutput}</CodeBlock>
## Breaking it down

View File

@@ -0,0 +1,19 @@
package main
import (
"path/filepath"
"testing"
)
// Run these with go test -v to see the verbose names
func TestHelloHolos(t *testing.T) {
t.Run("TestHelloHolos", func(t *testing.T) {
// Get an ordered list of test script files.
dir := "_hello-holos"
for _, file := range sortedTestScripts(t, filepath.Join(dir, "examples")) {
t.Run("examples", func(t *testing.T) {
runOneScript(t, dir, file)
})
}
})
}

View File

@@ -7,6 +7,7 @@ sidebar_position: 45
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
# Kustomize
@@ -24,6 +25,17 @@ covered in the [Helm Values] tutorial.
## The Code
### Holos Version
Ensure you have a current version of `holos` installed. This document was
tested with the following version.
import HolosVersionCommand from '!!raw-loader!./_kustomize/script-01-holos-version/command.sh';
import HolosVersionOutput from '!!raw-loader!./_kustomize/script-01-holos-version/output.txt';
<CodeBlock language="bash">{HolosVersionCommand}</CodeBlock>
<CodeBlock language="txt">{HolosVersionOutput}</CodeBlock>
### Generating the structure
<Tabs>
@@ -39,18 +51,14 @@ Use `holos` to generate a minimal platform directory structure. First, create
and navigate into a blank directory. Then, run the `holos init platform`
command.
```shell
mkdir holos-kustomize-tutorial
cd holos-kustomize-tutorial
holos init platform v1alpha5
```
import MkdirAndInit from '!!raw-loader!./_kustomize/script-02-kustomize/mkdir-and-init.sh';
import GitInit from '!!raw-loader!./_kustomize/script-02-kustomize/git-init.sh';
<CodeBlock language="bash">{MkdirAndInit}</CodeBlock>
Make a commit to track changes.
```bash
git init . && git add . && git commit -m initial
```
<CodeBlock language="bash">{GitInit}</CodeBlock>
</TabItem>
</Tabs>
@@ -59,97 +67,26 @@ git init . && git add . && git commit -m initial
Create the `httpbin` component directory, and add the `httpbin.cue` and
`httpbin.yaml` files to it for configuration and setup.
import MkdirComponent from '!!raw-loader!./_kustomize/script-02-kustomize/mkdir-component.sh';
import HttpbinComponentHeader from '!!raw-loader!./_kustomize/script-02-kustomize/httpbin-component-header.sh';
import HttpbinComponentBody from '!!raw-loader!./_kustomize/script-02-kustomize/httpbin-component-body.cue';
import EofTrailer from '!!raw-loader!./_kustomize/script-02-kustomize/eof-trailer.sh';
import HttpbinYamlHeader from '!!raw-loader!./_kustomize/script-02-kustomize/httpbin-yaml-header.sh';
import HttpbinYamlBody from '!!raw-loader!./_kustomize/script-02-kustomize/httpbin-yaml-body.yaml';
<Tabs groupId="800C3AE7-E7F8-4AFC-ABF1-6AFECD945958">
<TabItem value="setup" label="Setup">
```bash
mkdir -p components/httpbin
```
<CodeBlock language="bash">{MkdirComponent}</CodeBlock>
</TabItem>
<TabItem value="components/httpbin/httpbin.cue" label="httpbin.cue">
```bash
cat <<EOF > components/httpbin/httpbin.cue
```
```cue showLineNumbers
package holos
// Produce a Kustomize BuildPlan for Holos
holos: Kustomize.BuildPlan
// https://github.com/mccutchen/go-httpbin/blob/v2.15.0/kustomize/README.md
Kustomize: #Kustomize & {
KustomizeConfig: {
// Files tells Holos to copy the file from the component path to the
// temporary directory Holos uses for BuildPlan execution.
Files: {
"httpbin.yaml": _
}
CommonLabels: {
"app.kubernetes.io/name": "httpbin"
}
// Kustomization represents a kustomization.yaml file in CUE. Holos
// marshals this field into a `kustomization.yaml` while processing a
// BuildPlan. See
// https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/
Kustomization: {
images: [{name: "mccutchen/go-httpbin"}]
// Use a hidden field to compose patches easily with a struct. Hidden
// fields are not included in exported structures.
_patches: {}
// Convert the hidden struct to a list.
patches: [for x in _patches {x}]
}
}
}
```
```bash
EOF
```
<CodeBlock language="bash">{HttpbinComponentHeader}</CodeBlock>
<CodeBlock language="cue" showLineNumbers>{HttpbinComponentBody}</CodeBlock>
<CodeBlock language="bash">{EofTrailer}</CodeBlock>
</TabItem>
<TabItem value="components/httpbin/httpbin.yaml" label="httpbin.yaml">
```bash
cat <<EOF > components/httpbin/httpbin.yaml
```
```yaml showLineNumbers
# https://github.com/mccutchen/go-httpbin/blob/v2.15.0/kustomize/resources.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
spec:
template:
spec:
containers:
- name: httpbin
image: mccutchen/go-httpbin
ports:
- name: http
containerPort: 8080
protocol: TCP
livenessProbe:
httpGet:
path: /status/200
port: http
readinessProbe:
httpGet:
path: /status/200
port: http
resources: {}
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
spec:
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
appProtocol: http
```
```bash
EOF
```
<CodeBlock language="bash">{HttpbinYamlHeader}</CodeBlock>
<CodeBlock language="yaml" showLineNumbers>{HttpbinYamlBody}</CodeBlock>
<CodeBlock language="bash">{EofTrailer}</CodeBlock>
</TabItem>
</Tabs>
@@ -161,56 +98,38 @@ Holos knows the `httpbin.yaml` file is part of the BuildPlan because of the
Register `httpbin` with the platform by adding the following file to the
platform directory.
```bash
cat <<EOF > platform/httpbin.cue
```
```cue showLineNumbers
package holos
import RegisterComponentHeader from '!!raw-loader!./_kustomize/script-02-kustomize/register-component-header.sh';
import RegisterComponentBody from '!!raw-loader!./_kustomize/script-02-kustomize/register-component-body.cue';
Platform: Components: {
httpbin: {
name: "httpbin"
path: "components/httpbin"
}
}
```
```bash
EOF
```
<CodeBlock language="bash">{RegisterComponentHeader}</CodeBlock>
<CodeBlock language="cue">{RegisterComponentBody}</CodeBlock>
<CodeBlock language="bash">{EofTrailer}</CodeBlock>
Render the platform.
import RenderCommand from '!!raw-loader!./_kustomize/script-02-kustomize/render.sh';
import RegisterComponentOutput from '!!raw-loader!./_kustomize/script-02-kustomize/register-component-output.txt';
<Tabs groupId="B120D5D1-0EAB-41E0-AD21-15526EBDD53D">
<TabItem value="command" label="Command">
```bash
holos render platform
```
<CodeBlock language="bash">{RenderCommand}</CodeBlock>
</TabItem>
<TabItem value="output" label="Output">
```txt
rendered httpbin in 707.554666ms
rendered platform in 707.9845ms
```
<CodeBlock language="txt">{RegisterComponentOutput}</CodeBlock>
</TabItem>
</Tabs>
Commit the results.
import GitCommitComponent from '!!raw-loader!./_kustomize/script-02-kustomize/git-commit-component.sh';
import GitCommitComponentOutput from '!!raw-loader!./_kustomize/script-02-kustomize/git-commit-component-output.txt';
<Tabs groupId="446CC550-A634-45C0-BEC7-992E5C56D4FA">
<TabItem value="command" label="Command">
```bash
git add . && git commit -m 'add httpbin'
```
<CodeBlock language="bash">{GitCommitComponent}</CodeBlock>
</TabItem>
<TabItem value="output" label="Output">
```txt
[main c05f9ef] add httpbin
4 files changed, 118 insertions(+)
create mode 100644 components/httpbin/httpbin.cue
create mode 100644 components/httpbin/httpbin.yaml
create mode 100644 deploy/components/httpbin/httpbin.gen.yaml
create mode 100644 platform/httpbin.cue
```
<CodeBlock language="txt">{GitCommitComponentOutput}</CodeBlock>
</TabItem>
</Tabs>
@@ -220,55 +139,15 @@ We can see the [BuildPlan] exported to `holos` by the `holos:
Kustomize.BuildPlan` line in `httpbin.cue`. Holos processes this build plan to
produce the fully rendered manifests.
import CueExport from '!!raw-loader!./_kustomize/script-02-kustomize/cue-export.sh';
import BuildplanOutput from '!!raw-loader!./_kustomize/script-02-kustomize/buildplan-output.cue';
<Tabs groupId="DD697D65-5BEC-4B92-BB33-59BE4FEC112F">
<TabItem value="command" label="Command">
```bash
holos cue export --expression holos --out=yaml ./components/httpbin
```
<CodeBlock language="bash">{CueExport}</CodeBlock>
</TabItem>
<TabItem value="output" label="Output">
```yaml showLineNumbers
kind: BuildPlan
apiVersion: v1alpha5
metadata:
name: no-name
spec:
artifacts:
- artifact: components/no-name/no-name.gen.yaml
generators:
- kind: Resources
output: resources.gen.yaml
resources: {}
- kind: File
output: httpbin.yaml
file:
source: httpbin.yaml
transformers:
- kind: Kustomize
inputs:
- resources.gen.yaml
- httpbin.yaml
output: components/no-name/no-name.gen.yaml
kustomize:
kustomization:
labels:
- includeSelectors: false
pairs:
app.kubernetes.io/name: httpbin
patches: []
images:
- name: mccutchen/go-httpbin
resources:
- resources.gen.yaml
- httpbin.yaml
kind: Kustomization
apiVersion: kustomize.config.k8s.io/v1beta1
source:
component:
name: no-name
path: no-path
parameters: {}
```
<CodeBlock language="yaml">{BuildplanOutput}</CodeBlock>
</TabItem>
</Tabs>
@@ -291,30 +170,12 @@ need to edit any YAML files manually.
Add a new `patches.cue` file to the `httpbin` component with the following
content.
```bash
cat <<EOF > components/httpbin/patches.cue
```
```cue showLineNumbers
package holos
import HttpbinPatchHeader from '!!raw-loader!./_kustomize/script-02-kustomize/httpbin-patch-header.sh';
import HttpbinPatchBody from '!!raw-loader!./_kustomize/script-02-kustomize/httpbin-patch-body.cue';
import "encoding/yaml"
// Mix in a Kustomize patch to the configuration.
Kustomize: KustomizeConfig: Kustomization: _patches: {
probe: {
target: kind: "Service"
target: name: "httpbin"
patch: yaml.Marshal([{
op: "add"
path: "/metadata/annotations/prometheus.io~1probe"
value: "true"
}])
}
}
```
```bash
EOF
```
<CodeBlock language="bash">{HttpbinPatchHeader}</CodeBlock>
<CodeBlock language="bash" showLineNumbers>{HttpbinPatchBody}</CodeBlock>
<CodeBlock language="bash">{EofTrailer}</CodeBlock>
:::note
We use a hidden `_patches` field to easily unify data into a struct, then
@@ -325,62 +186,43 @@ convert the struct into a list for export.
Render the platform to see the result of the kustomization patch.
import KustomizePatchRenderOutput from '!!raw-loader!./_kustomize/script-02-kustomize/kustomize-patch-render-output.txt';
<Tabs groupId="5D1812DD-8E7B-4F97-B349-275214F38B6E">
<TabItem value="command" label="Command">
```bash
holos render platform
```
<CodeBlock language="bash">{RenderCommand}</CodeBlock>
</TabItem>
<TabItem value="output" label="Output">
```txt
rendered httpbin in 197.030208ms
rendered platform in 197.416416ms
```
<CodeBlock language="txt">{KustomizePatchRenderOutput}</CodeBlock>
</TabItem>
</Tabs>
Holos is configuring Kustomize to patch the plain `httpbin.yaml` file with the
annotation.
import GitDiff from '!!raw-loader!./_kustomize/script-02-kustomize/git-diff.sh';
import GitDiffOutput from '!!raw-loader!./_kustomize/script-02-kustomize/git.diff';
<Tabs groupId="3D80279E-8EDE-4B3E-9269-50F5D1C1CA42">
<TabItem value="command" label="Command">
```bash
git diff
```
<CodeBlock language="bash">{GitDiff}</CodeBlock>
</TabItem>
<TabItem value="output" label="Output">
```diff
diff --git a/deploy/components/httpbin/httpbin.gen.yaml b/deploy/components/httpbin/httpbin.gen.yaml
index 298b9a8..a16bd1a 100644
--- a/deploy/components/httpbin/httpbin.gen.yaml
+++ b/deploy/components/httpbin/httpbin.gen.yaml
@@ -1,6 +1,8 @@
apiVersion: v1
kind: Service
metadata:
+ annotations:
+ prometheus.io/probe: "true"
labels:
app.kubernetes.io/name: httpbin
name: httpbin
```
<CodeBlock language="diff">{GitDiffOutput}</CodeBlock>
</TabItem>
</Tabs>
Add and commit the final changes.
import GitCommitFinal from '!!raw-loader!./_kustomize/script-02-kustomize/git-commit-final.sh';
import GitCommitFinalOutput from '!!raw-loader!./_kustomize/script-02-kustomize/git-commit-final-output.txt';
<Tabs groupId="54C335C8-B382-4277-AE87-0D6556921955">
<TabItem value="command" label="Command">
```bash
git add . && git commit -m 'annotate httpbin for prometheus probes'
```
<CodeBlock language="bash">{GitCommitFinal}</CodeBlock>
</TabItem>
<TabItem value="output" label="Output">
```txt
[main 6eeeadb] annotate httpbin for prometheus probes
2 files changed, 3 insertions(+), 1 deletion(-)
```
<CodeBlock language="txt">{GitCommitFinalOutput}</CodeBlock>
</TabItem>
</Tabs>

View File

@@ -0,0 +1,19 @@
package main
import (
"path/filepath"
"testing"
)
// Run these with go test -v to see the verbose names
func TestKustomize(t *testing.T) {
t.Run("TestKustomize", func(t *testing.T) {
// Get an ordered list of test script files.
dir := "_kustomize"
for _, file := range sortedTestScripts(t, filepath.Join(dir, "examples")) {
t.Run("examples", func(t *testing.T) {
runOneScript(t, dir, file)
})
}
})
}

View File

@@ -1,752 +0,0 @@
---
unlisted: true
slug: simplify-helm-value-files-with-unification
title: Simplify Helm Value Files with Unification
authors: [jeff]
tags: [holos, helm, gitops]
# image: /img/cards/validators.png
description: Migrate an ApplicationSet to the rendered manifest pattern with Holos, removing unnecessary complexity.
keywords:
- Holos
- CUE
- Configuration
- Kubernetes
- Hydrated
- Rendered
- Manifest
- Pattern
- Rendered Manifest Pattern
- Unification
- ArgoCD
- ApplicationSet
- Application
- Multi Source
- Values
- Hierarchy
- Merge
- Override
- GitOps
- Complexity
---
## Simplifying a Hierarchy
In [Part 1] of our series on migrating a complex multi environment
ApplicationSet to Holos we reduced complexity by replacing the ApplicationSet Go
template generator with an Application resource exported from CUE. We completed
the migration to implement the rendered manifest pattern, but complexity remains
in the 5 layers of Helm value file overrides.
We'll continue eliminating accidental complexity by refactoring the Helm value
file hierarchy into one unified layer. The data will be visible and within
reach through the command line. Any future changes will either unify
successfully or produce an immediate error, significantly reducing the
complexity of managing Kubernetes by eliminating the accidental complexity of a
Helm value hierarchy.
[Part 1]: ./2025-01-13-replace-an-applicationset-with-the-rendered-manifest-pattern.mdx
{/* truncate */}
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
### Why are overrides a problem?
Consider this snippet form the [original ApplicationSet] we migrated:
```yaml
helm:
valueFiles:
- $values/my-values/common-values.yaml
- $values/my-values/app-version/{{.version}}-values.yaml
- $values/my-values/env-type/{{.type}}-values.yaml
- $values/my-values/regions/{{.region}}-values.yaml
- $values/my-values/envs/{{.env}}-values.yaml
```
Both Holos and ArgoCD pass these value files to Helm in order, resulting in the
following Helm command:
```bash
helm template my-chart \
-f my-values/common-values.yaml \
-f my-values/app-version/prod-values.yaml \
-f my-values/env-type/prod-values.yaml \
-f my-values/regions/us-values.yaml \
-f my-values/envs/prod-us-values.yaml \
...
```
Helm merges each of the value files on top of one another in a last in first out
manner. Imagine we're troubleshooting an issue where the Deployment in the live
system has `replicas: 3` but it should have `replicas: 5`. We need to
reconfigure the replicas.
1. **It's unclear where the `replicas: 3` value came from** when looking at the live system.
2. **It's unclear if or where `replicaCount` is used** when looking at each value file.
3. **It's unclear where we need to set a value of `5` to fix the problem.** Common
values would probably affect too many deployments. Prod-us values would likely
be too specific, missing other prod environments.
4. **Complexity accumulates over time.** Each time we make a change we're invited
to add a new level of overrides. If we're adding a value that's not broad
enough at one level, but too broad at the next level, then we have no choice but
to add one more level in between.
5. **It's difficult to see the actual values passed to Helm.** We have to implement
the last in first out merge algorithm in our head as we page through each file,
an extremely error prone chore.
For example, `common-values.yaml` has `replicaCount: 1`. Is that value actually
used anywhere? The only way to know is to walk through all permutations and
determine if it's overridden or not. Spoiler, `common-values.yaml` is _always_
overridden in the original ApplicationSet we migrated. It serves no purpose,
yet it lays a hidden trap for us to trip over in the future. If we remove a
value overriding common-values.yaml then we don't know if the freshly uncovered
value had an important purpose relevant now or if it no longer serves a purpose.
This particular form of override hierarchy is similar to inheritance, suffering
from the same problems. The central concept of unification in CUE elegantly
solves these problems.
> Like with other configuration languages, CUE can add complexity if values are organized to come from multiple places. However, as CUE disallows overrides, deep layerings are naturally prevented. More importantly, CUE can also enhance readability. A definition in one file may apply to values in many other files. Where one would usually have to open all these files to verify validity; with CUE one can see it at a glance.
Attribution: [Simplicity at Scale](https://cuelang.org/docs/concept/configuration-use-case/#simplicity-at-scale)
> Inheritance is not commutative and idempotent in the general case. In other words, order matters. This makes it hard to track where values are coming from. This is not only true for humans, but also machines. It makes it very complicated, if not impossible, to do any kind of automation.
>
> The basic operation of CUE is commutative, associative and idempotent. This order independence helps both humans and machines. The resulting model is much less complex.
Attribution: [Inheritance-based configuration languages](https://cuelang.org/docs/concept/configuration-use-case/#inheritance-based-configuration-languages)
In CUE, **order is irrelevant**. This property greatly simplifies configuration
as we'll see by unifying these value files.
### What's the desired outcome?
For this refactoring, we'd like to achieve the following goals:
1. Prune unused values.
2. Reduce the five layers of abstraction down to one.
3. Gain insight into the values passed into Helm.
4. Fail fast if a future change creates a conflict.
5. Fail fast if a necessary value is not provided.
6. Prevent complex layers of abstraction from accumulating.
7. Add type checks, schema validation, and constraints to Helm values.
### Starting Context
If you didn't work through [Part 1] the final results are available in the
[end-of-part-1] branch for your reference.
### Pruning Unused Values
We need a way to identify which values are used so we can prune the unused ones.
Holos simplifies this task by rendering all of the manifests to the local
filesystem. We can simply grep the deploy directory to see what values are
actually used.
import GrepReplicasCmd from '!!raw-loader!./_migrate_appset/script-06-unification/grep.sh';
import GrepReplicasOut from '!!raw-loader!./_migrate_appset/script-06-unification/grep.txt';
<Tabs groupId="grep-replicas">
<TabItem value="Command" label="Command">
<CodeBlock language="bash">{GrepReplicasCmd}</CodeBlock>
</TabItem>
<TabItem value="Output" label="Output">
<CodeBlock language="txt">{GrepReplicasOut}</CodeBlock>
</TabItem>
</Tabs>
The `grep` output indicates **3, 8 and 10** are the only values used, yet
`common-values.yaml` configures a value of 1.
import CommonPath from '!!raw-loader!./_migrate_appset/script-06-unification/common.path';
import CommonYAML from '!!raw-loader!./_migrate_appset/script-06-unification/common.yaml';
<CodeBlock language="txt">{CommonPath}</CodeBlock>
<CodeBlock language="yaml" showLineNumbers>{CommonYAML}</CodeBlock>
The `common-values.yaml` file is therefore useless. Let's remove it.
import RemoveHead from '!!raw-loader!./_migrate_appset/script-06-unification/remove.head';
import RemoveBody from '!!raw-loader!./_migrate_appset/script-06-unification/remove.body';
import RemoveTail from '!!raw-loader!./_migrate_appset/script-06-unification/remove.tail';
import RemoveOut from '!!raw-loader!./_migrate_appset/script-06-unification/remove.out';
<Tabs groupId="remove-common-values">
<TabItem value="Command" label="Command">
<CodeBlock language="bash">{RemoveHead}</CodeBlock>
<CodeBlock language="diff" showLineNumbers>{RemoveBody}</CodeBlock>
<CodeBlock language="bash">{RemoveTail}</CodeBlock>
</TabItem>
<TabItem value="Output" label="Output">
<CodeBlock language="txt">{RemoveOut}</CodeBlock>
</TabItem>
</Tabs>
We double check by rendering the platform. There should be no changes to the
deploy directory even though we removed `common-values.yaml` from the Helm
hierarchy.
import RenderCmd from '!!raw-loader!./_migrate_appset/script-06-unification/render.sh';
import RenderOut from '!!raw-loader!./_migrate_appset/script-06-unification/render.txt';
<Tabs groupId="render-command">
<TabItem value="Command" label="Command">
<CodeBlock language="bash">{RenderCmd}</CodeBlock>
</TabItem>
<TabItem value="Output" label="Output">
<CodeBlock language="txt">{RenderOut}</CodeBlock>
</TabItem>
</Tabs>
import CheckCmd from '!!raw-loader!./_migrate_appset/script-06-unification/check.sh';
import CheckOut from '!!raw-loader!./_migrate_appset/script-06-unification/check.txt';
<Tabs groupId="git-status">
<TabItem value="Command" label="Command">
<CodeBlock language="bash">{CheckCmd}</CodeBlock>
</TabItem>
<TabItem value="Output" label="Output">
<CodeBlock language="txt">{CheckOut}</CodeBlock>
</TabItem>
</Tabs>
:::tip
Holos makes it easier to confidently remove values which are never used.
:::
If we didn't have the rendered manifests in hand this would be a much more
difficult task.
### Eliminating Complexity
Let's unify all the levels of the value hierarchy into one layer and see where
the conflicts are. This is straight forward with `holos`.
:::important
One unified layer is significantly less complicated than a hierarchy of
overrides.
:::
import UnifyHead from '!!raw-loader!./_migrate_appset/script-06-unification/unify.head';
import UnifyBody from '!!raw-loader!./_migrate_appset/script-06-unification/unify.body';
import UnifyTail from '!!raw-loader!./_migrate_appset/script-06-unification/unify.tail';
import UnifyOut from '!!raw-loader!./_migrate_appset/script-06-unification/unify.out';
<Tabs groupId="unify-values">
<TabItem value="Command" label="Command">
<CodeBlock language="bash">{UnifyHead}</CodeBlock>
<CodeBlock language="diff" showLineNumbers>{UnifyBody}</CodeBlock>
<CodeBlock language="bash">{UnifyTail}</CodeBlock>
</TabItem>
<TabItem value="Output" label="Output">
<CodeBlock language="txt">{UnifyOut}</CodeBlock>
</TabItem>
</Tabs>
:::important
The 4 ordered list elements convert into one unified struct.
:::
Render all components to see conflicting values. We use concurrency 1 to return
the first error encountered.
import Render2Cmd from '!!raw-loader!./_migrate_appset/script-06-unification/render2.sh';
import Render2Out from '!!raw-loader!./_migrate_appset/script-06-unification/render2.txt';
<Tabs groupId="render2-command">
<TabItem value="Command" label="Command">
<CodeBlock language="bash">{Render2Cmd}</CodeBlock>
</TabItem>
<TabItem value="Output" label="Output">
<CodeBlock language="txt">{Render2Out}</CodeBlock>
</TabItem>
</Tabs>
The `prod-eu` environment has a conflict:
```txt
values.replicaCount: conflicting values 8 and 5
```
The error is detailed, helpfully listing all of the potential locations the
conflict may arise from. We can hone in on the yaml files in the `my-values`
directory:
1. my-values/env-type/prod-values.yaml:2:15
2. my-values/envs/prod-eu-values.yaml:2:15
These files we originally migrated without modifying them are:
import ConflictA from '!!raw-loader!./_migrate_appset/script-06-unification/conflict/prod-values.yaml';
import ConflictB from '!!raw-loader!./_migrate_appset/script-06-unification/conflict/prod-eu-values.yaml';
<Tabs groupId="conflict-files">
<TabItem value="prod-values.yaml" label="prod-values.yaml">
<CodeBlock language="yaml" showLineNumbers>{ConflictA}</CodeBlock>
</TabItem>
<TabItem value="prod-eu-values.yaml" label="prod-eu-values.yaml">
<CodeBlock language="yaml" showLineNumbers>{ConflictB}</CodeBlock>
</TabItem>
</Tabs>
:::important
The conflict arises from the original article specifying a value for the same
field along two different aspects of our configuration: specific environments
(envs) and broad types of environments (env-types).
:::
### Resolving Conflicts
In Holos and CUE we resolve these conflicts by picking one aspect to specify a
given field value. We'll pick specific environments in this case because it's
not too broad and not too specific.
We previously determined **3, 8 and 10** are the only values actually used in
the final configurations, so we already know `replicaCount: 5` in the
`my-values/env-type/prod-values.yaml` file is useless.
Let's remove it.
import Unify2Head from '!!raw-loader!./_migrate_appset/script-06-unification/unify2.head';
import Unify2Body from '!!raw-loader!./_migrate_appset/script-06-unification/unify2.body';
import Unify2Tail from '!!raw-loader!./_migrate_appset/script-06-unification/unify2.tail';
import Unify2Out from '!!raw-loader!./_migrate_appset/script-06-unification/unify2.out';
<Tabs groupId="unify2-values">
<TabItem value="Command" label="Command">
<CodeBlock language="bash">{Unify2Head}</CodeBlock>
<CodeBlock language="diff" showLineNumbers>{Unify2Body}</CodeBlock>
<CodeBlock language="bash">{Unify2Tail}</CodeBlock>
</TabItem>
<TabItem value="Output" label="Output">
<CodeBlock language="txt">{Unify2Out}</CodeBlock>
</TabItem>
</Tabs>
Now we can render the platform again and verify there are no changes to the
rendered manifests in the `deploy` directory.
import Render3Cmd from '!!raw-loader!./_migrate_appset/script-06-unification/render3.sh';
import Render3Out from '!!raw-loader!./_migrate_appset/script-06-unification/render3.txt';
<Tabs groupId="render3-command">
<TabItem value="Command" label="Command">
<CodeBlock language="bash">{Render3Cmd}</CodeBlock>
</TabItem>
<TabItem value="Output" label="Output">
<CodeBlock language="txt">{Render3Out}</CodeBlock>
</TabItem>
</Tabs>
import Status3Cmd from '!!raw-loader!./_migrate_appset/script-06-unification/status3.sh';
import Status3Out from '!!raw-loader!./_migrate_appset/script-06-unification/status3.txt';
<Tabs groupId="status3-command">
<TabItem value="Command" label="Command">
<CodeBlock language="bash">{Status3Cmd}</CodeBlock>
</TabItem>
<TabItem value="Output" label="Output">
<CodeBlock language="txt">{Status3Out}</CodeBlock>
</TabItem>
</Tabs>
Voila! We've successfully refactored all of the value files for Helm into a
single unified data structure. We know we're done because unification succeeds
and there are no changes to the deploy directory.
## Simplifying a Complex Hierarchy
We've removed the complexity of the Go template in the ApplicationSet, and 5
more layers of complexity in the Helm value files, but the original data didn't
have many overrides. It was the best case scenario, flattening the hierarchy by
trial and error was straight forward.
What about a complex hierarchy with lots of overrides? This same trial and
error approach would take too long. Holos offers a solution in this scenario.
In this section we'll use `holos` to create a flattened value file for each of
the config.json deployment configs without using trial and error.
The layout of the deployment configs is a key aspect of this method. The
deployment config inputs always map 1:1 to the rendered manifests and associated
Application resource. Therefore, any intermediate layers of overrides are not
strictly necessary, an opportunity to reduce complexity significantly.
In this example the deployment configs are organized by customer and cluster, so
we'll work to flatten the unnecessary levels of the hierarchy while also
organizing the output around customers and clusters to get everything lined up
nicely.
Using the same deployment configs at each step, we'll:
1. Render my-app using the helm values hierarchy to get a reference point.
2. Render a special chart, render-values, to flatten the value files hierarchy into one file.
3. Render my-app using the flattened values file.
4. Verify there are no changes to the deploy artifacts.
We'll be able to quickly locate and read the configuration given a customer and
a cluster.
### What's the worst case scenario?
In the worst case scenario there is little rhyme or reason to how values are set
and overridden in a hierarchy. We'll start with this worst case scenario,
spraying data across clusters and override layers. This starting point looks
like the following, with the highest precedence values at the top of the table.
| Num | Layer | Description |
| - | - | - |
| 1 | Customer | customer-zzsbbmfc, customer-xxxxxxx, ... |
| 2 | Namespace | prod-myapp, dev-myapp, ... |
| 3 | Application | myapp, yourapp, ... |
| 4 | Cluster | prod1-customer, dev2-internal, uat3-management, ... |
| 5 | Environment | prod, uat, test, dev |
| 6 | Tier | prod, nonprod |
| 7 | Scope | customer, internal, management |
| 8 | Zone | us-east1-a, us-east1-b, ... |
| 9 | Region | us-east1, us-west1, ... |
| 10 | Location | us, eu, ap, ... |
| 11 | Common | Base layer |
Across these layers the following fields may be set:
| Field | Type | Description |
| - | - | - |
| enabled | bool | Feature flag |
| image | string | Container image URI, e.g. "oci://example.com/myservice" |
| version | string | Version string, e.g. "v0.1.0" |
| domain | string | DNS domain, e.g. "example.com" |
| replicas | int | number of replicas |
| clientID | string | OAuth 2.0 client ID |
| issuer | string | OIDC issuer uri, e.g. `https://login.example.com` |
| projectID | string | cloud project id, e.g. "my-project-123456" |
| accountID | int | cloud account id, e.g. 012345678901 |
| arn | string | resource name, e.g. "arn:partition:service:region:account-id:resource-type:resource-id" |
| cores | float | cpu cores, e.g. 2.0 |
| memory | int | memory in MiB, e.g. 2048 |
| labels | map[string]string | resource labels |
### Generating complexity
Generate the deployment configs and the value files. The RNG is seeded with
constant values so the output is deterministic. If you'd like truly random data
set `RANDOMIZE=1` in the environment before running this command..
import GeneratorCmd from '!!raw-loader!./_migrate_appset/script-08-complex-unification/generator.sh';
<CodeBlock language="bash">{GeneratorCmd}</CodeBlock>
{/* Show the generated structure */}
Deployment configs are generated in the following directory. The `config`
directory contains concrete values by convention, organized in packages.
import ShowDeploymentConfigsCmd from '!!raw-loader!./_migrate_appset/script-08-complex-unification/show-deployment-configs.sh';
import ShowDeploymentConfigsOut from '!!raw-loader!./_migrate_appset/script-08-complex-unification/show-deployment-configs.txt';
<CodeBlock language="bash">{ShowDeploymentConfigsCmd}</CodeBlock>
<CodeBlock language="txt">{ShowDeploymentConfigsOut}</CodeBlock>
Each of these {ShowDeploymentConfigsOut} deployment config files map 1:1 to a
`holos` `BuildPlan` and an ArgoCD `Application`.
The Helm value files hierarchy files are written into the `my-app` component
directory. By convention values reside in the component directory so they're
closely associated with the helm chart using them.
import ShowValueFilesCmd from '!!raw-loader!./_migrate_appset/script-08-complex-unification/show-value-files.sh';
import ShowValueFilesOut from '!!raw-loader!./_migrate_appset/script-08-complex-unification/show-value-files.txt';
<Tabs groupId="show-value-files">
<TabItem value="Command" label="Command">
<CodeBlock language="bash">{ShowValueFilesCmd}</CodeBlock>
</TabItem>
<TabItem value="Output" label="Output">
<CodeBlock language="txt">{ShowValueFilesOut}</CodeBlock>
</TabItem>
</Tabs>
### Flattening Step 1
We'll use CUE build tags to render `my-app` instead of `my-chart` for this
example. Build tags alow us to exclude files used in the previous example, like
`platform/my-chart.cue`, and include files for this example like
`platform/my-app.cue`.
This example is about flattening the helm values file, so we use `-t flatten`.
There are three steps to flatten the hierarchy, so we'll use `-t stepX` for each
step along the way.
Finally, we'll use selectors to focus on one customer specifically. It takes a
few minutes (about 4 on my machine) to render all {ShowDeploymentConfigsOut}
deployments for all customers, so we can develop and test the migration process
quickly with one customer, then roll the change out to all customers once we're
ready.
Let's take a look at one `BuildPlan` for one customer. Take note of the
valueFiles hierarchy in the output. Our goal is to reduce complexity by
collapsing this down to one layer with at most one override of a default value.
First, set the customer as a variable:
```bash
export CUSTOMER="customer-zzsbbmfc"
```
import ShowOneBuildPlanCmd from '!!raw-loader!./_migrate_appset/script-08-complex-unification/show-one-buildplan.sh';
import ShowOneBuildPlanOut from '!!raw-loader!./_migrate_appset/script-08-complex-unification/show-one-buildplan.txt';
<Tabs groupId="show-one-buildplan">
<TabItem value="Command" label="Command">
<CodeBlock language="bash">{ShowOneBuildPlanCmd}</CodeBlock>
</TabItem>
<TabItem value="Output" label="Output">
<CodeBlock language="yaml" showLineNumbers>{ShowOneBuildPlanOut}</CodeBlock>
</TabItem>
</Tabs>
The other `BuildPlan` specifications are similar. Values are randomly
distributed through the hierarchy making it a challenge to comprehend which
value is used in the final configuration.
Render the final manifests for this customer so we have a reference point for
the rest of the migration.
import RenderOneCustomerCmd from '!!raw-loader!./_migrate_appset/script-08-complex-unification/render-one-customer.sh';
import RenderOneCustomerOut from '!!raw-loader!./_migrate_appset/script-08-complex-unification/render-one-customer.txt';
<Tabs groupId="render-one-customer">
<TabItem value="Command" label="Command">
<CodeBlock language="bash">{RenderOneCustomerCmd}</CodeBlock>
</TabItem>
<TabItem value="Output" label="Output">
<CodeBlock language="txt">{RenderOneCustomerOut}</CodeBlock>
</TabItem>
</Tabs>
Add and commit these changes so we can easily see any future changes. For the
rest of the migration there should be no changes to the final configuration.
import AddCommitStep1Cmd from '!!raw-loader!./_migrate_appset/script-08-complex-unification/add-and-commit-step1.sh';
import AddCommitStep1Out from '!!raw-loader!./_migrate_appset/script-08-complex-unification/add-and-commit-step1.txt';
<Tabs groupId="add-commit-step1">
<TabItem value="Command" label="Command">
<CodeBlock language="bash">{AddCommitStep1Cmd}</CodeBlock>
</TabItem>
<TabItem value="Output" label="Output">
<CodeBlock language="txt">{AddCommitStep1Out}</CodeBlock>
</TabItem>
</Tabs>
### Flattening Step 2
Now that we have a reference point we can use `holos` to flatten the hierarchy.
We'll pass the same value files to a special `render-values` chart that simply
echos back the final merged values. Holos writes the value files to
`deploy/values` organized by customer and cluster to match the organization of
the source deployment configs, the `config.json` files.
import RenderStep2Cmd from '!!raw-loader!./_migrate_appset/script-08-complex-unification/render-step2.sh';
import RenderStep2Out from '!!raw-loader!./_migrate_appset/script-08-complex-unification/render-step2.txt';
<Tabs groupId="render-step2">
<TabItem value="Command" label="Command">
<CodeBlock language="bash">{RenderStep2Cmd}</CodeBlock>
</TabItem>
<TabItem value="Output" label="Output">
<CodeBlock language="txt">{RenderStep2Out}</CodeBlock>
</TabItem>
</Tabs>
This command produces flattened `values.yaml` files for each one of the input
deployment configs.
import ShowFlattenedValuesCmd from '!!raw-loader!./_migrate_appset/script-08-complex-unification/show-flattened-values.sh';
import ShowFlattenedValuesOut from '!!raw-loader!./_migrate_appset/script-08-complex-unification/show-flattened-values.txt';
<Tabs groupId="show-flattened-values">
<TabItem value="Command" label="Command">
<CodeBlock language="bash">{ShowFlattenedValuesCmd}</CodeBlock>
</TabItem>
<TabItem value="Output" label="Output">
<CodeBlock language="txt">{ShowFlattenedValuesOut}</CodeBlock>
</TabItem>
</Tabs>
Now we can proceed to change the `my-app` Holos component to use these flattened
values in place of the value files hierarchy.
### Flattening Step 3
The final step of the migration is to use the flattened values in place of the
complex hierarchy. In the component definition we replace the use of
`valueFiles` with one `values` struct.
Normally we'd move the `deploy/values` directory into `components/my-app`, but
for the article we use a symlink instead: `components/my-app/flattened-values ->
../../deploy/values`
Here's how the final `BuildPlan` looks. Note how the values are flattened and
the complexity of the override layers are gone.
import Step3ShowOneBuildPlanCmd from '!!raw-loader!./_migrate_appset/script-09-step3/show-one-buildplan.sh';
import Step3ShowOneBuildPlanOut from '!!raw-loader!./_migrate_appset/script-09-step3/show-one-buildplan.txt';
<Tabs groupId="step3-show-one-buildplan">
<TabItem value="Command" label="Command">
<CodeBlock language="bash">{Step3ShowOneBuildPlanCmd}</CodeBlock>
</TabItem>
<TabItem value="Output" label="Output">
<CodeBlock language="yaml" showLineNumbers>{Step3ShowOneBuildPlanOut}</CodeBlock>
</TabItem>
<TabItem value="Step 1" label="Step 1 Comparison">
This is the previous BuildPlan from Step 1 for comparison.
<CodeBlock language="yaml" showLineNumbers>{ShowOneBuildPlanOut}</CodeBlock>
</TabItem>
</Tabs>
Render the platform to ensure we're producing the same output as we did when we
started in step 1.
import RenderStep3Cmd from '!!raw-loader!./_migrate_appset/script-09-step3/render-one-customer.sh';
import RenderStep3Out from '!!raw-loader!./_migrate_appset/script-09-step3/render-one-customer.txt';
<Tabs groupId="render-step3">
<TabItem value="Command" label="Command">
<CodeBlock language="bash">{RenderStep3Cmd}</CodeBlock>
</TabItem>
<TabItem value="Output" label="Output">
<CodeBlock language="txt">{RenderStep3Out}</CodeBlock>
</TabItem>
</Tabs>
The manifests rendered with the flattened values are identical to those rendered
with the more complex hierarchy of overrides.
import GitStatusStep3Cmd from '!!raw-loader!./_migrate_appset/script-09-step3/git-status.sh';
import GitStatusStep3Out from '!!raw-loader!./_migrate_appset/script-09-step3/git-status.txt';
<Tabs groupId="git-status-step3">
<TabItem value="Command" label="Command">
<CodeBlock language="bash">{GitStatusStep3Cmd}</CodeBlock>
</TabItem>
<TabItem value="Output" label="Output">
<CodeBlock language="txt">{GitStatusStep3Out}</CodeBlock>
</TabItem>
</Tabs>
### Going deeper
If you'd like to dive deeper into these steps, take a look at the following
files which are the entrypoints for the `holos render platform` command at each
step. From there, take a look at the component definitions in
`components/my-app/*.cue` and `components/render-values/*.cue`
#### Entrypoints
import S2PlatformMyApp from '!!raw-loader!./_migrate_appset/script-08-complex-unification/files/platform-my-app.cue';
import S2PlatformRenderValues from '!!raw-loader!./_migrate_appset/script-08-complex-unification/files/platform-render-values.cue';
<Tabs groupId="review">
<TabItem value="Step 1" label="Step 1">
```
platform/my-app.cue
```
<CodeBlock language="cue" showLineNumbers>{S2PlatformMyApp}</CodeBlock>
</TabItem>
<TabItem value="Step 2" label="Step 2">
```
platform/render-values.cue
```
<CodeBlock language="cue" showLineNumbers>{S2PlatformRenderValues}</CodeBlock>
</TabItem>
<TabItem value="Step 3" label="Step 3">
:::note
Step 3 uses the same entrypoint as Step 1, completing the migration. The
main difference is in `components/my-app/step3.cue` where the flattened
values are used.
:::
</TabItem>
</Tabs>
#### Component Definition
The `my-app` component definition starts off in step 1, is not used in step 2,
and changes to a flattened values structure in step3. Here are the changes at
each step.
import ComponentDefMyAppXMain from '!!raw-loader!./_migrate_appset/script-09-step3/files/my-app.cue';
import ComponentDefMyAppStep1 from '!!raw-loader!./_migrate_appset/script-09-step3/files/step1.cue';
import ComponentDefMyAppStep3 from '!!raw-loader!./_migrate_appset/script-09-step3/files/step3.cue';
<Tabs groupId="review-component-definition">
<TabItem value="Component Definition" label="Component Definition">
```
components/my-app/my-app.cue
```
<CodeBlock language="cue" showLineNumbers>{ComponentDefMyAppXMain}</CodeBlock>
</TabItem>
<TabItem value="Step 1" label="Step 1">
```
components/my-app/step1.cue
```
<CodeBlock language="cue" showLineNumbers>{ComponentDefMyAppStep1}</CodeBlock>
</TabItem>
<TabItem value="Step 3" label="Step 3">
```
components/my-app/step3.cue
```
<CodeBlock language="cue" showLineNumbers>{ComponentDefMyAppStep3}</CodeBlock>
</TabItem>
</Tabs>
## Concluding Remarks
The original article used 5 layers of Helm value files. Migrating the
configuration to Holos uncovered issues and solved problems.
1. `replicaCount: 1` in common-values.yaml was unnecessary, it was always overridden.
2. `replicaCount: 5` in prod-values.yaml was _also_ unnecessary, it was never used.
3. Removing these two values allowed unification to succeed, which indicates
there was no need for a Helm value hierarchy at all.
The Helm value hierarchy added significant accidental complexity, accidental
because it was not necessary and complex because the layers of override made it
difficult to reason about the system.
Migrating to Holos achieves the same result, the deploy directory remains
unchanged, while leaving us with a much simpler solution.
1. **Complexity remains constant over time.** New aspects can be added, for
example specifying values by customer without introducing a new layer of
overrides. With the previous approach of Helm value overrides _each additional
layer accidentally increased complexity_.
2. **Conflicts are clear and immediate** indicating the exact files and line
numbers where we need to resolve the conflict.
3. **Data is within our reach** we no longer need to rely on ArgoCD running in a
remote cluster to see the desired state. We can inspect the intermediate state
with `holos show buildplans` and the final manifests with `holos render
platform`. We can use simple tools like `grep` to make well informed decisions
about the platform wide configuration.
For example, here's the `holos` `BuildPlan` for prod-us where we see the actual
unified values provided to `helm`.
import ShowBuildPlansCmd from '!!raw-loader!./_migrate_appset/script-06-unification/buildplan.sh';
import ShowBuildPlansOut from '!!raw-loader!./_migrate_appset/script-06-unification/buildplan.txt';
<Tabs groupId="show-buildplans-command">
<TabItem value="Command" label="Command">
<CodeBlock language="bash">{ShowBuildPlansCmd}</CodeBlock>
</TabItem>
<TabItem value="Output" label="Output">
<CodeBlock language="yaml" showLineNumbers>{ShowBuildPlansOut}</CodeBlock>
</TabItem>
</Tabs>
[Part 1]: ./2025-01-13-replace-an-applicationset-with-the-rendered-manifest-pattern.mdx
[original ApplicationSet]: https://github.com/holos-run/multi-sources-example/blob/v0.1.0/appsets/4-final/all-my-envs-appset-with-version.yaml#L27-L32
[end-of-part-1]: https://github.com/holos-run/multi-sources-example/tree/end-of-part-1

View File

@@ -30,7 +30,6 @@ exec $WORK/update.sh $WORK/manifest.yaml
# Make a commit
exec git add .
exec git commit -m '05-application.txtar'
exec git branch end-of-part-1
-- manifest.path --
deploy/environments/prod-us/components/my-chart/my-chart.gen.yaml

View File

@@ -1,198 +0,0 @@
# Work in the root of the example repo
cd ../script-01-clone/multi-sources-example
chmod 0755 $WORK/update.sh
# Grep for replicas: to see what's used
exec bash -c 'bash -euo pipefail $WORK/grep.sh 2>&1'
stdin stdout
exec $WORK/update.sh $WORK/grep.txt
# Common values
exec bash -c 'cp $(<$WORK/common.path) $WORK/common.yaml'
# Remove common values
exec cat $WORK/remove.head $WORK/remove.body $WORK/remove.tail
stdin stdout
exec bash -xeuo pipefail
cp stdout $WORK/remove.out
# Render platform
exec bash -c 'bash -euo pipefail $WORK/render.sh 2>&1'
stdin stdout
exec $WORK/update.sh $WORK/render.txt
# Check results
exec bash -c 'bash -euo pipefail $WORK/check.sh 2>&1'
stdin stdout
exec $WORK/update.sh $WORK/check.txt
# Commit 1
exec bash -c 'bash -euo pipefail $WORK/commit1.sh 2>&1'
stdin stdout
exec $WORK/update.sh $WORK/commit1.txt
# Unification Section
# Unify Values
exec cat $WORK/unify.head $WORK/unify.body $WORK/unify.tail
stdin stdout
exec bash -xeuo pipefail
cp stdout $WORK/unify.out
# Render the platform to see the conflicts
! exec bash -euo pipefail -c 'bash -euo pipefail $WORK/render2.sh 2>&1 | sed s,$(pwd)/,,g'
stdin stdout
exec $WORK/update.sh $WORK/render2.txt
# Copy the value files to show the conflict
mkdir $WORK/conflict
cp components/my-chart/my-values/env-type/prod-values.yaml $WORK/conflict/prod-values.yaml
cp components/my-chart/my-values/envs/prod-eu-values.yaml $WORK/conflict/prod-eu-values.yaml
# Commit 2
exec bash -c 'bash -euo pipefail $WORK/commit2.sh 2>&1'
stdin stdout
exec $WORK/update.sh $WORK/commit2.txt
# Remove replicaCount: 5 from env-type/prod-values.yaml
exec cat $WORK/unify2.head $WORK/unify2.body $WORK/unify2.tail
stdin stdout
exec bash -xeuo pipefail
cp stdout $WORK/unify2.out
# Render the platform again: no conflicts
exec bash -euo pipefail -c 'bash -euo pipefail $WORK/render3.sh 2>&1'
stdin stdout
exec $WORK/update.sh $WORK/render3.txt
# Verify there are no changes to the deploy directory
exec bash -c 'bash -euo pipefail $WORK/status3.sh 2>&1'
stdin stdout
exec $WORK/update.sh $WORK/status3.txt
# Commit 3
exec bash -c 'bash -euo pipefail $WORK/commit3.sh 2>&1'
stdin stdout
exec $WORK/update.sh $WORK/commit3.txt
# Final wrap up - show build plan
exec bash -c 'bash -euo pipefail $WORK/buildplan.sh 2>&1'
cp stdout $WORK/buildplan.txt
-- buildplan.sh --
holos show buildplans --selector env=prod-us
-- status3.sh --
git status deploy
-- render3.sh --
rm -rf deploy
holos render platform
-- unify2.head --
patch -p1 <<'EOF'
-- unify2.tail --
EOF
-- unify2.body --
diff --git a/components/my-chart/my-values/env-type/prod-values.yaml b/components/my-chart/my-values/env-type/prod-values.yaml
index fef58f4..a3cce4a 100644
--- a/components/my-chart/my-values/env-type/prod-values.yaml
+++ b/components/my-chart/my-values/env-type/prod-values.yaml
@@ -1,11 +1,5 @@
-# Kubernetes settings
-replicaCount: 5
-
# Environment settings
environmentType: production
paypalUrl: "production.paypal.com"
dbUser: "prod_username"
dbPassword: "prod_password"
-
-
-
-- render2.sh --
holos render platform --concurrency 1
-- unify.head --
patch -p1 <<'EOF'
-- unify.tail --
EOF
-- unify.body --
diff --git a/components/my-chart/my-chart.cue b/components/my-chart/my-chart.cue
index cf1dae4..4f01828 100644
--- a/components/my-chart/my-chart.cue
+++ b/components/my-chart/my-chart.cue
@@ -31,23 +31,14 @@ component: #Helm & {
// article uses the ApplicationSet template to specify the namespace.
KustomizeConfig: Kustomization: namespace: parameters.env
- // Migrate the Helm Hierarchy preserving the behavior of over writing values.
- // Migrated from [valueFiles]. Later files win.
+ // Migrate the Helm Hierarchy to CUE. Conflicts are errors.
+ // Migrated from [valueFiles].
//
// [valueFiles]: https://github.com/holos-run/multi-sources-example/blob/v0.1.0/appsets/4-final/all-my-envs-appset-with-version.yaml#L27-L32
- ValueFiles: [{
- name: "version-values.yaml"
- values: valueFiles["my-values/app-version/\(parameters.version)-values.yaml"]
- }, {
- name: "type-values.yaml"
- values: valueFiles["my-values/env-type/\(parameters.type)-values.yaml"]
- }, {
- name: "region-values.yaml"
- values: valueFiles["my-values/regions/\(parameters.region)-values.yaml"]
- }, {
- name: "env-values.yaml"
- values: valueFiles["my-values/envs/\(parameters.env)-values.yaml"]
- }]
+ Values: valueFiles["my-values/app-version/\(parameters.version)-values.yaml"]
+ Values: valueFiles["my-values/env-type/\(parameters.type)-values.yaml"]
+ Values: valueFiles["my-values/regions/\(parameters.region)-values.yaml"]
+ Values: valueFiles["my-values/envs/\(parameters.env)-values.yaml"]
}
// holos represents the output for the holos command line to process. The holos
-- commit3.sh --
git add .
git commit -m '06-unification step 3'
-- commit2.sh --
git add .
git commit -m '06-unification step 2'
-- commit1.sh --
git add .
git commit -m '06-unification step 1'
-- render.sh --
rm -rf deploy
holos render platform
-- check.sh --
git status deploy
-- remove.head --
git rm -f components/my-chart/my-values/common-values.yaml
patch -p1 <<'EOF'
-- remove.tail --
EOF
-- remove.body --
diff --git a/components/my-chart/my-chart.cue b/components/my-chart/my-chart.cue
index 2809d1a..cf1dae4 100644
--- a/components/my-chart/my-chart.cue
+++ b/components/my-chart/my-chart.cue
@@ -36,9 +36,6 @@ component: #Helm & {
//
// [valueFiles]: https://github.com/holos-run/multi-sources-example/blob/v0.1.0/appsets/4-final/all-my-envs-appset-with-version.yaml#L27-L32
ValueFiles: [{
- name: "common-values.yaml"
- values: valueFiles["my-values/common-values.yaml"]
- }, {
name: "version-values.yaml"
values: valueFiles["my-values/app-version/\(parameters.version)-values.yaml"]
}, {
@@ -61,5 +58,4 @@ component: #Helm & {
holos: component.BuildPlan
// Migrated from https://github.com/holos-run/multi-sources-example/blob/v0.1.0/appsets/4-final/all-my-envs-appset-with-version.yaml#L27-L32
-valueFiles: _ @embed(glob=my-values/*.yaml)
valueFiles: _ @embed(glob=my-values/*/*-values.yaml)
-- common.path --
components/my-chart/my-values/common-values.yaml
-- grep.sh --
grep -r replicas: deploy
-- update.sh --
#! /bin/bash
set -euo pipefail
[[ -s "$1" ]] && [[ -z "${HOLOS_UPDATE_SCRIPTS:-}" ]] && exit 0
cat > "$1"

View File

@@ -1,5 +0,0 @@
# Work in the root of the example repo
cd ../script-01-clone/multi-sources-example
# Checkout the v0.4.x branch
exec git checkout v0.4.x

View File

@@ -1,77 +0,0 @@
# Work in the root of the example repo
cd ../script-01-clone/multi-sources-example
env HOME=$WORK/.tmp
env CUSTOMER=customer-zzsbbmfc
chmod 0755 $WORK/update.sh
mkdir $WORK/files
# Reset
exec git reset --hard origin/v0.4.x
# Values Generator
exec bash -c 'bash -euo pipefail $WORK/generator.sh 2>&1'
# Show the generated structure
exec bash -c 'bash -eu $WORK/show-deployment-configs.sh 2>&1'
cp stdout $WORK/show-deployment-configs.txt
exec bash -c 'bash -euo pipefail $WORK/show-value-files.sh 2>&1'
cp stdout $WORK/show-value-files.txt
# Show one buildplan
exec bash -c 'bash -euo pipefail $WORK/show-one-buildplan.sh 2>&1'
cp stdout $WORK/show-one-buildplan.txt
# Render one customer
exec bash -c 'bash -euo pipefail $WORK/render-one-customer.sh 2>&1'
stdin stdout
exec $WORK/update.sh $WORK/render-one-customer.txt
# Add and commit
exec bash -c 'bash -euo pipefail $WORK/add-and-commit-step1.sh 2>&1'
stdin stdout
exec $WORK/update.sh $WORK/add-and-commit-step1.txt
# Flattening Values
exec bash -c 'bash -euo pipefail $WORK/render-step2.sh 2>&1'
stdin stdout
exec $WORK/update.sh $WORK/render-step2.txt
# Show the flattened values
exec bash -c 'bash -euo pipefail $WORK/show-flattened-values.sh 2>&1'
cp stdout $WORK/show-flattened-values.txt
# Step 2 - Take a look at the following files
cp platform/my-app.cue $WORK/files/platform-my-app.cue
cp platform/render-values.cue $WORK/files/platform-render-values.cue
-- show-flattened-values.sh --
# Flattened values written here
tree deploy/values/customers/$CUSTOMER
# Note how the input deployment configs now map 1:1 to values files.
tree config/my-app/deployment/customers/$CUSTOMER
-- render-step2.sh --
holos render platform -t flatten -t step2 \
--selector customer=$CUSTOMER
-- add-and-commit-step1.sh --
git add deploy
git commit -m 'render step1 with helm value file overrides'
-- render-one-customer.sh --
holos render platform -t flatten -t step1 \
--selector customer=$CUSTOMER
-- show-one-buildplan.sh --
holos show buildplans -t flatten -t step1 \
--selector customer=$CUSTOMER,cluster=prod9-management
-- show-deployment-configs.sh --
ls config/my-app/deployment/customers/*/clusters/*/config.json | wc -l
-- show-value-files.sh --
tree -d components/my-app/values/
tree components/my-app/values/05-environments
tree components/my-app/values/06-tiers
tree components/my-app/values/07-scopes
-- generator.sh --
go run ./generator
-- update.sh --
#! /bin/bash
set -euo pipefail
[[ -s "$1" ]] && [[ -z "${HOLOS_UPDATE_SCRIPTS:-}" ]] && exit 0
cat > "$1"

View File

@@ -1,38 +0,0 @@
# Work in the root of the example repo
cd ../script-01-clone/multi-sources-example
env CUSTOMER=customer-zzsbbmfc
chmod 0755 $WORK/update.sh
# Show one buildplan
exec bash -c 'bash -euo pipefail $WORK/show-one-buildplan.sh 2>&1'
cp stdout $WORK/show-one-buildplan.txt
# Render one customer
exec bash -c 'bash -euo pipefail $WORK/render-one-customer.sh 2>&1'
stdin stdout
exec $WORK/update.sh $WORK/render-one-customer.txt
# Git status
exec bash -c 'bash -euo pipefail $WORK/git-status.sh 2>&1'
cp stdout $WORK/git-status.txt
# Component definitions
mkdir $WORK/files
cp components/my-app/my-app.cue $WORK/files/my-app.cue
cp components/my-app/step1.cue $WORK/files/step1.cue
cp components/my-app/step3.cue $WORK/files/step3.cue
-- git-status.sh --
git status
-- render-one-customer.sh --
find deploy/clusters -name $CUSTOMER -print0 | xargs -0 rm -rf
holos render platform -t flatten -t step3 \
--selector customer=$CUSTOMER
-- show-one-buildplan.sh --
holos show buildplans -t flatten -t step3 \
--selector customer=$CUSTOMER,cluster=prod9-management
-- update.sh --
#! /bin/bash
set -euo pipefail
[[ -s "$1" ]] && [[ -z "${HOLOS_UPDATE_SCRIPTS:-}" ]] && exit 0
cat > "$1"

View File

@@ -1 +1 @@
6a882ac5aee7241e0130a59737cc46db5f636a21
f35da50452b346d4eea3f3e59ff5ae6b8c221218

View File

@@ -1,8 +1,8 @@
rendered my-chart 0.1.0 for environment integration-gpu in 451.061ms
rendered my-chart 0.1.0 for environment prod-eu in 451.063834ms
rendered my-chart 0.1.0 for environment prod-us in 451.098417ms
rendered my-chart 0.2.0 for environment staging-eu in 451.417625ms
rendered my-chart 0.2.0 for environment staging-us in 471.239083ms
rendered my-chart 0.2.0 for environment integration-non-gpu in 471.789667ms
rendered my-chart 0.2.0 for environment qa in 471.892041ms
rendered platform in 471.935667ms
rendered my-chart 0.1.0 for environment integration-gpu in 428.168708ms
rendered my-chart 0.1.0 for environment prod-us in 428.221333ms
rendered my-chart 0.1.0 for environment prod-eu in 428.148834ms
rendered my-chart 0.2.0 for environment qa in 433.4605ms
rendered my-chart 0.2.0 for environment staging-us in 493.320625ms
rendered my-chart 0.2.0 for environment integration-non-gpu in 493.343917ms
rendered my-chart 0.2.0 for environment staging-eu in 493.325917ms
rendered platform in 493.432542ms

View File

@@ -1,8 +1,8 @@
rendered my-chart 0.2.0 for environment integration-non-gpu in 189.944ms
rendered my-chart 0.1.0 for environment prod-eu in 198.639375ms
rendered my-chart 0.1.0 for environment prod-us in 199.318375ms
rendered my-chart 0.2.0 for environment staging-us in 202.999667ms
rendered my-chart 0.2.0 for environment qa in 203.460125ms
rendered my-chart 0.1.0 for environment integration-gpu in 204.000958ms
rendered my-chart 0.2.0 for environment staging-eu in 204.434791ms
rendered platform in 204.515917ms
rendered my-chart 0.2.0 for environment integration-non-gpu in 204.149958ms
rendered my-chart 0.1.0 for environment prod-us in 205.34475ms
rendered my-chart 0.2.0 for environment staging-eu in 206.376291ms
rendered my-chart 0.1.0 for environment prod-eu in 207.298833ms
rendered my-chart 0.1.0 for environment integration-gpu in 207.896ms
rendered my-chart 0.2.0 for environment staging-us in 210.70825ms
rendered my-chart 0.2.0 for environment qa in 210.695667ms
rendered platform in 210.776584ms

View File

@@ -1 +0,0 @@
holos show buildplans --selector env=prod-us

View File

@@ -1,86 +0,0 @@
kind: BuildPlan
apiVersion: v1alpha5
metadata:
name: my-chart
labels:
env: prod-us
annotations:
app.holos.run/description: my-chart 0.1.0 for environment prod-us
spec:
artifacts:
- artifact: environments/prod-us/components/my-chart/my-chart.gen.yaml
generators:
- kind: Helm
output: helm.gen.yaml
helm:
chart:
name: my-chart
version: 0.1.0
release: my-chart
repository:
name: multi-sources-example
url: https://kostis-codefresh.github.io/multi-sources-example
values:
cacheSize: 1024kb
dbPassword: prod_password
dbUser: prod_username
environment: prod-us
environmentType: production
gpuEnabled: "1"
imageVersion: "1.0"
nBuckets: "42"
pageLimit: "25"
paypalUrl: production.paypal.com
region: us
replicaCount: 10
sorting: Ascending
userInterfaceTheme: dark
- kind: Resources
output: resources.gen.yaml
transformers:
- kind: Kustomize
inputs:
- helm.gen.yaml
- resources.gen.yaml
output: environments/prod-us/components/my-chart/my-chart.gen.yaml
kustomize:
kustomization:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
labels:
- includeSelectors: false
pairs:
argocd.argoproj.io/instance: prod-us-my-chart
namespace: prod-us
resources:
- helm.gen.yaml
- resources.gen.yaml
- artifact: gitops/prod-us-my-chart-application.gen.yaml
generators:
- kind: Resources
output: gitops/prod-us-my-chart-application.gen.yaml
resources:
Application:
prod-us-my-chart:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
labels:
env: prod-us
name: prod-us-my-chart
namespace: argocd
spec:
destination:
namespace: prod-us
server: https://kubernetes.default.svc
project: default
source:
path: deploy/environments/prod-us/components/my-chart
repoURL: https://github.com/holos-run/multi-sources-example
targetRevision: main
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true

View File

@@ -1 +0,0 @@
git status deploy

View File

@@ -1,2 +0,0 @@
On branch work
nothing to commit, working tree clean

View File

@@ -1,2 +0,0 @@
git add .
git commit -m '06-unification step 1'

View File

@@ -1,3 +0,0 @@
[work ba3701f] 06-unification step 1
2 files changed, 6 deletions(-)
delete mode 100644 components/my-chart/my-values/common-values.yaml

View File

@@ -1,2 +0,0 @@
git add .
git commit -m '06-unification step 2'

View File

@@ -1,2 +0,0 @@
[work cd67fc5] 06-unification step 2
1 file changed, 6 insertions(+), 15 deletions(-)

View File

@@ -1,2 +0,0 @@
git add .
git commit -m '06-unification step 3'

View File

@@ -1,2 +0,0 @@
[work 44027c3] 06-unification step 3
1 file changed, 6 deletions(-)

View File

@@ -1 +0,0 @@
components/my-chart/my-values/common-values.yaml

View File

@@ -1,2 +0,0 @@
# Kubernetes settings
replicaCount: 1

View File

@@ -1,13 +0,0 @@
# Kubernetes settings
replicaCount: 8
# Environment settings
environment: prod-eu
# Application settings
userInterfaceTheme: "dark"
cacheSize: "1024kb"
gpuEnabled: "1"
pageLimit: "25"
sorting: "Ascending"
nBuckets: "42"

View File

@@ -1,11 +0,0 @@
# Kubernetes settings
replicaCount: 5
# Environment settings
environmentType: production
paypalUrl: "production.paypal.com"
dbUser: "prod_username"
dbPassword: "prod_password"

View File

@@ -1 +0,0 @@
grep -r replicas: deploy

View File

@@ -1,7 +0,0 @@
deploy/environments/integration-gpu/components/my-chart/my-chart.gen.yaml: replicas: 3
deploy/environments/prod-eu/components/my-chart/my-chart.gen.yaml: replicas: 8
deploy/environments/integration-non-gpu/components/my-chart/my-chart.gen.yaml: replicas: 3
deploy/environments/qa/components/my-chart/my-chart.gen.yaml: replicas: 3
deploy/environments/staging-eu/components/my-chart/my-chart.gen.yaml: replicas: 3
deploy/environments/prod-us/components/my-chart/my-chart.gen.yaml: replicas: 10
deploy/environments/staging-us/components/my-chart/my-chart.gen.yaml: replicas: 3

View File

@@ -1,20 +0,0 @@
diff --git a/components/my-chart/my-chart.cue b/components/my-chart/my-chart.cue
index 2809d1a..cf1dae4 100644
--- a/components/my-chart/my-chart.cue
+++ b/components/my-chart/my-chart.cue
@@ -36,9 +36,6 @@ component: #Helm & {
//
// [valueFiles]: https://github.com/holos-run/multi-sources-example/blob/v0.1.0/appsets/4-final/all-my-envs-appset-with-version.yaml#L27-L32
ValueFiles: [{
- name: "common-values.yaml"
- values: valueFiles["my-values/common-values.yaml"]
- }, {
name: "version-values.yaml"
values: valueFiles["my-values/app-version/\(parameters.version)-values.yaml"]
}, {
@@ -61,5 +58,4 @@ component: #Helm & {
holos: component.BuildPlan
// Migrated from https://github.com/holos-run/multi-sources-example/blob/v0.1.0/appsets/4-final/all-my-envs-appset-with-version.yaml#L27-L32
-valueFiles: _ @embed(glob=my-values/*.yaml)
valueFiles: _ @embed(glob=my-values/*/*-values.yaml)

View File

@@ -1,2 +0,0 @@
git rm -f components/my-chart/my-values/common-values.yaml
patch -p1 <<'EOF'

View File

@@ -1,2 +0,0 @@
rm 'components/my-chart/my-values/common-values.yaml'
patching file 'components/my-chart/my-chart.cue'

View File

@@ -1,8 +0,0 @@
rendered my-chart 0.2.0 for environment staging-eu in 247.658792ms
rendered my-chart 0.1.0 for environment integration-gpu in 272.017ms
rendered my-chart 0.2.0 for environment qa in 279.942875ms
rendered my-chart 0.1.0 for environment prod-us in 285.04225ms
rendered my-chart 0.2.0 for environment integration-non-gpu in 285.188667ms
rendered my-chart 0.1.0 for environment prod-eu in 285.855333ms
rendered my-chart 0.2.0 for environment staging-us in 286.05975ms
rendered platform in 286.136375ms

View File

@@ -1 +0,0 @@
holos render platform --concurrency 1

View File

@@ -1,15 +0,0 @@
rendered my-chart 0.2.0 for environment qa in 167.755583ms
rendered my-chart 0.2.0 for environment staging-eu in 183.818166ms
rendered my-chart 0.2.0 for environment staging-us in 205.0915ms
could not run: component.Artifacts.HolosComponent.generators.0.helm.values.replicaCount: conflicting values 8 and 5 at internal/builder/instance.go:129
component.Artifacts.HolosComponent.generators.0.helm.values.replicaCount: conflicting values 8 and 5:
components/my-chart/my-chart.cue:18:12
components/my-chart/my-chart.cue:39:10
components/my-chart/my-chart.cue:41:10
components/schema.cue:36:2
cue.mod/pkg/github.com/holos-run/holos/api/author/v1alpha5/definitions.cue:115:15
my-values/env-type/prod-values.yaml:2:15
my-values/envs/prod-eu-values.yaml:2:15
could not run: could not render component: could not run command:
holos '--log-level' 'info' '--log-format' 'console' 'render' 'component' '--inject' 'version=prod' '--inject' 'outputBaseDir=environments/prod-eu' '--inject' 'chart=0.1.0' '--inject' 'env=prod-eu' '--inject' 'region=eu' '--inject' 'type=prod' '--inject' 'holos_component_name=my-chart' '--inject' 'holos_component_path=components/my-chart' '--inject' 'holos_component_labels={"env":"prod-eu"}' '--inject' 'holos_component_annotations={"app.holos.run/description":"my-chart 0.1.0 for environment prod-eu"}' './components/my-chart'
exit status 1 at cli/render/render.go:171

View File

@@ -1,8 +0,0 @@
rendered my-chart 0.2.0 for environment staging-eu in 263.07275ms
rendered my-chart 0.1.0 for environment prod-eu in 268.438375ms
rendered my-chart 0.2.0 for environment staging-us in 269.214167ms
rendered my-chart 0.2.0 for environment integration-non-gpu in 272.854334ms
rendered my-chart 0.2.0 for environment qa in 273.286416ms
rendered my-chart 0.1.0 for environment integration-gpu in 273.956417ms
rendered my-chart 0.1.0 for environment prod-us in 274.647041ms
rendered platform in 274.712875ms

View File

@@ -1 +0,0 @@
git status deploy

View File

@@ -1,2 +0,0 @@
On branch work
nothing to commit, working tree clean

View File

@@ -1,34 +0,0 @@
diff --git a/components/my-chart/my-chart.cue b/components/my-chart/my-chart.cue
index cf1dae4..4f01828 100644
--- a/components/my-chart/my-chart.cue
+++ b/components/my-chart/my-chart.cue
@@ -31,23 +31,14 @@ component: #Helm & {
// article uses the ApplicationSet template to specify the namespace.
KustomizeConfig: Kustomization: namespace: parameters.env
- // Migrate the Helm Hierarchy preserving the behavior of over writing values.
- // Migrated from [valueFiles]. Later files win.
+ // Migrate the Helm Hierarchy to CUE. Conflicts are errors.
+ // Migrated from [valueFiles].
//
// [valueFiles]: https://github.com/holos-run/multi-sources-example/blob/v0.1.0/appsets/4-final/all-my-envs-appset-with-version.yaml#L27-L32
- ValueFiles: [{
- name: "version-values.yaml"
- values: valueFiles["my-values/app-version/\(parameters.version)-values.yaml"]
- }, {
- name: "type-values.yaml"
- values: valueFiles["my-values/env-type/\(parameters.type)-values.yaml"]
- }, {
- name: "region-values.yaml"
- values: valueFiles["my-values/regions/\(parameters.region)-values.yaml"]
- }, {
- name: "env-values.yaml"
- values: valueFiles["my-values/envs/\(parameters.env)-values.yaml"]
- }]
+ Values: valueFiles["my-values/app-version/\(parameters.version)-values.yaml"]
+ Values: valueFiles["my-values/env-type/\(parameters.type)-values.yaml"]
+ Values: valueFiles["my-values/regions/\(parameters.region)-values.yaml"]
+ Values: valueFiles["my-values/envs/\(parameters.env)-values.yaml"]
}
// holos represents the output for the holos command line to process. The holos

View File

@@ -1 +0,0 @@
patch -p1 <<'EOF'

View File

@@ -1 +0,0 @@
patching file 'components/my-chart/my-chart.cue'

View File

@@ -1,16 +0,0 @@
diff --git a/components/my-chart/my-values/env-type/prod-values.yaml b/components/my-chart/my-values/env-type/prod-values.yaml
index fef58f4..a3cce4a 100644
--- a/components/my-chart/my-values/env-type/prod-values.yaml
+++ b/components/my-chart/my-values/env-type/prod-values.yaml
@@ -1,11 +1,5 @@
-# Kubernetes settings
-replicaCount: 5
-
# Environment settings
environmentType: production
paypalUrl: "production.paypal.com"
dbUser: "prod_username"
dbPassword: "prod_password"
-
-
-

View File

@@ -1 +0,0 @@
patch -p1 <<'EOF'

View File

@@ -1 +0,0 @@
patching file 'components/my-chart/my-values/env-type/prod-values.yaml'

View File

@@ -1,2 +0,0 @@
git add deploy
git commit -m 'render step1 with helm value file overrides'

View File

@@ -1,18 +0,0 @@
[v0.4.x fa82933] render step1 with helm value file overrides
16 files changed, 512 insertions(+)
create mode 100644 deploy/apps/customer-zzsbbmfc-myapp137-dev14-management-application.gen.yaml
create mode 100644 deploy/apps/customer-zzsbbmfc-myapp137-prod9-management-application.gen.yaml
create mode 100644 deploy/apps/customer-zzsbbmfc-myapp137-test8-management-application.gen.yaml
create mode 100644 deploy/apps/customer-zzsbbmfc-myapp137-uat10-management-application.gen.yaml
create mode 100644 deploy/apps/customer-zzsbbmfc-myapp306-dev12-internal-application.gen.yaml
create mode 100644 deploy/apps/customer-zzsbbmfc-myapp306-prod10-internal-application.gen.yaml
create mode 100644 deploy/apps/customer-zzsbbmfc-myapp306-test7-internal-application.gen.yaml
create mode 100644 deploy/apps/customer-zzsbbmfc-myapp306-uat9-internal-application.gen.yaml
create mode 100644 deploy/clusters/dev12-internal/customers/customer-zzsbbmfc/components/my-app/my-app.gen.yaml
create mode 100644 deploy/clusters/dev14-management/customers/customer-zzsbbmfc/components/my-app/my-app.gen.yaml
create mode 100644 deploy/clusters/prod10-internal/customers/customer-zzsbbmfc/components/my-app/my-app.gen.yaml
create mode 100644 deploy/clusters/prod9-management/customers/customer-zzsbbmfc/components/my-app/my-app.gen.yaml
create mode 100644 deploy/clusters/test7-internal/customers/customer-zzsbbmfc/components/my-app/my-app.gen.yaml
create mode 100644 deploy/clusters/test8-management/customers/customer-zzsbbmfc/components/my-app/my-app.gen.yaml
create mode 100644 deploy/clusters/uat10-management/customers/customer-zzsbbmfc/components/my-app/my-app.gen.yaml
create mode 100644 deploy/clusters/uat9-internal/customers/customer-zzsbbmfc/components/my-app/my-app.gen.yaml

View File

@@ -1,52 +0,0 @@
@if(flatten && step1 || step2 || step3)
package holos
import (
"encoding/json"
// The deployment config.json configs reside in this package.
"holos.example/config/my-app/deployment"
)
// #MyApp defines a re-usable way to manage my-app for each deployment config.
#MyApp: {
// _config represents the concrete values from the deployment config.json
_config: _
// Render components/my-app by default. See render-values.cue for where this
// gets overridden in subsequent steps of the migration.
name: string | *"my-app"
path: "components/\(name)"
// CUE supports constraints, here we constrain environment to one of three
// possible values.
parameters: {
// For use in components/my-app and components/render-values
config: json.Marshal(_config)
// For use in components/componentconfig-gitops.cue
env: _config.env
// The output is the reverse of the deployment config filesystem structure,
// cluster then customer instead of customer then cluster, reflecting the
// perspective of the platform team compared with the perspective of the app
// team. It could be either way.
outputBaseDir: "clusters/\(_config.cluster)/customers/\(_config.customer)"
}
// The app.holos.run/description annotation configures holos render platform
// log messages.
annotations: "app.holos.run/description": string | *"\(name) for \(_config.customer) cluster \(_config.cluster)"
// Selector labels, useful to quickly render combinations of customer,
// cluster, and app
labels: customer: _config.customer
labels: cluster: _config.cluster
labels: app: _config.application
}
// Add one holos component for each config.json file to the
// Platform.spec.components list.
for KEY, CONFIG in deployment.config {
Platform: Components: (KEY): #MyApp & {
_config: CONFIG
}
}

View File

@@ -1,15 +0,0 @@
@if(flatten && step2)
package holos
#MyApp: {
// Renders components/render-values instead of the default components/my-app
// configured in my-app.cue
name: "render-values"
// Bring the config.json values into scope so we can reference them.
_config: _
// Adjust the output of holos render platform so it's clear we're flatting
// values in step 2.
annotations: "app.holos.run/description": "flattened values for \(_config.customer) \(_config.cluster)"
}

Some files were not shown because too many files have changed in this diff Show More