Compare commits

..

8 Commits

Author SHA1 Message Date
Jeff McCune
2b3b5a4887 (#36) Issue login and httpbin certs
This patch uses cert manager in the provisioner cluster to provision tls
certs for https://login.example.com and https://httpbin.k2.example.com

The certs are not yet synced to the clusters.  Next step is to replace
the Certificate resources with ExternalSecret resources, then remove
cert manager from the workload clusters.
2024-03-05 14:27:37 -08:00
Jeff McCune
7426e8f867 (#36) Move cert-manager to the provisioner cluster
This patch moves certificate management to the provisioner cluster to
centralize all secrets into the highly secured cluster.  This change
also simplifies the architecture in a number of ways:

1. Certificate lives are now completely independent of cluster
   lifecycle.
2. Remove the need for bi-directional sync to save cert secrets.
3. Workload clusters no longer need access to DNS.
2024-03-05 12:51:58 -08:00
Jeff McCune
cf0c455aa2 (#34) Add test for print secret data 2024-03-05 11:14:37 -08:00
Jeff McCune
752a3f912d (#34) Remove debug info logs 2024-03-05 11:05:51 -08:00
Jeff McCune
7d5852d675 (#34) Print secret data as json
Closes: #34
2024-03-05 11:03:47 -08:00
Jeff McCune
66b4ca0e6c (#31) Fix helm missing in actions workflow
Causing test failures that should pass.
2024-03-05 10:11:43 -08:00
Jeff McCune
b3f682453d (#31) Inject istio sidecar into Deployment zitadel using Kustomize
Multiple holos components rely on kustomize to modify the output of the
upstream helm chart, for example patching a Deployment to inject the
istio sidecar.

The new holos cue based component system did not support running
kustomize after helm template.  This patch adds the kustomize execution
if two fields are defined in the helm chart kind of cue output.

The API spec is pretty loose in this patch but I'm proceeding for
expedience and to inform the final API with more use cases as more
components are migrated to cue.
2024-03-05 09:56:39 -08:00
Jeff McCune
0c3181ae05 (#31) Add VirtualService for Zitadel
Also import the Kustomize types using:

    cue get go sigs.k8s.io/kustomize/api/types/...
2024-03-04 17:18:46 -08:00
58 changed files with 1473 additions and 193 deletions

View File

@@ -23,5 +23,10 @@ jobs:
with:
go-version: stable
- name: Set up Helm
uses: azure/setup-helm@v4.1.0
with:
version: 'latest'
- name: Test
run: ./scripts/test

View File

@@ -0,0 +1,7 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
_#_BuiltinPluginLoadingOptions_name: "BploUndefinedBploUseStaticallyLinkedBploLoadFromFileSys"

View File

@@ -0,0 +1,10 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
// ConfigMapArgs contains the metadata of how to generate a configmap.
#ConfigMapArgs: {
#GeneratorArgs
}

View File

@@ -0,0 +1,10 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
// Package types holds the definition of the kustomization struct and
// supporting structs. It's the k8s API conformant object that describes
// a set of generation and transformation operations to create and/or
// modify k8s resources.
// A kustomization file is a serialization of this struct.
package types

View File

@@ -0,0 +1,29 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
// FieldSpec completely specifies a kustomizable field in a k8s API object.
// It helps define the operands of transformations.
//
// For example, a directive to add a common label to objects
// will need to know that a 'Deployment' object (in API group
// 'apps', any version) can have labels at field path
// 'spec/template/metadata/labels', and further that it is OK
// (or not OK) to add that field path to the object if the
// field path doesn't exist already.
//
// This would look like
// {
// group: apps
// kind: Deployment
// path: spec/template/metadata/labels
// create: true
// }
#FieldSpec: {
path?: string @go(Path)
create?: bool @go(CreateIfNotPresent)
}
#FsSlice: [...#FieldSpec]

View File

@@ -0,0 +1,33 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
// GenerationBehavior specifies generation behavior of configmaps, secrets and maybe other resources.
#GenerationBehavior: int // #enumGenerationBehavior
#enumGenerationBehavior:
#BehaviorUnspecified |
#BehaviorCreate |
#BehaviorReplace |
#BehaviorMerge
#values_GenerationBehavior: {
BehaviorUnspecified: #BehaviorUnspecified
BehaviorCreate: #BehaviorCreate
BehaviorReplace: #BehaviorReplace
BehaviorMerge: #BehaviorMerge
}
// BehaviorUnspecified is an Unspecified behavior; typically treated as a Create.
#BehaviorUnspecified: #GenerationBehavior & 0
// BehaviorCreate makes a new resource.
#BehaviorCreate: #GenerationBehavior & 1
// BehaviorReplace replaces a resource.
#BehaviorReplace: #GenerationBehavior & 2
// BehaviorMerge attempts to merge a new resource with an existing resource.
#BehaviorMerge: #GenerationBehavior & 3

View File

@@ -0,0 +1,27 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
// GeneratorArgs contains arguments common to ConfigMap and Secret generators.
#GeneratorArgs: {
// Namespace for the resource, optional
namespace?: string @go(Namespace)
// Name - actually the partial name - of the generated resource.
// The full name ends up being something like
// NamePrefix + this.Name + hash(content of generated resource).
name?: string @go(Name)
// Behavior of generated resource, must be one of:
// 'create': create a new one
// 'replace': replace the existing one
// 'merge': merge with the existing one
behavior?: string @go(Behavior)
#KvPairSources
// Local overrides to global generatorOptions field.
options?: null | #GeneratorOptions @go(Options,*GeneratorOptions)
}

View File

@@ -0,0 +1,22 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
// GeneratorOptions modify behavior of all ConfigMap and Secret generators.
#GeneratorOptions: {
// Labels to add to all generated resources.
labels?: {[string]: string} @go(Labels,map[string]string)
// Annotations to add to all generated resources.
annotations?: {[string]: string} @go(Annotations,map[string]string)
// DisableNameSuffixHash if true disables the default behavior of adding a
// suffix to the names of generated resources that is a hash of the
// resource contents.
disableNameSuffixHash?: bool @go(DisableNameSuffixHash)
// Immutable if true add to all generated resources.
immutable?: bool @go(Immutable)
}

View File

@@ -0,0 +1,116 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
#HelmDefaultHome: "charts"
#HelmGlobals: {
// ChartHome is a file path, relative to the kustomization root,
// to a directory containing a subdirectory for each chart to be
// included in the kustomization.
// The default value of this field is "charts".
// So, for example, kustomize looks for the minecraft chart
// at {kustomizationRoot}/{ChartHome}/minecraft.
// If the chart is there at build time, kustomize will use it as found,
// and not check version numbers or dates.
// If the chart is not there, kustomize will attempt to pull it
// using the version number specified in the kustomization file,
// and put it there. To suppress the pull attempt, simply assure
// that the chart is already there.
chartHome?: string @go(ChartHome)
// ConfigHome defines a value that kustomize should pass to helm via
// the HELM_CONFIG_HOME environment variable. kustomize doesn't attempt
// to read or write this directory.
// If omitted, {tmpDir}/helm is used, where {tmpDir} is some temporary
// directory created by kustomize for the benefit of helm.
// Likewise, kustomize sets
// HELM_CACHE_HOME={ConfigHome}/.cache
// HELM_DATA_HOME={ConfigHome}/.data
// for the helm subprocess.
configHome?: string @go(ConfigHome)
}
#HelmChart: {
// Name is the name of the chart, e.g. 'minecraft'.
name?: string @go(Name)
// Version is the version of the chart, e.g. '3.1.3'
version?: string @go(Version)
// Repo is a URL locating the chart on the internet.
// This is the argument to helm's `--repo` flag, e.g.
// `https://itzg.github.io/minecraft-server-charts`.
repo?: string @go(Repo)
// ReleaseName replaces RELEASE-NAME in chart template output,
// making a particular inflation of a chart unique with respect to
// other inflations of the same chart in a cluster. It's the first
// argument to the helm `install` and `template` commands, i.e.
// helm install {RELEASE-NAME} {chartName}
// helm template {RELEASE-NAME} {chartName}
// If omitted, the flag --generate-name is passed to 'helm template'.
releaseName?: string @go(ReleaseName)
// Namespace set the target namespace for a release. It is .Release.Namespace
// in the helm template
namespace?: string @go(Namespace)
// AdditionalValuesFiles are local file paths to values files to be used in
// addition to either the default values file or the values specified in ValuesFile.
additionalValuesFiles?: [...string] @go(AdditionalValuesFiles,[]string)
// ValuesFile is a local file path to a values file to use _instead of_
// the default values that accompanied the chart.
// The default values are in '{ChartHome}/{Name}/values.yaml'.
valuesFile?: string @go(ValuesFile)
// ValuesInline holds value mappings specified directly,
// rather than in a separate file.
valuesInline?: {...} @go(ValuesInline,map[string]interface{})
// ValuesMerge specifies how to treat ValuesInline with respect to Values.
// Legal values: 'merge', 'override', 'replace'.
// Defaults to 'override'.
valuesMerge?: string @go(ValuesMerge)
// IncludeCRDs specifies if Helm should also generate CustomResourceDefinitions.
// Defaults to 'false'.
includeCRDs?: bool @go(IncludeCRDs)
// SkipHooks sets the --no-hooks flag when calling helm template. This prevents
// helm from erroneously rendering test templates.
skipHooks?: bool @go(SkipHooks)
// ApiVersions is the kubernetes apiversions used for Capabilities.APIVersions
apiVersions?: [...string] @go(ApiVersions,[]string)
// KubeVersion is the kubernetes version used by Helm for Capabilities.KubeVersion"
kubeVersion?: string @go(KubeVersion)
// NameTemplate is for specifying the name template used to name the release.
nameTemplate?: string @go(NameTemplate)
// SkipTests skips tests from templated output.
skipTests?: bool @go(SkipTests)
}
// HelmChartArgs contains arguments to helm.
// Deprecated. Use HelmGlobals and HelmChart instead.
#HelmChartArgs: {
chartName?: string @go(ChartName)
chartVersion?: string @go(ChartVersion)
chartRepoUrl?: string @go(ChartRepoURL)
chartHome?: string @go(ChartHome)
chartRepoName?: string @go(ChartRepoName)
helmBin?: string @go(HelmBin)
helmHome?: string @go(HelmHome)
values?: string @go(Values)
valuesLocal?: {...} @go(ValuesLocal,map[string]interface{})
valuesMerge?: string @go(ValuesMerge)
releaseName?: string @go(ReleaseName)
releaseNamespace?: string @go(ReleaseNamespace)
extraArgs?: [...string] @go(ExtraArgs,[]string)
}

