Skip to content

Commit

Permalink
Merge pull request #190 from holos-run/jeff/189-reference-docs
Browse files Browse the repository at this point in the history
(#189) v1alpha2 API for reference docs
  • Loading branch information
jeffmccune authored Jun 30, 2024
2 parents 6d2daac + a39807a commit 8bc7804
Show file tree
Hide file tree
Showing 35 changed files with 1,228 additions and 333 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ tidy: ## Tidy go module.
.PHONY: fmt
fmt: ## Format code.
cd docs/examples && cue fmt ./...
cd internal/generate/platforms && cue fmt ./...
go fmt ./...

.PHONY: vet
Expand Down Expand Up @@ -131,6 +132,7 @@ go-deps: ## tool versions pinned in tools.go
go install google.golang.org/protobuf/cmd/protoc-gen-go
go install connectrpc.com/connect/cmd/protoc-gen-connect-go
go install honnef.co/go/tools/cmd/staticcheck
go install golang.org/x/tools/cmd/godoc
# curl https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | bash

.PHONY: frontend-deps
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Holos
38 changes: 38 additions & 0 deletions api/core/v1alpha2/apiobjects.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package v1alpha2

import "google.golang.org/protobuf/types/known/structpb"

// Label is an arbitrary unique identifier. Defined as a type for clarity and type checking.
type Label string

// Kind is a kubernetes api object kind. Defined as a type for clarity and type checking.
type Kind string

// APIObjectMap represents the marshalled yaml representation of kubernetes api
// objects. Do not produce an APIObjectMap directly, instead use [APIObjects]
// to produce the marshalled yaml representation from CUE data, then provide the
// result to [HolosComponent].
type APIObjectMap map[Kind]map[Label]string

// APIObjects represents kubernetes api objects to apply to the api server.
// Useful to mix in resources to each HolosComponent type, for example adding an
// ExternalSecret to a HelmChart HolosComponent.
//
// Kind must be the resource kind, e.g. Deployment or Service.
//
// Label is an arbitrary internal identifier to uniquely identify the resource
// within the context of a `holos` command. Holos will never write the
// intermediate label to rendered output.
//
// Refer to [HolosComponent] which accepts an [APIObjectMap] field provided by
// [APIObjects].
type APIObjects struct {
// APIObjects represents Kubernetes API objects defined directly from CUE
// code. Useful to mix in resources, for example adding an ExternalSecret
// resource to a HelmChart HolosComponent.
APIObjects map[Kind]map[Label]structpb.Struct `json:"apiObjects"`
// APIObjectMap represents the marshalled yaml representation of APIObjects,
// useful to inspect the rendered representation of the resource which will be
// sent to the kubernetes API server.
APIObjectMap APIObjectMap `json:"apiObjectMap"`
}
116 changes: 116 additions & 0 deletions api/core/v1alpha2/buildplan.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package v1alpha2

import (
"fmt"
"strings"
)

// FileContentMap represents a mapping of file names to file content.
type FileContentMap map[string]string

// BuildPlan represents a build plan for the holos cli to execute. A build plan
// is a set of zero or more holos components. The purpose of a BuildPlan is to
// define one or more [HolosComponent] kinds, for example a [HelmChart] or
// [KustomizeBuild].
//
// A BuildPlan usually has an additional empty [KubernetesObjects] for the
// purpose of using the [HolosComponent] DeployFiles field to deploy an ArgoCD
// or Flux gitops resource for the holos component.
type BuildPlan struct {
Kind string `json:"kind" cue:"\"BuildPlan\""`
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha2\""`
Spec BuildPlanSpec `json:"spec"`
}

func (bp *BuildPlan) Validate() error {
errs := make([]string, 0, 2)
if bp.Kind != BuildPlanKind {
errs = append(errs, fmt.Sprintf("kind invalid: want: %s have: %s", BuildPlanKind, bp.Kind))
}
if bp.APIVersion != APIVersion {
errs = append(errs, fmt.Sprintf("apiVersion invalid: want: %s have: %s", APIVersion, bp.APIVersion))
}
if len(errs) > 0 {
return fmt.Errorf("invalid BuildPlan: " + strings.Join(errs, ", "))
}
return nil
}

func (bp *BuildPlan) ResultCapacity() (count int) {
if bp == nil {
return 0
}
count = len(bp.Spec.Components.HelmChartList) +
len(bp.Spec.Components.KubernetesObjectsList) +
len(bp.Spec.Components.KustomizeBuildList) +
len(bp.Spec.Components.Resources)
return count
}

type BuildPlanSpec struct {
Disabled bool `json:"disabled,omitempty"`
Components BuildPlanComponents `json:"components,omitempty"`
}

type BuildPlanComponents struct {
Resources map[string]KubernetesObjects `json:"resources,omitempty"`
KubernetesObjectsList []KubernetesObjects `json:"kubernetesObjectsList,omitempty"`
HelmChartList []HelmChart `json:"helmChartList,omitempty"`
KustomizeBuildList []KustomizeBuild `json:"kustomizeBuildList,omitempty"`
}

// HolosComponent defines the fields common to all holos component kinds. Every
// holos component kind should embed HolosComponent.
type HolosComponent struct {
// Kind is a string value representing the resource this object represents.
Kind string `json:"kind"`
// APIVersion represents the versioned schema of this representation of an object.
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha2\""`
// Metadata represents data about the holos component such as the Name.
Metadata Metadata `json:"metadata"`

// APIObjectMap holds the marshalled representation of api objects. Useful to
// mix in resources to each HolosComponent type, for example adding an
// ExternalSecret to a HelmChart HolosComponent. Refer to [APIObjects].
APIObjectMap APIObjectMap `json:"apiObjectMap,omitempty"`

// DeployFiles represents file paths relative to the cluster deploy directory
// with the value representing the file content. Intended for defining the
// ArgoCD Application resource or Flux Kustomization resource from within CUE,
// but may be used to render any file related to the build plan from CUE.
DeployFiles FileContentMap `json:"deployFiles,omitempty"`

// Kustomize represents a kubectl kustomize build post-processing step.
Kustomize `json:"kustomize,omitempty"`

// Skip causes holos to take no action regarding this component.
Skip bool `json:"skip" cue:"bool | *false"`
}

// Metadata represents data about the holos component such as the Name.
type Metadata struct {
// Name represents the name of the holos component.
Name string `json:"name"`
// Namespace is the primary namespace of the holos component. A holos
// component may manage resources in multiple namespaces, in this case
// consider setting the component namespace to default.
//
// This field is optional because not all resources require a namespace,
// particularly CRD's and DeployFiles functionality.
// +optional
Namespace string `json:"namespace,omitempty"`
}

// Kustomize represents resources necessary to execute a kustomize build.
// Intended for at least two use cases:
//
// 1. Process a [KustomizeBuild] [HolosComponent] which represents raw yaml
// file resources in a holos component directory.
// 2. Post process a [HelmChart] [HolosComponent] to inject istio, patch jobs,
// add custom labels, etc...
type Kustomize struct {
// KustomizeFiles holds file contents for kustomize, e.g. patch files.
KustomizeFiles FileContentMap `json:"kustomizeFiles,omitempty"`
// ResourcesFile is the file name used for api objects in kustomization.yaml
ResourcesFile string `json:"resourcesFile,omitempty"`
}
11 changes: 11 additions & 0 deletions api/core/v1alpha2/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package v1alpha2

const (
APIVersion = "v1alpha2"
BuildPlanKind = "BuildPlan"
HelmChartKind = "HelmChart"
// ChartDir is the directory name created in the holos component directory to cache a chart.
ChartDir = "vendor"
// ResourcesFile is the file name used to store component output when post-processing with kustomize.
ResourcesFile = "resources.yaml"
)
24 changes: 13 additions & 11 deletions api/core/v1alpha2/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,26 @@ package v1alpha2

import "google.golang.org/protobuf/types/known/structpb"

type PlatformMetadata struct {
// Name represents the Platform name.
Name string `json:"name"`
}

// Platform represents a platform to manage. A Platform resource informs holos
// which components to build. The platform resource also acts as a container
// for the platform model form values provided by the PlatformService. The
// primary use case is to collect the cluster names, cluster types, platform
// model, and holos components to build into one resource.
type Platform struct {
// Kind is a string value representing the resource this object represents.
Kind string `json:"kind" yaml:"kind" cue:"\"Platform\""`
Kind string `json:"kind" cue:"\"Platform\""`
// APIVersion represents the versioned schema of this representation of an object.
APIVersion string `json:"apiVersion" yaml:"apiVersion" cue:"string | *\"v1alpha2\""`
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha2\""`
// Metadata represents data about the object such as the Name.
Metadata struct {
// Name represents the Platform name.
Name string `json:"name" yaml:"name"`
} `json:"metadata" yaml:"metadata"`
Metadata PlatformMetadata `json:"metadata"`

// Spec represents the specification.
Spec PlatformSpec `json:"spec" yaml:"spec"`
Spec PlatformSpec `json:"spec"`
}

// PlatformSpec represents the specification of a Platform. Think of a platform
Expand All @@ -33,15 +35,15 @@ type Platform struct {
type PlatformSpec struct {
// Model represents the platform model holos gets from from the
// PlatformService.GetPlatform rpc method and provides to CUE using a tag.
Model structpb.Struct `json:"model" yaml:"model"`
Model structpb.Struct `json:"model"`
// Components represents a list of holos components to manage.
Components []PlatformSpecComponent `json:"components" yaml:"components"`
Components []PlatformSpecComponent `json:"components"`
}

// PlatformSpecComponent represents a holos component to build or render.
type PlatformSpecComponent struct {
// Path is the path of the component relative to the platform root.
Path string `json:"path" yaml:"path"`
Path string `json:"path"`
// Cluster is the cluster name to provide when rendering the component.
Cluster string `json:"cluster" yaml:"cluster"`
Cluster string `json:"cluster"`
}
38 changes: 38 additions & 0 deletions api/core/v1alpha2/helm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package v1alpha2

// HelmChart represents a holos component which wraps around an upstream helm
// chart. Holos orchestrates helm by providing values obtained from CUE,
// renders the output using `helm template`, then post-processes the helm output
// yaml using the general functionality provided by [HolosComponent], for
// example [Kustomize] post-rendering and mixing in additional kubernetes api
// objects.
type HelmChart struct {
HolosComponent `json:",inline"`
Kind string `json:"kind" cue:"\"HelmChart\""`

// Chart represents a helm chart to manage.
Chart Chart `json:"chart"`
// ValuesContent represents the values.yaml file holos passes to the `helm
// template` command.
ValuesContent string `json:"valuesContent"`
// EnableHooks enables helm hooks when executing the `helm template` command.
EnableHooks bool `json:"enableHooks" cue:"bool | *false"`
}

// Chart represents a helm chart.
type Chart struct {
// Name represents the chart name.
Name string `json:"name"`
// Version represents the chart version.
Version string `json:"version"`
// Release represents the chart release when executing helm template.
Release string `json:"release"`
// Repository represents the repository to fetch the chart from.
Repository Repository `json:"repository,omitempty"`
}

// Repository represents a helm chart repository.
type Repository struct {
Name string `json:"name"`
URL string `json:"url"`
}
10 changes: 10 additions & 0 deletions api/core/v1alpha2/kubernetesobjects.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package v1alpha2

const KubernetesObjectsKind = "KubernetesObjects"

// KubernetesObjects represents a [HolosComponent] composed of kubernetes api
// objects provided directly from CUE using [APIObjects].
type KubernetesObjects struct {
HolosComponent `json:",inline"`
Kind string `json:"kind" cue:"\"KubernetesObjects\""`
}
8 changes: 8 additions & 0 deletions api/core/v1alpha2/kustomizebuild.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package v1alpha2

// KustomizeBuild renders plain yaml files in the holos component directory
// using kubectl kustomize build.
type KustomizeBuild struct {
HolosComponent `json:",inline"`
Kind string `json:"kind" cue:"\"KustomizeBuild\""`
}
8 changes: 4 additions & 4 deletions api/meta/v1alpha2/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ package v1alpha2
// Structures that are versioned or persisted should inline TypeMeta.
type TypeMeta struct {
// Kind is a string value representing the resource this object represents.
Kind string `json:"kind" yaml:"kind"`
Kind string `json:"kind"`
// APIVersion defines the versioned schema of this representation of an object.
APIVersion string `json:"apiVersion" yaml:"apiVersion" cue:"string | *\"v1alpha2\""`
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha2\""`
}

func (tm *TypeMeta) GetKind() string {
Expand All @@ -31,7 +31,7 @@ type Discriminator interface {
// kubernetes api objects.
type ObjectMeta struct {
// Name uniquely identifies the holos component instance and must be suitable as a file name.
Name string `json:"name,omitempty" yaml:"name,omitempty"`
Name string `json:"name,omitempty"`
// Namespace confines a holos component to a single namespace via kustomize if set.
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
Namespace string `json:"namespace,omitempty"`
}
5 changes: 0 additions & 5 deletions api/v1alpha1/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,6 @@ func (r *Result) KustomizationFilename(writeTo string, cluster string) string {
return filepath.Join(writeTo, "clusters", cluster, "holos", "components", r.Metadata.Name+"-kustomization.gen.yaml")
}

// KustomizationContent returns the kustomization file contents to write.
func (r *Result) KustomizationContent() string {
return r.KsContent
}

// AccumulatedOutput returns the accumulated rendered output.
func (r *Result) AccumulatedOutput() string {
return r.accumulatedOutput
Expand Down
1 change: 1 addition & 0 deletions docs/examples/cue.mod/module.cue
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
module: "github.com/holos-run/holos/docs/examples"
language: version: "v0.9.2"
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ let OBJECTS = #APIObjects & {
loopback: #Service & {
_description: LoopbackDescription
metadata: LoopbackMetaName
spec: selector: LoopbackLabels
spec: selector: LoopbackLabels
spec: ports: [{port: 80, name: "http"}, {port: 443, name: "https"}]
}
}
Expand Down
5 changes: 2 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ require (
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.9.0
golang.org/x/net v0.26.0
golang.org/x/sync v0.7.0
golang.org/x/tools v0.22.0
google.golang.org/genproto/googleapis/rpc v0.0.0-20240325203815-454cdb8f5daa
google.golang.org/protobuf v1.33.1-0.20240408130810-98873a205002
Expand All @@ -44,7 +45,6 @@ require (

require (
ariga.io/atlas v0.19.1-0.20240203083654-5948b60a8e43 // indirect
cloud.google.com/go/compute v1.23.3 // indirect
cloud.google.com/go/compute/metadata v0.3.0 // indirect
cuelabs.dev/go/oci/ociregistry v0.0.0-20240404174027-a39bec0462d2 // indirect
github.com/AlecAivazis/survey/v2 v2.3.7 // indirect
Expand Down Expand Up @@ -215,6 +215,7 @@ require (
github.com/stoewer/go-strcase v1.3.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/tchap/go-patricia/v2 v2.3.1 // indirect
github.com/tetratelabs/wazero v1.6.0 // indirect
github.com/tidwall/gjson v1.17.1 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
Expand Down Expand Up @@ -242,12 +243,10 @@ require (
golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a // indirect
golang.org/x/mod v0.18.0 // indirect
golang.org/x/oauth2 v0.20.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/term v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240325203815-454cdb8f5daa // indirect
google.golang.org/grpc v1.62.1 // indirect
Expand Down
Loading

0 comments on commit 8bc7804

Please sign in to comment.