mirror of
https://github.com/holos-run/holos.git
synced 2026-03-04 07:50:15 +00:00
Compare commits
123 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a2571a745 | ||
|
|
bfd8b20b6a | ||
|
|
07cd8737b0 | ||
|
|
ff5bdab948 | ||
|
|
40093956d3 | ||
|
|
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 |
19
.cspell.json
19
.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,7 @@
|
||||
"fieldmaskpb",
|
||||
"fieldspec",
|
||||
"flushcache",
|
||||
"fluxcd",
|
||||
"fullname",
|
||||
"gatewayclass",
|
||||
"gatewayclasses",
|
||||
@@ -137,6 +148,7 @@
|
||||
"httproute",
|
||||
"httproutes",
|
||||
"iampolicygenerator",
|
||||
"incpatch",
|
||||
"Infima",
|
||||
"intstr",
|
||||
"isatty",
|
||||
@@ -146,6 +158,7 @@
|
||||
"jetstack",
|
||||
"jiralert",
|
||||
"Jsonnet",
|
||||
"Kargo",
|
||||
"kfbh",
|
||||
"killall",
|
||||
"kubeadm",
|
||||
@@ -183,6 +196,7 @@
|
||||
"mutatingwebhookconfigurations",
|
||||
"mvdan",
|
||||
"mxcl",
|
||||
"mychart",
|
||||
"myhostname",
|
||||
"myRegistrKeySecretName",
|
||||
"mysecret",
|
||||
@@ -256,6 +270,7 @@
|
||||
"rolebinding",
|
||||
"rootfs",
|
||||
"ropc",
|
||||
"sboms",
|
||||
"seccomp",
|
||||
"secretargs",
|
||||
"SECRETKEY",
|
||||
@@ -268,6 +283,7 @@
|
||||
"serviceentries",
|
||||
"serviceentry",
|
||||
"servicemonitor",
|
||||
"sigstore",
|
||||
"somevalue",
|
||||
"SOMEVAR",
|
||||
"sortoptions",
|
||||
@@ -298,14 +314,17 @@
|
||||
"tokencache",
|
||||
"Tokener",
|
||||
"tolerations",
|
||||
"TOPLEVEL",
|
||||
"Traceid",
|
||||
"traefik",
|
||||
"transactionhistory",
|
||||
"tsdb",
|
||||
"txtar",
|
||||
"typemeta",
|
||||
"udev",
|
||||
"uibutton",
|
||||
"Unmarshal",
|
||||
"unshallow",
|
||||
"unstage",
|
||||
"untar",
|
||||
"upbound",
|
||||
|
||||
131
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
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
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
.github/workflows/dev-deploy.yaml
vendored
@@ -2,7 +2,7 @@ name: Dev Deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ['main', 'dev-deploy']
|
||||
branches: ['dev-deploy']
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
|
||||
2
.github/workflows/golangci-lint.yaml
vendored
2
.github/workflows/golangci-lint.yaml
vendored
@@ -27,4 +27,4 @@ jobs:
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v6
|
||||
with:
|
||||
version: v1.60
|
||||
version: v1.64.5
|
||||
|
||||
33
.github/workflows/lint.yaml
vendored
33
.github/workflows/lint.yaml
vendored
@@ -1,6 +1,5 @@
|
||||
---
|
||||
# https://github.com/golangci/golangci-lint-action?tab=readme-ov-file#how-to-use
|
||||
name: Lint
|
||||
name: Spelling
|
||||
"on":
|
||||
push:
|
||||
branches:
|
||||
@@ -8,35 +7,11 @@ name: Lint
|
||||
- test
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: lint
|
||||
cspell:
|
||||
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
|
||||
- uses: actions/checkout@v4
|
||||
- run: ./hack/cspell
|
||||
|
||||
13
.github/workflows/release.yaml
vendored
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 }}
|
||||
|
||||
8
.github/workflows/test.yaml
vendored
8
.github/workflows/test.yaml
vendored
@@ -28,19 +28,11 @@ 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
|
||||
|
||||
- name: Set up Kubectl
|
||||
uses: azure/setup-kubectl@v4
|
||||
|
||||
- name: Install Tools
|
||||
run: |
|
||||
set -x
|
||||
make tools
|
||||
|
||||
- name: Test
|
||||
run: ./scripts/test
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -12,3 +12,4 @@ tmp/
|
||||
/holos-k3d/
|
||||
/holos-infra/
|
||||
node_modules/
|
||||
.tmp/
|
||||
|
||||
@@ -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"
|
||||
|
||||
39
Dockerfile
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"]
|
||||
|
||||
13
Makefile
13
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.
|
||||
@@ -75,6 +78,12 @@ build: ## Build holos executable.
|
||||
@echo "GOPATH=${GOPATH}"
|
||||
go build -trimpath -o bin/$(BIN_NAME) -ldflags $(LD_FLAGS) $(REPO_PATH)/cmd/$(BIN_NAME)
|
||||
|
||||
.PHONY: debug
|
||||
debug: ## Build debug executable.
|
||||
@echo "building ${BIN_NAME}-debug ${VERSION}"
|
||||
@echo "GOPATH=${GOPATH}"
|
||||
go build -o bin/$(BIN_NAME)-debug $(REPO_PATH)/cmd/$(BIN_NAME)
|
||||
|
||||
linux: ## Build holos executable for tilt.
|
||||
@echo "building ${BIN_NAME}.linux ${VERSION}"
|
||||
@echo "GOPATH=${GOPATH}"
|
||||
@@ -154,6 +163,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
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/
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -23,31 +23,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 +61,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 +81,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 +110,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 +151,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]
|
||||
@@ -167,21 +190,23 @@ type Repository struct {
|
||||
// 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. [Slice] - Slice an artifact into multiple artifacts using [kubectl-slice].
|
||||
//
|
||||
// [Introduction to Kustomize]: https://kubectl.docs.kubernetes.io/guides/config_management/introduction/
|
||||
// [kubectl-slice]: https://github.com/patrickdappollonio/kubectl-slice
|
||||
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\" | \"Slice\""`
|
||||
// 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 +216,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 +233,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 +276,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 +295,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 +316,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"`
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
63
cmd/cmd.go
Normal file
63
cmd/cmd.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"runtime/pprof"
|
||||
"runtime/trace"
|
||||
|
||||
"github.com/holos-run/holos/internal/cli"
|
||||
"github.com/holos-run/holos/internal/holos"
|
||||
)
|
||||
|
||||
// MakeMain makes a main function for the cli or tests.
|
||||
func MakeMain(options ...holos.Option) func() int {
|
||||
return func() (exitCode int) {
|
||||
cfg := holos.New(options...)
|
||||
slog.SetDefault(cfg.Logger())
|
||||
ctx := context.Background()
|
||||
|
||||
if format := os.Getenv("HOLOS_CPU_PROFILE"); format != "" {
|
||||
f, _ := os.Create(fmt.Sprintf(format, os.Getppid(), os.Getpid()))
|
||||
err := pprof.StartCPUProfile(f)
|
||||
defer func() {
|
||||
pprof.StopCPUProfile()
|
||||
f.Close()
|
||||
}()
|
||||
if err != nil {
|
||||
return cli.HandleError(ctx, err, cfg)
|
||||
}
|
||||
}
|
||||
defer memProfile(ctx, cfg)
|
||||
|
||||
if format := os.Getenv("HOLOS_TRACE"); format != "" {
|
||||
f, _ := os.Create(fmt.Sprintf(format, os.Getppid(), os.Getpid()))
|
||||
err := trace.Start(f)
|
||||
defer func() {
|
||||
trace.Stop()
|
||||
f.Close()
|
||||
}()
|
||||
if err != nil {
|
||||
return cli.HandleError(ctx, err, cfg)
|
||||
}
|
||||
}
|
||||
|
||||
feature := &holos.EnvFlagger{}
|
||||
if err := cli.New(cfg, feature).ExecuteContext(ctx); err != nil {
|
||||
return cli.HandleError(ctx, err, cfg)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func memProfile(ctx context.Context, cfg *holos.Config) {
|
||||
if format := os.Getenv("HOLOS_MEM_PROFILE"); format != "" {
|
||||
f, _ := os.Create(fmt.Sprintf(format, os.Getppid(), os.Getpid()))
|
||||
defer f.Close()
|
||||
if err := pprof.WriteHeapProfile(f); err != nil {
|
||||
_ = cli.HandleError(ctx, err, cfg)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
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."
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,11 +7,11 @@ 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
|
||||
exec holos show platform
|
||||
cmp stdout want/1.platform_spec.yaml
|
||||
|
||||
# Define the host and port in projects/blackbox.schema.cue
|
||||
@@ -22,7 +22,7 @@ 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
|
||||
@@ -73,8 +73,8 @@ core.#BuildPlan & {
|
||||
metadata: name: _Tags.component.name
|
||||
}
|
||||
-- want/1.platform_spec.yaml --
|
||||
kind: Platform
|
||||
apiVersion: v1alpha5
|
||||
kind: Platform
|
||||
metadata:
|
||||
name: default
|
||||
spec:
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
422
cmd/holos/tests/v1alpha5/issues/holos-show.txt
Normal file
422
cmd/holos/tests/v1alpha5/issues/holos-show.txt
Normal file
@@ -0,0 +1,422 @@
|
||||
# https://github.com/holos-run/holos/issues/331
|
||||
# ensure holos show components --labels selects correctly.
|
||||
# ensure BuildPlan includes labels and annotations from the platform component.
|
||||
# ensure holos render platform injects the holos_component_labels and
|
||||
# holos_component_annotations tags.
|
||||
env HOME=$WORK
|
||||
|
||||
exec holos init platform v1alpha5 --force
|
||||
exec holos show platform
|
||||
cmp stdout want/platform.yaml
|
||||
|
||||
# all buildplans are selected by default
|
||||
exec holos show buildplans
|
||||
cmp stdout want/all-buildplans.yaml
|
||||
|
||||
# one = works in the selector
|
||||
exec holos show buildplans --selector app.holos.run/name=empty1-label
|
||||
cmp stdout want/buildplans.1.yaml
|
||||
|
||||
# double == works in the selector
|
||||
exec holos show buildplans --selector app.holos.run/name==empty2-label
|
||||
cmp stdout want/buildplans.2.yaml
|
||||
|
||||
# not equal != negates the selection
|
||||
exec holos show buildplans --selector app.holos.run/name!=empty3-label
|
||||
cmp stdout want/buildplans.3.yaml
|
||||
exec holos show buildplans --selector app.holos.run/name!=something-else
|
||||
cmp stdout want/buildplans.4.yaml
|
||||
|
||||
-- platform/empty.cue --
|
||||
package holos
|
||||
|
||||
Platform: Components: {
|
||||
empty1: _
|
||||
empty2: _
|
||||
empty3: _
|
||||
empty4: _
|
||||
}
|
||||
-- platform/metadata.cue --
|
||||
package holos
|
||||
|
||||
Platform: Components: [NAME=string]: {
|
||||
name: NAME
|
||||
path: "components/empty"
|
||||
labels: "app.holos.run/name": "\(name)-label"
|
||||
annotations: "app.holos.run/description": "\(name)-annotation empty test case"
|
||||
}
|
||||
-- components/empty/empty.cue --
|
||||
package holos
|
||||
|
||||
Component: #Kubernetes & {}
|
||||
holos: Component.BuildPlan
|
||||
-- want/platform.yaml --
|
||||
apiVersion: v1alpha5
|
||||
kind: Platform
|
||||
metadata:
|
||||
name: default
|
||||
spec:
|
||||
components:
|
||||
- annotations:
|
||||
app.holos.run/description: empty1-annotation empty test case
|
||||
labels:
|
||||
app.holos.run/name: empty1-label
|
||||
name: empty1
|
||||
path: components/empty
|
||||
- annotations:
|
||||
app.holos.run/description: empty2-annotation empty test case
|
||||
labels:
|
||||
app.holos.run/name: empty2-label
|
||||
name: empty2
|
||||
path: components/empty
|
||||
- annotations:
|
||||
app.holos.run/description: empty3-annotation empty test case
|
||||
labels:
|
||||
app.holos.run/name: empty3-label
|
||||
name: empty3
|
||||
path: components/empty
|
||||
- annotations:
|
||||
app.holos.run/description: empty4-annotation empty test case
|
||||
labels:
|
||||
app.holos.run/name: empty4-label
|
||||
name: empty4
|
||||
path: components/empty
|
||||
-- want/empty.yaml --
|
||||
-- want/all-buildplans.yaml --
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: empty1
|
||||
labels:
|
||||
app.holos.run/name: empty1-label
|
||||
annotations:
|
||||
app.holos.run/description: empty1-annotation empty test case
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: components/empty1/empty1.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- resources.gen.yaml
|
||||
output: components/empty1/empty1.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- resources.gen.yaml
|
||||
---
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: empty2
|
||||
labels:
|
||||
app.holos.run/name: empty2-label
|
||||
annotations:
|
||||
app.holos.run/description: empty2-annotation empty test case
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: components/empty2/empty2.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- resources.gen.yaml
|
||||
output: components/empty2/empty2.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- resources.gen.yaml
|
||||
---
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: empty3
|
||||
labels:
|
||||
app.holos.run/name: empty3-label
|
||||
annotations:
|
||||
app.holos.run/description: empty3-annotation empty test case
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: components/empty3/empty3.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- resources.gen.yaml
|
||||
output: components/empty3/empty3.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- resources.gen.yaml
|
||||
---
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: empty4
|
||||
labels:
|
||||
app.holos.run/name: empty4-label
|
||||
annotations:
|
||||
app.holos.run/description: empty4-annotation empty test case
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: components/empty4/empty4.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- resources.gen.yaml
|
||||
output: components/empty4/empty4.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- resources.gen.yaml
|
||||
-- want/buildplans.1.yaml --
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: empty1
|
||||
labels:
|
||||
app.holos.run/name: empty1-label
|
||||
annotations:
|
||||
app.holos.run/description: empty1-annotation empty test case
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: components/empty1/empty1.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- resources.gen.yaml
|
||||
output: components/empty1/empty1.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- resources.gen.yaml
|
||||
-- want/buildplans.2.yaml --
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: empty2
|
||||
labels:
|
||||
app.holos.run/name: empty2-label
|
||||
annotations:
|
||||
app.holos.run/description: empty2-annotation empty test case
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: components/empty2/empty2.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- resources.gen.yaml
|
||||
output: components/empty2/empty2.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- resources.gen.yaml
|
||||
-- want/buildplans.3.yaml --
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: empty1
|
||||
labels:
|
||||
app.holos.run/name: empty1-label
|
||||
annotations:
|
||||
app.holos.run/description: empty1-annotation empty test case
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: components/empty1/empty1.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- resources.gen.yaml
|
||||
output: components/empty1/empty1.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- resources.gen.yaml
|
||||
---
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: empty2
|
||||
labels:
|
||||
app.holos.run/name: empty2-label
|
||||
annotations:
|
||||
app.holos.run/description: empty2-annotation empty test case
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: components/empty2/empty2.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- resources.gen.yaml
|
||||
output: components/empty2/empty2.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- resources.gen.yaml
|
||||
---
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: empty4
|
||||
labels:
|
||||
app.holos.run/name: empty4-label
|
||||
annotations:
|
||||
app.holos.run/description: empty4-annotation empty test case
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: components/empty4/empty4.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- resources.gen.yaml
|
||||
output: components/empty4/empty4.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- resources.gen.yaml
|
||||
-- want/buildplans.4.yaml --
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: empty1
|
||||
labels:
|
||||
app.holos.run/name: empty1-label
|
||||
annotations:
|
||||
app.holos.run/description: empty1-annotation empty test case
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: components/empty1/empty1.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- resources.gen.yaml
|
||||
output: components/empty1/empty1.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- resources.gen.yaml
|
||||
---
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: empty2
|
||||
labels:
|
||||
app.holos.run/name: empty2-label
|
||||
annotations:
|
||||
app.holos.run/description: empty2-annotation empty test case
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: components/empty2/empty2.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- resources.gen.yaml
|
||||
output: components/empty2/empty2.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- resources.gen.yaml
|
||||
---
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: empty3
|
||||
labels:
|
||||
app.holos.run/name: empty3-label
|
||||
annotations:
|
||||
app.holos.run/description: empty3-annotation empty test case
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: components/empty3/empty3.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- resources.gen.yaml
|
||||
output: components/empty3/empty3.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- resources.gen.yaml
|
||||
---
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: empty4
|
||||
labels:
|
||||
app.holos.run/name: empty4-label
|
||||
annotations:
|
||||
app.holos.run/description: empty4-annotation empty test case
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: components/empty4/empty4.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- resources.gen.yaml
|
||||
output: components/empty4/empty4.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- resources.gen.yaml
|
||||
@@ -0,0 +1,64 @@
|
||||
# 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
|
||||
cmp stdout 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
|
||||
50
cmd/holos/tests/v1alpha5/issues/issue366-cue-build-tags.txt
Normal file
50
cmd/holos/tests/v1alpha5/issues/issue366-cue-build-tags.txt
Normal file
@@ -0,0 +1,50 @@
|
||||
# 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
|
||||
cmp stdout want/empty.yaml
|
||||
|
||||
exec holos show platform -t foo
|
||||
cmp stdout 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 --
|
||||
apiVersion: v1alpha5
|
||||
kind: Platform
|
||||
metadata:
|
||||
name: default
|
||||
spec:
|
||||
components: []
|
||||
-- want/foo.yaml --
|
||||
apiVersion: v1alpha5
|
||||
kind: Platform
|
||||
metadata:
|
||||
name: default
|
||||
spec:
|
||||
components:
|
||||
- annotations:
|
||||
app.holos.run/description: foo empty test case
|
||||
labels:
|
||||
app.holos.run/name: foo
|
||||
name: foo
|
||||
path: components/empty
|
||||
@@ -1,7 +1,9 @@
|
||||
# https://github.com/holos-run/holos/issues/330
|
||||
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
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
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
|
||||
@@ -38,15 +38,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
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"
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,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.
|
||||
@@ -57,8 +62,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.
|
||||
@@ -79,6 +86,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.
|
||||
|
||||
@@ -15,17 +15,21 @@ Package core contains schemas for a [Platform](<#Platform>) and [BuildPlan](<#Bu
|
||||
## Index
|
||||
|
||||
- [type Artifact](<#Artifact>)
|
||||
- [type Auth](<#Auth>)
|
||||
- [type AuthSource](<#AuthSource>)
|
||||
- [type BuildPlan](<#BuildPlan>)
|
||||
- [type BuildPlanSource](<#BuildPlanSource>)
|
||||
- [type BuildPlanSpec](<#BuildPlanSpec>)
|
||||
- [type Chart](<#Chart>)
|
||||
- [type Command](<#Command>)
|
||||
- [type Component](<#Component>)
|
||||
- [type ExtractYAML](<#ExtractYAML>)
|
||||
- [type File](<#File>)
|
||||
- [type FileContent](<#FileContent>)
|
||||
- [type FileContentMap](<#FileContentMap>)
|
||||
- [type FilePath](<#FilePath>)
|
||||
- [type Generator](<#Generator>)
|
||||
- [type Helm](<#Helm>)
|
||||
- [type Instance](<#Instance>)
|
||||
- [type InternalLabel](<#InternalLabel>)
|
||||
- [type Join](<#Join>)
|
||||
- [type Kind](<#Kind>)
|
||||
@@ -38,6 +42,8 @@ Package core contains schemas for a [Platform](<#Platform>) and [BuildPlan](<#Bu
|
||||
- [type Resource](<#Resource>)
|
||||
- [type Resources](<#Resources>)
|
||||
- [type Transformer](<#Transformer>)
|
||||
- [type Validator](<#Validator>)
|
||||
- [type ValueFile](<#ValueFile>)
|
||||
- [type Values](<#Values>)
|
||||
|
||||
|
||||
@@ -56,10 +62,35 @@ Output fields are write\-once. It is an error for multiple Generators or Transfo
|
||||
|
||||
```go
|
||||
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"`
|
||||
}
|
||||
```
|
||||
|
||||
<a name="Auth"></a>
|
||||
## type Auth {#Auth}
|
||||
|
||||
Auth represents environment variable names containing auth credentials.
|
||||
|
||||
```go
|
||||
type Auth struct {
|
||||
Username AuthSource `json:"username" yaml:"username"`
|
||||
Password AuthSource `json:"password" yaml:"password"`
|
||||
}
|
||||
```
|
||||
|
||||
<a name="AuthSource"></a>
|
||||
## type AuthSource {#AuthSource}
|
||||
|
||||
AuthSource represents a source for the value of an [Auth](<#Auth>) field.
|
||||
|
||||
```go
|
||||
type AuthSource struct {
|
||||
Value string `json:"value,omitempty" yaml:"value,omitempty"`
|
||||
FromEnv string `json:"fromEnv,omitempty" yaml:"fromEnv,omitempty"`
|
||||
}
|
||||
```
|
||||
|
||||
@@ -75,27 +106,13 @@ Holos uses CUE to construct a BuildPlan. A future enhancement will support user
|
||||
```go
|
||||
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"`
|
||||
}
|
||||
```
|
||||
|
||||
<a name="BuildPlanSource"></a>
|
||||
## type BuildPlanSource {#BuildPlanSource}
|
||||
|
||||
BuildPlanSource reflects the origin of a [BuildPlan](<#BuildPlan>). Useful to save a build plan to a file, then re\-generate it without needing to process a [Platform](<#Platform>) component collection.
|
||||
|
||||
```go
|
||||
type BuildPlanSource struct {
|
||||
// Component reflects the component that produced the build plan.
|
||||
Component Component `json:"component,omitempty"`
|
||||
Spec BuildPlanSpec `json:"spec" yaml:"spec"`
|
||||
}
|
||||
```
|
||||
|
||||
@@ -107,9 +124,9 @@ BuildPlanSpec represents the specification of the [BuildPlan](<#BuildPlan>).
|
||||
```go
|
||||
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"`
|
||||
Disabled bool `json:"disabled,omitempty" yaml:"disabled,omitempty"`
|
||||
}
|
||||
```
|
||||
|
||||
@@ -121,13 +138,24 @@ Chart represents a [Helm](<#Helm>) Chart.
|
||||
```go
|
||||
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"`
|
||||
}
|
||||
```
|
||||
|
||||
<a name="Command"></a>
|
||||
## type Command {#Command}
|
||||
|
||||
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.
|
||||
|
||||
```go
|
||||
type Command struct {
|
||||
Args []string `json:"args,omitempty" yaml:"args,omitempty"`
|
||||
}
|
||||
```
|
||||
|
||||
@@ -140,19 +168,40 @@ Component represents the complete context necessary to produce a [BuildPlan](<#B
|
||||
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"`
|
||||
}
|
||||
```
|
||||
|
||||
<a name="ExtractYAML"></a>
|
||||
## type ExtractYAML {#ExtractYAML}
|
||||
|
||||
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.
|
||||
|
||||
```go
|
||||
type ExtractYAML struct {
|
||||
Path string `json:"path" yaml:"path"`
|
||||
}
|
||||
```
|
||||
|
||||
@@ -164,7 +213,7 @@ File represents a simple single file copy [Generator](<#Generator>). Useful with
|
||||
```go
|
||||
type File struct {
|
||||
// Source represents a file sub-path relative to the component path.
|
||||
Source FilePath `json:"source"`
|
||||
Source FilePath `json:"source" yaml:"source"`
|
||||
}
|
||||
```
|
||||
|
||||
@@ -209,19 +258,19 @@ Each Generator in an [Artifact](<#Artifact>) must have a distinct Output value f
|
||||
```go
|
||||
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"`
|
||||
}
|
||||
```
|
||||
|
||||
@@ -233,18 +282,38 @@ Helm represents a [Chart](<#Chart>) manifest [Generator](<#Generator>).
|
||||
```go
|
||||
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"`
|
||||
}
|
||||
```
|
||||
|
||||
<a name="Instance"></a>
|
||||
## type Instance {#Instance}
|
||||
|
||||
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](<https://docs.kargo.io/>) executes the [yaml update](<https://docs.kargo.io/references/promotion-steps#yaml-update>) and [git wait for pr](<https://docs.kargo.io/references/promotion-steps#git-wait-for-pr>) promotion steps.
|
||||
|
||||
```go
|
||||
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"`
|
||||
}
|
||||
```
|
||||
|
||||
@@ -264,7 +333,7 @@ Join represents a [Transformer](<#Transformer>) using [bytes.Join](<https://pkg.
|
||||
|
||||
```go
|
||||
type Join struct {
|
||||
Separator string `json:"separator" cue:"string | *\"---\\n\""`
|
||||
Separator string `json:"separator,omitempty" yaml:"separator,omitempty"`
|
||||
}
|
||||
```
|
||||
|
||||
@@ -294,9 +363,9 @@ Kustomize represents a kustomization [Transformer](<#Transformer>).
|
||||
```go
|
||||
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"`
|
||||
}
|
||||
```
|
||||
|
||||
@@ -308,7 +377,13 @@ Metadata represents data about the resource such as the Name.
|
||||
```go
|
||||
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"`
|
||||
}
|
||||
```
|
||||
|
||||
@@ -326,14 +401,14 @@ cue export --out yaml ./platform
|
||||
```go
|
||||
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"`
|
||||
}
|
||||
```
|
||||
|
||||
@@ -345,7 +420,7 @@ PlatformSpec represents the platform specification.
|
||||
```go
|
||||
type PlatformSpec struct {
|
||||
// Components represents a collection of holos components to manage.
|
||||
Components []Component `json:"components"`
|
||||
Components []Component `json:"components" yaml:"components"`
|
||||
}
|
||||
```
|
||||
|
||||
@@ -354,10 +429,13 @@ type PlatformSpec struct {
|
||||
|
||||
Repository represents a [Helm](<#Helm>) [Chart](<#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.
|
||||
|
||||
```go
|
||||
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"`
|
||||
}
|
||||
```
|
||||
|
||||
@@ -386,21 +464,55 @@ Transformer combines multiple inputs from prior [Generator](<#Generator>) or [Tr
|
||||
|
||||
1. [Kustomize](<#Kustomize>) \- Patch and transform the output from prior generators or transformers. See [Introduction to Kustomize](<https://kubectl.docs.kubernetes.io/guides/config_management/introduction/>).
|
||||
2. [Join](<#Join>) \- Concatenate multiple prior outputs into one output.
|
||||
3. \[Slice\] \- Slice an artifact into multiple artifacts using [kubectl\\\-slice](<https://github.com/patrickdappollonio/kubectl-slice>).
|
||||
|
||||
```go
|
||||
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\" | \"Slice\""`
|
||||
// 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"`
|
||||
}
|
||||
```
|
||||
|
||||
<a name="Validator"></a>
|
||||
## type Validator {#Validator}
|
||||
|
||||
Validator validates files. Useful to validate an [Artifact](<#Artifact>) prior to writing it out to the final destination. Holos may execute validators concurrently. See the [validators](<https://holos.run/docs/v1alpha5/tutorial/validators/>) tutorial for an end to end example.
|
||||
|
||||
```go
|
||||
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"`
|
||||
}
|
||||
```
|
||||
|
||||
<a name="ValueFile"></a>
|
||||
## type ValueFile {#ValueFile}
|
||||
|
||||
ValueFile represents one Helm value file produced from CUE.
|
||||
|
||||
```go
|
||||
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"`
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
16
doc/md/common/example-component-integrate.mdx
Normal file
16
doc/md/common/example-component-integrate.mdx
Normal file
@@ -0,0 +1,16 @@
|
||||
Integrate the `podinfo` component into the platform.
|
||||
|
||||
```bash
|
||||
cat <<EOF >platform/podinfo.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
Platform: Components: podinfo: {
|
||||
name: "podinfo"
|
||||
path: "components/podinfo"
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
34
doc/md/common/example-component.mdx
Normal file
34
doc/md/common/example-component.mdx
Normal file
@@ -0,0 +1,34 @@
|
||||
Create a directory for the example `podinfo` component we'll use to render
|
||||
platform manifests.
|
||||
|
||||
```bash
|
||||
mkdir -p components/podinfo
|
||||
```
|
||||
|
||||
Create the CUE configuration for the example `podinfo` component.
|
||||
|
||||
```bash
|
||||
cat <<EOF >components/podinfo/podinfo.cue
|
||||
```
|
||||
```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)
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
description: Architecture diagrams.
|
||||
slug: architecture
|
||||
sidebar_position: 90
|
||||
sidebar_position: 100
|
||||
---
|
||||
|
||||
import RenderPlatformDiagram from '@site/src/diagrams/render-platform-sequence.mdx';
|
||||
|
||||
57
doc/md/topics/comparison.mdx
Normal file
57
doc/md/topics/comparison.mdx
Normal file
@@ -0,0 +1,57 @@
|
||||
---
|
||||
description: Holos compared to other tools
|
||||
sidebar_label: Comparison
|
||||
slug: comparison
|
||||
sidebar_position: 40
|
||||
---
|
||||
|
||||
{/* cspell:ignore Prodan, rollouts */}
|
||||
|
||||
# Holos compared to other tools
|
||||
|
||||
## Timoni
|
||||
|
||||
Holos and Timoni both aim to solve similar problems but approach them at
|
||||
different levels of the stack.
|
||||
|
||||
Timoni focuses on managing applications by evaluating [CUE] stored in OCI
|
||||
containers. Its creator, Stephan Prodan, envisions a controller that applies the
|
||||
resulting manifests. In this process, Timoni defers to [Flux] for managing Helm
|
||||
charts within the cluster.
|
||||
|
||||
In contrast, Holos implements the [Rendered Manifests Pattern] and takes a
|
||||
different approach, particularly in how it handles [Helm] charts. Like
|
||||
[ArgoCD], Holos renders Helm charts into manifests using the `helm template`
|
||||
command in its rendering pipeline. Holos differs from Timoni in several important
|
||||
ways:
|
||||
|
||||
1. **Separation of Responsibilities:** Holos stops short of applying
|
||||
rendered manifests to a cluster, leaving that task to existing tools like
|
||||
[ArgoCD], [Flux], or even basic `kubectl apply` commands.
|
||||
|
||||
2. **Ecosystem Integration:** By focusing solely on rendering Kubernetes
|
||||
manifests, Holos creates space for other tools to handle deployment and
|
||||
management. For instance, Holos integrates seamlessly with [Kargo] for
|
||||
progressive rollouts, as [Kargo] operates between Holos and the Kubernetes API.
|
||||
This approach ensures that you're not locked into any specific tool and can
|
||||
choose the best solution for each task.
|
||||
|
||||
3. **Platform Integration:** Holos focuses on integrating multiple Components
|
||||
into a larger Platform. In Holos terminology, a Component refers to a wrapper
|
||||
for [Helm] charts, [Kustomize] bases, or raw YAML files, integrated into the
|
||||
rendering pipeline through [CUE]. A Platform represents the full combination of
|
||||
these components.
|
||||
|
||||
4. **Explicit Rendering Pipeline:** Holos emphasizes flexibility in its
|
||||
rendering pipeline. The system allows any tool that generates Kubernetes
|
||||
manifests to be wrapped in a Generator, which can then feed into existing
|
||||
transformers like [Kustomize]. This explicit separation makes Holos highly
|
||||
adaptable for different workflows.
|
||||
|
||||
[Kargo]: https://kargo.io/
|
||||
[Flux]: https://fluxcd.io
|
||||
[Helm]: https://helm.sh
|
||||
[ArgoCD]: https://argoproj.github.io/cd/
|
||||
[Kustomize]: https://kustomize.io/
|
||||
[CUE]: https://cuelang.org/
|
||||
[Rendered Manifests Pattern]: https://akuity.io/blog/the-rendered-manifests-pattern
|
||||
@@ -1,12 +0,0 @@
|
||||
---
|
||||
description: Re-use components by passing in parameters.
|
||||
slug: component-parameters
|
||||
sidebar_position: 400
|
||||
---
|
||||
|
||||
# Component Parameters
|
||||
|
||||
Key points:
|
||||
|
||||
1. Components can be reused.
|
||||
2. The Platform spec can pass user defined parameters to a component.
|
||||
@@ -1,12 +0,0 @@
|
||||
---
|
||||
description: Organize clusters into fleets.
|
||||
slug: fleets
|
||||
sidebar_position: 300
|
||||
---
|
||||
|
||||
# Fleets
|
||||
|
||||
Key points:
|
||||
|
||||
1. Workload fleet.
|
||||
2. Management fleet.
|
||||
@@ -7,6 +7,8 @@ sidebar_position: 110
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CommonComponent from '../../common/example-component.mdx';
|
||||
import CommonComponentIntegrate from '../../common/example-component-integrate.mdx';
|
||||
|
||||
# ArgoCD Application
|
||||
|
||||
@@ -30,62 +32,10 @@ mkdir holos-argocd-application && cd holos-argocd-application
|
||||
holos init platform v1alpha5
|
||||
```
|
||||
|
||||
### Creating a component
|
||||
### Creating an example Component
|
||||
|
||||
Create a directory for the `podinfo` component. Create an empty file and then
|
||||
add the following CUE configuration to it.
|
||||
|
||||
<Tabs groupId="1D2C6013-3D19-4516-8147-5A6EE214CAFF">
|
||||
<TabItem value="components/podinfo/podinfo.cue" label="Podinfo Helm Chart">
|
||||
```bash
|
||||
mkdir -p components/podinfo
|
||||
touch components/podinfo/podinfo.cue
|
||||
```
|
||||
```bash
|
||||
cat <<EOF >components/podinfo/podinfo.cue
|
||||
```
|
||||
```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"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Integrate the `podinfo` component into the platform.
|
||||
|
||||
<Tabs groupId="tutorial-hello-register-podinfo-component">
|
||||
<TabItem value="platform/podinfo.cue" label="Register Podinfo">
|
||||
```bash
|
||||
cat <<EOF >platform/podinfo.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
Platform: Components: podinfo: {
|
||||
name: "podinfo"
|
||||
path: "components/podinfo"
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
<CommonComponent />
|
||||
<CommonComponentIntegrate />
|
||||
|
||||
## Adding ArgoCD Application
|
||||
|
||||
@@ -227,7 +177,7 @@ source:
|
||||
<Tabs groupId="E150C802-7162-4FBF-82A7-77D9ADAEE847">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
holos render platform ./platform
|
||||
holos render platform
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
@@ -267,8 +217,7 @@ spec:
|
||||
[podinfo]: https://github.com/stefanprodan/podinfo
|
||||
[CUE Module]: https://cuelang.org/docs/reference/modules/
|
||||
[CUE Tags]: https://cuelang.org/docs/howto/inject-value-into-evaluation-using-tag-attribute/
|
||||
[Platform]: ../api/author.md#Platform
|
||||
[Component Parameters]: ../topics/component-parameters.mdx
|
||||
[Application]: https://argo-cd.readthedocs.io/en/stable/user-guide/application-specification/
|
||||
[ComponentConfig]: ../api/author.md#ComponentConfig
|
||||
[Artifact]: ../api/core.md#Artifact
|
||||
[Platform]: ../../api/author.md#Platform
|
||||
[ComponentConfig]: ../../api/author.md#ComponentConfig
|
||||
[Artifact]: ../../api/core.md#Artifact
|
||||
218
doc/md/topics/gitops/flux-kustomization.mdx
Normal file
218
doc/md/topics/gitops/flux-kustomization.mdx
Normal file
@@ -0,0 +1,218 @@
|
||||
---
|
||||
slug: flux-kustomization
|
||||
title: Flux Kustomization
|
||||
description: Configuring a Kustomization for each Component.
|
||||
sidebar_position: 120
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CommonComponent from '../../common/example-component.mdx';
|
||||
import CommonComponentIntegrate from '../../common/example-component-integrate.mdx';
|
||||
|
||||
# Flux Kustomization
|
||||
|
||||
## Overview
|
||||
|
||||
This topic covers how to mix in a Flux Kustomization to all components. We'll
|
||||
use the `Artifacts` field of [ComponentConfig] defined by the author schema.
|
||||
|
||||
## The Code
|
||||
|
||||
### Generating the structure
|
||||
|
||||
Use `holos` to generate a minimal platform directory structure. Start by
|
||||
creating a blank directory to hold the platform configuration.
|
||||
|
||||
```shell
|
||||
mkdir holos-flux-kustomization && cd holos-flux-kustomization
|
||||
```
|
||||
|
||||
```shell
|
||||
holos init platform v1alpha5
|
||||
```
|
||||
|
||||
### Creating an example Component
|
||||
|
||||
<CommonComponent />
|
||||
<CommonComponentIntegrate />
|
||||
|
||||
## Adding Flux Kustomizations
|
||||
|
||||
Configure Holos to render a [Kustomization] by defining an [Artifact] for it in
|
||||
every BuildPlan holos produces. We're unifying our custom configuration with
|
||||
the existing `#ComponentConfig` defined in `schema.cue`.
|
||||
|
||||
```bash
|
||||
cat <<EOF >flux-kustomization.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
import (
|
||||
"path"
|
||||
flux "kustomize.toolkit.fluxcd.io/kustomization/v1"
|
||||
)
|
||||
|
||||
#ComponentConfig: {
|
||||
Name: _
|
||||
OutputBaseDir: _
|
||||
|
||||
let ArtifactPath = path.Join([OutputBaseDir, "gitops", "\(Name).kustomization.gen.yaml"], path.Unix)
|
||||
let ResourcesPath = path.Join(["deploy", OutputBaseDir, "components", Name], path.Unix)
|
||||
|
||||
Artifacts: "\(Name)-kustomization": {
|
||||
artifact: ArtifactPath
|
||||
generators: [{
|
||||
kind: "Resources"
|
||||
output: artifact
|
||||
resources: Kustomization: (Name): flux.#Kustomization & {
|
||||
metadata: name: Name
|
||||
metadata: namespace: "default"
|
||||
spec: {
|
||||
interval: "5m"
|
||||
timeout: "1m"
|
||||
prune: true
|
||||
path: ResourcesPath
|
||||
sourceRef: {
|
||||
kind: "GitRepository"
|
||||
name: "webapp"
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
## Inspecting the BuildPlan
|
||||
|
||||
Our customized `#ComponentConfig` results in the following `BuildPlan`.
|
||||
|
||||
:::note
|
||||
The second artifact around line 40 contains the configured `Kustomization`
|
||||
resource.
|
||||
:::
|
||||
|
||||
<Tabs groupId="55075C71-02E8-4222-88C0-2D52C82D18FC">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
holos cue export --expression holos --out=yaml ./components/podinfo
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```yaml showLineNumbers
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: podinfo
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: components/podinfo/podinfo.gen.yaml
|
||||
generators:
|
||||
- kind: Helm
|
||||
output: helm.gen.yaml
|
||||
helm:
|
||||
chart:
|
||||
name: podinfo
|
||||
version: 6.6.2
|
||||
release: podinfo
|
||||
repository:
|
||||
name: podinfo
|
||||
url: https://stefanprodan.github.io/podinfo
|
||||
values:
|
||||
ui:
|
||||
message: Hello World
|
||||
enableHooks: false
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
resources: {}
|
||||
validators: []
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- helm.gen.yaml
|
||||
- resources.gen.yaml
|
||||
output: components/podinfo/podinfo.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
resources:
|
||||
- helm.gen.yaml
|
||||
- resources.gen.yaml
|
||||
kind: Kustomization
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
- artifact: gitops/podinfo.kustomization.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: gitops/podinfo.kustomization.gen.yaml
|
||||
resources:
|
||||
Kustomization:
|
||||
podinfo:
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: podinfo
|
||||
namespace: default
|
||||
spec:
|
||||
interval: 5m
|
||||
path: deploy/components/podinfo
|
||||
prune: true
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: webapp
|
||||
timeout: 1m
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Rendering manifests
|
||||
|
||||
<Tabs groupId="E150C802-7162-4FBF-82A7-77D9ADAEE847">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
holos render platform
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```
|
||||
rendered podinfo in 140.341417ms
|
||||
rendered platform in 140.441333ms
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Reviewing the Kustomization
|
||||
|
||||
The Artifact we added to `#ComponentConfig` will produce a Flux Kustomization
|
||||
resource for every component in the platform. The output in this example is
|
||||
located at:
|
||||
|
||||
```txt
|
||||
deploy/gitops/podinfo.kustomization.gen.yaml
|
||||
```
|
||||
```yaml showLineNumbers
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: podinfo
|
||||
namespace: default
|
||||
spec:
|
||||
interval: 5m
|
||||
path: deploy/components/podinfo
|
||||
prune: true
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: webapp
|
||||
timeout: 1m
|
||||
```
|
||||
|
||||
[podinfo]: https://github.com/stefanprodan/podinfo
|
||||
[CUE Module]: https://cuelang.org/docs/reference/modules/
|
||||
[CUE Tags]: https://cuelang.org/docs/howto/inject-value-into-evaluation-using-tag-attribute/
|
||||
[Kustomization]: https://fluxcd.io/flux/components/kustomize/kustomizations/
|
||||
[Platform]: ../../api/author.md#Platform
|
||||
[ComponentConfig]: ../../api/author.md#ComponentConfig
|
||||
[Artifact]: ../../api/core.md#Artifact
|
||||
19
doc/md/topics/gitops/index.mdx
Normal file
19
doc/md/topics/gitops/index.mdx
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
slug: .
|
||||
title: GitOps
|
||||
description: Managing resources with GitOps.
|
||||
sidebar_position: 120
|
||||
---
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
|
||||
# GitOps
|
||||
|
||||
This section has self contained articles covering how to manage resources using
|
||||
GitOps tooling like [ArgoCD] and [Flux].
|
||||
|
||||
---
|
||||
|
||||
<DocCardList />
|
||||
|
||||
[ArgoCD]: https://argo-cd.readthedocs.io/en/stable/
|
||||
[Flux]: https://fluxcd.io/
|
||||
20
doc/md/topics/kargo.mdx
Normal file
20
doc/md/topics/kargo.mdx
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
description: Kargo
|
||||
slug: kargo
|
||||
sidebar_position: 110
|
||||
---
|
||||
|
||||
# Kargo
|
||||
|
||||
Holos pairs nicely with [Kargo], offering a holistic solution for code
|
||||
promotion across stages.
|
||||
|
||||
Watch this space for a more detailed write up of the integration being
|
||||
developed.
|
||||
|
||||
If you're interested in this topic, please thumbs up the [Kargo
|
||||
Topic](https://github.com/holos-run/holos/issues/378) issue, or drop into
|
||||
[Discord] and let us know about your use case.
|
||||
|
||||
[Kargo]: https://kargo.io/
|
||||
[Discord]: https://discord.gg/JgDVbNpye7
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
description: Build a local cluster for use with Holos.
|
||||
slug: local-cluster
|
||||
sidebar_position: 100
|
||||
sidebar_position: 50
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
---
|
||||
description: Management Cluster
|
||||
slug: management-cluster
|
||||
sidebar_position: 200
|
||||
---
|
||||
|
||||
# Management Cluster
|
||||
|
||||
Key points:
|
||||
|
||||
1. Namespaces
|
||||
2. Certificates
|
||||
3. Secrets
|
||||
4. CronJobs
|
||||
5. GKE autopilot
|
||||
65
doc/md/topics/oci-helm-charts.mdx
Normal file
65
doc/md/topics/oci-helm-charts.mdx
Normal file
@@ -0,0 +1,65 @@
|
||||
---
|
||||
description: OCI Helm Charts
|
||||
slug: oci-helm-charts
|
||||
sidebar_position: 710
|
||||
---
|
||||
|
||||
# OCI Helm Charts
|
||||
|
||||
Holos supports OCI Helm charts. Use the following example to get started.
|
||||
|
||||
```bash
|
||||
mkdir -p oci-helm && cd oci-helm
|
||||
holos init platform v1alpha5
|
||||
```
|
||||
|
||||
```bash
|
||||
mkdir -p components/podinfo-oci
|
||||
cat <<EOF > components/podinfo-oci/podinfo-oci.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
holos: Component.BuildPlan
|
||||
|
||||
Component: #Helm & {
|
||||
Chart: {
|
||||
name: "oci://ghcr.io/stefanprodan/charts/podinfo"
|
||||
release: "podinfo"
|
||||
version: "6.6.2"
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
Register the component with the platform.
|
||||
|
||||
```bash
|
||||
cat <<EOF >platform/podinfo-oci.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
Platform: Components: podinfo: {
|
||||
name: "podinfo-oci"
|
||||
path: "components/podinfo-oci"
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
The OCI chart is cached in the vendor directory and rendered.
|
||||
|
||||
```bash
|
||||
holos render platform
|
||||
```
|
||||
|
||||
```txt
|
||||
Pulled: ghcr.io/stefanprodan/charts/podinfo:6.6.2
|
||||
Digest: sha256:83295d47de6d6ca634ed4b952a7572fc176bcc38854d0c11ca0fa197bc5f1154
|
||||
rendered podinfo-oci in 7.21581325s
|
||||
rendered platform in 7.216199167s
|
||||
```
|
||||
183
doc/md/topics/private-helm.mdx
Normal file
183
doc/md/topics/private-helm.mdx
Normal file
@@ -0,0 +1,183 @@
|
||||
---
|
||||
description: Private Helm Repositories
|
||||
slug: private-helm
|
||||
sidebar_position: 700
|
||||
---
|
||||
|
||||
# Private Helm
|
||||
|
||||
Holos supports private Helm repositories accessed with http basic authentication
|
||||
since `v0.101.4`. Use the following command to update your author and core
|
||||
schemas to support this configuration.
|
||||
|
||||
```bash
|
||||
holos init platform v1alpha5 --force
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Holos uses the Helm SDK and defers to it for authentication to private
|
||||
repositories. Each Helm Generator supports providing http basic authentication
|
||||
credentials from environment variables.
|
||||
|
||||
For example, the following BuildPlan causes `holos` to get the admin username
|
||||
password from the `HOLOS_TEST_PASS` environment variable.
|
||||
|
||||
```bash
|
||||
mkdir -p projects/holos/components/private-chart
|
||||
cat <<EOF > projects/holos/components/private-chart/private-chart.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
holos: Component.BuildPlan
|
||||
|
||||
// Test holos can access a private repository with basic auth.
|
||||
// https://github.com/holos-run/holos/issues/370
|
||||
Component: #Helm & {
|
||||
Chart: {
|
||||
name: "mychart"
|
||||
version: "0.1.0"
|
||||
repository: {
|
||||
name: "holos-test"
|
||||
url: "https://charts.holos.localhost"
|
||||
// auth: username: fromEnv: "HOLOS_TEST_USER"
|
||||
auth: username: value: "admin"
|
||||
auth: password: fromEnv: "HOLOS_TEST_PASS"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
Verify `holos` can access a private Helm repository by setting [ChartMuseum] up
|
||||
on a [Local Cluster]. We'll use https with basic auth to authenticate to the
|
||||
chart repository.
|
||||
|
||||
Using the [bank of holos] repository, deploy chart museum:
|
||||
|
||||
```bash
|
||||
holos render platform -t ChartMuseum
|
||||
```
|
||||
|
||||
Apply the manifests:
|
||||
|
||||
```bash
|
||||
kubectl apply --server-side=true -f deploy/clusters/workload/projects/holos/components/chart-museum
|
||||
kubectl apply --server-side=true -f deploy/clusters/workload/projects/network/components/httproutes
|
||||
```
|
||||
|
||||
Get the admin password:
|
||||
|
||||
```bash
|
||||
kubectl get secret -n holos chartmuseum-auth -o json \
|
||||
| jq --exit-status -r '.data.password | @base64d'
|
||||
```
|
||||
|
||||
Add a local repo:
|
||||
|
||||
```bash
|
||||
helm repo add holos-test https://charts.holos.localhost --username admin
|
||||
```
|
||||
```txt
|
||||
Password:
|
||||
"holos-test" has been added to your repositories
|
||||
```
|
||||
|
||||
:::note
|
||||
Helm by default stores this password in `~/Library/Preferences/helm/repositories.yaml`
|
||||
:::
|
||||
|
||||
Create a chart:
|
||||
|
||||
```bash
|
||||
helm create mychart
|
||||
```
|
||||
```txt
|
||||
Creating mychart
|
||||
```
|
||||
|
||||
Package it up.
|
||||
|
||||
```bash
|
||||
helm package mychart
|
||||
```
|
||||
```txt
|
||||
Successfully packaged chart and saved it to: mychart-0.1.0.tgz
|
||||
```
|
||||
|
||||
Publish it.
|
||||
|
||||
```bash
|
||||
curl --user "admin:$(pbpaste)" --data-binary "@mychart-0.1.0.tgz" https://charts.holos.localhost/api/charts
|
||||
```
|
||||
```json
|
||||
{"saved":true}
|
||||
```
|
||||
|
||||
Remove all cached charts:
|
||||
|
||||
```bash
|
||||
find . -name vendor | xargs rm -rf
|
||||
```
|
||||
|
||||
Render the chart:
|
||||
|
||||
```bash
|
||||
cat <<EOF > test-private-repo.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
@if(TestPrivateRepo)
|
||||
package holos
|
||||
|
||||
// Test holos can access a private repository with basic auth.
|
||||
// https://github.com/holos-run/holos/issues/370
|
||||
Projects: holos: #ProjectBuilder & {
|
||||
team: "holos-authors"
|
||||
|
||||
namespaces: holos: _
|
||||
_components: "private-chart": _
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
```
|
||||
time holos render platform -t TestPrivateRepo
|
||||
```
|
||||
|
||||
Check the chart was pulled and cached:
|
||||
|
||||
```shell
|
||||
tree ./projects/holos/components/private-chart/vendor
|
||||
```
|
||||
```txt
|
||||
./projects/holos/components/private-chart/vendor
|
||||
└── 0.1.0
|
||||
├── mychart
|
||||
│ ├── Chart.yaml
|
||||
│ ├── mychart-0.1.0.tgz
|
||||
│ ├── templates
|
||||
│ │ ├── NOTES.txt
|
||||
│ │ ├── _helpers.tpl
|
||||
│ │ ├── deployment.yaml
|
||||
│ │ ├── hpa.yaml
|
||||
│ │ ├── ingress.yaml
|
||||
│ │ ├── service.yaml
|
||||
│ │ ├── serviceaccount.yaml
|
||||
│ │ └── tests
|
||||
│ │ └── test-connection.yaml
|
||||
│ └── values.yaml
|
||||
└── mychart-0.1.0.tgz
|
||||
|
||||
6 directories, 11 files
|
||||
```
|
||||
|
||||
[Local Cluster]: ./local-cluster.mdx
|
||||
[ChartMuseum]: https://chartmuseum.com/docs/
|
||||
[bank of holos]: https://github.com/holos-run/bank-of-holos
|
||||
@@ -1,12 +0,0 @@
|
||||
---
|
||||
description: Secrets Management
|
||||
slug: secrets-management
|
||||
sidebar_position: 150
|
||||
---
|
||||
|
||||
# Secrets Management
|
||||
|
||||
Key points:
|
||||
|
||||
1. Namespaces
|
||||
2. ExternalSecrets
|
||||
425
doc/md/topics/structures/clusters.mdx
Normal file
425
doc/md/topics/structures/clusters.mdx
Normal file
@@ -0,0 +1,425 @@
|
||||
---
|
||||
slug: clusters
|
||||
title: Clusters
|
||||
description: Managing clusters - management and workload sets.
|
||||
sidebar_position: 100
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CommonComponent from '../../common/example-component.mdx';
|
||||
|
||||
# Clusters
|
||||
|
||||
## Overview
|
||||
|
||||
This topic covers one common method to manage multiple clusters with Holos. We'll
|
||||
define two schemas to hold cluster attributes. First, a single `#Cluster` then
|
||||
a `#Clusters` collection. We'll use a `Clusters: #Clusters` struct to look up
|
||||
configuration data using a key. We'll use the cluster name as the lookup key
|
||||
identifying the cluster.
|
||||
|
||||
We'll also organize sets of similar clusters by defining `#ClusterSet` and
|
||||
`#ClusterSets`. We'll use a `ClusterSets:
|
||||
#ClusterSets` struct to configure a management cluster and iterate over all
|
||||
workload clusters.
|
||||
|
||||
## The Code
|
||||
|
||||
### Initializing the structure
|
||||
|
||||
Use `holos` to generate a minimal platform directory structure. Start by
|
||||
creating a blank directory to hold the platform configuration.
|
||||
|
||||
```shell
|
||||
mkdir holos-multiple-clusters && cd holos-multiple-clusters
|
||||
```
|
||||
|
||||
```shell
|
||||
holos init platform v1alpha5
|
||||
```
|
||||
|
||||
### Using an example Component
|
||||
|
||||
<CommonComponent />
|
||||
|
||||
We'll integrate the component with the platform after we define the
|
||||
configuration structures.
|
||||
|
||||
## Defining Clusters
|
||||
|
||||
We'll define a `#Cluster` schema and a `#Clusters` collection in this section.
|
||||
We'll use these schemas to define a `Clusters` structure we use to manage
|
||||
multiple clusters.
|
||||
|
||||
### Assumptions
|
||||
|
||||
We'll make the following assumptions, which hold true for many real world
|
||||
environments.
|
||||
|
||||
1. There are two sets of clusters, workload clusters and management clusters.
|
||||
2. There is one management cluster.
|
||||
3. There are multiple workload clusters.
|
||||
4. Each workload cluster is configured similarly, but not identically, to the
|
||||
others.
|
||||
|
||||
### Prototyping the data
|
||||
|
||||
Before we define the schema, let's prototype the data structure we want to work
|
||||
with. We want a structure that makes it easy to iterate over each cluster in
|
||||
two distinct sets of clusters, management clusters and workload clusters. The
|
||||
following `ClusterSets` struct accomplishes this goal.
|
||||
|
||||
```yaml showLineNumbers
|
||||
management:
|
||||
name: management
|
||||
clusters:
|
||||
management:
|
||||
name: management
|
||||
region: us-central1
|
||||
set: management
|
||||
workload:
|
||||
name: workload
|
||||
clusters:
|
||||
e1:
|
||||
name: e1
|
||||
region: us-east1
|
||||
set: workload
|
||||
w1:
|
||||
name: w1
|
||||
region: us-west1
|
||||
set: workload
|
||||
```
|
||||
|
||||
:::tip
|
||||
The `ClusterSets` data structure supports iterating over each cluster in each
|
||||
cluster set.
|
||||
:::
|
||||
|
||||
:::important
|
||||
You're free to define your own fields and structures like we define `region` in
|
||||
this topic.
|
||||
:::
|
||||
|
||||
### Defining the schema
|
||||
|
||||
Armed with a concrete example of the structure, we can write a schema to define
|
||||
and validate the data.
|
||||
|
||||
In CUE, schema definitions are usually defined at the root so they're accessible
|
||||
in all subdirectories. The following is one example schema, you're free to
|
||||
modify it to your situation. Holos is flexible, supporting schemas that match
|
||||
your unique use case.
|
||||
|
||||
```bash
|
||||
cat <<EOF > clusters.schema.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
import "strings"
|
||||
|
||||
// #Cluster represents one cluster
|
||||
#Cluster: {
|
||||
// name represents the cluster name.
|
||||
name: string & =~"[a-z][a-z0-9]+" & strings.MinRunes(2) & strings.MaxRunes(63)
|
||||
// Constrain the regions. No default, the region must be specified.
|
||||
region: "us-east1" | "us-central1" | "us-west1"
|
||||
// Each cluster must be in only one set of clusters. All but one cluster are
|
||||
// workload clusters, so make it the default.
|
||||
set: "management" | *"workload"
|
||||
}
|
||||
|
||||
// #Clusters represents a cluster collection structure
|
||||
#Clusters: {
|
||||
// name is the lookup key for the collection.
|
||||
[NAME=string]: #Cluster & {
|
||||
// name must match the struct field name.
|
||||
name: NAME
|
||||
}
|
||||
}
|
||||
|
||||
// #ClusterSet represents a set of clusters.
|
||||
#ClusterSet: {
|
||||
// name represents the cluster set name.
|
||||
name: string & =~"[a-z][a-z0-9]+" & strings.MinRunes(2) & strings.MaxRunes(63)
|
||||
clusters: #Clusters & {
|
||||
// Constrain the cluster set to clusters having the same set. Ensures
|
||||
// clusters are never mis-categorized.
|
||||
[_]: set: name
|
||||
}
|
||||
}
|
||||
|
||||
// #ClusterSets represents a cluster set collection.
|
||||
#ClusterSets: {
|
||||
// name is the lookup key for the collection.
|
||||
[NAME=string]: #ClusterSet & {
|
||||
// name must match the struct field name.
|
||||
name: NAME
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
### Defining the data
|
||||
|
||||
With a schema defined, we also define the data close to the root so it's
|
||||
accessible through the unified configuration tree.
|
||||
|
||||
```bash
|
||||
cat <<EOF > clusters.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
Clusters: #Clusters & {
|
||||
// Management Cluster
|
||||
management: region: "us-central1"
|
||||
management: set: "management"
|
||||
// Local Cluster
|
||||
local: region: "us-west1"
|
||||
// Some example clusters. Add new clusters to the Clusters struct like this.
|
||||
e1: region: "us-east1"
|
||||
e2: region: "us-east1"
|
||||
e3: region: "us-east1"
|
||||
w1: region: "us-west1"
|
||||
w2: region: "us-west1"
|
||||
w3: region: "us-west1"
|
||||
}
|
||||
|
||||
// ClusterSets is dynamically built from the Clusters structure.
|
||||
ClusterSets: #ClusterSets & {
|
||||
// Map every cluster into the correct set.
|
||||
for CLUSTER in Clusters {
|
||||
(CLUSTER.set): clusters: (CLUSTER.name): CLUSTER
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
### Inspecting the data
|
||||
|
||||
We'll use the `holos cue` command to inspect the `ClusterSets` data structure we
|
||||
just defined.
|
||||
|
||||
<Tabs groupId="9190BDAD-B4C5-4386-9C94-8E178AA6178A">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
holos cue export --expression ClusterSets --out=yaml ./
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```yaml showLineNumbers
|
||||
management:
|
||||
name: management
|
||||
clusters:
|
||||
management:
|
||||
name: management
|
||||
region: us-central1
|
||||
set: management
|
||||
workload:
|
||||
name: workload
|
||||
clusters:
|
||||
local:
|
||||
name: local
|
||||
region: us-west1
|
||||
set: workload
|
||||
e1:
|
||||
name: e1
|
||||
region: us-east1
|
||||
set: workload
|
||||
e2:
|
||||
name: e2
|
||||
region: us-east1
|
||||
set: workload
|
||||
e3:
|
||||
name: e3
|
||||
region: us-east1
|
||||
set: workload
|
||||
w1:
|
||||
name: w1
|
||||
region: us-west1
|
||||
set: workload
|
||||
w2:
|
||||
name: w2
|
||||
region: us-west1
|
||||
set: workload
|
||||
w3:
|
||||
name: w3
|
||||
region: us-west1
|
||||
set: workload
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This looks like our prototype, we're confident we can iterate over each cluster
|
||||
in each set.
|
||||
|
||||
## Integrating Components
|
||||
|
||||
The `ClusterSets` data structure unlocks the capability to iterate over each
|
||||
cluster in each cluster set. We'll use this capability to integrate the
|
||||
`podinfo` component with each cluster in the platform.
|
||||
|
||||
### Configuring the Output directory
|
||||
|
||||
We need to configure `holos` to write output manifests into a cluster specific
|
||||
output directory. We'll use the [ComponentConfig] `OutputBaseDir` field for
|
||||
this purpose. We'll pass the value of this field as a component parameter.
|
||||
|
||||
```bash
|
||||
cat <<EOF > componentconfig.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
#ComponentConfig: {
|
||||
// Inject the output base directory from platform component parameters.
|
||||
OutputBaseDir: string @tag(outputBaseDir, type=string)
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
### Integrating Podinfo
|
||||
|
||||
```bash
|
||||
cat <<EOF >platform/podinfo.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
// Manage podinfo on all workload clusters.
|
||||
for CLUSTER in ClusterSets.workload.clusters {
|
||||
// We use the cluster name to disambiguate different podinfo build plans.
|
||||
Platform: Components: "\(CLUSTER.name)-podinfo": {
|
||||
name: "podinfo"
|
||||
// Reuse the same component across multiple workload clusters.
|
||||
path: "components/podinfo"
|
||||
// Configure a cluster-unique message in the podinfo UI.
|
||||
parameters: message: "Hello, I am cluster \(CLUSTER.name) in region \(CLUSTER.region)"
|
||||
// Write to deploy/{outputBaseDir}/components/{name}/{name}.gen.yaml
|
||||
parameters: outputBaseDir: "clusters/\(CLUSTER.name)"
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
## Rendering manifests
|
||||
|
||||
### Rendering the Platform
|
||||
|
||||
Render the platform to configure `podinfo` on each cluster.
|
||||
|
||||
<Tabs groupId="34A2D80B-0E86-4142-B65B-7DF70C47E1D2">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
holos render platform
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```txt
|
||||
cached podinfo 6.6.2
|
||||
rendered podinfo in 164.278583ms
|
||||
rendered podinfo in 165.48525ms
|
||||
rendered podinfo in 165.186208ms
|
||||
rendered podinfo in 165.831792ms
|
||||
rendered podinfo in 166.845208ms
|
||||
rendered podinfo in 167.000208ms
|
||||
rendered podinfo in 167.012208ms
|
||||
rendered platform in 167.06525ms
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### Inspecting the Tree
|
||||
|
||||
Rendering the platform produces the following rendered manifests.
|
||||
|
||||
```bash
|
||||
tree deploy
|
||||
```
|
||||
```txt showLineNumbers
|
||||
deploy
|
||||
└── clusters
|
||||
├── e1
|
||||
│ └── components
|
||||
│ └── podinfo
|
||||
│ └── podinfo.gen.yaml
|
||||
├── e2
|
||||
│ └── components
|
||||
│ └── podinfo
|
||||
│ └── podinfo.gen.yaml
|
||||
├── e3
|
||||
│ └── components
|
||||
│ └── podinfo
|
||||
│ └── podinfo.gen.yaml
|
||||
├── local
|
||||
│ └── components
|
||||
│ └── podinfo
|
||||
│ └── podinfo.gen.yaml
|
||||
├── w1
|
||||
│ └── components
|
||||
│ └── podinfo
|
||||
│ └── podinfo.gen.yaml
|
||||
├── w2
|
||||
│ └── components
|
||||
│ └── podinfo
|
||||
│ └── podinfo.gen.yaml
|
||||
└── w3
|
||||
└── components
|
||||
└── podinfo
|
||||
└── podinfo.gen.yaml
|
||||
|
||||
23 directories, 7 files
|
||||
```
|
||||
|
||||
### Inspecting the Variation
|
||||
|
||||
Note how each component has slight variation using the component parameters.
|
||||
|
||||
```bash
|
||||
diff -U2 deploy/clusters/{e,w}1/components/podinfo/podinfo.gen.yaml
|
||||
```
|
||||
|
||||
```diff
|
||||
--- deploy/clusters/e1/components/podinfo/podinfo.gen.yaml 2024-11-17 14:20:17
|
||||
+++ deploy/clusters/w1/components/podinfo/podinfo.gen.yaml 2024-11-17 14:20:17
|
||||
@@ -61,5 +61,5 @@
|
||||
env:
|
||||
- name: PODINFO_UI_MESSAGE
|
||||
- value: Hello, I am cluster e1 in region us-east1
|
||||
+ value: Hello, I am cluster w1 in region us-west1
|
||||
- name: PODINFO_UI_COLOR
|
||||
value: '#34577c'
|
||||
|
||||
```
|
||||
|
||||
## Concluding Remarks
|
||||
|
||||
In this topic we covered how to use CUE structures to organize multiple clusters
|
||||
into various sets.
|
||||
|
||||
1. Clusters are defined in one place at the root of the configuration.
|
||||
2. Clusters may be organized into sets by their purpose.
|
||||
3. Most organizations have at least two sets, a set of workload clusters and a
|
||||
set of management clusters.
|
||||
4. Holos uses CUE, a super set of JSON. New clusters may be added by dropping a
|
||||
JSON file into the root of the repository.
|
||||
5. The pattern of defining a `#Cluster` and a `#Clusters` collection is a
|
||||
general pattern. We'll see the same pattern for environments, projects, owners,
|
||||
and more.
|
||||
6. Component parameters are a flexible way to inject user defined configuration
|
||||
from the platform level into a reusable component.
|
||||
|
||||
[ClusterSet]: https://multicluster.sigs.k8s.io/api-types/cluster-set/
|
||||
[Environments]: ./environments.mdx
|
||||
[Namespace Sameness - SIG Multicluster Position Statement]: https://github.com/kubernetes/community/blob/master/sig-multicluster/namespace-sameness-position-statement.md
|
||||
[ComponentConfig]: ../../api/author.md#ComponentConfig
|
||||
521
doc/md/topics/structures/environments.mdx
Normal file
521
doc/md/topics/structures/environments.mdx
Normal file
@@ -0,0 +1,521 @@
|
||||
---
|
||||
slug: environments
|
||||
title: Environments
|
||||
description: Managing Environments - dev, test, stage, prod.
|
||||
sidebar_position: 130
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CommonComponent from '../../common/example-component.mdx';
|
||||
|
||||
# Environments
|
||||
|
||||
## Overview
|
||||
|
||||
This topic covers how to model environments in Holos. We'll define schemas for
|
||||
`#Environment` and `#Environments` to represent one environment and a
|
||||
collection. The `Environments: #Environments` struct maps environment names to
|
||||
configurations.
|
||||
|
||||
:::note
|
||||
This approach unifies the component definition with the overall platform
|
||||
configuration, creating a tight coupling between the two.
|
||||
:::
|
||||
|
||||
This tight coupling is appropriate when you're configuring your own platform.
|
||||
For example:
|
||||
|
||||
1. When you're integrating third party software into your own platform.
|
||||
2. When you're configuring first party in-house software into your own platform.
|
||||
|
||||
This approach is not well suited to writing a component to share outside of your
|
||||
own organization, which we can think of as configuring someone else's platform.
|
||||
|
||||
## The Code
|
||||
|
||||
### Generating the structure
|
||||
|
||||
Use `holos init platform` to generate a minimal platform structure:
|
||||
|
||||
```shell
|
||||
mkdir holos-environments-tutorial && cd holos-environments-tutorial
|
||||
holos init platform v1alpha5
|
||||
```
|
||||
|
||||
### Using an example Component
|
||||
|
||||
Create a directory for the example `podinfo` component we'll use to render
|
||||
platform manifests.
|
||||
|
||||
```bash
|
||||
mkdir -p components/podinfo
|
||||
```
|
||||
|
||||
Create the CUE configuration for the example `podinfo` component.
|
||||
|
||||
```bash
|
||||
cat <<EOF >components/podinfo/podinfo.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
holos: Component.BuildPlan
|
||||
|
||||
Component: #Helm & {
|
||||
Chart: {
|
||||
name: "podinfo"
|
||||
version: "6.6.2"
|
||||
repository: {
|
||||
name: "podinfo"
|
||||
url: "https://stefanprodan.github.io/podinfo"
|
||||
}
|
||||
}
|
||||
Values: ui: {
|
||||
message: string | *"Hello World" @tag(message, type=string)
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
We'll integrate the component with the platform after we define the
|
||||
configuration structures.
|
||||
|
||||
## Defining Environments
|
||||
|
||||
We'll define an `#Environment` schema `#Environments` collection. We'll use
|
||||
these schemas to define an `Environments` struct of concrete configuration
|
||||
values.
|
||||
|
||||
### Assumptions
|
||||
|
||||
There are two tiers of environments, prod and nonprod. Prod environments
|
||||
organized along broad jurisdictions, for example US and EU. Nonprod
|
||||
environments are organized by purpose, dev, test, and stage.
|
||||
|
||||
### Prototyping the data
|
||||
|
||||
Before we define the schema, let's prototype the data structure we want to work
|
||||
with from the perspective of each component.
|
||||
|
||||
Let's imagine we're configuring `podinfo` to comply with regulations. When
|
||||
podinfo is deployed to production in the EU, we'll configure opt-in behavior.
|
||||
In the US we'll configure opt-out behavior.
|
||||
|
||||
We'll pass the environment name as a component parameter. The component
|
||||
definition can then look up the jurisdiction to determine the appropriate
|
||||
configuration values.
|
||||
|
||||
```shell
|
||||
holos cue export --out=yaml --expression Environments
|
||||
```
|
||||
|
||||
```yaml showLineNumbers
|
||||
prod-pdx:
|
||||
name: prod-pdx
|
||||
tier: prod
|
||||
jurisdiction: us
|
||||
state: oregon
|
||||
prod-cmh:
|
||||
name: prod-cmh
|
||||
tier: prod
|
||||
jurisdiction: us
|
||||
state: ohio
|
||||
prod-ams:
|
||||
name: prod-ams
|
||||
tier: prod
|
||||
jurisdiction: eu
|
||||
state: netherlands
|
||||
dev:
|
||||
name: dev
|
||||
tier: nonprod
|
||||
jurisdiction: us
|
||||
state: oregon
|
||||
test:
|
||||
name: test
|
||||
tier: nonprod
|
||||
jurisdiction: us
|
||||
state: oregon
|
||||
stage:
|
||||
name: stage
|
||||
tier: nonprod
|
||||
jurisdiction: us
|
||||
state: oregon
|
||||
```
|
||||
|
||||
### Defining the schema
|
||||
|
||||
Given the example structure, we can write a schema to define and validate the
|
||||
data.
|
||||
|
||||
```shell
|
||||
cat <<EOF > environments.schema.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
#Environment: {
|
||||
name: string
|
||||
tier: "prod" | "nonprod"
|
||||
jurisdiction: "us" | "eu" | "uk" | "global"
|
||||
state: "oregon" | "ohio" | "germany" | "netherlands" | "england" | "global"
|
||||
|
||||
// Prod environment names must be prefixed with prod for clarity.
|
||||
if tier == "prod" {
|
||||
name: "prod" | =~"^prod-"
|
||||
}
|
||||
}
|
||||
|
||||
#Environments: {
|
||||
[NAME=string]: #Environment & {
|
||||
name: NAME
|
||||
}
|
||||
}
|
||||
```
|
||||
```shell
|
||||
EOF
|
||||
```
|
||||
|
||||
### Adding configuration
|
||||
|
||||
With a schema defined, we can fill in the concrete values.
|
||||
|
||||
```shell
|
||||
cat <<EOF > environments.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
// Injected from Platform.spec.components.parameters.EnvironmentName
|
||||
EnvironmentName: string @tag(EnvironmentName)
|
||||
|
||||
Environments: #Environments & {
|
||||
"prod-pdx": {
|
||||
tier: "prod"
|
||||
jurisdiction: "us"
|
||||
state: "oregon"
|
||||
}
|
||||
"prod-cmh": {
|
||||
tier: "prod"
|
||||
jurisdiction: "us"
|
||||
state: "ohio"
|
||||
}
|
||||
"prod-ams": {
|
||||
tier: "prod"
|
||||
jurisdiction: "eu"
|
||||
state: "netherlands"
|
||||
}
|
||||
// Nonprod environments are colocated together.
|
||||
_nonprod: {
|
||||
tier: "nonprod"
|
||||
jurisdiction: "us"
|
||||
state: "oregon"
|
||||
}
|
||||
dev: _nonprod
|
||||
test: _nonprod
|
||||
stage: _nonprod
|
||||
}
|
||||
```
|
||||
```shell
|
||||
EOF
|
||||
```
|
||||
|
||||
### Inspecting the configuration
|
||||
|
||||
Inspect the `Environments` data structure to verify the schema and concrete
|
||||
values are what we want.
|
||||
|
||||
<Tabs groupId="FF820F5A-A85F-464D-B299-39CAAFFCE5C6">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
holos cue export --out=yaml --expression Environments
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```yaml showLineNumbers
|
||||
prod-pdx:
|
||||
name: prod-pdx
|
||||
tier: prod
|
||||
jurisdiction: us
|
||||
state: oregon
|
||||
prod-cmh:
|
||||
name: prod-cmh
|
||||
tier: prod
|
||||
jurisdiction: us
|
||||
state: ohio
|
||||
prod-ams:
|
||||
name: prod-ams
|
||||
tier: prod
|
||||
jurisdiction: eu
|
||||
state: netherlands
|
||||
dev:
|
||||
name: dev
|
||||
tier: nonprod
|
||||
jurisdiction: us
|
||||
state: oregon
|
||||
test:
|
||||
name: test
|
||||
tier: nonprod
|
||||
jurisdiction: us
|
||||
state: oregon
|
||||
stage:
|
||||
name: stage
|
||||
tier: nonprod
|
||||
jurisdiction: us
|
||||
state: oregon
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This looks like our prototype, we're confident we can iterate over each
|
||||
environment and get a handle on the configuration values we need.
|
||||
|
||||
## Integrating components
|
||||
|
||||
The `Environments` data structure unlocks the capability to look up concrete
|
||||
values specific to a named environment. We'll use this capability to configure
|
||||
the `podinfo` component in compliance with the regulations of the jurisdiction.
|
||||
|
||||
### Configuring the environment
|
||||
|
||||
Inject the environment name when we integrate `podinfo` with the platform.
|
||||
|
||||
```shell
|
||||
cat <<EOF > platform/podinfo.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
Platform: Components: {
|
||||
podinfoPDX: ProdPodinfo & {_city: "pdx"}
|
||||
podinfoCMH: ProdPodinfo & {_city: "cmh"}
|
||||
podinfoAMS: ProdPodinfo & {_city: "ams"}
|
||||
podinfoDEV: {
|
||||
name: "podinfo-dev"
|
||||
path: "components/podinfo"
|
||||
labels: "app.holos.run/component": "podinfo"
|
||||
parameters: EnvironmentName: "dev"
|
||||
}
|
||||
}
|
||||
|
||||
let ProdPodinfo = {
|
||||
_city: string
|
||||
name: "podinfo-\(_city)"
|
||||
path: "components/podinfo"
|
||||
labels: "app.holos.run/component": "podinfo"
|
||||
labels: "app.holos.run/tier": "prod"
|
||||
labels: "app.holos.run/city": _city
|
||||
parameters: EnvironmentName: "prod-\(_city)"
|
||||
}
|
||||
```
|
||||
```
|
||||
EOF
|
||||
```
|
||||
|
||||
### Using the environment
|
||||
|
||||
Now we can configure `podinfo` based on the jurisdiction of the environment.
|
||||
|
||||
```shell
|
||||
cat <<EOF > components/podinfo/cookie-consent.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
// Schema definition for our configuration.
|
||||
#Values: {
|
||||
ui: enableCookieConsent: *true | false
|
||||
ui: message: string
|
||||
}
|
||||
|
||||
// Map jurisdiction to helm values
|
||||
JurisdictionValues: {
|
||||
// Enable cookie consent by default in any jurisdiction.
|
||||
[_]: #Values
|
||||
// Disable in the US.
|
||||
us: ui: enableCookieConsent: false
|
||||
eu: ui: enableCookieConsent: true
|
||||
}
|
||||
|
||||
// Look up the configuration values associated with the environment name.
|
||||
Component: Values: JurisdictionValues[Environments[EnvironmentName].jurisdiction]
|
||||
```
|
||||
```shell
|
||||
EOF
|
||||
```
|
||||
|
||||
### Inspecting the BuildPlans
|
||||
|
||||
With the above configuration, we can inspect the buildplans for this component.
|
||||
The prod environment in Amsterdam has cookie consent enabled on line 26.
|
||||
|
||||
<Tabs groupId="6EC991F3-F78C-43F1-8A6D-E68D8BDAF58B">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
holos show buildplans --selector app.holos.run/city=ams
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```yaml showLineNumbers
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: podinfo-ams
|
||||
labels:
|
||||
app.holos.run/city: ams
|
||||
app.holos.run/component: podinfo
|
||||
app.holos.run/name: podinfo-ams
|
||||
app.holos.run/tier: prod
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: components/podinfo-ams/podinfo-ams.gen.yaml
|
||||
generators:
|
||||
- kind: Helm
|
||||
output: helm.gen.yaml
|
||||
helm:
|
||||
chart:
|
||||
name: podinfo
|
||||
version: 6.6.2
|
||||
release: podinfo
|
||||
repository:
|
||||
name: podinfo
|
||||
url: https://stefanprodan.github.io/podinfo
|
||||
values:
|
||||
ui:
|
||||
# highlight-next-line
|
||||
enableCookieConsent: true
|
||||
message: Hello World
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- helm.gen.yaml
|
||||
- resources.gen.yaml
|
||||
output: components/podinfo-ams/podinfo-ams.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
labels:
|
||||
- includeSelectors: false
|
||||
pairs: {}
|
||||
resources:
|
||||
- helm.gen.yaml
|
||||
- resources.gen.yaml
|
||||
- artifact: gitops/podinfo-ams.application.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: gitops/podinfo-ams.application.gen.yaml
|
||||
resources:
|
||||
Application:
|
||||
podinfo-ams:
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: podinfo-ams
|
||||
namespace: argocd
|
||||
spec:
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
project: default
|
||||
source:
|
||||
path: deploy/components/podinfo-ams
|
||||
repoURL: https://github.com/brenix/holos-demo.git
|
||||
targetRevision: main
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
In Portland cookie consent is disabled.
|
||||
|
||||
<Tabs groupId="3438335B-1FFC-4838-B8DE-C54B8346CDB4">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
holos show buildplans --selector app.holos.run/city=pdx
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```yaml showLineNumbers
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha5
|
||||
metadata:
|
||||
name: podinfo-pdx
|
||||
labels:
|
||||
app.holos.run/city: pdx
|
||||
app.holos.run/component: podinfo
|
||||
app.holos.run/name: podinfo-pdx
|
||||
app.holos.run/tier: prod
|
||||
spec:
|
||||
artifacts:
|
||||
- artifact: components/podinfo-pdx/podinfo-pdx.gen.yaml
|
||||
generators:
|
||||
- kind: Helm
|
||||
output: helm.gen.yaml
|
||||
helm:
|
||||
chart:
|
||||
name: podinfo
|
||||
version: 6.6.2
|
||||
release: podinfo
|
||||
repository:
|
||||
name: podinfo
|
||||
url: https://stefanprodan.github.io/podinfo
|
||||
values:
|
||||
ui:
|
||||
# highlight-next-line
|
||||
enableCookieConsent: false
|
||||
message: Hello World
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- helm.gen.yaml
|
||||
- resources.gen.yaml
|
||||
output: components/podinfo-pdx/podinfo-pdx.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
labels:
|
||||
- includeSelectors: false
|
||||
pairs: {}
|
||||
resources:
|
||||
- helm.gen.yaml
|
||||
- resources.gen.yaml
|
||||
- artifact: gitops/podinfo-pdx.application.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: gitops/podinfo-pdx.application.gen.yaml
|
||||
resources:
|
||||
Application:
|
||||
podinfo-pdx:
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: podinfo-pdx
|
||||
namespace: argocd
|
||||
spec:
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
project: default
|
||||
source:
|
||||
path: deploy/components/podinfo-pdx
|
||||
repoURL: https://github.com/brenix/holos-demo.git
|
||||
targetRevision: main
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Concluding Remarks
|
||||
|
||||
In this topic we covered how to use a CUE structure to define attributes of prod
|
||||
and nonprod environments.
|
||||
|
||||
1. We passed the environment name as a parameter to each component using a CUE `@tag`.
|
||||
2. The component definition uses the environment name as a key to get a handle
|
||||
on attributes. For example, the jurisdiction a service operates within.
|
||||
3. The example podinfo component uses an additional structure to map
|
||||
jurisdictions to concrete configuration values.
|
||||
25
doc/md/topics/structures/index.mdx
Normal file
25
doc/md/topics/structures/index.mdx
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
slug: .
|
||||
title: Structures
|
||||
description: Commonly used CUE structures.
|
||||
sidebar_position: 120
|
||||
---
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
|
||||
# Structures
|
||||
|
||||
This section has self contained articles covering commonly used CUE structures.
|
||||
These structures are organized and presented as recipes you may adopt and adjust
|
||||
to your unique organization.
|
||||
|
||||
:::important
|
||||
Structures are defined by Holos Users, unlike the standardized [Core] and
|
||||
[Author] schemas defined by the Holos Authors.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
<DocCardList />
|
||||
|
||||
[Core]: ../../api/core.md
|
||||
[Author]: ../../api/author.md
|
||||
@@ -1,12 +0,0 @@
|
||||
---
|
||||
description: Workload Cluster
|
||||
slug: workload-cluster
|
||||
sidebar_position: 250
|
||||
---
|
||||
|
||||
# Workload Cluster
|
||||
|
||||
Key points:
|
||||
|
||||
1. Namespaces
|
||||
2. ExternalSecrets
|
||||
@@ -0,0 +1,7 @@
|
||||
exec bash -c 'bash -euo pipefail $WORK/command.sh 2>&1'
|
||||
cmp stdout $WORK/output.txt
|
||||
|
||||
-- command.sh --
|
||||
holos --version
|
||||
-- output.txt --
|
||||
0.104.1
|
||||
126
doc/md/tutorial/_hello-holos/examples/02-hello-holos.txt
Normal file
126
doc/md/tutorial/_hello-holos/examples/02-hello-holos.txt
Normal file
@@ -0,0 +1,126 @@
|
||||
# Set $HOME because:
|
||||
# - Helm uses it for temporary files
|
||||
# - Git requires it for setting author name/email globally
|
||||
env HOME=$WORK/.tmp
|
||||
chmod 0755 $WORK/update.sh
|
||||
|
||||
# Configure git author for testscript execution
|
||||
exec git config --global user.name 'Holos Docs'
|
||||
exec git config --global user.email 'hello@holos.run'
|
||||
exec git config --global init.defaultBranch main
|
||||
|
||||
# Remove the tutorial directory if it already exists
|
||||
exec rm -rf holos-tutorial
|
||||
|
||||
# Create and change to the tutorial directory, and then initialize the Holos platform
|
||||
exec bash -c 'bash -euo pipefail $WORK/mkdir-and-init.sh'
|
||||
cd holos-tutorial
|
||||
|
||||
# Create the components directory
|
||||
exec bash -c 'bash -euo pipefail $WORK/mkdir-components.sh'
|
||||
|
||||
# Combine and execute the multiline podinfo component header/body/trailer files
|
||||
exec cat $WORK/podinfo-component-header.sh ../podinfo-component-body.cue ../eof-trailer.sh
|
||||
stdin stdout
|
||||
exec bash -xeuo pipefail
|
||||
|
||||
# Combine and execute the multiline platform registration header/body/trailer files
|
||||
exec cat $WORK/register-podinfo-header.sh ../register-podinfo-body.cue ../eof-trailer.sh
|
||||
stdin stdout
|
||||
exec bash -xeuo pipefail
|
||||
|
||||
# Render the platform, capture stdout, and use update.sh to gate whether the
|
||||
# output file should be updated.
|
||||
#
|
||||
# NOTE: The [net] condition will test whether external network access is available
|
||||
[net] exec bash -c 'bash -euo pipefail $WORK/render.sh 2>&1'
|
||||
[net] stdin stdout
|
||||
exec $WORK/update.sh $WORK/register-components-output.txt
|
||||
|
||||
# Generate and update the tree of the tutorial directory (omitting the cue.mod directory)
|
||||
exec bash -c 'bash -euo pipefail $WORK/tree.sh'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/tree.txt
|
||||
|
||||
# Split the rendered manifest into two separate files to display separately
|
||||
exec bash -c 'bash -euo pipefail $WORK/split-rendered-manifest.sh $WORK/holos-tutorial/deploy/components/podinfo/podinfo.gen.yaml $WORK'
|
||||
|
||||
# Grep for the Hello Holos message and write the output file
|
||||
exec bash -c 'bash -euo pipefail $WORK/grep-for-message.sh'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/grepped-output.txt
|
||||
|
||||
# Clean up the tutorial directory and tmp $HOME directory
|
||||
cd $WORK
|
||||
exec rm -rf holos-tutorial
|
||||
exec rm -rf $HOME
|
||||
|
||||
-- update.sh --
|
||||
#! /bin/bash
|
||||
set -euo pipefail
|
||||
[[ -s "$1" ]] && [[ -z "${HOLOS_UPDATE_SCRIPTS:-}" ]] && exit 0
|
||||
cat > "$1"
|
||||
-- mkdir-and-init.sh --
|
||||
mkdir holos-tutorial && cd holos-tutorial
|
||||
holos init platform v1alpha5
|
||||
-- tree.sh --
|
||||
tree -L 3 -I cue.mod .
|
||||
-- mkdir-components.sh --
|
||||
mkdir -p components/podinfo
|
||||
-- podinfo-component-header.sh --
|
||||
cat <<EOF > components/podinfo/podinfo.cue
|
||||
-- podinfo-component-body.cue --
|
||||
package holos
|
||||
|
||||
// Produce a helm chart build plan.
|
||||
holos: HelmChart.BuildPlan
|
||||
|
||||
HelmChart: #Helm & {
|
||||
Name: "podinfo"
|
||||
Chart: {
|
||||
version: "6.6.2"
|
||||
repository: {
|
||||
name: "podinfo"
|
||||
url: "https://stefanprodan.github.io/podinfo"
|
||||
}
|
||||
}
|
||||
// Holos marshals Values into values.yaml for Helm.
|
||||
Values: {
|
||||
// message is a string with a default value. @tag indicates a value may
|
||||
// be injected from the platform spec component parameters.
|
||||
ui: {
|
||||
message: string | *"Hello World" @tag(greeting, type=string)
|
||||
}
|
||||
}
|
||||
}
|
||||
-- eof-trailer.sh --
|
||||
EOF
|
||||
-- register-podinfo-header.sh --
|
||||
cat <<EOF > platform/podinfo.cue
|
||||
-- register-podinfo-body.cue --
|
||||
package holos
|
||||
|
||||
Platform: Components: podinfo: {
|
||||
name: "podinfo"
|
||||
path: "components/podinfo"
|
||||
// Inject a value into the component.
|
||||
parameters: greeting: "Hello Holos!"
|
||||
}
|
||||
-- render.sh --
|
||||
holos render platform
|
||||
-- register-components-output.txt --
|
||||
cached podinfo 6.6.2
|
||||
rendered podinfo in 1.938665041s
|
||||
rendered platform in 1.938759417s
|
||||
-- podinfo-rendered-path.sh --
|
||||
deploy/components/podinfo/podinfo.gen.yaml
|
||||
-- split-rendered-manifest.sh --
|
||||
awk 'BEGIN {RS="---"} NR==1 {print > "service.yaml"} NR==2 {print > "deployment.yaml"}' $1
|
||||
mv service.yaml $2/rendered-service.yaml
|
||||
mv deployment.yaml $2/rendered-deployment.yaml
|
||||
-- grep-for-message.sh --
|
||||
grep -B2 Hello deploy/components/podinfo/podinfo.gen.yaml
|
||||
-- grepped-output.txt --
|
||||
env:
|
||||
- name: PODINFO_UI_MESSAGE
|
||||
value: Hello Holos!
|
||||
@@ -0,0 +1 @@
|
||||
holos --version
|
||||
@@ -0,0 +1 @@
|
||||
0.104.1
|
||||
@@ -0,0 +1 @@
|
||||
EOF
|
||||
@@ -0,0 +1 @@
|
||||
grep -B2 Hello deploy/components/podinfo/podinfo.gen.yaml
|
||||
@@ -0,0 +1,3 @@
|
||||
env:
|
||||
- name: PODINFO_UI_MESSAGE
|
||||
value: Hello Holos!
|
||||
@@ -0,0 +1,2 @@
|
||||
mkdir holos-tutorial && cd holos-tutorial
|
||||
holos init platform v1alpha5
|
||||
@@ -0,0 +1 @@
|
||||
mkdir -p components/podinfo
|
||||
@@ -0,0 +1,23 @@
|
||||
package holos
|
||||
|
||||
// Produce a helm chart build plan.
|
||||
holos: HelmChart.BuildPlan
|
||||
|
||||
HelmChart: #Helm & {
|
||||
Name: "podinfo"
|
||||
Chart: {
|
||||
version: "6.6.2"
|
||||
repository: {
|
||||
name: "podinfo"
|
||||
url: "https://stefanprodan.github.io/podinfo"
|
||||
}
|
||||
}
|
||||
// Holos marshals Values into values.yaml for Helm.
|
||||
Values: {
|
||||
// message is a string with a default value. @tag indicates a value may
|
||||
// be injected from the platform spec component parameters.
|
||||
ui: {
|
||||
message: string | *"Hello World" @tag(greeting, type=string)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
cat <<EOF > components/podinfo/podinfo.cue
|
||||
@@ -0,0 +1 @@
|
||||
deploy/components/podinfo/podinfo.gen.yaml
|
||||
@@ -0,0 +1,2 @@
|
||||
rendered podinfo in 312.472625ms
|
||||
rendered platform in 312.557375ms
|
||||
@@ -0,0 +1,8 @@
|
||||
package holos
|
||||
|
||||
Platform: Components: podinfo: {
|
||||
name: "podinfo"
|
||||
path: "components/podinfo"
|
||||
// Inject a value into the component.
|
||||
parameters: greeting: "Hello Holos!"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
cat <<EOF > platform/podinfo.cue
|
||||
@@ -0,0 +1 @@
|
||||
holos render platform
|
||||
@@ -0,0 +1,93 @@
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
app.kubernetes.io/name: podinfo
|
||||
app.kubernetes.io/version: 6.6.2
|
||||
helm.sh/chart: podinfo-6.6.2
|
||||
name: podinfo
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: podinfo
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxUnavailable: 1
|
||||
type: RollingUpdate
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
prometheus.io/port: "9898"
|
||||
prometheus.io/scrape: "true"
|
||||
labels:
|
||||
app.kubernetes.io/name: podinfo
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- ./podinfo
|
||||
- --port=9898
|
||||
- --cert-path=/data/cert
|
||||
- --port-metrics=9797
|
||||
- --grpc-port=9999
|
||||
- --grpc-service-name=podinfo
|
||||
- --level=info
|
||||
- --random-delay=false
|
||||
- --random-error=false
|
||||
env:
|
||||
- name: PODINFO_UI_MESSAGE
|
||||
value: Hello Holos!
|
||||
- name: PODINFO_UI_COLOR
|
||||
value: '#34577c'
|
||||
image: ghcr.io/stefanprodan/podinfo:6.6.2
|
||||
imagePullPolicy: IfNotPresent
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- podcli
|
||||
- check
|
||||
- http
|
||||
- localhost:9898/healthz
|
||||
failureThreshold: 3
|
||||
initialDelaySeconds: 1
|
||||
periodSeconds: 10
|
||||
successThreshold: 1
|
||||
timeoutSeconds: 5
|
||||
name: podinfo
|
||||
ports:
|
||||
- containerPort: 9898
|
||||
name: http
|
||||
protocol: TCP
|
||||
- containerPort: 9797
|
||||
name: http-metrics
|
||||
protocol: TCP
|
||||
- containerPort: 9999
|
||||
name: grpc
|
||||
protocol: TCP
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- podcli
|
||||
- check
|
||||
- http
|
||||
- localhost:9898/readyz
|
||||
failureThreshold: 3
|
||||
initialDelaySeconds: 1
|
||||
periodSeconds: 10
|
||||
successThreshold: 1
|
||||
timeoutSeconds: 5
|
||||
resources:
|
||||
limits: null
|
||||
requests:
|
||||
cpu: 1m
|
||||
memory: 16Mi
|
||||
volumeMounts:
|
||||
- mountPath: /data
|
||||
name: data
|
||||
terminationGracePeriodSeconds: 30
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
name: data
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
app.kubernetes.io/name: podinfo
|
||||
app.kubernetes.io/version: 6.6.2
|
||||
helm.sh/chart: podinfo-6.6.2
|
||||
name: podinfo
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 9898
|
||||
protocol: TCP
|
||||
targetPort: http
|
||||
- name: grpc
|
||||
port: 9999
|
||||
protocol: TCP
|
||||
targetPort: grpc
|
||||
selector:
|
||||
app.kubernetes.io/name: podinfo
|
||||
type: ClusterIP
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
awk 'BEGIN {RS="---"} NR==1 {print > "service.yaml"} NR==2 {print > "deployment.yaml"}' $1
|
||||
mv service.yaml $2/rendered-service.yaml
|
||||
mv deployment.yaml $2/rendered-deployment.yaml
|
||||
@@ -0,0 +1 @@
|
||||
tree -L 3 -I cue.mod .
|
||||
17
doc/md/tutorial/_hello-holos/script-02-hello-holos/tree.txt
Normal file
17
doc/md/tutorial/_hello-holos/script-02-hello-holos/tree.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
.
|
||||
|-- components
|
||||
| `-- podinfo
|
||||
| |-- podinfo.cue
|
||||
| `-- vendor
|
||||
|-- deploy
|
||||
| `-- components
|
||||
| `-- podinfo
|
||||
|-- platform
|
||||
| |-- platform.gen.cue
|
||||
| `-- podinfo.cue
|
||||
|-- platform.metadata.json
|
||||
|-- resources.cue
|
||||
|-- schema.cue
|
||||
`-- tags.cue
|
||||
|
||||
8 directories, 7 files
|
||||
4
doc/md/tutorial/_hello-holos/script-02-hello-holos/update.sh
Executable file
4
doc/md/tutorial/_hello-holos/script-02-hello-holos/update.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#! /bin/bash
|
||||
set -euo pipefail
|
||||
[[ -s "$1" ]] && [[ -z "${HOLOS_UPDATE_SCRIPTS:-}" ]] && exit 0
|
||||
cat > "$1"
|
||||
@@ -0,0 +1,7 @@
|
||||
exec bash -c 'bash -euo pipefail $WORK/command.sh 2>&1'
|
||||
cmp stdout $WORK/output.txt
|
||||
|
||||
-- command.sh --
|
||||
holos --version
|
||||
-- output.txt --
|
||||
0.104.1
|
||||
374
doc/md/tutorial/_helm-values/examples/02-helm-values.txt
Normal file
374
doc/md/tutorial/_helm-values/examples/02-helm-values.txt
Normal file
@@ -0,0 +1,374 @@
|
||||
# Set $HOME because:
|
||||
# - Helm uses it for temporary files
|
||||
# - Git requires it for setting author name/email globally
|
||||
env HOME=$WORK/.tmp
|
||||
chmod 0755 $WORK/update.sh
|
||||
|
||||
# Configure git author for testscript execution
|
||||
exec git config --global user.name 'Holos Docs'
|
||||
exec git config --global user.email 'hello@holos.run'
|
||||
exec git config --global init.defaultBranch main
|
||||
|
||||
# Remove the tutorial directory if it already exists
|
||||
exec rm -rf holos-helm-values-tutorial
|
||||
|
||||
# Create and change to the tutorial directory, and then initialize the Holos platform
|
||||
exec bash -c 'bash -euo pipefail mkdir-and-init.sh'
|
||||
cd holos-helm-values-tutorial
|
||||
|
||||
# Git init and create the component directories
|
||||
exec bash -c 'bash -euo pipefail $WORK/git-init.sh'
|
||||
exec bash -c 'bash -euo pipefail $WORK/mkdir-components.sh'
|
||||
|
||||
# Combine and execute the multiline prometheus/blackbox component header/body/trailer files
|
||||
exec cat $WORK/prometheus-component-header.sh ../prometheus-component-body.cue ../eof-trailer.sh
|
||||
stdin stdout
|
||||
exec bash -xeuo pipefail
|
||||
exec cat $WORK/blackbox-component-header.sh ../blackbox-component-body.cue ../eof-trailer.sh
|
||||
stdin stdout
|
||||
exec bash -xeuo pipefail
|
||||
|
||||
# Combine and execute the multiline platform registration header/body/trailer files.
|
||||
exec cat $WORK/register-components-header.sh ../register-components-body.cue ../eof-trailer.sh
|
||||
stdin stdout
|
||||
exec bash -xeuo pipefail
|
||||
|
||||
# Render the platform, capture stdout, and use update.sh to gate whether the
|
||||
# output file should be updated.
|
||||
#
|
||||
# NOTE: The [net] condition will test whether external network access is available
|
||||
[net] exec bash -c 'bash -euo pipefail $WORK/render.sh 2>&1'
|
||||
[net] stdin stdout
|
||||
exec $WORK/update.sh $WORK/register-components-output.txt
|
||||
|
||||
# Commit and conditionally update the output file
|
||||
exec bash -c 'bash -euo pipefail $WORK/register-components-git-commit.sh'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/register-components-git-commit-output.txt
|
||||
|
||||
# Import values
|
||||
exec bash -c 'bash -euo pipefail $WORK/import-prometheus-values.sh'
|
||||
exec bash -c 'bash -euo pipefail $WORK/import-blackbox-values.sh'
|
||||
|
||||
# Render, update the output file, commit, and update the commit output file.
|
||||
[net] exec bash -c 'bash -euo pipefail $WORK/render.sh 2>&1'
|
||||
[net] stdin stdout
|
||||
exec $WORK/update.sh $WORK/import-values-render-output.txt
|
||||
exec bash -c 'bash -euo pipefail $WORK/import-values-git-commit.sh'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/import-values-git-output.txt
|
||||
|
||||
# Create the common configuration path
|
||||
exec bash -c 'bash -euo pipefail $WORK/mkdir-common-config.sh'
|
||||
|
||||
# Combine and execute the common configuration header/body/trailer to write the cue file.
|
||||
exec cat $WORK/blackbox-common-config-header.sh ../blackbox-common-config-body.cue ../eof-trailer.sh
|
||||
stdin stdout
|
||||
exec bash -xeuo pipefail
|
||||
|
||||
# Git commit blackbox common config
|
||||
exec bash -c 'bash -euo pipefail $WORK/blackbox-common-config-git-commit.sh'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/blackbox-common-config-git-output.txt
|
||||
|
||||
# Patch the common config values file and write to output file.
|
||||
#
|
||||
# NOTE: Using a symlink here because the patch script references values.patch
|
||||
# within the same directory, but it actually lives one directory up in the
|
||||
# testscript $WORK dir.
|
||||
exec ln -s $WORK/values.patch values.patch
|
||||
exec bash -c 'bash -euo pipefail $WORK/common-config-patch.sh'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/common-config-patch.txt
|
||||
|
||||
# Remove patch and commit changes
|
||||
exec bash -c 'bash -euo pipefail $WORK/common-config-rm.sh'
|
||||
exec bash -c 'bash -euo pipefail $WORK/common-config-git.sh'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/common-config-git-output.txt
|
||||
|
||||
# Final render and update of output file.
|
||||
[net] exec bash -c 'bash -euo pipefail $WORK/render.sh 2>&1'
|
||||
[net] stdin stdout
|
||||
exec $WORK/update.sh $WORK/reviewing-changes-git-output.txt
|
||||
|
||||
# Git diff and write to output file.
|
||||
exec bash -c 'bash -euo pipefail $WORK/git-diff.sh'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/git.diff
|
||||
|
||||
# Final commit and write to output file
|
||||
exec bash -c 'bash -euo pipefail $WORK/reviewing-changes-git-commit.sh'
|
||||
stdin stdout
|
||||
exec $WORK/update.sh $WORK/reviewing-changes-git-output.txt
|
||||
|
||||
# Clean up the tutorial directory and tmp $HOME directory
|
||||
cd $WORK
|
||||
exec rm -rf holos-helm-values-tutorial
|
||||
exec rm -rf $HOME
|
||||
|
||||
-- update.sh --
|
||||
#! /bin/bash
|
||||
set -euo pipefail
|
||||
[[ -s "$1" ]] && [[ -z "${HOLOS_UPDATE_SCRIPTS:-}" ]] && exit 0
|
||||
cat > "$1"
|
||||
-- mkdir-and-init.sh --
|
||||
mkdir holos-helm-values-tutorial
|
||||
cd holos-helm-values-tutorial
|
||||
holos init platform v1alpha5
|
||||
-- git-init.sh --
|
||||
git init . && git add . && git commit -m "initial commit"
|
||||
-- mkdir-components.sh --
|
||||
mkdir -p components/prometheus components/blackbox
|
||||
-- prometheus-component-header.sh --
|
||||
cat <<EOF > components/prometheus/prometheus.cue
|
||||
-- prometheus-component-body.cue --
|
||||
package holos
|
||||
|
||||
// Produce a helm chart build plan.
|
||||
holos: Helm.BuildPlan
|
||||
|
||||
Helm: #Helm & {
|
||||
Chart: {
|
||||
name: "prometheus"
|
||||
version: "25.27.0"
|
||||
repository: {
|
||||
name: "prometheus-community"
|
||||
url: "https://prometheus-community.github.io/helm-charts"
|
||||
}
|
||||
}
|
||||
}
|
||||
-- eof-trailer.sh --
|
||||
EOF
|
||||
-- blackbox-component-header.sh --
|
||||
cat <<EOF > components/blackbox/blackbox.cue
|
||||
-- blackbox-component-body.cue --
|
||||
package holos
|
||||
|
||||
// Produce a helm chart build plan.
|
||||
holos: Helm.BuildPlan
|
||||
|
||||
Helm: #Helm & {
|
||||
Chart: {
|
||||
name: "prometheus-blackbox-exporter"
|
||||
version: "9.0.1"
|
||||
repository: {
|
||||
name: "prometheus-community"
|
||||
url: "https://prometheus-community.github.io/helm-charts"
|
||||
}
|
||||
}
|
||||
}
|
||||
-- register-components-header.sh --
|
||||
cat <<EOF > platform/prometheus.cue
|
||||
-- register-components-body.cue --
|
||||
package holos
|
||||
|
||||
Platform: Components: {
|
||||
prometheus: {
|
||||
name: "prometheus"
|
||||
path: "components/prometheus"
|
||||
}
|
||||
blackbox: {
|
||||
name: "blackbox"
|
||||
path: "components/blackbox"
|
||||
}
|
||||
}
|
||||
-- render.sh --
|
||||
holos render platform
|
||||
-- register-components-output.txt --
|
||||
cached prometheus-blackbox-exporter 9.0.1
|
||||
rendered blackbox in 3.825430417s
|
||||
cached prometheus 25.27.0
|
||||
rendered prometheus in 4.840089667s
|
||||
rendered platform in 4.840137792s
|
||||
-- register-components-git-commit.sh --
|
||||
git add . && git commit -m 'add blackbox and prometheus'
|
||||
-- register-components-git-commit-output.txt --
|
||||
[main b5df111] add blackbox and prometheus
|
||||
5 files changed, 1550 insertions(+)
|
||||
create mode 100644 components/blackbox/blackbox.cue
|
||||
create mode 100644 components/prometheus/prometheus.cue
|
||||
create mode 100644 deploy/components/blackbox/blackbox.gen.yaml
|
||||
create mode 100644 deploy/components/prometheus/prometheus.gen.yaml
|
||||
create mode 100644 platform/prometheus.cue
|
||||
-- import-prometheus-values.sh --
|
||||
holos cue import \
|
||||
--package holos \
|
||||
--path 'Helm: Values:' \
|
||||
--outfile components/prometheus/values.cue \
|
||||
components/prometheus/vendor/25.27.0/prometheus/values.yaml
|
||||
-- import-blackbox-values.sh --
|
||||
holos cue import \
|
||||
--package holos \
|
||||
--path 'Helm: Values:' \
|
||||
--outfile components/blackbox/values.cue \
|
||||
components/blackbox/vendor/9.0.1/prometheus-blackbox-exporter/values.yaml
|
||||
-- import-values-render-output.txt --
|
||||
rendered blackbox in 365.936792ms
|
||||
rendered prometheus in 371.855875ms
|
||||
rendered platform in 372.109916ms
|
||||
-- import-values-git-commit.sh --
|
||||
git add . && git commit -m 'import values'
|
||||
-- import-values-git-output.txt --
|
||||
[main 52e90ea] import values
|
||||
2 files changed, 1815 insertions(+)
|
||||
create mode 100644 components/blackbox/values.cue
|
||||
create mode 100644 components/prometheus/values.cue
|
||||
-- mkdir-common-config.sh --
|
||||
mkdir -p config/prometheus
|
||||
-- blackbox-common-config-header.sh --
|
||||
cat <<EOF > config/prometheus/blackbox.cue
|
||||
-- blackbox-common-config-body.cue --
|
||||
package prometheus
|
||||
|
||||
// Schema Definition
|
||||
#Blackbox: {
|
||||
// host constrained to a lower case dns label
|
||||
host: string & =~"^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$"
|
||||
// port constrained to a valid range
|
||||
port: int & >0 & <=65535
|
||||
}
|
||||
|
||||
// Concrete values must validate against the schema.
|
||||
blackbox: #Blackbox & {
|
||||
host: "blackbox"
|
||||
port: 9115
|
||||
}
|
||||
-- blackbox-common-config-git-commit.sh --
|
||||
git add . && git commit -m 'add blackbox configuration'
|
||||
-- blackbox-common-config-git-output.txt --
|
||||
[main 1adcd08] add blackbox configuration
|
||||
1 file changed, 15 insertions(+)
|
||||
create mode 100644 components/blackbox.cue
|
||||
-- common-config-patch.sh --
|
||||
patch -p1 < values.patch
|
||||
-- values.patch --
|
||||
--- a/components/blackbox/values.cue
|
||||
+++ b/components/blackbox/values.cue
|
||||
@@ -1,6 +1,11 @@
|
||||
package holos
|
||||
|
||||
+// Import common blackbox configuration
|
||||
+import "holos.example/config/prometheus"
|
||||
+
|
||||
Helm: Values: {
|
||||
+ fullnameOverride: prometheus.blackbox.host
|
||||
+
|
||||
global: {
|
||||
//# Global image registry to use if it needs to be overriden for some specific use cases (e.g local registries, custom images, ...)
|
||||
//#
|
||||
@@ -192,7 +197,7 @@ Helm: Values: {
|
||||
annotations: {}
|
||||
labels: {}
|
||||
type: "ClusterIP"
|
||||
- port: 9115
|
||||
+ port: prometheus.blackbox.port
|
||||
ipDualStack: {
|
||||
enabled: false
|
||||
ipFamilies: ["IPv6", "IPv4"]
|
||||
--- a/components/prometheus/values.cue
|
||||
+++ b/components/prometheus/values.cue
|
||||
@@ -1,5 +1,8 @@
|
||||
package holos
|
||||
|
||||
+// Import common blackbox configuration
|
||||
+import "holos.example/config/prometheus"
|
||||
+
|
||||
Helm: Values: {
|
||||
// yaml-language-server: $schema=values.schema.json
|
||||
// Default values for prometheus.
|
||||
@@ -1083,7 +1086,7 @@ Helm: Values: {
|
||||
target_label: "__param_target"
|
||||
}, {
|
||||
target_label: "__address__"
|
||||
- replacement: "blackbox"
|
||||
+ replacement: "\(prometheus.blackbox.host):\(prometheus.blackbox.port)"
|
||||
}, {
|
||||
source_labels: ["__param_target"]
|
||||
target_label: "instance"
|
||||
-- common-config-patch.txt --
|
||||
patching file 'components/blackbox/values.cue'
|
||||
patching file 'components/prometheus/values.cue'
|
||||
-- common-config-rm.sh --
|
||||
rm values.patch
|
||||
-- common-config-git.sh --
|
||||
git add . && git commit -m 'integrate blackbox and prometheus together'
|
||||
-- common-config-git-output.txt --
|
||||
[main 4221803] integrate blackbox and prometheus together
|
||||
2 files changed, 4 insertions(+), 2 deletions(-)
|
||||
-- reviewing-changes-render-output.txt --
|
||||
rendered blackbox in 374.810666ms
|
||||
rendered prometheus in 382.899334ms
|
||||
rendered platform in 383.270625ms
|
||||
-- git-diff.sh --
|
||||
git diff
|
||||
-- git.diff --
|
||||
diff --git a/deploy/components/blackbox/blackbox.gen.yaml b/deploy/components/blackbox/blackbox.gen.yaml
|
||||
index 3db20cd..5336f44 100644
|
||||
--- a/deploy/components/blackbox/blackbox.gen.yaml
|
||||
+++ b/deploy/components/blackbox/blackbox.gen.yaml
|
||||
@@ -7,7 +7,7 @@ metadata:
|
||||
app.kubernetes.io/name: prometheus-blackbox-exporter
|
||||
app.kubernetes.io/version: v0.25.0
|
||||
helm.sh/chart: prometheus-blackbox-exporter-9.0.1
|
||||
- name: prometheus-blackbox-exporter
|
||||
+ name: blackbox
|
||||
namespace: default
|
||||
---
|
||||
apiVersion: v1
|
||||
@@ -31,7 +31,7 @@ metadata:
|
||||
app.kubernetes.io/name: prometheus-blackbox-exporter
|
||||
app.kubernetes.io/version: v0.25.0
|
||||
helm.sh/chart: prometheus-blackbox-exporter-9.0.1
|
||||
- name: prometheus-blackbox-exporter
|
||||
+ name: blackbox
|
||||
namespace: default
|
||||
---
|
||||
apiVersion: v1
|
||||
@@ -43,7 +43,7 @@ metadata:
|
||||
app.kubernetes.io/name: prometheus-blackbox-exporter
|
||||
app.kubernetes.io/version: v0.25.0
|
||||
helm.sh/chart: prometheus-blackbox-exporter-9.0.1
|
||||
- name: prometheus-blackbox-exporter
|
||||
+ name: blackbox
|
||||
namespace: default
|
||||
spec:
|
||||
ports:
|
||||
@@ -65,7 +65,7 @@ metadata:
|
||||
app.kubernetes.io/name: prometheus-blackbox-exporter
|
||||
app.kubernetes.io/version: v0.25.0
|
||||
helm.sh/chart: prometheus-blackbox-exporter-9.0.1
|
||||
- name: prometheus-blackbox-exporter
|
||||
+ name: blackbox
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 1
|
||||
@@ -119,8 +119,8 @@ spec:
|
||||
name: config
|
||||
hostNetwork: false
|
||||
restartPolicy: Always
|
||||
- serviceAccountName: prometheus-blackbox-exporter
|
||||
+ serviceAccountName: blackbox
|
||||
volumes:
|
||||
- configMap:
|
||||
- name: prometheus-blackbox-exporter
|
||||
+ name: blackbox
|
||||
name: config
|
||||
diff --git a/deploy/components/prometheus/prometheus.gen.yaml b/deploy/components/prometheus/prometheus.gen.yaml
|
||||
index 9e02bce..ab638f0 100644
|
||||
--- a/deploy/components/prometheus/prometheus.gen.yaml
|
||||
+++ b/deploy/components/prometheus/prometheus.gen.yaml
|
||||
@@ -589,7 +589,7 @@ data:
|
||||
- source_labels:
|
||||
- __address__
|
||||
target_label: __param_target
|
||||
- - replacement: blackbox
|
||||
+ - replacement: blackbox:9115
|
||||
target_label: __address__
|
||||
- source_labels:
|
||||
- __param_target
|
||||
-- reviewing-changes-git-commit.sh --
|
||||
git add . && git commit -m 'render integrated blackbox and prometheus manifests'
|
||||
-- reviewing-changes-git-output.txt --
|
||||
[main 67efe0d] render integrated blackbox and prometheus manifests
|
||||
2 files changed, 7 insertions(+), 7 deletions(-)
|
||||
@@ -0,0 +1 @@
|
||||
holos --version
|
||||
@@ -0,0 +1 @@
|
||||
0.104.1
|
||||
@@ -0,0 +1,15 @@
|
||||
package prometheus
|
||||
|
||||
// Schema Definition
|
||||
#Blackbox: {
|
||||
// host constrained to a lower case dns label
|
||||
host: string & =~"^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$"
|
||||
// port constrained to a valid range
|
||||
port: int & >0 & <=65535
|
||||
}
|
||||
|
||||
// Concrete values must validate against the schema.
|
||||
blackbox: #Blackbox & {
|
||||
host: "blackbox"
|
||||
port: 9115
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
git add . && git commit -m 'add blackbox configuration'
|
||||
@@ -0,0 +1,3 @@
|
||||
[main aa9749e] add blackbox configuration
|
||||
1 file changed, 15 insertions(+)
|
||||
create mode 100644 config/prometheus/blackbox.cue
|
||||
@@ -0,0 +1 @@
|
||||
cat <<EOF > config/prometheus/blackbox.cue
|
||||
@@ -0,0 +1,15 @@
|
||||
package holos
|
||||
|
||||
// Produce a helm chart build plan.
|
||||
holos: Helm.BuildPlan
|
||||
|
||||
Helm: #Helm & {
|
||||
Chart: {
|
||||
name: "prometheus-blackbox-exporter"
|
||||
version: "9.0.1"
|
||||
repository: {
|
||||
name: "prometheus-community"
|
||||
url: "https://prometheus-community.github.io/helm-charts"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
cat <<EOF > components/blackbox/blackbox.cue
|
||||
@@ -0,0 +1,3 @@
|
||||
[main 656d4ee] integrate blackbox and prometheus together
|
||||
3 files changed, 1348 insertions(+), 2 deletions(-)
|
||||
create mode 100644 components/prometheus/values.cue.orig
|
||||
@@ -0,0 +1 @@
|
||||
git add . && git commit -m 'integrate blackbox and prometheus together'
|
||||
@@ -0,0 +1 @@
|
||||
patch -p1 < values.patch
|
||||
@@ -0,0 +1,2 @@
|
||||
patching file 'components/blackbox/values.cue'
|
||||
patching file 'components/prometheus/values.cue'
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user