View File

@@ -0,0 +1,40 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
#Cloud: string // #enumCloud
#enumCloud:
#GKE
#GKE: #Cloud & "gke"
// IAMPolicyGeneratorArgs contains arguments to generate a GKE service account resource.
#IAMPolicyGeneratorArgs: {
// which cloud provider to generate for (e.g. "gke")
cloud: #Cloud @go(Cloud)
// information about the kubernetes cluster for this object
kubernetesService: #KubernetesService @go(KubernetesService)
// information about the service account and project
serviceAccount: #ServiceAccount @go(ServiceAccount)
}
#KubernetesService: {
// the name used for the Kubernetes service account
name: string @go(Name)
// the name of the Kubernetes namespace for this object
namespace?: string @go(Namespace)
}
#ServiceAccount: {
// the name of the new cloud provider service account
name: string @go(Name)
// The ID of the project
projectId: string @go(ProjectId)
}

View File

@@ -0,0 +1,26 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
// Image contains an image name, a new name, a new tag or digest,
// which will replace the original name and tag.
#Image: {
// Name is a tag-less image name.
name?: string @go(Name)
// NewName is the value used to replace the original name.
newName?: string @go(NewName)
// TagSuffix is the value used to suffix the original tag
// If Digest and NewTag is present an error is thrown
tagSuffix?: string @go(TagSuffix)
// NewTag is the value used to replace the original tag.
newTag?: string @go(NewTag)
// Digest is the value used to replace the original image tag.
// If digest is present NewTag value is ignored.
digest?: string @go(Digest)
}

View File

