Compare commits
48 commits
main
...
refactor-e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f0e042eac | ||
|
|
66ab048612 | ||
|
|
cc52c69922 | ||
|
|
4270d66376 | ||
|
|
2ca68eda69 | ||
|
|
9db99f7233 | ||
|
|
a89dd819ff | ||
|
|
657bddaeb9 | ||
|
|
51d0001589 | ||
|
|
e0ec967120 | ||
|
|
b77791a5fe | ||
|
|
3d9cfee401 | ||
|
|
e046206d2b | ||
|
|
c69756de51 | ||
|
|
15a9180b67 | ||
|
|
451ef73172 | ||
|
|
2077b0e515 | ||
|
|
aaf2d1326a | ||
|
|
ea1d0363d1 | ||
|
|
45bd323c6e | ||
|
|
b328124be7 | ||
|
|
35086bc362 | ||
|
|
7b28139ad9 | ||
|
|
5883fbf7ea | ||
|
|
167e85004c | ||
|
|
7fc458d136 | ||
|
|
bb220647ad | ||
|
|
a4cb9ae30b | ||
|
|
982727ac91 | ||
|
|
6c3a7b7efb | ||
|
|
923dbd209d | ||
|
|
c23826efac | ||
|
|
36119cec45 | ||
|
|
f98b429ad2 | ||
|
|
8a0935fb37 | ||
|
|
5dc9f590cf | ||
|
|
17286ad213 | ||
|
|
ea9d44b4af | ||
|
|
7c2bec197b | ||
|
|
4b1525a5f8 | ||
|
|
2113d17a54 | ||
|
|
4f97aef04c | ||
|
|
4b5d777b81 | ||
|
|
75197c6d25 | ||
|
|
c808ed6f24 | ||
|
|
222b582b68 | ||
|
|
2a87c83043 | ||
|
|
e5b65e8e77 |
356 changed files with 20895 additions and 4007 deletions
2
.github/workflows/pull-requests.yaml
vendored
2
.github/workflows/pull-requests.yaml
vendored
|
|
@ -58,7 +58,7 @@ jobs:
|
||||||
DOCKER_CONFIG: ${{ runner.temp }}/.docker
|
DOCKER_CONFIG: ${{ runner.temp }}/.docker
|
||||||
|
|
||||||
- name: Build Talos image
|
- name: Build Talos image
|
||||||
run: make -C packages/core/installer talos-nocloud
|
run: make -C packages/core/talos talos-nocloud
|
||||||
|
|
||||||
- name: Save git diff as patch
|
- name: Save git diff as patch
|
||||||
if: "!contains(github.event.pull_request.labels.*.name, 'release')"
|
if: "!contains(github.event.pull_request.labels.*.name, 'release')"
|
||||||
|
|
|
||||||
15
Makefile
15
Makefile
|
|
@ -26,21 +26,18 @@ build: build-deps
|
||||||
make -C packages/system/bucket image
|
make -C packages/system/bucket image
|
||||||
make -C packages/system/objectstorage-controller image
|
make -C packages/system/objectstorage-controller image
|
||||||
make -C packages/core/testing image
|
make -C packages/core/testing image
|
||||||
make -C packages/core/installer image
|
make -C packages/core/installer image-operator
|
||||||
|
make -C packages/core/talos image
|
||||||
|
make -C packages/core/platform image
|
||||||
|
make -C packages/core/installer image-packages
|
||||||
make manifests
|
make manifests
|
||||||
|
|
||||||
repos:
|
|
||||||
rm -rf _out
|
|
||||||
make -C packages/system repo
|
|
||||||
make -C packages/apps repo
|
|
||||||
make -C packages/extra repo
|
|
||||||
|
|
||||||
manifests:
|
manifests:
|
||||||
mkdir -p _out/assets
|
mkdir -p _out/assets
|
||||||
(cd packages/core/installer/; helm template -n cozy-installer installer .) > _out/assets/cozystack-installer.yaml
|
(cd packages/core/installer/; helm template -n cozy-system cozystack-operator . | sed '/^WARNING/d') > _out/assets/cozystack-installer.yaml
|
||||||
|
|
||||||
assets:
|
assets:
|
||||||
make -C packages/core/installer assets
|
make -C packages/core/talos assets
|
||||||
|
|
||||||
test:
|
test:
|
||||||
make -C packages/core/testing apply
|
make -C packages/core/testing apply
|
||||||
|
|
|
||||||
|
|
@ -18,50 +18,51 @@ package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:object:root=true
|
// +kubebuilder:object:root=true
|
||||||
// +kubebuilder:resource:scope=Cluster
|
// +kubebuilder:resource:scope=Cluster,shortName=appdef
|
||||||
|
|
||||||
// CozystackResourceDefinition is the Schema for the cozystackresourcedefinitions API
|
// ApplicationDefinition is the Schema for the applicationdefinitions API
|
||||||
type CozystackResourceDefinition struct {
|
type ApplicationDefinition struct {
|
||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
Spec CozystackResourceDefinitionSpec `json:"spec,omitempty"`
|
Spec ApplicationDefinitionSpec `json:"spec,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +kubebuilder:object:root=true
|
// +kubebuilder:object:root=true
|
||||||
|
|
||||||
// CozystackResourceDefinitionList contains a list of CozystackResourceDefinitions
|
// ApplicationDefinitionList contains a list of ApplicationDefinitions
|
||||||
type CozystackResourceDefinitionList struct {
|
type ApplicationDefinitionList struct {
|
||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
metav1.ListMeta `json:"metadata,omitempty"`
|
metav1.ListMeta `json:"metadata,omitempty"`
|
||||||
Items []CozystackResourceDefinition `json:"items"`
|
Items []ApplicationDefinition `json:"items"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
SchemeBuilder.Register(&CozystackResourceDefinition{}, &CozystackResourceDefinitionList{})
|
SchemeBuilder.Register(&ApplicationDefinition{}, &ApplicationDefinitionList{})
|
||||||
}
|
}
|
||||||
|
|
||||||
type CozystackResourceDefinitionSpec struct {
|
type ApplicationDefinitionSpec struct {
|
||||||
// Application configuration
|
// Application configuration
|
||||||
Application CozystackResourceDefinitionApplication `json:"application"`
|
Application ApplicationDefinitionApplication `json:"application"`
|
||||||
// Release configuration
|
// Release configuration
|
||||||
Release CozystackResourceDefinitionRelease `json:"release"`
|
Release ApplicationDefinitionRelease `json:"release"`
|
||||||
|
|
||||||
// Secret selectors
|
// Secret selectors
|
||||||
Secrets CozystackResourceDefinitionResources `json:"secrets,omitempty"`
|
Secrets ApplicationDefinitionResources `json:"secrets,omitempty"`
|
||||||
// Service selectors
|
// Service selectors
|
||||||
Services CozystackResourceDefinitionResources `json:"services,omitempty"`
|
Services ApplicationDefinitionResources `json:"services,omitempty"`
|
||||||
// Ingress selectors
|
// Ingress selectors
|
||||||
Ingresses CozystackResourceDefinitionResources `json:"ingresses,omitempty"`
|
Ingresses ApplicationDefinitionResources `json:"ingresses,omitempty"`
|
||||||
|
|
||||||
// Dashboard configuration for this resource
|
// Dashboard configuration for this resource
|
||||||
Dashboard *CozystackResourceDefinitionDashboard `json:"dashboard,omitempty"`
|
Dashboard *ApplicationDefinitionDashboard `json:"dashboard,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CozystackResourceDefinitionChart struct {
|
type ApplicationDefinitionChart struct {
|
||||||
// Name of the Helm chart
|
// Name of the Helm chart
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
// Source reference for the Helm chart
|
// Source reference for the Helm chart
|
||||||
|
|
@ -79,7 +80,7 @@ type SourceRef struct {
|
||||||
Namespace string `json:"namespace"`
|
Namespace string `json:"namespace"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CozystackResourceDefinitionApplication struct {
|
type ApplicationDefinitionApplication struct {
|
||||||
// Kind of the application, used for UI and API
|
// Kind of the application, used for UI and API
|
||||||
Kind string `json:"kind"`
|
Kind string `json:"kind"`
|
||||||
// OpenAPI schema for the application, used for API validation
|
// OpenAPI schema for the application, used for API validation
|
||||||
|
|
@ -90,16 +91,30 @@ type CozystackResourceDefinitionApplication struct {
|
||||||
Singular string `json:"singular"`
|
Singular string `json:"singular"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CozystackResourceDefinitionRelease struct {
|
// +kubebuilder:validation:XValidation:rule="(has(self.chart) && !has(self.chartRef)) || (!has(self.chart) && has(self.chartRef))",message="either chart or chartRef must be set, but not both"
|
||||||
// Helm chart configuration
|
type ApplicationDefinitionRelease struct {
|
||||||
Chart CozystackResourceDefinitionChart `json:"chart"`
|
// Helm chart configuration (for HelmRepository source)
|
||||||
|
// +optional
|
||||||
|
Chart *ApplicationDefinitionChart `json:"chart,omitempty"`
|
||||||
|
// Chart reference configuration (for ExternalArtifact source)
|
||||||
|
// +optional
|
||||||
|
ChartRef *ApplicationDefinitionChartRef `json:"chartRef,omitempty"`
|
||||||
// Labels for the release
|
// Labels for the release
|
||||||
Labels map[string]string `json:"labels,omitempty"`
|
Labels map[string]string `json:"labels,omitempty"`
|
||||||
// Prefix for the release name
|
// Prefix for the release name
|
||||||
Prefix string `json:"prefix"`
|
Prefix string `json:"prefix"`
|
||||||
|
// Default values to be merged into every HelmRelease created from this resource definition
|
||||||
|
// User-specified values in Application spec will override these default values
|
||||||
|
// +optional
|
||||||
|
Values *apiextensionsv1.JSON `json:"values,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CozystackResourceDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support.
|
type ApplicationDefinitionChartRef struct {
|
||||||
|
// Source reference for the chart (ExternalArtifact)
|
||||||
|
SourceRef SourceRef `json:"sourceRef"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplicationDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support.
|
||||||
// A resource matches this selector only if it satisfies ALL criteria:
|
// A resource matches this selector only if it satisfies ALL criteria:
|
||||||
// - Label selector conditions (matchExpressions and matchLabels)
|
// - Label selector conditions (matchExpressions and matchLabels)
|
||||||
// - AND has a name that matches one of the names in resourceNames (if specified)
|
// - AND has a name that matches one of the names in resourceNames (if specified)
|
||||||
|
|
@ -121,7 +136,7 @@ type CozystackResourceDefinitionRelease struct {
|
||||||
// - "{{ .name }}-secret"
|
// - "{{ .name }}-secret"
|
||||||
// - "{{ .kind }}-{{ .name }}-tls"
|
// - "{{ .kind }}-{{ .name }}-tls"
|
||||||
// - "specificname"
|
// - "specificname"
|
||||||
type CozystackResourceDefinitionResourceSelector struct {
|
type ApplicationDefinitionResourceSelector struct {
|
||||||
metav1.LabelSelector `json:",inline"`
|
metav1.LabelSelector `json:",inline"`
|
||||||
// ResourceNames is a list of resource names to match
|
// ResourceNames is a list of resource names to match
|
||||||
// If specified, the resource must have one of these exact names to match the selector
|
// If specified, the resource must have one of these exact names to match the selector
|
||||||
|
|
@ -129,16 +144,16 @@ type CozystackResourceDefinitionResourceSelector struct {
|
||||||
ResourceNames []string `json:"resourceNames,omitempty"`
|
ResourceNames []string `json:"resourceNames,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CozystackResourceDefinitionResources struct {
|
type ApplicationDefinitionResources struct {
|
||||||
// Exclude contains an array of resource selectors that target resources.
|
// Exclude contains an array of resource selectors that target resources.
|
||||||
// If a resource matches the selector in any of the elements in the array, it is
|
// If a resource matches the selector in any of the elements in the array, it is
|
||||||
// hidden from the user, regardless of the matches in the include array.
|
// hidden from the user, regardless of the matches in the include array.
|
||||||
Exclude []*CozystackResourceDefinitionResourceSelector `json:"exclude,omitempty"`
|
Exclude []*ApplicationDefinitionResourceSelector `json:"exclude,omitempty"`
|
||||||
// Include contains an array of resource selectors that target resources.
|
// Include contains an array of resource selectors that target resources.
|
||||||
// If a resource matches the selector in any of the elements in the array, and
|
// If a resource matches the selector in any of the elements in the array, and
|
||||||
// matches none of the selectors in the exclude array that resource is marked
|
// matches none of the selectors in the exclude array that resource is marked
|
||||||
// as a tenant resource and is visible to users.
|
// as a tenant resource and is visible to users.
|
||||||
Include []*CozystackResourceDefinitionResourceSelector `json:"include,omitempty"`
|
Include []*ApplicationDefinitionResourceSelector `json:"include,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Dashboard types ----
|
// ---- Dashboard types ----
|
||||||
|
|
@ -155,8 +170,8 @@ const (
|
||||||
DashboardTabYAML DashboardTab = "yaml"
|
DashboardTabYAML DashboardTab = "yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CozystackResourceDefinitionDashboard describes how this resource appears in the UI.
|
// ApplicationDefinitionDashboard describes how this resource appears in the UI.
|
||||||
type CozystackResourceDefinitionDashboard struct {
|
type ApplicationDefinitionDashboard struct {
|
||||||
// Human-readable name shown in the UI (e.g., "Bucket")
|
// Human-readable name shown in the UI (e.g., "Bucket")
|
||||||
Singular string `json:"singular"`
|
Singular string `json:"singular"`
|
||||||
// Plural human-readable name (e.g., "Buckets")
|
// Plural human-readable name (e.g., "Buckets")
|
||||||
230
api/v1alpha1/bundles_types.go
Normal file
230
api/v1alpha1/bundles_types.go
Normal file
|
|
@ -0,0 +1,230 @@
|
||||||
|
/*
|
||||||
|
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=bundle
|
||||||
|
|
||||||
|
// Bundle is the Schema for the bundles API
|
||||||
|
type Bundle struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
Spec BundleSpec `json:"spec,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
|
||||||
|
// BundleList contains a list of Bundles
|
||||||
|
type BundleList struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ListMeta `json:"metadata,omitempty"`
|
||||||
|
Items []Bundle `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
SchemeBuilder.Register(&Bundle{}, &BundleList{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// BundleSpec defines the desired state of Bundle
|
||||||
|
type BundleSpec struct {
|
||||||
|
// SourceRef is the source reference for the bundle charts
|
||||||
|
// +required
|
||||||
|
SourceRef BundleSourceRef `json:"sourceRef"`
|
||||||
|
|
||||||
|
// DependsOn is a list of bundle dependencies in the format "bundleName/target"
|
||||||
|
// For example: "cozystack-system/network"
|
||||||
|
// If specified, the dependencies listed in the target's packages will be taken
|
||||||
|
// from the specified bundle and added to all packages in this bundle
|
||||||
|
// +optional
|
||||||
|
DependsOn []string `json:"dependsOn,omitempty"`
|
||||||
|
|
||||||
|
// DependencyTargets defines named groups of packages that can be referenced
|
||||||
|
// by other bundles via dependsOn. Each target has a name and a list of packages.
|
||||||
|
// +optional
|
||||||
|
DependencyTargets []BundleDependencyTarget `json:"dependencyTargets,omitempty"`
|
||||||
|
|
||||||
|
// Libraries is a list of Helm library charts used by packages
|
||||||
|
// +optional
|
||||||
|
Libraries []BundleLibrary `json:"libraries,omitempty"`
|
||||||
|
|
||||||
|
// Artifacts is a list of Helm charts that will be built as ExternalArtifacts
|
||||||
|
// These artifacts can be referenced by ApplicationDefinitions
|
||||||
|
// +optional
|
||||||
|
Artifacts []BundleArtifact `json:"artifacts,omitempty"`
|
||||||
|
|
||||||
|
// Packages is a list of Helm releases to be installed as part of this bundle
|
||||||
|
// +required
|
||||||
|
Packages []BundleRelease `json:"packages"`
|
||||||
|
|
||||||
|
// DeletionPolicy defines how child resources should be handled when the bundle is deleted.
|
||||||
|
// - "Delete" (default): Child resources will be deleted when the bundle is deleted (via ownerReference).
|
||||||
|
// - "Orphan": Child resources will be orphaned (ownerReferences will be removed).
|
||||||
|
// +kubebuilder:validation:Enum=Delete;Orphan
|
||||||
|
// +kubebuilder:default=Delete
|
||||||
|
// +optional
|
||||||
|
DeletionPolicy DeletionPolicy `json:"deletionPolicy,omitempty"`
|
||||||
|
|
||||||
|
// Labels are labels that will be applied to all resources created by this bundle
|
||||||
|
// (ArtifactGenerators and HelmReleases). These labels are merged with the default
|
||||||
|
// cozystack.io/bundle label.
|
||||||
|
// +optional
|
||||||
|
Labels map[string]string `json:"labels,omitempty"`
|
||||||
|
|
||||||
|
// BasePath 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
|
||||||
|
BasePath string `json:"basePath,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeletionPolicy defines how child resources should be handled when the parent is deleted.
|
||||||
|
// +kubebuilder:validation:Enum=Delete;Orphan
|
||||||
|
type DeletionPolicy string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DeletionPolicyDelete means child resources will be deleted when the parent is deleted.
|
||||||
|
DeletionPolicyDelete DeletionPolicy = "Delete"
|
||||||
|
// DeletionPolicyOrphan means child resources will be orphaned (ownerReferences removed).
|
||||||
|
DeletionPolicyOrphan DeletionPolicy = "Orphan"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BundleDependencyTarget defines a named group of packages that can be referenced
|
||||||
|
// by other bundles via dependsOn
|
||||||
|
type BundleDependencyTarget struct {
|
||||||
|
// Name is the unique identifier for this dependency target
|
||||||
|
// +required
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// Packages is a list of package names that belong to this target
|
||||||
|
// These packages will be added as dependencies when this target is referenced
|
||||||
|
// +required
|
||||||
|
Packages []string `json:"packages"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BundleLibrary defines a Helm library chart
|
||||||
|
type BundleLibrary struct {
|
||||||
|
// Name is the unique identifier for this library
|
||||||
|
// +required
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// Path is the path to the library chart directory
|
||||||
|
// +required
|
||||||
|
Path string `json:"path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BundleArtifact defines a Helm chart artifact that will be built as ExternalArtifact
|
||||||
|
type BundleArtifact struct {
|
||||||
|
// Name is the unique identifier for this artifact (used as ExternalArtifact name)
|
||||||
|
// +required
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// Path is the path to the Helm chart directory
|
||||||
|
// +required
|
||||||
|
Path string `json:"path"`
|
||||||
|
|
||||||
|
// Libraries is a list of library names that this artifact depends on
|
||||||
|
// +optional
|
||||||
|
Libraries []string `json:"libraries,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BundleSourceRef defines the source reference for bundle charts
|
||||||
|
type BundleSourceRef 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:validation:XValidation:rule="(has(self.path) && !has(self.artifact)) || (!has(self.path) && has(self.artifact))",message="either path or artifact must be set, but not both"
|
||||||
|
// BundleRelease defines a single Helm release within a bundle
|
||||||
|
type BundleRelease struct {
|
||||||
|
// Name is the unique identifier for this release within the bundle
|
||||||
|
// +required
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// ReleaseName is the name of the HelmRelease resource that will be created
|
||||||
|
// +required
|
||||||
|
ReleaseName string `json:"releaseName"`
|
||||||
|
|
||||||
|
// Path is the path to the Helm chart directory
|
||||||
|
// Either Path or Artifact must be specified, but not both
|
||||||
|
// +optional
|
||||||
|
Path string `json:"path,omitempty"`
|
||||||
|
|
||||||
|
// Artifact is the name of an artifact from the bundle's artifacts list
|
||||||
|
// The artifact must exist in the bundle's artifacts section
|
||||||
|
// Either Path or Artifact must be specified, but not both
|
||||||
|
// +optional
|
||||||
|
Artifact string `json:"artifact,omitempty"`
|
||||||
|
|
||||||
|
// Namespace is the Kubernetes namespace where the release will be installed
|
||||||
|
// +required
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
|
||||||
|
// Privileged indicates whether this release requires privileged access
|
||||||
|
// +optional
|
||||||
|
Privileged bool `json:"privileged,omitempty"`
|
||||||
|
|
||||||
|
// Disabled indicates whether this release is disabled (should not be installed)
|
||||||
|
// +optional
|
||||||
|
Disabled bool `json:"disabled,omitempty"`
|
||||||
|
|
||||||
|
// DependsOn is a list of release names that must be installed before this release
|
||||||
|
// +optional
|
||||||
|
DependsOn []string `json:"dependsOn,omitempty"`
|
||||||
|
|
||||||
|
// Libraries is a list of library names that this package depends on
|
||||||
|
// +optional
|
||||||
|
Libraries []string `json:"libraries,omitempty"`
|
||||||
|
|
||||||
|
// Values contains Helm chart values as a JSON object
|
||||||
|
// +optional
|
||||||
|
Values *apiextensionsv1.JSON `json:"values,omitempty"`
|
||||||
|
|
||||||
|
// ValuesFiles is a list of values file names to use
|
||||||
|
// +optional
|
||||||
|
ValuesFiles []string `json:"valuesFiles,omitempty"`
|
||||||
|
|
||||||
|
// Labels are labels that will be applied to the HelmRelease created for this package
|
||||||
|
// These labels are merged with bundle-level labels and the default cozystack.io/bundle label
|
||||||
|
// +optional
|
||||||
|
Labels map[string]string `json:"labels,omitempty"`
|
||||||
|
|
||||||
|
// NamespaceLabels are labels that will be applied to the namespace for this package
|
||||||
|
// These labels are merged with labels from other packages in the same namespace
|
||||||
|
// +optional
|
||||||
|
NamespaceLabels map[string]string `json:"namespaceLabels,omitempty"`
|
||||||
|
|
||||||
|
// NamespaceAnnotations are annotations that will be applied to the namespace for this package
|
||||||
|
// These annotations are merged with annotations from other packages in the same namespace
|
||||||
|
// +optional
|
||||||
|
NamespaceAnnotations map[string]string `json:"namespaceAnnotations,omitempty"`
|
||||||
|
}
|
||||||
71
api/v1alpha1/platform_types.go
Normal file
71
api/v1alpha1/platform_types.go
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
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=platform
|
||||||
|
|
||||||
|
// Platform is the Schema for the platforms API
|
||||||
|
type Platform struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
Spec PlatformSpec `json:"spec,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
|
||||||
|
// PlatformList contains a list of Platform
|
||||||
|
type PlatformList struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ListMeta `json:"metadata,omitempty"`
|
||||||
|
Items []Platform `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
SchemeBuilder.Register(&Platform{}, &PlatformList{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlatformSpec defines the desired state of Platform
|
||||||
|
type PlatformSpec struct {
|
||||||
|
// SourceRef is the source reference for the platform chart
|
||||||
|
// This is used to generate the ArtifactGenerator
|
||||||
|
// +required
|
||||||
|
SourceRef SourceRef `json:"sourceRef"`
|
||||||
|
|
||||||
|
// Values contains Helm chart values as a JSON object
|
||||||
|
// These values are passed directly to HelmRelease.values
|
||||||
|
// +optional
|
||||||
|
Values *apiextensionsv1.JSON `json:"values,omitempty"`
|
||||||
|
|
||||||
|
// Interval is the interval at which to reconcile the HelmRelease
|
||||||
|
// +kubebuilder:default="5m"
|
||||||
|
// +optional
|
||||||
|
Interval *metav1.Duration `json:"interval,omitempty"`
|
||||||
|
|
||||||
|
// BasePath is the base path where the platform chart is located in the source.
|
||||||
|
// For GitRepository, defaults to "packages/core/platform" if not specified.
|
||||||
|
// For OCIRepository, defaults to "core/platform" if not specified.
|
||||||
|
// +optional
|
||||||
|
BasePath string `json:"basePath,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -21,30 +21,32 @@ limitations under the License.
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *CozystackResourceDefinition) DeepCopyInto(out *CozystackResourceDefinition) {
|
func (in *ApplicationDefinition) DeepCopyInto(out *ApplicationDefinition) {
|
||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
in.Spec.DeepCopyInto(&out.Spec)
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinition.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinition.
|
||||||
func (in *CozystackResourceDefinition) DeepCopy() *CozystackResourceDefinition {
|
func (in *ApplicationDefinition) DeepCopy() *ApplicationDefinition {
|
||||||
if in == nil {
|
if in == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
out := new(CozystackResourceDefinition)
|
out := new(ApplicationDefinition)
|
||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
func (in *CozystackResourceDefinition) DeepCopyObject() runtime.Object {
|
func (in *ApplicationDefinition) DeepCopyObject() runtime.Object {
|
||||||
if c := in.DeepCopy(); c != nil {
|
if c := in.DeepCopy(); c != nil {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
@ -52,38 +54,54 @@ func (in *CozystackResourceDefinition) DeepCopyObject() runtime.Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *CozystackResourceDefinitionApplication) DeepCopyInto(out *CozystackResourceDefinitionApplication) {
|
func (in *ApplicationDefinitionApplication) DeepCopyInto(out *ApplicationDefinitionApplication) {
|
||||||
*out = *in
|
*out = *in
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionApplication.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionApplication.
|
||||||
func (in *CozystackResourceDefinitionApplication) DeepCopy() *CozystackResourceDefinitionApplication {
|
func (in *ApplicationDefinitionApplication) DeepCopy() *ApplicationDefinitionApplication {
|
||||||
if in == nil {
|
if in == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
out := new(CozystackResourceDefinitionApplication)
|
out := new(ApplicationDefinitionApplication)
|
||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *CozystackResourceDefinitionChart) DeepCopyInto(out *CozystackResourceDefinitionChart) {
|
func (in *ApplicationDefinitionChart) DeepCopyInto(out *ApplicationDefinitionChart) {
|
||||||
*out = *in
|
*out = *in
|
||||||
out.SourceRef = in.SourceRef
|
out.SourceRef = in.SourceRef
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionChart.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionChart.
|
||||||
func (in *CozystackResourceDefinitionChart) DeepCopy() *CozystackResourceDefinitionChart {
|
func (in *ApplicationDefinitionChart) DeepCopy() *ApplicationDefinitionChart {
|
||||||
if in == nil {
|
if in == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
out := new(CozystackResourceDefinitionChart)
|
out := new(ApplicationDefinitionChart)
|
||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *CozystackResourceDefinitionDashboard) DeepCopyInto(out *CozystackResourceDefinitionDashboard) {
|
func (in *ApplicationDefinitionChartRef) DeepCopyInto(out *ApplicationDefinitionChartRef) {
|
||||||
|
*out = *in
|
||||||
|
out.SourceRef = in.SourceRef
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionChartRef.
|
||||||
|
func (in *ApplicationDefinitionChartRef) DeepCopy() *ApplicationDefinitionChartRef {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ApplicationDefinitionChartRef)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ApplicationDefinitionDashboard) DeepCopyInto(out *ApplicationDefinitionDashboard) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.Tags != nil {
|
if in.Tags != nil {
|
||||||
in, out := &in.Tags, &out.Tags
|
in, out := &in.Tags, &out.Tags
|
||||||
|
|
@ -108,42 +126,42 @@ func (in *CozystackResourceDefinitionDashboard) DeepCopyInto(out *CozystackResou
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionDashboard.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionDashboard.
|
||||||
func (in *CozystackResourceDefinitionDashboard) DeepCopy() *CozystackResourceDefinitionDashboard {
|
func (in *ApplicationDefinitionDashboard) DeepCopy() *ApplicationDefinitionDashboard {
|
||||||
if in == nil {
|
if in == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
out := new(CozystackResourceDefinitionDashboard)
|
out := new(ApplicationDefinitionDashboard)
|
||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *CozystackResourceDefinitionList) DeepCopyInto(out *CozystackResourceDefinitionList) {
|
func (in *ApplicationDefinitionList) DeepCopyInto(out *ApplicationDefinitionList) {
|
||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||||
if in.Items != nil {
|
if in.Items != nil {
|
||||||
in, out := &in.Items, &out.Items
|
in, out := &in.Items, &out.Items
|
||||||
*out = make([]CozystackResourceDefinition, len(*in))
|
*out = make([]ApplicationDefinition, len(*in))
|
||||||
for i := range *in {
|
for i := range *in {
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionList.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionList.
|
||||||
func (in *CozystackResourceDefinitionList) DeepCopy() *CozystackResourceDefinitionList {
|
func (in *ApplicationDefinitionList) DeepCopy() *ApplicationDefinitionList {
|
||||||
if in == nil {
|
if in == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
out := new(CozystackResourceDefinitionList)
|
out := new(ApplicationDefinitionList)
|
||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
func (in *CozystackResourceDefinitionList) DeepCopyObject() runtime.Object {
|
func (in *ApplicationDefinitionList) DeepCopyObject() runtime.Object {
|
||||||
if c := in.DeepCopy(); c != nil {
|
if c := in.DeepCopy(); c != nil {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
@ -151,9 +169,18 @@ func (in *CozystackResourceDefinitionList) DeepCopyObject() runtime.Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *CozystackResourceDefinitionRelease) DeepCopyInto(out *CozystackResourceDefinitionRelease) {
|
func (in *ApplicationDefinitionRelease) DeepCopyInto(out *ApplicationDefinitionRelease) {
|
||||||
*out = *in
|
*out = *in
|
||||||
out.Chart = in.Chart
|
if in.Chart != nil {
|
||||||
|
in, out := &in.Chart, &out.Chart
|
||||||
|
*out = new(ApplicationDefinitionChart)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.ChartRef != nil {
|
||||||
|
in, out := &in.ChartRef, &out.ChartRef
|
||||||
|
*out = new(ApplicationDefinitionChartRef)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
if in.Labels != nil {
|
if in.Labels != nil {
|
||||||
in, out := &in.Labels, &out.Labels
|
in, out := &in.Labels, &out.Labels
|
||||||
*out = make(map[string]string, len(*in))
|
*out = make(map[string]string, len(*in))
|
||||||
|
|
@ -161,20 +188,25 @@ func (in *CozystackResourceDefinitionRelease) DeepCopyInto(out *CozystackResourc
|
||||||
(*out)[key] = val
|
(*out)[key] = val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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 CozystackResourceDefinitionRelease.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionRelease.
|
||||||
func (in *CozystackResourceDefinitionRelease) DeepCopy() *CozystackResourceDefinitionRelease {
|
func (in *ApplicationDefinitionRelease) DeepCopy() *ApplicationDefinitionRelease {
|
||||||
if in == nil {
|
if in == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
out := new(CozystackResourceDefinitionRelease)
|
out := new(ApplicationDefinitionRelease)
|
||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *CozystackResourceDefinitionResourceSelector) DeepCopyInto(out *CozystackResourceDefinitionResourceSelector) {
|
func (in *ApplicationDefinitionResourceSelector) DeepCopyInto(out *ApplicationDefinitionResourceSelector) {
|
||||||
*out = *in
|
*out = *in
|
||||||
in.LabelSelector.DeepCopyInto(&out.LabelSelector)
|
in.LabelSelector.DeepCopyInto(&out.LabelSelector)
|
||||||
if in.ResourceNames != nil {
|
if in.ResourceNames != nil {
|
||||||
|
|
@ -184,55 +216,55 @@ func (in *CozystackResourceDefinitionResourceSelector) DeepCopyInto(out *Cozysta
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionResourceSelector.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionResourceSelector.
|
||||||
func (in *CozystackResourceDefinitionResourceSelector) DeepCopy() *CozystackResourceDefinitionResourceSelector {
|
func (in *ApplicationDefinitionResourceSelector) DeepCopy() *ApplicationDefinitionResourceSelector {
|
||||||
if in == nil {
|
if in == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
out := new(CozystackResourceDefinitionResourceSelector)
|
out := new(ApplicationDefinitionResourceSelector)
|
||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *CozystackResourceDefinitionResources) DeepCopyInto(out *CozystackResourceDefinitionResources) {
|
func (in *ApplicationDefinitionResources) DeepCopyInto(out *ApplicationDefinitionResources) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.Exclude != nil {
|
if in.Exclude != nil {
|
||||||
in, out := &in.Exclude, &out.Exclude
|
in, out := &in.Exclude, &out.Exclude
|
||||||
*out = make([]*CozystackResourceDefinitionResourceSelector, len(*in))
|
*out = make([]*ApplicationDefinitionResourceSelector, len(*in))
|
||||||
for i := range *in {
|
for i := range *in {
|
||||||
if (*in)[i] != nil {
|
if (*in)[i] != nil {
|
||||||
in, out := &(*in)[i], &(*out)[i]
|
in, out := &(*in)[i], &(*out)[i]
|
||||||
*out = new(CozystackResourceDefinitionResourceSelector)
|
*out = new(ApplicationDefinitionResourceSelector)
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if in.Include != nil {
|
if in.Include != nil {
|
||||||
in, out := &in.Include, &out.Include
|
in, out := &in.Include, &out.Include
|
||||||
*out = make([]*CozystackResourceDefinitionResourceSelector, len(*in))
|
*out = make([]*ApplicationDefinitionResourceSelector, len(*in))
|
||||||
for i := range *in {
|
for i := range *in {
|
||||||
if (*in)[i] != nil {
|
if (*in)[i] != nil {
|
||||||
in, out := &(*in)[i], &(*out)[i]
|
in, out := &(*in)[i], &(*out)[i]
|
||||||
*out = new(CozystackResourceDefinitionResourceSelector)
|
*out = new(ApplicationDefinitionResourceSelector)
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionResources.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionResources.
|
||||||
func (in *CozystackResourceDefinitionResources) DeepCopy() *CozystackResourceDefinitionResources {
|
func (in *ApplicationDefinitionResources) DeepCopy() *ApplicationDefinitionResources {
|
||||||
if in == nil {
|
if in == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
out := new(CozystackResourceDefinitionResources)
|
out := new(ApplicationDefinitionResources)
|
||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *CozystackResourceDefinitionSpec) DeepCopyInto(out *CozystackResourceDefinitionSpec) {
|
func (in *ApplicationDefinitionSpec) DeepCopyInto(out *ApplicationDefinitionSpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
out.Application = in.Application
|
out.Application = in.Application
|
||||||
in.Release.DeepCopyInto(&out.Release)
|
in.Release.DeepCopyInto(&out.Release)
|
||||||
|
|
@ -241,17 +273,339 @@ func (in *CozystackResourceDefinitionSpec) DeepCopyInto(out *CozystackResourceDe
|
||||||
in.Ingresses.DeepCopyInto(&out.Ingresses)
|
in.Ingresses.DeepCopyInto(&out.Ingresses)
|
||||||
if in.Dashboard != nil {
|
if in.Dashboard != nil {
|
||||||
in, out := &in.Dashboard, &out.Dashboard
|
in, out := &in.Dashboard, &out.Dashboard
|
||||||
*out = new(CozystackResourceDefinitionDashboard)
|
*out = new(ApplicationDefinitionDashboard)
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionSpec.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionSpec.
|
||||||
func (in *CozystackResourceDefinitionSpec) DeepCopy() *CozystackResourceDefinitionSpec {
|
func (in *ApplicationDefinitionSpec) DeepCopy() *ApplicationDefinitionSpec {
|
||||||
if in == nil {
|
if in == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
out := new(CozystackResourceDefinitionSpec)
|
out := new(ApplicationDefinitionSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *Bundle) DeepCopyInto(out *Bundle) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Bundle.
|
||||||
|
func (in *Bundle) DeepCopy() *Bundle {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(Bundle)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *Bundle) 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 *BundleArtifact) DeepCopyInto(out *BundleArtifact) {
|
||||||
|
*out = *in
|
||||||
|
if in.Libraries != nil {
|
||||||
|
in, out := &in.Libraries, &out.Libraries
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleArtifact.
|
||||||
|
func (in *BundleArtifact) DeepCopy() *BundleArtifact {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(BundleArtifact)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *BundleDependencyTarget) DeepCopyInto(out *BundleDependencyTarget) {
|
||||||
|
*out = *in
|
||||||
|
if in.Packages != nil {
|
||||||
|
in, out := &in.Packages, &out.Packages
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleDependencyTarget.
|
||||||
|
func (in *BundleDependencyTarget) DeepCopy() *BundleDependencyTarget {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(BundleDependencyTarget)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *BundleLibrary) DeepCopyInto(out *BundleLibrary) {
|
||||||
|
*out = *in
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleLibrary.
|
||||||
|
func (in *BundleLibrary) DeepCopy() *BundleLibrary {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(BundleLibrary)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *BundleList) DeepCopyInto(out *BundleList) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||||
|
if in.Items != nil {
|
||||||
|
in, out := &in.Items, &out.Items
|
||||||
|
*out = make([]Bundle, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleList.
|
||||||
|
func (in *BundleList) DeepCopy() *BundleList {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(BundleList)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *BundleList) 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 *BundleRelease) DeepCopyInto(out *BundleRelease) {
|
||||||
|
*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([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Values != nil {
|
||||||
|
in, out := &in.Values, &out.Values
|
||||||
|
*out = new(v1.JSON)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
if in.ValuesFiles != nil {
|
||||||
|
in, out := &in.ValuesFiles, &out.ValuesFiles
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Labels != nil {
|
||||||
|
in, out := &in.Labels, &out.Labels
|
||||||
|
*out = make(map[string]string, len(*in))
|
||||||
|
for key, val := range *in {
|
||||||
|
(*out)[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.NamespaceLabels != nil {
|
||||||
|
in, out := &in.NamespaceLabels, &out.NamespaceLabels
|
||||||
|
*out = make(map[string]string, len(*in))
|
||||||
|
for key, val := range *in {
|
||||||
|
(*out)[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.NamespaceAnnotations != nil {
|
||||||
|
in, out := &in.NamespaceAnnotations, &out.NamespaceAnnotations
|
||||||
|
*out = make(map[string]string, len(*in))
|
||||||
|
for key, val := range *in {
|
||||||
|
(*out)[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleRelease.
|
||||||
|
func (in *BundleRelease) DeepCopy() *BundleRelease {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(BundleRelease)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *BundleSourceRef) DeepCopyInto(out *BundleSourceRef) {
|
||||||
|
*out = *in
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleSourceRef.
|
||||||
|
func (in *BundleSourceRef) DeepCopy() *BundleSourceRef {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(BundleSourceRef)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *BundleSpec) DeepCopyInto(out *BundleSpec) {
|
||||||
|
*out = *in
|
||||||
|
out.SourceRef = in.SourceRef
|
||||||
|
if in.DependsOn != nil {
|
||||||
|
in, out := &in.DependsOn, &out.DependsOn
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.DependencyTargets != nil {
|
||||||
|
in, out := &in.DependencyTargets, &out.DependencyTargets
|
||||||
|
*out = make([]BundleDependencyTarget, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.Libraries != nil {
|
||||||
|
in, out := &in.Libraries, &out.Libraries
|
||||||
|
*out = make([]BundleLibrary, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Artifacts != nil {
|
||||||
|
in, out := &in.Artifacts, &out.Artifacts
|
||||||
|
*out = make([]BundleArtifact, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.Packages != nil {
|
||||||
|
in, out := &in.Packages, &out.Packages
|
||||||
|
*out = make([]BundleRelease, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.Labels != nil {
|
||||||
|
in, out := &in.Labels, &out.Labels
|
||||||
|
*out = make(map[string]string, len(*in))
|
||||||
|
for key, val := range *in {
|
||||||
|
(*out)[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleSpec.
|
||||||
|
func (in *BundleSpec) DeepCopy() *BundleSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(BundleSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *Platform) DeepCopyInto(out *Platform) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Platform.
|
||||||
|
func (in *Platform) DeepCopy() *Platform {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(Platform)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *Platform) 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 *PlatformList) DeepCopyInto(out *PlatformList) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||||
|
if in.Items != nil {
|
||||||
|
in, out := &in.Items, &out.Items
|
||||||
|
*out = make([]Platform, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlatformList.
|
||||||
|
func (in *PlatformList) DeepCopy() *PlatformList {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(PlatformList)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *PlatformList) 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 *PlatformSpec) DeepCopyInto(out *PlatformSpec) {
|
||||||
|
*out = *in
|
||||||
|
out.SourceRef = in.SourceRef
|
||||||
|
if in.Values != nil {
|
||||||
|
in, out := &in.Values, &out.Values
|
||||||
|
*out = new(v1.JSON)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
if in.Interval != nil {
|
||||||
|
in, out := &in.Interval, &out.Interval
|
||||||
|
*out = new(metav1.Duration)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlatformSpec.
|
||||||
|
func (in *PlatformSpec) DeepCopy() *PlatformSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(PlatformSpec)
|
||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
addr := flag.String("address", ":8123", "Address to listen on")
|
|
||||||
dir := flag.String("dir", "/cozystack/assets", "Directory to serve files from")
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
absDir, err := filepath.Abs(*dir)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error getting absolute path for %s: %v", *dir, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fs := http.FileServer(http.Dir(absDir))
|
|
||||||
http.Handle("/", fs)
|
|
||||||
|
|
||||||
log.Printf("Server starting on %s, serving directory %s", *addr, absDir)
|
|
||||||
|
|
||||||
err = http.ListenAndServe(*addr, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Server failed to start: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"flag"
|
"flag"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
|
||||||
|
|
||||||
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
|
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
|
||||||
// to ensure that exec-entrypoint and run can make use of them.
|
// to ensure that exec-entrypoint and run can make use of them.
|
||||||
|
|
@ -39,7 +38,6 @@ import (
|
||||||
cozystackiov1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
cozystackiov1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
||||||
"github.com/cozystack/cozystack/internal/controller"
|
"github.com/cozystack/cozystack/internal/controller"
|
||||||
"github.com/cozystack/cozystack/internal/controller/dashboard"
|
"github.com/cozystack/cozystack/internal/controller/dashboard"
|
||||||
"github.com/cozystack/cozystack/internal/telemetry"
|
|
||||||
|
|
||||||
helmv2 "github.com/fluxcd/helm-controller/api/v2"
|
helmv2 "github.com/fluxcd/helm-controller/api/v2"
|
||||||
// +kubebuilder:scaffold:imports
|
// +kubebuilder:scaffold:imports
|
||||||
|
|
@ -65,10 +63,6 @@ func main() {
|
||||||
var probeAddr string
|
var probeAddr string
|
||||||
var secureMetrics bool
|
var secureMetrics bool
|
||||||
var enableHTTP2 bool
|
var enableHTTP2 bool
|
||||||
var disableTelemetry bool
|
|
||||||
var telemetryEndpoint string
|
|
||||||
var telemetryInterval string
|
|
||||||
var cozystackVersion string
|
|
||||||
var reconcileDeployment bool
|
var reconcileDeployment bool
|
||||||
var tlsOpts []func(*tls.Config)
|
var tlsOpts []func(*tls.Config)
|
||||||
flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+
|
flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+
|
||||||
|
|
@ -81,14 +75,6 @@ func main() {
|
||||||
"If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.")
|
"If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.")
|
||||||
flag.BoolVar(&enableHTTP2, "enable-http2", false,
|
flag.BoolVar(&enableHTTP2, "enable-http2", false,
|
||||||
"If set, HTTP/2 will be enabled for the metrics and webhook servers")
|
"If set, HTTP/2 will be enabled for the metrics and webhook servers")
|
||||||
flag.BoolVar(&disableTelemetry, "disable-telemetry", false,
|
|
||||||
"Disable telemetry collection")
|
|
||||||
flag.StringVar(&telemetryEndpoint, "telemetry-endpoint", "https://telemetry.cozystack.io",
|
|
||||||
"Endpoint for sending telemetry data")
|
|
||||||
flag.StringVar(&telemetryInterval, "telemetry-interval", "15m",
|
|
||||||
"Interval between telemetry data collection (e.g. 15m, 1h)")
|
|
||||||
flag.StringVar(&cozystackVersion, "cozystack-version", "unknown",
|
|
||||||
"Version of Cozystack")
|
|
||||||
flag.BoolVar(&reconcileDeployment, "reconcile-deployment", false,
|
flag.BoolVar(&reconcileDeployment, "reconcile-deployment", false,
|
||||||
"If set, the Cozystack API server is assumed to run as a Deployment, else as a DaemonSet.")
|
"If set, the Cozystack API server is assumed to run as a Deployment, else as a DaemonSet.")
|
||||||
opts := zap.Options{
|
opts := zap.Options{
|
||||||
|
|
@ -97,21 +83,6 @@ func main() {
|
||||||
opts.BindFlags(flag.CommandLine)
|
opts.BindFlags(flag.CommandLine)
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
// Parse telemetry interval
|
|
||||||
interval, err := time.ParseDuration(telemetryInterval)
|
|
||||||
if err != nil {
|
|
||||||
setupLog.Error(err, "invalid telemetry interval")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure telemetry
|
|
||||||
telemetryConfig := telemetry.Config{
|
|
||||||
Disabled: disableTelemetry,
|
|
||||||
Endpoint: telemetryEndpoint,
|
|
||||||
Interval: interval,
|
|
||||||
CozystackVersion: cozystackVersion,
|
|
||||||
}
|
|
||||||
|
|
||||||
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
|
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
|
||||||
|
|
||||||
// if the enable-http2 flag is false (the default), http/2 should be disabled
|
// if the enable-http2 flag is false (the default), http/2 should be disabled
|
||||||
|
|
@ -200,32 +171,20 @@ func main() {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = (&controller.TenantHelmReconciler{
|
if err = (&controller.NamespaceHelmReconciler{
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
}).SetupWithManager(mgr); err != nil {
|
}).SetupWithManager(mgr); err != nil {
|
||||||
setupLog.Error(err, "unable to create controller", "controller", "TenantHelmReconciler")
|
setupLog.Error(err, "unable to create controller", "controller", "NamespaceHelmReconciler")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = (&controller.CozystackConfigReconciler{
|
if err = (&controller.ApplicationDefinitionReconciler{
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
|
CozystackAPIKind: "Deployment",
|
||||||
}).SetupWithManager(mgr); err != nil {
|
}).SetupWithManager(mgr); err != nil {
|
||||||
setupLog.Error(err, "unable to create controller", "controller", "CozystackConfigReconciler")
|
setupLog.Error(err, "unable to create controller", "controller", "ApplicationDefinitionReconciler")
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
cozyAPIKind := "DaemonSet"
|
|
||||||
if reconcileDeployment {
|
|
||||||
cozyAPIKind = "Deployment"
|
|
||||||
}
|
|
||||||
if err = (&controller.CozystackResourceDefinitionReconciler{
|
|
||||||
Client: mgr.GetClient(),
|
|
||||||
Scheme: mgr.GetScheme(),
|
|
||||||
CozystackAPIKind: cozyAPIKind,
|
|
||||||
}).SetupWithManager(mgr); err != nil {
|
|
||||||
setupLog.Error(err, "unable to create controller", "controller", "CozystackResourceDefinitionReconciler")
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -249,19 +208,6 @@ func main() {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize telemetry collector
|
|
||||||
collector, err := telemetry.NewCollector(mgr.GetClient(), &telemetryConfig, mgr.GetConfig())
|
|
||||||
if err != nil {
|
|
||||||
setupLog.V(1).Error(err, "unable to create telemetry collector, telemetry will be disabled")
|
|
||||||
}
|
|
||||||
|
|
||||||
if collector != nil {
|
|
||||||
if err := mgr.Add(collector); err != nil {
|
|
||||||
setupLog.Error(err, "unable to set up telemetry collector")
|
|
||||||
setupLog.V(1).Error(err, "unable to set up telemetry collector, continuing without telemetry")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setupLog.Info("starting manager")
|
setupLog.Info("starting manager")
|
||||||
ctx := ctrl.SetupSignalHandler()
|
ctx := ctrl.SetupSignalHandler()
|
||||||
dashboardManager.InitializeStaticResources(ctx)
|
dashboardManager.InitializeStaticResources(ctx)
|
||||||
|
|
|
||||||
312
cmd/cozystack-operator/main.go
Normal file
312
cmd/cozystack-operator/main.go
Normal file
|
|
@ -0,0 +1,312 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 The Cozystack Authors.
|
||||||
|
|
||||||
|
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 main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
|
||||||
|
// to ensure that exec-entrypoint and run can make use of them.
|
||||||
|
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||||
|
|
||||||
|
cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
||||||
|
helmv2 "github.com/fluxcd/helm-controller/api/v2"
|
||||||
|
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||||
|
sourcewatcherv1beta1 "github.com/fluxcd/source-watcher/api/v2/v1beta1"
|
||||||
|
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
|
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||||
|
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||||
|
|
||||||
|
"github.com/cozystack/cozystack/internal/fluxinstall"
|
||||||
|
"github.com/cozystack/cozystack/internal/operator"
|
||||||
|
"github.com/cozystack/cozystack/internal/telemetry"
|
||||||
|
// +kubebuilder:scaffold:imports
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
scheme = runtime.NewScheme()
|
||||||
|
setupLog = ctrl.Log.WithName("setup")
|
||||||
|
)
|
||||||
|
|
||||||
|
// stringSliceFlag is a custom flag type that allows multiple values
|
||||||
|
type stringSliceFlag []string
|
||||||
|
|
||||||
|
func (f *stringSliceFlag) String() string {
|
||||||
|
return strings.Join(*f, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *stringSliceFlag) Set(value string) error {
|
||||||
|
*f = append(*f, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
|
||||||
|
utilruntime.Must(apiextensionsv1.AddToScheme(scheme))
|
||||||
|
utilruntime.Must(cozyv1alpha1.AddToScheme(scheme))
|
||||||
|
utilruntime.Must(helmv2.AddToScheme(scheme))
|
||||||
|
utilruntime.Must(sourcev1.AddToScheme(scheme))
|
||||||
|
utilruntime.Must(sourcewatcherv1beta1.AddToScheme(scheme))
|
||||||
|
// +kubebuilder:scaffold:scheme
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var metricsAddr string
|
||||||
|
var enableLeaderElection bool
|
||||||
|
var probeAddr string
|
||||||
|
var secureMetrics bool
|
||||||
|
var enableHTTP2 bool
|
||||||
|
var installFlux bool
|
||||||
|
var disableTelemetry bool
|
||||||
|
var telemetryEndpoint string
|
||||||
|
var telemetryInterval string
|
||||||
|
var cozystackVersion string
|
||||||
|
var installFluxResources stringSliceFlag
|
||||||
|
|
||||||
|
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
|
||||||
|
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
|
||||||
|
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
|
||||||
|
"Enable leader election for controller manager. "+
|
||||||
|
"Enabling this will ensure there is only one active controller manager.")
|
||||||
|
flag.BoolVar(&secureMetrics, "metrics-secure", false,
|
||||||
|
"If set the metrics endpoint is served securely")
|
||||||
|
flag.BoolVar(&enableHTTP2, "enable-http2", false,
|
||||||
|
"If set, HTTP/2 will be enabled for the metrics and webhook servers")
|
||||||
|
flag.BoolVar(&installFlux, "install-flux", false, "Install Flux components before starting reconcile loop")
|
||||||
|
flag.Var(&installFluxResources, "install-flux-resource", "Install Flux resource (JSON format). Can be specified multiple times. Applied after Flux installation.")
|
||||||
|
flag.BoolVar(&disableTelemetry, "disable-telemetry", false,
|
||||||
|
"Disable telemetry collection")
|
||||||
|
flag.StringVar(&telemetryEndpoint, "telemetry-endpoint", "https://telemetry.cozystack.io",
|
||||||
|
"Endpoint for sending telemetry data")
|
||||||
|
flag.StringVar(&telemetryInterval, "telemetry-interval", "15m",
|
||||||
|
"Interval between telemetry data collection (e.g. 15m, 1h)")
|
||||||
|
flag.StringVar(&cozystackVersion, "cozystack-version", "unknown",
|
||||||
|
"Version of Cozystack")
|
||||||
|
|
||||||
|
opts := zap.Options{
|
||||||
|
Development: true,
|
||||||
|
}
|
||||||
|
opts.BindFlags(flag.CommandLine)
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
// Parse telemetry interval
|
||||||
|
interval, err := time.ParseDuration(telemetryInterval)
|
||||||
|
if err != nil {
|
||||||
|
setupLog.Error(err, "invalid telemetry interval")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure telemetry
|
||||||
|
telemetryConfig := telemetry.Config{
|
||||||
|
Disabled: disableTelemetry,
|
||||||
|
Endpoint: telemetryEndpoint,
|
||||||
|
Interval: interval,
|
||||||
|
CozystackVersion: cozystackVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
|
||||||
|
|
||||||
|
config := ctrl.GetConfigOrDie()
|
||||||
|
|
||||||
|
// Start the controller manager
|
||||||
|
setupLog.Info("Starting controller manager")
|
||||||
|
mgr, err := ctrl.NewManager(config, ctrl.Options{
|
||||||
|
Scheme: scheme,
|
||||||
|
Metrics: metricsserver.Options{
|
||||||
|
BindAddress: metricsAddr,
|
||||||
|
SecureServing: secureMetrics,
|
||||||
|
},
|
||||||
|
WebhookServer: webhook.NewServer(webhook.Options{
|
||||||
|
Port: 9443,
|
||||||
|
}),
|
||||||
|
HealthProbeBindAddress: probeAddr,
|
||||||
|
LeaderElection: enableLeaderElection,
|
||||||
|
LeaderElectionID: "platform-operator.cozystack.io",
|
||||||
|
// LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily
|
||||||
|
// when the Manager ends. This requires the binary to immediately end when the
|
||||||
|
// Manager is stopped, otherwise, setting this significantly speeds up voluntary
|
||||||
|
// leader transitions as the new leader don't have to wait LeaseDuration time first.
|
||||||
|
//
|
||||||
|
// In the default scaffold provided, the program ends immediately after
|
||||||
|
// the manager stops, so would be fine to enable this option. However,
|
||||||
|
// if you are doing or is intended to do any operation such as perform cleanups
|
||||||
|
// after the manager stops then its usage might be unsafe.
|
||||||
|
// LeaderElectionReleaseOnCancel: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
setupLog.Error(err, "unable to start manager")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install Flux before starting reconcile loop
|
||||||
|
if installFlux {
|
||||||
|
setupLog.Info("Installing Flux components before starting reconcile loop")
|
||||||
|
installCtx, installCancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
|
defer installCancel()
|
||||||
|
|
||||||
|
// The namespace will be automatically extracted from the embedded manifests
|
||||||
|
if err := fluxinstall.Install(installCtx, mgr.GetClient(), fluxinstall.WriteEmbeddedManifests); err != nil {
|
||||||
|
setupLog.Error(err, "failed to install Flux, continuing anyway")
|
||||||
|
// Don't exit - allow operator to start even if Flux install fails
|
||||||
|
// This allows the operator to work in environments where Flux is already installed
|
||||||
|
} else {
|
||||||
|
setupLog.Info("Flux installation completed successfully")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install Flux resources after Flux installation
|
||||||
|
if len(installFluxResources) > 0 {
|
||||||
|
setupLog.Info("Installing Flux resources", "count", len(installFluxResources))
|
||||||
|
installCtx, installCancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||||
|
defer installCancel()
|
||||||
|
|
||||||
|
if err := installFluxResourcesFunc(installCtx, mgr.GetClient(), installFluxResources); err != nil {
|
||||||
|
setupLog.Error(err, "failed to install Flux resources, continuing anyway")
|
||||||
|
// Don't exit - allow operator to start even if resource installation fails
|
||||||
|
} else {
|
||||||
|
setupLog.Info("Flux resources installation completed successfully")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bundleReconciler := &operator.BundleReconciler{
|
||||||
|
Client: mgr.GetClient(),
|
||||||
|
Scheme: mgr.GetScheme(),
|
||||||
|
}
|
||||||
|
if err = bundleReconciler.SetupWithManager(mgr); err != nil {
|
||||||
|
setupLog.Error(err, "unable to create controller", "controller", "Bundle")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
platformReconciler := &operator.PlatformReconciler{
|
||||||
|
Client: mgr.GetClient(),
|
||||||
|
Scheme: mgr.GetScheme(),
|
||||||
|
}
|
||||||
|
if err = platformReconciler.SetupWithManager(mgr); err != nil {
|
||||||
|
setupLog.Error(err, "unable to create controller", "controller", "Platform")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:scaffold:builder
|
||||||
|
|
||||||
|
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
|
||||||
|
setupLog.Error(err, "unable to set up health check")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
|
||||||
|
setupLog.Error(err, "unable to set up ready check")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize telemetry collector
|
||||||
|
collector, err := telemetry.NewCollector(mgr.GetClient(), &telemetryConfig, mgr.GetConfig())
|
||||||
|
if err != nil {
|
||||||
|
setupLog.V(1).Error(err, "unable to create telemetry collector, telemetry will be disabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
if collector != nil {
|
||||||
|
if err := mgr.Add(collector); err != nil {
|
||||||
|
setupLog.Error(err, "unable to set up telemetry collector")
|
||||||
|
setupLog.V(1).Error(err, "unable to set up telemetry collector, continuing without telemetry")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setupLog.Info("Starting controller manager")
|
||||||
|
mgrCtx := ctrl.SetupSignalHandler()
|
||||||
|
if err := mgr.Start(mgrCtx); err != nil {
|
||||||
|
setupLog.Error(err, "problem running manager")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// installFluxResourcesFunc installs Flux resources from JSON strings
|
||||||
|
func installFluxResourcesFunc(ctx context.Context, k8sClient client.Client, resources []string) error {
|
||||||
|
logger := log.FromContext(ctx)
|
||||||
|
|
||||||
|
for i, resourceJSON := range resources {
|
||||||
|
logger.Info("Installing Flux resource", "index", i+1, "total", len(resources))
|
||||||
|
|
||||||
|
// Parse JSON into unstructured object
|
||||||
|
var obj unstructured.Unstructured
|
||||||
|
if err := json.Unmarshal([]byte(resourceJSON), &obj.Object); err != nil {
|
||||||
|
return fmt.Errorf("failed to parse resource JSON at index %d: %w", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate that it has required fields
|
||||||
|
if obj.GetAPIVersion() == "" {
|
||||||
|
return fmt.Errorf("resource at index %d missing apiVersion", i)
|
||||||
|
}
|
||||||
|
if obj.GetKind() == "" {
|
||||||
|
return fmt.Errorf("resource at index %d missing kind", i)
|
||||||
|
}
|
||||||
|
if obj.GetName() == "" {
|
||||||
|
return fmt.Errorf("resource at index %d missing metadata.name", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the resource (create or update)
|
||||||
|
logger.Info("Applying Flux resource",
|
||||||
|
"apiVersion", obj.GetAPIVersion(),
|
||||||
|
"kind", obj.GetKind(),
|
||||||
|
"name", obj.GetName(),
|
||||||
|
"namespace", obj.GetNamespace(),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Use server-side apply or create/update
|
||||||
|
existing := &unstructured.Unstructured{}
|
||||||
|
existing.SetGroupVersionKind(obj.GroupVersionKind())
|
||||||
|
key := client.ObjectKey{
|
||||||
|
Name: obj.GetName(),
|
||||||
|
Namespace: obj.GetNamespace(),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := k8sClient.Get(ctx, key, existing)
|
||||||
|
if err != nil {
|
||||||
|
if client.IgnoreNotFound(err) == nil {
|
||||||
|
// Resource doesn't exist, create it
|
||||||
|
if err := k8sClient.Create(ctx, &obj); err != nil {
|
||||||
|
return fmt.Errorf("failed to create resource %s/%s: %w", obj.GetKind(), obj.GetName(), err)
|
||||||
|
}
|
||||||
|
logger.Info("Created Flux resource", "kind", obj.GetKind(), "name", obj.GetName())
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("failed to check if resource exists: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Resource exists, update it
|
||||||
|
obj.SetResourceVersion(existing.GetResourceVersion())
|
||||||
|
if err := k8sClient.Update(ctx, &obj); err != nil {
|
||||||
|
return fmt.Errorf("failed to update resource %s/%s: %w", obj.GetKind(), obj.GetName(), err)
|
||||||
|
}
|
||||||
|
logger.Info("Updated Flux resource", "kind", obj.GetKind(), "name", obj.GetName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
31
examples/platform-example.yaml
Normal file
31
examples/platform-example.yaml
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
apiVersion: cozystack.io/v1alpha1
|
||||||
|
kind: Platform
|
||||||
|
metadata:
|
||||||
|
name: cozystack-platform
|
||||||
|
# Cluster-scoped resource, no namespace needed
|
||||||
|
spec:
|
||||||
|
# SourceRef is required - reference to the OCIRepository or GitRepository
|
||||||
|
sourceRef:
|
||||||
|
kind: OCIRepository
|
||||||
|
name: cozystack-packages
|
||||||
|
namespace: cozy-system
|
||||||
|
|
||||||
|
# Optional: Interval for HelmRelease reconciliation (default: 5m)
|
||||||
|
interval: 5m
|
||||||
|
|
||||||
|
# Optional: BasePath is the base path where the platform chart is located in the source.
|
||||||
|
# For GitRepository, defaults to "packages/core/platform" if not specified.
|
||||||
|
# For OCIRepository, defaults to "core/platform" if not specified.
|
||||||
|
# basePath: core/platform
|
||||||
|
|
||||||
|
# Optional: Values to pass to HelmRelease
|
||||||
|
# These values will be merged with sourceRef (which is automatically added)
|
||||||
|
values:
|
||||||
|
# Any custom values can be added here
|
||||||
|
# sourceRef will be automatically added by the controller
|
||||||
|
# Example custom values:
|
||||||
|
# customKey: customValue
|
||||||
|
# nested:
|
||||||
|
# config:
|
||||||
|
# enabled: true
|
||||||
|
|
||||||
148
go.mod
148
go.mod
|
|
@ -2,33 +2,39 @@
|
||||||
|
|
||||||
module github.com/cozystack/cozystack
|
module github.com/cozystack/cozystack
|
||||||
|
|
||||||
go 1.23.0
|
go 1.25.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/fluxcd/helm-controller/api v1.1.0
|
github.com/fluxcd/helm-controller/api v1.4.3
|
||||||
|
github.com/fluxcd/source-controller/api v1.6.2
|
||||||
|
github.com/fluxcd/source-watcher/api/v2 v2.0.2
|
||||||
|
github.com/go-logr/logr v1.4.3
|
||||||
|
github.com/go-logr/zapr v1.3.0
|
||||||
github.com/google/gofuzz v1.2.0
|
github.com/google/gofuzz v1.2.0
|
||||||
github.com/onsi/ginkgo/v2 v2.19.0
|
github.com/onsi/ginkgo/v2 v2.23.3
|
||||||
github.com/onsi/gomega v1.33.1
|
github.com/onsi/gomega v1.37.0
|
||||||
github.com/spf13/cobra v1.8.1
|
github.com/prometheus/client_golang v1.22.0
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/spf13/cobra v1.9.1
|
||||||
|
github.com/stretchr/testify v1.11.1
|
||||||
|
go.uber.org/zap v1.27.0
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
k8s.io/api v0.31.2
|
k8s.io/api v0.34.1
|
||||||
k8s.io/apiextensions-apiserver v0.31.2
|
k8s.io/apiextensions-apiserver v0.34.1
|
||||||
k8s.io/apimachinery v0.31.2
|
k8s.io/apimachinery v0.34.1
|
||||||
k8s.io/apiserver v0.31.2
|
k8s.io/apiserver v0.34.1
|
||||||
k8s.io/client-go v0.31.2
|
k8s.io/client-go v0.34.1
|
||||||
k8s.io/component-base v0.31.2
|
k8s.io/component-base v0.34.1
|
||||||
k8s.io/klog/v2 v2.130.1
|
k8s.io/klog/v2 v2.130.1
|
||||||
k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2
|
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
|
||||||
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8
|
k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d
|
||||||
sigs.k8s.io/controller-runtime v0.19.0
|
sigs.k8s.io/controller-runtime v0.22.2
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1
|
sigs.k8s.io/structured-merge-diff/v4 v4.7.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
cel.dev/expr v0.24.0 // indirect
|
||||||
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
|
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
|
||||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect
|
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||||
|
|
@ -36,86 +42,88 @@ require (
|
||||||
github.com/coreos/go-semver v0.3.1 // indirect
|
github.com/coreos/go-semver v0.3.1 // indirect
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
||||||
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
|
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
|
||||||
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
|
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/fluxcd/pkg/apis/kustomize v1.6.1 // indirect
|
github.com/fluxcd/pkg/apis/acl v0.9.0 // indirect
|
||||||
github.com/fluxcd/pkg/apis/meta v1.6.1 // indirect
|
github.com/fluxcd/pkg/apis/kustomize v1.13.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
github.com/fluxcd/pkg/apis/meta v1.22.0 // indirect
|
||||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||||
github.com/go-logr/logr v1.4.2 // indirect
|
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-logr/zapr v1.3.0 // indirect
|
|
||||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||||
github.com/go-openapi/swag v0.23.0 // indirect
|
github.com/go-openapi/swag v0.23.0 // indirect
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/google/cel-go v0.21.0 // indirect
|
github.com/google/btree v1.1.3 // indirect
|
||||||
github.com/google/gnostic-models v0.6.8 // indirect
|
github.com/google/cel-go v0.26.0 // indirect
|
||||||
github.com/google/go-cmp v0.6.0 // indirect
|
github.com/google/gnostic-models v0.7.0 // indirect
|
||||||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
|
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/gorilla/websocket v1.5.0 // indirect
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
|
||||||
github.com/imdario/mergo v0.3.6 // indirect
|
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||||
github.com/moby/spdystream v0.4.0 // indirect
|
github.com/mailru/easyjson v0.9.0 // indirect
|
||||||
|
github.com/moby/spdystream v0.5.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/prometheus/client_golang v1.19.1 // indirect
|
|
||||||
github.com/prometheus/client_model v0.6.1 // indirect
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
github.com/prometheus/common v0.55.0 // indirect
|
github.com/prometheus/common v0.62.0 // indirect
|
||||||
github.com/prometheus/procfs v0.15.1 // indirect
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.7 // indirect
|
||||||
github.com/stoewer/go-strcase v1.3.0 // indirect
|
github.com/stoewer/go-strcase v1.3.0 // indirect
|
||||||
github.com/x448/float16 v0.8.4 // indirect
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
go.etcd.io/etcd/api/v3 v3.5.16 // indirect
|
go.etcd.io/etcd/api/v3 v3.6.4 // indirect
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.16 // indirect
|
go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect
|
||||||
go.etcd.io/etcd/client/v3 v3.5.16 // indirect
|
go.etcd.io/etcd/client/v3 v3.6.4 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect
|
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.28.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
|
go.opentelemetry.io/otel v1.35.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.28.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk v1.28.0 // indirect
|
go.opentelemetry.io/otel/metric v1.35.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.28.0 // indirect
|
go.opentelemetry.io/otel/sdk v1.34.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
go.opentelemetry.io/otel/trace v1.35.0 // indirect
|
||||||
|
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.uber.org/zap v1.27.0 // indirect
|
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||||
golang.org/x/crypto v0.31.0 // indirect
|
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||||
|
golang.org/x/crypto v0.42.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||||
golang.org/x/net v0.33.0 // indirect
|
golang.org/x/net v0.45.0 // indirect
|
||||||
golang.org/x/oauth2 v0.23.0 // indirect
|
golang.org/x/oauth2 v0.29.0 // indirect
|
||||||
golang.org/x/sync v0.10.0 // indirect
|
golang.org/x/sync v0.17.0 // indirect
|
||||||
golang.org/x/sys v0.28.0 // indirect
|
golang.org/x/sys v0.36.0 // indirect
|
||||||
golang.org/x/term v0.27.0 // indirect
|
golang.org/x/term v0.35.0 // indirect
|
||||||
golang.org/x/text v0.21.0 // indirect
|
golang.org/x/text v0.29.0 // indirect
|
||||||
golang.org/x/time v0.7.0 // indirect
|
golang.org/x/time v0.11.0 // indirect
|
||||||
golang.org/x/tools v0.26.0 // indirect
|
golang.org/x/tools v0.37.0 // indirect
|
||||||
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
|
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||||
google.golang.org/grpc v1.65.0 // indirect
|
google.golang.org/grpc v1.72.1 // indirect
|
||||||
google.golang.org/protobuf v1.34.2 // indirect
|
google.golang.org/protobuf v1.36.5 // indirect
|
||||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
k8s.io/kms v0.31.2 // indirect
|
k8s.io/kms v0.34.1 // indirect
|
||||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 // indirect
|
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect
|
||||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
|
||||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||||
|
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
|
||||||
|
sigs.k8s.io/yaml v1.6.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
||||||
345
go.sum
345
go.sum
|
|
@ -1,11 +1,11 @@
|
||||||
|
cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
|
||||||
|
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
|
||||||
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
||||||
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
|
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
|
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
|
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
|
|
||||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||||
|
|
@ -18,45 +18,48 @@ github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr
|
||||||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||||
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
|
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
|
||||||
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||||
github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
|
github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=
|
||||||
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
|
github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
|
||||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/fluxcd/helm-controller/api v1.1.0 h1:NS5Wm3U6Kv4w7Cw2sDOV++vf2ecGfFV00x1+2Y3QcOY=
|
github.com/fluxcd/helm-controller/api v1.4.3 h1:CdZwjL1liXmYCWyk2jscmFEB59tICIlnWB9PfDDW5q4=
|
||||||
github.com/fluxcd/helm-controller/api v1.1.0/go.mod h1:BgHMgMY6CWynzl4KIbHpd6Wpn3FN9BqgkwmvoKCp6iE=
|
github.com/fluxcd/helm-controller/api v1.4.3/go.mod h1:0XrBhKEaqvxyDj/FziG1Q8Fmx2UATdaqLgYqmZh6wW4=
|
||||||
github.com/fluxcd/pkg/apis/kustomize v1.6.1 h1:22FJc69Mq4i8aCxnKPlddHhSMyI4UPkQkqiAdWFcqe0=
|
github.com/fluxcd/pkg/apis/acl v0.9.0 h1:wBpgsKT+jcyZEcM//OmZr9RiF8klL3ebrDp2u2ThsnA=
|
||||||
github.com/fluxcd/pkg/apis/kustomize v1.6.1/go.mod h1:5dvQ4IZwz0hMGmuj8tTWGtarsuxW0rWsxJOwC6i+0V8=
|
github.com/fluxcd/pkg/apis/acl v0.9.0/go.mod h1:TttNS+gocsGLwnvmgVi3/Yscwqrjc17+vhgYfqkfrV4=
|
||||||
github.com/fluxcd/pkg/apis/meta v1.6.1 h1:maLhcRJ3P/70ArLCY/LF/YovkxXbX+6sTWZwZQBeNq0=
|
github.com/fluxcd/pkg/apis/kustomize v1.13.0 h1:GGf0UBVRIku+gebY944icVeEIhyg1P/KE3IrhOyJJnE=
|
||||||
github.com/fluxcd/pkg/apis/meta v1.6.1/go.mod h1:YndB/gxgGZmKfqpAfFxyCDNFJFP0ikpeJzs66jwq280=
|
github.com/fluxcd/pkg/apis/kustomize v1.13.0/go.mod h1:TLKVqbtnzkhDuhWnAsN35977HvRfIjs+lgMuNro/LEc=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/fluxcd/pkg/apis/meta v1.22.0 h1:EHWQH5ZWml7i8eZ/AMjm1jxid3j/PQ31p+hIwCt6crM=
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
github.com/fluxcd/pkg/apis/meta v1.22.0/go.mod h1:Kc1+bWe5p0doROzuV9XiTfV/oL3ddsemYXt8ZYWdVVg=
|
||||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
github.com/fluxcd/source-controller/api v1.6.2 h1:UmodAeqLIeF29HdTqf2GiacZyO+hJydJlepDaYsMvhc=
|
||||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
github.com/fluxcd/source-controller/api v1.6.2/go.mod h1:ZJcAi0nemsnBxjVgmJl0WQzNvB0rMETxQMTdoFosmMw=
|
||||||
|
github.com/fluxcd/source-watcher/api/v2 v2.0.2 h1:fWSxsDqYN7My2AEpQwbP7O6Qjix8nGBX+UE/qWHtZfM=
|
||||||
|
github.com/fluxcd/source-watcher/api/v2 v2.0.2/go.mod h1:Hs6ueayPt23jlkIr/d1pGPZ+OHiibQwWjxvU6xqljzg=
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
|
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
|
||||||
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
|
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
|
||||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
||||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
||||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
|
||||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||||
|
|
@ -64,162 +67,169 @@ github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZ
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||||
github.com/google/cel-go v0.21.0 h1:cl6uW/gxN+Hy50tNYvI691+sXxioCnstFzLp2WO4GCI=
|
github.com/google/cel-go v0.26.0 h1:DPGjXackMpJWH680oGY4lZhYjIameYmR+/6RBdDGmaI=
|
||||||
github.com/google/cel-go v0.21.0/go.mod h1:rHUlWCcBKgyEk+eV03RPdZUekPp6YcJwV0FxuUksYxc=
|
github.com/google/cel-go v0.26.0/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM=
|
||||||
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
|
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
|
||||||
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
|
github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k=
|
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
|
||||||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
|
||||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
|
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
|
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.0 h1:FbSCl+KggFl+Ocym490i/EyXF4lPgLoUtcSWquBM0Rs=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.0/go.mod h1:qOchhhIlmRcqk/O9uCo/puJlyo07YINaIqdZfZG3Jkc=
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
|
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
|
|
||||||
github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
|
|
||||||
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
|
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
|
||||||
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
|
||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||||
|
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8=
|
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||||
github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
|
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||||
|
github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
|
||||||
|
github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
|
||||||
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
|
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
|
||||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||||
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
|
github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0=
|
||||||
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
|
github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM=
|
||||||
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
|
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
|
||||||
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
|
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||||
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||||
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
|
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||||
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
|
github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
|
||||||
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
|
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
|
||||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
|
||||||
|
github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
|
github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
|
||||||
github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
|
github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk=
|
||||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
|
github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
|
go.etcd.io/bbolt v1.4.2 h1:IrUHp260R8c+zYx/Tm8QZr04CX+qWS5PGfPdevhdm1I=
|
||||||
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
|
go.etcd.io/bbolt v1.4.2/go.mod h1:Is8rSHO/b4f3XigBC0lL0+4FwAQv3HXEEIgFMuKHceM=
|
||||||
go.etcd.io/etcd/api/v3 v3.5.16 h1:WvmyJVbjWqK4R1E+B12RRHz3bRGy9XVfh++MgbN+6n0=
|
go.etcd.io/etcd/api/v3 v3.6.4 h1:7F6N7toCKcV72QmoUKa23yYLiiljMrT4xCeBL9BmXdo=
|
||||||
go.etcd.io/etcd/api/v3 v3.5.16/go.mod h1:1P4SlIP/VwkDmGo3OlOD7faPeP8KDIFhqvciH5EfN28=
|
go.etcd.io/etcd/api/v3 v3.6.4/go.mod h1:eFhhvfR8Px1P6SEuLT600v+vrhdDTdcfMzmnxVXXSbk=
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.16 h1:ZgY48uH6UvB+/7R9Yf4x574uCO3jIx0TRDyetSfId3Q=
|
go.etcd.io/etcd/client/pkg/v3 v3.6.4 h1:9HBYrjppeOfFjBjaMTRxT3R7xT0GLK8EJMVC4xg6ok0=
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.16/go.mod h1:V8acl8pcEK0Y2g19YlOV9m9ssUe6MgiDSobSoaBAM0E=
|
go.etcd.io/etcd/client/pkg/v3 v3.6.4/go.mod h1:sbdzr2cl3HzVmxNw//PH7aLGVtY4QySjQFuaCgcRFAI=
|
||||||
go.etcd.io/etcd/client/v2 v2.305.13 h1:RWfV1SX5jTU0lbCvpVQe3iPQeAHETWdOTb6pxhd77C8=
|
go.etcd.io/etcd/client/v3 v3.6.4 h1:YOMrCfMhRzY8NgtzUsHl8hC2EBSnuqbR3dh84Uryl7A=
|
||||||
go.etcd.io/etcd/client/v2 v2.305.13/go.mod h1:iQnL7fepbiomdXMb3om1rHq96htNNGv2sJkEcZGDRRg=
|
go.etcd.io/etcd/client/v3 v3.6.4/go.mod h1:jaNNHCyg2FdALyKWnd7hxZXZxZANb0+KGY+YQaEMISo=
|
||||||
go.etcd.io/etcd/client/v3 v3.5.16 h1:sSmVYOAHeC9doqi0gv7v86oY/BTld0SEFGaxsU9eRhE=
|
go.etcd.io/etcd/pkg/v3 v3.6.4 h1:fy8bmXIec1Q35/jRZ0KOes8vuFxbvdN0aAFqmEfJZWA=
|
||||||
go.etcd.io/etcd/client/v3 v3.5.16/go.mod h1:X+rExSGkyqxvu276cr2OwPLBaeqFu1cIl4vmRjAD/50=
|
go.etcd.io/etcd/pkg/v3 v3.6.4/go.mod h1:kKcYWP8gHuBRcteyv6MXWSN0+bVMnfgqiHueIZnKMtE=
|
||||||
go.etcd.io/etcd/pkg/v3 v3.5.13 h1:st9bDWNsKkBNpP4PR1MvM/9NqUPfvYZx/YXegsYEH8M=
|
go.etcd.io/etcd/server/v3 v3.6.4 h1:LsCA7CzjVt+8WGrdsnh6RhC0XqCsLkBly3ve5rTxMAU=
|
||||||
go.etcd.io/etcd/pkg/v3 v3.5.13/go.mod h1:N+4PLrp7agI/Viy+dUYpX7iRtSPvKq+w8Y14d1vX+m0=
|
go.etcd.io/etcd/server/v3 v3.6.4/go.mod h1:aYCL/h43yiONOv0QIR82kH/2xZ7m+IWYjzRmyQfnCAg=
|
||||||
go.etcd.io/etcd/raft/v3 v3.5.13 h1:7r/NKAOups1YnKcfro2RvGGo2PTuizF/xh26Z2CTAzA=
|
go.etcd.io/raft/v3 v3.6.0 h1:5NtvbDVYpnfZWcIHgGRk9DyzkBIXOi8j+DDp1IcnUWQ=
|
||||||
go.etcd.io/etcd/raft/v3 v3.5.13/go.mod h1:uUFibGLn2Ksm2URMxN1fICGhk8Wu96EfDQyuLhAcAmw=
|
go.etcd.io/raft/v3 v3.6.0/go.mod h1:nLvLevg6+xrVtHUmVaTcTz603gQPHfh7kUAwV6YpfGo=
|
||||||
go.etcd.io/etcd/server/v3 v3.5.13 h1:V6KG+yMfMSqWt+lGnhFpP5z5dRUj1BDRJ5k1fQ9DFok=
|
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||||
go.etcd.io/etcd/server/v3 v3.5.13/go.mod h1:K/8nbsGupHqmr5MkgaZpLlH1QdX1pcNQLAkODy44XcQ=
|
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q=
|
||||||
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
|
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||||
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
|
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE=
|
||||||
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
|
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
||||||
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
|
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
||||||
go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
|
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
|
||||||
go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
|
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
|
||||||
go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
|
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||||
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
|
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
|
||||||
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
|
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
||||||
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
|
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
|
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||||
|
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||||
|
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||||
|
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
|
@ -228,50 +238,48 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
|
||||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||||
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
|
golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
|
||||||
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
|
||||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
|
||||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
|
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
|
||||||
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
|
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
|
||||||
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY=
|
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950=
|
||||||
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
|
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=
|
google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
|
google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||||
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
|
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||||
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
|
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
|
||||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
|
@ -281,39 +289,44 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||||
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 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
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-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0=
|
k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM=
|
||||||
k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk=
|
k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk=
|
||||||
k8s.io/apiextensions-apiserver v0.31.2 h1:W8EwUb8+WXBLu56ser5IudT2cOho0gAKeTOnywBLxd0=
|
k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI=
|
||||||
k8s.io/apiextensions-apiserver v0.31.2/go.mod h1:i+Geh+nGCJEGiCGR3MlBDkS7koHIIKWVfWeRFiOsUcM=
|
k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc=
|
||||||
k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw=
|
k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4=
|
||||||
k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
|
k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||||
k8s.io/apiserver v0.31.2 h1:VUzOEUGRCDi6kX1OyQ801m4A7AUPglpsmGvdsekmcI4=
|
k8s.io/apiserver v0.34.1 h1:U3JBGdgANK3dfFcyknWde1G6X1F4bg7PXuvlqt8lITA=
|
||||||
k8s.io/apiserver v0.31.2/go.mod h1:o3nKZR7lPlJqkU5I3Ove+Zx3JuoFjQobGX1Gctw6XuE=
|
k8s.io/apiserver v0.34.1/go.mod h1:eOOc9nrVqlBI1AFCvVzsob0OxtPZUCPiUJL45JOTBG0=
|
||||||
k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc=
|
k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY=
|
||||||
k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs=
|
k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8=
|
||||||
k8s.io/component-base v0.31.2 h1:Z1J1LIaC0AV+nzcPRFqfK09af6bZ4D1nAOpWsy9owlA=
|
k8s.io/component-base v0.34.1 h1:v7xFgG+ONhytZNFpIz5/kecwD+sUhVE6HU7qQUiRM4A=
|
||||||
k8s.io/component-base v0.31.2/go.mod h1:9PeyyFN/drHjtJZMCTkSpQJS3U9OXORnHQqMLDz0sUQ=
|
k8s.io/component-base v0.34.1/go.mod h1:mknCpLlTSKHzAQJJnnHVKqjxR7gBeHRv0rPXA7gdtQ0=
|
||||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||||
k8s.io/kms v0.31.2 h1:pyx7l2qVOkClzFMIWMVF/FxsSkgd+OIGH7DecpbscJI=
|
k8s.io/kms v0.34.1 h1:iCFOvewDPzWM9fMTfyIPO+4MeuZ0tcZbugxLNSHFG4w=
|
||||||
k8s.io/kms v0.31.2/go.mod h1:OZKwl1fan3n3N5FFxnW5C4V3ygrah/3YXeJWS3O6+94=
|
k8s.io/kms v0.34.1/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM=
|
||||||
k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 h1:GKE9U8BH16uynoxQii0auTjmmmuZ3O0LFMN6S0lPPhI=
|
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA=
|
||||||
k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA=
|
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts=
|
||||||
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
|
k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d h1:wAhiDyZ4Tdtt7e46e9M5ZSAJ/MnPGPs+Ki1gHw4w1R0=
|
||||||
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 h1:CPT0ExVicCzcpeN4baWEV2ko2Z/AsiZgEdwgcfwLgMo=
|
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM=
|
||||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
|
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
|
||||||
sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q=
|
sigs.k8s.io/controller-runtime v0.22.2 h1:cK2l8BGWsSWkXz09tcS4rJh95iOLney5eawcK5A33r4=
|
||||||
sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4=
|
sigs.k8s.io/controller-runtime v0.22.2/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8=
|
||||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
|
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
|
||||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
|
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
|
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
|
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
|
||||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||||
|
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
|
||||||
|
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,19 @@ command -V tar >/dev/null || exit $?
|
||||||
|
|
||||||
echo "Collecting Cozystack information..."
|
echo "Collecting Cozystack information..."
|
||||||
mkdir -p $REPORT_DIR/cozystack
|
mkdir -p $REPORT_DIR/cozystack
|
||||||
kubectl get deploy -n cozy-system cozystack -o jsonpath='{.spec.template.spec.containers[0].image}' > $REPORT_DIR/cozystack/image.txt 2>&1
|
kubectl get deploy -n cozy-system cozystack-operator cozystack-controller -o yaml > $REPORT_DIR/cozystack/deployments.yaml 2>&1
|
||||||
kubectl get cm -n cozy-system --no-headers | awk '$1 ~ /^cozystack/' |
|
|
||||||
while read NAME _; do
|
echo "Collecting platforms..."
|
||||||
DIR=$REPORT_DIR/cozystack/configs
|
kubectl get platforms.cozystack.io -A > $REPORT_DIR/cozystack/platforms.txt 2>&1
|
||||||
mkdir -p $DIR
|
kubectl get platforms.cozystack.io -A -o yaml > $REPORT_DIR/cozystack/platforms.yaml 2>&1
|
||||||
kubectl get cm -n cozy-system $NAME -o yaml > $DIR/$NAME.yaml 2>&1
|
|
||||||
done
|
echo "Collecting bundles..."
|
||||||
|
kubectl get bundles.cozystack.io -A > $REPORT_DIR/cozystack/bundles.txt 2>&1
|
||||||
|
kubectl get bundles.cozystack.io -A -o yaml > $REPORT_DIR/cozystack/bundles.yaml 2>&1
|
||||||
|
|
||||||
|
echo "Collecting applicationdefinitions..."
|
||||||
|
kubectl get applicationdefinitions.cozystack.io -A > $REPORT_DIR/cozystack/applicationdefinitions.txt 2>&1
|
||||||
|
kubectl get applicationdefinitions.cozystack.io -A -o yaml > $REPORT_DIR/cozystack/applicationdefinitions.yaml 2>&1
|
||||||
|
|
||||||
# -- kubernetes module
|
# -- kubernetes module
|
||||||
|
|
||||||
|
|
@ -56,6 +62,36 @@ kubectl get hr -A --no-headers | awk '$4 != "True"' | \
|
||||||
kubectl describe hr -n $NAMESPACE $NAME > $DIR/describe.txt 2>&1
|
kubectl describe hr -n $NAMESPACE $NAME > $DIR/describe.txt 2>&1
|
||||||
done
|
done
|
||||||
|
|
||||||
|
echo "Collecting artifactgenerators..."
|
||||||
|
kubectl get artifactgenerators.source.extensions.fluxcd.io -A > $REPORT_DIR/kubernetes/artifactgenerators.txt 2>&1
|
||||||
|
kubectl get artifactgenerators.source.extensions.fluxcd.io -A --no-headers | awk '$4 != "True"' | \
|
||||||
|
while read NAMESPACE NAME _; do
|
||||||
|
DIR=$REPORT_DIR/kubernetes/artifactgenerators/$NAMESPACE/$NAME
|
||||||
|
mkdir -p $DIR
|
||||||
|
kubectl get artifactgenerators.source.extensions.fluxcd.io -n $NAMESPACE $NAME -o yaml > $DIR/artifactgenerator.yaml 2>&1
|
||||||
|
kubectl describe artifactgenerators.source.extensions.fluxcd.io -n $NAMESPACE $NAME > $DIR/describe.txt 2>&1
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Collecting ocirepositories..."
|
||||||
|
kubectl get ocirepositories.source.toolkit.fluxcd.io -A > $REPORT_DIR/kubernetes/ocirepositories.txt 2>&1
|
||||||
|
kubectl get ocirepositories.source.toolkit.fluxcd.io -A --no-headers | awk '$4 != "True"' | \
|
||||||
|
while read NAMESPACE NAME _; do
|
||||||
|
DIR=$REPORT_DIR/kubernetes/ocirepositories/$NAMESPACE/$NAME
|
||||||
|
mkdir -p $DIR
|
||||||
|
kubectl get ocirepositories.source.toolkit.fluxcd.io -n $NAMESPACE $NAME -o yaml > $DIR/ocirepository.yaml 2>&1
|
||||||
|
kubectl describe ocirepositories.source.toolkit.fluxcd.io -n $NAMESPACE $NAME > $DIR/describe.txt 2>&1
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Collecting gitrepositories..."
|
||||||
|
kubectl get gitrepositories.source.toolkit.fluxcd.io -A > $REPORT_DIR/kubernetes/gitrepositories.txt 2>&1
|
||||||
|
kubectl get gitrepositories.source.toolkit.fluxcd.io -A --no-headers | awk '$4 != "True"' | \
|
||||||
|
while read NAMESPACE NAME _; do
|
||||||
|
DIR=$REPORT_DIR/kubernetes/gitrepositories/$NAMESPACE/$NAME
|
||||||
|
mkdir -p $DIR
|
||||||
|
kubectl get gitrepositories.source.toolkit.fluxcd.io -n $NAMESPACE $NAME -o yaml > $DIR/gitrepository.yaml 2>&1
|
||||||
|
kubectl describe gitrepositories.source.toolkit.fluxcd.io -n $NAMESPACE $NAME > $DIR/describe.txt 2>&1
|
||||||
|
done
|
||||||
|
|
||||||
echo "Collecting pods..."
|
echo "Collecting pods..."
|
||||||
kubectl get pod -A -o wide > $REPORT_DIR/kubernetes/pods.txt 2>&1
|
kubectl get pod -A -o wide > $REPORT_DIR/kubernetes/pods.txt 2>&1
|
||||||
kubectl get pod -A --no-headers | awk '$4 !~ /Running|Succeeded|Completed/' |
|
kubectl get pod -A --no-headers | awk '$4 !~ /Running|Succeeded|Completed/' |
|
||||||
|
|
|
||||||
|
|
@ -8,23 +8,51 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Install Cozystack" {
|
@test "Install Cozystack" {
|
||||||
# Create namespace & configmap required by installer
|
|
||||||
kubectl create namespace cozy-system --dry-run=client -o yaml | kubectl apply -f -
|
|
||||||
kubectl create configmap cozystack -n cozy-system \
|
|
||||||
--from-literal=bundle-name=paas-full \
|
|
||||||
--from-literal=ipv4-pod-cidr=10.244.0.0/16 \
|
|
||||||
--from-literal=ipv4-pod-gateway=10.244.0.1 \
|
|
||||||
--from-literal=ipv4-svc-cidr=10.96.0.0/16 \
|
|
||||||
--from-literal=ipv4-join-cidr=100.64.0.0/16 \
|
|
||||||
--from-literal=root-host=example.org \
|
|
||||||
--from-literal=api-server-endpoint=https://192.168.123.10:6443 \
|
|
||||||
--dry-run=client -o yaml | kubectl apply -f -
|
|
||||||
|
|
||||||
# Apply installer manifests from file
|
# Apply installer manifests from file
|
||||||
kubectl apply -f _out/assets/cozystack-installer.yaml
|
kubectl apply -f _out/assets/cozystack-installer.yaml
|
||||||
|
|
||||||
# Wait for the installer deployment to become available
|
# Wait for the installer deployment to become available
|
||||||
kubectl wait deployment/cozystack -n cozy-system --timeout=1m --for=condition=Available
|
kubectl wait deployment/cozystack-operator -n cozy-system --timeout=1m --for=condition=Available
|
||||||
|
|
||||||
|
# Wait for cozy-fluxcd namespace to be created
|
||||||
|
timeout 30 sh -ec 'until kubectl get namespace cozy-fluxcd >/dev/null 2>&1; do sleep 1; done'
|
||||||
|
|
||||||
|
# Wait for Flux deployment
|
||||||
|
timeout 30 sh -ec 'until kubectl get deployment/flux -n cozy-fluxcd >/dev/null 2>&1; do sleep 1; done'
|
||||||
|
kubectl wait deployment/flux -n cozy-fluxcd --timeout=1m --for=condition=Available
|
||||||
|
|
||||||
|
# Create Platform resource instead of configmap
|
||||||
|
kubectl apply -f - <<'EOF'
|
||||||
|
apiVersion: cozystack.io/v1alpha1
|
||||||
|
kind: Platform
|
||||||
|
metadata:
|
||||||
|
name: cozystack-platform
|
||||||
|
spec:
|
||||||
|
sourceRef:
|
||||||
|
kind: OCIRepository
|
||||||
|
name: cozystack-packages
|
||||||
|
namespace: cozy-system
|
||||||
|
values:
|
||||||
|
bundles:
|
||||||
|
system:
|
||||||
|
type: "full"
|
||||||
|
networking:
|
||||||
|
podCIDR: "10.244.0.0/16"
|
||||||
|
podGateway: "10.244.0.1"
|
||||||
|
serviceCIDR: "10.96.0.0/16"
|
||||||
|
joinCIDR: "100.64.0.0/16"
|
||||||
|
publishing:
|
||||||
|
host: "example.org"
|
||||||
|
apiServerEndpoint: "https://192.168.123.10:6443"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Wait for ArtifactGenerator for cozystack-packages
|
||||||
|
timeout 60 sh -ec 'until kubectl get artifactgenerators.source.extensions.fluxcd.io cozystack-packages -n cozy-system >/dev/null 2>&1; do sleep 1; done'
|
||||||
|
kubectl wait artifactgenerators.source.extensions.fluxcd.io/cozystack-packages -n cozy-system --for=condition=ready --timeout=5m
|
||||||
|
|
||||||
|
# Wait for bundle ArtifactGenerators
|
||||||
|
timeout 60 sh -ec 'until kubectl get artifactgenerators.source.extensions.fluxcd.io cozystack-system cozystack-iaas cozystack-paas cozystack-naas -n cozy-system >/dev/null 2>&1; do sleep 1; done'
|
||||||
|
kubectl wait artifactgenerators.source.extensions.fluxcd.io -n cozy-system --for=condition=ready --timeout=5m cozystack-system cozystack-iaas cozystack-paas cozystack-naas
|
||||||
|
|
||||||
# Wait until HelmReleases appear & reconcile them
|
# Wait until HelmReleases appear & reconcile them
|
||||||
timeout 60 sh -ec 'until kubectl get hr -A -l cozystack.io/system-app=true | grep -q cozys; do sleep 1; done'
|
timeout 60 sh -ec 'until kubectl get hr -A -l cozystack.io/system-app=true | grep -q cozys; do sleep 1; done'
|
||||||
|
|
@ -140,9 +168,8 @@ EOF
|
||||||
kubectl wait hr/seaweedfs-system -n tenant-root --timeout=2m --for=condition=ready
|
kubectl wait hr/seaweedfs-system -n tenant-root --timeout=2m --for=condition=ready
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Expose Cozystack services through ingress
|
# Expose Cozystack services through ingress
|
||||||
kubectl patch configmap/cozystack -n cozy-system --type merge -p '{"data":{"expose-services":"api,dashboard,cdi-uploadproxy,vm-exportproxy,keycloak"}}'
|
kubectl patch platform/cozystack-platform --type merge -p '{"spec":{"values":{"publishing":{"exposedServices":["api","dashboard","cdi-uploadproxy","vm-exportproxy","keycloak"]}}}}'
|
||||||
|
|
||||||
# NGINX ingress controller
|
# NGINX ingress controller
|
||||||
timeout 60 sh -ec 'until kubectl get deploy root-ingress-controller -n tenant-root >/dev/null 2>&1; do sleep 1; done'
|
timeout 60 sh -ec 'until kubectl get deploy root-ingress-controller -n tenant-root >/dev/null 2>&1; do sleep 1; done'
|
||||||
|
|
@ -169,7 +196,7 @@ EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Keycloak OIDC stack is healthy" {
|
@test "Keycloak OIDC stack is healthy" {
|
||||||
kubectl patch configmap/cozystack -n cozy-system --type merge -p '{"data":{"oidc-enabled":"true"}}'
|
kubectl patch platform/cozystack-platform --type merge -p '{"spec":{"values":{"authentication":{"oidc":{"enabled":true}}}}}'
|
||||||
|
|
||||||
timeout 120 sh -ec 'until kubectl get hr -n cozy-keycloak keycloak keycloak-configure keycloak-operator >/dev/null 2>&1; do sleep 1; done'
|
timeout 120 sh -ec 'until kubectl get hr -n cozy-keycloak keycloak keycloak-configure keycloak-operator >/dev/null 2>&1; do sleep 1; done'
|
||||||
kubectl wait hr/keycloak hr/keycloak-configure hr/keycloak-operator -n cozy-keycloak --timeout=10m --for=condition=ready
|
kubectl wait hr/keycloak hr/keycloak-configure hr/keycloak-operator -n cozy-keycloak --timeout=10m --for=condition=ready
|
||||||
|
|
|
||||||
|
|
@ -54,5 +54,9 @@ kube::codegen::gen_openapi \
|
||||||
|
|
||||||
$CONTROLLER_GEN object:headerFile="hack/boilerplate.go.txt" paths="./api/..."
|
$CONTROLLER_GEN object:headerFile="hack/boilerplate.go.txt" paths="./api/..."
|
||||||
$CONTROLLER_GEN rbac:roleName=manager-role crd paths="./api/..." output:crd:artifacts:config=packages/system/cozystack-controller/crds
|
$CONTROLLER_GEN rbac:roleName=manager-role crd paths="./api/..." output:crd:artifacts:config=packages/system/cozystack-controller/crds
|
||||||
mv packages/system/cozystack-controller/crds/cozystack.io_cozystackresourcedefinitions.yaml \
|
mv packages/system/cozystack-controller/crds/cozystack.io_applicationdefinitions.yaml \
|
||||||
packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml
|
packages/core/installer/crds/cozystack.io_applicationdefinitions.yaml
|
||||||
|
mv packages/system/cozystack-controller/crds/cozystack.io_bundles.yaml \
|
||||||
|
packages/core/installer/crds/cozystack.io_bundles.yaml
|
||||||
|
mv packages/system/cozystack-controller/crds/cozystack.io_platforms.yaml \
|
||||||
|
packages/core/installer/crds/cozystack.io_platforms.yaml
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ need yq; need jq; need base64
|
||||||
CHART_YAML="${CHART_YAML:-Chart.yaml}"
|
CHART_YAML="${CHART_YAML:-Chart.yaml}"
|
||||||
VALUES_YAML="${VALUES_YAML:-values.yaml}"
|
VALUES_YAML="${VALUES_YAML:-values.yaml}"
|
||||||
SCHEMA_JSON="${SCHEMA_JSON:-values.schema.json}"
|
SCHEMA_JSON="${SCHEMA_JSON:-values.schema.json}"
|
||||||
CRD_DIR="../../system/cozystack-resource-definitions/cozyrds"
|
CRD_DIR="../../core/platform/bundles/*/applicationdefinitions"
|
||||||
|
|
||||||
[[ -f "$CHART_YAML" ]] || { echo "No $CHART_YAML found"; exit 1; }
|
[[ -f "$CHART_YAML" ]] || { echo "No $CHART_YAML found"; exit 1; }
|
||||||
[[ -f "$SCHEMA_JSON" ]] || { echo "No $SCHEMA_JSON found"; exit 1; }
|
[[ -f "$SCHEMA_JSON" ]] || { echo "No $SCHEMA_JSON found"; exit 1; }
|
||||||
|
|
@ -54,37 +54,71 @@ fi
|
||||||
# Base64 (portable: no -w / -b options)
|
# Base64 (portable: no -w / -b options)
|
||||||
ICON_B64="$(base64 < "$ICON_PATH" | tr -d '\n' | tr -d '\r')"
|
ICON_B64="$(base64 < "$ICON_PATH" | tr -d '\n' | tr -d '\r')"
|
||||||
|
|
||||||
# Decide which HelmRepository name to use based on path
|
# Find path to output CRD YAML
|
||||||
# .../apps/... -> cozystack-apps
|
OUT="$(find $CRD_DIR -type f -name "${NAME}.yaml" | head -n 1)"
|
||||||
# .../extra/... -> cozystack-extra
|
if [[ -z "$OUT" ]]; then
|
||||||
# default: cozystack-apps
|
echo "Error: ApplicationDefinition file for '${NAME}' not found in ${CRD_DIR}"
|
||||||
SOURCE_NAME="cozystack-apps"
|
echo "Please create the file first in one of the following directories:"
|
||||||
case "$PWD" in
|
|
||||||
*"/apps/"*) SOURCE_NAME="cozystack-apps" ;;
|
# Auto-detect existing directories
|
||||||
*"/extra/"*) SOURCE_NAME="cozystack-extra" ;;
|
BASE_DIR="../../core/platform/bundles"
|
||||||
esac
|
if [[ -d "$BASE_DIR" ]]; then
|
||||||
|
for bundle_dir in "$BASE_DIR"/*/applicationdefinitions; do
|
||||||
|
if [[ -d "$bundle_dir" ]]; then
|
||||||
|
bundle_name="$(basename "$(dirname "$bundle_dir")")"
|
||||||
|
echo " touch ${bundle_dir}/${NAME}.yaml # ${bundle_name}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
# Fallback if base directory doesn't exist
|
||||||
|
echo " touch ../../core/platform/bundles/iaas/applicationdefinitions/${NAME}.yaml"
|
||||||
|
echo " touch ../../core/platform/bundles/paas/applicationdefinitions/${NAME}.yaml"
|
||||||
|
echo " touch ../../core/platform/bundles/naas/applicationdefinitions/${NAME}.yaml"
|
||||||
|
echo " touch ../../core/platform/bundles/system/applicationdefinitions/${NAME}.yaml"
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# If file doesn't exist, create a minimal skeleton
|
if [[ ! -s "$OUT" ]]; then
|
||||||
OUT="${OUT:-$CRD_DIR/$NAME.yaml}"
|
|
||||||
if [[ ! -f "$OUT" ]]; then
|
|
||||||
cat >"$OUT" <<EOF
|
cat >"$OUT" <<EOF
|
||||||
apiVersion: cozystack.io/v1alpha1
|
apiVersion: cozystack.io/v1alpha1
|
||||||
kind: CozystackResourceDefinition
|
kind: ApplicationDefinition
|
||||||
metadata:
|
metadata:
|
||||||
name: ${NAME}
|
name: ${NAME}
|
||||||
spec: {}
|
spec:
|
||||||
|
release:
|
||||||
|
values:
|
||||||
|
_cozystack:
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Determine package type (apps or extra) from current directory
|
||||||
|
CURRENT_DIR="$(pwd)"
|
||||||
|
PACKAGE_TYPE="apps" # default
|
||||||
|
if [[ "$CURRENT_DIR" == *"/packages/extra/"* ]]; then
|
||||||
|
PACKAGE_TYPE="extra"
|
||||||
|
elif [[ "$CURRENT_DIR" == *"/packages/apps/"* ]]; then
|
||||||
|
PACKAGE_TYPE="apps"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract bundle type (iaas, paas, naas, system) from OUT path
|
||||||
|
OUT_DIR="$(dirname "$OUT")"
|
||||||
|
BUNDLE_DIR="$(dirname "$OUT_DIR")"
|
||||||
|
BUNDLE_TYPE="$(basename "$BUNDLE_DIR")"
|
||||||
|
ARTIFACT_PREFIX="cozystack-${BUNDLE_TYPE}"
|
||||||
|
ARTIFACT_NAME="${ARTIFACT_PREFIX}-${NAME}"
|
||||||
|
|
||||||
# Export vars for yq env()
|
# Export vars for yq env()
|
||||||
export RES_NAME="$NAME"
|
export RES_NAME="$NAME"
|
||||||
export PREFIX="$NAME-"
|
# For packages/extra, prefix should be empty; for packages/apps, prefix is "${NAME}-"
|
||||||
if [ "$SOURCE_NAME" == "cozystack-extra" ]; then
|
if [[ "$PACKAGE_TYPE" == "extra" ]]; then
|
||||||
export PREFIX=""
|
export PREFIX=""
|
||||||
|
else
|
||||||
|
export PREFIX="${NAME}-"
|
||||||
fi
|
fi
|
||||||
export DESCRIPTION="$DESC"
|
export DESCRIPTION="$DESC"
|
||||||
export ICON_B64="$ICON_B64"
|
export ICON_B64="$ICON_B64"
|
||||||
export SOURCE_NAME="$SOURCE_NAME"
|
export ARTIFACT_NAME="$ARTIFACT_NAME"
|
||||||
export SCHEMA_JSON_MIN="$(jq -c . "$SCHEMA_JSON")"
|
export SCHEMA_JSON_MIN="$(jq -c . "$SCHEMA_JSON")"
|
||||||
|
|
||||||
# Generate keysOrder from values.yaml
|
# Generate keysOrder from values.yaml
|
||||||
|
|
@ -114,6 +148,12 @@ export KEYS_ORDER="$(
|
||||||
'
|
'
|
||||||
)"
|
)"
|
||||||
|
|
||||||
|
# Remove lines with cozystack.build-values before updating (Helm template syntax breaks yq parsing)
|
||||||
|
if [[ -f "$OUT" && -n "$OUT" ]]; then
|
||||||
|
# Use grep to filter out the line, more reliable than sed
|
||||||
|
grep -v 'cozystack\.build-values' "$OUT" > "${OUT}.tmp" && mv "${OUT}.tmp" "$OUT"
|
||||||
|
fi
|
||||||
|
|
||||||
# Update only necessary fields in-place
|
# Update only necessary fields in-place
|
||||||
# - openAPISchema is loaded from file as a multi-line string (block scalar)
|
# - openAPISchema is loaded from file as a multi-line string (block scalar)
|
||||||
# - labels ensure cozystack.io/ui: "true"
|
# - labels ensure cozystack.io/ui: "true"
|
||||||
|
|
@ -121,19 +161,26 @@ export KEYS_ORDER="$(
|
||||||
# - sourceRef derived from directory (apps|extra)
|
# - sourceRef derived from directory (apps|extra)
|
||||||
yq -i '
|
yq -i '
|
||||||
.apiVersion = (.apiVersion // "cozystack.io/v1alpha1") |
|
.apiVersion = (.apiVersion // "cozystack.io/v1alpha1") |
|
||||||
.kind = (.kind // "CozystackResourceDefinition") |
|
.kind = (.kind // "ApplicationDefinition") |
|
||||||
.metadata.name = strenv(RES_NAME) |
|
.metadata.name = strenv(RES_NAME) |
|
||||||
.spec.application.openAPISchema = strenv(SCHEMA_JSON_MIN) |
|
.spec.application.openAPISchema = strenv(SCHEMA_JSON_MIN) |
|
||||||
(.spec.application.openAPISchema style="literal") |
|
(.spec.application.openAPISchema style="literal") |
|
||||||
.spec.release.prefix = (strenv(PREFIX)) |
|
.spec.release.prefix = (strenv(PREFIX)) |
|
||||||
.spec.release.labels."cozystack.io/ui" = "true" |
|
.spec.release.labels."cozystack.io/ui" = "true" |
|
||||||
.spec.release.chart.name = strenv(RES_NAME) |
|
del(.spec.release.chart) |
|
||||||
.spec.release.chart.sourceRef.kind = "HelmRepository" |
|
.spec.release.chartRef.sourceRef.kind = "ExternalArtifact" |
|
||||||
.spec.release.chart.sourceRef.name = strenv(SOURCE_NAME) |
|
.spec.release.chartRef.sourceRef.name = strenv(ARTIFACT_NAME) |
|
||||||
.spec.release.chart.sourceRef.namespace = "cozy-public" |
|
.spec.release.chartRef.sourceRef.namespace = "cozy-system" |
|
||||||
.spec.dashboard.description = strenv(DESCRIPTION) |
|
.spec.dashboard.description = strenv(DESCRIPTION) |
|
||||||
.spec.dashboard.icon = strenv(ICON_B64) |
|
.spec.dashboard.icon = strenv(ICON_B64) |
|
||||||
.spec.dashboard.keysOrder = env(KEYS_ORDER)
|
.spec.dashboard.keysOrder = env(KEYS_ORDER)
|
||||||
' "$OUT"
|
' "$OUT"
|
||||||
|
|
||||||
|
# Add back the Helm template line after _cozystack
|
||||||
|
if [[ -f "$OUT" && -n "$OUT" ]]; then
|
||||||
|
HELM_TEMPLATE=' {{- include "cozystack.build-values" . | nindent 8 }}'
|
||||||
|
# Use awk for more reliable insertion
|
||||||
|
awk -v template="$HELM_TEMPLATE" '/_cozystack:/ {print; print template; next} {print}' "$OUT" > "${OUT}.tmp" && mv "${OUT}.tmp" "$OUT"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Updated $OUT"
|
echo "Updated $OUT"
|
||||||
|
|
|
||||||
502
internal/controller/applicationdefinition_controller.go
Normal file
502
internal/controller/applicationdefinition_controller.go
Normal file
|
|
@ -0,0 +1,502 @@
|
||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"slices"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
||||||
|
helmv2 "github.com/fluxcd/helm-controller/api/v2"
|
||||||
|
|
||||||
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||||
|
|
||||||
|
"github.com/cozystack/cozystack/pkg/cozylib"
|
||||||
|
)
|
||||||
|
|
||||||
|
// +kubebuilder:rbac:groups=cozystack.io,resources=applicationdefinitions,verbs=get;list;watch
|
||||||
|
// +kubebuilder:rbac:groups=helm.toolkit.fluxcd.io,resources=helmreleases,verbs=get;list;watch;update;patch
|
||||||
|
// +kubebuilder:rbac:groups=core,resources=namespaces,verbs=get;list;watch
|
||||||
|
type ApplicationDefinitionReconciler struct {
|
||||||
|
client.Client
|
||||||
|
Scheme *runtime.Scheme
|
||||||
|
|
||||||
|
Debounce time.Duration
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
|
lastEvent time.Time
|
||||||
|
lastHandled time.Time
|
||||||
|
|
||||||
|
CozystackAPIKind string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ApplicationDefinitionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||||
|
logger := log.FromContext(ctx)
|
||||||
|
logger.Info("Reconciling ApplicationDefinitions", "request", req.NamespacedName)
|
||||||
|
|
||||||
|
// Get all ApplicationDefinitions
|
||||||
|
crdList := &cozyv1alpha1.ApplicationDefinitionList{}
|
||||||
|
if err := r.List(ctx, crdList); err != nil {
|
||||||
|
logger.Error(err, "failed to list ApplicationDefinitions")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("Found ApplicationDefinitions", "count", len(crdList.Items))
|
||||||
|
|
||||||
|
// Update HelmReleases for each CRD
|
||||||
|
for i := range crdList.Items {
|
||||||
|
crd := &crdList.Items[i]
|
||||||
|
logger.V(4).Info("Processing CRD", "crd", crd.Name, "hasValues", crd.Spec.Release.Values != nil)
|
||||||
|
if err := r.updateHelmReleasesForCRD(ctx, crd); err != nil {
|
||||||
|
logger.Error(err, "failed to update HelmReleases for CRD", "crd", crd.Name)
|
||||||
|
// Continue with other CRDs even if one fails
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue with debounced restart logic
|
||||||
|
return r.debouncedRestart(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ApplicationDefinitionReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
|
if r.Debounce == 0 {
|
||||||
|
r.Debounce = 5 * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
|
Named("applicationdefinition-controller").
|
||||||
|
Watches(
|
||||||
|
&cozyv1alpha1.ApplicationDefinition{},
|
||||||
|
handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request {
|
||||||
|
r.mu.Lock()
|
||||||
|
r.lastEvent = time.Now()
|
||||||
|
r.mu.Unlock()
|
||||||
|
return []reconcile.Request{{
|
||||||
|
NamespacedName: types.NamespacedName{
|
||||||
|
Namespace: "cozy-system",
|
||||||
|
Name: "cozystack-api",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
}),
|
||||||
|
).
|
||||||
|
Watches(
|
||||||
|
&helmv2.HelmRelease{},
|
||||||
|
handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request {
|
||||||
|
hr, ok := obj.(*helmv2.HelmRelease)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Only watch HelmReleases with cozystack.io/ui=true label
|
||||||
|
if hr.Labels == nil || hr.Labels["cozystack.io/ui"] != "true" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Trigger reconciliation of all CRDs when a HelmRelease with the label is created/updated
|
||||||
|
r.mu.Lock()
|
||||||
|
r.lastEvent = time.Now()
|
||||||
|
r.mu.Unlock()
|
||||||
|
return []reconcile.Request{{
|
||||||
|
NamespacedName: types.NamespacedName{
|
||||||
|
Namespace: "cozy-system",
|
||||||
|
Name: "cozystack-api",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
}),
|
||||||
|
).
|
||||||
|
Complete(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
type crdHashView struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Spec cozyv1alpha1.ApplicationDefinitionSpec `json:"spec"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ApplicationDefinitionReconciler) computeConfigHash(ctx context.Context) (string, error) {
|
||||||
|
list := &cozyv1alpha1.ApplicationDefinitionList{}
|
||||||
|
if err := r.List(ctx, list); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
slices.SortFunc(list.Items, sortApplicationDefinitions)
|
||||||
|
|
||||||
|
views := make([]crdHashView, 0, len(list.Items))
|
||||||
|
for i := range list.Items {
|
||||||
|
views = append(views, crdHashView{
|
||||||
|
Name: list.Items[i].Name,
|
||||||
|
Spec: list.Items[i].Spec,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
b, err := json.Marshal(views)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
sum := sha256.Sum256(b)
|
||||||
|
return hex.EncodeToString(sum[:]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ApplicationDefinitionReconciler) debouncedRestart(ctx context.Context) (ctrl.Result, error) {
|
||||||
|
logger := log.FromContext(ctx)
|
||||||
|
|
||||||
|
r.mu.Lock()
|
||||||
|
le := r.lastEvent
|
||||||
|
lh := r.lastHandled
|
||||||
|
debounce := r.Debounce
|
||||||
|
r.mu.Unlock()
|
||||||
|
|
||||||
|
if debounce <= 0 {
|
||||||
|
debounce = 5 * time.Second
|
||||||
|
}
|
||||||
|
if le.IsZero() {
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
if d := time.Since(le); d < debounce {
|
||||||
|
return ctrl.Result{RequeueAfter: debounce - d}, nil
|
||||||
|
}
|
||||||
|
if !lh.Before(le) {
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
newHash, err := r.computeConfigHash(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tpl, obj, patch, err := r.getWorkload(ctx, types.NamespacedName{Namespace: "cozy-system", Name: "cozystack-api"})
|
||||||
|
if err != nil {
|
||||||
|
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldHash := tpl.Annotations["cozystack.io/config-hash"]
|
||||||
|
|
||||||
|
if oldHash == newHash && oldHash != "" {
|
||||||
|
r.mu.Lock()
|
||||||
|
r.lastHandled = le
|
||||||
|
r.mu.Unlock()
|
||||||
|
logger.Info("No changes in CRD config; skipping restart", "hash", newHash)
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
tpl.Annotations["cozystack.io/config-hash"] = newHash
|
||||||
|
|
||||||
|
if err := r.Patch(ctx, obj, patch); err != nil {
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
r.mu.Lock()
|
||||||
|
r.lastHandled = le
|
||||||
|
r.mu.Unlock()
|
||||||
|
|
||||||
|
logger.Info("Updated cozystack-api podTemplate config-hash; rollout triggered",
|
||||||
|
"old", oldHash, "new", newHash)
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ApplicationDefinitionReconciler) getWorkload(
|
||||||
|
ctx context.Context,
|
||||||
|
key types.NamespacedName,
|
||||||
|
) (tpl *corev1.PodTemplateSpec, obj client.Object, patch client.Patch, err error) {
|
||||||
|
if r.CozystackAPIKind == "Deployment" {
|
||||||
|
dep := &appsv1.Deployment{}
|
||||||
|
if err := r.Get(ctx, key, dep); err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
obj = dep
|
||||||
|
tpl = &dep.Spec.Template
|
||||||
|
patch = client.MergeFrom(dep.DeepCopy())
|
||||||
|
} else {
|
||||||
|
ds := &appsv1.DaemonSet{}
|
||||||
|
if err := r.Get(ctx, key, ds); err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
obj = ds
|
||||||
|
tpl = &ds.Spec.Template
|
||||||
|
patch = client.MergeFrom(ds.DeepCopy())
|
||||||
|
}
|
||||||
|
if tpl.Annotations == nil {
|
||||||
|
tpl.Annotations = make(map[string]string)
|
||||||
|
}
|
||||||
|
return tpl, obj, patch, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sortApplicationDefinitions(a, b cozyv1alpha1.ApplicationDefinition) int {
|
||||||
|
if a.Name == b.Name {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if a.Name < b.Name {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateHelmReleasesForCRD updates all HelmReleases that match the application labels from ApplicationDefinition
|
||||||
|
func (r *ApplicationDefinitionReconciler) updateHelmReleasesForCRD(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) error {
|
||||||
|
logger := log.FromContext(ctx)
|
||||||
|
|
||||||
|
// Use application labels to find HelmReleases
|
||||||
|
// Labels: apps.cozystack.io/application.kind and apps.cozystack.io/application.group
|
||||||
|
applicationKind := crd.Spec.Application.Kind
|
||||||
|
applicationGroup := "apps.cozystack.io" // All applications use this group
|
||||||
|
|
||||||
|
// Build label selector for HelmReleases
|
||||||
|
// Only reconcile HelmReleases with cozystack.io/ui=true label
|
||||||
|
labelSelector := client.MatchingLabels{
|
||||||
|
"apps.cozystack.io/application.kind": applicationKind,
|
||||||
|
"apps.cozystack.io/application.group": applicationGroup,
|
||||||
|
"cozystack.io/ui": "true",
|
||||||
|
}
|
||||||
|
|
||||||
|
// List all HelmReleases with matching labels
|
||||||
|
hrList := &helmv2.HelmReleaseList{}
|
||||||
|
if err := r.List(ctx, hrList, labelSelector); err != nil {
|
||||||
|
logger.Error(err, "failed to list HelmReleases", "kind", applicationKind, "group", applicationGroup)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("Found HelmReleases to update", "crd", crd.Name, "kind", applicationKind, "count", len(hrList.Items), "hasValues", crd.Spec.Release.Values != nil)
|
||||||
|
if crd.Spec.Release.Values != nil {
|
||||||
|
logger.V(4).Info("CRD has values", "crd", crd.Name, "valuesSize", len(crd.Spec.Release.Values.Raw))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log each HelmRelease that will be updated
|
||||||
|
for i := range hrList.Items {
|
||||||
|
hr := &hrList.Items[i]
|
||||||
|
logger.V(4).Info("Processing HelmRelease", "name", hr.Name, "namespace", hr.Namespace, "kind", applicationKind)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update each HelmRelease
|
||||||
|
for i := range hrList.Items {
|
||||||
|
hr := &hrList.Items[i]
|
||||||
|
if err := r.updateHelmReleaseChart(ctx, hr, crd); err != nil {
|
||||||
|
logger.Error(err, "failed to update HelmRelease", "name", hr.Name, "namespace", hr.Namespace)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateHelmReleaseChart updates the chart/chartRef and values in HelmRelease based on ApplicationDefinition
|
||||||
|
func (r *ApplicationDefinitionReconciler) updateHelmReleaseChart(ctx context.Context, hr *helmv2.HelmRelease, crd *cozyv1alpha1.ApplicationDefinition) error {
|
||||||
|
logger := log.FromContext(ctx)
|
||||||
|
updated := false
|
||||||
|
hrCopy := hr.DeepCopy()
|
||||||
|
|
||||||
|
// Update based on Chart or ChartRef configuration
|
||||||
|
if crd.Spec.Release.Chart != nil {
|
||||||
|
// Using Chart (HelmRepository)
|
||||||
|
if hrCopy.Spec.Chart == nil {
|
||||||
|
// Need to create Chart spec
|
||||||
|
hrCopy.Spec.Chart = &helmv2.HelmChartTemplate{
|
||||||
|
Spec: helmv2.HelmChartTemplateSpec{
|
||||||
|
Chart: crd.Spec.Release.Chart.Name,
|
||||||
|
SourceRef: helmv2.CrossNamespaceObjectReference{
|
||||||
|
Kind: crd.Spec.Release.Chart.SourceRef.Kind,
|
||||||
|
Name: crd.Spec.Release.Chart.SourceRef.Name,
|
||||||
|
Namespace: crd.Spec.Release.Chart.SourceRef.Namespace,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// Clear ChartRef if it exists
|
||||||
|
hrCopy.Spec.ChartRef = nil
|
||||||
|
updated = true
|
||||||
|
} else {
|
||||||
|
// Update existing Chart spec
|
||||||
|
if hrCopy.Spec.Chart.Spec.Chart != crd.Spec.Release.Chart.Name ||
|
||||||
|
hrCopy.Spec.Chart.Spec.SourceRef.Kind != crd.Spec.Release.Chart.SourceRef.Kind ||
|
||||||
|
hrCopy.Spec.Chart.Spec.SourceRef.Name != crd.Spec.Release.Chart.SourceRef.Name ||
|
||||||
|
hrCopy.Spec.Chart.Spec.SourceRef.Namespace != crd.Spec.Release.Chart.SourceRef.Namespace {
|
||||||
|
hrCopy.Spec.Chart.Spec.Chart = crd.Spec.Release.Chart.Name
|
||||||
|
hrCopy.Spec.Chart.Spec.SourceRef = helmv2.CrossNamespaceObjectReference{
|
||||||
|
Kind: crd.Spec.Release.Chart.SourceRef.Kind,
|
||||||
|
Name: crd.Spec.Release.Chart.SourceRef.Name,
|
||||||
|
Namespace: crd.Spec.Release.Chart.SourceRef.Namespace,
|
||||||
|
}
|
||||||
|
// Clear ChartRef if it exists
|
||||||
|
hrCopy.Spec.ChartRef = nil
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if crd.Spec.Release.ChartRef != nil {
|
||||||
|
// Using ChartRef (ExternalArtifact)
|
||||||
|
expectedChartRef := &helmv2.CrossNamespaceSourceReference{
|
||||||
|
Kind: "ExternalArtifact",
|
||||||
|
Name: crd.Spec.Release.ChartRef.SourceRef.Name,
|
||||||
|
Namespace: crd.Spec.Release.ChartRef.SourceRef.Namespace,
|
||||||
|
}
|
||||||
|
|
||||||
|
if hrCopy.Spec.ChartRef == nil {
|
||||||
|
// Need to create ChartRef
|
||||||
|
hrCopy.Spec.ChartRef = expectedChartRef
|
||||||
|
// Clear Chart if it exists
|
||||||
|
hrCopy.Spec.Chart = nil
|
||||||
|
updated = true
|
||||||
|
} else {
|
||||||
|
// Update existing ChartRef
|
||||||
|
if hrCopy.Spec.ChartRef.Kind != expectedChartRef.Kind ||
|
||||||
|
hrCopy.Spec.ChartRef.Name != expectedChartRef.Name ||
|
||||||
|
hrCopy.Spec.ChartRef.Namespace != expectedChartRef.Namespace {
|
||||||
|
hrCopy.Spec.ChartRef = expectedChartRef
|
||||||
|
// Clear Chart if it exists
|
||||||
|
hrCopy.Spec.Chart = nil
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Values from CRD if specified
|
||||||
|
var mergedValues *apiextensionsv1.JSON
|
||||||
|
var err error
|
||||||
|
if crd.Spec.Release.Values != nil {
|
||||||
|
logger.V(4).Info("Merging values from CRD", "name", hr.Name, "namespace", hr.Namespace, "crd", crd.Name)
|
||||||
|
mergedValues, err = cozylib.MergeValuesWithCRDPriority(crd.Spec.Release.Values, hrCopy.Spec.Values)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err, "failed to merge values", "name", hr.Name, "namespace", hr.Namespace)
|
||||||
|
return fmt.Errorf("failed to merge values: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Even if CRD has no values, we still need to ensure _namespace is set
|
||||||
|
mergedValues = hrCopy.Spec.Values
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always inject namespace annotations (top-level _namespace field)
|
||||||
|
// This matches the behavior in cozystack-api and NamespaceHelmReconciler
|
||||||
|
namespace := &corev1.Namespace{}
|
||||||
|
if err := r.Get(ctx, client.ObjectKey{Name: hrCopy.Namespace}, namespace); err == nil {
|
||||||
|
mergedValues, err = cozylib.InjectNamespaceAnnotationsIntoValues(mergedValues, namespace)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err, "failed to inject namespace annotations", "name", hr.Name, "namespace", hr.Namespace)
|
||||||
|
// Continue even if namespace annotations injection fails
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always update values to ensure _cozystack and _namespace are applied
|
||||||
|
// This ensures that CRD values (especially _cozystack and _namespace) are always applied
|
||||||
|
// We always update to ensure CRD values are propagated, even if they appear equal
|
||||||
|
// This is important because JSON comparison might not catch all differences (e.g., field order)
|
||||||
|
if crd.Spec.Release.Values != nil || mergedValues != hrCopy.Spec.Values {
|
||||||
|
hrCopy.Spec.Values = mergedValues
|
||||||
|
updated = true
|
||||||
|
if crd.Spec.Release.Values != nil {
|
||||||
|
logger.Info("Updated values from CRD", "name", hr.Name, "namespace", hr.Namespace, "crd", crd.Name)
|
||||||
|
} else {
|
||||||
|
logger.V(4).Info("Updated values with namespace labels", "name", hr.Name, "namespace", hr.Namespace, "crd", crd.Name)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.V(4).Info("No values update needed", "name", hr.Name, "namespace", hr.Namespace, "crd", crd.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !updated {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the HelmRelease
|
||||||
|
patch := client.MergeFrom(hr.DeepCopy())
|
||||||
|
if err := r.Patch(ctx, hrCopy, patch); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("Updated HelmRelease", "name", hr.Name, "namespace", hr.Namespace, "crd", crd.Name)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// mergeHelmReleaseValues merges CRD default values with existing HelmRelease values
|
||||||
|
// All fields are merged except "_cozystack" and "_namespace" which are fully overwritten from CRD values
|
||||||
|
// Existing HelmRelease values (outside of _cozystack and _namespace) take precedence (user values override defaults)
|
||||||
|
func (r *ApplicationDefinitionReconciler) mergeHelmReleaseValues(crdValues, existingValues *apiextensionsv1.JSON) (*apiextensionsv1.JSON, error) {
|
||||||
|
// If CRD has no values, preserve existing
|
||||||
|
if crdValues == nil || len(crdValues.Raw) == 0 {
|
||||||
|
return existingValues, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If existing has no values, use CRD values
|
||||||
|
if existingValues == nil || len(existingValues.Raw) == 0 {
|
||||||
|
return crdValues, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var crdMap, existingMap map[string]interface{}
|
||||||
|
|
||||||
|
// Parse CRD values (defaults)
|
||||||
|
if err := json.Unmarshal(crdValues.Raw, &crdMap); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to unmarshal CRD values: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse existing HelmRelease values
|
||||||
|
if err := json.Unmarshal(existingValues.Raw, &existingMap); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to unmarshal existing values: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start with existing values as base (user values take priority)
|
||||||
|
// Then merge CRD values on top, but _cozystack and _namespace from CRD completely overwrite
|
||||||
|
merged := deepMergeMaps(existingMap, crdMap)
|
||||||
|
|
||||||
|
// Explicitly handle "_cozystack" field: CRD values completely overwrite existing
|
||||||
|
// This ensures _cozystack field from CRD is always used, even if user modified it
|
||||||
|
if crdCozystack, exists := crdMap["_cozystack"]; exists {
|
||||||
|
merged["_cozystack"] = crdCozystack
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explicitly handle "_namespace" field: CRD values completely overwrite existing
|
||||||
|
// This ensures _namespace field from CRD is always used, even if user modified it
|
||||||
|
if crdNamespace, exists := crdMap["_namespace"]; exists {
|
||||||
|
merged["_namespace"] = crdNamespace
|
||||||
|
}
|
||||||
|
|
||||||
|
mergedJSON, err := json.Marshal(merged)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to marshal merged values: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &apiextensionsv1.JSON{Raw: mergedJSON}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// deepMergeMaps performs a deep merge of two maps
|
||||||
|
func deepMergeMaps(base, override map[string]interface{}) map[string]interface{} {
|
||||||
|
result := make(map[string]interface{})
|
||||||
|
|
||||||
|
// Copy base map
|
||||||
|
for k, v := range base {
|
||||||
|
result[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge override map
|
||||||
|
for k, v := range override {
|
||||||
|
if baseVal, exists := result[k]; exists {
|
||||||
|
// If both are maps, recursively merge
|
||||||
|
if baseMap, ok := baseVal.(map[string]interface{}); ok {
|
||||||
|
if overrideMap, ok := v.(map[string]interface{}); ok {
|
||||||
|
result[k] = deepMergeMaps(baseMap, overrideMap)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Override takes precedence
|
||||||
|
result[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// valuesEqual compares two JSON values for equality
|
||||||
|
func valuesEqual(a, b *apiextensionsv1.JSON) bool {
|
||||||
|
if a == nil && b == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if a == nil || b == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// Simple byte comparison (could be improved with canonical JSON)
|
||||||
|
return string(a.Raw) == string(b.Raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,187 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
|
||||||
"slices"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
|
||||||
|
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
|
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CozystackResourceDefinitionReconciler struct {
|
|
||||||
client.Client
|
|
||||||
Scheme *runtime.Scheme
|
|
||||||
|
|
||||||
Debounce time.Duration
|
|
||||||
|
|
||||||
mu sync.Mutex
|
|
||||||
lastEvent time.Time
|
|
||||||
lastHandled time.Time
|
|
||||||
|
|
||||||
CozystackAPIKind string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *CozystackResourceDefinitionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
|
||||||
return r.debouncedRestart(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *CozystackResourceDefinitionReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
|
||||||
if r.Debounce == 0 {
|
|
||||||
r.Debounce = 5 * time.Second
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctrl.NewControllerManagedBy(mgr).
|
|
||||||
Named("cozystackresource-controller").
|
|
||||||
Watches(
|
|
||||||
&cozyv1alpha1.CozystackResourceDefinition{},
|
|
||||||
handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request {
|
|
||||||
r.mu.Lock()
|
|
||||||
r.lastEvent = time.Now()
|
|
||||||
r.mu.Unlock()
|
|
||||||
return []reconcile.Request{{
|
|
||||||
NamespacedName: types.NamespacedName{
|
|
||||||
Namespace: "cozy-system",
|
|
||||||
Name: "cozystack-api",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
}),
|
|
||||||
).
|
|
||||||
Complete(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
type crdHashView struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Spec cozyv1alpha1.CozystackResourceDefinitionSpec `json:"spec"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *CozystackResourceDefinitionReconciler) computeConfigHash(ctx context.Context) (string, error) {
|
|
||||||
list := &cozyv1alpha1.CozystackResourceDefinitionList{}
|
|
||||||
if err := r.List(ctx, list); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
slices.SortFunc(list.Items, sortCozyRDs)
|
|
||||||
|
|
||||||
views := make([]crdHashView, 0, len(list.Items))
|
|
||||||
for i := range list.Items {
|
|
||||||
views = append(views, crdHashView{
|
|
||||||
Name: list.Items[i].Name,
|
|
||||||
Spec: list.Items[i].Spec,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
b, err := json.Marshal(views)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
sum := sha256.Sum256(b)
|
|
||||||
return hex.EncodeToString(sum[:]), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *CozystackResourceDefinitionReconciler) debouncedRestart(ctx context.Context) (ctrl.Result, error) {
|
|
||||||
logger := log.FromContext(ctx)
|
|
||||||
|
|
||||||
r.mu.Lock()
|
|
||||||
le := r.lastEvent
|
|
||||||
lh := r.lastHandled
|
|
||||||
debounce := r.Debounce
|
|
||||||
r.mu.Unlock()
|
|
||||||
|
|
||||||
if debounce <= 0 {
|
|
||||||
debounce = 5 * time.Second
|
|
||||||
}
|
|
||||||
if le.IsZero() {
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
if d := time.Since(le); d < debounce {
|
|
||||||
return ctrl.Result{RequeueAfter: debounce - d}, nil
|
|
||||||
}
|
|
||||||
if !lh.Before(le) {
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
newHash, err := r.computeConfigHash(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return ctrl.Result{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tpl, obj, patch, err := r.getWorkload(ctx, types.NamespacedName{Namespace: "cozy-system", Name: "cozystack-api"})
|
|
||||||
if err != nil {
|
|
||||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
oldHash := tpl.Annotations["cozystack.io/config-hash"]
|
|
||||||
|
|
||||||
if oldHash == newHash && oldHash != "" {
|
|
||||||
r.mu.Lock()
|
|
||||||
r.lastHandled = le
|
|
||||||
r.mu.Unlock()
|
|
||||||
logger.Info("No changes in CRD config; skipping restart", "hash", newHash)
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
tpl.Annotations["cozystack.io/config-hash"] = newHash
|
|
||||||
|
|
||||||
if err := r.Patch(ctx, obj, patch); err != nil {
|
|
||||||
return ctrl.Result{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
r.mu.Lock()
|
|
||||||
r.lastHandled = le
|
|
||||||
r.mu.Unlock()
|
|
||||||
|
|
||||||
logger.Info("Updated cozystack-api podTemplate config-hash; rollout triggered",
|
|
||||||
"old", oldHash, "new", newHash)
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *CozystackResourceDefinitionReconciler) getWorkload(
|
|
||||||
ctx context.Context,
|
|
||||||
key types.NamespacedName,
|
|
||||||
) (tpl *corev1.PodTemplateSpec, obj client.Object, patch client.Patch, err error) {
|
|
||||||
if r.CozystackAPIKind == "Deployment" {
|
|
||||||
dep := &appsv1.Deployment{}
|
|
||||||
if err := r.Get(ctx, key, dep); err != nil {
|
|
||||||
return nil, nil, nil, err
|
|
||||||
}
|
|
||||||
obj = dep
|
|
||||||
tpl = &dep.Spec.Template
|
|
||||||
patch = client.MergeFrom(dep.DeepCopy())
|
|
||||||
} else {
|
|
||||||
ds := &appsv1.DaemonSet{}
|
|
||||||
if err := r.Get(ctx, key, ds); err != nil {
|
|
||||||
return nil, nil, nil, err
|
|
||||||
}
|
|
||||||
obj = ds
|
|
||||||
tpl = &ds.Spec.Template
|
|
||||||
patch = client.MergeFrom(ds.DeepCopy())
|
|
||||||
}
|
|
||||||
if tpl.Annotations == nil {
|
|
||||||
tpl.Annotations = make(map[string]string)
|
|
||||||
}
|
|
||||||
return tpl, obj, patch, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func sortCozyRDs(a, b cozyv1alpha1.CozystackResourceDefinition) int {
|
|
||||||
if a.Name == b.Name {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
if a.Name < b.Name {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
@ -14,7 +14,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// ensureBreadcrumb creates or updates a Breadcrumb resource for the given CRD
|
// ensureBreadcrumb creates or updates a Breadcrumb resource for the given CRD
|
||||||
func (m *Manager) ensureBreadcrumb(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) error {
|
func (m *Manager) ensureBreadcrumb(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) error {
|
||||||
group, version, kind := pickGVK(crd)
|
group, version, kind := pickGVK(crd)
|
||||||
|
|
||||||
lowerKind := strings.ToLower(kind)
|
lowerKind := strings.ToLower(kind)
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import (
|
||||||
//
|
//
|
||||||
// metadata.name: stock-namespace-<group>.<version>.<plural>
|
// metadata.name: stock-namespace-<group>.<version>.<plural>
|
||||||
// spec.id: stock-namespace-/<group>/<version>/<plural>
|
// spec.id: stock-namespace-/<group>/<version>/<plural>
|
||||||
func (m *Manager) ensureCustomColumnsOverride(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) (controllerutil.OperationResult, error) {
|
func (m *Manager) ensureCustomColumnsOverride(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) (controllerutil.OperationResult, error) {
|
||||||
g, v, kind := pickGVK(crd)
|
g, v, kind := pickGVK(crd)
|
||||||
plural := pickPlural(kind, crd)
|
plural := pickPlural(kind, crd)
|
||||||
// Details page segment uses lowercase kind, mirroring your example
|
// Details page segment uses lowercase kind, mirroring your example
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// ensureCustomFormsOverride creates or updates a CustomFormsOverride resource for the given CRD
|
// ensureCustomFormsOverride creates or updates a CustomFormsOverride resource for the given CRD
|
||||||
func (m *Manager) ensureCustomFormsOverride(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) error {
|
func (m *Manager) ensureCustomFormsOverride(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) error {
|
||||||
g, v, kind := pickGVK(crd)
|
g, v, kind := pickGVK(crd)
|
||||||
plural := pickPlural(kind, crd)
|
plural := pickPlural(kind, crd)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// ensureCustomFormsPrefill creates or updates a CustomFormsPrefill resource for the given CRD
|
// ensureCustomFormsPrefill creates or updates a CustomFormsPrefill resource for the given CRD
|
||||||
func (m *Manager) ensureCustomFormsPrefill(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) (reconcile.Result, error) {
|
func (m *Manager) ensureCustomFormsPrefill(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) (reconcile.Result, error) {
|
||||||
logger := log.FromContext(ctx)
|
logger := log.FromContext(ctx)
|
||||||
|
|
||||||
app := crd.Spec.Application
|
app := crd.Spec.Application
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// ensureFactory creates or updates a Factory resource for the given CRD
|
// ensureFactory creates or updates a Factory resource for the given CRD
|
||||||
func (m *Manager) ensureFactory(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) error {
|
func (m *Manager) ensureFactory(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) error {
|
||||||
g, v, kind := pickGVK(crd)
|
g, v, kind := pickGVK(crd)
|
||||||
plural := pickPlural(kind, crd)
|
plural := pickPlural(kind, crd)
|
||||||
|
|
||||||
|
|
@ -557,7 +557,7 @@ type factoryFlags struct {
|
||||||
|
|
||||||
// factoryFeatureFlags tries several conventional locations so you can evolve the API
|
// factoryFeatureFlags tries several conventional locations so you can evolve the API
|
||||||
// without breaking the controller. Defaults are false (hidden).
|
// without breaking the controller. Defaults are false (hidden).
|
||||||
func factoryFeatureFlags(crd *cozyv1alpha1.CozystackResourceDefinition) factoryFlags {
|
func factoryFeatureFlags(crd *cozyv1alpha1.ApplicationDefinition) factoryFlags {
|
||||||
var f factoryFlags
|
var f factoryFlags
|
||||||
|
|
||||||
f.Workloads = true
|
f.Workloads = true
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ type fieldInfo struct {
|
||||||
|
|
||||||
// pickGVK tries to read group/version/kind from the CRD. We prefer the "application" section,
|
// pickGVK tries to read group/version/kind from the CRD. We prefer the "application" section,
|
||||||
// falling back to other likely fields if your schema differs.
|
// falling back to other likely fields if your schema differs.
|
||||||
func pickGVK(crd *cozyv1alpha1.CozystackResourceDefinition) (group, version, kind string) {
|
func pickGVK(crd *cozyv1alpha1.ApplicationDefinition) (group, version, kind string) {
|
||||||
// Best guess based on your examples:
|
// Best guess based on your examples:
|
||||||
if crd.Spec.Application.Kind != "" {
|
if crd.Spec.Application.Kind != "" {
|
||||||
kind = crd.Spec.Application.Kind
|
kind = crd.Spec.Application.Kind
|
||||||
|
|
@ -41,7 +41,7 @@ func pickGVK(crd *cozyv1alpha1.CozystackResourceDefinition) (group, version, kin
|
||||||
}
|
}
|
||||||
|
|
||||||
// pickPlural prefers a field on the CRD if you have it; otherwise do a simple lowercase + "s".
|
// pickPlural prefers a field on the CRD if you have it; otherwise do a simple lowercase + "s".
|
||||||
func pickPlural(kind string, crd *cozyv1alpha1.CozystackResourceDefinition) string {
|
func pickPlural(kind string, crd *cozyv1alpha1.ApplicationDefinition) string {
|
||||||
// If you have crd.Spec.Application.Plural, prefer it. Example:
|
// If you have crd.Spec.Application.Plural, prefer it. Example:
|
||||||
if crd.Spec.Application.Plural != "" {
|
if crd.Spec.Application.Plural != "" {
|
||||||
return crd.Spec.Application.Plural
|
return crd.Spec.Application.Plural
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ func NewManager(c client.Client, scheme *runtime.Scheme) *Manager {
|
||||||
func (m *Manager) SetupWithManager(mgr ctrl.Manager) error {
|
func (m *Manager) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
if err := ctrl.NewControllerManagedBy(mgr).
|
if err := ctrl.NewControllerManagedBy(mgr).
|
||||||
Named("dashboard-reconciler").
|
Named("dashboard-reconciler").
|
||||||
For(&cozyv1alpha1.CozystackResourceDefinition{}).
|
For(&cozyv1alpha1.ApplicationDefinition{}).
|
||||||
Complete(m); err != nil {
|
Complete(m); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -72,7 +72,7 @@ func (m *Manager) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
func (m *Manager) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
func (m *Manager) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||||
l := log.FromContext(ctx)
|
l := log.FromContext(ctx)
|
||||||
|
|
||||||
crd := &cozyv1alpha1.CozystackResourceDefinition{}
|
crd := &cozyv1alpha1.ApplicationDefinition{}
|
||||||
|
|
||||||
err := m.Get(ctx, types.NamespacedName{Name: req.Name}, crd)
|
err := m.Get(ctx, types.NamespacedName{Name: req.Name}, crd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -99,7 +99,7 @@ func (m *Manager) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result,
|
||||||
// - ensureMarketplacePanel (implemented)
|
// - ensureMarketplacePanel (implemented)
|
||||||
// - ensureSidebar (implemented)
|
// - ensureSidebar (implemented)
|
||||||
// - ensureTableUriMapping (implemented)
|
// - ensureTableUriMapping (implemented)
|
||||||
func (m *Manager) EnsureForCRD(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) (reconcile.Result, error) {
|
func (m *Manager) EnsureForCRD(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) (reconcile.Result, error) {
|
||||||
// Early return if crd.Spec.Dashboard is nil to prevent oscillation
|
// Early return if crd.Spec.Dashboard is nil to prevent oscillation
|
||||||
if crd.Spec.Dashboard == nil {
|
if crd.Spec.Dashboard == nil {
|
||||||
return reconcile.Result{}, nil
|
return reconcile.Result{}, nil
|
||||||
|
|
@ -148,7 +148,7 @@ func (m *Manager) InitializeStaticResources(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// addDashboardLabels adds standard dashboard management labels to a resource
|
// addDashboardLabels adds standard dashboard management labels to a resource
|
||||||
func (m *Manager) addDashboardLabels(obj client.Object, crd *cozyv1alpha1.CozystackResourceDefinition, resourceType string) {
|
func (m *Manager) addDashboardLabels(obj client.Object, crd *cozyv1alpha1.ApplicationDefinition, resourceType string) {
|
||||||
labels := obj.GetLabels()
|
labels := obj.GetLabels()
|
||||||
if labels == nil {
|
if labels == nil {
|
||||||
labels = make(map[string]string)
|
labels = make(map[string]string)
|
||||||
|
|
@ -197,7 +197,7 @@ func (m *Manager) getStaticResourceSelector() client.MatchingLabels {
|
||||||
// CleanupOrphanedResources removes dashboard resources that are no longer needed
|
// CleanupOrphanedResources removes dashboard resources that are no longer needed
|
||||||
// This should be called after cache warming to ensure all current resources are known
|
// This should be called after cache warming to ensure all current resources are known
|
||||||
func (m *Manager) CleanupOrphanedResources(ctx context.Context) error {
|
func (m *Manager) CleanupOrphanedResources(ctx context.Context) error {
|
||||||
var crdList cozyv1alpha1.CozystackResourceDefinitionList
|
var crdList cozyv1alpha1.ApplicationDefinitionList
|
||||||
if err := m.List(ctx, &crdList, &client.ListOptions{}); err != nil {
|
if err := m.List(ctx, &crdList, &client.ListOptions{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -228,7 +228,7 @@ func (m *Manager) CleanupOrphanedResources(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildExpectedResourceSet creates a map of expected resource names by type
|
// buildExpectedResourceSet creates a map of expected resource names by type
|
||||||
func (m *Manager) buildExpectedResourceSet(crds []cozyv1alpha1.CozystackResourceDefinition) map[string]map[string]bool {
|
func (m *Manager) buildExpectedResourceSet(crds []cozyv1alpha1.ApplicationDefinition) map[string]map[string]bool {
|
||||||
expected := make(map[string]map[string]bool)
|
expected := make(map[string]map[string]bool)
|
||||||
|
|
||||||
// Initialize maps for each resource type
|
// Initialize maps for each resource type
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// ensureMarketplacePanel creates or updates a MarketplacePanel resource for the given CRD
|
// ensureMarketplacePanel creates or updates a MarketplacePanel resource for the given CRD
|
||||||
func (m *Manager) ensureMarketplacePanel(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) (reconcile.Result, error) {
|
func (m *Manager) ensureMarketplacePanel(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) (reconcile.Result, error) {
|
||||||
logger := log.FromContext(ctx)
|
logger := log.FromContext(ctx)
|
||||||
|
|
||||||
mp := &dashv1alpha1.MarketplacePanel{}
|
mp := &dashv1alpha1.MarketplacePanel{}
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,12 @@ import (
|
||||||
// - Categories are ordered strictly as:
|
// - Categories are ordered strictly as:
|
||||||
// Marketplace, IaaS, PaaS, NaaS, <others A→Z>, Resources, Administration
|
// Marketplace, IaaS, PaaS, NaaS, <others A→Z>, Resources, Administration
|
||||||
// - Items within each category: sort by Weight (desc), then Label (A→Z).
|
// - Items within each category: sort by Weight (desc), then Label (A→Z).
|
||||||
func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) error {
|
func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) error {
|
||||||
// Build the full menu once.
|
// Build the full menu once.
|
||||||
|
|
||||||
// 1) Fetch all CRDs
|
// 1) Fetch all CRDs
|
||||||
var all []cozyv1alpha1.CozystackResourceDefinition
|
var all []cozyv1alpha1.ApplicationDefinition
|
||||||
var crdList cozyv1alpha1.CozystackResourceDefinitionList
|
var crdList cozyv1alpha1.ApplicationDefinitionList
|
||||||
if err := m.List(ctx, &crdList, &client.ListOptions{}); err != nil {
|
if err := m.List(ctx, &crdList, &client.ListOptions{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -228,7 +228,7 @@ func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.Cozystack
|
||||||
// upsertMultipleSidebars creates/updates several Sidebar resources with the same menu spec.
|
// upsertMultipleSidebars creates/updates several Sidebar resources with the same menu spec.
|
||||||
func (m *Manager) upsertMultipleSidebars(
|
func (m *Manager) upsertMultipleSidebars(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
crd *cozyv1alpha1.CozystackResourceDefinition,
|
crd *cozyv1alpha1.ApplicationDefinition,
|
||||||
ids []string,
|
ids []string,
|
||||||
keysAndTags map[string]any,
|
keysAndTags map[string]any,
|
||||||
menuItems []any,
|
menuItems []any,
|
||||||
|
|
@ -335,7 +335,7 @@ func orderCategoryLabels[T any](cats map[string][]T) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// safeCategory returns spec.dashboard.category or "Resources" if not set.
|
// safeCategory returns spec.dashboard.category or "Resources" if not set.
|
||||||
func safeCategory(def *cozyv1alpha1.CozystackResourceDefinition) string {
|
func safeCategory(def *cozyv1alpha1.ApplicationDefinition) string {
|
||||||
if def == nil || def.Spec.Dashboard == nil {
|
if def == nil || def.Spec.Dashboard == nil {
|
||||||
return "Resources"
|
return "Resources"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// ensureTableUriMapping creates or updates a TableUriMapping resource for the given CRD
|
// ensureTableUriMapping creates or updates a TableUriMapping resource for the given CRD
|
||||||
func (m *Manager) ensureTableUriMapping(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) error {
|
func (m *Manager) ensureTableUriMapping(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) error {
|
||||||
// Links are fully managed by the CustomColumnsOverride.
|
// Links are fully managed by the CustomColumnsOverride.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
170
internal/controller/namespace_helm_reconciler.go
Normal file
170
internal/controller/namespace_helm_reconciler.go
Normal file
|
|
@ -0,0 +1,170 @@
|
||||||
|
/*
|
||||||
|
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 controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
helmv2 "github.com/fluxcd/helm-controller/api/v2"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
|
||||||
|
"github.com/cozystack/cozystack/pkg/cozylib"
|
||||||
|
)
|
||||||
|
|
||||||
|
// +kubebuilder:rbac:groups=core,resources=namespaces,verbs=get;list;watch
|
||||||
|
// +kubebuilder:rbac:groups=helm.toolkit.fluxcd.io,resources=helmreleases,verbs=get;list;watch;update;patch
|
||||||
|
type NamespaceHelmReconciler struct {
|
||||||
|
client.Client
|
||||||
|
Scheme *runtime.Scheme
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconcile processes namespace changes and updates HelmReleases with namespace labels
|
||||||
|
func (r *NamespaceHelmReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||||
|
logger := log.FromContext(ctx)
|
||||||
|
|
||||||
|
// Get the namespace
|
||||||
|
namespace := &corev1.Namespace{}
|
||||||
|
if err := r.Get(ctx, req.NamespacedName, namespace); err != nil {
|
||||||
|
logger.Error(err, "unable to fetch Namespace")
|
||||||
|
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract namespace.cozystack.io/* annotations
|
||||||
|
namespaceLabels := cozylib.ExtractNamespaceAnnotations(namespace)
|
||||||
|
if len(namespaceLabels) == 0 {
|
||||||
|
// No namespace labels to process, skip
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("processing namespace labels", "namespace", namespace.Name, "labels", namespaceLabels)
|
||||||
|
|
||||||
|
// List all HelmReleases in this namespace
|
||||||
|
helmReleaseList := &helmv2.HelmReleaseList{}
|
||||||
|
if err := r.List(ctx, helmReleaseList, client.InNamespace(namespace.Name)); err != nil {
|
||||||
|
logger.Error(err, "unable to list HelmReleases in namespace", "namespace", namespace.Name)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update each HelmRelease with namespace labels
|
||||||
|
updated := 0
|
||||||
|
for i := range helmReleaseList.Items {
|
||||||
|
hr := &helmReleaseList.Items[i]
|
||||||
|
if err := r.updateHelmReleaseWithNamespaceLabels(ctx, hr, namespaceLabels); err != nil {
|
||||||
|
logger.Error(err, "failed to update HelmRelease", "name", hr.Name, "namespace", hr.Namespace)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
updated++
|
||||||
|
}
|
||||||
|
|
||||||
|
if updated > 0 {
|
||||||
|
logger.Info("updated HelmReleases with namespace labels", "namespace", namespace.Name, "count", updated)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// updateHelmReleaseWithNamespaceLabels updates HelmRelease values with namespace labels
|
||||||
|
func (r *NamespaceHelmReconciler) updateHelmReleaseWithNamespaceLabels(ctx context.Context, hr *helmv2.HelmRelease, namespaceLabels map[string]string) error {
|
||||||
|
logger := log.FromContext(ctx)
|
||||||
|
|
||||||
|
// Parse current values
|
||||||
|
var valuesMap map[string]interface{}
|
||||||
|
if hr.Spec.Values != nil && len(hr.Spec.Values.Raw) > 0 {
|
||||||
|
if err := json.Unmarshal(hr.Spec.Values.Raw, &valuesMap); err != nil {
|
||||||
|
return fmt.Errorf("failed to unmarshal HelmRelease values: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
valuesMap = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert namespaceLabels from map[string]string to map[string]interface{}
|
||||||
|
namespaceLabelsMap := make(map[string]interface{})
|
||||||
|
for k, v := range namespaceLabels {
|
||||||
|
namespaceLabelsMap[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if namespace labels need to be updated (top-level _namespace field)
|
||||||
|
needsUpdate := false
|
||||||
|
currentNamespace, exists := valuesMap["_namespace"]
|
||||||
|
if !exists {
|
||||||
|
needsUpdate = true
|
||||||
|
valuesMap["_namespace"] = namespaceLabelsMap
|
||||||
|
} else {
|
||||||
|
currentNamespaceMap, ok := currentNamespace.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
needsUpdate = true
|
||||||
|
valuesMap["_namespace"] = namespaceLabelsMap
|
||||||
|
} else {
|
||||||
|
// Compare and update if different
|
||||||
|
for k, v := range namespaceLabelsMap {
|
||||||
|
if currentVal, exists := currentNamespaceMap[k]; !exists || currentVal != v {
|
||||||
|
needsUpdate = true
|
||||||
|
currentNamespaceMap[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Remove keys that are no longer in namespace labels
|
||||||
|
for k := range currentNamespaceMap {
|
||||||
|
if _, exists := namespaceLabelsMap[k]; !exists {
|
||||||
|
needsUpdate = true
|
||||||
|
delete(currentNamespaceMap, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if needsUpdate {
|
||||||
|
valuesMap["_namespace"] = currentNamespaceMap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !needsUpdate {
|
||||||
|
// No changes needed
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal back to JSON
|
||||||
|
mergedJSON, err := json.Marshal(valuesMap)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to marshal values with namespace labels: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update HelmRelease
|
||||||
|
patchTarget := hr.DeepCopy()
|
||||||
|
patchTarget.Spec.Values = &apiextensionsv1.JSON{Raw: mergedJSON}
|
||||||
|
|
||||||
|
patch := client.MergeFrom(hr)
|
||||||
|
if err := r.Patch(ctx, patchTarget, patch); err != nil {
|
||||||
|
return fmt.Errorf("failed to patch HelmRelease: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("updated HelmRelease with namespace labels", "name", hr.Name, "namespace", hr.Namespace)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupWithManager sets up the controller with the Manager
|
||||||
|
func (r *NamespaceHelmReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
|
For(&corev1.Namespace{}).
|
||||||
|
Complete(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,140 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
helmv2 "github.com/fluxcd/helm-controller/api/v2"
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CozystackConfigReconciler struct {
|
|
||||||
client.Client
|
|
||||||
Scheme *runtime.Scheme
|
|
||||||
}
|
|
||||||
|
|
||||||
var configMapNames = []string{"cozystack", "cozystack-branding", "cozystack-scheduling"}
|
|
||||||
|
|
||||||
const configMapNamespace = "cozy-system"
|
|
||||||
const digestAnnotation = "cozystack.io/cozy-config-digest"
|
|
||||||
const forceReconcileKey = "reconcile.fluxcd.io/forceAt"
|
|
||||||
const requestedAt = "reconcile.fluxcd.io/requestedAt"
|
|
||||||
|
|
||||||
func (r *CozystackConfigReconciler) Reconcile(ctx context.Context, _ ctrl.Request) (ctrl.Result, error) {
|
|
||||||
log := log.FromContext(ctx)
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
|
|
||||||
digest, err := r.computeDigest(ctx)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err, "failed to compute config digest")
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var helmList helmv2.HelmReleaseList
|
|
||||||
if err := r.List(ctx, &helmList); err != nil {
|
|
||||||
return ctrl.Result{}, fmt.Errorf("failed to list HelmReleases: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
now := time.Now().Format(time.RFC3339Nano)
|
|
||||||
updated := 0
|
|
||||||
|
|
||||||
for _, hr := range helmList.Items {
|
|
||||||
isSystemApp := hr.Labels["cozystack.io/system-app"] == "true"
|
|
||||||
isTenantRoot := hr.Namespace == "tenant-root" && hr.Name == "tenant-root"
|
|
||||||
if !isSystemApp && !isTenantRoot {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
patchTarget := hr.DeepCopy()
|
|
||||||
|
|
||||||
if hr.Annotations == nil {
|
|
||||||
hr.Annotations = map[string]string{}
|
|
||||||
}
|
|
||||||
|
|
||||||
if hr.Annotations[digestAnnotation] == digest {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
patchTarget.Annotations[digestAnnotation] = digest
|
|
||||||
patchTarget.Annotations[forceReconcileKey] = now
|
|
||||||
patchTarget.Annotations[requestedAt] = now
|
|
||||||
|
|
||||||
patch := client.MergeFrom(hr.DeepCopy())
|
|
||||||
if err := r.Patch(ctx, patchTarget, patch); err != nil {
|
|
||||||
log.Error(err, "failed to patch HelmRelease", "name", hr.Name, "namespace", hr.Namespace)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
updated++
|
|
||||||
log.Info("patched HelmRelease with new config digest", "name", hr.Name, "namespace", hr.Namespace)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("finished reconciliation", "updatedHelmReleases", updated)
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *CozystackConfigReconciler) computeDigest(ctx context.Context) (string, error) {
|
|
||||||
hash := sha256.New()
|
|
||||||
|
|
||||||
for _, name := range configMapNames {
|
|
||||||
var cm corev1.ConfigMap
|
|
||||||
err := r.Get(ctx, client.ObjectKey{Namespace: configMapNamespace, Name: name}, &cm)
|
|
||||||
if err != nil {
|
|
||||||
if kerrors.IsNotFound(err) {
|
|
||||||
continue // ignore missing
|
|
||||||
}
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort keys for consistent hashing
|
|
||||||
var keys []string
|
|
||||||
for k := range cm.Data {
|
|
||||||
keys = append(keys, k)
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
|
|
||||||
for _, k := range keys {
|
|
||||||
v := cm.Data[k]
|
|
||||||
fmt.Fprintf(hash, "%s:%s=%s\n", name, k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return hex.EncodeToString(hash.Sum(nil)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *CozystackConfigReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
|
||||||
return ctrl.NewControllerManagedBy(mgr).
|
|
||||||
WithEventFilter(predicate.Funcs{
|
|
||||||
UpdateFunc: func(e event.UpdateEvent) bool {
|
|
||||||
cm, ok := e.ObjectNew.(*corev1.ConfigMap)
|
|
||||||
return ok && cm.Namespace == configMapNamespace && contains(configMapNames, cm.Name)
|
|
||||||
},
|
|
||||||
CreateFunc: func(e event.CreateEvent) bool {
|
|
||||||
cm, ok := e.Object.(*corev1.ConfigMap)
|
|
||||||
return ok && cm.Namespace == configMapNamespace && contains(configMapNames, cm.Name)
|
|
||||||
},
|
|
||||||
DeleteFunc: func(e event.DeleteEvent) bool {
|
|
||||||
cm, ok := e.Object.(*corev1.ConfigMap)
|
|
||||||
return ok && cm.Namespace == configMapNamespace && contains(configMapNames, cm.Name)
|
|
||||||
},
|
|
||||||
}).
|
|
||||||
For(&corev1.ConfigMap{}).
|
|
||||||
Complete(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func contains(slice []string, val string) bool {
|
|
||||||
for _, s := range slice {
|
|
||||||
if s == val {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
@ -1,159 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
e "errors"
|
|
||||||
|
|
||||||
helmv2 "github.com/fluxcd/helm-controller/api/v2"
|
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TenantHelmReconciler struct {
|
|
||||||
client.Client
|
|
||||||
Scheme *runtime.Scheme
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *TenantHelmReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
|
||||||
logger := log.FromContext(ctx)
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
|
|
||||||
hr := &helmv2.HelmRelease{}
|
|
||||||
if err := r.Get(ctx, req.NamespacedName, hr); err != nil {
|
|
||||||
if errors.IsNotFound(err) {
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
logger.Error(err, "unable to fetch HelmRelease")
|
|
||||||
return ctrl.Result{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !strings.HasPrefix(hr.Name, "tenant-") {
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(hr.Status.Conditions) == 0 || hr.Status.Conditions[0].Type != "Ready" {
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(hr.Status.History) == 0 {
|
|
||||||
logger.Info("no history in HelmRelease status", "name", hr.Name)
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if hr.Status.History[0].Status != "deployed" {
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
newDigest := hr.Status.History[0].Digest
|
|
||||||
var hrList helmv2.HelmReleaseList
|
|
||||||
childNamespace := getChildNamespace(hr.Namespace, hr.Name)
|
|
||||||
if childNamespace == "tenant-root" && hr.Name == "tenant-root" {
|
|
||||||
if hr.Spec.Values == nil {
|
|
||||||
logger.Error(e.New("hr.Spec.Values is nil"), "cant annotate tenant-root ns")
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
err := annotateTenantRootNs(*hr.Spec.Values, r.Client)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(err, "cant annotate tenant-root ns")
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
logger.Info("namespace 'tenant-root' annotated")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := r.List(ctx, &hrList, client.InNamespace(childNamespace)); err != nil {
|
|
||||||
logger.Error(err, "unable to list HelmReleases in namespace", "namespace", hr.Name)
|
|
||||||
return ctrl.Result{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, item := range hrList.Items {
|
|
||||||
if item.Name == hr.Name {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
oldDigest := item.GetAnnotations()["cozystack.io/tenant-config-digest"]
|
|
||||||
if oldDigest == newDigest {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
patchTarget := item.DeepCopy()
|
|
||||||
|
|
||||||
if patchTarget.Annotations == nil {
|
|
||||||
patchTarget.Annotations = map[string]string{}
|
|
||||||
}
|
|
||||||
ts := time.Now().Format(time.RFC3339Nano)
|
|
||||||
|
|
||||||
patchTarget.Annotations["cozystack.io/tenant-config-digest"] = newDigest
|
|
||||||
patchTarget.Annotations["reconcile.fluxcd.io/forceAt"] = ts
|
|
||||||
patchTarget.Annotations["reconcile.fluxcd.io/requestedAt"] = ts
|
|
||||||
|
|
||||||
patch := client.MergeFrom(item.DeepCopy())
|
|
||||||
if err := r.Patch(ctx, patchTarget, patch); err != nil {
|
|
||||||
logger.Error(err, "failed to patch HelmRelease", "name", patchTarget.Name)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Info("patched HelmRelease with new digest", "name", patchTarget.Name, "digest", newDigest, "version", hr.Status.History[0].Version)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *TenantHelmReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
|
||||||
return ctrl.NewControllerManagedBy(mgr).
|
|
||||||
For(&helmv2.HelmRelease{}).
|
|
||||||
Complete(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getChildNamespace(currentNamespace, hrName string) string {
|
|
||||||
tenantName := strings.TrimPrefix(hrName, "tenant-")
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case currentNamespace == "tenant-root" && hrName == "tenant-root":
|
|
||||||
// 1) root tenant inside root namespace
|
|
||||||
return "tenant-root"
|
|
||||||
|
|
||||||
case currentNamespace == "tenant-root":
|
|
||||||
// 2) any other tenant in root namespace
|
|
||||||
return fmt.Sprintf("tenant-%s", tenantName)
|
|
||||||
|
|
||||||
default:
|
|
||||||
// 3) tenant in a dedicated namespace
|
|
||||||
return fmt.Sprintf("%s-%s", currentNamespace, tenantName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func annotateTenantRootNs(values apiextensionsv1.JSON, c client.Client) error {
|
|
||||||
var data map[string]interface{}
|
|
||||||
if err := yaml.Unmarshal(values.Raw, &data); err != nil {
|
|
||||||
return fmt.Errorf("failed to parse HelmRelease values: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
host, ok := data["host"].(string)
|
|
||||||
if !ok || host == "" {
|
|
||||||
return fmt.Errorf("host field not found or not a string")
|
|
||||||
}
|
|
||||||
|
|
||||||
var ns corev1.Namespace
|
|
||||||
if err := c.Get(context.TODO(), client.ObjectKey{Name: "tenant-root"}, &ns); err != nil {
|
|
||||||
return fmt.Errorf("failed to get namespace tenant-root: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ns.Annotations == nil {
|
|
||||||
ns.Annotations = map[string]string{}
|
|
||||||
}
|
|
||||||
ns.Annotations["namespace.cozystack.io/host"] = host
|
|
||||||
|
|
||||||
if err := c.Update(context.TODO(), &ns); err != nil {
|
|
||||||
return fmt.Errorf("failed to update namespace: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
352
internal/fluxinstall/install.go
Normal file
352
internal/fluxinstall/install.go
Normal file
|
|
@ -0,0 +1,352 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 The Cozystack Authors.
|
||||||
|
|
||||||
|
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 fluxinstall
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/serializer/yaml"
|
||||||
|
k8syaml "k8s.io/apimachinery/pkg/util/yaml"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Install installs Flux components using embedded manifests.
|
||||||
|
// It extracts the manifests and applies them to the cluster.
|
||||||
|
// The namespace is automatically determined from the Namespace object in the manifests.
|
||||||
|
func Install(ctx context.Context, k8sClient client.Client, writeEmbeddedManifests func(string) error) error {
|
||||||
|
logger := log.FromContext(ctx)
|
||||||
|
|
||||||
|
// Create temporary directory for manifests
|
||||||
|
tmpDir, err := os.MkdirTemp("", "flux-install-*")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create temp directory: %w", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
|
// Extract embedded manifests (generated by cozypkg)
|
||||||
|
manifestsDir := filepath.Join(tmpDir, "manifests")
|
||||||
|
if err := os.MkdirAll(manifestsDir, 0755); err != nil {
|
||||||
|
return fmt.Errorf("failed to create manifests directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := writeEmbeddedManifests(manifestsDir); err != nil {
|
||||||
|
return fmt.Errorf("failed to extract embedded manifests: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the manifest file (should be fluxcd.yaml from cozypkg)
|
||||||
|
manifestPath := filepath.Join(manifestsDir, "fluxcd.yaml")
|
||||||
|
if _, err := os.Stat(manifestPath); err != nil {
|
||||||
|
// Try to find any YAML file if fluxcd.yaml doesn't exist
|
||||||
|
entries, err := os.ReadDir(manifestsDir)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read manifests directory: %w", err)
|
||||||
|
}
|
||||||
|
for _, entry := range entries {
|
||||||
|
if strings.HasSuffix(entry.Name(), ".yaml") {
|
||||||
|
manifestPath = filepath.Join(manifestsDir, entry.Name())
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse and apply manifests
|
||||||
|
objects, err := parseManifests(manifestPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to parse manifests: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(objects) == 0 {
|
||||||
|
return fmt.Errorf("no objects found in manifests")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inject KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT if set in operator environment
|
||||||
|
if err := injectKubernetesServiceEnv(objects); err != nil {
|
||||||
|
logger.Info("Failed to inject KUBERNETES_SERVICE_* env vars, continuing anyway", "error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract namespace from Namespace object in manifests
|
||||||
|
namespace, err := extractNamespace(objects)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to extract namespace from manifests: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("Installing Flux components", "namespace", namespace)
|
||||||
|
|
||||||
|
// Apply manifests using server-side apply
|
||||||
|
logger.Info("Applying Flux manifests", "count", len(objects), "manifest", manifestPath, "namespace", namespace)
|
||||||
|
if err := applyManifests(ctx, k8sClient, objects); err != nil {
|
||||||
|
return fmt.Errorf("failed to apply manifests: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("Flux installation completed successfully")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseManifests parses YAML manifests into unstructured objects.
|
||||||
|
func parseManifests(manifestPath string) ([]*unstructured.Unstructured, error) {
|
||||||
|
data, err := os.ReadFile(manifestPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read manifest file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return readYAMLObjects(bytes.NewReader(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// readYAMLObjects parses multi-document YAML into unstructured objects.
|
||||||
|
func readYAMLObjects(reader io.Reader) ([]*unstructured.Unstructured, error) {
|
||||||
|
var objects []*unstructured.Unstructured
|
||||||
|
yamlReader := k8syaml.NewYAMLReader(bufio.NewReader(reader))
|
||||||
|
|
||||||
|
for {
|
||||||
|
doc, err := yamlReader.Read()
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("failed to read YAML document: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip empty documents
|
||||||
|
if len(bytes.TrimSpace(doc)) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
obj := &unstructured.Unstructured{}
|
||||||
|
decoder := k8syaml.NewYAMLOrJSONDecoder(bytes.NewReader(doc), len(doc))
|
||||||
|
if err := decoder.Decode(obj); err != nil {
|
||||||
|
// Skip documents that can't be decoded (might be comments or empty)
|
||||||
|
if err == io.EOF {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("failed to decode YAML document: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip empty objects (no kind)
|
||||||
|
if obj.GetKind() == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
objects = append(objects, obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
return objects, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyManifests applies Kubernetes objects using server-side apply.
|
||||||
|
func applyManifests(ctx context.Context, k8sClient client.Client, objects []*unstructured.Unstructured) error {
|
||||||
|
logger := log.FromContext(ctx)
|
||||||
|
decoder := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme)
|
||||||
|
|
||||||
|
// Separate CRDs and namespaces from other resources
|
||||||
|
var stageOne []*unstructured.Unstructured // CRDs and Namespaces
|
||||||
|
var stageTwo []*unstructured.Unstructured // Everything else
|
||||||
|
|
||||||
|
for _, obj := range objects {
|
||||||
|
if isClusterDefinition(obj) {
|
||||||
|
stageOne = append(stageOne, obj)
|
||||||
|
} else {
|
||||||
|
stageTwo = append(stageTwo, obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply stage one (CRDs and Namespaces) first
|
||||||
|
if len(stageOne) > 0 {
|
||||||
|
logger.Info("Applying cluster definitions", "count", len(stageOne))
|
||||||
|
if err := applyObjects(ctx, k8sClient, decoder, stageOne); err != nil {
|
||||||
|
return fmt.Errorf("failed to apply cluster definitions: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait a bit for CRDs to be registered
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply stage two (everything else)
|
||||||
|
if len(stageTwo) > 0 {
|
||||||
|
logger.Info("Applying resources", "count", len(stageTwo))
|
||||||
|
if err := applyObjects(ctx, k8sClient, decoder, stageTwo); err != nil {
|
||||||
|
return fmt.Errorf("failed to apply resources: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyObjects applies a list of objects using server-side apply.
|
||||||
|
func applyObjects(ctx context.Context, k8sClient client.Client, decoder runtime.Decoder, objects []*unstructured.Unstructured) error {
|
||||||
|
for _, obj := range objects {
|
||||||
|
// Use server-side apply with force ownership and field manager
|
||||||
|
// FieldManager is required for apply patch operations
|
||||||
|
patchOptions := &client.PatchOptions{
|
||||||
|
FieldManager: "cozystack-operator",
|
||||||
|
Force: func() *bool { b := true; return &b }(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := k8sClient.Patch(ctx, obj, client.Apply, patchOptions); err != nil {
|
||||||
|
return fmt.Errorf("failed to apply object %s/%s: %w", obj.GetKind(), obj.GetName(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// extractNamespace extracts the namespace name from the Namespace object in the manifests.
|
||||||
|
func extractNamespace(objects []*unstructured.Unstructured) (string, error) {
|
||||||
|
for _, obj := range objects {
|
||||||
|
if obj.GetKind() == "Namespace" {
|
||||||
|
namespace := obj.GetName()
|
||||||
|
if namespace == "" {
|
||||||
|
return "", fmt.Errorf("Namespace object has no name")
|
||||||
|
}
|
||||||
|
return namespace, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("no Namespace object found in manifests")
|
||||||
|
}
|
||||||
|
|
||||||
|
// isClusterDefinition checks if an object is a CRD or Namespace.
|
||||||
|
func isClusterDefinition(obj *unstructured.Unstructured) bool {
|
||||||
|
kind := obj.GetKind()
|
||||||
|
return kind == "CustomResourceDefinition" || kind == "Namespace"
|
||||||
|
}
|
||||||
|
|
||||||
|
// injectKubernetesServiceEnv injects KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT
|
||||||
|
// environment variables into all containers of Deployment, StatefulSet, and DaemonSet objects
|
||||||
|
// if these variables are set in the operator's environment.
|
||||||
|
func injectKubernetesServiceEnv(objects []*unstructured.Unstructured) error {
|
||||||
|
kubernetesHost := os.Getenv("KUBERNETES_SERVICE_HOST")
|
||||||
|
kubernetesPort := os.Getenv("KUBERNETES_SERVICE_PORT")
|
||||||
|
|
||||||
|
// If neither variable is set, nothing to do
|
||||||
|
if kubernetesHost == "" && kubernetesPort == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, obj := range objects {
|
||||||
|
kind := obj.GetKind()
|
||||||
|
if kind != "Deployment" && kind != "StatefulSet" && kind != "DaemonSet" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Navigate to spec.template.spec.containers
|
||||||
|
spec, found, err := unstructured.NestedMap(obj.Object, "spec", "template", "spec")
|
||||||
|
if !found || err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update containers
|
||||||
|
containers, found, err := unstructured.NestedSlice(spec, "containers")
|
||||||
|
if found && err == nil {
|
||||||
|
containers = updateContainersEnv(containers, kubernetesHost, kubernetesPort)
|
||||||
|
if err := unstructured.SetNestedSlice(spec, containers, "containers"); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update initContainers
|
||||||
|
initContainers, found, err := unstructured.NestedSlice(spec, "initContainers")
|
||||||
|
if found && err == nil {
|
||||||
|
initContainers = updateContainersEnv(initContainers, kubernetesHost, kubernetesPort)
|
||||||
|
if err := unstructured.SetNestedSlice(spec, initContainers, "initContainers"); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update spec in the object
|
||||||
|
if err := unstructured.SetNestedMap(obj.Object, spec, "spec", "template", "spec"); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateContainersEnv updates environment variables for a slice of containers.
|
||||||
|
func updateContainersEnv(containers []interface{}, kubernetesHost, kubernetesPort string) []interface{} {
|
||||||
|
for i, container := range containers {
|
||||||
|
containerMap, ok := container.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
env, found, err := unstructured.NestedSlice(containerMap, "env")
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
env = []interface{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update or add KUBERNETES_SERVICE_HOST
|
||||||
|
if kubernetesHost != "" {
|
||||||
|
env = setEnvVar(env, "KUBERNETES_SERVICE_HOST", kubernetesHost)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update or add KUBERNETES_SERVICE_PORT
|
||||||
|
if kubernetesPort != "" {
|
||||||
|
env = setEnvVar(env, "KUBERNETES_SERVICE_PORT", kubernetesPort)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the container's env
|
||||||
|
if err := unstructured.SetNestedSlice(containerMap, env, "env"); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the container in the slice
|
||||||
|
containers[i] = containerMap
|
||||||
|
}
|
||||||
|
|
||||||
|
return containers
|
||||||
|
}
|
||||||
|
|
||||||
|
// setEnvVar updates or adds an environment variable in the env slice.
|
||||||
|
func setEnvVar(env []interface{}, name, value string) []interface{} {
|
||||||
|
// Check if variable already exists
|
||||||
|
for i, envVar := range env {
|
||||||
|
envVarMap, ok := envVar.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if envVarMap["name"] == name {
|
||||||
|
// Update existing variable
|
||||||
|
envVarMap["value"] = value
|
||||||
|
env[i] = envVarMap
|
||||||
|
return env
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new variable
|
||||||
|
env = append(env, map[string]interface{}{
|
||||||
|
"name": name,
|
||||||
|
"value": value,
|
||||||
|
})
|
||||||
|
|
||||||
|
return env
|
||||||
|
}
|
||||||
|
|
||||||
51
internal/fluxinstall/manifests.embed.go
Normal file
51
internal/fluxinstall/manifests.embed.go
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 The Cozystack Authors.
|
||||||
|
|
||||||
|
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 fluxinstall
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed manifests/*.yaml
|
||||||
|
var embeddedFluxManifests embed.FS
|
||||||
|
|
||||||
|
// WriteEmbeddedManifests extracts embedded Flux manifests to a temporary directory.
|
||||||
|
func WriteEmbeddedManifests(dir string) error {
|
||||||
|
manifests, err := fs.ReadDir(embeddedFluxManifests, "manifests")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read embedded manifests: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, manifest := range manifests {
|
||||||
|
data, err := fs.ReadFile(embeddedFluxManifests, path.Join("manifests", manifest.Name()))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read file %s: %w", manifest.Name(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
outputPath := path.Join(dir, manifest.Name())
|
||||||
|
if err := os.WriteFile(outputPath, data, 0666); err != nil {
|
||||||
|
return fmt.Errorf("failed to write file %s: %w", outputPath, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
11951
internal/fluxinstall/manifests/fluxcd.yaml
Normal file
11951
internal/fluxinstall/manifests/fluxcd.yaml
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -2,49 +2,38 @@ package lineagecontrollerwebhook
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
|
||||||
helmv2 "github.com/fluxcd/helm-controller/api/v2"
|
helmv2 "github.com/fluxcd/helm-controller/api/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type chartRef struct {
|
|
||||||
repo string
|
|
||||||
chart string
|
|
||||||
}
|
|
||||||
|
|
||||||
type appRef struct {
|
|
||||||
group string
|
|
||||||
kind string
|
|
||||||
}
|
|
||||||
|
|
||||||
type runtimeConfig struct {
|
|
||||||
chartAppMap map[chartRef]*cozyv1alpha1.CozystackResourceDefinition
|
|
||||||
appCRDMap map[appRef]*cozyv1alpha1.CozystackResourceDefinition
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *LineageControllerWebhook) initConfig() {
|
func (l *LineageControllerWebhook) initConfig() {
|
||||||
l.initOnce.Do(func() {
|
// No longer needed - we use labels directly from HelmRelease
|
||||||
if l.config.Load() == nil {
|
|
||||||
l.config.Store(&runtimeConfig{
|
|
||||||
chartAppMap: make(map[chartRef]*cozyv1alpha1.CozystackResourceDefinition),
|
|
||||||
appCRDMap: make(map[appRef]*cozyv1alpha1.CozystackResourceDefinition),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LineageControllerWebhook) Map(hr *helmv2.HelmRelease) (string, string, string, error) {
|
func (l *LineageControllerWebhook) Map(hr *helmv2.HelmRelease) (string, string, string, error) {
|
||||||
cfg, ok := l.config.Load().(*runtimeConfig)
|
// Extract application metadata from labels
|
||||||
|
appKind, ok := hr.Labels["apps.cozystack.io/application.kind"]
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", "", "", fmt.Errorf("failed to load chart-app mapping from config")
|
return "", "", "", fmt.Errorf("cannot map helm release %s/%s to dynamic app: missing apps.cozystack.io/application.kind label", hr.Namespace, hr.Name)
|
||||||
}
|
}
|
||||||
if hr.Spec.Chart == nil {
|
|
||||||
return "", "", "", fmt.Errorf("cannot map helm release %s/%s to dynamic app", hr.Namespace, hr.Name)
|
appGroup, ok := hr.Labels["apps.cozystack.io/application.group"]
|
||||||
}
|
|
||||||
s := hr.Spec.Chart.Spec
|
|
||||||
val, ok := cfg.chartAppMap[chartRef{s.SourceRef.Name, s.Chart}]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", "", "", fmt.Errorf("cannot map helm release %s/%s to dynamic app", hr.Namespace, hr.Name)
|
return "", "", "", fmt.Errorf("cannot map helm release %s/%s to dynamic app: missing apps.cozystack.io/application.group label", hr.Namespace, hr.Name)
|
||||||
}
|
}
|
||||||
return "apps.cozystack.io/v1alpha1", val.Spec.Application.Kind, val.Spec.Release.Prefix, nil
|
|
||||||
|
appName, ok := hr.Labels["apps.cozystack.io/application.name"]
|
||||||
|
if !ok {
|
||||||
|
return "", "", "", fmt.Errorf("cannot map helm release %s/%s to dynamic app: missing apps.cozystack.io/application.name label", hr.Namespace, hr.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct API version from group
|
||||||
|
apiVersion := fmt.Sprintf("%s/v1alpha1", appGroup)
|
||||||
|
|
||||||
|
// Extract prefix from HelmRelease name by removing the application name
|
||||||
|
// HelmRelease name format: <prefix><application-name>
|
||||||
|
prefix := strings.TrimSuffix(hr.Name, appName)
|
||||||
|
|
||||||
|
return apiVersion, appKind, prefix, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,54 +1,11 @@
|
||||||
package lineagecontrollerwebhook
|
package lineagecontrollerwebhook
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
|
|
||||||
cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackresourcedefinitions,verbs=list;watch;get
|
// SetupWithManagerAsController is no longer needed since we don't watch ApplicationDefinitions
|
||||||
|
|
||||||
func (c *LineageControllerWebhook) SetupWithManagerAsController(mgr ctrl.Manager) error {
|
func (c *LineageControllerWebhook) SetupWithManagerAsController(mgr ctrl.Manager) error {
|
||||||
return ctrl.NewControllerManagedBy(mgr).
|
// No controller needed - we use labels directly from HelmRelease
|
||||||
For(&cozyv1alpha1.CozystackResourceDefinition{}).
|
return nil
|
||||||
Complete(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *LineageControllerWebhook) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
|
||||||
l := log.FromContext(ctx)
|
|
||||||
crds := &cozyv1alpha1.CozystackResourceDefinitionList{}
|
|
||||||
if err := c.List(ctx, crds); err != nil {
|
|
||||||
l.Error(err, "failed reading CozystackResourceDefinitions")
|
|
||||||
return ctrl.Result{}, err
|
|
||||||
}
|
|
||||||
cfg := &runtimeConfig{
|
|
||||||
chartAppMap: make(map[chartRef]*cozyv1alpha1.CozystackResourceDefinition),
|
|
||||||
appCRDMap: make(map[appRef]*cozyv1alpha1.CozystackResourceDefinition),
|
|
||||||
}
|
|
||||||
for _, crd := range crds.Items {
|
|
||||||
chRef := chartRef{
|
|
||||||
crd.Spec.Release.Chart.SourceRef.Name,
|
|
||||||
crd.Spec.Release.Chart.Name,
|
|
||||||
}
|
|
||||||
appRef := appRef{
|
|
||||||
"apps.cozystack.io",
|
|
||||||
crd.Spec.Application.Kind,
|
|
||||||
}
|
|
||||||
|
|
||||||
newRef := crd
|
|
||||||
if _, exists := cfg.chartAppMap[chRef]; exists {
|
|
||||||
l.Info("duplicate chart mapping detected; ignoring subsequent entry", "key", chRef)
|
|
||||||
} else {
|
|
||||||
cfg.chartAppMap[chRef] = &newRef
|
|
||||||
}
|
|
||||||
if _, exists := cfg.appCRDMap[appRef]; exists {
|
|
||||||
l.Info("duplicate app mapping detected; ignoring subsequent entry", "key", appRef)
|
|
||||||
} else {
|
|
||||||
cfg.appCRDMap[appRef] = &newRef
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.config.Store(cfg)
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ func matchName(ctx context.Context, name string, templateContext map[string]stri
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchResourceToSelector(ctx context.Context, name string, templateContext, l map[string]string, s *cozyv1alpha1.CozystackResourceDefinitionResourceSelector) bool {
|
func matchResourceToSelector(ctx context.Context, name string, templateContext, l map[string]string, s *cozyv1alpha1.ApplicationDefinitionResourceSelector) bool {
|
||||||
sel, err := metav1.LabelSelectorAsSelector(&s.LabelSelector)
|
sel, err := metav1.LabelSelectorAsSelector(&s.LabelSelector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(ctx).Error(err, "failed to convert label selector to selector")
|
log.FromContext(ctx).Error(err, "failed to convert label selector to selector")
|
||||||
|
|
@ -53,7 +53,7 @@ func matchResourceToSelector(ctx context.Context, name string, templateContext,
|
||||||
return labelMatches && nameMatches
|
return labelMatches && nameMatches
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchResourceToSelectorArray(ctx context.Context, name string, templateContext, l map[string]string, ss []*cozyv1alpha1.CozystackResourceDefinitionResourceSelector) bool {
|
func matchResourceToSelectorArray(ctx context.Context, name string, templateContext, l map[string]string, ss []*cozyv1alpha1.ApplicationDefinitionResourceSelector) bool {
|
||||||
for _, s := range ss {
|
for _, s := range ss {
|
||||||
if matchResourceToSelector(ctx, name, templateContext, l, s) {
|
if matchResourceToSelector(ctx, name, templateContext, l, s) {
|
||||||
return true
|
return true
|
||||||
|
|
@ -62,7 +62,7 @@ func matchResourceToSelectorArray(ctx context.Context, name string, templateCont
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchResourceToExcludeInclude(ctx context.Context, name string, templateContext, l map[string]string, resources *cozyv1alpha1.CozystackResourceDefinitionResources) bool {
|
func matchResourceToExcludeInclude(ctx context.Context, name string, templateContext, l map[string]string, resources *cozyv1alpha1.ApplicationDefinitionResources) bool {
|
||||||
if resources == nil {
|
if resources == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/cozystack/cozystack/pkg/lineage"
|
"github.com/cozystack/cozystack/pkg/lineage"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
|
@ -33,8 +32,8 @@ const (
|
||||||
ManagerNameKey = "apps.cozystack.io/application.name"
|
ManagerNameKey = "apps.cozystack.io/application.name"
|
||||||
)
|
)
|
||||||
|
|
||||||
// getResourceSelectors returns the appropriate CozystackResourceDefinitionResources for a given GroupKind
|
// getResourceSelectors returns the appropriate ApplicationDefinitionResources for a given GroupKind
|
||||||
func (h *LineageControllerWebhook) getResourceSelectors(gk schema.GroupKind, crd *cozyv1alpha1.CozystackResourceDefinition) *cozyv1alpha1.CozystackResourceDefinitionResources {
|
func (h *LineageControllerWebhook) getResourceSelectors(gk schema.GroupKind, crd *cozyv1alpha1.ApplicationDefinition) *cozyv1alpha1.ApplicationDefinitionResources {
|
||||||
switch {
|
switch {
|
||||||
case gk.Group == "" && gk.Kind == "Secret":
|
case gk.Group == "" && gk.Kind == "Secret":
|
||||||
return &crd.Spec.Secrets
|
return &crd.Spec.Secrets
|
||||||
|
|
@ -88,13 +87,16 @@ func (h *LineageControllerWebhook) Handle(ctx context.Context, req admission.Req
|
||||||
"name", req.Name,
|
"name", req.Name,
|
||||||
"operation", req.Operation,
|
"operation", req.Operation,
|
||||||
)
|
)
|
||||||
|
logger.Info("webhook called", "gvk", req.Kind.String(), "namespace", req.Namespace, "name", req.Name, "operation", req.Operation)
|
||||||
warn := make(admission.Warnings, 0)
|
warn := make(admission.Warnings, 0)
|
||||||
|
|
||||||
obj := &unstructured.Unstructured{}
|
obj := &unstructured.Unstructured{}
|
||||||
if err := h.decodeUnstructured(req, obj); err != nil {
|
if err := h.decodeUnstructured(req, obj); err != nil {
|
||||||
|
logger.Error(err, "failed to decode object")
|
||||||
return admission.Errored(400, fmt.Errorf("decode object: %w", err))
|
return admission.Errored(400, fmt.Errorf("decode object: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.V(1).Info("decoded object", "labels", obj.GetLabels(), "ownerReferences", obj.GetOwnerReferences())
|
||||||
labels, err := h.computeLabels(ctx, obj)
|
labels, err := h.computeLabels(ctx, obj)
|
||||||
for {
|
for {
|
||||||
if err != nil && errors.Is(err, NoAncestors) {
|
if err != nil && errors.Is(err, NoAncestors) {
|
||||||
|
|
@ -117,9 +119,10 @@ func (h *LineageControllerWebhook) Handle(ctx context.Context, req admission.Req
|
||||||
|
|
||||||
mutated, err := json.Marshal(obj)
|
mutated, err := json.Marshal(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return admission.Errored(500, fmt.Errorf("marshal mutated pod: %w", err))
|
logger.Error(err, "failed to marshal mutated object")
|
||||||
|
return admission.Errored(500, fmt.Errorf("marshal mutated object: %w", err))
|
||||||
}
|
}
|
||||||
logger.V(1).Info("mutated pod", "namespace", obj.GetNamespace(), "name", obj.GetName())
|
logger.Info("mutated object", "namespace", obj.GetNamespace(), "name", obj.GetName(), "labels", labels)
|
||||||
return admission.PatchResponseFromRaw(req.Object.Raw, mutated).WithWarnings(warn...)
|
return admission.PatchResponseFromRaw(req.Object.Raw, mutated).WithWarnings(warn...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,21 +159,9 @@ func (h *LineageControllerWebhook) computeLabels(ctx context.Context, o *unstruc
|
||||||
ManagerKindKey: obj.GetKind(),
|
ManagerKindKey: obj.GetKind(),
|
||||||
ManagerNameKey: obj.GetName(),
|
ManagerNameKey: obj.GetName(),
|
||||||
}
|
}
|
||||||
templateLabels := map[string]string{
|
// Resource selectors are no longer needed since we don't use ApplicationDefinitions
|
||||||
"kind": strings.ToLower(obj.GetKind()),
|
// Set tenant resource label to false by default (can be overridden by other logic if needed)
|
||||||
"name": obj.GetName(),
|
labels[corev1alpha1.TenantResourceLabelKey] = "false"
|
||||||
"namespace": o.GetNamespace(),
|
|
||||||
}
|
|
||||||
cfg := h.config.Load().(*runtimeConfig)
|
|
||||||
crd := cfg.appCRDMap[appRef{gv.Group, obj.GetKind()}]
|
|
||||||
resourceSelectors := h.getResourceSelectors(o.GroupVersionKind().GroupKind(), crd)
|
|
||||||
|
|
||||||
labels[corev1alpha1.TenantResourceLabelKey] = func(b bool) string {
|
|
||||||
if b {
|
|
||||||
return corev1alpha1.TenantResourceLabelValue
|
|
||||||
}
|
|
||||||
return "false"
|
|
||||||
}(matchResourceToExcludeInclude(ctx, o.GetName(), templateLabels, o.GetLabels(), resourceSelectors))
|
|
||||||
return labels, err
|
return labels, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
1235
internal/operator/bundle_reconciler.go
Normal file
1235
internal/operator/bundle_reconciler.go
Normal file
File diff suppressed because it is too large
Load diff
541
internal/operator/platform_reconciler.go
Normal file
541
internal/operator/platform_reconciler.go
Normal file
|
|
@ -0,0 +1,541 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 The Cozystack Authors.
|
||||||
|
|
||||||
|
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 operator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
||||||
|
helmv2 "github.com/fluxcd/helm-controller/api/v2"
|
||||||
|
sourcewatcherv1beta1 "github.com/fluxcd/source-watcher/api/v2/v1beta1"
|
||||||
|
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PlatformReconciler reconciles Platform resources
|
||||||
|
type PlatformReconciler struct {
|
||||||
|
client.Client
|
||||||
|
Scheme *runtime.Scheme
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:rbac:groups=cozystack.io,resources=platforms,verbs=get;list;watch;create;update;patch;delete
|
||||||
|
// +kubebuilder:rbac:groups=cozystack.io,resources=platforms/status,verbs=get;update;patch
|
||||||
|
// +kubebuilder:rbac:groups=helm.toolkit.fluxcd.io,resources=helmreleases,verbs=get;list;watch;create;update;patch;delete
|
||||||
|
// +kubebuilder:rbac:groups=source.extensions.fluxcd.io,resources=artifactgenerators,verbs=get;list;watch;create;update;patch;delete
|
||||||
|
|
||||||
|
// Reconcile is part of the main kubernetes reconciliation loop
|
||||||
|
func (r *PlatformReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||||
|
logger := log.FromContext(ctx)
|
||||||
|
|
||||||
|
platform := &cozyv1alpha1.Platform{}
|
||||||
|
if err := r.Get(ctx, req.NamespacedName, platform); err != nil {
|
||||||
|
if apierrors.IsNotFound(err) {
|
||||||
|
// Cleanup orphaned resources
|
||||||
|
return r.cleanupOrphanedResources(ctx, req.NamespacedName)
|
||||||
|
}
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set defaults
|
||||||
|
if platform.Spec.Interval == nil {
|
||||||
|
platform.Spec.Interval = &metav1.Duration{Duration: 5 * 60 * 1000000000} // 5m
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconcile ArtifactGenerator
|
||||||
|
if err := r.reconcileArtifactGenerator(ctx, platform); err != nil {
|
||||||
|
logger.Error(err, "failed to reconcile ArtifactGenerator")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconcile HelmRelease
|
||||||
|
if err := r.reconcileHelmRelease(ctx, platform); err != nil {
|
||||||
|
logger.Error(err, "failed to reconcile HelmRelease")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup orphaned resources with platform label
|
||||||
|
if err := r.cleanupOrphanedPlatformResources(ctx, platform); err != nil {
|
||||||
|
logger.Error(err, "failed to cleanup orphaned platform resources")
|
||||||
|
// Don't return error, just log it - cleanup is best effort
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// reconcileArtifactGenerator creates or updates the ArtifactGenerator for the platform
|
||||||
|
func (r *PlatformReconciler) reconcileArtifactGenerator(ctx context.Context, platform *cozyv1alpha1.Platform) error {
|
||||||
|
logger := log.FromContext(ctx)
|
||||||
|
|
||||||
|
// Use fixed namespace for cluster-scoped resource
|
||||||
|
namespace := "cozy-system"
|
||||||
|
|
||||||
|
// Get basePath with default values (already includes full path to platform)
|
||||||
|
basePath := r.getBasePath(platform)
|
||||||
|
|
||||||
|
// Build full path from basePath (basePath already contains the full path)
|
||||||
|
fullPath := r.buildSourcePath(platform.Spec.SourceRef.Name, basePath, "")
|
||||||
|
// Extract the last component for the artifact name
|
||||||
|
artifactPathParts := strings.Split(strings.Trim(basePath, "/"), "/")
|
||||||
|
artifactName := artifactPathParts[len(artifactPathParts)-1]
|
||||||
|
|
||||||
|
copyOps := []sourcewatcherv1beta1.CopyOperation{
|
||||||
|
{
|
||||||
|
From: fullPath + "/**",
|
||||||
|
To: fmt.Sprintf("@artifact/%s/", artifactName),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create ArtifactGenerator
|
||||||
|
ag := &sourcewatcherv1beta1.ArtifactGenerator{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: platform.Name,
|
||||||
|
Namespace: namespace,
|
||||||
|
Labels: map[string]string{
|
||||||
|
"cozystack.io/platform": platform.Name,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: sourcewatcherv1beta1.ArtifactGeneratorSpec{
|
||||||
|
Sources: []sourcewatcherv1beta1.SourceReference{
|
||||||
|
{
|
||||||
|
Alias: platform.Spec.SourceRef.Name,
|
||||||
|
Kind: platform.Spec.SourceRef.Kind,
|
||||||
|
Name: platform.Spec.SourceRef.Name,
|
||||||
|
Namespace: platform.Spec.SourceRef.Namespace,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
OutputArtifacts: []sourcewatcherv1beta1.OutputArtifact{
|
||||||
|
{
|
||||||
|
Name: artifactName,
|
||||||
|
Copy: copyOps,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set ownerReference
|
||||||
|
ag.OwnerReferences = []metav1.OwnerReference{
|
||||||
|
{
|
||||||
|
APIVersion: platform.APIVersion,
|
||||||
|
Kind: platform.Kind,
|
||||||
|
Name: platform.Name,
|
||||||
|
UID: platform.UID,
|
||||||
|
Controller: func() *bool { b := true; return &b }(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("reconciling ArtifactGenerator", "name", platform.Name, "namespace", namespace)
|
||||||
|
|
||||||
|
if err := r.createOrUpdate(ctx, ag); err != nil {
|
||||||
|
return fmt.Errorf("failed to reconcile ArtifactGenerator %s: %w", platform.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("reconciled ArtifactGenerator", "name", platform.Name, "namespace", namespace)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// reconcileHelmRelease creates or updates the HelmRelease for the platform
|
||||||
|
func (r *PlatformReconciler) reconcileHelmRelease(ctx context.Context, platform *cozyv1alpha1.Platform) error {
|
||||||
|
logger := log.FromContext(ctx)
|
||||||
|
|
||||||
|
// HelmRelease name is fixed: cozystack-platform
|
||||||
|
// Use fixed namespace for cluster-scoped resource
|
||||||
|
namespace := "cozy-system"
|
||||||
|
|
||||||
|
// Get artifact name (last component of basePath)
|
||||||
|
basePath := r.getBasePath(platform)
|
||||||
|
artifactPathParts := strings.Split(strings.Trim(basePath, "/"), "/")
|
||||||
|
artifactName := artifactPathParts[len(artifactPathParts)-1]
|
||||||
|
|
||||||
|
// Merge values with sourceRef
|
||||||
|
values := r.mergeValuesWithSourceRef(platform.Spec.Values, platform.Spec.SourceRef)
|
||||||
|
|
||||||
|
// Create HelmRelease
|
||||||
|
hr := &helmv2.HelmRelease{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: platform.Name,
|
||||||
|
Namespace: namespace,
|
||||||
|
Labels: map[string]string{
|
||||||
|
"cozystack.io/platform": platform.Name,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: helmv2.HelmReleaseSpec{
|
||||||
|
Interval: *platform.Spec.Interval,
|
||||||
|
TargetNamespace: "cozy-system",
|
||||||
|
ReleaseName: "cozystack-platform",
|
||||||
|
ChartRef: &helmv2.CrossNamespaceSourceReference{
|
||||||
|
Kind: "ExternalArtifact",
|
||||||
|
Name: artifactName,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
Values: values,
|
||||||
|
Install: &helmv2.Install{
|
||||||
|
Remediation: &helmv2.InstallRemediation{
|
||||||
|
Retries: -1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Upgrade: &helmv2.Upgrade{
|
||||||
|
Remediation: &helmv2.UpgradeRemediation{
|
||||||
|
Retries: -1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set ownerReference
|
||||||
|
hr.OwnerReferences = []metav1.OwnerReference{
|
||||||
|
{
|
||||||
|
APIVersion: platform.APIVersion,
|
||||||
|
Kind: platform.Kind,
|
||||||
|
Name: platform.Name,
|
||||||
|
UID: platform.UID,
|
||||||
|
Controller: func() *bool { b := true; return &b }(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("reconciling HelmRelease", "name", platform.Name, "namespace", namespace)
|
||||||
|
|
||||||
|
if err := r.createOrUpdate(ctx, hr); err != nil {
|
||||||
|
return fmt.Errorf("failed to reconcile HelmRelease %s: %w", platform.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("reconciled HelmRelease", "name", platform.Name, "namespace", namespace)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// mergeValuesWithSourceRef merges platform values with sourceRef
|
||||||
|
func (r *PlatformReconciler) mergeValuesWithSourceRef(values *apiextensionsv1.JSON, sourceRef cozyv1alpha1.SourceRef) *apiextensionsv1.JSON {
|
||||||
|
// Build sourceRef map
|
||||||
|
sourceRefMap := map[string]interface{}{
|
||||||
|
"kind": sourceRef.Kind,
|
||||||
|
"name": sourceRef.Name,
|
||||||
|
"namespace": sourceRef.Namespace,
|
||||||
|
}
|
||||||
|
|
||||||
|
// If values is nil or empty, create new values with sourceRef
|
||||||
|
if values == nil || len(values.Raw) == 0 {
|
||||||
|
valuesMap := map[string]interface{}{
|
||||||
|
"sourceRef": sourceRefMap,
|
||||||
|
}
|
||||||
|
raw, _ := json.Marshal(valuesMap)
|
||||||
|
return &apiextensionsv1.JSON{Raw: raw}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse existing values
|
||||||
|
var valuesMap map[string]interface{}
|
||||||
|
if err := json.Unmarshal(values.Raw, &valuesMap); err != nil {
|
||||||
|
// If unmarshal fails, create new values with sourceRef
|
||||||
|
valuesMap = map[string]interface{}{
|
||||||
|
"sourceRef": sourceRefMap,
|
||||||
|
}
|
||||||
|
raw, _ := json.Marshal(valuesMap)
|
||||||
|
return &apiextensionsv1.JSON{Raw: raw}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge sourceRef into values (overwrite if exists)
|
||||||
|
valuesMap["sourceRef"] = sourceRefMap
|
||||||
|
|
||||||
|
// Marshal back to JSON
|
||||||
|
raw, err := json.Marshal(valuesMap)
|
||||||
|
if err != nil {
|
||||||
|
// If marshal fails, return original values
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
|
||||||
|
return &apiextensionsv1.JSON{Raw: raw}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getBasePath returns the basePath with default values based on source kind
|
||||||
|
func (r *PlatformReconciler) getBasePath(platform *cozyv1alpha1.Platform) string {
|
||||||
|
if platform.Spec.BasePath != "" {
|
||||||
|
return platform.Spec.BasePath
|
||||||
|
}
|
||||||
|
// Default values based on kind
|
||||||
|
if platform.Spec.SourceRef.Kind == "OCIRepository" {
|
||||||
|
return "core/platform" // Full path for OCI
|
||||||
|
}
|
||||||
|
// Default for GitRepository
|
||||||
|
return "packages/core/platform" // Full path for Git
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildSourcePath builds the full source path from basePath and chart path
|
||||||
|
func (r *PlatformReconciler) buildSourcePath(sourceName, basePath, chartPath string) string {
|
||||||
|
// Remove leading/trailing slashes and combine
|
||||||
|
parts := []string{}
|
||||||
|
if basePath != "" {
|
||||||
|
parts = append(parts, strings.Trim(basePath, "/"))
|
||||||
|
}
|
||||||
|
if chartPath != "" {
|
||||||
|
parts = append(parts, strings.Trim(chartPath, "/"))
|
||||||
|
}
|
||||||
|
fullPath := strings.Join(parts, "/")
|
||||||
|
if fullPath == "" {
|
||||||
|
return fmt.Sprintf("@%s", sourceName)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("@%s/%s", sourceName, fullPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanupOrphanedResources removes ArtifactGenerator and HelmRelease when Platform is deleted
|
||||||
|
func (r *PlatformReconciler) cleanupOrphanedResources(ctx context.Context, name client.ObjectKey) (ctrl.Result, error) {
|
||||||
|
logger := log.FromContext(ctx)
|
||||||
|
namespace := "cozy-system"
|
||||||
|
|
||||||
|
// Cleanup HelmReleases with the platform label that don't match
|
||||||
|
hrList := &helmv2.HelmReleaseList{}
|
||||||
|
if err := r.List(ctx, hrList, client.InNamespace(namespace), client.MatchingLabels{
|
||||||
|
"cozystack.io/platform": name.Name,
|
||||||
|
}); err != nil {
|
||||||
|
logger.Error(err, "failed to list HelmReleases for cleanup")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range hrList.Items {
|
||||||
|
hr := &hrList.Items[i]
|
||||||
|
// Check if this HelmRelease should exist (matches current Platform name)
|
||||||
|
// Since Platform is being deleted, all matching HelmReleases should be deleted
|
||||||
|
// OwnerReferences should handle this, but we'll also delete explicitly
|
||||||
|
if err := r.Delete(ctx, hr); err != nil {
|
||||||
|
if !apierrors.IsNotFound(err) {
|
||||||
|
logger.Error(err, "failed to delete orphaned HelmRelease", "name", hr.Name)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.Info("deleted orphaned HelmRelease", "name", hr.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup ArtifactGenerators with the platform label
|
||||||
|
agList := &sourcewatcherv1beta1.ArtifactGeneratorList{}
|
||||||
|
if err := r.List(ctx, agList, client.InNamespace(namespace), client.MatchingLabels{
|
||||||
|
"cozystack.io/platform": name.Name,
|
||||||
|
}); err != nil {
|
||||||
|
logger.Error(err, "failed to list ArtifactGenerators for cleanup")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range agList.Items {
|
||||||
|
ag := &agList.Items[i]
|
||||||
|
if err := r.Delete(ctx, ag); err != nil {
|
||||||
|
if !apierrors.IsNotFound(err) {
|
||||||
|
logger.Error(err, "failed to delete orphaned ArtifactGenerator", "name", ag.Name)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.Info("deleted orphaned ArtifactGenerator", "name", ag.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanupOrphanedPlatformResources removes HelmRelease and ArtifactGenerator resources
|
||||||
|
// that have the platform label but don't match the current Platform
|
||||||
|
func (r *PlatformReconciler) cleanupOrphanedPlatformResources(ctx context.Context, platform *cozyv1alpha1.Platform) error {
|
||||||
|
logger := log.FromContext(ctx)
|
||||||
|
namespace := "cozy-system"
|
||||||
|
platformName := platform.Name
|
||||||
|
|
||||||
|
// Cleanup orphaned HelmReleases
|
||||||
|
hrList := &helmv2.HelmReleaseList{}
|
||||||
|
if err := r.List(ctx, hrList, client.InNamespace(namespace), client.MatchingLabels{
|
||||||
|
"cozystack.io/platform": platformName,
|
||||||
|
}); err != nil {
|
||||||
|
return fmt.Errorf("failed to list HelmReleases: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range hrList.Items {
|
||||||
|
hr := &hrList.Items[i]
|
||||||
|
// Only delete if it doesn't match the current Platform name
|
||||||
|
// (in case Platform name changed)
|
||||||
|
if hr.Name != platformName {
|
||||||
|
logger.Info("deleting orphaned HelmRelease", "name", hr.Name, "expected", platformName)
|
||||||
|
if err := r.Delete(ctx, hr); err != nil {
|
||||||
|
if !apierrors.IsNotFound(err) {
|
||||||
|
logger.Error(err, "failed to delete orphaned HelmRelease", "name", hr.Name)
|
||||||
|
// Continue with other resources
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup orphaned ArtifactGenerators
|
||||||
|
agList := &sourcewatcherv1beta1.ArtifactGeneratorList{}
|
||||||
|
if err := r.List(ctx, agList, client.InNamespace(namespace), client.MatchingLabels{
|
||||||
|
"cozystack.io/platform": platformName,
|
||||||
|
}); err != nil {
|
||||||
|
return fmt.Errorf("failed to list ArtifactGenerators: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range agList.Items {
|
||||||
|
ag := &agList.Items[i]
|
||||||
|
// Only delete if it doesn't match the current Platform name
|
||||||
|
if ag.Name != platformName {
|
||||||
|
logger.Info("deleting orphaned ArtifactGenerator", "name", ag.Name, "expected", platformName)
|
||||||
|
if err := r.Delete(ctx, ag); err != nil {
|
||||||
|
if !apierrors.IsNotFound(err) {
|
||||||
|
logger.Error(err, "failed to delete orphaned ArtifactGenerator", "name", ag.Name)
|
||||||
|
// Continue with other resources
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// createOrUpdate creates or updates a resource
|
||||||
|
func (r *PlatformReconciler) createOrUpdate(ctx context.Context, obj client.Object) error {
|
||||||
|
existing := obj.DeepCopyObject().(client.Object)
|
||||||
|
key := client.ObjectKeyFromObject(obj)
|
||||||
|
|
||||||
|
err := r.Get(ctx, key, existing)
|
||||||
|
if apierrors.IsNotFound(err) {
|
||||||
|
return r.Create(ctx, obj)
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preserve resource version
|
||||||
|
obj.SetResourceVersion(existing.GetResourceVersion())
|
||||||
|
// Merge labels and annotations
|
||||||
|
labels := obj.GetLabels()
|
||||||
|
if labels == nil {
|
||||||
|
labels = make(map[string]string)
|
||||||
|
}
|
||||||
|
for k, v := range existing.GetLabels() {
|
||||||
|
if _, ok := labels[k]; !ok {
|
||||||
|
labels[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj.SetLabels(labels)
|
||||||
|
|
||||||
|
annotations := obj.GetAnnotations()
|
||||||
|
if annotations == nil {
|
||||||
|
annotations = make(map[string]string)
|
||||||
|
}
|
||||||
|
for k, v := range existing.GetAnnotations() {
|
||||||
|
if _, ok := annotations[k]; !ok {
|
||||||
|
annotations[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj.SetAnnotations(annotations)
|
||||||
|
|
||||||
|
// For ArtifactGenerator, explicitly update Spec and ownerReferences
|
||||||
|
if ag, ok := obj.(*sourcewatcherv1beta1.ArtifactGenerator); ok {
|
||||||
|
if existingAG, ok := existing.(*sourcewatcherv1beta1.ArtifactGenerator); ok {
|
||||||
|
logger := log.FromContext(ctx)
|
||||||
|
logger.V(1).Info("updating ArtifactGenerator Spec", "name", ag.Name, "namespace", ag.Namespace)
|
||||||
|
existingAG.Spec = ag.Spec
|
||||||
|
existingAG.SetLabels(ag.GetLabels())
|
||||||
|
existingAG.SetAnnotations(ag.GetAnnotations())
|
||||||
|
// Always use ownerReferences from the new object (set in reconcileArtifactGenerator)
|
||||||
|
existingAG.SetOwnerReferences(ag.GetOwnerReferences())
|
||||||
|
obj = existingAG
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For HelmRelease, explicitly update Spec and ownerReferences
|
||||||
|
if hr, ok := obj.(*helmv2.HelmRelease); ok {
|
||||||
|
if existingHR, ok := existing.(*helmv2.HelmRelease); ok {
|
||||||
|
logger := log.FromContext(ctx)
|
||||||
|
logger.V(1).Info("updating HelmRelease Spec", "name", hr.Name, "namespace", hr.Namespace)
|
||||||
|
existingHR.Spec = hr.Spec
|
||||||
|
existingHR.SetLabels(hr.GetLabels())
|
||||||
|
existingHR.SetAnnotations(hr.GetAnnotations())
|
||||||
|
// Always use ownerReferences from the new object (set in reconcileHelmRelease)
|
||||||
|
existingHR.SetOwnerReferences(hr.GetOwnerReferences())
|
||||||
|
obj = existingHR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.Update(ctx, obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupWithManager sets up the controller with the Manager
|
||||||
|
func (r *PlatformReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
|
Named("cozystack-platform").
|
||||||
|
For(&cozyv1alpha1.Platform{}).
|
||||||
|
Watches(
|
||||||
|
&helmv2.HelmRelease{},
|
||||||
|
handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request {
|
||||||
|
hr, ok := obj.(*helmv2.HelmRelease)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Only watch HelmReleases with cozystack.io/platform label
|
||||||
|
platformName := hr.Labels["cozystack.io/platform"]
|
||||||
|
if platformName == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return []reconcile.Request{
|
||||||
|
{
|
||||||
|
NamespacedName: client.ObjectKey{
|
||||||
|
Name: platformName,
|
||||||
|
// Cluster-scoped resource has no namespace
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
builder.WithPredicates(
|
||||||
|
predicate.NewPredicateFuncs(func(obj client.Object) bool {
|
||||||
|
// Only watch resources with cozystack.io/platform label
|
||||||
|
labels := obj.GetLabels()
|
||||||
|
return labels != nil && labels["cozystack.io/platform"] != ""
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
).
|
||||||
|
Watches(
|
||||||
|
&sourcewatcherv1beta1.ArtifactGenerator{},
|
||||||
|
handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request {
|
||||||
|
ag, ok := obj.(*sourcewatcherv1beta1.ArtifactGenerator)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Only watch ArtifactGenerators with cozystack.io/platform label
|
||||||
|
platformName := ag.Labels["cozystack.io/platform"]
|
||||||
|
if platformName == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return []reconcile.Request{
|
||||||
|
{
|
||||||
|
NamespacedName: client.ObjectKey{
|
||||||
|
Name: platformName,
|
||||||
|
// Cluster-scoped resource has no namespace
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
builder.WithPredicates(
|
||||||
|
predicate.NewPredicateFuncs(func(obj client.Object) bool {
|
||||||
|
// Only watch resources with cozystack.io/platform label
|
||||||
|
labels := obj.GetLabels()
|
||||||
|
return labels != nil && labels["cozystack.io/platform"] != ""
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
).
|
||||||
|
Complete(r)
|
||||||
|
}
|
||||||
|
|
@ -11,13 +11,13 @@ import (
|
||||||
|
|
||||||
type Memory struct {
|
type Memory struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
data map[string]cozyv1alpha1.CozystackResourceDefinition
|
data map[string]cozyv1alpha1.ApplicationDefinition
|
||||||
primed bool
|
primed bool
|
||||||
primeOnce sync.Once
|
primeOnce sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() *Memory {
|
func New() *Memory {
|
||||||
return &Memory{data: make(map[string]cozyv1alpha1.CozystackResourceDefinition)}
|
return &Memory{data: make(map[string]cozyv1alpha1.ApplicationDefinition)}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -30,7 +30,7 @@ func Global() *Memory {
|
||||||
return global
|
return global
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Memory) Upsert(obj *cozyv1alpha1.CozystackResourceDefinition) {
|
func (m *Memory) Upsert(obj *cozyv1alpha1.ApplicationDefinition) {
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -45,10 +45,10 @@ func (m *Memory) Delete(name string) {
|
||||||
m.mu.Unlock()
|
m.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Memory) Snapshot() []cozyv1alpha1.CozystackResourceDefinition {
|
func (m *Memory) Snapshot() []cozyv1alpha1.ApplicationDefinition {
|
||||||
m.mu.RLock()
|
m.mu.RLock()
|
||||||
defer m.mu.RUnlock()
|
defer m.mu.RUnlock()
|
||||||
out := make([]cozyv1alpha1.CozystackResourceDefinition, 0, len(m.data))
|
out := make([]cozyv1alpha1.ApplicationDefinition, 0, len(m.data))
|
||||||
for _, v := range m.data {
|
for _, v := range m.data {
|
||||||
out = append(out, v)
|
out = append(out, v)
|
||||||
}
|
}
|
||||||
|
|
@ -72,7 +72,7 @@ func (m *Memory) EnsurePrimingWithManager(mgr ctrl.Manager) error {
|
||||||
if ok := mgr.GetCache().WaitForCacheSync(ctx); !ok {
|
if ok := mgr.GetCache().WaitForCacheSync(ctx); !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var list cozyv1alpha1.CozystackResourceDefinitionList
|
var list cozyv1alpha1.ApplicationDefinitionList
|
||||||
if err := mgr.GetClient().List(ctx, &list); err == nil {
|
if err := mgr.GetClient().List(ctx, &list); err == nil {
|
||||||
for i := range list.Items {
|
for i := range list.Items {
|
||||||
m.Upsert(&list.Items[i])
|
m.Upsert(&list.Items[i])
|
||||||
|
|
@ -87,11 +87,11 @@ func (m *Memory) EnsurePrimingWithManager(mgr ctrl.Manager) error {
|
||||||
return errOut
|
return errOut
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Memory) ListFromCacheOrAPI(ctx context.Context, c client.Client) ([]cozyv1alpha1.CozystackResourceDefinition, error) {
|
func (m *Memory) ListFromCacheOrAPI(ctx context.Context, c client.Client) ([]cozyv1alpha1.ApplicationDefinition, error) {
|
||||||
if m.IsPrimed() {
|
if m.IsPrimed() {
|
||||||
return m.Snapshot(), nil
|
return m.Snapshot(), nil
|
||||||
}
|
}
|
||||||
var list cozyv1alpha1.CozystackResourceDefinitionList
|
var list cozyv1alpha1.ApplicationDefinitionList
|
||||||
if err := c.List(ctx, &list); err != nil {
|
if err := c.List(ctx, &list); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -120,16 +121,50 @@ func (c *Collector) collect(ctx context.Context) {
|
||||||
|
|
||||||
clusterID := string(kubeSystemNS.UID)
|
clusterID := string(kubeSystemNS.UID)
|
||||||
|
|
||||||
var cozystackCM corev1.ConfigMap
|
// Get all Bundles
|
||||||
if err := c.client.Get(ctx, types.NamespacedName{Namespace: "cozy-system", Name: "cozystack"}, &cozystackCM); err != nil {
|
var bundleList cozyv1alpha1.BundleList
|
||||||
logger.Info(fmt.Sprintf("Failed to get cozystack configmap in cozy-system namespace: %v", err))
|
bundleNameStr := ""
|
||||||
return
|
bundleEnable := ""
|
||||||
}
|
bundleDisable := ""
|
||||||
|
oidcEnabled := "false"
|
||||||
|
|
||||||
oidcEnabled := cozystackCM.Data["oidc-enabled"]
|
if err := c.client.List(ctx, &bundleList); err != nil {
|
||||||
bundle := cozystackCM.Data["bundle-name"]
|
logger.Info(fmt.Sprintf("Failed to list Bundles: %v", err))
|
||||||
bundleEnable := cozystackCM.Data["bundle-enable"]
|
// Continue with empty bundle data instead of returning
|
||||||
bundleDisable := cozystackCM.Data["bundle-disable"]
|
} else {
|
||||||
|
// Collect bundle names (sorted alphabetically)
|
||||||
|
bundleNames := make([]string, 0, len(bundleList.Items))
|
||||||
|
for _, bundle := range bundleList.Items {
|
||||||
|
bundleNames = append(bundleNames, bundle.Name)
|
||||||
|
}
|
||||||
|
sort.Strings(bundleNames)
|
||||||
|
bundleNameStr = strings.Join(bundleNames, ",")
|
||||||
|
|
||||||
|
// Collect all packages from all bundles
|
||||||
|
var allEnabledPackages []string
|
||||||
|
var allDisabledPackages []string
|
||||||
|
|
||||||
|
for _, bundle := range bundleList.Items {
|
||||||
|
for _, pkg := range bundle.Spec.Packages {
|
||||||
|
if pkg.Disabled {
|
||||||
|
allDisabledPackages = append(allDisabledPackages, pkg.Name)
|
||||||
|
} else {
|
||||||
|
allEnabledPackages = append(allEnabledPackages, pkg.Name)
|
||||||
|
// Check if keycloak package is enabled
|
||||||
|
if pkg.Name == "keycloak" {
|
||||||
|
oidcEnabled = "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort package lists alphabetically
|
||||||
|
sort.Strings(allEnabledPackages)
|
||||||
|
sort.Strings(allDisabledPackages)
|
||||||
|
|
||||||
|
bundleEnable = strings.Join(allEnabledPackages, ",")
|
||||||
|
bundleDisable = strings.Join(allDisabledPackages, ",")
|
||||||
|
}
|
||||||
|
|
||||||
// Get Kubernetes version from nodes
|
// Get Kubernetes version from nodes
|
||||||
var nodeList corev1.NodeList
|
var nodeList corev1.NodeList
|
||||||
|
|
@ -143,32 +178,41 @@ func (c *Collector) collect(ctx context.Context) {
|
||||||
|
|
||||||
// Add Cozystack info metric
|
// Add Cozystack info metric
|
||||||
if len(nodeList.Items) > 0 {
|
if len(nodeList.Items) > 0 {
|
||||||
k8sVersion, _ := c.discoveryClient.ServerVersion()
|
k8sVersion := "unknown"
|
||||||
|
if version, err := c.discoveryClient.ServerVersion(); err == nil && version != nil {
|
||||||
|
k8sVersion = version.String()
|
||||||
|
}
|
||||||
metrics.WriteString(fmt.Sprintf(
|
metrics.WriteString(fmt.Sprintf(
|
||||||
"cozy_cluster_info{cozystack_version=\"%s\",kubernetes_version=\"%s\",oidc_enabled=\"%s\",bundle_name=\"%s\",bunde_enable=\"%s\",bunde_disable=\"%s\"} 1\n",
|
"cozy_cluster_info{cozystack_version=\"%s\",kubernetes_version=\"%s\",oidc_enabled=\"%s\",bundle_name=\"%s\",bundle_enable=\"%s\",bundle_disable=\"%s\"} 1\n",
|
||||||
c.config.CozystackVersion,
|
c.config.CozystackVersion,
|
||||||
k8sVersion,
|
k8sVersion,
|
||||||
oidcEnabled,
|
oidcEnabled,
|
||||||
bundle,
|
bundleNameStr,
|
||||||
bundleEnable,
|
bundleEnable,
|
||||||
bundleDisable,
|
bundleDisable,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect node metrics
|
// Collect node metrics
|
||||||
|
if len(nodeList.Items) > 0 {
|
||||||
nodeOSCount := make(map[string]int)
|
nodeOSCount := make(map[string]int)
|
||||||
|
kernelVersion := "unknown"
|
||||||
for _, node := range nodeList.Items {
|
for _, node := range nodeList.Items {
|
||||||
key := fmt.Sprintf("%s (%s)", node.Status.NodeInfo.OperatingSystem, node.Status.NodeInfo.OSImage)
|
key := fmt.Sprintf("%s (%s)", node.Status.NodeInfo.OperatingSystem, node.Status.NodeInfo.OSImage)
|
||||||
nodeOSCount[key] = nodeOSCount[key] + 1
|
nodeOSCount[key] = nodeOSCount[key] + 1
|
||||||
|
if kernelVersion == "unknown" && node.Status.NodeInfo.KernelVersion != "" {
|
||||||
|
kernelVersion = node.Status.NodeInfo.KernelVersion
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for osKey, count := range nodeOSCount {
|
for osKey, count := range nodeOSCount {
|
||||||
metrics.WriteString(fmt.Sprintf(
|
metrics.WriteString(fmt.Sprintf(
|
||||||
"cozy_nodes_count{os=\"%s\",kernel=\"%s\"} %d\n",
|
"cozy_nodes_count{os=\"%s\",kernel=\"%s\"} %d\n",
|
||||||
osKey,
|
osKey,
|
||||||
nodeList.Items[0].Status.NodeInfo.KernelVersion,
|
kernelVersion,
|
||||||
count,
|
count,
|
||||||
))
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect LoadBalancer services metrics
|
// Collect LoadBalancer services metrics
|
||||||
|
|
@ -248,9 +292,8 @@ func (c *Collector) collect(ctx context.Context) {
|
||||||
var monitorList cozyv1alpha1.WorkloadMonitorList
|
var monitorList cozyv1alpha1.WorkloadMonitorList
|
||||||
if err := c.client.List(ctx, &monitorList); err != nil {
|
if err := c.client.List(ctx, &monitorList); err != nil {
|
||||||
logger.Info(fmt.Sprintf("Failed to list WorkloadMonitors: %v", err))
|
logger.Info(fmt.Sprintf("Failed to list WorkloadMonitors: %v", err))
|
||||||
return
|
// Continue without workload metrics instead of returning
|
||||||
}
|
} else {
|
||||||
|
|
||||||
for _, monitor := range monitorList.Items {
|
for _, monitor := range monitorList.Items {
|
||||||
metrics.WriteString(fmt.Sprintf(
|
metrics.WriteString(fmt.Sprintf(
|
||||||
"cozy_workloads_count{uid=\"%s\",kind=\"%s\",type=\"%s\",version=\"%s\"} %d\n",
|
"cozy_workloads_count{uid=\"%s\",kind=\"%s\",type=\"%s\",version=\"%s\"} %d\n",
|
||||||
|
|
@ -260,6 +303,7 @@ func (c *Collector) collect(ctx context.Context) {
|
||||||
monitor.Spec.Version,
|
monitor.Spec.Version,
|
||||||
monitor.Status.ObservedReplicas,
|
monitor.Status.ObservedReplicas,
|
||||||
))
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send metrics
|
// Send metrics
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,7 @@
|
||||||
OUT=../../_out/repos/apps
|
OUT=../../_out/repos/apps
|
||||||
CHARTS := $(shell find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}')
|
CHARTS := $(shell find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}')
|
||||||
|
|
||||||
include ../../scripts/common-envs.mk
|
include ../../hack/common-envs.mk
|
||||||
|
|
||||||
repo:
|
|
||||||
rm -rf "$(OUT)"
|
|
||||||
helm package -d "$(OUT)" $(CHARTS) --version $(COZYSTACK_VERSION)
|
|
||||||
helm repo index "$(OUT)"
|
|
||||||
|
|
||||||
fix-charts:
|
fix-charts:
|
||||||
find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}' | while read i; do sed -i -e "s/^name: .*/name: $$i/" -e "s/^version: .*/version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process/g" "$$i/Chart.yaml"; done
|
find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}' | while read i; do sed -i -e "s/^name: .*/name: $$i/" -e "s/^version: .*/version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process/g" "$$i/Chart.yaml"; done
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
### How to test packages local
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd packages/core/installer
|
|
||||||
make image-cozystack REGISTRY=YOUR_CUSTOM_REGISTRY
|
|
||||||
make apply
|
|
||||||
kubectl delete po -l app=source-controller -n cozy-fluxcd
|
|
||||||
```
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
include ../../../scripts/package.mk
|
include ../../../hack/package.mk
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }}
|
{{- $cozystack := .Values._cozystack | default dict }}
|
||||||
{{- $seaweedfs := index $myNS.metadata.annotations "namespace.cozystack.io/seaweedfs" }}
|
{{- $namespace := .Values._namespace | default dict }}
|
||||||
|
{{- $seaweedfs := dig "seaweedfs" "" $namespace }}
|
||||||
apiVersion: objectstorage.k8s.io/v1alpha1
|
apiVersion: objectstorage.k8s.io/v1alpha1
|
||||||
kind: BucketClaim
|
kind: BucketClaim
|
||||||
metadata:
|
metadata:
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,10 @@ kind: HelmRelease
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ .Release.Name }}-system
|
name: {{ .Release.Name }}-system
|
||||||
spec:
|
spec:
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: cozy-bucket
|
name: cozystack-iaas-bucket
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-system
|
|
||||||
namespace: cozy-system
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
interval: 5m
|
interval: 5m
|
||||||
timeout: 10m
|
timeout: 10m
|
||||||
install:
|
install:
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
CLICKHOUSE_BACKUP_TAG = $(shell awk '$$0 ~ /^version:/ {print $$2}' Chart.yaml)
|
CLICKHOUSE_BACKUP_TAG = $(shell awk '$$0 ~ /^version:/ {print $$2}' Chart.yaml)
|
||||||
|
|
||||||
include ../../../scripts/common-envs.mk
|
include ../../../hack/common-envs.mk
|
||||||
include ../../../scripts/package.mk
|
include ../../../hack/package.mk
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }}
|
{{- $cozystack := .Values._cozystack | default dict }}
|
||||||
{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }}
|
{{- $clusterDomain := dig "networking" "clusterDomain" "cozy.local" $cozystack }}
|
||||||
|
|
||||||
{{- if .Values.clickhouseKeeper.enabled }}
|
{{- if .Values.clickhouseKeeper.enabled }}
|
||||||
apiVersion: "clickhouse-keeper.altinity.com/v1"
|
apiVersion: "clickhouse-keeper.altinity.com/v1"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }}
|
{{- $cozystack := .Values._cozystack | default dict }}
|
||||||
{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }}
|
{{- $clusterDomain := dig "networking" "clusterDomain" "cozy.local" $cozystack }}
|
||||||
{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-credentials" .Release.Name) }}
|
{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-credentials" .Release.Name) }}
|
||||||
{{- $passwords := dict }}
|
{{- $passwords := dict }}
|
||||||
{{- $users := .Values.users }}
|
{{- $users := .Values.users }}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
include ../../../scripts/package.mk
|
include ../../../hack/package.mk
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||||
|
|
|
||||||
|
|
@ -50,15 +50,13 @@ spec:
|
||||||
postgresUID: 999
|
postgresUID: 999
|
||||||
postgresGID: 999
|
postgresGID: 999
|
||||||
enableSuperuserAccess: true
|
enableSuperuserAccess: true
|
||||||
{{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }}
|
{{- $cozystack := .Values._cozystack | default dict }}
|
||||||
{{- if $configMap }}
|
{{- $topologySpreadConstraints := dig "scheduling" "topologySpreadConstraints" (list) $cozystack }}
|
||||||
{{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }}
|
{{- if $topologySpreadConstraints }}
|
||||||
{{- if $rawConstraints }}
|
topologySpreadConstraints:
|
||||||
{{- $rawConstraints | fromYaml | toYaml | nindent 2 }}
|
{{- range $topologySpreadConstraints }}
|
||||||
labelSelector:
|
- {{- mergeOverwrite (dict "labelSelector" (dict "matchLabels" (dict "cnpg.io/cluster" (printf "%s-postgres" $.Release.Name)))) . | toYaml | nindent 6 | trim }}
|
||||||
matchLabels:
|
{{- end }}
|
||||||
cnpg.io/cluster: {{ .Release.Name }}-postgres
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
{{- end }}
|
||||||
minSyncReplicas: {{ .Values.quorum.minSyncReplicas }}
|
minSyncReplicas: {{ .Values.quorum.minSyncReplicas }}
|
||||||
maxSyncReplicas: {{ .Values.quorum.maxSyncReplicas }}
|
maxSyncReplicas: {{ .Values.quorum.maxSyncReplicas }}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
include ../../../scripts/package.mk
|
include ../../../hack/package.mk
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" | default (dict "data" (dict)) }}
|
{{- $cozystack := .Values._cozystack | default dict }}
|
||||||
{{- $clusterDomain := index $cozyConfig.data "cluster-domain" | default "cozy.local" }}
|
{{- $clusterDomain := dig "networking" "clusterDomain" "cozy.local" $cozystack }}
|
||||||
---
|
---
|
||||||
apiVersion: apps.foundationdb.org/v1beta2
|
apiVersion: apps.foundationdb.org/v1beta2
|
||||||
kind: FoundationDBCluster
|
kind: FoundationDBCluster
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
NGINX_CACHE_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml)
|
NGINX_CACHE_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml)
|
||||||
|
|
||||||
include ../../../scripts/common-envs.mk
|
include ../../../hack/common-envs.mk
|
||||||
include ../../../scripts/package.mk
|
include ../../../hack/package.mk
|
||||||
|
|
||||||
image: image-nginx
|
image: image-nginx
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
include ../../../scripts/package.mk
|
include ../../../hack/package.mk
|
||||||
PRESET_ENUM := ["nano","micro","small","medium","large","xlarge","2xlarge"]
|
PRESET_ENUM := ["nano","micro","small","medium","large","xlarge","2xlarge"]
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
KUBERNETES_VERSION = v1.33
|
KUBERNETES_VERSION = v1.33
|
||||||
KUBERNETES_PKG_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml)
|
KUBERNETES_PKG_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml)
|
||||||
|
|
||||||
include ../../../scripts/common-envs.mk
|
include ../../../hack/common-envs.mk
|
||||||
include ../../../scripts/package.mk
|
include ../../../hack/package.mk
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }}
|
{{- $cozystack := .Values._cozystack | default dict }}
|
||||||
{{- $etcd := index $myNS.metadata.annotations "namespace.cozystack.io/etcd" }}
|
{{- $namespace := .Values._namespace | default dict }}
|
||||||
{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }}
|
{{- $etcd := dig "etcd" "" $namespace }}
|
||||||
{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }}
|
{{- $ingress := dig "ingress" "" $namespace }}
|
||||||
|
{{- $host := dig "host" "" $namespace }}
|
||||||
{{- $kubevirtmachinetemplateNames := list }}
|
{{- $kubevirtmachinetemplateNames := list }}
|
||||||
{{- define "kubevirtmachinetemplate" -}}
|
{{- define "kubevirtmachinetemplate" -}}
|
||||||
spec:
|
spec:
|
||||||
|
|
@ -31,14 +32,11 @@ spec:
|
||||||
{{- end }}
|
{{- end }}
|
||||||
cluster.x-k8s.io/deployment-name: {{ $.Release.Name }}-{{ .groupName }}
|
cluster.x-k8s.io/deployment-name: {{ $.Release.Name }}-{{ .groupName }}
|
||||||
spec:
|
spec:
|
||||||
{{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }}
|
{{- $cozystack := $.Values._cozystack | default dict }}
|
||||||
{{- if $configMap }}
|
{{- $topologySpreadConstraints := dig "scheduling" "topologySpreadConstraints" (list) $cozystack }}
|
||||||
{{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }}
|
{{- if $topologySpreadConstraints }}
|
||||||
{{- if $rawConstraints }}
|
{{- range $topologySpreadConstraints }}
|
||||||
{{- $rawConstraints | fromYaml | toYaml | nindent 10 }}
|
- {{- mergeOverwrite (dict "labelSelector" (dict "matchLabels" (dict "cluster.x-k8s.io/cluster-name" $.Release.Name))) . | toYaml | nindent 12 | trim }}
|
||||||
labelSelector:
|
|
||||||
matchLabels:
|
|
||||||
cluster.x-k8s.io/cluster-name: {{ $.Release.Name }}
|
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
domain:
|
domain:
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,10 @@ metadata:
|
||||||
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
||||||
spec:
|
spec:
|
||||||
releaseName: cert-manager-crds
|
releaseName: cert-manager-crds
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: cozy-cert-manager-crds
|
name: cozystack-iaas-kubernetes-cert-manager-crds
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-system
|
|
||||||
namespace: cozy-system
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
kubeConfig:
|
kubeConfig:
|
||||||
secretRef:
|
secretRef:
|
||||||
name: {{ .Release.Name }}-admin-kubeconfig
|
name: {{ .Release.Name }}-admin-kubeconfig
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,10 @@ metadata:
|
||||||
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
||||||
spec:
|
spec:
|
||||||
releaseName: cert-manager
|
releaseName: cert-manager
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: cozy-cert-manager
|
name: cozystack-iaas-kubernetes-cert-manager
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-system
|
|
||||||
namespace: cozy-system
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
kubeConfig:
|
kubeConfig:
|
||||||
secretRef:
|
secretRef:
|
||||||
name: {{ .Release.Name }}-admin-kubeconfig
|
name: {{ .Release.Name }}-admin-kubeconfig
|
||||||
|
|
|
||||||
|
|
@ -22,15 +22,10 @@ metadata:
|
||||||
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
||||||
spec:
|
spec:
|
||||||
releaseName: cilium
|
releaseName: cilium
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: cozy-cilium
|
name: cozystack-iaas-kubernetes-cilium
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-system
|
|
||||||
namespace: cozy-system
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
kubeConfig:
|
kubeConfig:
|
||||||
secretRef:
|
secretRef:
|
||||||
name: {{ .Release.Name }}-admin-kubeconfig
|
name: {{ .Release.Name }}-admin-kubeconfig
|
||||||
|
|
|
||||||
|
|
@ -13,15 +13,10 @@ metadata:
|
||||||
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
||||||
spec:
|
spec:
|
||||||
releaseName: coredns
|
releaseName: coredns
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: cozy-coredns
|
name: cozystack-iaas-kubernetes-coredns
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-system
|
|
||||||
namespace: cozy-system
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
kubeConfig:
|
kubeConfig:
|
||||||
secretRef:
|
secretRef:
|
||||||
name: {{ .Release.Name }}-admin-kubeconfig
|
name: {{ .Release.Name }}-admin-kubeconfig
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,10 @@ metadata:
|
||||||
spec:
|
spec:
|
||||||
interval: 5m
|
interval: 5m
|
||||||
releaseName: csi
|
releaseName: csi
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: cozy-kubevirt-csi-node
|
name: cozystack-iaas-kubernetes-kubevirt-csi-node
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-system
|
|
||||||
namespace: cozy-system
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
kubeConfig:
|
kubeConfig:
|
||||||
secretRef:
|
secretRef:
|
||||||
name: {{ .Release.Name }}-admin-kubeconfig
|
name: {{ .Release.Name }}-admin-kubeconfig
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,10 @@ metadata:
|
||||||
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
||||||
spec:
|
spec:
|
||||||
releaseName: fluxcd-operator
|
releaseName: fluxcd-operator
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: cozy-fluxcd-operator
|
name: cozystack-iaas-kubernetes-fluxcd-operator
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-system
|
|
||||||
namespace: cozy-system
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
kubeConfig:
|
kubeConfig:
|
||||||
secretRef:
|
secretRef:
|
||||||
name: {{ .Release.Name }}-admin-kubeconfig
|
name: {{ .Release.Name }}-admin-kubeconfig
|
||||||
|
|
@ -56,15 +51,10 @@ metadata:
|
||||||
spec:
|
spec:
|
||||||
interval: 5m
|
interval: 5m
|
||||||
releaseName: fluxcd
|
releaseName: fluxcd
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: cozy-fluxcd
|
name: cozystack-iaas-kubernetes-fluxcd
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-system
|
|
||||||
namespace: cozy-system
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
kubeConfig:
|
kubeConfig:
|
||||||
secretRef:
|
secretRef:
|
||||||
name: {{ .Release.Name }}-kubeconfig
|
name: {{ .Release.Name }}-kubeconfig
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,10 @@ metadata:
|
||||||
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
||||||
spec:
|
spec:
|
||||||
releaseName: gateway-api-crds
|
releaseName: gateway-api-crds
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: cozy-gateway-api-crds
|
name: cozystack-iaas-kubernetes-gateway-api-crds
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-system
|
|
||||||
namespace: cozy-system
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
kubeConfig:
|
kubeConfig:
|
||||||
secretRef:
|
secretRef:
|
||||||
name: {{ .Release.Name }}-admin-kubeconfig
|
name: {{ .Release.Name }}-admin-kubeconfig
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,10 @@ metadata:
|
||||||
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
||||||
spec:
|
spec:
|
||||||
releaseName: gpu-operator
|
releaseName: gpu-operator
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: cozy-gpu-operator
|
name: cozystack-iaas-kubernetes-gpu-operator
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-system
|
|
||||||
namespace: cozy-system
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
kubeConfig:
|
kubeConfig:
|
||||||
secretRef:
|
secretRef:
|
||||||
name: {{ .Release.Name }}-admin-kubeconfig
|
name: {{ .Release.Name }}-admin-kubeconfig
|
||||||
|
|
|
||||||
|
|
@ -27,15 +27,10 @@ metadata:
|
||||||
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
||||||
spec:
|
spec:
|
||||||
releaseName: ingress-nginx
|
releaseName: ingress-nginx
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: cozy-ingress-nginx
|
name: cozystack-iaas-kubernetes-ingress-nginx
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-system
|
|
||||||
namespace: cozy-system
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
kubeConfig:
|
kubeConfig:
|
||||||
secretRef:
|
secretRef:
|
||||||
name: {{ .Release.Name }}-admin-kubeconfig
|
name: {{ .Release.Name }}-admin-kubeconfig
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }}
|
{{- $cozystack := .Values._cozystack | default dict }}
|
||||||
{{- $targetTenant := index $myNS.metadata.annotations "namespace.cozystack.io/monitoring" }}
|
{{- $namespace := .Values._namespace | default dict }}
|
||||||
|
{{- $targetTenant := dig "monitoring" "" $namespace }}
|
||||||
{{- if .Values.addons.monitoringAgents.enabled }}
|
{{- if .Values.addons.monitoringAgents.enabled }}
|
||||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||||
kind: HelmRelease
|
kind: HelmRelease
|
||||||
|
|
@ -10,15 +11,10 @@ metadata:
|
||||||
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
||||||
spec:
|
spec:
|
||||||
releaseName: cozy-monitoring-agents
|
releaseName: cozy-monitoring-agents
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: cozy-monitoring-agents
|
name: cozystack-iaas-kubernetes-monitoring-agents
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-system
|
|
||||||
namespace: cozy-system
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
kubeConfig:
|
kubeConfig:
|
||||||
secretRef:
|
secretRef:
|
||||||
name: {{ .Release.Name }}-admin-kubeconfig
|
name: {{ .Release.Name }}-admin-kubeconfig
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,10 @@ metadata:
|
||||||
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
||||||
spec:
|
spec:
|
||||||
releaseName: velero
|
releaseName: velero
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: cozy-velero
|
name: cozystack-iaas-kubernetes-velero
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-system
|
|
||||||
namespace: cozy-system
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
kubeConfig:
|
kubeConfig:
|
||||||
secretRef:
|
secretRef:
|
||||||
name: {{ .Release.Name }}-admin-kubeconfig
|
name: {{ .Release.Name }}-admin-kubeconfig
|
||||||
|
|
|
||||||
|
|
@ -9,15 +9,10 @@ metadata:
|
||||||
spec:
|
spec:
|
||||||
interval: 5m
|
interval: 5m
|
||||||
releaseName: vertical-pod-autoscaler-crds
|
releaseName: vertical-pod-autoscaler-crds
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: cozy-vertical-pod-autoscaler-crds
|
name: cozystack-iaas-kubernetes-vertical-pod-autoscaler-crds
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-system
|
|
||||||
namespace: cozy-system
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
kubeConfig:
|
kubeConfig:
|
||||||
secretRef:
|
secretRef:
|
||||||
name: {{ .Release.Name }}-admin-kubeconfig
|
name: {{ .Release.Name }}-admin-kubeconfig
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
{{- define "cozystack.defaultVPAValues" -}}
|
{{- define "cozystack.defaultVPAValues" -}}
|
||||||
{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }}
|
{{- $cozystack := .Values._cozystack | default dict }}
|
||||||
{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }}
|
{{- $clusterDomain := dig "networking" "clusterDomain" "cozy.local" $cozystack }}
|
||||||
{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }}
|
{{- $namespace := .Values._namespace | default dict }}
|
||||||
{{- $targetTenant := index $myNS.metadata.annotations "namespace.cozystack.io/monitoring" }}
|
{{- $targetTenant := dig "monitoring" "" $namespace }}
|
||||||
vpaForVPA: false
|
vpaForVPA: false
|
||||||
vertical-pod-autoscaler:
|
vertical-pod-autoscaler:
|
||||||
recommender:
|
recommender:
|
||||||
|
|
@ -36,15 +36,10 @@ metadata:
|
||||||
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
||||||
spec:
|
spec:
|
||||||
releaseName: vertical-pod-autoscaler
|
releaseName: vertical-pod-autoscaler
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: cozy-vertical-pod-autoscaler
|
name: cozystack-iaas-kubernetes-vertical-pod-autoscaler
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-system
|
|
||||||
namespace: cozy-system
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
kubeConfig:
|
kubeConfig:
|
||||||
secretRef:
|
secretRef:
|
||||||
name: {{ .Release.Name }}-admin-kubeconfig
|
name: {{ .Release.Name }}-admin-kubeconfig
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,10 @@ metadata:
|
||||||
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
||||||
spec:
|
spec:
|
||||||
releaseName: cozy-victoria-metrics-operator
|
releaseName: cozy-victoria-metrics-operator
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: cozy-victoria-metrics-operator
|
name: cozystack-iaas-kubernetes-victoria-metrics-operator
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-system
|
|
||||||
namespace: cozy-system
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
kubeConfig:
|
kubeConfig:
|
||||||
secretRef:
|
secretRef:
|
||||||
name: {{ .Release.Name }}-admin-kubeconfig
|
name: {{ .Release.Name }}-admin-kubeconfig
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,10 @@ metadata:
|
||||||
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
||||||
spec:
|
spec:
|
||||||
releaseName: vsnap-crd
|
releaseName: vsnap-crd
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: cozy-vsnap-crd
|
name: cozystack-iaas-kubernetes-volumesnapshot-crd
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-system
|
|
||||||
namespace: cozy-system
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
kubeConfig:
|
kubeConfig:
|
||||||
secretRef:
|
secretRef:
|
||||||
name: {{ .Release.Name }}-admin-kubeconfig
|
name: {{ .Release.Name }}-admin-kubeconfig
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }}
|
{{- $cozystack := .Values._cozystack | default dict }}
|
||||||
{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }}
|
{{- $namespace := .Values._namespace | default dict }}
|
||||||
|
{{- $ingress := dig "ingress" "" $namespace }}
|
||||||
{{- if and (eq .Values.addons.ingressNginx.exposeMethod "Proxied") .Values.addons.ingressNginx.hosts }}
|
{{- if and (eq .Values.addons.ingressNginx.exposeMethod "Proxied") .Values.addons.ingressNginx.hosts }}
|
||||||
---
|
---
|
||||||
apiVersion: networking.k8s.io/v1
|
apiVersion: networking.k8s.io/v1
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
MARIADB_BACKUP_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml)
|
MARIADB_BACKUP_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml)
|
||||||
|
|
||||||
include ../../../scripts/common-envs.mk
|
include ../../../hack/common-envs.mk
|
||||||
include ../../../scripts/package.mk
|
include ../../../hack/package.mk
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
include ../../../scripts/package.mk
|
include ../../../hack/package.mk
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }}
|
{{- $cozystack := .Values._cozystack | default dict }}
|
||||||
{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }}
|
{{- $clusterDomain := dig "networking" "clusterDomain" "cozy.local" $cozystack }}
|
||||||
{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-credentials" .Release.Name) }}
|
{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-credentials" .Release.Name) }}
|
||||||
{{- $passwords := dict }}
|
{{- $passwords := dict }}
|
||||||
|
|
||||||
|
|
@ -35,15 +35,10 @@ kind: HelmRelease
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ .Release.Name }}-system
|
name: {{ .Release.Name }}-system
|
||||||
spec:
|
spec:
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: cozy-nats
|
name: cozystack-paas-nats
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-system
|
|
||||||
namespace: cozy-system
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
interval: 5m
|
interval: 5m
|
||||||
timeout: 10m
|
timeout: 10m
|
||||||
install:
|
install:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
include ../../../scripts/package.mk
|
include ../../../hack/package.mk
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||||
|
|
|
||||||
|
|
@ -45,15 +45,13 @@ spec:
|
||||||
resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 4 }}
|
resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 4 }}
|
||||||
|
|
||||||
enableSuperuserAccess: true
|
enableSuperuserAccess: true
|
||||||
{{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }}
|
{{- $cozystack := .Values._cozystack | default dict }}
|
||||||
{{- if $configMap }}
|
{{- $topologySpreadConstraints := dig "scheduling" "topologySpreadConstraints" (list) $cozystack }}
|
||||||
{{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }}
|
{{- if $topologySpreadConstraints }}
|
||||||
{{- if $rawConstraints }}
|
topologySpreadConstraints:
|
||||||
{{- $rawConstraints | fromYaml | toYaml | nindent 2 }}
|
{{- range $topologySpreadConstraints }}
|
||||||
labelSelector:
|
- {{- mergeOverwrite (dict "labelSelector" (dict "matchLabels" (dict "cnpg.io/cluster" $.Release.Name))) . | toYaml | nindent 6 | trim }}
|
||||||
matchLabels:
|
{{- end }}
|
||||||
cnpg.io/cluster: {{ .Release.Name }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
{{- end }}
|
||||||
postgresql:
|
postgresql:
|
||||||
parameters:
|
parameters:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
include ../../../scripts/package.mk
|
include ../../../hack/package.mk
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
include ../../../scripts/package.mk
|
include ../../../hack/package.mk
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
include ../../../scripts/package.mk
|
include ../../../hack/package.mk
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
include ../../../scripts/package.mk
|
include ../../../hack/package.mk
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,14 @@ metadata:
|
||||||
internal.cozystack.io/tenantmodule: "true"
|
internal.cozystack.io/tenantmodule: "true"
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
apps.cozystack.io/application.kind: Etcd
|
||||||
|
apps.cozystack.io/application.group: apps.cozystack.io
|
||||||
|
apps.cozystack.io/application.name: etcd
|
||||||
spec:
|
spec:
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: etcd
|
name: cozystack-system-etcd
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-extra
|
|
||||||
namespace: cozy-public
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
interval: 5m
|
interval: 5m
|
||||||
timeout: 10m
|
timeout: 10m
|
||||||
install:
|
install:
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,14 @@ metadata:
|
||||||
internal.cozystack.io/tenantmodule: "true"
|
internal.cozystack.io/tenantmodule: "true"
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
apps.cozystack.io/application.kind: Info
|
||||||
|
apps.cozystack.io/application.group: apps.cozystack.io
|
||||||
|
apps.cozystack.io/application.name: info
|
||||||
spec:
|
spec:
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: info
|
name: cozystack-system-info
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-extra
|
|
||||||
namespace: cozy-public
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
interval: 5m
|
interval: 5m
|
||||||
timeout: 10m
|
timeout: 10m
|
||||||
install:
|
install:
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,14 @@ metadata:
|
||||||
internal.cozystack.io/tenantmodule: "true"
|
internal.cozystack.io/tenantmodule: "true"
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
apps.cozystack.io/application.kind: Ingress
|
||||||
|
apps.cozystack.io/application.group: apps.cozystack.io
|
||||||
|
apps.cozystack.io/application.name: ingress
|
||||||
spec:
|
spec:
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: ingress
|
name: cozystack-system-ingress
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-extra
|
|
||||||
namespace: cozy-public
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
interval: 5m
|
interval: 5m
|
||||||
timeout: 10m
|
timeout: 10m
|
||||||
install:
|
install:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }}
|
{{- $cozystack := .Values._cozystack | default dict }}
|
||||||
{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }}
|
{{- $authentication := $cozystack.authentication | default dict }}
|
||||||
{{- if eq $oidcEnabled "true" }}
|
{{- $oidc := $authentication.oidc | default dict }}
|
||||||
|
{{- $oidcEnabled := $oidc.enabled | default false }}
|
||||||
|
{{- if $oidcEnabled }}
|
||||||
{{- if .Capabilities.APIVersions.Has "v1.edp.epam.com/v1" }}
|
{{- if .Capabilities.APIVersions.Has "v1.edp.epam.com/v1" }}
|
||||||
apiVersion: v1.edp.epam.com/v1
|
apiVersion: v1.edp.epam.com/v1
|
||||||
kind: KeycloakRealmGroup
|
kind: KeycloakRealmGroup
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,14 @@ metadata:
|
||||||
internal.cozystack.io/tenantmodule: "true"
|
internal.cozystack.io/tenantmodule: "true"
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
apps.cozystack.io/application.kind: Monitoring
|
||||||
|
apps.cozystack.io/application.group: apps.cozystack.io
|
||||||
|
apps.cozystack.io/application.name: monitoring
|
||||||
spec:
|
spec:
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: monitoring
|
name: cozystack-system-monitoring
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-extra
|
|
||||||
namespace: cozy-public
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
interval: 5m
|
interval: 5m
|
||||||
timeout: 10m
|
timeout: 10m
|
||||||
install:
|
install:
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,21 @@
|
||||||
{{- define "cozystack.namespace-anotations" }}
|
{{- define "cozystack.namespace-anotations" }}
|
||||||
{{- $context := index . 0 }}
|
{{- $context := index . 0 }}
|
||||||
{{- $existingNS := index . 1 }}
|
{{- $namespace := index . 1 }}
|
||||||
{{- range $x := list "etcd" "monitoring" "ingress" "seaweedfs" }}
|
{{- range $x := list "etcd" "monitoring" "ingress" "seaweedfs" }}
|
||||||
{{- if (index $context.Values $x) }}
|
{{- if (index $context.Values $x) }}
|
||||||
namespace.cozystack.io/{{ $x }}: "{{ include "tenant.name" $context }}"
|
namespace.cozystack.io/{{ $x }}: "{{ include "tenant.name" $context }}"
|
||||||
{{- else }}
|
{{- else }}
|
||||||
namespace.cozystack.io/{{ $x }}: "{{ index $existingNS.metadata.annotations (printf "namespace.cozystack.io/%s" $x) | required (printf "namespace %s has no namespace.cozystack.io/%s annotation" $context.Release.Namespace $x) }}"
|
{{- $value := dig $x "" $namespace }}
|
||||||
|
{{- if $value }}
|
||||||
|
namespace.cozystack.io/{{ $x }}: "{{ $value }}"
|
||||||
|
{{- else }}
|
||||||
|
{{- fail (printf "namespace %s has no namespace.cozystack.io/%s in values.namespace" $context.Release.Namespace $x) }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
{{- $namespace := .Values._namespace | default dict }}
|
||||||
{{- $existingNS := lookup "v1" "Namespace" "" .Release.Namespace }}
|
{{- $existingNS := lookup "v1" "Namespace" "" .Release.Namespace }}
|
||||||
{{- if not $existingNS }}
|
{{- if not $existingNS }}
|
||||||
{{- fail (printf "error lookup existing namespace: %s" .Release.Namespace) }}
|
{{- fail (printf "error lookup existing namespace: %s" .Release.Namespace) }}
|
||||||
|
|
@ -26,10 +32,13 @@ metadata:
|
||||||
{{- if .Values.host }}
|
{{- if .Values.host }}
|
||||||
namespace.cozystack.io/host: "{{ .Values.host }}"
|
namespace.cozystack.io/host: "{{ .Values.host }}"
|
||||||
{{- else }}
|
{{- else }}
|
||||||
{{ $parentHost := index $existingNS.metadata.annotations "namespace.cozystack.io/host" | required (printf "namespace %s has no namespace.cozystack.io/host annotation" .Release.Namespace) }}
|
{{- $parentHost := dig "host" "" $namespace }}
|
||||||
|
{{- if not $parentHost }}
|
||||||
|
{{- fail (printf "namespace %s has no host in values.namespace" .Release.Namespace) }}
|
||||||
|
{{- end }}
|
||||||
namespace.cozystack.io/host: "{{ splitList "-" (include "tenant.name" .) | last }}.{{ $parentHost }}"
|
namespace.cozystack.io/host: "{{ splitList "-" (include "tenant.name" .) | last }}.{{ $parentHost }}"
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- include "cozystack.namespace-anotations" (list . $existingNS) | nindent 4 }}
|
{{- include "cozystack.namespace-anotations" (list . $namespace) | nindent 4 }}
|
||||||
labels:
|
labels:
|
||||||
tenant.cozystack.io/{{ include "tenant.name" $ }}: ""
|
tenant.cozystack.io/{{ include "tenant.name" $ }}: ""
|
||||||
{{- if hasPrefix "tenant-" .Release.Namespace }}
|
{{- if hasPrefix "tenant-" .Release.Namespace }}
|
||||||
|
|
@ -40,7 +49,7 @@ metadata:
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- include "cozystack.namespace-anotations" (list $ $existingNS) | nindent 4 }}
|
{{- include "cozystack.namespace-anotations" (list $ $namespace) | nindent 4 }}
|
||||||
alpha.kubevirt.io/auto-memory-limits-ratio: "1.0"
|
alpha.kubevirt.io/auto-memory-limits-ratio: "1.0"
|
||||||
ownerReferences:
|
ownerReferences:
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,14 @@ metadata:
|
||||||
internal.cozystack.io/tenantmodule: "true"
|
internal.cozystack.io/tenantmodule: "true"
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
apps.cozystack.io/application.kind: SeaweedFS
|
||||||
|
apps.cozystack.io/application.group: apps.cozystack.io
|
||||||
|
apps.cozystack.io/application.name: seaweedfs
|
||||||
spec:
|
spec:
|
||||||
chart:
|
chartRef:
|
||||||
spec:
|
kind: ExternalArtifact
|
||||||
chart: seaweedfs
|
name: cozystack-system-seaweedfs
|
||||||
reconcileStrategy: Revision
|
namespace: cozy-system
|
||||||
sourceRef:
|
|
||||||
kind: HelmRepository
|
|
||||||
name: cozystack-extra
|
|
||||||
namespace: cozy-public
|
|
||||||
version: '>= 0.0.0-0'
|
|
||||||
interval: 5m
|
interval: 5m
|
||||||
timeout: 10m
|
timeout: 10m
|
||||||
install:
|
install:
|
||||||
|
|
|
||||||
|
|
@ -385,7 +385,7 @@ apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: Role
|
kind: Role
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "tenant.name" . }}
|
name: {{ include "tenant.name" . }}
|
||||||
namespace: cozy-public
|
namespace: cozy-system
|
||||||
rules:
|
rules:
|
||||||
- apiGroups: ["source.toolkit.fluxcd.io"]
|
- apiGroups: ["source.toolkit.fluxcd.io"]
|
||||||
resources: ["helmrepositories"]
|
resources: ["helmrepositories"]
|
||||||
|
|
@ -398,7 +398,7 @@ apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: RoleBinding
|
kind: RoleBinding
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "tenant.name" . }}
|
name: {{ include "tenant.name" . }}
|
||||||
namespace: cozy-public
|
namespace: cozy-system
|
||||||
subjects:
|
subjects:
|
||||||
- kind: Group
|
- kind: Group
|
||||||
name: {{ include "tenant.name" . }}-super-admin
|
name: {{ include "tenant.name" . }}-super-admin
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
include ../../../scripts/package.mk
|
include ../../../hack/package.mk
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ spec:
|
||||||
{{- if $dv }}
|
{{- if $dv }}
|
||||||
pvc:
|
pvc:
|
||||||
name: vm-image-{{ .Values.systemDisk.image }}
|
name: vm-image-{{ .Values.systemDisk.image }}
|
||||||
namespace: cozy-public
|
namespace: cozy-system
|
||||||
{{- else }}
|
{{- else }}
|
||||||
http:
|
http:
|
||||||
{{- if eq .Values.systemDisk.image "cirros" }}
|
{{- if eq .Values.systemDisk.image "cirros" }}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
include ../../../scripts/package.mk
|
include ../../../hack/package.mk
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
include ../../../scripts/package.mk
|
include ../../../hack/package.mk
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
include ../../../scripts/package.mk
|
include ../../../hack/package.mk
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
cozyvalues-gen -v values.yaml -s values.schema.json
|
cozyvalues-gen -v values.yaml -s values.schema.json
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
include ../../../scripts/package.mk
|
include ../../../hack/package.mk
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }}
|
{{- $cozystack := .Values._cozystack | default dict }}
|
||||||
{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }}
|
{{- $namespace := .Values._namespace | default dict }}
|
||||||
|
{{- $host := dig "host" "" $namespace }}
|
||||||
{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-vpn" .Release.Name) }}
|
{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-vpn" .Release.Name) }}
|
||||||
{{- $accessKeys := list }}
|
{{- $accessKeys := list }}
|
||||||
{{- $passwords := dict }}
|
{{- $passwords := dict }}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue