Compare commits

..

44 Commits

Author SHA1 Message Date
Jeff McCune
c6a13059f3 v0.97.1 2024-10-28 11:12:55 -07:00
Jeff McCune
ff3eb896f3 webite: put ois logo back
Until we get a better logo.
2024-10-28 10:46:59 -07:00
Jeff McCune
70f70ae6b9 website: fix launch announcement 2024-10-28 10:45:43 -07:00
Jeff McCune
2580ec1c5f website: fix order of api references
The api references are in reverse order and don't have good descriptions
in the index listings.  This patch adds front matter to each generated
document to order them correctly and add a nice description.
2024-10-27 20:43:54 -07:00
Jeff McCune
4fa99e0faa website: add helm prometheus blackbox httpbin guide
The purpose of this guide is to demonstrate how holos offers value
above and beyond helm and kustomize alone.
2024-10-27 19:48:42 -07:00
Jeff McCune
7341d25483 website: add at proto did for bsky 2024-10-25 14:26:42 -07:00
Jeff McCune
3074b3a241 website: add discord invite link 2024-10-24 10:27:37 -07:00
Jeff McCune
9a5e7869c6 v1alpha4: omit the platform model if empty
The platform model distracts from getting started:

  cue export --out yaml ./platform

  kind: Platform
  apiVersion: v1alpha4
  metadata:
    name: default
  spec:
    components:
      - name: prometheus
        component: projects/platform/components/prometheus
        cluster: local
        model: {}

With this patch it's absent by default.
2024-10-23 13:46:58 -07:00
Jeff McCune
1064ceba31 v1alpha4: manage a single workload cluster named local by default
Manage a single cluster by default after generating the platform.
Assume it's a local cluster for use with the guides.
2024-10-23 13:42:46 -07:00
Jeff McCune
4bccaa3710 v1alpha4: _Platform not #Platform for component registration
`_Platform` is a hidden field representing the platform components,
`#Platform` defines the schema of the hidden field.
2024-10-23 13:33:28 -07:00
Jeff McCune
95efae1343 docs: update rendered manifest figure in technical overview
It's too wide with KubeAPI, take it out.
2024-10-20 10:11:57 -07:00
Jeff McCune
ba88125877 v1alpha4: enable config map generator for Kustomize
Without this patch it's difficult to mix in a plain file as a config
map.  This is necessary for the use case of using a Job to generate a
secret in-cluster.  We want a plain shell script to be carried through
and transformed into the job.

We already have the KustomizeConfig fields to support this, they just
weren't wired up to the #Kustomization component kind.

I didn't check if it's wired up to Helm and Kustomize for expedience.
They may be missing there as well.
2024-10-19 10:57:37 -07:00
Jeff McCune
d12c1a0c11 Merge pull request #284 from holos-run/gl/deploy-a-service-v4alpha-update
Update deploy-a-service guide for Author API v1alpha4
2024-10-18 20:35:51 -07:00
Jeff McCune
d56d3400a7 docs: replace tabs in deploy-a-service guide 2024-10-18 20:33:54 -07:00
Gary Larizza
4f0f9dced5 Update deploy-a-service guide for Author API v1alpha4
PROBLEM:

Version v1alpha4 of the Author API has been updated with backwards
incompatible changes, and the deploy-a-service guide uses code from
version v1alpha3.

SOLUTION:

Update any code, links, and data that is out of date, and then run
through the guide to make sure it works locally.

OUTCOME:

