mirror of
https://github.com/holos-run/holos.git
synced 2026-03-19 00:37:45 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03b796312a | ||
|
|
20fb39e49b | ||
|
|
c9c8c13810 | ||
|
|
374cd872e9 | ||
|
|
8db06dd0e1 | ||
|
|
66acadf86d | ||
|
|
032f72b435 | ||
|
|
2380223794 | ||
|
|
e6892c3b16 | ||
|
|
847fd2958e | ||
|
|
cf622835db | ||
|
|
1f5dc3a082 |
@@ -11,6 +11,7 @@
|
||||
"admissionregistration",
|
||||
"alertmanager",
|
||||
"alertmanagers",
|
||||
"anchore",
|
||||
"anthos",
|
||||
"apiextensions",
|
||||
"apimachinery",
|
||||
@@ -56,6 +57,7 @@
|
||||
"Cmds",
|
||||
"CNCF",
|
||||
"CODEOWNERS",
|
||||
"componentconfig",
|
||||
"configdir",
|
||||
"configmap",
|
||||
"configmapargs",
|
||||
@@ -75,6 +77,7 @@
|
||||
"deploymentruntimeconfig",
|
||||
"destinationrule",
|
||||
"destinationrules",
|
||||
"devel",
|
||||
"devicecode",
|
||||
"dnsmasq",
|
||||
"dscacheutil",
|
||||
@@ -137,6 +140,7 @@
|
||||
"httproute",
|
||||
"httproutes",
|
||||
"iampolicygenerator",
|
||||
"incpatch",
|
||||
"Infima",
|
||||
"intstr",
|
||||
"isatty",
|
||||
@@ -153,6 +157,7 @@
|
||||
"kubelet",
|
||||
"kubelogin",
|
||||
"kubernetesobjects",
|
||||
"kubeversion",
|
||||
"Kustomization",
|
||||
"Kustomizations",
|
||||
"kustomize",
|
||||
@@ -255,6 +260,7 @@
|
||||
"rolebinding",
|
||||
"rootfs",
|
||||
"ropc",
|
||||
"sboms",
|
||||
"seccomp",
|
||||
"secretargs",
|
||||
"SECRETKEY",
|
||||
@@ -304,6 +310,7 @@
|
||||
"typemeta",
|
||||
"udev",
|
||||
"uibutton",
|
||||
"Unmarshal",
|
||||
"unstage",
|
||||
"untar",
|
||||
"upbound",
|
||||
|
||||
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 }}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -81,6 +81,10 @@ type Helm struct {
|
||||
EnableHooks bool `cue:"true | *false"`
|
||||
// Namespace sets the helm chart namespace flag if provided.
|
||||
Namespace string `json:",omitempty"`
|
||||
// APIVersions represents the helm template --api-versions flag
|
||||
APIVersions []string `json:",omitempty"`
|
||||
// KubeVersion represents the helm template --kube-version flag
|
||||
KubeVersion string `json:",omitempty"`
|
||||
|
||||
// BuildPlan represents the derived BuildPlan produced for the holos render
|
||||
// component command.
|
||||
|
||||
@@ -133,6 +133,10 @@ type Helm struct {
|
||||
EnableHooks bool `json:"enableHooks,omitempty"`
|
||||
// Namespace represents the helm namespace flag
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
// APIVersions represents the helm template --api-versions flag
|
||||
APIVersions []string `json:"apiVersions,omitempty"`
|
||||
// KubeVersion represents the helm template --kube-version flag
|
||||
KubeVersion string `json:"kubeVersion,omitempty"`
|
||||
}
|
||||
|
||||
// Values represents [Helm] Chart values generated from CUE.
|
||||
|
||||
@@ -28,6 +28,10 @@ func TestSchemas_v1alpha5(t *testing.T) {
|
||||
testscript.Run(t, params(filepath.Join("v1alpha5", "schemas")))
|
||||
}
|
||||
|
||||
func TestIssues_v1alpha5(t *testing.T) {
|
||||
testscript.Run(t, params(filepath.Join("v1alpha5", "issues")))
|
||||
}
|
||||
|
||||
func TestCLI(t *testing.T) {
|
||||
testscript.Run(t, params("cli"))
|
||||
}
|
||||
|
||||
38
cmd/holos/tests/v1alpha5/issues/helm-pull-errors.txt
Normal file
38
cmd/holos/tests/v1alpha5/issues/helm-pull-errors.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
# 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
144
cmd/holos/tests/v1alpha5/schemas/capabilities.txt
Normal file
144
cmd/holos/tests/v1alpha5/schemas/capabilities.txt
Normal file
@@ -0,0 +1,144 @@
|
||||
# https://github.com/holos-run/holos/issues/330
|
||||
exec holos init platform v1alpha5 --force
|
||||
exec helm template ./components/capabilities/vendor/0.1.0/capabilities
|
||||
cmp stdout want/helm-template.yaml
|
||||
exec holos render platform ./platform
|
||||
# When no capabilities are specified
|
||||
cmp deploy/components/capabilities/capabilities.gen.yaml want/when-no-capabilities-specified.yaml
|
||||
# With APIVersions specified
|
||||
cmp deploy/components/specified/specified.gen.yaml want/with-capabilities-specified.yaml
|
||||
# With KubeVersion specified
|
||||
cmp deploy/components/kubeversion1/kubeversion1.gen.yaml want/with-kubeversion-specified.yaml
|
||||
# With both APIVersions and KubeVersion specified
|
||||
cmp deploy/components/kubeversion2/kubeversion2.gen.yaml want/with-both-specified.yaml
|
||||
-- want/with-both-specified.yaml --
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
kubeVersion: v1.20.0
|
||||
name: has-foo-v1
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: http
|
||||
-- want/with-kubeversion-specified.yaml --
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
kubeVersion: v1.20.0
|
||||
name: has-foo-v1beta1
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: http
|
||||
-- want/when-no-capabilities-specified.yaml --
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
kubeVersion: v1.31.0
|
||||
name: has-foo-v1beta1
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: http
|
||||
-- want/with-capabilities-specified.yaml --
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
kubeVersion: v1.31.0
|
||||
name: has-foo-v1
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: http
|
||||
-- platform/capabilities.cue --
|
||||
package holos
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
Platform: Components: capabilities: {
|
||||
name: "capabilities"
|
||||
path: "components/capabilities"
|
||||
}
|
||||
Platform: Components: specified: {
|
||||
name: "specified"
|
||||
path: "components/capabilities"
|
||||
parameters: apiVersions: json.Marshal(["foo/v1","bar/v1"])
|
||||
}
|
||||
Platform: Components: kubeversion1: {
|
||||
name: "kubeversion1"
|
||||
path: "components/capabilities"
|
||||
parameters: kubeVersion: "v1.20.0"
|
||||
}
|
||||
Platform: Components: kubeversion2: {
|
||||
name: "kubeversion2"
|
||||
path: "components/capabilities"
|
||||
parameters: kubeVersion: "v1.20.0"
|
||||
parameters: apiVersions: json.Marshal(["foo/v1","bar/v1"])
|
||||
}
|
||||
-- components/capabilities/capabilities.cue --
|
||||
package holos
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
holos: Component.BuildPlan
|
||||
|
||||
Component: #Helm & {
|
||||
Name: string @tag(holos_component_name, type=string)
|
||||
Chart: name: "capabilities"
|
||||
Chart: version: "0.1.0"
|
||||
_APIVersions: string | *"[]" @tag(apiVersions, type=string)
|
||||
APIVersions: json.Unmarshal(_APIVersions)
|
||||
KubeVersion: string | *"v1.31.0" @tag(kubeVersion, type=string)
|
||||
}
|
||||
-- components/capabilities/vendor/0.1.0/capabilities/Chart.yaml --
|
||||
apiVersion: v2
|
||||
name: capabilities
|
||||
description: A Helm chart for Kubernetes
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "1.16.0"
|
||||
-- components/capabilities/vendor/0.1.0/capabilities/templates/service.yaml --
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
{{- if .Capabilities.APIVersions.Has "foo/v1" }}
|
||||
name: has-foo-v1
|
||||
{{- else }}
|
||||
name: has-foo-v1beta1
|
||||
{{- end }}
|
||||
annotations:
|
||||
kubeVersion: {{ .Capabilities.KubeVersion }}
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
-- want/helm-template.yaml --
|
||||
---
|
||||
# Source: capabilities/templates/service.yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: has-foo-v1beta1
|
||||
annotations:
|
||||
kubeVersion: v1.31.0
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
@@ -83,6 +83,10 @@ type Helm struct {
|
||||
EnableHooks bool `cue:"true | *false"`
|
||||
// Namespace sets the helm chart namespace flag if provided.
|
||||
Namespace string `json:",omitempty"`
|
||||
// APIVersions represents the helm template --api-versions flag
|
||||
APIVersions []string `json:",omitempty"`
|
||||
// KubeVersion represents the helm template --kube-version flag
|
||||
KubeVersion string `json:",omitempty"`
|
||||
|
||||
// BuildPlan represents the derived BuildPlan produced for the holos render
|
||||
// component command.
|
||||
|
||||
@@ -241,6 +241,10 @@ type Helm struct {
|
||||
EnableHooks bool `json:"enableHooks,omitempty"`
|
||||
// Namespace represents the helm namespace flag
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
// APIVersions represents the helm template --api-versions flag
|
||||
APIVersions []string `json:"apiVersions,omitempty"`
|
||||
// KubeVersion represents the helm template --kube-version flag
|
||||
KubeVersion string `json:"kubeVersion,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';
|
||||
|
||||
224
doc/md/topics/gitops/argocd-application.mdx
Normal file
224
doc/md/topics/gitops/argocd-application.mdx
Normal file
@@ -0,0 +1,224 @@
|
||||
---
|
||||
slug: argocd-application
|
||||
title: ArgoCD Application
|
||||
description: Configuring an Application for each Component.
|
||||
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
|
||||
|
||||
## Overview
|
||||
|
||||
This topic covers how to mix in an ArgoCD Application 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-argocd-application && cd holos-argocd-application
|
||||
```
|
||||
|
||||
```shell
|
||||
holos init platform v1alpha5
|
||||
```
|
||||
|
||||
### Creating an example Component
|
||||
|
||||
<CommonComponent />
|
||||
<CommonComponentIntegrate />
|
||||
|
||||
## Adding ArgoCD Application
|
||||
|
||||
Configure Holos to render an [Application] 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 >argocd-application.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
import (
|
||||
"path"
|
||||
app "argoproj.io/application/v1alpha1"
|
||||
)
|
||||
|
||||
#ComponentConfig: {
|
||||
Name: _
|
||||
OutputBaseDir: _
|
||||
|
||||
let ArtifactPath = path.Join([OutputBaseDir, "gitops", "\(Name).application.gen.yaml"], path.Unix)
|
||||
let ResourcesPath = path.Join(["deploy", OutputBaseDir, "components", Name], path.Unix)
|
||||
|
||||
Artifacts: "\(Name)-application": {
|
||||
artifact: ArtifactPath
|
||||
generators: [{
|
||||
kind: "Resources"
|
||||
output: artifact
|
||||
resources: Application: (Name): app.#Application & {
|
||||
metadata: name: Name
|
||||
metadata: namespace: "argocd"
|
||||
spec: {
|
||||
destination: server: "https://kubernetes.default.svc"
|
||||
project: "default"
|
||||
source: {
|
||||
path: ResourcesPath
|
||||
repoURL: "https://example.com/example.git"
|
||||
targetRevision: "main"
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
## Inspecting the BuildPlan
|
||||
|
||||
Our customized `#ComponentConfig` results in the following `BuildPlan`.
|
||||
|
||||
:::note
|
||||
The second artifact around line 40 contains the configured `Application`
|
||||
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: {}
|
||||
enableHooks: false
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
resources: {}
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- helm.gen.yaml
|
||||
- resources.gen.yaml
|
||||
output: components/podinfo/podinfo.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
labels:
|
||||
- includeSelectors: false
|
||||
pairs: {}
|
||||
resources:
|
||||
- helm.gen.yaml
|
||||
- resources.gen.yaml
|
||||
kind: Kustomization
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
- artifact: gitops/podinfo.application.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: gitops/podinfo.application.gen.yaml
|
||||
resources:
|
||||
Application:
|
||||
podinfo:
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: podinfo
|
||||
namespace: argocd
|
||||
spec:
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
project: default
|
||||
source:
|
||||
path: deploy/components/podinfo
|
||||
repoURL: https://example.com/example.git
|
||||
targetRevision: main
|
||||
source:
|
||||
component:
|
||||
name: podinfo
|
||||
path: no-path
|
||||
parameters: {}
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Rendering manifests
|
||||
|
||||
<Tabs groupId="E150C802-7162-4FBF-82A7-77D9ADAEE847">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
holos render platform ./platform
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```
|
||||
cached podinfo 6.6.2
|
||||
rendered podinfo in 1.938665041s
|
||||
rendered platform in 1.938759417s
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Reviewing the Application
|
||||
|
||||
The Artifact we added to `#ComponentConfig` will produce an ArgoCD Application
|
||||
resource for every component in the platform. The output in this example is
|
||||
located at:
|
||||
|
||||
```txt
|
||||
deploy/gitops/podinfo.application.gen.yaml
|
||||
```
|
||||
```yaml showLineNumbers
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: podinfo
|
||||
namespace: argocd
|
||||
spec:
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
project: default
|
||||
source:
|
||||
path: deploy/components/podinfo
|
||||
repoURL: https://example.com/example.git
|
||||
targetRevision: main
|
||||
```
|
||||
|
||||
[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/
|
||||
[Application]: https://argo-cd.readthedocs.io/en/stable/user-guide/application-specification/
|
||||
[Component Parameters]: ../component-parameters.mdx
|
||||
[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/
|
||||
@@ -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';
|
||||
|
||||
424
doc/md/topics/structures/clusters.mdx
Normal file
424
doc/md/topics/structures/clusters.mdx
Normal file
@@ -0,0 +1,424 @@
|
||||
---
|
||||
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
|
||||
```
|
||||
|
||||
### Example Component
|
||||
|
||||
<CommonComponent />
|
||||
|
||||
We'll integrate the component with the platform after we define clusters.
|
||||
|
||||
## 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 ./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
|
||||
29
doc/md/topics/structures/environments.mdx
Normal file
29
doc/md/topics/structures/environments.mdx
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
slug: environments
|
||||
title: Environments
|
||||
description: Managing Environments - dev, test, stage, prod.
|
||||
sidebar_position: 130
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# Environments
|
||||
|
||||
## Overview
|
||||
|
||||
## The Code
|
||||
|
||||
### Generating the structure
|
||||
|
||||
### Using an example Component
|
||||
|
||||
## Defining Environments
|
||||
|
||||
### Defining one Environment
|
||||
|
||||
### Defining a collection of Environments
|
||||
|
||||
## Rendering manifests
|
||||
|
||||
## Reviewing the Manifests
|
||||
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
|
||||
29
doc/md/topics/structures/owners.mdx
Normal file
29
doc/md/topics/structures/owners.mdx
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
slug: owners
|
||||
title: Owners
|
||||
description: Managing and mapping projects to owners.
|
||||
sidebar_position: 150
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# Owners
|
||||
|
||||
## Overview
|
||||
|
||||
## The Code
|
||||
|
||||
### Generating the structure
|
||||
|
||||
### Using an example Component
|
||||
|
||||
## Defining Owners
|
||||
|
||||
### Defining one Owner
|
||||
|
||||
### Defining a collection of Owners
|
||||
|
||||
## Rendering manifests
|
||||
|
||||
## Reviewing the Manifests
|
||||
29
doc/md/topics/structures/projects.mdx
Normal file
29
doc/md/topics/structures/projects.mdx
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
slug: projects
|
||||
title: Projects
|
||||
description: Managing components organizing them into projects.
|
||||
sidebar_position: 140
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# Projects
|
||||
|
||||
## Overview
|
||||
|
||||
## The Code
|
||||
|
||||
### Generating the structure
|
||||
|
||||
### Using an example Component
|
||||
|
||||
## Defining Projects
|
||||
|
||||
### Defining one Project
|
||||
|
||||
### Defining a collection of Projects
|
||||
|
||||
## Rendering manifests
|
||||
|
||||
## Reviewing the Manifests
|
||||
@@ -43,7 +43,9 @@ add the following CUE configuration to it.
|
||||
|
||||
```bash
|
||||
mkdir -p components/podinfo
|
||||
touch components/podinfo/podinfo.cue
|
||||
```
|
||||
```bash
|
||||
cat <<EOF > components/podinfo/podinfo.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
@@ -66,11 +68,14 @@ Component: #Helm & {
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
Integrate the component with the platform.
|
||||
|
||||
```bash
|
||||
touch platform/podinfo.cue
|
||||
cat <<EOF > platform/podinfo.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
@@ -80,6 +85,9 @@ Platform: Components: podinfo: {
|
||||
path: "components/podinfo"
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
Render the platform.
|
||||
|
||||
@@ -113,7 +121,7 @@ component kind. This field is a convenient wrapper around the core [BuildPlan]
|
||||
Create the mixins.cue file.
|
||||
|
||||
```bash
|
||||
touch components/podinfo/mixins.cue
|
||||
cat <<EOF > components/podinfo/mixins.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
@@ -142,6 +150,9 @@ Component: {
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
:::important
|
||||
Holos uses CUE to validate mixed in resources against a schema. The `Resources`
|
||||
|
||||
@@ -109,11 +109,11 @@ initialization.
|
||||
Start by creating a directory for the `podinfo` component. Create an empty file
|
||||
and then add the following CUE configuration to it.
|
||||
|
||||
<Tabs groupId="tutorial-hello-podinfo-helm-cue-code">
|
||||
<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
|
||||
@@ -140,8 +140,9 @@ HelmChart: #Helm & {
|
||||
}
|
||||
}
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
:::important
|
||||
CUE loads all of `*.cue` files in the component directory to define component,
|
||||
@@ -156,13 +157,11 @@ platform root directory. In this example, `#Helm` on line 6 is defined in
|
||||
|
||||
### Integrating the component
|
||||
|
||||
Integrate the `podinfo` component into the platform by creating a new cue file
|
||||
Integrate the `podinfo` component into the platform by creating a new CUE file
|
||||
in the `platform` directory with the following content.
|
||||
|
||||
<Tabs groupId="tutorial-hello-register-podinfo-component">
|
||||
<TabItem value="platform/podinfo.cue" label="Register Podinfo">
|
||||
```bash
|
||||
touch platform/podinfo.cue
|
||||
cat <<EOF > platform/podinfo.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
@@ -174,8 +173,9 @@ Platform: Components: podinfo: {
|
||||
parameters: greeting: "Hello Holos!"
|
||||
}
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
:::tip
|
||||
Component parameters may have any name as long as they don't start with
|
||||
@@ -348,7 +348,7 @@ grep -B2 Hello deploy/components/podinfo/podinfo.gen.yaml
|
||||
|
||||
## Breaking it down
|
||||
|
||||
We run `holos render platform ./platform` because the cue files in the platform
|
||||
We run `holos render platform ./platform` because the CUE files in the platform
|
||||
directory export a [Platform] resource to `holos`. The platform directory is
|
||||
the entrypoint to the platform rendering process.
|
||||
|
||||
@@ -358,7 +358,7 @@ file integrates the `podinfo` Component with the Platform.
|
||||
Holos requires two fields to integrate a component with the platform.
|
||||
|
||||
1. A unique name for the component.
|
||||
2. The component path to the directory containing the cue files exporting a
|
||||
2. The component path to the directory containing the CUE files exporting a
|
||||
`BuildPlan` defining the component.
|
||||
|
||||
Component parameters are optional. They allow re-use of the same component.
|
||||
|
||||
@@ -59,14 +59,12 @@ the following file contents.
|
||||
|
||||
```bash
|
||||
mkdir -p components/prometheus components/blackbox
|
||||
touch components/prometheus/prometheus.cue
|
||||
touch components/blackbox/blackbox.cue
|
||||
```
|
||||
|
||||
<Tabs groupId="D15A3008-1EFC-4D34-BED1-15BC0C736CC3">
|
||||
<TabItem value="prometheus.cue" label="prometheus.cue">
|
||||
```txt
|
||||
components/prometheus/prometheus.cue
|
||||
```bash
|
||||
cat <<EOF > components/prometheus/prometheus.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
@@ -84,11 +82,14 @@ Helm: #Helm & {
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="blackbox.cue" label="blackbox.cue">
|
||||
```txt
|
||||
components/blackbox/blackbox.cue
|
||||
```bash
|
||||
cat <<EOF > components/blackbox/blackbox.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
@@ -106,6 +107,9 @@ Helm: #Helm & {
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
@@ -116,9 +120,8 @@ Integrate the components with the platform by adding the following file to the
|
||||
platform directory.
|
||||
|
||||
```bash
|
||||
touch platform/prometheus.cue
|
||||
cat <<EOF > platform/prometheus.cue
|
||||
```
|
||||
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
@@ -133,6 +136,9 @@ Platform: Components: {
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
Render the platform.
|
||||
|
||||
@@ -196,8 +202,8 @@ holos cue import \
|
||||
components/blackbox/vendor/9.0.1/prometheus-blackbox-exporter/values.yaml
|
||||
```
|
||||
|
||||
These command convert the YAML data into CUE code and nest the values under the
|
||||
`Values` field of the `Holos` struct.
|
||||
These commands convert the YAML data into CUE code and nest the values under the
|
||||
`Values` field of the `Helm` struct.
|
||||
|
||||
:::important
|
||||
CUE unifies `values.cue` with the other `*.cue` files in the same directory.
|
||||
@@ -243,9 +249,8 @@ use. We add this configuration to the `components` directory so it's in scope
|
||||
for all components.
|
||||
|
||||
```bash
|
||||
touch components/blackbox.cue
|
||||
cat <<EOF > components/blackbox.cue
|
||||
```
|
||||
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
@@ -263,6 +268,9 @@ Blackbox: #Blackbox & {
|
||||
port: 9115
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
:::important
|
||||
1. CUE loads and unifies all `*.cue` files from the root directory containing
|
||||
|
||||
@@ -61,11 +61,12 @@ Create the `httpbin` component directory and add the `httpbin.cue` and
|
||||
<TabItem value="setup" label="Setup">
|
||||
```bash
|
||||
mkdir -p components/httpbin
|
||||
touch components/httpbin/httpbin.cue
|
||||
touch components/httpbin/httpbin.yaml
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="components/httpbin/httpbin.cue" label="httpbin.cue">
|
||||
```bash
|
||||
cat <<EOF > components/httpbin/httpbin.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
@@ -97,9 +98,15 @@ Kustomize: #Kustomize & {
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="components/httpbin/httpbin.yaml" label="httpbin.yaml">
|
||||
```bash
|
||||
cat <<EOF > components/httpbin/httpbin.yaml
|
||||
```
|
||||
```yaml showLineNumbers
|
||||
# https://github.com/mccutchen/go-httpbin/blob/v2.15.0/kustomize/resources.yaml
|
||||
apiVersion: apps/v1
|
||||
@@ -137,6 +144,9 @@ spec:
|
||||
protocol: TCP
|
||||
name: http
|
||||
appProtocol: http
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
@@ -150,9 +160,8 @@ Integrate `httpbin` with the platform by adding the following file to the
|
||||
platform directory.
|
||||
|
||||
```bash
|
||||
touch platform/httpbin.cue
|
||||
cat <<EOF > platform/httpbin.cue
|
||||
```
|
||||
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
@@ -163,6 +172,9 @@ Platform: Components: {
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
Render the platform.
|
||||
|
||||
@@ -275,13 +287,9 @@ makes this easier with CUE. We don't need to edit any yaml files.
|
||||
Add a new `patches.cue` file to the `httpbin` component with the following
|
||||
content.
|
||||
|
||||
<Tabs groupId="104D40FD-ED59-4F66-8B91-435436084743">
|
||||
<TabItem value="touch" label="touch">
|
||||
```bash
|
||||
touch components/httpbin/patches.cue
|
||||
cat <<EOF > components/httpbin/patches.cue
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="patches.cue" label="patches.cue">
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
@@ -300,8 +308,9 @@ Kustomize: KustomizeConfig: Kustomization: _patches: {
|
||||
}
|
||||
}
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
```bash
|
||||
EOF
|
||||
```
|
||||
|
||||
:::note
|
||||
We use a hidden `_patches` field to easily unify data into a struct, then
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
slug: schema-definitions
|
||||
title: Schema Definitions
|
||||
description: Define your own custom data structures.
|
||||
sidebar_position: 70
|
||||
---
|
||||
|
||||
# Schema Definitions
|
||||
|
||||
- Work through defining a `#Cluster` schema and a `Clusters` struct.
|
||||
- Direct the reader to [topics] for more recipes.
|
||||
|
||||
[topics]: ../topics.mdx
|
||||
@@ -17,22 +17,54 @@ This tutorial will guide you through the installation of Holos and its
|
||||
dependencies, as well as the initialization of a minimal Platform that you can
|
||||
extend to meet your specific needs.
|
||||
|
||||
## Installing Holos
|
||||
## Installing
|
||||
|
||||
Holos is distributed as a single file executable that can be installed in a
|
||||
couple of ways.
|
||||
|
||||
<Tabs groupId="FE2C74C8-B3A3-4AEA-BBD3-F57FAA654B6F">
|
||||
<TabItem value="brew" label="Install with brew">
|
||||
```bash
|
||||
brew install holos-run/tap/holos
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="go" label="Go">
|
||||
```bash
|
||||
go install github.com/holos-run/holos/cmd/holos@latest
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### Completion
|
||||
|
||||
<Tabs groupId="65F79D28-2E57-4A90-8EBA-3D8758C80233">
|
||||
<TabItem value="zsh" label="zsh">
|
||||
```bash
|
||||
source <(holos completion zsh)
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="bash" label="bash">
|
||||
```bash
|
||||
source <(holos completion bash)
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="fish" label="fish">
|
||||
```bash
|
||||
source <(holos completion fish)
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="ksh" label="ksh">
|
||||
```bash
|
||||
source <(holos completion ksh)
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### Releases
|
||||
|
||||
Download `holos` from the [releases] page and place the executable into your
|
||||
shell path.
|
||||
|
||||
### Go Install
|
||||
|
||||
```shell
|
||||
go install github.com/holos-run/holos/cmd/holos@latest
|
||||
```
|
||||
|
||||
### Dependencies
|
||||
|
||||
Holos integrates with the following tools that should be installed to enable
|
||||
@@ -41,6 +73,13 @@ their functionality.
|
||||
- [Helm] to fetch and render Helm chart Components.
|
||||
- [Kubectl] to [kustomize] components.
|
||||
|
||||
:::note
|
||||
Holos is tested with Helm version `v3.16.2`.
|
||||
:::
|
||||
|
||||
Please try upgrading helm if you encounter `Error: chart requires kubeVersion
|
||||
...` errors.
|
||||
|
||||
## Next Steps
|
||||
|
||||
You've got the structure of your platform configuration in place. Continue on to
|
||||
|
||||
@@ -333,6 +333,12 @@ func (b *BuildPlan) helm(
|
||||
if !g.Helm.EnableHooks {
|
||||
args = append(args, "--no-hooks")
|
||||
}
|
||||
for _, apiVersion := range g.Helm.APIVersions {
|
||||
args = append(args, "--api-versions", apiVersion)
|
||||
}
|
||||
if kubeVersion := g.Helm.KubeVersion; kubeVersion != "" {
|
||||
args = append(args, "--kube-version", kubeVersion)
|
||||
}
|
||||
args = append(args,
|
||||
"--include-crds",
|
||||
"--values", valuesPath,
|
||||
@@ -347,6 +353,7 @@ func (b *BuildPlan) helm(
|
||||
stderr := helmOut.Stderr.String()
|
||||
lines := strings.Split(stderr, "\n")
|
||||
for _, line := range lines {
|
||||
log.DebugContext(ctx, line)
|
||||
if strings.HasPrefix(line, "Error:") {
|
||||
err = fmt.Errorf("%s: %w", line, err)
|
||||
}
|
||||
@@ -514,7 +521,15 @@ func (b *BuildPlan) cacheChart(
|
||||
}
|
||||
helmOut, err := util.RunCmd(ctx, "helm", "pull", "--destination", cacheTemp, "--untar=true", "--version", chart.Version, cn)
|
||||
if err != nil {
|
||||
return errors.Wrap(fmt.Errorf("could not run helm pull: %w", err))
|
||||
stderr := helmOut.Stderr.String()
|
||||
lines := strings.Split(stderr, "\n")
|
||||
for _, line := range lines {
|
||||
log.DebugContext(ctx, line)
|
||||
if strings.HasPrefix(line, "Error:") {
|
||||
err = fmt.Errorf("%s: %w", line, err)
|
||||
}
|
||||
}
|
||||
return errors.Format("could not run helm pull: %w", err)
|
||||
}
|
||||
log.Debug("helm pull", "stdout", helmOut.Stdout, "stderr", helmOut.Stderr)
|
||||
|
||||
|
||||
@@ -28,13 +28,13 @@ func New(cfg *holos.Config, feature holos.Flagger) *cobra.Command {
|
||||
cmd := command.New("render")
|
||||
cmd.Args = cobra.NoArgs
|
||||
cmd.Short = "render platforms and components to manifest files"
|
||||
cmd.AddCommand(NewComponent(cfg))
|
||||
cmd.AddCommand(NewPlatform(cfg))
|
||||
cmd.AddCommand(NewComponent(cfg, feature))
|
||||
cmd.AddCommand(NewPlatform(cfg, feature))
|
||||
return cmd
|
||||
}
|
||||
|
||||
// New returns the component subcommand for the render command
|
||||
func NewComponent(cfg *holos.Config) *cobra.Command {
|
||||
func NewComponent(cfg *holos.Config, feature holos.Flagger) *cobra.Command {
|
||||
cmd := command.New("component DIRECTORY")
|
||||
cmd.Args = cobra.ExactArgs(1)
|
||||
cmd.Short = "render a platform component"
|
||||
@@ -43,8 +43,10 @@ func NewComponent(cfg *holos.Config) *cobra.Command {
|
||||
cmd.Flags().AddGoFlagSet(cfg.ClusterFlagSet())
|
||||
|
||||
config := client.NewConfig(cfg)
|
||||
cmd.PersistentFlags().AddGoFlagSet(config.ClientFlagSet())
|
||||
cmd.PersistentFlags().AddGoFlagSet(config.TokenFlagSet())
|
||||
if feature.Flag(holos.ClientFeature) {
|
||||
cmd.PersistentFlags().AddGoFlagSet(config.ClientFlagSet())
|
||||
cmd.PersistentFlags().AddGoFlagSet(config.TokenFlagSet())
|
||||
}
|
||||
|
||||
flagSet := flag.NewFlagSet("", flag.ContinueOnError)
|
||||
|
||||
@@ -176,15 +178,17 @@ func NewComponent(cfg *holos.Config) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func NewPlatform(cfg *holos.Config) *cobra.Command {
|
||||
func NewPlatform(cfg *holos.Config, feature holos.Flagger) *cobra.Command {
|
||||
cmd := command.New("platform DIRECTORY")
|
||||
cmd.Args = cobra.ExactArgs(1)
|
||||
cmd.Example = " holos render platform ./platform"
|
||||
cmd.Short = "render an entire platform"
|
||||
|
||||
config := client.NewConfig(cfg)
|
||||
cmd.PersistentFlags().AddGoFlagSet(config.ClientFlagSet())
|
||||
cmd.PersistentFlags().AddGoFlagSet(config.TokenFlagSet())
|
||||
if feature.Flag(holos.ClientFeature) {
|
||||
cmd.PersistentFlags().AddGoFlagSet(config.ClientFlagSet())
|
||||
cmd.PersistentFlags().AddGoFlagSet(config.TokenFlagSet())
|
||||
}
|
||||
|
||||
var concurrency int
|
||||
cmd.Flags().IntVar(&concurrency, "concurrency", min(runtime.NumCPU(), 8), "number of components to render concurrently")
|
||||
@@ -274,17 +278,18 @@ func (t tags) Tags() []string {
|
||||
}
|
||||
|
||||
func (t tags) String() string {
|
||||
return strings.Join(t.Tags(), ",")
|
||||
return strings.Join(t.Tags(), " ")
|
||||
}
|
||||
|
||||
// Set sets a value. Only one value per flag is supported. For example
|
||||
// --inject=foo=bar --inject=bar=baz. For JSON values, --inject=foo=bar,bar=baz
|
||||
// is not supported.
|
||||
func (t tags) Set(value string) error {
|
||||
for _, item := range strings.Split(value, ",") {
|
||||
parts := strings.SplitN(item, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
return errors.Format("invalid format, must be tag=value")
|
||||
}
|
||||
t[parts[0]] = parts[1]
|
||||
parts := strings.SplitN(value, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
return errors.Format("invalid format, must be tag=value")
|
||||
}
|
||||
t[parts[0]] = parts[1]
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -92,6 +92,12 @@ import "github.com/holos-run/holos/api/core/v1alpha5:core"
|
||||
// Namespace sets the helm chart namespace flag if provided.
|
||||
Namespace?: string
|
||||
|
||||
// APIVersions represents the helm template --api-versions flag
|
||||
APIVersions?: [...string] @go(,[]string)
|
||||
|
||||
// KubeVersion represents the helm template --kube-version flag
|
||||
KubeVersion?: string
|
||||
|
||||
// BuildPlan represents the derived BuildPlan produced for the holos render
|
||||
// component command.
|
||||
BuildPlan: core.#BuildPlan
|
||||
|
||||
@@ -147,6 +147,12 @@ package core
|
||||
|
||||
// Namespace represents the helm namespace flag
|
||||
namespace?: string @go(Namespace)
|
||||
|
||||
// APIVersions represents the helm template --api-versions flag
|
||||
apiVersions?: [...string] @go(APIVersions,[]string)
|
||||
|
||||
// KubeVersion represents the helm template --kube-version flag
|
||||
kubeVersion?: string @go(KubeVersion)
|
||||
}
|
||||
|
||||
// Values represents [Helm] Chart values generated from CUE.
|
||||
|
||||
@@ -106,9 +106,11 @@ import (
|
||||
name: string | *Name
|
||||
release: string | *name
|
||||
}
|
||||
Values: _
|
||||
EnableHooks: _
|
||||
Namespace?: _
|
||||
Values: _
|
||||
EnableHooks: _
|
||||
Namespace?: _
|
||||
APIVersions?: _
|
||||
KubeVersion?: _
|
||||
|
||||
Artifacts: {
|
||||
HolosComponent: {
|
||||
@@ -134,6 +136,12 @@ import (
|
||||
if Namespace != _|_ {
|
||||
namespace: Namespace
|
||||
}
|
||||
if APIVersions != _|_ {
|
||||
apiVersions: APIVersions
|
||||
}
|
||||
if KubeVersion != _|_ {
|
||||
kubeVersion: KubeVersion
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -31,6 +31,7 @@ type feature string
|
||||
|
||||
const BuildFeature = feature("BUILD")
|
||||
const ServerFeature = feature("SERVER")
|
||||
const ClientFeature = feature("CLIENT")
|
||||
const PreflightFeature = feature("PREFLIGHT")
|
||||
const GenerateComponentFeature = feature("GENERATE_COMPONENT")
|
||||
const SecretsFeature = feature("SECRETS")
|
||||
|
||||
@@ -1 +1 @@
|
||||
98
|
||||
99
|
||||
|
||||
@@ -1 +1 @@
|
||||
2
|
||||
3
|
||||
|
||||
Reference in New Issue
Block a user