From 98488100e4e1cc545150c5d5b62a5ff2abc63aaf Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 22 Dec 2025 08:48:54 +0100 Subject: [PATCH] [cozystack-operator] Introduce API objects: packages and packagesources Signed-off-by: Andrei Kvapil --- .../cozystackresourcedefinitions_types.go | 26 +- api/v1alpha1/package_types.go | 89 +++++ api/v1alpha1/packagesource_types.go | 171 +++++++++ api/v1alpha1/zz_generated.deepcopy.go | 355 ++++++++++++++++++ hack/update-codegen.sh | 6 +- .../core/installer/definitions/.gitattributes | 1 + .../definitions/cozystack.io_packages.yaml | 156 ++++++++ .../cozystack.io_packagesources.yaml | 251 +++++++++++++ packages/core/installer/templates/crds.yaml | 6 + 9 files changed, 1048 insertions(+), 13 deletions(-) create mode 100644 api/v1alpha1/package_types.go create mode 100644 api/v1alpha1/packagesource_types.go create mode 100644 packages/core/installer/definitions/.gitattributes create mode 100644 packages/core/installer/definitions/cozystack.io_packages.yaml create mode 100644 packages/core/installer/definitions/cozystack.io_packagesources.yaml create mode 100644 packages/core/installer/templates/crds.yaml diff --git a/api/v1alpha1/cozystackresourcedefinitions_types.go b/api/v1alpha1/cozystackresourcedefinitions_types.go index b2baee85..2f25fb2d 100644 --- a/api/v1alpha1/cozystackresourcedefinitions_types.go +++ b/api/v1alpha1/cozystackresourcedefinitions_types.go @@ -92,7 +92,8 @@ type CozystackResourceDefinitionApplication struct { type CozystackResourceDefinitionRelease struct { // Helm chart configuration - Chart CozystackResourceDefinitionChart `json:"chart"` + // +optional + Chart CozystackResourceDefinitionChart `json:"chart,omitempty"` // Labels for the release Labels map[string]string `json:"labels,omitempty"` // Prefix for the release name @@ -110,17 +111,18 @@ type CozystackResourceDefinitionRelease struct { // - {{ .namespace }}: The namespace of the resource being processed // // Example YAML: -// secrets: -// include: -// - matchExpressions: -// - key: badlabel -// operator: DoesNotExist -// matchLabels: -// goodlabel: goodvalue -// resourceNames: -// - "{{ .name }}-secret" -// - "{{ .kind }}-{{ .name }}-tls" -// - "specificname" +// +// secrets: +// include: +// - matchExpressions: +// - key: badlabel +// operator: DoesNotExist +// matchLabels: +// goodlabel: goodvalue +// resourceNames: +// - "{{ .name }}-secret" +// - "{{ .kind }}-{{ .name }}-tls" +// - "specificname" type CozystackResourceDefinitionResourceSelector struct { metav1.LabelSelector `json:",inline"` // ResourceNames is a list of resource names to match diff --git a/api/v1alpha1/package_types.go b/api/v1alpha1/package_types.go new file mode 100644 index 00000000..e1a3184b --- /dev/null +++ b/api/v1alpha1/package_types.go @@ -0,0 +1,89 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster,shortName={pkg,pkgs} +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Variant",type="string",JSONPath=".spec.variant",description="Selected variant" +// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].status",description="Ready status" +// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].message",description="Ready message" + +// Package is the Schema for the packages API +type Package struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec PackageSpec `json:"spec,omitempty"` + Status PackageStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// PackageList contains a list of Packages +type PackageList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Package `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Package{}, &PackageList{}) +} + +// PackageSpec defines the desired state of Package +type PackageSpec struct { + // Variant is the name of the variant to use from the PackageSource + // If not specified, defaults to "default" + // +optional + Variant string `json:"variant,omitempty"` + + // IgnoreDependencies is a list of package source dependencies to ignore + // Dependencies listed here will not be installed even if they are specified in the PackageSource + // +optional + IgnoreDependencies []string `json:"ignoreDependencies,omitempty"` + + // Components is a map of release name to component overrides + // Allows overriding values and enabling/disabling specific components from the PackageSource + // +optional + Components map[string]PackageComponent `json:"components,omitempty"` +} + +// PackageComponent defines overrides for a specific component +type PackageComponent struct { + // Enabled indicates whether this component should be installed + // If false, the component will be disabled even if it's defined in the PackageSource + // +optional + Enabled *bool `json:"enabled,omitempty"` + + // Values contains Helm chart values as a JSON object + // These values will be merged with the default values from the PackageSource + // +optional + Values *apiextensionsv1.JSON `json:"values,omitempty"` +} + +// PackageStatus defines the observed state of Package +type PackageStatus struct { + // Conditions represents the latest available observations of a Package's state + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` +} diff --git a/api/v1alpha1/packagesource_types.go b/api/v1alpha1/packagesource_types.go new file mode 100644 index 00000000..9586b568 --- /dev/null +++ b/api/v1alpha1/packagesource_types.go @@ -0,0 +1,171 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster,shortName={pkgsrc,pkgsrcs} +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Variants",type="string",JSONPath=".status.variants",description="Package variants (comma-separated)" +// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].status",description="Ready status" +// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].message",description="Ready message" + +// PackageSource is the Schema for the packagesources API +type PackageSource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec PackageSourceSpec `json:"spec,omitempty"` + Status PackageSourceStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// PackageSourceList contains a list of PackageSources +type PackageSourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []PackageSource `json:"items"` +} + +func init() { + SchemeBuilder.Register(&PackageSource{}, &PackageSourceList{}) +} + +// PackageSourceSpec defines the desired state of PackageSource +type PackageSourceSpec struct { + // SourceRef is the source reference for the package source charts + // +optional + SourceRef *PackageSourceRef `json:"sourceRef,omitempty"` + + // Variants is a list of package source variants + // Each variant defines components, applications, dependencies, and libraries for a specific configuration + // +optional + Variants []Variant `json:"variants,omitempty"` +} + +// Variant defines a single variant configuration +type Variant struct { + // Name is the unique identifier for this variant + // +required + Name string `json:"name"` + + // DependsOn is a list of package source dependencies + // For example: "cozystack.networking" + // +optional + DependsOn []string `json:"dependsOn,omitempty"` + + // Libraries is a list of Helm library charts used by components in this variant + // +optional + Libraries []Library `json:"libraries,omitempty"` + + // Components is a list of Helm releases to be installed as part of this variant + // +optional + Components []Component `json:"components,omitempty"` +} + +// Library defines a Helm library chart +type Library struct { + // Name is the optional name for library placed in charts + // +optional + Name string `json:"name,omitempty"` + + // Path is the path to the library chart directory + // +required + Path string `json:"path"` +} + +// PackageSourceRef defines the source reference for package source charts +type PackageSourceRef struct { + // Kind of the source reference + // +kubebuilder:validation:Enum=GitRepository;OCIRepository + // +required + Kind string `json:"kind"` + + // Name of the source reference + // +required + Name string `json:"name"` + + // Namespace of the source reference + // +required + Namespace string `json:"namespace"` + + // Path is the base path where packages are located in the source. + // For GitRepository, defaults to "packages" if not specified. + // For OCIRepository, defaults to empty string (root) if not specified. + // +optional + Path string `json:"path,omitempty"` +} + +// ComponentInstall defines installation parameters for a component +type ComponentInstall struct { + // ReleaseName is the name of the HelmRelease resource that will be created + // If not specified, defaults to the component Name field + // +optional + ReleaseName string `json:"releaseName,omitempty"` + + // Namespace is the Kubernetes namespace where the release will be installed + // +optional + Namespace string `json:"namespace,omitempty"` + + // Privileged indicates whether this release requires privileged access + // +optional + Privileged bool `json:"privileged,omitempty"` + + // DependsOn is a list of component names that must be installed before this component + // +optional + DependsOn []string `json:"dependsOn,omitempty"` +} + +// Component defines a single Helm release component within a package source +type Component struct { + // Name is the unique identifier for this component within the package source + // +required + Name string `json:"name"` + + // Path is the path to the Helm chart directory + // +required + Path string `json:"path"` + + // Install defines installation parameters for this component + // +optional + Install *ComponentInstall `json:"install,omitempty"` + + // Libraries is a list of library names that this component depends on + // These libraries must be defined at the variant level + // +optional + Libraries []string `json:"libraries,omitempty"` + + // ValuesFiles is a list of values file names to use + // +optional + ValuesFiles []string `json:"valuesFiles,omitempty"` +} + +// PackageSourceStatus defines the observed state of PackageSource +type PackageSourceStatus struct { + // Variants is a comma-separated list of package variant names + // This field is populated by the controller based on spec.variants keys + // +optional + Variants string `json:"variants,omitempty"` + + // Conditions represents the latest available observations of a PackageSource's state + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 42cf4c4a..10f6ebad 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -21,10 +21,62 @@ limitations under the License. package v1alpha1 import ( + "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Component) DeepCopyInto(out *Component) { + *out = *in + if in.Install != nil { + in, out := &in.Install, &out.Install + *out = new(ComponentInstall) + (*in).DeepCopyInto(*out) + } + if in.Libraries != nil { + in, out := &in.Libraries, &out.Libraries + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.ValuesFiles != nil { + in, out := &in.ValuesFiles, &out.ValuesFiles + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Component. +func (in *Component) DeepCopy() *Component { + if in == nil { + return nil + } + out := new(Component) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ComponentInstall) DeepCopyInto(out *ComponentInstall) { + *out = *in + if in.DependsOn != nil { + in, out := &in.DependsOn, &out.DependsOn + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComponentInstall. +func (in *ComponentInstall) DeepCopy() *ComponentInstall { + if in == nil { + return nil + } + out := new(ComponentInstall) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CozystackResourceDefinition) DeepCopyInto(out *CozystackResourceDefinition) { *out = *in @@ -256,6 +308,277 @@ func (in *CozystackResourceDefinitionSpec) DeepCopy() *CozystackResourceDefiniti return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Library) DeepCopyInto(out *Library) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Library. +func (in *Library) DeepCopy() *Library { + if in == nil { + return nil + } + out := new(Library) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Package) DeepCopyInto(out *Package) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Package. +func (in *Package) DeepCopy() *Package { + if in == nil { + return nil + } + out := new(Package) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Package) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PackageComponent) DeepCopyInto(out *PackageComponent) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) + **out = **in + } + if in.Values != nil { + in, out := &in.Values, &out.Values + *out = new(v1.JSON) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageComponent. +func (in *PackageComponent) DeepCopy() *PackageComponent { + if in == nil { + return nil + } + out := new(PackageComponent) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PackageList) DeepCopyInto(out *PackageList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Package, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageList. +func (in *PackageList) DeepCopy() *PackageList { + if in == nil { + return nil + } + out := new(PackageList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PackageList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PackageSource) DeepCopyInto(out *PackageSource) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageSource. +func (in *PackageSource) DeepCopy() *PackageSource { + if in == nil { + return nil + } + out := new(PackageSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PackageSource) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PackageSourceList) DeepCopyInto(out *PackageSourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]PackageSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageSourceList. +func (in *PackageSourceList) DeepCopy() *PackageSourceList { + if in == nil { + return nil + } + out := new(PackageSourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PackageSourceList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PackageSourceRef) DeepCopyInto(out *PackageSourceRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageSourceRef. +func (in *PackageSourceRef) DeepCopy() *PackageSourceRef { + if in == nil { + return nil + } + out := new(PackageSourceRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PackageSourceSpec) DeepCopyInto(out *PackageSourceSpec) { + *out = *in + if in.SourceRef != nil { + in, out := &in.SourceRef, &out.SourceRef + *out = new(PackageSourceRef) + **out = **in + } + if in.Variants != nil { + in, out := &in.Variants, &out.Variants + *out = make([]Variant, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageSourceSpec. +func (in *PackageSourceSpec) DeepCopy() *PackageSourceSpec { + if in == nil { + return nil + } + out := new(PackageSourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PackageSourceStatus) DeepCopyInto(out *PackageSourceStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageSourceStatus. +func (in *PackageSourceStatus) DeepCopy() *PackageSourceStatus { + if in == nil { + return nil + } + out := new(PackageSourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PackageSpec) DeepCopyInto(out *PackageSpec) { + *out = *in + if in.IgnoreDependencies != nil { + in, out := &in.IgnoreDependencies, &out.IgnoreDependencies + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Components != nil { + in, out := &in.Components, &out.Components + *out = make(map[string]PackageComponent, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageSpec. +func (in *PackageSpec) DeepCopy() *PackageSpec { + if in == nil { + return nil + } + out := new(PackageSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PackageStatus) DeepCopyInto(out *PackageStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageStatus. +func (in *PackageStatus) DeepCopy() *PackageStatus { + if in == nil { + return nil + } + out := new(PackageStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in Selector) DeepCopyInto(out *Selector) { { @@ -292,6 +615,38 @@ func (in *SourceRef) DeepCopy() *SourceRef { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Variant) DeepCopyInto(out *Variant) { + *out = *in + if in.DependsOn != nil { + in, out := &in.DependsOn, &out.DependsOn + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Libraries != nil { + in, out := &in.Libraries, &out.Libraries + *out = make([]Library, len(*in)) + copy(*out, *in) + } + if in.Components != nil { + in, out := &in.Components, &out.Components + *out = make([]Component, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Variant. +func (in *Variant) DeepCopy() *Variant { + if in == nil { + return nil + } + out := new(Variant) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Workload) DeepCopyInto(out *Workload) { *out = *in diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 0e43f717..3b2af7d9 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -24,7 +24,8 @@ API_KNOWN_VIOLATIONS_DIR="${API_KNOWN_VIOLATIONS_DIR:-"${SCRIPT_ROOT}/api/api-ru UPDATE_API_KNOWN_VIOLATIONS="${UPDATE_API_KNOWN_VIOLATIONS:-true}" CONTROLLER_GEN="go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.16.4" TMPDIR=$(mktemp -d) -COZY_CONTROLLER_CRDDIR=packages/system/cozystack-controller/crds +OPERATOR_CRDDIR=packages/core/installer/definitions +COZY_CONTROLLER_CRDDIR=packages/system/cozystack-controller/definitions COZY_RD_CRDDIR=packages/system/cozystack-resource-definition-crd/definition BACKUPS_CORE_CRDDIR=packages/system/backup-controller/definitions BACKUPSTRATEGY_CRDDIR=packages/system/backupstrategy-controller/definitions @@ -62,6 +63,9 @@ kube::codegen::gen_openapi \ $CONTROLLER_GEN object:headerFile="hack/boilerplate.go.txt" paths="./api/..." $CONTROLLER_GEN rbac:roleName=manager-role crd paths="./api/..." output:crd:artifacts:config=${TMPDIR} +mv ${TMPDIR}/cozystack.io_packages.yaml ${OPERATOR_CRDDIR}/cozystack.io_packages.yaml +mv ${TMPDIR}/cozystack.io_packagesources.yaml ${OPERATOR_CRDDIR}/cozystack.io_packagesources.yaml + mv ${TMPDIR}/cozystack.io_cozystackresourcedefinitions.yaml \ ${COZY_RD_CRDDIR}/cozystack.io_cozystackresourcedefinitions.yaml diff --git a/packages/core/installer/definitions/.gitattributes b/packages/core/installer/definitions/.gitattributes new file mode 100644 index 00000000..f581feca --- /dev/null +++ b/packages/core/installer/definitions/.gitattributes @@ -0,0 +1 @@ +*.yaml linguist-generated diff --git a/packages/core/installer/definitions/cozystack.io_packages.yaml b/packages/core/installer/definitions/cozystack.io_packages.yaml new file mode 100644 index 00000000..e048b636 --- /dev/null +++ b/packages/core/installer/definitions/cozystack.io_packages.yaml @@ -0,0 +1,156 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: packages.cozystack.io +spec: + group: cozystack.io + names: + kind: Package + listKind: PackageList + plural: packages + shortNames: + - pkg + - pkgs + singular: package + scope: Cluster + versions: + - additionalPrinterColumns: + - description: Selected variant + jsonPath: .spec.variant + name: Variant + type: string + - description: Ready status + jsonPath: .status.conditions[?(@.type=='Ready')].status + name: Ready + type: string + - description: Ready message + jsonPath: .status.conditions[?(@.type=='Ready')].message + name: Status + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Package is the Schema for the packages API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: PackageSpec defines the desired state of Package + properties: + components: + additionalProperties: + description: PackageComponent defines overrides for a specific component + properties: + enabled: + description: |- + Enabled indicates whether this component should be installed + If false, the component will be disabled even if it's defined in the PackageSource + type: boolean + values: + description: |- + Values contains Helm chart values as a JSON object + These values will be merged with the default values from the PackageSource + x-kubernetes-preserve-unknown-fields: true + type: object + description: |- + Components is a map of release name to component overrides + Allows overriding values and enabling/disabling specific components from the PackageSource + type: object + ignoreDependencies: + description: |- + IgnoreDependencies is a list of package source dependencies to ignore + Dependencies listed here will not be installed even if they are specified in the PackageSource + items: + type: string + type: array + variant: + description: |- + Variant is the name of the variant to use from the PackageSource + If not specified, defaults to "default" + type: string + type: object + status: + description: PackageStatus defines the observed state of Package + properties: + conditions: + description: Conditions represents the latest available observations + of a Package's state + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/core/installer/definitions/cozystack.io_packagesources.yaml b/packages/core/installer/definitions/cozystack.io_packagesources.yaml new file mode 100644 index 00000000..92a6335f --- /dev/null +++ b/packages/core/installer/definitions/cozystack.io_packagesources.yaml @@ -0,0 +1,251 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: packagesources.cozystack.io +spec: + group: cozystack.io + names: + kind: PackageSource + listKind: PackageSourceList + plural: packagesources + shortNames: + - pkgsrc + - pkgsrcs + singular: packagesource + scope: Cluster + versions: + - additionalPrinterColumns: + - description: Package variants (comma-separated) + jsonPath: .status.variants + name: Variants + type: string + - description: Ready status + jsonPath: .status.conditions[?(@.type=='Ready')].status + name: Ready + type: string + - description: Ready message + jsonPath: .status.conditions[?(@.type=='Ready')].message + name: Status + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: PackageSource is the Schema for the packagesources API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: PackageSourceSpec defines the desired state of PackageSource + properties: + sourceRef: + description: SourceRef is the source reference for the package source + charts + properties: + kind: + description: Kind of the source reference + enum: + - GitRepository + - OCIRepository + type: string + name: + description: Name of the source reference + type: string + namespace: + description: Namespace of the source reference + type: string + path: + description: |- + Path is the base path where packages are located in the source. + For GitRepository, defaults to "packages" if not specified. + For OCIRepository, defaults to empty string (root) if not specified. + type: string + required: + - kind + - name + - namespace + type: object + variants: + description: |- + Variants is a list of package source variants + Each variant defines components, applications, dependencies, and libraries for a specific configuration + items: + description: Variant defines a single variant configuration + properties: + components: + description: Components is a list of Helm releases to be installed + as part of this variant + items: + description: Component defines a single Helm release component + within a package source + properties: + install: + description: Install defines installation parameters for + this component + properties: + dependsOn: + description: DependsOn is a list of component names + that must be installed before this component + items: + type: string + type: array + namespace: + description: Namespace is the Kubernetes namespace + where the release will be installed + type: string + privileged: + description: Privileged indicates whether this release + requires privileged access + type: boolean + releaseName: + description: |- + ReleaseName is the name of the HelmRelease resource that will be created + If not specified, defaults to the component Name field + type: string + type: object + libraries: + description: |- + Libraries is a list of library names that this component depends on + These libraries must be defined at the variant level + items: + type: string + type: array + name: + description: Name is the unique identifier for this component + within the package source + type: string + path: + description: Path is the path to the Helm chart directory + type: string + valuesFiles: + description: ValuesFiles is a list of values file names + to use + items: + type: string + type: array + required: + - name + - path + type: object + type: array + dependsOn: + description: |- + DependsOn is a list of package source dependencies + For example: "cozystack.networking" + items: + type: string + type: array + libraries: + description: Libraries is a list of Helm library charts used + by components in this variant + items: + description: Library defines a Helm library chart + properties: + name: + description: Name is the optional name for library placed + in charts + type: string + path: + description: Path is the path to the library chart directory + type: string + required: + - path + type: object + type: array + name: + description: Name is the unique identifier for this variant + type: string + required: + - name + type: object + type: array + type: object + status: + description: PackageSourceStatus defines the observed state of PackageSource + properties: + conditions: + description: Conditions represents the latest available observations + of a PackageSource's state + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + variants: + description: |- + Variants is a comma-separated list of package variant names + This field is populated by the controller based on spec.variants keys + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/core/installer/templates/crds.yaml b/packages/core/installer/templates/crds.yaml new file mode 100644 index 00000000..fd7cf0a7 --- /dev/null +++ b/packages/core/installer/templates/crds.yaml @@ -0,0 +1,6 @@ +{{/* +{{- range $path, $_ := .Files.Glob "definitions/*.yaml" }} +--- +{{ $.Files.Get $path }} +{{- end }} +*/}}