Compare commits
257 Commits
release
...
jeff/435-e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a533d4e7d9 | ||
|
|
f6c06df979 | ||
|
|
524b01a6b3 | ||
|
|
c1a064fd70 | ||
|
|
69f6a8b1eb | ||
|
|
4482930e82 | ||
|
|
12389320a6 | ||
|
|
b024346f19 | ||
|
|
e58433fe08 | ||
|
|
c94d5b69c5 | ||
|
|
65430e3379 | ||
|
|
1945392227 | ||
|
|
b4361e3997 | ||
|
|
1b562118a8 | ||
|
|
578677d9a6 | ||
|
|
49398fe211 | ||
|
|
82c429b8df | ||
|
|
012de360ac | ||
|
|
c5600f2310 | ||
|
|
bc0266e5e3 | ||
|
|
18be14c2ea | ||
|
|
ab49a40246 | ||
|
|
28a0a3625e | ||
|
|
1bdb580aca | ||
|
|
c1b749c6bc | ||
|
|
12ee084759 | ||
|
|
6a2a81e3fc | ||
|
|
204ce788b6 | ||
|
|
abb014ee48 | ||
|
|
e7cd480510 | ||
|
|
bd32ad62a4 | ||
|
|
57789b48e5 | ||
|
|
8476a8748f | ||
|
|
2b89b45fc5 | ||
|
|
23e38f1e7e | ||
|
|
a0f6776358 | ||
|
|
830bb4f804 | ||
|
|
2e02bfe48a | ||
|
|
b0d5fe0072 | ||
|
|
f1ae5db910 | ||
|
|
bc8ad22492 | ||
|
|
4da0740a5e | ||
|
|
ee2d86d7df | ||
|
|
7a94cc5f87 | ||
|
|
0e9b02f337 | ||
|
|
a419b08cca | ||
|
|
04f1a21ee8 | ||
|
|
88663e223b | ||
|
|
2f77b1c09f | ||
|
|
e2ea6deda2 | ||
|
|
2131a99a30 | ||
|
|
9702efca70 | ||
|
|
658453bd76 | ||
|
|
da7430e741 | ||
|
|
57b491065a | ||
|
|
48a40c808f | ||
|
|
228dc3474b | ||
|
|
d83765e980 | ||
|
|
6ca6080a3f | ||
|
|
491efa0f4f | ||
|
|
5c1689b52b | ||
|
|
cd33f7b1dc | ||
|
|
80559b7ca6 | ||
|
|
de9b177c71 | ||
|
|
ebb8d8d44c | ||
|
|
c9994a0851 | ||
|
|
45568f2e6d | ||
|
|
46cb7f5d29 | ||
|
|
f34624e416 | ||
|
|
19690d760a | ||
|
|
35ede4293b | ||
|
|
1b499b1ab6 | ||
|
|
6a3b8da7f2 | ||
|
|
ee9969d409 | ||
|
|
b635c233fa | ||
|
|
5290a2044f | ||
|
|
4d47963b0a | ||
|
|
4c05e4b410 | ||
|
|
851ee2b33d | ||
|
|
063df94fed | ||
|
|
3b2605aacc | ||
|
|
5b5deca5d2 | ||
|
|
9d92c292a6 | ||
|
|
a9e8756687 | ||
|
|
3a205ccce7 | ||
|
|
9597b313a4 | ||
|
|
fafae89403 | ||
|
|
33bc8f8e23 | ||
|
|
04ce0e8710 | ||
|
|
1371e6a84b | ||
|
|
7f7d373b2a | ||
|
|
b78e862d09 | ||
|
|
0866ace8d8 | ||
|
|
86f0d277d6 | ||
|
|
87c537bb0e | ||
|
|
708f58638d | ||
|
|
b590824034 | ||
|
|
17287a3bf8 | ||
|
|
5076f8e7b9 | ||
|
|
49cdf2f9d5 | ||
|
|
7a31849e96 | ||
|
|
1028b8a56f | ||
|
|
dbe832a05c | ||
|
|
6c4561bd84 | ||
|
|
36ade0b5b6 | ||
|
|
ddb6dc8dee | ||
|
|
99feed7c8b | ||
|
|
0ff59b4feb | ||
|
|
b01bcd8a1d | ||
|
|
95d53062da | ||
|
|
779f04b85a | ||
|
|
2a13a65a4d | ||
|
|
27cfd1de6c | ||
|
|
78b35cfa77 | ||
|
|
1321e27208 | ||
|
|
a4ea3cd500 | ||
|
|
e1f654b53c | ||
|
|
2b246a2691 | ||
|
|
7b583f036e | ||
|
|
ed419af340 | ||
|
|
71d293e58e | ||
|
|
ef546f6614 | ||
|
|
b2b7c705a0 | ||
|
|
d23b41cefe | ||
|
|
f886823405 | ||
|
|
d260343278 | ||
|
|
04079385b5 | ||
|
|
7bd24adead | ||
|
|
dab94961ff | ||
|
|
f9c3b328a8 | ||
|
|
abb5b22037 | ||
|
|
5e5a517df3 | ||
|
|
e52f009132 | ||
|
|
48b92b4423 | ||
|
|
745d8e5010 | ||
|
|
1245cc583f | ||
|
|
5631370a48 | ||
|
|
039583a755 | ||
|
|
d838880585 | ||
|
|
8e690b43ee | ||
|
|
a4ceb1cdb2 | ||
|
|
ddb5c0e07b | ||
|
|
a14d3ba0f4 | ||
|
|
f7e0470c48 | ||
|
|
d5c7b82684 | ||
|
|
7d0392e596 | ||
|
|
410b882d1d | ||
|
|
e2648202dc | ||
|
|
44c2fe220a | ||
|
|
fe1ae2fa80 | ||
|
|
8fbee1cbd9 | ||
|
|
982db2cccc | ||
|
|
e9d1240d63 | ||
|
|
03fa4eaaa2 | ||
|
|
e363f3a597 | ||
|
|
8b49ed93be | ||
|
|
d2be9fe278 | ||
|
|
6ec341bbb1 | ||
|
|
13a4305b78 | ||
|
|
0cfce3a823 | ||
|
|
61d7539e1c | ||
|
|
bf84724137 | ||
|
|
9f0de7555c | ||
|
|
650636f944 | ||
|
|
b28c110694 | ||
|
|
5bb3e90b38 | ||
|
|
6a60b613ff | ||
|
|
5862725bab | ||
|
|
8660826b05 | ||
|
|
449df91e33 | ||
|
|
ac59173b30 | ||
|
|
fb75e560fc | ||
|
|
69a064e3ea | ||
|
|
71b72807bb | ||
|
|
0e4ecf9d13 | ||
|
|
ec2fdadd44 | ||
|
|
38b082095f | ||
|
|
f9346ea7c0 | ||
|
|
0f7010288a | ||
|
|
386fb89cc6 | ||
|
|
c5401d6b02 | ||
|
|
f215405643 | ||
|
|
2c79982bd3 | ||
|
|
e5e4de3073 | ||
|
|
ec462f5f0b | ||
|
|
0e95a2812e | ||
|
|
54efe3e24a | ||
|
|
f693f049f4 | ||
|
|
85238710ac | ||
|
|
3ec62d272e | ||
|
|
49afb44fd4 | ||
|
|
a023f135ab | ||
|
|
c6a3a5d689 | ||
|
|
3f1eed3f06 | ||
|
|
7fb7df1441 | ||
|
|
a798111d4d | ||
|
|
3ddb823341 | ||
|
|
70d48592c4 | ||
|
|
006f08df93 | ||
|
|
39e2db5d37 | ||
|
|
ceb293fd8a | ||
|
|
188ff95015 | ||
|
|
5f658e0ba0 | ||
|
|
18b2850d3c | ||
|
|
366a7fe93d | ||
|
|
f71d6d5bd9 | ||
|
|
4529673e93 | ||
|
|
16a6447926 | ||
|
|
111a5944ff | ||
|
|
ff1446dc93 | ||
|
|
67ef990c37 | ||
|
|
6bd54ab856 | ||
|
|
89a23a10fd | ||
|
|
5a939bb6fe | ||
|
|
ee16f14e03 | ||
|
|
7530345620 | ||
|
|
47d60ef86d | ||
|
|
9e9f6efd04 | ||
|
|
fb4a043823 | ||
|
|
d718ab1910 | ||
|
|
c649db18a9 | ||
|
|
b3bddf3ee3 | ||
|
|
77836be250 | ||
|
|
4db670b854 | ||
|
|
d87c919519 | ||
|
|
2184bda2a1 | ||
|
|
a8ab4dabaa | ||
|
|
7175950ce0 | ||
|
|
e186c1be37 | ||
|
|
a998513e34 | ||
|
|
2f821ec33c | ||
|
|
4d54190f2e | ||
|
|
b466ec3457 | ||
|
|
45120797b9 | ||
|
|
e6d25bf5eb | ||
|
|
3ad6e69336 | ||
|
|
9b10e23e43 | ||
|
|
b19022d3ff | ||
|
|
3fd06f594b | ||
|
|
a75338f21c | ||
|
|
6002040360 | ||
|
|
864d7d442b | ||
|
|
791c0a9ffd | ||
|
|
bfe4a8d7c4 | ||
|
|
eaa508a6f8 | ||
|
|
63256a2845 | ||
|
|
937c1dc953 | ||
|
|
11bd50e2eb | ||
|
|
7cfcf55565 | ||
|
|
8b22ba04e1 | ||
|
|
7d5187873b | ||
|
|
03b796312a | ||
|
|
20fb39e49b | ||
|
|
c9c8c13810 | ||
|
|
374cd872e9 | ||
|
|
8db06dd0e1 | ||
|
|
66acadf86d |
18
.claude/settings.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(make:*)",
|
||||
"Bash(holos:*)",
|
||||
"Bash(cue:*)",
|
||||
"Bash(grep:*)",
|
||||
"Bash(cd:*)",
|
||||
"Bash(mkdir:*)",
|
||||
"Bash(find:*)",
|
||||
"Bash(echo:*)",
|
||||
"Bash(head:*)",
|
||||
"Bash(git commit:*)",
|
||||
"Bash(git add:*)"
|
||||
],
|
||||
"deny": []
|
||||
}
|
||||
}
|
||||
26
.cspell.json
@@ -11,6 +11,7 @@
|
||||
"admissionregistration",
|
||||
"alertmanager",
|
||||
"alertmanagers",
|
||||
"anchore",
|
||||
"anthos",
|
||||
"apiextensions",
|
||||
"apimachinery",
|
||||
@@ -28,12 +29,15 @@
|
||||
"authpolicy",
|
||||
"authproxy",
|
||||
"authroutes",
|
||||
"autoload",
|
||||
"automount",
|
||||
"automounting",
|
||||
"autoscaler",
|
||||
"balancereader",
|
||||
"blackbox",
|
||||
"buildplan",
|
||||
"buildplans",
|
||||
"Buildx",
|
||||
"builtinpluginloadingoptions",
|
||||
"cachedir",
|
||||
"cadvisor",
|
||||
@@ -42,6 +46,7 @@
|
||||
"certificaterequest",
|
||||
"certificaterequests",
|
||||
"certificatesigningrequests",
|
||||
"chartmuseum",
|
||||
"clientset",
|
||||
"clsx",
|
||||
"clusterexternalsecret",
|
||||
@@ -56,6 +61,8 @@
|
||||
"Cmds",
|
||||
"CNCF",
|
||||
"CODEOWNERS",
|
||||
"compinit",
|
||||
"componentconfig",
|
||||
"configdir",
|
||||
"configmap",
|
||||
"configmapargs",
|
||||
@@ -68,6 +75,7 @@
|
||||
"creds",
|
||||
"crossplane",
|
||||
"crunchydata",
|
||||
"ctxt",
|
||||
"cuecontext",
|
||||
"cuelang",
|
||||
"customresourcedefinition",
|
||||
@@ -75,7 +83,9 @@
|
||||
"deploymentruntimeconfig",
|
||||
"destinationrule",
|
||||
"destinationrules",
|
||||
"devel",
|
||||
"devicecode",
|
||||
"distroless",
|
||||
"dnsmasq",
|
||||
"dscacheutil",
|
||||
"ecrauthorizationtoken",
|
||||
@@ -94,6 +104,8 @@
|
||||
"fieldmaskpb",
|
||||
"fieldspec",
|
||||
"flushcache",
|
||||
"fluxcd",
|
||||
"fsys",
|
||||
"fullname",
|
||||
"gatewayclass",
|
||||
"gatewayclasses",
|
||||
@@ -120,6 +132,7 @@
|
||||
"grpcroute",
|
||||
"grpcroutes",
|
||||
"grpcurl",
|
||||
"hcfg",
|
||||
"healthchecks",
|
||||
"healthz",
|
||||
"helmchartargs",
|
||||
@@ -137,6 +150,7 @@
|
||||
"httproute",
|
||||
"httproutes",
|
||||
"iampolicygenerator",
|
||||
"incpatch",
|
||||
"Infima",
|
||||
"intstr",
|
||||
"isatty",
|
||||
@@ -146,6 +160,7 @@
|
||||
"jetstack",
|
||||
"jiralert",
|
||||
"Jsonnet",
|
||||
"Kargo",
|
||||
"kfbh",
|
||||
"killall",
|
||||
"kubeadm",
|
||||
@@ -183,6 +198,7 @@
|
||||
"mutatingwebhookconfigurations",
|
||||
"mvdan",
|
||||
"mxcl",
|
||||
"mychart",
|
||||
"myhostname",
|
||||
"myRegistrKeySecretName",
|
||||
"mysecret",
|
||||
@@ -204,6 +220,7 @@
|
||||
"overriden",
|
||||
"Parentspanid",
|
||||
"patchstrategicmerge",
|
||||
"pcfg",
|
||||
"pcjc",
|
||||
"peerauthentication",
|
||||
"peerauthentications",
|
||||
@@ -256,6 +273,7 @@
|
||||
"rolebinding",
|
||||
"rootfs",
|
||||
"ropc",
|
||||
"sboms",
|
||||
"seccomp",
|
||||
"secretargs",
|
||||
"SECRETKEY",
|
||||
@@ -268,6 +286,7 @@
|
||||
"serviceentries",
|
||||
"serviceentry",
|
||||
"servicemonitor",
|
||||
"sigstore",
|
||||
"somevalue",
|
||||
"SOMEVAR",
|
||||
"sortoptions",
|
||||
@@ -280,6 +299,7 @@
|
||||
"stefanprodan",
|
||||
"storageclasses",
|
||||
"streamwatcher",
|
||||
"stretchr",
|
||||
"struct",
|
||||
"structpb",
|
||||
"subcharts",
|
||||
@@ -288,8 +308,10 @@
|
||||
"sysfs",
|
||||
"systemconnect",
|
||||
"tablewriter",
|
||||
"taskset",
|
||||
"templatable",
|
||||
"testscript",
|
||||
"testutil",
|
||||
"thanos",
|
||||
"Tiltfile",
|
||||
"timestamppb",
|
||||
@@ -298,14 +320,18 @@
|
||||
"tokencache",
|
||||
"Tokener",
|
||||
"tolerations",
|
||||
"TOPLEVEL",
|
||||
"Traceid",
|
||||
"traefik",
|
||||
"transactionhistory",
|
||||
"tsdb",
|
||||
"txtar",
|
||||
"typemeta",
|
||||
"udev",
|
||||
"uibutton",
|
||||
"Unmarshal",
|
||||
"unmarshals",
|
||||
"unshallow",
|
||||
"unstage",
|
||||
"untar",
|
||||
"upbound",
|
||||
|
||||
7
.envrc
Normal file
@@ -0,0 +1,7 @@
|
||||
if ! use flake .#default --accept-flake-config --print-build-logs
|
||||
then
|
||||
echo "nix flake could not be built; update flake.nix and run direnv allow/reload" >&2
|
||||
fi
|
||||
|
||||
watch_file nix/*.nix
|
||||
watch_file flake.nix
|
||||
131
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: NeedsInvestigation, Triage
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
<!--
|
||||
Please answer these questions before submitting your issue. Thanks!
|
||||
To ask questions, see https://github.com/holos-run/holos/discussions
|
||||
-->
|
||||
|
||||
### What version of holos are you using (`holos --version`)?
|
||||
|
||||
```
|
||||
0.0.0
|
||||
```
|
||||
|
||||
### Does this issue reproduce with the latest release?
|
||||
|
||||
<!--
|
||||
Get the latest release with:
|
||||
|
||||
brew install holos-run/tap/holos
|
||||
|
||||
Or see https://holos.run/docs/v1alpha5/tutorial/setup/
|
||||
-->
|
||||
|
||||
### What did you do?
|
||||
|
||||
<!--
|
||||
Please provide a testscript that should pass, but does not because of the bug.
|
||||
See the below example.
|
||||
|
||||
You can create a txtar from a directory with:
|
||||
|
||||
holos txtar ./path/to/dir
|
||||
|
||||
Refer to: https://github.com/rogpeppe/go-internal/tree/master/cmd/testscript
|
||||
-->
|
||||
|
||||
Steps to reproduce:
|
||||
|
||||
```shell
|
||||
testscript -v -continue <<EOF
|
||||
```
|
||||
|
||||
```txtar
|
||||
# Have: an error related to the imported Kustomize schemas.
|
||||
# Want: holos show buildplans to work.
|
||||
exec holos --version
|
||||
exec holos init platform v1alpha5 --force
|
||||
# remove the fix to trigger the bug
|
||||
rm cue.mod/pkg/sigs.k8s.io/kustomize/api/types/var.cue
|
||||
# want a BuildPlan shown
|
||||
exec holos show buildplans
|
||||
cmp stdout buildplan.yaml
|
||||
# want this error to go away
|
||||
! stderr 'cannot convert non-concrete value string'
|
||||
-- buildplan.yaml --
|
||||
kind: BuildPlan
|
||||
-- platform/example.cue --
|
||||
package holos
|
||||
|
||||
Platform: Components: example: {
|
||||
name: "example"
|
||||
path: "components/example"
|
||||
}
|
||||
-- components/example/example.cue --
|
||||
package holos
|
||||
|
||||
import "encoding/yaml"
|
||||
|
||||
holos: Component.BuildPlan
|
||||
|
||||
Component: #Kustomize & {
|
||||
KustomizeConfig: Kustomization: patches: [
|
||||
{
|
||||
target: kind: "CustomResourceDefinition"
|
||||
patch: yaml.Marshal([{
|
||||
op: "add"
|
||||
path: "/metadata/annotations/example"
|
||||
value: "example-value"
|
||||
}])
|
||||
},
|
||||
]
|
||||
}
|
||||
```
|
||||
```shell
|
||||
EOF
|
||||
```
|
||||
|
||||
### What did you expect to see?
|
||||
|
||||
The testscript should pass.
|
||||
|
||||
### What did you see instead?
|
||||
|
||||
The testscript fails because of the bug.
|
||||
|
||||
```txt
|
||||
# Have: an error related to the imported Kustomize schemas.
|
||||
# Want: holos show buildplans to work. (0.168s)
|
||||
> exec holos --version
|
||||
[stdout]
|
||||
0.100.1-2-g9b10e23-dirty
|
||||
> exec holos init platform v1alpha5 --force
|
||||
# remove the fix to trigger the bug (0.000s)
|
||||
> rm cue.mod/pkg/sigs.k8s.io/kustomize/api/types/var.cue
|
||||
# want a BuildPlan shown (0.091s)
|
||||
> exec holos show buildplans
|
||||
[stderr]
|
||||
could not run: holos.spec.artifacts.0.transformers.0.kustomize.kustomization.patches.0.target.name: cannot convert non-concrete value string at builder/v1alpha5/builder.go:218
|
||||
holos.spec.artifacts.0.transformers.0.kustomize.kustomization.patches.0.target.name: cannot convert non-concrete value string:
|
||||
$WORK/cue.mod/gen/sigs.k8s.io/kustomize/api/types/var_go_gen.cue:33:2
|
||||
[exit status 1]
|
||||
FAIL: <stdin>:8: unexpected command failure
|
||||
> cmp stdout buildplan.yaml
|
||||
diff stdout buildplan.yaml
|
||||
--- stdout
|
||||
+++ buildplan.yaml
|
||||
@@ -0,0 +1,1 @@
|
||||
+kind: BuildPlan
|
||||
|
||||
FAIL: <stdin>:9: stdout and buildplan.yaml differ
|
||||
# want this error to go away (0.000s)
|
||||
> ! stderr 'cannot convert non-concrete value string'
|
||||
FAIL: <stdin>:11: unexpected match for `cannot convert non-concrete value string` found in stderr: cannot convert non-concrete value string
|
||||
failed run
|
||||
```
|
||||
143
.github/workflows/container.yaml
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
name: Container
|
||||
|
||||
# Only allow actors with write permission to the repository to trigger this
|
||||
# workflow.
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
git_ref:
|
||||
description: 'Git ref to build (e.g., refs/tags/v1.2.3, refs/heads/main)'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
buildx:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
attestations: write
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Set tag from trigger event
|
||||
id: opts
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||
echo "ref=${{ inputs.git_ref }}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "ref=${GITHUB_REF}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ steps.opts.outputs.ref }}
|
||||
- name: SHA
|
||||
id: sha
|
||||
run: echo "sha=$(/usr/bin/git log -1 --format='%H')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Fetch tags
|
||||
run: git fetch --prune --unshallow --tags
|
||||
- name: Set Tags
|
||||
id: tags
|
||||
run: |
|
||||
echo "detail=$(/usr/bin/git describe --tags HEAD)" >> $GITHUB_OUTPUT
|
||||
echo "suffix=$(test -n "$(git status --porcelain)" && echo '-dirty' || echo '')" >> $GITHUB_OUTPUT
|
||||
echo "tag=$(/usr/bin/git describe --tags HEAD)$(test -n "$(git status --porcelain)" && echo '-dirty' || echo '')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Login to ghcr.io
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build and push container images
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
ghcr.io/holos-run/holos:${{ steps.tags.outputs.tag }}
|
||||
ghcr.io/holos-run/holos:${{ steps.sha.outputs.sha }}${{ steps.tags.outputs.suffix }}
|
||||
- name: Setup Cosign to sign container images
|
||||
uses: sigstore/cosign-installer@v3.7.0
|
||||
- name: Sign with GitHub OIDC Token
|
||||
env:
|
||||
DIGEST: ${{ steps.build-and-push.outputs.digest }}
|
||||
run: |
|
||||
cosign sign --yes ghcr.io/holos-run/holos:${{ steps.tags.outputs.tag }}@${DIGEST}
|
||||
cosign sign --yes ghcr.io/holos-run/holos:${{ steps.sha.outputs.sha }}${{ steps.tags.outputs.suffix }}@${DIGEST}
|
||||
|
||||
- uses: actions/create-github-app-token@v1
|
||||
id: app-token
|
||||
with:
|
||||
owner: ${{ github.repository_owner }}
|
||||
app-id: ${{ vars.GORELEASER_APP_ID }}
|
||||
private-key: ${{ secrets.GORELEASER_APP_PRIVATE_KEY }}
|
||||
- name: Get GitHub App User ID
|
||||
id: get-user-id
|
||||
run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
- run: |
|
||||
git config --global user.name '${{ steps.app-token.outputs.app-slug }}[bot]'
|
||||
git config --global user.email '${{ steps.get-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com'
|
||||
- name: Update holos-run/holos-action
|
||||
env:
|
||||
IMAGE: ghcr.io/holos-run/holos:v0.102.1
|
||||
VERSION: ${{ steps.tags.outputs.tag }}
|
||||
USER_ID: ${{ steps.get-user-id.outputs.user-id }}
|
||||
TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
git clone "https://github.com/holos-run/holos-action"
|
||||
cd holos-action
|
||||
git remote set-url origin https://${USER_ID}:${TOKEN}@github.com/holos-run/holos-action
|
||||
docker pull --quiet "${IMAGE}"
|
||||
docker run -v $(pwd):/app --workdir /app --rm "${IMAGE}" \
|
||||
holos cue export --out yaml action.cue -t "version=${VERSION}" > action.yml
|
||||
git add action.yml
|
||||
git commit -m "ci: update holos to ${VERSION} - https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" || (echo "No changes to commit"; exit 0)
|
||||
git push origin HEAD:main HEAD:v0 HEAD:v1
|
||||
|
||||
- name: Login to quay.io
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: quay.io
|
||||
username: ${{ secrets.QUAY_USER }}
|
||||
password: ${{ secrets.QUAY_TOKEN }}
|
||||
- name: Push to quay.io
|
||||
env:
|
||||
DIGEST: ${{ steps.build-and-push.outputs.digest }}
|
||||
run: |
|
||||
# docker push quay.io/holos-run/holos:${{ steps.tags.outputs.tag }}
|
||||
docker pull --quiet ghcr.io/holos-run/holos:${{ steps.tags.outputs.tag }}@${DIGEST}
|
||||
docker tag ghcr.io/holos-run/holos:${{ steps.tags.outputs.tag }}@${DIGEST} \
|
||||
quay.io/holos-run/holos:${{ steps.tags.outputs.tag }}
|
||||
docker push quay.io/holos-run/holos:${{ steps.tags.outputs.tag }}
|
||||
|
||||
docker pull --quiet ghcr.io/holos-run/holos:${{ steps.sha.outputs.sha }}${{ steps.tags.outputs.suffix }}@${DIGEST}
|
||||
docker tag ghcr.io/holos-run/holos:${{ steps.sha.outputs.sha }}${{ steps.tags.outputs.suffix }}@${DIGEST} \
|
||||
quay.io/holos-run/holos:${{ steps.sha.outputs.sha }}${{ steps.tags.outputs.suffix }}
|
||||
docker push quay.io/holos-run/holos:${{ steps.sha.outputs.sha }}${{ steps.tags.outputs.suffix }}
|
||||
- name: Sign quay.io image
|
||||
env:
|
||||
DIGEST: ${{ steps.build-and-push.outputs.digest }}
|
||||
run: |
|
||||
cosign sign --yes quay.io/holos-run/holos:${{ steps.tags.outputs.tag }}@${DIGEST}
|
||||
cosign sign --yes quay.io/holos-run/holos:${{ steps.sha.outputs.sha }}${{ steps.tags.outputs.suffix }}@${DIGEST}
|
||||
|
||||
outputs:
|
||||
tag: ${{ steps.tags.outputs.tag }}
|
||||
detail: ${{ steps.tags.outputs.detail }}
|
||||
2
.github/workflows/dev-deploy.yaml
vendored
@@ -2,7 +2,7 @@ name: Dev Deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ['main', 'dev-deploy']
|
||||
branches: ['dev-deploy']
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
|
||||
4
.github/workflows/golangci-lint.yaml
vendored
@@ -25,6 +25,6 @@ jobs:
|
||||
with:
|
||||
go-version: stable
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v6
|
||||
uses: golangci/golangci-lint-action@v7
|
||||
with:
|
||||
version: v1.60
|
||||
version: v2.1.6
|
||||
|
||||
42
.github/workflows/lint.yaml
vendored
@@ -1,42 +0,0 @@
|
||||
---
|
||||
# https://github.com/golangci/golangci-lint-action?tab=readme-ov-file#how-to-use
|
||||
name: Lint
|
||||
"on":
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- test
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: stable
|
||||
|
||||
## Not needed on ubuntu-latest
|
||||
# - name: Install Packages
|
||||
# run: sudo apt update && sudo apt -qq -y install git curl zip unzip tar bzip2 make
|
||||
|
||||
- name: Install Tools
|
||||
run: make tools
|
||||
|
||||
- name: Lint
|
||||
# golangci-lint runs in a separate workflow.
|
||||
run: make lint -o golangci-lint
|
||||
13
.github/workflows/release.yaml
vendored
@@ -35,6 +35,9 @@ jobs:
|
||||
with:
|
||||
go-version: stable
|
||||
|
||||
- name: Setup Syft
|
||||
uses: anchore/sbom-action/download-syft@1ca97d9028b51809cf6d3c934c3e160716e1b605 # v0.17.5
|
||||
|
||||
# Necessary to run these outside of goreleaser, otherwise
|
||||
# /home/runner/_work/holos/holos/internal/frontend/node_modules/.bin/protoc-gen-connect-query is not in PATH
|
||||
- name: Install Tools
|
||||
@@ -54,11 +57,19 @@ jobs:
|
||||
- name: Git diff
|
||||
run: git diff
|
||||
|
||||
- uses: actions/create-github-app-token@v1
|
||||
id: app-token
|
||||
with:
|
||||
owner: ${{ github.repository_owner }}
|
||||
app-id: ${{ vars.GORELEASER_APP_ID }}
|
||||
private-key: ${{ secrets.GORELEASER_APP_PRIVATE_KEY }}
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v5
|
||||
with:
|
||||
distribution: goreleaser
|
||||
version: latest
|
||||
version: '~> v2'
|
||||
args: release --clean
|
||||
env:
|
||||
HOMEBREW_TAP_GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
17
.github/workflows/spelling.yaml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Spelling
|
||||
"on":
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- test
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
cspell:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: ./hack/cspell
|
||||
11
.github/workflows/test.yaml
vendored
@@ -28,19 +28,16 @@ jobs:
|
||||
with:
|
||||
go-version: stable
|
||||
|
||||
- name: Install Packages
|
||||
run: sudo apt update && sudo apt -qq -y install git curl zip unzip tar bzip2 make
|
||||
|
||||
- name: Set up Helm
|
||||
uses: azure/setup-helm@v4
|
||||
with:
|
||||
version: '3.17.3'
|
||||
|
||||
- name: Set up Kubectl
|
||||
uses: azure/setup-kubectl@v4
|
||||
|
||||
- name: Install Tools
|
||||
run: |
|
||||
set -x
|
||||
make tools
|
||||
- name: Install holos
|
||||
run: make install
|
||||
|
||||
- name: Test
|
||||
run: ./scripts/test
|
||||
|
||||
8
.gitignore
vendored
@@ -12,3 +12,11 @@ tmp/
|
||||
/holos-k3d/
|
||||
/holos-infra/
|
||||
node_modules/
|
||||
.tmp/
|
||||
|
||||
# nix
|
||||
/.direnv/
|
||||
result
|
||||
|
||||
# claude
|
||||
/.claude/settings.local.json
|
||||
|
||||
@@ -1,2 +1,20 @@
|
||||
run:
|
||||
timeout: 5m
|
||||
version: "2"
|
||||
linters:
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
- comments
|
||||
- common-false-positives
|
||||
- legacy
|
||||
- std-error-handling
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
formatters:
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
|
||||
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
|
||||
|
||||
version: 1
|
||||
version: 2
|
||||
|
||||
before:
|
||||
hooks:
|
||||
@@ -50,3 +50,39 @@ changelog:
|
||||
exclude:
|
||||
- "^docs:"
|
||||
- "^test:"
|
||||
|
||||
source:
|
||||
enabled: true
|
||||
name_template: '{{ .ProjectName }}_{{ .Version }}_source_code'
|
||||
|
||||
sboms:
|
||||
- id: source
|
||||
artifacts: source
|
||||
documents:
|
||||
- "{{ .ProjectName }}_{{ .Version }}_sbom.spdx.json"
|
||||
|
||||
brews:
|
||||
- name: holos
|
||||
repository:
|
||||
owner: holos-run
|
||||
name: homebrew-tap
|
||||
branch: main
|
||||
token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"
|
||||
directory: Formula
|
||||
homepage: "https://holos.run"
|
||||
description: "Holos CLI"
|
||||
dependencies:
|
||||
- name: helm
|
||||
type: optional
|
||||
- name: kubectl
|
||||
type: optional
|
||||
install: |
|
||||
bin.install "holos"
|
||||
bash_output = Utils.safe_popen_read(bin/"holos", "completion", "bash")
|
||||
(bash_completion/"holos").write bash_output
|
||||
zsh_output = Utils.safe_popen_read(bin/"holos", "completion", "zsh")
|
||||
(zsh_completion/"_holos").write zsh_output
|
||||
fish_output = Utils.safe_popen_read(bin/"holos", "completion", "fish")
|
||||
(fish_completion/"holos.fish").write fish_output
|
||||
test: |
|
||||
system "#{bin}/holos --version"
|
||||
|
||||
13
.ko.yaml
@@ -1,13 +0,0 @@
|
||||
# Refer to https://ko.build/configuration/#overriding-go-build-settings
|
||||
builds:
|
||||
- id: holos
|
||||
dir: .
|
||||
main: ./cmd/holos
|
||||
env:
|
||||
- GOPRIVATE=github.com/holos-run/\*
|
||||
ldflags:
|
||||
- -s
|
||||
- -w
|
||||
- -X
|
||||
# Makefile provides GIT_DETAIL and GIT_SUFFIX.
|
||||
- github.com/holos-run/holos/version.GitDescribe={{.Env.GIT_DETAIL}}{{.Env.GIT_SUFFIX}}
|
||||
116
CLAUDE.md
Normal file
@@ -0,0 +1,116 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
Holos is a configuration management tool for Kubernetes that implements the rendered manifests pattern using CUE. It unifies Helm charts, Kustomize bases, and raw Kubernetes manifests into a single, declarative pipeline.
|
||||
|
||||
### Core Flow
|
||||
```
|
||||
Platform → Components → BuildPlan → Generators → Transformers → Validators → Manifests
|
||||
```
|
||||
|
||||
## Key Commands
|
||||
|
||||
```bash
|
||||
# Development
|
||||
make build # Build the binary
|
||||
make install # Install binary (REQUIRED before testing holos commands)
|
||||
make test # Run all tests
|
||||
make fmt # Format Go code
|
||||
make lint # Run linters
|
||||
make coverage # Generate coverage report
|
||||
|
||||
# Documentation
|
||||
make update-docs # Update generated docs
|
||||
make website # Build the documentation website
|
||||
|
||||
# Usage (run 'make install' first to test code changes)
|
||||
holos render platform # Render entire platform
|
||||
holos render component # Render single component
|
||||
holos show buildplans # Show build plans
|
||||
holos init platform # Initialize new platform
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
### Directory Structure
|
||||
- `/api/` - API definitions (v1alpha5 stable, v1alpha6 in development)
|
||||
- `/cmd/` - CLI entry point
|
||||
- `/internal/cli/` - Command implementations
|
||||
- `/internal/component/` - Component handling logic
|
||||
- `/internal/platform/` - Platform handling logic
|
||||
- `/internal/generate/` - Code generation
|
||||
|
||||
### Key Files
|
||||
- `/internal/cli/render/render.go` - Core render logic
|
||||
- `/internal/component/component.go` - Component processing
|
||||
- `/api/core/v1alpha*/types.go` - API type definitions
|
||||
|
||||
### Component Types
|
||||
1. **Helm** - Wraps Helm charts
|
||||
2. **Kustomize** - Wraps Kustomize bases
|
||||
3. **Kubernetes** - Raw Kubernetes manifests
|
||||
|
||||
## CUE Patterns
|
||||
|
||||
Components are defined in CUE:
|
||||
```cue
|
||||
package holos
|
||||
|
||||
holos: Component.BuildPlan
|
||||
|
||||
Component: #Helm & {
|
||||
Name: "example"
|
||||
Chart: {
|
||||
version: "1.0.0"
|
||||
repository: {
|
||||
name: "example"
|
||||
url: "https://charts.example.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
- Unit tests: `*_test.go` files colocated with source
|
||||
- Integration tests: `/cmd/holos/tests/`
|
||||
- Example platforms: `/internal/testutil/fixtures/`
|
||||
- Run single test: `go test -run TestName ./path/to/package`
|
||||
|
||||
## Development Patterns
|
||||
|
||||
1. Error handling: Prefer `errors.Format()` from `/internal/errors/` over `fmt.Errorf()`
|
||||
2. Logging: Use structured `slog`, get logger with `logger.FromContext(ctx)`
|
||||
3. CLI commands: Follow Cobra patterns in `/internal/cli/`
|
||||
4. CUE formatting: Always run `cue fmt` on CUE files
|
||||
5. Go formatting: Always run `go fmt` on go files
|
||||
6. Develop against v1alpha6 packages.
|
||||
7. Commits: Use the package name as the first word in the commit, lower case. Commit without asking permission. Always run `make lint` and `make test` before committing.
|
||||
|
||||
## Version Management
|
||||
|
||||
- Version files: `/version/embedded/{major,minor,patch}`
|
||||
- Bump version: `make bump`
|
||||
- API versions: v1alpha5 (stable), v1alpha6 (development)
|
||||
|
||||
## Key Concepts
|
||||
|
||||
- **Platform**: Top-level configuration containing all components
|
||||
- **Component**: Unit of configuration (DAG of Tasks producing deployment configs for one component)
|
||||
- **TaskSet**: DAG of Tasks (Similar to how make tasks behave)
|
||||
- **BuildPlan**: Instructions for building a component. Deprecated in v1alpha6, use TaskSet instead.
|
||||
- **Generator**: Creates manifests (Helm, Kustomize, etc.) author schema only in v1alpha6
|
||||
- **Transformer**: Modifies generated manifests, author schema only in v1alpha6
|
||||
- **Validator**: Validates final manifests, author schema only in v1alpha6
|
||||
|
||||
## Resources
|
||||
|
||||
- Tutorials: `/doc/md/tutorial/`
|
||||
- Platform templates: `/internal/generate/platforms/`
|
||||
- Test fixtures: `/internal/testutil/fixtures/`
|
||||
- Core schemas: `/api/core/` (Abstraction over low level data pipeline tasks)
|
||||
- Author schemas: `/api/author/` (User facing abstractions over core Schemas)
|
||||
- Task planning documents are located in the `/tasks/` directory
|
||||
39
Dockerfile
@@ -1,8 +1,31 @@
|
||||
FROM quay.io/holos-run/debian:bullseye AS final
|
||||
USER root
|
||||
WORKDIR /app
|
||||
ADD bin bin
|
||||
RUN chown -R app: /app
|
||||
# Kubernetes requires the user to be numeric
|
||||
USER 8192
|
||||
ENTRYPOINT bin/holos server
|
||||
FROM registry.k8s.io/kubectl:v1.31.0 AS kubectl
|
||||
# https://github.com/GoogleContainerTools/distroless
|
||||
FROM golang:1.23 AS build
|
||||
|
||||
WORKDIR /go/src/app
|
||||
COPY . .
|
||||
|
||||
RUN CGO_ENABLED=0 make install
|
||||
RUN CGO_ENABLED=0 go install sigs.k8s.io/kustomize/kustomize/v5
|
||||
|
||||
# Install helm to /usr/local/bin/helm
|
||||
# https://helm.sh/docs/intro/install/#from-script
|
||||
# https://holos.run/docs/v1alpha5/tutorial/setup/#dependencies
|
||||
RUN curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 \
|
||||
&& chmod 700 get_helm.sh \
|
||||
&& DESIRED_VERSION=v3.16.2 ./get_helm.sh \
|
||||
&& rm -f get_helm.sh
|
||||
|
||||
COPY --from=kubectl /bin/kubectl /usr/local/bin/
|
||||
|
||||
# distroless
|
||||
FROM gcr.io/distroless/static-debian12 AS final
|
||||
COPY --from=build \
|
||||
/go/bin/holos \
|
||||
/go/bin/kustomize \
|
||||
/usr/local/bin/kubectl \
|
||||
/usr/local/bin/helm \
|
||||
/bin/
|
||||
|
||||
# Usage: docker run -v $(pwd):/app --workdir /app --rm -it quay.io/holos-run/holos holos render platform
|
||||
CMD ["/bin/holos"]
|
||||
|
||||
45
Makefile
@@ -32,17 +32,20 @@ bump: bumppatch
|
||||
.PHONY: bumppatch
|
||||
bumppatch: ## Bump the patch version.
|
||||
scripts/bump patch
|
||||
HOLOS_UPDATE_SCRIPTS=1 scripts/test
|
||||
|
||||
.PHONY: bumpminor
|
||||
bumpminor: ## Bump the minor version.
|
||||
scripts/bump minor
|
||||
scripts/bump patch 0
|
||||
HOLOS_UPDATE_SCRIPTS=1 scripts/test
|
||||
|
||||
.PHONY: bumpmajor
|
||||
bumpmajor: ## Bump the major version.
|
||||
scripts/bump major
|
||||
scripts/bump minor 0
|
||||
scripts/bump patch 0
|
||||
HOLOS_UPDATE_SCRIPTS=1 scripts/test
|
||||
|
||||
.PHONY: show-version
|
||||
show-version: ## Print the full version.
|
||||
@@ -58,8 +61,8 @@ tidy: ## Tidy go module.
|
||||
|
||||
.PHONY: fmt
|
||||
fmt: ## Format code.
|
||||
cd internal/generate/platforms && cue fmt ./...
|
||||
go fmt ./...
|
||||
cue fmt ./...
|
||||
|
||||
.PHONY: vet
|
||||
vet: ## Vet Go code.
|
||||
@@ -75,10 +78,11 @@ build: ## Build holos executable.
|
||||
@echo "GOPATH=${GOPATH}"
|
||||
go build -trimpath -o bin/$(BIN_NAME) -ldflags $(LD_FLAGS) $(REPO_PATH)/cmd/$(BIN_NAME)
|
||||
|
||||
linux: ## Build holos executable for tilt.
|
||||
@echo "building ${BIN_NAME}.linux ${VERSION}"
|
||||
.PHONY: debug
|
||||
debug: ## Build debug executable.
|
||||
@echo "building ${BIN_NAME}-debug ${VERSION}"
|
||||
@echo "GOPATH=${GOPATH}"
|
||||
GOOS=linux go build -trimpath -o bin/$(BIN_NAME).linux -ldflags $(LD_FLAGS) $(REPO_PATH)/cmd/$(BIN_NAME)
|
||||
go build -o bin/$(BIN_NAME)-debug $(REPO_PATH)/cmd/$(BIN_NAME)
|
||||
|
||||
.PHONY: install
|
||||
install: build ## Install holos to GOPATH/bin
|
||||
@@ -97,9 +101,7 @@ golangci-lint:
|
||||
golangci-lint run
|
||||
|
||||
.PHONY: lint
|
||||
lint: golangci-lint ## Run linters.
|
||||
buf lint
|
||||
cd internal/frontend/holos && ng lint
|
||||
lint: vet golangci-lint ## Run linters.
|
||||
./hack/cspell
|
||||
|
||||
.PHONY: coverage
|
||||
@@ -111,41 +113,18 @@ snapshot: ## Go release snapshot
|
||||
goreleaser release --snapshot --clean
|
||||
|
||||
.PHONY: tools
|
||||
tools: go-deps frontend-deps website-deps ## install tool dependencies
|
||||
tools: go-deps website-deps ## install tool dependencies
|
||||
|
||||
.PHONY: go-deps
|
||||
go-deps: ## tool versions pinned in tools.go
|
||||
go install cuelang.org/go/cmd/cue
|
||||
go install github.com/bufbuild/buf/cmd/buf
|
||||
go install github.com/fullstorydev/grpcurl/cmd/grpcurl
|
||||
go install google.golang.org/protobuf/cmd/protoc-gen-go
|
||||
go install connectrpc.com/connect/cmd/protoc-gen-connect-go
|
||||
go install honnef.co/go/tools/cmd/staticcheck
|
||||
go install golang.org/x/tools/cmd/godoc
|
||||
go install github.com/princjef/gomarkdoc/cmd/gomarkdoc
|
||||
go install github.com/google/ko
|
||||
# curl https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | bash
|
||||
|
||||
.PHONY: frontend-deps
|
||||
frontend-deps: ## Install Angular deps for go generate
|
||||
cd internal/frontend/holos && npm install
|
||||
|
||||
.PHONY: website-deps
|
||||
website-deps: ## Install Docusaurus deps for go generate
|
||||
cd doc/website && npm install
|
||||
|
||||
.PHONY: image # refer to .ko.yaml as well
|
||||
image: ## Container image build for workflows/publish.yaml
|
||||
KO_DOCKER_REPO=$(DOCKER_REPO) GIT_DETAIL=$(GIT_DETAIL) GIT_SUFFIX=$(GIT_SUFFIX) ko build --platform=all --bare ./cmd/holos --tags $(GIT_DETAIL)$(GIT_SUFFIX) --tags latest
|
||||
|
||||
.PHONY: prod-deploy
|
||||
prod-deploy: install image ## deploy to PROD
|
||||
GIT_DETAIL=$(GIT_DETAIL) GIT_SUFFIX=$(GIT_SUFFIX) bash ./hack/deploy
|
||||
|
||||
.PHONY: dev-deploy
|
||||
dev-deploy: install image ## deploy to dev
|
||||
GIT_DETAIL=$(GIT_DETAIL) GIT_SUFFIX=$(GIT_SUFFIX) bash ./hack/deploy-dev
|
||||
|
||||
.PHONY: website
|
||||
website: ## Build website
|
||||
./hack/build-website
|
||||
@@ -154,6 +133,10 @@ website: ## Build website
|
||||
unity: ## https://cuelabs.dev/unity/
|
||||
./scripts/unity
|
||||
|
||||
.PHONY: update-docs
|
||||
update-docs: ## Update doc examples
|
||||
HOLOS_UPDATE_SCRIPTS=1 go test -v ./doc/md/...
|
||||
|
||||
.PHONY: help
|
||||
help: ## Display this help menu.
|
||||
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
|
||||
|
||||
129
README.md
@@ -1,35 +1,130 @@
|
||||
## Holos - A Holistic Development Platform
|
||||
# Holos
|
||||
|
||||
<img width="50%"
|
||||
align="right"
|
||||
style="display: block; margin: 40px auto;"
|
||||
src="https://openinfrastructure.co/blog/2016/02/27/logo/logorectangle.png">
|
||||
|
||||
Building and maintaining a software development platform is a complex and time
|
||||
consuming endeavour. Organizations often dedicate a team of 3-4 who need 6-12
|
||||
months to build the platform.
|
||||
[Holos] is a configuration management tool for Kubernetes implementing the
|
||||
[rendered manifests pattern]. It handles configurations ranging from single
|
||||
resources to multi-cluster platforms across regions.
|
||||
|
||||
Holos is a tool and a reference platform to reduce the complexity and speed up
|
||||
the process of building a modern, cloud native software development platform.
|
||||
Key components:
|
||||
- Platform schemas defining component integration
|
||||
- Building blocks unifying Helm, Kustomize and Kubernetes configs with CUE
|
||||
- BuildPlan pipeline for generating, transforming and validating manifests
|
||||
|
||||
- **Accelerate new projects** - Reduce time to market and operational complexity by starting your new project on top of the Holos reference platform.
|
||||
- **Modernize existing projects** - Incrementally incorporate your existing platform services into Holos for simpler integration.
|
||||
- **Unified configuration model** - Increase safety and reduce the risk of config changes with CUE.
|
||||
- **First class Helm and Kustomize support** - Leverage and reuse your existing investment in existing configuration tools such as Helm and Kustomize.
|
||||
- **Modern Authentication and Authorization** - Holos seamlessly integrates platform identity and access management with zero-trust beyond corp style authorization policy.
|
||||
```mermaid
|
||||
---
|
||||
title: Rendering Overview
|
||||
---
|
||||
graph LR
|
||||
Platform[<a href="https://holos.run/docs/v1alpha5/api/author/#Platform">Platform</a>]
|
||||
Component[<a href="https://holos.run/docs/v1alpha5/api/author/#ComponentConfig">Components</a>]
|
||||
|
||||
## Quick Installation
|
||||
Helm[<a href="https://holos.run/docs/v1alpha5/api/author/#Helm">Helm</a>]
|
||||
Kustomize[<a href="https://holos.run/docs/v1alpha5/api/author/#Kustomize">Kustomize</a>]
|
||||
Kubernetes[<a href="https://holos.run/docs/v1alpha5/api/author/#Kubernetes">Kubernetes</a>]
|
||||
|
||||
```console
|
||||
go install github.com/holos-run/holos/cmd/holos@latest
|
||||
BuildPlan[<a href="https://holos.run/docs/v1alpha5/api/core/#BuildPlan">BuildPlan</a>]
|
||||
|
||||
ResourcesArtifact[<a href="https://holos.run/docs/v1alpha5/api/core/#Artifact">Resources<br/>Artifact</a>]
|
||||
GitOpsArtifact[<a href="https://holos.run/docs/v1alpha5/api/core/#Artifact">GitOps<br/>Artifact</a>]
|
||||
|
||||
Generators[<a href="https://holos.run/docs/v1alpha5/api/core/#Generator">Generators</a>]
|
||||
Transformers[<a href="https://holos.run/docs/v1alpha5/api/core/#Transformer">Transformers</a>]
|
||||
Validators[<a href="https://holos.run/docs/v1alpha5/api/core/#Validator">Validators</a>]
|
||||
Files[Manifest<br/>Files]
|
||||
|
||||
Platform --> Component
|
||||
Component --> Helm --> BuildPlan
|
||||
Component --> Kubernetes --> BuildPlan
|
||||
Component --> Kustomize --> BuildPlan
|
||||
|
||||
BuildPlan --> ResourcesArtifact --> Generators
|
||||
BuildPlan --> GitOpsArtifact --> Generators
|
||||
|
||||
Generators --> Transformers --> Validators --> Files
|
||||
```
|
||||
|
||||
## Docs and Support
|
||||
## Setup
|
||||
|
||||
The documentation for developing and using Holos is available at: https://holos.run
|
||||
```shell
|
||||
brew install holos-run/tap/holos
|
||||
```
|
||||
|
||||
For discussion and support, [open a discussion](https://github.com/orgs/holos-run/discussions/new/choose).
|
||||
Refer to [setup] for other installation methods and dependencies.
|
||||
|
||||
## Example
|
||||
|
||||
See our [tutorial] for a complete hello world example.
|
||||
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
holos: Component.BuildPlan
|
||||
|
||||
Component: #Helm & {
|
||||
Name: "podinfo"
|
||||
Chart: {
|
||||
version: "6.6.2"
|
||||
repository: {
|
||||
name: "podinfo"
|
||||
url: "https://stefanprodan.github.io/podinfo"
|
||||
}
|
||||
}
|
||||
Values: ui: {
|
||||
message: string | *"Hello World" @tag(message, type=string)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Organizational Role
|
||||
|
||||
Platform engineers use Holos to generate Kubernetes manifests, both locally and
|
||||
in CI pipelines. The manifests are committed to version control and deployed via
|
||||
GitOps tools like ArgoCD or Flux.
|
||||
|
||||
Holos integrates seamlessly with existing Helm charts, Kustomize bases, and
|
||||
other version-controlled configurations.
|
||||
|
||||
## Advantages of Holos
|
||||
|
||||
### Safe
|
||||
|
||||
Holos leverages [CUE] for strong typing and validation of configuration data,
|
||||
ensuring consistent output from Helm and other tools.
|
||||
|
||||
### Consistent
|
||||
|
||||
A unified pipeline processes all configurations - whether from CUE, Helm, or
|
||||
Kustomize - through the same well-defined stages.
|
||||
|
||||
### Flexible
|
||||
|
||||
Composable building blocks for generation, transformation, validation and
|
||||
integration let teams assemble workflows that match their needs.
|
||||
|
||||
The core is intentionally unopinionated about platform configuration patterns.
|
||||
Common needs like environments and clusters are provided as customizable
|
||||
[topics] recipes rather than enforced structures.
|
||||
|
||||
## Getting Help
|
||||
|
||||
Get support through our [Discord] channel or [GitHub discussions]. Configuration
|
||||
challenges arise at all experience levels - we welcome your questions and are
|
||||
here to help.
|
||||
|
||||
## License
|
||||
|
||||
Holos is licensed under Apache 2.0 as found in the [LICENSE file](LICENSE).
|
||||
|
||||
[Holos]: https://holos.run/docs/overview/
|
||||
[rendered manifests pattern]: https://akuity.io/blog/the-rendered-manifests-pattern
|
||||
[CUE]: https://cuelang.org/
|
||||
[Discord]: https://discord.gg/JgDVbNpye7
|
||||
[GitHub discussions]: https://github.com/holos-run/holos/discussions
|
||||
[Why CUE for Configuration]: https://holos.run/blog/why-cue-for-configuration/
|
||||
[tutorial]: https://holos.run/docs/overview/
|
||||
[setup]: https://holos.run/docs/setup/
|
||||
[topics]: https://holos.run/docs/topics/
|
||||
|
||||
110
Tiltfile
@@ -1,110 +0,0 @@
|
||||
# -*- mode: Python -*-
|
||||
# This Tiltfile manages a Go project with live reload in Kubernetes
|
||||
|
||||
listen_port = 3000
|
||||
metrics_port = 9090
|
||||
|
||||
# Use our wrapper to set the kube namespace
|
||||
if os.getenv('TILT_WRAPPER') != '1':
|
||||
fail("could not run, ./hack/tilt/bin/tilt was not used to start tilt")
|
||||
|
||||
# Resource ids
|
||||
holos_backend = 'Holos Server'
|
||||
compile_id = 'Go Build'
|
||||
|
||||
# Default Registry.
|
||||
# See: https://github.com/tilt-dev/tilt.build/blob/master/docs/choosing_clusters.md#manual-configuration
|
||||
# Note, Tilt will append the image name to the registry uri path
|
||||
# default_registry('{account}.dkr.ecr.{region}.amazonaws.com/holos-run/holos'.format(account=aws_account, region=aws_region))
|
||||
|
||||
# Set a name prefix specific to the user. Multiple developers share the tilt-holos namespace.
|
||||
developer = os.getenv('USER')
|
||||
holos_server = 'holos'
|
||||
|
||||
# We always develop against the k3d-workload cluster
|
||||
os.putenv('KUBECONFIG', os.path.abspath('./hack/tilt/kubeconfig'))
|
||||
|
||||
# Extensions are open-source, pre-packaged functions that extend Tilt
|
||||
#
|
||||
# More info: https://github.com/tilt-dev/tilt-extensions
|
||||
# More info: https://docs.tilt.dev/extensions.html
|
||||
load('ext://restart_process', 'docker_build_with_restart')
|
||||
load('ext://k8s_attach', 'k8s_attach')
|
||||
load('ext://git_resource', 'git_checkout')
|
||||
load('ext://uibutton', 'cmd_button')
|
||||
|
||||
# Paths edited by the developer Tilt watches to trigger compilation.
|
||||
# Generated files should be excluded to avoid an infinite build loop.
|
||||
developer_paths = [
|
||||
'./cmd',
|
||||
'./internal/server',
|
||||
'./internal/ent/schema',
|
||||
'./frontend/package-lock.json',
|
||||
'./frontend/src',
|
||||
'./go.mod',
|
||||
'./pkg',
|
||||
'./service/holos',
|
||||
]
|
||||
|
||||
# Builds the holos executable GOOS=linux
|
||||
local_resource(compile_id, 'make linux', deps=developer_paths)
|
||||
|
||||
# Build Docker image
|
||||
# Tilt will automatically associate image builds with the resource(s)
|
||||
# that reference them (e.g. via Kubernetes or Docker Compose YAML).
|
||||
#
|
||||
# More info: https://docs.tilt.dev/api.html#api.docker_build
|
||||
#
|
||||
docker_build_with_restart(
|
||||
'k3d-registry.holos.localhost:5100/holos',
|
||||
context='.',
|
||||
entrypoint=[
|
||||
'/app/bin/holos.linux',
|
||||
'server',
|
||||
'--log-format=text',
|
||||
'--oidc-issuer=https://login.holos.run',
|
||||
'--oidc-audience=275804490387516853@holos_quickstart', # auth proxy
|
||||
'--oidc-audience=270319630705329162@holos_platform', # holos cli
|
||||
],
|
||||
dockerfile='./Dockerfile',
|
||||
only=['./bin'],
|
||||
# (Recommended) Updating a running container in-place
|
||||
# https://docs.tilt.dev/live_update_reference.html
|
||||
live_update=[
|
||||
# Sync files from host to container
|
||||
sync('./bin/', '/app/bin/'),
|
||||
],
|
||||
)
|
||||
|
||||
# Troubleshooting
|
||||
def resource_name(id):
|
||||
print('resource: {}'.format(id))
|
||||
return id.name
|
||||
|
||||
workload_to_resource_function(resource_name)
|
||||
|
||||
# Customize a Kubernetes resource
|
||||
# By default, Kubernetes resource names are automatically assigned
|
||||
# based on objects in the YAML manifests, e.g. Deployment name.
|
||||
#
|
||||
# Tilt strives for sane defaults, so calling k8s_resource is
|
||||
# optional, and you only need to pass the arguments you want to
|
||||
# override.
|
||||
#
|
||||
# More info: https://docs.tilt.dev/api.html#api.k8s_resource
|
||||
#
|
||||
k8s_yaml(blob(str(read_file('./hack/tilt/k8s/dev-holos-app/deployment.yaml'))))
|
||||
|
||||
# Backend server process
|
||||
k8s_resource(
|
||||
workload=holos_server,
|
||||
new_name=holos_backend,
|
||||
objects=[],
|
||||
resource_deps=[compile_id],
|
||||
links=[
|
||||
link('https://app.holos.localhost/ui/'.format(developer), "Holos Web UI")
|
||||
],
|
||||
)
|
||||
|
||||
# Database
|
||||
print("✨ Tiltfile evaluated")
|
||||
@@ -1,226 +0,0 @@
|
||||
// Package v1alpha3 contains CUE definitions intended as convenience wrappers
|
||||
// around the core data types defined in package core. The purpose of these
|
||||
// wrappers is to make life easier for platform engineers by reducing boiler
|
||||
// plate code and generating component build plans in a consistent manner.
|
||||
package v1alpha3
|
||||
|
||||
import (
|
||||
core "github.com/holos-run/holos/api/core/v1alpha3"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
//go:generate ../../../hack/gendoc
|
||||
|
||||
// Component represents the fields common the different kinds of component. All
|
||||
// components have a name, support mixing in resources, and produce a BuildPlan.
|
||||
type ComponentFields struct {
|
||||
// Name represents the Component name.
|
||||
Name string
|
||||
// Resources are kubernetes api objects to mix into the output.
|
||||
Resources map[string]any
|
||||
// ArgoConfig represents the ArgoCD GitOps configuration for this Component.
|
||||
ArgoConfig ArgoConfig
|
||||
// BuildPlan represents the derived BuildPlan for the Holos cli to render.
|
||||
BuildPlan core.BuildPlan
|
||||
}
|
||||
|
||||
// Helm provides a BuildPlan via the Output field which contains one HelmChart
|
||||
// from package core. Useful as a convenience wrapper to render a HelmChart
|
||||
// with optional mix-in resources and Kustomization post-processing.
|
||||
type Helm struct {
|
||||
ComponentFields `json:",inline"`
|
||||
|
||||
// Version represents the chart version.
|
||||
Version string
|
||||
// Namespace represents the helm namespace option when rendering the chart.
|
||||
Namespace string
|
||||
|
||||
// Repo represents the chart repository
|
||||
Repo struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
// Values represents data to marshal into a values.yaml for helm.
|
||||
Values interface{} `cue:"{...}"`
|
||||
|
||||
// Chart represents the derived HelmChart for inclusion in the BuildPlan
|
||||
// Output field value. The default HelmChart field values are derived from
|
||||
// other Helm field values and should be sufficient for most use cases.
|
||||
Chart core.HelmChart
|
||||
|
||||
// EnableKustomizePostProcessor processes helm output with kustomize if true.
|
||||
EnableKustomizePostProcessor bool `cue:"true | *false"`
|
||||
|
||||
// KustomizeFiles represents additional files to include in a Kustomization
|
||||
// resources list. Useful to patch helm output. The implementation is a
|
||||
// struct with filename keys and structs as values. Holos encodes the struct
|
||||
// value to yaml then writes the result to the filename key. Component
|
||||
// authors may then reference the filename in the kustomization.yaml resources
|
||||
// or patches lists.
|
||||
// Requires EnableKustomizePostProcessor: true.
|
||||
KustomizeFiles map[string]any `cue:"{[string]: {...}}"`
|
||||
|
||||
// KustomizePatches represents patches to apply to the helm output. Requires
|
||||
// EnableKustomizePostProcessor: true.
|
||||
KustomizePatches map[core.InternalLabel]any `cue:"{[string]: {...}}"`
|
||||
|
||||
// KustomizeResources represents additional resources files to include in the
|
||||
// kustomize resources list.
|
||||
KustomizeResources map[string]any `cue:"{[string]: {...}}"`
|
||||
}
|
||||
|
||||
// Kustomize provides a BuildPlan via the Output field which contains one
|
||||
// KustomizeBuild from package core.
|
||||
type Kustomize struct {
|
||||
ComponentFields `json:",inline"`
|
||||
// Kustomization represents the kustomize build plan for holos to render.
|
||||
Kustomization core.KustomizeBuild
|
||||
}
|
||||
|
||||
// Kubernetes provides a BuildPlan via the Output field which contains inline
|
||||
// API Objects provided directly from CUE.
|
||||
type Kubernetes struct {
|
||||
ComponentFields `json:",inline"`
|
||||
// Objects represents the kubernetes api objects for the Component.
|
||||
Objects core.KubernetesObjects
|
||||
}
|
||||
|
||||
// ArgoConfig represents the ArgoCD GitOps configuration for a Component.
|
||||
// Useful to define once at the root of the Platform configuration and reuse
|
||||
// across all Components.
|
||||
type ArgoConfig struct {
|
||||
// Enabled causes holos to render an ArgoCD Application resource for GitOps if true.
|
||||
Enabled bool `cue:"true | *false"`
|
||||
// ClusterName represents the cluster within the platform the Application
|
||||
// resource is intended for.
|
||||
ClusterName string
|
||||
// DeployRoot represents the path from the git repository root to the `deploy`
|
||||
// rendering output directory. Used as a prefix for the
|
||||
// Application.spec.source.path field.
|
||||
DeployRoot string `cue:"string | *\".\""`
|
||||
// RepoURL represents the value passed to the Application.spec.source.repoURL
|
||||
// field.
|
||||
RepoURL string
|
||||
// TargetRevision represents the value passed to the
|
||||
// Application.spec.source.targetRevision field. Defaults to the branch named
|
||||
// main.
|
||||
TargetRevision string `cue:"string | *\"main\""`
|
||||
// AppProject represents the ArgoCD Project to associate the Application with.
|
||||
AppProject string `cue:"string | *\"default\""`
|
||||
}
|
||||
|
||||
// Cluster represents a cluster managed by the Platform.
|
||||
type Cluster struct {
|
||||
// Name represents the cluster name, for example "east1", "west1", or
|
||||
// "management".
|
||||
Name string `json:"name"`
|
||||
// Primary represents if the cluster is marked as the primary among a set of
|
||||
// candidate clusters. Useful for promotion of database leaders.
|
||||
Primary bool `json:"primary" cue:"true | *false"`
|
||||
}
|
||||
|
||||
// Fleet represents a named collection of similarly configured Clusters. Useful
|
||||
// to segregate workload clusters from their management cluster.
|
||||
type Fleet struct {
|
||||
Name string `json:"name"`
|
||||
// Clusters represents a mapping of Clusters by their name.
|
||||
Clusters map[string]Cluster `json:"clusters" cue:"{[Name=_]: name: Name}"`
|
||||
}
|
||||
|
||||
// StandardFleets represents the standard set of Clusters in a Platform
|
||||
// segmented into Fleets by their purpose. The management Fleet contains a
|
||||
// single Cluster, for example a GKE autopilot cluster with no workloads
|
||||
// deployed for reliability and cost efficiency. The workload Fleet contains
|
||||
// all other Clusters which contain workloads and sync Secrets from the
|
||||
// management cluster.
|
||||
type StandardFleets struct {
|
||||
// Workload represents a Fleet of zero or more workload Clusters.
|
||||
Workload Fleet `json:"workload" cue:"{name: \"workload\"}"`
|
||||
// Management represents a Fleet with one Cluster named management.
|
||||
Management Fleet `json:"management" cue:"{name: \"management\"}"`
|
||||
}
|
||||
|
||||
// Platform is a convenience structure to produce a core Platform specification
|
||||
// value in the Output field. Useful to collect components at the root of the
|
||||
// Platform configuration tree as a struct, which are automatically converted
|
||||
// into a list for the core Platform spec output.
|
||||
type Platform struct {
|
||||
// Name represents the Platform name.
|
||||
Name string `cue:"string | *\"holos\""`
|
||||
// Components is a structured map of components to manage by their name.
|
||||
Components map[string]core.PlatformSpecComponent
|
||||
// Model represents the Platform model holos gets from from the
|
||||
// PlatformService.GetPlatform rpc method and provides to CUE using a tag.
|
||||
Model structpb.Struct `cue:"{...}"`
|
||||
// Output represents the core Platform spec for the holos cli to iterate over
|
||||
// and render each listed Component, injecting the Model.
|
||||
Output core.Platform
|
||||
// Domain represents the primary domain the Platform operates in. This field
|
||||
// is intended as a sensible default for component authors to reference and
|
||||
// platform operators to define.
|
||||
Domain string `cue:"string | *\"holos.localhost\""`
|
||||
}
|
||||
|
||||
// Organization represents organizational metadata useful across the platform.
|
||||
type Organization struct {
|
||||
Name string
|
||||
DisplayName string
|
||||
Domain string
|
||||
}
|
||||
|
||||
// OrganizationStrict represents organizational metadata useful across the
|
||||
// platform. This is an example of using CUE regular expressions to constrain
|
||||
// and validate configuration.
|
||||
type OrganizationStrict struct {
|
||||
Organization `json:",inline"`
|
||||
// Name represents the organization name as a resource name. Must be 63
|
||||
// characters or less. Must start with a letter. May contain non-repeating
|
||||
// hyphens, letters, and numbers. Must end with a letter or number.
|
||||
Name string `cue:"=~ \"^[a-z][0-9a-z-]{1,61}[0-9a-z]$\" & !~ \"--\""`
|
||||
// DisplayName represents the human readable organization name.
|
||||
DisplayName string `cue:"=~ \"^[0-9A-Za-z][0-9A-Za-z ]{2,61}[0-9A-Za-z]$\" & !~ \" \""`
|
||||
}
|
||||
|
||||
// Projects represents projects managed by the platform team for use by other
|
||||
// teams using the platform.
|
||||
type Projects map[core.NameLabel]Project
|
||||
|
||||
// Project represents logical grouping of components owned by one or more teams.
|
||||
// Useful for the platform team to manage resources for project teams to use.
|
||||
type Project struct {
|
||||
// Name represents project name.
|
||||
Name string
|
||||
// Owner represents the team who own this project.
|
||||
Owner Owner
|
||||
// Namespaces represents the namespaces assigned to this project.
|
||||
Namespaces map[core.NameLabel]Namespace
|
||||
// Hostnames represents the host names to expose for this project.
|
||||
Hostnames map[core.NameLabel]Hostname
|
||||
}
|
||||
|
||||
// Owner represents the owner of a resource. For example, the name and email
|
||||
// address of an engineering team.
|
||||
type Owner struct {
|
||||
Name string
|
||||
Email string
|
||||
}
|
||||
|
||||
// Namespace represents a Kubernetes namespace.
|
||||
type Namespace struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
// Hostname represents the left most dns label of a domain name.
|
||||
type Hostname struct {
|
||||
// Name represents the subdomain to expose, e.g. "www"
|
||||
Name string
|
||||
// Namespace represents the namespace metadata.name field of backend object
|
||||
// reference.
|
||||
Namespace string
|
||||
// Service represents the Service metadata.name field of backend object
|
||||
// reference.
|
||||
Service string
|
||||
// Port represents the Service port of the backend object reference.
|
||||
Port int
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
description: Simplified abstraction to generate core v1alpha3 components.
|
||||
sidebar_position: 997
|
||||
---
|
||||
@@ -1,290 +0,0 @@
|
||||
// # Author API
|
||||
//
|
||||
// Package v1alpha4 contains ergonomic CUE definitions for Holos component
|
||||
// authors. These definitions serve as adapters to produce [Core API] resources
|
||||
// for the holos command line tool.
|
||||
//
|
||||
// [Core API]: https://holos.run/docs/api/core/v1alpha4/
|
||||
package v1alpha4
|
||||
|
||||
import core "github.com/holos-run/holos/api/core/v1alpha4"
|
||||
|
||||
//go:generate ../../../hack/gendoc
|
||||
|
||||
// Platform assembles a Core API [Platform] in the Resource field for the holos
|
||||
// render platform command. Use the Components field to register components
|
||||
// with the platform using a struct. This struct is converted into a list for
|
||||
// final output to holos.
|
||||
//
|
||||
// See related:
|
||||
//
|
||||
// - [Component] collection of components composing the platform.
|
||||
// - [Platform] resource assembled for holos to process.
|
||||
//
|
||||
// [Platform]: https://holos.run/docs/api/core/v1alpha4/#Platform
|
||||
// [Component]: https://holos.run/docs/api/core/v1alpha4/#Component
|
||||
type Platform struct {
|
||||
Name string
|
||||
Components map[NameLabel]core.Component
|
||||
Resource core.Platform
|
||||
}
|
||||
|
||||
// Cluster represents a cluster managed by the Platform.
|
||||
type Cluster struct {
|
||||
// Name represents the cluster name, for example "east1", "west1", or
|
||||
// "management".
|
||||
Name string `json:"name"`
|
||||
// Primary represents if the cluster is marked as the primary among a set of
|
||||
// candidate clusters. Useful for promotion of database leaders.
|
||||
Primary bool `json:"primary" cue:"true | *false"`
|
||||
}
|
||||
|
||||
// Fleet represents a named collection of similarly configured Clusters. Useful
|
||||
// to segregate workload clusters from their management cluster.
|
||||
type Fleet struct {
|
||||
Name string `json:"name"`
|
||||
// Clusters represents a mapping of Clusters by their name.
|
||||
Clusters map[string]Cluster `json:"clusters" cue:"{[Name=_]: name: Name}"`
|
||||
}
|
||||
|
||||
// StandardFleets represents the standard set of Clusters in a Platform
|
||||
// segmented into Fleets by their purpose. The management Fleet contains a
|
||||
// single Cluster, for example a GKE autopilot cluster with no workloads
|
||||
// deployed for reliability and cost efficiency. The workload Fleet contains
|
||||
// all other Clusters which contain workloads and sync Secrets from the
|
||||
// management cluster.
|
||||
type StandardFleets struct {
|
||||
// Workload represents a Fleet of zero or more workload Clusters.
|
||||
Workload Fleet `json:"workload" cue:"{name: \"workload\"}"`
|
||||
// Management represents a Fleet with one Cluster named management.
|
||||
Management Fleet `json:"management" cue:"{name: \"management\"}"`
|
||||
}
|
||||
|
||||
// ArgoConfig represents the ArgoCD GitOps configuration associated with a
|
||||
// [BuildPlan]. Useful to define once at the root of the Platform configuration
|
||||
// and reuse across all components.
|
||||
//
|
||||
// [BuildPlan]: https://holos.run/docs/api/core/v1alpha4/#buildplan
|
||||
type ArgoConfig struct {
|
||||
// Enabled causes holos to render an Application resource when true.
|
||||
Enabled bool `cue:"true | *false"`
|
||||
// RepoURL represents the value passed to the Application.spec.source.repoURL
|
||||
// field.
|
||||
RepoURL string
|
||||
// Root represents the path from the git repository root to the WriteTo output
|
||||
// directory, the behavior of the holos render component --write-to flag and
|
||||
// the Core API Component WriteTo field. Used as a prefix for the
|
||||
// Application.spec.source.path field.
|
||||
Root string `cue:"string | *\"deploy\""`
|
||||
// TargetRevision represents the value passed to the
|
||||
// Application.spec.source.targetRevision field. Defaults to the branch named
|
||||
// main.
|
||||
TargetRevision string `cue:"string | *\"main\""`
|
||||
// AppProject represents the ArgoCD Project to associate the Application with.
|
||||
AppProject string `cue:"string | *\"default\""`
|
||||
}
|
||||
|
||||
// Organization represents organizational metadata useful across the platform.
|
||||
type Organization struct {
|
||||
Name string
|
||||
DisplayName string
|
||||
Domain string
|
||||
}
|
||||
|
||||
// OrganizationStrict represents organizational metadata useful across the
|
||||
// platform. This is an example of using CUE regular expressions to constrain
|
||||
// and validate configuration.
|
||||
type OrganizationStrict struct {
|
||||
Organization `json:",inline"`
|
||||
// Name represents the organization name as a resource name. Must be 63
|
||||
// characters or less. Must start with a letter. May contain non-repeating
|
||||
// hyphens, letters, and numbers. Must end with a letter or number.
|
||||
Name string `cue:"=~ \"^[a-z][0-9a-z-]{1,61}[0-9a-z]$\" & !~ \"--\""`
|
||||
// DisplayName represents the human readable organization name.
|
||||
DisplayName string `cue:"=~ \"^[0-9A-Za-z][0-9A-Za-z ]{2,61}[0-9A-Za-z]$\" & !~ \" \""`
|
||||
}
|
||||
|
||||
// Kubernetes provides a [BuildPlan] via the Output field which contains inline
|
||||
// API Objects provided directly from CUE in the Resources field of
|
||||
// [ComponentConfig].
|
||||
//
|
||||
// See related:
|
||||
//
|
||||
// - [ComponentConfig]
|
||||
// - [BuildPlan]
|
||||
//
|
||||
// [BuildPlan]: https://holos.run/docs/api/core/v1alpha4/#BuildPlan
|
||||
type Kubernetes struct {
|
||||
ComponentConfig `json:",inline"`
|
||||
|
||||
// BuildPlan represents the derived BuildPlan produced for the holos render
|
||||
// component command.
|
||||
BuildPlan core.BuildPlan
|
||||
}
|
||||
|
||||
// Helm provides a [BuildPlan] via the Output field which generates manifests
|
||||
// from a helm chart with optional mix-in resources provided directly from CUE
|
||||
// in the Resources field.
|
||||
//
|
||||
// This definition is a convenient way to produce a [BuildPlan] composed of
|
||||
// three [Resources] generators with one [Kustomize] transformer.
|
||||
//
|
||||
// See related:
|
||||
//
|
||||
// - [ComponentConfig]
|
||||
// - [Chart]
|
||||
// - [Values]
|
||||
// - [BuildPlan]
|
||||
//
|
||||
// [BuildPlan]: https://holos.run/docs/api/core/v1alpha4/#BuildPlan
|
||||
// [Chart]: https://holos.run/docs/api/core/v1alpha4/#Chart
|
||||
// [Values]: https://holos.run/docs/api/core/v1alpha4/#Values
|
||||
type Helm struct {
|
||||
ComponentConfig `json:",inline"`
|
||||
|
||||
// Chart represents a Helm chart.
|
||||
Chart core.Chart
|
||||
// Values represents data to marshal into a values.yaml for helm.
|
||||
Values core.Values
|
||||
// EnableHooks enables helm hooks when executing the `helm template` command.
|
||||
EnableHooks bool
|
||||
|
||||
// BuildPlan represents the derived BuildPlan produced for the holos render
|
||||
// component command.
|
||||
BuildPlan core.BuildPlan
|
||||
}
|
||||
|
||||
// Kustomize provides a [BuildPlan] via the Output field which generates
|
||||
// manifests from a kustomize kustomization with optional mix-in resources
|
||||
// provided directly from CUE in the Resources field.
|
||||
//
|
||||
// See related:
|
||||
//
|
||||
// - [ComponentConfig]
|
||||
// - [BuildPlan]
|
||||
//
|
||||
// [BuildPlan]: https://holos.run/docs/api/core/v1alpha4/#buildplan
|
||||
type Kustomize struct {
|
||||
ComponentConfig `json:",inline"`
|
||||
|
||||
// BuildPlan represents the derived BuildPlan produced for the holos render
|
||||
// component command.
|
||||
BuildPlan core.BuildPlan
|
||||
}
|
||||
|
||||
// ComponentConfig represents the configuration common to all kinds of
|
||||
// component.
|
||||
//
|
||||
// - [Helm] charts.
|
||||
// - [Kubernetes] resources generated from CUE.
|
||||
// - [Kustomize] bases.
|
||||
//
|
||||
// See the following resources for additional details:
|
||||
//
|
||||
// - [Resources]
|
||||
// - [ArgoConfig]
|
||||
// - [KustomizeConfig]
|
||||
// - [BuildPlan]
|
||||
//
|
||||
// [BuildPlan]: https://holos.run/docs/api/core/v1alpha4/#BuildPlan
|
||||
// [Resources]: https://holos.run/docs/api/core/v1alpha4/#Resources
|
||||
type ComponentConfig struct {
|
||||
// Name represents the BuildPlan metadata.name field. Used to construct the
|
||||
// fully rendered manifest file path.
|
||||
Name string
|
||||
// Component represents the path to the component producing the BuildPlan.
|
||||
Component string
|
||||
// Cluster represents the name of the cluster this BuildPlan is for.
|
||||
Cluster string
|
||||
// Resources represents kubernetes resources mixed into the rendered manifest.
|
||||
Resources core.Resources
|
||||
// ArgoConfig represents the ArgoCD GitOps configuration for this BuildPlan.
|
||||
ArgoConfig ArgoConfig
|
||||
// CommonLabels represents common labels to manage on all rendered manifests.
|
||||
CommonLabels map[string]string
|
||||
// Namespace manages the metadata.namespace field on all resources except the
|
||||
// ArgoCD Application.
|
||||
Namespace string `json:",omitempty"`
|
||||
|
||||
// KustomizeConfig represents the configuration for kustomize.
|
||||
KustomizeConfig KustomizeConfig
|
||||
}
|
||||
|
||||
// KustomizeConfig represents the configuration for kustomize post processing.
|
||||
// The Files field is used to mixing in static manifest files from the component
|
||||
// directory. The Resources field is used for mixing in manifests from network
|
||||
// locations urls.
|
||||
//
|
||||
// See related:
|
||||
//
|
||||
// - [ComponentConfig]
|
||||
// - [Kustomization]
|
||||
//
|
||||
// [Kustomization]: https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/
|
||||
type KustomizeConfig struct {
|
||||
// Kustomization represents the kustomization used to transform resources.
|
||||
// Note the resources field is internally managed from the Files and Resources fields.
|
||||
Kustomization map[string]any `json:",omitempty"`
|
||||
// Files represents files to copy from the component directory for kustomization.
|
||||
Files map[string]struct{ Source string } `cue:"{[NAME=_]: Source: NAME}"`
|
||||
// Resources represents additional entries to included in the resources list.
|
||||
Resources map[string]struct{ Source string } `cue:"{[NAME=_]: Source: NAME}"`
|
||||
}
|
||||
|
||||
// Projects represents projects managed by the platform team for use by other
|
||||
// teams using the platform.
|
||||
type Projects map[NameLabel]Project
|
||||
|
||||
// Project represents logical grouping of components owned by one or more teams.
|
||||
// Useful for the platform team to manage resources for project teams to use.
|
||||
type Project struct {
|
||||
// Name represents project name.
|
||||
Name string
|
||||
// Owner represents the team who own this project.
|
||||
Owner Owner
|
||||
// Namespaces represents the namespaces assigned to this project.
|
||||
Namespaces map[NameLabel]Namespace
|
||||
// Hostnames represents the host names to expose for this project.
|
||||
Hostnames map[NameLabel]Hostname
|
||||
// CommonLabels represents common labels to manage on all rendered manifests.
|
||||
CommonLabels map[string]string
|
||||
}
|
||||
|
||||
// Owner represents the owner of a resource. For example, the name and email
|
||||
// address of an engineering team.
|
||||
type Owner struct {
|
||||
Name string
|
||||
Email string
|
||||
}
|
||||
|
||||
// Namespace represents a Kubernetes namespace.
|
||||
type Namespace struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
// Hostname represents the left most dns label of a domain name.
|
||||
type Hostname struct {
|
||||
// Name represents the subdomain to expose, e.g. "www"
|
||||
Name string
|
||||
// Namespace represents the namespace metadata.name field of backend object
|
||||
// reference.
|
||||
Namespace string
|
||||
// Service represents the Service metadata.name field of backend object
|
||||
// reference.
|
||||
Service string
|
||||
// Port represents the Service port of the backend object reference.
|
||||
Port int
|
||||
}
|
||||
|
||||
// NameLabel signals the common use case of converting a struct to a list where
|
||||
// the name field of each value unifies with the field name of the outer struct.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// S: [NameLabel=string]: name: NameLabel
|
||||
// S: jeff: _
|
||||
// S: gary: _
|
||||
// S: nate: _
|
||||
// L: [for x in S {x}]
|
||||
// // L is [{name: "jeff"}, {name: "gary"}, {name: "nate"}]
|
||||
type NameLabel string
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
description: Simplified abstraction to generate core v1alpha4 build plans.
|
||||
sidebar_position: 996
|
||||
---
|
||||
@@ -46,6 +46,11 @@ type ComponentConfig struct {
|
||||
// Name represents the BuildPlan metadata.name field. Used to construct the
|
||||
// fully rendered manifest file path.
|
||||
Name string
|
||||
// Labels represent the BuildPlan metadata.labels field.
|
||||
Labels map[string]string
|
||||
// Annotations represent the BuildPlan metadata.annotations field.
|
||||
Annotations map[string]string
|
||||
|
||||
// Path represents the path to the component producing the BuildPlan.
|
||||
Path string
|
||||
// Parameters are useful to reuse a component with various parameters.
|
||||
@@ -60,8 +65,10 @@ type ComponentConfig struct {
|
||||
|
||||
// Resources represents kubernetes resources mixed into the rendered manifest.
|
||||
Resources core.Resources
|
||||
// KustomizeConfig represents the configuration kustomize.
|
||||
// KustomizeConfig represents the kustomize configuration.
|
||||
KustomizeConfig KustomizeConfig
|
||||
// Validators represent checks that must pass for output to be written.
|
||||
Validators map[NameLabel]core.Validator
|
||||
// Artifacts represents additional artifacts to mix in. Useful for adding
|
||||
// GitOps resources. Each Artifact is unified without modification into the
|
||||
// BuildPlan.
|
||||
@@ -77,6 +84,9 @@ type Helm struct {
|
||||
Chart core.Chart
|
||||
// Values represents data to marshal into a values.yaml for helm.
|
||||
Values core.Values
|
||||
// ValueFiles represents value files for migration from helm value
|
||||
// hierarchies. Use Values instead.
|
||||
ValueFiles []core.ValueFile `json:",omitempty"`
|
||||
// EnableHooks enables helm hooks when executing the `helm template` command.
|
||||
EnableHooks bool `cue:"true | *false"`
|
||||
// Namespace sets the helm chart namespace flag if provided.
|
||||
|
||||
155
api/author/v1alpha6/definitions.go
Normal file
@@ -0,0 +1,155 @@
|
||||
// Package author contains a standard set of schemas for component authors to
|
||||
// generate common [core] BuildPlans.
|
||||
//
|
||||
// Holos values stability, flexibility, and composition. This package
|
||||
// intentionally defines only the minimal necessary set of structures.
|
||||
// Component authors are encouraged to define their own structures building on
|
||||
// our example [topics].
|
||||
//
|
||||
// The Holos Maintainers may add definitions to this package if the community
|
||||
// identifies nearly all users must define the exact same structure. Otherwise,
|
||||
// definitions should be added as a customizable example in [topics].
|
||||
//
|
||||
// For example, structures representing a cluster and environment almost always
|
||||
// need to be defined. Their definition varies from one organization to the
|
||||
// next. Therefore, customizable definitions for a cluster and environment are
|
||||
// best maintained in [topics], not standardized in this package.
|
||||
//
|
||||
// [core]: https://holos.run/docs/api/core/
|
||||
// [topics]: https://holos.run/docs/topics/
|
||||
package author
|
||||
|
||||
import core "github.com/holos-run/holos/api/core/v1alpha6"
|
||||
|
||||
//go:generate ../../../hack/gendoc
|
||||
|
||||
// Platform assembles a core Platform in the Resource field for the holos render
|
||||
// platform command. Use the Components field to register components with the
|
||||
// platform.
|
||||
type Platform struct {
|
||||
Name string `json:"name" yaml:"name" cue:"string | *\"default\""`
|
||||
Components map[NameLabel]core.Component `json:"components" yaml:"components"`
|
||||
Resource core.Platform `json:"resource" yaml:"resource"`
|
||||
}
|
||||
|
||||
// ComponentConfig represents the configuration common to all kinds of
|
||||
// components for use with the holos render component command. All component
|
||||
// kinds may be transformed with [kustomize] configured with the
|
||||
// [KustomizeConfig] field.
|
||||
//
|
||||
// - [Helm] charts.
|
||||
// - [Kubernetes] resources generated from CUE.
|
||||
// - [Kustomize] bases.
|
||||
//
|
||||
// [kustomize]: https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/
|
||||
type ComponentConfig struct {
|
||||
// Name represents the BuildPlan metadata.name field. Used to construct the
|
||||
// fully rendered manifest file path.
|
||||
Name string
|
||||
// Labels represent the BuildPlan metadata.labels field.
|
||||
Labels map[string]string
|
||||
// Annotations represent the BuildPlan metadata.annotations field.
|
||||
Annotations map[string]string
|
||||
|
||||
// Path represents the path to the component producing the BuildPlan.
|
||||
Path string
|
||||
// Parameters are useful to reuse a component with various parameters.
|
||||
// Injected as CUE @tag variables. Parameters with a "holos_" prefix are
|
||||
// reserved for use by the Holos Authors.
|
||||
Parameters map[string]string
|
||||
// OutputBaseDir represents the output base directory used when assembling
|
||||
// artifacts. Useful to organize components by clusters or other parameters.
|
||||
// For example, holos writes resource manifests to
|
||||
// {WriteTo}/{OutputBaseDir}/components/{Name}/{Name}.gen.yaml
|
||||
OutputBaseDir string `cue:"string | *\"\""`
|
||||
|
||||
// Resources represents kubernetes resources mixed into the rendered manifest.
|
||||
Resources core.Resources
|
||||
// KustomizeConfig represents the kustomize configuration.
|
||||
KustomizeConfig KustomizeConfig
|
||||
// Validators represent checks that must pass for output to be written.
|
||||
Validators map[NameLabel]core.Validator
|
||||
// Artifacts represents additional artifacts to mix in. Useful for adding
|
||||
// GitOps resources. Each Artifact is unified without modification into the
|
||||
// BuildPlan.
|
||||
Artifacts map[NameLabel]core.Artifact
|
||||
}
|
||||
|
||||
// Helm assembles a BuildPlan rendering a helm chart. Useful to mix in
|
||||
// additional resources from CUE and transform the helm output with kustomize.
|
||||
type Helm struct {
|
||||
ComponentConfig `json:",inline"`
|
||||
|
||||
// Chart represents a Helm chart.
|
||||
Chart core.Chart
|
||||
// Values represents data to marshal into a values.yaml for helm.
|
||||
Values core.Values
|
||||
// ValueFiles represents value files for migration from helm value
|
||||
// hierarchies. Use Values instead.
|
||||
ValueFiles []core.ValueFile `json:",omitempty"`
|
||||
// EnableHooks enables helm hooks when executing the `helm template` command.
|
||||
EnableHooks bool `cue:"true | *false"`
|
||||
// Namespace sets the helm chart namespace flag if provided.
|
||||
Namespace string `json:",omitempty"`
|
||||
// APIVersions represents the helm template --api-versions flag
|
||||
APIVersions []string `json:",omitempty"`
|
||||
// KubeVersion represents the helm template --kube-version flag
|
||||
KubeVersion string `json:",omitempty"`
|
||||
|
||||
// BuildPlan represents the derived BuildPlan produced for the holos render
|
||||
// component command.
|
||||
BuildPlan core.BuildPlan
|
||||
}
|
||||
|
||||
// Kubernetes assembles a BuildPlan containing inline resources exported from
|
||||
// CUE.
|
||||
type Kubernetes struct {
|
||||
ComponentConfig `json:",inline"`
|
||||
|
||||
// BuildPlan represents the derived BuildPlan produced for the holos render
|
||||
// component command.
|
||||
BuildPlan core.BuildPlan
|
||||
}
|
||||
|
||||
// Kustomize assembles a BuildPlan rendering manifests from a [kustomize]
|
||||
// kustomization.
|
||||
//
|
||||
// [kustomize]: https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/
|
||||
type Kustomize struct {
|
||||
ComponentConfig `json:",inline"`
|
||||
|
||||
// BuildPlan represents the derived BuildPlan produced for the holos render
|
||||
// component command.
|
||||
BuildPlan core.BuildPlan
|
||||
}
|
||||
|
||||
// KustomizeConfig represents the configuration for [kustomize] post processing.
|
||||
// Use the Files field to mix in plain manifest files located in the component
|
||||
// directory. Use the Resources field to mix in manifests from network urls.
|
||||
//
|
||||
// [kustomize]: https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/
|
||||
type KustomizeConfig struct {
|
||||
// Kustomization represents the kustomization used to transform resources.
|
||||
// Note the resources field is internally managed from the Files and Resources fields.
|
||||
Kustomization map[string]any `json:",omitempty"`
|
||||
// Files represents files to copy from the component directory for kustomization.
|
||||
Files map[string]struct{ Source string } `cue:"{[NAME=_]: Source: NAME}"`
|
||||
// Resources represents additional entries to included in the resources list.
|
||||
Resources map[string]struct{ Source string } `cue:"{[NAME=_]: Source: NAME}"`
|
||||
// CommonLabels represents common labels added without including selectors.
|
||||
CommonLabels map[string]string
|
||||
}
|
||||
|
||||
// NameLabel represents the common use case of converting a struct to a list
|
||||
// where the name field of each value unifies with the field name of the outer
|
||||
// struct.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// S: [NameLabel=string]: name: NameLabel
|
||||
// S: jeff: _
|
||||
// S: gary: _
|
||||
// S: nate: _
|
||||
// L: [for x in S {x}]
|
||||
// // L is [{name: "jeff"}, {name: "gary"}, {name: "nate"}]
|
||||
type NameLabel string
|
||||
5
api/author/v1alpha6/header.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: Author Schemas
|
||||
description: Standardized schemas for component authors.
|
||||
sidebar_position: 200
|
||||
---
|
||||
@@ -1,44 +0,0 @@
|
||||
package v1alpha2
|
||||
|
||||
import "google.golang.org/protobuf/types/known/structpb"
|
||||
|
||||
// Label is an arbitrary unique identifier internal to holos itself. The holos
|
||||
// cli is expected to never write a Label value to rendered output files,
|
||||
// therefore use a [Label] then the identifier must be unique and internal.
|
||||
// Defined as a type for clarity and type checking.
|
||||
//
|
||||
// A Label is useful to convert a CUE struct to a list, for example producing a list of [APIObject] resources from an [APIObjectMap]. A CUE struct using
|
||||
// Label keys is guaranteed to not lose data when rendering output because a
|
||||
// Label is expected to never be written to the final output.
|
||||
type Label string
|
||||
|
||||
// Kind is a kubernetes api object kind. Defined as a type for clarity and type checking.
|
||||
type Kind string
|
||||
|
||||
// APIObject represents the most basic generic form of a single kubernetes api
|
||||
// object. Represented as a JSON object internally for compatibility between
|
||||
// tools, for example loading from CUE.
|
||||
type APIObject structpb.Struct
|
||||
|
||||
// APIObjectMap represents the marshalled yaml representation of kubernetes api
|
||||
// objects. Do not produce an APIObjectMap directly, instead use [APIObjects]
|
||||
// to produce the marshalled yaml representation from CUE data, then provide the
|
||||
// result to [HolosComponent].
|
||||
type APIObjectMap map[Kind]map[Label]string
|
||||
|
||||
// APIObjects represents Kubernetes API objects defined directly from CUE code.
|
||||
// Useful to mix in resources to any kind of [HolosComponent], for example
|
||||
// adding an ExternalSecret resource to a [HelmChart].
|
||||
//
|
||||
// [Kind] must be the resource kind, e.g. Deployment or Service.
|
||||
//
|
||||
// [Label] is an arbitrary internal identifier to uniquely identify the resource
|
||||
// within the context of a `holos` command. Holos will never write the
|
||||
// intermediate label to rendered output.
|
||||
//
|
||||
// Refer to [HolosComponent] which accepts an [APIObjectMap] field provided by
|
||||
// [APIObjects].
|
||||
type APIObjects struct {
|
||||
APIObjects map[Kind]map[Label]APIObject `json:"apiObjects"`
|
||||
APIObjectMap APIObjectMap `json:"apiObjectMap"`
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package v1alpha2
|
||||
|
||||
// FilePath represents a file path.
|
||||
type FilePath string
|
||||
|
||||
// FileContent represents file contents.
|
||||
type FileContent string
|
||||
|
||||
// FileContentMap represents a mapping of file paths to file contents. Paths
|
||||
// are relative to the `holos` output "deploy" directory, and may contain
|
||||
// sub-directories.
|
||||
type FileContentMap map[FilePath]FileContent
|
||||
|
||||
// BuildPlan represents a build plan for the holos cli to execute. The purpose
|
||||
// of a BuildPlan is to define one or more [HolosComponent] kinds. For example a
|
||||
// [HelmChart], [KustomizeBuild], or [KubernetesObjects].
|
||||
//
|
||||
// A BuildPlan usually has an additional empty [KubernetesObjects] for the
|
||||
// purpose of using the [HolosComponent] DeployFiles field to deploy an ArgoCD
|
||||
// or Flux gitops resource for the holos component.
|
||||
type BuildPlan struct {
|
||||
Kind string `json:"kind" cue:"\"BuildPlan\""`
|
||||
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha2\""`
|
||||
Spec BuildPlanSpec `json:"spec"`
|
||||
}
|
||||
|
||||
// BuildPlanSpec represents the specification of the build plan.
|
||||
type BuildPlanSpec struct {
|
||||
// Disabled causes the holos cli to take no action over the [BuildPlan].
|
||||
Disabled bool `json:"disabled,omitempty"`
|
||||
// Components represents multiple [HolosComponent] kinds to manage.
|
||||
Components BuildPlanComponents `json:"components,omitempty"`
|
||||
}
|
||||
|
||||
type BuildPlanComponents struct {
|
||||
Resources map[Label]KubernetesObjects `json:"resources,omitempty"`
|
||||
KubernetesObjectsList []KubernetesObjects `json:"kubernetesObjectsList,omitempty"`
|
||||
HelmChartList []HelmChart `json:"helmChartList,omitempty"`
|
||||
KustomizeBuildList []KustomizeBuild `json:"kustomizeBuildList,omitempty"`
|
||||
}
|
||||
|
||||
// HolosComponent defines the fields common to all holos component kinds. Every
|
||||
// holos component kind should embed HolosComponent.
|
||||
type HolosComponent struct {
|
||||
// Kind is a string value representing the resource this object represents.
|
||||
Kind string `json:"kind"`
|
||||
// APIVersion represents the versioned schema of this representation of an object.
|
||||
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha2\""`
|
||||
// Metadata represents data about the holos component such as the Name.
|
||||
Metadata Metadata `json:"metadata"`
|
||||
|
||||
// APIObjectMap holds the marshalled representation of api objects. Useful to
|
||||
// mix in resources to each HolosComponent type, for example adding an
|
||||
// ExternalSecret to a HelmChart HolosComponent. Refer to [APIObjects].
|
||||
APIObjectMap APIObjectMap `json:"apiObjectMap,omitempty"`
|
||||
|
||||
// DeployFiles represents file paths relative to the cluster deploy directory
|
||||
// with the value representing the file content. Intended for defining the
|
||||
// ArgoCD Application resource or Flux Kustomization resource from within CUE,
|
||||
// but may be used to render any file related to the build plan from CUE.
|
||||
DeployFiles FileContentMap `json:"deployFiles,omitempty"`
|
||||
|
||||
// Kustomize represents a kubectl kustomize build post-processing step.
|
||||
Kustomize `json:"kustomize,omitempty"`
|
||||
|
||||
// Skip causes holos to take no action regarding this component.
|
||||
Skip bool `json:"skip" cue:"bool | *false"`
|
||||
}
|
||||
|
||||
// Metadata represents data about the holos component such as the Name.
|
||||
type Metadata struct {
|
||||
// Name represents the name of the holos component.
|
||||
Name string `json:"name"`
|
||||
// Namespace is the primary namespace of the holos component. A holos
|
||||
// component may manage resources in multiple namespaces, in this case
|
||||
// consider setting the component namespace to default.
|
||||
//
|
||||
// This field is optional because not all resources require a namespace,
|
||||
// particularly CRD's and DeployFiles functionality.
|
||||
// +optional
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
// Kustomize represents resources necessary to execute a kustomize build.
|
||||
// Intended for at least two use cases:
|
||||
//
|
||||
// 1. Process a [KustomizeBuild] [HolosComponent] which represents raw yaml
|
||||
// file resources in a holos component directory.
|
||||
// 2. Post process a [HelmChart] [HolosComponent] to inject istio, patch jobs,
|
||||
// add custom labels, etc...
|
||||
type Kustomize struct {
|
||||
// KustomizeFiles holds file contents for kustomize, e.g. patch files.
|
||||
KustomizeFiles FileContentMap `json:"kustomizeFiles,omitempty"`
|
||||
// ResourcesFile is the file name used for api objects in kustomization.yaml
|
||||
ResourcesFile string `json:"resourcesFile,omitempty"`
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package v1alpha2
|
||||
|
||||
const (
|
||||
APIVersion = "v1alpha2"
|
||||
BuildPlanKind = "BuildPlan"
|
||||
HelmChartKind = "HelmChart"
|
||||
// ChartDir is the directory name created in the holos component directory to cache a chart.
|
||||
ChartDir = "vendor"
|
||||
// ResourcesFile is the file name used to store component output when post-processing with kustomize.
|
||||
ResourcesFile = "resources.yaml"
|
||||
)
|
||||
@@ -1,44 +0,0 @@
|
||||
package v1alpha2
|
||||
|
||||
import "google.golang.org/protobuf/types/known/structpb"
|
||||
|
||||
type PlatformMetadata struct {
|
||||
// Name represents the Platform name.
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// Platform represents a platform to manage. A Platform resource informs holos
|
||||
// which components to build. The platform resource also acts as a container
|
||||
// for the platform model form values provided by the PlatformService. The
|
||||
// primary use case is to collect the cluster names, cluster types, platform
|
||||
// model, and holos components to build into one resource.
|
||||
type Platform struct {
|
||||
// Kind is a string value representing the resource this object represents.
|
||||
Kind string `json:"kind" cue:"\"Platform\""`
|
||||
// APIVersion represents the versioned schema of this representation of an object.
|
||||
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha2\""`
|
||||
// Metadata represents data about the object such as the Name.
|
||||
Metadata PlatformMetadata `json:"metadata"`
|
||||
|
||||
// Spec represents the specification.
|
||||
Spec PlatformSpec `json:"spec"`
|
||||
}
|
||||
|
||||
// PlatformSpec represents the specification of a Platform. Think of a platform
|
||||
// specification as a list of platform components to apply to a list of
|
||||
// kubernetes clusters combined with the user-specified Platform Model.
|
||||
type PlatformSpec struct {
|
||||
// Model represents the platform model holos gets from from the
|
||||
// PlatformService.GetPlatform rpc method and provides to CUE using a tag.
|
||||
Model structpb.Struct `json:"model"`
|
||||
// Components represents a list of holos components to manage.
|
||||
Components []PlatformSpecComponent `json:"components"`
|
||||
}
|
||||
|
||||
// PlatformSpecComponent represents a holos component to build or render.
|
||||
type PlatformSpecComponent struct {
|
||||
// Path is the path of the component relative to the platform root.
|
||||
Path string `json:"path"`
|
||||
// Cluster is the cluster name to provide when rendering the component.
|
||||
Cluster string `json:"cluster"`
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// Package v1alpha2 contains the core API contract between the holos cli and CUE
|
||||
// configuration code. Platform designers, operators, and software developers
|
||||
// use this API to write configuration in CUE which `holos` loads. The overall
|
||||
// shape of the API defines imperative actions `holos` should carry out to
|
||||
// render the complete yaml that represents a Platform.
|
||||
//
|
||||
// [Platform] defines the complete configuration of a platform. With the holos
|
||||
// reference platform this takes the shape of one management cluster and at
|
||||
// least two workload cluster. Each cluster has multiple [HolosComponent]
|
||||
// resources applied to it.
|
||||
//
|
||||
// Each holos component path, e.g. `components/namespaces` produces exactly one
|
||||
// [BuildPlan] which in turn contains a set of [HolosComponent] kinds.
|
||||
//
|
||||
// The primary kinds of [HolosComponent] are:
|
||||
//
|
||||
// 1. [HelmChart] to render config from a helm chart.
|
||||
// 2. [KustomizeBuild] to render config from [Kustomize]
|
||||
// 3. [KubernetesObjects] to render [APIObjects] defined directly in CUE
|
||||
// configuration.
|
||||
//
|
||||
// Note that Holos operates as a data pipeline, so the output of a [HelmChart]
|
||||
// may be provided to [Kustomize] for post-processing.
|
||||
package v1alpha2
|
||||
|
||||
//go:generate ../../../hack/gendoc
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
description: Core v1alpha4 schema for advanced use cases.
|
||||
sidebar_position: 998
|
||||
---
|
||||
@@ -1,38 +0,0 @@
|
||||
package v1alpha2
|
||||
|
||||
// HelmChart represents a holos component which wraps around an upstream helm
|
||||
// chart. Holos orchestrates helm by providing values obtained from CUE,
|
||||
// renders the output using `helm template`, then post-processes the helm output
|
||||
// yaml using the general functionality provided by [HolosComponent], for
|
||||
// example [Kustomize] post-rendering and mixing in additional kubernetes api
|
||||
// objects.
|
||||
type HelmChart struct {
|
||||
HolosComponent `json:",inline"`
|
||||
Kind string `json:"kind" cue:"\"HelmChart\""`
|
||||
|
||||
// Chart represents a helm chart to manage.
|
||||
Chart Chart `json:"chart"`
|
||||
// ValuesContent represents the values.yaml file holos passes to the `helm
|
||||
// template` command.
|
||||
ValuesContent string `json:"valuesContent"`
|
||||
// EnableHooks enables helm hooks when executing the `helm template` command.
|
||||
EnableHooks bool `json:"enableHooks" cue:"bool | *false"`
|
||||
}
|
||||
|
||||
// Chart represents a helm chart.
|
||||
type Chart struct {
|
||||
// Name represents the chart name.
|
||||
Name string `json:"name"`
|
||||
// Version represents the chart version.
|
||||
Version string `json:"version"`
|
||||
// Release represents the chart release when executing helm template.
|
||||
Release string `json:"release"`
|
||||
// Repository represents the repository to fetch the chart from.
|
||||
Repository Repository `json:"repository,omitempty"`
|
||||
}
|
||||
|
||||
// Repository represents a helm chart repository.
|
||||
type Repository struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package v1alpha2
|
||||
|
||||
const KubernetesObjectsKind = "KubernetesObjects"
|
||||
|
||||
// KubernetesObjects represents a [HolosComponent] composed of Kubernetes API
|
||||
// objects provided directly from CUE using [APIObjects].
|
||||
type KubernetesObjects struct {
|
||||
HolosComponent `json:",inline"`
|
||||
Kind string `json:"kind" cue:"\"KubernetesObjects\""`
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package v1alpha2
|
||||
|
||||
// KustomizeBuild represents a [HolosComponent] that renders plain yaml files in
|
||||
// the holos component directory using `kubectl kustomize build`.
|
||||
type KustomizeBuild struct {
|
||||
HolosComponent `json:",inline"`
|
||||
Kind string `json:"kind" cue:"\"KustomizeBuild\""`
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package v1alpha3
|
||||
|
||||
import "google.golang.org/protobuf/types/known/structpb"
|
||||
|
||||
// InternalLabel is an arbitrary unique identifier internal to holos itself.
|
||||
// The holos cli is expected to never write a InternalLabel value to rendered
|
||||
// output files, therefore use a [InternalLabel] when the identifier must be
|
||||
// unique and internal. Defined as a type for clarity and type checking.
|
||||
//
|
||||
// A InternalLabel is useful to convert a CUE struct to a list, for example
|
||||
// producing a list of [APIObject] resources from an [APIObjectMap]. A CUE
|
||||
// struct using InternalLabel keys is guaranteed to not lose data when rendering
|
||||
// output because a InternalLabel is expected to never be written to the final
|
||||
// output.
|
||||
type InternalLabel string
|
||||
|
||||
// NameLabel is a unique identifier useful to convert a CUE struct to a list
|
||||
// when the values have a Name field with a default value. This type is
|
||||
// intended to indicate the common use case of converting a struct to a list
|
||||
// where the Name field of the value aligns with the struct field name.
|
||||
type NameLabel string
|
||||
|
||||
// Kind is a kubernetes api object kind. Defined as a type for clarity and type
|
||||
// checking.
|
||||
type Kind string
|
||||
|
||||
// APIObject represents the most basic generic form of a single kubernetes api
|
||||
// object. Represented as a JSON object internally for compatibility between
|
||||
// tools, for example loading from CUE.
|
||||
type APIObject structpb.Struct
|
||||
|
||||
// APIObjectMap represents the marshalled yaml representation of kubernetes api
|
||||
// objects. Do not produce an APIObjectMap directly, instead use [APIObjects]
|
||||
// to produce the marshalled yaml representation from CUE data, then provide the
|
||||
// result to [Component].
|
||||
type APIObjectMap map[Kind]map[InternalLabel]string
|
||||
|
||||
// APIObjects represents Kubernetes API objects defined directly from CUE code.
|
||||
// Useful to mix in resources to any kind of [Component], for example
|
||||
// adding an ExternalSecret resource to a [HelmChart].
|
||||
//
|
||||
// [Kind] must be the resource kind, e.g. Deployment or Service.
|
||||
//
|
||||
// [InternalLabel] is an arbitrary internal identifier to uniquely identify the resource
|
||||
// within the context of a `holos` command. Holos will never write the
|
||||
// intermediate label to rendered output.
|
||||
//
|
||||
// Refer to [Component] which accepts an [APIObjectMap] field provided by
|
||||
// [APIObjects].
|
||||
type APIObjects struct {
|
||||
APIObjects map[Kind]map[InternalLabel]APIObject `json:"apiObjects"`
|
||||
APIObjectMap APIObjectMap `json:"apiObjectMap"`
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package v1alpha3
|
||||
|
||||
// FilePath represents a file path.
|
||||
type FilePath string
|
||||
|
||||
// FileContent represents file contents.
|
||||
type FileContent string
|
||||
|
||||
// FileContentMap represents a mapping of file paths to file contents.
|
||||
type FileContentMap map[FilePath]FileContent
|
||||
|
||||
// BuildPlan represents a build plan for the holos cli to execute. The purpose
|
||||
// of a BuildPlan is to define one or more [Component] kinds. For example a
|
||||
// [HelmChart], [KustomizeBuild], or [KubernetesObjects].
|
||||
//
|
||||
// A BuildPlan usually has an additional empty [KubernetesObjects] for the
|
||||
// purpose of using the [Component] DeployFiles field to deploy an ArgoCD
|
||||
// or Flux gitops resource for the holos component.
|
||||
type BuildPlan struct {
|
||||
Kind string `json:"kind" cue:"\"BuildPlan\""`
|
||||
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha3\""`
|
||||
Spec BuildPlanSpec `json:"spec"`
|
||||
}
|
||||
|
||||
// BuildPlanSpec represents the specification of the build plan.
|
||||
type BuildPlanSpec struct {
|
||||
// Disabled causes the holos cli to take no action over the [BuildPlan].
|
||||
Disabled bool `json:"disabled,omitempty"`
|
||||
// Components represents multiple [HolosComponent] kinds to manage.
|
||||
Components BuildPlanComponents `json:"components,omitempty"`
|
||||
}
|
||||
|
||||
type BuildPlanComponents struct {
|
||||
Resources map[InternalLabel]KubernetesObjects `json:"resources,omitempty"`
|
||||
KubernetesObjectsList []KubernetesObjects `json:"kubernetesObjectsList,omitempty"`
|
||||
HelmChartList []HelmChart `json:"helmChartList,omitempty"`
|
||||
KustomizeBuildList []KustomizeBuild `json:"kustomizeBuildList,omitempty"`
|
||||
}
|
||||
|
||||
// Kustomize represents resources necessary to execute a kustomize build.
|
||||
// Intended for at least two use cases:
|
||||
//
|
||||
// 1. Process a [KustomizeBuild] [Component] which represents raw yaml
|
||||
// file resources in a holos component directory.
|
||||
// 2. Post process a [HelmChart] [Component] to inject istio, patch jobs,
|
||||
// add custom labels, etc...
|
||||
type Kustomize struct {
|
||||
// KustomizeFiles holds file contents for kustomize, e.g. patch files.
|
||||
KustomizeFiles FileContentMap `json:"kustomizeFiles,omitempty"`
|
||||
// ResourcesFile is the file name used for api objects in kustomization.yaml
|
||||
ResourcesFile string `json:"resourcesFile,omitempty"`
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package v1alpha3
|
||||
|
||||
// Component defines the fields common to all holos component kinds. Every
|
||||
// holos component kind should embed Component.
|
||||
type Component struct {
|
||||
// Kind is a string value representing the resource this object represents.
|
||||
Kind string `json:"kind"`
|
||||
// APIVersion represents the versioned schema of this representation of an object.
|
||||
APIVersion string `json:"apiVersion" cue:"\"v1alpha3\""`
|
||||
// Metadata represents data about the holos component such as the Name.
|
||||
Metadata Metadata `json:"metadata"`
|
||||
|
||||
// APIObjectMap holds the marshalled representation of api objects. Useful to
|
||||
// mix in resources to each Component type, for example adding an
|
||||
// ExternalSecret to a [HelmChart] Component. Refer to [APIObjects].
|
||||
APIObjectMap APIObjectMap `json:"apiObjectMap,omitempty"`
|
||||
|
||||
// DeployFiles represents file paths relative to the cluster deploy directory
|
||||
// with the value representing the file content. Intended for defining the
|
||||
// ArgoCD Application resource or Flux Kustomization resource from within CUE,
|
||||
// but may be used to render any file related to the build plan from CUE.
|
||||
DeployFiles FileContentMap `json:"deployFiles,omitempty"`
|
||||
|
||||
// Kustomize represents a kubectl kustomize build post-processing step.
|
||||
Kustomize `json:"kustomize,omitempty"`
|
||||
|
||||
// Skip causes holos to take no action regarding this component.
|
||||
Skip bool `json:"skip" cue:"bool | *false"`
|
||||
}
|
||||
|
||||
// Metadata represents data about the object such as the Name.
|
||||
type Metadata struct {
|
||||
// Name represents the name of the holos component.
|
||||
Name string `json:"name"`
|
||||
// Namespace is the primary namespace of the holos component. A holos
|
||||
// component may manage resources in multiple namespaces, in this case
|
||||
// consider setting the component namespace to default.
|
||||
//
|
||||
// This field is optional because not all resources require a namespace,
|
||||
// particularly CRDs and DeployFiles functionality.
|
||||
// +optional
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package v1alpha3
|
||||
|
||||
const (
|
||||
APIVersion = "v1alpha3"
|
||||
BuildPlanKind = "BuildPlan"
|
||||
HelmChartKind = "HelmChart"
|
||||
// ChartDir is the directory name created in the holos component directory to cache a chart.
|
||||
ChartDir = "vendor"
|
||||
// ResourcesFile is the file name used to store component output when post-processing with kustomize.
|
||||
ResourcesFile = "resources.yaml"
|
||||
)
|
||||
@@ -1,26 +0,0 @@
|
||||
// Package v1alpha3 contains the core API contract between the holos cli and CUE
|
||||
// configuration code. Platform designers, operators, and software developers
|
||||
// use this API to write configuration in CUE which `holos` loads. The overall
|
||||
// shape of the API defines imperative actions `holos` should carry out to
|
||||
// render the complete yaml that represents a Platform.
|
||||
//
|
||||
// [Platform] defines the complete configuration of a platform. With the holos
|
||||
// reference platform this takes the shape of one management cluster and at
|
||||
// least two workload cluster. Each cluster has multiple [Component]
|
||||
// resources applied to it.
|
||||
//
|
||||
// Each holos component path, e.g. `components/namespaces` produces exactly one
|
||||
// [BuildPlan] which in turn contains a set of [Component] kinds.
|
||||
//
|
||||
// The primary kinds of [Component] are:
|
||||
//
|
||||
// 1. [HelmChart] to render config from a helm chart.
|
||||
// 2. [KustomizeBuild] to render config from [Kustomize]
|
||||
// 3. [KubernetesObjects] to render [APIObjects] defined directly in CUE
|
||||
// configuration.
|
||||
//
|
||||
// Note that Holos operates as a data pipeline, so the output of a [HelmChart]
|
||||
// may be provided to [Kustomize] for post-processing.
|
||||
package v1alpha3
|
||||
|
||||
//go:generate ../../../hack/gendoc
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
description: Core v1alpha3 schema for advanced use cases.
|
||||
sidebar_position: 997
|
||||
---
|
||||
@@ -1,38 +0,0 @@
|
||||
package v1alpha3
|
||||
|
||||
// HelmChart represents a holos component which wraps around an upstream helm
|
||||
// chart. Holos orchestrates helm by providing values obtained from CUE,
|
||||
// renders the output using `helm template`, then post-processes the helm output
|
||||
// yaml using the general functionality provided by [Component], for
|
||||
// example [Kustomize] post-rendering and mixing in additional kubernetes api
|
||||
// objects.
|
||||
type HelmChart struct {
|
||||
Component `json:",inline"`
|
||||
Kind string `json:"kind" cue:"\"HelmChart\""`
|
||||
|
||||
// Chart represents a helm chart to manage.
|
||||
Chart Chart `json:"chart"`
|
||||
// ValuesContent represents the values.yaml file holos passes to the `helm
|
||||
// template` command.
|
||||
ValuesContent string `json:"valuesContent"`
|
||||
// EnableHooks enables helm hooks when executing the `helm template` command.
|
||||
EnableHooks bool `json:"enableHooks" cue:"bool | *false"`
|
||||
}
|
||||
|
||||
// Chart represents a helm chart.
|
||||
type Chart struct {
|
||||
// Name represents the chart name.
|
||||
Name string `json:"name"`
|
||||
// Version represents the chart version.
|
||||
Version string `json:"version"`
|
||||
// Release represents the chart release when executing helm template.
|
||||
Release string `json:"release"`
|
||||
// Repository represents the repository to fetch the chart from.
|
||||
Repository Repository `json:"repository,omitempty"`
|
||||
}
|
||||
|
||||
// Repository represents a helm chart repository.
|
||||
type Repository struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package v1alpha3
|
||||
|
||||
const KubernetesObjectsKind = "KubernetesObjects"
|
||||
|
||||
// KubernetesObjects represents a [Component] composed of Kubernetes API
|
||||
// objects provided directly from CUE using [APIObjects].
|
||||
type KubernetesObjects struct {
|
||||
Component `json:",inline"`
|
||||
Kind string `json:"kind" cue:"\"KubernetesObjects\""`
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package v1alpha3
|
||||
|
||||
// KustomizeBuild represents a [Component] that renders plain yaml files in
|
||||
// the holos component directory using `kubectl kustomize build`.
|
||||
type KustomizeBuild struct {
|
||||
Component `json:",inline"`
|
||||
Kind string `json:"kind" cue:"\"KustomizeBuild\""`
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package v1alpha3
|
||||
|
||||
import "google.golang.org/protobuf/types/known/structpb"
|
||||
|
||||
// Platform represents a platform to manage. A Platform resource informs holos
|
||||
// which components to build. The platform resource also acts as a container
|
||||
// for the platform model form values provided by the PlatformService. The
|
||||
// primary use case is to collect the cluster names, cluster types, platform
|
||||
// model, and holos components to build into one resource.
|
||||
type Platform struct {
|
||||
// Kind is a string value representing the resource this object represents.
|
||||
Kind string `json:"kind" cue:"\"Platform\""`
|
||||
// APIVersion represents the versioned schema of this representation of an object.
|
||||
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha3\""`
|
||||
// Metadata represents data about the object such as the Name.
|
||||
Metadata PlatformMetadata `json:"metadata"`
|
||||
|
||||
// Spec represents the specification.
|
||||
Spec PlatformSpec `json:"spec"`
|
||||
}
|
||||
|
||||
type PlatformMetadata struct {
|
||||
// Name represents the Platform name.
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// PlatformSpec represents the specification of a Platform. Think of a platform
|
||||
// specification as a list of platform components to apply to a list of
|
||||
// kubernetes clusters combined with the user-specified Platform Model.
|
||||
type PlatformSpec struct {
|
||||
// Model represents the platform model holos gets from from the
|
||||
// PlatformService.GetPlatform rpc method and provides to CUE using a tag.
|
||||
Model structpb.Struct `json:"model" cue:"{...}"`
|
||||
// Components represents a list of holos components to manage.
|
||||
Components []PlatformSpecComponent `json:"components"`
|
||||
}
|
||||
|
||||
// PlatformSpecComponent represents a holos component to build or render.
|
||||
type PlatformSpecComponent struct {
|
||||
// Path is the path of the component relative to the platform root.
|
||||
Path string `json:"path"`
|
||||
// Cluster is the cluster name to provide when rendering the component.
|
||||
Cluster string `json:"cluster"`
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
description: Core schema for holos to render a component BuildPlan.
|
||||
sidebar_position: 100
|
||||
---
|
||||
@@ -1,402 +0,0 @@
|
||||
// # Core API
|
||||
//
|
||||
// Package v1alpha4 contains the core API contract between the holos cli and CUE
|
||||
// configuration code. Platform designers, operators, and software developers
|
||||
// use this API to write configuration in CUE which holos loads. The Core API
|
||||
// is declarative. Each resource represents a desired state necessary for holos
|
||||
// to fully render Kubernetes manifests into plain files.
|
||||
//
|
||||
// The following resources provide important context for the Core API. The
|
||||
// [Author API] is intended for component authors as a convenient adapter for
|
||||
// the Core API resources Holos expects.
|
||||
//
|
||||
// 1. [Technical Overview]
|
||||
// 2. [Quickstart]
|
||||
// 3. [Author API]
|
||||
//
|
||||
// # Platform
|
||||
//
|
||||
// [Platform] defines the complete configuration of a platform. A platform
|
||||
// represents a [Component] collection.
|
||||
//
|
||||
// Inspect a Platform resource holos would process by executing:
|
||||
//
|
||||
// cue export --out yaml ./platform
|
||||
//
|
||||
// # Component
|
||||
//
|
||||
// A [Component] is the combination of CUE code along one path relative to the
|
||||
// platform root directory plus data injected from the [PlatformSpec] via CUE tags.
|
||||
// The platform configuration root is the directory containing cue.mod.
|
||||
//
|
||||
// A [Component] always produces exactly one [BuildPlan].
|
||||
//
|
||||
// # BuildPlan
|
||||
//
|
||||
// A [BuildPlan] contains an [Artifact] collection. A BuildPlan often produces
|
||||
// two artifacts, one containing the fully rendered Kubernetes API resources,
|
||||
// the other containing an additional resource to manage the former with GitOps.
|
||||
// For example, a BuildPlan for a podinfo component produces a manifest
|
||||
// containing a Deployment and a Service, along with a second manifest
|
||||
// containing an ArgoCD Application.
|
||||
//
|
||||
// Inspect a BuildPlan resource holos render component would process by executing:
|
||||
//
|
||||
// cue export --out yaml ./projects/platform/components/namespaces
|
||||
//
|
||||
// # Artifact
|
||||
//
|
||||
// An [Artifact] is one fully rendered manifest file produced from the final
|
||||
// [Transformer] in a sequence of transformers. An Artifact may also be
|
||||
// produced directly from a [Generator], but this use case is uncommon.
|
||||
//
|
||||
// # Transformer
|
||||
//
|
||||
// A [Transformer] takes multiple inputs from prior [Generator] or [Transformer]
|
||||
// outputs, then transforms the data into one output. [Kustomize] is the most
|
||||
// commonly used transformer, though a simple [Join] is also supported.
|
||||
//
|
||||
// 1. [Kustomize] - Patch and transform the output from prior generators or
|
||||
// transformers. See [Introduction to Kustomize].
|
||||
// 2. [Join] - Concatenate multiple prior outputs into one output.
|
||||
//
|
||||
// # Generators
|
||||
//
|
||||
// A [Generator] generates Kubernetes resources. [Helm] and [Resources] are the
|
||||
// most commonly used, often paired together to mix-in resources to an
|
||||
// unmodified Helm chart. A simple [File] generator is also available for use
|
||||
// with the [Kustomize] transformer.
|
||||
//
|
||||
// 1. [Resources] - Generates resources from CUE code.
|
||||
// 2. [Helm] - Generates rendered yaml from a [Chart].
|
||||
// 3. [File] - Generates data by reading a file from the component directory.
|
||||
//
|
||||
// [Introduction to Kustomize]: https://kubectl.docs.kubernetes.io/guides/config_management/introduction/
|
||||
// [Author API]: https://holos.run/docs/api/author/
|
||||
// [Quickstart]: https://holos.run/docs/quickstart/
|
||||
// [Technical Overview]: https://holos.run/docs/technical-overview/
|
||||
package v1alpha4
|
||||
|
||||
//go:generate ../../../hack/gendoc
|
||||
|
||||
// BuildPlan represents a build plan for holos to execute. Each [Platform]
|
||||
// component produces exactly one BuildPlan.
|
||||
//
|
||||
// One or more [Artifact] files are produced by a BuildPlan, representing the
|
||||
// fully rendered manifests for the Kubernetes API Server.
|
||||
//
|
||||
// # Example BuildPlan
|
||||
//
|
||||
// Command:
|
||||
//
|
||||
// cue export --out yaml ./projects/platform/components/namespaces
|
||||
//
|
||||
// Output:
|
||||
//
|
||||
// kind: BuildPlan
|
||||
// apiVersion: v1alpha4
|
||||
// metadata:
|
||||
// name: dev-namespaces
|
||||
// spec:
|
||||
// component: projects/platform/components/namespaces
|
||||
// artifacts:
|
||||
// - artifact: clusters/no-cluster/components/dev-namespaces/dev-namespaces.gen.yaml
|
||||
// generators:
|
||||
// - kind: Resources
|
||||
// output: resources.gen.yaml
|
||||
// resources:
|
||||
// Namespace:
|
||||
// dev-jeff:
|
||||
// metadata:
|
||||
// name: dev-jeff
|
||||
// labels:
|
||||
// kubernetes.io/metadata.name: dev-jeff
|
||||
// kind: Namespace
|
||||
// apiVersion: v1
|
||||
// transformers:
|
||||
// - kind: Kustomize
|
||||
// inputs:
|
||||
// - resources.gen.yaml
|
||||
// output: clusters/no-cluster/components/dev-namespaces/dev-namespaces.gen.yaml
|
||||
// kustomize:
|
||||
// kustomization:
|
||||
// commonLabels:
|
||||
// holos.run/component.name: dev-namespaces
|
||||
// resources:
|
||||
// - resources.gen.yaml
|
||||
type BuildPlan struct {
|
||||
// Kind represents the type of the resource.
|
||||
Kind string `json:"kind" cue:"\"BuildPlan\""`
|
||||
// APIVersion represents the versioned schema of the resource.
|
||||
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha4\""`
|
||||
// Metadata represents data about the resource such as the Name.
|
||||
Metadata Metadata `json:"metadata"`
|
||||
// Spec specifies the desired state of the resource.
|
||||
Spec BuildPlanSpec `json:"spec"`
|
||||
}
|
||||
|
||||
// BuildPlanSpec represents the specification of the [BuildPlan].
|
||||
type BuildPlanSpec struct {
|
||||
// Component represents the component that produced the build plan.
|
||||
// Represented as a path relative to the platform root.
|
||||
Component string `json:"component"`
|
||||
// Disabled causes the holos cli to disregard the build plan.
|
||||
Disabled bool `json:"disabled,omitempty"`
|
||||
// Artifacts represents the artifacts for holos to build.
|
||||
Artifacts []Artifact `json:"artifacts"`
|
||||
}
|
||||
|
||||
// Artifact represents one fully rendered manifest produced by a [Transformer]
|
||||
// sequence, which transforms a [Generator] collection. A [BuildPlan] produces
|
||||
// an [Artifact] collection.
|
||||
//
|
||||
// Each Artifact produces one manifest file artifact. Generator Output values
|
||||
// are used as Transformer Inputs. The Output field of the final [Transformer]
|
||||
// should have the same value as the Artifact field.
|
||||
//
|
||||
// When there is more than one [Generator] there must be at least one
|
||||
// [Transformer] to combine outputs into one Artifact. If there is a single
|
||||
// Generator, it may directly produce the Artifact output.
|
||||
//
|
||||
// An Artifact is processed concurrently with other artifacts in the same
|
||||
// [BuildPlan]. An Artifact should not use an output from another Artifact as
|
||||
// an input. Each [Generator] may also run concurrently. Each [Transformer] is
|
||||
// executed sequentially starting after all generators have completed.
|
||||
//
|
||||
// Output fields are write-once. It is an error for multiple Generators or
|
||||
// Transformers to produce the same Output value within the context of a
|
||||
// [BuildPlan].
|
||||
type Artifact struct {
|
||||
Artifact FilePath `json:"artifact,omitempty"`
|
||||
Generators []Generator `json:"generators,omitempty"`
|
||||
Transformers []Transformer `json:"transformers,omitempty"`
|
||||
Skip bool `json:"skip,omitempty"`
|
||||
}
|
||||
|
||||
// Generator generates an intermediate manifest for a [Artifact].
|
||||
//
|
||||
// Each Generator in a [Artifact] must have a distinct Output value for a
|
||||
// [Transformer] to reference.
|
||||
//
|
||||
// Refer to [Resources], [Helm], and [File].
|
||||
type Generator struct {
|
||||
// Kind represents the kind of generator. Must be Resources, Helm, or File.
|
||||
Kind string `json:"kind" cue:"\"Resources\" | \"Helm\" | \"File\""`
|
||||
// Output represents a file for a Transformer or Artifact to consume.
|
||||
Output FilePath `json:"output"`
|
||||
// Resources generator. Ignored unless kind is Resources. Resources are
|
||||
// stored as a two level struct. The top level key is the Kind of resource,
|
||||
// e.g. Namespace or Deployment. The second level key is an arbitrary
|
||||
// InternalLabel. The third level is a map[string]any representing the
|
||||
// Resource.
|
||||
Resources Resources `json:"resources,omitempty"`
|
||||
// Helm generator. Ignored unless kind is Helm.
|
||||
Helm Helm `json:"helm,omitempty"`
|
||||
// File generator. Ignored unless kind is File.
|
||||
File File `json:"file,omitempty"`
|
||||
}
|
||||
|
||||
// Resource represents one kubernetes api object.
|
||||
type Resource map[string]any
|
||||
|
||||
// Resources represents a kubernetes resources [Generator] from CUE.
|
||||
type Resources map[Kind]map[InternalLabel]Resource
|
||||
|
||||
// File represents a simple single file copy [Generator]. Useful with a
|
||||
// [Kustomize] [Transformer] to process plain manifest files stored in the
|
||||
// component directory. Multiple File generators may be used to transform
|
||||
// multiple resources.
|
||||
type File struct {
|
||||
// Source represents a file sub-path relative to the component path.
|
||||
Source FilePath `json:"source"`
|
||||
}
|
||||
|
||||
// Helm represents a [Chart] manifest [Generator].
|
||||
type Helm struct {
|
||||
// Chart represents a helm chart to manage.
|
||||
Chart Chart `json:"chart"`
|
||||
// Values represents values for holos to marshal into values.yaml when
|
||||
// rendering the chart.
|
||||
Values Values `json:"values"`
|
||||
// EnableHooks enables helm hooks when executing the `helm template` command.
|
||||
EnableHooks bool `json:"enableHooks,omitempty"`
|
||||
// Namespace represents the helm namespace flag
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
// Values represents [Helm] Chart values generated from CUE.
|
||||
type Values map[string]any
|
||||
|
||||
// Chart represents a [Helm] Chart.
|
||||
type Chart struct {
|
||||
// Name represents the chart name.
|
||||
Name string `json:"name"`
|
||||
// Version represents the chart version.
|
||||
Version string `json:"version"`
|
||||
// Release represents the chart release when executing helm template.
|
||||
Release string `json:"release"`
|
||||
// Repository represents the repository to fetch the chart from.
|
||||
Repository Repository `json:"repository,omitempty"`
|
||||
}
|
||||
|
||||
// Repository represents a [Helm] [Chart] repository.
|
||||
type Repository struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
// Transformer transforms [Generator] manifests within a [Artifact].
|
||||
type Transformer struct {
|
||||
// Kind represents the kind of transformer. Must be Kustomize, or Join.
|
||||
Kind string `json:"kind" cue:"\"Kustomize\" | \"Join\""`
|
||||
// Inputs represents the files to transform. The Output of prior Generators
|
||||
// and Transformers.
|
||||
Inputs []FilePath `json:"inputs"`
|
||||
// Output represents a file for a subsequent Transformer or Artifact to
|
||||
// consume.
|
||||
Output FilePath `json:"output"`
|
||||
// Kustomize transformer. Ignored unless kind is Kustomize.
|
||||
Kustomize Kustomize `json:"kustomize,omitempty"`
|
||||
// Join transformer. Ignored unless kind is Join.
|
||||
Join Join `json:"join,omitempty"`
|
||||
}
|
||||
|
||||
// Join represents a [Transformer] using [bytes.Join] to concatenate multiple
|
||||
// inputs into one output with a separator. Useful for combining output from
|
||||
// [Helm] and [Resources] together into one [Artifact] when [Kustomize] is
|
||||
// otherwise unnecessary.
|
||||
//
|
||||
// [bytes.Join]: https://pkg.go.dev/bytes#Join
|
||||
type Join struct {
|
||||
Separator string `json:"separator" cue:"string | *\"---\\n\""`
|
||||
}
|
||||
|
||||
// Kustomize represents a kustomization [Transformer].
|
||||
type Kustomize struct {
|
||||
// Kustomization represents the decoded kustomization.yaml file
|
||||
Kustomization Kustomization `json:"kustomization"`
|
||||
// Files holds file contents for kustomize, e.g. patch files.
|
||||
Files FileContentMap `json:"files,omitempty"`
|
||||
}
|
||||
|
||||
// Kustomization represents a kustomization.yaml file for use with the
|
||||
// [Kustomize] [Transformer]. Untyped to avoid tightly coupling holos to
|
||||
// kubectl versions which was a problem for the Flux maintainers. Type checking
|
||||
// is expected to happen in CUE against the kubectl version the user prefers.
|
||||
type Kustomization map[string]any
|
||||
|
||||
// FileContent represents file contents.
|
||||
type FileContent string
|
||||
|
||||
// FileContentMap represents a mapping of file paths to file contents.
|
||||
type FileContentMap map[FilePath]FileContent
|
||||
|
||||
// FilePath represents a file path.
|
||||
type FilePath string
|
||||
|
||||
// InternalLabel is an arbitrary unique identifier internal to holos itself.
|
||||
// The holos cli is expected to never write a InternalLabel value to rendered
|
||||
// output files, therefore use a InternalLabel when the identifier must be
|
||||
// unique and internal. Defined as a type for clarity and type checking.
|
||||
type InternalLabel string
|
||||
|
||||
// Kind is a discriminator. Defined as a type for clarity and type checking.
|
||||
type Kind string
|
||||
|
||||
// NameLabel is a unique identifier useful to convert a CUE struct to a list
|
||||
// when the values have a Name field with a default value. NameLabel indicates
|
||||
// the common use case of converting a struct to a list where the Name field of
|
||||
// the value aligns with the outer struct field name.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// Outer: [NAME=_]: Name: NAME
|
||||
type NameLabel string
|
||||
|
||||
// Platform represents a platform to manage. A Platform resource informs holos
|
||||
// which components to build. The platform resource also acts as a container
|
||||
// for the platform model form values provided by the PlatformService. The
|
||||
// primary use case is to collect the cluster names, cluster types, platform
|
||||
// model, and holos components to build into one resource.
|
||||
type Platform struct {
|
||||
// Kind is a string value representing the resource.
|
||||
Kind string `json:"kind" cue:"\"Platform\""`
|
||||
// APIVersion represents the versioned schema of this resource.
|
||||
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha4\""`
|
||||
// Metadata represents data about the resource such as the Name.
|
||||
Metadata Metadata `json:"metadata"`
|
||||
|
||||
// Spec represents the specification.
|
||||
Spec PlatformSpec `json:"spec"`
|
||||
}
|
||||
|
||||
// Metadata represents data about the resource such as the Name.
|
||||
type Metadata struct {
|
||||
// Name represents the resource name.
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// PlatformSpec represents the specification of a [Platform]. Think of a
|
||||
// platform spec as a [Component] collection for multiple kubernetes clusters
|
||||
// combined with the user-specified Platform Model.
|
||||
type PlatformSpec struct {
|
||||
// Components represents a list of holos components to manage.
|
||||
Components []Component `json:"components"`
|
||||
}
|
||||
|
||||
// Component represents the complete context necessary to produce a [BuildPlan].
|
||||
// Component carries information injected from holos render platform to holos
|
||||
// render component to produce each [BuildPlan].
|
||||
//
|
||||
// All of these fields are passed to the holos render component command using
|
||||
// flags, which in turn are injected to CUE using tags. For clarity, CUE field
|
||||
// and tag names should match the struct json tag names below.
|
||||
type Component struct {
|
||||
// Name represents the name of the component. Injected as the tag variable
|
||||
// "holos_name" to set the BuildPlan metadata.name field. Necessary for clear
|
||||
// user feedback during platform rendering.
|
||||
Name string `json:"name"`
|
||||
// Component represents the path of the component relative to the platform
|
||||
// root. Injected as the tag variable "holos_component".
|
||||
Component string `json:"component"`
|
||||
// Cluster is the cluster name to provide when rendering the component.
|
||||
// Injected as the tag variable "holos_cluster".
|
||||
Cluster string `json:"cluster"`
|
||||
// Model represents the platform model holos gets from from the
|
||||
// PlatformService.GetPlatform rpc method and provides to CUE using a tag.
|
||||
// Injected as the tag "holos_model".
|
||||
Model map[string]any `json:"model,omitempty"`
|
||||
// Tags represents cue @tag variables injected into the holos render component
|
||||
// command from the holos render platform command. Tags with a "holos_"
|
||||
// prefix are reserved for use by the Holos Authors.
|
||||
Tags map[string]string `json:"tags,omitempty"`
|
||||
// WriteTo represents the holos render component --write-to flag. If empty,
|
||||
// the default value for the --write-to flag is used.
|
||||
WriteTo string `json:"writeTo,omitempty"`
|
||||
}
|
||||
|
||||
// Tags represents standardized fields injected into the component [BuildPlan]
|
||||
// from the [Platform].
|
||||
//
|
||||
// Note, tags should have a reasonable default value to easily use cue eval and
|
||||
// cue export without needing to make a bunch of decisions about tag values.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// import core "github.com/holos-run/holos/api/core/v1alpha4"
|
||||
// _Tags: core.#Tags & {
|
||||
// cluster: _ @tag(cluster, type=string)
|
||||
// environment: _ @tag(environment, type=string)
|
||||
// component: _ @tag(component, type=string)
|
||||
// name: _ @tag(name, type=string)
|
||||
// }
|
||||
type Tags struct {
|
||||
// Name represents the BuildPlan metadata.name field injected from the Platform.
|
||||
Name string `json:"name" cue:"string | *\"no-name\""`
|
||||
// Cluster represents the cluster name injected from
|
||||
Cluster string `json:"cluster" cue:"string | *\"no-cluster\""`
|
||||
// Environment represents the build plan environment.
|
||||
Environment string `json:"environment" cue:"string | *\"no-environment\""`
|
||||
// Component represents the path of the component relative to the platform root.
|
||||
Component string `json:"component" cue:"string | *\"no-component\""`
|
||||
}
|
||||
@@ -1,9 +1,33 @@
|
||||
// Package core contains schemas for a [Platform] and [BuildPlan]. Holos takes
|
||||
// a [Platform] as input, then iterates over each [Component] to produce a
|
||||
// [BuildPlan]. Holos processes the [BuildPlan] to produce fully rendered
|
||||
// [BuildPlan]. Holos evaluates the [BuildPlan] to produce fully rendered
|
||||
// manifests, each an [Artifact].
|
||||
package core
|
||||
|
||||
// BuildContextTag represents the cue tag holos render component uses to inject
|
||||
// the json representation of a [BuildContext] for use in a BuildPlan.
|
||||
const BuildContextTag string = "holos_build_context"
|
||||
|
||||
// ComponentNameTag represents the cue tag holos uses to inject a [Component]
|
||||
// name from the holos render platform command to the holos render component
|
||||
// command.
|
||||
const ComponentNameTag string = "holos_component_name"
|
||||
|
||||
// ComponentPathTag represents the cue tag holos uses to inject a [Component]
|
||||
// path relative to the cue module root from the holos render platform command
|
||||
// to the holos render component command.
|
||||
const ComponentPathTag string = "holos_component_path"
|
||||
|
||||
// ComponentLabelsTag represents the cue tag holos uses to inject the json
|
||||
// representation of [Component] metadata labels from the holos render platform
|
||||
// command to the holos render component command.
|
||||
const ComponentLabelsTag string = "holos_component_labels"
|
||||
|
||||
// ComponentAnnotationsTag represents the tag holos uses to inject the json
|
||||
// representation of [Component] metadata annotations from the holos render
|
||||
// platform command to the holos render component command.
|
||||
const ComponentAnnotationsTag = "holos_component_annotations"
|
||||
|
||||
//go:generate ../../../hack/gendoc
|
||||
|
||||
// BuildPlan represents an implementation of the [rendered manifest pattern].
|
||||
@@ -23,31 +47,21 @@ package core
|
||||
// [external credential provider]: https://github.com/kubernetes/enhancements/blob/313ad8b59c80819659e1fbf0f165230f633f2b22/keps/sig-auth/541-external-credential-providers/README.md
|
||||
type BuildPlan struct {
|
||||
// Kind represents the type of the resource.
|
||||
Kind string `json:"kind" cue:"\"BuildPlan\""`
|
||||
Kind string `json:"kind" yaml:"kind" cue:"\"BuildPlan\""`
|
||||
// APIVersion represents the versioned schema of the resource.
|
||||
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha5\""`
|
||||
APIVersion string `json:"apiVersion" yaml:"apiVersion" cue:"string | *\"v1alpha5\""`
|
||||
// Metadata represents data about the resource such as the Name.
|
||||
Metadata Metadata `json:"metadata"`
|
||||
Metadata Metadata `json:"metadata" yaml:"metadata"`
|
||||
// Spec specifies the desired state of the resource.
|
||||
Spec BuildPlanSpec `json:"spec"`
|
||||
// Source reflects the origin of the BuildPlan.
|
||||
Source BuildPlanSource `json:"source,omitempty"`
|
||||
Spec BuildPlanSpec `json:"spec" yaml:"spec"`
|
||||
}
|
||||
|
||||
// BuildPlanSpec represents the specification of the [BuildPlan].
|
||||
type BuildPlanSpec struct {
|
||||
// Artifacts represents the artifacts for holos to build.
|
||||
Artifacts []Artifact `json:"artifacts"`
|
||||
Artifacts []Artifact `json:"artifacts" yaml:"artifacts"`
|
||||
// Disabled causes the holos cli to disregard the build plan.
|
||||
Disabled bool `json:"disabled,omitempty"`
|
||||
}
|
||||
|
||||
// BuildPlanSource reflects the origin of a [BuildPlan]. Useful to save a build
|
||||
// plan to a file, then re-generate it without needing to process a [Platform]
|
||||
// component collection.
|
||||
type BuildPlanSource struct {
|
||||
// Component reflects the component that produced the build plan.
|
||||
Component Component `json:"component,omitempty"`
|
||||
Disabled bool `json:"disabled,omitempty" yaml:"disabled,omitempty"`
|
||||
}
|
||||
|
||||
// Artifact represents one fully rendered manifest produced by a [Transformer]
|
||||
@@ -71,10 +85,11 @@ type BuildPlanSource struct {
|
||||
// Transformers to produce the same Output value within the context of a
|
||||
// [BuildPlan].
|
||||
type Artifact struct {
|
||||
Artifact FilePath `json:"artifact,omitempty"`
|
||||
Generators []Generator `json:"generators,omitempty"`
|
||||
Transformers []Transformer `json:"transformers,omitempty"`
|
||||
Skip bool `json:"skip,omitempty"`
|
||||
Artifact FilePath `json:"artifact,omitempty" yaml:"artifact,omitempty"`
|
||||
Generators []Generator `json:"generators,omitempty" yaml:"generators,omitempty"`
|
||||
Transformers []Transformer `json:"transformers,omitempty" yaml:"transformers,omitempty"`
|
||||
Validators []Validator `json:"validators,omitempty" yaml:"validators,omitempty"`
|
||||
Skip bool `json:"skip,omitempty" yaml:"skip,omitempty"`
|
||||
}
|
||||
|
||||
// Generator generates Kubernetes resources. [Helm] and [Resources] are the
|
||||
@@ -90,19 +105,19 @@ type Artifact struct {
|
||||
// 3. [File] - Generates data by reading a file from the component directory.
|
||||
type Generator struct {
|
||||
// Kind represents the kind of generator. Must be Resources, Helm, or File.
|
||||
Kind string `json:"kind" cue:"\"Resources\" | \"Helm\" | \"File\""`
|
||||
Kind string `json:"kind" yaml:"kind" cue:"\"Resources\" | \"Helm\" | \"File\""`
|
||||
// Output represents a file for a Transformer or Artifact to consume.
|
||||
Output FilePath `json:"output"`
|
||||
Output FilePath `json:"output" yaml:"output"`
|
||||
// Resources generator. Ignored unless kind is Resources. Resources are
|
||||
// stored as a two level struct. The top level key is the Kind of resource,
|
||||
// e.g. Namespace or Deployment. The second level key is an arbitrary
|
||||
// InternalLabel. The third level is a map[string]any representing the
|
||||
// Resource.
|
||||
Resources Resources `json:"resources,omitempty"`
|
||||
Resources Resources `json:"resources,omitempty" yaml:"resources,omitempty"`
|
||||
// Helm generator. Ignored unless kind is Helm.
|
||||
Helm Helm `json:"helm,omitempty"`
|
||||
Helm Helm `json:"helm,omitempty" yaml:"helm,omitempty"`
|
||||
// File generator. Ignored unless kind is File.
|
||||
File File `json:"file,omitempty"`
|
||||
File File `json:"file,omitempty" yaml:"file,omitempty"`
|
||||
}
|
||||
|
||||
// Resource represents one kubernetes api object.
|
||||
@@ -119,24 +134,39 @@ type Resources map[Kind]map[InternalLabel]Resource
|
||||
// multiple resources.
|
||||
type File struct {
|
||||
// Source represents a file sub-path relative to the component path.
|
||||
Source FilePath `json:"source"`
|
||||
Source FilePath `json:"source" yaml:"source"`
|
||||
}
|
||||
|
||||
// Helm represents a [Chart] manifest [Generator].
|
||||
type Helm struct {
|
||||
// Chart represents a helm chart to manage.
|
||||
Chart Chart `json:"chart"`
|
||||
Chart Chart `json:"chart" yaml:"chart"`
|
||||
// Values represents values for holos to marshal into values.yaml when
|
||||
// rendering the chart.
|
||||
Values Values `json:"values"`
|
||||
// rendering the chart. Values follow ValueFiles when both are provided.
|
||||
Values Values `json:"values" yaml:"values"`
|
||||
// ValueFiles represents hierarchial value files passed in order to the helm
|
||||
// template -f flag. Useful for migration from an ApplicationSet. Use Values
|
||||
// instead. ValueFiles precede Values when both are provided.
|
||||
ValueFiles []ValueFile `json:"valueFiles,omitempty" yaml:"valueFiles,omitempty"`
|
||||
// EnableHooks enables helm hooks when executing the `helm template` command.
|
||||
EnableHooks bool `json:"enableHooks,omitempty"`
|
||||
EnableHooks bool `json:"enableHooks,omitempty" yaml:"enableHooks,omitempty"`
|
||||
// Namespace represents the helm namespace flag
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
// APIVersions represents the helm template --api-versions flag
|
||||
APIVersions []string `json:"apiVersions,omitempty"`
|
||||
APIVersions []string `json:"apiVersions,omitempty" yaml:"apiVersions,omitempty"`
|
||||
// KubeVersion represents the helm template --kube-version flag
|
||||
KubeVersion string `json:"kubeVersion,omitempty"`
|
||||
KubeVersion string `json:"kubeVersion,omitempty" yaml:"kubeVersion,omitempty"`
|
||||
}
|
||||
|
||||
// ValueFile represents one Helm value file produced from CUE.
|
||||
type ValueFile struct {
|
||||
// Name represents the file name, e.g. "region-values.yaml"
|
||||
Name string `json:"name" yaml:"name"`
|
||||
// Kind is a discriminator.
|
||||
Kind string `json:"kind" yaml:"kind" cue:"\"Values\""`
|
||||
// Values represents values for holos to marshal into the file name specified
|
||||
// by Name when rendering the chart.
|
||||
Values Values `json:"values,omitempty" yaml:"values,omitempty"`
|
||||
}
|
||||
|
||||
// Values represents [Helm] Chart values generated from CUE.
|
||||
@@ -145,19 +175,36 @@ type Values map[string]any
|
||||
// Chart represents a [Helm] Chart.
|
||||
type Chart struct {
|
||||
// Name represents the chart name.
|
||||
Name string `json:"name"`
|
||||
Name string `json:"name" yaml:"name"`
|
||||
// Version represents the chart version.
|
||||
Version string `json:"version"`
|
||||
Version string `json:"version" yaml:"version"`
|
||||
// Release represents the chart release when executing helm template.
|
||||
Release string `json:"release"`
|
||||
Release string `json:"release" yaml:"release"`
|
||||
// Repository represents the repository to fetch the chart from.
|
||||
Repository Repository `json:"repository,omitempty"`
|
||||
Repository Repository `json:"repository,omitempty" yaml:"repository,omitempty"`
|
||||
}
|
||||
|
||||
// Repository represents a [Helm] [Chart] repository.
|
||||
//
|
||||
// The Auth field is useful to configure http basic authentication to the Helm
|
||||
// repository. Holos gets the username and password from the environment
|
||||
// variables represented by the Auth field.
|
||||
type Repository struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
Name string `json:"name" yaml:"name"`
|
||||
URL string `json:"url" yaml:"url"`
|
||||
Auth Auth `json:"auth,omitempty" yaml:"auth,omitempty"`
|
||||
}
|
||||
|
||||
// Auth represents environment variable names containing auth credentials.
|
||||
type Auth struct {
|
||||
Username AuthSource `json:"username" yaml:"username"`
|
||||
Password AuthSource `json:"password" yaml:"password"`
|
||||
}
|
||||
|
||||
// AuthSource represents a source for the value of an [Auth] field.
|
||||
type AuthSource struct {
|
||||
Value string `json:"value,omitempty" yaml:"value,omitempty"`
|
||||
FromEnv string `json:"fromEnv,omitempty" yaml:"fromEnv,omitempty"`
|
||||
}
|
||||
|
||||
// Transformer combines multiple inputs from prior [Generator] or [Transformer]
|
||||
@@ -171,17 +218,17 @@ type Repository struct {
|
||||
// [Introduction to Kustomize]: https://kubectl.docs.kubernetes.io/guides/config_management/introduction/
|
||||
type Transformer struct {
|
||||
// Kind represents the kind of transformer. Must be Kustomize, or Join.
|
||||
Kind string `json:"kind" cue:"\"Kustomize\" | \"Join\""`
|
||||
Kind string `json:"kind" yaml:"kind" cue:"\"Kustomize\" | \"Join\""`
|
||||
// Inputs represents the files to transform. The Output of prior Generators
|
||||
// and Transformers.
|
||||
Inputs []FilePath `json:"inputs"`
|
||||
Inputs []FilePath `json:"inputs" yaml:"inputs"`
|
||||
// Output represents a file for a subsequent Transformer or Artifact to
|
||||
// consume.
|
||||
Output FilePath `json:"output"`
|
||||
Output FilePath `json:"output" yaml:"output"`
|
||||
// Kustomize transformer. Ignored unless kind is Kustomize.
|
||||
Kustomize Kustomize `json:"kustomize,omitempty"`
|
||||
Kustomize Kustomize `json:"kustomize,omitempty" yaml:"kustomize,omitempty"`
|
||||
// Join transformer. Ignored unless kind is Join.
|
||||
Join Join `json:"join,omitempty"`
|
||||
Join Join `json:"join,omitempty" yaml:"join,omitempty"`
|
||||
}
|
||||
|
||||
// Join represents a [Transformer] using [bytes.Join] to concatenate multiple
|
||||
@@ -191,15 +238,15 @@ type Transformer struct {
|
||||
//
|
||||
// [bytes.Join]: https://pkg.go.dev/bytes#Join
|
||||
type Join struct {
|
||||
Separator string `json:"separator" cue:"string | *\"---\\n\""`
|
||||
Separator string `json:"separator,omitempty" yaml:"separator,omitempty"`
|
||||
}
|
||||
|
||||
// Kustomize represents a kustomization [Transformer].
|
||||
type Kustomize struct {
|
||||
// Kustomization represents the decoded kustomization.yaml file
|
||||
Kustomization Kustomization `json:"kustomization"`
|
||||
Kustomization Kustomization `json:"kustomization" yaml:"kustomization"`
|
||||
// Files holds file contents for kustomize, e.g. patch files.
|
||||
Files FileContentMap `json:"files,omitempty"`
|
||||
Files FileContentMap `json:"files,omitempty" yaml:"files,omitempty"`
|
||||
}
|
||||
|
||||
// Kustomization represents a kustomization.yaml file for use with the
|
||||
@@ -208,15 +255,37 @@ type Kustomize struct {
|
||||
// is expected to happen in CUE against the kubectl version the user prefers.
|
||||
type Kustomization map[string]any
|
||||
|
||||
// FileContent represents file contents.
|
||||
type FileContent string
|
||||
|
||||
// FileContentMap represents a mapping of file paths to file contents.
|
||||
type FileContentMap map[FilePath]FileContent
|
||||
|
||||
// FilePath represents a file path.
|
||||
type FilePath string
|
||||
|
||||
// FileContent represents file contents.
|
||||
type FileContent string
|
||||
|
||||
// Validator validates files. Useful to validate an [Artifact] prior to writing
|
||||
// it out to the final destination. Holos may execute validators concurrently.
|
||||
// See the [validators] tutorial for an end to end example.
|
||||
//
|
||||
// [validators]: https://holos.run/docs/v1alpha5/tutorial/validators/
|
||||
type Validator struct {
|
||||
// Kind represents the kind of transformer. Must be Kustomize, or Join.
|
||||
Kind string `json:"kind" yaml:"kind" cue:"\"Command\""`
|
||||
// Inputs represents the files to validate. Usually the final Artifact.
|
||||
Inputs []FilePath `json:"inputs" yaml:"inputs"`
|
||||
// Command represents a validation command. Ignored unless kind is Command.
|
||||
Command Command `json:"command,omitempty" yaml:"command,omitempty"`
|
||||
}
|
||||
|
||||
// Command represents a command vetting one or more artifacts. Holos appends
|
||||
// fully qualified input file paths to the end of the args list, then executes
|
||||
// the command. Inputs are written into a temporary directory prior to
|
||||
// executing the command and removed afterwards.
|
||||
type Command struct {
|
||||
Args []string `json:"args,omitempty" yaml:"args,omitempty"`
|
||||
}
|
||||
|
||||
// InternalLabel is an arbitrary unique identifier internal to holos itself.
|
||||
// The holos cli is expected to never write a InternalLabel value to rendered
|
||||
// output files, therefore use a InternalLabel when the identifier must be
|
||||
@@ -229,7 +298,13 @@ type Kind string
|
||||
// Metadata represents data about the resource such as the Name.
|
||||
type Metadata struct {
|
||||
// Name represents the resource name.
|
||||
Name string `json:"name"`
|
||||
Name string `json:"name" yaml:"name"`
|
||||
// Labels represents a resource selector.
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
// Annotations represents arbitrary non-identifying metadata. For example
|
||||
// holos uses the `app.holos.run/description` annotation to log resources in a
|
||||
// user customized way.
|
||||
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
|
||||
}
|
||||
|
||||
// Platform represents a platform to manage. A Platform specifies a [Component]
|
||||
@@ -242,20 +317,20 @@ type Metadata struct {
|
||||
// cue export --out yaml ./platform
|
||||
type Platform struct {
|
||||
// Kind is a string value representing the resource.
|
||||
Kind string `json:"kind" cue:"\"Platform\""`
|
||||
Kind string `json:"kind" yaml:"kind" cue:"\"Platform\""`
|
||||
// APIVersion represents the versioned schema of this resource.
|
||||
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha5\""`
|
||||
APIVersion string `json:"apiVersion" yaml:"apiVersion" cue:"string | *\"v1alpha5\""`
|
||||
// Metadata represents data about the resource such as the Name.
|
||||
Metadata Metadata `json:"metadata"`
|
||||
Metadata Metadata `json:"metadata" yaml:"metadata"`
|
||||
|
||||
// Spec represents the platform specification.
|
||||
Spec PlatformSpec `json:"spec"`
|
||||
Spec PlatformSpec `json:"spec" yaml:"spec"`
|
||||
}
|
||||
|
||||
// PlatformSpec represents the platform specification.
|
||||
type PlatformSpec struct {
|
||||
// Components represents a collection of holos components to manage.
|
||||
Components []Component `json:"components"`
|
||||
Components []Component `json:"components" yaml:"components"`
|
||||
}
|
||||
|
||||
// Component represents the complete context necessary to produce a [BuildPlan]
|
||||
@@ -263,17 +338,51 @@ type PlatformSpec struct {
|
||||
type Component struct {
|
||||
// Name represents the name of the component. Injected as the tag variable
|
||||
// "holos_component_name".
|
||||
Name string `json:"name"`
|
||||
Name string `json:"name" yaml:"name"`
|
||||
// Path represents the path of the component relative to the platform root.
|
||||
// Injected as the tag variable "holos_component_path".
|
||||
Path string `json:"path"`
|
||||
Path string `json:"path" yaml:"path"`
|
||||
// Instances represents additional cue instance paths to unify with Path.
|
||||
// Useful to unify data files into a component BuildPlan. Added in holos
|
||||
// 0.101.7.
|
||||
Instances []Instance `json:"instances,omitempty" yaml:"instances,omitempty"`
|
||||
// WriteTo represents the holos render component --write-to flag. If empty,
|
||||
// the default value for the --write-to flag is used.
|
||||
WriteTo string `json:"writeTo,omitempty"`
|
||||
WriteTo string `json:"writeTo,omitempty" yaml:"writeTo,omitempty"`
|
||||
// Parameters represent user defined input variables to produce various
|
||||
// [BuildPlan] resources from one component path. Injected as CUE @tag
|
||||
// variables. Parameters with a "holos_" prefix are reserved for use by the
|
||||
// Holos Authors. Multiple environments are a prime example of an input
|
||||
// parameter that should always be user defined, never defined by Holos.
|
||||
Parameters map[string]string `json:"parameters,omitempty"`
|
||||
Parameters map[string]string `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||
// Labels represent selector labels for the component. Copied to the
|
||||
// resulting BuildPlan.
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
// Annotations represents arbitrary non-identifying metadata. Use the
|
||||
// `app.holos.run/description` to customize the log message of each BuildPlan.
|
||||
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
|
||||
}
|
||||
|
||||
// Instance represents a data instance to unify with the configuration.
|
||||
//
|
||||
// Useful to unify json and yaml files with cue configuration files for
|
||||
// integration with other tools. For example, executing holos render platform
|
||||
// from a pull request workflow after [Kargo] executes the [yaml update] and
|
||||
// [git wait for pr] promotion steps.
|
||||
//
|
||||
// [Kargo]: https://docs.kargo.io/
|
||||
// [yaml update]: https://docs.kargo.io/references/promotion-steps#yaml-update
|
||||
// [git wait for pr]: https://docs.kargo.io/references/promotion-steps#git-wait-for-pr
|
||||
type Instance struct {
|
||||
// Kind is a discriminator.
|
||||
Kind string `json:"kind" yaml:"kind" cue:"\"ExtractYAML\""`
|
||||
// Ignored unless kind is ExtractYAML.
|
||||
ExtractYAML ExtractYAML `json:"extractYAML,omitempty" yaml:"extractYAML,omitempty"`
|
||||
}
|
||||
|
||||
// ExtractYAML represents a cue data instance encoded as yaml or json. If Path
|
||||
// refers to a directory all files in the directory are extracted
|
||||
// non-recursively. Otherwise, path must refer to a file.
|
||||
type ExtractYAML struct {
|
||||
Path string `json:"path" yaml:"path"`
|
||||
}
|
||||
|
||||
5
api/core/v1alpha6/header.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: Core Schemas
|
||||
description: BuildPlan defines the holos rendering pipeline.
|
||||
sidebar_position: 100
|
||||
---
|
||||
457
api/core/v1alpha6/types.go
Normal file
@@ -0,0 +1,457 @@
|
||||
// Package core contains schemas for a [Platform] and [BuildPlan]. Holos takes
|
||||
// a [Platform] as input, then iterates over each [Component] to produce a
|
||||
// [BuildPlan]. Holos processes the [BuildPlan] to produce fully rendered
|
||||
// manifests, each an [Artifact].
|
||||
package core
|
||||
|
||||
// BuildContextTag represents the cue tag holos render component uses to inject
|
||||
// the json representation of a [BuildContext] for use in a BuildPlan.
|
||||
const BuildContextTag string = "holos_build_context"
|
||||
|
||||
// ComponentNameTag represents the cue tag holos uses to inject a [Component]
|
||||
// name from the holos render platform command to the holos render component
|
||||
// command.
|
||||
const ComponentNameTag string = "holos_component_name"
|
||||
|
||||
// ComponentPathTag represents the cue tag holos uses to inject a [Component]
|
||||
// path relative to the cue module root from the holos render platform command
|
||||
// to the holos render component command.
|
||||
const ComponentPathTag string = "holos_component_path"
|
||||
|
||||
// ComponentLabelsTag represents the cue tag holos uses to inject the json
|
||||
// representation of [Component] metadata labels from the holos render platform
|
||||
// command to the holos render component command.
|
||||
const ComponentLabelsTag string = "holos_component_labels"
|
||||
|
||||
// ComponentAnnotationsTag represents the tag holos uses to inject the json
|
||||
// representation of [Component] metadata annotations from the holos render
|
||||
// platform command to the holos render component command.
|
||||
const ComponentAnnotationsTag = "holos_component_annotations"
|
||||
|
||||
//go:generate ../../../hack/gendoc
|
||||
|
||||
// BuildPlan represents an implementation of the [rendered manifest pattern].
|
||||
// Holos processes a BuildPlan to produce one or more [Artifact] output files.
|
||||
// BuildPlan artifact files usually contain Kubernetes manifests, but they may
|
||||
// have any content.
|
||||
//
|
||||
// A BuildPlan usually produces two artifacts. One artifact contains a manifest
|
||||
// of resources. A second artifact contains a GitOps resource to manage the
|
||||
// first, usually an ArgoCD Application resource.
|
||||
//
|
||||
// Holos uses CUE to construct a BuildPlan. Holos injects late binding values
|
||||
// such as the build temp dir using the [BuildContext].
|
||||
//
|
||||
// [rendered manifest pattern]: https://akuity.io/blog/the-rendered-manifests-pattern
|
||||
//
|
||||
// [external credential provider]: https://github.com/kubernetes/enhancements/blob/313ad8b59c80819659e1fbf0f165230f633f2b22/keps/sig-auth/541-external-credential-providers/README.md
|
||||
type BuildPlan struct {
|
||||
// APIVersion represents the versioned schema of the resource.
|
||||
APIVersion string `json:"apiVersion" yaml:"apiVersion" cue:"\"v1alpha6\""`
|
||||
// Kind represents the type of the resource.
|
||||
Kind string `json:"kind" yaml:"kind" cue:"\"BuildPlan\""`
|
||||
// Metadata represents data about the resource such as the Name.
|
||||
Metadata Metadata `json:"metadata" yaml:"metadata"`
|
||||
// Spec specifies the desired state of the resource.
|
||||
Spec BuildPlanSpec `json:"spec" yaml:"spec"`
|
||||
// BuildContext represents values injected by holos just before evaluating a
|
||||
// BuildPlan, for example the tempDir used for the build.
|
||||
BuildContext BuildContext `json:"buildContext" yaml:"buildContext"`
|
||||
}
|
||||
|
||||
// BuildContext represents build context values owned by the holos render
|
||||
// component command. End users should not manage context field values. End
|
||||
// users may reference fields from within CUE to refer to late binding
|
||||
// concrete values defined just before holos executes a [BuildPlan].
|
||||
//
|
||||
// Holos injects build context values by marshalling this struct to json through
|
||||
// the holos_build_context cue tag.
|
||||
//
|
||||
// Example usage from cue to produce a [BuildPlan]:
|
||||
//
|
||||
// package holos
|
||||
//
|
||||
// import (
|
||||
// "encoding/json"
|
||||
// "github.com/holos-run/holos/api/core/v1alpha6:core"
|
||||
// )
|
||||
//
|
||||
// _BuildContextJSON: string | *"{}" @tag(holos_build_context, type=string)
|
||||
// BuildContext: core.#BuildContext & json.Unmarshal(_BuildContextJSON)
|
||||
//
|
||||
// holos: core.#BuildPlan & {
|
||||
// buildContext: BuildContext
|
||||
// "spec": {
|
||||
// "artifacts": [
|
||||
// {
|
||||
// artifact: "components/slice",
|
||||
// "transformers": [
|
||||
// {
|
||||
// "kind": "Command"
|
||||
// "inputs": ["resources.gen.yaml"]
|
||||
// "output": artifact
|
||||
// "command": {
|
||||
// "args": [
|
||||
// "kubectl-slice",
|
||||
// "-f",
|
||||
// "\(buildContext.tempDir)/resources.gen.yaml",
|
||||
// "-o",
|
||||
// "\(buildContext.tempDir)/\(artifact)",
|
||||
// ]
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// }
|
||||
type BuildContext struct {
|
||||
// TempDir represents the temporary directory managed and owned by the holos
|
||||
// render component command for the execution of one BuildPlan. Multiple
|
||||
// tasks in the build plan share this temporary directory and therefore should
|
||||
// avoid reading and writing into the same sub-directories as one another.
|
||||
TempDir string `json:"tempDir" yaml:"tempDir" cue:"string | *\"${TEMP_DIR_PLACEHOLDER}\""`
|
||||
// RootDir represents the fully qualified path to the platform root directory.
|
||||
// Useful to construct arguments for commands in BuildPlan tasks.
|
||||
RootDir string `json:"rootDir" yaml:"rootDir" cue:"string | *\"${ROOT_DIR_PLACEHOLDER}\""`
|
||||
// LeafDir represents the cleaned path to the holos component relative to the
|
||||
// platform root. Useful to construct arguments for commands in BuildPlan
|
||||
// tasks.
|
||||
LeafDir string `json:"leafDir" yaml:"leafDir" cue:"string | *\"${LEAF_DIR_PLACEHOLDER}\""`
|
||||
// HolosExecutable represents the fully qualified path to the holos
|
||||
// executable. Useful to execute tools embedded as subcommands such as holos
|
||||
// cue vet.
|
||||
HolosExecutable string `json:"holosExecutable" yaml:"holosExecutable" cue:"string | *\"holos\""`
|
||||
}
|
||||
|
||||
// TODO(jjm): Decide if RootDir and LeafDir are useful. We have
|
||||
// [Component.Path] and [Command] executes with the platform root as the current
|
||||
// working directory.
|
||||
|
||||
// BuildPlanSpec represents the specification of the [BuildPlan].
|
||||
type BuildPlanSpec struct {
|
||||
// Artifacts represents the artifacts for holos to build.
|
||||
Artifacts []Artifact `json:"artifacts" yaml:"artifacts"`
|
||||
// Disabled causes the holos render platform command to skip the BuildPlan.
|
||||
Disabled bool `json:"disabled,omitempty" yaml:"disabled,omitempty"`
|
||||
}
|
||||
|
||||
// Artifact represents one fully rendered manifest produced by a [Transformer]
|
||||
// sequence, which transforms a [Generator] collection. A [BuildPlan] produces
|
||||
// an [Artifact] collection.
|
||||
//
|
||||
// Each Artifact produces one manifest file or directory artifact. Generator
|
||||
// Output values are used as Transformer Inputs. The Output field of the final
|
||||
// [Transformer] should have the same value as the Artifact field.
|
||||
//
|
||||
// When there is more than one [Generator] there should be at least one
|
||||
// [Transformer] to combine outputs into one Artifact file, or the final
|
||||
// artifact should be a directory containing the outputs of the generators. If
|
||||
// there is a single Generator, it may directly produce the Artifact output.
|
||||
//
|
||||
// An Artifact is processed concurrently with other artifacts in the same
|
||||
// [BuildPlan]. One Artifact must not use an output of another Artifact as an
|
||||
// input. Each [Generator] within an artifact also runs concurrently with
|
||||
// generators of the same artifact. Each [Transformer] is executed sequentially
|
||||
// starting after all generators have completed.
|
||||
//
|
||||
// Output fields are write-once. It is an error for multiple Generators or
|
||||
// Transformers to produce the same Output value within the context of a
|
||||
// [BuildPlan].
|
||||
//
|
||||
// When directories are used as inputs or outputs, they behave similar to how
|
||||
// `git` works with directories. When the output field references a directory,
|
||||
// all files within the directory are recursively stored using their relative
|
||||
// path as a key. Similar to git add . When the input field references an
|
||||
// absent file, a / is appended and the resulting value is used as a prefix
|
||||
// match against all previous task outputs.
|
||||
type Artifact struct {
|
||||
Artifact FileOrDirectoryPath `json:"artifact,omitempty" yaml:"artifact,omitempty"`
|
||||
Generators []Generator `json:"generators,omitempty" yaml:"generators,omitempty"`
|
||||
Transformers []Transformer `json:"transformers,omitempty" yaml:"transformers,omitempty"`
|
||||
Validators []Validator `json:"validators,omitempty" yaml:"validators,omitempty"`
|
||||
Skip bool `json:"skip,omitempty" yaml:"skip,omitempty"`
|
||||
}
|
||||
|
||||
// Generator generates Kubernetes resources. [Helm] and [Resources] are the
|
||||
// most commonly used, often paired together to mix-in resources to an
|
||||
// unmodified Helm chart. A simple [File] generator is also available for use
|
||||
// with the [Kustomize] transformer.
|
||||
//
|
||||
// Each Generator in an [Artifact] must have a distinct Output value for a
|
||||
// [Transformer] to reference.
|
||||
//
|
||||
// 1. [Resources] - Generates resources from CUE code.
|
||||
// 2. [Helm] - Generates rendered yaml from a [Chart].
|
||||
// 3. [File] - Generates data by reading a file from the component directory.
|
||||
// 4. [Command] - Generates data by executing an user defined command.
|
||||
type Generator struct {
|
||||
// Kind represents the kind of generator. Must be Resources, Helm, or File.
|
||||
Kind string `json:"kind" yaml:"kind" cue:"\"Resources\" | \"Helm\" | \"File\" | \"Command\""`
|
||||
// Output represents a file for a Transformer or Artifact to consume.
|
||||
Output FileOrDirectoryPath `json:"output" yaml:"output"`
|
||||
// Resources generator. Ignored unless kind is Resources. Resources are
|
||||
// stored as a two level struct. The top level key is the Kind of resource,
|
||||
// e.g. Namespace or Deployment. The second level key is an arbitrary
|
||||
// InternalLabel. The third level is a map[string]any representing the
|
||||
// Resource.
|
||||
Resources Resources `json:"resources,omitempty" yaml:"resources,omitempty"`
|
||||
// Helm generator. Ignored unless kind is Helm.
|
||||
Helm Helm `json:"helm,omitempty" yaml:"helm,omitempty"`
|
||||
// File generator. Ignored unless kind is File.
|
||||
File File `json:"file,omitempty" yaml:"file,omitempty"`
|
||||
// Command generator. Ignored unless kind is Command.
|
||||
Command Command `json:"command,omitempty" yaml:"command,omitempty"`
|
||||
}
|
||||
|
||||
// Resource represents one kubernetes api object.
|
||||
type Resource map[string]any
|
||||
|
||||
// Resources represents Kubernetes resources. Most commonly used to mix
|
||||
// resources into the [BuildPlan] generated from CUE, but may be generated from
|
||||
// elsewhere.
|
||||
type Resources map[Kind]map[InternalLabel]Resource
|
||||
|
||||
// File represents a simple single file copy [Generator]. Useful with a
|
||||
// [Kustomize] [Transformer] to process plain manifest files stored in the
|
||||
// component directory. Multiple File generators may be used to transform
|
||||
// multiple resources.
|
||||
type File struct {
|
||||
// Source represents a file sub-path relative to the component path.
|
||||
Source FilePath `json:"source" yaml:"source"`
|
||||
}
|
||||
|
||||
// Helm represents a [Chart] manifest [Generator].
|
||||
type Helm struct {
|
||||
// Chart represents a helm chart to manage.
|
||||
Chart Chart `json:"chart" yaml:"chart"`
|
||||
// Values represents values for holos to marshal into values.yaml when
|
||||
// rendering the chart. Values follow ValueFiles when both are provided.
|
||||
Values Values `json:"values" yaml:"values"`
|
||||
// ValueFiles represents hierarchial value files passed in order to the helm
|
||||
// template -f flag. Useful for migration from an ApplicationSet. Use Values
|
||||
// instead. ValueFiles precede Values when both are provided.
|
||||
ValueFiles []ValueFile `json:"valueFiles,omitempty" yaml:"valueFiles,omitempty"`
|
||||
// EnableHooks enables helm hooks when executing the `helm template` command.
|
||||
EnableHooks bool `json:"enableHooks,omitempty" yaml:"enableHooks,omitempty"`
|
||||
// Namespace represents the helm namespace flag
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
// APIVersions represents the helm template --api-versions flag
|
||||
APIVersions []string `json:"apiVersions,omitempty" yaml:"apiVersions,omitempty"`
|
||||
// KubeVersion represents the helm template --kube-version flag
|
||||
KubeVersion string `json:"kubeVersion,omitempty" yaml:"kubeVersion,omitempty"`
|
||||
}
|
||||
|
||||
// ValueFile represents one Helm value file produced from CUE.
|
||||
type ValueFile struct {
|
||||
// Name represents the file name, e.g. "region-values.yaml"
|
||||
Name string `json:"name" yaml:"name"`
|
||||
// Kind is a discriminator.
|
||||
Kind string `json:"kind" yaml:"kind" cue:"\"Values\""`
|
||||
// Values represents values for holos to marshal into the file name specified
|
||||
// by Name when rendering the chart.
|
||||
Values Values `json:"values,omitempty" yaml:"values,omitempty"`
|
||||
}
|
||||
|
||||
// Values represents [Helm] Chart values generated from CUE.
|
||||
type Values map[string]any
|
||||
|
||||
// Chart represents a [Helm] Chart.
|
||||
type Chart struct {
|
||||
// Name represents the chart name.
|
||||
Name string `json:"name" yaml:"name"`
|
||||
// Version represents the chart version.
|
||||
Version string `json:"version" yaml:"version"`
|
||||
// Release represents the chart release when executing helm template.
|
||||
Release string `json:"release" yaml:"release"`
|
||||
// Repository represents the repository to fetch the chart from.
|
||||
Repository Repository `json:"repository,omitempty" yaml:"repository,omitempty"`
|
||||
}
|
||||
|
||||
// Repository represents a [Helm] [Chart] repository.
|
||||
//
|
||||
// The Auth field is useful to configure http basic authentication to the Helm
|
||||
// repository. Holos gets the username and password from the environment
|
||||
// variables represented by the Auth field.
|
||||
type Repository struct {
|
||||
Name string `json:"name" yaml:"name"`
|
||||
URL string `json:"url" yaml:"url"`
|
||||
Auth Auth `json:"auth,omitempty" yaml:"auth,omitempty"`
|
||||
}
|
||||
|
||||
// Auth represents environment variable names containing auth credentials.
|
||||
type Auth struct {
|
||||
Username AuthSource `json:"username" yaml:"username"`
|
||||
Password AuthSource `json:"password" yaml:"password"`
|
||||
}
|
||||
|
||||
// AuthSource represents a source for the value of an [Auth] field.
|
||||
type AuthSource struct {
|
||||
Value string `json:"value,omitempty" yaml:"value,omitempty"`
|
||||
FromEnv string `json:"fromEnv,omitempty" yaml:"fromEnv,omitempty"`
|
||||
}
|
||||
|
||||
// Transformer combines multiple inputs from prior [Generator] or [Transformer]
|
||||
// outputs into one output. [Kustomize] is the most commonly used transformer.
|
||||
// A simple [Join] is also supported for use with plain manifest files.
|
||||
//
|
||||
// 1. [Kustomize] - Patch and transform the output from prior generators or
|
||||
// transformers. See [Introduction to Kustomize].
|
||||
// 2. [Join] - Concatenate multiple prior outputs into one output.
|
||||
// 3. [Command] - Transforms data by executing an user defined command.
|
||||
//
|
||||
// [Introduction to Kustomize]: https://kubectl.docs.kubernetes.io/guides/config_management/introduction/
|
||||
type Transformer struct {
|
||||
// Kind represents the kind of transformer. Must be Kustomize, or Join.
|
||||
Kind string `json:"kind" yaml:"kind" cue:"\"Kustomize\" | \"Join\" | \"Command\""`
|
||||
// Inputs represents the files to transform. The Output of prior Generators
|
||||
// and Transformers.
|
||||
Inputs []FileOrDirectoryPath `json:"inputs" yaml:"inputs"`
|
||||
// Output represents a file or directory for a subsequent Transformer or
|
||||
// Artifact to consume.
|
||||
Output FileOrDirectoryPath `json:"output" yaml:"output"`
|
||||
// Kustomize transformer. Ignored unless kind is Kustomize.
|
||||
Kustomize Kustomize `json:"kustomize,omitempty" yaml:"kustomize,omitempty"`
|
||||
// Join transformer. Ignored unless kind is Join.
|
||||
Join Join `json:"join,omitempty" yaml:"join,omitempty"`
|
||||
// Command transformer. Ignored unless kind is Command.
|
||||
Command Command `json:"command,omitempty" yaml:"command,omitempty"`
|
||||
}
|
||||
|
||||
// Join represents a [Transformer] using [bytes.Join] to concatenate multiple
|
||||
// inputs into one output with a separator. Useful for combining output from
|
||||
// [Helm] and [Resources] together into one [Artifact] when [Kustomize] is
|
||||
// otherwise unnecessary.
|
||||
//
|
||||
// [bytes.Join]: https://pkg.go.dev/bytes#Join
|
||||
type Join struct {
|
||||
Separator string `json:"separator,omitempty" yaml:"separator,omitempty"`
|
||||
}
|
||||
|
||||
// Kustomize represents a kustomization [Transformer].
|
||||
type Kustomize struct {
|
||||
// Kustomization represents the decoded kustomization.yaml file
|
||||
Kustomization Kustomization `json:"kustomization" yaml:"kustomization"`
|
||||
// Files holds file contents for kustomize, e.g. patch files.
|
||||
Files FileContentMap `json:"files,omitempty" yaml:"files,omitempty"`
|
||||
}
|
||||
|
||||
// Kustomization represents a kustomization.yaml file for use with the
|
||||
// [Kustomize] [Transformer]. Untyped to avoid tightly coupling holos to
|
||||
// kubectl versions which was a problem for the Flux maintainers. Type checking
|
||||
// is expected to happen in CUE against the kubectl version the user prefers.
|
||||
type Kustomization map[string]any
|
||||
|
||||
// FileContentMap represents a mapping of file paths to file contents.
|
||||
type FileContentMap map[FilePath]FileContent
|
||||
|
||||
// FilePath represents a file path.
|
||||
type FilePath string
|
||||
|
||||
// FileOrDirectoryPath represents a file or a directory path.
|
||||
type FileOrDirectoryPath string
|
||||
|
||||
// FileContent represents file contents.
|
||||
type FileContent string
|
||||
|
||||
// Validator validates files. Useful to validate an [Artifact] prior to writing
|
||||
// it out to the final destination. Holos may execute validators concurrently.
|
||||
// See the [validators] tutorial for an end to end example.
|
||||
//
|
||||
// [validators]: https://holos.run/docs/v1alpha6/tutorial/validators/
|
||||
type Validator struct {
|
||||
// Kind represents the kind of transformer. Must be Kustomize, or Join.
|
||||
Kind string `json:"kind" yaml:"kind" cue:"\"Command\""`
|
||||
// Inputs represents the files to validate. Usually the final Artifact.
|
||||
Inputs []FileOrDirectoryPath `json:"inputs" yaml:"inputs"`
|
||||
// Command validator. Ignored unless kind is Command.
|
||||
Command Command `json:"command,omitempty" yaml:"command,omitempty"`
|
||||
}
|
||||
|
||||
// Command represents a [BuildPlan] task implemented by executing an user
|
||||
// defined system command. A task is defined as a [Generator], [Transformer],
|
||||
// or [Validator]. Commands are executed with the working directory set to the
|
||||
// platform root.
|
||||
type Command struct {
|
||||
// DisplayName of the command. The basename of args[0] is used if empty.
|
||||
DisplayName string `json:"displayName,omitempty" yaml:"displayName,omitempty"`
|
||||
// Args represents the argument vector passed to the os. to execute the
|
||||
// command.
|
||||
Args []string `json:"args,omitempty" yaml:"args,omitempty"`
|
||||
// IsStdoutOutput captures the command stdout as the task output if true.
|
||||
IsStdoutOutput bool `json:"isStdoutOutput,omitempty" yaml:"isStdoutOutput,omitempty"`
|
||||
}
|
||||
|
||||
// NameLabel indicates a field name matching the name of the value. Usually the
|
||||
// name or metadata.name field of the struct value.
|
||||
type NameLabel string
|
||||
|
||||
// InternalLabel is an arbitrary unique identifier internal to holos itself.
|
||||
// The holos cli is expected to never write a InternalLabel value to rendered
|
||||
// output files, therefore use a InternalLabel when the identifier must be
|
||||
// unique and internal. Defined as a type for clarity and type checking.
|
||||
type InternalLabel string
|
||||
|
||||
// Kind is a discriminator. Defined as a type for clarity and type checking.
|
||||
type Kind string
|
||||
|
||||
// Metadata represents data about the resource such as the Name.
|
||||
type Metadata struct {
|
||||
// Name represents the resource name.
|
||||
Name string `json:"name" yaml:"name"`
|
||||
// Labels represents a resource selector.
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
// Annotations represents arbitrary non-identifying metadata. For example
|
||||
// holos uses the `app.holos.run/description` annotation to log resources in a
|
||||
// user customized way.
|
||||
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
|
||||
}
|
||||
|
||||
// Platform represents a platform to manage. A Platform specifies a [Component]
|
||||
// collection and integrates the components together into a holistic platform.
|
||||
// Holos iterates over the [Component] collection producing a [BuildPlan] for
|
||||
// each, which holos then executes to render manifests.
|
||||
//
|
||||
// Inspect a Platform resource holos would process by executing:
|
||||
//
|
||||
// cue export --out yaml ./platform
|
||||
type Platform struct {
|
||||
// APIVersion represents the versioned schema of this resource.
|
||||
APIVersion string `json:"apiVersion" yaml:"apiVersion" cue:"string | *\"v1alpha6\""`
|
||||
// Kind is a string value representing the resource.
|
||||
Kind string `json:"kind" yaml:"kind" cue:"\"Platform\""`
|
||||
// Metadata represents data about the resource such as the Name.
|
||||
Metadata Metadata `json:"metadata" yaml:"metadata"`
|
||||
|
||||
// Spec represents the platform specification.
|
||||
Spec PlatformSpec `json:"spec" yaml:"spec"`
|
||||
}
|
||||
|
||||
// PlatformSpec represents the platform specification.
|
||||
type PlatformSpec struct {
|
||||
// Components represents a collection of holos components to manage.
|
||||
Components map[NameLabel]Component `json:"components" yaml:"components" cue:"{[NAME=string]: name: NAME}"`
|
||||
}
|
||||
|
||||
// Component represents the complete context necessary to produce a [BuildPlan]
|
||||
// from a path containing parameterized CUE configuration.
|
||||
type Component struct {
|
||||
// Name represents the name of the component. Injected as the tag variable
|
||||
// "holos_component_name".
|
||||
Name string `json:"name" yaml:"name"`
|
||||
// Path represents the path of the component relative to the platform root.
|
||||
// Injected as the tag variable "holos_component_path".
|
||||
Path string `json:"path" yaml:"path"`
|
||||
// Parameters represent user defined input variables to produce various
|
||||
// [BuildPlan] resources from one component path. Injected as CUE @tag
|
||||
// variables. Parameters with a "holos_" prefix are reserved for use by the
|
||||
// Holos Authors. Multiple environments are a prime example of an input
|
||||
// parameter that should always be user defined, never defined by Holos.
|
||||
Parameters map[string]string `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||
// Labels represent selector labels for the component. Holos copies Labels
|
||||
// from the Component to the resulting BuildPlan.
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
// Annotations represents arbitrary non-identifying metadata. Use the
|
||||
// `app.holos.run/description` to customize the log message of each BuildPlan.
|
||||
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package v1alpha2
|
||||
|
||||
// TypeMeta describes an individual object in an API response or request with
|
||||
// strings representing the type of the object and its API schema version.
|
||||
// Structures that are versioned or persisted should inline TypeMeta.
|
||||
type TypeMeta struct {
|
||||
// Kind is a string value representing the resource this object represents.
|
||||
Kind string `json:"kind"`
|
||||
// APIVersion defines the versioned schema of this representation of an object.
|
||||
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha2\""`
|
||||
}
|
||||
|
||||
func (tm *TypeMeta) GetKind() string {
|
||||
return tm.Kind
|
||||
}
|
||||
|
||||
func (tm *TypeMeta) GetAPIVersion() string {
|
||||
return tm.APIVersion
|
||||
}
|
||||
|
||||
// Discriminator discriminates the kind of an api object.
|
||||
type Discriminator interface {
|
||||
// GetKind returns Kind.
|
||||
GetKind() string
|
||||
// GetAPIVersion returns APIVersion.
|
||||
GetAPIVersion() string
|
||||
}
|
||||
|
||||
// ObjectMeta represents metadata of a holos component object. The fields are a
|
||||
// copy of upstream kubernetes api machinery but are holos objects distinct from
|
||||
// kubernetes api objects.
|
||||
type ObjectMeta struct {
|
||||
// Name uniquely identifies the holos component instance and must be suitable as a file name.
|
||||
Name string `json:"name,omitempty"`
|
||||
// Namespace confines a holos component to a single namespace via kustomize if set.
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// BuildPlan is the primary interface between CUE and the Holos cli.
|
||||
type BuildPlan struct {
|
||||
TypeMeta `json:",inline" yaml:",inline"`
|
||||
// Metadata represents the holos component name
|
||||
Metadata ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||
Spec BuildPlanSpec `json:"spec,omitempty" yaml:"spec,omitempty"`
|
||||
}
|
||||
|
||||
type BuildPlanSpec struct {
|
||||
Disabled bool `json:"disabled,omitempty" yaml:"disabled,omitempty"`
|
||||
Components BuildPlanComponents `json:"components,omitempty" yaml:"components,omitempty"`
|
||||
// DeployFiles keys represent file paths relative to the cluster deploy
|
||||
// directory. Map values represent the string encoded file contents. Used to
|
||||
// write the argocd Application, but may be used to render any file from CUE.
|
||||
DeployFiles FileContentMap `json:"deployFiles,omitempty" yaml:"deployFiles,omitempty"`
|
||||
}
|
||||
|
||||
type BuildPlanComponents struct {
|
||||
HelmChartList []HelmChart `json:"helmChartList,omitempty" yaml:"helmChartList,omitempty"`
|
||||
KubernetesObjectsList []KubernetesObjects `json:"kubernetesObjectsList,omitempty" yaml:"kubernetesObjectsList,omitempty"`
|
||||
KustomizeBuildList []KustomizeBuild `json:"kustomizeBuildList,omitempty" yaml:"kustomizeBuildList,omitempty"`
|
||||
Resources map[string]KubernetesObjects `json:"resources,omitempty" yaml:"resources,omitempty"`
|
||||
}
|
||||
|
||||
func (bp *BuildPlan) Validate() error {
|
||||
errs := make([]string, 0, 2)
|
||||
if bp.Kind != BuildPlanKind {
|
||||
errs = append(errs, fmt.Sprintf("kind invalid: want: %s have: %s", BuildPlanKind, bp.Kind))
|
||||
}
|
||||
if bp.APIVersion != APIVersion {
|
||||
errs = append(errs, fmt.Sprintf("apiVersion invalid: want: %s have: %s", APIVersion, bp.APIVersion))
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return errors.New("invalid BuildPlan: " + strings.Join(errs, ", "))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bp *BuildPlan) ResultCapacity() (count int) {
|
||||
if bp == nil {
|
||||
return 0
|
||||
}
|
||||
count = len(bp.Spec.Components.HelmChartList) +
|
||||
len(bp.Spec.Components.KubernetesObjectsList) +
|
||||
len(bp.Spec.Components.KustomizeBuildList) +
|
||||
len(bp.Spec.Components.Resources)
|
||||
return count
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package v1alpha1
|
||||
|
||||
// HolosComponent defines the fields common to all holos component kinds including the Render Result.
|
||||
type HolosComponent struct {
|
||||
TypeMeta `json:",inline" yaml:",inline"`
|
||||
// Metadata represents the holos component name
|
||||
Metadata ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||
// APIObjectMap holds the marshalled representation of api objects. Think of
|
||||
// these as resources overlaid at the back of the render pipeline.
|
||||
APIObjectMap APIObjectMap `json:"apiObjectMap,omitempty" yaml:"apiObjectMap,omitempty"`
|
||||
// Kustomization holds the marshalled representation of the flux kustomization
|
||||
// which reconciles resources in git with the api server.
|
||||
Kustomization `json:",inline" yaml:",inline"`
|
||||
// Kustomize represents a kubectl kustomize build post-processing step.
|
||||
Kustomize `json:",inline" yaml:",inline"`
|
||||
// Skip causes holos to take no action regarding the component.
|
||||
Skip bool
|
||||
}
|
||||
|
||||
func (hc *HolosComponent) NewResult() *Result {
|
||||
return &Result{HolosComponent: *hc}
|
||||
}
|
||||
|
||||
func (hc *HolosComponent) GetAPIVersion() string {
|
||||
return hc.APIVersion
|
||||
}
|
||||
|
||||
func (hc *HolosComponent) GetKind() string {
|
||||
return hc.Kind
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package v1alpha1
|
||||
|
||||
const (
|
||||
APIVersion = "holos.run/v1alpha1"
|
||||
BuildPlanKind = "BuildPlan"
|
||||
HelmChartKind = "HelmChart"
|
||||
// ChartDir is the directory name created in the holos component directory to cache a chart.
|
||||
ChartDir = "vendor"
|
||||
// ResourcesFile is the file name used to store component output when post-processing with kustomize.
|
||||
ResourcesFile = "resources.yaml"
|
||||
)
|
||||
@@ -1,2 +0,0 @@
|
||||
// Package v1alpha1 defines the api boundary between CUE and Holos.
|
||||
package v1alpha1
|
||||
@@ -1,13 +0,0 @@
|
||||
package v1alpha1
|
||||
|
||||
import object "github.com/holos-run/holos/service/gen/holos/object/v1alpha1"
|
||||
|
||||
// Form represents a collection of Formly json powered form.
|
||||
type Form struct {
|
||||
TypeMeta `json:",inline" yaml:",inline"`
|
||||
Spec FormSpec `json:"spec" yaml:"spec"`
|
||||
}
|
||||
|
||||
type FormSpec struct {
|
||||
Form object.Form `json:"form" yaml:"form"`
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/holos-run/holos"
|
||||
"github.com/holos-run/holos/internal/errors"
|
||||
"github.com/holos-run/holos/internal/logger"
|
||||
"github.com/holos-run/holos/internal/util"
|
||||
)
|
||||
|
||||
// A HelmChart represents a helm command to provide chart values in order to render kubernetes api objects.
|
||||
type HelmChart struct {
|
||||
HolosComponent `json:",inline" yaml:",inline"`
|
||||
// Namespace is the namespace to install into. TODO: Use metadata.namespace instead.
|
||||
Namespace string `json:"namespace"`
|
||||
Chart Chart `json:"chart"`
|
||||
ValuesContent string `json:"valuesContent"`
|
||||
EnableHooks bool `json:"enableHooks"`
|
||||
}
|
||||
|
||||
type Chart struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Release string `json:"release"`
|
||||
Repository Repository `json:"repository,omitempty"`
|
||||
}
|
||||
|
||||
type Repository struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
func (hc *HelmChart) Render(ctx context.Context, path holos.InstancePath) (*Result, error) {
|
||||
result := Result{HolosComponent: hc.HolosComponent}
|
||||
if err := hc.helm(ctx, &result, path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.addObjectMap(ctx, hc.APIObjectMap)
|
||||
if err := result.kustomize(ctx); err != nil {
|
||||
return nil, errors.Wrap(fmt.Errorf("could not kustomize: %w", err))
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// runHelm provides the values produced by CUE to helm template and returns
|
||||
// the rendered kubernetes api objects in the result.
|
||||
func (hc *HelmChart) helm(ctx context.Context, r *Result, path holos.InstancePath) error {
|
||||
log := logger.FromContext(ctx).With("chart", hc.Chart.Name)
|
||||
if hc.Chart.Name == "" {
|
||||
log.WarnContext(ctx, "skipping helm: no chart name specified, use a different component type")
|
||||
return nil
|
||||
}
|
||||
|
||||
cachedChartPath := filepath.Join(string(path), ChartDir, filepath.Base(hc.Chart.Name))
|
||||
if isNotExist(cachedChartPath) {
|
||||
// Add repositories
|
||||
repo := hc.Chart.Repository
|
||||
if repo.URL != "" {
|
||||
out, err := util.RunCmd(ctx, "helm", "repo", "add", repo.Name, repo.URL)
|
||||
if err != nil {
|
||||
log.ErrorContext(ctx, "could not run helm", "stderr", out.Stderr.String(), "stdout", out.Stdout.String())
|
||||
return errors.Wrap(fmt.Errorf("could not run helm repo add: %w", err))
|
||||
}
|
||||
// Update repository
|
||||
out, err = util.RunCmd(ctx, "helm", "repo", "update", repo.Name)
|
||||
if err != nil {
|
||||
log.ErrorContext(ctx, "could not run helm", "stderr", out.Stderr.String(), "stdout", out.Stdout.String())
|
||||
return errors.Wrap(fmt.Errorf("could not run helm repo update: %w", err))
|
||||
}
|
||||
} else {
|
||||
log.DebugContext(ctx, "no chart repository url proceeding assuming oci chart")
|
||||
}
|
||||
|
||||
// Cache the chart
|
||||
if err := cacheChart(ctx, path, ChartDir, hc.Chart); err != nil {
|
||||
return fmt.Errorf("could not cache chart: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Write values file
|
||||
tempDir, err := os.MkdirTemp("", "holos")
|
||||
if err != nil {
|
||||
return errors.Wrap(fmt.Errorf("could not make temp dir: %w", err))
|
||||
}
|
||||
defer util.Remove(ctx, tempDir)
|
||||
|
||||
valuesPath := filepath.Join(tempDir, "values.yaml")
|
||||
if err := os.WriteFile(valuesPath, []byte(hc.ValuesContent), 0644); err != nil {
|
||||
return errors.Wrap(fmt.Errorf("could not write values: %w", err))
|
||||
}
|
||||
log.DebugContext(ctx, "helm: wrote values", "path", valuesPath, "bytes", len(hc.ValuesContent))
|
||||
|
||||
// Run charts
|
||||
chart := hc.Chart
|
||||
args := []string{"template"}
|
||||
if !hc.EnableHooks {
|
||||
args = append(args, "--no-hooks")
|
||||
}
|
||||
namespace := hc.Namespace
|
||||
args = append(args, "--include-crds", "--values", valuesPath, "--namespace", namespace, "--kubeconfig", "/dev/null", "--version", chart.Version, chart.Release, cachedChartPath)
|
||||
helmOut, err := util.RunCmd(ctx, "helm", args...)
|
||||
if err != nil {
|
||||
stderr := helmOut.Stderr.String()
|
||||
lines := strings.Split(stderr, "\n")
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, "Error:") {
|
||||
err = fmt.Errorf("%s: %w", line, err)
|
||||
}
|
||||
}
|
||||
return errors.Wrap(fmt.Errorf("could not run helm template: %w", err))
|
||||
}
|
||||
|
||||
r.accumulatedOutput = helmOut.Stdout.String()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// cacheChart stores a cached copy of Chart in the chart subdirectory of path.
|
||||
//
|
||||
// It is assumed that the only method responsible for writing to chartDir is
|
||||
// cacheChart itself.
|
||||
//
|
||||
// This relies on the atomicity of moving temporary directories into place on
|
||||
// the same filesystem via os.Rename. If a syscall.EEXIST error occurs during
|
||||
// renaming, it indicates that the cached chart already exists, which is an
|
||||
// expected scenario when this function is called concurrently.
|
||||
func cacheChart(ctx context.Context, path holos.InstancePath, chartDir string, chart Chart) error {
|
||||
log := logger.FromContext(ctx)
|
||||
|
||||
cacheTemp, err := os.MkdirTemp(string(path), chartDir)
|
||||
if err != nil {
|
||||
return errors.Wrap(fmt.Errorf("could not make temp dir: %w", err))
|
||||
}
|
||||
defer util.Remove(ctx, cacheTemp)
|
||||
|
||||
chartName := chart.Name
|
||||
if chart.Repository.Name != "" {
|
||||
chartName = fmt.Sprintf("%s/%s", chart.Repository.Name, chart.Name)
|
||||
}
|
||||
helmOut, err := util.RunCmd(ctx, "helm", "pull", "--destination", cacheTemp, "--untar=true", "--version", chart.Version, chartName)
|
||||
if err != nil {
|
||||
return errors.Wrap(fmt.Errorf("could not run helm pull: %w", err))
|
||||
}
|
||||
log.Debug("helm pull", "stdout", helmOut.Stdout, "stderr", helmOut.Stderr)
|
||||
|
||||
cachePath := filepath.Join(string(path), chartDir)
|
||||
|
||||
if err := os.MkdirAll(cachePath, 0777); err != nil {
|
||||
return errors.Wrap(fmt.Errorf("could not mkdir: %w", err))
|
||||
}
|
||||
|
||||
items, err := os.ReadDir(cacheTemp)
|
||||
if err != nil {
|
||||
return errors.Wrap(fmt.Errorf("could not read directory: %w", err))
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
src := filepath.Join(cacheTemp, item.Name())
|
||||
dst := filepath.Join(cachePath, item.Name())
|
||||
log.DebugContext(ctx, "rename", "src", src, "dst", dst)
|
||||
if err := os.Rename(src, dst); err != nil {
|
||||
var linkErr *os.LinkError
|
||||
if errors.As(err, &linkErr) && errors.Is(linkErr.Err, syscall.EEXIST) {
|
||||
log.DebugContext(ctx, "cache already exists", "chart", chart.Name, "chart_version", chart.Version, "path", cachePath)
|
||||
} else {
|
||||
return errors.Wrap(fmt.Errorf("could not rename: %w", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.InfoContext(ctx, "cached", "chart", chart.Name, "chart_version", chart.Version, "path", cachePath)
|
||||
|
||||
return nil
|
||||
}
|
||||
func isNotExist(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
return os.IsNotExist(err)
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/holos-run/holos"
|
||||
)
|
||||
|
||||
const KubernetesObjectsKind = "KubernetesObjects"
|
||||
|
||||
// KubernetesObjects represents CUE output which directly provides Kubernetes api objects to holos.
|
||||
type KubernetesObjects struct {
|
||||
HolosComponent `json:",inline" yaml:",inline"`
|
||||
}
|
||||
|
||||
// Render produces kubernetes api objects from the APIObjectMap
|
||||
func (o *KubernetesObjects) Render(ctx context.Context, path holos.InstancePath) (*Result, error) {
|
||||
result := Result{HolosComponent: o.HolosComponent}
|
||||
result.addObjectMap(ctx, o.APIObjectMap)
|
||||
return &result, nil
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package v1alpha1
|
||||
|
||||
// Kustomization holds the rendered flux kustomization api object content for git ops.
|
||||
type Kustomization struct {
|
||||
// KsContent is the yaml representation of the flux kustomization for gitops.
|
||||
KsContent string `json:"ksContent,omitempty" yaml:"ksContent,omitempty"`
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/holos-run/holos"
|
||||
"github.com/holos-run/holos/internal/errors"
|
||||
"github.com/holos-run/holos/internal/logger"
|
||||
"github.com/holos-run/holos/internal/util"
|
||||
)
|
||||
|
||||
const KustomizeBuildKind = "KustomizeBuild"
|
||||
|
||||
// Kustomize represents resources necessary to execute a kustomize build.
|
||||
// Intended for at least two use cases:
|
||||
//
|
||||
// 1. Process raw yaml file resources in a holos component directory.
|
||||
// 2. Post process a HelmChart to inject istio, add custom labels, etc...
|
||||
type Kustomize struct {
|
||||
// KustomizeFiles holds file contents for kustomize, e.g. patch files.
|
||||
KustomizeFiles FileContentMap `json:"kustomizeFiles,omitempty" yaml:"kustomizeFiles,omitempty"`
|
||||
// ResourcesFile is the file name used for api objects in kustomization.yaml
|
||||
ResourcesFile string `json:"resourcesFile,omitempty" yaml:"resourcesFile,omitempty"`
|
||||
}
|
||||
|
||||
// KustomizeBuild renders plain yaml files in the holos component directory using kubectl kustomize build.
|
||||
type KustomizeBuild struct {
|
||||
HolosComponent `json:",inline" yaml:",inline"`
|
||||
}
|
||||
|
||||
// Render produces a Result by executing kubectl kustomize on the holos
|
||||
// component path. Useful for processing raw yaml files.
|
||||
func (kb *KustomizeBuild) Render(ctx context.Context, path holos.InstancePath) (*Result, error) {
|
||||
log := logger.FromContext(ctx)
|
||||
result := Result{HolosComponent: kb.HolosComponent}
|
||||
// Run kustomize.
|
||||
kOut, err := util.RunCmd(ctx, "kubectl", "kustomize", string(path))
|
||||
if err != nil {
|
||||
log.ErrorContext(ctx, kOut.Stderr.String())
|
||||
return nil, errors.Wrap(err)
|
||||
}
|
||||
// Replace the accumulated output
|
||||
result.accumulatedOutput = kOut.Stdout.String()
|
||||
// Add CUE based api objects.
|
||||
result.addObjectMap(ctx, kb.APIObjectMap)
|
||||
return &result, nil
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package v1alpha1
|
||||
|
||||
// Label is an arbitrary unique identifier. Defined as a type for clarity and type checking.
|
||||
type Label string
|
||||
|
||||
// Kind is a kubernetes api object kind. Defined as a type for clarity and type checking.
|
||||
type Kind string
|
||||
|
||||
// APIObjectMap is the shape of marshalled api objects returned from cue to the
|
||||
// holos cli. A map is used to improve the clarity of error messages from cue.
|
||||
type APIObjectMap map[Kind]map[Label]string
|
||||
|
||||
// FileContentMap is a map of file names to file contents.
|
||||
type FileContentMap map[string]string
|
||||
@@ -1,15 +0,0 @@
|
||||
package v1alpha1
|
||||
|
||||
// ObjectMeta represents metadata of a holos component object. The fields are a
|
||||
// copy of upstream kubernetes api machinery but are by holos objects distinct
|
||||
// from kubernetes api objects.
|
||||
type ObjectMeta struct {
|
||||
// Name uniquely identifies the holos component instance and must be suitable as a file name.
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
// Namespace confines a holos component to a single namespace via kustomize if set.
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
// Labels are not used but are copied from api machinery ObjectMeta for completeness.
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
// Annotations are not used but are copied from api machinery ObjectMeta for completeness.
|
||||
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package v1alpha1
|
||||
|
||||
import "google.golang.org/protobuf/types/known/structpb"
|
||||
|
||||
// Platform represents a platform to manage. A Platform resource informs holos
|
||||
// which components to build. The platform resource also acts as a container
|
||||
// for the platform model form values provided by the PlatformService. The
|
||||
// primary use case is to collect the cluster names, cluster types, platform
|
||||
// model, and holos components to build into one resource.
|
||||
type Platform struct {
|
||||
TypeMeta `json:",inline" yaml:",inline"`
|
||||
Metadata ObjectMeta `json:"metadata" yaml:"metadata"`
|
||||
Spec PlatformSpec `json:"spec" yaml:"spec"`
|
||||
}
|
||||
|
||||
// PlatformSpec represents the platform build plan specification.
|
||||
type PlatformSpec struct {
|
||||
// Model represents the platform model holos gets from from the
|
||||
// holos.platform.v1alpha1.PlatformService.GetPlatform method and provides to
|
||||
// CUE using a tag.
|
||||
Model structpb.Struct `json:"model" yaml:"model"`
|
||||
Components []PlatformSpecComponent `json:"components" yaml:"components"`
|
||||
}
|
||||
|
||||
// PlatformSpecComponent represents a component to build or render with flags to
|
||||
// pass, for example the cluster name.
|
||||
type PlatformSpecComponent struct {
|
||||
// Path is the path of the component relative to the platform root.
|
||||
Path string `json:"path" yaml:"path"`
|
||||
// Cluster is the cluster name to use when building the component.
|
||||
Cluster string `json:"cluster" yaml:"cluster"`
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/holos-run/holos"
|
||||
)
|
||||
|
||||
type Renderer interface {
|
||||
GetKind() string
|
||||
Render(ctx context.Context, path holos.InstancePath) (*Result, error)
|
||||
}
|
||||
|
||||
// Render produces a Result representing the kubernetes api objects to
|
||||
// configure. Each of the various holos component types, e.g. Helm, Kustomize,
|
||||
// et al, should implement the Renderer interface. This process is best
|
||||
// conceptualized as a data pipeline, for example a component may render a
|
||||
// result by first calling helm template, then passing the result through
|
||||
// kustomize, then mixing in overlay api objects.
|
||||
func Render(ctx context.Context, r Renderer, path holos.InstancePath) (*Result, error) {
|
||||
return r.Render(ctx, path)
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
|
||||
"github.com/holos-run/holos/internal/errors"
|
||||
"github.com/holos-run/holos/internal/logger"
|
||||
"github.com/holos-run/holos/internal/util"
|
||||
)
|
||||
|
||||
// Result is the build result for display or writing. Holos components Render the Result as a data pipeline.
|
||||
type Result struct {
|
||||
HolosComponent
|
||||
// accumulatedOutput accumulates rendered api objects.
|
||||
accumulatedOutput string
|
||||
// DeployFiles keys represent file paths relative to the cluster deploy
|
||||
// directory. Map values represent the string encoded file contents. Used to
|
||||
// write the argocd Application, but may be used to render any file from CUE.
|
||||
DeployFiles FileContentMap `json:"deployFiles,omitempty" yaml:"deployFiles,omitempty"`
|
||||
}
|
||||
|
||||
// Continue returns true if Skip is true indicating the result is to be skipped over.
|
||||
func (r *Result) Continue() bool {
|
||||
if r == nil {
|
||||
return false
|
||||
}
|
||||
return r.Skip
|
||||
}
|
||||
|
||||
func (r *Result) Name() string {
|
||||
return r.Metadata.Name
|
||||
}
|
||||
|
||||
func (r *Result) Filename(writeTo string, cluster string) string {
|
||||
name := r.Metadata.Name
|
||||
return filepath.Join(writeTo, "clusters", cluster, "components", name, name+".gen.yaml")
|
||||
}
|
||||
|
||||
func (r *Result) KustomizationFilename(writeTo string, cluster string) string {
|
||||
return filepath.Join(writeTo, "clusters", cluster, "holos", "components", r.Metadata.Name+"-kustomization.gen.yaml")
|
||||
}
|
||||
|
||||
// AccumulatedOutput returns the accumulated rendered output.
|
||||
func (r *Result) AccumulatedOutput() string {
|
||||
return r.accumulatedOutput
|
||||
}
|
||||
|
||||
// addObjectMap renders the provided APIObjectMap into the accumulated output.
|
||||
func (r *Result) addObjectMap(ctx context.Context, objectMap APIObjectMap) {
|
||||
log := logger.FromContext(ctx)
|
||||
b := []byte(r.AccumulatedOutput())
|
||||
kinds := make([]Kind, 0, len(objectMap))
|
||||
// Sort the keys
|
||||
for kind := range objectMap {
|
||||
kinds = append(kinds, kind)
|
||||
}
|
||||
slices.Sort(kinds)
|
||||
|
||||
for _, kind := range kinds {
|
||||
v := objectMap[kind]
|
||||
// Sort the keys
|
||||
names := make([]Label, 0, len(v))
|
||||
for name := range v {
|
||||
names = append(names, name)
|
||||
}
|
||||
slices.Sort(names)
|
||||
|
||||
for _, name := range names {
|
||||
yamlString := v[name]
|
||||
log.Debug(fmt.Sprintf("%s/%s", kind, name), "kind", kind, "name", name)
|
||||
b = util.EnsureNewline(b)
|
||||
header := fmt.Sprintf("---\n# Source: CUE apiObjects.%s.%s\n", kind, name)
|
||||
b = append(b, []byte(header+yamlString)...)
|
||||
b = util.EnsureNewline(b)
|
||||
}
|
||||
}
|
||||
r.accumulatedOutput = string(b)
|
||||
}
|
||||
|
||||
// kustomize replaces the accumulated output with the output of kustomize build
|
||||
func (r *Result) kustomize(ctx context.Context) error {
|
||||
log := logger.FromContext(ctx)
|
||||
if r.ResourcesFile == "" {
|
||||
log.DebugContext(ctx, "skipping kustomize: no resourcesFile")
|
||||
return nil
|
||||
}
|
||||
if len(r.KustomizeFiles) < 1 {
|
||||
log.DebugContext(ctx, "skipping kustomize: no kustomizeFiles")
|
||||
return nil
|
||||
}
|
||||
tempDir, err := os.MkdirTemp("", "holos.kustomize")
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
defer util.Remove(ctx, tempDir)
|
||||
|
||||
// Write the main api object resources file for kustomize.
|
||||
target := filepath.Join(tempDir, r.ResourcesFile)
|
||||
b := []byte(r.AccumulatedOutput())
|
||||
b = util.EnsureNewline(b)
|
||||
if err := os.WriteFile(target, b, 0644); err != nil {
|
||||
return errors.Wrap(fmt.Errorf("could not write resources: %w", err))
|
||||
}
|
||||
log.DebugContext(ctx, "wrote: "+target, "op", "write", "path", target, "bytes", len(b))
|
||||
|
||||
// Write the kustomization tree, kustomization.yaml must be in this map for kustomize to work.
|
||||
for file, content := range r.KustomizeFiles {
|
||||
target := filepath.Join(tempDir, file)
|
||||
if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
b := []byte(content)
|
||||
b = util.EnsureNewline(b)
|
||||
if err := os.WriteFile(target, b, 0644); err != nil {
|
||||
return errors.Wrap(fmt.Errorf("could not write: %w", err))
|
||||
}
|
||||
log.DebugContext(ctx, "wrote: "+target, "op", "write", "path", target, "bytes", len(b))
|
||||
}
|
||||
|
||||
// Run kustomize.
|
||||
kOut, err := util.RunCmd(ctx, "kubectl", "kustomize", tempDir)
|
||||
if err != nil {
|
||||
log.ErrorContext(ctx, kOut.Stderr.String())
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
// Replace the accumulated output
|
||||
r.accumulatedOutput = kOut.Stdout.String()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Result) WriteDeployFiles(ctx context.Context, path string) error {
|
||||
log := logger.FromContext(ctx)
|
||||
if len(r.DeployFiles) == 0 {
|
||||
return nil
|
||||
}
|
||||
for k, content := range r.DeployFiles {
|
||||
path := filepath.Join(path, k)
|
||||
if err := r.Save(ctx, path, content); err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
log.InfoContext(ctx, "wrote deploy file", "path", path, "bytes", len(content))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Save writes the content to the filesystem for git ops.
|
||||
func (r *Result) Save(ctx context.Context, path string, content string) error {
|
||||
log := logger.FromContext(ctx)
|
||||
dir := filepath.Dir(path)
|
||||
if err := os.MkdirAll(dir, os.FileMode(0775)); err != nil {
|
||||
log.WarnContext(ctx, "could not mkdir", "path", dir, "err", err)
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
// Write the file content
|
||||
if err := os.WriteFile(path, []byte(content), os.FileMode(0644)); err != nil {
|
||||
log.WarnContext(ctx, "could not write", "path", path, "err", err)
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
log.DebugContext(ctx, "out: wrote "+path, "action", "write", "path", path, "status", "ok")
|
||||
return nil
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package v1alpha1
|
||||
|
||||
type TypeMeta struct {
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
}
|
||||
|
||||
func (tm *TypeMeta) GetKind() string {
|
||||
return tm.Kind
|
||||
}
|
||||
|
||||
func (tm *TypeMeta) GetAPIVersion() string {
|
||||
return tm.APIVersion
|
||||
}
|
||||
|
||||
// Discriminator is an interface to discriminate the kind api object.
|
||||
type Discriminator interface {
|
||||
GetKind() string
|
||||
GetAPIVersion() string
|
||||
}
|
||||
20
buf.gen.yaml
@@ -1,20 +0,0 @@
|
||||
# Generates gRPC and ConnectRPC bindings for Go and TypeScript
|
||||
#
|
||||
# Note: protoc-gen-connect-query is the primary method of wiring up the React
|
||||
# frontend.
|
||||
version: v1
|
||||
plugins:
|
||||
- plugin: go
|
||||
out: service/gen
|
||||
opt: paths=source_relative
|
||||
- plugin: connect-go
|
||||
out: service/gen
|
||||
opt: paths=source_relative
|
||||
- plugin: es
|
||||
out: internal/frontend/holos/src/app/gen
|
||||
opt:
|
||||
- target=ts
|
||||
- plugin: connect-es
|
||||
out: internal/frontend/holos/src/app/gen
|
||||
opt:
|
||||
- target=ts
|
||||
8
buf.lock
@@ -1,8 +0,0 @@
|
||||
# Generated by buf. DO NOT EDIT.
|
||||
version: v1
|
||||
deps:
|
||||
- remote: buf.build
|
||||
owner: bufbuild
|
||||
repository: protovalidate
|
||||
commit: b983156c5e994cc9892e0ce3e64e17e0
|
||||
digest: shake256:fb47a62989d38c2529bcc5cd86ded43d800eb84cee82b42b9e8a9e815d4ee8134a0fb9d0ce8299b27c2d2bbb7d6ade0c4ad5a8a4d467e1e2c7ca619ae9f634e2
|
||||
@@ -1,3 +0,0 @@
|
||||
version: v1
|
||||
directories:
|
||||
- service
|
||||
34
cmd/cmd.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/holos-run/holos/internal/cli"
|
||||
"github.com/holos-run/holos/internal/holos"
|
||||
"github.com/holos-run/holos/version"
|
||||
)
|
||||
|
||||
// MakeMain makes a main function for the cli or tests.
|
||||
func MakeMain(options ...holos.Option) func() int {
|
||||
return func() (exitCode int) {
|
||||
// TODO(jjm): check HOLOS_CHDIR and chdir if set for tests.
|
||||
if len(os.Args) >= 2 && os.Args[1] == "version" {
|
||||
if _, err := fmt.Println(version.GetVersion()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
cfg := holos.New(options...)
|
||||
slog.SetDefault(cfg.Logger())
|
||||
ctx := context.Background()
|
||||
cmd := cli.New(cfg)
|
||||
|
||||
if err := cmd.ExecuteContext(ctx); err != nil {
|
||||
return cli.HandleError(ctx, err, cfg)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,9 @@ package main
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/holos-run/holos/internal/cli"
|
||||
"github.com/holos-run/holos/cmd"
|
||||
)
|
||||
|
||||
func main() {
|
||||
os.Exit(cli.MakeMain()())
|
||||
os.Exit(cmd.MakeMain()())
|
||||
}
|
||||
|
||||
@@ -6,20 +6,18 @@ import (
|
||||
"testing"
|
||||
|
||||
cue "cuelang.org/go/cmd/cue/cmd"
|
||||
"github.com/holos-run/holos/internal/cli"
|
||||
"github.com/holos-run/holos/cmd"
|
||||
"github.com/rogpeppe/go-internal/testscript"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
os.Exit(testscript.RunMain(m, map[string]func() int{
|
||||
"holos": cli.MakeMain(),
|
||||
"cue": cue.Main,
|
||||
}))
|
||||
holosMain := cmd.MakeMain()
|
||||
testscript.Main(m, map[string]func(){
|
||||
"holos": func() { os.Exit(holosMain()) },
|
||||
"cue": func() { os.Exit(cue.Main()) },
|
||||
})
|
||||
}
|
||||
|
||||
func TestGuides_v1alpha4(t *testing.T) {
|
||||
testscript.Run(t, params(filepath.Join("v1alpha4", "guides")))
|
||||
}
|
||||
func TestGuides_v1alpha5(t *testing.T) {
|
||||
testscript.Run(t, params(filepath.Join("v1alpha5", "guides")))
|
||||
}
|
||||
|
||||
12
cmd/holos/tests/cli/cue-vet.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
# https://github.com/holos-run/holos/issues/358
|
||||
# holos cue vet should fail verifications with exit code 1
|
||||
! exec holos cue vet ./policy --path strings.ToLower(kind) ./data/secret.yaml
|
||||
# holos cue vet should report validation errors to stderr
|
||||
stderr 'Forbidden. Use an ExternalSecret instead.'
|
||||
|
||||
-- data/secret.yaml --
|
||||
kind: Secret
|
||||
-- policy/validators.cue --
|
||||
package policy
|
||||
|
||||
secret: kind: "Forbidden. Use an ExternalSecret instead."
|
||||
@@ -1,2 +1,7 @@
|
||||
# https://github.com/holos-run/holos/issues/334
|
||||
exec holos
|
||||
stdout Usage
|
||||
exec holos --version
|
||||
stdout \d+\.\d+\.\d+
|
||||
exec holos version
|
||||
stdout \d+\.\d+\.\d+
|
||||
|
||||
@@ -7,12 +7,13 @@ cd $WORK
|
||||
exec holos generate platform v1alpha5 --force
|
||||
|
||||
# Platforms are empty by default.
|
||||
exec holos render platform ./platform
|
||||
exec holos render platform
|
||||
stderr -count=1 '^rendered platform'
|
||||
|
||||
# Holos uses CUE to build a platform specification.
|
||||
exec cue export --expression holos --out=yaml ./platform
|
||||
cmp stdout want/1.platform_spec.yaml
|
||||
exec holos show platform
|
||||
cp stdout platform.yaml
|
||||
exec holos compare yaml platform.yaml want/1.platform_spec.yaml
|
||||
|
||||
# Define the host and port in projects/blackbox.schema.cue
|
||||
mv projects/blackbox.schema.cue.disabled projects/blackbox.schema.cue
|
||||
@@ -22,10 +23,10 @@ mv projects/platform/components/prometheus/prometheus.cue.disabled projects/plat
|
||||
mv platform/prometheus.cue.disabled platform/prometheus.cue
|
||||
|
||||
# Render the platform to render the prometheus chart.
|
||||
exec holos render platform ./platform
|
||||
exec holos render platform
|
||||
stderr -count=1 '^rendered prometheus'
|
||||
stderr -count=1 '^rendered platform'
|
||||
cmp deploy/components/prometheus/prometheus.gen.yaml want/1.prometheus.gen.yaml
|
||||
exec holos compare yaml deploy/components/prometheus/prometheus.gen.yaml want/1.prometheus.gen.yaml
|
||||
|
||||
# Add the CUE configuration to manage the blackbox Helm Chart component.
|
||||
mv projects/platform/components/blackbox/blackbox.cue.disabled projects/platform/components/blackbox/blackbox.cue
|
||||
@@ -37,7 +38,7 @@ exec holos render platform ./platform
|
||||
stderr -count=1 '^rendered prometheus'
|
||||
stderr -count=1 '^rendered blackbox'
|
||||
stderr -count=1 '^rendered platform'
|
||||
cmp deploy/components/blackbox/blackbox.gen.yaml want/1.blackbox.gen.yaml
|
||||
exec holos compare yaml deploy/components/blackbox/blackbox.gen.yaml want/1.blackbox.gen.yaml
|
||||
|
||||
# Import helm values
|
||||
exec cue import --package holos --path 'Helm: Values:' --outfile projects/platform/components/prometheus/values.cue projects/platform/components/prometheus/vendor/25.27.0/prometheus/values.yaml
|
||||
@@ -55,7 +56,7 @@ mv platform/httpbin.cue.disabled platform/httpbin.cue
|
||||
# Render the platform with httpbin
|
||||
exec holos render platform ./platform
|
||||
stderr -count=1 '^rendered httpbin'
|
||||
cmp deploy/components/httpbin/httpbin.gen.yaml want/1.httpbin.gen.yaml
|
||||
exec holos compare yaml deploy/components/httpbin/httpbin.gen.yaml want/1.httpbin.gen.yaml
|
||||
|
||||
# Verify the labels are correct
|
||||
grep 'replacement: blackbox:9115' deploy/components/prometheus/prometheus.gen.yaml
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
# https://github.com/holos-run/holos/issues/332
|
||||
env HOME=$WORK
|
||||
# Mock with a stub helm command
|
||||
env PATH=$WORK/bin:$PATH
|
||||
chmod 755 bin/helm
|
||||
# Initialize the platform
|
||||
exec holos init platform v1alpha5 --force
|
||||
# when helm update returns an error
|
||||
! exec holos render platform ./platform
|
||||
# holos should log the helm error to stderr
|
||||
stderr 'Error: chart "podinfo" matching 0.0.0 not found in podinfo index'
|
||||
-- bin/helm --
|
||||
#! /bin/bash
|
||||
echo 'Error: chart "podinfo" matching 0.0.0 not found in podinfo index' >&2
|
||||
exit 2
|
||||
-- platform/podinfo.cue --
|
||||
package holos
|
||||
|
||||
Platform: Components: podinfo: {
|
||||
name: "podinfo"
|
||||
path: "components/podinfo"
|
||||
}
|
||||
-- components/podinfo/podinfo.cue --
|
||||
package holos
|
||||
|
||||
// Produce a helm chart build plan.
|
||||
holos: HelmChart.BuildPlan
|
||||
|
||||
HelmChart: #Helm & {
|
||||
Name: "podinfo"
|
||||
Chart: {
|
||||
version: "0.0.0"
|
||||
repository: {
|
||||
name: "podinfo"
|
||||
url: "https://stefanprodan.github.io/podinfo"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
# https://github.com/holos-run/holos/issues/348
|
||||
# when the optional kustomize patch name field is omitted
|
||||
exec holos init platform v1alpha5 --force
|
||||
# want a buildplan shown
|
||||
exec holos show buildplans
|
||||
cp stdout buildplan-output.yaml
|
||||
exec holos compare yaml buildplan-output.yaml buildplan.yaml
|
||||
# want this error to go away
|
||||
! stderr 'cannot convert non-concrete value string'
|
||||
-- platform/example.cue --
|
||||
package holos
|
||||
|
||||
Platform: Components: example: {
|
||||
name: "example"
|
||||
path: "components/example"
|
||||
}
|
||||
-- components/example/example.cue --
|
||||
package holos
|
||||
|
||||
import "encoding/yaml"
|
||||
|
||||
holos: Component.BuildPlan
|
||||
|
||||
Component: #Kustomize & {
|
||||
KustomizeConfig: Kustomization: patches: [
|
||||
{
|
||||
target: kind: "CustomResourceDefinition"
|
||||
patch: yaml.Marshal([{
|
||||
op: "add"
|
||||
path: "/metadata/annotations/example"
|
||||
value: "example-value"
|
||||
}])
|
||||
},
|
||||
]
|
||||
}
|
||||
-- buildplan.yaml --
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: example
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: components/example/example.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- resources.gen.yaml
|
||||
output: components/example/example.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
patches:
|
||||
- patch: |
|
||||
- op: add
|
||||
path: /metadata/annotations/example
|
||||
value: example-value
|
||||
target:
|
||||
kind: CustomResourceDefinition
|
||||
name: ""
|
||||
resources:
|
||||
- resources.gen.yaml
|
||||
52
cmd/holos/tests/v1alpha5/issues/issue366-cue-build-tags.txt
Normal file
@@ -0,0 +1,52 @@
|
||||
# https://github.com/holos-run/holos/issues/366
|
||||
# Build tags conditionally include CUE files.
|
||||
env HOME=$WORK
|
||||
|
||||
exec holos init platform v1alpha5 --force
|
||||
exec holos show platform
|
||||
cp stdout empty.yaml
|
||||
exec holos compare yaml empty.yaml want/empty.yaml
|
||||
|
||||
exec holos show platform -t foo
|
||||
cp stdout foo.yaml
|
||||
exec holos compare yaml foo.yaml want/foo.yaml
|
||||
|
||||
-- platform/empty.cue --
|
||||
@if(foo)
|
||||
package holos
|
||||
|
||||
Platform: Components: foo: _
|
||||
-- platform/metadata.cue --
|
||||
package holos
|
||||
|
||||
Platform: Components: [NAME=string]: {
|
||||
name: NAME
|
||||
path: "components/empty"
|
||||
labels: "app.holos.run/name": NAME
|
||||
annotations: "app.holos.run/description": "\(NAME) empty test case"
|
||||
}
|
||||
-- components/empty/empty.cue --
|
||||
package holos
|
||||
|
||||
Component: #Kubernetes & {}
|
||||
holos: Component.BuildPlan
|
||||
-- want/empty.yaml --
|
||||
kind: Platform
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: default
|
||||
spec:
|
||||
components: []
|
||||
-- want/foo.yaml --
|
||||
kind: Platform
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: default
|
||||
spec:
|
||||
components:
|
||||
- name: foo
|
||||
path: components/empty
|
||||
labels:
|
||||
app.holos.run/name: foo
|
||||
annotations:
|
||||
app.holos.run/description: foo empty test case
|
||||
@@ -1,16 +1,19 @@
|
||||
# https://github.com/holos-run/holos/issues/330
|
||||
# take care to install helm 3.17.3 otherwise kube versions may not align
|
||||
exec holos init platform v1alpha5 --force
|
||||
# Make sure the helm chart works with plain helm
|
||||
exec helm template ./components/capabilities/vendor/0.1.0/capabilities
|
||||
cmp stdout want/helm-template.yaml
|
||||
stdout 'name: has-foo-v1beta1'
|
||||
stdout 'kubeVersion: v'
|
||||
exec holos render platform ./platform
|
||||
# When no capabilities are specified
|
||||
cmp deploy/components/capabilities/capabilities.gen.yaml want/when-no-capabilities-specified.yaml
|
||||
exec holos compare yaml deploy/components/capabilities/capabilities.gen.yaml want/when-no-capabilities-specified.yaml
|
||||
# With APIVersions specified
|
||||
cmp deploy/components/specified/specified.gen.yaml want/with-capabilities-specified.yaml
|
||||
exec holos compare yaml deploy/components/specified/specified.gen.yaml want/with-capabilities-specified.yaml
|
||||
# With KubeVersion specified
|
||||
cmp deploy/components/kubeversion1/kubeversion1.gen.yaml want/with-kubeversion-specified.yaml
|
||||
exec holos compare yaml deploy/components/kubeversion1/kubeversion1.gen.yaml want/with-kubeversion-specified.yaml
|
||||
# With both APIVersions and KubeVersion specified
|
||||
cmp deploy/components/kubeversion2/kubeversion2.gen.yaml want/with-both-specified.yaml
|
||||
exec holos compare yaml deploy/components/kubeversion2/kubeversion2.gen.yaml want/with-both-specified.yaml
|
||||
-- want/with-both-specified.yaml --
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
@@ -42,7 +45,7 @@ apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
kubeVersion: v1.31.0
|
||||
kubeVersion: v1.99.0
|
||||
name: has-foo-v1beta1
|
||||
spec:
|
||||
ports:
|
||||
@@ -55,7 +58,7 @@ apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
kubeVersion: v1.31.0
|
||||
kubeVersion: v1.99.0
|
||||
name: has-foo-v1
|
||||
spec:
|
||||
ports:
|
||||
@@ -101,7 +104,7 @@ Component: #Helm & {
|
||||
Chart: version: "0.1.0"
|
||||
_APIVersions: string | *"[]" @tag(apiVersions, type=string)
|
||||
APIVersions: json.Unmarshal(_APIVersions)
|
||||
KubeVersion: string | *"v1.31.0" @tag(kubeVersion, type=string)
|
||||
KubeVersion: string | *"v1.99.0" @tag(kubeVersion, type=string)
|
||||
}
|
||||
-- components/capabilities/vendor/0.1.0/capabilities/Chart.yaml --
|
||||
apiVersion: v2
|
||||
@@ -135,7 +138,7 @@ kind: Service
|
||||
metadata:
|
||||
name: has-foo-v1beta1
|
||||
annotations:
|
||||
kubeVersion: v1.31.0
|
||||
kubeVersion: v1.99.0
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
|
||||
@@ -4,15 +4,16 @@
|
||||
cd $WORK
|
||||
|
||||
# Generate the directory structure we're going to work in.
|
||||
exec holos generate platform v1alpha5 --force
|
||||
exec holos init platform v1alpha5 --force
|
||||
|
||||
# Platforms are empty by default.
|
||||
exec holos render platform ./platform
|
||||
exec holos render platform
|
||||
stderr -count=1 '^rendered platform'
|
||||
|
||||
# When author.#Kubernetes is empty
|
||||
exec holos cue export --expression holos --out=yaml ./components/empty
|
||||
cmp stdout want.txt
|
||||
cp stdout empty.yaml
|
||||
exec holos compare yaml empty.yaml want.txt
|
||||
|
||||
-- components/empty/empty.cue --
|
||||
package holos
|
||||
@@ -38,15 +39,8 @@ spec:
|
||||
output: components/no-name/no-name.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
labels:
|
||||
- includeSelectors: false
|
||||
pairs: {}
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- resources.gen.yaml
|
||||
kind: Kustomization
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
source:
|
||||
component:
|
||||
name: no-name
|
||||
path: no-path
|
||||
parameters: {}
|
||||
validators: []
|
||||
|
||||
37
cmd/holos/tests/v1alpha5/schemas/validators.txt
Normal file
@@ -0,0 +1,37 @@
|
||||
# https://github.com/holos-run/holos/issues/357
|
||||
exec holos init platform v1alpha5 --force
|
||||
! exec holos render platform
|
||||
stderr 'secret.kind: conflicting values "Forbidden. Use an ExternalSecret instead." and "Secret"'
|
||||
|
||||
-- validators.cue --
|
||||
package holos
|
||||
|
||||
import "github.com/holos-run/holos/api/author/v1alpha5:author"
|
||||
|
||||
#ComponentConfig: author.#ComponentConfig & {
|
||||
Validators: cue: {
|
||||
kind: "Command"
|
||||
command: args: ["holos", "cue", "vet", "./policy", "--path", "strings.ToLower(kind)"]
|
||||
}
|
||||
}
|
||||
-- policy/validations.cue --
|
||||
package validations
|
||||
|
||||
secret: kind: "Forbidden. Use an ExternalSecret instead."
|
||||
-- platform/example.cue --
|
||||
package holos
|
||||
|
||||
Platform: Components: example: {
|
||||
name: "example"
|
||||
path: "components/example"
|
||||
}
|
||||
-- components/example/secret.cue --
|
||||
package holos
|
||||
|
||||
holos: Component.BuildPlan
|
||||
|
||||
Component: #Kubernetes & {
|
||||
Resources: Secret: test: {
|
||||
metadata: name: "test"
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
# Backstory
|
||||
|
||||
Holos is a tool intended to lighten the burden of managing Kubernetes resources. In 2020 we set out to develop a holistic platform composed from open source cloud native components. We quickly became frustrated with how each of the major components packaged and distributed their software in a different way. Many projects choose to distribute their software with Helm charts, while others provide plain yaml files and Kustomize bases. The popular Kube Prometheus Stack project provides Jsonnet to render and update Kubernetes yaml manifests.
|
||||
@@ -1,3 +0,0 @@
|
||||
# CLI
|
||||
|
||||
Use the `holos` command line interface (CLI) to render individual platform components, entire platforms, and push/pull the platform model.
|
||||
@@ -1,29 +0,0 @@
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
|
||||
# Guides
|
||||
|
||||
## Technical Overview
|
||||
|
||||
Please see the [Technical Overview] to learn about Holos. If you're ready to
|
||||
drive in and try Holos, please work through the following guides.
|
||||
|
||||
## Bank of Holos
|
||||
The guides are organized as a progression. We'll use Holos to manage a
|
||||
fictional bank's platform, the Bank of Holos in each of the guides. In doing so
|
||||
we'll take the time to explain the foundational concepts of Holos.
|
||||
|
||||
1. [Quickstart] covers the foundational concepts of Holos.
|
||||
2. [Deploy a Service] explains how to deploy a containerized service using an
|
||||
existing Helm chart. This guide then explains how to deploy a similar service
|
||||
safely and consistently with CUE instead of Helm.
|
||||
3. [Change a Service] covers the day two task of making configuration changes to
|
||||
deployed services safely and consistently.
|
||||
|
||||
---
|
||||
|
||||
<DocCardList />
|
||||
|
||||
[Quickstart]: /docs/quickstart/
|
||||
[Deploy a Service]: /docs/guides/deploy-a-service/
|
||||
[Change a Service]: /docs/guides/change-a-service/
|
||||
[Technical Overview]: /docs/technical-overview/
|
||||
@@ -1,735 +0,0 @@
|
||||
---
|
||||
description: Change a service on your platform.
|
||||
slug: /guides/change-a-service
|
||||
sidebar_position: 300
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import Admonition from '@theme/Admonition';
|
||||
|
||||
# Change a Service
|
||||
|
||||
In this guide, we'll explore how Holos supports the frontend development team at [Bank of Holos] in reconfiguring an already deployed service. Along the way, we'll demonstrate how simple configuration changes are made safer with type checking, and how rendering the complete platform provides clear visibility into those changes.
|
||||
|
||||
This guide builds on the concepts covered in the [Quickstart] and [Deploy a Service] guides.
|
||||
|
||||
## What you'll need {#requirements}
|
||||
|
||||
Like our other guides, this guide is intended to be useful without needing to
|
||||
run each command. If you'd like to apply the manifests to a real Cluster,
|
||||
complete the [Local Cluster Guide](/docs/guides/local-cluster) before this
|
||||
guide.
|
||||
|
||||
You'll need the following tools installed to run the commands in this guide.
|
||||
|
||||
1. [holos](/docs/install) - to build the Platform.
|
||||
2. [helm](https://helm.sh/docs/intro/install/) - to render Holos Components that
|
||||
wrap Helm charts.
|
||||
3. [kubectl](https://kubernetes.io/docs/tasks/tools/) - to render Holos
|
||||
Components that render with Kustomize.
|
||||
|
||||
## Fork the Git Repository
|
||||
|
||||
If you haven't already done so, [fork the Bank of
|
||||
Holos](https://github.com/holos-run/bank-of-holos/fork) then clone the
|
||||
repository to your local machine.
|
||||
|
||||
<Tabs groupId="git-clone">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
# Change YourName
|
||||
git clone https://github.com/YourName/bank-of-holos
|
||||
cd bank-of-holos
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```txt
|
||||
Cloning into 'bank-of-holos'...
|
||||
remote: Enumerating objects: 1177, done.
|
||||
remote: Counting objects: 100% (1177/1177), done.
|
||||
remote: Compressing objects: 100% (558/558), done.
|
||||
remote: Total 1177 (delta 394), reused 1084 (delta 303), pack-reused 0 (from 0)
|
||||
Receiving objects: 100% (1177/1177), 2.89 MiB | 6.07 MiB/s, done.
|
||||
Resolving deltas: 100% (394/394), done.
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Run the rest of the commands in this guide from the root of the repository.
|
||||
|
||||
If you plan to apply the changes we make, you can delete and re-create your
|
||||
local platform synced to the start of this guide.
|
||||
|
||||
```bash
|
||||
./scripts/reset-cluster
|
||||
./scripts/apply
|
||||
```
|
||||
|
||||
## Rename the Bank
|
||||
|
||||
Let's imagine the bank recently re-branded from The Bank of Holos to The
|
||||
Holistic Bank. The software development team responsible for the front end
|
||||
website needs to update the branding accordingly.
|
||||
|
||||
Let's explore how Holos catches errors early, before they land in production,
|
||||
then guides the team to the best place to make a change.
|
||||
|
||||
The bank front end web service is managed by the
|
||||
`projects/bank-of-holos/frontend/components/bank-frontend/` component which
|
||||
refers to the organization display name in `schema.gen.cue`.
|
||||
|
||||
<Tabs groupId="F5B546EB-566F-4B83-84C3-C55B40F55555">
|
||||
<TabItem value="schema.cue" label="schema.cue">
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
import api "github.com/holos-run/holos/api/author/v1alpha4"
|
||||
|
||||
// Define the default organization name.
|
||||
_Organization: api.#OrganizationStrict & {
|
||||
DisplayName: string | *"Bank of Holos"
|
||||
Name: string | *"bank-of-holos"
|
||||
Domain: string | *"holos.localhost"
|
||||
}
|
||||
|
||||
// Projects represents a way to organize components into projects with owners.
|
||||
// https://holos.run/docs/api/author/v1alpha4/#Projects
|
||||
_Projects: api.#Projects
|
||||
|
||||
// ArgoConfig represents the configuration of ArgoCD Application resources for
|
||||
// each component.
|
||||
// https://holos.run/docs/api/author/v1alpha4/#ArgoConfig
|
||||
_ArgoConfig: api.#ArgoConfig
|
||||
|
||||
#ComponentConfig: api.#ComponentConfig & {
|
||||
Name: _Tags.name
|
||||
Component: _Tags.component
|
||||
Cluster: _Tags.cluster
|
||||
ArgoConfig: _ArgoConfig & {
|
||||
if _Tags.project != "no-project" {
|
||||
AppProject: _Tags.project
|
||||
}
|
||||
}
|
||||
Resources: #Resources
|
||||
|
||||
// Mix in project labels if the project is defined by the platform.
|
||||
if _Tags.project != "no-project" {
|
||||
CommonLabels: _Projects[_Tags.project].CommonLabels
|
||||
}
|
||||
}
|
||||
|
||||
// https://holos.run/docs/api/author/v1alpha4/#Kubernetes
|
||||
#Kubernetes: close({
|
||||
#ComponentConfig
|
||||
api.#Kubernetes
|
||||
})
|
||||
|
||||
// https://holos.run/docs/api/author/v1alpha4/#Kustomize
|
||||
#Kustomize: close({
|
||||
#ComponentConfig
|
||||
api.#Kustomize
|
||||
})
|
||||
|
||||
// https://holos.run/docs/api/author/v1alpha4/#Helm
|
||||
#Helm: close({
|
||||
#ComponentConfig
|
||||
api.#Helm
|
||||
})
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="projects/bank-of-holos/frontend/components/bank-frontend/bank-frontend.cue" label="projects/bank-of-holos/frontend/components/bank-frontend/bank-frontend.cue">
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
// Produce a kubernetes objects build plan.
|
||||
(#Kubernetes & Objects).BuildPlan
|
||||
|
||||
let Objects = {
|
||||
Name: "bank-frontend"
|
||||
Namespace: _BankOfHolos.Frontend.Namespace
|
||||
|
||||
// Ensure resources go in the correct namespace
|
||||
Resources: [_]: [_]: metadata: namespace: Namespace
|
||||
|
||||
// https://github.com/GoogleCloudPlatform/bank-of-anthos/blob/release/v0.6.5/kubernetes-manifests/frontend.yaml
|
||||
Resources: {
|
||||
Service: frontend: {
|
||||
metadata: name: "frontend"
|
||||
metadata: labels: {
|
||||
application: "bank-of-holos"
|
||||
environment: "development"
|
||||
team: "frontend"
|
||||
tier: "web"
|
||||
}
|
||||
spec: {
|
||||
selector: {
|
||||
app: "frontend"
|
||||
application: "bank-of-holos"
|
||||
environment: "development"
|
||||
team: "frontend"
|
||||
tier: "web"
|
||||
}
|
||||
_ports: http: {
|
||||
name: "http"
|
||||
port: 80
|
||||
targetPort: 8080
|
||||
protocol: "TCP"
|
||||
}
|
||||
ports: [for x in _ports {x}]
|
||||
}
|
||||
}
|
||||
|
||||
Deployment: frontend: {
|
||||
metadata: name: "frontend"
|
||||
metadata: labels: {
|
||||
application: "bank-of-holos"
|
||||
environment: "development"
|
||||
team: "frontend"
|
||||
tier: "web"
|
||||
}
|
||||
spec: {
|
||||
selector: matchLabels: {
|
||||
app: "frontend"
|
||||
application: "bank-of-holos"
|
||||
environment: "development"
|
||||
team: "frontend"
|
||||
tier: "web"
|
||||
}
|
||||
template: {
|
||||
metadata: labels: {
|
||||
app: "frontend"
|
||||
application: "bank-of-holos"
|
||||
environment: "development"
|
||||
team: "frontend"
|
||||
tier: "web"
|
||||
}
|
||||
spec: {
|
||||
securityContext: {
|
||||
seccompProfile: type: "RuntimeDefault"
|
||||
fsGroup: 1000
|
||||
runAsGroup: 1000
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
}
|
||||
serviceAccountName: "bank-of-holos"
|
||||
terminationGracePeriodSeconds: 5
|
||||
containers: [{
|
||||
env: [{
|
||||
name: "BANK_NAME"
|
||||
value: _Organization.DisplayName
|
||||
}, {
|
||||
name: "ENV_PLATFORM"
|
||||
value: "local"
|
||||
}, {
|
||||
name: "VERSION"
|
||||
value: "v0.6.5"
|
||||
}, {
|
||||
name: "PORT"
|
||||
value: "8080"
|
||||
}, {
|
||||
name: "ENABLE_TRACING"
|
||||
value: "false"
|
||||
}, {
|
||||
name: "SCHEME"
|
||||
value: "https"
|
||||
}, {
|
||||
name: "LOG_LEVEL"
|
||||
value: "info"
|
||||
}, {
|
||||
name: "DEFAULT_USERNAME"
|
||||
valueFrom: configMapKeyRef: {
|
||||
key: "DEMO_LOGIN_USERNAME"
|
||||
name: "demo-data-config"
|
||||
}
|
||||
}, {
|
||||
name: "DEFAULT_PASSWORD"
|
||||
valueFrom: configMapKeyRef: {
|
||||
key: "DEMO_LOGIN_PASSWORD"
|
||||
name: "demo-data-config"
|
||||
}
|
||||
}, {
|
||||
name: "REGISTERED_OAUTH_CLIENT_ID"
|
||||
valueFrom: configMapKeyRef: {
|
||||
key: "DEMO_OAUTH_CLIENT_ID"
|
||||
name: "oauth-config"
|
||||
optional: true
|
||||
}
|
||||
}, {
|
||||
name: "ALLOWED_OAUTH_REDIRECT_URI"
|
||||
valueFrom: configMapKeyRef: {
|
||||
key: "DEMO_OAUTH_REDIRECT_URI"
|
||||
name: "oauth-config"
|
||||
optional: true
|
||||
}
|
||||
}]
|
||||
envFrom: [{
|
||||
configMapRef: name: "environment-config"
|
||||
}, {
|
||||
configMapRef: name: "service-api-config"
|
||||
}]
|
||||
image: "us-central1-docker.pkg.dev/bank-of-anthos-ci/bank-of-anthos/frontend:v0.6.5@sha256:d72050f70d12383e4434ad04d189b681dc625f696087ddf0b5df641645c9dafa"
|
||||
livenessProbe: {
|
||||
httpGet: {
|
||||
path: "/ready"
|
||||
port: 8080
|
||||
}
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 15
|
||||
timeoutSeconds: 30
|
||||
}
|
||||
name: "front"
|
||||
readinessProbe: {
|
||||
httpGet: {
|
||||
path: "/ready"
|
||||
port: 8080
|
||||
}
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 10
|
||||
}
|
||||
resources: {
|
||||
limits: {
|
||||
cpu: "250m"
|
||||
memory: "128Mi"
|
||||
}
|
||||
requests: {
|
||||
cpu: "100m"
|
||||
memory: "64Mi"
|
||||
}
|
||||
}
|
||||
securityContext: {
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities: drop: ["all"]
|
||||
privileged: false
|
||||
readOnlyRootFilesystem: true
|
||||
}
|
||||
volumeMounts: [{
|
||||
mountPath: "/tmp"
|
||||
name: "tmp"
|
||||
}, {
|
||||
mountPath: "/tmp/.ssh"
|
||||
name: "publickey"
|
||||
readOnly: true
|
||||
}]
|
||||
}]
|
||||
volumes: [
|
||||
{
|
||||
emptyDir: {}
|
||||
name: "tmp"
|
||||
},
|
||||
{
|
||||
name: "publickey"
|
||||
secret: {
|
||||
items: [{key: "jwtRS256.key.pub", path: "publickey"}]
|
||||
secretName: "jwt-key"
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allow HTTPRoutes in the ingress gateway namespace to reference Services
|
||||
// in this namespace.
|
||||
ReferenceGrant: grant: _ReferenceGrant & {
|
||||
metadata: namespace: Namespace
|
||||
}
|
||||
|
||||
// Include shared resources
|
||||
_BankOfHolos.Resources
|
||||
}
|
||||
}
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Line 7 of the `schema.cue` file defines the _default_ value for
|
||||
`_Organization.DisplayName` by using `string | *"..."`. In CUE, the `*`
|
||||
asterisk character denotes a [default value].
|
||||
|
||||
Line 78 of the `bank-frontend.cue` file refers to `_Organization.DisplayName` to
|
||||
configure the front end web container.
|
||||
|
||||
Let's change the name of the bank by defining a new value for
|
||||
`_Organization.DisplayName` at the root of the configuration. Create
|
||||
`projects/organization.cue` with the following content.
|
||||
|
||||
<Tabs groupId="B386181F-EBE7-469D-8CB5-37631067669B">
|
||||
<TabItem value="projects/organization.cue" label="projects/organization.cue">
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
_Organization: DisplayName: "The Holistic-Bank"
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Let's render the platform and see if this changes the name.
|
||||
|
||||
<Tabs groupId="A014333C-3271-4C22-87E6-2B7BF898EA3E">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
holos render platform ./platform
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```txt
|
||||
could not run: could not marshal json projects/platform/components/istio/cni: cue: marshal error: _Organization.DisplayName: 2 errors in empty disjunction: (and 2 more errors) at internal/builder/builder.go:63
|
||||
_Organization.DisplayName: _Organization.DisplayName: 2 errors in empty disjunction: (and 2 more errors)
|
||||
could not run: could not marshal json projects/platform/components/argocd/crds: cue: marshal error: _Organization.DisplayName: 2 errors in empty disjunction: (and 2 more errors) at internal/builder/builder.go:63
|
||||
_Organization.DisplayName: _Organization.DisplayName: 2 errors in empty disjunction: (and 2 more errors)
|
||||
could not run: could not render component: exit status 1 at builder/v1alpha4/builder.go:95
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::warning Whoops
|
||||
The development team defined a value that isn't allowed by the
|
||||
configuration.
|
||||
:::
|
||||
|
||||
Someone else in the organization placed a [constraint] on the
|
||||
configuration to ensure the display name contains only letters, numbers, and
|
||||
spaces. This constraint is expressed as a [regular expression].
|
||||
|
||||
:::tip
|
||||
CUE provides clear visibility where to start looking to resolve conflicts. Each
|
||||
file and line number listed is a place the `#Organization.DisplayName` field is
|
||||
defined.
|
||||
:::
|
||||
|
||||
Let's try again, this time replacing the hyphen with a space.
|
||||
|
||||
<Tabs groupId="F93B34FA-C0C6-4793-A32F-DAD094403208">
|
||||
<TabItem value="projects/organization.cue" label="projects/organization.cue">
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
_Organization: DisplayName: "The Holistic Bank"
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
<Tabs groupId="5FD68778-476A-4F82-8817-71CEE205216E">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
holos render platform ./platform
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```txt
|
||||
rendered bank-ledger-db for cluster workload in 139.863625ms
|
||||
rendered bank-accounts-db for cluster workload in 151.74875ms
|
||||
rendered bank-balance-reader for cluster workload in 154.356083ms
|
||||
rendered bank-ledger-writer for cluster workload in 161.209541ms
|
||||
rendered bank-userservice for cluster workload in 163.373417ms
|
||||
rendered bank-backend-config for cluster workload in 179.271208ms
|
||||
rendered bank-secrets for cluster workload in 204.35625ms
|
||||
rendered gateway for cluster workload in 118.707583ms
|
||||
rendered httproutes for cluster workload in 140.981541ms
|
||||
rendered bank-transaction-history for cluster workload in 156.066875ms
|
||||
rendered bank-frontend for cluster workload in 300.102292ms
|
||||
rendered bank-contacts for cluster workload in 159.89625ms
|
||||
rendered cni for cluster workload in 150.754458ms
|
||||
rendered istiod for cluster workload in 222.922625ms
|
||||
rendered app-projects for cluster workload in 118.422792ms
|
||||
rendered ztunnel for cluster workload in 142.840625ms
|
||||
rendered cert-manager for cluster workload in 190.938834ms
|
||||
rendered base for cluster workload in 340.679416ms
|
||||
rendered local-ca for cluster workload in 107.120334ms
|
||||
rendered external-secrets for cluster workload in 145.020834ms
|
||||
rendered argocd for cluster workload in 299.690917ms
|
||||
rendered namespaces for cluster workload in 115.862334ms
|
||||
rendered gateway-api for cluster workload in 225.783833ms
|
||||
rendered external-secrets-crds for cluster workload in 339.741166ms
|
||||
rendered crds for cluster workload in 421.849041ms
|
||||
rendered platform in 718.015959ms
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::tip Success
|
||||
Great, the platform rendered. We know the display name is valid according to
|
||||
the constraints.
|
||||
:::
|
||||
|
||||
Let's see if the new display name value updated the configuration for the bank
|
||||
frontend.
|
||||
|
||||
<Tabs groupId="6C068651-2061-4262-BE1E-7BB3E7EB66CB">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
git status
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```txt
|
||||
On branch main
|
||||
Your branch and 'jeffmccune/main' have diverged,
|
||||
and have 2 and 4 different commits each, respectively.
|
||||
(use "git pull" to merge the remote branch into yours)
|
||||
|
||||
Changes not staged for commit:
|
||||
(use "git add <file>..." to update what will be committed)
|
||||
(use "git restore <file>..." to discard changes in working directory)
|
||||
// highlight-next-line
|
||||
modified: deploy/clusters/workload/components/app-projects/app-projects.gen.yaml
|
||||
modified: deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml
|
||||
|
||||
Untracked files:
|
||||
(use "git add <file>..." to include in what will be committed)
|
||||
projects/organization.cue
|
||||
|
||||
no changes added to commit (use "git add" and/or "git commit -a")
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
<Tabs groupId="4A20831E-461B-4EDE-8F6E-E73C3AEC12DB">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
git diff
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```diff
|
||||
diff --git a/deploy/clusters/workload/components/app-projects/app-projects.gen.yaml b/deploy/clusters/workload/components/app-projects/app-projects.gen.yaml
|
||||
index 7914756..250c660 100644
|
||||
--- a/deploy/clusters/workload/components/app-projects/app-projects.gen.yaml
|
||||
+++ b/deploy/clusters/workload/components/app-projects/app-projects.gen.yaml
|
||||
@@ -9,7 +9,7 @@ spec:
|
||||
clusterResourceWhitelist:
|
||||
- group: '*'
|
||||
kind: '*'
|
||||
- description: Holos managed AppProject for Bank of Holos
|
||||
+ description: Holos managed AppProject for The Holistic Bank
|
||||
destinations:
|
||||
- namespace: '*'
|
||||
server: '*'
|
||||
@@ -26,7 +26,7 @@ spec:
|
||||
clusterResourceWhitelist:
|
||||
- group: '*'
|
||||
kind: '*'
|
||||
- description: Holos managed AppProject for Bank of Holos
|
||||
+ description: Holos managed AppProject for The Holistic Bank
|
||||
destinations:
|
||||
- namespace: '*'
|
||||
server: '*'
|
||||
@@ -43,7 +43,7 @@ spec:
|
||||
clusterResourceWhitelist:
|
||||
- group: '*'
|
||||
kind: '*'
|
||||
- description: Holos managed AppProject for Bank of Holos
|
||||
+ description: Holos managed AppProject for The Holistic Bank
|
||||
destinations:
|
||||
- namespace: '*'
|
||||
server: '*'
|
||||
@@ -60,7 +60,7 @@ spec:
|
||||
clusterResourceWhitelist:
|
||||
- group: '*'
|
||||
kind: '*'
|
||||
- description: Holos managed AppProject for Bank of Holos
|
||||
+ description: Holos managed AppProject for The Holistic Bank
|
||||
destinations:
|
||||
- namespace: '*'
|
||||
server: '*'
|
||||
diff --git a/deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml b/deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml
|
||||
index dae6f93..d41516b 100644
|
||||
--- a/deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml
|
||||
+++ b/deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml
|
||||
@@ -71,7 +71,7 @@ spec:
|
||||
containers:
|
||||
- env:
|
||||
- name: BANK_NAME
|
||||
- value: Bank of Holos
|
||||
+ value: The Holistic Bank
|
||||
- name: ENV_PLATFORM
|
||||
value: local
|
||||
- name: VERSION
|
||||
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::danger
|
||||
The new display name changed the frontend container, but it _also_ affected the
|
||||
app-projects component owned by the platform team.
|
||||
:::
|
||||
|
||||
Submitting a pull request would trigger a code review from the platform
|
||||
engineering team who manages the app-projects component. Let's see how to
|
||||
narrow the change down to limit the scope to the bank's user facing services.
|
||||
All of these services are managed under `projects/bank-of-holos/` Move the
|
||||
`organization.cue` file into this folder to limit the scope of configuration to
|
||||
the the components contained within.
|
||||
|
||||
```bash
|
||||
mv projects/organization.cue projects/bank-of-holos/
|
||||
```
|
||||
|
||||
Render the platform and let's see what changed.
|
||||
|
||||
<Tabs groupId="0FFEC244-B59B-4136-9C82-837985DC2AB8">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
holos render platform ./platform
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```txt
|
||||
rendered bank-ledger-db for cluster workload in 163.814917ms
|
||||
rendered bank-accounts-db for cluster workload in 163.960208ms
|
||||
rendered bank-userservice for cluster workload in 164.1625ms
|
||||
rendered bank-ledger-writer for cluster workload in 169.185291ms
|
||||
rendered bank-balance-reader for cluster workload in 174.5455ms
|
||||
rendered bank-backend-config for cluster workload in 178.092125ms
|
||||
rendered bank-secrets for cluster workload in 202.305334ms
|
||||
rendered gateway for cluster workload in 122.81725ms
|
||||
rendered httproutes for cluster workload in 134.121084ms
|
||||
rendered bank-contacts for cluster workload in 146.4185ms
|
||||
rendered bank-frontend for cluster workload in 311.35425ms
|
||||
rendered bank-transaction-history for cluster workload in 160.103ms
|
||||
rendered cni for cluster workload in 145.762083ms
|
||||
rendered istiod for cluster workload in 216.0065ms
|
||||
rendered app-projects for cluster workload in 117.684333ms
|
||||
rendered ztunnel for cluster workload in 144.555292ms
|
||||
rendered cert-manager for cluster workload in 178.247917ms
|
||||
rendered base for cluster workload in 336.679ms
|
||||
rendered external-secrets for cluster workload in 142.21825ms
|
||||
rendered local-ca for cluster workload in 101.249ms
|
||||
rendered argocd for cluster workload in 280.54525ms
|
||||
rendered namespaces for cluster workload in 106.822042ms
|
||||
rendered gateway-api for cluster workload in 200.459791ms
|
||||
rendered external-secrets-crds for cluster workload in 470.125833ms
|
||||
rendered crds for cluster workload in 844.388666ms
|
||||
rendered platform in 1.154937084s
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
<Tabs groupId="DE4FEEE5-FC53-48A6-BC6F-D0EA1DBFD00C">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
git diff
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```diff
|
||||
diff --git a/deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml b/deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml
|
||||
index dae6f93..d41516b 100644
|
||||
--- a/deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml
|
||||
+++ b/deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml
|
||||
@@ -71,7 +71,7 @@ spec:
|
||||
containers:
|
||||
- env:
|
||||
- name: BANK_NAME
|
||||
- value: Bank of Holos
|
||||
+ value: The Holistic Bank
|
||||
- name: ENV_PLATFORM
|
||||
value: local
|
||||
- name: VERSION
|
||||
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::tip Success
|
||||
Great! This time, the only manifest affected is our `bank-frontend.gen.yaml`.
|
||||
:::
|
||||
|
||||
The `BANK_NAME` environment variable will change as we expect, and only the dev
|
||||
teams managing the bank services components are affected by the change.
|
||||
|
||||
Let's commit and push this change and see if it works.
|
||||
|
||||
<Tabs groupId="435D9C60-F841-4CF1-A947-506422E6BAC9">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
git add .
|
||||
git commit -m 'frontend: rename bank to The Holistic Bank'
|
||||
git push
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```txt
|
||||
[main fda74ec] frontend: rename bank to The Holistic Bank
|
||||
2 files changed, 4 insertions(+), 1 deletion(-)
|
||||
create mode 100644 projects/bank-of-holos/organization.cue
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Now that we've pushed the change, let's apply the change to the platform.
|
||||
|
||||
## Apply the Change
|
||||
|
||||
Once we've pushed the change, navigate to the [bank-frontend GitOps
|
||||
Application](https://argocd.holos.localhost/applications/argocd/bank-frontend?view=tree&resource=).
|
||||
We can see the Deployment needs to sync to the desired state we just pushed.
|
||||
|
||||

|
||||
|
||||
Clicking on the frontend Deployment, we see the diff with the change we expect.
|
||||
|
||||

|
||||
|
||||
Sync the change, ArgoCD applies the desired configuration state to the cluster
|
||||
and Kubernetes handles rolling out the updated Deployment resource.
|
||||
|
||||

|
||||
|
||||
Soon, the deployment finishes and the component is in sync again.
|
||||
|
||||

|
||||
|
||||
Finally, let's see if the name actually changed on the website. Navigate to
|
||||
https://bank.holos.localhost/.
|
||||
|
||||

|
||||
|
||||
:::tip Success
|
||||
We successfully made our change and successfully applied the changed
|
||||
configuration to the platform.
|
||||
:::
|
||||
|
||||
Thanks for taking the time to work through this guide which covered:
|
||||
|
||||
- How multiple teams could be impacted by defining configuration at the
|
||||
`projects/` path.
|
||||
- How to scope our change to only affect components within the
|
||||
`projects/bank-of-holos/` path, eliminating the impact on other teams.
|
||||
- How CUE can [constrain] values in Holos, increasing safety.
|
||||
- How to handle a [default value] in CUE.
|
||||
- How CUE surfaces the file and line number of _every_ place to look for where a
|
||||
value is defined, making it faster and easier to troubleshoot problems.
|
||||
|
||||
|
||||
[Quickstart]: /docs/quickstart/
|
||||
[Deploy a Service]: /docs/guides/deploy-a-service/
|
||||
[Change a Service]: /docs/guides/change-a-service/
|
||||
[Helm]: /docs/api/author/v1alpha3/#Helm
|
||||
[Kubernetes]: /docs/api/author/v1alpha3/#Kubernetes
|
||||
[Kustomize]: /docs/api/author/v1alpha3/#Kustomize
|
||||
[ComponentFields]: /docs/api/author/v1alpha3/#ComponentFields
|
||||
[platform-files]: /docs/quickstart/#how-platform-rendering-works
|
||||
[AppProject]: https://argo-cd.readthedocs.io/en/stable/user-guide/projects/
|
||||
[unification operator]: https://cuelang.org/docs/reference/spec/#unification
|
||||
[code-owners]: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
|
||||
[Kustomization API]: https://github.com/kubernetes-sigs/kustomize/blob/release-kustomize-v5.2/api/types/kustomization.go#L34
|
||||
[cue import]: https://cuelang.org/docs/reference/command/cue-help-import/
|
||||
[cue get go]: https://cuelang.org/docs/concept/how-cue-works-with-go/
|
||||
[timoni-crds]: https://timoni.sh/cue/module/custom-resources/
|
||||
[HTTPRoute]: https://gateway-api.sigs.k8s.io/api-types/httproute/?h=filter
|
||||
[Ingress]: https://kubernetes.io/docs/concepts/services-networking/ingress/
|
||||
[hidden field]: https://cuelang.org/docs/tour/references/hidden/
|
||||
[comprehension]: https://cuelang.org/docs/reference/spec/#comprehensions
|
||||
[code owners]: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
|
||||
[ReferenceGrant]: https://gateway-api.sigs.k8s.io/api-types/referencegrant/
|
||||
[Local Cluster Guide]: /docs/guides/local-cluster
|
||||
[Bank of Holos]: https://github.com/holos-run/bank-of-holos
|
||||
[default value]: https://cuelang.org/docs/tour/types/defaults/
|
||||
[constrain]: https://cuelang.org/docs/tour/basics/constraints/
|
||||
[constraint]: https://cuelang.org/docs/tour/basics/constraints/
|
||||
[regular expression]: https://cuelang.org/docs/tour/expressions/regexp/
|
||||
|
Before Width: | Height: | Size: 690 KiB |
|
Before Width: | Height: | Size: 997 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 287 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1009 KiB |
|
Before Width: | Height: | Size: 617 KiB |
|
Before Width: | Height: | Size: 706 KiB |
|
Before Width: | Height: | Size: 794 KiB |