The instructions in the deploy-a-service guide will work successfully
with version v1alpha4 of the Author API.
2024-10-18 15:21:56 -07:00
Jeff McCune
6bf0cb8d8e v1alpha4: v0.97.0 2024-10-17 07:50:49 -07:00
Jeff McCune
766c8912b7 Merge pull request #281 from holos-run/jeff/280-authorapi-v1alpha4
v1alpha4 Author API
2024-10-17 07:17:14 -07:00
Jeff McCune
be1dee5f1c v1alpha4: update technical overview guide (#280)
Update the guide and the bank of holos repository to use v1alpha4
instead of v1alpha3.
2024-10-17 07:13:51 -07:00
Jeff McCune
6ad56525ac v1alpha4: refactor --tag to --inject and remove environment (#276)
Cue uses --inject, -t as the flags to set variables for fields tagged
using @tag(var,type=string).

We used --tag, which is different and requires a mental mapping.  Let's
use the same flag and also pass it multiple times like they require so
we can copy and paste the command line output from the debug logs into a
cue export command to see what's going on.

This patch deprecates the --cluster-name flag, use --inject
holos_cluster=mycluster instead.

This patch also removes the environment field from the Component core
API, leaving this to the user namespace to define via tags.  We don't
want to be too opinionated on how users manage their platform, baking
environment into the schema is a slippery slope toward those kinds of
opinions.

Closes: #276
2024-10-16 22:07:47 -07:00
Jeff McCune
791ec5ee71 v1alpha4: refactor core.Component Tags to map[string]string (#280)
Previously it was a []string slice that must be formatted as key=value.
This is more difficult to work with than a map[string]string.
2024-10-16 20:10:14 -07:00
Jeff McCune
638ac7473c fixup 2024-10-16 20:05:05 -07:00
Jeff McCune
ee24b5ce13 fixup 2024-10-16 20:04:18 -07:00
Jeff McCune
fa2fdbe4e8 fixup 2024-10-16 20:00:53 -07:00
Jeff McCune
63e1df1d4c v1alpha4: add common labels to projects schema (#280)
Now that we have CommonLabels as part of the ComponentConfig for all
components, it makes sense to also mix in CommonLabels for a Project.

Common labes are key aspect of the Technical Overview document.
2024-10-16 17:40:40 -07:00
Jeff McCune
2ad0c2a93e render: refactor tm to typeMeta
Gary and I noted tm wasn't clear when I was showing him code.
2024-10-16 17:11:09 -07:00
Jeff McCune
3a6a04f318 v1alpha4: add projects to author api (#280)
Projects are a key element of the Technical Overview guide, so we need
the schema for them in the Author API.
2024-10-16 12:29:35 -07:00
Jeff McCune
8afeece890 v1alpha4: embed ComponentConfig in Helm, Kustomize, Kubernetes (#280)
For the Author API, it would be nice to define a schema for the fields
common to all component kinds.  Users could then configure all kinds by
unifying the schema into their own platform tree.

This makes a clear use case to extract the common fields back into an
embedded struct like we did in v1alpha3.  I removed the embedded struct
in v1alpha4 because it wasn't clear why it should be separate, but now
the use case is clear, to configure all component kinds.
2024-10-16 12:16:48 -07:00
Jeff McCune
bc9c43a0b9 fix argocd application project 2024-10-15 20:52:56 -07:00
Jeff McCune
5a98c77e4c add argocd.argoproj.io/instance label to resources
But not the ArgoCD Application resource.
2024-10-15 20:41:39 -07:00
Jeff McCune
b3f7de39ec v1alpha4: feedback in case of chart cache dead lock (#280)
Without this patch holos render platform may hang until the overall
context timeout is reached.  This is a problem because the user has no
idea why it's hung.

This patch adds a warning at the 5 second and another at the 10 second
mark indicating the lock may be deadlocked.  The user can then remove
the directory.
2024-10-15 16:43:36 -07:00
Jeff McCune
ca4ecf1b28 v1alpha4: KustomizeConfig Resources and Files (#280)
The Kustomize build plan kind needs to support both copying files from
the component directory and pulling resources from https URL's.  Without
this patch this support is missing from the Author API

With this patch the Kustomize build plan kind has a KustomizeConfig
field with two structs, Files and Resources.  The kustomization
resources list is built up from both of these.

Two transformers are used so we don't affect the GitOps transfomer which
really only needs CommonLabels.

I decided to keep this field exclusive to the Kustomize kind, but it
could replace the Kustomization field of the other kinds as well.
2024-10-15 16:11:05 -07:00
Jeff McCune
9ce28660ce v1alpha4: intermediate kustomization (#280)
Without this patch the user facing API doesn't have a way to kustomize
the output of all the build plan kinds.  This patch ensures the
Kustomization field is present on all of Helm, Kustomize, and
Kubernetes.

This field is inteded for patches and transforms.  The second
kustomization in the transformer sequence is intended for common labels
and annotations, managed by a corresponding field instead of a full on
Kustomization resource.
2024-10-15 15:02:15 -07:00
Jeff McCune
728e8ba06e v1alpha4: default helm chart release to chart name (#280) 2024-10-15 14:47:42 -07:00
Jeff McCune
e4b07dad6d v1alpha4: helm enable hooks default false (#280)
Fix:

could not run: could not marshal json projects/platform/components/cert-manager: cue: marshal error: spec.artifacts.0.generators.0.helm.enableHooks: cannot convert incomplete value "bool" to JSON at internal/builder/builder.go:63
spec.artifacts.0.generators.0.helm.enableHooks: cannot convert incomplete value "bool" to JSON:
    /Users/jeff/Holos/bank-of-holos/cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha4/types_go_gen.cue:235:16
could not run: could not render component: exit status 1 at builder/v1alpha4/builder.go:94
2024-10-15 14:43:05 -07:00
Jeff McCune
b7c0bba2b9 v1alpha4: add resources to schema.cue (#280)
Without this patch kustomize cannot execute because resources from CUE
are incomplete.
2024-10-15 14:41:49 -07:00
Jeff McCune
847ab8441c v1alpha4: add default chart name (#280)
Defaults to the build plan name.
2024-10-15 14:40:36 -07:00
Jeff McCune
5f72af3d53 v1alpha4: link helm to the chart struct (#280) 2024-10-15 14:32:16 -07:00
Jeff McCune
33eed43fd1 v1alpha4: surface kustomize stderr output (#280)
Without this patch kustomize errors aren't surfaced when executing holos
render platform.

This patch gives a fighting chance to the user to figure out what's
going on.  The stderr is copied, logged, and surfaced up to the parent
holos render platform command.
2024-10-15 14:32:11 -07:00
Jeff McCune
d2fbbdd1cc logger: log the process pid (#280)
Useful when troubleshooting concurrent processes.
2024-10-15 14:31:42 -07:00
Jeff McCune
e42da118dc v1alpha4: add Helm and Kustomize to author api (#280)
Previously the #Helm and #Kustomize build plan helpers were not defined
in the v1alpha4 Author API.  We need this definition to update the
Quickstart guide for v1alpha4 from v1alpha3.

This patch defines the #Helm and #Kustomize helpers in the Author API
similar to how #Kubernetes is defined.
2024-10-15 10:32:16 -07:00
Jeff McCune
7d36567dcf v1alpha4: define Kubernetes in author api (#280)
Previously #Kubernetes was defined in the platform code.  This is a
problem because every platform engineer would need to copy and paste
this code.

This patch moves the #Kubernetes helper into the cue.mod directory so it
can be imported and used ergonomically.
2024-10-14 20:45:04 -07:00
Jeff McCune
bee698bebe v1alpha4: add platform to the author api (#280)
This patch gets the Author API rendering the namespaces component in the
Bank of Holos guide.  It's not the final form of the API yet, we still
need to decide how best to expose the Kubernetes, Helm, and Kustomize
definitions.

I'm thinking we abstract away the transformers and generators within the
Author API Kubernetes definition.
2024-10-14 17:19:49 -07:00
Jeff McCune
58df0626d0 v1alpha4: plumb --write-to flag from platform (#280)
Without this patch the --write-to flag can't be controlled from the
PlatformSpec in the CoreAPI.  We need to surface this for the ArgoConfig
struct in the AuthorAPI.

That is to say, in v1alpha3 the --write-to flag was previously assumed
to be deploy/ in ArgoConfig using the DeployFiles functionality.  We no
longer have DeployFiles in Core API v1alpha4, all artifacts are instead
written relative to the --write-to flag.  Still, we need to expose this
flag in the PlatformSpec so users can use something other than the
deploy directory.
2024-10-14 15:16:36 -07:00
Jeff McCune
c817a24704 v1alpha4: improve core api documentation 2024-10-10 20:37:38 -07:00
59 changed files with 7593 additions and 679 deletions

View File

@@ -7,34 +7,52 @@
"words": [
"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",
"cookiesecret",
"coredns",
"corev",
@@ -42,16 +60,22 @@
"crds",
"creds",
"crossplane",
"crunchydata",
"cuecontext",
"cuelang",
"customresourcedefinition",
"daemonset",
"deploymentruntimeconfig",
"destinationrule",
"destinationrules",
"devicecode",
"dnsmasq",
"dscacheutil",
"ecrauthorizationtokens",
"edns",
"endpointslices",
"entgo",
"envoyfilter",
"envoyfilters",
"errgroup",
"etcdsnapshotfiles",
@@ -59,51 +83,78 @@
"externalsecrets",
"fctr",
"fieldmaskpb",
"fieldspec",
"flushcache",
"fullname",
"gatewayclass",
"gatewayclasses",
"gcraccesstokens",
"gendoc",
"generationbehavior",
"generatorargs",
"generatoroptions",
"ggnpl",
"ghaction",
"githubaccesstokens",
"gitops",
"godoc",
"golangci",
"gomarkdoc",
"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",
"mindmap",
@@ -112,41 +163,79 @@
"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",
"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 +244,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 +292,18 @@
"userdata",
"userservice",
"validatingwebhookconfiguration",
"validatingwebhookconfigurations",
"vaultdynamicsecrets",
"virtualservice",
"virtualservices",
"volumeattachments",
"wasmplugin",
"wasmplugins",
"workloadentries",
"workloadentry",
"workloadgroup",
"workloadgroups",
"yournamespace",
"zerolog",
"zitadel",
"ztunnel"

View File

@@ -0,0 +1,4 @@
---
description: Simplified abstraction to generate core v1alpha3 components.
sidebar_position: 997
---

View 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

View File

@@ -0,0 +1,4 @@
---
description: Simplified abstraction to generate core v1alpha4 build plans.
sidebar_position: 996
---

View File

@@ -0,0 +1,4 @@
---
description: Core v1alpha4 schema for advanced use cases.
sidebar_position: 998
---

View File

@@ -0,0 +1,4 @@
---
description: Core v1alpha3 schema for advanced use cases.
sidebar_position: 997
---

View File

@@ -0,0 +1,4 @@
---
description: Core v1alpha2 schema for advanced use cases.
sidebar_position: 996
---

View File

@@ -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\""`
}

View File

@@ -1,3 +1,7 @@
---
description: Simplified abstraction to generate core v1alpha3 components.
sidebar_position: 997
---
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
# v1alpha3

View 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>)

View File

@@ -1,3 +1,7 @@
---
description: Core v1alpha4 schema for advanced use cases.
sidebar_position: 998
---
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
# v1alpha2

View File

@@ -1,3 +1,7 @@
---
description: Core v1alpha3 schema for advanced use cases.
sidebar_position: 997
---
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
# v1alpha3

View File

@@ -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}

View File

@@ -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
@@ -356,10 +356,17 @@ import ks "sigs.k8s.io/kustomize/api/types"
let Chart = {
// highlight-next-line
Name: "podinfo"
Version: "6.6.2"
// highlight-next-line
Namespace: #Migration.Namespace
Chart: {
version: "6.6.2"
repository: {
name: "podinfo"
url: "https://stefanprodan.github.io/podinfo"
}
}
// Necessary to ensure the resources go to the correct namespace.
// highlight-next-line
EnableKustomizePostProcessor: true
@@ -368,9 +375,6 @@ let Chart = {
namespace: Namespace
}
Repo: name: "podinfo"
Repo: url: "https://stefanprodan.github.io/podinfo"
// Allow the platform team to route traffic into our namespace.
// highlight-next-line
Resources: ReferenceGrant: grant: #ReferenceGrant & {
@@ -396,19 +400,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.
**Lines 14-15**: Unfortunately, the Helm chart doesn't set the
**Lines 20-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 27**: The migration team grants the platform team permission to route
traffic into the `migration` Namespace using a [ReferenceGrant].
:::note
@@ -780,7 +784,7 @@ the bank to register with. The `#HTTPRoutes` struct is similar to the
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">
@@ -813,7 +817,7 @@ import v1 "gateway.networking.k8s.io/httproute/v1"
// For the guides, we simplify this down to a flat namespace.
// highlight-next-line
[Name=string]: v1.#HTTPRoute & {
let HOST = Name + "." + #Platform.Domain
let HOST = Name + "." + #Organization.Domain
// highlight-next-line
_backendRefs: [NAME=string]: {
@@ -925,37 +929,38 @@ git diff
<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
index 06f7c91..349e070 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
@@ -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>
@@ -1428,10 +1433,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

View File

@@ -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

4793
doc/md/guides/helm.mdx Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

View File

@@ -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

View File

@@ -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

View File

@@ -186,32 +186,32 @@ holos render platform ./platform
</TabItem>
<TabItem value="output" label="Output">
```txt
rendered bank-accounts-db for cluster workload in 142.661334ms
rendered bank-ledger-db for cluster workload in 144.041417ms
rendered bank-userservice for cluster workload in 157.828709ms
rendered bank-ledger-writer for cluster workload in 161.138292ms
rendered bank-backend-config for cluster workload in 168.923459ms
rendered bank-balance-reader for cluster workload in 171.877875ms
rendered bank-secrets for cluster workload in 207.958792ms
rendered gateway for cluster workload in 123.572583ms
rendered bank-contacts for cluster workload in 144.466291ms
rendered bank-transaction-history for cluster workload in 151.520041ms
rendered httproutes for cluster workload in 139.590834ms
rendered bank-frontend for cluster workload in 309.679834ms
rendered app-projects for cluster workload in 107.136083ms
rendered ztunnel for cluster workload in 160.679791ms
rendered cni for cluster workload in 238.937625ms
rendered cert-manager for cluster workload in 178.610834ms
rendered istiod for cluster workload in 340.953208ms
rendered argocd for cluster workload in 286.277ms
rendered local-ca for cluster workload in 98.720208ms
rendered external-secrets for cluster workload in 141.459708ms
rendered base for cluster workload in 454.356667ms
rendered namespaces for cluster workload in 115.401709ms
rendered gateway-api for cluster workload in 203.5625ms
rendered external-secrets-crds for cluster workload in 525.180209ms
rendered crds for cluster workload in 888.406167ms
rendered platform in 1.182857542s
rendered app-projects for cluster workload in 206.109166ms
rendered httproutes for cluster workload in 222.3885ms
rendered istio-cni for cluster workload in 236.061167ms
rendered istio-gateway for cluster workload in 238.973167ms
rendered istio-ztunnel for cluster workload in 240.000042ms
rendered istiod for cluster workload in 275.385709ms
rendered bank-accounts-db for cluster workload in 215.252708ms
rendered bank-backend-config for cluster workload in 245.383333ms
rendered bank-secrets for cluster workload in 273.477458ms
rendered bank-userservice for cluster workload in 234.866375ms
rendered istio-base for cluster workload in 541.965042ms
rendered argocd for cluster workload in 352.4625ms
rendered bank-frontend for cluster workload in 374.208084ms
rendered bank-ledger-db for cluster workload in 224.120125ms
rendered bank-ledger-writer for cluster workload in 237.136042ms
rendered bank-balance-reader for cluster workload in 233.804083ms
rendered bank-transaction-history for cluster workload in 236.114542ms
rendered bank-contacts for cluster workload in 222.469875ms
rendered argocd-crds for cluster workload in 812.078042ms
rendered gateway-api for cluster workload in 173.66425ms
rendered external-secrets for cluster workload in 231.326958ms
rendered local-ca for cluster workload in 183.12425ms
rendered namespaces for cluster workload in 173.256125ms
rendered cert-manager for cluster workload in 432.088959ms
rendered external-secrets-crds for cluster workload in 496.282459ms
rendered platform in 1.106735958s
```
</TabItem>
</Tabs>
@@ -234,31 +234,31 @@ Your branch is up to date with 'origin/main'.
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)
modified: deploy/clusters/workload/gitops/app-projects.application.gen.yaml
modified: deploy/clusters/workload/gitops/argocd-crds.application.gen.yaml
modified: deploy/clusters/workload/gitops/argocd.application.gen.yaml
modified: deploy/clusters/workload/gitops/bank-accounts-db.application.gen.yaml
modified: deploy/clusters/workload/gitops/bank-backend-config.application.gen.yaml
modified: deploy/clusters/workload/gitops/bank-balance-reader.application.gen.yaml
modified: deploy/clusters/workload/gitops/bank-contacts.application.gen.yaml
modified: deploy/clusters/workload/gitops/bank-frontend.application.gen.yaml
modified: deploy/clusters/workload/gitops/bank-ledger-db.application.gen.yaml
modified: deploy/clusters/workload/gitops/bank-ledger-writer.application.gen.yaml
modified: deploy/clusters/workload/gitops/bank-secrets.application.gen.yaml
modified: deploy/clusters/workload/gitops/bank-transaction-history.application.gen.yaml
modified: deploy/clusters/workload/gitops/bank-userservice.application.gen.yaml
modified: deploy/clusters/workload/gitops/cert-manager.application.gen.yaml
modified: deploy/clusters/workload/gitops/external-secrets-crds.application.gen.yaml
modified: deploy/clusters/workload/gitops/external-secrets.application.gen.yaml
modified: deploy/clusters/workload/gitops/gateway-api.application.gen.yaml
modified: deploy/clusters/workload/gitops/httproutes.application.gen.yaml
modified: deploy/clusters/workload/gitops/istio-base.application.gen.yaml
modified: deploy/clusters/workload/gitops/istio-cni.application.gen.yaml
modified: deploy/clusters/workload/gitops/istio-gateway.application.gen.yaml
modified: deploy/clusters/workload/gitops/istio-ztunnel.application.gen.yaml
modified: deploy/clusters/workload/gitops/istiod.application.gen.yaml
modified: deploy/clusters/workload/gitops/local-ca.application.gen.yaml
modified: deploy/clusters/workload/gitops/namespaces.application.gen.yaml
modified: deploy/clusters/workload/gitops/app-projects.gen.yaml
modified: deploy/clusters/workload/gitops/argocd-crds.gen.yaml
modified: deploy/clusters/workload/gitops/argocd.gen.yaml
modified: deploy/clusters/workload/gitops/bank-accounts-db.gen.yaml
modified: deploy/clusters/workload/gitops/bank-backend-config.gen.yaml
modified: deploy/clusters/workload/gitops/bank-balance-reader.gen.yaml
modified: deploy/clusters/workload/gitops/bank-contacts.gen.yaml
modified: deploy/clusters/workload/gitops/bank-frontend.gen.yaml
modified: deploy/clusters/workload/gitops/bank-ledger-db.gen.yaml
modified: deploy/clusters/workload/gitops/bank-ledger-writer.gen.yaml
modified: deploy/clusters/workload/gitops/bank-secrets.gen.yaml
modified: deploy/clusters/workload/gitops/bank-transaction-history.gen.yaml
modified: deploy/clusters/workload/gitops/bank-userservice.gen.yaml
modified: deploy/clusters/workload/gitops/cert-manager.gen.yaml
modified: deploy/clusters/workload/gitops/external-secrets-crds.gen.yaml
modified: deploy/clusters/workload/gitops/external-secrets.gen.yaml
modified: deploy/clusters/workload/gitops/gateway-api.gen.yaml
modified: deploy/clusters/workload/gitops/httproutes.gen.yaml
modified: deploy/clusters/workload/gitops/istio-base.gen.yaml
modified: deploy/clusters/workload/gitops/istio-cni.gen.yaml
modified: deploy/clusters/workload/gitops/istio-gateway.gen.yaml
modified: deploy/clusters/workload/gitops/istio-ztunnel.gen.yaml
modified: deploy/clusters/workload/gitops/istiod.gen.yaml
modified: deploy/clusters/workload/gitops/local-ca.gen.yaml
modified: deploy/clusters/workload/gitops/namespaces.gen.yaml
modified: projects/argocd-config.cue
no changes added to commit (use "git add" and/or "git commit -a")
@@ -272,19 +272,19 @@ the changed `spec.source.repoURL` field.
<Tabs groupId="665E5402-FB42-4975-B654-3922EE73EE07">
<TabItem value="command" label="Command">
```bash
git diff deploy/clusters/workload/gitops/bank-frontend.application.gen.yaml
git diff deploy/clusters/workload/gitops/bank-frontend.gen.yaml
```
</TabItem>
<TabItem value="output" label="Output">
```diff showLineNumbers
diff --git a/deploy/clusters/workload/gitops/bank-frontend.application.gen.yaml b/deploy/clusters/workload/gitops/bank-frontend.application.gen.yaml
index d8ede55..aed4338 100644
--- a/deploy/clusters/workload/gitops/bank-frontend.application.gen.yaml
+++ b/deploy/clusters/workload/gitops/bank-frontend.application.gen.yaml
@@ -9,5 +9,5 @@ spec:
project: bank-frontend
diff --git a/deploy/clusters/workload/gitops/bank-frontend.gen.yaml b/deploy/clusters/workload/gitops/bank-frontend.gen.yaml
index 3a3dec0..22e21bb 100644
--- a/deploy/clusters/workload/gitops/bank-frontend.gen.yaml
+++ b/deploy/clusters/workload/gitops/bank-frontend.gen.yaml
@@ -11,5 +11,5 @@ spec:
project: default
source:
path: ./deploy/clusters/workload/components/bank-frontend
path: deploy/clusters/workload/components/bank-frontend
- repoURL: https://github.com/holos-run/bank-of-holos
+ repoURL: https://github.com/jeffmccune/bank-of-holos
targetRevision: main
@@ -406,20 +406,20 @@ files for now, they behave the same as these two.
```cue showLineNumbers
package holos
// Manage the component on every cluster in the platform
// Manage the Component on every Cluster in the Platform
for Fleet in #Fleets {
for Cluster in Fleet.clusters {
// highlight-next-line
#Platform: Components: "\(Cluster.name)/argocd-crds": {
path: "projects/platform/components/argocd/crds"
cluster: Cluster.name
}
// highlight-next-line
#Platform: Components: "\(Cluster.name)/argocd": {
path: "projects/platform/components/argocd/argocd"
cluster: Cluster.name
}
}
for Cluster in Fleet.clusters {
#Platform: Components: "\(Cluster.name):argocd-crds": {
name: "argocd-crds"
component: "projects/platform/components/argocd/crds"
cluster: Cluster.name
}
#Platform: Components: "\(Cluster.name):argocd": {
name: "argocd"
component: "projects/platform/components/argocd/argocd"
cluster: Cluster.name
}
}
}
```
</TabItem>
@@ -429,18 +429,18 @@ package holos
// Manage the component on every cluster in the platform
for Fleet in #Fleets {
for Cluster in Fleet.clusters {
// highlight-next-line
#Platform: Components: "\(Cluster.name)/external-secrets-crds": {
path: "projects/platform/components/external-secrets-crds"
cluster: Cluster.name
}
// highlight-next-line
#Platform: Components: "\(Cluster.name)/external-secrets": {
path: "projects/platform/components/external-secrets"
cluster: Cluster.name
}
}
for Cluster in Fleet.clusters {
#Platform: Components: "\(Cluster.name):external-secrets-crds": {
name: "external-secrets-crds"
component: "projects/platform/components/external-secrets-crds"
cluster: Cluster.name
}
#Platform: Components: "\(Cluster.name):external-secrets": {
name: "external-secrets"
component: "projects/platform/components/external-secrets"
cluster: Cluster.name
}
}
}
```
</TabItem>
@@ -456,7 +456,7 @@ services we deploy onto the platform.
manifests for a cluster.
:::important
On lines 6 and 10 we see a Component being assigned to the Platform. We also
On lines 6 and 11 we see a Component being assigned to the Platform. We also
start to dive into the syntax of CUE, which we need to understand a little
before going further.
:::
@@ -475,75 +475,7 @@ members are called fields, which link their name, or label, to a value.
There are two important things to know about CUE to understand these two files.
First, the curly braces have been omitted which is item 5 on the list above.
Second, CUE is all about _unification_. These files could have been written
like this:
<Tabs groupId="59FFCCB6-A584-42ED-AC37-1C2BDCF5A523">
<TabItem value="argocd" label="platform/argocd.cue">
```cue showLineNumbers
package holos
// Manage the component on every cluster in the platform
for Fleet in #Fleets {
for Cluster in Fleet.clusters {
#Platform: {
// highlight-next-line
// Define #Platform.Components
// highlight-next-line
Components: {
"\(Cluster.name)/argocd-crds": {
path: "projects/platform/components/argocd/crds"
cluster: Cluster.name
}
}
// highlight-next-line
// Define #Platform.Components again!? Error?
// highlight-next-line
Components: {
"\(Cluster.name)/argocd": {
path: "projects/platform/components/argocd/argocd"
cluster: Cluster.name
}
}
}
}
}
```
</TabItem>
<TabItem value="external-secrets" label="platform/external-secrets.cue">
```cue showLineNumbers
package holos
// Manage the component on every cluster in the platform
for Fleet in #Fleets {
for Cluster in Fleet.clusters {
#Platform: {
// highlight-next-line
// Define #Platform.Components
// highlight-next-line
Components: {
"\(Cluster.name)/external-secrets-crds": {
path: "projects/platform/components/external-secrets-crds"
cluster: Cluster.name
}
}
// highlight-next-line
// Define #Platform.Components again!? Error?
// highlight-next-line
Components: {
"\(Cluster.name)/external-secrets": {
path: "projects/platform/components/external-secrets"
cluster: Cluster.name
}
}
}
}
}
```
</TabItem>
</Tabs>
Second, CUE is about _unification_.
:::important
Unlike most other languages, it is common to declare the same field in multiple
@@ -567,13 +499,20 @@ It looks like this.
```cue showLineNumbers
package holos
#Platform.Output
import api "github.com/holos-run/holos/api/author/v1alpha4"
#Platform: api.#Platform & {
Name: "guide"
}
// Render a Platform resource for holos to process
#Platform.Resource
```
</TabItem>
</Tabs>
This file provides the value of the `#Platform.Output` field, the platform spec,
to `holos`.
This file provides the value of the `#Platform.Resource` field, the platform
spec, to `holos`.
Let's take a look at that Output value:
@@ -586,24 +525,31 @@ cue export --out yaml ./platform
<TabItem value="output" label="Output">
```yaml showLineNumbers
kind: Platform
apiVersion: v1alpha3
apiVersion: v1alpha4
metadata:
name: guide
spec:
model: {}
components: # This is a trimmed list for readability.
- path: projects/bank-of-holos/security/components/bank-secrets
- name: bank-secrets
component: projects/bank-of-holos/security/components/bank-secrets
cluster: workload
- path: projects/bank-of-holos/frontend/components/bank-frontend
model: {}
- name: bank-frontend
component: projects/bank-of-holos/frontend/components/bank-frontend
cluster: workload
- path: projects/platform/components/argocd/crds
model: {}
- name: bank-backend-config
component: projects/bank-of-holos/backend/components/bank-backend-config
cluster: workload
- path: projects/platform/components/argocd/argocd
model: {}
- name: bank-accounts-db
component: projects/bank-of-holos/backend/components/bank-accounts-db
cluster: workload
- path: projects/platform/components/external-secrets-crds
cluster: workload
- path: projects/platform/components/external-secrets
model: {}
- name: bank-userservice
component: projects/bank-of-holos/backend/components/bank-userservice
cluster: workload
model: {}
```
</TabItem>
</Tabs>
@@ -624,7 +570,7 @@ defining characteristic of CUE that makes it a unique, powerful, and _safe_
configuration language.
:::
Holos takes this list of components and builds each one by executing:
Holos takes this list of components and builds each one by executing the following command.
```bash
holos render component --cluster-name="example" "path/to/the/component"
@@ -654,26 +600,24 @@ start working with the cert-manager component.
package holos
// Produce a helm chart build plan.
// highlight-next-line
(#Helm & Chart).BuildPlan
// highlight-next-line
let Chart = {
Name: "cert-manager"
// #CertManager is defined in projects/cert-manager.cue
// highlight-next-line
Version: #CertManager.Version
// highlight-next-line
Namespace: #CertManager.Namespace
Name: "cert-manager"
Namespace: #CertManager.Namespace
Repo: name: "jetstack"
Repo: url: "https://charts.jetstack.io"
Chart: {
version: #CertManager.Version
repository: {
name: "jetstack"
url: "https://charts.jetstack.io"
}
}
// CUE offers type checking and validation of Helm values.
// highlight-next-line
Values: installCRDs: true
// highlight-next-line
Values: startupapicheck: enabled: false
Values: {
installCRDs: true
startupapicheck: enabled: false
}
}
```
</TabItem>
@@ -683,14 +627,11 @@ package holos
// Platform wide configuration
#CertManager: {
// highlight-next-line
Version: "1.15.3"
// highlight-next-line
Namespace: "cert-manager"
Version: "1.15.3"
Namespace: "cert-manager"
}
// Register the namespace
// The underscore indicates the value is defined elsewhere in CUE.
#Namespaces: (#CertManager.Namespace): _
```
</TabItem>
@@ -721,52 +662,88 @@ cue export --out yaml ./projects/platform/components/cert-manager
<TabItem value="output" label="Output">
```yaml showLineNumbers
kind: BuildPlan
apiVersion: v1alpha3
apiVersion: v1alpha4
metadata:
name: cert-manager
spec:
components:
resources:
gitops/cert-manager:
kind: KubernetesObjects
apiVersion: v1alpha3
metadata:
name: gitops/cert-manager
namespace: cert-manager
deployFiles:
clusters/no-name/gitops/cert-manager.application.gen.yaml: |
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
component: no-component
artifacts:
- artifact: clusters/no-cluster/components/cert-manager/cert-manager.gen.yaml
generators:
- kind: Helm
output: helm.gen.yaml
helm:
chart:
name: cert-manager
namespace: argocd
spec:
destination:
server: https://kubernetes.default.svc
project: platform
source:
path: ./deploy/clusters/no-name/components/cert-manager
repoURL: https://github.com/jeffmccune/bank-of-holos
targetRevision: main
skip: false
helmChartList:
- kind: HelmChart
apiVersion: v1alpha3
chart:
name: cert-manager
version: 1.15.3
release: cert-manager
repository:
name: jetstack
url: https://charts.jetstack.io
valuesContent: |
installCRDs: true
startupapicheck:
enabled: false
enableHooks: false
metadata:
name: cert-manager
namespace: cert-manager
apiObjectMap: {}
skip: false
version: 1.15.3
release: cert-manager
repository:
name: jetstack
url: https://charts.jetstack.io
values:
installCRDs: true
startupapicheck:
enabled: false
enableHooks: false
namespace: cert-manager
- kind: Resources
output: resources.gen.yaml
resources: {}
transformers:
- kind: Kustomize
inputs:
- helm.gen.yaml
- resources.gen.yaml
output: combined.gen.yaml
kustomize:
kustomization:
resources:
- helm.gen.yaml
- resources.gen.yaml
kind: Kustomization
apiVersion: kustomize.config.k8s.io/v1beta1
- kind: Kustomize
inputs:
- combined.gen.yaml
output: clusters/no-cluster/components/cert-manager/cert-manager.gen.yaml
kustomize:
kustomization:
namespace: cert-manager
commonLabels:
holos.run/component.name: cert-manager
resources:
- combined.gen.yaml
- artifact: clusters/no-cluster/gitops/cert-manager.gen.yaml
generators:
- kind: Resources
output: application.gen.yaml
resources:
Application:
cert-manager:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: cert-manager
namespace: argocd
spec:
destination:
server: https://kubernetes.default.svc
project: default
source:
path: deploy/clusters/no-cluster/components/cert-manager
repoURL: https://github.com/jeffmccune/bank-of-holos
targetRevision: main
transformers:
- kind: Kustomize
inputs:
- application.gen.yaml
output: clusters/no-cluster/gitops/cert-manager.gen.yaml
kustomize:
kustomization:
commonLabels:
holos.run/component.name: cert-manager
resources:
- application.gen.yaml
```
</TabItem>
</Tabs>
@@ -785,8 +762,8 @@ The BuildPlan API is flexible enough to write any file into the `deploy/`
directory. Holos uses this flexibility to support both Flux and ArgoCD.
:::
When we run `cue export`, we get back a Core API BuildPlan. The BuildPlan is
produced by the `#Helm` definition on line 4 which is part of the Author API.
When we run `cue export`, we get back a [Core API] BuildPlan. The BuildPlan is
produced by the `#Helm` definition on line 4 which is part of the [Author API].
The Core API is the contract between CUE and `holos`. As such, it's not as
friendly as the Author API. The Author API is the contract component authors
and platform engineers use to configure and manage the platform. The Author API
@@ -822,8 +799,9 @@ on how to [Deploy a Service] which explains how to take one of your existing
Helm charts or Deployments and manage it with Holos.
[application]: https://argo-cd.readthedocs.io/en/stable/user-guide/application-specification/
[schema]: /docs/api/schema/v1alpha3/
[core]: /docs/api/core/v1alpha3/
[core]: /docs/api/core/v1alpha4/
[Core API]: /docs/api/core/
[Author API]: /docs/api/author/
[Deploy a Service]: /docs/guides/deploy-a-service/
[Manage a Project]: /docs/guides/manage-a-project/
[rendered manifests pattern]: https://akuity.io/blog/the-rendered-manifests-pattern/

View File

@@ -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

View File

@@ -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

View File

@@ -45,35 +45,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
@@ -139,7 +138,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 +151,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.
:::
@@ -170,111 +170,124 @@ 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">
```
cat deploy/clusters/overview/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">
```
cat deploy/clusters/overview/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">
```
cat deploy/clusters/overview/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>
@@ -302,16 +315,16 @@ projects/platform/components/namespaces/namespaces.cue
```cue showLineNumbers
package holos
let Objects = {
_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">
@@ -321,7 +334,7 @@ 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
@@ -347,9 +360,7 @@ import api "github.com/holos-run/holos/api/author/v1alpha3"
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: {
CommonLabels: {
"\(#Organization.Domain)/project.name": Name
"\(#Organization.Domain)/owner.name": Owner.Name
"\(#Organization.Domain)/owner.email": Owner.Email
@@ -361,32 +372,32 @@ for Project in #Projects {
// Register project namespaces with the namespaces component.
#Namespaces: {
for Namespace in Project.Namespaces {
(Namespace.Name): metadata: labels: Project._CommonLabels
(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.2.0/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.2.0/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.2.0/examples/tech-overview/platform)
directory.
:::important
@@ -416,13 +427,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
@@ -437,9 +452,11 @@ 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
#Platform: Components: "\(Cluster.name):podinfo": {
name: "podinfo"
component: "projects/experiment/components/podinfo"
cluster: Cluster.name
tags: project: "experiment"
}
}
```
@@ -449,6 +466,14 @@ across the platform.
</TabItem>
</Tabs>
The project tag associates the `#Platform` component with the correct entry in 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 +485,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>
@@ -486,12 +511,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 +530,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 +544,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 +572,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 +650,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.2.0/schema.cue#L35-L40)
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 +678,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

View File

@@ -1,94 +0,0 @@
---
slug: holos-platform-manager
title: Holos Platform Manager
authors: [jeff]
tags: [holos]
---
## Introducing Holos
Im 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 wasnt 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 wasnt 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 CUEs 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/

View File

@@ -0,0 +1,118 @@
---
slug: announcing-holos
title: Announcing Holos
authors: [jeff]
tags: [holos, launch]
---
Im 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 didnt work with each other. I was frustrated with how
complicated and difficult to configure these charts were. They werent 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 didnt stray too far from the
default values, but we quickly ran into operational challenges. Upgrading the
chart introduced breaking changes we couldnt 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 couldnt find an agreed upon implementation. We built
a Go command line tool to implement the pattern as a data pipeline. Id 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 didnt have a good way to handle the data values. We were still
templating YAML which didnt 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 youre looking to implement the rendered manifests
pattern or cant 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

View File

@@ -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',

View File

@@ -0,0 +1 @@
did:plc:7jly72mfd42u4fj4mfyovxqz

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 KiB

View 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

View 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

View 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

View 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

View File

@@ -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"

View File

@@ -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))

View File

@@ -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())
}
}
}

View File

@@ -36,7 +36,7 @@ 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.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

View File

@@ -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)
}

File diff suppressed because one or more lines are too long

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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
}]
}
}
}
}

View File

@@ -1,5 +1,7 @@
package v1alpha4
#Component: tags?: [_]: !~"^holos_"
#Transformer: {
kind: _

View File

@@ -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

View File

@@ -0,0 +1,9 @@
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
vendor/
node_modules/

View 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: _
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -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

View 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"
}
}

View 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
})

View 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)
}

View File

@@ -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")

View File

@@ -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

View File

@@ -1 +1 @@
96
97

View File

@@ -1 +1 @@
0
1