Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6fb6afe8d5 | ||
|
|
d6f89052d9 | ||
|
|
e4aa7f5994 | ||
|
|
6e4c65cb6c | ||
|
|
4f091677e2 | ||
|
|
0c05df1162 | ||
|
|
64a745fd34 | ||
|
|
490f91f580 | ||
|
|
79b065cda8 | ||
|
|
0fa6047552 | ||
|
|
11ecc0cc3a | ||
|
|
a62e4ba117 | ||
|
|
07fe667f30 | ||
|
|
3ad994cbb9 | ||
|
|
b3d9bd32af | ||
|
|
d398b49d7f | ||
|
|
12179a6991 | ||
|
|
fee472bb66 | ||
|
|
c6a13059f3 | ||
|
|
ff3eb896f3 | ||
|
|
70f70ae6b9 | ||
|
|
2580ec1c5f | ||
|
|
4fa99e0faa | ||
|
|
7341d25483 | ||
|
|
3074b3a241 | ||
|
|
9a5e7869c6 | ||
|
|
1064ceba31 | ||
|
|
4bccaa3710 | ||
|
|
95efae1343 | ||
|
|
ba88125877 | ||
|
|
d12c1a0c11 | ||
|
|
d56d3400a7 | ||
|
|
4f0f9dced5 | ||
|
|
6bf0cb8d8e | ||
|
|
766c8912b7 | ||
|
|
be1dee5f1c | ||
|
|
6ad56525ac | ||
|
|
791ec5ee71 | ||
|
|
638ac7473c | ||
|
|
ee24b5ce13 | ||
|
|
fa2fdbe4e8 | ||
|
|
63e1df1d4c | ||
|
|
2ad0c2a93e | ||
|
|
3a6a04f318 | ||
|
|
8afeece890 | ||
|
|
bc9c43a0b9 | ||
|
|
5a98c77e4c | ||
|
|
b3f7de39ec | ||
|
|
ca4ecf1b28 | ||
|
|
9ce28660ce | ||
|
|
728e8ba06e | ||
|
|
e4b07dad6d | ||
|
|
b7c0bba2b9 | ||
|
|
847ab8441c | ||
|
|
5f72af3d53 | ||
|
|
33eed43fd1 | ||
|
|
d2fbbdd1cc | ||
|
|
e42da118dc | ||
|
|
7d36567dcf | ||
|
|
bee698bebe | ||
|
|
58df0626d0 | ||
|
|
c817a24704 |
121
.cspell.json
@@ -5,36 +5,56 @@
|
||||
"mdx"
|
||||
],
|
||||
"words": [
|
||||
"acmesolver",
|
||||
"acraccesstokens",
|
||||
"admissionregistration",
|
||||
"alertmanager",
|
||||
"alertmanagers",
|
||||
"anthos",
|
||||
"apiextensions",
|
||||
"apimachinery",
|
||||
"apiobjects",
|
||||
"apiservers",
|
||||
"applicationset",
|
||||
"applicationsets",
|
||||
"appproject",
|
||||
"appprojects",
|
||||
"argoproj",
|
||||
"argumentless",
|
||||
"authcode",
|
||||
"authorizationpolicies",
|
||||
"authorizationpolicy",
|
||||
"authpolicy",
|
||||
"authproxy",
|
||||
"authroutes",
|
||||
"automount",
|
||||
"automounting",
|
||||
"autoscaler",
|
||||
"balancereader",
|
||||
"blackbox",
|
||||
"buildplan",
|
||||
"builtinpluginloadingoptions",
|
||||
"cadvisor",
|
||||
"cainjector",
|
||||
"CAROOT",
|
||||
"certificaterequest",
|
||||
"certificaterequests",
|
||||
"certificatesigningrequests",
|
||||
"clsx",
|
||||
"clusterexternalsecret",
|
||||
"clusterexternalsecrets",
|
||||
"clusterissuer",
|
||||
"clusterissuers",
|
||||
"clusterrole",
|
||||
"clusterrolebinding",
|
||||
"clustersecretstore",
|
||||
"clustersecretstores",
|
||||
"clusterwide",
|
||||
"CNCF",
|
||||
"CODEOWNERS",
|
||||
"configmap",
|
||||
"configmapargs",
|
||||
"connectrpc",
|
||||
"cookiesecret",
|
||||
"coredns",
|
||||
"corev",
|
||||
@@ -42,111 +62,187 @@
|
||||
"crds",
|
||||
"creds",
|
||||
"crossplane",
|
||||
"crunchydata",
|
||||
"cuecontext",
|
||||
"cuelang",
|
||||
"customresourcedefinition",
|
||||
"daemonset",
|
||||
"deploymentruntimeconfig",
|
||||
"destinationrule",
|
||||
"destinationrules",
|
||||
"devicecode",
|
||||
"dnsmasq",
|
||||
"dscacheutil",
|
||||
"ecrauthorizationtokens",
|
||||
"edns",
|
||||
"endpointslices",
|
||||
"entgo",
|
||||
"envoyfilter",
|
||||
"envoyfilters",
|
||||
"errdetails",
|
||||
"errgroup",
|
||||
"etcdsnapshotfiles",
|
||||
"externalsecret",
|
||||
"externalsecrets",
|
||||
"fctr",
|
||||
"fieldmaskpb",
|
||||
"fieldspec",
|
||||
"flushcache",
|
||||
"fullname",
|
||||
"gatewayclass",
|
||||
"gatewayclasses",
|
||||
"gcraccesstokens",
|
||||
"gendoc",
|
||||
"generationbehavior",
|
||||
"generatorargs",
|
||||
"generatoroptions",
|
||||
"genproto",
|
||||
"ggnpl",
|
||||
"ghaction",
|
||||
"githubaccesstokens",
|
||||
"gitops",
|
||||
"godoc",
|
||||
"golangci",
|
||||
"gomarkdoc",
|
||||
"googleapis",
|
||||
"goreleaser",
|
||||
"gotypesalias",
|
||||
"grpcreflect",
|
||||
"grpcroute",
|
||||
"grpcroutes",
|
||||
"grpcurl",
|
||||
"healthchecks",
|
||||
"healthz",
|
||||
"helmchartargs",
|
||||
"helmchartconfigs",
|
||||
"helmcharts",
|
||||
"Hiera",
|
||||
"holos",
|
||||
"holoslogger",
|
||||
"horizontalpodautoscaler",
|
||||
"horizontalpodautoscalers",
|
||||
"Hostaliases",
|
||||
"Hostnames",
|
||||
"htpasswd",
|
||||
"httpbin",
|
||||
"httproute",
|
||||
"httproutes",
|
||||
"iampolicygenerator",
|
||||
"Infima",
|
||||
"intstr",
|
||||
"isatty",
|
||||
"istiod",
|
||||
"jbrx",
|
||||
"jeffmccune",
|
||||
"jetstack",
|
||||
"jiralert",
|
||||
"Jsonnet",
|
||||
"kfbh",
|
||||
"killall",
|
||||
"kubeadm",
|
||||
"kubeconfig",
|
||||
"kubelet",
|
||||
"kubelogin",
|
||||
"kubernetesobjects",
|
||||
"Kustomization",
|
||||
"Kustomizations",
|
||||
"kustomize",
|
||||
"kustomizebuild",
|
||||
"kvpairsources",
|
||||
"labeldrop",
|
||||
"labelmap",
|
||||
"ldflags",
|
||||
"leaderelection",
|
||||
"ledgerwriter",
|
||||
"libnss",
|
||||
"limitranges",
|
||||
"livez",
|
||||
"loadbalancer",
|
||||
"loadrestrictions",
|
||||
"logfmt",
|
||||
"mattn",
|
||||
"mccutchen",
|
||||
"metav",
|
||||
"mindmap",
|
||||
"mktemp",
|
||||
"msqbn",
|
||||
"mtls",
|
||||
"Multicluster",
|
||||
"mutatingwebhookconfiguration",
|
||||
"mutatingwebhookconfigurations",
|
||||
"mxcl",
|
||||
"myhostname",
|
||||
"myRegistrKeySecretName",
|
||||
"mysecret",
|
||||
"nameofclusterrole",
|
||||
"nameserver",
|
||||
"namespacedname",
|
||||
"ndots",
|
||||
"networkpolicies",
|
||||
"nodename",
|
||||
"nolint",
|
||||
"oauthproxy",
|
||||
"objectmap",
|
||||
"objectmeta",
|
||||
"organizationconnect",
|
||||
"orgid",
|
||||
"otelconnect",
|
||||
"overriden",
|
||||
"Parentspanid",
|
||||
"patchstrategicmerge",
|
||||
"pcjc",
|
||||
"peerauthentication",
|
||||
"peerauthentications",
|
||||
"persistentvolumeclaim",
|
||||
"persistentvolumeclaims",
|
||||
"persistentvolumes",
|
||||
"pflag",
|
||||
"pgadmin",
|
||||
"pgupgrade",
|
||||
"pipefail",
|
||||
"PKCE",
|
||||
"platformconnect",
|
||||
"pluginconfig",
|
||||
"pluginrestrictions",
|
||||
"podcli",
|
||||
"poddisruptionbudget",
|
||||
"poddisruptionbudgets",
|
||||
"podinfo",
|
||||
"podmonitor",
|
||||
"portmapping",
|
||||
"postgrescluster",
|
||||
"privs",
|
||||
"prometheuses",
|
||||
"promhttp",
|
||||
"protobuf",
|
||||
"protojson",
|
||||
"providerconfig",
|
||||
"proxyconfig",
|
||||
"proxyconfigs",
|
||||
"Pulumi",
|
||||
"pushgateway",
|
||||
"pushsecret",
|
||||
"pushsecrets",
|
||||
"putenv",
|
||||
"qjbp",
|
||||
"quickstart",
|
||||
"QVRFLS",
|
||||
"readyz",
|
||||
"referencegrant",
|
||||
"referencegrants",
|
||||
"Registr",
|
||||
"replacementfield",
|
||||
"replicasets",
|
||||
"replicationcontrollers",
|
||||
"requestauthentication",
|
||||
"requestauthentications",
|
||||
"resourcequotas",
|
||||
"retryable",
|
||||
"rolebinding",
|
||||
"rootfs",
|
||||
"ropc",
|
||||
"seccomp",
|
||||
"secretargs",
|
||||
"SECRETKEY",
|
||||
"secretstore",
|
||||
"secretstores",
|
||||
@@ -155,29 +251,47 @@
|
||||
"serviceaccount",
|
||||
"servicebindings",
|
||||
"serviceentries",
|
||||
"serviceentry",
|
||||
"servicemonitor",
|
||||
"somevalue",
|
||||
"SOMEVAR",
|
||||
"sortoptions",
|
||||
"spanid",
|
||||
"spiffe",
|
||||
"stackdriver",
|
||||
"startupapicheck",
|
||||
"statefulset",
|
||||
"statefulsets",
|
||||
"stefanprodan",
|
||||
"storageclasses",
|
||||
"streamwatcher",
|
||||
"struct",
|
||||
"structpb",
|
||||
"subcharts",
|
||||
"subjectaccessreviews",
|
||||
"svclb",
|
||||
"sysfs",
|
||||
"systemconnect",
|
||||
"tablewriter",
|
||||
"templatable",
|
||||
"thanos",
|
||||
"Tiltfile",
|
||||
"timestamppb",
|
||||
"Timoni",
|
||||
"tlsclientconfig",
|
||||
"tokencache",
|
||||
"Tokener",
|
||||
"tolerations",
|
||||
"Traceid",
|
||||
"traefik",
|
||||
"transactionhistory",
|
||||
"tsdb",
|
||||
"typemeta",
|
||||
"udev",
|
||||
"uibutton",
|
||||
"unstage",
|
||||
"untar",
|
||||
"upbound",
|
||||
"Upsert",
|
||||
"urandom",
|
||||
"usecases",
|
||||
@@ -185,11 +299,18 @@
|
||||
"userdata",
|
||||
"userservice",
|
||||
"validatingwebhookconfiguration",
|
||||
"validatingwebhookconfigurations",
|
||||
"vaultdynamicsecrets",
|
||||
"virtualservice",
|
||||
"virtualservices",
|
||||
"volumeattachments",
|
||||
"wasmplugin",
|
||||
"wasmplugins",
|
||||
"workloadentries",
|
||||
"workloadentry",
|
||||
"workloadgroup",
|
||||
"workloadgroups",
|
||||
"yournamespace",
|
||||
"zerolog",
|
||||
"zitadel",
|
||||
"ztunnel"
|
||||
|
||||
4
api/author/v1alpha3/header.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
description: Simplified abstraction to generate core v1alpha3 components.
|
||||
sidebar_position: 997
|
||||
---
|
||||
290
api/author/v1alpha4/definitions.go
Normal file
@@ -0,0 +1,290 @@
|
||||
// # Author API
|
||||
//
|
||||
// Package v1alpha4 contains ergonomic CUE definitions for Holos component
|
||||
// authors. These definitions serve as adapters to produce [Core API] resources
|
||||
// for the holos command line tool.
|
||||
//
|
||||
// [Core API]: https://holos.run/docs/api/core/v1alpha4/
|
||||
package v1alpha4
|
||||
|
||||
import core "github.com/holos-run/holos/api/core/v1alpha4"
|
||||
|
||||
//go:generate ../../../hack/gendoc
|
||||
|
||||
// Platform assembles a Core API [Platform] in the Resource field for the holos
|
||||
// render platform command. Use the Components field to register components
|
||||
// with the platform using a struct. This struct is converted into a list for
|
||||
// final output to holos.
|
||||
//
|
||||
// See related:
|
||||
//
|
||||
// - [Component] collection of components composing the platform.
|
||||
// - [Platform] resource assembled for holos to process.
|
||||
//
|
||||
// [Platform]: https://holos.run/docs/api/core/v1alpha4/#Platform
|
||||
// [Component]: https://holos.run/docs/api/core/v1alpha4/#Component
|
||||
type Platform struct {
|
||||
Name string
|
||||
Components map[NameLabel]core.Component
|
||||
Resource core.Platform
|
||||
}
|
||||
|
||||
// Cluster represents a cluster managed by the Platform.
|
||||
type Cluster struct {
|
||||
// Name represents the cluster name, for example "east1", "west1", or
|
||||
// "management".
|
||||
Name string `json:"name"`
|
||||
// Primary represents if the cluster is marked as the primary among a set of
|
||||
// candidate clusters. Useful for promotion of database leaders.
|
||||
Primary bool `json:"primary" cue:"true | *false"`
|
||||
}
|
||||
|
||||
// Fleet represents a named collection of similarly configured Clusters. Useful
|
||||
// to segregate workload clusters from their management cluster.
|
||||
type Fleet struct {
|
||||
Name string `json:"name"`
|
||||
// Clusters represents a mapping of Clusters by their name.
|
||||
Clusters map[string]Cluster `json:"clusters" cue:"{[Name=_]: name: Name}"`
|
||||
}
|
||||
|
||||
// StandardFleets represents the standard set of Clusters in a Platform
|
||||
// segmented into Fleets by their purpose. The management Fleet contains a
|
||||
// single Cluster, for example a GKE autopilot cluster with no workloads
|
||||
// deployed for reliability and cost efficiency. The workload Fleet contains
|
||||
// all other Clusters which contain workloads and sync Secrets from the
|
||||
// management cluster.
|
||||
type StandardFleets struct {
|
||||
// Workload represents a Fleet of zero or more workload Clusters.
|
||||
Workload Fleet `json:"workload" cue:"{name: \"workload\"}"`
|
||||
// Management represents a Fleet with one Cluster named management.
|
||||
Management Fleet `json:"management" cue:"{name: \"management\"}"`
|
||||
}
|
||||
|
||||
// ArgoConfig represents the ArgoCD GitOps configuration associated with a
|
||||
// [BuildPlan]. Useful to define once at the root of the Platform configuration
|
||||
// and reuse across all components.
|
||||
//
|
||||
// [BuildPlan]: https://holos.run/docs/api/core/v1alpha4/#buildplan
|
||||
type ArgoConfig struct {
|
||||
// Enabled causes holos to render an Application resource when true.
|
||||
Enabled bool `cue:"true | *false"`
|
||||
// RepoURL represents the value passed to the Application.spec.source.repoURL
|
||||
// field.
|
||||
RepoURL string
|
||||
// Root represents the path from the git repository root to the WriteTo output
|
||||
// directory, the behavior of the holos render component --write-to flag and
|
||||
// the Core API Component WriteTo field. Used as a prefix for the
|
||||
// Application.spec.source.path field.
|
||||
Root string `cue:"string | *\"deploy\""`
|
||||
// TargetRevision represents the value passed to the
|
||||
// Application.spec.source.targetRevision field. Defaults to the branch named
|
||||
// main.
|
||||
TargetRevision string `cue:"string | *\"main\""`
|
||||
// AppProject represents the ArgoCD Project to associate the Application with.
|
||||
AppProject string `cue:"string | *\"default\""`
|
||||
}
|
||||
|
||||
// Organization represents organizational metadata useful across the platform.
|
||||
type Organization struct {
|
||||
Name string
|
||||
DisplayName string
|
||||
Domain string
|
||||
}
|
||||
|
||||
// OrganizationStrict represents organizational metadata useful across the
|
||||
// platform. This is an example of using CUE regular expressions to constrain
|
||||
// and validate configuration.
|
||||
type OrganizationStrict struct {
|
||||
Organization `json:",inline"`
|
||||
// Name represents the organization name as a resource name. Must be 63
|
||||
// characters or less. Must start with a letter. May contain non-repeating
|
||||
// hyphens, letters, and numbers. Must end with a letter or number.
|
||||
Name string `cue:"=~ \"^[a-z][0-9a-z-]{1,61}[0-9a-z]$\" & !~ \"--\""`
|
||||
// DisplayName represents the human readable organization name.
|
||||
DisplayName string `cue:"=~ \"^[0-9A-Za-z][0-9A-Za-z ]{2,61}[0-9A-Za-z]$\" & !~ \" \""`
|
||||
}
|
||||
|
||||
// Kubernetes provides a [BuildPlan] via the Output field which contains inline
|
||||
// API Objects provided directly from CUE in the Resources field of
|
||||
// [ComponentConfig].
|
||||
//
|
||||
// See related:
|
||||
//
|
||||
// - [ComponentConfig]
|
||||
// - [BuildPlan]
|
||||
//
|
||||
// [BuildPlan]: https://holos.run/docs/api/core/v1alpha4/#BuildPlan
|
||||
type Kubernetes struct {
|
||||
ComponentConfig `json:",inline"`
|
||||
|
||||
// BuildPlan represents the derived BuildPlan produced for the holos render
|
||||
// component command.
|
||||
BuildPlan core.BuildPlan
|
||||
}
|
||||
|
||||
// Helm provides a [BuildPlan] via the Output field which generates manifests
|
||||
// from a helm chart with optional mix-in resources provided directly from CUE
|
||||
// in the Resources field.
|
||||
//
|
||||
// This definition is a convenient way to produce a [BuildPlan] composed of
|
||||
// three [Resources] generators with one [Kustomize] transformer.
|
||||
//
|
||||
// See related:
|
||||
//
|
||||
// - [ComponentConfig]
|
||||
// - [Chart]
|
||||
// - [Values]
|
||||
// - [BuildPlan]
|
||||
//
|
||||
// [BuildPlan]: https://holos.run/docs/api/core/v1alpha4/#BuildPlan
|
||||
// [Chart]: https://holos.run/docs/api/core/v1alpha4/#Chart
|
||||
// [Values]: https://holos.run/docs/api/core/v1alpha4/#Values
|
||||
type Helm struct {
|
||||
ComponentConfig `json:",inline"`
|
||||
|
||||
// Chart represents a Helm chart.
|
||||
Chart core.Chart
|
||||
// Values represents data to marshal into a values.yaml for helm.
|
||||
Values core.Values
|
||||
// EnableHooks enables helm hooks when executing the `helm template` command.
|
||||
EnableHooks bool
|
||||
|
||||
// BuildPlan represents the derived BuildPlan produced for the holos render
|
||||
// component command.
|
||||
BuildPlan core.BuildPlan
|
||||
}
|
||||
|
||||
// Kustomize provides a [BuildPlan] via the Output field which generates
|
||||
// manifests from a kustomize kustomization with optional mix-in resources
|
||||
// provided directly from CUE in the Resources field.
|
||||
//
|
||||
// See related:
|
||||
//
|
||||
// - [ComponentConfig]
|
||||
// - [BuildPlan]
|
||||
//
|
||||
// [BuildPlan]: https://holos.run/docs/api/core/v1alpha4/#buildplan
|
||||
type Kustomize struct {
|
||||
ComponentConfig `json:",inline"`
|
||||
|
||||
// BuildPlan represents the derived BuildPlan produced for the holos render
|
||||
// component command.
|
||||
BuildPlan core.BuildPlan
|
||||
}
|
||||
|
||||
// ComponentConfig represents the configuration common to all kinds of
|
||||
// component.
|
||||
//
|
||||
// - [Helm] charts.
|
||||
// - [Kubernetes] resources generated from CUE.
|
||||
// - [Kustomize] bases.
|
||||
//
|
||||
// See the following resources for additional details:
|
||||
//
|
||||
// - [Resources]
|
||||
// - [ArgoConfig]
|
||||
// - [KustomizeConfig]
|
||||
// - [BuildPlan]
|
||||
//
|
||||
// [BuildPlan]: https://holos.run/docs/api/core/v1alpha4/#BuildPlan
|
||||
// [Resources]: https://holos.run/docs/api/core/v1alpha4/#Resources
|
||||
type ComponentConfig struct {
|
||||
// Name represents the BuildPlan metadata.name field. Used to construct the
|
||||
// fully rendered manifest file path.
|
||||
Name string
|
||||
// Component represents the path to the component producing the BuildPlan.
|
||||
Component string
|
||||
// Cluster represents the name of the cluster this BuildPlan is for.
|
||||
Cluster string
|
||||
// Resources represents kubernetes resources mixed into the rendered manifest.
|
||||
Resources core.Resources
|
||||
// ArgoConfig represents the ArgoCD GitOps configuration for this BuildPlan.
|
||||
ArgoConfig ArgoConfig
|
||||
// CommonLabels represents common labels to manage on all rendered manifests.
|
||||
CommonLabels map[string]string
|
||||
// Namespace manages the metadata.namespace field on all resources except the
|
||||
// ArgoCD Application.
|
||||
Namespace string `json:",omitempty"`
|
||||
|
||||
// KustomizeConfig represents the configuration for kustomize.
|
||||
KustomizeConfig KustomizeConfig
|
||||
}
|
||||
|
||||
// KustomizeConfig represents the configuration for kustomize post processing.
|
||||
// The Files field is used to mixing in static manifest files from the component
|
||||
// directory. The Resources field is used for mixing in manifests from network
|
||||
// locations urls.
|
||||
//
|
||||
// See related:
|
||||
//
|
||||
// - [ComponentConfig]
|
||||
// - [Kustomization]
|
||||
//
|
||||
// [Kustomization]: https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/
|
||||
type KustomizeConfig struct {
|
||||
// Kustomization represents the kustomization used to transform resources.
|
||||
// Note the resources field is internally managed from the Files and Resources fields.
|
||||
Kustomization map[string]any `json:",omitempty"`
|
||||
// Files represents files to copy from the component directory for kustomization.
|
||||
Files map[string]struct{ Source string } `cue:"{[NAME=_]: Source: NAME}"`
|
||||
// Resources represents additional entries to included in the resources list.
|
||||
Resources map[string]struct{ Source string } `cue:"{[NAME=_]: Source: NAME}"`
|
||||
}
|
||||
|
||||
// Projects represents projects managed by the platform team for use by other
|
||||
// teams using the platform.
|
||||
type Projects map[NameLabel]Project
|
||||
|
||||
// Project represents logical grouping of components owned by one or more teams.
|
||||
// Useful for the platform team to manage resources for project teams to use.
|
||||
type Project struct {
|
||||
// Name represents project name.
|
||||
Name string
|
||||
// Owner represents the team who own this project.
|
||||
Owner Owner
|
||||
// Namespaces represents the namespaces assigned to this project.
|
||||
Namespaces map[NameLabel]Namespace
|
||||
// Hostnames represents the host names to expose for this project.
|
||||
Hostnames map[NameLabel]Hostname
|
||||
// CommonLabels represents common labels to manage on all rendered manifests.
|
||||
CommonLabels map[string]string
|
||||
}
|
||||
|
||||
// Owner represents the owner of a resource. For example, the name and email
|
||||
// address of an engineering team.
|
||||
type Owner struct {
|
||||
Name string
|
||||
Email string
|
||||
}
|
||||
|
||||
// Namespace represents a Kubernetes namespace.
|
||||
type Namespace struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
// Hostname represents the left most dns label of a domain name.
|
||||
type Hostname struct {
|
||||
// Name represents the subdomain to expose, e.g. "www"
|
||||
Name string
|
||||
// Namespace represents the namespace metadata.name field of backend object
|
||||
// reference.
|
||||
Namespace string
|
||||
// Service represents the Service metadata.name field of backend object
|
||||
// reference.
|
||||
Service string
|
||||
// Port represents the Service port of the backend object reference.
|
||||
Port int
|
||||
}
|
||||
|
||||
// NameLabel signals the common use case of converting a struct to a list where
|
||||
// the name field of each value unifies with the field name of the outer struct.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// S: [NameLabel=string]: name: NameLabel
|
||||
// S: jeff: _
|
||||
// S: gary: _
|
||||
// S: nate: _
|
||||
// L: [for x in S {x}]
|
||||
// // L is [{name: "jeff"}, {name: "gary"}, {name: "nate"}]
|
||||
type NameLabel string
|
||||
4
api/author/v1alpha4/header.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
description: Simplified abstraction to generate core v1alpha4 build plans.
|
||||
sidebar_position: 996
|
||||
---
|
||||
4
api/core/v1alpha2/header.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
description: Core v1alpha4 schema for advanced use cases.
|
||||
sidebar_position: 998
|
||||
---
|
||||
4
api/core/v1alpha3/header.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
description: Core v1alpha3 schema for advanced use cases.
|
||||
sidebar_position: 997
|
||||
---
|
||||
4
api/core/v1alpha4/header.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
description: Core v1alpha2 schema for advanced use cases.
|
||||
sidebar_position: 996
|
||||
---
|
||||
@@ -1,17 +1,80 @@
|
||||
// # Core API
|
||||
//
|
||||
// Package v1alpha4 contains the core API contract between the holos cli and CUE
|
||||
// configuration code. Platform designers, operators, and software developers
|
||||
// use this API to write configuration in CUE which `holos` loads. The overall
|
||||
// shape of the API defines imperative actions `holos` should carry out to
|
||||
// render the complete yaml that represents a Platform.
|
||||
// use this API to write configuration in CUE which holos loads. The Core API
|
||||
// is declarative. Each resource represents a desired state necessary for holos
|
||||
// to fully render Kubernetes manifests into plain files.
|
||||
//
|
||||
// [Platform] defines the complete configuration of a platform. With the holos
|
||||
// reference platform this takes the shape of one management cluster and at
|
||||
// least two workload clusters.
|
||||
// The following resources provide important context for the Core API. The
|
||||
// [Author API] is intended for component authors as a convenient adapter for
|
||||
// the Core API resources Holos expects.
|
||||
//
|
||||
// Each holos component path, e.g. `components/namespaces` produces exactly one
|
||||
// [BuildPlan] which produces an [Artifact] collection. An [Artifact] is a
|
||||
// fully rendered manifest produced from a [Transformer] sequence, which
|
||||
// transforms a [Generator] collection.
|
||||
// 1. [Technical Overview]
|
||||
// 2. [Quickstart]
|
||||
// 3. [Author API]
|
||||
//
|
||||
// # Platform
|
||||
//
|
||||
// [Platform] defines the complete configuration of a platform. A platform
|
||||
// represents a [Component] collection.
|
||||
//
|
||||
// Inspect a Platform resource holos would process by executing:
|
||||
//
|
||||
// cue export --out yaml ./platform
|
||||
//
|
||||
// # Component
|
||||
//
|
||||
// A [Component] is the combination of CUE code along one path relative to the
|
||||
// platform root directory plus data injected from the [PlatformSpec] via CUE tags.
|
||||
// The platform configuration root is the directory containing cue.mod.
|
||||
//
|
||||
// A [Component] always produces exactly one [BuildPlan].
|
||||
//
|
||||
// # BuildPlan
|
||||
//
|
||||
// A [BuildPlan] contains an [Artifact] collection. A BuildPlan often produces
|
||||
// two artifacts, one containing the fully rendered Kubernetes API resources,
|
||||
// the other containing an additional resource to manage the former with GitOps.
|
||||
// For example, a BuildPlan for a podinfo component produces a manifest
|
||||
// containing a Deployment and a Service, along with a second manifest
|
||||
// containing an ArgoCD Application.
|
||||
//
|
||||
// Inspect a BuildPlan resource holos render component would process by executing:
|
||||
//
|
||||
// cue export --out yaml ./projects/platform/components/namespaces
|
||||
//
|
||||
// # Artifact
|
||||
//
|
||||
// An [Artifact] is one fully rendered manifest file produced from the final
|
||||
// [Transformer] in a sequence of transformers. An Artifact may also be
|
||||
// produced directly from a [Generator], but this use case is uncommon.
|
||||
//
|
||||
// # Transformer
|
||||
//
|
||||
// A [Transformer] takes multiple inputs from prior [Generator] or [Transformer]
|
||||
// outputs, then transforms the data into one output. [Kustomize] is the most
|
||||
// commonly used transformer, though a simple [Join] is also supported.
|
||||
//
|
||||
// 1. [Kustomize] - Patch and transform the output from prior generators or
|
||||
// transformers. See [Introduction to Kustomize].
|
||||
// 2. [Join] - Concatenate multiple prior outputs into one output.
|
||||
//
|
||||
// # Generators
|
||||
//
|
||||
// A [Generator] generates Kubernetes resources. [Helm] and [Resources] are the
|
||||
// most commonly used, often paired together to mix-in resources to an
|
||||
// unmodified Helm chart. A simple [File] generator is also available for use
|
||||
// with the [Kustomize] transformer.
|
||||
//
|
||||
// 1. [Resources] - Generates resources from CUE code.
|
||||
// 2. [Helm] - Generates rendered yaml from a [Chart].
|
||||
// 3. [File] - Generates data by reading a file from the component directory.
|
||||
//
|
||||
// [Introduction to Kustomize]: https://kubectl.docs.kubernetes.io/guides/config_management/introduction/
|
||||
// [Author API]: https://holos.run/docs/api/author/
|
||||
// [Quickstart]: https://holos.run/docs/quickstart/
|
||||
// [Technical Overview]: https://holos.run/docs/technical-overview/
|
||||
package v1alpha4
|
||||
|
||||
//go:generate ../../../hack/gendoc
|
||||
@@ -21,6 +84,46 @@ package v1alpha4
|
||||
//
|
||||
// One or more [Artifact] files are produced by a BuildPlan, representing the
|
||||
// fully rendered manifests for the Kubernetes API Server.
|
||||
//
|
||||
// # Example BuildPlan
|
||||
//
|
||||
// Command:
|
||||
//
|
||||
// cue export --out yaml ./projects/platform/components/namespaces
|
||||
//
|
||||
// Output:
|
||||
//
|
||||
// kind: BuildPlan
|
||||
// apiVersion: v1alpha4
|
||||
// metadata:
|
||||
// name: dev-namespaces
|
||||
// spec:
|
||||
// component: projects/platform/components/namespaces
|
||||
// artifacts:
|
||||
// - artifact: clusters/no-cluster/components/dev-namespaces/dev-namespaces.gen.yaml
|
||||
// generators:
|
||||
// - kind: Resources
|
||||
// output: resources.gen.yaml
|
||||
// resources:
|
||||
// Namespace:
|
||||
// dev-jeff:
|
||||
// metadata:
|
||||
// name: dev-jeff
|
||||
// labels:
|
||||
// kubernetes.io/metadata.name: dev-jeff
|
||||
// kind: Namespace
|
||||
// apiVersion: v1
|
||||
// transformers:
|
||||
// - kind: Kustomize
|
||||
// inputs:
|
||||
// - resources.gen.yaml
|
||||
// output: clusters/no-cluster/components/dev-namespaces/dev-namespaces.gen.yaml
|
||||
// kustomize:
|
||||
// kustomization:
|
||||
// commonLabels:
|
||||
// holos.run/component.name: dev-namespaces
|
||||
// resources:
|
||||
// - resources.gen.yaml
|
||||
type BuildPlan struct {
|
||||
// Kind represents the type of the resource.
|
||||
Kind string `json:"kind" cue:"\"BuildPlan\""`
|
||||
@@ -158,9 +261,12 @@ type Transformer struct {
|
||||
Join Join `json:"join,omitempty"`
|
||||
}
|
||||
|
||||
// Join represents a [Join](https://pkg.go.dev/strings#Join) [Transformer].
|
||||
// Useful for the common case of combining the output of [Helm] and [Resources]
|
||||
// [Generator] into one [Artifact] when [Kustomize] is otherwise unnecessary.
|
||||
// Join represents a [Transformer] using [bytes.Join] to concatenate multiple
|
||||
// inputs into one output with a separator. Useful for combining output from
|
||||
// [Helm] and [Resources] together into one [Artifact] when [Kustomize] is
|
||||
// otherwise unnecessary.
|
||||
//
|
||||
// [bytes.Join]: https://pkg.go.dev/bytes#Join
|
||||
type Join struct {
|
||||
Separator string `json:"separator" cue:"string | *\"---\\n\""`
|
||||
}
|
||||
@@ -238,28 +344,59 @@ type PlatformSpec struct {
|
||||
Components []Component `json:"components"`
|
||||
}
|
||||
|
||||
// Component represents the complete context necessary to produce a [BuildPlan]
|
||||
// from a [Platform] component.
|
||||
// Component represents the complete context necessary to produce a [BuildPlan].
|
||||
// Component carries information injected from holos render platform to holos
|
||||
// render component to produce each [BuildPlan].
|
||||
//
|
||||
// All of these fields are passed to the holos render component command using
|
||||
// flags, which in turn are injected to CUE using tags. Field names should be
|
||||
// used consistently through the platform rendering process for readability.
|
||||
// flags, which in turn are injected to CUE using tags. For clarity, CUE field
|
||||
// and tag names should match the struct json tag names below.
|
||||
type Component struct {
|
||||
// Name represents the name of the component, injected as a tag to set the
|
||||
// BuildPlan metadata.name field. Necessary for clear user feedback during
|
||||
// platform rendering.
|
||||
// Name represents the name of the component. Injected as the tag variable
|
||||
// "holos_name" to set the BuildPlan metadata.name field. Necessary for clear
|
||||
// user feedback during platform rendering.
|
||||
Name string `json:"name"`
|
||||
// Component represents the path of the component relative to the platform root.
|
||||
// Component represents the path of the component relative to the platform
|
||||
// root. Injected as the tag variable "holos_component".
|
||||
Component string `json:"component"`
|
||||
// Cluster is the cluster name to provide when rendering the component.
|
||||
// Injected as the tag variable "holos_cluster".
|
||||
Cluster string `json:"cluster"`
|
||||
// Environment for example, dev, test, stage, prod
|
||||
Environment string `json:"environment,omitempty"`
|
||||
// Model represents the platform model holos gets from from the
|
||||
// PlatformService.GetPlatform rpc method and provides to CUE using a tag.
|
||||
Model map[string]any `json:"model"`
|
||||
// Tags represents cue tags to inject when rendering the component. The json
|
||||
// struct tag names of other fields in this struct are reserved tag names not
|
||||
// to be used in the tags collection.
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
// Injected as the tag "holos_model".
|
||||
Model map[string]any `json:"model,omitempty"`
|
||||
// Tags represents cue @tag variables injected into the holos render component
|
||||
// command from the holos render platform command. Tags with a "holos_"
|
||||
// prefix are reserved for use by the Holos Authors.
|
||||
Tags map[string]string `json:"tags,omitempty"`
|
||||
// WriteTo represents the holos render component --write-to flag. If empty,
|
||||
// the default value for the --write-to flag is used.
|
||||
WriteTo string `json:"writeTo,omitempty"`
|
||||
}
|
||||
|
||||
// Tags represents standardized fields injected into the component [BuildPlan]
|
||||
// from the [Platform].
|
||||
//
|
||||
// Note, tags should have a reasonable default value to easily use cue eval and
|
||||
// cue export without needing to make a bunch of decisions about tag values.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// import core "github.com/holos-run/holos/api/core/v1alpha4"
|
||||
// _Tags: core.#Tags & {
|
||||
// cluster: _ @tag(cluster, type=string)
|
||||
// environment: _ @tag(environment, type=string)
|
||||
// component: _ @tag(component, type=string)
|
||||
// name: _ @tag(name, type=string)
|
||||
// }
|
||||
type Tags struct {
|
||||
// Name represents the BuildPlan metadata.name field injected from the Platform.
|
||||
Name string `json:"name" cue:"string | *\"no-name\""`
|
||||
// Cluster represents the cluster name injected from
|
||||
Cluster string `json:"cluster" cue:"string | *\"no-cluster\""`
|
||||
// Environment represents the build plan environment.
|
||||
Environment string `json:"environment" cue:"string | *\"no-environment\""`
|
||||
// Component represents the path of the component relative to the platform root.
|
||||
Component string `json:"component" cue:"string | *\"no-component\""`
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
description: Simplified abstraction to generate core v1alpha3 components.
|
||||
sidebar_position: 997
|
||||
---
|
||||
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
|
||||
|
||||
# v1alpha3
|
||||
|
||||
381
doc/md/api/author/v1alpha4.md
Normal file
@@ -0,0 +1,381 @@
|
||||
---
|
||||
description: Simplified abstraction to generate core v1alpha4 build plans.
|
||||
sidebar_position: 996
|
||||
---
|
||||
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
|
||||
|
||||
# v1alpha4
|
||||
|
||||
```go
|
||||
import "github.com/holos-run/holos/api/author/v1alpha4"
|
||||
```
|
||||
|
||||
### Author API
|
||||
|
||||
Package v1alpha4 contains ergonomic CUE definitions for Holos component authors. These definitions serve as adapters to produce [Core API](<https://holos.run/docs/api/core/v1alpha4/>) resources for the holos command line tool.
|
||||
|
||||
## Index
|
||||
|
||||
- [type ArgoConfig](<#ArgoConfig>)
|
||||
- [type Cluster](<#Cluster>)
|
||||
- [type ComponentConfig](<#ComponentConfig>)
|
||||
- [type Fleet](<#Fleet>)
|
||||
- [type Helm](<#Helm>)
|
||||
- [type Hostname](<#Hostname>)
|
||||
- [type Kubernetes](<#Kubernetes>)
|
||||
- [type Kustomize](<#Kustomize>)
|
||||
- [type KustomizeConfig](<#KustomizeConfig>)
|
||||
- [type NameLabel](<#NameLabel>)
|
||||
- [type Namespace](<#Namespace>)
|
||||
- [type Organization](<#Organization>)
|
||||
- [type OrganizationStrict](<#OrganizationStrict>)
|
||||
- [type Owner](<#Owner>)
|
||||
- [type Platform](<#Platform>)
|
||||
- [type Project](<#Project>)
|
||||
- [type Projects](<#Projects>)
|
||||
- [type StandardFleets](<#StandardFleets>)
|
||||
|
||||
|
||||
<a name="ArgoConfig"></a>
|
||||
## type ArgoConfig {#ArgoConfig}
|
||||
|
||||
ArgoConfig represents the ArgoCD GitOps configuration associated with a [BuildPlan](<https://holos.run/docs/api/core/v1alpha4/#buildplan>). Useful to define once at the root of the Platform configuration and reuse across all components.
|
||||
|
||||
```go
|
||||
type ArgoConfig struct {
|
||||
// Enabled causes holos to render an Application resource when true.
|
||||
Enabled bool `cue:"true | *false"`
|
||||
// RepoURL represents the value passed to the Application.spec.source.repoURL
|
||||
// field.
|
||||
RepoURL string
|
||||
// Root represents the path from the git repository root to the WriteTo output
|
||||
// directory, the behavior of the holos render component --write-to flag and
|
||||
// the Core API Component WriteTo field. Used as a prefix for the
|
||||
// Application.spec.source.path field.
|
||||
Root string `cue:"string | *\"deploy\""`
|
||||
// TargetRevision represents the value passed to the
|
||||
// Application.spec.source.targetRevision field. Defaults to the branch named
|
||||
// main.
|
||||
TargetRevision string `cue:"string | *\"main\""`
|
||||
// AppProject represents the ArgoCD Project to associate the Application with.
|
||||
AppProject string `cue:"string | *\"default\""`
|
||||
}
|
||||
```
|
||||
|
||||
<a name="Cluster"></a>
|
||||
## type Cluster {#Cluster}
|
||||
|
||||
Cluster represents a cluster managed by the Platform.
|
||||
|
||||
```go
|
||||
type Cluster struct {
|
||||
// Name represents the cluster name, for example "east1", "west1", or
|
||||
// "management".
|
||||
Name string `json:"name"`
|
||||
// Primary represents if the cluster is marked as the primary among a set of
|
||||
// candidate clusters. Useful for promotion of database leaders.
|
||||
Primary bool `json:"primary" cue:"true | *false"`
|
||||
}
|
||||
```
|
||||
|
||||
<a name="ComponentConfig"></a>
|
||||
## type ComponentConfig {#ComponentConfig}
|
||||
|
||||
ComponentConfig represents the configuration common to all kinds of component.
|
||||
|
||||
- [Helm](<#Helm>) charts.
|
||||
- [Kubernetes](<#Kubernetes>) resources generated from CUE.
|
||||
- [Kustomize](<#Kustomize>) bases.
|
||||
|
||||
See the following resources for additional details:
|
||||
|
||||
- [Resources](<https://holos.run/docs/api/core/v1alpha4/#Resources>)
|
||||
- [ArgoConfig](<#ArgoConfig>)
|
||||
- [KustomizeConfig](<#KustomizeConfig>)
|
||||
- [BuildPlan](<https://holos.run/docs/api/core/v1alpha4/#BuildPlan>)
|
||||
|
||||
```go
|
||||
type ComponentConfig struct {
|
||||
// Name represents the BuildPlan metadata.name field. Used to construct the
|
||||
// fully rendered manifest file path.
|
||||
Name string
|
||||
// Component represents the path to the component producing the BuildPlan.
|
||||
Component string
|
||||
// Cluster represents the name of the cluster this BuildPlan is for.
|
||||
Cluster string
|
||||
// Resources represents kubernetes resources mixed into the rendered manifest.
|
||||
Resources core.Resources
|
||||
// ArgoConfig represents the ArgoCD GitOps configuration for this BuildPlan.
|
||||
ArgoConfig ArgoConfig
|
||||
// CommonLabels represents common labels to manage on all rendered manifests.
|
||||
CommonLabels map[string]string
|
||||
// Namespace manages the metadata.namespace field on all resources except the
|
||||
// ArgoCD Application.
|
||||
Namespace string `json:",omitempty"`
|
||||
|
||||
// KustomizeConfig represents the configuration for kustomize.
|
||||
KustomizeConfig KustomizeConfig
|
||||
}
|
||||
```
|
||||
|
||||
<a name="Fleet"></a>
|
||||
## type Fleet {#Fleet}
|
||||
|
||||
Fleet represents a named collection of similarly configured Clusters. Useful to segregate workload clusters from their management cluster.
|
||||
|
||||
```go
|
||||
type Fleet struct {
|
||||
Name string `json:"name"`
|
||||
// Clusters represents a mapping of Clusters by their name.
|
||||
Clusters map[string]Cluster `json:"clusters" cue:"{[Name=_]: name: Name}"`
|
||||
}
|
||||
```
|
||||
|
||||
<a name="Helm"></a>
|
||||
## type Helm {#Helm}
|
||||
|
||||
Helm provides a [BuildPlan](<https://holos.run/docs/api/core/v1alpha4/#BuildPlan>) via the Output field which generates manifests from a helm chart with optional mix\-in resources provided directly from CUE in the Resources field.
|
||||
|
||||
This definition is a convenient way to produce a [BuildPlan](<https://holos.run/docs/api/core/v1alpha4/#BuildPlan>) composed of three \[Resources\] generators with one [Kustomize](<#Kustomize>) transformer.
|
||||
|
||||
See related:
|
||||
|
||||
- [ComponentConfig](<#ComponentConfig>)
|
||||
- [Chart](<https://holos.run/docs/api/core/v1alpha4/#Chart>)
|
||||
- [Values](<https://holos.run/docs/api/core/v1alpha4/#Values>)
|
||||
- [BuildPlan](<https://holos.run/docs/api/core/v1alpha4/#BuildPlan>)
|
||||
|
||||
```go
|
||||
type Helm struct {
|
||||
ComponentConfig `json:",inline"`
|
||||
|
||||
// Chart represents a Helm chart.
|
||||
Chart core.Chart
|
||||
// Values represents data to marshal into a values.yaml for helm.
|
||||
Values core.Values
|
||||
// EnableHooks enables helm hooks when executing the `helm template` command.
|
||||
EnableHooks bool
|
||||
|
||||
// BuildPlan represents the derived BuildPlan produced for the holos render
|
||||
// component command.
|
||||
BuildPlan core.BuildPlan
|
||||
}
|
||||
```
|
||||
|
||||
<a name="Hostname"></a>
|
||||
## type Hostname {#Hostname}
|
||||
|
||||
Hostname represents the left most dns label of a domain name.
|
||||
|
||||
```go
|
||||
type Hostname struct {
|
||||
// Name represents the subdomain to expose, e.g. "www"
|
||||
Name string
|
||||
// Namespace represents the namespace metadata.name field of backend object
|
||||
// reference.
|
||||
Namespace string
|
||||
// Service represents the Service metadata.name field of backend object
|
||||
// reference.
|
||||
Service string
|
||||
// Port represents the Service port of the backend object reference.
|
||||
Port int
|
||||
}
|
||||
```
|
||||
|
||||
<a name="Kubernetes"></a>
|
||||
## type Kubernetes {#Kubernetes}
|
||||
|
||||
Kubernetes provides a [BuildPlan](<https://holos.run/docs/api/core/v1alpha4/#BuildPlan>) via the Output field which contains inline API Objects provided directly from CUE in the Resources field of [ComponentConfig](<#ComponentConfig>).
|
||||
|
||||
See related:
|
||||
|
||||
- [ComponentConfig](<#ComponentConfig>)
|
||||
- [BuildPlan](<https://holos.run/docs/api/core/v1alpha4/#BuildPlan>)
|
||||
|
||||
```go
|
||||
type Kubernetes struct {
|
||||
ComponentConfig `json:",inline"`
|
||||
|
||||
// BuildPlan represents the derived BuildPlan produced for the holos render
|
||||
// component command.
|
||||
BuildPlan core.BuildPlan
|
||||
}
|
||||
```
|
||||
|
||||
<a name="Kustomize"></a>
|
||||
## type Kustomize {#Kustomize}
|
||||
|
||||
Kustomize provides a [BuildPlan](<https://holos.run/docs/api/core/v1alpha4/#buildplan>) via the Output field which generates manifests from a kustomize kustomization with optional mix\-in resources provided directly from CUE in the Resources field.
|
||||
|
||||
See related:
|
||||
|
||||
- [ComponentConfig](<#ComponentConfig>)
|
||||
- [BuildPlan](<https://holos.run/docs/api/core/v1alpha4/#buildplan>)
|
||||
|
||||
```go
|
||||
type Kustomize struct {
|
||||
ComponentConfig `json:",inline"`
|
||||
|
||||
// BuildPlan represents the derived BuildPlan produced for the holos render
|
||||
// component command.
|
||||
BuildPlan core.BuildPlan
|
||||
}
|
||||
```
|
||||
|
||||
<a name="KustomizeConfig"></a>
|
||||
## type KustomizeConfig {#KustomizeConfig}
|
||||
|
||||
KustomizeConfig represents the configuration for kustomize post processing. The Files field is used to mixing in static manifest files from the component directory. The Resources field is used for mixing in manifests from network locations urls.
|
||||
|
||||
See related:
|
||||
|
||||
- [ComponentConfig](<#ComponentConfig>)
|
||||
- [Kustomization](<https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/>)
|
||||
|
||||
```go
|
||||
type KustomizeConfig struct {
|
||||
// Kustomization represents the kustomization used to transform resources.
|
||||
// Note the resources field is internally managed from the Files and Resources fields.
|
||||
Kustomization map[string]any `json:",omitempty"`
|
||||
// Files represents files to copy from the component directory for kustomization.
|
||||
Files map[string]struct{ Source string } `cue:"{[NAME=_]: Source: NAME}"`
|
||||
// Resources represents additional entries to included in the resources list.
|
||||
Resources map[string]struct{ Source string } `cue:"{[NAME=_]: Source: NAME}"`
|
||||
}
|
||||
```
|
||||
|
||||
<a name="NameLabel"></a>
|
||||
## type NameLabel {#NameLabel}
|
||||
|
||||
NameLabel signals the common use case of converting a struct to a list where the name field of each value unifies with the field name of the outer struct.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
S: [NameLabel=string]: name: NameLabel
|
||||
S: jeff: _
|
||||
S: gary: _
|
||||
S: nate: _
|
||||
L: [for x in S {x}]
|
||||
// L is [{name: "jeff"}, {name: "gary"}, {name: "nate"}]
|
||||
```
|
||||
|
||||
```go
|
||||
type NameLabel string
|
||||
```
|
||||
|
||||
<a name="Namespace"></a>
|
||||
## type Namespace {#Namespace}
|
||||
|
||||
Namespace represents a Kubernetes namespace.
|
||||
|
||||
```go
|
||||
type Namespace struct {
|
||||
Name string
|
||||
}
|
||||
```
|
||||
|
||||
<a name="Organization"></a>
|
||||
## type Organization {#Organization}
|
||||
|
||||
Organization represents organizational metadata useful across the platform.
|
||||
|
||||
```go
|
||||
type Organization struct {
|
||||
Name string
|
||||
DisplayName string
|
||||
Domain string
|
||||
}
|
||||
```
|
||||
|
||||
<a name="OrganizationStrict"></a>
|
||||
## type OrganizationStrict {#OrganizationStrict}
|
||||
|
||||
OrganizationStrict represents organizational metadata useful across the platform. This is an example of using CUE regular expressions to constrain and validate configuration.
|
||||
|
||||
```go
|
||||
type OrganizationStrict struct {
|
||||
Organization `json:",inline"`
|
||||
// Name represents the organization name as a resource name. Must be 63
|
||||
// characters or less. Must start with a letter. May contain non-repeating
|
||||
// hyphens, letters, and numbers. Must end with a letter or number.
|
||||
Name string `cue:"=~ \"^[a-z][0-9a-z-]{1,61}[0-9a-z]$\" & !~ \"--\""`
|
||||
// DisplayName represents the human readable organization name.
|
||||
DisplayName string `cue:"=~ \"^[0-9A-Za-z][0-9A-Za-z ]{2,61}[0-9A-Za-z]$\" & !~ \" \""`
|
||||
}
|
||||
```
|
||||
|
||||
<a name="Owner"></a>
|
||||
## type Owner {#Owner}
|
||||
|
||||
Owner represents the owner of a resource. For example, the name and email address of an engineering team.
|
||||
|
||||
```go
|
||||
type Owner struct {
|
||||
Name string
|
||||
Email string
|
||||
}
|
||||
```
|
||||
|
||||
<a name="Platform"></a>
|
||||
## type Platform {#Platform}
|
||||
|
||||
Platform assembles a Core API [Platform](<https://holos.run/docs/api/core/v1alpha4/#Platform>) in the Resource field for the holos render platform command. Use the Components field to register components with the platform using a struct. This struct is converted into a list for final output to holos.
|
||||
|
||||
See related:
|
||||
|
||||
- [Component](<https://holos.run/docs/api/core/v1alpha4/#Component>) collection of components composing the platform.
|
||||
- [Platform](<https://holos.run/docs/api/core/v1alpha4/#Platform>) resource assembled for holos to process.
|
||||
|
||||
```go
|
||||
type Platform struct {
|
||||
Name string
|
||||
Components map[NameLabel]core.Component
|
||||
Resource core.Platform
|
||||
}
|
||||
```
|
||||
|
||||
<a name="Project"></a>
|
||||
## type Project {#Project}
|
||||
|
||||
Project represents logical grouping of components owned by one or more teams. Useful for the platform team to manage resources for project teams to use.
|
||||
|
||||
```go
|
||||
type Project struct {
|
||||
// Name represents project name.
|
||||
Name string
|
||||
// Owner represents the team who own this project.
|
||||
Owner Owner
|
||||
// Namespaces represents the namespaces assigned to this project.
|
||||
Namespaces map[NameLabel]Namespace
|
||||
// Hostnames represents the host names to expose for this project.
|
||||
Hostnames map[NameLabel]Hostname
|
||||
// CommonLabels represents common labels to manage on all rendered manifests.
|
||||
CommonLabels map[string]string
|
||||
}
|
||||
```
|
||||
|
||||
<a name="Projects"></a>
|
||||
## type Projects {#Projects}
|
||||
|
||||
Projects represents projects managed by the platform team for use by other teams using the platform.
|
||||
|
||||
```go
|
||||
type Projects map[NameLabel]Project
|
||||
```
|
||||
|
||||
<a name="StandardFleets"></a>
|
||||
## type StandardFleets {#StandardFleets}
|
||||
|
||||
StandardFleets represents the standard set of Clusters in a Platform segmented into Fleets by their purpose. The management Fleet contains a single Cluster, for example a GKE autopilot cluster with no workloads deployed for reliability and cost efficiency. The workload Fleet contains all other Clusters which contain workloads and sync Secrets from the management cluster.
|
||||
|
||||
```go
|
||||
type StandardFleets struct {
|
||||
// Workload represents a Fleet of zero or more workload Clusters.
|
||||
Workload Fleet `json:"workload" cue:"{name: \"workload\"}"`
|
||||
// Management represents a Fleet with one Cluster named management.
|
||||
Management Fleet `json:"management" cue:"{name: \"management\"}"`
|
||||
}
|
||||
```
|
||||
|
||||
Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
description: Core v1alpha4 schema for advanced use cases.
|
||||
sidebar_position: 998
|
||||
---
|
||||
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
|
||||
|
||||
# v1alpha2
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
description: Core v1alpha3 schema for advanced use cases.
|
||||
sidebar_position: 997
|
||||
---
|
||||
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
|
||||
|
||||
# v1alpha3
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
description: Core v1alpha2 schema for advanced use cases.
|
||||
sidebar_position: 996
|
||||
---
|
||||
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
|
||||
|
||||
# v1alpha4
|
||||
@@ -6,11 +10,60 @@
|
||||
import "github.com/holos-run/holos/api/core/v1alpha4"
|
||||
```
|
||||
|
||||
Package v1alpha4 contains the core API contract between the holos cli and CUE configuration code. Platform designers, operators, and software developers use this API to write configuration in CUE which \`holos\` loads. The overall shape of the API defines imperative actions \`holos\` should carry out to render the complete yaml that represents a Platform.
|
||||
### Core API
|
||||
|
||||
[Platform](<#Platform>) defines the complete configuration of a platform. With the holos reference platform this takes the shape of one management cluster and at least two workload clusters.
|
||||
Package v1alpha4 contains the core API contract between the holos cli and CUE configuration code. Platform designers, operators, and software developers use this API to write configuration in CUE which holos loads. The Core API is declarative. Each resource represents a desired state necessary for holos to fully render Kubernetes manifests into plain files.
|
||||
|
||||
Each holos component path, e.g. \`components/namespaces\` produces exactly one [BuildPlan](<#BuildPlan>) which produces an [Artifact](<#Artifact>) collection. An [Artifact](<#Artifact>) is a fully rendered manifest produced from a [Transformer](<#Transformer>) sequence, which transforms a [Generator](<#Generator>) collection.
|
||||
The following resources provide important context for the Core API. The [Author API](<https://holos.run/docs/api/author/>) is intended for component authors as a convenient adapter for the Core API resources Holos expects.
|
||||
|
||||
1. [Technical Overview](<https://holos.run/docs/technical-overview/>)
|
||||
2. [Quickstart](<https://holos.run/docs/quickstart/>)
|
||||
3. [Author API](<https://holos.run/docs/api/author/>)
|
||||
|
||||
### Platform
|
||||
|
||||
[Platform](<#Platform>) defines the complete configuration of a platform. A platform represents a [Component](<#Component>) collection.
|
||||
|
||||
Inspect a Platform resource holos would process by executing:
|
||||
|
||||
```
|
||||
cue export --out yaml ./platform
|
||||
```
|
||||
|
||||
### Component
|
||||
|
||||
A [Component](<#Component>) is the combination of CUE code along one path relative to the platform root directory plus data injected from the [PlatformSpec](<#PlatformSpec>) via CUE tags. The platform configuration root is the directory containing cue.mod.
|
||||
|
||||
A [Component](<#Component>) always produces exactly one [BuildPlan](<#BuildPlan>).
|
||||
|
||||
### BuildPlan
|
||||
|
||||
A [BuildPlan](<#BuildPlan>) contains an [Artifact](<#Artifact>) collection. A BuildPlan often produces two artifacts, one containing the fully rendered Kubernetes API resources, the other containing an additional resource to manage the former with GitOps. For example, a BuildPlan for a podinfo component produces a manifest containing a Deployment and a Service, along with a second manifest containing an ArgoCD Application.
|
||||
|
||||
Inspect a BuildPlan resource holos render component would process by executing:
|
||||
|
||||
```
|
||||
cue export --out yaml ./projects/platform/components/namespaces
|
||||
```
|
||||
|
||||
### Artifact
|
||||
|
||||
An [Artifact](<#Artifact>) is one fully rendered manifest file produced from the final [Transformer](<#Transformer>) in a sequence of transformers. An Artifact may also be produced directly from a [Generator](<#Generator>), but this use case is uncommon.
|
||||
|
||||
### Transformer
|
||||
|
||||
A [Transformer](<#Transformer>) takes multiple inputs from prior [Generator](<#Generator>) or [Transformer](<#Transformer>) outputs, then transforms the data into one output. [Kustomize](<#Kustomize>) is the most commonly used transformer, though a simple [Join](<#Join>) is also supported.
|
||||
|
||||
1. [Kustomize](<#Kustomize>) \- Patch and transform the output from prior generators or transformers. See [Introduction to Kustomize](<https://kubectl.docs.kubernetes.io/guides/config_management/introduction/>).
|
||||
2. [Join](<#Join>) \- Concatenate multiple prior outputs into one output.
|
||||
|
||||
### Generators
|
||||
|
||||
A [Generator](<#Generator>) generates Kubernetes resources. [Helm](<#Helm>) and [Resources](<#Resources>) are the most commonly used, often paired together to mix\-in resources to an unmodified Helm chart. A simple [File](<#File>) generator is also available for use with the [Kustomize](<#Kustomize>) transformer.
|
||||
|
||||
1. [Resources](<#Resources>) \- Generates resources from CUE code.
|
||||
2. [Helm](<#Helm>) \- Generates rendered yaml from a [Chart](<#Chart>).
|
||||
3. [File](<#File>) \- Generates data by reading a file from the component directory.
|
||||
|
||||
## Index
|
||||
|
||||
@@ -37,6 +90,7 @@ Each holos component path, e.g. \`components/namespaces\` produces exactly one [
|
||||
- [type Repository](<#Repository>)
|
||||
- [type Resource](<#Resource>)
|
||||
- [type Resources](<#Resources>)
|
||||
- [type Tags](<#Tags>)
|
||||
- [type Transformer](<#Transformer>)
|
||||
- [type Values](<#Values>)
|
||||
|
||||
@@ -70,6 +124,50 @@ BuildPlan represents a build plan for holos to execute. Each [Platform](<#Platfo
|
||||
|
||||
One or more [Artifact](<#Artifact>) files are produced by a BuildPlan, representing the fully rendered manifests for the Kubernetes API Server.
|
||||
|
||||
### Example BuildPlan
|
||||
|
||||
Command:
|
||||
|
||||
```
|
||||
cue export --out yaml ./projects/platform/components/namespaces
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
kind: BuildPlan
|
||||
apiVersion: v1alpha4
|
||||
metadata:
|
||||
name: dev-namespaces
|
||||
spec:
|
||||
component: projects/platform/components/namespaces
|
||||
artifacts:
|
||||
- artifact: clusters/no-cluster/components/dev-namespaces/dev-namespaces.gen.yaml
|
||||
generators:
|
||||
- kind: Resources
|
||||
output: resources.gen.yaml
|
||||
resources:
|
||||
Namespace:
|
||||
dev-jeff:
|
||||
metadata:
|
||||
name: dev-jeff
|
||||
labels:
|
||||
kubernetes.io/metadata.name: dev-jeff
|
||||
kind: Namespace
|
||||
apiVersion: v1
|
||||
transformers:
|
||||
- kind: Kustomize
|
||||
inputs:
|
||||
- resources.gen.yaml
|
||||
output: clusters/no-cluster/components/dev-namespaces/dev-namespaces.gen.yaml
|
||||
kustomize:
|
||||
kustomization:
|
||||
commonLabels:
|
||||
holos.run/component.name: dev-namespaces
|
||||
resources:
|
||||
- resources.gen.yaml
|
||||
```
|
||||
|
||||
```go
|
||||
type BuildPlan struct {
|
||||
// Kind represents the type of the resource.
|
||||
@@ -121,29 +219,33 @@ type Chart struct {
|
||||
<a name="Component"></a>
|
||||
## type Component {#Component}
|
||||
|
||||
Component represents the complete context necessary to produce a [BuildPlan](<#BuildPlan>) from a [Platform](<#Platform>) component.
|
||||
Component represents the complete context necessary to produce a [BuildPlan](<#BuildPlan>). Component carries information injected from holos render platform to holos render component to produce each [BuildPlan](<#BuildPlan>).
|
||||
|
||||
All of these fields are passed to the holos render component command using flags, which in turn are injected to CUE using tags. Field names should be used consistently through the platform rendering process for readability.
|
||||
All of these fields are passed to the holos render component command using flags, which in turn are injected to CUE using tags. For clarity, CUE field and tag names should match the struct json tag names below.
|
||||
|
||||
```go
|
||||
type Component struct {
|
||||
// Name represents the name of the component, injected as a tag to set the
|
||||
// BuildPlan metadata.name field. Necessary for clear user feedback during
|
||||
// platform rendering.
|
||||
// Name represents the name of the component. Injected as the tag variable
|
||||
// "holos_name" to set the BuildPlan metadata.name field. Necessary for clear
|
||||
// user feedback during platform rendering.
|
||||
Name string `json:"name"`
|
||||
// Component represents the path of the component relative to the platform root.
|
||||
// Component represents the path of the component relative to the platform
|
||||
// root. Injected as the tag variable "holos_component".
|
||||
Component string `json:"component"`
|
||||
// Cluster is the cluster name to provide when rendering the component.
|
||||
// Injected as the tag variable "holos_cluster".
|
||||
Cluster string `json:"cluster"`
|
||||
// Environment for example, dev, test, stage, prod
|
||||
Environment string `json:"environment,omitempty"`
|
||||
// Model represents the platform model holos gets from from the
|
||||
// PlatformService.GetPlatform rpc method and provides to CUE using a tag.
|
||||
Model map[string]any `json:"model"`
|
||||
// Tags represents cue tags to inject when rendering the component. The json
|
||||
// struct tag names of other fields in this struct are reserved tag names not
|
||||
// to be used in the tags collection.
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
// Injected as the tag "holos_model".
|
||||
Model map[string]any `json:"model,omitempty"`
|
||||
// Tags represents cue @tag variables injected into the holos render component
|
||||
// command from the holos render platform command. Tags with a "holos_"
|
||||
// prefix are reserved for use by the Holos Authors.
|
||||
Tags map[string]string `json:"tags,omitempty"`
|
||||
// WriteTo represents the holos render component --write-to flag. If empty,
|
||||
// the default value for the --write-to flag is used.
|
||||
WriteTo string `json:"writeTo,omitempty"`
|
||||
}
|
||||
```
|
||||
|
||||
@@ -245,7 +347,7 @@ type InternalLabel string
|
||||
<a name="Join"></a>
|
||||
## type Join {#Join}
|
||||
|
||||
Join represents a [Join](<#Join>)\(https://pkg.go.dev/strings#Join\) [Transformer](<#Transformer>). Useful for the common case of combining the output of [Helm](<#Helm>) and [Resources](<#Resources>) [Generator](<#Generator>) into one [Artifact](<#Artifact>) when [Kustomize](<#Kustomize>) is otherwise unnecessary.
|
||||
Join represents a [Transformer](<#Transformer>) using [bytes.Join](<https://pkg.go.dev/bytes#Join>) to concatenate multiple inputs into one output with a separator. Useful for combining output from [Helm](<#Helm>) and [Resources](<#Resources>) together into one [Artifact](<#Artifact>) when [Kustomize](<#Kustomize>) is otherwise unnecessary.
|
||||
|
||||
```go
|
||||
type Join struct {
|
||||
@@ -373,6 +475,38 @@ Resources represents a kubernetes resources [Generator](<#Generator>) from CUE.
|
||||
type Resources map[Kind]map[InternalLabel]Resource
|
||||
```
|
||||
|
||||
<a name="Tags"></a>
|
||||
## type Tags {#Tags}
|
||||
|
||||
Tags represents standardized fields injected into the component [BuildPlan](<#BuildPlan>) from the [Platform](<#Platform>).
|
||||
|
||||
Note, tags should have a reasonable default value to easily use cue eval and cue export without needing to make a bunch of decisions about tag values.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
import core "github.com/holos-run/holos/api/core/v1alpha4"
|
||||
_Tags: core.#Tags & {
|
||||
cluster: _ @tag(cluster, type=string)
|
||||
environment: _ @tag(environment, type=string)
|
||||
component: _ @tag(component, type=string)
|
||||
name: _ @tag(name, type=string)
|
||||
}
|
||||
```
|
||||
|
||||
```go
|
||||
type Tags struct {
|
||||
// Name represents the BuildPlan metadata.name field injected from the Platform.
|
||||
Name string `json:"name" cue:"string | *\"no-name\""`
|
||||
// Cluster represents the cluster name injected from
|
||||
Cluster string `json:"cluster" cue:"string | *\"no-cluster\""`
|
||||
// Environment represents the build plan environment.
|
||||
Environment string `json:"environment" cue:"string | *\"no-environment\""`
|
||||
// Component represents the path of the component relative to the platform root.
|
||||
Component string `json:"component" cue:"string | *\"no-component\""`
|
||||
}
|
||||
```
|
||||
|
||||
<a name="Transformer"></a>
|
||||
## type Transformer {#Transformer}
|
||||
|
||||
|
||||
@@ -80,33 +80,62 @@ The bank front end web service is managed by the
|
||||
refers to the organization display name in `schema.gen.cue`.
|
||||
|
||||
<Tabs groupId="F5B546EB-566F-4B83-84C3-C55B40F55555">
|
||||
<TabItem value="schema.gen.cue" label="schema.gen.cue">
|
||||
<TabItem value="schema.cue" label="schema.cue">
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
import api "github.com/holos-run/holos/api/author/v1alpha3"
|
||||
import api "github.com/holos-run/holos/api/author/v1alpha4"
|
||||
|
||||
// Define the default organization name
|
||||
// highlight-next-line
|
||||
#Organization: DisplayName: string | *"Bank of Holos"
|
||||
#Organization: Name: string | *"bank-of-holos"
|
||||
|
||||
#Organization: api.#OrganizationStrict
|
||||
#Platform: api.#Platform
|
||||
#Fleets: api.#StandardFleets
|
||||
|
||||
_ComponentConfig: {
|
||||
Resources: #Resources
|
||||
ArgoConfig: #ArgoConfig
|
||||
// Define the default organization name.
|
||||
_Organization: api.#OrganizationStrict & {
|
||||
DisplayName: string | *"Bank of Holos"
|
||||
Name: string | *"bank-of-holos"
|
||||
Domain: string | *"holos.localhost"
|
||||
}
|
||||
|
||||
#Helm: api.#Helm & _ComponentConfig
|
||||
#Kustomize: api.#Kustomize & _ComponentConfig
|
||||
#Kubernetes: api.#Kubernetes & _ComponentConfig
|
||||
// Projects represents a way to organize components into projects with owners.
|
||||
// https://holos.run/docs/api/author/v1alpha4/#Projects
|
||||
_Projects: api.#Projects
|
||||
|
||||
#ArgoConfig: api.#ArgoConfig & {
|
||||
ClusterName: _ClusterName
|
||||
// ArgoConfig represents the configuration of ArgoCD Application resources for
|
||||
// each component.
|
||||
// https://holos.run/docs/api/author/v1alpha4/#ArgoConfig
|
||||
_ArgoConfig: api.#ArgoConfig
|
||||
|
||||
#ComponentConfig: api.#ComponentConfig & {
|
||||
Name: _Tags.name
|
||||
Component: _Tags.component
|
||||
Cluster: _Tags.cluster
|
||||
ArgoConfig: _ArgoConfig & {
|
||||
if _Tags.project != "no-project" {
|
||||
AppProject: _Tags.project
|
||||
}
|
||||
}
|
||||
Resources: #Resources
|
||||
|
||||
// Mix in project labels if the project is defined by the platform.
|
||||
if _Tags.project != "no-project" {
|
||||
CommonLabels: _Projects[_Tags.project].CommonLabels
|
||||
}
|
||||
}
|
||||
|
||||
// https://holos.run/docs/api/author/v1alpha4/#Kubernetes
|
||||
#Kubernetes: close({
|
||||
#ComponentConfig
|
||||
api.#Kubernetes
|
||||
})
|
||||
|
||||
// https://holos.run/docs/api/author/v1alpha4/#Kustomize
|
||||
#Kustomize: close({
|
||||
#ComponentConfig
|
||||
api.#Kustomize
|
||||
})
|
||||
|
||||
// https://holos.run/docs/api/author/v1alpha4/#Helm
|
||||
#Helm: close({
|
||||
#ComponentConfig
|
||||
api.#Helm
|
||||
})
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="projects/bank-of-holos/frontend/components/bank-frontend/bank-frontend.cue" label="projects/bank-of-holos/frontend/components/bank-frontend/bank-frontend.cue">
|
||||
@@ -117,215 +146,214 @@ package holos
|
||||
(#Kubernetes & Objects).BuildPlan
|
||||
|
||||
let Objects = {
|
||||
Name: "bank-frontend"
|
||||
Namespace: #BankOfHolos.Frontend.Namespace
|
||||
Name: "bank-frontend"
|
||||
Namespace: _BankOfHolos.Frontend.Namespace
|
||||
|
||||
// Ensure resources go in the correct namespace
|
||||
Resources: [_]: [_]: metadata: namespace: Namespace
|
||||
// Ensure resources go in the correct namespace
|
||||
Resources: [_]: [_]: metadata: namespace: Namespace
|
||||
|
||||
// https://github.com/GoogleCloudPlatform/bank-of-anthos/blob/release/v0.6.5/kubernetes-manifests/frontend.yaml
|
||||
Resources: {
|
||||
Service: frontend: {
|
||||
metadata: name: "frontend"
|
||||
metadata: labels: {
|
||||
application: "bank-of-holos"
|
||||
environment: "development"
|
||||
team: "frontend"
|
||||
tier: "web"
|
||||
}
|
||||
spec: {
|
||||
selector: {
|
||||
app: "frontend"
|
||||
application: "bank-of-holos"
|
||||
environment: "development"
|
||||
team: "frontend"
|
||||
tier: "web"
|
||||
}
|
||||
_ports: http: {
|
||||
name: "http"
|
||||
port: 80
|
||||
targetPort: 8080
|
||||
protocol: "TCP"
|
||||
}
|
||||
ports: [for x in _ports {x}]
|
||||
}
|
||||
}
|
||||
// https://github.com/GoogleCloudPlatform/bank-of-anthos/blob/release/v0.6.5/kubernetes-manifests/frontend.yaml
|
||||
Resources: {
|
||||
Service: frontend: {
|
||||
metadata: name: "frontend"
|
||||
metadata: labels: {
|
||||
application: "bank-of-holos"
|
||||
environment: "development"
|
||||
team: "frontend"
|
||||
tier: "web"
|
||||
}
|
||||
spec: {
|
||||
selector: {
|
||||
app: "frontend"
|
||||
application: "bank-of-holos"
|
||||
environment: "development"
|
||||
team: "frontend"
|
||||
tier: "web"
|
||||
}
|
||||
_ports: http: {
|
||||
name: "http"
|
||||
port: 80
|
||||
targetPort: 8080
|
||||
protocol: "TCP"
|
||||
}
|
||||
ports: [for x in _ports {x}]
|
||||
}
|
||||
}
|
||||
|
||||
Deployment: frontend: {
|
||||
metadata: name: "frontend"
|
||||
metadata: labels: {
|
||||
application: "bank-of-holos"
|
||||
environment: "development"
|
||||
team: "frontend"
|
||||
tier: "web"
|
||||
}
|
||||
spec: {
|
||||
selector: matchLabels: {
|
||||
app: "frontend"
|
||||
application: "bank-of-holos"
|
||||
environment: "development"
|
||||
team: "frontend"
|
||||
tier: "web"
|
||||
}
|
||||
template: {
|
||||
metadata: labels: {
|
||||
app: "frontend"
|
||||
application: "bank-of-holos"
|
||||
environment: "development"
|
||||
team: "frontend"
|
||||
tier: "web"
|
||||
}
|
||||
spec: {
|
||||
securityContext: {
|
||||
seccompProfile: type: "RuntimeDefault"
|
||||
fsGroup: 1000
|
||||
runAsGroup: 1000
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
}
|
||||
serviceAccountName: "bank-of-holos"
|
||||
terminationGracePeriodSeconds: 5
|
||||
containers: [{
|
||||
env: [{
|
||||
name: "BANK_NAME"
|
||||
// highlight-next-line
|
||||
value: #Organization.DisplayName
|
||||
}, {
|
||||
name: "ENV_PLATFORM"
|
||||
value: "local"
|
||||
}, {
|
||||
name: "VERSION"
|
||||
value: "v0.6.5"
|
||||
}, {
|
||||
name: "PORT"
|
||||
value: "8080"
|
||||
}, {
|
||||
name: "ENABLE_TRACING"
|
||||
value: "false"
|
||||
}, {
|
||||
name: "SCHEME"
|
||||
value: "https"
|
||||
}, {
|
||||
name: "LOG_LEVEL"
|
||||
value: "info"
|
||||
}, {
|
||||
name: "DEFAULT_USERNAME"
|
||||
valueFrom: configMapKeyRef: {
|
||||
key: "DEMO_LOGIN_USERNAME"
|
||||
name: "demo-data-config"
|
||||
}
|
||||
}, {
|
||||
name: "DEFAULT_PASSWORD"
|
||||
valueFrom: configMapKeyRef: {
|
||||
key: "DEMO_LOGIN_PASSWORD"
|
||||
name: "demo-data-config"
|
||||
}
|
||||
}, {
|
||||
name: "REGISTERED_OAUTH_CLIENT_ID"
|
||||
valueFrom: configMapKeyRef: {
|
||||
key: "DEMO_OAUTH_CLIENT_ID"
|
||||
name: "oauth-config"
|
||||
optional: true
|
||||
}
|
||||
}, {
|
||||
name: "ALLOWED_OAUTH_REDIRECT_URI"
|
||||
valueFrom: configMapKeyRef: {
|
||||
key: "DEMO_OAUTH_REDIRECT_URI"
|
||||
name: "oauth-config"
|
||||
optional: true
|
||||
}
|
||||
}]
|
||||
envFrom: [{
|
||||
configMapRef: name: "environment-config"
|
||||
}, {
|
||||
configMapRef: name: "service-api-config"
|
||||
}]
|
||||
image: "us-central1-docker.pkg.dev/bank-of-anthos-ci/bank-of-anthos/frontend:v0.6.5@sha256:d72050f70d12383e4434ad04d189b681dc625f696087ddf0b5df641645c9dafa"
|
||||
livenessProbe: {
|
||||
httpGet: {
|
||||
path: "/ready"
|
||||
port: 8080
|
||||
}
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 15
|
||||
timeoutSeconds: 30
|
||||
}
|
||||
name: "front"
|
||||
readinessProbe: {
|
||||
httpGet: {
|
||||
path: "/ready"
|
||||
port: 8080
|
||||
}
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 10
|
||||
}
|
||||
resources: {
|
||||
limits: {
|
||||
cpu: "250m"
|
||||
memory: "128Mi"
|
||||
}
|
||||
requests: {
|
||||
cpu: "100m"
|
||||
memory: "64Mi"
|
||||
}
|
||||
}
|
||||
securityContext: {
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities: drop: ["all"]
|
||||
privileged: false
|
||||
readOnlyRootFilesystem: true
|
||||
}
|
||||
volumeMounts: [{
|
||||
mountPath: "/tmp"
|
||||
name: "tmp"
|
||||
}, {
|
||||
mountPath: "/tmp/.ssh"
|
||||
name: "publickey"
|
||||
readOnly: true
|
||||
}]
|
||||
}]
|
||||
volumes: [
|
||||
{
|
||||
emptyDir: {}
|
||||
name: "tmp"
|
||||
},
|
||||
{
|
||||
name: "publickey"
|
||||
secret: {
|
||||
items: [{key: "jwtRS256.key.pub", path: "publickey"}]
|
||||
secretName: "jwt-key"
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Deployment: frontend: {
|
||||
metadata: name: "frontend"
|
||||
metadata: labels: {
|
||||
application: "bank-of-holos"
|
||||
environment: "development"
|
||||
team: "frontend"
|
||||
tier: "web"
|
||||
}
|
||||
spec: {
|
||||
selector: matchLabels: {
|
||||
app: "frontend"
|
||||
application: "bank-of-holos"
|
||||
environment: "development"
|
||||
team: "frontend"
|
||||
tier: "web"
|
||||
}
|
||||
template: {
|
||||
metadata: labels: {
|
||||
app: "frontend"
|
||||
application: "bank-of-holos"
|
||||
environment: "development"
|
||||
team: "frontend"
|
||||
tier: "web"
|
||||
}
|
||||
spec: {
|
||||
securityContext: {
|
||||
seccompProfile: type: "RuntimeDefault"
|
||||
fsGroup: 1000
|
||||
runAsGroup: 1000
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
}
|
||||
serviceAccountName: "bank-of-holos"
|
||||
terminationGracePeriodSeconds: 5
|
||||
containers: [{
|
||||
env: [{
|
||||
name: "BANK_NAME"
|
||||
value: _Organization.DisplayName
|
||||
}, {
|
||||
name: "ENV_PLATFORM"
|
||||
value: "local"
|
||||
}, {
|
||||
name: "VERSION"
|
||||
value: "v0.6.5"
|
||||
}, {
|
||||
name: "PORT"
|
||||
value: "8080"
|
||||
}, {
|
||||
name: "ENABLE_TRACING"
|
||||
value: "false"
|
||||
}, {
|
||||
name: "SCHEME"
|
||||
value: "https"
|
||||
}, {
|
||||
name: "LOG_LEVEL"
|
||||
value: "info"
|
||||
}, {
|
||||
name: "DEFAULT_USERNAME"
|
||||
valueFrom: configMapKeyRef: {
|
||||
key: "DEMO_LOGIN_USERNAME"
|
||||
name: "demo-data-config"
|
||||
}
|
||||
}, {
|
||||
name: "DEFAULT_PASSWORD"
|
||||
valueFrom: configMapKeyRef: {
|
||||
key: "DEMO_LOGIN_PASSWORD"
|
||||
name: "demo-data-config"
|
||||
}
|
||||
}, {
|
||||
name: "REGISTERED_OAUTH_CLIENT_ID"
|
||||
valueFrom: configMapKeyRef: {
|
||||
key: "DEMO_OAUTH_CLIENT_ID"
|
||||
name: "oauth-config"
|
||||
optional: true
|
||||
}
|
||||
}, {
|
||||
name: "ALLOWED_OAUTH_REDIRECT_URI"
|
||||
valueFrom: configMapKeyRef: {
|
||||
key: "DEMO_OAUTH_REDIRECT_URI"
|
||||
name: "oauth-config"
|
||||
optional: true
|
||||
}
|
||||
}]
|
||||
envFrom: [{
|
||||
configMapRef: name: "environment-config"
|
||||
}, {
|
||||
configMapRef: name: "service-api-config"
|
||||
}]
|
||||
image: "us-central1-docker.pkg.dev/bank-of-anthos-ci/bank-of-anthos/frontend:v0.6.5@sha256:d72050f70d12383e4434ad04d189b681dc625f696087ddf0b5df641645c9dafa"
|
||||
livenessProbe: {
|
||||
httpGet: {
|
||||
path: "/ready"
|
||||
port: 8080
|
||||
}
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 15
|
||||
timeoutSeconds: 30
|
||||
}
|
||||
name: "front"
|
||||
readinessProbe: {
|
||||
httpGet: {
|
||||
path: "/ready"
|
||||
port: 8080
|
||||
}
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 10
|
||||
}
|
||||
resources: {
|
||||
limits: {
|
||||
cpu: "250m"
|
||||
memory: "128Mi"
|
||||
}
|
||||
requests: {
|
||||
cpu: "100m"
|
||||
memory: "64Mi"
|
||||
}
|
||||
}
|
||||
securityContext: {
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities: drop: ["all"]
|
||||
privileged: false
|
||||
readOnlyRootFilesystem: true
|
||||
}
|
||||
volumeMounts: [{
|
||||
mountPath: "/tmp"
|
||||
name: "tmp"
|
||||
}, {
|
||||
mountPath: "/tmp/.ssh"
|
||||
name: "publickey"
|
||||
readOnly: true
|
||||
}]
|
||||
}]
|
||||
volumes: [
|
||||
{
|
||||
emptyDir: {}
|
||||
name: "tmp"
|
||||
},
|
||||
{
|
||||
name: "publickey"
|
||||
secret: {
|
||||
items: [{key: "jwtRS256.key.pub", path: "publickey"}]
|
||||
secretName: "jwt-key"
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allow HTTPRoutes in the ingress gateway namespace to reference Services
|
||||
// in this namespace.
|
||||
ReferenceGrant: grant: #ReferenceGrant & {
|
||||
metadata: namespace: Namespace
|
||||
}
|
||||
// Allow HTTPRoutes in the ingress gateway namespace to reference Services
|
||||
// in this namespace.
|
||||
ReferenceGrant: grant: _ReferenceGrant & {
|
||||
metadata: namespace: Namespace
|
||||
}
|
||||
|
||||
// Include shared resources
|
||||
#BankOfHolos.Resources
|
||||
}
|
||||
// Include shared resources
|
||||
_BankOfHolos.Resources
|
||||
}
|
||||
}
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Line 6 of the `schema.gen.cue` file defines the _default_ value for
|
||||
`#Organization.DisplayName` by using `string | *"..."`. In CUE, the `*`
|
||||
Line 7 of the `schema.cue` file defines the _default_ value for
|
||||
`_Organization.DisplayName` by using `string | *"..."`. In CUE, the `*`
|
||||
asterisk character denotes a [default value].
|
||||
|
||||
Line 78 of the `bank-frontend.cue` file refers to `#Organization.DisplayName` to
|
||||
Line 78 of the `bank-frontend.cue` file refers to `_Organization.DisplayName` to
|
||||
configure the front end web container.
|
||||
|
||||
Let's change the name of the bank by defining a new value for
|
||||
`#Organization.DisplayName` at the root of the configuration. Create
|
||||
`_Organization.DisplayName` at the root of the configuration. Create
|
||||
`projects/organization.cue` with the following content.
|
||||
|
||||
<Tabs groupId="B386181F-EBE7-469D-8CB5-37631067669B">
|
||||
@@ -333,7 +361,7 @@ Let's change the name of the bank by defining a new value for
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
#Organization: DisplayName: "The Holistic-Bank"
|
||||
_Organization: DisplayName: "The Holistic-Bank"
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
@@ -348,18 +376,11 @@ holos render platform ./platform
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```txt
|
||||
#Organization.DisplayName: 2 errors in empty disjunction:
|
||||
#Organization.DisplayName: conflicting values "Bank of Holos" and "The Holistic-Bank":
|
||||
/bank-of-holos/projects/organization.cue:3:29
|
||||
/bank-of-holos/schema.gen.cue:6:39
|
||||
// highlight-next-line
|
||||
#Organization.DisplayName: invalid value "The Holistic-Bank" (out of bound =~"^[0-9A-Za-z][0-9A-Za-z ]{2,61}[0-9A-Za-z]$"):
|
||||
/bank-of-holos/cue.mod/gen/github.com/holos-run/holos/api/author/v1alpha3/definitions_go_gen.cue:203:25
|
||||
/bank-of-holos/cue.mod/gen/github.com/holos-run/holos/api/author/v1alpha3/definitions_go_gen.cue:188:15
|
||||
/bank-of-holos/cue.mod/gen/github.com/holos-run/holos/api/author/v1alpha3/definitions_go_gen.cue:203:15
|
||||
/bank-of-holos/projects/organization.cue:3:29
|
||||
/bank-of-holos/schema.gen.cue:6:29
|
||||
could not run: could not render component: exit status 1 at internal/render/platform.go:50
|
||||
could not run: could not marshal json projects/platform/components/istio/cni: cue: marshal error: _Organization.DisplayName: 2 errors in empty disjunction: (and 2 more errors) at internal/builder/builder.go:63
|
||||
_Organization.DisplayName: _Organization.DisplayName: 2 errors in empty disjunction: (and 2 more errors)
|
||||
could not run: could not marshal json projects/platform/components/argocd/crds: cue: marshal error: _Organization.DisplayName: 2 errors in empty disjunction: (and 2 more errors) at internal/builder/builder.go:63
|
||||
_Organization.DisplayName: _Organization.DisplayName: 2 errors in empty disjunction: (and 2 more errors)
|
||||
could not run: could not render component: exit status 1 at builder/v1alpha4/builder.go:95
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
@@ -386,7 +407,7 @@ Let's try again, this time replacing the hyphen with a space.
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
#Organization: DisplayName: "The Holistic Bank"
|
||||
_Organization: DisplayName: "The Holistic Bank"
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
@@ -94,8 +94,8 @@ an ArgoCD Application or Flux Kustomization.
|
||||
consistently add common labels.
|
||||
|
||||
:::tip
|
||||
[ComponentFields] in the Author API describes the fields common to all kinds of
|
||||
component.
|
||||
[ComponentConfig] in the Author API describes the fields common to all kinds of
|
||||
components.
|
||||
:::
|
||||
|
||||
We'll start with a [Helm] component to deploy the service, then compare it to a
|
||||
@@ -130,23 +130,23 @@ package holos
|
||||
|
||||
// Platform wide definitions
|
||||
// highlight-next-line
|
||||
#Migration: Namespace: "migration"
|
||||
_Migration: Namespace: "migration"
|
||||
|
||||
// Register namespaces
|
||||
// highlight-next-line
|
||||
#Namespaces: (#Migration.Namespace): _
|
||||
_Namespaces: (_Migration.Namespace): _
|
||||
|
||||
// Register projects
|
||||
// highlight-next-line
|
||||
#AppProjects: migration: _
|
||||
_AppProjects: migration: _
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Each of the highlighted lines has a specific purpose.
|
||||
|
||||
- Line 4 defines the `#Migration` CUE struct. The team that currently owns the
|
||||
migration project defines this struct.
|
||||
- Line 4 defines the `_Migration` hidden field. The team owning the migration
|
||||
project manages this struct.
|
||||
- Line 7 registers the namespace with the `namespaces` component owned by the
|
||||
platform team. The `_` value indicates the value is defined elsewhere in CUE.
|
||||
In this case, the platform team defines what a Namespace is.
|
||||
@@ -208,9 +208,9 @@ Changes not staged for commit:
|
||||
(use "git add <file>..." to update what will be committed)
|
||||
(use "git restore <file>..." to discard changes in working directory)
|
||||
// highlight-next-line
|
||||
modified: deploy/clusters/workload/components/app-projects/app-projects.gen.yaml
|
||||
modified: deploy/clusters/local/components/app-projects/app-projects.gen.yaml
|
||||
// highlight-next-line
|
||||
modified: deploy/clusters/workload/components/namespaces/namespaces.gen.yaml
|
||||
modified: deploy/clusters/local/components/namespaces/namespaces.gen.yaml
|
||||
|
||||
Untracked files:
|
||||
(use "git add <file>..." to include in what will be committed)
|
||||
@@ -230,15 +230,14 @@ git diff deploy
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```diff
|
||||
diff --git a/deploy/clusters/workload/components/app-projects/app-projects.gen.yaml b/deploy/clusters/workload/components/app-projects/app-projects.gen.yaml
|
||||
diff --git a/deploy/clusters/local/components/app-projects/app-projects.gen.yaml b/deploy/clusters/local/components/app-projects/app-projects.gen.yaml
|
||||
index bdc8371..42cb01a 100644
|
||||
--- a/deploy/clusters/workload/components/app-projects/app-projects.gen.yaml
|
||||
+++ b/deploy/clusters/workload/components/app-projects/app-projects.gen.yaml
|
||||
--- a/deploy/clusters/local/components/app-projects/app-projects.gen.yaml
|
||||
+++ b/deploy/clusters/local/components/app-projects/app-projects.gen.yaml
|
||||
@@ -50,6 +50,23 @@ spec:
|
||||
sourceRepos:
|
||||
- '*'
|
||||
---
|
||||
+# Source: CUE apiObjects.AppProject.migration
|
||||
+apiVersion: argoproj.io/v1alpha1
|
||||
+kind: AppProject
|
||||
+metadata:
|
||||
@@ -255,19 +254,17 @@ index bdc8371..42cb01a 100644
|
||||
+ sourceRepos:
|
||||
+ - '*'
|
||||
+---
|
||||
# Source: CUE apiObjects.AppProject.platform
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: AppProject
|
||||
diff --git a/deploy/clusters/workload/components/namespaces/namespaces.gen.yaml b/deploy/clusters/workload/components/namespaces/namespaces.gen.yaml
|
||||
diff --git a/deploy/clusters/local/components/namespaces/namespaces.gen.yaml b/deploy/clusters/local/components/namespaces/namespaces.gen.yaml
|
||||
index de96ab9..7ddd870 100644
|
||||
--- a/deploy/clusters/workload/components/namespaces/namespaces.gen.yaml
|
||||
+++ b/deploy/clusters/workload/components/namespaces/namespaces.gen.yaml
|
||||
--- a/deploy/clusters/local/components/namespaces/namespaces.gen.yaml
|
||||
+++ b/deploy/clusters/local/components/namespaces/namespaces.gen.yaml
|
||||
@@ -62,3 +62,11 @@ metadata:
|
||||
kubernetes.io/metadata.name: istio-system
|
||||
kind: Namespace
|
||||
apiVersion: v1
|
||||
+---
|
||||
+# Source: CUE apiObjects.Namespace.migration
|
||||
+metadata:
|
||||
+ name: migration
|
||||
+ labels:
|
||||
@@ -351,33 +348,33 @@ import ks "sigs.k8s.io/kustomize/api/types"
|
||||
|
||||
// Produce a helm chart build plan.
|
||||
// highlight-next-line
|
||||
(#Helm & Chart).BuildPlan
|
||||
_Helm.BuildPlan
|
||||
|
||||
let Chart = {
|
||||
// highlight-next-line
|
||||
Name: "podinfo"
|
||||
Version: "6.6.2"
|
||||
// highlight-next-line
|
||||
Namespace: #Migration.Namespace
|
||||
_Helm: #Helm & {
|
||||
// highlight-next-line
|
||||
Name: "podinfo"
|
||||
// highlight-next-line
|
||||
Namespace: _Migration.Namespace
|
||||
|
||||
// Necessary to ensure the resources go to the correct namespace.
|
||||
// highlight-next-line
|
||||
EnableKustomizePostProcessor: true
|
||||
// highlight-next-line
|
||||
KustomizeFiles: "kustomization.yaml": ks.#Kustomization & {
|
||||
namespace: Namespace
|
||||
}
|
||||
Chart: {
|
||||
version: "6.6.2"
|
||||
repository: {
|
||||
name: "podinfo"
|
||||
url: "https://stefanprodan.github.io/podinfo"
|
||||
}
|
||||
}
|
||||
|
||||
Repo: name: "podinfo"
|
||||
Repo: url: "https://stefanprodan.github.io/podinfo"
|
||||
KustomizeConfig: Kustomization: ks.#Kustomization & {
|
||||
// highlight-next-line
|
||||
namespace: Namespace
|
||||
}
|
||||
|
||||
// Allow the platform team to route traffic into our namespace.
|
||||
// highlight-next-line
|
||||
Resources: ReferenceGrant: grant: #ReferenceGrant & {
|
||||
metadata: namespace: Namespace
|
||||
}
|
||||
// Allow the platform team to route traffic into our namespace.
|
||||
Resources: ReferenceGrant: grant: _ReferenceGrant & {
|
||||
// highlight-next-line
|
||||
metadata: namespace: Namespace
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
@@ -396,19 +393,19 @@ Name as the sub-directory name when it writes the rendered manifest into
|
||||
`deploy/`. Normally this name also matches the directory and file name of the
|
||||
component, `podinfo/podinfo.cue`, but `holos` doesn't enforce this convention.
|
||||
|
||||
**Line 11**: We use the same namespace we registered with the `namespaces`
|
||||
**Line 10**: We use the same namespace we registered with the `namespaces`
|
||||
component as the value we pass to Helm. This is a good example of Holos
|
||||
offering safety and consistency with CUE, if we change the value of
|
||||
`#Migration.Namespace`, multiple components stay consistent.
|
||||
`_Migration.Namespace`, multiple components stay consistent.
|
||||
|
||||
**Lines 14-15**: Unfortunately, the Helm chart doesn't set the
|
||||
**Lines 21**: Unfortunately, the Helm chart doesn't set the
|
||||
`metadata.namespace` field for the resources it generates, which creates a
|
||||
security problem. The resources will be created in the wrong namespace. We
|
||||
don't want to modify the upstream chart because it creates a maintenance burden.
|
||||
We solve the problem by having Holos post-process the Helm output with
|
||||
Kustomize. This ensures all resources go into the correct namespace.
|
||||
|
||||
**Lines 23**: The migration team grants the platform team permission to route
|
||||
**Lines 26**: The migration team grants the platform team permission to route
|
||||
traffic into the `migration` Namespace using a [ReferenceGrant].
|
||||
|
||||
:::note
|
||||
@@ -459,11 +456,12 @@ following content.
|
||||
package holos
|
||||
|
||||
// Manage on workload clusters only
|
||||
for Cluster in #Fleets.workload.clusters {
|
||||
#Platform: Components: "\(Cluster.name)/podinfo": {
|
||||
path: "projects/migration/components/podinfo"
|
||||
cluster: Cluster.name
|
||||
}
|
||||
for Cluster in _Fleets.workload.clusters {
|
||||
_Platform: Components: "\(Cluster.name)/podinfo": {
|
||||
name: "podinfo"
|
||||
component: "projects/migration/components/podinfo"
|
||||
cluster: Cluster.name
|
||||
}
|
||||
}
|
||||
```
|
||||
</TabItem>
|
||||
@@ -488,7 +486,7 @@ package holos
|
||||
|
||||
// Assign ArgoCD Applications to the migration AppProject
|
||||
// highlight-next-line
|
||||
#ArgoConfig: AppProject: #AppProjects.migration.metadata.name
|
||||
_ArgoConfig: AppProject: _AppProjects.migration.metadata.name
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
@@ -497,7 +495,7 @@ This file provides consistency and safety in a number of ways:
|
||||
|
||||
1. All components under `projects/migration/` will automatically have their
|
||||
ArgoCD Application assigned to the migration `AppProject`.
|
||||
2. `holos render platform` errors out if `#AppProjects.migration` is not
|
||||
2. `holos render platform` errors out if `_AppProjects.migration` is not
|
||||
defined, we defined it in `projects/migration.cue`
|
||||
3. The platform team is responsible for managing the `AppProject` resource
|
||||
itself, the team doing the migration refers to the `metadata.name` field defined
|
||||
@@ -557,14 +555,14 @@ git status
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```txt
|
||||
On branch main
|
||||
On branch jeff/291-consistent-fields
|
||||
Changes to be committed:
|
||||
(use "git restore --staged <file>..." to unstage)
|
||||
new file: deploy/clusters/workload/components/podinfo/podinfo.gen.yaml
|
||||
new file: deploy/clusters/workload/gitops/podinfo.application.gen.yaml
|
||||
new file: platform/migration-podinfo.cue
|
||||
new file: projects/migration/app-project.cue
|
||||
new file: projects/migration/components/podinfo/podinfo.cue
|
||||
new file: deploy/clusters/local/components/podinfo/podinfo.gen.yaml
|
||||
new file: deploy/clusters/local/gitops/podinfo.gen.yaml
|
||||
new file: platform/migration-podinfo.cue
|
||||
new file: projects/migration/app-project.cue
|
||||
new file: projects/migration/components/podinfo/podinfo.cue
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
@@ -574,25 +572,26 @@ in a new manifest for the Helm output along with an ArgoCD Application for
|
||||
GitOps. Here's what they look like:
|
||||
|
||||
<Tabs groupId="0F2B3066-B57F-466E-A27F-A603C1803E11">
|
||||
<TabItem value="deploy/clusters/workload/gitops/podinfo.application.gen.yaml" label="podinfo.application.gen.yaml">
|
||||
<TabItem value="deploy/clusters/local/gitops/podinfo.gen.yaml" label="podinfo.gen.yaml">
|
||||
```yaml showLineNumbers
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
labels:
|
||||
holos.run/component.name: podinfo
|
||||
name: podinfo
|
||||
namespace: argocd
|
||||
spec:
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
# highlight-next-line
|
||||
project: migration
|
||||
source:
|
||||
path: ./deploy/clusters/workload/components/podinfo
|
||||
path: deploy/clusters/local/components/podinfo
|
||||
repoURL: https://github.com/holos-run/bank-of-holos
|
||||
targetRevision: main
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="deploy/clusters/workload/components/podinfo/podinfo.gen.yaml" label="podinfo.gen.yaml">
|
||||
<TabItem value="deploy/clusters/local/components/podinfo/podinfo.gen.yaml" label="podinfo.gen.yaml">
|
||||
```yaml showLineNumbers
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
@@ -601,9 +600,10 @@ metadata:
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
app.kubernetes.io/name: podinfo
|
||||
app.kubernetes.io/version: 6.6.2
|
||||
argocd.argoproj.io/instance: podinfo
|
||||
helm.sh/chart: podinfo-6.6.2
|
||||
holos.run/component.name: podinfo
|
||||
name: podinfo
|
||||
# highlight-next-line
|
||||
namespace: migration
|
||||
spec:
|
||||
ports:
|
||||
@@ -617,6 +617,8 @@ spec:
|
||||
targetPort: grpc
|
||||
selector:
|
||||
app.kubernetes.io/name: podinfo
|
||||
argocd.argoproj.io/instance: podinfo
|
||||
holos.run/component.name: podinfo
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
@@ -626,15 +628,18 @@ metadata:
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
app.kubernetes.io/name: podinfo
|
||||
app.kubernetes.io/version: 6.6.2
|
||||
argocd.argoproj.io/instance: podinfo
|
||||
helm.sh/chart: podinfo-6.6.2
|
||||
holos.run/component.name: podinfo
|
||||
name: podinfo
|
||||
# highlight-next-line
|
||||
namespace: migration
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: podinfo
|
||||
argocd.argoproj.io/instance: podinfo
|
||||
holos.run/component.name: podinfo
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxUnavailable: 1
|
||||
@@ -646,6 +651,8 @@ spec:
|
||||
prometheus.io/scrape: "true"
|
||||
labels:
|
||||
app.kubernetes.io/name: podinfo
|
||||
argocd.argoproj.io/instance: podinfo
|
||||
holos.run/component.name: podinfo
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
@@ -710,6 +717,23 @@ spec:
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
name: data
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1beta1
|
||||
kind: ReferenceGrant
|
||||
metadata:
|
||||
labels:
|
||||
argocd.argoproj.io/instance: podinfo
|
||||
holos.run/component.name: podinfo
|
||||
name: istio-ingress
|
||||
namespace: migration
|
||||
spec:
|
||||
from:
|
||||
- group: gateway.networking.k8s.io
|
||||
kind: HTTPRoute
|
||||
namespace: istio-ingress
|
||||
to:
|
||||
- group: ""
|
||||
kind: Service
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
@@ -726,10 +750,10 @@ git commit -m 'register the migration project podinfo component with the platfor
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```txt
|
||||
[main] register the migration project podinfo component with the platform
|
||||
5 files changed, 167 insertions(+)
|
||||
create mode 100644 deploy/clusters/workload/components/podinfo/podinfo.gen.yaml
|
||||
create mode 100644 deploy/clusters/workload/gitops/podinfo.application.gen.yaml
|
||||
[main 31197e2] register the migration project podinfo component with the platform
|
||||
5 files changed, 205 insertions(+)
|
||||
create mode 100644 deploy/clusters/local/components/podinfo/podinfo.gen.yaml
|
||||
create mode 100644 deploy/clusters/local/gitops/podinfo.gen.yaml
|
||||
create mode 100644 platform/migration-podinfo.cue
|
||||
create mode 100644 projects/migration/app-project.cue
|
||||
create mode 100644 projects/migration/components/podinfo/podinfo.cue
|
||||
@@ -773,31 +797,29 @@ platform as a whole. Bank of Holos uses [HTTPRoute] routes from the new Gateway
|
||||
API. The company the bank acquired uses older Ingress resources from earlier
|
||||
Kubernetes versions.
|
||||
|
||||
The platform team at the bank defines a `#HTTPRoutes` struct for other teams at
|
||||
the bank to register with. The `#HTTPRoutes` struct is similar to the
|
||||
`#Namespaces` and `#AppProjects` structs we've already seen.
|
||||
The platform team at the bank defines a `_HTTPRoutes` struct for other teams at
|
||||
the bank to register with. The `_HTTPRoutes` struct is similar to the
|
||||
`_Namespaces` and `_AppProjects` structs we've already seen.
|
||||
|
||||
As a member of the migration team, we'll add the file
|
||||
`projects/migration-routes.cue` to expose the service we're migrating.
|
||||
|
||||
Go ahead and create this file with the following content.
|
||||
Go ahead and create this file (if it hasn't been created previously) with the following content.
|
||||
|
||||
<Tabs groupId="6F9044EC-1737-4926-BD07-455536BA6573">
|
||||
<TabItem value="projects/migration-routes.cue" label="projects/migration-routes.cue">
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
let Podinfo = {
|
||||
podinfo: {
|
||||
port: 9898
|
||||
namespace: #Migration.Namespace
|
||||
}
|
||||
}
|
||||
|
||||
// Route migration-podinfo.example.com to port 9898 of Service podinfo in the
|
||||
// migration namespace.
|
||||
// highlight-next-line
|
||||
#HTTPRoutes: "migration-podinfo": _backendRefs: Podinfo
|
||||
_HTTPRoutes: "migration-podinfo": _backendRefs: {
|
||||
podinfo: {
|
||||
port: 9898
|
||||
namespace: _Migration.Namespace
|
||||
}
|
||||
}
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="projects/httproutes.cue" label="projects/httproutes.cue">
|
||||
@@ -806,44 +828,45 @@ package holos
|
||||
|
||||
import v1 "gateway.networking.k8s.io/httproute/v1"
|
||||
|
||||
// #HTTPRoutes defines managed HTTPRoute resources for the platform. These
|
||||
// resources are managed in the istio-ingress namespace. Other components
|
||||
// define the routes they need close to the root of configuration.
|
||||
// Struct containing HTTPRoute configurations. These resources are managed in
|
||||
// the istio-ingress namespace. Other components define the routes they need
|
||||
// close to the root of configuration.
|
||||
_HTTPRoutes: #HTTPRoutes
|
||||
|
||||
// #HTTPRoutes defines the schema of managed HTTPRoute resources for the
|
||||
// platform.
|
||||
#HTTPRoutes: {
|
||||
// For the guides, we simplify this down to a flat namespace.
|
||||
// highlight-next-line
|
||||
[Name=string]: v1.#HTTPRoute & {
|
||||
let HOST = Name + "." + #Platform.Domain
|
||||
// For the guides, we simplify this down to a flat namespace.
|
||||
[Name=string]: v1.#HTTPRoute & {
|
||||
let HOST = Name + "." + _Organization.Domain
|
||||
|
||||
// highlight-next-line
|
||||
_backendRefs: [NAME=string]: {
|
||||
name: NAME
|
||||
namespace: string
|
||||
port: number | *80
|
||||
}
|
||||
_backendRefs: [NAME=string]: {
|
||||
name: NAME
|
||||
namespace: string
|
||||
port: number | *80
|
||||
}
|
||||
|
||||
metadata: name: Name
|
||||
metadata: namespace: #Istio.Gateway.Namespace
|
||||
metadata: labels: app: Name
|
||||
spec: hostnames: [HOST]
|
||||
spec: parentRefs: [{
|
||||
name: "default"
|
||||
namespace: metadata.namespace
|
||||
}]
|
||||
spec: rules: [
|
||||
{
|
||||
matches: [{path: {type: "PathPrefix", value: "/"}}]
|
||||
// highlight-next-line
|
||||
backendRefs: [for x in _backendRefs {x}]
|
||||
},
|
||||
]
|
||||
}
|
||||
metadata: name: Name
|
||||
metadata: namespace: _Istio.Gateway.Namespace
|
||||
metadata: labels: app: Name
|
||||
spec: hostnames: [HOST]
|
||||
spec: parentRefs: [{
|
||||
name: "default"
|
||||
namespace: metadata.namespace
|
||||
}]
|
||||
spec: rules: [
|
||||
{
|
||||
matches: [{path: {type: "PathPrefix", value: "/"}}]
|
||||
backendRefs: [for x in _backendRefs {x}]
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
In this file we're adding a field to the `#HTTPRoutes` struct the platform team
|
||||
In this file we're adding a field to the `_HTTPRoutes` struct the platform team
|
||||
defined for us.
|
||||
|
||||
You might be wondering how we knew all of these fields to put into this file.
|
||||
@@ -857,8 +880,9 @@ The most important things the migration team takes away from this file are:
|
||||
|
||||
1. The platform team requires a `gateway.networking.k8s.io/httproute/v1`
|
||||
`HTTPRoute`.
|
||||
2. Line 13 uses a [hidden field] so we can provide backend references as a struct instead of a list.
|
||||
3. Line 30 uses a [comprehension] to convert the struct to a list.
|
||||
2. Line 17 uses a [hidden field] so we can provide backend references as a
|
||||
struct instead of a list.
|
||||
3. Line 34 uses a [comprehension] to convert the struct to a list.
|
||||
|
||||
We can look up the spec for the fields we need to provide in the Gateway API
|
||||
reference documentation for [HTTPRoute].
|
||||
@@ -924,39 +948,39 @@ git diff
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```diff
|
||||
diff --git a/deploy/clusters/workload/components/httproutes/httproutes.gen.yaml b/deploy/clusters/workload/components/httproutes/httproutes.gen.yaml
|
||||
index 4b476da..a150015 100644
|
||||
--- a/deploy/clusters/workload/components/httproutes/httproutes.gen.yaml
|
||||
+++ b/deploy/clusters/workload/components/httproutes/httproutes.gen.yaml
|
||||
@@ -46,3 +46,27 @@ spec:
|
||||
- name: frontend
|
||||
namespace: bank-frontend
|
||||
port: 80
|
||||
diff --git a/deploy/clusters/local/components/httproutes/httproutes.gen.yaml b/deploy/clusters/local/components/httproutes/httproutes.gen.yaml
|
||||
index 06f7c91..349e070 100644
|
||||
--- a/deploy/clusters/local/components/httproutes/httproutes.gen.yaml
|
||||
+++ b/deploy/clusters/local/components/httproutes/httproutes.gen.yaml
|
||||
@@ -47,3 +47,28 @@ spec:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
+---
|
||||
+# Source: CUE apiObjects.HTTPRoute.migration-podinfo
|
||||
+apiVersion: gateway.networking.k8s.io/v1
|
||||
+kind: HTTPRoute
|
||||
+metadata:
|
||||
+ name: migration-podinfo
|
||||
+ namespace: istio-ingress
|
||||
+ labels:
|
||||
+ app: migration-podinfo
|
||||
+ argocd.argoproj.io/instance: httproutes
|
||||
+ holos.run/component.name: httproutes
|
||||
+ name: migration-podinfo
|
||||
+ namespace: istio-ingress
|
||||
+spec:
|
||||
+ hostnames:
|
||||
+ - migration-podinfo.holos.localhost
|
||||
+ - migration-podinfo.holos.localhost
|
||||
+ parentRefs:
|
||||
+ - name: default
|
||||
+ namespace: istio-ingress
|
||||
+ - name: default
|
||||
+ namespace: istio-ingress
|
||||
+ rules:
|
||||
+ - matches:
|
||||
+ - path:
|
||||
+ type: PathPrefix
|
||||
+ value: /
|
||||
+ backendRefs:
|
||||
+ - name: podinfo
|
||||
+ port: 9898
|
||||
+ namespace: migration
|
||||
|
||||
+ - backendRefs:
|
||||
+ - name: podinfo
|
||||
+ namespace: migration
|
||||
+ port: 9898
|
||||
+ matches:
|
||||
+ - path:
|
||||
+ type: PathPrefix
|
||||
+ value: /
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
@@ -1039,7 +1063,7 @@ in the `bank-of-holos` repository after resetting your cluster following the
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```txt
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/namespaces/namespaces.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/namespaces/namespaces.gen.yaml
|
||||
namespace/argocd serverside-applied
|
||||
namespace/bank-backend serverside-applied
|
||||
namespace/bank-frontend serverside-applied
|
||||
@@ -1049,17 +1073,17 @@ namespace/external-secrets serverside-applied
|
||||
namespace/istio-ingress serverside-applied
|
||||
namespace/istio-system serverside-applied
|
||||
namespace/migration serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/argocd-crds/argocd-crds.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/argocd-crds/argocd-crds.gen.yaml
|
||||
customresourcedefinition.apiextensions.k8s.io/applications.argoproj.io serverside-applied
|
||||
customresourcedefinition.apiextensions.k8s.io/applicationsets.argoproj.io serverside-applied
|
||||
customresourcedefinition.apiextensions.k8s.io/appprojects.argoproj.io serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/gateway-api/gateway-api.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/gateway-api/gateway-api.gen.yaml
|
||||
customresourcedefinition.apiextensions.k8s.io/gatewayclasses.gateway.networking.k8s.io serverside-applied
|
||||
customresourcedefinition.apiextensions.k8s.io/gateways.gateway.networking.k8s.io serverside-applied
|
||||
customresourcedefinition.apiextensions.k8s.io/grpcroutes.gateway.networking.k8s.io serverside-applied
|
||||
customresourcedefinition.apiextensions.k8s.io/httproutes.gateway.networking.k8s.io serverside-applied
|
||||
customresourcedefinition.apiextensions.k8s.io/referencegrants.gateway.networking.k8s.io serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/external-secrets-crds/external-secrets-crds.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/external-secrets-crds/external-secrets-crds.gen.yaml
|
||||
customresourcedefinition.apiextensions.k8s.io/acraccesstokens.generators.external-secrets.io serverside-applied
|
||||
customresourcedefinition.apiextensions.k8s.io/clusterexternalsecrets.external-secrets.io serverside-applied
|
||||
customresourcedefinition.apiextensions.k8s.io/clustersecretstores.external-secrets.io serverside-applied
|
||||
@@ -1121,7 +1145,7 @@ customresourcedefinition.apiextensions.k8s.io/wasmplugins.extensions.istio.io co
|
||||
customresourcedefinition.apiextensions.k8s.io/webhooks.generators.external-secrets.io condition met
|
||||
customresourcedefinition.apiextensions.k8s.io/workloadentries.networking.istio.io condition met
|
||||
customresourcedefinition.apiextensions.k8s.io/workloadgroups.networking.istio.io condition met
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/external-secrets/external-secrets.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/external-secrets/external-secrets.gen.yaml
|
||||
serviceaccount/external-secrets-cert-controller serverside-applied
|
||||
serviceaccount/external-secrets serverside-applied
|
||||
serviceaccount/external-secrets-webhook serverside-applied
|
||||
@@ -1141,7 +1165,7 @@ deployment.apps/external-secrets serverside-applied
|
||||
deployment.apps/external-secrets-webhook serverside-applied
|
||||
validatingwebhookconfiguration.admissionregistration.k8s.io/secretstore-validate serverside-applied
|
||||
validatingwebhookconfiguration.admissionregistration.k8s.io/externalsecret-validate serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/cert-manager/cert-manager.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/cert-manager/cert-manager.gen.yaml
|
||||
serviceaccount/cert-manager-cainjector serverside-applied
|
||||
serviceaccount/cert-manager serverside-applied
|
||||
serviceaccount/cert-manager-webhook serverside-applied
|
||||
@@ -1187,11 +1211,11 @@ deployment.apps/cert-manager serverside-applied
|
||||
deployment.apps/cert-manager-webhook serverside-applied
|
||||
mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook serverside-applied
|
||||
validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/local-ca/local-ca.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/local-ca/local-ca.gen.yaml
|
||||
clusterissuer.cert-manager.io/local-ca serverside-applied
|
||||
+ kubectl wait --for=condition=Ready clusterissuer/local-ca --timeout=30s
|
||||
clusterissuer.cert-manager.io/local-ca condition met
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/argocd/argocd.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/argocd/argocd.gen.yaml
|
||||
serviceaccount/argocd-application-controller serverside-applied
|
||||
serviceaccount/argocd-applicationset-controller serverside-applied
|
||||
serviceaccount/argocd-notifications-controller serverside-applied
|
||||
@@ -1238,13 +1262,13 @@ deployment.apps/argocd-server serverside-applied
|
||||
statefulset.apps/argocd-application-controller serverside-applied
|
||||
job.batch/argocd-redis-secret-init serverside-applied
|
||||
referencegrant.gateway.networking.k8s.io/istio-ingress serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/app-projects/app-projects.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/app-projects/app-projects.gen.yaml
|
||||
appproject.argoproj.io/bank-backend serverside-applied
|
||||
appproject.argoproj.io/bank-frontend serverside-applied
|
||||
appproject.argoproj.io/bank-security serverside-applied
|
||||
appproject.argoproj.io/migration serverside-applied
|
||||
appproject.argoproj.io/platform serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/istio-base/istio-base.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/istio-base/istio-base.gen.yaml
|
||||
customresourcedefinition.apiextensions.k8s.io/authorizationpolicies.security.istio.io serverside-applied
|
||||
customresourcedefinition.apiextensions.k8s.io/destinationrules.networking.istio.io serverside-applied
|
||||
customresourcedefinition.apiextensions.k8s.io/envoyfilters.networking.istio.io serverside-applied
|
||||
@@ -1261,7 +1285,7 @@ customresourcedefinition.apiextensions.k8s.io/workloadentries.networking.istio.i
|
||||
customresourcedefinition.apiextensions.k8s.io/workloadgroups.networking.istio.io serverside-applied
|
||||
serviceaccount/istio-reader-service-account serverside-applied
|
||||
validatingwebhookconfiguration.admissionregistration.k8s.io/istiod-default-validator serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/istiod/istiod.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/istiod/istiod.gen.yaml
|
||||
serviceaccount/istiod serverside-applied
|
||||
role.rbac.authorization.k8s.io/istiod serverside-applied
|
||||
clusterrole.rbac.authorization.k8s.io/istio-reader-clusterrole-istio-system serverside-applied
|
||||
@@ -1279,7 +1303,7 @@ poddisruptionbudget.policy/istiod serverside-applied
|
||||
horizontalpodautoscaler.autoscaling/istiod serverside-applied
|
||||
mutatingwebhookconfiguration.admissionregistration.k8s.io/istio-sidecar-injector serverside-applied
|
||||
validatingwebhookconfiguration.admissionregistration.k8s.io/istio-validator-istio-system serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/istio-cni/istio-cni.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/istio-cni/istio-cni.gen.yaml
|
||||
serviceaccount/istio-cni serverside-applied
|
||||
configmap/istio-cni-config serverside-applied
|
||||
clusterrole.rbac.authorization.k8s.io/istio-cni serverside-applied
|
||||
@@ -1291,20 +1315,20 @@ clusterrolebinding.rbac.authorization.k8s.io/istio-cni-ambient serverside-applie
|
||||
daemonset.apps/istio-cni-node serverside-applied
|
||||
+ kubectl wait --for=condition=Ready pod -l k8s-app=istio-cni-node --timeout=300s -n istio-system
|
||||
pod/istio-cni-node-7kfbh condition met
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/istio-ztunnel/istio-ztunnel.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/istio-ztunnel/istio-ztunnel.gen.yaml
|
||||
serviceaccount/ztunnel serverside-applied
|
||||
daemonset.apps/ztunnel serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/istio-gateway/istio-gateway.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/istio-gateway/istio-gateway.gen.yaml
|
||||
certificate.cert-manager.io/gateway-cert serverside-applied
|
||||
gateway.gateway.networking.k8s.io/default serverside-applied
|
||||
serviceaccount/default-istio serverside-applied
|
||||
+ kubectl wait --for=condition=Ready pod -l istio.io/gateway-name=default --timeout=300s -n istio-ingress
|
||||
pod/default-istio-54598d985b-69wmr condition met
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/httproutes/httproutes.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/httproutes/httproutes.gen.yaml
|
||||
httproute.gateway.networking.k8s.io/argocd serverside-applied
|
||||
httproute.gateway.networking.k8s.io/bank serverside-applied
|
||||
httproute.gateway.networking.k8s.io/migration-podinfo serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-secrets/bank-secrets.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-secrets/bank-secrets.gen.yaml
|
||||
configmap/jwt-key-writer serverside-applied
|
||||
job.batch/jwt-key-writer serverside-applied
|
||||
role.rbac.authorization.k8s.io/jwt-key-reader serverside-applied
|
||||
@@ -1314,7 +1338,7 @@ rolebinding.rbac.authorization.k8s.io/jwt-key-writer serverside-applied
|
||||
serviceaccount/jwt-key-writer serverside-applied
|
||||
+ kubectl wait --for=condition=complete job.batch/jwt-key-writer -n bank-security --timeout=300s
|
||||
job.batch/jwt-key-writer condition met
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-backend-config/bank-backend-config.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-backend-config/bank-backend-config.gen.yaml
|
||||
configmap/demo-data-config serverside-applied
|
||||
configmap/environment-config serverside-applied
|
||||
configmap/service-api-config serverside-applied
|
||||
@@ -1322,30 +1346,30 @@ externalsecret.external-secrets.io/jwt-key serverside-applied
|
||||
referencegrant.gateway.networking.k8s.io/istio-ingress serverside-applied
|
||||
secretstore.external-secrets.io/bank-security serverside-applied
|
||||
serviceaccount/bank-of-holos serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-accounts-db/bank-accounts-db.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-accounts-db/bank-accounts-db.gen.yaml
|
||||
configmap/accounts-db-config serverside-applied
|
||||
service/accounts-db serverside-applied
|
||||
statefulset.apps/accounts-db serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-ledger-db/bank-ledger-db.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-ledger-db/bank-ledger-db.gen.yaml
|
||||
configmap/ledger-db-config serverside-applied
|
||||
service/ledger-db serverside-applied
|
||||
statefulset.apps/ledger-db serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-contacts/bank-contacts.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-contacts/bank-contacts.gen.yaml
|
||||
deployment.apps/contacts serverside-applied
|
||||
service/contacts serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-balance-reader/bank-balance-reader.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-balance-reader/bank-balance-reader.gen.yaml
|
||||
deployment.apps/balancereader serverside-applied
|
||||
service/balancereader serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-userservice/bank-userservice.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-userservice/bank-userservice.gen.yaml
|
||||
deployment.apps/userservice serverside-applied
|
||||
service/userservice serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-ledger-writer/bank-ledger-writer.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-ledger-writer/bank-ledger-writer.gen.yaml
|
||||
deployment.apps/ledgerwriter serverside-applied
|
||||
service/ledgerwriter serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-transaction-history/bank-transaction-history.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-transaction-history/bank-transaction-history.gen.yaml
|
||||
deployment.apps/transactionhistory serverside-applied
|
||||
service/transactionhistory serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/components/bank-frontend/bank-frontend.gen.yaml
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/components/bank-frontend/bank-frontend.gen.yaml
|
||||
configmap/demo-data-config serverside-applied
|
||||
configmap/environment-config serverside-applied
|
||||
configmap/service-api-config serverside-applied
|
||||
@@ -1355,7 +1379,7 @@ referencegrant.gateway.networking.k8s.io/istio-ingress serverside-applied
|
||||
secretstore.external-secrets.io/bank-security serverside-applied
|
||||
service/frontend serverside-applied
|
||||
serviceaccount/bank-of-holos serverside-applied
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/workload/gitops
|
||||
+ kubectl apply --server-side=true -f deploy/clusters/local/gitops
|
||||
application.argoproj.io/app-projects serverside-applied
|
||||
application.argoproj.io/argocd-crds serverside-applied
|
||||
application.argoproj.io/argocd serverside-applied
|
||||
@@ -1428,10 +1452,10 @@ for some time.
|
||||
|
||||
[Quickstart]: /docs/quickstart/
|
||||
[Change a Service]: /docs/guides/change-a-service/
|
||||
[Helm]: /docs/api/author/v1alpha3/#Helm
|
||||
[Kubernetes]: /docs/api/author/v1alpha3/#Kubernetes
|
||||
[Kustomize]: /docs/api/author/v1alpha3/#Kustomize
|
||||
[ComponentFields]: /docs/api/author/v1alpha3/#ComponentFields
|
||||
[Helm]: /docs/api/author/v1alpha4/#Helm
|
||||
[Kubernetes]: /docs/api/author/v1alpha4/#Kubernetes
|
||||
[Kustomize]: /docs/api/author/v1alpha4/#Kustomize
|
||||
[ComponentConfig]: /docs/api/author/v1alpha4/#ComponentConfig
|
||||
[platform-files]: /docs/quickstart/#how-platform-rendering-works
|
||||
[AppProject]: https://argo-cd.readthedocs.io/en/stable/user-guide/projects/
|
||||
[unification operator]: https://cuelang.org/docs/reference/spec/#unification
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
---
|
||||
description: Helm Component
|
||||
slug: /guides/helm-component
|
||||
sidebar_position: 400
|
||||
---
|
||||
|
||||
# Helm Component
|
||||
|
||||
The [Deploy a Service](/docs/guides/deploy-a-service/) guide is the best guide
|
||||
we have on wrapping a Helm chart in a Holos Component. The [Helm] section of
|
||||
the Author API may also be useful.
|
||||
|
||||
[Helm]: /docs/api/author/v1alpha3/#Helm
|
||||
[Kubernetes]: /docs/api/author/v1alpha3/#Kubernetes
|
||||
[Kustomize]: /docs/api/author/v1alpha3/#Kustomize
|
||||
4808
doc/md/guides/helm.mdx
Normal file
BIN
doc/md/guides/img/helm-editor-constraints.png
Normal file
|
After Width: | Height: | Size: 248 KiB |
BIN
doc/md/guides/img/helm-prometheus-httpbin.png
Normal file
|
After Width: | Height: | Size: 206 KiB |
@@ -1,20 +0,0 @@
|
||||
---
|
||||
description: Kubernetes Component
|
||||
slug: /guides/kubernetes-component
|
||||
sidebar_position: 500
|
||||
---
|
||||
|
||||
# Kubernetes Component
|
||||
|
||||
:::warning
|
||||
TODO
|
||||
:::
|
||||
|
||||
This is a placeholder for a guide for managing Kubernetes resources directly
|
||||
from a Holos Component with strong type checking.
|
||||
|
||||
In the meantime, please refer to the [Kubernetes] section of the Author API.
|
||||
|
||||
[Helm]: /docs/api/author/v1alpha3/#Helm
|
||||
[Kubernetes]: /docs/api/author/v1alpha3/#Kubernetes
|
||||
[Kustomize]: /docs/api/author/v1alpha3/#Kustomize
|
||||
@@ -1,20 +0,0 @@
|
||||
---
|
||||
description: Wrap a Kustomize Kustomization in a Holos Component.
|
||||
slug: /guides/kustomize-component
|
||||
sidebar_position: 600
|
||||
---
|
||||
|
||||
# Kustomize Component
|
||||
|
||||
:::warning
|
||||
TODO
|
||||
:::
|
||||
|
||||
This is a placeholder for a guide on wrapping a Kustomize Kustomization base
|
||||
with a Holos component.
|
||||
|
||||
In the meantime, please refer to the [Kustomize] section of the Author API.
|
||||
|
||||
[Helm]: /docs/api/author/v1alpha3/#Helm
|
||||
[Kubernetes]: /docs/api/author/v1alpha3/#Kubernetes
|
||||
[Kustomize]: /docs/api/author/v1alpha3/#Kustomize
|
||||
@@ -42,9 +42,9 @@ graph TB
|
||||
Kustomize[<a href="#component">Kustomize</a>]
|
||||
CUE[<a href="#component">CUE</a>]
|
||||
|
||||
Cluster --> Platform
|
||||
Fleet --> Cluster
|
||||
Component --> Fleet
|
||||
Fleet --> Platform
|
||||
Cluster --> Fleet
|
||||
Component --> Cluster
|
||||
Helm --> Component
|
||||
Kustomize --> Component
|
||||
CUE --> Component
|
||||
|
||||
@@ -8,7 +8,7 @@ sidebar_position: 900
|
||||
|
||||
## Community Support
|
||||
|
||||
You can ask questions in our community forums in [GitHub Discussions](https://github.com/holos-run/holos/discussions) or [Google Groups](https://groups.google.com/g/holos-discuss).
|
||||
You can ask questions in our community forums in [GitHub Discussions](https://github.com/holos-run/holos/discussions), [Discord](https://discord.gg/JgDVbNpye7), or [Google Groups](https://groups.google.com/g/holos-discuss).
|
||||
|
||||
## Commercial Support and Services
|
||||
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
---
|
||||
slug: technical-overview
|
||||
title: Technical Overview
|
||||
description: Learn how Holos makes it easier for platform teams to integrate software into their platform.
|
||||
---
|
||||
|
||||
<head>
|
||||
<meta property="og:title" content="Technical Overview | Holos" />
|
||||
<meta property="og:image" content="/img/cards/technical-overview.png" />
|
||||
</head>
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import Admonition from '@theme/Admonition';
|
||||
@@ -45,35 +51,34 @@ Go command line tool leveraging [CUE] to fill this gap.
|
||||
|
||||
```mermaid
|
||||
---
|
||||
title: Figure 1 - Render Pipeline
|
||||
title: Figure 1 - v1alpha4 Rendered Manifest Pipeline
|
||||
---
|
||||
graph LR
|
||||
PS[<a href="/docs/api/author/v1alpha3/#Platform">Platform</a>]
|
||||
HC[<a href="/docs/api/author/v1alpha3/#ComponentFields">Components</a>]
|
||||
BP[<a href="/docs/api/core/v1alpha3#BuildPlan">BuildPlan</a>]
|
||||
Platform[<a href="/docs/api/author/v1alpha4/#Platform">Platform</a>]
|
||||
Component[<a href="/docs/api/author/v1alpha4/#ComponentConfig">Components</a>]
|
||||
|
||||
H[<a href="/docs/api/author/v1alpha3/#Helm">Helm</a>]
|
||||
K[<a href="/docs/api/author/v1alpha3/#Kustomize">Kustomize</a>]
|
||||
O[<a href="/docs/api/author/v1alpha3/#Kubernetes">Kubernetes</a>]
|
||||
Helm[<a href="/docs/api/author/v1alpha4/#Helm">Helm</a>]
|
||||
Kustomize[<a href="/docs/api/author/v1alpha4/#Kustomize">Kustomize</a>]
|
||||
Kubernetes[<a href="/docs/api/author/v1alpha4/#Kubernetes">Kubernetes</a>]
|
||||
|
||||
P[<a href="/docs/api/core/v1alpha3#Kustomize">Kustomize</a>]
|
||||
Y[Kubernetes <br/>Resources]
|
||||
G[GitOps <br/>Resource]
|
||||
FS[Local Files]
|
||||
BuildPlan[<a href="/docs/api/core/v1alpha4/#buildplan">BuildPlan</a>]
|
||||
|
||||
C[Kube API Server]
|
||||
ResourcesArtifact[<a href="/docs/api/core/v1alpha4/#artifact">Resources<br/>Artifact</a>]
|
||||
GitOpsArtifact[<a href="/docs/api/core/v1alpha4/#artifact">GitOps<br/>Artifact</a>]
|
||||
|
||||
PS --> HC --> BP
|
||||
BP --> H --> P
|
||||
BP --> K --> P
|
||||
BP --> O --> P
|
||||
Generators[<a href="/docs/api/core/v1alpha4/#generators">Generators</a>]
|
||||
Transformers[<a href="/docs/api/core/v1alpha4/#transformer">Transformers</a>]
|
||||
Files[Manifest<br/>Files]
|
||||
|
||||
P --> Y --> FS
|
||||
P --> G --> FS
|
||||
Platform --> Component
|
||||
Component --> Helm --> BuildPlan
|
||||
Component --> Kubernetes --> BuildPlan
|
||||
Component --> Kustomize --> BuildPlan
|
||||
|
||||
FS --> ArgoCD --> C
|
||||
FS --> Flux --> C
|
||||
FS --> kubectl --> C
|
||||
BuildPlan --> ResourcesArtifact --> Generators
|
||||
BuildPlan --> GitOpsArtifact --> Generators
|
||||
|
||||
Generators --> Transformers --> Files
|
||||
```
|
||||
|
||||
## Use Case
|
||||
@@ -108,7 +113,7 @@ The development team registers their experimental project, creatively named
|
||||
package holos
|
||||
|
||||
// The development team registers a project name.
|
||||
#Projects: experiment: {
|
||||
_Projects: experiment: {
|
||||
// The project owner must be named.
|
||||
Owner: Name: "dev-team"
|
||||
// Expose Service podinfo at https://podinfo.example.com
|
||||
@@ -139,7 +144,7 @@ HTTPRoute and AppProject go into two namespaces managed by the platform team.
|
||||
Holos makes it easier for the platform team to organize these resources into
|
||||
different components with different owners.
|
||||
|
||||
:::tip
|
||||
:::important
|
||||
Holos supports [CODEOWNERS] by clearly defining the teams responsible for each
|
||||
platform component.
|
||||
:::
|
||||
@@ -152,12 +157,13 @@ holos render platform ./platform
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```txt
|
||||
rendered namespaces for cluster overview in 93.024042ms
|
||||
rendered projects for cluster overview in 96.080667ms
|
||||
rendered httproutes for cluster overview in 96.047ms
|
||||
rendered platform in 96.805292ms
|
||||
rendered httproutes for cluster overview in 177.823625ms
|
||||
rendered app-projects for cluster overview in 180.946834ms
|
||||
rendered projects for cluster overview in 181.98725ms
|
||||
rendered namespaces for cluster overview in 182.30725ms
|
||||
rendered platform in 182.31075ms
|
||||
```
|
||||
:::note
|
||||
:::tip
|
||||
If you'd like to try this for yourself, `cd` into [examples/tech-overview] and
|
||||
render the platform.
|
||||
:::
|
||||
@@ -169,112 +175,125 @@ The fully rendered manifests are written into the `deploy/` directory organized
|
||||
by cluster and component for GitOps.
|
||||
|
||||
<Tabs groupId="07FBE14E-E9EA-437B-9FA1-C6D8806524AD">
|
||||
<TabItem value="deploy/clusters/overview/components/namespaces/namespaces.gen.yaml" label="namespaces">
|
||||
<TabItem value="deploy/clusters/local/components/namespaces/namespaces.gen.yaml" label="namespaces">
|
||||
```
|
||||
cat deploy/clusters/local/components/namespaces/namespaces.gen.yaml
|
||||
```
|
||||
```yaml showLineNumbers
|
||||
# deploy/clusters/overview/components/namespaces/namespaces.gen.yaml
|
||||
---
|
||||
metadata:
|
||||
name: experiment
|
||||
labels:
|
||||
kubernetes.io/metadata.name: experiment
|
||||
example.com/project.name: experiment
|
||||
example.com/owner.name: dev-team
|
||||
example.com/owner.email: sg-dev-team@example.com
|
||||
kind: Namespace
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
argocd.argoproj.io/instance: namespaces
|
||||
example.com/owner.email: sg-dev-team@example.com
|
||||
example.com/owner.name: dev-team
|
||||
example.com/project.name: experiment
|
||||
holos.run/component.name: namespaces
|
||||
kubernetes.io/metadata.name: experiment
|
||||
name: experiment
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="deploy/clusters/overview/components/projects/projects.gen.yaml" label="projects">
|
||||
<TabItem value="deploy/clusters/local/components/projects/projects.gen.yaml" label="projects">
|
||||
```
|
||||
cat deploy/clusters/local/components/projects/projects.gen.yaml
|
||||
```
|
||||
```yaml showLineNumbers
|
||||
# deploy/clusters/overview/components/projects/projects.gen.yaml
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1beta1
|
||||
kind: ReferenceGrant
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: istio-ingress
|
||||
namespace: experiment
|
||||
labels:
|
||||
example.com/project.name: experiment
|
||||
example.com/owner.name: dev-team
|
||||
argocd.argoproj.io/instance: projects
|
||||
example.com/owner.email: sg-dev-team@example.com
|
||||
spec:
|
||||
from:
|
||||
- group: gateway.networking.k8s.io
|
||||
kind: HTTPRoute
|
||||
namespace: istio-ingress
|
||||
to:
|
||||
- group: ""
|
||||
kind: Service
|
||||
---
|
||||
metadata:
|
||||
example.com/owner.name: dev-team
|
||||
example.com/project.name: experiment
|
||||
holos.run/component.name: projects
|
||||
name: admin
|
||||
namespace: experiment
|
||||
labels:
|
||||
example.com/project.name: experiment
|
||||
example.com/owner.name: dev-team
|
||||
example.com/owner.email: sg-dev-team@example.com
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: admin
|
||||
subjects:
|
||||
- apiGroup: rbac.authorization.k8s.io
|
||||
kind: Group
|
||||
name: oidc:sg-dev-team@example.com
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
- apiGroup: rbac.authorization.k8s.io
|
||||
kind: Group
|
||||
name: oidc:sg-dev-team@example.com
|
||||
---
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: SecretStore
|
||||
metadata:
|
||||
labels:
|
||||
argocd.argoproj.io/instance: projects
|
||||
example.com/owner.email: sg-dev-team@example.com
|
||||
example.com/owner.name: dev-team
|
||||
example.com/project.name: experiment
|
||||
holos.run/component.name: projects
|
||||
name: default
|
||||
namespace: experiment
|
||||
labels:
|
||||
example.com/project.name: experiment
|
||||
example.com/owner.name: dev-team
|
||||
example.com/owner.email: sg-dev-team@example.com
|
||||
spec:
|
||||
provider:
|
||||
kubernetes:
|
||||
remoteNamespace: experiment
|
||||
auth:
|
||||
token:
|
||||
bearerToken:
|
||||
key: token
|
||||
name: eso-reader
|
||||
remoteNamespace: experiment
|
||||
server:
|
||||
caBundle: LS0tLS1CRUd...QVRFLS0tLS0K
|
||||
url: https://management.example.com:6443
|
||||
caBundle: LS0tLS1CRUd...S0tLS0K
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1beta1
|
||||
kind: ReferenceGrant
|
||||
metadata:
|
||||
labels:
|
||||
argocd.argoproj.io/instance: projects
|
||||
example.com/owner.email: sg-dev-team@example.com
|
||||
example.com/owner.name: dev-team
|
||||
example.com/project.name: experiment
|
||||
holos.run/component.name: projects
|
||||
name: istio-ingress
|
||||
namespace: experiment
|
||||
spec:
|
||||
from:
|
||||
- group: gateway.networking.k8s.io
|
||||
kind: HTTPRoute
|
||||
namespace: istio-ingress
|
||||
to:
|
||||
- group: ""
|
||||
kind: Service
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="deploy/clusters/overview/components/httproutes/httproutes.gen.yaml" label="httproutes">
|
||||
<TabItem value="deploy/clusters/local/components/httproutes/httproutes.gen.yaml" label="httproutes">
|
||||
```
|
||||
cat deploy/clusters/local/components/httproutes/httproutes.gen.yaml
|
||||
```
|
||||
```yaml showLineNumbers
|
||||
# deploy/clusters/overview/components/httproutes/httproutes.gen.yaml
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: podinfo.holos.localhost
|
||||
namespace: istio-ingress
|
||||
labels:
|
||||
example.com/project.name: experiment
|
||||
example.com/owner.name: dev-team
|
||||
argocd.argoproj.io/instance: httproutes
|
||||
example.com/owner.email: sg-dev-team@example.com
|
||||
example.com/owner.name: dev-team
|
||||
example.com/project.name: experiment
|
||||
holos.run/component.name: httproutes
|
||||
name: podinfo.example.com
|
||||
namespace: istio-ingress
|
||||
spec:
|
||||
hostnames:
|
||||
- podinfo.holos.localhost
|
||||
- podinfo.example.com
|
||||
parentRefs:
|
||||
- name: default
|
||||
namespace: istio-ingress
|
||||
- name: default
|
||||
namespace: istio-ingress
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
backendRefs:
|
||||
- name: podinfo
|
||||
namespace: experiment
|
||||
port: 9898
|
||||
- backendRefs:
|
||||
- name: podinfo
|
||||
namespace: experiment
|
||||
port: 9898
|
||||
matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
@@ -282,7 +301,7 @@ spec:
|
||||
The rendered manifests are derived from the project registration information by
|
||||
definitions implemented by the platform team. The [Author API] provides a
|
||||
[Project] schema, but does not define an implementation. The platform team
|
||||
implements the [Project] schema by writing a `#Projects` definition to manage
|
||||
implements the [Project] schema by adding a `_Projects` struct to manage
|
||||
resources according to bank policies.
|
||||
|
||||
:::important
|
||||
@@ -290,7 +309,7 @@ The Author API is intended as a convenient, ergonomic reference for component
|
||||
authors. Definitions **are not** confined to the Author API.
|
||||
:::
|
||||
|
||||
The following example shows how the platform team wrote the `#Projects`
|
||||
The following example shows how the platform team wrote the `_Projects`
|
||||
definition to derive the Namespace from the project registration provided by the
|
||||
dev team.
|
||||
|
||||
@@ -302,97 +321,95 @@ projects/platform/components/namespaces/namespaces.cue
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
let Objects = {
|
||||
Name: "namespaces"
|
||||
Resources: Namespace: #Namespaces
|
||||
_Kubernetes: #Kubernetes & {
|
||||
Name: "namespaces"
|
||||
Resources: Namespace: _Namespaces
|
||||
}
|
||||
|
||||
// Produce a kubernetes objects build plan.
|
||||
(#Kubernetes & Objects).BuildPlan
|
||||
_Kubernetes.BuildPlan
|
||||
```
|
||||
|
||||
1. This is the namespaces component which simply manages all of the namespaces derived from the project registration data shown in the second tab.
|
||||
1. This is the namespaces component which manages a collection of Namespace resources derived from the project registration data shown in the second tab.
|
||||
2. Line 5 manages a Namespace for each value of the `#Namespaces` struct. See the second tab for how the platform team defines this structure.
|
||||
</TabItem>
|
||||
<TabItem value="projects/projects.cue" label="#Projects Definition">
|
||||
<TabItem value="projects/projects.cue" label="Projects Definition">
|
||||
```txt
|
||||
projects/projects.cue
|
||||
```
|
||||
```cue showLineNumbers
|
||||
package holos
|
||||
|
||||
import api "github.com/holos-run/holos/api/author/v1alpha3"
|
||||
import api "github.com/holos-run/holos/api/author/v1alpha4"
|
||||
|
||||
// Projects defines the structure other teams register with to manage project
|
||||
// resources. The platform team defines the schema, development teams provide
|
||||
// the values.
|
||||
#Projects: api.#Projects & {
|
||||
[NAME=string]: {
|
||||
Name: NAME
|
||||
// The platform team requires the development teams to indicate an owner of
|
||||
// the project.
|
||||
Owner: Name: string
|
||||
// The default value for the owner email address is derived from the owner
|
||||
// name, but development teams can provide a different email address if
|
||||
// needed.
|
||||
Owner: Email: string | *"sg-\(Owner.Name)@\(#Organization.Domain)"
|
||||
// The platform team constrains the project to a single namespace.
|
||||
Namespaces: close({(NAME): Name: NAME})
|
||||
// The platform team constrains the exposed services to the project
|
||||
// namespace.
|
||||
Hostnames: [HOST=string]: {
|
||||
Name: HOST
|
||||
Namespace: Namespaces[NAME].Name
|
||||
Service: HOST
|
||||
Port: number | *80
|
||||
}
|
||||
_Projects: api.#Projects & {
|
||||
[NAME=string]: {
|
||||
Name: NAME
|
||||
// The platform team requires the development teams to indicate an owner of
|
||||
// the project.
|
||||
Owner: Name: string
|
||||
// The default value for the owner email address is derived from the owner
|
||||
// name, but development teams can provide a different email address if
|
||||
// needed.
|
||||
Owner: Email: string | *"sg-\(Owner.Name)@\(_Organization.Domain)"
|
||||
// The platform team constrains the project to a single namespace.
|
||||
Namespaces: close({(NAME): Name: NAME})
|
||||
// The platform team constrains the exposed services to the project
|
||||
// namespace.
|
||||
Hostnames: [HOST=string]: {
|
||||
Name: HOST
|
||||
Namespace: Namespaces[NAME].Name
|
||||
Service: HOST
|
||||
Port: number | *80
|
||||
}
|
||||
|
||||
// CommonLabels is not part of the Projects API, so we use a hidden field to
|
||||
// provide common labels to components that render resources from CUE.
|
||||
_CommonLabels: {
|
||||
"\(#Organization.Domain)/project.name": Name
|
||||
"\(#Organization.Domain)/owner.name": Owner.Name
|
||||
"\(#Organization.Domain)/owner.email": Owner.Email
|
||||
}
|
||||
}
|
||||
CommonLabels: {
|
||||
"\(_Organization.Domain)/project.name": Name
|
||||
"\(_Organization.Domain)/owner.name": Owner.Name
|
||||
"\(_Organization.Domain)/owner.email": Owner.Email
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for Project in #Projects {
|
||||
// Register project namespaces with the namespaces component.
|
||||
#Namespaces: {
|
||||
for Namespace in Project.Namespaces {
|
||||
(Namespace.Name): metadata: labels: Project._CommonLabels
|
||||
}
|
||||
}
|
||||
for Project in _Projects {
|
||||
// Register project namespaces with the namespaces component.
|
||||
_Namespaces: {
|
||||
for Namespace in Project.Namespaces {
|
||||
(Namespace.Name): metadata: labels: Project.CommonLabels
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
1. On lines 8-37 the platform team derives most fields from the project name (line 9), and the owner name (line 13). The purpose is to fill in the remaining fields defined by the Author API.
|
||||
1. On lines 8-35 the platform team derives most fields from the project name (line 9), and the owner name (line 13). The purpose is to fill in the remaining fields defined by the Author API.
|
||||
2. Line 13 The dev team is expected to provide a concrete owner name, indicated by the `string` value.
|
||||
3. Line 17 The platform team provides a default value for the email address. The project team may define a different value.
|
||||
4. Line 19 The Author API allows a project to have many namespaces. The platform team constrains this down to one namespace per project by closing the struct. The namespace name must be the same as the project name.
|
||||
5. Lines 22-27 The platform team derives values for a Gateway API [BackendObjectReference] from the hostname provided by the project team. These values are used later to build HTTPRoutes to expose their service.
|
||||
6. Lines 31-35 Common labels aren't part of the Author API, so the platform team defines a hidden field to make them available throughout the configuration.
|
||||
7. Lines 39-46 The platform team adds a namespace with common labels for each project to the struct we saw in the first tab.
|
||||
6. Lines 30-32 Common labels are derived to mix into resources associated with this project.
|
||||
7. Lines 37-44 The platform team adds a namespace with common labels for each project to the struct we saw in the first tab.
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
The RoleBinding, SecretScore, and ReferenceGrant are managed in the
|
||||
[projects](https://github.com/holos-run/bank-of-holos/blob/v0.1.1/examples/tech-overview/projects/platform/components/projects/projects.cue)
|
||||
[projects](https://github.com/holos-run/bank-of-holos/blob/v0.4.1/examples/tech-overview/projects/platform/components/projects/projects.cue)
|
||||
component, similar to the previous namespaces example.
|
||||
The HTTPRoute is managed separately in the
|
||||
[httproutes](https://github.com/holos-run/bank-of-holos/blob/v0.1.1/examples/tech-overview/projects/platform/components/httproutes/httproutes.cue)
|
||||
[httproutes](https://github.com/holos-run/bank-of-holos/blob/v0.4.1/examples/tech-overview/projects/platform/components/httproutes/httproutes.cue)
|
||||
component.
|
||||
|
||||
All components are registered with the platform in the
|
||||
[platform](https://github.com/holos-run/bank-of-holos/tree/v0.1.1/examples/tech-overview/platform)
|
||||
[platform](https://github.com/holos-run/bank-of-holos/tree/v0.4.1/examples/tech-overview/platform)
|
||||
directory.
|
||||
|
||||
:::important
|
||||
Multiple components, potentially owned by different teams, derive fully rendered
|
||||
resources from the same three project values. The dev team added these three
|
||||
values to the `#Projects` definition. The platform team wrote the definition to
|
||||
values to the `_Projects` struct. The platform team wrote the definition to
|
||||
integrate software according to bank policies. CUE powers this _unified_
|
||||
platform configuration model.
|
||||
:::
|
||||
@@ -416,13 +433,17 @@ projects/experiment/components/podinfo/podinfo.cue
|
||||
package holos
|
||||
|
||||
// Produce a helm chart build plan.
|
||||
(#Helm & Chart).BuildPlan
|
||||
_HelmChart.BuildPlan
|
||||
|
||||
let Chart = {
|
||||
Name: "podinfo"
|
||||
Version: "6.6.2"
|
||||
Repo: name: "podinfo"
|
||||
Repo: url: "https://stefanprodan.github.io/podinfo"
|
||||
_HelmChart: #Helm & {
|
||||
Name: "podinfo"
|
||||
Chart: {
|
||||
version: "6.6.2"
|
||||
repository: {
|
||||
name: "podinfo"
|
||||
url: "https://stefanprodan.github.io/podinfo"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
This file represents a Helm chart component to add to the platform. The second
|
||||
@@ -436,11 +457,13 @@ platform/podinfo.cue
|
||||
package holos
|
||||
|
||||
// Manage the component on every workload Cluster, but not management clusters.
|
||||
for Cluster in #Fleets.workload.clusters {
|
||||
#Platform: Components: "\(Cluster.name)/podinfo": {
|
||||
path: "projects/experiment/components/podinfo"
|
||||
cluster: Cluster.name
|
||||
}
|
||||
for Cluster in _Fleets.workload.clusters {
|
||||
_Platform: Components: "\(Cluster.name):podinfo": {
|
||||
name: "podinfo"
|
||||
component: "projects/experiment/components/podinfo"
|
||||
cluster: Cluster.name
|
||||
tags: project: "experiment"
|
||||
}
|
||||
}
|
||||
```
|
||||
This file registers the component with the platform. When the platform is
|
||||
@@ -449,6 +472,14 @@ across the platform.
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
The project tag links the component to the same field of the `_Projects` struct.
|
||||
|
||||
:::important
|
||||
You can add your own key=value tags in your platform specification to inject
|
||||
values into components. This feature is useful to reuse one component path for
|
||||
several environments or customers.
|
||||
:::
|
||||
|
||||
Once the dev team's component is registered, rendering the platform will render
|
||||
their component.
|
||||
|
||||
@@ -460,13 +491,13 @@ holos render platform ./platform
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
```txt
|
||||
rendered app-projects for cluster overview in 92.087042ms
|
||||
rendered projects for cluster overview in 95.6325ms
|
||||
rendered httproutes for cluster overview in 96.968916ms
|
||||
rendered namespaces for cluster overview in 97.610291ms
|
||||
rendered namespaces for cluster overview in 185.64075ms
|
||||
rendered app-projects for cluster overview in 186.729292ms
|
||||
rendered httproutes for cluster overview in 195.222833ms
|
||||
rendered projects for cluster overview in 195.217125ms
|
||||
// highlight-next-line
|
||||
rendered podinfo for cluster overview in 155.410417ms
|
||||
rendered platform in 155.470542ms
|
||||
rendered podinfo for cluster overview in 195.830042ms
|
||||
rendered platform in 195.90275ms
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
@@ -474,7 +505,7 @@ rendered platform in 155.470542ms
|
||||
<Tabs groupId="77BF500B-105A-4AB4-A615-DEC19F501AE1">
|
||||
<TabItem value="command" label="Command">
|
||||
```bash
|
||||
cat deploy/clusters/overview/components/podinfo/podinfo.gen.yaml
|
||||
cat deploy/clusters/local/components/podinfo/podinfo.gen.yaml
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="output" label="Output">
|
||||
@@ -486,12 +517,13 @@ metadata:
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
app.kubernetes.io/name: podinfo
|
||||
app.kubernetes.io/version: 6.6.2
|
||||
argocd.argoproj.io/instance: podinfo
|
||||
example.com/owner.email: sg-dev-team@example.com
|
||||
example.com/owner.name: dev-team
|
||||
example.com/project.name: experiment
|
||||
helm.sh/chart: podinfo-6.6.2
|
||||
holos.run/component.name: podinfo
|
||||
name: podinfo
|
||||
namespace: experiment
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
@@ -504,9 +536,11 @@ spec:
|
||||
targetPort: grpc
|
||||
selector:
|
||||
app.kubernetes.io/name: podinfo
|
||||
argocd.argoproj.io/instance: podinfo
|
||||
example.com/owner.email: sg-dev-team@example.com
|
||||
example.com/owner.name: dev-team
|
||||
example.com/project.name: experiment
|
||||
holos.run/component.name: podinfo
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
@@ -516,20 +550,23 @@ metadata:
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
app.kubernetes.io/name: podinfo
|
||||
app.kubernetes.io/version: 6.6.2
|
||||
argocd.argoproj.io/instance: podinfo
|
||||
example.com/owner.email: sg-dev-team@example.com
|
||||
example.com/owner.name: dev-team
|
||||
example.com/project.name: experiment
|
||||
helm.sh/chart: podinfo-6.6.2
|
||||
holos.run/component.name: podinfo
|
||||
name: podinfo
|
||||
namespace: experiment
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: podinfo
|
||||
argocd.argoproj.io/instance: podinfo
|
||||
example.com/owner.email: sg-dev-team@example.com
|
||||
example.com/owner.name: dev-team
|
||||
example.com/project.name: experiment
|
||||
holos.run/component.name: podinfo
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxUnavailable: 1
|
||||
@@ -541,9 +578,11 @@ spec:
|
||||
prometheus.io/scrape: "true"
|
||||
labels:
|
||||
app.kubernetes.io/name: podinfo
|
||||
argocd.argoproj.io/instance: podinfo
|
||||
example.com/owner.email: sg-dev-team@example.com
|
||||
example.com/owner.name: dev-team
|
||||
example.com/project.name: experiment
|
||||
holos.run/component.name: podinfo
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
@@ -617,7 +656,8 @@ platform team added a constraint to the project so all Helm charts are post
|
||||
processed with Kustomize to add these common labels. The platform team
|
||||
accomplishes this by adding a constraint in the project directory. This can be
|
||||
seen in
|
||||
[experiment/components.cue](https://github.com/holos-run/bank-of-holos/blob/v0.1.1/examples/tech-overview/projects/experiment/components.cue)
|
||||
[schema.cue](https://github.com/holos-run/bank-of-holos/blob/v0.4.1/schema.cue#L35-L38)
|
||||
where the platform team configures all component kinds for the platform.
|
||||
|
||||
We've covered how the platform team provides a golden path for development teams
|
||||
to register their projects by defining a Projects structure. We've also covered
|
||||
@@ -644,7 +684,7 @@ how the development team deploys their existing Helm chart onto the platform.
|
||||
[Holos]: https://holos.run/
|
||||
[Quickstart]: /docs/quickstart/
|
||||
[rendered manifests pattern]: https://akuity.io/blog/the-rendered-manifests-pattern/
|
||||
[examples/tech-overview]: https://github.com/holos-run/bank-of-holos/tree/v0.1.1/examples/tech-overview
|
||||
[examples/tech-overview]: https://github.com/holos-run/bank-of-holos/tree/v0.2.0/examples/tech-overview
|
||||
[BackendObjectReference]: https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io%2fv1.BackendObjectReference
|
||||
[CODEOWNERS]: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
|
||||
[Project]: /docs/api/author/v1alpha3/#Project
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
---
|
||||
slug: holos-platform-manager
|
||||
title: Holos Platform Manager
|
||||
authors: [jeff]
|
||||
tags: [holos]
|
||||
---
|
||||
|
||||
## Introducing Holos
|
||||
|
||||
I’m excited to announce Holos, a tool designed to help engineering teams
|
||||
manage their software development platforms built on the Kubernetes resource
|
||||
model.
|
||||
|
||||
:::tip
|
||||
For a hands-on introduction, check out our [Quickstart] Guide.
|
||||
:::
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
### The Backstory
|
||||
|
||||
In our roles at [Open Infrastructure Services], and earlier at Puppet, we helped
|
||||
many companies automate infrastructure management. In 2017, we had the
|
||||
opportunity to work with Twitter to improve their configuration management
|
||||
system. This opportunity gave us insight into the challenges of managing a
|
||||
large-scale platform with multiple engineering teams. Our work involved
|
||||
everything from observability systems to application deployment workflows and of
|
||||
course, managing the core infrastructure.
|
||||
|
||||
This experience demonstrated the value of platform engineering. As the pandemic
|
||||
hit, I began thinking about what a fully cloud-native platform might look like
|
||||
using the Kubernetes resource model. Around the same time, I came across the
|
||||
Hacker News post, “[Why Are We Templating YAML]?”, which sparked a good
|
||||
discussion. It was clear I wasn’t alone in my frustration with managing YAML
|
||||
files and ensuring clear, predictable changes before merging them into
|
||||
production.
|
||||
|
||||
A common pain point and theme is the complexity of working with nested YAML
|
||||
configurations, especially with tools like ArgoCD and Helm. The lack of a
|
||||
standard for rendering YAML templates makes it difficult to see what changes are
|
||||
actually being applied to the Kubernetes API. This often results in trial and
|
||||
error, costly blue-green deployments, and hours of debugging.
|
||||
|
||||
During the pandemic, I began experimenting with a tool to address this issue,
|
||||
drawing on lessons from our work at Twitter. The key problems we aimed to solve
|
||||
are:
|
||||
|
||||
- **Lack of visibility**: Engineers struggled to foresee the impact of small changes.
|
||||
- **Large blast radius**: Small changes affected global systems, with no way to limit the impact.
|
||||
- **Incomplete tooling**: While processes were in place, the right information wasn’t surfaced at the right time.
|
||||
|
||||
We built several iterations of a reference platform based on Kubernetes,
|
||||
initially focusing on fully rendering manifests into plain files—a pattern now
|
||||
called the [rendered manifests pattern]. Over time, we realized we were spending
|
||||
most of our time maintaining bash scripts and YAML templates. This led back to
|
||||
the question: Why are we templating YAML? What _should_ replace templates?
|
||||
|
||||
We'd previously seen a colleague use CUE effectively to generate large scale
|
||||
configurations for Envoy, and ran into CUE again when we worked on a project
|
||||
involving Dagger, but I still hadn't taken a deep look at CUE.
|
||||
|
||||
At the end of 2023, I decided to dive deep with [CUE]. I quickly came to
|
||||
appreciate CUE’s unified approach where **order is irrelevant**. Before CUE, we
|
||||
handled configuration data in a hierarchy with a precedence ordering, similar to
|
||||
how we handled data in Puppet with Hiera. CUE's promise of no longer needing to
|
||||
think about ordering and precedence rules held, alleviating a large cognitive
|
||||
burden when dealing with complex configurations. CUE quickly allowed me to
|
||||
replace the unmaintainable bash scripts and complex Helm templates, simplifying
|
||||
our workflow.
|
||||
|
||||
### Enter Holos
|
||||
|
||||
Holos adds CUE as a well-specified integration layer over tools like Helm,
|
||||
Kustomize, ArgoCD, and Crossplane. With Holos, we can now efficiently integrate
|
||||
upstream Helm charts and Kustomize bases into our platform without the
|
||||
complexity of templates and scripts. This has also made it easy for one team to
|
||||
define "golden paths" that other teams can follow—like automatically configuring
|
||||
namespaces and security policies when dev teams start new projects.
|
||||
|
||||
We've found Holos incredibly useful and hope you do too. Let us know your
|
||||
thoughts!
|
||||
|
||||
[Guides]: /docs/guides/
|
||||
[API Reference]: /docs/api/
|
||||
[Quickstart]: /docs/quickstart/
|
||||
[CUE]: https://cuelang.org/
|
||||
[Author API]: /docs/api/author/
|
||||
[Core API]: /docs/api/core/
|
||||
[Open Infrastructure Services]: https://openinfrastructure.co/
|
||||
[Why are we templating YAML]: https://hn.algolia.com/?dateRange=all&page=0&prefix=false&query=https%3A%2F%2Fleebriggs.co.uk%2Fblog%2F2019%2F02%2F07%2Fwhy-are-we-templating-yaml&sort=byDate&type=story
|
||||
|
||||
[Holos]: https://holos.run/
|
||||
[Quickstart]: /docs/quickstart/
|
||||
[rendered manifests pattern]: https://akuity.io/blog/the-rendered-manifests-pattern/
|
||||
125
doc/website/blog/2024-10-28-holos.md
Normal file
@@ -0,0 +1,125 @@
|
||||
---
|
||||
slug: announcing-holos
|
||||
title: Announcing Holos
|
||||
authors: [jeff]
|
||||
tags: [holos, launch]
|
||||
image: /img/cards/announcing-holos.png
|
||||
description: Holistically manage Helm and Kustomize with CUE
|
||||
---
|
||||
|
||||
<head>
|
||||
<title>Announcing Holos</title>
|
||||
<meta property="og:title" content="Announcing Holos" />
|
||||
</head>
|
||||
|
||||
I'm excited to share Holos, a Go command line tool we developed to make it
|
||||
easier to manage a platform built on Kubernetes. Holos implements the rendered
|
||||
manifests pattern as a data pipeline to fully render manifests generated from
|
||||
[Helm], [Kustomize], or [CUE] in a holistic way.
|
||||
|
||||
[Helm]: https://helm.sh/
|
||||
[Kustomize]: https://kustomize.io/
|
||||
[CUE]: https://cuelang.org/
|
||||
|
||||
```mermaid
|
||||
---
|
||||
title: Rendered Manifest Pipeline
|
||||
---
|
||||
graph LR
|
||||
Platform[<a href="/docs/api/author/v1alpha4/#Platform">Platform</a>]
|
||||
Component[<a href="/docs/api/author/v1alpha4/#ComponentConfig">Components</a>]
|
||||
|
||||
Helm[<a href="/docs/api/author/v1alpha4/#Helm">Helm</a>]
|
||||
Kustomize[<a href="/docs/api/author/v1alpha4/#Kustomize">Kustomize</a>]
|
||||
Kubernetes[<a href="/docs/api/author/v1alpha4/#Kubernetes">Kubernetes</a>]
|
||||
|
||||
BuildPlan[<a href="/docs/api/core/v1alpha4/#buildplan">BuildPlan</a>]
|
||||
|
||||
ResourcesArtifact[<a href="/docs/api/core/v1alpha4/#artifact">Resources<br/>Artifact</a>]
|
||||
GitOpsArtifact[<a href="/docs/api/core/v1alpha4/#artifact">GitOps<br/>Artifact</a>]
|
||||
|
||||
Generators[<a href="/docs/api/core/v1alpha4/#generators">Generators</a>]
|
||||
Transformers[<a href="/docs/api/core/v1alpha4/#transformer">Transformers</a>]
|
||||
Files[Manifest<br/>Files]
|
||||
|
||||
Platform --> Component
|
||||
Component --> Helm --> BuildPlan
|
||||
Component --> Kubernetes --> BuildPlan
|
||||
Component --> Kustomize --> BuildPlan
|
||||
|
||||
BuildPlan --> ResourcesArtifact --> Generators
|
||||
BuildPlan --> GitOpsArtifact --> Generators
|
||||
|
||||
Generators --> Transformers --> Files
|
||||
```
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
At the start of the pandemic I was migrating our platform from VMs managed by
|
||||
Puppet to Kubernetes. My primary goal was to build an observability system
|
||||
similar to what we had when we managed Puppet at Twitter prior to the
|
||||
acquisition. I started building the observability system with the official
|
||||
[prometheus community charts], but quickly ran into issues where the
|
||||
individual charts didn’t work with each other. I was frustrated with how
|
||||
complicated and difficult to configure these charts were. They weren’t well
|
||||
integrated, so I switched to the [kube-prometheus-stack] umbrella chart which
|
||||
attempts to solve this integration problem.
|
||||
|
||||
The umbrella chart got us further, as long as we didn’t stray too far from the
|
||||
default values, but we quickly ran into operational challenges. Upgrading the
|
||||
chart introduced breaking changes we couldn’t see until they were applied,
|
||||
causing incidents. We needed to manage secrets securely so we mixed in
|
||||
ExternalSecrets with many of the charts. We decided to handle these
|
||||
customizations by implementing the [rendered manifests pattern] using scripts in
|
||||
our CI pipeline.
|
||||
|
||||
These scripts got us further, but we found them costly to maintain.
|
||||
Teammates needed to be careful to execute them with the same context they were
|
||||
executed in CI. We realized we were reinventing Hiera to manage a hierarchy of
|
||||
helm values.yaml files to inject into multiple charts.
|
||||
|
||||
At this point I started looking for a more holistic solution to this problem of
|
||||
integrating multiple charts together. We saw the value in the rendered
|
||||
manifests pattern, but we couldn’t find an agreed upon implementation. We built
|
||||
a Go command line tool to implement the pattern as a data pipeline. I’d been
|
||||
thinking about the comments from the [Why are we templating YAML] posts and
|
||||
wondering what an answer to this question would look like.
|
||||
|
||||
The Go command line tool was an incremental improvement over the CI scripts, but
|
||||
we still didn’t have a good way to handle the data values. We were still
|
||||
templating YAML which didn’t catch errors early enough. It was too easy to
|
||||
render invalid resources Kubernetes rejected, causing deployment problems. I
|
||||
searched for a solution to manage helm values, something like Hiera which we
|
||||
knew well from Puppet, but not hierarchical because we knew it was important to
|
||||
trace where config values came from in an outage. A few HN comments mentioned
|
||||
CUE, and an engineer we worked with at Twitter used CUE to configure Envoy at
|
||||
scale, so I gave it a try. I quickly appreciated how CUE provides both strong
|
||||
type checking and validation of constraints, unifies all configuration data, and
|
||||
provides clarity into where values originate from.
|
||||
|
||||
Take a look at Holos if you’re looking to implement the rendered manifests
|
||||
pattern or can’t shake that feeling it should be easier to integrate third party
|
||||
software into Kubernetes like we felt.
|
||||
|
||||
1. [Helm Guide] Walks through how we solved the challenges we faced with the prometheus Helm charts.
|
||||
2. [Quickstart] Works through how a platform team can define golden paths for other teams using CUE.
|
||||
3. [Author API] provides an ergonomic way to work with Helm, Kustomize, and CUE resources.
|
||||
|
||||
[Helm Guide]: /docs/guides/helm/
|
||||
[Guides]: /docs/guides/
|
||||
[API Reference]: /docs/api/
|
||||
[Quickstart]: /docs/quickstart/
|
||||
[Author API]: /docs/api/author/
|
||||
[Core API]: /docs/api/core/
|
||||
[Open Infrastructure Services]: https://openinfrastructure.co/
|
||||
[Why are we templating YAML]: https://hn.algolia.com/?dateRange=all&page=0&prefix=false&query=https%3A%2F%2Fleebriggs.co.uk%2Fblog%2F2019%2F02%2F07%2Fwhy-are-we-templating-yaml&sort=byDate&type=story
|
||||
|
||||
[Holos]: https://holos.run/
|
||||
[Quickstart]: /docs/quickstart/
|
||||
|
||||
[Helm]: https://helm.sh/
|
||||
[Kustomize]: https://kustomize.io/
|
||||
[CUE]: https://cuelang.org/
|
||||
[rendered manifests pattern]: https://akuity.io/blog/the-rendered-manifests-pattern/
|
||||
[prometheus community charts]: https://github.com/prometheus-community/helm-charts
|
||||
[kube-prometheus-stack]: https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack
|
||||
123
doc/website/blog/2024-10-28-why-cue.md
Normal file
@@ -0,0 +1,123 @@
|
||||
---
|
||||
slug: why-cue-for-configuration
|
||||
title: Why CUE for Configuration
|
||||
authors: [jeff]
|
||||
tags: [holos, cue]
|
||||
image: /img/cards/why-cue.png
|
||||
description: Why we use CUE for configuration in Holos
|
||||
date: 2024-10-28T16:00
|
||||
---
|
||||
|
||||
We selected [CUE](https://cuelang.org/) as the configuration language in Holos
|
||||
for a number of reasons described in this post. The process was a combination
|
||||
of process by elimination and the unique way CUE _unifies_ configuration.
|
||||
|
||||
<!-- truncate -->
|
||||
We evaluated a number of domain specific and general purpose languages before
|
||||
deciding on CUE. The CUE website, GitHub issues, and Marcel's videos do a great
|
||||
job of explaining most of these reasons, so I'll summarize and cite them here.
|
||||
|
||||
## DSL or GPL
|
||||
|
||||
The first decision was if we should use a turing complete general purpose
|
||||
language, or a domain specific language (DSL). We decided to use a DSL because
|
||||
we knew from hard won experience configuration with general purpose languages
|
||||
invites too many problems over time.
|
||||
|
||||
1. Configuration easily becomes non-deterministic, especially when remote procedure calls are involved.
|
||||
2. Many general purpose languages support type checking, but few support constraints and validation of data. We must write our own validation logic which often means validation happens haphazardly, if at all.
|
||||
3. Data is usually mutable, making it difficult to know where an output value came from.
|
||||
4. Configuration code is read much more frequently, and at more critical times like an outage, than it's written. I felt this pain and I don't want anyone using Holos to feel that way.
|
||||
|
||||
For these reasons we sought a domain specific language that focused on
|
||||
simplicity, readability, and data validation. This quote from Marcel got my attention focused on CUE.
|
||||
|
||||
> I would argue that for configuration languages maintainability and readability are more important even than for programming languages, because they are ofter viewed by a larger group, often need to be changed in emergency conditions, and also as they are supposed to convey a certain contract. Most configuration languages, like GCL (my own doing), are more like scripting languages, making it easier to crank out definitions of large swats of data compactly, but being harder to comprehend and modify later.
|
||||
|
||||
Source: [Comparisons between CUE, Jsonnet, Shall, OPA, etc.](https://github.com/cuelang/cue/discussions/669#discussioncomment-306811)
|
||||
|
||||
## Other DSLs
|
||||
|
||||
### Template Engines
|
||||
|
||||
Template engines are not exactly a domain specific language, but they're
|
||||
similar. We already used Go templates in Helm to produce YAML, and previously
|
||||
used Jinja2 and ERB templates extensively for configuration tasks.
|
||||
|
||||
The fundamental problem with text template engines is that they manipulate text,
|
||||
not data. As a result, output is often rendered without error or indication the
|
||||
configuration is invalid until it is applied to the live system. Errors need
|
||||
to be handled faster and earlier, ideally immediately as we're writing in our
|
||||
editor.
|
||||
|
||||
For these reasons we can set aside all tools based on text templating.
|
||||
|
||||
### Jsonnet
|
||||
|
||||
Marcel and the CUE website explain this much better than I can. We used Jsonnet
|
||||
to configure the kubernetes prometheus stack and experienced Jsonnet's lack of
|
||||
validation features first hand.
|
||||
|
||||
> Like Jsonnet, CUE is a superset of JSON. They also are both influenced by GCL. CUE, in turn is influenced by Jsonnet. This may give the semblance that the languages are very similar. At the core, though, they are very different.
|
||||
>
|
||||
> CUE’s focus is data validation whereas Jsonnet focuses on data templating (boilerplate removal). Jsonnet was not designed with validation in mind.
|
||||
>
|
||||
> Jsonnet and GCL can be quite powerful at reducing boilerplate. The goal of CUE is not to be better at boilerplate removal than Jsonnet or GCL. CUE was designed to be an answer to two major shortcomings of these approaches: complexity and lack of typing. Jsonnet reduces some of the complexities of GCL, but largely falls into the same category. For CUE, the tradeoff was to add typing and reduce complexity (for humans and machines), at the expense of giving up flexibility.
|
||||
|
||||
Source: [CUE Configuration Use Case - Jsonnet / GCL](https://cuelang.org/docs/concept/configuration-use-case/#jsonnet-gcl)
|
||||
|
||||
Marcel answered this question in more depth earlier:
|
||||
|
||||
> Jsonnet is based on BCL, an internal language at Google. It fixes a few things relative to BCL, but is mostly the same. This means it copies the biggest mistakes of BCL. Even though BCL is still widely used at Google, its issues are clear. It was just that the alternatives weren't that much better.
|
||||
>
|
||||
> There are a myriad of issues with BCL (and Jsonnet and pretty much all of its descendants), but I will mention a couple:
|
||||
>
|
||||
> 1. Most notably, the basic operation of composition of BCL/Jsonnet, inheritance, is not commutative and idempotent in the general case. In other words, order matters. This makes it, for humans, hard to track where values are coming from. But also, it makes it very complicated, if not impossible, to do any kind of automation. The complexity of inheritance is compounded by the fact that values can enter an object from one of several directions (super, overlay, etc.), and the order in which this happens matters. The basic operation of CUE is commutative, associative and idempotent. This order independence helps both humans and machines. The resulting model is much less complex.
|
||||
> 2. Typing: most of the BCL offshoots do not allow for schema definitions. This makes it hard to detect any kind of typos or user errors. For a large code bases, no one will question a requirement to have a compiled/typed language. Why should we not require the same kind of rigor for data? Some offshoots of BCL internal to Google and also external have tried to address this a bit, but none quite satisfactory. In CUE types and values are the same thing. This makes things both easier than schema-based languages (less concepts to learn), but also more powerful. It allows for intuitive but also precise typing.
|
||||
>
|
||||
> There are many other issues, like handling cycles, unprincipled workarounds for hermeticity, poor tooling and so forth that make BCL and offsprings often awkward.
|
||||
>
|
||||
> So why CUE? Configuration is still largely an unsolved problem. We have tried using code to generate configs, or hybrid languages, but that often results in a mess. Using generators on databases doesn't allow keeping it sync with revision control. Simpler approaches like HCL and Kustomize recognize the complexity issue by removing a lot of it, but then sometimes become too weak, and actually also reintroduce some of this complexity with overlays (a poor man's inheritance, if you will, but with some of the same negative consequences). Other forms of removing complexity, for instance by just introducing simpler forms/ abstraction layers of configuration, may work within certain context but are domain-specific and relatively hard to maintain.
|
||||
>
|
||||
> So inheritance-based languages, for all its flaws, were the best we had. The idea behind CUE is to recognize that a declarative language is the best approach for many (not all) configuration problems, but to tackle the fundamental issues of these languages.
|
||||
>
|
||||
> The idea for CUE is actually not new. It was invented about 30 years ago and has been in use and further developed since that time in the field of computational linguistics, where the concept is used to encode entire lexicons as well as very detailed grammars of human languages. If you think about it, these are huge configurations that are often maintained by both computer scientists and linguists. You can see this as a proof of concept that large-scale, declarative configuration for a highly complex domain can work.
|
||||
>
|
||||
> CUE is a bit different from the languages used in linguistics and more tailored to the general configuration issue as we've seen it at Google. But under the hood it adheres strictly to the concepts and principles of these approaches and we have been careful not to make the same mistakes made in BCL (which then were copied in all its offshoots). It also means that CUE can benefit from 30 years of research on this topic. For instance, under the hood, CUE uses a first-order unification algorithm, allowing us to build template extractors based on anti-unification (see issue #7 and #15), something that is not very meaningful or even possible with languages like BCL and Jsonnet.
|
||||
|
||||
Source: [how CUE differs from jsonnet](https://github.com/cuelang/cue/issues/33#issuecomment-483615374)
|
||||
|
||||
### Dhall
|
||||
|
||||
> Dhall addresses some of the issues of GCL and Jsonnet (like lack of typing), but lacks the detailed typing of CUE. But it still misses the most important property of CUE: its model of composability. Some of the benefits are explained in the above link. Conceptually, CUE is an aspect-oriented and constraint-based language. It allows you to specify fine-grained constraints on what are valid values. These constraints then double as templates, allowing to remove boilerplate often with the same efficacy as inheritance, even if it works very differently.
|
||||
|
||||
Source [Comparisons between CUE, Jsonnet, Dhall, OPA, etc.](https://github.com/cuelang/cue/discussions/669#discussioncomment-306811)
|
||||
|
||||
### Rego (OPA)
|
||||
|
||||
> CUE also can be used for policy specification, like Rego (OPA).CUE unifies values, types, and constraints in a single continuum. As it is a constraint-based language first and foremost, it is well suited for defining policy. It is less developed in that area than Rego, but it I expect it will ultimately be better suited for policy. Note that Rego is based on Datalog, which is more of a query language at hart, giving it quite a different feel for defining policy than CUE. Both are logic programming languages, though, and share many of the same properties.
|
||||
|
||||
Source [Comparisons between CUE, Jsonnet, Dhall, OPA, etc.](https://github.com/cuelang/cue/discussions/669#discussioncomment-306811)
|
||||
|
||||
### PKL
|
||||
|
||||
I didn't look deeply into [Pkl](https://github.com/apple/pkl) primarily because
|
||||
CUE, like Holos, is written in Go. It was straight forward to integrate CUE
|
||||
into Holos.
|
||||
|
||||
### HCL
|
||||
|
||||
I have extensive experience with HCL and found it challenging to work with at medium to large scales.
|
||||
|
||||
See also: [CUE Configuration Use Case - HCL](https://cuelang.org/docs/concept/configuration-use-case/#hcl)
|
||||
|
||||
## Editor Integration
|
||||
|
||||
CUE has good support today for Visual Studio Code, and better support coming,
|
||||
see the [CUE LSP Roadmap](https://github.com/orgs/cue-lang/projects/15)
|
||||
|
||||
## Additional Resources
|
||||
|
||||
The video [Large-Scale Engineering of Configuration with Unification (Marcel van
|
||||
Lohuizen)](https://www.youtube.com/watch?v=jSRXobu1jHk) motivated me to go
|
||||
deeper and invest significant time into CUE.
|
||||
@@ -116,6 +116,11 @@ const config: Config = {
|
||||
label: 'GitHub',
|
||||
position: 'right',
|
||||
},
|
||||
{
|
||||
href: 'https://discord.gg/JgDVbNpye7',
|
||||
label: 'Discord',
|
||||
position: 'right',
|
||||
},
|
||||
],
|
||||
},
|
||||
footer: {
|
||||
@@ -150,8 +155,8 @@ const config: Config = {
|
||||
href: '/docs/support',
|
||||
},
|
||||
{
|
||||
label: 'Announcements List',
|
||||
href: 'https://groups.google.com/g/holos-announce',
|
||||
label: 'Discord',
|
||||
href: 'https://discord.gg/JgDVbNpye7',
|
||||
},
|
||||
{
|
||||
label: 'Discussion List',
|
||||
|
||||
1
doc/website/static/.well-known/atproto-did
Normal file
@@ -0,0 +1 @@
|
||||
did:plc:7jly72mfd42u4fj4mfyovxqz
|
||||
BIN
doc/website/static/img/cards/announcing-holos.png
Normal file
|
After Width: | Height: | Size: 596 KiB |
BIN
doc/website/static/img/cards/background.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
doc/website/static/img/cards/guides-helm-2.png
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
doc/website/static/img/cards/guides-helm.png
Normal file
|
After Width: | Height: | Size: 521 KiB |
BIN
doc/website/static/img/cards/launch.jpg
Normal file
|
After Width: | Height: | Size: 166 KiB |
BIN
doc/website/static/img/cards/technical-overview.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
doc/website/static/img/cards/why-cue.png
Normal file
|
After Width: | Height: | Size: 486 KiB |
BIN
doc/website/static/img/github-mark-white.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
1
doc/website/static/img/github-mark-white.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="98" height="96" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 960 B |
BIN
doc/website/static/img/github-mark.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
1
doc/website/static/img/github-mark.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="98" height="96" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#24292f"/></svg>
|
||||
|
After Width: | Height: | Size: 963 B |
BIN
doc/website/static/img/holos-logo.png
Normal file
|
After Width: | Height: | Size: 645 KiB |
4
doc/website/static/img/logo-holos-dark.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="100" cy="100" r="90" fill="#FDF6E3" stroke="#073642" stroke-width="4" />
|
||||
<text x="50%" y="50%" text-anchor="middle" fill="#073642" font-size="96" dy=".35em" font-family="Arial, sans-serif" font-weight="bold">H</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 306 B |
4
doc/website/static/img/logo-holos.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="100" cy="100" r="90" stroke="#FDF6E3" fill="#073642" stroke-width="4" />
|
||||
<text x="50%" y="50%" text-anchor="middle" fill="#FDF6E3" font-size="96" dy=".35em" font-family="Arial, sans-serif" font-weight="bold">H</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 306 B |
12
doc/website/static/img/logo-ois-dark.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Created with Vectornator (http://vectornator.io/) -->
|
||||
<svg style="fill-rule:nonzero;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;" version="1.1" viewBox="0 0 605.044 336.948" xmlns="http://www.w3.org/2000/svg" xmlns:vectornator="http://vectornator.io" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs/>
|
||||
<g id="Logo" vectornator:layerName="Logo">
|
||||
<g opacity="1">
|
||||
<path d="M591.109 167.89C580.229 111.687 546.936 77.6261 491.282 65.5687C433.469 53.0447 384.362 69.3554 342.802 110.398C310.616 142.185 278.709 174.259 246.482 205.995C225.922 226.226 205.922 247.343 179.109 259.626C149.202 273.334 119.469 272.37 93.4157 251.847C66.8557 230.91 61.2157 201.791 69.349 169.809C81.5757 121.787 138.509 102.695 182.402 131.721C187.656 135.193 192.829 138.787 198.149 142.406C200.682 140.009 202.496 138.35 204.242 136.622C224.509 116.598 244.109 95.8634 265.162 76.7034C293.082 51.2821 325.909 36.9234 364.469 39.9821C377.656 41.0274 390.656 44.4154 406.242 47.1781C374.122 16.6794 338.802 2.73806 296.776 9.35939C257.362 15.5701 226.149 36.7381 199.789 65.6101C193.602 72.3927 188.029 74.0394 179.256 70.7394C168.722 66.7727 158.376 64.2394 148.229 63.0127L148.229 63.0087C148.216 63.0074 148.189 63.0074 148.176 63.0061C148.056 62.9914 147.936 62.9714 147.816 62.9581C147.802 62.9687 147.802 62.9767 147.789 62.9874C21.4957 55.3727 9.17567 165.405 9.17567 165.405C-2.58433 286.525 80.029 311.302 80.029 311.302L80.069 311.302C90.0823 315.263 100.456 318.062 111.029 320.229L111.042 320.25C111.042 320.25 112.962 320.745 116.509 321.295C117.456 321.47 118.402 321.653 119.349 321.819C119.376 321.781 119.402 321.745 119.416 321.706C138.362 324.111 187.416 325.538 246.122 289.946C246.242 289.951 246.376 289.939 246.496 289.95C284.176 252.225 321.882 214.525 359.722 176.97C377.829 159.006 394.296 138.981 418.056 127.409C455.242 109.302 501.269 117.934 522.642 147.982C539.616 171.834 541.616 197.893 529.402 223.943C516.682 251.057 493.776 265.733 464.016 266.622C423.082 267.846 382.082 267.358 341.122 267.277C332.309 267.259 325.469 269.946 319.336 276.357C306.549 289.741 293.216 302.61 280.202 315.782C278.402 317.595 275.269 320.245 272.429 323.437C276.522 323.878 281.362 324.021 283.762 324.023C330.429 324.065 377.096 324.385 423.762 323.905C446.856 323.666 470.549 324.903 492.896 320.317C561.376 306.267 604.602 237.579 591.109 167.89" fill="#fdf6e3" fill-rule="nonzero" opacity="1" stroke="none"/>
|
||||
<path d="M202.896 194.097C202.896 228.629 174.909 256.622 140.376 256.622C105.842 256.622 77.8423 228.629 77.8423 194.097C77.8423 159.565 105.842 131.57 140.376 131.57C174.909 131.57 202.896 159.565 202.896 194.097" fill="#fdf6e3" fill-rule="nonzero" opacity="1" stroke="none"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
12
doc/website/static/img/logo-ois.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Created with Vectornator (http://vectornator.io/) -->
|
||||
<svg style="fill-rule:nonzero;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;" version="1.1" viewBox="0 0 605.044 336.948" xmlns="http://www.w3.org/2000/svg" xmlns:vectornator="http://vectornator.io" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs/>
|
||||
<g id="Logo" vectornator:layerName="Logo">
|
||||
<g opacity="1">
|
||||
<path d="M591.109 167.89C580.229 111.687 546.936 77.6261 491.282 65.5687C433.469 53.0447 384.362 69.3554 342.802 110.398C310.616 142.185 278.709 174.259 246.482 205.995C225.922 226.226 205.922 247.343 179.109 259.626C149.202 273.334 119.469 272.37 93.4157 251.847C66.8557 230.91 61.2157 201.791 69.349 169.809C81.5757 121.787 138.509 102.695 182.402 131.721C187.656 135.193 192.829 138.787 198.149 142.406C200.682 140.009 202.496 138.35 204.242 136.622C224.509 116.598 244.109 95.8634 265.162 76.7034C293.082 51.2821 325.909 36.9234 364.469 39.9821C377.656 41.0274 390.656 44.4154 406.242 47.1781C374.122 16.6794 338.802 2.73806 296.776 9.35939C257.362 15.5701 226.149 36.7381 199.789 65.6101C193.602 72.3927 188.029 74.0394 179.256 70.7394C168.722 66.7727 158.376 64.2394 148.229 63.0127L148.229 63.0087C148.216 63.0074 148.189 63.0074 148.176 63.0061C148.056 62.9914 147.936 62.9714 147.816 62.9581C147.802 62.9687 147.802 62.9767 147.789 62.9874C21.4957 55.3727 9.17567 165.405 9.17567 165.405C-2.58433 286.525 80.029 311.302 80.029 311.302L80.069 311.302C90.0823 315.263 100.456 318.062 111.029 320.229L111.042 320.25C111.042 320.25 112.962 320.745 116.509 321.295C117.456 321.47 118.402 321.653 119.349 321.819C119.376 321.781 119.402 321.745 119.416 321.706C138.362 324.111 187.416 325.538 246.122 289.946C246.242 289.951 246.376 289.939 246.496 289.95C284.176 252.225 321.882 214.525 359.722 176.97C377.829 159.006 394.296 138.981 418.056 127.409C455.242 109.302 501.269 117.934 522.642 147.982C539.616 171.834 541.616 197.893 529.402 223.943C516.682 251.057 493.776 265.733 464.016 266.622C423.082 267.846 382.082 267.358 341.122 267.277C332.309 267.259 325.469 269.946 319.336 276.357C306.549 289.741 293.216 302.61 280.202 315.782C278.402 317.595 275.269 320.245 272.429 323.437C276.522 323.878 281.362 324.021 283.762 324.023C330.429 324.065 377.096 324.385 423.762 323.905C446.856 323.666 470.549 324.903 492.896 320.317C561.376 306.267 604.602 237.579 591.109 167.89" fill="#142831" fill-rule="nonzero" opacity="1" stroke="none"/>
|
||||
<path d="M202.896 194.097C202.896 228.629 174.909 256.622 140.376 256.622C105.842 256.622 77.8423 228.629 77.8423 194.097C77.8423 159.565 105.842 131.57 140.376 131.57C174.909 131.57 202.896 159.565 202.896 194.097" fill="#142831" fill-rule="nonzero" opacity="1" stroke="none"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
14
hack/gendoc
@@ -1,5 +1,12 @@
|
||||
#! /bin/bash
|
||||
#
|
||||
|
||||
tmpdir="$(mktemp -d)"
|
||||
finish() {
|
||||
rm -rf "$tmpdir"
|
||||
}
|
||||
trap finish EXIT
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Generate the documentation for the package the calls go:generate
|
||||
@@ -10,8 +17,5 @@ gomarkdoc --output "doc/md/${package%/}.md" "./${package}"
|
||||
|
||||
# Fix heading anchors by making them explicit
|
||||
# Refer to https://docusaurus.io/docs/markdown-features/toc#heading-ids
|
||||
stamp=$RANDOM
|
||||
# sed 's/^## type /## /' "doc/md/${package%/}.md" > "doc/md/${package%/}.md.${stamp}"
|
||||
|
||||
sed -E 's/## type ([A-Za-z0-9_]+)/## type \1 {#\1}/' "doc/md/${package%/}.md" > "doc/md/${package%/}.md.${stamp}"
|
||||
mv "doc/md/${package%/}.md.${stamp}" "doc/md/${package%/}.md"
|
||||
sed -E 's/## type ([A-Za-z0-9_]+)/## type \1 {#\1}/' "doc/md/${package%/}.md" > "${tmpdir}/doc.md"
|
||||
cat "./${package%%/}/header.yaml" "${tmpdir}/doc.md" > "doc/md/${package%/}.md"
|
||||
|
||||
@@ -18,8 +18,8 @@ import (
|
||||
|
||||
"github.com/holos-run/holos"
|
||||
core_v1alpha2 "github.com/holos-run/holos/api/core/v1alpha2"
|
||||
coreA3 "github.com/holos-run/holos/api/core/v1alpha3"
|
||||
metaA2 "github.com/holos-run/holos/api/meta/v1alpha2"
|
||||
core_v1alpha3 "github.com/holos-run/holos/api/core/v1alpha3"
|
||||
meta_v1alpha2 "github.com/holos-run/holos/api/meta/v1alpha2"
|
||||
"github.com/holos-run/holos/api/v1alpha1"
|
||||
"github.com/holos-run/holos/internal/client"
|
||||
"github.com/holos-run/holos/internal/errors"
|
||||
@@ -28,10 +28,10 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
KubernetesObjects = coreA3.KubernetesObjectsKind
|
||||
KubernetesObjects = core_v1alpha3.KubernetesObjectsKind
|
||||
// Helm is the value of the kind field of holos build output indicating helm
|
||||
// values and helm command information.
|
||||
Helm = coreA3.HelmChartKind
|
||||
Helm = core_v1alpha3.HelmChartKind
|
||||
// Skip is the value when the instance should be skipped
|
||||
Skip = "Skip"
|
||||
// KustomizeBuild is the value of the kind field of cue output indicating
|
||||
@@ -76,7 +76,7 @@ type Builder struct {
|
||||
}
|
||||
|
||||
type buildPlanWrapper struct {
|
||||
buildPlan *coreA3.BuildPlan
|
||||
buildPlan *core_v1alpha3.BuildPlan
|
||||
}
|
||||
|
||||
func (b *buildPlanWrapper) validate() error {
|
||||
@@ -88,7 +88,7 @@ func (b *buildPlanWrapper) validate() error {
|
||||
return fmt.Errorf("invalid BuildPlan: is nil")
|
||||
}
|
||||
errs := make([]string, 0, 2)
|
||||
if bp.Kind != coreA3.BuildPlanKind {
|
||||
if bp.Kind != core_v1alpha3.BuildPlanKind {
|
||||
errs = append(errs, fmt.Sprintf("kind invalid: want: %s have: %s", v1alpha1.BuildPlanKind, bp.Kind))
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
@@ -162,13 +162,22 @@ func (b *Builder) Unify(ctx context.Context, cfg *client.Config) (bd BuildData,
|
||||
return bd, errors.Wrap(fmt.Errorf("could not load platform model: %w", err))
|
||||
}
|
||||
|
||||
// TODO(jeff): Changing these tag names breaks backwards compatibility. We
|
||||
// need to refactor this unification into a versioned builder, at least at the
|
||||
// component level. Right now it's executed when rendering the initial
|
||||
// Platform spec, which should be backwards compatible but isn't because this
|
||||
// package is shared by all versions.
|
||||
tags := make([]string, 0, len(b.cfg.tags)+2)
|
||||
tags = append(tags,
|
||||
"cluster="+cfg.Holos().ClusterName(),
|
||||
// TODO: Use instance.FillPath to fill the platform config.
|
||||
// Refer to https://pkg.go.dev/cuelang.org/go/cue#Value.FillPath
|
||||
"platform_config="+string(platformConfigData),
|
||||
)
|
||||
// TODO: Use instance.FillPath to fill the platform config.
|
||||
// Refer to https://pkg.go.dev/cuelang.org/go/cue#Value.FillPath
|
||||
tags = append(tags, "holos_platform_config="+string(platformConfigData))
|
||||
// TODO(jeff): This is hacky after I switched to reserved holos_ tag names in
|
||||
// v1alpha4. Could use some serious clean up now that --cluster-name is
|
||||
// deprecated for --inject holos_cluster=foo, but it was kind of nice to have
|
||||
// a required argument.
|
||||
if cluster := cfg.Holos().ClusterName(); cluster != "" {
|
||||
tags = append(tags, "holos_cluster="+cluster)
|
||||
}
|
||||
tags = append(tags, b.cfg.tags...)
|
||||
|
||||
cueConfig := load.Config{
|
||||
@@ -306,7 +315,7 @@ func (b *Builder) build(ctx context.Context, bd BuildData) (results []*render.Re
|
||||
|
||||
switch tm.Kind {
|
||||
case "BuildPlan":
|
||||
var bp coreA3.BuildPlan
|
||||
var bp core_v1alpha3.BuildPlan
|
||||
if err = decoder.Decode(&bp); err != nil {
|
||||
err = errors.Wrap(fmt.Errorf("could not decode BuildPlan %s: %w", bd.Dir, err))
|
||||
return
|
||||
@@ -322,7 +331,7 @@ func (b *Builder) build(ctx context.Context, bd BuildData) (results []*render.Re
|
||||
return results, err
|
||||
}
|
||||
|
||||
func (b *Builder) buildPlan(ctx context.Context, buildPlan *coreA3.BuildPlan, path holos.InstancePath) (results []*render.Result, err error) {
|
||||
func (b *Builder) buildPlan(ctx context.Context, buildPlan *core_v1alpha3.BuildPlan, path holos.InstancePath) (results []*render.Result, err error) {
|
||||
log := logger.FromContext(ctx)
|
||||
|
||||
bpw := buildPlanWrapper{buildPlan: buildPlan}
|
||||
@@ -443,7 +452,7 @@ func (b *Builder) runPlatform(ctx context.Context, bd BuildData) (*core_v1alpha2
|
||||
|
||||
decoder := json.NewDecoder(bytes.NewReader(jsonBytes))
|
||||
// Discriminate the type of build plan.
|
||||
tm := &metaA2.TypeMeta{}
|
||||
tm := &meta_v1alpha2.TypeMeta{}
|
||||
err = decoder.Decode(tm)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(fmt.Errorf("invalid platform: %s: %w", bd.Dir, err))
|
||||
|
||||
@@ -60,27 +60,32 @@ func (p *Platform) Build(ctx context.Context, _ h.ArtifactMap) error {
|
||||
"name", component.Name,
|
||||
"path", component.Component,
|
||||
"cluster", component.Cluster,
|
||||
"environment", component.Environment,
|
||||
"num", idx+1,
|
||||
"total", total,
|
||||
)
|
||||
log.DebugContext(ctx, "render component")
|
||||
|
||||
tags := make([]string, 0, 3+len(component.Tags))
|
||||
tags = append(tags, "name="+component.Name)
|
||||
tags = append(tags, "component="+component.Component)
|
||||
tags = append(tags, "environment="+component.Environment)
|
||||
// Tags are unified, cue handles conflicts. We don't bother.
|
||||
tags = append(tags, component.Tags...)
|
||||
tags = append(tags, "holos_name="+component.Name)
|
||||
tags = append(tags, "holos_component="+component.Component)
|
||||
tags = append(tags, "holos_cluster="+component.Cluster)
|
||||
for key, value := range component.Tags {
|
||||
tags = append(tags, fmt.Sprintf("%s=%s", key, value))
|
||||
}
|
||||
|
||||
// Execute a sub-process to limit CUE memory usage.
|
||||
args := []string{
|
||||
args := make([]string, 0, 10)
|
||||
args = append(args,
|
||||
"render",
|
||||
"component",
|
||||
"--cluster-name", component.Cluster,
|
||||
"--tags", strings.Join(tags, ","),
|
||||
component.Component,
|
||||
)
|
||||
for _, tag := range tags {
|
||||
args = append(args, "--inject", tag)
|
||||
}
|
||||
if component.WriteTo != "" {
|
||||
args = append(args, "--write-to", component.WriteTo)
|
||||
}
|
||||
args = append(args, component.Component)
|
||||
result, err := util.RunCmd(ctx, "holos", args...)
|
||||
// I've lost an hour+ digging into why I couldn't see log output
|
||||
// from sub-processes. Make sure to surface at least stderr from
|
||||
@@ -285,9 +290,7 @@ func (b *BuildPlan) helm(
|
||||
|
||||
// Run charts
|
||||
args := []string{"template"}
|
||||
if g.Helm.EnableHooks {
|
||||
args = append(args, "--hooks")
|
||||
} else {
|
||||
if !g.Helm.EnableHooks {
|
||||
args = append(args, "--no-hooks")
|
||||
}
|
||||
args = append(args,
|
||||
@@ -337,7 +340,7 @@ func (b *BuildPlan) resources(
|
||||
}
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("could not generate %s for %s", g.Output, b.BuildPlan.Metadata.Name)
|
||||
msg := fmt.Sprintf("could not generate %s for %s path %s", g.Output, b.BuildPlan.Metadata.Name, b.BuildPlan.Spec.Component)
|
||||
|
||||
buf, err := marshal(list)
|
||||
if err != nil {
|
||||
@@ -363,7 +366,7 @@ func (b *BuildPlan) kustomize(
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
defer util.Remove(ctx, tempDir)
|
||||
msg := fmt.Sprintf("could not transform %s for %s", t.Output, b.BuildPlan.Metadata.Name)
|
||||
msg := fmt.Sprintf("could not transform %s for %s path %s", t.Output, b.BuildPlan.Metadata.Name, b.BuildPlan.Spec.Component)
|
||||
|
||||
// Write the kustomization
|
||||
data, err := yaml.Marshal(t.Kustomize.Kustomization)
|
||||
@@ -388,10 +391,9 @@ func (b *BuildPlan) kustomize(
|
||||
// Execute kustomize
|
||||
r, err := util.RunCmd(ctx, "kubectl", "kustomize", tempDir)
|
||||
if err != nil {
|
||||
kErr := r.Stderr.String()
|
||||
err = errors.Format("%s: could not run kustomize: %w", msg, err)
|
||||
if s := strings.ReplaceAll(r.Stderr.String(), "\n", "\n\t"); s != "" {
|
||||
err = errors.Format("%w\n\t%s", err, s)
|
||||
}
|
||||
log.ErrorContext(ctx, fmt.Sprintf("%s: stderr:\n%s", err.Error(), kErr), "err", err, "stderr", kErr)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -512,8 +514,8 @@ func onceWithLock(log *slog.Logger, ctx context.Context, path string, fn func()
|
||||
|
||||
err := os.Mkdir(lockDir, 0777)
|
||||
if err == nil {
|
||||
log.DebugContext(ctx, fmt.Sprintf("acquired %s", lockDir))
|
||||
defer os.RemoveAll(lockDir)
|
||||
log.DebugContext(ctx, fmt.Sprintf("acquired %s", lockDir))
|
||||
if err := fn(); err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
@@ -524,16 +526,21 @@ func onceWithLock(log *slog.Logger, ctx context.Context, path string, fn func()
|
||||
// Wait until the lock is released then return.
|
||||
if os.IsExist(err) {
|
||||
log.DebugContext(ctx, fmt.Sprintf("blocked %s", lockDir))
|
||||
stillBlocked := time.After(5 * time.Second)
|
||||
deadLocked := time.After(10 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return errors.Wrap(ctx.Err())
|
||||
default:
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
case <-stillBlocked:
|
||||
log.WarnContext(ctx, fmt.Sprintf("waiting for %s to be released", lockDir))
|
||||
case <-deadLocked:
|
||||
log.WarnContext(ctx, fmt.Sprintf("still waiting for %s to be released (dead lock?)", lockDir))
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
if _, err := os.Stat(lockDir); os.IsNotExist(err) {
|
||||
log.DebugContext(ctx, fmt.Sprintf("unblocked %s", lockDir))
|
||||
return nil
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return errors.Wrap(ctx.Err())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,8 +43,9 @@ func makeBuildRunFunc(cfg *client.Config) command.RunFunc {
|
||||
}
|
||||
|
||||
// New returns the build subcommand for the root command
|
||||
func New(cfg *holos.Config) *cobra.Command {
|
||||
func New(cfg *holos.Config, feature holos.Flagger) *cobra.Command {
|
||||
cmd := command.New("build DIRECTORY")
|
||||
cmd.Hidden = !feature.Flag(holos.BuildFeature)
|
||||
cmd.Args = cobra.ExactArgs(1)
|
||||
cmd.Short = "write kubernetes manifests to standard output"
|
||||
cmd.Example = " holos build components/argo/crds"
|
||||
|
||||
@@ -12,9 +12,10 @@ import (
|
||||
)
|
||||
|
||||
// New returns the create command for the cli
|
||||
func New(cfg *holos.Config) *cobra.Command {
|
||||
func New(cfg *holos.Config, feature holos.Flagger) *cobra.Command {
|
||||
cmd := command.New("create")
|
||||
cmd.Short = "create resources"
|
||||
cmd.Hidden = !feature.Flag(holos.ServerFeature)
|
||||
cmd.Flags().SortFlags = false
|
||||
cmd.RunE = func(c *cobra.Command, args []string) error {
|
||||
return c.Usage()
|
||||
|
||||
@@ -11,8 +11,9 @@ import (
|
||||
)
|
||||
|
||||
// New returns the command for the cli
|
||||
func New(cfg *holos.Config) *cobra.Command {
|
||||
func New(cfg *holos.Config, feature holos.Flagger) *cobra.Command {
|
||||
cmd := command.New("delete")
|
||||
cmd.Hidden = !feature.Flag(holos.ServerFeature)
|
||||
cmd.Aliases = []string{"destroy"}
|
||||
cmd.Short = "delete resources"
|
||||
cmd.Flags().SortFlags = false
|
||||
|
||||
@@ -14,14 +14,14 @@ import (
|
||||
)
|
||||
|
||||
// New returns a new generate command.
|
||||
func New(cfg *holos.Config) *cobra.Command {
|
||||
func New(cfg *holos.Config, feature holos.Flagger) *cobra.Command {
|
||||
cmd := command.New("generate")
|
||||
cmd.Aliases = []string{"gen"}
|
||||
cmd.Short = "generate local resources"
|
||||
cmd.Args = cobra.NoArgs
|
||||
|
||||
cmd.AddCommand(NewPlatform(cfg))
|
||||
cmd.AddCommand(NewComponent())
|
||||
cmd.AddCommand(NewComponent(feature))
|
||||
|
||||
return cmd
|
||||
}
|
||||
@@ -48,9 +48,10 @@ func NewPlatform(cfg *holos.Config) *cobra.Command {
|
||||
}
|
||||
|
||||
// NewComponent returns a command to generate a holos component
|
||||
func NewComponent() *cobra.Command {
|
||||
func NewComponent(feature holos.Flagger) *cobra.Command {
|
||||
cmd := command.New("component")
|
||||
cmd.Short = "generate a component from an embedded schematic"
|
||||
cmd.Hidden = !feature.Flag(holos.GenerateComponentFeature)
|
||||
|
||||
for _, name := range generate.Components("v1alpha3") {
|
||||
cmd.AddCommand(makeSchematicCommand("v1alpha3", name))
|
||||
|
||||
@@ -16,8 +16,10 @@ import (
|
||||
)
|
||||
|
||||
// New returns the get command for the cli.
|
||||
func New(hc *holos.Config) *cobra.Command {
|
||||
func New(hc *holos.Config, feature holos.Flagger) *cobra.Command {
|
||||
cmd := command.New("get")
|
||||
// not supported as of v0.97
|
||||
cmd.Hidden = !feature.Flag(holos.ServerFeature)
|
||||
cmd.Short = "get resources"
|
||||
cmd.Aliases = []string{"list"}
|
||||
cmd.Flags().SortFlags = false
|
||||
|
||||
@@ -10,8 +10,9 @@ import (
|
||||
)
|
||||
|
||||
// New returns the kv root command for the cli
|
||||
func New(cfg *holos.Config) *cobra.Command {
|
||||
func New(cfg *holos.Config, feature holos.Flagger) *cobra.Command {
|
||||
cmd := command.New("kv")
|
||||
cmd.Hidden = !feature.Flag(holos.SecretsFeature)
|
||||
cmd.Short = "work with secrets in the provisioner cluster"
|
||||
cmd.Flags().SortFlags = false
|
||||
cmd.RunE = func(c *cobra.Command, args []string) error {
|
||||
|
||||
@@ -13,8 +13,9 @@ import (
|
||||
)
|
||||
|
||||
// New returns a new login command.
|
||||
func New(cfg *holos.Config) *cobra.Command {
|
||||
func New(cfg *holos.Config, feature holos.Flagger) *cobra.Command {
|
||||
cmd := command.New("login")
|
||||
cmd.Hidden = !feature.Flag(holos.ServerFeature)
|
||||
cmd.Short = "log in by caching credentials"
|
||||
var printClaims bool
|
||||
|
||||
|
||||
@@ -11,8 +11,9 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func New(cfg *holos.Config) *cobra.Command {
|
||||
func New(cfg *holos.Config, feature holos.Flagger) *cobra.Command {
|
||||
cmd := command.New("logout")
|
||||
cmd.Hidden = !feature.Flag(holos.ServerFeature)
|
||||
cmd.Short = "log out by deleting cached credentials"
|
||||
cmd.RunE = func(c *cobra.Command, args []string) error {
|
||||
if err := os.RemoveAll(token.CacheDir); err != nil {
|
||||
|
||||
@@ -18,7 +18,8 @@ func MakeMain(options ...holos.Option) func() int {
|
||||
cfg := holos.New(options...)
|
||||
slog.SetDefault(cfg.Logger())
|
||||
ctx := context.Background()
|
||||
if err := New(cfg).ExecuteContext(ctx); err != nil {
|
||||
feature := &holos.EnvFlagger{}
|
||||
if err := New(cfg, feature).ExecuteContext(ctx); err != nil {
|
||||
return HandleError(ctx, err, cfg)
|
||||
}
|
||||
return 0
|
||||
|
||||
@@ -25,10 +25,10 @@ func newConfig() (*config, *flag.FlagSet) {
|
||||
}
|
||||
|
||||
// New returns the preflight command for the root command.
|
||||
func New(hc *holos.Config) *cobra.Command {
|
||||
func New(hc *holos.Config, feature holos.Flagger) *cobra.Command {
|
||||
cfg, flagSet := newConfig()
|
||||
|
||||
cmd := command.New("preflight")
|
||||
cmd.Hidden = !feature.Flag(holos.PreflightFeature)
|
||||
cmd.Short = "run holos preflight checks"
|
||||
cmd.Flags().AddGoFlagSet(flagSet)
|
||||
cmd.RunE = makePreflightRunFunc(hc, cfg)
|
||||
|
||||
@@ -14,8 +14,9 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func New(cfg *holos.Config) *cobra.Command {
|
||||
func New(cfg *holos.Config, feature holos.Flagger) *cobra.Command {
|
||||
cmd := command.New("pull")
|
||||
cmd.Hidden = !feature.Flag(holos.ServerFeature)
|
||||
cmd.Short = "pull resources from holos server"
|
||||
cmd.Args = cobra.NoArgs
|
||||
|
||||
|
||||
@@ -14,9 +14,10 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func New(cfg *holos.Config) *cobra.Command {
|
||||
func New(cfg *holos.Config, feature holos.Flagger) *cobra.Command {
|
||||
cmd := command.New("push")
|
||||
cmd.Short = "push resources to holos server"
|
||||
cmd.Hidden = !feature.Flag(holos.ServerFeature)
|
||||
cmd.Args = cobra.NoArgs
|
||||
|
||||
config := client.NewConfig(cfg)
|
||||
|
||||
@@ -10,8 +10,9 @@ import (
|
||||
)
|
||||
|
||||
// New returns a new register command.
|
||||
func New(cfg *holos.Config) *cobra.Command {
|
||||
func New(cfg *holos.Config, feature holos.Flagger) *cobra.Command {
|
||||
cmd := command.New("register")
|
||||
cmd.Hidden = !feature.Flag(holos.ServerFeature)
|
||||
cmd.Short = "rpc UserService.RegisterUser"
|
||||
cmd.Long = "register with holos server"
|
||||
cmd.Args = cobra.NoArgs
|
||||
|
||||
@@ -22,10 +22,10 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func New(cfg *holos.Config) *cobra.Command {
|
||||
func New(cfg *holos.Config, feature holos.Flagger) *cobra.Command {
|
||||
cmd := command.New("render")
|
||||
cmd.Args = cobra.NoArgs
|
||||
cmd.Short = "render platforms and components into the deploy/ directory"
|
||||
cmd.Short = "render platforms and components to manifest files"
|
||||
cmd.AddCommand(NewComponent(cfg))
|
||||
cmd.AddCommand(NewPlatform(cfg))
|
||||
return cmd
|
||||
@@ -35,8 +35,8 @@ func New(cfg *holos.Config) *cobra.Command {
|
||||
func NewComponent(cfg *holos.Config) *cobra.Command {
|
||||
cmd := command.New("component DIRECTORY")
|
||||
cmd.Args = cobra.ExactArgs(1)
|
||||
cmd.Short = "render specific components"
|
||||
cmd.Example = " holos render component --cluster-name=aws2 ./components/monitoring/kube-prometheus-stack"
|
||||
cmd.Short = "render a platform component"
|
||||
cmd.Example = " holos render component --inject holos_cluster=aws2 ./components/monitoring/kube-prometheus-stack"
|
||||
cmd.Flags().AddGoFlagSet(cfg.WriteFlagSet())
|
||||
cmd.Flags().AddGoFlagSet(cfg.ClusterFlagSet())
|
||||
|
||||
@@ -47,7 +47,8 @@ func NewComponent(cfg *holos.Config) *cobra.Command {
|
||||
flagSet := flag.NewFlagSet("", flag.ContinueOnError)
|
||||
|
||||
tagMap := make(tags)
|
||||
flagSet.Var(&tagMap, "tags", "cue tags as comma separated key=value pairs")
|
||||
cmd.PersistentFlags().VarP(&tagMap, "inject", "t", "set the value of a cue @tag field from a key=value pair")
|
||||
|
||||
var concurrency int
|
||||
flagSet.IntVar(&concurrency, "concurrency", min(runtime.NumCPU(), 8), "number of concurrent build steps")
|
||||
cmd.Flags().AddGoFlagSet(flagSet)
|
||||
@@ -67,16 +68,16 @@ func NewComponent(cfg *holos.Config) *cobra.Command {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
|
||||
tm, err := bd.TypeMeta()
|
||||
typeMeta, err := bd.TypeMeta()
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
|
||||
if tm.Kind != "BuildPlan" {
|
||||
return errors.Format("invalid kind: want: BuildPlan have: %s", tm.Kind)
|
||||
if typeMeta.Kind != "BuildPlan" {
|
||||
return errors.Format("invalid kind: want: BuildPlan have: %s", typeMeta.Kind)
|
||||
}
|
||||
|
||||
log.DebugContext(ctx, "discriminated "+tm.APIVersion+" "+tm.Kind)
|
||||
log.DebugContext(ctx, "discriminated "+typeMeta.APIVersion+" "+typeMeta.Kind)
|
||||
|
||||
jsonBytes, err := bd.Value.MarshalJSON()
|
||||
if err != nil {
|
||||
@@ -87,7 +88,7 @@ func NewComponent(cfg *holos.Config) *cobra.Command {
|
||||
|
||||
art := artifact.New()
|
||||
|
||||
switch version := tm.APIVersion; version {
|
||||
switch version := typeMeta.APIVersion; version {
|
||||
case "v1alpha4":
|
||||
builder := v1alpha4.BuildPlan{
|
||||
WriteTo: cfg.WriteTo(),
|
||||
@@ -242,6 +243,10 @@ func (t tags) Set(value string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t tags) Type() string {
|
||||
return "strings"
|
||||
}
|
||||
|
||||
// Deprecated: use render.Artifact instead.
|
||||
type Result interface {
|
||||
Continue() bool
|
||||
|
||||
@@ -35,7 +35,7 @@ import (
|
||||
var helpLong string
|
||||
|
||||
// New returns a new root *cobra.Command for command line execution.
|
||||
func New(cfg *holos.Config) *cobra.Command {
|
||||
func New(cfg *holos.Config, feature holos.Flagger) *cobra.Command {
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "holos",
|
||||
Short: "holos manages a holistic integrated software development platform",
|
||||
@@ -67,36 +67,37 @@ func New(cfg *holos.Config) *cobra.Command {
|
||||
rootCmd.PersistentFlags().AddGoFlagSet(cfg.LogFlagSet())
|
||||
|
||||
// subcommands
|
||||
rootCmd.AddCommand(build.New(cfg))
|
||||
rootCmd.AddCommand(render.New(cfg))
|
||||
rootCmd.AddCommand(get.New(cfg))
|
||||
rootCmd.AddCommand(create.New(cfg))
|
||||
rootCmd.AddCommand(destroy.New(cfg))
|
||||
rootCmd.AddCommand(preflight.New(cfg))
|
||||
rootCmd.AddCommand(login.New(cfg))
|
||||
rootCmd.AddCommand(logout.New(cfg))
|
||||
rootCmd.AddCommand(token.New(cfg))
|
||||
rootCmd.AddCommand(generate.New(cfg))
|
||||
rootCmd.AddCommand(register.New(cfg))
|
||||
rootCmd.AddCommand(pull.New(cfg))
|
||||
rootCmd.AddCommand(push.New(cfg))
|
||||
rootCmd.AddCommand(newOrgCmd())
|
||||
rootCmd.AddCommand(build.New(cfg, feature))
|
||||
rootCmd.AddCommand(render.New(cfg, feature))
|
||||
rootCmd.AddCommand(get.New(cfg, feature))
|
||||
rootCmd.AddCommand(create.New(cfg, feature))
|
||||
rootCmd.AddCommand(destroy.New(cfg, feature))
|
||||
rootCmd.AddCommand(preflight.New(cfg, feature))
|
||||
rootCmd.AddCommand(login.New(cfg, feature))
|
||||
rootCmd.AddCommand(logout.New(cfg, feature))
|
||||
rootCmd.AddCommand(token.New(cfg, feature))
|
||||
rootCmd.AddCommand(generate.New(cfg, feature))
|
||||
rootCmd.AddCommand(register.New(cfg, feature))
|
||||
rootCmd.AddCommand(pull.New(cfg, feature))
|
||||
rootCmd.AddCommand(push.New(cfg, feature))
|
||||
rootCmd.AddCommand(newOrgCmd(feature))
|
||||
|
||||
// Maybe not needed?
|
||||
rootCmd.AddCommand(txtar.New(cfg))
|
||||
|
||||
// Deprecated, remove?
|
||||
rootCmd.AddCommand(kv.New(cfg))
|
||||
rootCmd.AddCommand(kv.New(cfg, feature))
|
||||
|
||||
// Server
|
||||
rootCmd.AddCommand(server.New(cfg))
|
||||
rootCmd.AddCommand(server.New(cfg, feature))
|
||||
|
||||
return rootCmd
|
||||
}
|
||||
|
||||
func newOrgCmd() (cmd *cobra.Command) {
|
||||
func newOrgCmd(feature holos.Flagger) (cmd *cobra.Command) {
|
||||
cmd = command.New("orgid")
|
||||
cmd.Short = "print the current context org id."
|
||||
cmd.Hidden = !feature.Flag(holos.ServerFeature)
|
||||
cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Root().Context()
|
||||
cc := holos.NewClientContext(ctx)
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
func newCommand() (*cobra.Command, *bytes.Buffer) {
|
||||
var b1, b2 bytes.Buffer
|
||||
// discard stdout for now, it's a bunch of usage messages.
|
||||
cmd := New(holos.New(holos.Stdout(&b1), holos.Stderr(&b2)))
|
||||
cmd := New(holos.New(holos.Stdout(&b1), holos.Stderr(&b2)), &holos.EnvFlagger{})
|
||||
return cmd, &b2
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ func TestInvalidArgs(t *testing.T) {
|
||||
}
|
||||
for _, args := range invalidArgs {
|
||||
var b bytes.Buffer
|
||||
cmd := New(holos.New(holos.Stdout(&b)))
|
||||
cmd := New(holos.New(holos.Stdout(&b)), &holos.EnvFlagger{})
|
||||
cmd.SetArgs(args)
|
||||
err := cmd.Execute()
|
||||
if err == nil {
|
||||
@@ -115,7 +115,7 @@ func TestLoggerFromContext(t *testing.T) {
|
||||
|
||||
func TestVersion(t *testing.T) {
|
||||
var b bytes.Buffer
|
||||
cmd := New(holos.New(holos.Stdout(&b)))
|
||||
cmd := New(holos.New(holos.Stdout(&b)), &holos.EnvFlagger{})
|
||||
cmd.SetOut(&b)
|
||||
cmd.SetArgs([]string{"--version"})
|
||||
if err := cmd.Execute(); err != nil {
|
||||
|
||||
@@ -77,7 +77,7 @@ func cmdHolos(ts *testscript.TestScript, neg bool, args []string) {
|
||||
holos.Stderr(ts.Stderr()),
|
||||
)
|
||||
|
||||
cmd := cli.New(cfg)
|
||||
cmd := cli.New(cfg, &holos.EnvFlagger{})
|
||||
cmd.SetArgs(args)
|
||||
err := cmd.Execute()
|
||||
|
||||
|
||||
@@ -13,8 +13,9 @@ import (
|
||||
)
|
||||
|
||||
// New returns a new login command.
|
||||
func New(cfg *holos.Config) *cobra.Command {
|
||||
func New(cfg *holos.Config, feature holos.Flagger) *cobra.Command {
|
||||
cmd := command.New("token")
|
||||
cmd.Hidden = !feature.Flag(holos.ServerFeature)
|
||||
cmd.Short = "write id token to stdout"
|
||||
cmd.Long = "Useful with curl / grpcurl -H $(holos token)"
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ func NotImplemented() error {
|
||||
return wrap(New("not implemented"), 2)
|
||||
}
|
||||
|
||||
// Format calls fmt.Format(format, a...) and wraps the error with the caller
|
||||
// source location.
|
||||
// Format calls fmt.Errorf(format, a...) then wraps the error with the source
|
||||
// location of the caller.
|
||||
func Format(format string, a ...any) error {
|
||||
return wrap(fmt.Errorf(format, a...), 2)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,318 @@
|
||||
// Code generated by cue get go. DO NOT EDIT.
|
||||
|
||||
//cue:generate cue get go github.com/holos-run/holos/api/author/v1alpha4
|
||||
|
||||
// # Author API
|
||||
//
|
||||
// Package v1alpha4 contains ergonomic CUE definitions for Holos component
|
||||
// authors. These definitions serve as adapters to produce [Core API] resources
|
||||
// for the holos command line tool.
|
||||
//
|
||||
// [Core API]: https://holos.run/docs/api/core/v1alpha4/
|
||||
package v1alpha4
|
||||
|
||||
import core "github.com/holos-run/holos/api/core/v1alpha4"
|
||||
|
||||
// Platform assembles a Core API [Platform] in the Resource field for the holos
|
||||
// render platform command. Use the Components field to register components
|
||||
// with the platform using a struct. This struct is converted into a list for
|
||||
// final output to holos.
|
||||
//
|
||||
// See related:
|
||||
//
|
||||
// - [Component] collection of components composing the platform.
|
||||
// - [Platform] resource assembled for holos to process.
|
||||
//
|
||||
// [Platform]: https://holos.run/docs/api/core/v1alpha4/#Platform
|
||||
// [Component]: https://holos.run/docs/api/core/v1alpha4/#Component
|
||||
#Platform: {
|
||||
Name: string
|
||||
Components: {[string]: core.#Component} @go(,map[NameLabel]core.Component)
|
||||
Resource: core.#Platform
|
||||
}
|
||||
|
||||
// Cluster represents a cluster managed by the Platform.
|
||||
#Cluster: {
|
||||
// Name represents the cluster name, for example "east1", "west1", or
|
||||
// "management".
|
||||
name: string @go(Name)
|
||||
|
||||
// Primary represents if the cluster is marked as the primary among a set of
|
||||
// candidate clusters. Useful for promotion of database leaders.
|
||||
primary: bool & (true | *false) @go(Primary)
|
||||
}
|
||||
|
||||
// Fleet represents a named collection of similarly configured Clusters. Useful
|
||||
// to segregate workload clusters from their management cluster.
|
||||
#Fleet: {
|
||||
name: string @go(Name)
|
||||
|
||||
// Clusters represents a mapping of Clusters by their name.
|
||||
clusters: {[string]: #Cluster} & {[Name=_]: name: Name} @go(Clusters,map[string]Cluster)
|
||||
}
|
||||
|
||||
// StandardFleets represents the standard set of Clusters in a Platform
|
||||
// segmented into Fleets by their purpose. The management Fleet contains a
|
||||
// single Cluster, for example a GKE autopilot cluster with no workloads
|
||||
// deployed for reliability and cost efficiency. The workload Fleet contains
|
||||
// all other Clusters which contain workloads and sync Secrets from the
|
||||
// management cluster.
|
||||
#StandardFleets: {
|
||||
// Workload represents a Fleet of zero or more workload Clusters.
|
||||
workload: #Fleet & {name: "workload"} @go(Workload)
|
||||
|
||||
// Management represents a Fleet with one Cluster named management.
|
||||
management: #Fleet & {name: "management"} @go(Management)
|
||||
}
|
||||
|
||||
// ArgoConfig represents the ArgoCD GitOps configuration associated with a
|
||||
// [BuildPlan]. Useful to define once at the root of the Platform configuration
|
||||
// and reuse across all components.
|
||||
//
|
||||
// [BuildPlan]: https://holos.run/docs/api/core/v1alpha4/#buildplan
|
||||
#ArgoConfig: {
|
||||
// Enabled causes holos to render an Application resource when true.
|
||||
Enabled: bool & (true | *false)
|
||||
|
||||
// RepoURL represents the value passed to the Application.spec.source.repoURL
|
||||
// field.
|
||||
RepoURL: string
|
||||
|
||||
// Root represents the path from the git repository root to the WriteTo output
|
||||
// directory, the behavior of the holos render component --write-to flag and
|
||||
// the Core API Component WriteTo field. Used as a prefix for the
|
||||
// Application.spec.source.path field.
|
||||
Root: string & (string | *"deploy")
|
||||
|
||||
// TargetRevision represents the value passed to the
|
||||
// Application.spec.source.targetRevision field. Defaults to the branch named
|
||||
// main.
|
||||
TargetRevision: string & (string | *"main")
|
||||
|
||||
// AppProject represents the ArgoCD Project to associate the Application with.
|
||||
AppProject: string & (string | *"default")
|
||||
}
|
||||
|
||||
// Organization represents organizational metadata useful across the platform.
|
||||
#Organization: {
|
||||
Name: string
|
||||
DisplayName: string
|
||||
Domain: string
|
||||
}
|
||||
|
||||
// OrganizationStrict represents organizational metadata useful across the
|
||||
// platform. This is an example of using CUE regular expressions to constrain
|
||||
// and validate configuration.
|
||||
#OrganizationStrict: {
|
||||
#Organization
|
||||
|
||||
// Name represents the organization name as a resource name. Must be 63
|
||||
// characters or less. Must start with a letter. May contain non-repeating
|
||||
// hyphens, letters, and numbers. Must end with a letter or number.
|
||||
Name: string & (=~"^[a-z][0-9a-z-]{1,61}[0-9a-z]$" & !~"--")
|
||||
|
||||
// DisplayName represents the human readable organization name.
|
||||
DisplayName: string & (=~"^[0-9A-Za-z][0-9A-Za-z ]{2,61}[0-9A-Za-z]$" & !~" ")
|
||||
}
|
||||
|
||||
// Kubernetes provides a [BuildPlan] via the Output field which contains inline
|
||||
// API Objects provided directly from CUE in the Resources field of
|
||||
// [ComponentConfig].
|
||||
//
|
||||
// See related:
|
||||
//
|
||||
// - [ComponentConfig]
|
||||
// - [BuildPlan]
|
||||
//
|
||||
// [BuildPlan]: https://holos.run/docs/api/core/v1alpha4/#BuildPlan
|
||||
#Kubernetes: {
|
||||
#ComponentConfig
|
||||
|
||||
// BuildPlan represents the derived BuildPlan produced for the holos render
|
||||
// component command.
|
||||
BuildPlan: core.#BuildPlan
|
||||
}
|
||||
|
||||
// Helm provides a [BuildPlan] via the Output field which generates manifests
|
||||
// from a helm chart with optional mix-in resources provided directly from CUE
|
||||
// in the Resources field.
|
||||
//
|
||||
// This definition is a convenient way to produce a [BuildPlan] composed of
|
||||
// three [Resources] generators with one [Kustomize] transformer.
|
||||
//
|
||||
// See related:
|
||||
//
|
||||
// - [ComponentConfig]
|
||||
// - [Chart]
|
||||
// - [Values]
|
||||
// - [BuildPlan]
|
||||
//
|
||||
// [BuildPlan]: https://holos.run/docs/api/core/v1alpha4/#BuildPlan
|
||||
// [Chart]: https://holos.run/docs/api/core/v1alpha4/#Chart
|
||||
// [Values]: https://holos.run/docs/api/core/v1alpha4/#Values
|
||||
#Helm: {
|
||||
#ComponentConfig
|
||||
|
||||
// Chart represents a Helm chart.
|
||||
Chart: core.#Chart
|
||||
|
||||
// Values represents data to marshal into a values.yaml for helm.
|
||||
Values: core.#Values
|
||||
|
||||
// EnableHooks enables helm hooks when executing the `helm template` command.
|
||||
EnableHooks: bool
|
||||
|
||||
// BuildPlan represents the derived BuildPlan produced for the holos render
|
||||
// component command.
|
||||
BuildPlan: core.#BuildPlan
|
||||
}
|
||||
|
||||
// Kustomize provides a [BuildPlan] via the Output field which generates
|
||||
// manifests from a kustomize kustomization with optional mix-in resources
|
||||
// provided directly from CUE in the Resources field.
|
||||
//
|
||||
// See related:
|
||||
//
|
||||
// - [ComponentConfig]
|
||||
// - [BuildPlan]
|
||||
//
|
||||
// [BuildPlan]: https://holos.run/docs/api/core/v1alpha4/#buildplan
|
||||
#Kustomize: {
|
||||
#ComponentConfig
|
||||
|
||||
// BuildPlan represents the derived BuildPlan produced for the holos render
|
||||
// component command.
|
||||
BuildPlan: core.#BuildPlan
|
||||
}
|
||||
|
||||
// ComponentConfig represents the configuration common to all kinds of
|
||||
// component.
|
||||
//
|
||||
// - [Helm] charts.
|
||||
// - [Kubernetes] resources generated from CUE.
|
||||
// - [Kustomize] bases.
|
||||
//
|
||||
// See the following resources for additional details:
|
||||
//
|
||||
// - [Resources]
|
||||
// - [ArgoConfig]
|
||||
// - [KustomizeConfig]
|
||||
// - [BuildPlan]
|
||||
//
|
||||
// [BuildPlan]: https://holos.run/docs/api/core/v1alpha4/#BuildPlan
|
||||
// [Resources]: https://holos.run/docs/api/core/v1alpha4/#Resources
|
||||
#ComponentConfig: {
|
||||
// Name represents the BuildPlan metadata.name field. Used to construct the
|
||||
// fully rendered manifest file path.
|
||||
Name: string
|
||||
|
||||
// Component represents the path to the component producing the BuildPlan.
|
||||
Component: string
|
||||
|
||||
// Cluster represents the name of the cluster this BuildPlan is for.
|
||||
Cluster: string
|
||||
|
||||
// Resources represents kubernetes resources mixed into the rendered manifest.
|
||||
Resources: core.#Resources
|
||||
|
||||
// ArgoConfig represents the ArgoCD GitOps configuration for this BuildPlan.
|
||||
ArgoConfig: #ArgoConfig
|
||||
|
||||
// CommonLabels represents common labels to manage on all rendered manifests.
|
||||
CommonLabels: {[string]: string} @go(,map[string]string)
|
||||
|
||||
// Namespace manages the metadata.namespace field on all resources except the
|
||||
// ArgoCD Application.
|
||||
Namespace?: string
|
||||
|
||||
// KustomizeConfig represents the configuration for kustomize.
|
||||
KustomizeConfig: #KustomizeConfig
|
||||
}
|
||||
|
||||
// KustomizeConfig represents the configuration for kustomize post processing.
|
||||
// The Files field is used to mixing in static manifest files from the component
|
||||
// directory. The Resources field is used for mixing in manifests from network
|
||||
// locations urls.
|
||||
//
|
||||
// See related:
|
||||
//
|
||||
// - [ComponentConfig]
|
||||
// - [Kustomization]
|
||||
//
|
||||
// [Kustomization]: https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/
|
||||
#KustomizeConfig: {
|
||||
// Kustomization represents the kustomization used to transform resources.
|
||||
// Note the resources field is internally managed from the Files and Resources fields.
|
||||
Kustomization?: {...} @go(,map[string]any)
|
||||
|
||||
// Files represents files to copy from the component directory for kustomization.
|
||||
Files: {[string]: Source: string} & {[NAME=_]: Source: NAME} @go(,map[string]struct{Source string})
|
||||
|
||||
// Resources represents additional entries to included in the resources list.
|
||||
Resources: {[string]: Source: string} & {[NAME=_]: Source: NAME} @go(,map[string]struct{Source string})
|
||||
}
|
||||
|
||||
// Projects represents projects managed by the platform team for use by other
|
||||
// teams using the platform.
|
||||
#Projects: {[string]: #Project}
|
||||
|
||||
// Project represents logical grouping of components owned by one or more teams.
|
||||
// Useful for the platform team to manage resources for project teams to use.
|
||||
#Project: {
|
||||
// Name represents project name.
|
||||
Name: string
|
||||
|
||||
// Owner represents the team who own this project.
|
||||
Owner: #Owner
|
||||
|
||||
// Namespaces represents the namespaces assigned to this project.
|
||||
Namespaces: {[string]: #Namespace} @go(,map[NameLabel]Namespace)
|
||||
|
||||
// Hostnames represents the host names to expose for this project.
|
||||
Hostnames: {[string]: #Hostname} @go(,map[NameLabel]Hostname)
|
||||
|
||||
// CommonLabels represents common labels to manage on all rendered manifests.
|
||||
CommonLabels: {[string]: string} @go(,map[string]string)
|
||||
}
|
||||
|
||||
// Owner represents the owner of a resource. For example, the name and email
|
||||
// address of an engineering team.
|
||||
#Owner: {
|
||||
Name: string
|
||||
Email: string
|
||||
}
|
||||
|
||||
// Namespace represents a Kubernetes namespace.
|
||||
#Namespace: {
|
||||
Name: string
|
||||
}
|
||||
|
||||
// Hostname represents the left most dns label of a domain name.
|
||||
#Hostname: {
|
||||
// Name represents the subdomain to expose, e.g. "www"
|
||||
Name: string
|
||||
|
||||
// Namespace represents the namespace metadata.name field of backend object
|
||||
// reference.
|
||||
Namespace: string
|
||||
|
||||
// Service represents the Service metadata.name field of backend object
|
||||
// reference.
|
||||
Service: string
|
||||
|
||||
// Port represents the Service port of the backend object reference.
|
||||
Port: int
|
||||
}
|
||||
|
||||
// NameLabel signals the common use case of converting a struct to a list where
|
||||
// the name field of each value unifies with the field name of the outer struct.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// S: [NameLabel=string]: name: NameLabel
|
||||
// S: jeff: _
|
||||
// S: gary: _
|
||||
// S: nate: _
|
||||
// L: [for x in S {x}]
|
||||
// // L is [{name: "jeff"}, {name: "gary"}, {name: "nate"}]
|
||||
#NameLabel: string
|
||||
@@ -2,20 +2,83 @@
|
||||
|
||||
//cue:generate cue get go github.com/holos-run/holos/api/core/v1alpha4
|
||||
|
||||
// # Core API
|
||||
//
|
||||
// Package v1alpha4 contains the core API contract between the holos cli and CUE
|
||||
// configuration code. Platform designers, operators, and software developers
|
||||
// use this API to write configuration in CUE which `holos` loads. The overall
|
||||
// shape of the API defines imperative actions `holos` should carry out to
|
||||
// render the complete yaml that represents a Platform.
|
||||
// use this API to write configuration in CUE which holos loads. The Core API
|
||||
// is declarative. Each resource represents a desired state necessary for holos
|
||||
// to fully render Kubernetes manifests into plain files.
|
||||
//
|
||||
// [Platform] defines the complete configuration of a platform. With the holos
|
||||
// reference platform this takes the shape of one management cluster and at
|
||||
// least two workload clusters.
|
||||
// The following resources provide important context for the Core API. The
|
||||
// [Author API] is intended for component authors as a convenient adapter for
|
||||
// the Core API resources Holos expects.
|
||||
//
|
||||
// Each holos component path, e.g. `components/namespaces` produces exactly one
|
||||
// [BuildPlan] which produces an [Artifact] collection. An [Artifact] is a
|
||||
// fully rendered manifest produced from a [Transformer] sequence, which
|
||||
// transforms a [Generator] collection.
|
||||
// 1. [Technical Overview]
|
||||
// 2. [Quickstart]
|
||||
// 3. [Author API]
|
||||
//
|
||||
// # Platform
|
||||
//
|
||||
// [Platform] defines the complete configuration of a platform. A platform
|
||||
// represents a [Component] collection.
|
||||
//
|
||||
// Inspect a Platform resource holos would process by executing:
|
||||
//
|
||||
// cue export --out yaml ./platform
|
||||
//
|
||||
// # Component
|
||||
//
|
||||
// A [Component] is the combination of CUE code along one path relative to the
|
||||
// platform root directory plus data injected from the [PlatformSpec] via CUE tags.
|
||||
// The platform configuration root is the directory containing cue.mod.
|
||||
//
|
||||
// A [Component] always produces exactly one [BuildPlan].
|
||||
//
|
||||
// # BuildPlan
|
||||
//
|
||||
// A [BuildPlan] contains an [Artifact] collection. A BuildPlan often produces
|
||||
// two artifacts, one containing the fully rendered Kubernetes API resources,
|
||||
// the other containing an additional resource to manage the former with GitOps.
|
||||
// For example, a BuildPlan for a podinfo component produces a manifest
|
||||
// containing a Deployment and a Service, along with a second manifest
|
||||
// containing an ArgoCD Application.
|
||||
//
|
||||
// Inspect a BuildPlan resource holos render component would process by executing:
|
||||
//
|
||||
// cue export --out yaml ./projects/platform/components/namespaces
|
||||
//
|
||||
// # Artifact
|
||||
//
|
||||
// An [Artifact] is one fully rendered manifest file produced from the final
|
||||
// [Transformer] in a sequence of transformers. An Artifact may also be
|
||||
// produced directly from a [Generator], but this use case is uncommon.
|
||||
//
|
||||
// # Transformer
|
||||
//
|
||||
// A [Transformer] takes multiple inputs from prior [Generator] or [Transformer]
|
||||
// outputs, then transforms the data into one output. [Kustomize] is the most
|
||||
// commonly used transformer, though a simple [Join] is also supported.
|
||||
//
|
||||
// 1. [Kustomize] - Patch and transform the output from prior generators or
|
||||
// transformers. See [Introduction to Kustomize].
|
||||
// 2. [Join] - Concatenate multiple prior outputs into one output.
|
||||
//
|
||||
// # Generators
|
||||
//
|
||||
// A [Generator] generates Kubernetes resources. [Helm] and [Resources] are the
|
||||
// most commonly used, often paired together to mix-in resources to an
|
||||
// unmodified Helm chart. A simple [File] generator is also available for use
|
||||
// with the [Kustomize] transformer.
|
||||
//
|
||||
// 1. [Resources] - Generates resources from CUE code.
|
||||
// 2. [Helm] - Generates rendered yaml from a [Chart].
|
||||
// 3. [File] - Generates data by reading a file from the component directory.
|
||||
//
|
||||
// [Introduction to Kustomize]: https://kubectl.docs.kubernetes.io/guides/config_management/introduction/
|
||||
// [Author API]: https://holos.run/docs/api/author/
|
||||
// [Quickstart]: https://holos.run/docs/quickstart/
|
||||
// [Technical Overview]: https://holos.run/docs/technical-overview/
|
||||
package v1alpha4
|
||||
|
||||
// BuildPlan represents a build plan for holos to execute. Each [Platform]
|
||||
@@ -23,6 +86,46 @@ package v1alpha4
|
||||
//
|
||||
// One or more [Artifact] files are produced by a BuildPlan, representing the
|
||||
// fully rendered manifests for the Kubernetes API Server.
|
||||
//
|
||||
// # Example BuildPlan
|
||||
//
|
||||
// Command:
|
||||
//
|
||||
// cue export --out yaml ./projects/platform/components/namespaces
|
||||
//
|
||||
// Output:
|
||||
//
|
||||
// kind: BuildPlan
|
||||
// apiVersion: v1alpha4
|
||||
// metadata:
|
||||
// name: dev-namespaces
|
||||
// spec:
|
||||
// component: projects/platform/components/namespaces
|
||||
// artifacts:
|
||||
// - artifact: clusters/no-cluster/components/dev-namespaces/dev-namespaces.gen.yaml
|
||||
// generators:
|
||||
// - kind: Resources
|
||||
// output: resources.gen.yaml
|
||||
// resources:
|
||||
// Namespace:
|
||||
// dev-jeff:
|
||||
// metadata:
|
||||
// name: dev-jeff
|
||||
// labels:
|
||||
// kubernetes.io/metadata.name: dev-jeff
|
||||
// kind: Namespace
|
||||
// apiVersion: v1
|
||||
// transformers:
|
||||
// - kind: Kustomize
|
||||
// inputs:
|
||||
// - resources.gen.yaml
|
||||
// output: clusters/no-cluster/components/dev-namespaces/dev-namespaces.gen.yaml
|
||||
// kustomize:
|
||||
// kustomization:
|
||||
// commonLabels:
|
||||
// holos.run/component.name: dev-namespaces
|
||||
// resources:
|
||||
// - resources.gen.yaml
|
||||
#BuildPlan: {
|
||||
// Kind represents the type of the resource.
|
||||
kind: string & "BuildPlan" @go(Kind)
|
||||
@@ -179,9 +282,12 @@ package v1alpha4
|
||||
join?: #Join @go(Join)
|
||||
}
|
||||
|
||||
// Join represents a [Join](https://pkg.go.dev/strings#Join) [Transformer].
|
||||
// Useful for the common case of combining the output of [Helm] and [Resources]
|
||||
// [Generator] into one [Artifact] when [Kustomize] is otherwise unnecessary.
|
||||
// Join represents a [Transformer] using [bytes.Join] to concatenate multiple
|
||||
// inputs into one output with a separator. Useful for combining output from
|
||||
// [Helm] and [Resources] together into one [Artifact] when [Kustomize] is
|
||||
// otherwise unnecessary.
|
||||
//
|
||||
// [bytes.Join]: https://pkg.go.dev/bytes#Join
|
||||
#Join: {
|
||||
separator: string & (string | *"---\n") @go(Separator)
|
||||
}
|
||||
@@ -262,33 +368,67 @@ package v1alpha4
|
||||
components: [...#Component] @go(Components,[]Component)
|
||||
}
|
||||
|
||||
// Component represents the complete context necessary to produce a [BuildPlan]
|
||||
// from a [Platform] component.
|
||||
// Component represents the complete context necessary to produce a [BuildPlan].
|
||||
// Component carries information injected from holos render platform to holos
|
||||
// render component to produce each [BuildPlan].
|
||||
//
|
||||
// All of these fields are passed to the holos render component command using
|
||||
// flags, which in turn are injected to CUE using tags. Field names should be
|
||||
// used consistently through the platform rendering process for readability.
|
||||
// flags, which in turn are injected to CUE using tags. For clarity, CUE field
|
||||
// and tag names should match the struct json tag names below.
|
||||
#Component: {
|
||||
// Name represents the name of the component, injected as a tag to set the
|
||||
// BuildPlan metadata.name field. Necessary for clear user feedback during
|
||||
// platform rendering.
|
||||
// Name represents the name of the component. Injected as the tag variable
|
||||
// "holos_name" to set the BuildPlan metadata.name field. Necessary for clear
|
||||
// user feedback during platform rendering.
|
||||
name: string @go(Name)
|
||||
|
||||
// Component represents the path of the component relative to the platform root.
|
||||
// Component represents the path of the component relative to the platform
|
||||
// root. Injected as the tag variable "holos_component".
|
||||
component: string @go(Component)
|
||||
|
||||
// Cluster is the cluster name to provide when rendering the component.
|
||||
// Injected as the tag variable "holos_cluster".
|
||||
cluster: string @go(Cluster)
|
||||
|
||||
// Environment for example, dev, test, stage, prod
|
||||
environment?: string @go(Environment)
|
||||
|
||||
// Model represents the platform model holos gets from from the
|
||||
// PlatformService.GetPlatform rpc method and provides to CUE using a tag.
|
||||
model: {...} @go(Model,map[string]any)
|
||||
// Injected as the tag "holos_model".
|
||||
model?: {...} @go(Model,map[string]any)
|
||||
|
||||
// Tags represents cue tags to inject when rendering the component. The json
|
||||
// struct tag names of other fields in this struct are reserved tag names not
|
||||
// to be used in the tags collection.
|
||||
tags?: [...string] @go(Tags,[]string)
|
||||
// Tags represents cue @tag variables injected into the holos render component
|
||||
// command from the holos render platform command. Tags with a "holos_"
|
||||
// prefix are reserved for use by the Holos Authors.
|
||||
tags?: {[string]: string} @go(Tags,map[string]string)
|
||||
|
||||
// WriteTo represents the holos render component --write-to flag. If empty,
|
||||
// the default value for the --write-to flag is used.
|
||||
writeTo?: string @go(WriteTo)
|
||||
}
|
||||
|
||||
// Tags represents standardized fields injected into the component [BuildPlan]
|
||||
// from the [Platform].
|
||||
//
|
||||
// Note, tags should have a reasonable default value to easily use cue eval and
|
||||
// cue export without needing to make a bunch of decisions about tag values.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// import core "github.com/holos-run/holos/api/core/v1alpha4"
|
||||
// _Tags: core.#Tags & {
|
||||
// cluster: _ @tag(cluster, type=string)
|
||||
// environment: _ @tag(environment, type=string)
|
||||
// component: _ @tag(component, type=string)
|
||||
// name: _ @tag(name, type=string)
|
||||
// }
|
||||
#Tags: {
|
||||
// Name represents the BuildPlan metadata.name field injected from the Platform.
|
||||
name: string & (string | *"no-name") @go(Name)
|
||||
|
||||
// Cluster represents the cluster name injected from
|
||||
cluster: string & (string | *"no-cluster") @go(Cluster)
|
||||
|
||||
// Environment represents the build plan environment.
|
||||
environment: string & (string | *"no-environment") @go(Environment)
|
||||
|
||||
// Component represents the path of the component relative to the platform root.
|
||||
component: string & (string | *"no-component") @go(Component)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,364 @@
|
||||
package v1alpha4
|
||||
|
||||
import (
|
||||
ks "sigs.k8s.io/kustomize/api/types"
|
||||
app "argoproj.io/application/v1alpha1"
|
||||
core "github.com/holos-run/holos/api/core/v1alpha4"
|
||||
)
|
||||
|
||||
#Platform: {
|
||||
Name: string | *"no-platform-name"
|
||||
Components: _
|
||||
Resource: {
|
||||
metadata: name: Name
|
||||
spec: components: [for x in Components {x}]
|
||||
}
|
||||
}
|
||||
|
||||
// https://holos.run/docs/api/author/v1alpha4/#Kubernetes
|
||||
#Kubernetes: {
|
||||
Name: _
|
||||
Component: _
|
||||
Cluster: _
|
||||
Resources: _
|
||||
ArgoConfig: _
|
||||
CommonLabels: _
|
||||
Namespace?: _
|
||||
|
||||
KustomizeConfig: {
|
||||
Files: _
|
||||
Resources: _
|
||||
Kustomization: ks.#Kustomization & {
|
||||
apiVersion: "kustomize.config.k8s.io/v1beta1"
|
||||
kind: "Kustomization"
|
||||
}
|
||||
}
|
||||
|
||||
// Kustomize to add custom labels and manage the namespace. More advanced
|
||||
// functionality than this should use the Core API directly and propose
|
||||
// extending the Author API if the need is common.
|
||||
_TransformerArgo: core.#Transformer & {
|
||||
kind: "Kustomize"
|
||||
kustomize: kustomization: ks.#Kustomization & {
|
||||
commonLabels: "holos.run/component.name": BuildPlan.metadata.name
|
||||
commonLabels: CommonLabels
|
||||
}
|
||||
}
|
||||
|
||||
// Add the argocd.argoproj.io/instance label to resources, but not to the
|
||||
// argocd Application config.
|
||||
_Transformer: _TransformerArgo & {
|
||||
kustomize: kustomization: commonLabels: {
|
||||
"argocd.argoproj.io/instance": Name
|
||||
}
|
||||
}
|
||||
|
||||
_Artifacts: {
|
||||
component: {
|
||||
_path: "clusters/\(Cluster)/components/\(Name)"
|
||||
artifact: "\(_path)/\(Name).gen.yaml"
|
||||
let ResourcesOutput = "resources.gen.yaml"
|
||||
let IntermediateOutput = "combined.gen.yaml"
|
||||
generators: [
|
||||
{
|
||||
kind: "Resources"
|
||||
output: ResourcesOutput
|
||||
resources: Resources
|
||||
},
|
||||
for x in KustomizeConfig.Files {
|
||||
kind: "File"
|
||||
output: x.Source
|
||||
file: source: x.Source
|
||||
},
|
||||
for x in KustomizeConfig.Resources {
|
||||
kind: "File"
|
||||
output: x.Source
|
||||
file: source: x.Source
|
||||
},
|
||||
]
|
||||
transformers: [
|
||||
core.#Transformer & {
|
||||
kind: "Kustomize"
|
||||
inputs: [for x in generators {x.output}]
|
||||
output: IntermediateOutput
|
||||
kustomize: kustomization: KustomizeConfig.Kustomization & {
|
||||
resources: [
|
||||
ResourcesOutput,
|
||||
for x in KustomizeConfig.Resources {x.Source},
|
||||
]
|
||||
}
|
||||
},
|
||||
_Transformer & {
|
||||
inputs: [IntermediateOutput]
|
||||
output: artifact
|
||||
kustomize: kustomization: resources: inputs
|
||||
if Namespace != _|_ {
|
||||
kustomize: kustomization: namespace: Namespace
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
// Mix in the ArgoCD Application gitops artifact.
|
||||
(#ArgoArtifact & {
|
||||
name: Name
|
||||
cluster: Cluster
|
||||
config: ArgoConfig
|
||||
transformer: _TransformerArgo
|
||||
component: _Artifacts.component._path
|
||||
}).Artifact
|
||||
}
|
||||
|
||||
BuildPlan: {
|
||||
metadata: name: Name
|
||||
spec: component: Component
|
||||
spec: artifacts: [for x in _Artifacts {x}]
|
||||
}
|
||||
}
|
||||
|
||||
// https://holos.run/docs/api/author/v1alpha4/#Kustomize
|
||||
#Kustomize: {
|
||||
Name: _
|
||||
Component: _
|
||||
Cluster: _
|
||||
Resources: _
|
||||
ArgoConfig: _
|
||||
CommonLabels: _
|
||||
Namespace?: _
|
||||
|
||||
KustomizeConfig: {
|
||||
Files: _
|
||||
Resources: _
|
||||
Kustomization: ks.#Kustomization & {
|
||||
apiVersion: "kustomize.config.k8s.io/v1beta1"
|
||||
kind: "Kustomization"
|
||||
}
|
||||
}
|
||||
|
||||
// Kustomize to add custom labels and manage the namespace. More advanced
|
||||
// functionality than this should use the Core API directly and propose
|
||||
// extending the Author API if the need is common.
|
||||
_TransformerArgo: core.#Transformer & {
|
||||
kind: "Kustomize"
|
||||
kustomize: kustomization: ks.#Kustomization & {
|
||||
commonLabels: "holos.run/component.name": BuildPlan.metadata.name
|
||||
commonLabels: CommonLabels
|
||||
}
|
||||
}
|
||||
|
||||
// Add the argocd.argoproj.io/instance label to resources, but not to the
|
||||
// argocd Application config.
|
||||
_Transformer: _TransformerArgo & {
|
||||
kustomize: kustomization: commonLabels: {
|
||||
"argocd.argoproj.io/instance": Name
|
||||
}
|
||||
}
|
||||
|
||||
_Artifacts: {
|
||||
component: {
|
||||
_path: "clusters/\(Cluster)/components/\(Name)"
|
||||
artifact: "\(_path)/\(Name).gen.yaml"
|
||||
generators: [
|
||||
{
|
||||
kind: "Resources"
|
||||
output: "resources.gen.yaml"
|
||||
resources: Resources
|
||||
},
|
||||
for x in KustomizeConfig.Files {
|
||||
{
|
||||
kind: "File"
|
||||
file: source: x.Source
|
||||
output: file.source
|
||||
}
|
||||
},
|
||||
]
|
||||
let Intermediate = "intermediate.gen.yaml"
|
||||
transformers: [
|
||||
core.#Transformer & {
|
||||
kind: "Kustomize"
|
||||
inputs: [for x in generators {x.output}]
|
||||
output: Intermediate
|
||||
kustomize: kustomization: KustomizeConfig.Kustomization & {
|
||||
resources: [
|
||||
for x in inputs {x},
|
||||
for x in KustomizeConfig.Resources {x.Source},
|
||||
]
|
||||
}
|
||||
},
|
||||
_Transformer & {
|
||||
inputs: [Intermediate]
|
||||
output: artifact
|
||||
kustomize: kustomization: resources: inputs
|
||||
if Namespace != _|_ {
|
||||
kustomize: kustomization: namespace: Namespace
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
// Mix in the ArgoCD Application gitops artifact.
|
||||
(#ArgoArtifact & {
|
||||
name: Name
|
||||
cluster: Cluster
|
||||
config: ArgoConfig
|
||||
transformer: _TransformerArgo
|
||||
component: _Artifacts.component._path
|
||||
}).Artifact
|
||||
}
|
||||
|
||||
BuildPlan: {
|
||||
metadata: name: Name
|
||||
spec: component: Component
|
||||
spec: artifacts: [for x in _Artifacts {x}]
|
||||
}
|
||||
}
|
||||
|
||||
// https://holos.run/docs/api/author/v1alpha4/#Helm
|
||||
#Helm: {
|
||||
Name: _
|
||||
Component: _
|
||||
Cluster: _
|
||||
Resources: _
|
||||
ArgoConfig: _
|
||||
CommonLabels: _
|
||||
Namespace?: _
|
||||
|
||||
Chart: {
|
||||
name: string | *Name
|
||||
release: string | *name
|
||||
}
|
||||
Values: _
|
||||
EnableHooks: true | *false
|
||||
|
||||
KustomizeConfig: {
|
||||
Files: _
|
||||
Resources: _
|
||||
Kustomization: ks.#Kustomization & {
|
||||
apiVersion: "kustomize.config.k8s.io/v1beta1"
|
||||
kind: "Kustomization"
|
||||
}
|
||||
}
|
||||
|
||||
// Kustomize to add custom labels and manage the namespace. More advanced
|
||||
// functionality than this should use the Core API directly and propose
|
||||
// extending the Author API if the need is common.
|
||||
_TransformerArgo: core.#Transformer & {
|
||||
kind: "Kustomize"
|
||||
kustomize: kustomization: ks.#Kustomization & {
|
||||
commonLabels: "holos.run/component.name": BuildPlan.metadata.name
|
||||
commonLabels: CommonLabels
|
||||
}
|
||||
}
|
||||
|
||||
// Add the argocd.argoproj.io/instance label to resources, but not to the
|
||||
// argocd Application config.
|
||||
_Transformer: _TransformerArgo & {
|
||||
kustomize: kustomization: commonLabels: {
|
||||
"argocd.argoproj.io/instance": Name
|
||||
}
|
||||
}
|
||||
|
||||
_Artifacts: {
|
||||
component: {
|
||||
_path: "clusters/\(Cluster)/components/\(Name)"
|
||||
artifact: "\(_path)/\(Name).gen.yaml"
|
||||
let HelmOutput = "helm.gen.yaml"
|
||||
let ResourcesOutput = "resources.gen.yaml"
|
||||
let IntermediateOutput = "combined.gen.yaml"
|
||||
generators: [
|
||||
{
|
||||
kind: "Helm"
|
||||
output: HelmOutput
|
||||
helm: core.#Helm & {
|
||||
chart: Chart
|
||||
values: Values
|
||||
enableHooks: EnableHooks
|
||||
if Namespace != _|_ {
|
||||
namespace: Namespace
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
kind: "Resources"
|
||||
output: ResourcesOutput
|
||||
resources: Resources
|
||||
},
|
||||
]
|
||||
transformers: [
|
||||
core.#Transformer & {
|
||||
kind: "Kustomize"
|
||||
inputs: [HelmOutput, ResourcesOutput]
|
||||
output: IntermediateOutput
|
||||
kustomize: kustomization: KustomizeConfig.Kustomization & {
|
||||
resources: inputs
|
||||
}
|
||||
},
|
||||
_Transformer & {
|
||||
inputs: [IntermediateOutput]
|
||||
output: artifact
|
||||
kustomize: kustomization: resources: inputs
|
||||
if Namespace != _|_ {
|
||||
kustomize: kustomization: namespace: Namespace
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
// Mix in the ArgoCD Application gitops artifact.
|
||||
(#ArgoArtifact & {
|
||||
name: Name
|
||||
cluster: Cluster
|
||||
config: ArgoConfig
|
||||
transformer: _TransformerArgo
|
||||
component: _Artifacts.component._path
|
||||
}).Artifact
|
||||
}
|
||||
|
||||
BuildPlan: {
|
||||
metadata: name: Name
|
||||
spec: component: Component
|
||||
spec: artifacts: [for x in _Artifacts {x}]
|
||||
}
|
||||
}
|
||||
|
||||
#ArgoArtifact: {
|
||||
name: string
|
||||
let Name = name
|
||||
cluster: string
|
||||
let Cluster = cluster
|
||||
config: #ArgoConfig
|
||||
let ArgoConfig = config
|
||||
transformer: core.#Transformer
|
||||
component: string
|
||||
|
||||
Artifact: {}
|
||||
if ArgoConfig.Enabled {
|
||||
Artifact: {
|
||||
argocd: core.#Artifact & {
|
||||
artifact: "clusters/\(Cluster)/gitops/\(Name).gen.yaml"
|
||||
generators: [{
|
||||
kind: "Resources"
|
||||
output: "application.gen.yaml"
|
||||
resources: Application: (Name): app.#Application & {
|
||||
metadata: name: Name
|
||||
metadata: namespace: string | *"argocd"
|
||||
spec: {
|
||||
destination: server: string | *"https://kubernetes.default.svc"
|
||||
project: ArgoConfig.AppProject
|
||||
source: {
|
||||
repoURL: ArgoConfig.RepoURL
|
||||
path: "\(ArgoConfig.Root)/\(component)"
|
||||
targetRevision: ArgoConfig.TargetRevision
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
transformers: [transformer & {
|
||||
inputs: [for x in generators {x.output}]
|
||||
output: artifact
|
||||
kustomize: kustomization: resources: inputs
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package v1alpha4
|
||||
|
||||
#Component: tags?: [_]: !~"^holos_"
|
||||
|
||||
#Transformer: {
|
||||
kind: _
|
||||
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
package platforms
|
||||
|
||||
// TODO: Remove env GODEBUG=gotypesalias=0 when cue 0.11 is released and used.
|
||||
// See: https://github.com/cue-lang/cue/issues/3539
|
||||
|
||||
//go:generate rm -rf cue.mod/gen/github.com/holos-run/holos/api/v1alpha1
|
||||
//go:generate cue get go github.com/holos-run/holos/api/v1alpha1/...
|
||||
//go:generate env GODEBUG=gotypesalias=0 cue get go github.com/holos-run/holos/api/v1alpha1/...
|
||||
|
||||
//go generate rm -rf cue.mod/gen/github.com/holos-run/holos/api/core
|
||||
//go:generate cue get go github.com/holos-run/holos/api/core/...
|
||||
//go:generate env GODEBUG=gotypesalias=0 cue get go github.com/holos-run/holos/api/core/...
|
||||
|
||||
//go generate rm -rf cue.mod/gen/github.com/holos-run/holos/api/meta
|
||||
//go:generate cue get go github.com/holos-run/holos/api/meta/...
|
||||
//go:generate env GODEBUG=gotypesalias=0 cue get go github.com/holos-run/holos/api/meta/...
|
||||
|
||||
//go generate rm -rf cue.mod/gen/github.com/holos-run/holos/api/author
|
||||
//go:generate cue get go github.com/holos-run/holos/api/author/...
|
||||
//go:generate env GODEBUG=gotypesalias=0 cue get go github.com/holos-run/holos/api/author/...
|
||||
|
||||
//go generate rm -rf cue.mod/gen/github.com/holos-run/holos/service/gen/holos/object
|
||||
//go:generate cue import ../../../service/holos/object/v1alpha1/object.proto -o cue.mod/gen/github.com/holos-run/holos/service/gen/holos/object/v1alpha1/object.proto_gen.cue -I ../../../proto -f
|
||||
|
||||
9
internal/generate/platforms/v1alpha4/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
vendor/
|
||||
node_modules/
|
||||
8
internal/generate/platforms/v1alpha4/fleets.cue
Normal file
@@ -0,0 +1,8 @@
|
||||
package holos
|
||||
|
||||
import api "github.com/holos-run/holos/api/author/v1alpha4"
|
||||
|
||||
// Manage a workload cluster named local for use with the guides.
|
||||
_Fleets: api.#StandardFleets & {
|
||||
workload: clusters: local: _
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,10 @@
|
||||
package holos
|
||||
|
||||
import api "github.com/holos-run/holos/api/author/v1alpha4"
|
||||
|
||||
_Platform: api.#Platform & {
|
||||
Name: "default"
|
||||
}
|
||||
|
||||
// Render a Platform resource for holos to process
|
||||
_Platform.Resource
|
||||
49
internal/generate/platforms/v1alpha4/resources.cue
Normal file
@@ -0,0 +1,49 @@
|
||||
package holos
|
||||
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
|
||||
ci "cert-manager.io/clusterissuer/v1"
|
||||
rgv1 "gateway.networking.k8s.io/referencegrant/v1beta1"
|
||||
certv1 "cert-manager.io/certificate/v1"
|
||||
hrv1 "gateway.networking.k8s.io/httproute/v1"
|
||||
gwv1 "gateway.networking.k8s.io/gateway/v1"
|
||||
ap "argoproj.io/appproject/v1alpha1"
|
||||
es "external-secrets.io/externalsecret/v1beta1"
|
||||
ss "external-secrets.io/secretstore/v1beta1"
|
||||
)
|
||||
|
||||
#Resources: {
|
||||
[Kind=string]: [InternalLabel=string]: {
|
||||
kind: Kind
|
||||
metadata: name: string | *InternalLabel
|
||||
}
|
||||
|
||||
AppProject?: [_]: ap.#AppProject
|
||||
Certificate?: [_]: certv1.#Certificate
|
||||
ClusterIssuer?: [_]: ci.#ClusterIssuer
|
||||
ClusterRole?: [_]: rbacv1.#ClusterRole
|
||||
ClusterRoleBinding?: [_]: rbacv1.#ClusterRoleBinding
|
||||
ConfigMap?: [_]: corev1.#ConfigMap
|
||||
CronJob?: [_]: batchv1.#CronJob
|
||||
Deployment?: [_]: appsv1.#Deployment
|
||||
ExternalSecret?: [_]: es.#ExternalSecret
|
||||
HTTPRoute?: [_]: hrv1.#HTTPRoute
|
||||
Job?: [_]: batchv1.#Job
|
||||
Namespace?: [_]: corev1.#Namespace
|
||||
ReferenceGrant?: [_]: rgv1.#ReferenceGrant
|
||||
Role?: [_]: rbacv1.#Role
|
||||
RoleBinding?: [_]: rbacv1.#RoleBinding
|
||||
Secret?: [_]: corev1.#Secret
|
||||
SecretStore?: [_]: ss.#SecretStore
|
||||
Service?: [_]: corev1.#Service
|
||||
ServiceAccount?: [_]: corev1.#ServiceAccount
|
||||
StatefulSet?: [_]: appsv1.#StatefulSet
|
||||
|
||||
Gateway?: [_]: gwv1.#Gateway & {
|
||||
spec: gatewayClassName: string | *"istio"
|
||||
}
|
||||
}
|
||||
54
internal/generate/platforms/v1alpha4/schema.cue
Normal file
@@ -0,0 +1,54 @@
|
||||
package holos
|
||||
|
||||
import api "github.com/holos-run/holos/api/author/v1alpha4"
|
||||
|
||||
// Define the default organization name.
|
||||
_Organization: api.#OrganizationStrict & {
|
||||
DisplayName: string | *"Bank of Holos"
|
||||
Name: string | *"bank-of-holos"
|
||||
Domain: string | *"holos.localhost"
|
||||
}
|
||||
|
||||
// Projects represents a way to organize components into projects with owners.
|
||||
// https://holos.run/docs/api/author/v1alpha4/#Projects
|
||||
_Projects: api.#Projects
|
||||
|
||||
// ArgoConfig represents the configuration of ArgoCD Application resources for
|
||||
// each component.
|
||||
// https://holos.run/docs/api/author/v1alpha4/#ArgoConfig
|
||||
_ArgoConfig: api.#ArgoConfig
|
||||
|
||||
#ComponentConfig: api.#ComponentConfig & {
|
||||
Name: _Tags.name
|
||||
Component: _Tags.component
|
||||
Cluster: _Tags.cluster
|
||||
ArgoConfig: _ArgoConfig & {
|
||||
if _Tags.project != "no-project" {
|
||||
AppProject: _Tags.project
|
||||
}
|
||||
}
|
||||
Resources: #Resources
|
||||
|
||||
// Mix in project labels if the project is defined by the platform.
|
||||
if _Tags.project != "no-project" {
|
||||
CommonLabels: _Projects[_Tags.project].CommonLabels
|
||||
}
|
||||
}
|
||||
|
||||
// https://holos.run/docs/api/author/v1alpha4/#Kubernetes
|
||||
#Kubernetes: close({
|
||||
#ComponentConfig
|
||||
api.#Kubernetes
|
||||
})
|
||||
|
||||
// https://holos.run/docs/api/author/v1alpha4/#Kustomize
|
||||
#Kustomize: close({
|
||||
#ComponentConfig
|
||||
api.#Kustomize
|
||||
})
|
||||
|
||||
// https://holos.run/docs/api/author/v1alpha4/#Helm
|
||||
#Helm: close({
|
||||
#ComponentConfig
|
||||
api.#Helm
|
||||
})
|
||||
24
internal/generate/platforms/v1alpha4/tags.cue
Normal file
@@ -0,0 +1,24 @@
|
||||
package holos
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
dto "github.com/holos-run/holos/service/gen/holos/object/v1alpha1:object"
|
||||
)
|
||||
|
||||
// Note, tags should have a reasonable default value to easily use cue eval and
|
||||
// cue export without needing to make a bunch of decisions about tag values.
|
||||
|
||||
// _PlatformConfig represents all of the data passed from holos to cue, used to
|
||||
// carry the platform and project models.
|
||||
_PlatformConfig: dto.#PlatformConfig & json.Unmarshal(_PlatformConfigJSON)
|
||||
_PlatformConfigJSON: string | *"{}" @tag(holos_platform_config, type=string)
|
||||
|
||||
_Tags: {
|
||||
// Reserved tags
|
||||
name: string | *"no-name" @tag(holos_name, type=string)
|
||||
cluster: string | *"no-cluster" @tag(holos_cluster, type=string)
|
||||
component: string | *"no-component" @tag(holos_component, type=string)
|
||||
// User defined tags
|
||||
environment: string | *"no-environment" @tag(environment, type=string)
|
||||
project: string | *"no-project" @tag(project, type=string)
|
||||
}
|
||||
@@ -89,7 +89,7 @@ func New(opts ...Option) *Config {
|
||||
ServerConfig: &ServerConfig{},
|
||||
}
|
||||
writeFlagSet.StringVar(&cfg.writeTo, "write-to", cfg.writeTo, "write to directory")
|
||||
clusterFlagSet.StringVar(&cfg.clusterName, "cluster-name", cfg.clusterName, "cluster name")
|
||||
clusterFlagSet.StringVar(&cfg.clusterName, "cluster-name", cfg.clusterName, "cluster name (deprecated: use --inject holos_cluster=example instead)")
|
||||
kvDefault := ""
|
||||
if home := homedir.HomeDir(); home != "" {
|
||||
kvDefault = filepath.Join(home, ".holos", "kubeconfig.provisioner")
|
||||
|
||||
@@ -2,6 +2,7 @@ package holos
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -25,3 +26,23 @@ func (i *StringSlice) Set(value string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type feature string
|
||||
|
||||
const BuildFeature = feature("BUILD")
|
||||
const ServerFeature = feature("SERVER")
|
||||
const PreflightFeature = feature("PREFLIGHT")
|
||||
const GenerateComponentFeature = feature("GENERATE_COMPONENT")
|
||||
const SecretsFeature = feature("SECRETS")
|
||||
|
||||
// Flagger is the interface to check if an experimental feature is enabled.
|
||||
type Flagger interface {
|
||||
Flag(name feature) bool
|
||||
}
|
||||
|
||||
type EnvFlagger struct{}
|
||||
|
||||
func (e *EnvFlagger) Flag(name feature) bool {
|
||||
envVar := "HOLOS_FEATURE_" + strings.ToUpper(string(name))
|
||||
return os.Getenv(envVar) != ""
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ func (c *Config) handler(w io.Writer) (h slog.Handler) {
|
||||
|
||||
// NewLogger returns a *slog.Logs configured by c *Config which writes to w
|
||||
func (c *Config) NewLogger(w io.Writer) *slog.Logger {
|
||||
return slog.New(c.handler(w)).With("version", version.Version)
|
||||
return slog.New(c.handler(w)).With("version", version.Version, "pid", os.Getpid())
|
||||
}
|
||||
|
||||
// NewConfig returns a new logging Config struct
|
||||
|
||||
@@ -26,11 +26,12 @@ import (
|
||||
var helpLong string
|
||||
|
||||
// New builds a root cobra command with flags linked to the Config field.
|
||||
func New(cfg *holos.Config) *cobra.Command {
|
||||
func New(cfg *holos.Config, feature holos.Flagger) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "server",
|
||||
Short: "run the holos server",
|
||||
Long: helpLong,
|
||||
Use: "server",
|
||||
Short: "run the holos server",
|
||||
Hidden: !feature.Flag(holos.ServerFeature),
|
||||
Long: helpLong,
|
||||
// We handle our own errors.
|
||||
SilenceUsage: true,
|
||||
SilenceErrors: true,
|
||||
|
||||
@@ -1 +1 @@
|
||||
96
|
||||
97
|
||||
|
||||
@@ -1 +1 @@
|
||||
0
|
||||
3
|
||||
|
||||