@@ -0,0 +1,163 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
#KustomizationVersion: "kustomize.config.k8s.io/v1beta1"
#KustomizationKind: "Kustomization"
#ComponentVersion: "kustomize.config.k8s.io/v1alpha1"
#ComponentKind: "Component"
#MetadataNamespacePath: "metadata/namespace"
#MetadataNamespaceApiVersion: "v1"
#MetadataNamePath: "metadata/name"
#OriginAnnotations: "originAnnotations"
#TransformerAnnotations: "transformerAnnotations"
#ManagedByLabelOption: "managedByLabel"
// Kustomization holds the information needed to generate customized k8s api resources.
#Kustomization: {
#TypeMeta
// MetaData is a pointer to avoid marshalling empty struct
metadata?: null | #ObjectMeta @go(MetaData,*ObjectMeta)
// OpenAPI contains information about what kubernetes schema to use.
openapi?: {[string]: string} @go(OpenAPI,map[string]string)
// NamePrefix will prefix the names of all resources mentioned in the kustomization
// file including generated configmaps and secrets.
namePrefix?: string @go(NamePrefix)
// NameSuffix will suffix the names of all resources mentioned in the kustomization
// file including generated configmaps and secrets.
nameSuffix?: string @go(NameSuffix)
// Namespace to add to all objects.
namespace?: string @go(Namespace)
// CommonLabels to add to all objects and selectors.
commonLabels?: {[string]: string} @go(CommonLabels,map[string]string)
// Labels to add to all objects but not selectors.
labels?: [...#Label] @go(Labels,[]Label)
// CommonAnnotations to add to all objects.
commonAnnotations?: {[string]: string} @go(CommonAnnotations,map[string]string)
// Deprecated: Use the Patches field instead, which provides a superset of the functionality of PatchesStrategicMerge.
// PatchesStrategicMerge specifies the relative path to a file
// containing a strategic merge patch. Format documented at
// https://github.com/kubernetes/community/blob/master/contributors/devel/sig-api-machinery/strategic-merge-patch.md
// URLs and globs are not supported.
patchesStrategicMerge?: [...#PatchStrategicMerge] @go(PatchesStrategicMerge,[]PatchStrategicMerge)
// Deprecated: Use the Patches field instead, which provides a superset of the functionality of JSONPatches.
// JSONPatches is a list of JSONPatch for applying JSON patch.
// Format documented at https://tools.ietf.org/html/rfc6902
// and http://jsonpatch.com
patchesJson6902?: [...#Patch] @go(PatchesJson6902,[]Patch)
// Patches is a list of patches, where each one can be either a
// Strategic Merge Patch or a JSON patch.
// Each patch can be applied to multiple target objects.
patches?: [...#Patch] @go(Patches,[]Patch)
// Images is a list of (image name, new name, new tag or digest)
// for changing image names, tags or digests. This can also be achieved with a
// patch, but this operator is simpler to specify.
images?: [...#Image] @go(Images,[]Image)
// Deprecated: Use the Images field instead.
imageTags?: [...#Image] @go(ImageTags,[]Image)
// Replacements is a list of replacements, which will copy nodes from a
// specified source to N specified targets.
replacements?: [...#ReplacementField] @go(Replacements,[]ReplacementField)
// Replicas is a list of {resourcename, count} that allows for simpler replica
// specification. This can also be done with a patch.
replicas?: [...#Replica] @go(Replicas,[]Replica)
// Deprecated: Vars will be removed in future release. Migrate to Replacements instead.
// Vars allow things modified by kustomize to be injected into a
// kubernetes object specification. A var is a name (e.g. FOO) associated
// with a field in a specific resource instance. The field must
// contain a value of type string/bool/int/float, and defaults to the name field
// of the instance. Any appearance of "$(FOO)" in the object
// spec will be replaced at kustomize build time, after the final
// value of the specified field has been determined.
vars?: [...#Var] @go(Vars,[]Var)
// SortOptions change the order that kustomize outputs resources.
sortOptions?: null | #SortOptions @go(SortOptions,*SortOptions)
// Resources specifies relative paths to files holding YAML representations
// of kubernetes API objects, or specifications of other kustomizations
// via relative paths, absolute paths, or URLs.
resources?: [...string] @go(Resources,[]string)
// Components specifies relative paths to specifications of other Components
// via relative paths, absolute paths, or URLs.
components?: [...string] @go(Components,[]string)
// Crds specifies relative paths to Custom Resource Definition files.
// This allows custom resources to be recognized as operands, making
// it possible to add them to the Resources list.
// CRDs themselves are not modified.
crds?: [...string] @go(Crds,[]string)
// Deprecated: Anything that would have been specified here should be specified in the Resources field instead.
bases?: [...string] @go(Bases,[]string)
// ConfigMapGenerator is a list of configmaps to generate from
// local data (one configMap per list item).
// The resulting resource is a normal operand, subject to
// name prefixing, patching, etc. By default, the name of
// the map will have a suffix hash generated from its contents.
configMapGenerator?: [...#ConfigMapArgs] @go(ConfigMapGenerator,[]ConfigMapArgs)
// SecretGenerator is a list of secrets to generate from
// local data (one secret per list item).
// The resulting resource is a normal operand, subject to
// name prefixing, patching, etc. By default, the name of
// the map will have a suffix hash generated from its contents.
secretGenerator?: [...#SecretArgs] @go(SecretGenerator,[]SecretArgs)
// HelmGlobals contains helm configuration that isn't chart specific.
helmGlobals?: null | #HelmGlobals @go(HelmGlobals,*HelmGlobals)
// HelmCharts is a list of helm chart configuration instances.
helmCharts?: [...#HelmChart] @go(HelmCharts,[]HelmChart)
// HelmChartInflationGenerator is a list of helm chart configurations.
// Deprecated. Auto-converted to HelmGlobals and HelmCharts.
helmChartInflationGenerator?: [...#HelmChartArgs] @go(HelmChartInflationGenerator,[]HelmChartArgs)
// GeneratorOptions modify behavior of all ConfigMap and Secret generators.
generatorOptions?: null | #GeneratorOptions @go(GeneratorOptions,*GeneratorOptions)
// Configurations is a list of transformer configuration files
configurations?: [...string] @go(Configurations,[]string)
// Generators is a list of files containing custom generators
generators?: [...string] @go(Generators,[]string)
// Transformers is a list of files containing transformers
transformers?: [...string] @go(Transformers,[]string)
// Validators is a list of files containing validators
validators?: [...string] @go(Validators,[]string)
// BuildMetadata is a list of strings used to toggle different build options
buildMetadata?: [...string] @go(BuildMetadata,[]string)
}
_#deprecatedWarningToRunEditFix: "Run 'kustomize edit fix' to update your Kustomization automatically."
_#deprecatedWarningToRunEditFixExperimential: "[EXPERIMENTAL] Run 'kustomize edit fix' to update your Kustomization automatically."
_#deprecatedBaseWarningMessage: "# Warning: 'bases' is deprecated. Please use 'resources' instead. Run 'kustomize edit fix' to update your Kustomization automatically."
_#deprecatedImageTagsWarningMessage: "# Warning: 'imageTags' is deprecated. Please use 'images' instead. Run 'kustomize edit fix' to update your Kustomization automatically."
_#deprecatedPatchesJson6902Message: "# Warning: 'patchesJson6902' is deprecated. Please use 'patches' instead. Run 'kustomize edit fix' to update your Kustomization automatically."
_#deprecatedPatchesStrategicMergeMessage: "# Warning: 'patchesStrategicMerge' is deprecated. Please use 'patches' instead. Run 'kustomize edit fix' to update your Kustomization automatically."
_#deprecatedVarsMessage: "# Warning: 'vars' is deprecated. Please use 'replacements' instead. [EXPERIMENTAL] Run 'kustomize edit fix' to update your Kustomization automatically."
_#deprecatedCommonLabelsWarningMessage: "# Warning: 'commonLabels' is deprecated. Please use 'labels' instead. Run 'kustomize edit fix' to update your Kustomization automatically."

View File

@@ -0,0 +1,37 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
// KvPairSources defines places to obtain key value pairs.
#KvPairSources: {
// LiteralSources is a list of literal
// pair sources. Each literal source should
// be a key and literal value, e.g. `key=value`
literals?: [...string] @go(LiteralSources,[]string)
// FileSources is a list of file "sources" to
// use in creating a list of key, value pairs.
// A source takes the form: [{key}=]{path}
// If the "key=" part is missing, the key is the
// path's basename. If they "key=" part is present,
// it becomes the key (replacing the basename).
// In either case, the value is the file contents.
// Specifying a directory will iterate each named
// file in the directory whose basename is a
// valid configmap key.
files?: [...string] @go(FileSources,[]string)
// EnvSources is a list of file paths.
// The contents of each file should be one
// key=value pair per line, e.g. a Docker
// or npm ".env" file or a ".ini" file
// (wikipedia.org/wiki/INI_file)
envs?: [...string] @go(EnvSources,[]string)
// Older, singular form of EnvSources.
// On edits (e.g. `kustomize fix`) this is merged into the plural form
// for consistency with LiteralSources and FileSources.
env?: string @go(EnvSource)
}

View File

@@ -0,0 +1,23 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
#Label: {
// Pairs contains the key-value pairs for labels to add
pairs?: {[string]: string} @go(Pairs,map[string]string)
// IncludeSelectors inidicates should transformer include the
// fieldSpecs for selectors. Custom fieldSpecs specified by
// FieldSpecs will be merged with builtin fieldSpecs if this
// is true.
includeSelectors?: bool @go(IncludeSelectors)
// IncludeTemplates inidicates should transformer include the
// spec/template/metadata fieldSpec. Custom fieldSpecs specified by
// FieldSpecs will be merged with spec/template/metadata fieldSpec if this
// is true. If IncludeSelectors is true, IncludeTemplates is not needed.
includeTemplates?: bool @go(IncludeTemplates)
fields?: [...#FieldSpec] @go(FieldSpecs,[]FieldSpec)
}

View File

@@ -0,0 +1,34 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
// Restrictions on what things can be referred to
// in a kustomization file.
//
//go:generate stringer -type=LoadRestrictions
#LoadRestrictions: int // #enumLoadRestrictions
#enumLoadRestrictions:
#LoadRestrictionsUnknown |
#LoadRestrictionsRootOnly |
#LoadRestrictionsNone
#values_LoadRestrictions: {
LoadRestrictionsUnknown: #LoadRestrictionsUnknown
LoadRestrictionsRootOnly: #LoadRestrictionsRootOnly
LoadRestrictionsNone: #LoadRestrictionsNone
}
#LoadRestrictionsUnknown: #LoadRestrictions & 0
// Files referenced by a kustomization file must be in
// or under the directory holding the kustomization
// file itself.
#LoadRestrictionsRootOnly: #LoadRestrictions & 1
// The kustomization file may specify absolute or
// relative paths to patch or resources files outside
// its own tree.
#LoadRestrictionsNone: #LoadRestrictions & 2

View File

@@ -0,0 +1,7 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
_#_LoadRestrictions_name: "LoadRestrictionsUnknownLoadRestrictionsRootOnlyLoadRestrictionsNone"

View File

@@ -0,0 +1,14 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
// ObjectMeta partially copies apimachinery/pkg/apis/meta/v1.ObjectMeta
// No need for a direct dependence; the fields are stable.
#ObjectMeta: {
name?: string @go(Name)
namespace?: string @go(Namespace)
labels?: {[string]: string} @go(Labels,map[string]string)
annotations?: {[string]: string} @go(Annotations,map[string]string)
}

View File

@@ -0,0 +1,11 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
// Pair is a key value pair.
#Pair: {
Key: string
Value: string
}

View File

@@ -0,0 +1,23 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
// Patch represent either a Strategic Merge Patch or a JSON patch
// and its targets.
// The content of the patch can either be from a file
// or from an inline string.
#Patch: {
// Path is a relative file path to the patch file.
path?: string @go(Path)
// Patch is the content of a patch.
patch?: string @go(Patch)
// Target points to the resources that the patch is applied to
target?: #Target | #Selector @go(Target,*Selector)
// Options is a list of options for the patch
options?: {[string]: bool} @go(Options,map[string]bool)
}

View File

@@ -0,0 +1,10 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
// PatchStrategicMerge represents a relative path to a
// stategic merge patch with the format
// https://github.com/kubernetes/community/blob/master/contributors/devel/sig-api-machinery/strategic-merge-patch.md
#PatchStrategicMerge: string

View File

@@ -0,0 +1,27 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
#HelmConfig: {
Enabled: bool
Command: string
ApiVersions: [...string] @go(,[]string)
KubeVersion: string
}
// PluginConfig holds plugin configuration.
#PluginConfig: {
// PluginRestrictions distinguishes plugin restrictions.
PluginRestrictions: #PluginRestrictions
// BpLoadingOptions distinguishes builtin plugin behaviors.
BpLoadingOptions: #BuiltinPluginLoadingOptions
// FnpLoadingOptions sets the way function-based plugin behaviors.
FnpLoadingOptions: #FnPluginLoadingOptions
// HelmConfig contains metadata needed for allowing and running helm.
HelmConfig: #HelmConfig
}

View File

@@ -0,0 +1,87 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
// Some plugin classes
// - builtin: plugins defined in the kustomize repo.
// May be freely used and re-configured.
// - local: plugins that aren't builtin but are
// locally defined (presumably by the user), meaning
// the kustomization refers to them via a relative
// file path, not a URL.
// - remote: require a build-time download to obtain.
// Unadvised, unless one controls the
// serving site.
//
//go:generate stringer -type=PluginRestrictions
#PluginRestrictions: int // #enumPluginRestrictions
#enumPluginRestrictions:
#PluginRestrictionsUnknown |
#PluginRestrictionsBuiltinsOnly |
#PluginRestrictionsNone
#values_PluginRestrictions: {
PluginRestrictionsUnknown: #PluginRestrictionsUnknown
PluginRestrictionsBuiltinsOnly: #PluginRestrictionsBuiltinsOnly
PluginRestrictionsNone: #PluginRestrictionsNone
}
#PluginRestrictionsUnknown: #PluginRestrictions & 0
// Non-builtin plugins completely disabled.
#PluginRestrictionsBuiltinsOnly: #PluginRestrictions & 1
// No restrictions, do whatever you want.
#PluginRestrictionsNone: #PluginRestrictions & 2
// BuiltinPluginLoadingOptions distinguish ways in which builtin plugins are used.
//go:generate stringer -type=BuiltinPluginLoadingOptions
#BuiltinPluginLoadingOptions: int // #enumBuiltinPluginLoadingOptions
#enumBuiltinPluginLoadingOptions:
#BploUndefined |
#BploUseStaticallyLinked |
#BploLoadFromFileSys
#values_BuiltinPluginLoadingOptions: {
BploUndefined: #BploUndefined
BploUseStaticallyLinked: #BploUseStaticallyLinked
BploLoadFromFileSys: #BploLoadFromFileSys
}
#BploUndefined: #BuiltinPluginLoadingOptions & 0
// Desired in production use for performance.
#BploUseStaticallyLinked: #BuiltinPluginLoadingOptions & 1
// Desired in testing and development cycles where it's undesirable
// to generate static code.
#BploLoadFromFileSys: #BuiltinPluginLoadingOptions & 2
// FnPluginLoadingOptions set way functions-based plugins are restricted
#FnPluginLoadingOptions: {
// Allow to run executables
EnableExec: bool
// Allow to run starlark
EnableStar: bool
// Allow container access to network
Network: bool
NetworkName: string
// list of mounts
Mounts: [...string] @go(,[]string)
// list of env variables to pass to fn
Env: [...string] @go(,[]string)
// Run as uid and gid of the command executor
AsCurrentUser: bool
// Run in this working directory
WorkingDir: string
}

View File

@@ -0,0 +1,7 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
_#_PluginRestrictions_name: "PluginRestrictionsUnknownPluginRestrictionsBuiltinsOnlyPluginRestrictionsNone"

View File

@@ -0,0 +1,57 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
#DefaultReplacementFieldPath: "metadata.name"
// Replacement defines how to perform a substitution
// where it is from and where it is to.
#Replacement: {
// The source of the value.
source?: null | #SourceSelector @go(Source,*SourceSelector)
// The N fields to write the value to.
targets?: [...null | #TargetSelector] @go(Targets,[]*TargetSelector)
}
// SourceSelector is the source of the replacement transformer.
#SourceSelector: {
// Structured field path expected in the allowed object.
fieldPath?: string @go(FieldPath)
// Used to refine the interpretation of the field.
options?: null | #FieldOptions @go(Options,*FieldOptions)
}
// TargetSelector specifies fields in one or more objects.
#TargetSelector: {
// Include objects that match this.
select?: null | #Selector @go(Select,*Selector)
// From the allowed set, remove objects that match this.
reject?: [...null | #Selector] @go(Reject,[]*Selector)
// Structured field paths expected in each allowed object.
fieldPaths?: [...string] @go(FieldPaths,[]string)
// Used to refine the interpretation of the field.
options?: null | #FieldOptions @go(Options,*FieldOptions)
}
// FieldOptions refine the interpretation of FieldPaths.
#FieldOptions: {
// Used to split/join the field.
delimiter?: string @go(Delimiter)
// Which position in the split to consider.
index?: int @go(Index)
// TODO (#3492): Implement use of this option
// None, Base64, URL, Hex, etc
encoding?: string @go(Encoding)
// If field missing, add it.
create?: bool @go(Create)
}

