mirror of
https://github.com/holos-run/holos.git
synced 2026-03-19 00:37:45 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf28516b8b | ||
|
|
d81e25c4e4 | ||
|
|
c4612ff5d2 | ||
|
|
d70acbb47e | ||
|
|
3c977d22fe | ||
|
|
e34db2b583 | ||
|
|
71de57ac88 | ||
|
|
c7cc661018 | ||
|
|
09f39c02fe | ||
|
|
23c76a73e0 | ||
|
|
1cafe08237 | ||
|
|
45b07964ef | ||
|
|
6cc4a57b62 | ||
|
|
31280acbae |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@ coverage.out
|
||||
dist/
|
||||
*.hold/
|
||||
/deploy/
|
||||
.vscode/
|
||||
|
||||
@@ -19,13 +19,14 @@ type BuildPlanSpec struct {
|
||||
}
|
||||
|
||||
type BuildPlanComponents struct {
|
||||
HelmCharts []HelmChart `json:"helmCharts,omitempty" yaml:"helmCharts,omitempty"`
|
||||
KubernetesObjects []KubernetesObjects `json:"kubernetesObjects,omitempty" yaml:"kubernetesObjects,omitempty"`
|
||||
KustomizeBuilds []KustomizeBuild `json:"kustomizeBuilds,omitempty" yaml:"kustomizeBuilds,omitempty"`
|
||||
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, 10)
|
||||
errs := make([]string, 0, 2)
|
||||
if bp.Kind != BuildPlanKind {
|
||||
errs = append(errs, fmt.Sprintf("kind invalid: want: %s have: %s", BuildPlanKind, bp.Kind))
|
||||
}
|
||||
|
||||
@@ -6,4 +6,6 @@ const (
|
||||
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"
|
||||
)
|
||||
|
||||
@@ -3,13 +3,14 @@ package v1alpha1
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/holos-run/holos"
|
||||
"github.com/holos-run/holos/pkg/logger"
|
||||
"github.com/holos-run/holos/pkg/util"
|
||||
"github.com/holos-run/holos/pkg/wrapper"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A HelmChart represents a helm command to provide chart values in order to render kubernetes api objects.
|
||||
@@ -26,7 +27,7 @@ type Chart struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Release string `json:"release"`
|
||||
Repository Repository `json:"repository"`
|
||||
Repository Repository `json:"repository,omitempty"`
|
||||
}
|
||||
|
||||
type Repository struct {
|
||||
@@ -34,7 +35,7 @@ type Repository struct {
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
func (hc *HelmChart) Render(ctx context.Context, path holos.PathComponent) (*Result, error) {
|
||||
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
|
||||
@@ -48,7 +49,7 @@ func (hc *HelmChart) Render(ctx context.Context, path holos.PathComponent) (*Res
|
||||
|
||||
// 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.PathComponent) error {
|
||||
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")
|
||||
@@ -120,7 +121,7 @@ func (hc *HelmChart) helm(ctx context.Context, r *Result, path holos.PathCompone
|
||||
}
|
||||
|
||||
// cacheChart stores a cached copy of Chart in the chart subdirectory of path.
|
||||
func cacheChart(ctx context.Context, path holos.PathComponent, chartDir string, chart Chart) error {
|
||||
func cacheChart(ctx context.Context, path holos.InstancePath, chartDir string, chart Chart) error {
|
||||
log := logger.FromContext(ctx)
|
||||
|
||||
cacheTemp, err := os.MkdirTemp(string(path), chartDir)
|
||||
|
||||
@@ -2,6 +2,7 @@ package v1alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/holos-run/holos"
|
||||
)
|
||||
|
||||
@@ -13,12 +14,8 @@ type KubernetesObjects struct {
|
||||
}
|
||||
|
||||
// Render produces kubernetes api objects from the APIObjectMap
|
||||
func (o *KubernetesObjects) Render(ctx context.Context, path holos.PathComponent) (*Result, error) {
|
||||
result := Result{
|
||||
TypeMeta: o.TypeMeta,
|
||||
Metadata: o.Metadata,
|
||||
Kustomization: o.Kustomization,
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package v1alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/holos-run/holos"
|
||||
"github.com/holos-run/holos/pkg/logger"
|
||||
"github.com/holos-run/holos/pkg/util"
|
||||
@@ -29,7 +30,7 @@ type KustomizeBuild struct {
|
||||
|
||||
// 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.PathComponent) (*Result, error) {
|
||||
func (kb *KustomizeBuild) Render(ctx context.Context, path holos.InstancePath) (*Result, error) {
|
||||
log := logger.FromContext(ctx)
|
||||
result := Result{HolosComponent: kb.HolosComponent}
|
||||
// Run kustomize.
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
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[string]map[string]string
|
||||
type APIObjectMap map[Kind]map[Label]string
|
||||
|
||||
// FileContentMap is a map of file names to file contents.
|
||||
type FileContentMap map[string]string
|
||||
|
||||
@@ -2,12 +2,13 @@ package v1alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/holos-run/holos"
|
||||
)
|
||||
|
||||
type Renderer interface {
|
||||
GetKind() string
|
||||
Render(ctx context.Context, path holos.PathComponent) (*Result, error)
|
||||
Render(ctx context.Context, path holos.InstancePath) (*Result, error)
|
||||
}
|
||||
|
||||
// Render produces a Result representing the kubernetes api objects to
|
||||
@@ -16,6 +17,6 @@ type Renderer interface {
|
||||
// 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.PathComponent) (*Result, error) {
|
||||
func Render(ctx context.Context, r Renderer, path holos.InstancePath) (*Result, error) {
|
||||
return r.Render(ctx, path)
|
||||
}
|
||||
|
||||
@@ -3,21 +3,18 @@ package v1alpha1
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/holos-run/holos/pkg/logger"
|
||||
"github.com/holos-run/holos/pkg/util"
|
||||
"github.com/holos-run/holos/pkg/wrapper"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
|
||||
"github.com/holos-run/holos/pkg/logger"
|
||||
"github.com/holos-run/holos/pkg/util"
|
||||
"github.com/holos-run/holos/pkg/wrapper"
|
||||
)
|
||||
|
||||
// Result is the build result for display or writing. Holos components Render the Result as a data pipeline.
|
||||
type Result struct {
|
||||
HolosComponent
|
||||
TypeMeta `json:",inline" yaml:",inline"`
|
||||
Kustomization `json:",inline" yaml:",inline"`
|
||||
Kustomize `json:",inline" yaml:",inline"`
|
||||
Metadata ObjectMeta `json:"metadata,omitempty"`
|
||||
// accumulatedOutput accumulates rendered api objects.
|
||||
accumulatedOutput string
|
||||
}
|
||||
@@ -44,7 +41,7 @@ func (r *Result) AccumulatedOutput() string {
|
||||
func (r *Result) addObjectMap(ctx context.Context, objectMap APIObjectMap) {
|
||||
log := logger.FromContext(ctx)
|
||||
b := []byte(r.AccumulatedOutput())
|
||||
kinds := make([]string, 0, len(objectMap))
|
||||
kinds := make([]Kind, 0, len(objectMap))
|
||||
// Sort the keys
|
||||
for kind := range objectMap {
|
||||
kinds = append(kinds, kind)
|
||||
@@ -54,7 +51,7 @@ func (r *Result) addObjectMap(ctx context.Context, objectMap APIObjectMap) {
|
||||
for _, kind := range kinds {
|
||||
v := objectMap[kind]
|
||||
// Sort the keys
|
||||
names := make([]string, 0, len(v))
|
||||
names := make([]Label, 0, len(v))
|
||||
for name := range v {
|
||||
names = append(names, name)
|
||||
}
|
||||
|
||||
29
cmd/holos/testdata/constraints.txt
vendored
29
cmd/holos/testdata/constraints.txt
vendored
@@ -1,7 +1,6 @@
|
||||
# Want support for intermediary constraints
|
||||
exec holos build ./foo/... --log-level debug
|
||||
stdout '^bf2bc7f9-9ba0-4f9e-9bd2-9a205627eb0b$'
|
||||
stderr 'processing holos component kind Skip'
|
||||
|
||||
-- cue.mod --
|
||||
package holos
|
||||
@@ -12,31 +11,21 @@ metadata: name: "jeff"
|
||||
-- foo/bar/bar.cue --
|
||||
package holos
|
||||
|
||||
#KubernetesObjects & {
|
||||
apiObjectMap: foo: bar: "bf2bc7f9-9ba0-4f9e-9bd2-9a205627eb0b"
|
||||
}
|
||||
spec: components: KubernetesObjectsList: [
|
||||
#KubernetesObjects & {
|
||||
apiObjectMap: foo: bar: "bf2bc7f9-9ba0-4f9e-9bd2-9a205627eb0b"
|
||||
}
|
||||
]
|
||||
-- schema.cue --
|
||||
package holos
|
||||
|
||||
cluster: string @tag(cluster, string)
|
||||
|
||||
// #OutputTypeMeta is shared among all output types
|
||||
#OutputTypeMeta: {
|
||||
apiVersion: "holos.run/v1alpha1"
|
||||
kind: #KubernetesObjects.kind | #NoOutput.kind
|
||||
metadata: name: string
|
||||
}
|
||||
_cluster: string @tag(cluster, string)
|
||||
|
||||
#KubernetesObjects: {
|
||||
#OutputTypeMeta
|
||||
apiVersion: "holos.run/v1alpha1"
|
||||
kind: "KubernetesObjects"
|
||||
apiObjectMap: {...}
|
||||
}
|
||||
|
||||
#NoOutput: {
|
||||
#OutputTypeMeta
|
||||
kind: string | *"Skip"
|
||||
metadata: name: string | *"skipped"
|
||||
}
|
||||
|
||||
#NoOutput & {}
|
||||
apiVersion: "holos.run/v1alpha1"
|
||||
kind: "BuildPlan"
|
||||
|
||||
15
cmd/holos/testdata/issue15_cue_errors.txt
vendored
15
cmd/holos/testdata/issue15_cue_errors.txt
vendored
@@ -1,16 +1,17 @@
|
||||
# Want cue errors to show files and lines
|
||||
! exec holos build .
|
||||
stderr '^apiObjectMap.foo.bar: cannot convert non-concrete value string'
|
||||
stderr '/component.cue:7:20$'
|
||||
stderr 'apiObjectMap.foo.bar: cannot convert incomplete value'
|
||||
stderr '/component.cue:\d+:\d+$'
|
||||
|
||||
-- cue.mod --
|
||||
package holos
|
||||
-- component.cue --
|
||||
package holos
|
||||
|
||||
apiVersion: "holos.run/v1alpha1"
|
||||
kind: "KubernetesObjects"
|
||||
cluster: string @tag(cluster, string)
|
||||
_cluster: string @tag(cluster, string)
|
||||
|
||||
apiObjectMap: foo: bar: baz
|
||||
baz: string
|
||||
apiVersion: "holos.run/v1alpha1"
|
||||
kind: "BuildPlan"
|
||||
spec: components: KubernetesObjectsList: [{apiObjectMap: foo: bar: _baz}]
|
||||
|
||||
_baz: string
|
||||
|
||||
@@ -9,15 +9,17 @@ package holos
|
||||
package holos
|
||||
|
||||
apiVersion: "holos.run/v1alpha1"
|
||||
kind: "KubernetesObjects"
|
||||
cluster: string @tag(cluster, string)
|
||||
kind: "BuildPlan"
|
||||
spec: components: KubernetesObjectsList: [{apiObjectMap: #APIObjects.apiObjectMap}]
|
||||
|
||||
_cluster: string @tag(cluster, string)
|
||||
|
||||
#SecretStore: {
|
||||
kind: string
|
||||
metadata: name: string
|
||||
}
|
||||
|
||||
#APIObjects & {
|
||||
#APIObjects: {
|
||||
apiObjects: {
|
||||
SecretStore: {
|
||||
default: #SecretStore & { metadata: name: "default" }
|
||||
@@ -54,4 +56,3 @@ import "encoding/yaml"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,15 +10,17 @@ package holos
|
||||
package holos
|
||||
|
||||
apiVersion: "holos.run/v1alpha1"
|
||||
kind: "HelmChart"
|
||||
cluster: string @tag(cluster, string)
|
||||
kind: "BuildPlan"
|
||||
spec: components: HelmChartList: [{apiObjectMap: #APIObjects.apiObjectMap}]
|
||||
|
||||
_cluster: string @tag(cluster, string)
|
||||
|
||||
#SecretStore: {
|
||||
kind: string
|
||||
metadata: name: string
|
||||
}
|
||||
|
||||
#APIObjects & {
|
||||
#APIObjects: {
|
||||
apiObjects: {
|
||||
SecretStore: {
|
||||
default: #SecretStore & { metadata: name: "default" }
|
||||
@@ -55,4 +57,3 @@ import "encoding/yaml"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
33
cmd/holos/testdata/issue33_helm_stderr.txt
vendored
33
cmd/holos/testdata/issue33_helm_stderr.txt
vendored
@@ -7,22 +7,27 @@ package holos
|
||||
-- zitadel.cue --
|
||||
package holos
|
||||
|
||||
cluster: string @tag(cluster, string)
|
||||
|
||||
apiVersion: "holos.run/v1alpha1"
|
||||
kind: "HelmChart"
|
||||
metadata: name: "zitadel"
|
||||
namespace: "zitadel"
|
||||
chart: {
|
||||
name: "zitadel"
|
||||
version: "7.9.0"
|
||||
release: name
|
||||
repository: {
|
||||
name: "zitadel"
|
||||
url: "https://charts.zitadel.com"
|
||||
}
|
||||
}
|
||||
kind: "BuildPlan"
|
||||
spec: components: HelmChartList: [_HelmChart]
|
||||
|
||||
_cluster: string @tag(cluster, string)
|
||||
|
||||
_HelmChart: {
|
||||
apiVersion: "holos.run/v1alpha1"
|
||||
kind: "HelmChart"
|
||||
metadata: name: "zitadel"
|
||||
namespace: "zitadel"
|
||||
chart: {
|
||||
name: "zitadel"
|
||||
version: "7.9.0"
|
||||
release: name
|
||||
repository: {
|
||||
name: "zitadel"
|
||||
url: "https://charts.zitadel.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-- vendor/zitadel/templates/secret_zitadel-masterkey.yaml --
|
||||
{{- if (or (and .Values.zitadel.masterkey .Values.zitadel.masterkeySecretName) (and (not .Values.zitadel.masterkey) (not .Values.zitadel.masterkeySecretName)) ) }}
|
||||
|
||||
@@ -9,22 +9,25 @@ package holos
|
||||
-- component.cue --
|
||||
package holos
|
||||
|
||||
cluster: string @tag(cluster, string)
|
||||
_cluster: string @tag(cluster, string)
|
||||
|
||||
apiVersion: "holos.run/v1alpha1"
|
||||
kind: "KustomizeBuild"
|
||||
metadata: name: "kstest"
|
||||
kind: "BuildPlan"
|
||||
spec: components: KustomizeBuildList: [{metadata: name: "kstest"}]
|
||||
|
||||
-- kustomization.yaml --
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
namespace: mynamespace
|
||||
resources:
|
||||
- serviceaccount.yaml
|
||||
|
||||
-- serviceaccount.yaml --
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: test
|
||||
|
||||
-- want.yaml --
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
|
||||
14
cmd/holos/testdata/issue72_disallow_unknown_fields.txt
vendored
Normal file
14
cmd/holos/testdata/issue72_disallow_unknown_fields.txt
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# https://github.com/holos-run/holos/issues/72
|
||||
# Want holos to fail on unknown fields to catch typos and aid refactors
|
||||
! exec holos build .
|
||||
stderr 'unknown field \\"TypoKubernetesObjectsList\\"'
|
||||
|
||||
-- cue.mod --
|
||||
package holos
|
||||
-- component.cue --
|
||||
package holos
|
||||
_cluster: string @tag(cluster, string)
|
||||
|
||||
apiVersion: "holos.run/v1alpha1"
|
||||
kind: "BuildPlan"
|
||||
spec: components: TypoKubernetesObjectsList: []
|
||||
@@ -19,7 +19,8 @@ package v1alpha1
|
||||
}
|
||||
|
||||
#BuildPlanComponents: {
|
||||
helmCharts?: [...#HelmChart] @go(HelmCharts,[]HelmChart)
|
||||
kubernetesObjects?: [...#KubernetesObjects] @go(KubernetesObjects,[]KubernetesObjects)
|
||||
kustomizeBuilds?: [...#KustomizeBuild] @go(KustomizeBuilds,[]KustomizeBuild)
|
||||
helmChartList?: [...#HelmChart] @go(HelmChartList,[]HelmChart)
|
||||
kubernetesObjectsList?: [...#KubernetesObjects] @go(KubernetesObjectsList,[]KubernetesObjects)
|
||||
kustomizeBuildList?: [...#KustomizeBuild] @go(KustomizeBuildList,[]KustomizeBuild)
|
||||
resources?: {[string]: #KubernetesObjects} @go(Resources,map[string]KubernetesObjects)
|
||||
}
|
||||
|
||||
@@ -10,3 +10,6 @@ package v1alpha1
|
||||
|
||||
// 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"
|
||||
|
||||
@@ -16,10 +16,10 @@ package v1alpha1
|
||||
}
|
||||
|
||||
#Chart: {
|
||||
name: string @go(Name)
|
||||
version: string @go(Version)
|
||||
release: string @go(Release)
|
||||
repository: #Repository @go(Repository)
|
||||
name: string @go(Name)
|
||||
version: string @go(Version)
|
||||
release: string @go(Release)
|
||||
repository?: #Repository @go(Repository)
|
||||
}
|
||||
|
||||
#Repository: {
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
|
||||
package v1alpha1
|
||||
|
||||
// Label is an arbitrary unique identifier. Defined as a type for clarity and type checking.
|
||||
#Label: string
|
||||
|
||||
// Kind is a kubernetes api object kind. Defined as a type for clarity and type checking.
|
||||
#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.
|
||||
#APIObjectMap: {[string]: [string]: string}
|
||||
|
||||
@@ -7,11 +7,4 @@ package v1alpha1
|
||||
// Result is the build result for display or writing. Holos components Render the Result as a data pipeline.
|
||||
#Result: {
|
||||
HolosComponent: #HolosComponent
|
||||
|
||||
#TypeMeta
|
||||
|
||||
#Kustomization
|
||||
|
||||
#Kustomize
|
||||
metadata?: #ObjectMeta @go(Metadata)
|
||||
}
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
package v1alpha1
|
||||
|
||||
#HolosComponent: metadata: name: string
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
package v1alpha1
|
||||
|
||||
#HolosComponent: Skip: true | *false
|
||||
|
||||
#HelmChart: enableHooks: true | *false
|
||||
|
||||
@@ -7,14 +7,16 @@ import "encoding/yaml"
|
||||
// apiObjects holds each the api objects produced by cue.
|
||||
apiObjects: {
|
||||
[Kind=_]: {
|
||||
[Name=_]: {
|
||||
[string]: {
|
||||
kind: Kind
|
||||
...
|
||||
}
|
||||
}
|
||||
Namespace?: [Name=_]: #Namespace & {metadata: name: Name}
|
||||
ExternalSecret?: [Name=_]: #ExternalSecret & {_name: Name}
|
||||
VirtualService?: [Name=_]: #VirtualService & {metadata: name: Name}
|
||||
Issuer?: [Name=_]: #Issuer & {metadata: name: Name}
|
||||
Gateway?: [Name=_]: #Gateway & {metadata: name: Name}
|
||||
}
|
||||
|
||||
// apiObjectMap holds the marshalled representation of apiObjects
|
||||
|
||||
@@ -3,6 +3,7 @@ package holos
|
||||
import (
|
||||
"encoding/yaml"
|
||||
h "github.com/holos-run/holos/api/v1alpha1"
|
||||
kc "sigs.k8s.io/kustomize/api/types"
|
||||
ksv1 "kustomize.toolkit.fluxcd.io/kustomization/v1"
|
||||
)
|
||||
|
||||
@@ -13,20 +14,57 @@ import (
|
||||
// Constrain each CUE instance to output a BuildPlan.
|
||||
{} & h.#BuildPlan
|
||||
|
||||
let DependsOn = {[Name=_]: name: string & Name}
|
||||
|
||||
// #HolosComponent defines struct fields common to all holos component types.
|
||||
#HolosComponent: {
|
||||
h.#HolosComponent
|
||||
_dependsOn: DependsOn
|
||||
let DEPENDS_ON = _dependsOn
|
||||
metadata: name: string
|
||||
#namelen: len(metadata.name) & >=1
|
||||
let Name = metadata.name
|
||||
|
||||
// TODO: ksContent needs to be component scoped, not instance scoped.
|
||||
ksContent: yaml.Marshal(#Kustomization & {
|
||||
_dependsOn: DEPENDS_ON
|
||||
metadata: name: Name
|
||||
})
|
||||
// Leave the HolosComponent open for components with additional fields like HelmChart.
|
||||
// Refer to https://cuelang.org/docs/tour/types/closed/
|
||||
...
|
||||
}
|
||||
|
||||
//#KustomizeFiles represents resources for holos to write into files for kustomize post-processing.
|
||||
#KustomizeFiles: {
|
||||
// Objects collects files for Holos to write for kustomize post-processing.
|
||||
Objects: "kustomization.yaml": #Kustomize
|
||||
// Files holds the marshaled output of Objects holos writes to the filesystem before calling the kustomize post-processor.
|
||||
Files: {
|
||||
for filename, obj in Objects {
|
||||
"\(filename)": yaml.Marshal(obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Holos component types.
|
||||
#HelmChart: #HolosComponent & h.#HelmChart
|
||||
#HelmChart: #HolosComponent & h.#HelmChart & {
|
||||
_values: {...}
|
||||
_kustomizeFiles: #KustomizeFiles
|
||||
|
||||
// Render the values to yaml for holos to provide to helm.
|
||||
valuesContent: yaml.Marshal(_values)
|
||||
// Kustomize post-processor
|
||||
// resources is the intermediate file name for api objects.
|
||||
resourcesFile: h.#ResourcesFile
|
||||
// kustomizeFiles represents the files in a kustomize directory tree.
|
||||
kustomizeFiles: _kustomizeFiles.Files
|
||||
|
||||
chart: h.#Chart & {
|
||||
name: string
|
||||
release: string | *name
|
||||
}
|
||||
}
|
||||
#KubernetesObjects: #HolosComponent & h.#KubernetesObjects
|
||||
#KustomizeBuild: #HolosComponent & h.#KustomizeBuild
|
||||
|
||||
@@ -35,7 +73,7 @@ import (
|
||||
|
||||
// Flux Kustomization CRDs
|
||||
#Kustomization: #NamespaceObject & ksv1.#Kustomization & {
|
||||
_dependsOn: [Name=_]: name: string & Name
|
||||
_dependsOn: DependsOn
|
||||
|
||||
metadata: {
|
||||
name: string
|
||||
@@ -61,3 +99,19 @@ import (
|
||||
dependsOn: [for k, v in _dependsOn {v}, ...]
|
||||
}
|
||||
}
|
||||
|
||||
// #Kustomize represents the kustomize post processor.
|
||||
#Kustomize: kc.#Kustomization & {
|
||||
_patches: {[_]: kc.#Patch}
|
||||
apiVersion: "kustomize.config.k8s.io/v1beta1"
|
||||
kind: "Kustomization"
|
||||
// resources are file names holos will use to store intermediate component output for kustomize to post-process (i.e. helm template | kubectl kustomize)
|
||||
// See the related resourcesFile field of the holos component.
|
||||
resources: [h.#ResourcesFile]
|
||||
if len(_patches) > 0 {
|
||||
patches: [for v in _patches {v}]
|
||||
}
|
||||
}
|
||||
|
||||
// So components don't need to import the package.
|
||||
#Patch: kc.#Patch
|
||||
|
||||
@@ -20,7 +20,17 @@ let SecretNames = {
|
||||
},
|
||||
]
|
||||
|
||||
#KubernetesObjects & {
|
||||
spec: components: KubernetesObjectsList: [
|
||||
#KubernetesObjects & {
|
||||
metadata: name: "prod-iam-postgres-certs"
|
||||
|
||||
_dependsOn: "prod-secrets-stores": _
|
||||
|
||||
apiObjectMap: OBJECTS.apiObjectMap
|
||||
},
|
||||
]
|
||||
|
||||
let OBJECTS = #APIObjects & {
|
||||
apiObjects: {
|
||||
for s in SecretNames {
|
||||
ExternalSecret: "\(s.name)": _
|
||||
|
||||
@@ -33,7 +33,17 @@ let RestoreOptions = []
|
||||
},
|
||||
]
|
||||
|
||||
#KubernetesObjects & {
|
||||
spec: components: KubernetesObjectsList: [
|
||||
#KubernetesObjects & {
|
||||
metadata: name: "prod-iam-postgres"
|
||||
|
||||
_dependsOn: "prod-secrets-namespaces": _
|
||||
_dependsOn: "prod-iam-postgres-certs": _
|
||||
apiObjectMap: OBJECTS.apiObjectMap
|
||||
},
|
||||
]
|
||||
|
||||
let OBJECTS = #APIObjects & {
|
||||
apiObjects: {
|
||||
ExternalSecret: "\(S3Secret)": _
|
||||
PostgresCluster: db: #PostgresCluster & HighlyAvailable & {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package holos
|
||||
|
||||
#InstancePrefix: "prod-iam"
|
||||
#TargetNamespace: #InstancePrefix + "-zitadel"
|
||||
|
||||
// _DBName is the database name used across multiple holos components in this project
|
||||
|
||||
@@ -4,50 +4,30 @@ import "encoding/yaml"
|
||||
|
||||
let Name = "zitadel"
|
||||
#InputKeys: component: Name
|
||||
#DependsOn: postgres: _
|
||||
|
||||
// Upstream helm chart doesn't specify the namespace field for all resources.
|
||||
#Kustomization: spec: {
|
||||
targetNamespace: #TargetNamespace
|
||||
wait: false
|
||||
}
|
||||
spec: components: HelmChartList: [
|
||||
#HelmChart & {
|
||||
metadata: name: "\(#InstancePrefix)-zitadel"
|
||||
|
||||
if #IsPrimaryCluster == true {
|
||||
#Kustomization: spec: healthChecks: [
|
||||
{
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
name: Name
|
||||
namespace: #TargetNamespace
|
||||
},
|
||||
{
|
||||
apiVersion: "batch/v1"
|
||||
kind: "Job"
|
||||
name: "\(Name)-init"
|
||||
namespace: #TargetNamespace
|
||||
},
|
||||
{
|
||||
apiVersion: "batch/v1"
|
||||
kind: "Job"
|
||||
name: "\(Name)-setup"
|
||||
namespace: #TargetNamespace
|
||||
},
|
||||
]
|
||||
}
|
||||
_dependsOn: "prod-secrets-stores": _
|
||||
_dependsOn: "\(#InstancePrefix)-postgres": _
|
||||
|
||||
#HelmChart & {
|
||||
namespace: #TargetNamespace
|
||||
enableHooks: true
|
||||
chart: {
|
||||
name: Name
|
||||
version: "7.9.0"
|
||||
repository: {
|
||||
name: Name
|
||||
url: "https://charts.zitadel.com"
|
||||
namespace: #TargetNamespace
|
||||
enableHooks: true
|
||||
chart: {
|
||||
name: Name
|
||||
version: "7.9.0"
|
||||
repository: {
|
||||
name: Name
|
||||
url: "https://charts.zitadel.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
values: #Values
|
||||
_values: #Values
|
||||
apiObjectMap: OBJECTS.apiObjectMap
|
||||
},
|
||||
]
|
||||
|
||||
let OBJECTS = #APIObjects & {
|
||||
apiObjects: {
|
||||
ExternalSecret: "zitadel-masterkey": _
|
||||
VirtualService: "\(Name)": {
|
||||
@@ -97,7 +77,7 @@ let CAPatch = #Patch & {
|
||||
patch: yaml.Marshal(DatabaseCACertPatch)
|
||||
}
|
||||
|
||||
#KustomizePatches: {
|
||||
#Kustomize: _patches: {
|
||||
mesh: {
|
||||
target: {
|
||||
group: "apps"
|
||||
@@ -162,3 +142,32 @@ let CAPatch = #Patch & {
|
||||
}
|
||||
|
||||
let DisableFluxPatch = [{op: "replace", path: "/metadata/annotations/kustomize.toolkit.fluxcd.io~1reconcile", value: "disabled"}]
|
||||
|
||||
// Upstream helm chart doesn't specify the namespace field for all resources.
|
||||
#Kustomization: spec: {
|
||||
targetNamespace: #TargetNamespace
|
||||
wait: false
|
||||
}
|
||||
|
||||
if #IsPrimaryCluster == true {
|
||||
#Kustomization: spec: healthChecks: [
|
||||
{
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
name: Name
|
||||
namespace: #TargetNamespace
|
||||
},
|
||||
{
|
||||
apiVersion: "batch/v1"
|
||||
kind: "Job"
|
||||
name: "\(Name)-init"
|
||||
namespace: #TargetNamespace
|
||||
},
|
||||
{
|
||||
apiVersion: "batch/v1"
|
||||
kind: "Job"
|
||||
name: "\(Name)-setup"
|
||||
namespace: #TargetNamespace
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,32 +9,43 @@ let GitHubConfigSecret = "controller-manager"
|
||||
// Just sync the external secret, don't configure the scale set
|
||||
// Work around https://github.com/actions/actions-runner-controller/issues/3351
|
||||
if #IsPrimaryCluster == false {
|
||||
#KubernetesObjects & {
|
||||
apiObjects: ExternalSecret: "\(GitHubConfigSecret)": _
|
||||
}
|
||||
spec: components: KubernetesObjectsList: [
|
||||
#KubernetesObjects & {
|
||||
metadata: name: "prod-github-arc-runner"
|
||||
_dependsOn: "prod-secrets-namespaces": _
|
||||
|
||||
apiObjectMap: (#APIObjects & {
|
||||
apiObjects: ExternalSecret: "\(GitHubConfigSecret)": _
|
||||
}).apiObjectMap
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
// Put the scale set on the primary cluster.
|
||||
if #IsPrimaryCluster == true {
|
||||
#HelmChart & {
|
||||
values: {
|
||||
#Values
|
||||
controllerServiceAccount: name: "gha-rs-controller"
|
||||
controllerServiceAccount: namespace: "arc-system"
|
||||
githubConfigSecret: GitHubConfigSecret
|
||||
githubConfigUrl: "https://github.com/" + #Platform.org.github.orgs.primary.name
|
||||
}
|
||||
apiObjects: ExternalSecret: "\(values.githubConfigSecret)": _
|
||||
chart: {
|
||||
// Match the gha-base-name in the chart _helpers.tpl to avoid long full names.
|
||||
// NOTE: Unfortunately the INSTALLATION_NAME is used as the helm release
|
||||
// name and GitHub removed support for runner labels, so the only way to
|
||||
// specify which runner a workflow runs on is using this helm release name.
|
||||
// The quote is "Update the INSTALLATION_NAME value carefully. You will use
|
||||
// the installation name as the value of runs-on in your workflows." Refer to
|
||||
// https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners-with-actions-runner-controller/quickstart-for-actions-runner-controller
|
||||
release: "gha-rs"
|
||||
name: "oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set"
|
||||
}
|
||||
}
|
||||
spec: components: HelmChartList: [
|
||||
#HelmChart & {
|
||||
_dependsOn: "prod-secrets-namespaces": _
|
||||
metadata: name: "prod-github-arc-runner"
|
||||
_values: {
|
||||
#Values
|
||||
controllerServiceAccount: name: "gha-rs-controller"
|
||||
controllerServiceAccount: namespace: "arc-system"
|
||||
githubConfigSecret: GitHubConfigSecret
|
||||
githubConfigUrl: "https://github.com/" + #Platform.org.github.orgs.primary.name
|
||||
}
|
||||
apiObjectMap: (#APIObjects & {apiObjects: ExternalSecret: "\(_values.githubConfigSecret)": _}).apiObjectMap
|
||||
chart: {
|
||||
// Match the gha-base-name in the chart _helpers.tpl to avoid long full names.
|
||||
// NOTE: Unfortunately the INSTALLATION_NAME is used as the helm release
|
||||
// name and GitHub removed support for runner labels, so the only way to
|
||||
// specify which runner a workflow runs on is using this helm release name.
|
||||
// The quote is "Update the INSTALLATION_NAME value carefully. You will use
|
||||
// the installation name as the value of runs-on in your workflows." Refer to
|
||||
// https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners-with-actions-runner-controller/quickstart-for-actions-runner-controller
|
||||
release: "gha-rs"
|
||||
name: "oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set"
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,13 +3,18 @@ package holos
|
||||
#TargetNamespace: #ARCSystemNamespace
|
||||
#InputKeys: component: "arc-system"
|
||||
|
||||
#HelmChart & {
|
||||
values: #Values & #DefaultSecurityContext
|
||||
namespace: #TargetNamespace
|
||||
chart: {
|
||||
// Match the gha-base-name in the chart _helpers.tpl to avoid long full names.
|
||||
release: "gha-rs-controller"
|
||||
name: "oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller"
|
||||
version: "0.8.3"
|
||||
}
|
||||
}
|
||||
spec: components: HelmChartList: [
|
||||
#HelmChart & {
|
||||
metadata: name: "prod-github-arc-system"
|
||||
|
||||
_dependsOn: "prod-secrets-namespaces": _
|
||||
_values: #Values & #DefaultSecurityContext
|
||||
namespace: #TargetNamespace
|
||||
chart: {
|
||||
// Match the gha-base-name in the chart _helpers.tpl to avoid long full names.
|
||||
release: "gha-rs-controller"
|
||||
name: "oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller"
|
||||
version: "0.8.3"
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
@@ -2,7 +2,7 @@ package holos
|
||||
|
||||
import "list"
|
||||
|
||||
spec: components: KubernetesObjects: [
|
||||
spec: components: KubernetesObjectsList: [
|
||||
#KubernetesObjects & {
|
||||
metadata: name: "prod-secrets-namespaces"
|
||||
apiObjectMap: (#APIObjects & {
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
package holos
|
||||
|
||||
#InputKeys: component: "istio-base"
|
||||
#TargetNamespace: "istio-system"
|
||||
spec: components: HelmChartList: [
|
||||
#HelmChart & {
|
||||
_dependsOn: "prod-secrets-namespaces": _
|
||||
|
||||
#HelmChart & {
|
||||
namespace: #TargetNamespace
|
||||
chart: {
|
||||
name: "base"
|
||||
version: "1.20.3"
|
||||
repository: {
|
||||
name: "istio"
|
||||
url: "https://istio-release.storage.googleapis.com/charts"
|
||||
metadata: name: "prod-mesh-istio-base"
|
||||
namespace: "istio-system"
|
||||
chart: {
|
||||
name: "base"
|
||||
version: "1.20.3"
|
||||
repository: {
|
||||
name: "istio"
|
||||
url: "https://istio-release.storage.googleapis.com/charts"
|
||||
}
|
||||
}
|
||||
}
|
||||
values: #IstioValues
|
||||
}
|
||||
_values: #IstioValues
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package holos
|
||||
|
||||
#InputKeys: component: "cni"
|
||||
#TargetNamespace: "kube-system"
|
||||
spec: components: HelmChartList: [
|
||||
#HelmChart & {
|
||||
_dependsOn: "prod-secrets-namespaces": _
|
||||
_dependsOn: "prod-mesh-istio-base": _
|
||||
|
||||
#HelmChart & {
|
||||
namespace: #TargetNamespace
|
||||
chart: name: "cni"
|
||||
values: #IstioValues
|
||||
}
|
||||
_values: #IstioValues
|
||||
metadata: name: "\(#InstancePrefix)-\(chart.name)"
|
||||
namespace: "kube-system"
|
||||
chart: name: "cni"
|
||||
},
|
||||
]
|
||||
|
||||
@@ -4,15 +4,23 @@ import "list"
|
||||
|
||||
// The primary istio Gateway, named default
|
||||
let Name = "gateway"
|
||||
|
||||
#InputKeys: component: Name
|
||||
|
||||
#TargetNamespace: "istio-ingress"
|
||||
#DependsOn: _IngressGateway
|
||||
|
||||
let LoginCert = #PlatformCerts.login
|
||||
|
||||
#KubernetesObjects & {
|
||||
spec: components: KubernetesObjectsList: [
|
||||
#KubernetesObjects & {
|
||||
_dependsOn: "prod-secrets-namespaces": _
|
||||
_dependsOn: "prod-mesh-istio-base": _
|
||||
_dependsOn: "prod-mesh-ingress": _
|
||||
|
||||
metadata: name: "\(#InstancePrefix)-\(Name)"
|
||||
apiObjectMap: OBJECTS.apiObjectMap
|
||||
},
|
||||
]
|
||||
|
||||
let OBJECTS = #APIObjects & {
|
||||
apiObjects: {
|
||||
ExternalSecret: login: #ExternalSecret & {
|
||||
_name: "login"
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
package holos
|
||||
|
||||
let Name = "httpbin"
|
||||
let ComponentName = "\(#InstancePrefix)-\(Name)"
|
||||
|
||||
let SecretName = #InputKeys.cluster + "-" + Name
|
||||
let MatchLabels = {app: Name} & #SelectorLabels
|
||||
let MatchLabels = {
|
||||
app: Name
|
||||
"app.kubernetes.io/instance": ComponentName
|
||||
}
|
||||
let Metadata = {
|
||||
name: Name
|
||||
namespace: #TargetNamespace
|
||||
@@ -12,11 +17,22 @@ let Metadata = {
|
||||
#InputKeys: component: Name
|
||||
|
||||
#TargetNamespace: "istio-ingress"
|
||||
#DependsOn: _IngressGateway
|
||||
|
||||
let Cert = #PlatformCerts[SecretName]
|
||||
|
||||
#KubernetesObjects & {
|
||||
spec: components: KubernetesObjectsList: [
|
||||
#KubernetesObjects & {
|
||||
_dependsOn: "prod-secrets-namespaces": _
|
||||
_dependsOn: "\(#InstancePrefix)-istio-base": _
|
||||
_dependsOn: "\(#InstancePrefix)-ingress": _
|
||||
|
||||
metadata: name: ComponentName
|
||||
|
||||
apiObjectMap: OBJECTS.apiObjectMap
|
||||
},
|
||||
]
|
||||
|
||||
let OBJECTS = #APIObjects & {
|
||||
apiObjects: {
|
||||
ExternalSecret: "\(Cert.spec.secretName)": _
|
||||
Deployment: httpbin: #Deployment & {
|
||||
@@ -24,7 +40,6 @@ let Cert = #PlatformCerts[SecretName]
|
||||
spec: selector: matchLabels: MatchLabels
|
||||
spec: template: {
|
||||
metadata: labels: MatchLabels
|
||||
metadata: labels: #CommonLabels
|
||||
metadata: labels: #IstioSidecar
|
||||
spec: securityContext: seccompProfile: type: "RuntimeDefault"
|
||||
spec: containers: [{
|
||||
@@ -54,7 +69,7 @@ let Cert = #PlatformCerts[SecretName]
|
||||
spec: servers: [
|
||||
{
|
||||
hosts: [for host in Cert.spec.dnsNames {"\(#TargetNamespace)/\(host)"}]
|
||||
port: name: "https-\(#InstanceName)"
|
||||
port: name: "https-\(ComponentName)"
|
||||
port: number: 443
|
||||
port: protocol: "HTTPS"
|
||||
tls: credentialName: Cert.spec.secretName
|
||||
|
||||
@@ -2,50 +2,58 @@ package holos
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
#InputKeys: component: "ingress"
|
||||
#TargetNamespace: "istio-ingress"
|
||||
#DependsOn: _IstioD
|
||||
let ComponentName = "\(#InstancePrefix)-ingress"
|
||||
|
||||
#HelmChart & {
|
||||
chart: name: "gateway"
|
||||
namespace: #TargetNamespace
|
||||
values: #GatewayValues & {
|
||||
// This component expects the load balancer to send the PROXY protocol header.
|
||||
// Refer to: https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.2/guide/service/annotations/#proxy-protocol-v2
|
||||
podAnnotations: "proxy.istio.io/config": json.Marshal(_ProxyProtocol)
|
||||
// TODO This configuration is specific to the OIS Metal NLB, refactor it out to the metal collection.
|
||||
service: {
|
||||
type: "NodePort"
|
||||
annotations: "service.beta.kubernetes.io/aws-load-balancer-proxy-protocol": "*"
|
||||
externalTrafficPolicy: "Local"
|
||||
// Add 30000 to the port to get the Nodeport
|
||||
ports: [
|
||||
{
|
||||
name: "status-port"
|
||||
port: 15021
|
||||
protocol: "TCP"
|
||||
targetPort: 15021
|
||||
nodePort: 30021
|
||||
},
|
||||
{
|
||||
name: "http2"
|
||||
port: 80
|
||||
protocol: "TCP"
|
||||
targetPort: 80
|
||||
nodePort: 30080
|
||||
},
|
||||
{
|
||||
name: "https"
|
||||
port: 443
|
||||
protocol: "TCP"
|
||||
targetPort: 443
|
||||
nodePort: 30443
|
||||
},
|
||||
]
|
||||
#TargetNamespace: "istio-ingress"
|
||||
|
||||
spec: components: HelmChartList: [
|
||||
#HelmChart & {
|
||||
_dependsOn: "prod-secrets-namespaces": _
|
||||
_dependsOn: "\(#InstancePrefix)-istio-base": _
|
||||
_dependsOn: "\(#InstancePrefix)-istiod": _
|
||||
|
||||
metadata: name: ComponentName
|
||||
|
||||
chart: name: "gateway"
|
||||
namespace: #TargetNamespace
|
||||
_values: #GatewayValues & {
|
||||
// This component expects the load balancer to send the PROXY protocol header.
|
||||
// Refer to: https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.2/guide/service/annotations/#proxy-protocol-v2
|
||||
podAnnotations: "proxy.istio.io/config": json.Marshal(_ProxyProtocol)
|
||||
// TODO This configuration is specific to the OIS Metal NLB, refactor it out to the metal collection.
|
||||
service: {
|
||||
type: "NodePort"
|
||||
annotations: "service.beta.kubernetes.io/aws-load-balancer-proxy-protocol": "*"
|
||||
externalTrafficPolicy: "Local"
|
||||
// Add 30000 to the port to get the Nodeport
|
||||
ports: [
|
||||
{
|
||||
name: "status-port"
|
||||
port: 15021
|
||||
protocol: "TCP"
|
||||
targetPort: 15021
|
||||
nodePort: 30021
|
||||
},
|
||||
{
|
||||
name: "http2"
|
||||
port: 80
|
||||
protocol: "TCP"
|
||||
targetPort: 80
|
||||
nodePort: 30080
|
||||
},
|
||||
{
|
||||
name: "https"
|
||||
port: 443
|
||||
protocol: "TCP"
|
||||
targetPort: 443
|
||||
nodePort: 30443
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
apiObjects: _APIObjects
|
||||
}
|
||||
apiObjectMap: OBJECTS.apiObjectMap
|
||||
},
|
||||
]
|
||||
|
||||
_ProxyProtocol: gatewayTopology: proxyProtocol: {}
|
||||
|
||||
@@ -60,36 +68,82 @@ let RedirectMetaName = {
|
||||
namespace: #TargetNamespace
|
||||
}
|
||||
|
||||
// https-redirect
|
||||
_APIObjects: {
|
||||
Gateway: {
|
||||
"\(RedirectMetaName.name)": #Gateway & {
|
||||
metadata: RedirectMetaName
|
||||
spec: selector: GatewayLabels
|
||||
spec: servers: [{
|
||||
port: {
|
||||
number: 80
|
||||
name: "http2"
|
||||
protocol: "HTTP2"
|
||||
}
|
||||
hosts: ["*"]
|
||||
// handled by the VirtualService
|
||||
tls: httpsRedirect: false
|
||||
}]
|
||||
let OBJECTS = #APIObjects & {
|
||||
apiObjects: {
|
||||
Gateway: {
|
||||
"\(RedirectMetaName.name)": #Gateway & {
|
||||
metadata: RedirectMetaName
|
||||
spec: selector: GatewayLabels
|
||||
spec: servers: [{
|
||||
port: {
|
||||
number: 80
|
||||
name: "http2"
|
||||
protocol: "HTTP2"
|
||||
}
|
||||
hosts: ["*"]
|
||||
// handled by the VirtualService
|
||||
tls: httpsRedirect: false
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
VirtualService: {
|
||||
"\(RedirectMetaName.name)": #VirtualService & {
|
||||
metadata: RedirectMetaName
|
||||
spec: hosts: ["*"]
|
||||
spec: gateways: [RedirectMetaName.name]
|
||||
spec: http: [{
|
||||
match: [{withoutHeaders: ":path": prefix: "/.well-known/acme-challenge/"}]
|
||||
redirect: {
|
||||
scheme: "https"
|
||||
redirectCode: 302
|
||||
VirtualService: {
|
||||
"\(RedirectMetaName.name)": #VirtualService & {
|
||||
metadata: RedirectMetaName
|
||||
spec: hosts: ["*"]
|
||||
spec: gateways: [RedirectMetaName.name]
|
||||
spec: http: [{
|
||||
match: [{withoutHeaders: ":path": prefix: "/.well-known/acme-challenge/"}]
|
||||
redirect: {
|
||||
scheme: "https"
|
||||
redirectCode: 302
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
Deployment: {
|
||||
loopback: #Deployment & {
|
||||
_description: LoopbackDescription
|
||||
metadata: LoopbackMetaName
|
||||
spec: {
|
||||
selector: matchLabels: LoopbackLabels
|
||||
template: {
|
||||
metadata: {
|
||||
annotations: "inject.istio.io/templates": "gateway"
|
||||
annotations: #Description & {
|
||||
_Description: LoopbackDescription
|
||||
}
|
||||
labels: LoopbackLabels & {"sidecar.istio.io/inject": "true"}
|
||||
}
|
||||
spec: {
|
||||
serviceAccountName: "istio-ingressgateway"
|
||||
// Allow binding to all ports (such as 80 and 443)
|
||||
securityContext: {
|
||||
runAsNonRoot: true
|
||||
seccompProfile: type: "RuntimeDefault"
|
||||
sysctls: [{name: "net.ipv4.ip_unprivileged_port_start", value: "0"}]
|
||||
}
|
||||
containers: [{
|
||||
name: "istio-proxy"
|
||||
image: "auto" // Managed by istiod
|
||||
securityContext: {
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities: drop: ["ALL"]
|
||||
runAsUser: 1337
|
||||
runAsGroup: 1337
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
Service: {
|
||||
loopback: #Service & {
|
||||
_description: LoopbackDescription
|
||||
metadata: LoopbackMetaName
|
||||
spec: selector: LoopbackLabels
|
||||
spec: ports: [{port: 80, name: "http"}, {port: 443, name: "https"}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,52 +158,3 @@ let LoopbackMetaName = {
|
||||
name: LoopbackName
|
||||
namespace: #TargetNamespace
|
||||
}
|
||||
|
||||
// istio-ingressgateway-loopback
|
||||
_APIObjects: {
|
||||
Deployment: {
|
||||
loopback: #Deployment & {
|
||||
_description: LoopbackDescription
|
||||
metadata: LoopbackMetaName
|
||||
spec: {
|
||||
selector: matchLabels: LoopbackLabels
|
||||
template: {
|
||||
metadata: {
|
||||
annotations: "inject.istio.io/templates": "gateway"
|
||||
annotations: #Description & {
|
||||
_Description: LoopbackDescription
|
||||
}
|
||||
labels: LoopbackLabels & {"sidecar.istio.io/inject": "true"}
|
||||
}
|
||||
spec: {
|
||||
serviceAccountName: "istio-ingressgateway"
|
||||
// Allow binding to all ports (such as 80 and 443)
|
||||
securityContext: {
|
||||
runAsNonRoot: true
|
||||
seccompProfile: type: "RuntimeDefault"
|
||||
sysctls: [{name: "net.ipv4.ip_unprivileged_port_start", value: "0"}]
|
||||
}
|
||||
containers: [{
|
||||
name: "istio-proxy"
|
||||
image: "auto" // Managed by istiod
|
||||
securityContext: {
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities: drop: ["ALL"]
|
||||
runAsUser: 1337
|
||||
runAsGroup: 1337
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Service: {
|
||||
loopback: #Service & {
|
||||
_description: LoopbackDescription
|
||||
metadata: LoopbackMetaName
|
||||
spec: selector: LoopbackLabels
|
||||
spec: ports: [{port: 80, name: "http"}, {port: 443, name: "https"}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package holos
|
||||
|
||||
#DependsOn: _IstioBase
|
||||
|
||||
#HelmChart: {
|
||||
chart: {
|
||||
version: "1.20.3"
|
||||
|
||||
@@ -5,22 +5,28 @@ import "encoding/yaml"
|
||||
#InputKeys: component: "istiod"
|
||||
#TargetNamespace: "istio-system"
|
||||
|
||||
#HelmChart & {
|
||||
namespace: #TargetNamespace
|
||||
chart: {
|
||||
name: "istiod"
|
||||
}
|
||||
values: #IstioValues & {
|
||||
pilot: {
|
||||
// The istio meshconfig ConfigMap is handled in the holos component instead of
|
||||
// the upstream chart so extension providers can be collected from holos data.
|
||||
configMap: false
|
||||
// Set to `type: RuntimeDefault` to use the default profile if available.
|
||||
seccompProfile: type: "RuntimeDefault"
|
||||
spec: components: HelmChartList: [
|
||||
#HelmChart & {
|
||||
_dependsOn: "prod-secrets-namespaces": _
|
||||
_dependsOn: "\(#InstancePrefix)-istio-base": _
|
||||
|
||||
metadata: name: "prod-mesh-istiod"
|
||||
chart: name: "istiod"
|
||||
namespace: #TargetNamespace
|
||||
_values: #IstioValues & {
|
||||
pilot: {
|
||||
// The istio meshconfig ConfigMap is handled in the holos component instead of
|
||||
// the upstream chart so extension providers can be collected from holos data.
|
||||
configMap: false
|
||||
// Set to `type: RuntimeDefault` to use the default profile if available.
|
||||
seccompProfile: type: "RuntimeDefault"
|
||||
}
|
||||
}
|
||||
}
|
||||
apiObjects: ConfigMap: istio: #IstioConfigMap
|
||||
}
|
||||
apiObjectMap: OBJECTS.apiObjectMap
|
||||
},
|
||||
]
|
||||
|
||||
let OBJECTS = #APIObjects & {apiObjects: ConfigMap: istio: #IstioConfigMap}
|
||||
|
||||
#IstioConfigMap: #ConfigMap & {
|
||||
metadata: {
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
package holos
|
||||
|
||||
// Components under this directory are part of this collection
|
||||
#InputKeys: project: "mesh"
|
||||
|
||||
// Shared dependencies for all components in this collection.
|
||||
#DependsOn: _Namespaces
|
||||
|
||||
// Common Dependencies
|
||||
_CertManager: CertManager: name: "\(#InstancePrefix)-certmanager"
|
||||
_Namespaces: Namespaces: name: "\(#StageName)-secrets-namespaces"
|
||||
_IstioBase: IstioBase: name: "\(#InstancePrefix)-istio-base"
|
||||
_IstioD: IstioD: name: "\(#InstancePrefix)-istiod"
|
||||
_IngressGateway: IngressGateway: name: "\(#InstancePrefix)-ingress"
|
||||
#InstancePrefix: "prod-mesh"
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package holos
|
||||
|
||||
#DependsOn: Namespaces: name: "prod-secrets-namespaces"
|
||||
#DependsOn: CRDS: name: "\(#InstancePrefix)-crds"
|
||||
#InputKeys: component: "controller"
|
||||
{} & #KustomizeBuild
|
||||
spec: components: KustomizeBuildList: [
|
||||
#KustomizeBuild & {
|
||||
_dependsOn: "prod-secrets-namespaces": _
|
||||
_dependsOn: "prod-pgo-crds": _
|
||||
|
||||
metadata: name: "prod-pgo-controller"
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package holos
|
||||
|
||||
// Refer to https://github.com/CrunchyData/postgres-operator-examples/tree/main/kustomize/install/crd
|
||||
|
||||
#InputKeys: component: "crds"
|
||||
{} & #KustomizeBuild
|
||||
spec: components: KustomizeBuildList: [
|
||||
#KustomizeBuild & {
|
||||
metadata: name: "prod-pgo-crds"
|
||||
},
|
||||
]
|
||||
|
||||
@@ -2,8 +2,6 @@ package holos
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
#DependsOn: _ESO
|
||||
|
||||
#InputKeys: {
|
||||
project: "secrets"
|
||||
component: "eso-creds-refresher"
|
||||
@@ -11,8 +9,17 @@ import "encoding/json"
|
||||
|
||||
#TargetNamespace: #CredsRefresher.namespace
|
||||
|
||||
// output kubernetes api objects for holos
|
||||
#KubernetesObjects & {
|
||||
spec: components: KubernetesObjectsList: [
|
||||
#KubernetesObjects & {
|
||||
_dependsOn: "prod-secrets-namespaces": _
|
||||
_dependsOn: "prod-secrets-eso": _
|
||||
|
||||
metadata: name: "prod-secrets-eso-creds-refresher"
|
||||
apiObjectMap: OBJECTS.apiObjectMap
|
||||
},
|
||||
]
|
||||
|
||||
let OBJECTS = #APIObjects & {
|
||||
apiObjects: {
|
||||
for obj in #CredsRefresherService.objects {
|
||||
let Kind = obj.kind
|
||||
|
||||
@@ -3,26 +3,22 @@ package holos
|
||||
// Manages the External Secrets Operator from the official upstream Helm chart.
|
||||
|
||||
#TargetNamespace: "external-secrets"
|
||||
|
||||
#InputKeys: component: "eso"
|
||||
|
||||
#InputKeys: {
|
||||
project: "secrets"
|
||||
service: "eso"
|
||||
}
|
||||
|
||||
#Kustomization: spec: targetNamespace: #TargetNamespace
|
||||
#DependsOn: Namespaces: name: #InstancePrefix + "-namespaces"
|
||||
|
||||
#HelmChart & {
|
||||
values: installCrds: true
|
||||
namespace: #TargetNamespace
|
||||
chart: {
|
||||
name: "external-secrets"
|
||||
version: "0.9.12"
|
||||
repository: {
|
||||
name: "external-secrets"
|
||||
url: "https://charts.external-secrets.io"
|
||||
spec: components: HelmChartList: [
|
||||
#HelmChart & {
|
||||
_dependsOn: "prod-secrets-namespaces": _
|
||||
|
||||
metadata: name: "prod-secrets-eso"
|
||||
namespace: #TargetNamespace
|
||||
chart: {
|
||||
name: "external-secrets"
|
||||
version: "0.9.12"
|
||||
repository: {
|
||||
name: "external-secrets"
|
||||
url: "https://charts.external-secrets.io"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_values: installCrds: true
|
||||
},
|
||||
]
|
||||
|
||||
@@ -2,11 +2,3 @@ package holos
|
||||
|
||||
// Components under this directory are part of this collection
|
||||
#InputKeys: project: "secrets"
|
||||
|
||||
// Shared dependencies for all components in this collection.
|
||||
#DependsOn: _Namespaces
|
||||
|
||||
// Common Dependencies
|
||||
_Namespaces: Namespaces: name: "\(#StageName)-secrets-namespaces"
|
||||
_ESO: ESO: name: "\(#InstancePrefix)-eso"
|
||||
_ESOCreds: ESOCreds: name: "\(#InstancePrefix)-eso-creds-refresher"
|
||||
|
||||
@@ -2,27 +2,19 @@ package holos
|
||||
|
||||
import "list"
|
||||
|
||||
#DependsOn: _ESOCreds
|
||||
|
||||
#TargetNamespace: "default"
|
||||
|
||||
#InputKeys: {
|
||||
project: "secrets"
|
||||
component: "stores"
|
||||
}
|
||||
spec: components: KubernetesObjectsList: [
|
||||
#KubernetesObjects & {
|
||||
_dependsOn: "prod-secrets-namespaces": _
|
||||
_dependsOn: "prod-secrets-eso-creds-refresher": _
|
||||
|
||||
// #PlatformNamespaceObjects defines the api objects necessary for eso SecretStores in external clusters to access secrets in a given namespace in the provisioner cluster.
|
||||
#PlatformNamespaceObjects: {
|
||||
_ns: #PlatformNamespace
|
||||
metadata: name: "prod-secrets-stores"
|
||||
apiObjectMap: OBJECTS.apiObjectMap
|
||||
},
|
||||
]
|
||||
|
||||
objects: [
|
||||
#SecretStore & {
|
||||
_namespace: _ns.name
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
#KubernetesObjects & {
|
||||
let OBJECTS = #APIObjects & {
|
||||
apiObjects: {
|
||||
for ns in #PlatformNamespaces {
|
||||
for obj in (#PlatformNamespaceObjects & {_ns: ns}).objects {
|
||||
@@ -41,3 +33,14 @@ import "list"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #PlatformNamespaceObjects defines the api objects necessary for eso SecretStores in external clusters to access secrets in a given namespace in the provisioner cluster.
|
||||
#PlatformNamespaceObjects: {
|
||||
_ns: #PlatformNamespace
|
||||
|
||||
objects: [
|
||||
#SecretStore & {
|
||||
_namespace: _ns.name
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -4,14 +4,16 @@ package holos
|
||||
|
||||
#TargetNamespace: "holos-system"
|
||||
|
||||
#InputKeys: {
|
||||
project: "secrets"
|
||||
component: "validate"
|
||||
}
|
||||
spec: components: KubernetesObjectsList: [
|
||||
#KubernetesObjects & {
|
||||
_dependsOn: "prod-secrets-stores": _
|
||||
|
||||
#DependsOn: _ESO
|
||||
metadata: name: "prod-secrets-validate"
|
||||
apiObjectMap: OBJECTS.apiObjectMap
|
||||
},
|
||||
]
|
||||
|
||||
#KubernetesObjects & {
|
||||
let OBJECTS = #APIObjects & {
|
||||
apiObjects: {
|
||||
ExternalSecret: validate: #ExternalSecret & {
|
||||
_name: "validate"
|
||||
|
||||
@@ -6,29 +6,30 @@ package holos
|
||||
|
||||
#SecretName: "\(#ClusterName)-ceph-csi-rbd"
|
||||
|
||||
#InputKeys: {
|
||||
project: "metal"
|
||||
service: "ceph"
|
||||
component: "ceph"
|
||||
}
|
||||
#Kustomization: spec: targetNamespace: "ceph-system"
|
||||
|
||||
#Kustomization: spec: targetNamespace: #TargetNamespace
|
||||
#DependsOn: Namespaces: name: "\(#StageName)-secrets-namespaces"
|
||||
spec: components: HelmChartList: [
|
||||
#HelmChart & {
|
||||
_dependsOn: "prod-secrets-namespaces": _
|
||||
|
||||
#HelmChart & {
|
||||
namespace: #TargetNamespace
|
||||
chart: {
|
||||
name: "ceph-csi-rbd"
|
||||
version: "3.10.2"
|
||||
repository: {
|
||||
name: "ceph-csi"
|
||||
url: "https://ceph.github.io/csi-charts"
|
||||
metadata: name: "prod-metal-ceph"
|
||||
|
||||
namespace: #TargetNamespace
|
||||
chart: {
|
||||
name: "ceph-csi-rbd"
|
||||
version: "3.10.2"
|
||||
repository: {
|
||||
name: "ceph-csi"
|
||||
url: "https://ceph.github.io/csi-charts"
|
||||
}
|
||||
}
|
||||
}
|
||||
_values: #ChartValues
|
||||
apiObjectMap: OBJECTS.apiObjectMap
|
||||
},
|
||||
]
|
||||
|
||||
let OBJECTS = #APIObjects & {
|
||||
apiObjects: {
|
||||
ExternalSecret: "\(#SecretName)": #ExternalSecret & {
|
||||
_name: #SecretName
|
||||
}
|
||||
ExternalSecret: "\(#SecretName)": _
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,46 +5,31 @@ import "encoding/yaml"
|
||||
import "list"
|
||||
|
||||
let Name = "vault"
|
||||
#InputKeys: component: Name
|
||||
#InputKeys: project: "core"
|
||||
#TargetNamespace: "\(#InstancePrefix)-\(Name)"
|
||||
#TargetNamespace: "prod-core-\(Name)"
|
||||
|
||||
let Vault = #OptionalServices[Name]
|
||||
|
||||
if Vault.enabled && list.Contains(Vault.clusterNames, #ClusterName) {
|
||||
#HelmChart & {
|
||||
namespace: #TargetNamespace
|
||||
chart: {
|
||||
name: Name
|
||||
version: "0.25.0"
|
||||
repository: {
|
||||
name: "hashicorp"
|
||||
url: "https://helm.releases.hashicorp.com"
|
||||
}
|
||||
}
|
||||
values: #Values
|
||||
#Kustomization: spec: wait: true
|
||||
|
||||
apiObjects: {
|
||||
ExternalSecret: "gcpkms-creds": _
|
||||
ExternalSecret: "vault-server-cert": _
|
||||
VirtualService: "\(Name)": {
|
||||
metadata: name: Name
|
||||
metadata: namespace: #TargetNamespace
|
||||
spec: hosts: [for cert in Vault.certs {cert.spec.commonName}]
|
||||
spec: gateways: ["istio-ingress/\(Name)"]
|
||||
spec: http: [
|
||||
{
|
||||
route: [
|
||||
{
|
||||
destination: host: "\(Name)-active"
|
||||
destination: port: number: 8200
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
if Vault.enabled && list.Contains(Vault.clusterNames, #ClusterName) {
|
||||
spec: components: HelmChartList: [
|
||||
#HelmChart & {
|
||||
metadata: name: "prod-core-\(Name)"
|
||||
|
||||
namespace: #TargetNamespace
|
||||
chart: {
|
||||
name: Name
|
||||
version: "0.25.0"
|
||||
repository: {
|
||||
name: "hashicorp"
|
||||
url: "https://helm.releases.hashicorp.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_values: #Values
|
||||
apiObjectMap: OBJECTS.apiObjectMap
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
#Kustomize: {
|
||||
patches: [
|
||||
@@ -59,17 +44,40 @@ if Vault.enabled && list.Contains(Vault.clusterNames, #ClusterName) {
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
let EnvPatch = [
|
||||
{
|
||||
op: "test"
|
||||
path: "/spec/template/spec/containers/0/env/4/name"
|
||||
value: "VAULT_ADDR"
|
||||
},
|
||||
{
|
||||
op: "replace"
|
||||
path: "/spec/template/spec/containers/0/env/4/value"
|
||||
value: "http://$(VAULT_K8S_POD_NAME):8200"
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
let EnvPatch = [
|
||||
{
|
||||
op: "test"
|
||||
path: "/spec/template/spec/containers/0/env/4/name"
|
||||
value: "VAULT_ADDR"
|
||||
},
|
||||
{
|
||||
op: "replace"
|
||||
path: "/spec/template/spec/containers/0/env/4/value"
|
||||
value: "http://$(VAULT_K8S_POD_NAME):8200"
|
||||
},
|
||||
]
|
||||
|
||||
let OBJECTS = #APIObjects & {
|
||||
apiObjects: {
|
||||
ExternalSecret: "gcpkms-creds": _
|
||||
ExternalSecret: "vault-server-cert": _
|
||||
VirtualService: "\(Name)": {
|
||||
metadata: name: Name
|
||||
metadata: namespace: #TargetNamespace
|
||||
spec: hosts: [for cert in Vault.certs {cert.spec.commonName}]
|
||||
spec: gateways: ["istio-ingress/\(Name)"]
|
||||
spec: http: [
|
||||
{
|
||||
route: [
|
||||
{
|
||||
destination: host: "\(Name)-active"
|
||||
destination: port: number: 8200
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
31
docs/examples/platforms/reference/clusters/projects.cue
Normal file
31
docs/examples/platforms/reference/clusters/projects.cue
Normal file
@@ -0,0 +1,31 @@
|
||||
package holos
|
||||
|
||||
_Projects: #Projects & {
|
||||
holos: {
|
||||
clusters: {
|
||||
k1: _
|
||||
k2: _
|
||||
}
|
||||
environments: {
|
||||
prod: stage: "prod"
|
||||
dev: stage: "dev"
|
||||
jeff: stage: dev.stage
|
||||
gary: stage: dev.stage
|
||||
nate: stage: dev.stage
|
||||
}
|
||||
}
|
||||
|
||||
iam: {
|
||||
clusters: {
|
||||
core1: _
|
||||
core2: _
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Manage namespaces for platform project environments.
|
||||
for project in _Projects {
|
||||
for ns in project.managedNamespaces {
|
||||
#ManagedNamespaces: (ns.namespace.metadata.name): ns
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
package holos
|
||||
|
||||
#InputKeys: project: "projects"
|
||||
@@ -2,9 +2,3 @@ package holos
|
||||
|
||||
// Components under this directory are part of this collection
|
||||
#InputKeys: project: "iam"
|
||||
|
||||
// Shared dependencies for all components in this collection.
|
||||
#DependsOn: _Namespaces
|
||||
|
||||
// Common Dependencies
|
||||
_Namespaces: Namespaces: name: "\(#StageName)-secrets-namespaces"
|
||||
|
||||
@@ -8,13 +8,27 @@ package holos
|
||||
|
||||
// Refer to [Using Cert Manager to Deploy TLS for Postgres on Kubernetes](https://www.crunchydata.com/blog/using-cert-manager-to-deploy-tls-for-postgres-on-kubernetes)
|
||||
|
||||
#TargetNamespace: "prod-iam-zitadel"
|
||||
#InputKeys: component: "postgres-certs"
|
||||
|
||||
let SelfSigned = "\(_DBName)-selfsigned"
|
||||
let RootCA = "\(_DBName)-root-ca"
|
||||
let DBName = "zitadel"
|
||||
|
||||
let SelfSigned = "\(DBName)-selfsigned"
|
||||
let RootCA = "\(DBName)-root-ca"
|
||||
let Orgs = ["Database"]
|
||||
|
||||
#KubernetesObjects & {
|
||||
#Kustomization: spec: wait: true
|
||||
|
||||
spec: components: KubernetesObjectsList: [
|
||||
#KubernetesObjects & {
|
||||
metadata: name: "prod-iam-postgres-certs"
|
||||
|
||||
_dependsOn: "prod-secrets-namespaces": _
|
||||
apiObjectMap: OBJECTS.apiObjectMap
|
||||
},
|
||||
]
|
||||
|
||||
let OBJECTS = #APIObjects & {
|
||||
apiObjects: {
|
||||
// Put everything in the target namespace.
|
||||
[_]: {
|
||||
@@ -51,10 +65,10 @@ let Orgs = ["Database"]
|
||||
subject: organizations: Orgs
|
||||
}
|
||||
}
|
||||
"\(_DBName)-primary-tls": #DatabaseCert & {
|
||||
"\(DBName)-primary-tls": #DatabaseCert & {
|
||||
// PGO managed name is "<cluster name>-cluster-cert" e.g. zitadel-cluster-cert
|
||||
spec: {
|
||||
commonName: "\(_DBName)-primary"
|
||||
commonName: "\(DBName)-primary"
|
||||
dnsNames: [
|
||||
commonName,
|
||||
"\(commonName).\(#TargetNamespace)",
|
||||
@@ -66,16 +80,16 @@ let Orgs = ["Database"]
|
||||
usages: ["digital signature", "key encipherment"]
|
||||
}
|
||||
}
|
||||
"\(_DBName)-repl-tls": #DatabaseCert & {
|
||||
"\(DBName)-repl-tls": #DatabaseCert & {
|
||||
spec: {
|
||||
commonName: "_crunchyrepl"
|
||||
dnsNames: [commonName]
|
||||
usages: ["digital signature", "key encipherment"]
|
||||
}
|
||||
}
|
||||
"\(_DBName)-client-tls": #DatabaseCert & {
|
||||
"\(DBName)-client-tls": #DatabaseCert & {
|
||||
spec: {
|
||||
commonName: "\(_DBName)-client"
|
||||
commonName: "\(DBName)-client"
|
||||
dnsNames: [commonName]
|
||||
usages: ["digital signature", "key encipherment"]
|
||||
}
|
||||
|
||||
@@ -1,6 +1 @@
|
||||
package holos
|
||||
|
||||
#TargetNamespace: #InstancePrefix + "-zitadel"
|
||||
|
||||
// _DBName is the database name used across multiple holos components in this project
|
||||
_DBName: "zitadel"
|
||||
|
||||
@@ -1,20 +1,35 @@
|
||||
package holos
|
||||
|
||||
// Provision all platform certificates.
|
||||
#InputKeys: component: "certificates"
|
||||
|
||||
// Certificates usually go into the istio-system namespace, but they may go anywhere.
|
||||
#TargetNamespace: "default"
|
||||
|
||||
// Depends on issuers
|
||||
#DependsOn: _LetsEncrypt
|
||||
#Kustomization: spec: wait: true
|
||||
|
||||
#KubernetesObjects & {
|
||||
spec: components: KubernetesObjectsList: [
|
||||
#KubernetesObjects & {
|
||||
metadata: name: "\(#InstancePrefix)-certificates"
|
||||
|
||||
_dependsOn: "prod-secrets-namespaces": _
|
||||
_dependsOn: "prod-mesh-letsencrypt": _
|
||||
|
||||
apiObjectMap: OBJECTS.apiObjectMap
|
||||
},
|
||||
]
|
||||
|
||||
let Vault = #OptionalServices.vault
|
||||
|
||||
let OBJECTS = #APIObjects & {
|
||||
apiObjects: {
|
||||
for k, obj in #PlatformCerts {
|
||||
"\(obj.kind)": {
|
||||
"\(obj.metadata.namespace)/\(obj.metadata.name)": obj
|
||||
}
|
||||
}
|
||||
|
||||
if Vault.enabled {
|
||||
for k, obj in Vault.certs {
|
||||
"\(obj.kind)": "\(obj.metadata.name)": obj
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
package holos
|
||||
|
||||
let Vault = #OptionalServices.vault
|
||||
|
||||
if Vault.enabled {
|
||||
#KubernetesObjects & {
|
||||
apiObjects: {
|
||||
for k, obj in Vault.certs {
|
||||
"\(obj.kind)": "\(obj.metadata.name)": obj
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,28 +4,28 @@ package holos
|
||||
|
||||
#TargetNamespace: "cert-manager"
|
||||
|
||||
#InputKeys: {
|
||||
component: "certmanager"
|
||||
service: "cert-manager"
|
||||
}
|
||||
spec: components: HelmChartList: [
|
||||
#HelmChart & {
|
||||
metadata: name: "\(#InstancePrefix)-certmanager"
|
||||
|
||||
#HelmChart & {
|
||||
values: #Values & {
|
||||
installCRDs: true
|
||||
startupapicheck: enabled: false
|
||||
// Must not use kube-system on gke autopilot. GKE Warden authz blocks access.
|
||||
global: leaderElection: namespace: #TargetNamespace
|
||||
}
|
||||
namespace: #TargetNamespace
|
||||
chart: {
|
||||
name: "cert-manager"
|
||||
version: "1.14.3"
|
||||
repository: {
|
||||
name: "jetstack"
|
||||
url: "https://charts.jetstack.io"
|
||||
_dependsOn: "prod-secrets-namespaces": _
|
||||
namespace: #TargetNamespace
|
||||
_values: #Values & {
|
||||
installCRDs: true
|
||||
startupapicheck: enabled: false
|
||||
// Must not use kube-system on gke autopilot. GKE Warden authz blocks access.
|
||||
global: leaderElection: namespace: #TargetNamespace
|
||||
}
|
||||
}
|
||||
}
|
||||
chart: {
|
||||
name: "cert-manager"
|
||||
version: "1.14.3"
|
||||
repository: {
|
||||
name: "jetstack"
|
||||
url: "https://charts.jetstack.io"
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
// https://cloud.google.com/kubernetes-engine/docs/concepts/autopilot-resource-requests#min-max-requests
|
||||
#PodResources: {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package holos
|
||||
|
||||
// Lets Encrypt certificate issuers for public tls certs
|
||||
#InputKeys: component: "letsencrypt"
|
||||
#TargetNamespace: "cert-manager"
|
||||
|
||||
let Name = "letsencrypt"
|
||||
@@ -9,10 +8,17 @@ let Name = "letsencrypt"
|
||||
// The cloudflare api token is platform scoped, not cluster scoped.
|
||||
#SecretName: "cloudflare-api-token-secret"
|
||||
|
||||
// Depends on cert manager
|
||||
#DependsOn: _CertManager
|
||||
spec: components: KubernetesObjectsList: [
|
||||
#KubernetesObjects & {
|
||||
metadata: name: "\(#InstancePrefix)-letsencrypt"
|
||||
|
||||
#KubernetesObjects & {
|
||||
_dependsOn: "prod-secrets-namespaces": _
|
||||
_dependsOn: "\(#InstancePrefix)-certmanager": _
|
||||
apiObjectMap: OBJECTS.apiObjectMap
|
||||
},
|
||||
]
|
||||
|
||||
let OBJECTS = #APIObjects & {
|
||||
apiObjects: {
|
||||
ClusterIssuer: {
|
||||
letsencrypt: #ClusterIssuer & {
|
||||
|
||||
@@ -1,13 +1,3 @@
|
||||
package holos
|
||||
|
||||
// Components under this directory are part of this collection
|
||||
#InputKeys: project: "mesh"
|
||||
|
||||
// Shared dependencies for all components in this collection.
|
||||
#DependsOn: _Namespaces
|
||||
|
||||
// Common Dependencies
|
||||
_Namespaces: Namespaces: name: "\(#StageName)-secrets-namespaces"
|
||||
_CertManager: CertManager: name: "\(#InstancePrefix)-certmanager"
|
||||
_LetsEncrypt: LetsEncrypt: name: "\(#InstancePrefix)-letsencrypt"
|
||||
_Certificates: Certificates: name: "\(#InstancePrefix)-certificates"
|
||||
#InstancePrefix: "prod-mesh"
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package holos
|
||||
|
||||
for Project in _Projects {
|
||||
spec: components: resources: (#ProjectTemplate & {project: Project}).provisioner.resources
|
||||
}
|
||||
@@ -8,10 +8,15 @@ package holos
|
||||
// - Namespace
|
||||
// - ServiceAccount eso-reader, eso-writer
|
||||
|
||||
// No flux kustomization
|
||||
ksObjects: []
|
||||
spec: components: KubernetesObjectsList: [
|
||||
#KubernetesObjects & {
|
||||
metadata: name: "prod-secrets-eso-creds-refresher"
|
||||
|
||||
#KubernetesObjects & {
|
||||
apiObjectMap: OBJECTS.apiObjectMap
|
||||
},
|
||||
]
|
||||
|
||||
let OBJECTS = #APIObjects & {
|
||||
apiObjects: {
|
||||
let role = #CredsRefresherIAM.role
|
||||
let binding = #CredsRefresherIAM.binding
|
||||
@@ -35,12 +40,6 @@ ksObjects: []
|
||||
}
|
||||
}
|
||||
|
||||
#InputKeys: {
|
||||
cluster: "provisioner"
|
||||
project: "secrets"
|
||||
component: "eso-creds-refresher"
|
||||
}
|
||||
|
||||
// #CredsRefresherIAM defines the rbac policy for the job that refreshes credentials used by eso SecretStore resources in clusters other than the provisioner cluster.
|
||||
#CredsRefresherIAM: {
|
||||
let _name = #CredsRefresher.name
|
||||
|
||||
@@ -2,12 +2,15 @@ package holos
|
||||
|
||||
#TargetNamespace: "default"
|
||||
|
||||
#InputKeys: {
|
||||
project: "secrets"
|
||||
component: "namespaces"
|
||||
}
|
||||
spec: components: KubernetesObjectsList: [
|
||||
#KubernetesObjects & {
|
||||
metadata: name: "prod-secrets-namespaces"
|
||||
|
||||
#KubernetesObjects & {
|
||||
apiObjectMap: OBJECTS.apiObjectMap
|
||||
},
|
||||
]
|
||||
|
||||
let OBJECTS = #APIObjects & {
|
||||
apiObjects: {
|
||||
// #ManagedNamespaces is the set of all namespaces across all clusters in the platform.
|
||||
for nsName, ns in #ManagedNamespaces {
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package holos
|
||||
|
||||
for Project in _Projects {
|
||||
spec: components: resources: (#ProjectTemplate & {project: Project}).workload.resources
|
||||
}
|
||||
180
docs/examples/platforms/reference/platform_projects.cue
Normal file
180
docs/examples/platforms/reference/platform_projects.cue
Normal file
@@ -0,0 +1,180 @@
|
||||
package holos
|
||||
|
||||
import "strings"
|
||||
|
||||
// Platform level definition of a project.
|
||||
#Project: {
|
||||
name: string
|
||||
// All projects have at least a prod environment and stage.
|
||||
environments: prod: stage: "prod"
|
||||
environments: prod: dnsSegments: []
|
||||
stages: prod: _
|
||||
stages: dev: _
|
||||
// Short hostnames to construct fqdns.
|
||||
hosts: (name): _
|
||||
}
|
||||
|
||||
#ProjectTemplate: {
|
||||
project: #Project
|
||||
|
||||
// ExtAuthzHosts maps host names to the backend environment namespace for ExtAuthz.
|
||||
let ExtAuthzHosts = {
|
||||
// Initialize all stages, even if they have no environments.
|
||||
for stage in project.stages {
|
||||
(stage.name): {}
|
||||
}
|
||||
|
||||
for env in project.environments {
|
||||
(env.stage): {
|
||||
for host in project.hosts {
|
||||
let NAME = "https-\(project.name)-\(env.name)-\(host.name)"
|
||||
let SEGMENTS = [host.name] + env.dnsSegments + [#Platform.org.domain]
|
||||
let HOST = strings.Join(SEGMENTS, ".")
|
||||
(NAME): #GatewayServer & {
|
||||
hosts: ["\(env.namespace)/\(HOST)"]
|
||||
// name must be unique across all servers in all gateways
|
||||
port: name: NAME
|
||||
port: number: 443
|
||||
port: protocol: "HTTPS"
|
||||
// TODO: Manage a certificate with each host in the dns alt names.
|
||||
tls: credentialName: HOST
|
||||
tls: mode: "SIMPLE"
|
||||
}
|
||||
|
||||
for cluster in project.clusters {
|
||||
let NAME = "https-\(cluster.name)-\(project.name)-\(env.name)-\(host.name)"
|
||||
let SEGMENTS = [host.name] + env.dnsSegments + [cluster.name, #Platform.org.domain]
|
||||
let HOST = strings.Join(SEGMENTS, ".")
|
||||
(NAME): #GatewayServer & {
|
||||
hosts: ["\(env.namespace)/\(HOST)"]
|
||||
// name must be unique across all servers in all gateways
|
||||
port: name: NAME
|
||||
port: number: 443
|
||||
port: protocol: "HTTPS"
|
||||
// TODO: Manage a certificate with each host in the dns alt names.
|
||||
tls: credentialName: HOST
|
||||
tls: mode: "SIMPLE"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
workload: resources: {
|
||||
for stage in project.stages {
|
||||
// Istio Gateway
|
||||
"\(stage.slug)-gateway": #KubernetesObjects & {
|
||||
apiObjectMap: (#APIObjects & {
|
||||
apiObjects: Gateway: (stage.slug): #Gateway & {
|
||||
spec: servers: [for host in ExtAuthzHosts[stage.name] {host}]
|
||||
}
|
||||
|
||||
for host in ExtAuthzHosts[stage.name] {
|
||||
apiObjects: ExternalSecret: (host.tls.credentialName): metadata: namespace: "istio-ingress"
|
||||
}
|
||||
}).apiObjectMap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provisioner: resources: {
|
||||
for stage in project.stages {
|
||||
"\(stage.slug)-certs": #KubernetesObjects & {
|
||||
apiObjectMap: (#APIObjects & {
|
||||
for host in ExtAuthzHosts[stage.name] {
|
||||
let CN = host.tls.credentialName
|
||||
apiObjects: Certificate: (CN): #Certificate & {
|
||||
metadata: name: CN
|
||||
metadata: namespace: "istio-ingress"
|
||||
spec: {
|
||||
commonName: CN
|
||||
dnsNames: [CN]
|
||||
secretName: CN
|
||||
issuerRef: {
|
||||
kind: "ClusterIssuer"
|
||||
name: "letsencrypt"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}).apiObjectMap
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #GatewayServer defines the value of the istio Gateway.spec.servers field.
|
||||
#GatewayServer: {
|
||||
// The ip or the Unix domain socket to which the listener should
|
||||
// be bound to.
|
||||
bind?: string
|
||||
defaultEndpoint?: string
|
||||
|
||||
// One or more hosts exposed by this gateway.
|
||||
hosts: [...string]
|
||||
|
||||
// An optional name of the server, when set must be unique across
|
||||
// all servers.
|
||||
name?: string
|
||||
|
||||
// The Port on which the proxy should listen for incoming
|
||||
// connections.
|
||||
port: {
|
||||
// Label assigned to the port.
|
||||
name: string
|
||||
|
||||
// A valid non-negative integer port number.
|
||||
number: int
|
||||
|
||||
// The protocol exposed on the port.
|
||||
protocol: string
|
||||
targetPort?: int
|
||||
}
|
||||
|
||||
// Set of TLS related options that govern the server's behavior.
|
||||
tls?: {
|
||||
// REQUIRED if mode is `MUTUAL` or `OPTIONAL_MUTUAL`.
|
||||
caCertificates?: string
|
||||
|
||||
// Optional: If specified, only support the specified cipher list.
|
||||
cipherSuites?: [...string]
|
||||
|
||||
// For gateways running on Kubernetes, the name of the secret that
|
||||
// holds the TLS certs including the CA certificates.
|
||||
credentialName?: string
|
||||
|
||||
// If set to true, the load balancer will send a 301 redirect for
|
||||
// all http connections, asking the clients to use HTTPS.
|
||||
httpsRedirect?: bool
|
||||
|
||||
// Optional: Maximum TLS protocol version.
|
||||
maxProtocolVersion?: "TLS_AUTO" | "TLSV1_0" | "TLSV1_1" | "TLSV1_2" | "TLSV1_3"
|
||||
|
||||
// Optional: Minimum TLS protocol version.
|
||||
minProtocolVersion?: "TLS_AUTO" | "TLSV1_0" | "TLSV1_1" | "TLSV1_2" | "TLSV1_3"
|
||||
|
||||
// Optional: Indicates whether connections to this port should be
|
||||
// secured using TLS.
|
||||
mode?: "PASSTHROUGH" | "SIMPLE" | "MUTUAL" | "AUTO_PASSTHROUGH" | "ISTIO_MUTUAL" | "OPTIONAL_MUTUAL"
|
||||
|
||||
// REQUIRED if mode is `SIMPLE` or `MUTUAL`.
|
||||
privateKey?: string
|
||||
|
||||
// REQUIRED if mode is `SIMPLE` or `MUTUAL`.
|
||||
serverCertificate?: string
|
||||
|
||||
// A list of alternate names to verify the subject identity in the
|
||||
// certificate presented by the client.
|
||||
subjectAltNames?: [...string]
|
||||
|
||||
// An optional list of hex-encoded SHA-256 hashes of the
|
||||
// authorized client certificates.
|
||||
verifyCertificateHash?: [...string]
|
||||
|
||||
// An optional list of base64-encoded SHA-256 hashes of the SPKIs
|
||||
// of authorized client certificates.
|
||||
verifyCertificateSpki?: [...string]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package holos
|
||||
@@ -1,11 +1,94 @@
|
||||
package holos
|
||||
|
||||
import h "github.com/holos-run/holos/api/v1alpha1"
|
||||
|
||||
// #Projects is a map of all the projects in the platform.
|
||||
#Projects: [Name=_]: #Project & {name: Name}
|
||||
|
||||
#Project: {
|
||||
name: string
|
||||
let ProjectName = name
|
||||
description: string
|
||||
environments: [Name=string]: #Environment & {
|
||||
name: Name
|
||||
project: ProjectName
|
||||
}
|
||||
stages: [Name=string]: #Stage & {
|
||||
name: Name
|
||||
project: ProjectName
|
||||
}
|
||||
|
||||
// hosts are short hostnames to configure for the project.
|
||||
hosts: [Name=string]: #Host & {name: Name}
|
||||
// clusters are the cluster names the project is configured on.
|
||||
clusters: [Name=string]: #Cluster & {name: Name}
|
||||
|
||||
// managedNamespaces ensures project namespaces have SecretStores that can sync ExternalSecrets from the provisioner cluster.
|
||||
managedNamespaces: {
|
||||
// Define the shape of a managed namespace.
|
||||
[Name=_]: #ManagedNamespace & {
|
||||
namespace: metadata: name: Name
|
||||
clusterNames: ["provisioner", for c in clusters {c.name}]
|
||||
}
|
||||
|
||||
// Manage a system namespace for each stage in the project.
|
||||
for stage in stages {
|
||||
for ns in stage.namespaces {
|
||||
(ns.name): _
|
||||
}
|
||||
}
|
||||
|
||||
// Manage a namespace for each environment in the project.
|
||||
for env in environments {
|
||||
(env.namespace): _
|
||||
}
|
||||
}
|
||||
|
||||
// features is YAGNI maybe?
|
||||
features: [Name=string]: #Feature & {name: Name}
|
||||
}
|
||||
|
||||
#Projects: {
|
||||
[Name=_]: #Project & {
|
||||
name: Name
|
||||
// #Cluster defines a cluster
|
||||
#Cluster: name: string
|
||||
|
||||
// #Host defines a short hostname
|
||||
#Host: name: string
|
||||
|
||||
#Environment: {
|
||||
// name uniquely identifies the environment within the scope of the project.
|
||||
name: string
|
||||
project: string
|
||||
stage: string | "dev" | "prod"
|
||||
slug: "\(name)-\(project)"
|
||||
namespace: "\(name)-\(project)"
|
||||
dnsSegments: [...string] | *[name]
|
||||
}
|
||||
|
||||
#Stage: {
|
||||
name: string
|
||||
project: string
|
||||
slug: "\(name)-\(project)"
|
||||
// Manage a system namespace for each stage
|
||||
namespaces: [Name=_]: name: Name
|
||||
namespaces: "\(name)-\(project)-system": _
|
||||
}
|
||||
|
||||
#Feature: {
|
||||
name: string
|
||||
description: string
|
||||
enabled: *true | false
|
||||
}
|
||||
|
||||
#ProjectTemplate: {
|
||||
project: #Project
|
||||
|
||||
// workload cluster resources
|
||||
workload: resources: [Name=_]: h.#KubernetesObjects & {
|
||||
metadata: name: Name
|
||||
}
|
||||
|
||||
// provisioner cluster resources
|
||||
provisioner: resources: [Name=_]: h.#KubernetesObjects & {
|
||||
metadata: name: Name
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,13 +13,9 @@ import (
|
||||
crt "cert-manager.io/certificate/v1"
|
||||
gw "networking.istio.io/gateway/v1beta1"
|
||||
vs "networking.istio.io/virtualservice/v1beta1"
|
||||
kc "sigs.k8s.io/kustomize/api/types"
|
||||
pg "postgres-operator.crunchydata.com/postgrescluster/v1beta1"
|
||||
"encoding/yaml"
|
||||
)
|
||||
|
||||
let ResourcesFile = "resources.yaml"
|
||||
|
||||
// _apiVersion is the version of this schema. Defines the interface between CUE output and the holos cli.
|
||||
_apiVersion: "holos.run/v1alpha1"
|
||||
|
||||
@@ -58,7 +54,10 @@ _apiVersion: "holos.run/v1alpha1"
|
||||
}
|
||||
|
||||
// Kubernetes API Objects
|
||||
#Namespace: corev1.#Namespace
|
||||
#Namespace: corev1.#Namespace & {
|
||||
metadata: name: string
|
||||
metadata: labels: "kubernetes.io/metadata.name": metadata.name
|
||||
}
|
||||
|
||||
#ClusterRole: #ClusterObject & rbacv1.#ClusterRole
|
||||
#ClusterRoleBinding: #ClusterObject & rbacv1.#ClusterRoleBinding
|
||||
@@ -74,11 +73,15 @@ _apiVersion: "holos.run/v1alpha1"
|
||||
#Job: #NamespaceObject & batchv1.#Job
|
||||
#CronJob: #NamespaceObject & batchv1.#CronJob
|
||||
#Deployment: #NamespaceObject & appsv1.#Deployment
|
||||
#Gateway: #NamespaceObject & gw.#Gateway
|
||||
#VirtualService: #NamespaceObject & vs.#VirtualService
|
||||
#Certificate: #NamespaceObject & crt.#Certificate
|
||||
#PostgresCluster: #NamespaceObject & pg.#PostgresCluster
|
||||
|
||||
#Gateway: #NamespaceObject & gw.#Gateway & {
|
||||
metadata: namespace: string | *"istio-ingress"
|
||||
spec: selector: istio: string | *"ingressgateway"
|
||||
}
|
||||
|
||||
// #HTTP01Cert defines a http01 certificate.
|
||||
#HTTP01Cert: {
|
||||
_name: string
|
||||
@@ -275,38 +278,6 @@ _apiVersion: "holos.run/v1alpha1"
|
||||
...
|
||||
}
|
||||
|
||||
// #KustomizeTree represents a kustomize build.
|
||||
#KustomizeFiles: {
|
||||
Objects: {
|
||||
"kustomization.yaml": #Kustomize
|
||||
}
|
||||
// Files holds the marshaled output holos writes to the filesystem
|
||||
Files: {
|
||||
for filename, obj in Objects {
|
||||
"\(filename)": yaml.Marshal(obj)
|
||||
}
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
// kustomization.yaml
|
||||
#Kustomize: kc.#Kustomization & {
|
||||
apiVersion: "kustomize.config.k8s.io/v1beta1"
|
||||
kind: "Kustomization"
|
||||
resources: [ResourcesFile]
|
||||
...
|
||||
if len(#KustomizePatches) > 0 {
|
||||
patches: [for v in #KustomizePatches {v}]
|
||||
}
|
||||
}
|
||||
|
||||
#KustomizePatches: {
|
||||
[_]: #Patch
|
||||
}
|
||||
|
||||
// #Patch is a kustomize patch
|
||||
#Patch: kc.#Patch
|
||||
|
||||
// #DefaultSecurityContext is the holos default security context to comply with the restricted namespace policy.
|
||||
// Refer to https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted
|
||||
#DefaultSecurityContext: {
|
||||
|
||||
18
go.mod
18
go.mod
@@ -3,12 +3,12 @@ module github.com/holos-run/holos
|
||||
go 1.21.5
|
||||
|
||||
require (
|
||||
cuelang.org/go v0.7.0
|
||||
cuelang.org/go v0.8.0
|
||||
github.com/mattn/go-isatty v0.0.20
|
||||
github.com/rogpeppe/go-internal v1.12.0
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
golang.org/x/tools v0.18.0
|
||||
golang.org/x/tools v0.19.0
|
||||
k8s.io/api v0.29.2
|
||||
k8s.io/apimachinery v0.29.2
|
||||
k8s.io/client-go v0.29.2
|
||||
@@ -17,7 +17,7 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
cuelabs.dev/go/oci/ociregistry v0.0.0-20231103182354-93e78c079a13 // indirect
|
||||
cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e // indirect
|
||||
github.com/cockroachdb/apd/v3 v3.2.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
@@ -41,19 +41,17 @@ require (
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.15.0 // indirect
|
||||
github.com/onsi/gomega v1.31.1 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0-rc4 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/protocolbuffers/txtpbfmt v0.0.0-20230328191034-3462fbc510c0 // indirect
|
||||
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb // indirect
|
||||
golang.org/x/net v0.21.0 // indirect
|
||||
golang.org/x/oauth2 v0.16.0 // indirect
|
||||
golang.org/x/sys v0.17.0 // indirect
|
||||
golang.org/x/term v0.17.0 // indirect
|
||||
golang.org/x/net v0.22.0 // indirect
|
||||
golang.org/x/oauth2 v0.18.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/term v0.18.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
|
||||
40
go.sum
40
go.sum
@@ -1,7 +1,7 @@
|
||||
cuelabs.dev/go/oci/ociregistry v0.0.0-20231103182354-93e78c079a13 h1:zkiIe8AxZ/kDjqQN+mDKc5BxoVJOqioSdqApjc+eB1I=
|
||||
cuelabs.dev/go/oci/ociregistry v0.0.0-20231103182354-93e78c079a13/go.mod h1:XGKYSMtsJWfqQYPwq51ZygxAPqpEUj/9bdg16iDPTAA=
|
||||
cuelang.org/go v0.7.0 h1:gMztinxuKfJwMIxtboFsNc6s8AxwJGgsJV+3CuLffHI=
|
||||
cuelang.org/go v0.7.0/go.mod h1:ix+3dM/bSpdG9xg6qpCgnJnpeLtciZu+O/rDbywoMII=
|
||||
cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e h1:GwCVItFUPxwdsEYnlUcJ6PJxOjTeFFCKOh6QWg4oAzQ=
|
||||
cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e/go.mod h1:ApHceQLLwcOkCEXM1+DyCXTHEJhNGDpJ2kmV6axsx24=
|
||||
cuelang.org/go v0.8.0 h1:fO1XPe/SUGtc7dhnGnTPbpIDoQm/XxhDtoSF7jzO01c=
|
||||
cuelang.org/go v0.8.0/go.mod h1:CoDbYolfMms4BhWUlhD+t5ORnihR7wvjcfgyO9lL5FI=
|
||||
github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg=
|
||||
github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
@@ -80,8 +80,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de h1:D5x39vF5KCwKQaw+OC9ZPiLVHXz3UFw2+psEX+gYcto=
|
||||
github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de/go.mod h1:kJun4WP5gFuHZgRjZUWWuH1DTxCtxbHDOIJsudS8jzY=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
|
||||
@@ -90,8 +88,8 @@ github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo=
|
||||
github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
|
||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
@@ -121,23 +119,21 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8=
|
||||
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
||||
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
|
||||
golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
|
||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
|
||||
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -150,12 +146,12 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
@@ -169,8 +165,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
|
||||
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
|
||||
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
|
||||
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
4
holos.go
4
holos.go
@@ -5,6 +5,6 @@ package holos
|
||||
// It is given a unique type so the API is clear.
|
||||
type PathCueMod string
|
||||
|
||||
// A PathComponent is a string representing the filesystem path of a holos component.
|
||||
// A InstancePath is a string representing the filesystem path of a holos instance.
|
||||
// It is given a unique type so the API is clear.
|
||||
type PathComponent string
|
||||
type InstancePath string
|
||||
|
||||
@@ -4,14 +4,17 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"cuelang.org/go/cue/build"
|
||||
"cuelang.org/go/cue/cuecontext"
|
||||
"cuelang.org/go/cue/load"
|
||||
"fmt"
|
||||
"github.com/holos-run/holos/api/v1alpha1"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/holos-run/holos"
|
||||
"github.com/holos-run/holos/pkg/logger"
|
||||
@@ -122,19 +125,28 @@ func (b *Builder) Run(ctx context.Context) (results []*v1alpha1.Result, err erro
|
||||
log.DebugContext(ctx, "cue: building instance")
|
||||
value := cueCtx.BuildInstance(instance)
|
||||
if err := value.Err(); err != nil {
|
||||
return nil, wrapper.Wrap(fmt.Errorf("could not build: %w", err))
|
||||
return nil, wrapper.Wrap(fmt.Errorf("could not build %s: %w", instance.Dir, err))
|
||||
}
|
||||
log.DebugContext(ctx, "cue: validating instance")
|
||||
if err := value.Validate(); err != nil {
|
||||
return nil, wrapper.Wrap(fmt.Errorf("could not validate: %w", err))
|
||||
}
|
||||
|
||||
log.DebugContext(ctx, "cue: decoding holos build plan")
|
||||
if err := value.Decode(&buildPlan); err != nil {
|
||||
return nil, wrapper.Wrap(fmt.Errorf("could not decode: %w", err))
|
||||
// Hack to catch unknown fields https://github.com/holos-run/holos/issues/72
|
||||
jsonBytes, err := value.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, wrapper.Wrap(fmt.Errorf("could not marshal cue instance %s: %w", instance.Dir, err))
|
||||
}
|
||||
decoder := json.NewDecoder(bytes.NewReader(jsonBytes))
|
||||
decoder.DisallowUnknownFields()
|
||||
err = decoder.Decode(&buildPlan)
|
||||
if err != nil {
|
||||
return nil, wrapper.Wrap(fmt.Errorf("invalid BuildPlan: %s: %w", instance.Dir, err))
|
||||
}
|
||||
|
||||
if err := buildPlan.Validate(); err != nil {
|
||||
return nil, wrapper.Wrap(fmt.Errorf("could not render: %w", err))
|
||||
return nil, wrapper.Wrap(fmt.Errorf("could not validate %s: %w", instance.Dir, err))
|
||||
}
|
||||
|
||||
if buildPlan.Spec.Disabled {
|
||||
@@ -142,15 +154,35 @@ func (b *Builder) Run(ctx context.Context) (results []*v1alpha1.Result, err erro
|
||||
continue
|
||||
}
|
||||
|
||||
for _, ko := range buildPlan.Spec.Components.KubernetesObjects {
|
||||
result, err := ko.Render(ctx, holos.PathComponent(instance.Dir))
|
||||
if err != nil {
|
||||
// TODO: concurrent renders
|
||||
for _, component := range buildPlan.Spec.Components.Resources {
|
||||
if result, err := component.Render(ctx, holos.InstancePath(instance.Dir)); err != nil {
|
||||
return nil, wrapper.Wrap(fmt.Errorf("could not render: %w", err))
|
||||
} else {
|
||||
results = append(results, result)
|
||||
}
|
||||
}
|
||||
for _, component := range buildPlan.Spec.Components.KubernetesObjectsList {
|
||||
if result, err := component.Render(ctx, holos.InstancePath(instance.Dir)); err != nil {
|
||||
return nil, wrapper.Wrap(fmt.Errorf("could not render: %w", err))
|
||||
} else {
|
||||
results = append(results, result)
|
||||
}
|
||||
}
|
||||
for _, component := range buildPlan.Spec.Components.HelmChartList {
|
||||
if result, err := component.Render(ctx, holos.InstancePath(instance.Dir)); err != nil {
|
||||
return nil, wrapper.Wrap(fmt.Errorf("could not render: %w", err))
|
||||
} else {
|
||||
results = append(results, result)
|
||||
}
|
||||
}
|
||||
for _, component := range buildPlan.Spec.Components.KustomizeBuildList {
|
||||
if result, err := component.Render(ctx, holos.InstancePath(instance.Dir)); err != nil {
|
||||
return nil, wrapper.Wrap(fmt.Errorf("could not render: %w", err))
|
||||
} else {
|
||||
results = append(results, result)
|
||||
}
|
||||
results = append(results, result)
|
||||
}
|
||||
// TODO: HelmCharts
|
||||
// TODO: KustomizeBuilds
|
||||
}
|
||||
|
||||
return results, nil
|
||||
|
||||
@@ -1 +1 @@
|
||||
60
|
||||
61
|
||||
|
||||
@@ -1 +1 @@
|
||||
0
|
||||
1
|
||||
|
||||
Reference in New Issue
Block a user