mirror of
https://github.com/holos-run/holos.git
synced 2026-03-18 02:38:58 +00:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bc7804a9c | ||
|
|
a39807a858 | ||
|
|
5170650760 | ||
|
|
1d81b3c3b4 | ||
|
|
33970dafe8 | ||
|
|
faa46c54d8 | ||
|
|
42509a34cf | ||
|
|
ef369d4860 | ||
|
|
747ed3462a | ||
|
|
1fb1798f60 | ||
|
|
accf80200f | ||
|
|
4522ee1d4e | ||
|
|
313ebc6817 | ||
|
|
e0f439515f | ||
|
|
caa7560ab9 | ||
|
|
bbcf280da7 | ||
|
|
6d2daacb7b | ||
|
|
62f96a2d6c | ||
|
|
50f414d520 | ||
|
|
882f3894f3 | ||
|
|
30ddde7b49 |
9
Makefile
9
Makefile
@@ -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
|
||||
@@ -64,6 +65,8 @@ vet: ## Vet Go code.
|
||||
.PHONY: gencue
|
||||
gencue: ## Generate CUE definitions
|
||||
cd internal/generate/platforms && cue get go github.com/holos-run/holos/api/v1alpha1/...
|
||||
cd internal/generate/platforms && cue get go github.com/holos-run/holos/api/core/...
|
||||
cd internal/generate/platforms && cue get go github.com/holos-run/holos/api/meta/...
|
||||
|
||||
.PHONY: rmgen
|
||||
rmgen: ## Remove generated code
|
||||
@@ -123,11 +126,13 @@ tools: go-deps frontend-deps ## install tool dependencies
|
||||
|
||||
.PHONY: go-deps
|
||||
go-deps: ## tool versions pinned in tools.go
|
||||
go install cuelang.org/go/cmd/cue
|
||||
go install github.com/bufbuild/buf/cmd/buf
|
||||
go install github.com/fullstorydev/grpcurl/cmd/grpcurl
|
||||
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@latest
|
||||
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
|
||||
@@ -148,7 +153,7 @@ frontend: buf
|
||||
touch internal/frontend/frontend.go
|
||||
|
||||
.PHONY: image
|
||||
image: build
|
||||
image: build ## Docker image build
|
||||
docker build . -t ${DOCKER_REPO}:v$(shell ./bin/holos --version)
|
||||
docker push ${DOCKER_REPO}:v$(shell ./bin/holos --version)
|
||||
|
||||
|
||||
38
api/core/v1alpha2/apiobjects.go
Normal file
38
api/core/v1alpha2/apiobjects.go
Normal file
@@ -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
api/core/v1alpha2/buildplan.go
Normal file
116
api/core/v1alpha2/buildplan.go
Normal file
@@ -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
api/core/v1alpha2/constants.go
Normal file
11
api/core/v1alpha2/constants.go
Normal file
@@ -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"
|
||||
)
|
||||
49
api/core/v1alpha2/core.go
Normal file
49
api/core/v1alpha2/core.go
Normal file
@@ -0,0 +1,49 @@
|
||||
// Package v1alpha2 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.
|
||||
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" cue:"\"Platform\""`
|
||||
// APIVersion represents the versioned schema of this representation of an object.
|
||||
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha2\""`
|
||||
// Metadata represents data about the object such as the Name.
|
||||
Metadata PlatformMetadata `json:"metadata"`
|
||||
|
||||
// Spec represents the specification.
|
||||
Spec PlatformSpec `json:"spec"`
|
||||
}
|
||||
|
||||
// PlatformSpec represents the specification of a Platform. Think of a platform
|
||||
// specification as a list of platform components to apply to a list of
|
||||
// kubernetes clusters combined with the user-specified Platform Model.
|
||||
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"`
|
||||
// Components represents a list of holos components to manage.
|
||||
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"`
|
||||
// Cluster is the cluster name to provide when rendering the component.
|
||||
Cluster string `json:"cluster"`
|
||||
}
|
||||
38
api/core/v1alpha2/helm.go
Normal file
38
api/core/v1alpha2/helm.go
Normal file
@@ -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
api/core/v1alpha2/kubernetesobjects.go
Normal file
10
api/core/v1alpha2/kubernetesobjects.go
Normal file
@@ -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
api/core/v1alpha2/kustomizebuild.go
Normal file
8
api/core/v1alpha2/kustomizebuild.go
Normal file
@@ -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\""`
|
||||
}
|
||||
37
api/meta/v1alpha2/meta.go
Normal file
37
api/meta/v1alpha2/meta.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package v1alpha2
|
||||
|
||||
// TypeMeta describes an individual object in an API response or request with
|
||||
// strings representing the type of the object and its API schema version.
|
||||
// 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"`
|
||||
// APIVersion defines the versioned schema of this representation of an object.
|
||||
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha2\""`
|
||||
}
|
||||
|
||||
func (tm *TypeMeta) GetKind() string {
|
||||
return tm.Kind
|
||||
}
|
||||
|
||||
func (tm *TypeMeta) GetAPIVersion() string {
|
||||
return tm.APIVersion
|
||||
}
|
||||
|
||||
// Discriminator discriminates the kind of an api object.
|
||||
type Discriminator interface {
|
||||
// GetKind returns Kind.
|
||||
GetKind() string
|
||||
// GetAPIVersion returns APIVersion.
|
||||
GetAPIVersion() string
|
||||
}
|
||||
|
||||
// ObjectMeta represents metadata of a holos component object. The fields are a
|
||||
// copy of upstream kubernetes api machinery but are holos objects distinct from
|
||||
// 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"`
|
||||
// Namespace confines a holos component to a single namespace via kustomize if set.
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -10,7 +10,7 @@ func (tm *TypeMeta) GetKind() string {
|
||||
}
|
||||
|
||||
func (tm *TypeMeta) GetAPIVersion() string {
|
||||
return tm.Kind
|
||||
return tm.APIVersion
|
||||
}
|
||||
|
||||
// Discriminator is an interface to discriminate the kind api object.
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
module: "github.com/holos-run/holos/docs/examples"
|
||||
language: version: "v0.9.2"
|
||||
|
||||
@@ -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"}]
|
||||
}
|
||||
}
|
||||
|
||||
28
go.mod
28
go.mod
@@ -8,7 +8,7 @@ require (
|
||||
connectrpc.com/grpcreflect v1.2.0
|
||||
connectrpc.com/otelconnect v0.7.0
|
||||
connectrpc.com/validate v0.1.0
|
||||
cuelang.org/go v0.8.0
|
||||
cuelang.org/go v0.9.2
|
||||
entgo.io/ent v0.13.1
|
||||
github.com/bufbuild/buf v1.30.1
|
||||
github.com/choria-io/machine-room v0.0.0-20240417064836-c604da2f005e
|
||||
@@ -29,8 +29,9 @@ require (
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.9.0
|
||||
golang.org/x/net v0.24.0
|
||||
golang.org/x/tools v0.20.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
|
||||
honnef.co/go/tools v0.4.7
|
||||
@@ -44,9 +45,8 @@ 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.2.3 // indirect
|
||||
cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e // 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
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||
github.com/BurntSushi/toml v1.3.2 // indirect
|
||||
@@ -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
|
||||
@@ -225,6 +226,7 @@ require (
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xlab/tablewriter v0.0.0-20160610135559-80b567a11ad5 // indirect
|
||||
github.com/yashtewari/glob-intersection v0.2.0 // indirect
|
||||
github.com/yuin/goldmark v1.4.13 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
github.com/zclconf/go-cty v1.8.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
|
||||
@@ -236,17 +238,15 @@ require (
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/crypto v0.22.0 // indirect
|
||||
golang.org/x/crypto v0.24.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
|
||||
golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/oauth2 v0.18.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.19.0 // indirect
|
||||
golang.org/x/term v0.19.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/mod v0.18.0 // indirect
|
||||
golang.org/x/oauth2 v0.20.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
|
||||
|
||||
51
go.sum
51
go.sum
@@ -23,10 +23,8 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
|
||||
cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
|
||||
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
|
||||
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
||||
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
|
||||
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
@@ -46,10 +44,10 @@ connectrpc.com/otelconnect v0.7.0 h1:ZH55ZZtcJOTKWWLy3qmL4Pam4RzRWBJFOqTPyAqCXkY
|
||||
connectrpc.com/otelconnect v0.7.0/go.mod h1:Bt2ivBymHZHqxvo4HkJ0EwHuUzQN6k2l0oH+mp/8nwc=
|
||||
connectrpc.com/validate v0.1.0 h1:r55jirxMK7HO/xZwVHj3w2XkVFarsUM77ZDy367NtH4=
|
||||
connectrpc.com/validate v0.1.0/go.mod h1:GU47c9/x/gd+u9wRSPkrQOP46gx2rMN+Wo37EHgI3Ow=
|
||||
cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e h1:GwCVItFUPxwdsEYnlUcJ6PJxOjTeFFCKOh6QWg4oAzQ=
|
||||
cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e/go.mod h1:ApHceQLLwcOkCEXM1+DyCXTHEJhNGDpJ2kmV6axsx24=
|
||||
cuelang.org/go v0.8.0 h1:fO1XPe/SUGtc7dhnGnTPbpIDoQm/XxhDtoSF7jzO01c=
|
||||
cuelang.org/go v0.8.0/go.mod h1:CoDbYolfMms4BhWUlhD+t5ORnihR7wvjcfgyO9lL5FI=
|
||||
cuelabs.dev/go/oci/ociregistry v0.0.0-20240404174027-a39bec0462d2 h1:BnG6pr9TTr6CYlrJznYUDj6V7xldD1W+1iXPum0wT/w=
|
||||
cuelabs.dev/go/oci/ociregistry v0.0.0-20240404174027-a39bec0462d2/go.mod h1:pK23AUVXuNzzTpfMCA06sxZGeVQ/75FdVtW249de9Uo=
|
||||
cuelang.org/go v0.9.2 h1:pfNiry2PdRBr02G/aKm5k2vhzmqbAOoaB4WurmEbWvs=
|
||||
cuelang.org/go v0.9.2/go.mod h1:qpAYsLOf7gTM1YdEg6cxh553uZ4q9ZDWlPbtZr9q1Wk=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
entgo.io/ent v0.13.1 h1:uD8QwN1h6SNphdCCzmkMN3feSUzNnVvV/WIkHKMbzOE=
|
||||
entgo.io/ent v0.13.1/go.mod h1:qCEmo+biw3ccBn9OyL4ZK5dfpwg++l1Gxwac5B1206A=
|
||||
@@ -638,6 +636,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes=
|
||||
github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k=
|
||||
github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g=
|
||||
github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
|
||||
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
|
||||
github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
@@ -670,6 +670,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
@@ -719,8 +720,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -758,8 +759,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
|
||||
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -793,16 +794,16 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
|
||||
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
|
||||
golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
|
||||
golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -868,16 +869,16 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -885,12 +886,12 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -942,8 +943,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
|
||||
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
|
||||
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
|
||||
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -970,8 +971,6 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
// Package v1alpha1 is the unstable version of the core api.
|
||||
package v1alpha1
|
||||
@@ -15,22 +15,25 @@ import (
|
||||
"cuelang.org/go/cue/build"
|
||||
"cuelang.org/go/cue/cuecontext"
|
||||
"cuelang.org/go/cue/load"
|
||||
"github.com/holos-run/holos/api/core/v1alpha2"
|
||||
"github.com/holos-run/holos/api/v1alpha1"
|
||||
|
||||
"github.com/holos-run/holos"
|
||||
"github.com/holos-run/holos/internal/client"
|
||||
"github.com/holos-run/holos/internal/errors"
|
||||
"github.com/holos-run/holos/internal/logger"
|
||||
"github.com/holos-run/holos/internal/render"
|
||||
)
|
||||
|
||||
const (
|
||||
KubernetesObjects = v1alpha1.KubernetesObjectsKind
|
||||
KubernetesObjects = v1alpha2.KubernetesObjectsKind
|
||||
// Helm is the value of the kind field of holos build output indicating helm
|
||||
// values and helm command information.
|
||||
Helm = v1alpha1.HelmChartKind
|
||||
Helm = v1alpha2.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 holos should process the component using kustomize build to render output.
|
||||
// KustomizeBuild is the value of the kind field of cue output indicating
|
||||
// holos should process the component using kustomize build to render output.
|
||||
KustomizeBuild = v1alpha1.KustomizeBuildKind
|
||||
)
|
||||
|
||||
@@ -128,14 +131,14 @@ func (b *Builder) Instances(ctx context.Context, cfg *client.Config) ([]*build.I
|
||||
return load.Instances(args, &cueConfig), nil
|
||||
}
|
||||
|
||||
func (b *Builder) Run(ctx context.Context, cfg *client.Config) (results []*v1alpha1.Result, err error) {
|
||||
func (b *Builder) Run(ctx context.Context, cfg *client.Config) (results []*render.Result, err error) {
|
||||
log := logger.FromContext(ctx)
|
||||
log.DebugContext(ctx, "cue: building instances")
|
||||
instances, err := b.Instances(ctx, cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results = make([]*v1alpha1.Result, 0, len(instances)*8)
|
||||
results = make([]*render.Result, 0, len(instances)*8)
|
||||
|
||||
// Each CUE instance provides a BuildPlan
|
||||
for idx, instance := range instances {
|
||||
@@ -150,7 +153,7 @@ func (b *Builder) Run(ctx context.Context, cfg *client.Config) (results []*v1alp
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (b Builder) runInstance(ctx context.Context, instance *build.Instance) (results []*v1alpha1.Result, err error) {
|
||||
func (b Builder) runInstance(ctx context.Context, instance *build.Instance) (results []*render.Result, err error) {
|
||||
path := holos.InstancePath(instance.Dir)
|
||||
log := logger.FromContext(ctx).With("dir", path)
|
||||
|
||||
@@ -191,9 +194,8 @@ func (b Builder) runInstance(ctx context.Context, instance *build.Instance) (res
|
||||
decoder.DisallowUnknownFields()
|
||||
|
||||
switch tm.Kind {
|
||||
// TODO(jeff) Process a v1alpha1.Result here, the result is tightly coupled to a BuildPlan.
|
||||
case "BuildPlan":
|
||||
var bp v1alpha1.BuildPlan
|
||||
var bp v1alpha2.BuildPlan
|
||||
if err = decoder.Decode(&bp); err != nil {
|
||||
err = errors.Wrap(fmt.Errorf("could not decode BuildPlan %s: %w", instance.Dir, err))
|
||||
return
|
||||
@@ -209,7 +211,7 @@ func (b Builder) runInstance(ctx context.Context, instance *build.Instance) (res
|
||||
return results, err
|
||||
}
|
||||
|
||||
func (b *Builder) buildPlan(ctx context.Context, buildPlan *v1alpha1.BuildPlan, path holos.InstancePath) (results []*v1alpha1.Result, err error) {
|
||||
func (b *Builder) buildPlan(ctx context.Context, buildPlan *v1alpha2.BuildPlan, path holos.InstancePath) (results []*render.Result, err error) {
|
||||
log := logger.FromContext(ctx)
|
||||
|
||||
if err := buildPlan.Validate(); err != nil {
|
||||
@@ -222,11 +224,12 @@ func (b *Builder) buildPlan(ctx context.Context, buildPlan *v1alpha1.BuildPlan,
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: concurrent renders
|
||||
results = make([]*v1alpha1.Result, 0, buildPlan.ResultCapacity())
|
||||
results = make([]*render.Result, 0, buildPlan.ResultCapacity())
|
||||
log.DebugContext(ctx, "allocated results slice", "cap", buildPlan.ResultCapacity())
|
||||
|
||||
for _, component := range buildPlan.Spec.Components.Resources {
|
||||
if result, err := component.Render(ctx, path); err != nil {
|
||||
ko := render.KubernetesObjects{Component: component}
|
||||
if result, err := ko.Render(ctx, path); err != nil {
|
||||
return nil, errors.Wrap(fmt.Errorf("could not render: %w", err))
|
||||
} else {
|
||||
results = append(results, result)
|
||||
@@ -234,38 +237,30 @@ func (b *Builder) buildPlan(ctx context.Context, buildPlan *v1alpha1.BuildPlan,
|
||||
}
|
||||
|
||||
for _, component := range buildPlan.Spec.Components.KubernetesObjectsList {
|
||||
if result, err := component.Render(ctx, path); err != nil {
|
||||
ko := render.KubernetesObjects{Component: component}
|
||||
if result, err := ko.Render(ctx, path); err != nil {
|
||||
return nil, errors.Wrap(fmt.Errorf("could not render: %w", err))
|
||||
} else {
|
||||
results = append(results, result)
|
||||
}
|
||||
}
|
||||
for _, component := range buildPlan.Spec.Components.HelmChartList {
|
||||
if result, err := component.Render(ctx, path); err != nil {
|
||||
hc := render.HelmChart{Component: component}
|
||||
if result, err := hc.Render(ctx, path); err != nil {
|
||||
return nil, errors.Wrap(fmt.Errorf("could not render: %w", err))
|
||||
} else {
|
||||
results = append(results, result)
|
||||
}
|
||||
}
|
||||
for _, component := range buildPlan.Spec.Components.KustomizeBuildList {
|
||||
if result, err := component.Render(ctx, path); err != nil {
|
||||
kb := render.KustomizeBuild{Component: component}
|
||||
if result, err := kb.Render(ctx, path); err != nil {
|
||||
return nil, errors.Wrap(fmt.Errorf("could not render: %w", err))
|
||||
} else {
|
||||
results = append(results, result)
|
||||
}
|
||||
}
|
||||
|
||||
// Add a separate Result if there are DeployFiles from the BuildPlan.
|
||||
if len(buildPlan.Spec.DeployFiles) > 0 {
|
||||
results = append(results, &v1alpha1.Result{
|
||||
HolosComponent: v1alpha1.HolosComponent{
|
||||
TypeMeta: buildPlan.TypeMeta,
|
||||
Metadata: buildPlan.Metadata,
|
||||
},
|
||||
DeployFiles: buildPlan.Spec.DeployFiles,
|
||||
})
|
||||
}
|
||||
|
||||
log.DebugContext(ctx, "returning results", "len", len(results))
|
||||
|
||||
return results, nil
|
||||
|
||||
@@ -9,14 +9,15 @@ import (
|
||||
"cuelang.org/go/cue/build"
|
||||
"cuelang.org/go/cue/cuecontext"
|
||||
"github.com/holos-run/holos"
|
||||
"github.com/holos-run/holos/api/v1alpha1"
|
||||
core "github.com/holos-run/holos/api/core/v1alpha2"
|
||||
meta "github.com/holos-run/holos/api/meta/v1alpha2"
|
||||
"github.com/holos-run/holos/internal/client"
|
||||
"github.com/holos-run/holos/internal/errors"
|
||||
"github.com/holos-run/holos/internal/logger"
|
||||
)
|
||||
|
||||
// Platform builds a platform
|
||||
func (b *Builder) Platform(ctx context.Context, cfg *client.Config) (*v1alpha1.Platform, error) {
|
||||
func (b *Builder) Platform(ctx context.Context, cfg *client.Config) (*core.Platform, error) {
|
||||
log := logger.FromContext(ctx)
|
||||
log.DebugContext(ctx, "cue: building platform instance")
|
||||
instances, err := b.Instances(ctx, cfg)
|
||||
@@ -38,7 +39,7 @@ func (b *Builder) Platform(ctx context.Context, cfg *client.Config) (*v1alpha1.P
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (b Builder) runPlatform(ctx context.Context, instance *build.Instance) (*v1alpha1.Platform, error) {
|
||||
func (b Builder) runPlatform(ctx context.Context, instance *build.Instance) (*core.Platform, error) {
|
||||
path := holos.InstancePath(instance.Dir)
|
||||
log := logger.FromContext(ctx).With("dir", path)
|
||||
|
||||
@@ -60,22 +61,23 @@ func (b Builder) runPlatform(ctx context.Context, instance *build.Instance) (*v1
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(fmt.Errorf("could not marshal cue instance %s: %w", instance.Dir, err))
|
||||
}
|
||||
|
||||
decoder := json.NewDecoder(bytes.NewReader(jsonBytes))
|
||||
// Discriminate the type of build plan.
|
||||
tm := &v1alpha1.TypeMeta{}
|
||||
tm := &meta.TypeMeta{}
|
||||
err = decoder.Decode(tm)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(fmt.Errorf("invalid platform: %s: %w", instance.Dir, err))
|
||||
}
|
||||
|
||||
log.DebugContext(ctx, "cue: discriminated build kind: "+tm.Kind, "kind", tm.Kind, "apiVersion", tm.APIVersion)
|
||||
log.DebugContext(ctx, "cue: discriminated build kind: "+tm.GetKind(), "kind", tm.GetKind(), "apiVersion", tm.GetAPIVersion())
|
||||
|
||||
// New decoder for the full object
|
||||
decoder = json.NewDecoder(bytes.NewReader(jsonBytes))
|
||||
decoder.DisallowUnknownFields()
|
||||
|
||||
var pf v1alpha1.Platform
|
||||
switch tm.Kind {
|
||||
var pf core.Platform
|
||||
switch tm.GetKind() {
|
||||
case "Platform":
|
||||
if err = decoder.Decode(&pf); err != nil {
|
||||
err = errors.Wrap(fmt.Errorf("could not decode platform %s: %w", instance.Dir, err))
|
||||
@@ -83,7 +85,7 @@ func (b Builder) runPlatform(ctx context.Context, instance *build.Instance) (*v1
|
||||
}
|
||||
return &pf, nil
|
||||
default:
|
||||
err = errors.Wrap(fmt.Errorf("unknown kind: %v", tm.Kind))
|
||||
err = errors.Wrap(fmt.Errorf("unknown kind: %v", tm.GetKind()))
|
||||
}
|
||||
|
||||
return nil, err
|
||||
|
||||
@@ -26,7 +26,7 @@ func makeBuildRunFunc(cfg *client.Config) command.RunFunc {
|
||||
}
|
||||
outs := make([]string, 0, len(results))
|
||||
for idx, result := range results {
|
||||
if result == nil || result.Skip {
|
||||
if result.Continue() {
|
||||
slog.Debug("skip result", "idx", idx, "result", result)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -78,22 +78,13 @@ func NewComponent(cfg *holos.Config) *cobra.Command {
|
||||
if err := result.WriteDeployFiles(ctx, cfg.WriteTo()); err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
// Build plans don't have anything but DeployFiles to write.
|
||||
if result.GetKind() == "BuildPlan" {
|
||||
continue
|
||||
}
|
||||
|
||||
// API Objects
|
||||
path := result.Filename(cfg.WriteTo(), cfg.ClusterName())
|
||||
if err := result.Save(ctx, path, result.AccumulatedOutput()); err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
// Kustomization
|
||||
if result.KustomizationContent() == "" {
|
||||
log.DebugContext(ctx, "flux kustomization: skipped "+result.Name(), "status", "ok", "action", "skipped")
|
||||
if result.SkipWriteAccumulatedOutput() {
|
||||
log.DebugContext(ctx, "skipped writing k8s objects for "+result.Name())
|
||||
} else {
|
||||
path = result.KustomizationFilename(cfg.WriteTo(), cfg.ClusterName())
|
||||
if err := result.Save(ctx, path, result.KustomizationContent()); err != nil {
|
||||
path := result.Filename(cfg.WriteTo(), cfg.ClusterName())
|
||||
if err := result.Save(ctx, path, result.AccumulatedOutput()); err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
}
|
||||
@@ -139,7 +130,7 @@ type Result interface {
|
||||
KustomizationFilename(writeTo string, cluster string) string
|
||||
Save(ctx context.Context, path string, content string) error
|
||||
AccumulatedOutput() string
|
||||
KustomizationContent() string
|
||||
SkipWriteAccumulatedOutput() bool
|
||||
WriteDeployFiles(ctx context.Context, writeTo string) error
|
||||
GetKind() string
|
||||
GetAPIVersion() string
|
||||
|
||||
56
internal/frontend/holos/package-lock.json
generated
56
internal/frontend/holos/package-lock.json
generated
@@ -37,7 +37,7 @@
|
||||
"@angular-eslint/template-parser": "17.3.0",
|
||||
"@angular/cli": "^17.3.4",
|
||||
"@angular/compiler-cli": "^17.3.0",
|
||||
"@bufbuild/buf": "^1.32.2",
|
||||
"@bufbuild/buf": "^1.34.0",
|
||||
"@bufbuild/protoc-gen-es": "^1.10.0",
|
||||
"@connectrpc/protoc-gen-connect-es": "^1.4.0",
|
||||
"@connectrpc/protoc-gen-connect-query": "^1.4.1",
|
||||
@@ -2494,9 +2494,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@bufbuild/buf": {
|
||||
"version": "1.32.2",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/buf/-/buf-1.32.2.tgz",
|
||||
"integrity": "sha512-WL2mpou8k9EBo2US0KyZhFSHrDmRZvv5ZMp7lywUFb+3lW1+E/OZnBaBYTrSAb9vfzSmwdRsSOJwKdDpfbjdSg==",
|
||||
"version": "1.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/buf/-/buf-1.34.0.tgz",
|
||||
"integrity": "sha512-DR0P746bYiY7ziQTui0bKAvPa7ihCNxONWLtW54HQXvTkGnTc6C1keVaSz4UhNdSsBu/Xsj69GO9SizodfjUtQ==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
@@ -2508,18 +2508,18 @@
|
||||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@bufbuild/buf-darwin-arm64": "1.32.2",
|
||||
"@bufbuild/buf-darwin-x64": "1.32.2",
|
||||
"@bufbuild/buf-linux-aarch64": "1.32.2",
|
||||
"@bufbuild/buf-linux-x64": "1.32.2",
|
||||
"@bufbuild/buf-win32-arm64": "1.32.2",
|
||||
"@bufbuild/buf-win32-x64": "1.32.2"
|
||||
"@bufbuild/buf-darwin-arm64": "1.34.0",
|
||||
"@bufbuild/buf-darwin-x64": "1.34.0",
|
||||
"@bufbuild/buf-linux-aarch64": "1.34.0",
|
||||
"@bufbuild/buf-linux-x64": "1.34.0",
|
||||
"@bufbuild/buf-win32-arm64": "1.34.0",
|
||||
"@bufbuild/buf-win32-x64": "1.34.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@bufbuild/buf-darwin-arm64": {
|
||||
"version": "1.32.2",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/buf-darwin-arm64/-/buf-darwin-arm64-1.32.2.tgz",
|
||||
"integrity": "sha512-AR6WlhY6CmLlZetvYzLjbyVpU5jM4eDd3PRTUAK5NcpqIPdCMiMK9nc33Yxc8pO04Lv4yrYdzWnFqZdbCzsS2g==",
|
||||
"version": "1.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/buf-darwin-arm64/-/buf-darwin-arm64-1.34.0.tgz",
|
||||
"integrity": "sha512-3+h/jSAr7H+KT8MWWRMbN/gQ87KlGLkTGwm4/mpry1ap9Thw/UdOrk5MfmbK3CRM/rlw4mAn1Egu/Q7R5eO98g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2533,9 +2533,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@bufbuild/buf-darwin-x64": {
|
||||
"version": "1.32.2",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/buf-darwin-x64/-/buf-darwin-x64-1.32.2.tgz",
|
||||
"integrity": "sha512-ZmVYsMcS06KHZYy4DmKf95BnDWji5/xo42oybqjtlE/wPGKNpqgiq0UGHSlK0oCh67sybHidXVci6LC95xHNrw==",
|
||||
"version": "1.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/buf-darwin-x64/-/buf-darwin-x64-1.34.0.tgz",
|
||||
"integrity": "sha512-Jdm0COuA2CMKoef2H8rBsRnc16mJUmCQ2KvJH5otvFrMhzPmr1MUyicCybY26HXFD/6DcnbWZvf6W8LfDMMyGQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2549,9 +2549,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@bufbuild/buf-linux-aarch64": {
|
||||
"version": "1.32.2",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-aarch64/-/buf-linux-aarch64-1.32.2.tgz",
|
||||
"integrity": "sha512-OG509xwJHjuzSn5nNrVWghW/RpB76Ovhj7LCKi52QVh/qQq6VUXeQk42XIWjXY/Cmzmg81G7t97kLw27JLzH0w==",
|
||||
"version": "1.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-aarch64/-/buf-linux-aarch64-1.34.0.tgz",
|
||||
"integrity": "sha512-utSspJlPmVPh4Ugvn9k7MEEMHDZMI13jvwHkBE6wNSkYxxYTRR5zLHtmysaYQo51Fx+3ar6mL4HnhTqLrgO5GA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2565,9 +2565,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@bufbuild/buf-linux-x64": {
|
||||
"version": "1.32.2",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-x64/-/buf-linux-x64-1.32.2.tgz",
|
||||
"integrity": "sha512-TFNN87nhLyGFUKOy3beU/0GZk7TEs57J5VQczSq83rHLC+7t1nDuk5Rew8QEyV0OzEzZF+BkpLZj0jY+dWg6/g==",
|
||||
"version": "1.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-x64/-/buf-linux-x64-1.34.0.tgz",
|
||||
"integrity": "sha512-INCGsPLBL4aK2jHBMdZzEJUPv7f6f8skIUMMip7YdJl1nsIh27C/Dl7Q6A6/sv9IhYibWKAoxP7SuiOv2iTdEw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2581,9 +2581,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@bufbuild/buf-win32-arm64": {
|
||||
"version": "1.32.2",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/buf-win32-arm64/-/buf-win32-arm64-1.32.2.tgz",
|
||||
"integrity": "sha512-SsGUfILZblPNbCgG6W9DxzCdfHnT2YTYQEkCS877DL1wkWMlMJ/ijZA9Cg2fx8NrLKzFTKC1nlTfqRBcLPf2Mg==",
|
||||
"version": "1.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/buf-win32-arm64/-/buf-win32-arm64-1.34.0.tgz",
|
||||
"integrity": "sha512-g1EogebjJ93bzmyn/fEi47tTz57M+7WYZ7/vX+DFXgLLYIxTWHDK4YN+3Hs+K7Sbx7KaVdsdEqof8xZ4WoVFnQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2597,9 +2597,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@bufbuild/buf-win32-x64": {
|
||||
"version": "1.32.2",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/buf-win32-x64/-/buf-win32-x64-1.32.2.tgz",
|
||||
"integrity": "sha512-FXOHmXB0kxQ7nQ0JYWpByl6/ebkKwWPPjucOHIDcfo7czg5ZD/fRusb738YJ1qeN+5RXybkvhJIrewxVnhYuhg==",
|
||||
"version": "1.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/buf-win32-x64/-/buf-win32-x64-1.34.0.tgz",
|
||||
"integrity": "sha512-0rPXP7pV7+2twhcpN8hDdgV68UCiazLRcMBjWKubwcSJhAP8jRLqSJv3VGnXmpdYPbYGDQ0htfcgLNUvzllRhQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
"@angular-eslint/template-parser": "17.3.0",
|
||||
"@angular/cli": "^17.3.4",
|
||||
"@angular/compiler-cli": "^17.3.0",
|
||||
"@bufbuild/buf": "^1.32.2",
|
||||
"@bufbuild/buf": "^1.34.0",
|
||||
"@bufbuild/protoc-gen-es": "^1.10.0",
|
||||
"@connectrpc/protoc-gen-connect-es": "^1.4.0",
|
||||
"@connectrpc/protoc-gen-connect-query": "^1.4.1",
|
||||
|
||||
@@ -1,33 +1,34 @@
|
||||
package holos
|
||||
|
||||
import "encoding/yaml"
|
||||
|
||||
import v1 "github.com/holos-run/holos/api/v1alpha1"
|
||||
|
||||
// #Helm represents a holos build plan composed of one or more helm charts.
|
||||
#Helm: {
|
||||
Name: string
|
||||
Version: string
|
||||
Namespace: string
|
||||
Name: string
|
||||
Version: string
|
||||
Namespace: string
|
||||
|
||||
Repo: {
|
||||
name: string | *""
|
||||
url: string | *""
|
||||
}
|
||||
Repo: {
|
||||
name: string | *""
|
||||
url: string | *""
|
||||
}
|
||||
|
||||
Values: {...}
|
||||
Values: {...}
|
||||
|
||||
Chart: v1.#HelmChart & {
|
||||
metadata: name: string | *Name
|
||||
namespace: string | *Namespace
|
||||
chart: name: string | *Name
|
||||
chart: version: string | *Version
|
||||
chart: repository: Repo
|
||||
// Render the values to yaml for holos to provide to helm.
|
||||
valuesContent: yaml.Marshal(Values)
|
||||
}
|
||||
Chart: v1.#HelmChart & {
|
||||
metadata: name: string | *Name
|
||||
namespace: string | *Namespace
|
||||
chart: name: string | *Name
|
||||
chart: version: string | *Version
|
||||
chart: repository: Repo
|
||||
// Render the values to yaml for holos to provide to helm.
|
||||
valuesContent: yaml.Marshal(Values)
|
||||
}
|
||||
|
||||
// output represents the build plan provided to the holos cli.
|
||||
// output represents the build plan provided to the holos cli.
|
||||
Output: v1.#BuildPlan & {
|
||||
spec: components: helmChartList: [Chart]
|
||||
}
|
||||
spec: components: helmChartList: [Chart]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,13 +58,13 @@ let FormBuilder = v1.#FormBuilder & {
|
||||
multiple: true
|
||||
selectAllOption: "Select All"
|
||||
options: [
|
||||
{value: "aws", label: "Amazon Web Services"},
|
||||
{value: "gcp", label: "Google Cloud Platform"},
|
||||
{value: "azure", label: "Microsoft Azure"},
|
||||
{value: "aws", label: "Amazon Web Services"},
|
||||
{value: "gcp", label: "Google Cloud Platform"},
|
||||
{value: "azure", label: "Microsoft Azure"},
|
||||
{value: "cloudflare", label: "Cloudflare"},
|
||||
{value: "github", label: "GitHub"},
|
||||
{value: "ois", label: "Open Infrastructure Services"},
|
||||
{value: "onprem", label: "On Premises", disabled: true},
|
||||
{value: "github", label: "GitHub"},
|
||||
{value: "ois", label: "Open Infrastructure Services"},
|
||||
{value: "onprem", label: "On Premises", disabled: true},
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -237,73 +237,73 @@ let FormBuilder = v1.#FormBuilder & {
|
||||
}
|
||||
|
||||
let GCPRegions = [
|
||||
{value: "africa-south1", label: "africa-south1"},
|
||||
{value: "asia-east1", label: "asia-east1"},
|
||||
{value: "asia-east2", label: "asia-east2"},
|
||||
{value: "asia-northeast1", label: "asia-northeast1"},
|
||||
{value: "asia-northeast2", label: "asia-northeast2"},
|
||||
{value: "asia-northeast3", label: "asia-northeast3"},
|
||||
{value: "asia-south1", label: "asia-south1"},
|
||||
{value: "asia-south2", label: "asia-south2"},
|
||||
{value: "asia-southeast1", label: "asia-southeast1"},
|
||||
{value: "asia-southeast2", label: "asia-southeast2"},
|
||||
{value: "australia-southeast1", label: "australia-southeast1"},
|
||||
{value: "australia-southeast2", label: "australia-southeast2"},
|
||||
{value: "europe-central2", label: "europe-central2"},
|
||||
{value: "europe-north1", label: "europe-north1"},
|
||||
{value: "europe-southwest1", label: "europe-southwest1"},
|
||||
{value: "europe-west1", label: "europe-west1"},
|
||||
{value: "europe-west10", label: "europe-west10"},
|
||||
{value: "europe-west12", label: "europe-west12"},
|
||||
{value: "europe-west2", label: "europe-west2"},
|
||||
{value: "europe-west3", label: "europe-west3"},
|
||||
{value: "europe-west4", label: "europe-west4"},
|
||||
{value: "europe-west6", label: "europe-west6"},
|
||||
{value: "europe-west8", label: "europe-west8"},
|
||||
{value: "europe-west9", label: "europe-west9"},
|
||||
{value: "me-central1", label: "me-central1"},
|
||||
{value: "me-central2", label: "me-central2"},
|
||||
{value: "me-west1", label: "me-west1"},
|
||||
{value: "africa-south1", label: "africa-south1"},
|
||||
{value: "asia-east1", label: "asia-east1"},
|
||||
{value: "asia-east2", label: "asia-east2"},
|
||||
{value: "asia-northeast1", label: "asia-northeast1"},
|
||||
{value: "asia-northeast2", label: "asia-northeast2"},
|
||||
{value: "asia-northeast3", label: "asia-northeast3"},
|
||||
{value: "asia-south1", label: "asia-south1"},
|
||||
{value: "asia-south2", label: "asia-south2"},
|
||||
{value: "asia-southeast1", label: "asia-southeast1"},
|
||||
{value: "asia-southeast2", label: "asia-southeast2"},
|
||||
{value: "australia-southeast1", label: "australia-southeast1"},
|
||||
{value: "australia-southeast2", label: "australia-southeast2"},
|
||||
{value: "europe-central2", label: "europe-central2"},
|
||||
{value: "europe-north1", label: "europe-north1"},
|
||||
{value: "europe-southwest1", label: "europe-southwest1"},
|
||||
{value: "europe-west1", label: "europe-west1"},
|
||||
{value: "europe-west10", label: "europe-west10"},
|
||||
{value: "europe-west12", label: "europe-west12"},
|
||||
{value: "europe-west2", label: "europe-west2"},
|
||||
{value: "europe-west3", label: "europe-west3"},
|
||||
{value: "europe-west4", label: "europe-west4"},
|
||||
{value: "europe-west6", label: "europe-west6"},
|
||||
{value: "europe-west8", label: "europe-west8"},
|
||||
{value: "europe-west9", label: "europe-west9"},
|
||||
{value: "me-central1", label: "me-central1"},
|
||||
{value: "me-central2", label: "me-central2"},
|
||||
{value: "me-west1", label: "me-west1"},
|
||||
{value: "northamerica-northeast1", label: "northamerica-northeast1"},
|
||||
{value: "northamerica-northeast2", label: "northamerica-northeast2"},
|
||||
{value: "southamerica-east1", label: "southamerica-east1"},
|
||||
{value: "southamerica-west1", label: "southamerica-west1"},
|
||||
{value: "us-central1", label: "us-central1"},
|
||||
{value: "us-east1", label: "us-east1"},
|
||||
{value: "us-east4", label: "us-east4"},
|
||||
{value: "us-east5", label: "us-east5"},
|
||||
{value: "us-south1", label: "us-south1"},
|
||||
{value: "us-west1", label: "us-west1"},
|
||||
{value: "us-west2", label: "us-west2"},
|
||||
{value: "us-west3", label: "us-west3"},
|
||||
{value: "us-west4", label: "us-west4"},
|
||||
{value: "southamerica-east1", label: "southamerica-east1"},
|
||||
{value: "southamerica-west1", label: "southamerica-west1"},
|
||||
{value: "us-central1", label: "us-central1"},
|
||||
{value: "us-east1", label: "us-east1"},
|
||||
{value: "us-east4", label: "us-east4"},
|
||||
{value: "us-east5", label: "us-east5"},
|
||||
{value: "us-south1", label: "us-south1"},
|
||||
{value: "us-west1", label: "us-west1"},
|
||||
{value: "us-west2", label: "us-west2"},
|
||||
{value: "us-west3", label: "us-west3"},
|
||||
{value: "us-west4", label: "us-west4"},
|
||||
]
|
||||
|
||||
let AWSRegions = [
|
||||
{value: "us-east-1", label: "N. Virginia (us-east-1)"},
|
||||
{value: "us-east-2", label: "Ohio (us-east-2)"},
|
||||
{value: "us-west-1", label: "N. California (us-west-1)"},
|
||||
{value: "us-west-2", label: "Oregon (us-west-2)"},
|
||||
{value: "us-gov-west1", label: "US GovCloud West (us-gov-west1)"},
|
||||
{value: "us-gov-east1", label: "US GovCloud East (us-gov-east1)"},
|
||||
{value: "ca-central-1", label: "Canada (ca-central-1)"},
|
||||
{value: "eu-north-1", label: "Stockholm (eu-north-1)"},
|
||||
{value: "eu-west-1", label: "Ireland (eu-west-1)"},
|
||||
{value: "eu-west-2", label: "London (eu-west-2)"},
|
||||
{value: "eu-west-3", label: "Paris (eu-west-3)"},
|
||||
{value: "eu-central-1", label: "Frankfurt (eu-central-1)"},
|
||||
{value: "eu-south-1", label: "Milan (eu-south-1)"},
|
||||
{value: "af-south-1", label: "Cape Town (af-south-1)"},
|
||||
{value: "us-east-1", label: "N. Virginia (us-east-1)"},
|
||||
{value: "us-east-2", label: "Ohio (us-east-2)"},
|
||||
{value: "us-west-1", label: "N. California (us-west-1)"},
|
||||
{value: "us-west-2", label: "Oregon (us-west-2)"},
|
||||
{value: "us-gov-west1", label: "US GovCloud West (us-gov-west1)"},
|
||||
{value: "us-gov-east1", label: "US GovCloud East (us-gov-east1)"},
|
||||
{value: "ca-central-1", label: "Canada (ca-central-1)"},
|
||||
{value: "eu-north-1", label: "Stockholm (eu-north-1)"},
|
||||
{value: "eu-west-1", label: "Ireland (eu-west-1)"},
|
||||
{value: "eu-west-2", label: "London (eu-west-2)"},
|
||||
{value: "eu-west-3", label: "Paris (eu-west-3)"},
|
||||
{value: "eu-central-1", label: "Frankfurt (eu-central-1)"},
|
||||
{value: "eu-south-1", label: "Milan (eu-south-1)"},
|
||||
{value: "af-south-1", label: "Cape Town (af-south-1)"},
|
||||
{value: "ap-northeast-1", label: "Tokyo (ap-northeast-1)"},
|
||||
{value: "ap-northeast-2", label: "Seoul (ap-northeast-2)"},
|
||||
{value: "ap-northeast-3", label: "Osaka (ap-northeast-3)"},
|
||||
{value: "ap-southeast-1", label: "Singapore (ap-southeast-1)"},
|
||||
{value: "ap-southeast-2", label: "Sydney (ap-southeast-2)"},
|
||||
{value: "ap-east-1", label: "Hong Kong (ap-east-1)"},
|
||||
{value: "ap-south-1", label: "Mumbai (ap-south-1)"},
|
||||
{value: "me-south-1", label: "Bahrain (me-south-1)"},
|
||||
{value: "sa-east-1", label: "São Paulo (sa-east-1)"},
|
||||
{value: "cn-north-1", label: "Bejing (cn-north-1)"},
|
||||
{value: "ap-east-1", label: "Hong Kong (ap-east-1)"},
|
||||
{value: "ap-south-1", label: "Mumbai (ap-south-1)"},
|
||||
{value: "me-south-1", label: "Bahrain (me-south-1)"},
|
||||
{value: "sa-east-1", label: "São Paulo (sa-east-1)"},
|
||||
{value: "cn-north-1", label: "Bejing (cn-north-1)"},
|
||||
{value: "cn-northwest-1", label: "Ningxia (cn-northwest-1)"},
|
||||
{value: "ap-southeast-3", label: "Jakarta (ap-southeast-3)"},
|
||||
]
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// Code generated by cue get go. DO NOT EDIT.
|
||||
|
||||
//cue:generate cue get go github.com/holos-run/holos/api/core/v1alpha2
|
||||
|
||||
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.
|
||||
#Label: string
|
||||
|
||||
// Kind is a kubernetes api object kind. Defined as a type for clarity and type checking.
|
||||
#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.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// # CUE
|
||||
// apiObjectMap: (#APIObjects & {apiObjects: Resources}).apiObjectMap
|
||||
#APIObjectMap: {[string]: [string]: 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].
|
||||
#APIObjects: {
|
||||
// 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: {[string]: [string]: structpb.#Struct} @go(APIObjects,map[Kind]map[Label]structpb.Struct)
|
||||
|
||||
// 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 @go(APIObjectMap)
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
// Code generated by cue get go. DO NOT EDIT.
|
||||
|
||||
//cue:generate cue get go github.com/holos-run/holos/api/core/v1alpha2
|
||||
|
||||
package v1alpha2
|
||||
|
||||
// FileContentMap represents a mapping of file names to file content.
|
||||
#FileContentMap: {[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.
|
||||
#BuildPlan: {
|
||||
kind: string & "BuildPlan" @go(Kind)
|
||||
apiVersion: string & (string | *"v1alpha2") @go(APIVersion)
|
||||
spec: #BuildPlanSpec @go(Spec)
|
||||
}
|
||||
|
||||
#BuildPlanSpec: {
|
||||
disabled?: bool @go(Disabled)
|
||||
components?: #BuildPlanComponents @go(Components)
|
||||
}
|
||||
|
||||
#BuildPlanComponents: {
|
||||
resources?: {[string]: #KubernetesObjects} @go(Resources,map[string]KubernetesObjects)
|
||||
kubernetesObjectsList?: [...#KubernetesObjects] @go(KubernetesObjectsList,[]KubernetesObjects)
|
||||
helmChartList?: [...#HelmChart] @go(HelmChartList,[]HelmChart)
|
||||
kustomizeBuildList?: [...#KustomizeBuild] @go(KustomizeBuildList,[]KustomizeBuild)
|
||||
}
|
||||
|
||||
// HolosComponent defines the fields common to all holos component kinds. Every
|
||||
// holos component kind should embed HolosComponent.
|
||||
#HolosComponent: {
|
||||
// Kind is a string value representing the resource this object represents.
|
||||
kind: string @go(Kind)
|
||||
|
||||
// APIVersion represents the versioned schema of this representation of an object.
|
||||
apiVersion: string & (string | *"v1alpha2") @go(APIVersion)
|
||||
|
||||
// Metadata represents data about the holos component such as the Name.
|
||||
metadata: #Metadata @go(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 @go(APIObjectMap)
|
||||
|
||||
// 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 @go(DeployFiles)
|
||||
|
||||
// Kustomize represents a kubectl kustomize build post-processing step.
|
||||
kustomize?: #Kustomize @go(Kustomize)
|
||||
|
||||
// Skip causes holos to take no action regarding this component.
|
||||
skip: bool & (bool | *false) @go(Skip)
|
||||
}
|
||||
|
||||
// Metadata represents data about the holos component such as the Name.
|
||||
#Metadata: {
|
||||
// Name represents the name of the holos component.
|
||||
name: string @go(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 @go(Namespace)
|
||||
}
|
||||
|
||||
// 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...
|
||||
#Kustomize: {
|
||||
// KustomizeFiles holds file contents for kustomize, e.g. patch files.
|
||||
kustomizeFiles?: #FileContentMap @go(KustomizeFiles)
|
||||
|
||||
// ResourcesFile is the file name used for api objects in kustomization.yaml
|
||||
resourcesFile?: string @go(ResourcesFile)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Code generated by cue get go. DO NOT EDIT.
|
||||
|
||||
//cue:generate cue get go github.com/holos-run/holos/api/core/v1alpha2
|
||||
|
||||
package v1alpha2
|
||||
|
||||
#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"
|
||||
@@ -0,0 +1,55 @@
|
||||
// Code generated by cue get go. DO NOT EDIT.
|
||||
|
||||
//cue:generate cue get go github.com/holos-run/holos/api/core/v1alpha2
|
||||
|
||||
// Package v1alpha2 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.
|
||||
package v1alpha2
|
||||
|
||||
import "google.golang.org/protobuf/types/known/structpb"
|
||||
|
||||
// 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.
|
||||
#Platform: {
|
||||
// Kind is a string value representing the resource this object represents.
|
||||
kind: string & "Platform" @go(Kind)
|
||||
|
||||
// APIVersion represents the versioned schema of this representation of an object.
|
||||
apiVersion: string & (string | *"v1alpha2") @go(APIVersion)
|
||||
|
||||
// Metadata represents data about the object such as the Name.
|
||||
metadata: {
|
||||
// Name represents the Platform name.
|
||||
name: string @go(Name)
|
||||
} @go(Metadata,"struct{Name string \"json:\\\"name\\\" yaml:\\\"name\\\"\"}")
|
||||
|
||||
// Spec represents the specification.
|
||||
spec: #PlatformSpec @go(Spec)
|
||||
}
|
||||
|
||||
// PlatformSpec represents the specification of a Platform. Think of a platform
|
||||
// specification as a list of platform components to apply to a list of
|
||||
// kubernetes clusters combined with the user-specified Platform Model.
|
||||
#PlatformSpec: {
|
||||
// Model represents the platform model holos gets from from the
|
||||
// PlatformService.GetPlatform rpc method and provides to CUE using a tag.
|
||||
model: structpb.#Struct @go(Model)
|
||||
|
||||
// Components represents a list of holos components to manage.
|
||||
components: [...#PlatformSpecComponent] @go(Components,[]PlatformSpecComponent)
|
||||
}
|
||||
|
||||
// PlatformSpecComponent represents a holos component to build or render.
|
||||
#PlatformSpecComponent: {
|
||||
// Path is the path of the component relative to the platform root.
|
||||
path: string @go(Path)
|
||||
|
||||
// Cluster is the cluster name to provide when rendering the component.
|
||||
cluster: string @go(Cluster)
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Code generated by cue get go. DO NOT EDIT.
|
||||
|
||||
//cue:generate cue get go github.com/holos-run/holos/api/core/v1alpha2
|
||||
|
||||
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.
|
||||
#HelmChart: {
|
||||
#HolosComponent
|
||||
kind: string & "HelmChart" @go(Kind)
|
||||
|
||||
// Chart represents a helm chart to manage.
|
||||
chart: #Chart @go(Chart)
|
||||
|
||||
// ValuesContent represents the values.yaml file holos passes to the `helm
|
||||
// template` command.
|
||||
valuesContent: string @go(ValuesContent)
|
||||
|
||||
// EnableHooks enables helm hooks when executing the `helm template` command.
|
||||
enableHooks: bool & (bool | *false) @go(EnableHooks)
|
||||
}
|
||||
|
||||
// Chart represents a helm chart.
|
||||
#Chart: {
|
||||
// Name represents the chart name.
|
||||
name: string @go(Name)
|
||||
|
||||
// Version represents the chart version.
|
||||
version: string @go(Version)
|
||||
|
||||
// Release represents the chart release when executing helm template.
|
||||
release: string @go(Release)
|
||||
|
||||
// Repository represents the repository to fetch the chart from.
|
||||
repository?: #Repository @go(Repository)
|
||||
}
|
||||
|
||||
// Repository represents a helm chart repository.
|
||||
#Repository: {
|
||||
name: string @go(Name)
|
||||
url: string @go(URL)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// Code generated by cue get go. DO NOT EDIT.
|
||||
|
||||
//cue:generate cue get go github.com/holos-run/holos/api/core/v1alpha2
|
||||
|
||||
package v1alpha2
|
||||
|
||||
#KubernetesObjectsKind: "KubernetesObjects"
|
||||
|
||||
// KubernetesObjects represents a holos component composed of kubernetes api
|
||||
// objects provided directly from CUE.
|
||||
#KubernetesObjects: {
|
||||
#HolosComponent
|
||||
kind: string & "KubernetesObjects" @go(Kind)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// Code generated by cue get go. DO NOT EDIT.
|
||||
|
||||
//cue:generate cue get go github.com/holos-run/holos/api/core/v1alpha2
|
||||
|
||||
package v1alpha2
|
||||
|
||||
// KustomizeBuild renders plain yaml files in the holos component directory
|
||||
// using kubectl kustomize build.
|
||||
#KustomizeBuild: {
|
||||
#HolosComponent
|
||||
kind: string & "KustomizeBuild" @go(Kind)
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Code generated by cue get go. DO NOT EDIT.
|
||||
|
||||
//cue:generate cue get go github.com/holos-run/holos/api/meta/v1alpha2
|
||||
|
||||
package v1alpha2
|
||||
|
||||
// TypeMeta describes an individual object in an API response or request with
|
||||
// strings representing the type of the object and its API schema version.
|
||||
// Structures that are versioned or persisted should inline TypeMeta.
|
||||
#TypeMeta: {
|
||||
// Kind is a string value representing the resource this object represents.
|
||||
kind: string @go(Kind)
|
||||
|
||||
// APIVersion defines the versioned schema of this representation of an object.
|
||||
apiVersion: string & (string | *"v1alpha2") @go(APIVersion)
|
||||
}
|
||||
|
||||
// Discriminator discriminates the kind of an api object.
|
||||
#Discriminator: _
|
||||
|
||||
// ObjectMeta represents metadata of a holos component object. The fields are a
|
||||
// copy of upstream kubernetes api machinery but are holos objects distinct from
|
||||
// kubernetes api objects.
|
||||
#ObjectMeta: {
|
||||
// Name uniquely identifies the holos component instance and must be suitable as a file name.
|
||||
name?: string @go(Name)
|
||||
|
||||
// Namespace confines a holos component to a single namespace via kustomize if set.
|
||||
namespace?: string @go(Namespace)
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
module: "user.holos.run/platform"
|
||||
language: version: "v0.9.2"
|
||||
|
||||
@@ -78,13 +78,13 @@ let FormBuilder = v1.#FormBuilder & {
|
||||
multiple: true
|
||||
selectAllOption: "Select All"
|
||||
options: [
|
||||
{value: "aws", label: "Amazon Web Services"},
|
||||
{value: "gcp", label: "Google Cloud Platform"},
|
||||
{value: "azure", label: "Microsoft Azure"},
|
||||
{value: "aws", label: "Amazon Web Services"},
|
||||
{value: "gcp", label: "Google Cloud Platform"},
|
||||
{value: "azure", label: "Microsoft Azure"},
|
||||
{value: "cloudflare", label: "Cloudflare"},
|
||||
{value: "github", label: "GitHub"},
|
||||
{value: "ois", label: "Open Infrastructure Services"},
|
||||
{value: "onprem", label: "On Premises", disabled: true},
|
||||
{value: "github", label: "GitHub"},
|
||||
{value: "ois", label: "Open Infrastructure Services"},
|
||||
{value: "onprem", label: "On Premises", disabled: true},
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -281,73 +281,73 @@ let FormBuilder = v1.#FormBuilder & {
|
||||
}
|
||||
|
||||
let GCPRegions = [
|
||||
{value: "africa-south1", label: "africa-south1"},
|
||||
{value: "asia-east1", label: "asia-east1"},
|
||||
{value: "asia-east2", label: "asia-east2"},
|
||||
{value: "asia-northeast1", label: "asia-northeast1"},
|
||||
{value: "asia-northeast2", label: "asia-northeast2"},
|
||||
{value: "asia-northeast3", label: "asia-northeast3"},
|
||||
{value: "asia-south1", label: "asia-south1"},
|
||||
{value: "asia-south2", label: "asia-south2"},
|
||||
{value: "asia-southeast1", label: "asia-southeast1"},
|
||||
{value: "asia-southeast2", label: "asia-southeast2"},
|
||||
{value: "australia-southeast1", label: "australia-southeast1"},
|
||||
{value: "australia-southeast2", label: "australia-southeast2"},
|
||||
{value: "europe-central2", label: "europe-central2"},
|
||||
{value: "europe-north1", label: "europe-north1"},
|
||||
{value: "europe-southwest1", label: "europe-southwest1"},
|
||||
{value: "europe-west1", label: "europe-west1"},
|
||||
{value: "europe-west10", label: "europe-west10"},
|
||||
{value: "europe-west12", label: "europe-west12"},
|
||||
{value: "europe-west2", label: "europe-west2"},
|
||||
{value: "europe-west3", label: "europe-west3"},
|
||||
{value: "europe-west4", label: "europe-west4"},
|
||||
{value: "europe-west6", label: "europe-west6"},
|
||||
{value: "europe-west8", label: "europe-west8"},
|
||||
{value: "europe-west9", label: "europe-west9"},
|
||||
{value: "me-central1", label: "me-central1"},
|
||||
{value: "me-central2", label: "me-central2"},
|
||||
{value: "me-west1", label: "me-west1"},
|
||||
{value: "africa-south1", label: "africa-south1"},
|
||||
{value: "asia-east1", label: "asia-east1"},
|
||||
{value: "asia-east2", label: "asia-east2"},
|
||||
{value: "asia-northeast1", label: "asia-northeast1"},
|
||||
{value: "asia-northeast2", label: "asia-northeast2"},
|
||||
{value: "asia-northeast3", label: "asia-northeast3"},
|
||||
{value: "asia-south1", label: "asia-south1"},
|
||||
{value: "asia-south2", label: "asia-south2"},
|
||||
{value: "asia-southeast1", label: "asia-southeast1"},
|
||||
{value: "asia-southeast2", label: "asia-southeast2"},
|
||||
{value: "australia-southeast1", label: "australia-southeast1"},
|
||||
{value: "australia-southeast2", label: "australia-southeast2"},
|
||||
{value: "europe-central2", label: "europe-central2"},
|
||||
{value: "europe-north1", label: "europe-north1"},
|
||||
{value: "europe-southwest1", label: "europe-southwest1"},
|
||||
{value: "europe-west1", label: "europe-west1"},
|
||||
{value: "europe-west10", label: "europe-west10"},
|
||||
{value: "europe-west12", label: "europe-west12"},
|
||||
{value: "europe-west2", label: "europe-west2"},
|
||||
{value: "europe-west3", label: "europe-west3"},
|
||||
{value: "europe-west4", label: "europe-west4"},
|
||||
{value: "europe-west6", label: "europe-west6"},
|
||||
{value: "europe-west8", label: "europe-west8"},
|
||||
{value: "europe-west9", label: "europe-west9"},
|
||||
{value: "me-central1", label: "me-central1"},
|
||||
{value: "me-central2", label: "me-central2"},
|
||||
{value: "me-west1", label: "me-west1"},
|
||||
{value: "northamerica-northeast1", label: "northamerica-northeast1"},
|
||||
{value: "northamerica-northeast2", label: "northamerica-northeast2"},
|
||||
{value: "southamerica-east1", label: "southamerica-east1"},
|
||||
{value: "southamerica-west1", label: "southamerica-west1"},
|
||||
{value: "us-central1", label: "us-central1"},
|
||||
{value: "us-east1", label: "us-east1"},
|
||||
{value: "us-east4", label: "us-east4"},
|
||||
{value: "us-east5", label: "us-east5"},
|
||||
{value: "us-south1", label: "us-south1"},
|
||||
{value: "us-west1", label: "us-west1"},
|
||||
{value: "us-west2", label: "us-west2"},
|
||||
{value: "us-west3", label: "us-west3"},
|
||||
{value: "us-west4", label: "us-west4"},
|
||||
{value: "southamerica-east1", label: "southamerica-east1"},
|
||||
{value: "southamerica-west1", label: "southamerica-west1"},
|
||||
{value: "us-central1", label: "us-central1"},
|
||||
{value: "us-east1", label: "us-east1"},
|
||||
{value: "us-east4", label: "us-east4"},
|
||||
{value: "us-east5", label: "us-east5"},
|
||||
{value: "us-south1", label: "us-south1"},
|
||||
{value: "us-west1", label: "us-west1"},
|
||||
{value: "us-west2", label: "us-west2"},
|
||||
{value: "us-west3", label: "us-west3"},
|
||||
{value: "us-west4", label: "us-west4"},
|
||||
]
|
||||
|
||||
let AWSRegions = [
|
||||
{value: "us-east-1", label: "N. Virginia (us-east-1)"},
|
||||
{value: "us-east-2", label: "Ohio (us-east-2)"},
|
||||
{value: "us-west-1", label: "N. California (us-west-1)"},
|
||||
{value: "us-west-2", label: "Oregon (us-west-2)"},
|
||||
{value: "us-gov-west1", label: "US GovCloud West (us-gov-west1)"},
|
||||
{value: "us-gov-east1", label: "US GovCloud East (us-gov-east1)"},
|
||||
{value: "ca-central-1", label: "Canada (ca-central-1)"},
|
||||
{value: "eu-north-1", label: "Stockholm (eu-north-1)"},
|
||||
{value: "eu-west-1", label: "Ireland (eu-west-1)"},
|
||||
{value: "eu-west-2", label: "London (eu-west-2)"},
|
||||
{value: "eu-west-3", label: "Paris (eu-west-3)"},
|
||||
{value: "eu-central-1", label: "Frankfurt (eu-central-1)"},
|
||||
{value: "eu-south-1", label: "Milan (eu-south-1)"},
|
||||
{value: "af-south-1", label: "Cape Town (af-south-1)"},
|
||||
{value: "us-east-1", label: "N. Virginia (us-east-1)"},
|
||||
{value: "us-east-2", label: "Ohio (us-east-2)"},
|
||||
{value: "us-west-1", label: "N. California (us-west-1)"},
|
||||
{value: "us-west-2", label: "Oregon (us-west-2)"},
|
||||
{value: "us-gov-west1", label: "US GovCloud West (us-gov-west1)"},
|
||||
{value: "us-gov-east1", label: "US GovCloud East (us-gov-east1)"},
|
||||
{value: "ca-central-1", label: "Canada (ca-central-1)"},
|
||||
{value: "eu-north-1", label: "Stockholm (eu-north-1)"},
|
||||
{value: "eu-west-1", label: "Ireland (eu-west-1)"},
|
||||
{value: "eu-west-2", label: "London (eu-west-2)"},
|
||||
{value: "eu-west-3", label: "Paris (eu-west-3)"},
|
||||
{value: "eu-central-1", label: "Frankfurt (eu-central-1)"},
|
||||
{value: "eu-south-1", label: "Milan (eu-south-1)"},
|
||||
{value: "af-south-1", label: "Cape Town (af-south-1)"},
|
||||
{value: "ap-northeast-1", label: "Tokyo (ap-northeast-1)"},
|
||||
{value: "ap-northeast-2", label: "Seoul (ap-northeast-2)"},
|
||||
{value: "ap-northeast-3", label: "Osaka (ap-northeast-3)"},
|
||||
{value: "ap-southeast-1", label: "Singapore (ap-southeast-1)"},
|
||||
{value: "ap-southeast-2", label: "Sydney (ap-southeast-2)"},
|
||||
{value: "ap-east-1", label: "Hong Kong (ap-east-1)"},
|
||||
{value: "ap-south-1", label: "Mumbai (ap-south-1)"},
|
||||
{value: "me-south-1", label: "Bahrain (me-south-1)"},
|
||||
{value: "sa-east-1", label: "São Paulo (sa-east-1)"},
|
||||
{value: "cn-north-1", label: "Bejing (cn-north-1)"},
|
||||
{value: "ap-east-1", label: "Hong Kong (ap-east-1)"},
|
||||
{value: "ap-south-1", label: "Mumbai (ap-south-1)"},
|
||||
{value: "me-south-1", label: "Bahrain (me-south-1)"},
|
||||
{value: "sa-east-1", label: "São Paulo (sa-east-1)"},
|
||||
{value: "cn-north-1", label: "Bejing (cn-north-1)"},
|
||||
{value: "cn-northwest-1", label: "Ningxia (cn-northwest-1)"},
|
||||
{value: "ap-southeast-3", label: "Jakarta (ap-southeast-3)"},
|
||||
]
|
||||
|
||||
@@ -2,7 +2,7 @@ package holos
|
||||
|
||||
import (
|
||||
"encoding/yaml"
|
||||
v1 "github.com/holos-run/holos/api/v1alpha1"
|
||||
core "github.com/holos-run/holos/api/core/v1alpha2"
|
||||
|
||||
kc "sigs.k8s.io/kustomize/api/types"
|
||||
|
||||
@@ -103,13 +103,13 @@ import (
|
||||
|
||||
Values: {...}
|
||||
|
||||
Chart: v1.#HelmChart & {
|
||||
metadata: name: string | *Name
|
||||
namespace: string | *Namespace
|
||||
chart: name: string | *Name
|
||||
chart: release: chart.name
|
||||
chart: version: string | *Version
|
||||
chart: repository: Repo
|
||||
Chart: core.#HelmChart & {
|
||||
metadata: name: string | *Name
|
||||
metadata: namespace: string | *Namespace
|
||||
chart: name: string | *Name
|
||||
chart: release: chart.name
|
||||
chart: version: string | *Version
|
||||
chart: repository: Repo
|
||||
|
||||
// Render the values to yaml for holos to provide to helm.
|
||||
valuesContent: yaml.Marshal(Values)
|
||||
@@ -119,15 +119,15 @@ import (
|
||||
// resourcesFile represents the file helm output is written two and
|
||||
// kustomize reads from. Typically "resources.yaml" but referenced as a
|
||||
// constant to ensure the holos cli uses the same file.
|
||||
resourcesFile: v1.#ResourcesFile
|
||||
kustomize: resourcesFile: core.#ResourcesFile
|
||||
// kustomizeFiles represents the files in a kustomize directory tree.
|
||||
kustomizeFiles: v1.#FileContentMap
|
||||
kustomize: kustomizeFiles: core.#FileContentMap
|
||||
for FileName, Object in KustomizeFiles {
|
||||
kustomizeFiles: "\(FileName)": yaml.Marshal(Object)
|
||||
kustomize: kustomizeFiles: "\(FileName)": yaml.Marshal(Object)
|
||||
}
|
||||
}
|
||||
|
||||
apiObjectMap: (v1.#APIObjects & {apiObjects: Resources}).apiObjectMap
|
||||
apiObjectMap: (#APIObjects & {apiObjects: Resources}).apiObjectMap
|
||||
}
|
||||
|
||||
// EnableKustomizePostProcessor processes helm output with kustomize if true.
|
||||
@@ -147,7 +147,7 @@ import (
|
||||
"kustomization.yaml": kc.#Kustomization & {
|
||||
apiVersion: "kustomize.config.k8s.io/v1beta1"
|
||||
kind: "Kustomization"
|
||||
resources: [v1.#ResourcesFile, for FileName, _ in KustomizeResources {FileName}]
|
||||
resources: [core.#ResourcesFile, for FileName, _ in KustomizeResources {FileName}]
|
||||
patches: [for x in KustomizePatches {x}]
|
||||
}
|
||||
}
|
||||
@@ -160,7 +160,8 @@ import (
|
||||
|
||||
// output represents the build plan provided to the holos cli.
|
||||
Output: #BuildPlan & {
|
||||
metadata: name: Name
|
||||
_Name: Name
|
||||
_Namespace: Namespace
|
||||
spec: components: helmChartList: [Chart]
|
||||
}
|
||||
}
|
||||
@@ -170,13 +171,13 @@ import (
|
||||
// Name represents the holos component name
|
||||
Name: string
|
||||
|
||||
Kustomization: v1.#KustomizeBuild & {
|
||||
Kustomization: core.#KustomizeBuild & {
|
||||
metadata: name: string | *Name
|
||||
}
|
||||
|
||||
// output represents the build plan provided to the holos cli.
|
||||
Output: #BuildPlan & {
|
||||
metadata: name: Name
|
||||
_Name: Name
|
||||
spec: components: kustomizeBuildList: [Kustomization]
|
||||
}
|
||||
}
|
||||
@@ -191,19 +192,31 @@ import (
|
||||
|
||||
// output represents the build plan provided to the holos cli.
|
||||
Output: #BuildPlan & {
|
||||
metadata: name: Name
|
||||
_Name: Name
|
||||
_Namespace: Namespace
|
||||
// resources is a map unlike other build plans which use a list.
|
||||
spec: components: resources: "\(Name)": {
|
||||
metadata: name: Name
|
||||
apiObjectMap: (v1.#APIObjects & {apiObjects: Resources}).apiObjectMap
|
||||
metadata: name: Name
|
||||
metadata: namespace: Namespace
|
||||
apiObjectMap: (#APIObjects & {apiObjects: Resources}).apiObjectMap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#BuildPlan: v1.#BuildPlan & {
|
||||
metadata: name: string
|
||||
// Render the ArgoCD Application
|
||||
spec: deployFiles: (#Argo & {ComponentName: metadata.name}).deployFiles
|
||||
#BuildPlan: core.#BuildPlan & {
|
||||
_Name: string
|
||||
_Namespace?: string
|
||||
let NAME = "gitops/\(_Name)"
|
||||
|
||||
// Render the ArgoCD Application for GitOps.
|
||||
spec: components: resources: (NAME): {
|
||||
metadata: name: NAME
|
||||
if _Namespace != _|_ {
|
||||
metadata: namespace: _Namespace
|
||||
}
|
||||
|
||||
deployFiles: (#Argo & {ComponentName: _Name}).deployFiles
|
||||
}
|
||||
}
|
||||
|
||||
// #ArgoApplication represents an argocd Application resource for each
|
||||
@@ -228,3 +241,31 @@ import (
|
||||
// deployFiles represents the output files to write along side the component.
|
||||
deployFiles: "clusters/\(_ClusterName)/gitops/\(ComponentName).application.gen.yaml": yaml.Marshal(Application)
|
||||
}
|
||||
|
||||
// #APIObjects defines the output format for kubernetes api objects. The holos
|
||||
// cli expects the yaml representation of each api object in the apiObjectMap
|
||||
// field.
|
||||
#APIObjects: core.#APIObjects & {
|
||||
// apiObjects represents the un-marshalled form of each kubernetes api object
|
||||
// managed by a holos component.
|
||||
apiObjects: {
|
||||
[Kind=string]: {
|
||||
[string]: {
|
||||
kind: Kind
|
||||
...
|
||||
}
|
||||
}
|
||||
ConfigMap: [string]: corev1.#ConfigMap & {apiVersion: "v1"}
|
||||
}
|
||||
|
||||
// apiObjectMap holds the marshalled representation of apiObjects
|
||||
apiObjectMap: {
|
||||
for kind, v in apiObjects {
|
||||
"\(kind)": {
|
||||
for name, obj in v {
|
||||
"\(name)": yaml.Marshal(obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@ let Objects = {
|
||||
// Work with a struct of listeners instead of a list.
|
||||
_listeners: (#WildcardListener & {Name: "admin", Selector: _Selector.GrantSubdomainAdmin, Cluster: true}).Output
|
||||
_listeners: (#WildcardListener & {Name: "login", Selector: _Selector.GrantSubdomainLogin, Cluster: false}).Output
|
||||
_listeners: (#WildcardListener & {Name: "app", Selector: _Selector.GrantSubdomainApp, Cluster: false}).Output
|
||||
_listeners: (#WildcardListener & {Name: "app", Selector: _Selector.GrantSubdomainApp, Cluster: true}).Output
|
||||
_listeners: (#WildcardListener & {Name: "app", Selector: _Selector.GrantSubdomainApp, Cluster: false}).Output
|
||||
_listeners: (#WildcardListener & {Name: "app", Selector: _Selector.GrantSubdomainApp, Cluster: true}).Output
|
||||
listeners: [for x in _listeners {x}]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,73 +385,73 @@ let FormBuilder = v1.#FormBuilder & {
|
||||
}
|
||||
|
||||
let GCPRegions = [
|
||||
{value: "africa-south1", label: "africa-south1"},
|
||||
{value: "asia-east1", label: "asia-east1"},
|
||||
{value: "asia-east2", label: "asia-east2"},
|
||||
{value: "asia-northeast1", label: "asia-northeast1"},
|
||||
{value: "asia-northeast2", label: "asia-northeast2"},
|
||||
{value: "asia-northeast3", label: "asia-northeast3"},
|
||||
{value: "asia-south1", label: "asia-south1"},
|
||||
{value: "asia-south2", label: "asia-south2"},
|
||||
{value: "asia-southeast1", label: "asia-southeast1"},
|
||||
{value: "asia-southeast2", label: "asia-southeast2"},
|
||||
{value: "australia-southeast1", label: "australia-southeast1"},
|
||||
{value: "australia-southeast2", label: "australia-southeast2"},
|
||||
{value: "europe-central2", label: "europe-central2"},
|
||||
{value: "europe-north1", label: "europe-north1"},
|
||||
{value: "europe-southwest1", label: "europe-southwest1"},
|
||||
{value: "europe-west1", label: "europe-west1"},
|
||||
{value: "europe-west10", label: "europe-west10"},
|
||||
{value: "europe-west12", label: "europe-west12"},
|
||||
{value: "europe-west2", label: "europe-west2"},
|
||||
{value: "europe-west3", label: "europe-west3"},
|
||||
{value: "europe-west4", label: "europe-west4"},
|
||||
{value: "europe-west6", label: "europe-west6"},
|
||||
{value: "europe-west8", label: "europe-west8"},
|
||||
{value: "europe-west9", label: "europe-west9"},
|
||||
{value: "me-central1", label: "me-central1"},
|
||||
{value: "me-central2", label: "me-central2"},
|
||||
{value: "me-west1", label: "me-west1"},
|
||||
{value: "africa-south1", label: "africa-south1"},
|
||||
{value: "asia-east1", label: "asia-east1"},
|
||||
{value: "asia-east2", label: "asia-east2"},
|
||||
{value: "asia-northeast1", label: "asia-northeast1"},
|
||||
{value: "asia-northeast2", label: "asia-northeast2"},
|
||||
{value: "asia-northeast3", label: "asia-northeast3"},
|
||||
{value: "asia-south1", label: "asia-south1"},
|
||||
{value: "asia-south2", label: "asia-south2"},
|
||||
{value: "asia-southeast1", label: "asia-southeast1"},
|
||||
{value: "asia-southeast2", label: "asia-southeast2"},
|
||||
{value: "australia-southeast1", label: "australia-southeast1"},
|
||||
{value: "australia-southeast2", label: "australia-southeast2"},
|
||||
{value: "europe-central2", label: "europe-central2"},
|
||||
{value: "europe-north1", label: "europe-north1"},
|
||||
{value: "europe-southwest1", label: "europe-southwest1"},
|
||||
{value: "europe-west1", label: "europe-west1"},
|
||||
{value: "europe-west10", label: "europe-west10"},
|
||||
{value: "europe-west12", label: "europe-west12"},
|
||||
{value: "europe-west2", label: "europe-west2"},
|
||||
{value: "europe-west3", label: "europe-west3"},
|
||||
{value: "europe-west4", label: "europe-west4"},
|
||||
{value: "europe-west6", label: "europe-west6"},
|
||||
{value: "europe-west8", label: "europe-west8"},
|
||||
{value: "europe-west9", label: "europe-west9"},
|
||||
{value: "me-central1", label: "me-central1"},
|
||||
{value: "me-central2", label: "me-central2"},
|
||||
{value: "me-west1", label: "me-west1"},
|
||||
{value: "northamerica-northeast1", label: "northamerica-northeast1"},
|
||||
{value: "northamerica-northeast2", label: "northamerica-northeast2"},
|
||||
{value: "southamerica-east1", label: "southamerica-east1"},
|
||||
{value: "southamerica-west1", label: "southamerica-west1"},
|
||||
{value: "us-central1", label: "us-central1"},
|
||||
{value: "us-east1", label: "us-east1"},
|
||||
{value: "us-east4", label: "us-east4"},
|
||||
{value: "us-east5", label: "us-east5"},
|
||||
{value: "us-south1", label: "us-south1"},
|
||||
{value: "us-west1", label: "us-west1"},
|
||||
{value: "us-west2", label: "us-west2"},
|
||||
{value: "us-west3", label: "us-west3"},
|
||||
{value: "us-west4", label: "us-west4"},
|
||||
{value: "southamerica-east1", label: "southamerica-east1"},
|
||||
{value: "southamerica-west1", label: "southamerica-west1"},
|
||||
{value: "us-central1", label: "us-central1"},
|
||||
{value: "us-east1", label: "us-east1"},
|
||||
{value: "us-east4", label: "us-east4"},
|
||||
{value: "us-east5", label: "us-east5"},
|
||||
{value: "us-south1", label: "us-south1"},
|
||||
{value: "us-west1", label: "us-west1"},
|
||||
{value: "us-west2", label: "us-west2"},
|
||||
{value: "us-west3", label: "us-west3"},
|
||||
{value: "us-west4", label: "us-west4"},
|
||||
]
|
||||
|
||||
let AWSRegions = [
|
||||
{value: "us-east-1", label: "N. Virginia (us-east-1)"},
|
||||
{value: "us-east-2", label: "Ohio (us-east-2)"},
|
||||
{value: "us-west-1", label: "N. California (us-west-1)"},
|
||||
{value: "us-west-2", label: "Oregon (us-west-2)"},
|
||||
{value: "us-gov-west1", label: "US GovCloud West (us-gov-west1)"},
|
||||
{value: "us-gov-east1", label: "US GovCloud East (us-gov-east1)"},
|
||||
{value: "ca-central-1", label: "Canada (ca-central-1)"},
|
||||
{value: "eu-north-1", label: "Stockholm (eu-north-1)"},
|
||||
{value: "eu-west-1", label: "Ireland (eu-west-1)"},
|
||||
{value: "eu-west-2", label: "London (eu-west-2)"},
|
||||
{value: "eu-west-3", label: "Paris (eu-west-3)"},
|
||||
{value: "eu-central-1", label: "Frankfurt (eu-central-1)"},
|
||||
{value: "eu-south-1", label: "Milan (eu-south-1)"},
|
||||
{value: "af-south-1", label: "Cape Town (af-south-1)"},
|
||||
{value: "us-east-1", label: "N. Virginia (us-east-1)"},
|
||||
{value: "us-east-2", label: "Ohio (us-east-2)"},
|
||||
{value: "us-west-1", label: "N. California (us-west-1)"},
|
||||
{value: "us-west-2", label: "Oregon (us-west-2)"},
|
||||
{value: "us-gov-west1", label: "US GovCloud West (us-gov-west1)"},
|
||||
{value: "us-gov-east1", label: "US GovCloud East (us-gov-east1)"},
|
||||
{value: "ca-central-1", label: "Canada (ca-central-1)"},
|
||||
{value: "eu-north-1", label: "Stockholm (eu-north-1)"},
|
||||
{value: "eu-west-1", label: "Ireland (eu-west-1)"},
|
||||
{value: "eu-west-2", label: "London (eu-west-2)"},
|
||||
{value: "eu-west-3", label: "Paris (eu-west-3)"},
|
||||
{value: "eu-central-1", label: "Frankfurt (eu-central-1)"},
|
||||
{value: "eu-south-1", label: "Milan (eu-south-1)"},
|
||||
{value: "af-south-1", label: "Cape Town (af-south-1)"},
|
||||
{value: "ap-northeast-1", label: "Tokyo (ap-northeast-1)"},
|
||||
{value: "ap-northeast-2", label: "Seoul (ap-northeast-2)"},
|
||||
{value: "ap-northeast-3", label: "Osaka (ap-northeast-3)"},
|
||||
{value: "ap-southeast-1", label: "Singapore (ap-southeast-1)"},
|
||||
{value: "ap-southeast-2", label: "Sydney (ap-southeast-2)"},
|
||||
{value: "ap-east-1", label: "Hong Kong (ap-east-1)"},
|
||||
{value: "ap-south-1", label: "Mumbai (ap-south-1)"},
|
||||
{value: "me-south-1", label: "Bahrain (me-south-1)"},
|
||||
{value: "sa-east-1", label: "São Paulo (sa-east-1)"},
|
||||
{value: "cn-north-1", label: "Bejing (cn-north-1)"},
|
||||
{value: "ap-east-1", label: "Hong Kong (ap-east-1)"},
|
||||
{value: "ap-south-1", label: "Mumbai (ap-south-1)"},
|
||||
{value: "me-south-1", label: "Bahrain (me-south-1)"},
|
||||
{value: "sa-east-1", label: "São Paulo (sa-east-1)"},
|
||||
{value: "cn-north-1", label: "Bejing (cn-north-1)"},
|
||||
{value: "cn-northwest-1", label: "Ningxia (cn-northwest-1)"},
|
||||
{value: "ap-southeast-3", label: "Jakarta (ap-southeast-3)"},
|
||||
]
|
||||
|
||||
@@ -2,7 +2,7 @@ package holos
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
v1 "github.com/holos-run/holos/api/v1alpha1"
|
||||
core "github.com/holos-run/holos/api/core/v1alpha2"
|
||||
dto "github.com/holos-run/holos/service/gen/holos/object/v1alpha1:object"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
certv1 "cert-manager.io/certificate/v1"
|
||||
@@ -50,12 +50,12 @@ _Platform: #Platform & {
|
||||
Name: string | *"holos"
|
||||
|
||||
// Components represent the platform components to render.
|
||||
Components: [string]: v1.#PlatformSpecComponent
|
||||
Components: [string]: core.#PlatformSpecComponent
|
||||
|
||||
// Model represents the platform model from the web app form.
|
||||
Model: dto.#PlatformConfig.platform_model
|
||||
|
||||
Output: v1.#Platform & {
|
||||
Output: core.#Platform & {
|
||||
metadata: name: Name
|
||||
|
||||
spec: {
|
||||
|
||||
52
internal/render/component.go
Normal file
52
internal/render/component.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package render
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/holos-run/holos"
|
||||
"github.com/holos-run/holos/api/core/v1alpha2"
|
||||
"github.com/holos-run/holos/internal/errors"
|
||||
"github.com/holos-run/holos/internal/server/middleware/logger"
|
||||
"github.com/holos-run/holos/internal/util"
|
||||
)
|
||||
|
||||
const KubernetesObjectsKind = "KubernetesObjects"
|
||||
|
||||
// KubernetesObjects represents CUE output which directly provides Kubernetes api objects to holos.
|
||||
type KubernetesObjects struct {
|
||||
Component v1alpha2.KubernetesObjects `json:"component" yaml:"component"`
|
||||
}
|
||||
|
||||
// Render produces kubernetes api objects from the APIObjectMap of the holos component.
|
||||
func (o *KubernetesObjects) Render(ctx context.Context, path holos.InstancePath) (*Result, error) {
|
||||
result := NewResult(o.Component.HolosComponent)
|
||||
result.addObjectMap(ctx, o.Component.APIObjectMap)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// KustomizeBuild renders plain yaml files in the holos component directory
|
||||
// using kubectl kustomize build.
|
||||
type KustomizeBuild struct {
|
||||
Component v1alpha2.KustomizeBuild `json:"component" yaml:"component"`
|
||||
}
|
||||
|
||||
// Render produces a Result by executing kubectl kustomize on the holos
|
||||
// component path. Useful for processing raw yaml files.
|
||||
func (kb *KustomizeBuild) Render(ctx context.Context, path holos.InstancePath) (*Result, error) {
|
||||
if kb == nil {
|
||||
return nil, nil
|
||||
}
|
||||
log := logger.FromContext(ctx)
|
||||
result := NewResult(kb.Component.HolosComponent)
|
||||
// Run kustomize.
|
||||
kOut, err := util.RunCmd(ctx, "kubectl", "kustomize", string(path))
|
||||
if err != nil {
|
||||
log.ErrorContext(ctx, kOut.Stderr.String())
|
||||
return nil, errors.Wrap(err)
|
||||
}
|
||||
// Replace the accumulated output
|
||||
result.accumulatedOutput = kOut.Stdout.String()
|
||||
// Add CUE based api objects.
|
||||
result.addObjectMap(ctx, kb.Component.APIObjectMap)
|
||||
return result, nil
|
||||
}
|
||||
171
internal/render/helm.go
Normal file
171
internal/render/helm.go
Normal file
@@ -0,0 +1,171 @@
|
||||
package render
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/holos-run/holos"
|
||||
"github.com/holos-run/holos/api/core/v1alpha2"
|
||||
core "github.com/holos-run/holos/api/core/v1alpha2"
|
||||
"github.com/holos-run/holos/internal/errors"
|
||||
"github.com/holos-run/holos/internal/server/middleware/logger"
|
||||
"github.com/holos-run/holos/internal/util"
|
||||
)
|
||||
|
||||
type HelmChart struct {
|
||||
Component core.HelmChart `json:"component"`
|
||||
}
|
||||
|
||||
func (hc *HelmChart) Render(ctx context.Context, path holos.InstancePath) (*Result, error) {
|
||||
if hc == nil {
|
||||
return nil, nil
|
||||
}
|
||||
result := NewResult(hc.Component.HolosComponent)
|
||||
if err := hc.helm(ctx, result, path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.addObjectMap(ctx, hc.Component.APIObjectMap)
|
||||
if err := result.kustomize(ctx); err != nil {
|
||||
return nil, errors.Wrap(fmt.Errorf("could not kustomize: %w", err))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// runHelm provides the values produced by CUE to helm template and returns
|
||||
// the rendered kubernetes api objects in the result.
|
||||
func (hc *HelmChart) helm(ctx context.Context, r *Result, path holos.InstancePath) error {
|
||||
log := logger.FromContext(ctx).With("chart", hc.Component.Chart.Name)
|
||||
if hc.Component.Chart.Name == "" {
|
||||
log.WarnContext(ctx, "skipping helm: no chart name specified, use a different component type")
|
||||
return nil
|
||||
}
|
||||
|
||||
cachedChartPath := filepath.Join(string(path), v1alpha2.ChartDir, filepath.Base(hc.Component.Chart.Name))
|
||||
if isNotExist(cachedChartPath) {
|
||||
// Add repositories
|
||||
repo := hc.Component.Chart.Repository
|
||||
if repo.URL != "" {
|
||||
out, err := util.RunCmd(ctx, "helm", "repo", "add", repo.Name, repo.URL)
|
||||
if err != nil {
|
||||
log.ErrorContext(ctx, "could not run helm", "stderr", out.Stderr.String(), "stdout", out.Stdout.String())
|
||||
return errors.Wrap(fmt.Errorf("could not run helm repo add: %w", err))
|
||||
}
|
||||
// Update repository
|
||||
out, err = util.RunCmd(ctx, "helm", "repo", "update", repo.Name)
|
||||
if err != nil {
|
||||
log.ErrorContext(ctx, "could not run helm", "stderr", out.Stderr.String(), "stdout", out.Stdout.String())
|
||||
return errors.Wrap(fmt.Errorf("could not run helm repo update: %w", err))
|
||||
}
|
||||
} else {
|
||||
log.DebugContext(ctx, "no chart repository url proceeding assuming oci chart")
|
||||
}
|
||||
|
||||
// Cache the chart
|
||||
if err := cacheChart(ctx, path, v1alpha2.ChartDir, hc.Component.Chart); err != nil {
|
||||
return fmt.Errorf("could not cache chart: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Write values file
|
||||
tempDir, err := os.MkdirTemp("", "holos")
|
||||
if err != nil {
|
||||
return errors.Wrap(fmt.Errorf("could not make temp dir: %w", err))
|
||||
}
|
||||
defer util.Remove(ctx, tempDir)
|
||||
|
||||
valuesPath := filepath.Join(tempDir, "values.yaml")
|
||||
if err := os.WriteFile(valuesPath, []byte(hc.Component.ValuesContent), 0644); err != nil {
|
||||
return errors.Wrap(fmt.Errorf("could not write values: %w", err))
|
||||
}
|
||||
log.DebugContext(ctx, "helm: wrote values", "path", valuesPath, "bytes", len(hc.Component.ValuesContent))
|
||||
|
||||
// Run charts
|
||||
chart := hc.Component.Chart
|
||||
args := []string{"template"}
|
||||
if !hc.Component.EnableHooks {
|
||||
args = append(args, "--no-hooks")
|
||||
}
|
||||
namespace := hc.Component.Metadata.Namespace
|
||||
args = append(args, "--include-crds", "--values", valuesPath, "--namespace", namespace, "--kubeconfig", "/dev/null", "--version", chart.Version, chart.Release, cachedChartPath)
|
||||
helmOut, err := util.RunCmd(ctx, "helm", args...)
|
||||
if err != nil {
|
||||
stderr := helmOut.Stderr.String()
|
||||
lines := strings.Split(stderr, "\n")
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, "Error:") {
|
||||
err = fmt.Errorf("%s: %w", line, err)
|
||||
}
|
||||
}
|
||||
return errors.Wrap(fmt.Errorf("could not run helm template: %w", err))
|
||||
}
|
||||
|
||||
r.accumulatedOutput = helmOut.Stdout.String()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// cacheChart stores a cached copy of Chart in the chart subdirectory of path.
|
||||
//
|
||||
// It is assumed that the only method responsible for writing to chartDir is
|
||||
// cacheChart itself.
|
||||
//
|
||||
// This relies on the atomicity of moving temporary directories into place on
|
||||
// the same filesystem via os.Rename. If a syscall.EEXIST error occurs during
|
||||
// renaming, it indicates that the cached chart already exists, which is an
|
||||
// expected scenario when this function is called concurrently.
|
||||
func cacheChart(ctx context.Context, path holos.InstancePath, chartDir string, chart v1alpha2.Chart) error {
|
||||
log := logger.FromContext(ctx)
|
||||
|
||||
cacheTemp, err := os.MkdirTemp(string(path), chartDir)
|
||||
if err != nil {
|
||||
return errors.Wrap(fmt.Errorf("could not make temp dir: %w", err))
|
||||
}
|
||||
defer util.Remove(ctx, cacheTemp)
|
||||
|
||||
chartName := chart.Name
|
||||
if chart.Repository.Name != "" {
|
||||
chartName = fmt.Sprintf("%s/%s", chart.Repository.Name, chart.Name)
|
||||
}
|
||||
helmOut, err := util.RunCmd(ctx, "helm", "pull", "--destination", cacheTemp, "--untar=true", "--version", chart.Version, chartName)
|
||||
if err != nil {
|
||||
return errors.Wrap(fmt.Errorf("could not run helm pull: %w", err))
|
||||
}
|
||||
log.Debug("helm pull", "stdout", helmOut.Stdout, "stderr", helmOut.Stderr)
|
||||
|
||||
cachePath := filepath.Join(string(path), chartDir)
|
||||
|
||||
if err := os.MkdirAll(cachePath, 0777); err != nil {
|
||||
return errors.Wrap(fmt.Errorf("could not mkdir: %w", err))
|
||||
}
|
||||
|
||||
items, err := os.ReadDir(cacheTemp)
|
||||
if err != nil {
|
||||
return errors.Wrap(fmt.Errorf("could not read directory: %w", err))
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
src := filepath.Join(cacheTemp, item.Name())
|
||||
dst := filepath.Join(cachePath, item.Name())
|
||||
log.DebugContext(ctx, "rename", "src", src, "dst", dst)
|
||||
if err := os.Rename(src, dst); err != nil {
|
||||
var linkErr *os.LinkError
|
||||
if errors.As(err, &linkErr) && errors.Is(linkErr.Err, syscall.EEXIST) {
|
||||
log.DebugContext(ctx, "cache already exists", "chart", chart.Name, "chart_version", chart.Version, "path", cachePath)
|
||||
} else {
|
||||
return errors.Wrap(fmt.Errorf("could not rename: %w", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.InfoContext(ctx, "cached", "chart", chart.Name, "chart_version", chart.Version, "path", cachePath)
|
||||
|
||||
return nil
|
||||
}
|
||||
func isNotExist(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
return os.IsNotExist(err)
|
||||
}
|
||||
@@ -6,14 +6,14 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/holos-run/holos/api/v1alpha1"
|
||||
core "github.com/holos-run/holos/api/core/v1alpha2"
|
||||
"github.com/holos-run/holos/internal/errors"
|
||||
"github.com/holos-run/holos/internal/server/middleware/logger"
|
||||
"github.com/holos-run/holos/internal/util"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
func Platform(ctx context.Context, concurrency int, pf *v1alpha1.Platform, stderr io.Writer) error {
|
||||
func Platform(ctx context.Context, concurrency int, pf *core.Platform, stderr io.Writer) error {
|
||||
total := len(pf.Spec.Components)
|
||||
|
||||
g, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
230
internal/render/result.go
Normal file
230
internal/render/result.go
Normal file
@@ -0,0 +1,230 @@
|
||||
package render
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/holos-run/holos/api/core/v1alpha2"
|
||||
"github.com/holos-run/holos/internal/errors"
|
||||
"github.com/holos-run/holos/internal/server/middleware/logger"
|
||||
"github.com/holos-run/holos/internal/util"
|
||||
)
|
||||
|
||||
// NewResult returns a new Result with the given holos component.
|
||||
func NewResult(component v1alpha2.HolosComponent) *Result {
|
||||
return &Result{
|
||||
Kind: "Result",
|
||||
APIVersion: "v1alpha2",
|
||||
Component: component,
|
||||
accumulatedOutput: "",
|
||||
}
|
||||
}
|
||||
|
||||
// Result is the build result for display or writing. Holos components Render
|
||||
// the Result as a data pipeline.
|
||||
type Result struct {
|
||||
// Kind is a string value representing the resource this object represents.
|
||||
Kind string `json:"kind" yaml:"kind" cue:"string | *\"Result\""`
|
||||
// APIVersion represents the versioned schema of this representation of an object.
|
||||
APIVersion string `json:"apiVersion" yaml:"apiVersion" cue:"string | *\"v1alpha2\""`
|
||||
|
||||
// Component represents the common fields of all holos component kinds.
|
||||
Component v1alpha2.HolosComponent
|
||||
|
||||
// accumulatedOutput accumulates rendered api objects.
|
||||
accumulatedOutput string
|
||||
}
|
||||
|
||||
func (r *Result) GetAPIVersion() string {
|
||||
if r == nil {
|
||||
return ""
|
||||
}
|
||||
return r.APIVersion
|
||||
}
|
||||
|
||||
func (r *Result) GetKind() string {
|
||||
if r == nil {
|
||||
return ""
|
||||
}
|
||||
return r.Kind
|
||||
}
|
||||
|
||||
// Continue returns true if the result should be skipped over.
|
||||
func (r *Result) Continue() bool {
|
||||
// Skip over a nil result
|
||||
if r == nil {
|
||||
return true
|
||||
}
|
||||
return r.Component.Skip
|
||||
}
|
||||
|
||||
// Name returns the name of the component from the Metadata field.
|
||||
func (r *Result) Name() string {
|
||||
if r == nil {
|
||||
return ""
|
||||
}
|
||||
return r.Component.Metadata.Name
|
||||
}
|
||||
|
||||
// Filename returns the filename representing the rendered api objects of the Result.
|
||||
func (r *Result) Filename(writeTo string, cluster string) string {
|
||||
name := r.Name()
|
||||
return filepath.Join(writeTo, "clusters", cluster, "components", name, name+".gen.yaml")
|
||||
}
|
||||
|
||||
// KustomizationFilename returns the Flux Kustomization file path.
|
||||
//
|
||||
// Deprecated: Use DeployFiles instead.
|
||||
func (r *Result) KustomizationFilename(writeTo string, cluster string) string {
|
||||
return filepath.Join(writeTo, "clusters", cluster, "holos", "components", r.Name()+"-kustomization.gen.yaml")
|
||||
}
|
||||
|
||||
// AccumulatedOutput returns the accumulated rendered output.
|
||||
func (r *Result) AccumulatedOutput() string {
|
||||
if r == nil {
|
||||
return ""
|
||||
}
|
||||
return r.accumulatedOutput
|
||||
}
|
||||
|
||||
// addObjectMap renders the provided APIObjectMap into the accumulated output.
|
||||
func (r *Result) addObjectMap(ctx context.Context, objectMap v1alpha2.APIObjectMap) {
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
log := logger.FromContext(ctx)
|
||||
b := []byte(r.AccumulatedOutput())
|
||||
kinds := make([]v1alpha2.Kind, 0, len(objectMap))
|
||||
// Sort the keys
|
||||
for kind := range objectMap {
|
||||
kinds = append(kinds, kind)
|
||||
}
|
||||
slices.Sort(kinds)
|
||||
|
||||
for _, kind := range kinds {
|
||||
v := objectMap[kind]
|
||||
// Sort the keys
|
||||
names := make([]v1alpha2.Label, 0, len(v))
|
||||
for name := range v {
|
||||
names = append(names, name)
|
||||
}
|
||||
slices.Sort(names)
|
||||
|
||||
for _, name := range names {
|
||||
yamlString := v[name]
|
||||
log.Debug(fmt.Sprintf("%s/%s", kind, name), "kind", kind, "name", name)
|
||||
b = util.EnsureNewline(b)
|
||||
header := fmt.Sprintf("---\n# Source: CUE apiObjects.%s.%s\n", kind, name)
|
||||
b = append(b, []byte(header+yamlString)...)
|
||||
b = util.EnsureNewline(b)
|
||||
}
|
||||
}
|
||||
r.accumulatedOutput = string(b)
|
||||
}
|
||||
|
||||
// kustomize replaces the accumulated output with the output of kustomize build
|
||||
func (r *Result) kustomize(ctx context.Context) error {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
log := logger.FromContext(ctx)
|
||||
if r.Component.Kustomize.ResourcesFile == "" {
|
||||
log.DebugContext(ctx, "skipping kustomize: no resourcesFile")
|
||||
return nil
|
||||
}
|
||||
if len(r.Component.Kustomize.KustomizeFiles) < 1 {
|
||||
log.DebugContext(ctx, "skipping kustomize: no kustomizeFiles")
|
||||
return nil
|
||||
}
|
||||
tempDir, err := os.MkdirTemp("", "holos.kustomize")
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
defer util.Remove(ctx, tempDir)
|
||||
|
||||
// Write the main api object resources file for kustomize.
|
||||
target := filepath.Join(tempDir, r.Component.Kustomize.ResourcesFile)
|
||||
b := []byte(r.AccumulatedOutput())
|
||||
b = util.EnsureNewline(b)
|
||||
if err := os.WriteFile(target, b, 0644); err != nil {
|
||||
return errors.Wrap(fmt.Errorf("could not write resources: %w", err))
|
||||
}
|
||||
log.DebugContext(ctx, "wrote: "+target, "op", "write", "path", target, "bytes", len(b))
|
||||
|
||||
// Write the kustomization tree, kustomization.yaml must be in this map for kustomize to work.
|
||||
for file, content := range r.Component.Kustomize.KustomizeFiles {
|
||||
target := filepath.Join(tempDir, file)
|
||||
if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
b := []byte(content)
|
||||
b = util.EnsureNewline(b)
|
||||
if err := os.WriteFile(target, b, 0644); err != nil {
|
||||
return errors.Wrap(fmt.Errorf("could not write: %w", err))
|
||||
}
|
||||
log.DebugContext(ctx, "wrote: "+target, "op", "write", "path", target, "bytes", len(b))
|
||||
}
|
||||
|
||||
// Run kustomize.
|
||||
kOut, err := util.RunCmd(ctx, "kubectl", "kustomize", tempDir)
|
||||
if err != nil {
|
||||
log.ErrorContext(ctx, kOut.Stderr.String())
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
// Replace the accumulated output
|
||||
r.accumulatedOutput = kOut.Stdout.String()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Result) WriteDeployFiles(ctx context.Context, path string) error {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
log := logger.FromContext(ctx)
|
||||
if len(r.Component.DeployFiles) == 0 {
|
||||
return nil
|
||||
}
|
||||
for k, content := range r.Component.DeployFiles {
|
||||
path := filepath.Join(path, k)
|
||||
if err := r.Save(ctx, path, content); err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
log.InfoContext(ctx, "wrote deploy file", "path", path, "bytes", len(content))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Save writes the content to the filesystem for git ops.
|
||||
func (r *Result) Save(ctx context.Context, path string, content string) error {
|
||||
log := logger.FromContext(ctx)
|
||||
dir := filepath.Dir(path)
|
||||
if err := os.MkdirAll(dir, os.FileMode(0775)); err != nil {
|
||||
log.WarnContext(ctx, "could not mkdir", "path", dir, "err", err)
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
// Write the file content
|
||||
if err := os.WriteFile(path, []byte(content), os.FileMode(0644)); err != nil {
|
||||
log.WarnContext(ctx, "could not write", "path", path, "err", err)
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
log.DebugContext(ctx, "out: wrote "+path, "action", "write", "path", path, "status", "ok")
|
||||
return nil
|
||||
}
|
||||
|
||||
// SkipWriteAccumulatedOutput returns true if writing the accumulated output of
|
||||
// k8s api objects should be skipped. Useful for results which only write
|
||||
// deployment files, like Flux or ArgoCD GitOps resources.
|
||||
func (r *Result) SkipWriteAccumulatedOutput() bool {
|
||||
if r == nil {
|
||||
return true
|
||||
}
|
||||
// This is a hack and should be moved to a HolosComponent field or similar.
|
||||
if strings.HasPrefix(r.Component.Metadata.Name, "gitops/") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -7,8 +7,10 @@ package tools
|
||||
|
||||
import (
|
||||
_ "connectrpc.com/connect/cmd/protoc-gen-connect-go"
|
||||
_ "cuelang.org/go/cmd/cue"
|
||||
_ "github.com/bufbuild/buf/cmd/buf"
|
||||
_ "github.com/fullstorydev/grpcurl/cmd/grpcurl"
|
||||
_ "golang.org/x/tools/cmd/godoc"
|
||||
_ "google.golang.org/protobuf/cmd/protoc-gen-go"
|
||||
_ "honnef.co/go/tools/cmd/staticcheck"
|
||||
)
|
||||
|
||||
@@ -1 +1 @@
|
||||
84
|
||||
85
|
||||
|
||||
Reference in New Issue
Block a user