View File

@@ -0,0 +1,10 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
#ReplacementField: {
#Replacement
path?: string @go(Path)
}

View File

@@ -0,0 +1,17 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
// Replica specifies a modification to a replica config.
// The number of replicas of a resource whose name matches will be set to count.
// This struct is used by the ReplicaCountTransform, and is meant to supplement
// the existing patch functionality with a simpler syntax for replica configuration.
#Replica: {
// The name of the resource to change the replica count
name?: string @go(Name)
// The number of replicas required.
count: int64 @go(Count)
}

View File

@@ -0,0 +1,19 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
// SecretArgs contains the metadata of how to generate a secret.
#SecretArgs: {
#GeneratorArgs
// Type of the secret.
//
// This is the same field as the secret type field in v1/Secret:
// It can be "Opaque" (default), or "kubernetes.io/tls".
//
// If type is "kubernetes.io/tls", then "literals" or "files" must have exactly two
// keys: "tls.key" and "tls.crt"
type?: string @go(Type)
}

View File

@@ -0,0 +1,20 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
// Selector specifies a set of resources.
// Any resource that matches intersection of all conditions
// is included in this set.
#Selector: {
// AnnotationSelector is a string that follows the label selection expression
// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
// It matches with the resource annotations.
annotationSelector?: string @go(AnnotationSelector)
// LabelSelector is a string that follows the label selection expression
// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
// It matches with the resource labels.
labelSelector?: string @go(LabelSelector)
}

View File

@@ -0,0 +1,36 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
// SortOptions defines the order that kustomize outputs resources.
#SortOptions: {
// Order selects the ordering strategy.
order?: #SortOrder @go(Order)
// LegacySortOptions tweaks the sorting for the "legacy" sort ordering
// strategy.
legacySortOptions?: null | #LegacySortOptions @go(LegacySortOptions,*LegacySortOptions)
}
// SortOrder defines different ordering strategies.
#SortOrder: string // #enumSortOrder
#enumSortOrder:
#LegacySortOrder |
#FIFOSortOrder
#LegacySortOrder: #SortOrder & "legacy"
#FIFOSortOrder: #SortOrder & "fifo"
// LegacySortOptions define various options for tweaking the "legacy" ordering
// strategy.
#LegacySortOptions: {
// OrderFirst selects the resource kinds to order first.
orderFirst: [...string] @go(OrderFirst,[]string)
// OrderLast selects the resource kinds to order last.
orderLast: [...string] @go(OrderLast,[]string)
}

View File

@@ -0,0 +1,12 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
// TypeMeta partially copies apimachinery/pkg/apis/meta/v1.TypeMeta
// No need for a direct dependence; the fields are stable.
#TypeMeta: {
kind?: string @go(Kind)
apiVersion?: string @go(APIVersion)
}

View File

@@ -0,0 +1,45 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go sigs.k8s.io/kustomize/api/types
package types
// Var represents a variable whose value will be sourced
// from a field in a Kubernetes object.
#Var: {
// Value of identifier name e.g. FOO used in container args, annotations
// Appears in pod template as $(FOO)
name: string @go(Name)
// ObjRef must refer to a Kubernetes resource under the
// purview of this kustomization. ObjRef should use the
// raw name of the object (the name specified in its YAML,
// before addition of a namePrefix and a nameSuffix).
objref: #Target @go(ObjRef)
// FieldRef refers to the field of the object referred to by
// ObjRef whose value will be extracted for use in
// replacing $(FOO).
// If unspecified, this defaults to fieldPath: $defaultFieldPath
fieldref?: #FieldSelector @go(FieldRef)
}
// Target refers to a kubernetes object by Group, Version, Kind and Name
// gvk.Gvk contains Group, Version and Kind
// APIVersion is added to keep the backward compatibility of using ObjectReference
// for Var.ObjRef
#Target: {
apiVersion?: string @go(APIVersion)
name: string @go(Name)
namespace?: string @go(Namespace)
}
// FieldSelector contains the fieldPath to an object field.
// This struct is added to keep the backward compatibility of using ObjectFieldSelector
// for Var.FieldRef
#FieldSelector: {
fieldPath?: string @go(FieldPath)
}
// byName is a sort interface which sorts Vars by name alphabetically
_#byName: [...#Var]

View File

@@ -1,6 +1,6 @@
package v1
#Deployment: {
apiVersion: "apps/v1"
kind: "Deployment"
apiVersion: "apps/v1"
kind: "Deployment"
}

View File

@@ -1,11 +1,11 @@
package v1
#CronJob: {
apiVersion: "batch/v1"
kind: "CronJob"
apiVersion: "batch/v1"
kind: "CronJob"
}
#Job: {
apiVersion: "batch/v1"
kind: "Job"
apiVersion: "batch/v1"
kind: "Job"
}

View File

@@ -1,26 +1,26 @@
package v1
#Namespace: {
apiVersion: "v1"
kind: "Namespace"
apiVersion: "v1"
kind: "Namespace"
}
#ConfigMap: {
apiVersion: "v1"
kind: "ConfigMap"
apiVersion: "v1"
kind: "ConfigMap"
}
#ServiceAccount: {
apiVersion: "v1"
kind: "ServiceAccount"
apiVersion: "v1"
kind: "ServiceAccount"
}
#Pod: {
apiVersion: "v1"
kind: "Pod"
apiVersion: "v1"
kind: "Pod"
}
#Service: {
apiVersion: "v1"
kind: "Service"
apiVersion: "v1"
kind: "Service"
}

View File

@@ -0,0 +1,15 @@
package types
#Patch: {
// Path is a relative file path to the patch file.
path?: string @go(Path)
// Patch is the content of a patch.
patch?: string @go(Patch)
// Target points to the resources that the patch is applied to
target?: #Target | #Selector @go(Target,*Selector)
// Options is a list of options for the patch
options?: {[string]: bool} @go(Options,map[string]bool)
}

View File

@@ -0,0 +1,7 @@
package types
#Target: {
group?: string @go(Group)
version?: string @go(Version)
kind?: string @go(Kind)
}

View File

@@ -0,0 +1,56 @@
package holos
#PlatformCerts: {
// Login service for IAM.
login: #PlatformCert & {
_name: "login"
_wildcard: true
_description: "Cert for Zitadel the platform oidc identity provider for iam"
}
"k2-httpbin": #ClusterCert & {
_name: "httpbin"
_cluster: "k2"
_description: "Test endpoint to verify the service mesh ingress gateway"
}
}
// #PlatformCert provisions a cert in the provisioner cluster. Workload clusters use ExternalSecret resources to fetch the Secret tls key and cert from the provisioner cluster.
#PlatformCert: #Certificate & {
_name: string
_wildcard: true | *false
metadata: name: string | *_name
metadata: namespace: string | *"istio-ingress"
spec: {
commonName: string | *"\(_name).\(#Platform.org.domain)"
if _wildcard {
dnsNames: [commonName, "*.\(commonName)"]
}
if !_wildcard {
dnsNames: [commonName]
}
secretName: metadata.name
issuerRef: kind: "ClusterIssuer"
issuerRef: name: string | *"letsencrypt"
}
}
// #ClusterCert provisions a cluster specific certificate.
#ClusterCert: #Certificate & {
_name: string
_cluster: string
_wildcard: true | *false
metadata: name: string | *"\(_cluster)-\(_name)"
metadata: namespace: string | *"istio-ingress"
spec: {
commonName: string | *"\(_name).\(_cluster).\(#Platform.org.domain)"
if _wildcard {
dnsNames: [commonName, "*.\(commonName)"]
}
if !_wildcard {
dnsNames: [commonName]
}
secretName: metadata.name
issuerRef: kind: "ClusterIssuer"
issuerRef: name: string | *"letsencrypt"
}
}

View File

@@ -0,0 +1,20 @@
package holos
// Provision all platform certificates.
#InputKeys: component: "certificates"
// Certificates usually go into the istio-system namespace, but they may go anywhere.
#TargetNamespace: "default"
// Depends on issuers
#DependsOn: _LetsEncrypt
#KubernetesObjects & {
apiObjects: {
for k, obj in #PlatformCerts {
"\(obj.kind)": {
"\(obj.metadata.namespace)/\(obj.metadata.name)": obj
}
}
}
}

View File

@@ -0,0 +1,43 @@
package holos
// https://cert-manager.io/docs/
#TargetNamespace: "cert-manager"
#InputKeys: {
component: "certmanager"
service: "cert-manager"
}
#HelmChart & {
values: #Values & {
installCRDs: true
startupapicheck: enabled: false
// Must not use kube-system on gke autopilot. GKE Warden authz blocks access.
global: leaderElection: namespace: #TargetNamespace
}
namespace: #TargetNamespace
chart: {
name: "cert-manager"
version: "1.14.3"
repository: {
name: "jetstack"
url: "https://charts.jetstack.io"
}
}
}
// https://cloud.google.com/kubernetes-engine/docs/concepts/autopilot-resource-requests#min-max-requests
#PodResources: {
requests: {
cpu: string | *"250m"
memory: string | *"512Mi"
"ephemeral-storage": string | *"100Mi"
}
}
// https://cloud.google.com/kubernetes-engine/docs/how-to/autopilot-spot-pods
#NodeSelector: {
"kubernetes.io/os": "linux"
"cloud.google.com/gke-spot": "true"
}

View File

@@ -1,6 +1,6 @@
package holos
#UpstreamValues: {
#Values: {
// +docs:section=Global
// Default values for cert-manager.
@@ -51,7 +51,7 @@ package holos
leaderElection: {
// Override the namespace used for the leader election lease
namespace: "kube-system"
namespace: string | *"kube-system"
}
}
@@ -246,7 +246,7 @@ package holos
// memory: 32Mi
//
// ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
resources: {}
resources: #PodResources
// Pod Security Context
// ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
@@ -310,9 +310,7 @@ package holos
// This default ensures that Pods are only scheduled to Linux nodes.
// It prevents Pods being scheduled to Windows nodes in a mixed OS cluster.
// +docs:property
nodeSelector: {
"kubernetes.io/os": "linux"
}
nodeSelector: #NodeSelector
// +docs:ignore
ingressShim: {}
@@ -408,7 +406,7 @@ package holos
enabled: true
servicemonitor: {
// Create a ServiceMonitor to add cert-manager to Prometheus
enabled: false
enabled: true | *false
// Specifies the `prometheus` label on the created ServiceMonitor, this is
// used when different Prometheus instances have label selectors matching
@@ -652,7 +650,7 @@ package holos
// memory: 32Mi
//
// ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
resources: {}
resources: #PodResources
// Liveness probe values
// ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes
@@ -685,9 +683,7 @@ package holos
// This default ensures that Pods are only scheduled to Linux nodes.
// It prevents Pods being scheduled to Windows nodes in a mixed OS cluster.
// +docs:property
nodeSelector: {
"kubernetes.io/os": "linux"
}
nodeSelector: #NodeSelector
// A Kubernetes Affinity, if required; see https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core
//
@@ -959,7 +955,7 @@ package holos
// memory: 32Mi
//
// ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
resources: {}
resources: #PodResources
// The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with
// matching labels.
@@ -968,9 +964,7 @@ package holos
// This default ensures that Pods are only scheduled to Linux nodes.
// It prevents Pods being scheduled to Windows nodes in a mixed OS cluster.
// +docs:property
nodeSelector: {
"kubernetes.io/os": "linux"
}
nodeSelector: #NodeSelector
// A Kubernetes Affinity, if required; see https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core
//
@@ -1098,7 +1092,7 @@ package holos
startupapicheck: {
// Enables the startup api check
enabled: true
enabled: *true | false
// Pod Security Context to be set on the startupapicheck component Pod
// ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
@@ -1151,7 +1145,7 @@ package holos
// memory: 32Mi
//
// ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
resources: {}
resources: #PodResources
// The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with
// matching labels.
@@ -1160,9 +1154,7 @@ package holos
// This default ensures that Pods are only scheduled to Linux nodes.
// It prevents Pods being scheduled to Windows nodes in a mixed OS cluster.
// +docs:property
nodeSelector: {
"kubernetes.io/os": "linux"
}
nodeSelector: #NodeSelector
// A Kubernetes Affinity, if required; see https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core
//

View File

@@ -0,0 +1,78 @@
package holos
// Lets Encrypt certificate issuers for public tls certs
#InputKeys: component: "letsencrypt"
#TargetNamespace: "cert-manager"
let Name = "letsencrypt"
// The cloudflare api token is platform scoped, not cluster scoped.
#SecretName: "cloudflare-api-token-secret"
// Depends on cert manager
#DependsOn: _CertManager
#KubernetesObjects & {
apiObjects: {
ClusterIssuer: {
letsencrypt: #ClusterIssuer & {
metadata: name: Name
spec: {
acme: {
email: #Platform.org.contact.email
server: "https://acme-v02.api.letsencrypt.org/directory"
privateKeySecretRef: name: Name
solvers: [{
dns01: cloudflare: {
email: #Platform.org.cloudflare.email
apiTokenSecretRef: name: #SecretName
apiTokenSecretRef: key: "api_token"
}}]
}
}
}
letsencryptStaging: #ClusterIssuer & {
metadata: name: Name + "-staging"
spec: {
acme: {
email: #Platform.org.contact.email
server: "https://acme-staging-v02.api.letsencrypt.org/directory"
privateKeySecretRef: name: Name + "-staging"
solvers: [{
dns01: cloudflare: {
email: #Platform.org.cloudflare.email
apiTokenSecretRef: name: #SecretName
apiTokenSecretRef: key: "api_token"
}}]
}
}
}
}
}
}
// _HTTPSolvers are disabled in the provisioner cluster, dns is the method supported by holos.
_HTTPSolvers: {
letsencryptHTTP: #ClusterIssuer & {
metadata: name: Name + "-http"
spec: {
acme: {
email: #Platform.org.contact.email
server: "https://acme-v02.api.letsencrypt.org/directory"
privateKeySecretRef: name: Name
solvers: [{http01: ingress: class: "istio"}]
}
}
}
letsencryptHTTPStaging: #ClusterIssuer & {
metadata: name: Name + "-http-staging"
spec: {
acme: {
email: #Platform.org.contact.email
server: "https://acme-staging-v02.api.letsencrypt.org/directory"
privateKeySecretRef: name: Name + "-staging"
solvers: [{http01: ingress: class: "istio"}]
}
}
}
}

View File

@@ -0,0 +1,13 @@
package holos
// Components under this directory are part of this collection
#InputKeys: project: "mesh"
// Shared dependencies for all components in this collection.
#DependsOn: _Namespaces
// Common Dependencies
_Namespaces: Namespaces: name: "\(#StageName)-secrets-namespaces"
_CertManager: CertManager: name: "\(#InstancePrefix)-certmanager"
_LetsEncrypt: LetsEncrypt: name: "\(#InstancePrefix)-letsencrypt"
_Certificates: Certificates: name: "\(#InstancePrefix)-certificates"

View File

@@ -3,7 +3,7 @@ package holos
#TargetNamespace: #InstancePrefix + "-zitadel"
#DB: {
Host: "crdb-public"
Host: "crdb-public"
}
// The canonical login domain for the entire platform. Zitadel will be active on a singlec cluster at a time, but always accessible from this hostname.

View File

@@ -1,6 +1,9 @@
package holos
#InputKeys: component: "zitadel"
import "encoding/yaml"
let Name = "zitadel"
#InputKeys: component: Name
// Upstream helm chart doesn't specify the namespace field for all resources.
#Kustomization: spec: targetNamespace: #TargetNamespace
@@ -8,10 +11,10 @@ package holos
#HelmChart & {
namespace: #TargetNamespace
chart: {
name: "zitadel"
name: Name
version: "7.9.0"
repository: {
name: "zitadel"
name: Name
url: "https://charts.zitadel.com"
}
}
@@ -22,22 +25,46 @@ package holos
_name: "zitadel-masterkey"
}
Certificate: zitadel: #Certificate & {
metadata: name: "crdb-zitadel-client"
metadata: name: "crdb-zitadel-client"
metadata: namespace: #TargetNamespace
spec: {
commonName: "zitadel"
issuerRef: {
group: "cert-manager.io"
kind: "Issuer"
name: "crdb-ca-issuer"
kind: "Issuer"
name: "crdb-ca-issuer"
}
privateKey: algorithm: "RSA"
privateKey: size: 2048
privateKey: size: 2048
renewBefore: "48h0m0s"
secretName: "cockroachdb-zitadel"
secretName: "cockroachdb-zitadel"
subject: organizations: ["Cockroach"]
usages: ["digital signature", "key encipherment", "client auth"]
}
}
VirtualService: zitadel: #VirtualService & {
metadata: name: Name
metadata: namespace: #TargetNamespace
spec: hosts: ["login.\(#Platform.org.domain)"]
spec: gateways: ["istio-ingress/default"]
spec: http: [{route: [{destination: host: Name}]}]
}
}
}
// TODO: Generalize this common pattern of injecting the istio sidecar into a Deployment
let Patch = [{op: "add", path: "/spec/template/metadata/labels/sidecar.istio.io~1inject", value: "true"}]
#Kustomize: {
patches: [
{
target: {
group: "apps"
version: "v1"
kind: "Deployment"
name: Name
}
patch: yaml.Marshal(Patch)
},
]
}

View File

@@ -1,61 +0,0 @@
package holos
// Lets Encrypt certificate issuers for public tls certs
#InputKeys: component: "certissuers"
#TargetNamespace: "cert-manager"
let Name = "letsencrypt"
// The cloudflare api token is platform scoped, not cluster scoped.
#SecretName: "cloudflare-api-token-secret"
// Depends on cert manager
#DependsOn: _CertManager
#KubernetesObjects & {
apiObjects: {
ClusterIssuer: {
letsencrypt: #ClusterIssuer & {
metadata: name: Name
spec: {
acme: {
email: #Platform.org.contact.email
server: "https://acme-v02.api.letsencrypt.org/directory"
privateKeySecretRef: name: Name + "-istio"
solvers: [{http01: ingress: class: "istio"}]
}
}
}
letsencryptStaging: #ClusterIssuer & {
metadata: name: Name + "-staging"
spec: {
acme: {
email: #Platform.org.contact.email
server: "https://acme-staging-v02.api.letsencrypt.org/directory"
privateKeySecretRef: name: Name + "-staging-istio"
solvers: [{http01: ingress: class: "istio"}]
}
}
}
letsencryptDns: #ClusterIssuer & {
metadata: name: Name + "-dns"
spec: {
acme: {
email: #Platform.org.contact.email
server: "https://acme-v02.api.letsencrypt.org/directory"
privateKeySecretRef: name: Name + "-istio"
solvers: [{
dns01: cloudflare: {
email: #Platform.org.cloudflare.email
apiTokenSecretRef: name: #SecretName
apiTokenSecretRef: key: "api_token"
}}]
}
}
}
}
ExternalSecret: "\(#SecretName)": #ExternalSecret & {
_name: #SecretName
}
}
}

View File

@@ -1,25 +0,0 @@
package holos
// https://cert-manager.io/docs/
#TargetNamespace: "cert-manager"
#InputKeys: {
component: "certmanager"
service: "cert-manager"
}
#HelmChart & {
values: #UpstreamValues & {
installCRDs: true
}
namespace: #TargetNamespace
chart: {
name: "cert-manager"
version: "1.14.3"
repository: {
name: "jetstack"
url: "https://charts.jetstack.io"
}
}
}

View File

@@ -11,24 +11,24 @@ let Name = "gateway"
// TODO: We need to generalize this for multiple services hanging off the default gateway.
let LoginCert = #Certificate & {
metadata: {
name: "login"
namespace: #TargetNamespace
}
spec: {
commonName: "login.\(#Platform.org.domain)"
dnsNames: [commonName]
secretName: metadata.name
issuerRef: kind: "ClusterIssuer"
issuerRef: name: "letsencrypt"
}
metadata: {
name: "login"
namespace: #TargetNamespace
}
spec: {
commonName: "login.\(#Platform.org.domain)"
dnsNames: [commonName]
secretName: metadata.name
issuerRef: kind: "ClusterIssuer"
issuerRef: name: "letsencrypt"
}
}
#KubernetesObjects & {
apiObjects: {
Certificate: login: LoginCert
Gateway: default: #Gateway & {
metadata: name: "default"
metadata: name: "default"
metadata: namespace: #TargetNamespace
spec: selector: istio: "ingressgateway"
spec: servers: [

View File

@@ -14,9 +14,12 @@ import (
crt "cert-manager.io/certificate/v1"
gw "networking.istio.io/gateway/v1beta1"
vs "networking.istio.io/virtualservice/v1beta1"
kc "sigs.k8s.io/kustomize/api/types"
"encoding/yaml"
)
let ResourcesFile = "resources.yaml"
// _apiVersion is the version of this schema. Defines the interface between CUE output and the holos cli.
_apiVersion: "holos.run/v1alpha1"
@@ -260,7 +263,7 @@ _apiVersion: "holos.run/v1alpha1"
}
}
// apiObjectsContent holds the marshalled representation of apiObjects
// apiObjectMap holds the marshalled representation of apiObjects
apiObjectMap: {
for kind, v in apiObjects {
"\(kind)": {
@@ -340,6 +343,10 @@ _apiVersion: "holos.run/v1alpha1"
platform: #Platform
// instance returns the key values of the holos component instance.
instance: #InputKeys
// resources is the intermediate file name for api objects.
resourcesFile: ResourcesFile
// kustomizeFiles represents the files in a kustomize directory tree.
kustomizeFiles: #KustomizeFiles.Files
}
// #PlatformSpec is the output schema of a platform specification.
@@ -360,6 +367,28 @@ _apiVersion: "holos.run/v1alpha1"
...
}
// #KustomizeTree represents a kustomize build.
#KustomizeFiles: {
Objects: {
"kustomization.yaml": #Kustomize
}
// Files holds the marshaled output holos writes to the filesystem
Files: {
for filename, obj in Objects {
"\(filename)": yaml.Marshal(obj)
}
...
}
}
// kustomization.yaml
#Kustomize: kc.#Kustomization & {
apiVersion: "kustomize.config.k8s.io/v1beta1"
kind: "Kustomization"
resources: [ResourcesFile]
...
}
// By default, render kind: Skipped so holos knows to skip over intermediate cue files.
// This enables the use of holos render ./foo/bar/baz/... when bar contains intermediary constraints which are not complete components.
// Holos skips over these intermediary cue instances.

10
go.mod
View File

@@ -5,10 +5,14 @@ go 1.21.5
require (
cuelang.org/go v0.7.0
github.com/mattn/go-isatty v0.0.20
github.com/rogpeppe/go-internal v1.12.0
github.com/spf13/cobra v1.7.0
golang.org/x/tools v0.18.0
k8s.io/api v0.29.2
k8s.io/apimachinery v0.29.2
k8s.io/client-go v0.29.2
k8s.io/kubectl v0.29.2
sigs.k8s.io/yaml v1.4.0
)
require (
@@ -27,7 +31,7 @@ require (
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/imdario/mergo v0.3.6 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
@@ -41,7 +45,6 @@ require (
github.com/opencontainers/image-spec v1.1.0-rc4 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/protocolbuffers/txtpbfmt v0.0.0-20230328191034-3462fbc510c0 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/oauth2 v0.10.0 // indirect
@@ -54,12 +57,9 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.29.2 // indirect
k8s.io/klog/v2 v2.110.1 // indirect
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
k8s.io/kubectl v0.29.2 // indirect
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)

11
go.sum
View File

@@ -46,8 +46,8 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJY
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -96,8 +96,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/protocolbuffers/txtpbfmt v0.0.0-20230328191034-3462fbc510c0 h1:sadMIsgmHpEOGbUs6VtHBXRR1OHevnj7hLx9ZcdNGW4=
github.com/protocolbuffers/txtpbfmt v0.0.0-20230328191034-3462fbc510c0/go.mod h1:jgxiZysxFPM+iWKwQwPR+y+Jvo54ARd4EisXxKYpB5c=
github.com/rogpeppe/go-internal v1.11.1-0.20231026093722-fa6a31e0812c h1:fPpdjePK1atuOg28PXfNSqgwf9I/qD1Hlo39JFwKBXk=
github.com/rogpeppe/go-internal v1.11.1-0.20231026093722-fa6a31e0812c/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -177,6 +175,7 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.29.2 h1:hBC7B9+MU+ptchxEqTNW2DkUosJpp1P+Wn6YncZ474A=
@@ -197,5 +196,5 @@ sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMm
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=

View File

@@ -23,7 +23,7 @@ func makeBuildRunFunc(cfg *holos.Config) command.RunFunc {
if result.Skip {
continue
}
outs = append(outs, result.FinalOutput())
outs = append(outs, result.AccumulatedOutput())
}
out := strings.Join(outs, "---\n")
if _, err := fmt.Fprintln(cmd.OutOrStdout(), out); err != nil {

View File

@@ -32,7 +32,7 @@ func makeRenderRunFunc(cfg *holos.Config) command.RunFunc {
}
// API Objects
path := result.Filename(cfg.WriteTo(), cfg.ClusterName())
if err := result.Save(ctx, path, result.FinalOutput()); err != nil {
if err := result.Save(ctx, path, result.AccumulatedOutput()); err != nil {
return wrapper.Wrap(err)
}
// Kustomization

View File

@@ -2,10 +2,12 @@ package secret
import (
"context"
"encoding/json"
"fmt"
"github.com/holos-run/holos/pkg/cli/command"
"github.com/holos-run/holos/pkg/holos"
"github.com/holos-run/holos/pkg/logger"
"github.com/holos-run/holos/pkg/util"
"github.com/holos-run/holos/pkg/wrapper"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -90,17 +92,24 @@ func makeGetRunFunc(hc *holos.Config, cfg *config) command.RunFunc {
printFile := *cfg.printFile
if len(toExtract) == 0 {
if printFile == "" {
printFile = secretName
}
}
if printFile != "" {
if data, found := secret.Data[printFile]; found {
hc.Write(data)
} else {
err := fmt.Errorf("cannot print: want %s have %v: did you mean --extract-all or --%s=name", printFile, keys, printFlagName)
return wrapper.Wrap(err)
if printFile == "" { // print all data keys
data := make(map[string]string)
for k, v := range secret.Data {
data[k] = string(v)
}
b, err := json.MarshalIndent(data, "", " ")
if err != nil {
return wrapper.Wrap(err)
}
b = util.EnsureNewline(b)
hc.Write(b)
} else { // print named data keys keys
if data, found := secret.Data[printFile]; found {
hc.Write(data)
} else {
err := fmt.Errorf("cannot print: want %s have %v: did you mean --extract-all or --%s=name", printFile, keys, printFlagName)
return wrapper.Wrap(err)
}
}
}

View File

@@ -36,6 +36,30 @@ var secret = v1.Secret{
Type: "Opaque",
}
var loginSecret = v1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "zitadel-admin-d7fgbgbfbt",
Namespace: "secrets",
Labels: map[string]string{
"holos.run/owner.name": "jeff",
"holos.run/secret.name": "zitadel-admin",
},
CreationTimestamp: metav1.Time{
Time: time.Date(2021, time.January, 1, 0, 0, 0, 0, time.UTC),
},
},
Data: map[string][]byte{
"url": []byte("https://login.example.com"),
"username": []byte("zitadel-admin@zitadel.login.example.com"),
"password": []byte("Password1!"),
},
Type: "Opaque",
}
// cmdHolos executes the holos root command with a kubernetes.Interface that
// persists for the duration of the testscript. holos is NOT executed in a
// subprocess, the current working directory is not and should not be changed.
@@ -72,7 +96,7 @@ func TestSecrets(t *testing.T) {
testscript.Run(t, testscript.Params{
Dir: "testdata",
Setup: func(env *testscript.Env) error {
env.Values[clientsetKey] = fake.NewSimpleClientset(&secret)
env.Values[clientsetKey] = fake.NewSimpleClientset(&secret, &loginSecret)
return nil
},
Cmds: map[string]func(ts *testscript.TestScript, neg bool, args []string){

View File

@@ -0,0 +1,7 @@
# Print the data key by default
holos get secret zitadel-admin
stdout '^{$'
stdout '^ "url": "https://login.example.com"'
stdout '^ "username": "zitadel-admin@zitadel.login.example.com"'
stdout '^ "password": "Password1!"'
stdout '^}$'

View File

@@ -82,13 +82,21 @@ type Metadata struct {
// holos cli. A map is used to improve the clarity of error messages from cue.
type apiObjectMap map[string]map[string]string
// fileContentMap is a map of file names to file contents.
type fileContentMap map[string]string
// Result is the build result for display or writing.
type Result struct {
Metadata Metadata `json:"metadata,omitempty"`
KsContent string `json:"ksContent,omitempty"`
APIObjectMap apiObjectMap `json:"apiObjectMap,omitempty"`
finalOutput string
Skip bool
Metadata Metadata `json:"metadata,omitempty"`
KsContent string `json:"ksContent,omitempty"`
// APIObjectMap holds the marshalled representation of api objects.
APIObjectMap apiObjectMap `json:"apiObjectMap,omitempty"`
accumulatedOutput string
Skip bool
// KustomizeFiles holds the files for a kustomize kustomization directory.
KustomizeFiles fileContentMap `json:"kustomizeFiles"`
// ResourcesFile is the file name used for api objects in kustomization.yaml
ResourcesFile string `json:"resourcesFile,omitempty"`
}
type Repository struct {
@@ -104,14 +112,15 @@ type Chart struct {
// A HelmChart represents a helm command to provide chart values in order to render kubernetes api objects.
type HelmChart struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Metadata Metadata `json:"metadata"`
KsContent string `json:"ksContent"`
Namespace string `json:"namespace"`
Chart Chart `json:"chart"`
ValuesContent string `json:"valuesContent"`
APIObjectMap apiObjectMap `json:"APIObjectMap"`
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Metadata Metadata `json:"metadata"`
KsContent string `json:"ksContent"`
Namespace string `json:"namespace"`
Chart Chart `json:"chart"`
ValuesContent string `json:"valuesContent"`
// APIObjectMap holds the marshalled representation of api objects.
APIObjectMap apiObjectMap `json:"APIObjectMap"`
}
// Name returns the metadata name of the result. Equivalent to the
@@ -128,14 +137,14 @@ func (r *Result) KustomizationFilename(writeTo string, cluster string) string {
return filepath.Join(writeTo, "clusters", cluster, "holos", "components", r.Name()+"-kustomization.gen.yaml")
}
// FinalOutput returns the final rendered output.
func (r *Result) FinalOutput() string {
return r.finalOutput
// AccumulatedOutput returns the accumulated rendered output.
func (r *Result) AccumulatedOutput() string {
return r.accumulatedOutput
}
// addAPIObjects adds the overlay api objects to finalOutput.
// addAPIObjects adds the overlay api objects to accumulatedOutput.
func (r *Result) addOverlayObjects(log *slog.Logger) {
b := []byte(r.FinalOutput())
b := []byte(r.AccumulatedOutput())
kinds := make([]string, 0, len(r.APIObjectMap))
// Sort the keys
for kind := range r.APIObjectMap {
@@ -155,13 +164,64 @@ func (r *Result) addOverlayObjects(log *slog.Logger) {
for _, name := range names {
yamlString := v[name]
log.Debug(fmt.Sprintf("%s/%s", kind, name), "kind", kind, "name", name)
util.EnsureNewline(b)
b = util.EnsureNewline(b)
header := fmt.Sprintf("---\n# Source: CUE apiObjects.%s.%s\n", kind, name)
b = append(b, []byte(header+yamlString)...)
util.EnsureNewline(b)
b = util.EnsureNewline(b)
}
}
r.finalOutput = string(b)
r.accumulatedOutput = string(b)
}
// kustomize replaces the final output with the output of kustomize build if the
func (r *Result) kustomize(ctx context.Context) error {
log := logger.FromContext(ctx)
if r.ResourcesFile == "" {
log.DebugContext(ctx, "skipping kustomize: no resourcesFile")
return nil
}
if len(r.KustomizeFiles) < 1 {
log.DebugContext(ctx, "skipping kustomize: no kustomizeFiles")
return nil
}
tempDir, err := os.MkdirTemp("", "holos.kustomize")
if err != nil {
return wrapper.Wrap(err)
}
defer remove(ctx, tempDir)
// Write the main api object resources file for kustomize.
target := filepath.Join(tempDir, r.ResourcesFile)
b := []byte(r.AccumulatedOutput())
b = util.EnsureNewline(b)
if err := os.WriteFile(target, b, 0644); err != nil {
return wrapper.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.KustomizeFiles {
target := filepath.Join(tempDir, file)
if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
return wrapper.Wrap(err)
}
b := []byte(content)
b = util.EnsureNewline(b)
if err := os.WriteFile(target, b, 0644); err != nil {
return wrapper.Wrap(fmt.Errorf("could not write: %w", err))
}
log.DebugContext(ctx, "wrote: "+target, "op", "write", "path", target, "bytes", len(b))
}
// Run kustomize.
kOut, err := runCmd(ctx, "kubectl", "kustomize", tempDir)
if err != nil {
log.ErrorContext(ctx, kOut.stderr.String())
return wrapper.Wrap(err)
}
// Replace the accumulated output
r.accumulatedOutput = kOut.stdout.String()
return nil
}
// Save writes the content to the filesystem for git ops.
@@ -278,6 +338,9 @@ func (b *Builder) Run(ctx context.Context) (results []*Result, err error) {
return nil, err
}
result.addOverlayObjects(log)
if err := result.kustomize(ctx); err != nil {
return nil, wrapper.Wrap(fmt.Errorf("could not kustomize: %w", err))
}
default:
return nil, wrapper.Wrap(fmt.Errorf("build kind not implemented: %v", kind))
}
@@ -392,7 +455,7 @@ func runHelm(ctx context.Context, hc *HelmChart, r *Result, path holos.PathCompo
return wrapper.Wrap(fmt.Errorf("could not run helm template: %w", err))
}
r.finalOutput = helmOut.stdout.String()
r.accumulatedOutput = helmOut.stdout.String()
return nil
}

View File

@@ -1 +1 @@
50
52

View File

@@ -1 +1 @@
2
0