From e5b65e8e779da0b3087357d973ce0c8f4bad4acf Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 18 Nov 2025 17:48:46 +0100 Subject: [PATCH 01/46] Remove cozystack-assets-server and move grafana-dashboards into separate pod Signed-off-by: Andrei Kvapil --- cmd/cozystack-assets-server/main.go | 29 ------ .../installer/images/cozystack/Dockerfile | 9 +- .../images/cozystack/Dockerfile.dockerignore | 13 ++- .../core/installer/templates/cozystack.yaml | 23 ----- .../core/platform/templates/artifacts.yaml | 92 ++++++++++++++++++ .../core/platform/templates/helmrepos.yaml | 97 +++++++++++++++++++ .../monitoring/templates/dashboards.yaml | 2 +- packages/system/grafana-operator/Makefile | 12 +++ .../images/grafana-dashboards.tag | 1 + .../images/grafana-dashboards/Dockerfile | 12 +++ .../Dockerfile.dockerignore | 3 + .../templates/dashboards-deployment.yaml | 42 ++++++++ .../templates/dashboards-service.yaml | 20 ++++ 13 files changed, 294 insertions(+), 61 deletions(-) delete mode 100644 cmd/cozystack-assets-server/main.go create mode 100644 packages/core/platform/templates/artifacts.yaml create mode 100644 packages/system/grafana-operator/images/grafana-dashboards.tag create mode 100644 packages/system/grafana-operator/images/grafana-dashboards/Dockerfile create mode 100644 packages/system/grafana-operator/images/grafana-dashboards/Dockerfile.dockerignore create mode 100644 packages/system/grafana-operator/templates/dashboards-deployment.yaml create mode 100644 packages/system/grafana-operator/templates/dashboards-service.yaml diff --git a/cmd/cozystack-assets-server/main.go b/cmd/cozystack-assets-server/main.go deleted file mode 100644 index 75563712..00000000 --- a/cmd/cozystack-assets-server/main.go +++ /dev/null @@ -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) - } -} diff --git a/packages/core/installer/images/cozystack/Dockerfile b/packages/core/installer/images/cozystack/Dockerfile index 7327698e..0f98f492 100644 --- a/packages/core/installer/images/cozystack/Dockerfile +++ b/packages/core/installer/images/cozystack/Dockerfile @@ -21,15 +21,13 @@ ARG TARGETARCH RUN apk add --no-cache make git RUN apk add helm --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community +# Check Dockerfile.dockerignore! COPY . /src/ + WORKDIR /src RUN go mod download -RUN go build -o /cozystack-assets-server -ldflags '-extldflags "-static" -w -s' ./cmd/cozystack-assets-server - -RUN make repos - FROM alpine:3.22 RUN wget -O- https://github.com/cozystack/cozypkg/raw/refs/heads/main/hack/install.sh | sh -s -- -v 1.2.0 @@ -39,10 +37,7 @@ RUN apk add --no-cache make kubectl helm coreutils git jq COPY --from=builder /src/scripts /cozystack/scripts COPY --from=builder /src/packages/core /cozystack/packages/core COPY --from=builder /src/packages/system /cozystack/packages/system -COPY --from=builder /src/_out/repos /cozystack/assets/repos -COPY --from=builder /cozystack-assets-server /usr/bin/cozystack-assets-server COPY --from=k8s-await-election-builder /k8s-await-election /usr/bin/k8s-await-election -COPY --from=builder /src/dashboards /cozystack/assets/dashboards WORKDIR /cozystack ENTRYPOINT ["/usr/bin/k8s-await-election", "/cozystack/scripts/installer.sh" ] diff --git a/packages/core/installer/images/cozystack/Dockerfile.dockerignore b/packages/core/installer/images/cozystack/Dockerfile.dockerignore index c1d18d8a..6803982e 100644 --- a/packages/core/installer/images/cozystack/Dockerfile.dockerignore +++ b/packages/core/installer/images/cozystack/Dockerfile.dockerignore @@ -1 +1,12 @@ -_out +# Exclude everything except src directory +* +!src/** +!api/** +!cmd/** +!hack/** +!internal/** +!packages/** +!pkg/** +!scripts/** +!go.mod +!go.sum diff --git a/packages/core/installer/templates/cozystack.yaml b/packages/core/installer/templates/cozystack.yaml index 10ebdc1f..0f084b90 100644 --- a/packages/core/installer/templates/cozystack.yaml +++ b/packages/core/installer/templates/cozystack.yaml @@ -68,15 +68,6 @@ spec: valueFrom: fieldRef: fieldPath: metadata.name - - name: assets - image: "{{ .Values.cozystack.image }}" - command: - - /usr/bin/cozystack-assets-server - - "-dir=/cozystack/assets" - - "-address=:8123" - ports: - - name: http - containerPort: 8123 tolerations: - key: "node.kubernetes.io/not-ready" operator: "Exists" @@ -84,17 +75,3 @@ spec: - key: "node.cilium.io/agent-not-ready" operator: "Exists" effect: "NoSchedule" ---- -apiVersion: v1 -kind: Service -metadata: - name: cozystack - namespace: cozy-system -spec: - ports: - - name: http - port: 80 - targetPort: 8123 - selector: - app: cozystack - type: ClusterIP diff --git a/packages/core/platform/templates/artifacts.yaml b/packages/core/platform/templates/artifacts.yaml new file mode 100644 index 00000000..15105de8 --- /dev/null +++ b/packages/core/platform/templates/artifacts.yaml @@ -0,0 +1,92 @@ +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: GitRepository +metadata: + name: cozystack + namespace: cozy-system +spec: + interval: 1m0s + ref: + tag: v0.37.6 + timeout: 60s + url: https://github.com/cozystack/cozystack.git + ignore: | + # exclude all + /* + # include packages dir + !/packages + +--- +apiVersion: source.extensions.fluxcd.io/v1beta1 +kind: ArtifactGenerator +metadata: + name: system + namespace: cozy-system +spec: + sources: + - alias: cozystack + kind: GitRepository + name: cozystack + namespace: cozy-system + artifacts: + - name: system-cilium + copy: + - from: "@cozystack/packages/system/cilium/**" + to: "@artifact/cilium/" + - name: system-kubeovn + copy: + - from: "@cozystack/packages/system/kubeovn/**" + to: "@artifact/kubeovn/" + +--- +apiVersion: source.extensions.fluxcd.io/v1beta1 +kind: ArtifactGenerator +metadata: + name: apps + namespace: cozy-public +spec: + sources: + - alias: cozystack + kind: GitRepository + name: cozystack + namespace: cozy-system + artifacts: + - name: apps-virtual-machine + copy: + - from: "@cozystack/packages/apps/virtual-machine/**" + to: "@artifact/virtual-machine/" + - from: "@cozystack/packages/library/cozy-lib/**" + to: "@artifact/virtual-machine/charts/cozy-lib/" + - name: apps-vm-instance + copy: + - from: "@cozystack/packages/apps/vm-instance/**" + to: "@artifact/vm-instance/" + - from: "@cozystack/packages/library/cozy-lib/**" + to: "@artifact/vm-instance/charts/cozy-lib/" + +--- +apiVersion: source.extensions.fluxcd.io/v1beta1 +kind: ArtifactGenerator +metadata: + name: extra + namespace: cozy-public +spec: + sources: + - alias: cozystack + kind: GitRepository + name: cozystack + namespace: cozy-system + artifacts: + - name: extra-etcd + copy: + - from: "@cozystack/packages/extra/etcd/**" + to: "@artifact/extra/" + - from: "@cozystack/packages/library/cozy-lib/**" + to: "@artifact/extra/charts/cozy-lib/" + - name: extra-seaweedfs + copy: + - from: "@cozystack/packages/extra/seaweedfs/**" + to: "@artifact/seaweedfs/" + - from: "@cozystack/packages/library/cozy-lib/**" + to: "@artifact/seaweedfs/charts/cozy-lib/" + diff --git a/packages/core/platform/templates/helmrepos.yaml b/packages/core/platform/templates/helmrepos.yaml index 69f77534..f65c8471 100644 --- a/packages/core/platform/templates/helmrepos.yaml +++ b/packages/core/platform/templates/helmrepos.yaml @@ -32,3 +32,100 @@ metadata: spec: interval: 5m0s url: http://cozystack.cozy-system.svc/repos/extra + + +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: GitRepository +metadata: + name: cozystack + namespace: cozy-system +spec: + interval: 1m0s + ref: + tag: v0.37.6 + timeout: 60s + url: https://github.com/cozystack/cozystack.git + ignore: | + # exclude all + /* + # include packages dir + !/packages + +--- +# ArtifactGenerator with explicit copy operations (no symlinks needed) +apiVersion: source.extensions.fluxcd.io/v1beta1 +kind: ArtifactGenerator +metadata: + name: system + namespace: cozy-system +spec: + sources: + - alias: cozystack + kind: GitRepository + name: cozystack + namespace: cozy-system + artifacts: + - name: system-cilium + copy: + - from: "@cozystack/packages/system/cilium/**" + to: "@artifact/cilium/" + - name: system-kubeovn + copy: + - from: "@cozystack/packages/system/kubeovn/**" + to: "@artifact/kubeovn/" + +--- +# ArtifactGenerator with explicit copy operations (no symlinks needed) +apiVersion: source.extensions.fluxcd.io/v1beta1 +kind: ArtifactGenerator +metadata: + name: apps + namespace: cozy-public +spec: + sources: + - alias: cozystack + kind: GitRepository + name: cozystack + namespace: cozy-system + artifacts: + - name: apps-virtual-machine + copy: + - from: "@cozystack/packages/apps/virtual-machine/**" + to: "@artifact/virtual-machine/" + - from: "@cozystack/packages/library/cozy-lib/**" + to: "@artifact/virtual-machine/charts/cozy-lib/" + - name: apps-vm-instance + copy: + - from: "@cozystack/packages/apps/vm-instance/**" + to: "@artifact/vm-instance/" + - from: "@cozystack/packages/library/cozy-lib/**" + to: "@artifact/vm-instance/charts/cozy-lib/" + +--- +# ArtifactGenerator with explicit copy operations (no symlinks needed) +apiVersion: source.extensions.fluxcd.io/v1beta1 +kind: ArtifactGenerator +metadata: + name: extra + namespace: cozy-public +spec: + sources: + - alias: cozystack + kind: GitRepository + name: cozystack + namespace: cozy-public + artifacts: + - name: extra-etcd + copy: + - from: "@cozystack/packages/extra/etcd/**" + to: "@artifact/extra/" + - from: "@cozystack/packages/library/cozy-lib/**" + to: "@artifact/extra/charts/cozy-lib/" + - name: extra-seaweedfs + copy: + - from: "@cozystack/packages/extra/seaweedfs/**" + to: "@artifact/seaweedfs/" + - from: "@cozystack/packages/library/cozy-lib/**" + to: "@artifact/seaweedfs/charts/cozy-lib/" + diff --git a/packages/extra/monitoring/templates/dashboards.yaml b/packages/extra/monitoring/templates/dashboards.yaml index 3facf66c..a4685428 100644 --- a/packages/extra/monitoring/templates/dashboards.yaml +++ b/packages/extra/monitoring/templates/dashboards.yaml @@ -11,6 +11,6 @@ spec: instanceSelector: matchLabels: dashboards: grafana - url: http://cozystack.cozy-system.svc/dashboards/{{ . }}.json + url: http://grafana-dashboards.cozy-grafana-operator.svc/{{ . }}.json {{- end }} {{- end }} diff --git a/packages/system/grafana-operator/Makefile b/packages/system/grafana-operator/Makefile index 82c734d4..b7cd9de2 100644 --- a/packages/system/grafana-operator/Makefile +++ b/packages/system/grafana-operator/Makefile @@ -1,6 +1,7 @@ export NAME=grafana-operator export NAMESPACE=cozy-grafana-operator +include ../../../scripts/common-envs.mk include ../../../scripts/package.mk update: @@ -8,3 +9,14 @@ update: mkdir -p charts curl -sSL https://github.com/grafana-operator/grafana-operator/archive/refs/heads/master.tar.gz | \ tar xzvf - --strip 3 -C charts grafana-operator-master/deploy/helm/grafana-operator + +image: + docker buildx build -f images/grafana-dashboards/Dockerfile ../../.. \ + --tag $(REGISTRY)/grafana-dashboards:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/grafana-dashboards:latest \ + --cache-to type=inline \ + --metadata-file images/grafana-dashboards.json \ + $(BUILDX_ARGS) + echo "$(REGISTRY)/grafana-dashboards:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/grafana-dashboards.json -o json -r)" \ + > images/grafana-dashboards.tag + rm -f images/grafana-dashboards.json diff --git a/packages/system/grafana-operator/images/grafana-dashboards.tag b/packages/system/grafana-operator/images/grafana-dashboards.tag new file mode 100644 index 00000000..c0277bfe --- /dev/null +++ b/packages/system/grafana-operator/images/grafana-dashboards.tag @@ -0,0 +1 @@ +ghcr.io/cozystack/cozystack/grafana-dashboards:v0.38.0-alpha.1@sha256:7e81580beb417ef8a54492b35b2b78cd51ed991f7dca65be6d771ca4ca1f1d61 diff --git a/packages/system/grafana-operator/images/grafana-dashboards/Dockerfile b/packages/system/grafana-operator/images/grafana-dashboards/Dockerfile new file mode 100644 index 00000000..619f09fa --- /dev/null +++ b/packages/system/grafana-operator/images/grafana-dashboards/Dockerfile @@ -0,0 +1,12 @@ +FROM alpine:3.22 + +RUN apk add --no-cache darkhttpd + +COPY dashboards /var/www/dashboards + +WORKDIR /var/www + +EXPOSE 8080 + +CMD ["darkhttpd", "/var/www/dashboards", "--port", "8080", "--addr", "0.0.0.0"] + diff --git a/packages/system/grafana-operator/images/grafana-dashboards/Dockerfile.dockerignore b/packages/system/grafana-operator/images/grafana-dashboards/Dockerfile.dockerignore new file mode 100644 index 00000000..fa588871 --- /dev/null +++ b/packages/system/grafana-operator/images/grafana-dashboards/Dockerfile.dockerignore @@ -0,0 +1,3 @@ +# Exclude everything except dashboards directory +* +!dashboards/** diff --git a/packages/system/grafana-operator/templates/dashboards-deployment.yaml b/packages/system/grafana-operator/templates/dashboards-deployment.yaml new file mode 100644 index 00000000..e1e81b45 --- /dev/null +++ b/packages/system/grafana-operator/templates/dashboards-deployment.yaml @@ -0,0 +1,42 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana-dashboards + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: grafana-dashboards + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: dashboards +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: grafana-dashboards + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: grafana-dashboards + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: dashboards + spec: + containers: + - name: dashboards + image: {{ $.Files.Get "images/grafana-dashboards.tag" | trim }} + ports: + - containerPort: 8080 + name: http + protocol: TCP + livenessProbe: + httpGet: + path: / + port: 8080 + initialDelaySeconds: 10 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 5 + diff --git a/packages/system/grafana-operator/templates/dashboards-service.yaml b/packages/system/grafana-operator/templates/dashboards-service.yaml new file mode 100644 index 00000000..e4b6859e --- /dev/null +++ b/packages/system/grafana-operator/templates/dashboards-service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + name: grafana-dashboards + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: grafana-dashboards + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: dashboards +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 8080 + protocol: TCP + name: http + selector: + app.kubernetes.io/name: grafana-dashboards + app.kubernetes.io/instance: {{ .Release.Name }} + From 2a87c83043efae81225e4e255cd10a7d8f72b99a Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 18 Nov 2025 19:56:27 +0100 Subject: [PATCH 02/46] Update Fluxcd 2.7.x, enable source-watcher Signed-off-by: Andrei Kvapil --- .../charts/flux-operator/Chart.yaml | 4 ++-- .../charts/flux-operator/README.md | 2 +- .../charts/flux-operator/templates/crds.yaml | 15 +++++++++++++++ .../flux-operator/templates/network-policy.yaml | 3 --- .../system/fluxcd/charts/flux-instance/Chart.yaml | 4 ++-- .../system/fluxcd/charts/flux-instance/README.md | 2 +- packages/system/fluxcd/values.yaml | 5 +++-- 7 files changed, 24 insertions(+), 11 deletions(-) rename packages/system/fluxcd-operator/{ => packages/system/fluxcd-operator}/charts/flux-operator/templates/network-policy.yaml (93%) diff --git a/packages/system/fluxcd-operator/charts/flux-operator/Chart.yaml b/packages/system/fluxcd-operator/charts/flux-operator/Chart.yaml index b95a2a04..d59dedfa 100644 --- a/packages/system/fluxcd-operator/charts/flux-operator/Chart.yaml +++ b/packages/system/fluxcd-operator/charts/flux-operator/Chart.yaml @@ -8,7 +8,7 @@ annotations: - name: Upstream Project url: https://github.com/controlplaneio-fluxcd/flux-operator apiVersion: v2 -appVersion: v0.30.0 +appVersion: v0.33.0 description: 'A Helm chart for deploying the Flux Operator. ' home: https://github.com/controlplaneio-fluxcd icon: https://raw.githubusercontent.com/cncf/artwork/main/projects/flux/icon/color/flux-icon-color.png @@ -25,4 +25,4 @@ sources: - https://github.com/controlplaneio-fluxcd/flux-operator - https://github.com/controlplaneio-fluxcd/charts type: application -version: 0.30.0 +version: 0.33.0 diff --git a/packages/system/fluxcd-operator/charts/flux-operator/README.md b/packages/system/fluxcd-operator/charts/flux-operator/README.md index 0367d113..036fc534 100644 --- a/packages/system/fluxcd-operator/charts/flux-operator/README.md +++ b/packages/system/fluxcd-operator/charts/flux-operator/README.md @@ -1,6 +1,6 @@ # flux-operator -![Version: 0.30.0](https://img.shields.io/badge/Version-0.30.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.30.0](https://img.shields.io/badge/AppVersion-v0.30.0-informational?style=flat-square) +![Version: 0.33.0](https://img.shields.io/badge/Version-0.33.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.33.0](https://img.shields.io/badge/AppVersion-v0.33.0-informational?style=flat-square) The [Flux Operator](https://github.com/controlplaneio-fluxcd/flux-operator) provides a declarative API for the installation and upgrade of CNCF [Flux](https://fluxcd.io) and the diff --git a/packages/system/fluxcd-operator/charts/flux-operator/templates/crds.yaml b/packages/system/fluxcd-operator/charts/flux-operator/templates/crds.yaml index 764382d2..fdd6fe76 100644 --- a/packages/system/fluxcd-operator/charts/flux-operator/templates/crds.yaml +++ b/packages/system/fluxcd-operator/charts/flux-operator/templates/crds.yaml @@ -203,6 +203,15 @@ spec: Registry address to pull the distribution images from e.g. 'ghcr.io/fluxcd'. type: string + variant: + description: |- + Variant specifies the Flux distribution flavor stored + in the registry. + enum: + - upstream-alpine + - enterprise-alpine + - enterprise-distroless + type: string version: description: Version semver expression e.g. '2.x', '2.3.x'. type: string @@ -583,6 +592,12 @@ spec: LastAttemptedRevision is the version and digest of the distribution config that was last attempted to reconcile. type: string + lastHandledForceAt: + description: |- + LastHandledForceAt holds the value of the most recent + force request value, so a change of the annotation value + can be detected. + type: string lastHandledReconcileAt: description: |- LastHandledReconcileAt holds the value of the most recent diff --git a/packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml b/packages/system/fluxcd-operator/packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml similarity index 93% rename from packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml rename to packages/system/fluxcd-operator/packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml index 0a9db1cc..5c7267ce 100644 --- a/packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml +++ b/packages/system/fluxcd-operator/packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml @@ -1,5 +1,4 @@ {{- if .Capabilities.APIVersions.Has "cilium.io/v2/CiliumClusterwideNetworkPolicy" }} ---- apiVersion: cilium.io/v2 kind: CiliumClusterwideNetworkPolicy metadata: @@ -17,5 +16,3 @@ spec: protocol: TCP ingress: - fromEntities: - - cluster -{{- end }} diff --git a/packages/system/fluxcd/charts/flux-instance/Chart.yaml b/packages/system/fluxcd/charts/flux-instance/Chart.yaml index 90dfadb5..448e6600 100644 --- a/packages/system/fluxcd/charts/flux-instance/Chart.yaml +++ b/packages/system/fluxcd/charts/flux-instance/Chart.yaml @@ -8,7 +8,7 @@ annotations: - name: Upstream Project url: https://github.com/controlplaneio-fluxcd/flux-operator apiVersion: v2 -appVersion: v0.30.0 +appVersion: v0.33.0 description: 'A Helm chart for deploying a Flux instance managed by Flux Operator. ' home: https://github.com/controlplaneio-fluxcd icon: https://raw.githubusercontent.com/cncf/artwork/main/projects/flux/icon/color/flux-icon-color.png @@ -25,4 +25,4 @@ sources: - https://github.com/controlplaneio-fluxcd/flux-operator - https://github.com/controlplaneio-fluxcd/charts type: application -version: 0.30.0 +version: 0.33.0 diff --git a/packages/system/fluxcd/charts/flux-instance/README.md b/packages/system/fluxcd/charts/flux-instance/README.md index a6611caf..e788edf1 100644 --- a/packages/system/fluxcd/charts/flux-instance/README.md +++ b/packages/system/fluxcd/charts/flux-instance/README.md @@ -1,6 +1,6 @@ # flux-instance -![Version: 0.30.0](https://img.shields.io/badge/Version-0.30.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.30.0](https://img.shields.io/badge/AppVersion-v0.30.0-informational?style=flat-square) +![Version: 0.33.0](https://img.shields.io/badge/Version-0.33.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.33.0](https://img.shields.io/badge/AppVersion-v0.33.0-informational?style=flat-square) This chart is a thin wrapper around the `FluxInstance` custom resource, which is used by the [Flux Operator](https://github.com/controlplaneio-fluxcd/flux-operator) diff --git a/packages/system/fluxcd/values.yaml b/packages/system/fluxcd/values.yaml index 837be8d8..b07fe06a 100644 --- a/packages/system/fluxcd/values.yaml +++ b/packages/system/fluxcd/values.yaml @@ -5,10 +5,11 @@ flux-instance: domain: cozy.local # -- default value is overriden in patches distribution: artifact: "" - version: 2.6.x + version: 2.7.x registry: ghcr.io/fluxcd components: - source-controller + - source-watcher - kustomize-controller - helm-controller - notification-controller @@ -33,7 +34,7 @@ flux-instance: memory: 2048Mi - target: kind: Deployment - name: source-controller + name: (source-controller|source-watcher) patch: | - op: add path: /spec/template/spec/containers/0/args/- From 222b582b68659a65b465d795ea3354f665a9e8a4 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 18 Nov 2025 22:51:00 +0100 Subject: [PATCH 03/46] Introduce cozystack-operator Signed-off-by: Andrei Kvapil --- cmd/cozystack-operator/main.go | 739 ++++++++++++++++++ go.mod | 131 ++-- go.sum | 265 ++++--- hack/e2e-install-cozystack.bats | 2 +- internal/operator/reconciler.go | 593 ++++++++++++++ .../installer/images/cozystack/Dockerfile | 31 +- .../core/installer/templates/cozystack.yaml | 24 +- packages/core/installer/values.yaml | 2 +- packages/core/platform/Makefile | 1 - packages/core/platform/templates/apps.yaml | 64 -- .../core/platform/templates/artifacts.yaml | 92 --- .../platform/templates/bundles-configmap.yaml | 17 + .../core/platform/templates/helmreleases.yaml | 97 --- .../core/platform/templates/helmrepos.yaml | 131 ---- .../core/platform/templates/namespaces.yaml | 40 - .../fluxcd-operator/templates/_helpers.tpl | 4 +- pkg/config/apiserver.go | 57 ++ pkg/config/config.go | 165 +++- scripts/installer.sh | 100 --- scripts/migrations/21 | 17 + 20 files changed, 1794 insertions(+), 778 deletions(-) create mode 100644 cmd/cozystack-operator/main.go create mode 100644 internal/operator/reconciler.go delete mode 100644 packages/core/platform/templates/apps.yaml delete mode 100644 packages/core/platform/templates/artifacts.yaml create mode 100644 packages/core/platform/templates/bundles-configmap.yaml delete mode 100644 packages/core/platform/templates/helmreleases.yaml delete mode 100644 packages/core/platform/templates/helmrepos.yaml delete mode 100644 packages/core/platform/templates/namespaces.yaml create mode 100644 pkg/config/apiserver.go delete mode 100755 scripts/installer.sh create mode 100755 scripts/migrations/21 diff --git a/cmd/cozystack-operator/main.go b/cmd/cozystack-operator/main.go new file mode 100644 index 00000000..28e011b3 --- /dev/null +++ b/cmd/cozystack-operator/main.go @@ -0,0 +1,739 @@ +/* +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" + "flag" + "fmt" + "os" + "os/exec" + "path/filepath" + "sort" + "strconv" + "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" + + helmv2 "github.com/fluxcd/helm-controller/api/v2" + sourcev1 "github.com/fluxcd/source-controller/api/v1" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + 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" + "k8s.io/apimachinery/pkg/types" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/wait" + 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/zap" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "sigs.k8s.io/controller-runtime/pkg/webhook" + + "github.com/cozystack/cozystack/internal/operator" + // +kubebuilder:scaffold:imports +) + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(apiextensionsv1.AddToScheme(scheme)) + utilruntime.Must(helmv2.AddToScheme(scheme)) + utilruntime.Must(sourcev1.AddToScheme(scheme)) + // +kubebuilder:scaffold:scheme +} + +func main() { + var metricsAddr string + var enableLeaderElection bool + var probeAddr string + var secureMetrics bool + var enableHTTP2 bool + + 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") + + opts := zap.Options{ + Development: true, + } + opts.BindFlags(flag.CommandLine) + flag.Parse() + + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + + config := ctrl.GetConfigOrDie() + + // Phase 1: Install fluxcd-operator and fluxcd, wait for CRDs + // This allows controller manager to start (it needs CRDs to be registered) + // Use a direct (non-cached) client for bootstrap since manager cache is not started yet + bootstrapClient, err := client.New(config, client.Options{Scheme: scheme}) + if err != nil { + setupLog.Error(err, "failed to create bootstrap client") + os.Exit(1) + } + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute) + defer cancel() + + setupLog.Info("Starting bootstrap phase 1: fluxcd installation") + if err := runBootstrapPhase1(ctx, bootstrapClient); err != nil { + setupLog.Error(err, "bootstrap phase 1 failed") + os.Exit(1) + } + + // Now that CRDs are available, we can start the controller manager + // The controller manager needs CRDs to be registered in the scheme + setupLog.Info("Starting controller manager (CRDs are now available)") + 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) + } + + // Setup PlatformReconciler + if err = (&operator.PlatformReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).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) + } + + // Phase 2: Install basic charts and other components after controller manager is ready + // Start manager in a goroutine so we can proceed with phase 2 + mgrCtx := ctrl.SetupSignalHandler() + mgrStarted := make(chan struct{}) + go func() { + // Wait a bit for manager to initialize + time.Sleep(2 * time.Second) + close(mgrStarted) + setupLog.Info("starting manager") + if err := mgr.Start(mgrCtx); err != nil { + setupLog.Error(err, "problem running manager") + os.Exit(1) + } + }() + + // Wait for manager to initialize before starting phase 2 + <-mgrStarted + + setupLog.Info("Starting bootstrap phase 2: basic charts installation") + phase2Ctx, phase2Cancel := context.WithTimeout(context.Background(), 30*time.Minute) + defer phase2Cancel() + + if err := runBootstrapPhase2(phase2Ctx, bootstrapClient); err != nil { + setupLog.Error(err, "bootstrap phase 2 failed") + os.Exit(1) + } + + setupLog.Info("Bootstrap completed, controller manager is running") + // Wait for manager (this blocks until context is cancelled) + <-mgrCtx.Done() +} + +// runBootstrapPhase1 installs fluxcd-operator and fluxcd, waits for CRDs +// This must complete before controller manager can start (manager needs CRDs registered) +// Basic charts (cilium, kubeovn) are NOT installed here - they are installed in phase 2 after manager starts +func runBootstrapPhase1(ctx context.Context, c client.Client) error { + // Create cozy-system and cozy-public namespaces first (needed for ConfigMap and HelmRepositories) + if err := ensureBootstrapNamespace(ctx, c, "cozy-system", true); err != nil { + return fmt.Errorf("failed to create cozy-system namespace: %w", err) + } + if err := ensureBootstrapNamespace(ctx, c, "cozy-public", false); err != nil { + return fmt.Errorf("failed to create cozy-public namespace: %w", err) + } + + // Get bundle name + bundle, err := getBundle(ctx, c) + if err != nil { + return err + } + setupLog.Info("Bundle detected", "bundle", bundle) + + // Calculate and run migrations + version, err := calculateVersion() + if err != nil { + return err + } + setupLog.Info("Target version", "version", version) + + if err := runMigrations(ctx, c, version); err != nil { + return err + } + + // Create cozy-fluxcd namespace (needed for fluxcd-operator and fluxcd) + if err := ensureBootstrapNamespace(ctx, c, "cozy-fluxcd", true); err != nil { + return fmt.Errorf("failed to create cozy-fluxcd namespace: %w", err) + } + + // Ensure fluxcd-operator and fluxcd are installed + // This installs/resumes helmreleases and waits for CRDs to be registered + // After CRDs are available, controller manager can start + if err := ensureFluxCD(ctx, c); err != nil { + return err + } + + setupLog.Info("Bootstrap phase 1 completed: fluxcd installed, CRDs available") + return nil +} + +// runBootstrapPhase2 installs basic charts and performs post-fluxcd operations +// This runs after controller manager has started (CRDs are available for manager) +func runBootstrapPhase2(ctx context.Context, c client.Client) error { + setupLog.Info("Starting bootstrap phase 2: basic charts installation") + + // Get bundle name + bundle, err := getBundle(ctx, c) + if err != nil { + return err + } + setupLog.Info("Bundle detected", "bundle", bundle) + + // Install basic charts (cilium, kubeovn) + // These are installed after controller manager has started + // The controller manager can now handle HelmReleases from these charts + setupLog.Info("Installing basic charts (controller manager is running)") + if err := installBasicCharts(ctx, c, bundle); err != nil { + return err + } + + // Unsuspend and update charts + if err := unsuspendCozystackCharts(ctx, c); err != nil { + return err + } + if err := updateCozystackCharts(ctx, c); err != nil { + return err + } + + setupLog.Info("Bootstrap phase 2 completed") + return nil +} + +// ensureBootstrapNamespace creates or updates a namespace for bootstrap operations +func ensureBootstrapNamespace(ctx context.Context, c client.Client, name string, privileged bool) error { + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Labels: map[string]string{ + "cozystack.io/system": "true", + }, + Annotations: map[string]string{ + "helm.sh/resource-policy": "keep", + }, + }, + } + + if privileged { + namespace.Labels["pod-security.kubernetes.io/enforce"] = "privileged" + } + + existingNs := &corev1.Namespace{} + err := c.Get(ctx, types.NamespacedName{Name: name}, existingNs) + if apierrors.IsNotFound(err) { + setupLog.Info("Creating namespace for bootstrap", "name", name, "privileged", privileged) + if err := c.Create(ctx, namespace); err != nil { + return fmt.Errorf("failed to create namespace %s: %w", name, err) + } + } else if err != nil { + return fmt.Errorf("failed to get namespace %s: %w", name, err) + } else { + // Update labels and annotations if needed + needsUpdate := false + if existingNs.Labels == nil { + existingNs.Labels = make(map[string]string) + needsUpdate = true + } + for k, v := range namespace.Labels { + if existingNs.Labels[k] != v { + existingNs.Labels[k] = v + needsUpdate = true + } + } + if existingNs.Annotations == nil { + existingNs.Annotations = make(map[string]string) + needsUpdate = true + } + for k, v := range namespace.Annotations { + if existingNs.Annotations[k] != v { + existingNs.Annotations[k] = v + needsUpdate = true + } + } + if needsUpdate { + setupLog.Info("Updating namespace for bootstrap", "name", name) + if err := c.Update(ctx, existingNs); err != nil { + return fmt.Errorf("failed to update namespace %s: %w", name, err) + } + } + } + + return nil +} + +// Bootstrap helper functions (moved from installer logic) + +func getBundle(ctx context.Context, c client.Client) (string, error) { + cm := &corev1.ConfigMap{} + key := types.NamespacedName{Namespace: "cozy-system", Name: "cozystack"} + if err := c.Get(ctx, key, cm); err != nil { + return "", err + } + bundle, ok := cm.Data["bundle-name"] + if !ok { + return "", fmt.Errorf("bundle-name not found in cozystack configmap") + } + return bundle, nil +} + +func calculateVersion() (int, error) { + migrationsDir := "scripts/migrations" + entries, err := os.ReadDir(migrationsDir) + if err != nil { + return 0, fmt.Errorf("failed to read migrations directory: %w", err) + } + + var versions []int + for _, entry := range entries { + if entry.IsDir() { + continue + } + version, err := strconv.Atoi(entry.Name()) + if err != nil { + continue + } + versions = append(versions, version) + } + + if len(versions) == 0 { + return 1, nil + } + + sort.Ints(versions) + return versions[len(versions)-1] + 1, nil +} + +func runMigrations(ctx context.Context, c client.Client, targetVersion int) error { + cm := &corev1.ConfigMap{} + key := types.NamespacedName{Namespace: "cozy-system", Name: "cozystack-version"} + var currentVersion int + + err := c.Get(ctx, key, cm) + if err != nil { + if apierrors.IsNotFound(err) { + setupLog.Info("cozystack-version configmap does not exist, creating with version 0") + currentVersion = 0 + } else { + return err + } + } else { + versionStr, ok := cm.Data["version"] + if !ok { + currentVersion = 0 + } else { + currentVersion, err = strconv.Atoi(versionStr) + if err != nil { + setupLog.Info("Invalid version in configmap, starting from 0", "version", versionStr) + currentVersion = 0 + } + } + } + + for currentVersion < targetVersion { + nextVersion := currentVersion + 1 + setupLog.Info("Running migration", "from", currentVersion, "to", targetVersion) + + migrationPath := filepath.Join("scripts", "migrations", strconv.Itoa(currentVersion)) + if _, err := os.Stat(migrationPath); os.IsNotExist(err) { + setupLog.Info("Migration script does not exist, skipping", "path", migrationPath) + currentVersion = nextVersion + continue + } + + // Make script executable + if err := os.Chmod(migrationPath, 0755); err != nil { + return fmt.Errorf("failed to make migration script executable: %w", err) + } + + // Run migration script + cmd := exec.CommandContext(ctx, migrationPath) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return fmt.Errorf("migration %d failed: %w", currentVersion, err) + } + + // Update version in configmap + newCM := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cozystack-version", + Namespace: "cozy-system", + }, + Data: map[string]string{ + "version": strconv.Itoa(nextVersion), + }, + } + + // Try to update first + existingCM := &corev1.ConfigMap{} + err = c.Get(ctx, key, existingCM) + if err != nil { + if apierrors.IsNotFound(err) { + // Create if doesn't exist + if err := c.Create(ctx, newCM); err != nil { + return fmt.Errorf("failed to create version configmap: %w", err) + } + } else { + return fmt.Errorf("failed to get version configmap: %w", err) + } + } else { + // Update existing + newCM.ResourceVersion = existingCM.ResourceVersion + if err := c.Update(ctx, newCM); err != nil { + return fmt.Errorf("failed to update version configmap: %w", err) + } + } + + currentVersion = nextVersion + } + + return nil +} + +func ensureFluxCD(ctx context.Context, c client.Client) error { + fluxOK, err := fluxIsOK(ctx, c) + if err != nil { + return err + } + if fluxOK { + setupLog.Info("fluxcd is already ready, skipping installation") + // Still need to ensure CRDs are available for controller manager + // Check if CRDs exist + if err := waitForCRDs(ctx, c, "helmreleases.helm.toolkit.fluxcd.io", "helmrepositories.source.toolkit.fluxcd.io"); err != nil { + return err + } + return nil + } + setupLog.Info("fluxcd is not ready, proceeding with installation/resume") + + // Install fluxcd-operator + hr := &helmv2.HelmRelease{} + key := types.NamespacedName{Namespace: "cozy-fluxcd", Name: "fluxcd-operator"} + err = c.Get(ctx, key, hr) + if err == nil { + // HelmRelease exists, apply and resume it + // This matches installer.sh: make -C packages/system/fluxcd-operator apply resume + setupLog.Info("Applying and resuming fluxcd-operator helmrelease") + cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd-operator", "apply", "resume") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to apply and resume fluxcd-operator: %w", err) + } + } else if apierrors.IsNotFound(err) { + // HelmRelease doesn't exist, need to create it + // This matches installer.sh: make -C packages/system/fluxcd-operator apply-locally + setupLog.Info("Creating fluxcd-operator using make (TODO: use helm-controller API)") + cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd-operator", "apply-locally") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to install fluxcd-operator: %w", err) + } + } else { + return fmt.Errorf("failed to check fluxcd-operator: %w", err) + } + + // Wait for CRD + if err := waitForCRDs(ctx, c, "fluxinstances.fluxcd.controlplane.io"); err != nil { + return err + } + + // Install fluxcd + hr = &helmv2.HelmRelease{} + key = types.NamespacedName{Namespace: "cozy-fluxcd", Name: "fluxcd"} + err = c.Get(ctx, key, hr) + if err == nil { + // HelmRelease exists, apply and resume it + // This matches installer.sh: make -C packages/system/fluxcd apply resume + setupLog.Info("Applying and resuming fluxcd helmrelease") + cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd", "apply", "resume") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to apply and resume fluxcd: %w", err) + } + } else if apierrors.IsNotFound(err) { + // HelmRelease doesn't exist, need to create it + // This matches installer.sh: make -C packages/system/fluxcd apply-locally + setupLog.Info("Creating fluxcd using make (TODO: use helm-controller API)") + cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd", "apply-locally") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to install fluxcd: %w", err) + } + } else { + return fmt.Errorf("failed to check fluxcd: %w", err) + } + + // Wait for CRDs + // CRDs must be available before controller manager can start + // Controller manager needs CRDs to be registered in the scheme + if err := waitForCRDs(ctx, c, "helmreleases.helm.toolkit.fluxcd.io", "helmrepositories.source.toolkit.fluxcd.io"); err != nil { + return err + } + + // Note: We don't wait for fluxcd to be fully ready (source-controller, helm-controller deployments) + // We only wait for CRDs to be registered, then controller manager can start + // Basic charts will be installed in phase 2 after controller manager has started + + return nil +} + +func fluxIsOK(ctx context.Context, c client.Client) (bool, error) { + // Check source-controller deployment + sourceDeploy := &appsv1.Deployment{} + key := types.NamespacedName{Namespace: "cozy-fluxcd", Name: "source-controller"} + if err := c.Get(ctx, key, sourceDeploy); err != nil { + setupLog.Info("fluxcd check: source-controller deployment not found") + return false, nil + } + if !isDeploymentAvailable(sourceDeploy) { + setupLog.Info("fluxcd check: source-controller deployment not available") + return false, nil + } + + // Check helm-controller deployment + helmDeploy := &appsv1.Deployment{} + key = types.NamespacedName{Namespace: "cozy-fluxcd", Name: "helm-controller"} + if err := c.Get(ctx, key, helmDeploy); err != nil { + setupLog.Info("fluxcd check: helm-controller deployment not found") + return false, nil + } + if !isDeploymentAvailable(helmDeploy) { + setupLog.Info("fluxcd check: helm-controller deployment not available") + return false, nil + } + + // Check fluxcd helmrelease is ready + // This matches installer.sh: kubectl wait --for=condition=ready -n cozy-fluxcd helmrelease/fluxcd --timeout=1s + hr := &helmv2.HelmRelease{} + key = types.NamespacedName{Namespace: "cozy-fluxcd", Name: "fluxcd"} + if err := c.Get(ctx, key, hr); err != nil { + setupLog.Info("fluxcd check: fluxcd helmrelease not found") + return false, nil + } + + // Check if ready (this implicitly checks suspend, as suspended HelmRelease cannot be Ready) + if hr.Status.Conditions != nil { + for _, cond := range hr.Status.Conditions { + if cond.Type == "Ready" && cond.Status == metav1.ConditionTrue { + setupLog.Info("fluxcd check: fluxcd is ready") + return true, nil + } + } + } + + setupLog.Info("fluxcd check: fluxcd helmrelease not ready") + return false, nil +} + +func isDeploymentAvailable(deploy *appsv1.Deployment) bool { + for _, cond := range deploy.Status.Conditions { + if cond.Type == appsv1.DeploymentAvailable && cond.Status == corev1.ConditionTrue { + return true + } + } + return false +} + +func waitForCRDs(ctx context.Context, c client.Client, crdNames ...string) error { + for _, crdName := range crdNames { + setupLog.Info("Waiting for CRD", "crd", crdName) + + err := wait.PollUntilContextTimeout(ctx, 1*time.Second, 60*time.Second, true, func(ctx context.Context) (bool, error) { + crd := &apiextensionsv1.CustomResourceDefinition{} + key := types.NamespacedName{Name: crdName} + if err := c.Get(ctx, key, crd); err != nil { + if apierrors.IsNotFound(err) { + // CRD not found yet, continue waiting + return false, nil + } + // Other error, return it + return false, err + } + // CRD found + setupLog.Info("CRD found", "crd", crdName) + return true, nil + }) + + if err != nil { + return fmt.Errorf("timeout waiting for CRD %s: %w", crdName, err) + } + } + return nil +} + +func resumeHelmRelease(ctx context.Context, c client.Client, hr *helmv2.HelmRelease) error { + if !hr.Spec.Suspend { + return nil + } + + patch := client.MergeFrom(hr.DeepCopy()) + hr.Spec.Suspend = false + + if err := c.Patch(ctx, hr, patch); err != nil { + return fmt.Errorf("failed to patch HelmRelease: %w", err) + } + + return nil +} + +func installBasicCharts(ctx context.Context, c client.Client, bundle string) error { + if bundle == "paas-full" || bundle == "distro-full" { + // Install cilium + // TODO: Create HelmRelease for cilium using helm-controller API + setupLog.Info("Installing cilium using make (TODO: use helm-controller API)") + cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/cilium", "apply", "resume") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to install cilium: %w", err) + } + } + + if bundle == "paas-full" { + // Install kubeovn + // TODO: Create HelmRelease for kubeovn using helm-controller API + setupLog.Info("Installing kubeovn using make (TODO: use helm-controller API)") + cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/kubeovn", "apply", "resume") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to install kubeovn: %w", err) + } + } + + return nil +} + +func unsuspendCozystackCharts(ctx context.Context, c client.Client) error { + hrList := &helmv2.HelmReleaseList{} + if err := c.List(ctx, hrList); err != nil { + return fmt.Errorf("failed to list HelmReleases: %w", err) + } + + for _, hr := range hrList.Items { + if !hr.Spec.Suspend { + continue + } + + // Check if it's from a Cozystack managed repository + if hr.Spec.Chart == nil || hr.Spec.Chart.Spec.SourceRef.Name == "" { + continue + } + + sourceRef := hr.Spec.Chart.Spec.SourceRef + repoKey := fmt.Sprintf("%s/%s", sourceRef.Namespace, sourceRef.Name) + + switch repoKey { + case "cozy-system/cozystack-system", "cozy-public/cozystack-extra", "cozy-public/cozystack-apps": + setupLog.Info("Unsuspending HelmRelease", "namespace", hr.Namespace, "name", hr.Name) + if err := resumeHelmRelease(ctx, c, &hr); err != nil { + setupLog.Error(err, "Failed to unsuspend HelmRelease", "namespace", hr.Namespace, "name", hr.Name) + continue + } + } + } + + return nil +} + +func updateCozystackCharts(ctx context.Context, c client.Client) error { + hrList := &helmv2.HelmReleaseList{} + if err := c.List(ctx, hrList, client.MatchingLabels{"cozystack.io/ui": "true"}); err != nil { + return fmt.Errorf("failed to list HelmReleases: %w", err) + } + + for _, hr := range hrList.Items { + if hr.Spec.Chart == nil { + continue + } + + // Update version to >= 0.0.0-0 + patch := client.MergeFrom(hr.DeepCopy()) + hr.Spec.Chart.Spec.Version = ">= 0.0.0-0" + + setupLog.Info("Updating HelmRelease to latest version", "namespace", hr.Namespace, "name", hr.Name) + if err := c.Patch(ctx, &hr, patch); err != nil { + setupLog.Error(err, "Failed to update HelmRelease", "namespace", hr.Namespace, "name", hr.Name) + continue + } + } + + return nil +} diff --git a/go.mod b/go.mod index 041aa96a..e3eca735 100644 --- a/go.mod +++ b/go.mod @@ -2,30 +2,36 @@ module github.com/cozystack/cozystack -go 1.23.0 +go 1.25.0 require ( github.com/fluxcd/helm-controller/api v1.1.0 + github.com/fluxcd/source-controller/api v1.4.1 + 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/onsi/ginkgo/v2 v2.19.0 - github.com/onsi/gomega v1.33.1 - github.com/spf13/cobra v1.8.1 - github.com/stretchr/testify v1.9.0 + github.com/onsi/ginkgo/v2 v2.22.0 + github.com/onsi/gomega v1.36.1 + github.com/prometheus/client_golang v1.22.0 + github.com/spf13/cobra v1.9.1 + github.com/stretchr/testify v1.10.0 + go.uber.org/zap v1.27.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/apimachinery v0.31.2 + k8s.io/apimachinery v0.34.1 k8s.io/apiserver v0.31.2 - k8s.io/client-go v0.31.2 - k8s.io/component-base v0.31.2 + k8s.io/client-go v0.34.1 + k8s.io/component-base v0.34.1 k8s.io/klog/v2 v2.130.1 - k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 - k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 - sigs.k8s.io/controller-runtime v0.19.0 + k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b + k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 + sigs.k8s.io/controller-runtime v0.19.7 sigs.k8s.io/structured-merge-diff/v4 v4.4.1 ) require ( + cel.dev/expr v0.24.0 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect @@ -36,86 +42,87 @@ require ( github.com/coreos/go-semver v0.3.1 // 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/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/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/fluxcd/pkg/apis/acl v0.9.0 // indirect github.com/fluxcd/pkg/apis/kustomize v1.6.1 // indirect - github.com/fluxcd/pkg/apis/meta v1.6.1 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/fluxcd/pkg/apis/meta v1.22.0 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // 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/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // 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/google/cel-go v0.21.0 // indirect - github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.6.0 // indirect - github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect + github.com/google/cel-go v0.26.0 // indirect + github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // 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/grpc-gateway/v2 v2.20.0 // indirect - github.com/imdario/mergo v0.3.6 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/moby/spdystream v0.4.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/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/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/pkg/errors v0.9.1 // 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/common v0.55.0 // indirect + github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/pflag v1.0.6 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect github.com/x448/float16 v0.8.4 // indirect - go.etcd.io/etcd/api/v3 v3.5.16 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.16 // indirect - go.etcd.io/etcd/client/v3 v3.5.16 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect - go.opentelemetry.io/otel v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect - go.opentelemetry.io/otel/metric v1.28.0 // indirect - go.opentelemetry.io/otel/sdk v1.28.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect - go.opentelemetry.io/proto/otlp v1.3.1 // indirect + go.etcd.io/etcd/api/v3 v3.6.4 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect + go.etcd.io/etcd/client/v3 v3.6.4 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect + go.opentelemetry.io/otel v1.35.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 // indirect + go.opentelemetry.io/otel/metric v1.35.0 // indirect + go.opentelemetry.io/otel/sdk v1.34.0 // 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/zap v1.27.0 // indirect - golang.org/x/crypto v0.31.0 // indirect + go.yaml.in/yaml/v2 v2.4.2 // 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/net v0.33.0 // indirect - golang.org/x/oauth2 v0.23.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/term v0.27.0 // indirect - golang.org/x/text v0.21.0 // indirect - golang.org/x/time v0.7.0 // indirect - golang.org/x/tools v0.26.0 // indirect + golang.org/x/net v0.45.0 // indirect + golang.org/x/oauth2 v0.27.0 // indirect + golang.org/x/sync v0.17.0 // indirect + golang.org/x/sys v0.36.0 // indirect + golang.org/x/term v0.35.0 // indirect + golang.org/x/text v0.29.0 // indirect + golang.org/x/time v0.9.0 // indirect + golang.org/x/tools v0.36.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/rpc v0.0.0-20240701130421-f6361c86f094 // indirect - google.golang.org/grpc v1.65.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect + google.golang.org/grpc v1.72.1 // indirect + google.golang.org/protobuf v1.36.5 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/kms v0.31.2 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 // indirect - sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect + k8s.io/kms v0.34.1 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect + sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // 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 ) diff --git a/go.sum b/go.sum index a1090f31..d7033ed9 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +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/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= @@ -18,7 +20,7 @@ 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-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= 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.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -26,27 +28,31 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 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/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.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= +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/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.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= +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/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fluxcd/helm-controller/api v1.1.0 h1:NS5Wm3U6Kv4w7Cw2sDOV++vf2ecGfFV00x1+2Y3QcOY= github.com/fluxcd/helm-controller/api v1.1.0/go.mod h1:BgHMgMY6CWynzl4KIbHpd6Wpn3FN9BqgkwmvoKCp6iE= +github.com/fluxcd/pkg/apis/acl v0.9.0 h1:wBpgsKT+jcyZEcM//OmZr9RiF8klL3ebrDp2u2ThsnA= +github.com/fluxcd/pkg/apis/acl v0.9.0/go.mod h1:TttNS+gocsGLwnvmgVi3/Yscwqrjc17+vhgYfqkfrV4= github.com/fluxcd/pkg/apis/kustomize v1.6.1 h1:22FJc69Mq4i8aCxnKPlddHhSMyI4UPkQkqiAdWFcqe0= github.com/fluxcd/pkg/apis/kustomize v1.6.1/go.mod h1:5dvQ4IZwz0hMGmuj8tTWGtarsuxW0rWsxJOwC6i+0V8= -github.com/fluxcd/pkg/apis/meta v1.6.1 h1:maLhcRJ3P/70ArLCY/LF/YovkxXbX+6sTWZwZQBeNq0= -github.com/fluxcd/pkg/apis/meta v1.6.1/go.mod h1:YndB/gxgGZmKfqpAfFxyCDNFJFP0ikpeJzs66jwq280= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/fluxcd/pkg/apis/meta v1.22.0 h1:EHWQH5ZWml7i8eZ/AMjm1jxid3j/PQ31p+hIwCt6crM= +github.com/fluxcd/pkg/apis/meta v1.22.0/go.mod h1:Kc1+bWe5p0doROzuV9XiTfV/oL3ddsemYXt8ZYWdVVg= +github.com/fluxcd/source-controller/api v1.4.1 h1:zV01D7xzHOXWbYXr36lXHWWYS7POARsjLt61Nbh3kVY= +github.com/fluxcd/source-controller/api v1.4.1/go.mod h1:gSjg57T+IG66SsBR0aquv+DFrm4YyBNpKIJVDnu3Ya8= +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.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +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/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= @@ -66,38 +72,34 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 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/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -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/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/cel-go v0.21.0 h1:cl6uW/gxN+Hy50tNYvI691+sXxioCnstFzLp2WO4GCI= -github.com/google/cel-go v0.21.0/go.mod h1:rHUlWCcBKgyEk+eV03RPdZUekPp6YcJwV0FxuUksYxc= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/cel-go v0.26.0 h1:DPGjXackMpJWH680oGY4lZhYjIameYmR+/6RBdDGmaI= +github.com/google/cel-go v0.26.0/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= +github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= +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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +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.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= 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-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= 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/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= +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 v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= 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/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -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/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= @@ -108,6 +110,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr 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/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +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.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -115,58 +119,63 @@ 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/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= -github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +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-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 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.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/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/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= -github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= -github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= +github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= +github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 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.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 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.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +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/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +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/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +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/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= 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/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 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/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.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.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.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 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/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= @@ -177,49 +186,57 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de 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.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= -go.etcd.io/etcd/api/v3 v3.5.16 h1:WvmyJVbjWqK4R1E+B12RRHz3bRGy9XVfh++MgbN+6n0= -go.etcd.io/etcd/api/v3 v3.5.16/go.mod h1:1P4SlIP/VwkDmGo3OlOD7faPeP8KDIFhqvciH5EfN28= -go.etcd.io/etcd/client/pkg/v3 v3.5.16 h1:ZgY48uH6UvB+/7R9Yf4x574uCO3jIx0TRDyetSfId3Q= -go.etcd.io/etcd/client/pkg/v3 v3.5.16/go.mod h1:V8acl8pcEK0Y2g19YlOV9m9ssUe6MgiDSobSoaBAM0E= +go.etcd.io/etcd/api/v3 v3.6.4 h1:7F6N7toCKcV72QmoUKa23yYLiiljMrT4xCeBL9BmXdo= +go.etcd.io/etcd/api/v3 v3.6.4/go.mod h1:eFhhvfR8Px1P6SEuLT600v+vrhdDTdcfMzmnxVXXSbk= +go.etcd.io/etcd/client/pkg/v3 v3.6.4 h1:9HBYrjppeOfFjBjaMTRxT3R7xT0GLK8EJMVC4xg6ok0= +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/v2 v2.305.13/go.mod h1:iQnL7fepbiomdXMb3om1rHq96htNNGv2sJkEcZGDRRg= -go.etcd.io/etcd/client/v3 v3.5.16 h1:sSmVYOAHeC9doqi0gv7v86oY/BTld0SEFGaxsU9eRhE= -go.etcd.io/etcd/client/v3 v3.5.16/go.mod h1:X+rExSGkyqxvu276cr2OwPLBaeqFu1cIl4vmRjAD/50= +go.etcd.io/etcd/client/v3 v3.6.4 h1:YOMrCfMhRzY8NgtzUsHl8hC2EBSnuqbR3dh84Uryl7A= +go.etcd.io/etcd/client/v3 v3.6.4/go.mod h1:jaNNHCyg2FdALyKWnd7hxZXZxZANb0+KGY+YQaEMISo= go.etcd.io/etcd/pkg/v3 v3.5.13 h1:st9bDWNsKkBNpP4PR1MvM/9NqUPfvYZx/YXegsYEH8M= go.etcd.io/etcd/pkg/v3 v3.5.13/go.mod h1:N+4PLrp7agI/Viy+dUYpX7iRtSPvKq+w8Y14d1vX+m0= go.etcd.io/etcd/raft/v3 v3.5.13 h1:7r/NKAOups1YnKcfro2RvGGo2PTuizF/xh26Z2CTAzA= go.etcd.io/etcd/raft/v3 v3.5.13/go.mod h1:uUFibGLn2Ksm2URMxN1fICGhk8Wu96EfDQyuLhAcAmw= go.etcd.io/etcd/server/v3 v3.5.13 h1:V6KG+yMfMSqWt+lGnhFpP5z5dRUj1BDRJ5k1fQ9DFok= go.etcd.io/etcd/server/v3 v3.5.13/go.mod h1:K/8nbsGupHqmr5MkgaZpLlH1QdX1pcNQLAkODy44XcQ= -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.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= -go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= -go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +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.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= +go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U= +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.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= +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/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= 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/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= 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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= +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/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -228,34 +245,34 @@ 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-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.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= -golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= +golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= +golang.org/x/oauth2 v0.27.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-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.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +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-20190412213103-97732733099d/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.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= +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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= -golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= +golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= +golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= 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-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.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= -golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= +golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -264,14 +281,14 @@ gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw 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 v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw= -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-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950= +google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 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/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -287,33 +304,37 @@ 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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 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.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= +k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM= +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.31.2/go.mod h1:i+Geh+nGCJEGiCGR3MlBDkS7koHIIKWVfWeRFiOsUcM= -k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= -k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4= +k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= k8s.io/apiserver v0.31.2 h1:VUzOEUGRCDi6kX1OyQ801m4A7AUPglpsmGvdsekmcI4= k8s.io/apiserver v0.31.2/go.mod h1:o3nKZR7lPlJqkU5I3Ove+Zx3JuoFjQobGX1Gctw6XuE= -k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc= -k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs= -k8s.io/component-base v0.31.2 h1:Z1J1LIaC0AV+nzcPRFqfK09af6bZ4D1nAOpWsy9owlA= -k8s.io/component-base v0.31.2/go.mod h1:9PeyyFN/drHjtJZMCTkSpQJS3U9OXORnHQqMLDz0sUQ= +k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY= +k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8= +k8s.io/component-base v0.34.1 h1:v7xFgG+ONhytZNFpIz5/kecwD+sUhVE6HU7qQUiRM4A= +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/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kms v0.31.2 h1:pyx7l2qVOkClzFMIWMVF/FxsSkgd+OIGH7DecpbscJI= -k8s.io/kms v0.31.2/go.mod h1:OZKwl1fan3n3N5FFxnW5C4V3ygrah/3YXeJWS3O6+94= -k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 h1:GKE9U8BH16uynoxQii0auTjmmmuZ3O0LFMN6S0lPPhI= -k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/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.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= -sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= -sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= +k8s.io/kms v0.34.1 h1:iCFOvewDPzWM9fMTfyIPO+4MeuZ0tcZbugxLNSHFG4w= +k8s.io/kms v0.34.1/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM= +k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA= +k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts= +k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y= +k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/controller-runtime v0.19.7 h1:DLABZfMr20A+AwCZOHhcbcu+TqBXnJZaVBri9K3EO48= +sigs.k8s.io/controller-runtime v0.19.7/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +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.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/hack/e2e-install-cozystack.bats b/hack/e2e-install-cozystack.bats index da132132..2ecb2312 100644 --- a/hack/e2e-install-cozystack.bats +++ b/hack/e2e-install-cozystack.bats @@ -24,7 +24,7 @@ kubectl apply -f _out/assets/cozystack-installer.yaml # 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 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' diff --git a/internal/operator/reconciler.go b/internal/operator/reconciler.go new file mode 100644 index 00000000..65fecf66 --- /dev/null +++ b/internal/operator/reconciler.go @@ -0,0 +1,593 @@ +/* +Copyright 2024 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" + + "gopkg.in/yaml.v3" + + helmv2 "github.com/fluxcd/helm-controller/api/v2" + sourcev1 "github.com/fluxcd/source-controller/api/v1" + corev1 "k8s.io/api/core/v1" + 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" + "k8s.io/apimachinery/pkg/types" + 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/config" +) + +const ( + cozystackConfigMapName = "cozystack" + systemBundleConfigMapName = "system-bundle" + cozystackConfigMapNamespace = "cozy-system" + platformOperatorLabel = "cozystack.io/platform-operator" +) + +// PlatformReconciler reconciles the platform configuration. +type PlatformReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +// +kubebuilder:rbac:groups=core,resources=configmaps,verbs=get;list;watch +// +kubebuilder:rbac:groups=core,resources=configmaps/status,verbs=get +// +kubebuilder:rbac:groups=core,resources=namespaces,verbs=get;list;watch;create;update;patch +// +kubebuilder:rbac:groups=helm.toolkit.fluxcd.io,resources=helmreleases,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=helmrepositories,verbs=get;list;watch;create;update;patch +// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=gitrepositories,verbs=get;list;watch;create;update;patch + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +func (r *PlatformReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + + // Reconcile on changes to cozystack ConfigMap or system-bundle ConfigMap + if req.Namespace != cozystackConfigMapNamespace { + return ctrl.Result{}, nil + } + + // Reconcile on changes to cozystack ConfigMap + // Also reconcile when system-bundle changes (it will read bundle-name from cozystack ConfigMap) + if req.Name != cozystackConfigMapName && req.Name != systemBundleConfigMapName { + return ctrl.Result{}, nil + } + + // If system-bundle changed, we still need to get the cozystack ConfigMap to read bundle-name + if req.Name == systemBundleConfigMapName { + logger.Info("system-bundle ConfigMap changed, reconciling platform") + // Continue to get cozystack ConfigMap to determine which bundle to use + req.Name = cozystackConfigMapName + } + + // Get the cozystack ConfigMap + configMap := &corev1.ConfigMap{} + if err := r.Get(ctx, req.NamespacedName, configMap); err != nil { + if apierrors.IsNotFound(err) { + logger.Info("cozystack ConfigMap not found") + return ctrl.Result{}, nil + } + return ctrl.Result{}, err + } + + // Parse ConfigMap data + cfg := config.ParseConfigMapData(configMap.Data) + if cfg.BundleName == "" { + logger.Info("bundle-name not set in cozystack ConfigMap") + return ctrl.Result{}, nil + } + + logger.Info("Reconciling platform", "bundle", cfg.BundleName) + + // Reconcile HelmRepository resources + if err := r.reconcileHelmRepositories(ctx, cfg); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to reconcile HelmRepositories: %w", err) + } + + // Reconcile namespaces + if err := r.reconcileNamespaces(ctx, cfg); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to reconcile namespaces: %w", err) + } + + // Reconcile HelmReleases (from bundle) + if err := r.reconcileHelmReleases(ctx, cfg); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to reconcile HelmReleases: %w", err) + } + + // Reconcile tenant-root + if err := r.reconcileTenantRoot(ctx, cfg); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to reconcile tenant-root: %w", err) + } + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *PlatformReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + Named("platform-operator"). + For(&corev1.ConfigMap{}). + Complete(r) +} + +func (r *PlatformReconciler) reconcileHelmRepositories(ctx context.Context, cfg *config.CozystackConfig) error { + logger := log.FromContext(ctx) + + repos := []struct { + name string + namespace string + url string + labels map[string]string + }{ + { + name: "cozystack-system", + namespace: "cozy-system", + url: "http://cozystack.cozy-system.svc/repos/system", + labels: map[string]string{ + "cozystack.io/repository": "system", + }, + }, + { + name: "cozystack-apps", + namespace: "cozy-public", + url: "http://cozystack.cozy-system.svc/repos/apps", + labels: map[string]string{ + "cozystack.io/ui": "true", + "cozystack.io/repository": "apps", + }, + }, + { + name: "cozystack-extra", + namespace: "cozy-public", + url: "http://cozystack.cozy-system.svc/repos/extra", + labels: map[string]string{ + "cozystack.io/repository": "extra", + }, + }, + } + + for _, repo := range repos { + hr := &sourcev1.HelmRepository{ + ObjectMeta: metav1.ObjectMeta{ + Name: repo.name, + Namespace: repo.namespace, + Labels: repo.labels, + }, + Spec: sourcev1.HelmRepositorySpec{ + URL: repo.url, + Interval: metav1.Duration{Duration: 5 * 60 * 1000000000}, // 5m + }, + } + + if err := r.CreateOrUpdate(ctx, hr); err != nil { + logger.Error(err, "failed to reconcile HelmRepository", "name", repo.name, "namespace", repo.namespace) + return err + } + logger.Info("reconciled HelmRepository", "name", repo.name, "namespace", repo.namespace) + } + + return nil +} + +func (r *PlatformReconciler) reconcileNamespaces(ctx context.Context, cfg *config.CozystackConfig) error { + logger := log.FromContext(ctx) + + // Load bundle to determine namespaces + bundle, err := loadBundle(ctx, r.Client, cfg.BundleName) + if err != nil { + logger.Error(err, "failed to load bundle, using default namespaces", "bundle", cfg.BundleName) + // Fallback to default namespaces if bundle loading fails + bundle = nil + } + + // Collect namespaces from bundle releases + namespacesMap := make(map[string]bool) + + if bundle != nil { + for _, release := range bundle.Releases { + // Check if release is disabled + if cfg.IsComponentDisabled(release.Name) { + continue + } + + // Check if optional release is enabled + if release.Optional && !cfg.IsComponentEnabled(release.Name) { + continue + } + + // If at least one release requires a privileged namespace, then it should be privileged + if release.Namespace != "" { + if release.Privileged { + namespacesMap[release.Namespace] = true + } else if _, exists := namespacesMap[release.Namespace]; !exists { + namespacesMap[release.Namespace] = false + } + } + } + } + + // Always add cozy-system (privileged) and cozy-public (non-privileged) + namespacesMap["cozy-system"] = true + namespacesMap["cozy-public"] = false + + // Create/update all namespaces + for nsName, privileged := range namespacesMap { + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: nsName, + Annotations: map[string]string{ + "helm.sh/resource-policy": "keep", + }, + Labels: map[string]string{ + "cozystack.io/system": "true", + }, + }, + } + + if privileged { + namespace.Labels["pod-security.kubernetes.io/enforce"] = "privileged" + } + + if err := r.CreateOrUpdate(ctx, namespace); err != nil { + logger.Error(err, "failed to reconcile Namespace", "name", nsName) + return err + } + logger.Info("reconciled Namespace", "name", nsName, "privileged", privileged) + } + + return nil +} + +func (r *PlatformReconciler) reconcileTenantRoot(ctx context.Context, cfg *config.CozystackConfig) error { + logger := log.FromContext(ctx) + + host := cfg.RootHost + if host == "" { + host = "example.org" + } + + // Reconcile tenant-root namespace + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tenant-root", + Annotations: map[string]string{ + "helm.sh/resource-policy": "keep", + "namespace.cozystack.io/etcd": "tenant-root", + "namespace.cozystack.io/monitoring": "tenant-root", + "namespace.cozystack.io/ingress": "tenant-root", + "namespace.cozystack.io/seaweedfs": "tenant-root", + "namespace.cozystack.io/host": host, + }, + }, + } + + if err := r.CreateOrUpdate(ctx, namespace); err != nil { + logger.Error(err, "failed to reconcile tenant-root Namespace") + return err + } + + // Reconcile tenant-root HelmRelease + hr := &helmv2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tenant-root", + Namespace: "tenant-root", + Labels: map[string]string{ + "cozystack.io/ui": "true", + }, + }, + Spec: helmv2.HelmReleaseSpec{ + Interval: metav1.Duration{Duration: 0}, // 0s + ReleaseName: "tenant-root", + Chart: &helmv2.HelmChartTemplate{ + Spec: helmv2.HelmChartTemplateSpec{ + Chart: "tenant", + Version: ">= 0.0.0-0", + SourceRef: helmv2.CrossNamespaceObjectReference{ + Kind: "HelmRepository", + Name: "cozystack-apps", + Namespace: "cozy-public", + }, + }, + }, + Values: &apiextensionsv1.JSON{ + Raw: []byte(fmt.Sprintf(`{"host":%q}`, host)), + }, + Install: &helmv2.Install{ + Remediation: &helmv2.InstallRemediation{ + Retries: -1, + }, + }, + Upgrade: &helmv2.Upgrade{ + Remediation: &helmv2.UpgradeRemediation{ + Retries: -1, + }, + }, + }, + } + + if err := r.CreateOrUpdate(ctx, hr); err != nil { + logger.Error(err, "failed to reconcile tenant-root HelmRelease") + return err + } + + logger.Info("reconciled tenant-root") + return nil +} + +func (r *PlatformReconciler) reconcileHelmReleases(ctx context.Context, cfg *config.CozystackConfig) error { + logger := log.FromContext(ctx) + + // Load bundle to determine desired HelmReleases + bundle, err := loadBundle(ctx, r.Client, cfg.BundleName) + if err != nil { + logger.Error(err, "failed to load bundle, skipping HelmReleases reconciliation", "bundle", cfg.BundleName) + return nil // Don't fail if bundle loading fails + } + + // Determine desired HelmReleases from bundle + desiredReleases := make(map[string]map[string]bool) // namespace -> name -> true + for _, release := range bundle.Releases { + // Check if release is disabled + if cfg.IsComponentDisabled(release.Name) { + continue + } + + // Check if optional release is enabled + if release.Optional && !cfg.IsComponentEnabled(release.Name) { + continue + } + + if release.Namespace == "" { + logger.Info("skipping release without namespace", "name", release.Name) + continue + } + + if desiredReleases[release.Namespace] == nil { + desiredReleases[release.Namespace] = make(map[string]bool) + } + desiredReleases[release.Namespace][release.Name] = true + + // Create or update HelmRelease + hr := &helmv2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: release.Name, + Namespace: release.Namespace, + Labels: map[string]string{ + platformOperatorLabel: "true", + }, + }, + Spec: helmv2.HelmReleaseSpec{ + Interval: metav1.Duration{Duration: 5 * 60 * 1000000000}, // 5m + ReleaseName: release.ReleaseName, + Chart: &helmv2.HelmChartTemplate{ + Spec: helmv2.HelmChartTemplateSpec{ + Chart: release.Chart, + Version: ">= 0.0.0-0", + SourceRef: helmv2.CrossNamespaceObjectReference{ + Kind: "HelmRepository", + Name: "cozystack-system", + Namespace: "cozy-system", + }, + }, + }, + Install: &helmv2.Install{ + Remediation: &helmv2.InstallRemediation{ + Retries: -1, + }, + }, + Upgrade: &helmv2.Upgrade{ + Remediation: &helmv2.UpgradeRemediation{ + Retries: -1, + }, + }, + }, + } + + // Set values if provided + if len(release.Values) > 0 { + valuesJSON, err := json.Marshal(release.Values) + if err != nil { + logger.Error(err, "failed to marshal values for release", "name", release.Name) + return fmt.Errorf("failed to marshal values for release %s: %w", release.Name, err) + } + hr.Spec.Values = &apiextensionsv1.JSON{ + Raw: valuesJSON, + } + } + + // Get component-specific values from config if available + if componentValues, ok := cfg.GetComponentValues(release.Name); ok { + // Merge with existing values if any + mergedValues := make(map[string]interface{}) + if len(release.Values) > 0 { + mergedValues = release.Values + } + // Parse component values (they might be YAML or JSON string) + var componentValuesMap map[string]interface{} + if err := yaml.Unmarshal([]byte(componentValues), &componentValuesMap); err != nil { + logger.Error(err, "failed to parse component values for release", "name", release.Name) + return fmt.Errorf("failed to parse component values for release %s: %w", release.Name, err) + } + // Merge maps (component values override bundle values) + for k, v := range componentValuesMap { + mergedValues[k] = v + } + // Marshal merged values + valuesJSON, err := json.Marshal(mergedValues) + if err != nil { + logger.Error(err, "failed to marshal merged values for release", "name", release.Name) + return fmt.Errorf("failed to marshal merged values for release %s: %w", release.Name, err) + } + hr.Spec.Values = &apiextensionsv1.JSON{ + Raw: valuesJSON, + } + } + + if err := r.CreateOrUpdate(ctx, hr); err != nil { + logger.Error(err, "failed to reconcile HelmRelease", "name", release.Name, "namespace", release.Namespace) + return err + } + logger.Info("reconciled HelmRelease", "name", release.Name, "namespace", release.Namespace) + } + + // Find all HelmReleases managed by this operator + hrList := &helmv2.HelmReleaseList{} + if err := r.List(ctx, hrList, client.MatchingLabels{ + platformOperatorLabel: "true", + }); err != nil { + return fmt.Errorf("failed to list HelmReleases: %w", err) + } + + // Delete HelmReleases that are no longer desired + for _, hr := range hrList.Items { + // Skip tenant-root as it's managed separately + if hr.Name == "tenant-root" && hr.Namespace == "tenant-root" { + continue + } + + // Check if this HelmRelease is still desired + if desiredNamespaces, ok := desiredReleases[hr.Namespace]; ok { + if desiredNamespaces[hr.Name] { + // Still desired, keep it + continue + } + } + + // Not desired anymore, delete it + if err := r.Delete(ctx, &hr); err != nil { + if apierrors.IsNotFound(err) { + // Already deleted, ignore + continue + } + logger.Error(err, "failed to delete HelmRelease", "name", hr.Name, "namespace", hr.Namespace) + // Continue with other deletions + } else { + logger.Info("deleted HelmRelease (no longer in bundle)", "name", hr.Name, "namespace", hr.Namespace) + } + } + + 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) + + return r.Update(ctx, obj) +} + +// Bundle represents the structure of a bundle YAML file. +type Bundle struct { + Releases []BundleRelease `yaml:"releases"` +} + +// BundleRelease represents a single release in a bundle. +type BundleRelease struct { + Name string `yaml:"name"` + ReleaseName string `yaml:"releaseName"` + Chart string `yaml:"chart"` + Namespace string `yaml:"namespace"` + Privileged bool `yaml:"privileged,omitempty"` + Optional bool `yaml:"optional,omitempty"` + DependsOn []string `yaml:"dependsOn,omitempty"` + Values map[string]interface{} `yaml:"values,omitempty"` + ValuesFiles []string `yaml:"valuesFiles,omitempty"` +} + +// loadBundle loads a bundle from the system-bundle ConfigMap in cozy-system namespace. +// The ConfigMap contains all bundles as data keys: {bundleName}.yaml +func loadBundle(ctx context.Context, c client.Client, bundleName string) (*Bundle, error) { + if bundleName == "" { + return nil, fmt.Errorf("bundle name is empty") + } + + // Get the system-bundle ConfigMap + configMap := &corev1.ConfigMap{} + key := types.NamespacedName{Namespace: "cozy-system", Name: "system-bundle"} + if err := c.Get(ctx, key, configMap); err != nil { + if apierrors.IsNotFound(err) { + return nil, fmt.Errorf("system-bundle ConfigMap not found in cozy-system namespace") + } + return nil, fmt.Errorf("failed to get system-bundle ConfigMap: %w", err) + } + + // Get the bundle data from ConfigMap + bundleKey := bundleName + ".yaml" + bundleData, ok := configMap.Data[bundleKey] + if !ok { + return nil, fmt.Errorf("bundle %s not found in system-bundle ConfigMap (available keys: %v)", bundleName, getMapKeys(configMap.Data)) + } + + var bundle Bundle + // Note: bundle files contain Helm template syntax ({{ }}), but after Helm rendering + // they should be valid YAML. If template syntax remains, it will be treated as strings + // which is fine for extracting namespace and privileged fields + if err := yaml.Unmarshal([]byte(bundleData), &bundle); err != nil { + return nil, fmt.Errorf("failed to parse bundle %s from ConfigMap: %w", bundleName, err) + } + + return &bundle, nil +} + +// getMapKeys returns a slice of keys from a map for error messages +func getMapKeys(m map[string]string) []string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + return keys +} diff --git a/packages/core/installer/images/cozystack/Dockerfile b/packages/core/installer/images/cozystack/Dockerfile index 0f98f492..454cd934 100644 --- a/packages/core/installer/images/cozystack/Dockerfile +++ b/packages/core/installer/images/cozystack/Dockerfile @@ -1,19 +1,4 @@ -FROM golang:1.24-alpine as k8s-await-election-builder - -ARG K8S_AWAIT_ELECTION_GITREPO=https://github.com/LINBIT/k8s-await-election -ARG K8S_AWAIT_ELECTION_VERSION=0.4.1 - -# TARGETARCH is a docker special variable: https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope -ARG TARGETARCH - -RUN apk add --no-cache git make -RUN git clone ${K8S_AWAIT_ELECTION_GITREPO} /usr/local/go/k8s-await-election/ \ - && cd /usr/local/go/k8s-await-election \ - && git reset --hard v${K8S_AWAIT_ELECTION_VERSION} \ - && make \ - && mv ./out/k8s-await-election-${TARGETARCH} /k8s-await-election - -FROM golang:1.24-alpine as builder +FROM golang:1.25-alpine as builder ARG TARGETOS ARG TARGETARCH @@ -21,23 +6,27 @@ ARG TARGETARCH RUN apk add --no-cache make git RUN apk add helm --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community -# Check Dockerfile.dockerignore! COPY . /src/ - WORKDIR /src RUN go mod download +# Build cozystack-operator +RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \ + -ldflags="-w -s" \ + -o /cozystack-operator \ + ./cmd/cozystack-operator + FROM alpine:3.22 RUN wget -O- https://github.com/cozystack/cozypkg/raw/refs/heads/main/hack/install.sh | sh -s -- -v 1.2.0 -RUN apk add --no-cache make kubectl helm coreutils git jq +RUN apk add --no-cache make kubectl helm coreutils git jq ca-certificates COPY --from=builder /src/scripts /cozystack/scripts COPY --from=builder /src/packages/core /cozystack/packages/core COPY --from=builder /src/packages/system /cozystack/packages/system -COPY --from=k8s-await-election-builder /k8s-await-election /usr/bin/k8s-await-election +COPY --from=builder /cozystack-operator /usr/bin/cozystack-operator WORKDIR /cozystack -ENTRYPOINT ["/usr/bin/k8s-await-election", "/cozystack/scripts/installer.sh" ] +ENTRYPOINT ["/usr/bin/cozystack-operator"] diff --git a/packages/core/installer/templates/cozystack.yaml b/packages/core/installer/templates/cozystack.yaml index 0f084b90..e98d2c8b 100644 --- a/packages/core/installer/templates/cozystack.yaml +++ b/packages/core/installer/templates/cozystack.yaml @@ -29,13 +29,13 @@ roleRef: apiVersion: apps/v1 kind: Deployment metadata: - name: cozystack + name: cozystack-operator namespace: cozy-system spec: replicas: 1 selector: matchLabels: - app: cozystack + app: cozystack-operator strategy: type: RollingUpdate rollingUpdate: @@ -44,30 +44,22 @@ spec: template: metadata: labels: - app: cozystack + app: cozystack-operator spec: hostNetwork: true serviceAccountName: cozystack containers: - - name: cozystack + - name: cozystack-operator image: "{{ .Values.cozystack.image }}" env: - name: KUBERNETES_SERVICE_HOST value: localhost - name: KUBERNETES_SERVICE_PORT value: "7445" - - name: K8S_AWAIT_ELECTION_ENABLED - value: "1" - - name: K8S_AWAIT_ELECTION_NAME - value: cozystack - - name: K8S_AWAIT_ELECTION_LOCK_NAME - value: cozystack - - name: K8S_AWAIT_ELECTION_LOCK_NAMESPACE - value: cozy-system - - name: K8S_AWAIT_ELECTION_IDENTITY - valueFrom: - fieldRef: - fieldPath: metadata.name + args: + - --leader-elect=true + - --metrics-bind-address=0 + - --health-probe-bind-address=:8082 tolerations: - key: "node.kubernetes.io/not-ready" operator: "Exists" diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index 498112b1..f5521623 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:v0.38.0-alpha.1@sha256:ba25a3e1c3008e0bcf5e50b6ac2cce371cec880a7f4fe4b8de1abf621bb3017f + image: ghcr.io/cozystack/cozystack/installer:latest@sha256:b1d74a1f72a1264ddae87acee2c5f214de3233c313637392c0b34d6e607db881 diff --git a/packages/core/platform/Makefile b/packages/core/platform/Makefile index ab0e17bf..d3695c8a 100644 --- a/packages/core/platform/Makefile +++ b/packages/core/platform/Makefile @@ -6,7 +6,6 @@ show: apply: cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f- - kubectl delete helmreleases.helm.toolkit.fluxcd.io -l cozystack.io/marked-for-deletion=true -A reconcile: apply diff --git a/packages/core/platform/templates/apps.yaml b/packages/core/platform/templates/apps.yaml deleted file mode 100644 index c7653e03..00000000 --- a/packages/core/platform/templates/apps.yaml +++ /dev/null @@ -1,64 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $bundleName := index $cozyConfig.data "bundle-name" }} -{{- $bundle := tpl (.Files.Get (printf "bundles/%s.yaml" $bundleName)) . | fromYaml }} -{{- $host := "example.org" }} -{{- $host := "example.org" }} -{{- if $cozyConfig.data }} - {{- if hasKey $cozyConfig.data "root-host" }} - {{- $host = index $cozyConfig.data "root-host" }} - {{- end }} -{{- end }} -{{- $tenantRoot := dict }} -{{- if .Capabilities.APIVersions.Has "helm.toolkit.fluxcd.io/v2" }} -{{- $tenantRoot = lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" "tenant-root" "tenant-root" }} -{{- end }} -{{- if and $tenantRoot $tenantRoot.spec $tenantRoot.spec.values $tenantRoot.spec.values.host }} -{{- $host = $tenantRoot.spec.values.host }} -{{- else }} -{{- end }} ---- -apiVersion: v1 -kind: Namespace -metadata: - annotations: - helm.sh/resource-policy: keep - namespace.cozystack.io/etcd: tenant-root - namespace.cozystack.io/monitoring: tenant-root - namespace.cozystack.io/ingress: tenant-root - namespace.cozystack.io/seaweedfs: tenant-root - namespace.cozystack.io/host: "{{ $host }}" - name: tenant-root ---- -apiVersion: helm.toolkit.fluxcd.io/v2 -kind: HelmRelease -metadata: - name: tenant-root - namespace: tenant-root - labels: - cozystack.io/ui: "true" -spec: - interval: 0s - releaseName: tenant-root - install: - remediation: - retries: -1 - upgrade: - remediation: - retries: -1 - chart: - spec: - chart: tenant - version: '>= 0.0.0-0' - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - values: - host: "{{ $host }}" - dependsOn: - {{- range $x := $bundle.releases }} - {{- if has $x.name (list "cilium" "kubeovn") }} - - name: {{ $x.name }} - namespace: {{ $x.namespace }} - {{- end }} - {{- end }} diff --git a/packages/core/platform/templates/artifacts.yaml b/packages/core/platform/templates/artifacts.yaml deleted file mode 100644 index 15105de8..00000000 --- a/packages/core/platform/templates/artifacts.yaml +++ /dev/null @@ -1,92 +0,0 @@ ---- -apiVersion: source.toolkit.fluxcd.io/v1 -kind: GitRepository -metadata: - name: cozystack - namespace: cozy-system -spec: - interval: 1m0s - ref: - tag: v0.37.6 - timeout: 60s - url: https://github.com/cozystack/cozystack.git - ignore: | - # exclude all - /* - # include packages dir - !/packages - ---- -apiVersion: source.extensions.fluxcd.io/v1beta1 -kind: ArtifactGenerator -metadata: - name: system - namespace: cozy-system -spec: - sources: - - alias: cozystack - kind: GitRepository - name: cozystack - namespace: cozy-system - artifacts: - - name: system-cilium - copy: - - from: "@cozystack/packages/system/cilium/**" - to: "@artifact/cilium/" - - name: system-kubeovn - copy: - - from: "@cozystack/packages/system/kubeovn/**" - to: "@artifact/kubeovn/" - ---- -apiVersion: source.extensions.fluxcd.io/v1beta1 -kind: ArtifactGenerator -metadata: - name: apps - namespace: cozy-public -spec: - sources: - - alias: cozystack - kind: GitRepository - name: cozystack - namespace: cozy-system - artifacts: - - name: apps-virtual-machine - copy: - - from: "@cozystack/packages/apps/virtual-machine/**" - to: "@artifact/virtual-machine/" - - from: "@cozystack/packages/library/cozy-lib/**" - to: "@artifact/virtual-machine/charts/cozy-lib/" - - name: apps-vm-instance - copy: - - from: "@cozystack/packages/apps/vm-instance/**" - to: "@artifact/vm-instance/" - - from: "@cozystack/packages/library/cozy-lib/**" - to: "@artifact/vm-instance/charts/cozy-lib/" - ---- -apiVersion: source.extensions.fluxcd.io/v1beta1 -kind: ArtifactGenerator -metadata: - name: extra - namespace: cozy-public -spec: - sources: - - alias: cozystack - kind: GitRepository - name: cozystack - namespace: cozy-system - artifacts: - - name: extra-etcd - copy: - - from: "@cozystack/packages/extra/etcd/**" - to: "@artifact/extra/" - - from: "@cozystack/packages/library/cozy-lib/**" - to: "@artifact/extra/charts/cozy-lib/" - - name: extra-seaweedfs - copy: - - from: "@cozystack/packages/extra/seaweedfs/**" - to: "@artifact/seaweedfs/" - - from: "@cozystack/packages/library/cozy-lib/**" - to: "@artifact/seaweedfs/charts/cozy-lib/" - diff --git a/packages/core/platform/templates/bundles-configmap.yaml b/packages/core/platform/templates/bundles-configmap.yaml new file mode 100644 index 00000000..d10811fb --- /dev/null +++ b/packages/core/platform/templates/bundles-configmap.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: system-bundle + namespace: cozy-system + labels: + cozystack.io/system: "true" +data: + paas-full.yaml: | +{{- trim (tpl (.Files.Get "bundles/paas-full.yaml") .) | indent 4 }} + paas-hosted.yaml: | +{{- trim (tpl (.Files.Get "bundles/paas-hosted.yaml") .) | indent 4 }} + distro-full.yaml: | +{{- trim (tpl (.Files.Get "bundles/distro-full.yaml") .) | indent 4 }} + distro-hosted.yaml: | +{{- trim (tpl (.Files.Get "bundles/distro-hosted.yaml") .) | indent 4 }} + diff --git a/packages/core/platform/templates/helmreleases.yaml b/packages/core/platform/templates/helmreleases.yaml deleted file mode 100644 index 6ed61ed8..00000000 --- a/packages/core/platform/templates/helmreleases.yaml +++ /dev/null @@ -1,97 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $bundleName := index $cozyConfig.data "bundle-name" }} -{{- $bundle := tpl (.Files.Get (printf "bundles/%s.yaml" $bundleName)) . | fromYaml }} -{{- $dependencyNamespaces := dict }} -{{- $disabledComponents := splitList "," ((index $cozyConfig.data "bundle-disable") | default "") }} -{{- $enabledComponents := splitList "," ((index $cozyConfig.data "bundle-enable") | default "") }} -{{- $oidcEnabled := (index (default dict $cozyConfig.data) "oidc-enabled") | default "false" | eq "true" }} - -{{/* collect dependency namespaces from releases */}} -{{- range $x := $bundle.releases }} -{{- $_ := set $dependencyNamespaces $x.name $x.namespace }} -{{- end }} - -{{- range $x := $bundle.releases }} - -{{- $shouldInstall := true }} -{{- $shouldDelete := false }} -{{- $notEnabledOptionalComponent := and ($x.optional) (not (has $x.name $enabledComponents)) }} -{{- $disabledComponent := has $x.name $disabledComponents }} -{{- $isKeycloakComponent := or (eq $x.name "keycloak") (eq $x.name "keycloak-operator") (eq $x.name "keycloak-configure") }} - -{{- if and $isKeycloakComponent (not $oidcEnabled) }} -{{- $shouldInstall = false }} -{{- if $.Capabilities.APIVersions.Has "helm.toolkit.fluxcd.io/v2" }} -{{- if lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" $x.namespace $x.name }} -{{- $shouldDelete = true }} -{{- end }} -{{- end }} -{{- else if or $disabledComponent $notEnabledOptionalComponent }} -{{- $shouldInstall = false }} -{{- if $.Capabilities.APIVersions.Has "helm.toolkit.fluxcd.io/v2" }} -{{- if lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" $x.namespace $x.name }} -{{- $shouldDelete = true }} -{{- end }} -{{- end }} -{{- end }} - -{{- if or $shouldInstall $shouldDelete }} ---- -apiVersion: helm.toolkit.fluxcd.io/v2 -kind: HelmRelease -metadata: - name: {{ $x.name }} - namespace: {{ $x.namespace }} - labels: - cozystack.io/repository: system - cozystack.io/system-app: "true" - {{- if $shouldDelete }} - cozystack.io/marked-for-deletion: "true" - {{- end }} -spec: - interval: 5m - releaseName: {{ $x.releaseName | default $x.name }} - install: - crds: CreateReplace - remediation: - retries: -1 - upgrade: - crds: CreateReplace - remediation: - retries: -1 - chart: - spec: - chart: {{ $x.chart }} - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' - {{- with $x.valuesFiles }} - valuesFiles: - {{- toYaml $x.valuesFiles | nindent 6 }} - {{- end }} - {{- $values := dict }} - {{- with $x.values }} - {{- $values = merge . $values }} - {{- end }} - {{- with index $cozyConfig.data (printf "values-%s" $x.name) }} - {{- $values = mergeOverwrite $values (fromYaml .) }} - {{- end }} - {{- with $values }} - values: - {{- toYaml . | nindent 4}} - {{- end }} - - {{- with $x.dependsOn }} - dependsOn: - {{- range $dep := . }} - {{- if not (has $dep $disabledComponents) }} - - name: {{ $dep }} - namespace: {{ index $dependencyNamespaces $dep }} - {{- end }} - {{- end }} - {{- end }} -{{- end }} -{{- end }} diff --git a/packages/core/platform/templates/helmrepos.yaml b/packages/core/platform/templates/helmrepos.yaml deleted file mode 100644 index f65c8471..00000000 --- a/packages/core/platform/templates/helmrepos.yaml +++ /dev/null @@ -1,131 +0,0 @@ ---- -apiVersion: source.toolkit.fluxcd.io/v1 -kind: HelmRepository -metadata: - name: cozystack-system - namespace: cozy-system - labels: - cozystack.io/repository: system -spec: - interval: 5m0s - url: http://cozystack.cozy-system.svc/repos/system ---- -apiVersion: source.toolkit.fluxcd.io/v1 -kind: HelmRepository -metadata: - name: cozystack-apps - namespace: cozy-public - labels: - cozystack.io/ui: "true" - cozystack.io/repository: apps -spec: - interval: 5m0s - url: http://cozystack.cozy-system.svc/repos/apps ---- -apiVersion: source.toolkit.fluxcd.io/v1 -kind: HelmRepository -metadata: - name: cozystack-extra - namespace: cozy-public - labels: - cozystack.io/repository: extra -spec: - interval: 5m0s - url: http://cozystack.cozy-system.svc/repos/extra - - ---- -apiVersion: source.toolkit.fluxcd.io/v1 -kind: GitRepository -metadata: - name: cozystack - namespace: cozy-system -spec: - interval: 1m0s - ref: - tag: v0.37.6 - timeout: 60s - url: https://github.com/cozystack/cozystack.git - ignore: | - # exclude all - /* - # include packages dir - !/packages - ---- -# ArtifactGenerator with explicit copy operations (no symlinks needed) -apiVersion: source.extensions.fluxcd.io/v1beta1 -kind: ArtifactGenerator -metadata: - name: system - namespace: cozy-system -spec: - sources: - - alias: cozystack - kind: GitRepository - name: cozystack - namespace: cozy-system - artifacts: - - name: system-cilium - copy: - - from: "@cozystack/packages/system/cilium/**" - to: "@artifact/cilium/" - - name: system-kubeovn - copy: - - from: "@cozystack/packages/system/kubeovn/**" - to: "@artifact/kubeovn/" - ---- -# ArtifactGenerator with explicit copy operations (no symlinks needed) -apiVersion: source.extensions.fluxcd.io/v1beta1 -kind: ArtifactGenerator -metadata: - name: apps - namespace: cozy-public -spec: - sources: - - alias: cozystack - kind: GitRepository - name: cozystack - namespace: cozy-system - artifacts: - - name: apps-virtual-machine - copy: - - from: "@cozystack/packages/apps/virtual-machine/**" - to: "@artifact/virtual-machine/" - - from: "@cozystack/packages/library/cozy-lib/**" - to: "@artifact/virtual-machine/charts/cozy-lib/" - - name: apps-vm-instance - copy: - - from: "@cozystack/packages/apps/vm-instance/**" - to: "@artifact/vm-instance/" - - from: "@cozystack/packages/library/cozy-lib/**" - to: "@artifact/vm-instance/charts/cozy-lib/" - ---- -# ArtifactGenerator with explicit copy operations (no symlinks needed) -apiVersion: source.extensions.fluxcd.io/v1beta1 -kind: ArtifactGenerator -metadata: - name: extra - namespace: cozy-public -spec: - sources: - - alias: cozystack - kind: GitRepository - name: cozystack - namespace: cozy-public - artifacts: - - name: extra-etcd - copy: - - from: "@cozystack/packages/extra/etcd/**" - to: "@artifact/extra/" - - from: "@cozystack/packages/library/cozy-lib/**" - to: "@artifact/extra/charts/cozy-lib/" - - name: extra-seaweedfs - copy: - - from: "@cozystack/packages/extra/seaweedfs/**" - to: "@artifact/seaweedfs/" - - from: "@cozystack/packages/library/cozy-lib/**" - to: "@artifact/seaweedfs/charts/cozy-lib/" - diff --git a/packages/core/platform/templates/namespaces.yaml b/packages/core/platform/templates/namespaces.yaml deleted file mode 100644 index 11d00553..00000000 --- a/packages/core/platform/templates/namespaces.yaml +++ /dev/null @@ -1,40 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $bundleName := index $cozyConfig.data "bundle-name" }} -{{- $bundle := tpl (.Files.Get (printf "bundles/%s.yaml" $bundleName)) . | fromYaml }} -{{- $disabledComponents := splitList "," ((index $cozyConfig.data "bundle-disable") | default "") }} -{{- $enabledComponents := splitList "," ((index $cozyConfig.data "bundle-enable") | default "") }} -{{- $namespaces := dict }} - -{{/* collect namespaces from releases */}} -{{- range $x := $bundle.releases }} - {{- if not (hasKey $namespaces $x.namespace) }} - {{- if not (has $x.name $disabledComponents) }} - {{- if or (not $x.optional) (and ($x.optional) (has $x.name $enabledComponents)) }} - {{- $_ := set $namespaces $x.namespace false }} - {{- end }} - {{- end }} - {{- end }} - {{/* if at least one release requires a privileged namespace, then it should be privileged */}} - {{- if or $x.privileged (index $namespaces $x.namespace) }} - {{- $_ := set $namespaces $x.namespace true }} - {{- end }} -{{- end }} - -{{/* Add extra namespaces */}} -{{- $_ := set $namespaces "cozy-system" true }} -{{- $_ := set $namespaces "cozy-public" false }} - -{{- range $namespace, $privileged := $namespaces }} ---- -apiVersion: v1 -kind: Namespace -metadata: - annotations: - "helm.sh/resource-policy": keep - labels: - cozystack.io/system: "true" - {{- if $privileged }} - pod-security.kubernetes.io/enforce: privileged - {{- end }} - name: {{ $namespace }} -{{- end }} diff --git a/packages/system/fluxcd-operator/templates/_helpers.tpl b/packages/system/fluxcd-operator/templates/_helpers.tpl index e22979ba..0271a10f 100644 --- a/packages/system/fluxcd-operator/templates/_helpers.tpl +++ b/packages/system/fluxcd-operator/templates/_helpers.tpl @@ -1,8 +1,8 @@ {{- define "cozy.kubernetes_envs" }} -{{- $cozyDeployment := lookup "apps/v1" "Deployment" "cozy-system" "cozystack" }} +{{- $cozyDeployment := lookup "apps/v1" "Deployment" "cozy-system" "cozystack-operator" }} {{- $cozyContainers := dig "spec" "template" "spec" "containers" dict $cozyDeployment }} {{- range $cozyContainers }} -{{- if eq .name "cozystack" }} +{{- if eq .name "cozystack-operator" }} {{- range .env }} {{- if has .name (list "KUBERNETES_SERVICE_HOST" "KUBERNETES_SERVICE_PORT") }} - {{ toJson . }} diff --git a/pkg/config/apiserver.go b/pkg/config/apiserver.go new file mode 100644 index 00000000..390918a6 --- /dev/null +++ b/pkg/config/apiserver.go @@ -0,0 +1,57 @@ +/* +Copyright 2024 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 config + +// ResourceConfig represents the structure of the configuration file. +type ResourceConfig struct { + Resources []Resource `yaml:"resources"` +} + +// Resource describes an individual resource. +type Resource struct { + Application ApplicationConfig `yaml:"application"` + Release ReleaseConfig `yaml:"release"` +} + +// ApplicationConfig contains the application settings. +type ApplicationConfig struct { + Kind string `yaml:"kind"` + Singular string `yaml:"singular"` + Plural string `yaml:"plural"` + ShortNames []string `yaml:"shortNames"` + OpenAPISchema string `yaml:"openAPISchema"` +} + +// ReleaseConfig contains the release settings. +type ReleaseConfig struct { + Prefix string `yaml:"prefix"` + Labels map[string]string `yaml:"labels"` + Chart ChartConfig `yaml:"chart"` +} + +// ChartConfig contains the chart settings. +type ChartConfig struct { + Name string `yaml:"name"` + SourceRef SourceRefConfig `yaml:"sourceRef"` +} + +// SourceRefConfig contains the reference to the chart source. +type SourceRefConfig struct { + Kind string `yaml:"kind"` + Name string `yaml:"name"` + Namespace string `yaml:"namespace"` +} diff --git a/pkg/config/config.go b/pkg/config/config.go index 390918a6..0fd39bd6 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -16,42 +16,151 @@ limitations under the License. package config -// ResourceConfig represents the structure of the configuration file. -type ResourceConfig struct { - Resources []Resource `yaml:"resources"` +import "strings" + +// CozystackConfig represents the structure of the cozystack ConfigMap. +type CozystackConfig struct { + // BundleName specifies which bundle to use (e.g., "paas-full", "distro-full", etc.) + BundleName string `yaml:"bundle-name,omitempty"` + + // BundleDisable is a comma-separated list of components to disable + BundleDisable string `yaml:"bundle-disable,omitempty"` + + // BundleEnable is a comma-separated list of optional components to enable + BundleEnable string `yaml:"bundle-enable,omitempty"` + + // OIDCEnabled indicates whether OIDC is enabled (default: "false") + OIDCEnabled string `yaml:"oidc-enabled,omitempty"` + + // RootHost specifies the root host for tenant-root namespace + RootHost string `yaml:"root-host,omitempty"` + + // APIServerEndpoint specifies the API server endpoint + APIServerEndpoint string `yaml:"api-server-endpoint,omitempty"` + + // ClusterDomain specifies the cluster domain (default: "cozy.local") + ClusterDomain string `yaml:"cluster-domain,omitempty"` + + // IPv4PodCIDR specifies the IPv4 pod CIDR + IPv4PodCIDR string `yaml:"ipv4-pod-cidr,omitempty"` + + // IPv4PodGateway specifies the IPv4 pod gateway + IPv4PodGateway string `yaml:"ipv4-pod-gateway,omitempty"` + + // IPv4SvcCIDR specifies the IPv4 service CIDR + IPv4SvcCIDR string `yaml:"ipv4-svc-cidr,omitempty"` + + // IPv4JoinCIDR specifies the IPv4 join CIDR + IPv4JoinCIDR string `yaml:"ipv4-join-cidr,omitempty"` + + // Values contains component-specific values keyed by component name + // Key format: "values-{component-name}" + Values map[string]string `yaml:",inline"` } -// Resource describes an individual resource. -type Resource struct { - Application ApplicationConfig `yaml:"application"` - Release ReleaseConfig `yaml:"release"` +// ParseConfigMapData parses ConfigMap data into CozystackConfig. +func ParseConfigMapData(data map[string]string) *CozystackConfig { + cfg := &CozystackConfig{ + Values: make(map[string]string), + } + + if v, ok := data["bundle-name"]; ok { + cfg.BundleName = v + } + if v, ok := data["bundle-disable"]; ok { + cfg.BundleDisable = v + } + if v, ok := data["bundle-enable"]; ok { + cfg.BundleEnable = v + } + if v, ok := data["oidc-enabled"]; ok { + cfg.OIDCEnabled = v + } + if v, ok := data["root-host"]; ok { + cfg.RootHost = v + } + if v, ok := data["api-server-endpoint"]; ok { + cfg.APIServerEndpoint = v + } + if v, ok := data["cluster-domain"]; ok { + cfg.ClusterDomain = v + } else { + cfg.ClusterDomain = "cozy.local" + } + if v, ok := data["ipv4-pod-cidr"]; ok { + cfg.IPv4PodCIDR = v + } + if v, ok := data["ipv4-pod-gateway"]; ok { + cfg.IPv4PodGateway = v + } + if v, ok := data["ipv4-svc-cidr"]; ok { + cfg.IPv4SvcCIDR = v + } + if v, ok := data["ipv4-join-cidr"]; ok { + cfg.IPv4JoinCIDR = v + } + + // Extract values-* keys + for k, v := range data { + if len(k) > 7 && k[:7] == "values-" { + cfg.Values[k] = v + } + } + + return cfg } -// ApplicationConfig contains the application settings. -type ApplicationConfig struct { - Kind string `yaml:"kind"` - Singular string `yaml:"singular"` - Plural string `yaml:"plural"` - ShortNames []string `yaml:"shortNames"` - OpenAPISchema string `yaml:"openAPISchema"` +// GetComponentValues returns values for a specific component. +func (c *CozystackConfig) GetComponentValues(componentName string) (string, bool) { + key := "values-" + componentName + v, ok := c.Values[key] + return v, ok } -// ReleaseConfig contains the release settings. -type ReleaseConfig struct { - Prefix string `yaml:"prefix"` - Labels map[string]string `yaml:"labels"` - Chart ChartConfig `yaml:"chart"` +// IsComponentDisabled checks if a component is in the disabled list. +func (c *CozystackConfig) IsComponentDisabled(componentName string) bool { + if c.BundleDisable == "" { + return false + } + disabled := splitList(c.BundleDisable) + for _, d := range disabled { + if d == componentName { + return true + } + } + return false } -// ChartConfig contains the chart settings. -type ChartConfig struct { - Name string `yaml:"name"` - SourceRef SourceRefConfig `yaml:"sourceRef"` +// IsComponentEnabled checks if an optional component is in the enabled list. +func (c *CozystackConfig) IsComponentEnabled(componentName string) bool { + if c.BundleEnable == "" { + return false + } + enabled := splitList(c.BundleEnable) + for _, e := range enabled { + if e == componentName { + return true + } + } + return false } -// SourceRefConfig contains the reference to the chart source. -type SourceRefConfig struct { - Kind string `yaml:"kind"` - Name string `yaml:"name"` - Namespace string `yaml:"namespace"` +// IsOIDCEnabled checks if OIDC is enabled. +func (c *CozystackConfig) IsOIDCEnabled() bool { + return c.OIDCEnabled == "true" +} + +// splitList splits a comma-separated string into a slice. +func splitList(s string) []string { + if s == "" { + return nil + } + var result []string + parts := strings.Split(s, ",") + for _, part := range parts { + if trimmed := strings.TrimSpace(part); trimmed != "" { + result = append(result, trimmed) + } + } + return result } diff --git a/scripts/installer.sh b/scripts/installer.sh deleted file mode 100755 index 8dfa68ee..00000000 --- a/scripts/installer.sh +++ /dev/null @@ -1,100 +0,0 @@ -#!/bin/sh -set -o pipefail -set -e - -BUNDLE=$(set -x; kubectl get configmap -n cozy-system cozystack -o 'go-template={{index .data "bundle-name"}}') -VERSION=$(find scripts/migrations -mindepth 1 -maxdepth 1 -type f | sort -V | awk -F/ 'END {print $NF+1}') - -run_migrations() { - if ! kubectl get configmap -n cozy-system cozystack-version; then - kubectl create configmap -n cozy-system cozystack-version --from-literal=version="$VERSION" --dry-run=client -o yaml | kubectl create -f- - return - fi - current_version=$(kubectl get configmap -n cozy-system cozystack-version -o jsonpath='{.data.version}') || true - until [ "$current_version" = "$VERSION" ]; do - echo "run migration: $current_version --> $VERSION" - chmod +x scripts/migrations/$current_version - scripts/migrations/$current_version - current_version=$(kubectl get configmap -n cozy-system cozystack-version -o jsonpath='{.data.version}') - done -} - -flux_is_ok() { - kubectl wait --for=condition=available -n cozy-fluxcd deploy/source-controller deploy/helm-controller --timeout=1s - kubectl wait --for=condition=ready -n cozy-fluxcd helmrelease/fluxcd --timeout=1s # to call "apply resume" below -} - -ensure_fluxcd() { - if flux_is_ok; then - return - fi - # Install fluxcd-operator - if kubectl get helmreleases.helm.toolkit.fluxcd.io -n cozy-fluxcd fluxcd-operator; then - make -C packages/system/fluxcd-operator apply resume - else - make -C packages/system/fluxcd-operator apply-locally - fi - wait_for_crds fluxinstances.fluxcd.controlplane.io - - # Install fluxcd - if kubectl get helmreleases.helm.toolkit.fluxcd.io -n cozy-fluxcd fluxcd; then - make -C packages/system/fluxcd apply resume - else - make -C packages/system/fluxcd apply-locally - fi - wait_for_crds helmreleases.helm.toolkit.fluxcd.io helmrepositories.source.toolkit.fluxcd.io -} - -wait_for_crds() { - timeout 60 sh -c "until kubectl get crd $*; do sleep 1; done" -} - -install_basic_charts() { - if [ "$BUNDLE" = "paas-full" ] || [ "$BUNDLE" = "distro-full" ]; then - make -C packages/system/cilium apply resume - fi - if [ "$BUNDLE" = "paas-full" ]; then - make -C packages/system/kubeovn apply resume - fi -} - -cd "$(dirname "$0")/.." - -# Run migrations -run_migrations - -# Install namespaces -make -C packages/core/platform namespaces-apply - -# Install fluxcd -ensure_fluxcd - -# Install platform chart -make -C packages/core/platform reconcile - -# Install basic charts -if ! flux_is_ok; then - install_basic_charts -fi - -# Reconcile Helm repositories -kubectl annotate helmrepositories.source.toolkit.fluxcd.io -A -l cozystack.io/repository reconcile.fluxcd.io/requestedAt=$(date +"%Y-%m-%dT%H:%M:%SZ") --overwrite - -# Unsuspend all Cozystack managed charts -kubectl get hr -A -o go-template='{{ range .items }}{{ if .spec.suspend }}{{ .spec.chart.spec.sourceRef.namespace }}/{{ .spec.chart.spec.sourceRef.name }} {{ .metadata.namespace }} {{ .metadata.name }}{{ "\n" }}{{ end }}{{ end }}' | while read repo namespace name; do - case "$repo" in - cozy-system/cozystack-system|cozy-public/cozystack-extra|cozy-public/cozystack-apps) - kubectl patch hr -n "$namespace" "$name" -p '{"spec": {"suspend": null}}' --type=merge --field-manager=flux-client-side-apply - ;; - esac -done - -# Update all Cozystack managed charts to latest version -kubectl get hr -A -l cozystack.io/ui=true --no-headers | awk '{print "kubectl patch helmrelease -n " $1 " " $2 " --type=merge -p '\''{\"spec\":{\"chart\":{\"spec\":{\"version\":\">= 0.0.0-0\"}}}}'\'' "}' | sh -x - -# Reconcile platform chart -trap 'exit' INT TERM -while true; do - sleep 60 & wait - make -C packages/core/platform reconcile -done diff --git a/scripts/migrations/21 b/scripts/migrations/21 new file mode 100755 index 00000000..86c6048d --- /dev/null +++ b/scripts/migrations/21 @@ -0,0 +1,17 @@ +#!/bin/sh +# Migration 21 --> 22 + +set -euo pipefail + +# Delete old cozystack deployment +kubectl -n cozy-system delete deployment cozystack --ignore-not-found +while [ $( kubectl -n cozy-system get po -l app=cozystack --no-headers 2>/dev/null | wc -l ) != 0 ] ; +do + echo "Waiting for old cozystack deployment pods to be deleted"; + sleep 1 +done + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=22 --dry-run=client -o yaml | kubectl apply -f- + From c808ed6f2471bd9d4a1ce8d84f0120bb8dc5e0ef Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 19 Nov 2025 00:07:20 +0100 Subject: [PATCH 04/46] Add ArtifactGenerators reconciler Signed-off-by: Andrei Kvapil --- cmd/cozystack-operator/main.go | 2 + go.mod | 51 ++-- go.sum | 57 ++++ internal/operator/reconciler.go | 444 ++++++++++++++++++++++++---- packages/core/installer/values.yaml | 2 +- 5 files changed, 483 insertions(+), 73 deletions(-) diff --git a/cmd/cozystack-operator/main.go b/cmd/cozystack-operator/main.go index 28e011b3..6cefc090 100644 --- a/cmd/cozystack-operator/main.go +++ b/cmd/cozystack-operator/main.go @@ -33,6 +33,7 @@ import ( 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" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -64,6 +65,7 @@ func init() { utilruntime.Must(apiextensionsv1.AddToScheme(scheme)) utilruntime.Must(helmv2.AddToScheme(scheme)) utilruntime.Must(sourcev1.AddToScheme(scheme)) + utilruntime.Must(sourcewatcherv1beta1.AddToScheme(scheme)) // +kubebuilder:scaffold:scheme } diff --git a/go.mod b/go.mod index e3eca735..92fc3bc9 100644 --- a/go.mod +++ b/go.mod @@ -5,29 +5,29 @@ module github.com/cozystack/cozystack go 1.25.0 require ( - github.com/fluxcd/helm-controller/api v1.1.0 - github.com/fluxcd/source-controller/api v1.4.1 + github.com/fluxcd/helm-controller/api v1.4.3 + github.com/fluxcd/source-controller/api v1.6.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/onsi/ginkgo/v2 v2.22.0 - github.com/onsi/gomega v1.36.1 + github.com/onsi/ginkgo/v2 v2.23.3 + github.com/onsi/gomega v1.37.0 github.com/prometheus/client_golang v1.22.0 github.com/spf13/cobra v1.9.1 - github.com/stretchr/testify v1.10.0 + github.com/stretchr/testify v1.11.1 go.uber.org/zap v1.27.0 gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.34.1 - k8s.io/apiextensions-apiserver v0.31.2 + k8s.io/apiextensions-apiserver v0.34.1 k8s.io/apimachinery v0.34.1 - k8s.io/apiserver v0.31.2 + k8s.io/apiserver v0.34.1 k8s.io/client-go v0.34.1 k8s.io/component-base v0.34.1 k8s.io/klog/v2 v2.130.1 k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b - k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 - sigs.k8s.io/controller-runtime v0.19.7 - sigs.k8s.io/structured-merge-diff/v4 v4.4.1 + k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d + sigs.k8s.io/controller-runtime v0.22.2 + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 ) require ( @@ -41,49 +41,62 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/cyphar/filepath-securejoin v0.4.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // 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/v5 v5.9.11 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fluxcd/pkg/apis/acl v0.9.0 // indirect - github.com/fluxcd/pkg/apis/kustomize v1.6.1 // indirect + github.com/fluxcd/pkg/apis/kustomize v1.13.0 // indirect github.com/fluxcd/pkg/apis/meta v1.22.0 // indirect + github.com/fluxcd/pkg/http/fetch v0.15.0 // indirect + github.com/fluxcd/pkg/runtime v0.60.0 // indirect + github.com/fluxcd/pkg/tar v0.12.0 // indirect + github.com/fluxcd/source-watcher v1.3.0 // indirect + github.com/fluxcd/source-watcher/api/v2 v2.0.2 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/go-logr/stdr v1.2.2 // 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-task/slim-sprig/v3 v3.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect + github.com/google/btree v1.1.3 // indirect github.com/google/cel-go v0.26.0 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/uuid v1.6.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/grpc-gateway/v2 v2.26.3 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/kylelemons/godebug v1.1.0 // indirect - github.com/mailru/easyjson v0.7.7 // 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/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/go-digest/blake3 v0.0.0-20240426182413-22b78e47854a // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/pflag v1.0.7 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect github.com/x448/float16 v0.8.4 // indirect + github.com/zeebo/blake3 v0.2.4 // indirect go.etcd.io/etcd/api/v3 v3.6.4 // indirect go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect go.etcd.io/etcd/client/v3 v3.6.4 // indirect @@ -103,13 +116,13 @@ require ( golang.org/x/crypto v0.42.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/net v0.45.0 // indirect - golang.org/x/oauth2 v0.27.0 // indirect + golang.org/x/oauth2 v0.29.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.36.0 // indirect golang.org/x/term v0.35.0 // indirect golang.org/x/text v0.29.0 // indirect - golang.org/x/time v0.9.0 // indirect - golang.org/x/tools v0.36.0 // indirect + golang.org/x/time v0.11.0 // indirect + golang.org/x/tools v0.37.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect @@ -121,7 +134,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/kms v0.34.1 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect - sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // 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 diff --git a/go.sum b/go.sum index d7033ed9..1da2dc3a 100644 --- a/go.sum +++ b/go.sum @@ -22,6 +22,8 @@ github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8 github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 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/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= +github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= 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.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -38,14 +40,30 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2 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.1.0/go.mod h1:BgHMgMY6CWynzl4KIbHpd6Wpn3FN9BqgkwmvoKCp6iE= +github.com/fluxcd/helm-controller/api v1.4.3 h1:CdZwjL1liXmYCWyk2jscmFEB59tICIlnWB9PfDDW5q4= +github.com/fluxcd/helm-controller/api v1.4.3/go.mod h1:0XrBhKEaqvxyDj/FziG1Q8Fmx2UATdaqLgYqmZh6wW4= github.com/fluxcd/pkg/apis/acl v0.9.0 h1:wBpgsKT+jcyZEcM//OmZr9RiF8klL3ebrDp2u2ThsnA= github.com/fluxcd/pkg/apis/acl v0.9.0/go.mod h1:TttNS+gocsGLwnvmgVi3/Yscwqrjc17+vhgYfqkfrV4= github.com/fluxcd/pkg/apis/kustomize v1.6.1 h1:22FJc69Mq4i8aCxnKPlddHhSMyI4UPkQkqiAdWFcqe0= github.com/fluxcd/pkg/apis/kustomize v1.6.1/go.mod h1:5dvQ4IZwz0hMGmuj8tTWGtarsuxW0rWsxJOwC6i+0V8= +github.com/fluxcd/pkg/apis/kustomize v1.13.0 h1:GGf0UBVRIku+gebY944icVeEIhyg1P/KE3IrhOyJJnE= +github.com/fluxcd/pkg/apis/kustomize v1.13.0/go.mod h1:TLKVqbtnzkhDuhWnAsN35977HvRfIjs+lgMuNro/LEc= github.com/fluxcd/pkg/apis/meta v1.22.0 h1:EHWQH5ZWml7i8eZ/AMjm1jxid3j/PQ31p+hIwCt6crM= github.com/fluxcd/pkg/apis/meta v1.22.0/go.mod h1:Kc1+bWe5p0doROzuV9XiTfV/oL3ddsemYXt8ZYWdVVg= +github.com/fluxcd/pkg/http/fetch v0.15.0 h1:AJ1JuE2asuK4QMfbHjxctFURke5FvZtyljjI1Qv4ArQ= +github.com/fluxcd/pkg/http/fetch v0.15.0/go.mod h1:feTESfETKU14jq+e/Ce8QnMBTCh9O79bLMSMe5t55fQ= +github.com/fluxcd/pkg/runtime v0.60.0 h1:d++EkV3FlycB+bzakB5NumwY4J8xts8i7lbvD6jBLeU= +github.com/fluxcd/pkg/runtime v0.60.0/go.mod h1:UeU0/eZLErYC/1bTmgzBfNXhiHy9fuQzjfLK0HxRgxY= +github.com/fluxcd/pkg/tar v0.12.0 h1:og6F+ivnWNRbNJSq0ukCTVs7YrGIlzjxSVZU+E8NprM= +github.com/fluxcd/pkg/tar v0.12.0/go.mod h1:Ra5Cj++MD5iCy7bZGKJJX3GpOeMPv+ZDkPO9bBwpDeU= github.com/fluxcd/source-controller/api v1.4.1 h1:zV01D7xzHOXWbYXr36lXHWWYS7POARsjLt61Nbh3kVY= github.com/fluxcd/source-controller/api v1.4.1/go.mod h1:gSjg57T+IG66SsBR0aquv+DFrm4YyBNpKIJVDnu3Ya8= +github.com/fluxcd/source-controller/api v1.6.2 h1:UmodAeqLIeF29HdTqf2GiacZyO+hJydJlepDaYsMvhc= +github.com/fluxcd/source-controller/api v1.6.2/go.mod h1:ZJcAi0nemsnBxjVgmJl0WQzNvB0rMETxQMTdoFosmMw= +github.com/fluxcd/source-watcher v1.3.0 h1:G88lVPkHvtx16mzhEE7oNaOtBoSpzYIsoIpFI709/A0= +github.com/fluxcd/source-watcher v1.3.0/go.mod h1:NHAT0zD/pNoPVtHRY712nffO+m9dtfqycIOrWQhboO8= +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= @@ -62,6 +80,8 @@ github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1 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.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +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/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= @@ -88,6 +108,7 @@ 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/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +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/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= @@ -100,6 +121,10 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= @@ -112,6 +137,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 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/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -123,6 +150,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +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= @@ -137,8 +166,14 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/go-digest/blake3 v0.0.0-20240426182413-22b78e47854a h1:xwooQrLddjfeKhucuLS4ElD3TtuuRwF8QWC9eHrnbxY= +github.com/opencontainers/go-digest/blake3 v0.0.0-20240426182413-22b78e47854a/go.mod h1:kqQaIc6bZstKgnGpL7GD5dWoLKbA6mH1Y9ULjGImBnM= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 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= @@ -163,6 +198,8 @@ github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/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/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -176,6 +213,7 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.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/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= @@ -184,6 +222,8 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= +github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= go.etcd.io/etcd/api/v3 v3.6.4 h1:7F6N7toCKcV72QmoUKa23yYLiiljMrT4xCeBL9BmXdo= @@ -249,6 +289,8 @@ golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98= +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-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -267,12 +309,15 @@ golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= +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-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-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= +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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -308,10 +353,13 @@ k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM= 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.31.2/go.mod h1:i+Geh+nGCJEGiCGR3MlBDkS7koHIIKWVfWeRFiOsUcM= +k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI= +k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc= k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4= k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= k8s.io/apiserver v0.31.2 h1:VUzOEUGRCDi6kX1OyQ801m4A7AUPglpsmGvdsekmcI4= 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.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY= k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8= k8s.io/component-base v0.34.1 h1:v7xFgG+ONhytZNFpIz5/kecwD+sUhVE6HU7qQUiRM4A= @@ -324,17 +372,26 @@ k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOP k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts= k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y= k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d h1:wAhiDyZ4Tdtt7e46e9M5ZSAJ/MnPGPs+Ki1gHw4w1R0= +k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= sigs.k8s.io/controller-runtime v0.19.7 h1:DLABZfMr20A+AwCZOHhcbcu+TqBXnJZaVBri9K3EO48= sigs.k8s.io/controller-runtime v0.19.7/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= +sigs.k8s.io/controller-runtime v0.22.2 h1:cK2l8BGWsSWkXz09tcS4rJh95iOLney5eawcK5A33r4= +sigs.k8s.io/controller-runtime v0.22.2/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/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.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/internal/operator/reconciler.go b/internal/operator/reconciler.go index 65fecf66..0cb1ebfc 100644 --- a/internal/operator/reconciler.go +++ b/internal/operator/reconciler.go @@ -25,6 +25,7 @@ import ( 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" corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -55,8 +56,9 @@ type PlatformReconciler struct { // +kubebuilder:rbac:groups=core,resources=configmaps/status,verbs=get // +kubebuilder:rbac:groups=core,resources=namespaces,verbs=get;list;watch;create;update;patch // +kubebuilder:rbac:groups=helm.toolkit.fluxcd.io,resources=helmreleases,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=helmrepositories,verbs=get;list;watch;create;update;patch +// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=helmrepositories,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=gitrepositories,verbs=get;list;watch;create;update;patch +// +kubebuilder:rbac:groups=source.extensions.fluxcd.io,resources=artifactgenerators,verbs=get;list;watch;create;update;patch // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. @@ -100,11 +102,21 @@ func (r *PlatformReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c logger.Info("Reconciling platform", "bundle", cfg.BundleName) - // Reconcile HelmRepository resources - if err := r.reconcileHelmRepositories(ctx, cfg); err != nil { + // Reconcile HelmRepositories (delete old ones, we no longer create them) + if err := r.reconcileHelmRepositories(ctx); err != nil { return ctrl.Result{}, fmt.Errorf("failed to reconcile HelmRepositories: %w", err) } + // Reconcile GitRepository + if err := r.reconcileGitRepository(ctx); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to reconcile GitRepository: %w", err) + } + + // Reconcile ArtifactGenerators + if err := r.reconcileArtifactGenerators(ctx); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to reconcile ArtifactGenerators: %w", err) + } + // Reconcile namespaces if err := r.reconcileNamespaces(ctx, cfg); err != nil { return ctrl.Result{}, fmt.Errorf("failed to reconcile namespaces: %w", err) @@ -131,60 +143,332 @@ func (r *PlatformReconciler) SetupWithManager(mgr ctrl.Manager) error { Complete(r) } -func (r *PlatformReconciler) reconcileHelmRepositories(ctx context.Context, cfg *config.CozystackConfig) error { +func (r *PlatformReconciler) reconcileHelmRepositories(ctx context.Context) error { logger := log.FromContext(ctx) - repos := []struct { - name string - namespace string - url string - labels map[string]string - }{ - { - name: "cozystack-system", - namespace: "cozy-system", - url: "http://cozystack.cozy-system.svc/repos/system", - labels: map[string]string{ - "cozystack.io/repository": "system", + // We no longer create HelmRepositories, we use ArtifactGenerators instead + // Delete all old HelmRepositories that were managed by this operator + + desiredRepos := map[string]string{} // empty - we don't want any HelmRepositories + + // List all HelmRepositories that were managed by this operator + hrList := &sourcev1.HelmRepositoryList{} + if err := r.List(ctx, hrList, client.MatchingLabels{ + platformOperatorLabel: "true", + }); err != nil { + return fmt.Errorf("failed to list HelmRepositories: %w", err) + } + + // Also list by old labels for backward compatibility + oldLabels := []map[string]string{ + {"cozystack.io/repository": "system"}, + {"cozystack.io/repository": "apps"}, + {"cozystack.io/repository": "extra"}, + } + + reposToCheck := make(map[types.NamespacedName]bool) + for _, hr := range hrList.Items { + key := types.NamespacedName{Name: hr.Name, Namespace: hr.Namespace} + reposToCheck[key] = true + } + + for _, labels := range oldLabels { + oldList := &sourcev1.HelmRepositoryList{} + if err := r.List(ctx, oldList, client.MatchingLabels(labels)); err != nil { + logger.Error(err, "failed to list HelmRepositories by old labels") + continue + } + for _, hr := range oldList.Items { + key := types.NamespacedName{Name: hr.Name, Namespace: hr.Namespace} + reposToCheck[key] = true + } + } + + // Delete all HelmRepositories that are no longer desired + for key := range reposToCheck { + hr := &sourcev1.HelmRepository{} + if err := r.Get(ctx, key, hr); err != nil { + if apierrors.IsNotFound(err) { + continue + } + return fmt.Errorf("failed to get HelmRepository %s/%s: %w", key.Namespace, key.Name, err) + } + + // Check if this HelmRepository is still desired (none are desired now) + desiredKey := fmt.Sprintf("%s/%s", hr.Namespace, hr.Name) + if _, ok := desiredRepos[desiredKey]; !ok { + // Not desired anymore, delete it + if err := r.Delete(ctx, hr); err != nil { + if apierrors.IsNotFound(err) { + continue + } + logger.Error(err, "failed to delete HelmRepository", "name", hr.Name, "namespace", hr.Namespace) + // Continue with other deletions + } else { + logger.Info("deleted HelmRepository (no longer needed)", "name", hr.Name, "namespace", hr.Namespace) + } + } + } + + return nil +} + +func (r *PlatformReconciler) reconcileGitRepository(ctx context.Context) error { + logger := log.FromContext(ctx) + + // Define desired GitRepository + desiredGR := &sourcev1.GitRepository{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cozystack", + Namespace: "cozy-system", + Labels: map[string]string{ + platformOperatorLabel: "true", }, }, - { - name: "cozystack-apps", - namespace: "cozy-public", - url: "http://cozystack.cozy-system.svc/repos/apps", - labels: map[string]string{ - "cozystack.io/ui": "true", - "cozystack.io/repository": "apps", - }, - }, - { - name: "cozystack-extra", - namespace: "cozy-public", - url: "http://cozystack.cozy-system.svc/repos/extra", - labels: map[string]string{ - "cozystack.io/repository": "extra", + Spec: sourcev1.GitRepositorySpec{ + URL: "https://github.com/cozystack/cozystack.git", + Interval: metav1.Duration{Duration: 1 * 60 * 1000000000}, // 1m + Timeout: &metav1.Duration{Duration: 60 * 1000000000}, // 60s + Reference: &sourcev1.GitRepositoryRef{ + Tag: "v0.38.0-alpha.2", }, + Ignore: func() *string { + ignore := `# exclude all +/* +# include packages dir +!/packages` + return &ignore + }(), }, } - for _, repo := range repos { - hr := &sourcev1.HelmRepository{ - ObjectMeta: metav1.ObjectMeta{ - Name: repo.name, - Namespace: repo.namespace, - Labels: repo.labels, - }, - Spec: sourcev1.HelmRepositorySpec{ - URL: repo.url, - Interval: metav1.Duration{Duration: 5 * 60 * 1000000000}, // 5m + // Create or update desired GitRepository + if err := r.CreateOrUpdate(ctx, desiredGR); err != nil { + logger.Error(err, "failed to reconcile GitRepository") + return err + } + logger.Info("reconciled GitRepository", "name", "cozystack") + + // List all GitRepositories managed by this operator and delete unwanted ones + grList := &sourcev1.GitRepositoryList{} + if err := r.List(ctx, grList, client.MatchingLabels{ + platformOperatorLabel: "true", + }); err != nil { + return fmt.Errorf("failed to list GitRepositories: %w", err) + } + + for _, gr := range grList.Items { + key := types.NamespacedName{Name: gr.Name, Namespace: gr.Namespace} + desiredKey := types.NamespacedName{Name: desiredGR.Name, Namespace: desiredGR.Namespace} + if key != desiredKey { + // Not desired, delete it + if err := r.Delete(ctx, &gr); err != nil { + if apierrors.IsNotFound(err) { + continue + } + logger.Error(err, "failed to delete GitRepository", "name", gr.Name, "namespace", gr.Namespace) + // Continue with other deletions + } else { + logger.Info("deleted GitRepository (not in desired state)", "name", gr.Name, "namespace", gr.Namespace) + } + } + } + + return nil +} + +func (r *PlatformReconciler) reconcileArtifactGenerators(ctx context.Context) error { + logger := log.FromContext(ctx) + + // Packages that use cozy-lib + packagesWithCozyLib := map[string]bool{ + "bootbox": true, "bucket": true, "clickhouse": true, "etcd": true, + "ferretdb": true, "foundationdb": true, "http-cache": true, "info": true, + "ingress": true, "kafka": true, "kubernetes": true, "monitoring": true, + "mysql": true, "nats": true, "postgres": true, "rabbitmq": true, + "redis": true, "seaweedfs": true, "tcp-balancer": true, "tenant": true, + "virtual-machine": true, "vm-disk": true, "vm-instance": true, + "vpc": true, "vpn": true, + } + + // System packages + systemPackages := []string{ + "bootbox", "bucket", "capi-operator", "capi-providers-bootstrap", + "capi-providers-core", "capi-providers-cpprovider", "capi-providers-infraprovider", + "cert-manager", "cert-manager-crds", "cert-manager-issuers", "cilium", + "cilium-networkpolicy", "clickhouse-operator", "coredns", "cozy-proxy", + "cozystack-api", "cozystack-controller", "cozystack-resource-definition-crd", + "cozystack-resource-definitions", "dashboard", "etcd-operator", "external-dns", + "external-secrets-operator", "fluxcd", "fluxcd-operator", "foundationdb-operator", + "gateway-api-crds", "goldpinger", "gpu-operator", "grafana-operator", + "hetzner-robotlb", "ingress-nginx", "kafka-operator", "kamaji", + "keycloak", "keycloak-configure", "keycloak-operator", "kubeovn", + "kubeovn-plunger", "kubeovn-webhook", "kubevirt", "kubevirt-cdi", + "kubevirt-cdi-operator", "kubevirt-csi-node", "kubevirt-instancetypes", + "kubevirt-operator", "lineage-controller-webhook", "linstor", "mariadb-operator", + "metallb", "monitoring-agents", "multus", "nats", "nfs-driver", + "objectstorage-controller", "opencost", "piraeus-operator", "postgres-operator", + "rabbitmq-operator", "redis-operator", "reloader", "seaweedfs", + "snapshot-controller", "telepresence", "velero", "vertical-pod-autoscaler", + "vertical-pod-autoscaler-crds", "victoria-metrics-operator", "vsnap-crd", + } + + // Apps packages + appsPackages := []string{ + "bucket", "clickhouse", "ferretdb", "foundationdb", "http-cache", + "kafka", "kubernetes", "mysql", "nats", "postgres", "rabbitmq", + "redis", "tcp-balancer", "tenant", "virtual-machine", "vm-disk", + "vm-instance", "vpc", "vpn", + } + + // Extra packages + extraPackages := []string{ + "bootbox", "etcd", "info", "ingress", "monitoring", "seaweedfs", + } + + // Define desired ArtifactGenerators + desiredAGs := []struct { + name string + namespace string + packages []string + }{ + {"system", "cozy-system", systemPackages}, + {"apps", "cozy-public", appsPackages}, + {"extra", "cozy-public", extraPackages}, + } + + // Create or update desired ArtifactGenerators + for _, ag := range desiredAGs { + if err := r.reconcileArtifactGenerator(ctx, ag.name, ag.namespace, ag.packages, packagesWithCozyLib); err != nil { + logger.Error(err, "failed to reconcile ArtifactGenerator", "name", ag.name) + return err + } + } + + // List all ArtifactGenerators managed by this operator and delete unwanted ones + agList := &sourcewatcherv1beta1.ArtifactGeneratorList{} + if err := r.List(ctx, agList, client.MatchingLabels{ + platformOperatorLabel: "true", + }); err != nil { + // If CRD doesn't exist, just log and continue + logger.Info("ArtifactGenerator CRD may not exist, skipping cleanup", "error", err) + } else { + // Build desired map + desiredMap := make(map[types.NamespacedName]bool) + for _, ag := range desiredAGs { + key := types.NamespacedName{Name: ag.name, Namespace: ag.namespace} + desiredMap[key] = true + } + + // Delete unwanted ArtifactGenerators + for _, item := range agList.Items { + key := types.NamespacedName{Name: item.Name, Namespace: item.Namespace} + if !desiredMap[key] { + // Not desired, delete it + if err := r.Delete(ctx, &item); err != nil { + if apierrors.IsNotFound(err) { + continue + } + logger.Error(err, "failed to delete ArtifactGenerator", "name", item.Name, "namespace", item.Namespace) + // Continue with other deletions + } else { + logger.Info("deleted ArtifactGenerator (not in desired state)", "name", item.Name, "namespace", item.Namespace) + } + } + } + } + + return nil +} + +func (r *PlatformReconciler) reconcileArtifactGenerator(ctx context.Context, name, namespace string, packages []string, packagesWithCozyLib map[string]bool) error { + logger := log.FromContext(ctx) + + // Build output artifacts + outputArtifacts := []sourcewatcherv1beta1.OutputArtifact{} + for _, pkg := range packages { + copyOps := []sourcewatcherv1beta1.CopyOperation{ + { + From: fmt.Sprintf("@cozystack/packages/%s/%s/**", name, pkg), + To: fmt.Sprintf("@artifact/%s/", pkg), }, } - if err := r.CreateOrUpdate(ctx, hr); err != nil { - logger.Error(err, "failed to reconcile HelmRepository", "name", repo.name, "namespace", repo.namespace) - return err + // Add cozy-lib if package uses it + if packagesWithCozyLib[pkg] { + copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ + From: "@cozystack/packages/library/cozy-lib/**", + To: fmt.Sprintf("@artifact/%s/charts/cozy-lib/", pkg), + }) } - logger.Info("reconciled HelmRepository", "name", repo.name, "namespace", repo.namespace) + + outputArtifacts = append(outputArtifacts, sourcewatcherv1beta1.OutputArtifact{ + Name: fmt.Sprintf("%s-%s", name, pkg), + Copy: copyOps, + }) + } + + // Define desired ArtifactGenerator + ag := &sourcewatcherv1beta1.ArtifactGenerator{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + Labels: map[string]string{ + platformOperatorLabel: "true", + }, + }, + Spec: sourcewatcherv1beta1.ArtifactGeneratorSpec{ + Sources: []sourcewatcherv1beta1.SourceReference{ + { + Alias: "cozystack", + Kind: "GitRepository", + Name: "cozystack", + Namespace: "cozy-system", + }, + }, + OutputArtifacts: outputArtifacts, + }, + } + + // Get existing resource to preserve resourceVersion + existing := &sourcewatcherv1beta1.ArtifactGenerator{} + key := client.ObjectKey{Name: name, Namespace: namespace} + if err := r.Get(ctx, key, existing); err == nil { + ag.SetResourceVersion(existing.GetResourceVersion()) + // Merge labels and annotations + labels := ag.GetLabels() + if labels == nil { + labels = make(map[string]string) + } + for k, v := range existing.GetLabels() { + if _, ok := labels[k]; !ok { + labels[k] = v + } + } + ag.SetLabels(labels) + + annotations := ag.GetAnnotations() + if annotations == nil { + annotations = make(map[string]string) + } + for k, v := range existing.GetAnnotations() { + if _, ok := annotations[k]; !ok { + annotations[k] = v + } + } + ag.SetAnnotations(annotations) + + if err := r.Update(ctx, ag); err != nil { + return fmt.Errorf("failed to update ArtifactGenerator: %w", err) + } + logger.Info("updated ArtifactGenerator", "name", name, "namespace", namespace) + } else if apierrors.IsNotFound(err) { + if err := r.Create(ctx, ag); err != nil { + return fmt.Errorf("failed to create ArtifactGenerator: %w", err) + } + logger.Info("created ArtifactGenerator", "name", name, "namespace", namespace) + } else { + return fmt.Errorf("failed to get ArtifactGenerator: %w", err) } return nil @@ -231,7 +515,7 @@ func (r *PlatformReconciler) reconcileNamespaces(ctx context.Context, cfg *confi namespacesMap["cozy-system"] = true namespacesMap["cozy-public"] = false - // Create/update all namespaces + // Create/update all desired namespaces for nsName, privileged := range namespacesMap { namespace := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -256,6 +540,34 @@ func (r *PlatformReconciler) reconcileNamespaces(ctx context.Context, cfg *confi logger.Info("reconciled Namespace", "name", nsName, "privileged", privileged) } + // List all namespaces managed by this operator and delete unwanted ones + nsList := &corev1.NamespaceList{} + if err := r.List(ctx, nsList, client.MatchingLabels{ + "cozystack.io/system": "true", + }); err != nil { + return fmt.Errorf("failed to list namespaces: %w", err) + } + + for _, ns := range nsList.Items { + // Skip tenant-root as it's managed separately + if ns.Name == "tenant-root" { + continue + } + + if _, ok := namespacesMap[ns.Name]; !ok { + // Not desired, delete it + if err := r.Delete(ctx, &ns); err != nil { + if apierrors.IsNotFound(err) { + continue + } + logger.Error(err, "failed to delete Namespace", "name", ns.Name) + // Continue with other deletions + } else { + logger.Info("deleted Namespace (not in desired state)", "name", ns.Name) + } + } + } + return nil } @@ -267,8 +579,8 @@ func (r *PlatformReconciler) reconcileTenantRoot(ctx context.Context, cfg *confi host = "example.org" } - // Reconcile tenant-root namespace - namespace := &corev1.Namespace{ + // Define desired tenant-root namespace + desiredNamespace := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: "tenant-root", Annotations: map[string]string{ @@ -282,13 +594,14 @@ func (r *PlatformReconciler) reconcileTenantRoot(ctx context.Context, cfg *confi }, } - if err := r.CreateOrUpdate(ctx, namespace); err != nil { + if err := r.CreateOrUpdate(ctx, desiredNamespace); err != nil { logger.Error(err, "failed to reconcile tenant-root Namespace") return err } + logger.Info("reconciled tenant-root Namespace") - // Reconcile tenant-root HelmRelease - hr := &helmv2.HelmRelease{ + // Define desired tenant-root HelmRelease + desiredHR := &helmv2.HelmRelease{ ObjectMeta: metav1.ObjectMeta{ Name: "tenant-root", Namespace: "tenant-root", @@ -326,12 +639,37 @@ func (r *PlatformReconciler) reconcileTenantRoot(ctx context.Context, cfg *confi }, } - if err := r.CreateOrUpdate(ctx, hr); err != nil { + if err := r.CreateOrUpdate(ctx, desiredHR); err != nil { logger.Error(err, "failed to reconcile tenant-root HelmRelease") return err } + logger.Info("reconciled tenant-root HelmRelease") + + // List all tenant-root HelmReleases and delete unwanted ones + hrList := &helmv2.HelmReleaseList{} + if err := r.List(ctx, hrList, client.InNamespace("tenant-root"), client.MatchingLabels{ + "cozystack.io/ui": "true", + }); err != nil { + return fmt.Errorf("failed to list tenant-root HelmReleases: %w", err) + } + + desiredHRKey := types.NamespacedName{Name: desiredHR.Name, Namespace: desiredHR.Namespace} + for _, hr := range hrList.Items { + key := types.NamespacedName{Name: hr.Name, Namespace: hr.Namespace} + if key != desiredHRKey { + // Not desired, delete it + if err := r.Delete(ctx, &hr); err != nil { + if apierrors.IsNotFound(err) { + continue + } + logger.Error(err, "failed to delete tenant-root HelmRelease", "name", hr.Name) + // Continue with other deletions + } else { + logger.Info("deleted tenant-root HelmRelease (not in desired state)", "name", hr.Name) + } + } + } - logger.Info("reconciled tenant-root") return nil } diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index f5521623..72ba2f9a 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:latest@sha256:b1d74a1f72a1264ddae87acee2c5f214de3233c313637392c0b34d6e607db881 + image: ghcr.io/cozystack/cozystack/installer:latest@sha256:a40c4e5216eee3a44936795df3ab2f3d62f321bd3262abe02c20c24972632a99 From 75197c6d25e2f1ee85423a329fb6bafbe32e4577 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 19 Nov 2025 00:41:09 +0100 Subject: [PATCH 05/46] Update apps to use ExternalArtifacts Signed-off-by: Andrei Kvapil --- .../cozystackresourcedefinitions_types.go | 14 +- api/v1alpha1/zz_generated.deepcopy.go | 27 +++- hack/update-crd.sh | 27 ++-- internal/lineagecontrollerwebhook/config.go | 32 ++++- .../lineagecontrollerwebhook/controller.go | 23 +++- internal/operator/reconciler.go | 37 +++-- .../apps/bucket/templates/helmrelease.yaml | 13 +- .../helmreleases/cert-manager-crds.yaml | 13 +- .../templates/helmreleases/cert-manager.yaml | 13 +- .../templates/helmreleases/cilium.yaml | 13 +- .../templates/helmreleases/coredns.yaml | 13 +- .../templates/helmreleases/csi.yaml | 13 +- .../templates/helmreleases/fluxcd.yaml | 26 ++-- .../helmreleases/gateway-api-crds.yaml | 13 +- .../templates/helmreleases/gpu-operator.yaml | 13 +- .../templates/helmreleases/ingress-nginx.yaml | 13 +- .../helmreleases/monitoring-agents.yaml | 13 +- .../templates/helmreleases/velero.yaml | 13 +- .../vertical-pod-autoscaler-crds.yaml | 13 +- .../helmreleases/vertical-pod-autoscaler.yaml | 13 +- .../victoria-metrics-operator.yaml | 13 +- .../helmreleases/volumesnapshot_crd.yaml | 13 +- packages/apps/nats/templates/nats.yaml | 13 +- packages/apps/tenant/templates/etcd.yaml | 13 +- packages/apps/tenant/templates/info.yaml | 13 +- packages/apps/tenant/templates/ingress.yaml | 13 +- .../apps/tenant/templates/monitoring.yaml | 13 +- packages/apps/tenant/templates/seaweedfs.yaml | 13 +- .../ingress/templates/nginx-ingress.yaml | 13 +- .../extra/seaweedfs/templates/seaweedfs.yaml | 13 +- ...stack.io_cozystackresourcedefinitions.yaml | 33 ++++- .../cozyrds/bootbox.yaml | 7 +- .../cozyrds/bucket.yaml | 7 +- .../cozyrds/clickhouse.yaml | 7 +- .../cozyrds/etcd.yaml | 7 +- .../cozyrds/ferretdb.yaml | 7 +- .../cozyrds/foundationdb.yaml | 9 +- .../cozyrds/http-cache.yaml | 7 +- .../cozyrds/info.yaml | 7 +- .../cozyrds/ingress.yaml | 7 +- .../cozyrds/kafka.yaml | 7 +- .../cozyrds/kubernetes.yaml | 7 +- .../cozyrds/monitoring.yaml | 7 +- .../cozyrds/mysql.yaml | 7 +- .../cozyrds/nats.yaml | 7 +- .../cozyrds/postgres.yaml | 7 +- .../cozyrds/rabbitmq.yaml | 7 +- .../cozyrds/redis.yaml | 7 +- .../cozyrds/seaweedfs.yaml | 7 +- .../cozyrds/tcp-balancer.yaml | 7 +- .../cozyrds/tenant.yaml | 7 +- .../cozyrds/virtual-machine.yaml | 7 +- .../cozyrds/virtualprivatecloud.yaml | 7 +- .../cozyrds/vm-disk.yaml | 7 +- .../cozyrds/vm-instance.yaml | 7 +- .../cozyrds/vpn.yaml | 7 +- pkg/config/apiserver.go | 14 +- pkg/generated/openapi/zz_generated.openapi.go | 49 ++++++- pkg/registry/apps/application/rest.go | 129 ++++++++++++++---- 59 files changed, 485 insertions(+), 402 deletions(-) diff --git a/api/v1alpha1/cozystackresourcedefinitions_types.go b/api/v1alpha1/cozystackresourcedefinitions_types.go index b2baee85..6e71512d 100644 --- a/api/v1alpha1/cozystackresourcedefinitions_types.go +++ b/api/v1alpha1/cozystackresourcedefinitions_types.go @@ -90,15 +90,25 @@ type CozystackResourceDefinitionApplication struct { Singular string `json:"singular"` } +// +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" type CozystackResourceDefinitionRelease struct { - // Helm chart configuration - Chart CozystackResourceDefinitionChart `json:"chart"` + // Helm chart configuration (for HelmRepository source) + // +optional + Chart *CozystackResourceDefinitionChart `json:"chart,omitempty"` + // Chart reference configuration (for ExternalArtifact source) + // +optional + ChartRef *CozystackResourceDefinitionChartRef `json:"chartRef,omitempty"` // Labels for the release Labels map[string]string `json:"labels,omitempty"` // Prefix for the release name Prefix string `json:"prefix"` } +type CozystackResourceDefinitionChartRef struct { + // Source reference for the chart (ExternalArtifact) + SourceRef SourceRef `json:"sourceRef"` +} + // CozystackResourceDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support. // A resource matches this selector only if it satisfies ALL criteria: // - Label selector conditions (matchExpressions and matchLabels) diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 42cf4c4a..45b03556 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -82,6 +82,22 @@ func (in *CozystackResourceDefinitionChart) DeepCopy() *CozystackResourceDefinit return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CozystackResourceDefinitionChartRef) DeepCopyInto(out *CozystackResourceDefinitionChartRef) { + *out = *in + out.SourceRef = in.SourceRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionChartRef. +func (in *CozystackResourceDefinitionChartRef) DeepCopy() *CozystackResourceDefinitionChartRef { + if in == nil { + return nil + } + out := new(CozystackResourceDefinitionChartRef) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CozystackResourceDefinitionDashboard) DeepCopyInto(out *CozystackResourceDefinitionDashboard) { *out = *in @@ -153,7 +169,16 @@ func (in *CozystackResourceDefinitionList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CozystackResourceDefinitionRelease) DeepCopyInto(out *CozystackResourceDefinitionRelease) { *out = *in - out.Chart = in.Chart + if in.Chart != nil { + in, out := &in.Chart, &out.Chart + *out = new(CozystackResourceDefinitionChart) + **out = **in + } + if in.ChartRef != nil { + in, out := &in.ChartRef, &out.ChartRef + *out = new(CozystackResourceDefinitionChartRef) + **out = **in + } if in.Labels != nil { in, out := &in.Labels, &out.Labels *out = make(map[string]string, len(*in)) diff --git a/hack/update-crd.sh b/hack/update-crd.sh index 456bf842..4df190c5 100755 --- a/hack/update-crd.sh +++ b/hack/update-crd.sh @@ -54,15 +54,16 @@ fi # Base64 (portable: no -w / -b options) ICON_B64="$(base64 < "$ICON_PATH" | tr -d '\n' | tr -d '\r')" -# Decide which HelmRepository name to use based on path -# .../apps/... -> cozystack-apps -# .../extra/... -> cozystack-extra -# default: cozystack-apps -SOURCE_NAME="cozystack-apps" +# Decide which ExternalArtifact name to use based on path +# .../apps/... -> apps- +# .../extra/... -> extra- +# default: apps- +ARTIFACT_PREFIX="apps" case "$PWD" in - *"/apps/"*) SOURCE_NAME="cozystack-apps" ;; - *"/extra/"*) SOURCE_NAME="cozystack-extra" ;; + *"/apps/"*) ARTIFACT_PREFIX="apps" ;; + *"/extra/"*) ARTIFACT_PREFIX="extra" ;; esac +ARTIFACT_NAME="${ARTIFACT_PREFIX}-${NAME}" # If file doesn't exist, create a minimal skeleton OUT="${OUT:-$CRD_DIR/$NAME.yaml}" @@ -79,12 +80,12 @@ fi # Export vars for yq env() export RES_NAME="$NAME" export PREFIX="$NAME-" -if [ "$SOURCE_NAME" == "cozystack-extra" ]; then +if [ "$ARTIFACT_PREFIX" == "extra" ]; then export PREFIX="" fi export DESCRIPTION="$DESC" export ICON_B64="$ICON_B64" -export SOURCE_NAME="$SOURCE_NAME" +export ARTIFACT_NAME="$ARTIFACT_NAME" export SCHEMA_JSON_MIN="$(jq -c . "$SCHEMA_JSON")" # Generate keysOrder from values.yaml @@ -127,10 +128,10 @@ yq -i ' (.spec.application.openAPISchema style="literal") | .spec.release.prefix = (strenv(PREFIX)) | .spec.release.labels."cozystack.io/ui" = "true" | - .spec.release.chart.name = strenv(RES_NAME) | - .spec.release.chart.sourceRef.kind = "HelmRepository" | - .spec.release.chart.sourceRef.name = strenv(SOURCE_NAME) | - .spec.release.chart.sourceRef.namespace = "cozy-public" | + del(.spec.release.chart) | + .spec.release.chartRef.sourceRef.kind = "ExternalArtifact" | + .spec.release.chartRef.sourceRef.name = strenv(ARTIFACT_NAME) | + .spec.release.chartRef.sourceRef.namespace = "cozy-public" | .spec.dashboard.description = strenv(DESCRIPTION) | .spec.dashboard.icon = strenv(ICON_B64) | .spec.dashboard.keysOrder = env(KEYS_ORDER) diff --git a/internal/lineagecontrollerwebhook/config.go b/internal/lineagecontrollerwebhook/config.go index 4ca45c13..dbf29df0 100644 --- a/internal/lineagecontrollerwebhook/config.go +++ b/internal/lineagecontrollerwebhook/config.go @@ -8,8 +8,14 @@ import ( ) type chartRef struct { + // For chart (HelmRepository): repo is SourceRef.Name, chart is Chart.Name + // For chartRef (ExternalArtifact): repo is empty, chart is SourceRef.Name repo string chart string + // isChartRef indicates if this is a chartRef (ExternalArtifact) reference + isChartRef bool + // namespace is used for chartRef (ExternalArtifact) + namespace string } type appRef struct { @@ -38,11 +44,29 @@ func (l *LineageControllerWebhook) Map(hr *helmv2.HelmRelease) (string, string, if !ok { return "", "", "", fmt.Errorf("failed to load chart-app mapping from config") } - if hr.Spec.Chart == nil { - return "", "", "", fmt.Errorf("cannot map helm release %s/%s to dynamic app", hr.Namespace, hr.Name) + + var chRef chartRef + if hr.Spec.Chart != nil { + // Using chart (HelmRepository) + s := hr.Spec.Chart.Spec + chRef = chartRef{ + repo: s.SourceRef.Name, + chart: s.Chart, + isChartRef: false, + } + } else if hr.Spec.ChartRef != nil { + // Using chartRef (ExternalArtifact) + chRef = chartRef{ + repo: "", + chart: hr.Spec.ChartRef.Name, + isChartRef: true, + namespace: hr.Spec.ChartRef.Namespace, + } + } else { + return "", "", "", fmt.Errorf("cannot map helm release %s/%s to dynamic app: neither chart nor chartRef is set", hr.Namespace, hr.Name) } - s := hr.Spec.Chart.Spec - val, ok := cfg.chartAppMap[chartRef{s.SourceRef.Name, s.Chart}] + + val, ok := cfg.chartAppMap[chRef] if !ok { return "", "", "", fmt.Errorf("cannot map helm release %s/%s to dynamic app", hr.Namespace, hr.Name) } diff --git a/internal/lineagecontrollerwebhook/controller.go b/internal/lineagecontrollerwebhook/controller.go index e7522f62..2441c601 100644 --- a/internal/lineagecontrollerwebhook/controller.go +++ b/internal/lineagecontrollerwebhook/controller.go @@ -28,10 +28,27 @@ func (c *LineageControllerWebhook) Reconcile(ctx context.Context, req ctrl.Reque appCRDMap: make(map[appRef]*cozyv1alpha1.CozystackResourceDefinition), } for _, crd := range crds.Items { - chRef := chartRef{ - crd.Spec.Release.Chart.SourceRef.Name, - crd.Spec.Release.Chart.Name, + var chRef chartRef + if crd.Spec.Release.Chart != nil { + // Using chart (HelmRepository) + chRef = chartRef{ + repo: crd.Spec.Release.Chart.SourceRef.Name, + chart: crd.Spec.Release.Chart.Name, + isChartRef: false, + } + } else if crd.Spec.Release.ChartRef != nil { + // Using chartRef (ExternalArtifact) + chRef = chartRef{ + repo: "", + chart: crd.Spec.Release.ChartRef.SourceRef.Name, + isChartRef: true, + namespace: crd.Spec.Release.ChartRef.SourceRef.Namespace, + } + } else { + l.Info("CozystackResourceDefinition has neither chart nor chartRef, skipping", "name", crd.Name) + continue } + appRef := appRef{ "apps.cozystack.io", crd.Spec.Application.Kind, diff --git a/internal/operator/reconciler.go b/internal/operator/reconciler.go index 0cb1ebfc..5bbe2e01 100644 --- a/internal/operator/reconciler.go +++ b/internal/operator/reconciler.go @@ -718,17 +718,6 @@ func (r *PlatformReconciler) reconcileHelmReleases(ctx context.Context, cfg *con Spec: helmv2.HelmReleaseSpec{ Interval: metav1.Duration{Duration: 5 * 60 * 1000000000}, // 5m ReleaseName: release.ReleaseName, - Chart: &helmv2.HelmChartTemplate{ - Spec: helmv2.HelmChartTemplateSpec{ - Chart: release.Chart, - Version: ">= 0.0.0-0", - SourceRef: helmv2.CrossNamespaceObjectReference{ - Kind: "HelmRepository", - Name: "cozystack-system", - Namespace: "cozy-system", - }, - }, - }, Install: &helmv2.Install{ Remediation: &helmv2.InstallRemediation{ Retries: -1, @@ -742,6 +731,32 @@ func (r *PlatformReconciler) reconcileHelmReleases(ctx context.Context, cfg *con }, } + // Determine if this is a system resource (installed in cozy-system namespace) + // System resources use chartRef (ExternalArtifact), others use Chart (HelmRepository) + if release.Namespace == "cozy-system" { + // System resource: use chartRef with ExternalArtifact + // Artifact name format: system-{chart-name} + artifactName := fmt.Sprintf("system-%s", release.Chart) + hr.Spec.ChartRef = &helmv2.CrossNamespaceSourceReference{ + Kind: "ExternalArtifact", + Name: artifactName, + Namespace: "cozy-system", + } + } else { + // Non-system resource: use Chart with HelmRepository + hr.Spec.Chart = &helmv2.HelmChartTemplate{ + Spec: helmv2.HelmChartTemplateSpec{ + Chart: release.Chart, + Version: ">= 0.0.0-0", + SourceRef: helmv2.CrossNamespaceObjectReference{ + Kind: "HelmRepository", + Name: "cozystack-system", + Namespace: "cozy-system", + }, + }, + } + } + // Set values if provided if len(release.Values) > 0 { valuesJSON, err := json.Marshal(release.Values) diff --git a/packages/apps/bucket/templates/helmrelease.yaml b/packages/apps/bucket/templates/helmrelease.yaml index 45959572..4255b21d 100644 --- a/packages/apps/bucket/templates/helmrelease.yaml +++ b/packages/apps/bucket/templates/helmrelease.yaml @@ -3,15 +3,10 @@ kind: HelmRelease metadata: name: {{ .Release.Name }}-system spec: - chart: - spec: - chart: cozy-bucket - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-bucket + namespace: cozy-system interval: 5m timeout: 10m install: diff --git a/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml b/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml index 3bf7a5d2..4ebc1212 100644 --- a/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml @@ -8,15 +8,10 @@ metadata: cozystack.io/target-cluster-name: {{ .Release.Name }} spec: releaseName: cert-manager-crds - chart: - spec: - chart: cozy-cert-manager-crds - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-cert-manager-crds + namespace: cozy-system kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml b/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml index e0caf4cb..e2f67d08 100644 --- a/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml @@ -8,15 +8,10 @@ metadata: cozystack.io/target-cluster-name: {{ .Release.Name }} spec: releaseName: cert-manager - chart: - spec: - chart: cozy-cert-manager - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-cert-manager + namespace: cozy-system kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/cilium.yaml b/packages/apps/kubernetes/templates/helmreleases/cilium.yaml index c356dc79..6a549f17 100644 --- a/packages/apps/kubernetes/templates/helmreleases/cilium.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/cilium.yaml @@ -22,15 +22,10 @@ metadata: cozystack.io/target-cluster-name: {{ .Release.Name }} spec: releaseName: cilium - chart: - spec: - chart: cozy-cilium - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-cilium + namespace: cozy-system kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/coredns.yaml b/packages/apps/kubernetes/templates/helmreleases/coredns.yaml index 37a09a0b..3629d881 100644 --- a/packages/apps/kubernetes/templates/helmreleases/coredns.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/coredns.yaml @@ -13,15 +13,10 @@ metadata: cozystack.io/target-cluster-name: {{ .Release.Name }} spec: releaseName: coredns - chart: - spec: - chart: cozy-coredns - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-coredns + namespace: cozy-system kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/csi.yaml b/packages/apps/kubernetes/templates/helmreleases/csi.yaml index 09927e8a..8c389337 100644 --- a/packages/apps/kubernetes/templates/helmreleases/csi.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/csi.yaml @@ -8,15 +8,10 @@ metadata: spec: interval: 5m releaseName: csi - chart: - spec: - chart: cozy-kubevirt-csi-node - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-kubevirt-csi-node + namespace: cozy-system kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml b/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml index 7518601b..5e091323 100644 --- a/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml @@ -8,15 +8,10 @@ metadata: cozystack.io/target-cluster-name: {{ .Release.Name }} spec: releaseName: fluxcd-operator - chart: - spec: - chart: cozy-fluxcd-operator - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-fluxcd-operator + namespace: cozy-system kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig @@ -56,15 +51,10 @@ metadata: spec: interval: 5m releaseName: fluxcd - chart: - spec: - chart: cozy-fluxcd - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-fluxcd + namespace: cozy-system kubeConfig: secretRef: name: {{ .Release.Name }}-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml b/packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml index 48a20c5a..b847e0fc 100644 --- a/packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml @@ -8,15 +8,10 @@ metadata: cozystack.io/target-cluster-name: {{ .Release.Name }} spec: releaseName: gateway-api-crds - chart: - spec: - chart: cozy-gateway-api-crds - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-gateway-api-crds + namespace: cozy-system kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml b/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml index fbee1724..3bbb6590 100644 --- a/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml @@ -8,15 +8,10 @@ metadata: cozystack.io/target-cluster-name: {{ .Release.Name }} spec: releaseName: gpu-operator - chart: - spec: - chart: cozy-gpu-operator - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-gpu-operator + namespace: cozy-system kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml b/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml index f80dd7ae..1f43f4fb 100644 --- a/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml @@ -27,15 +27,10 @@ metadata: cozystack.io/target-cluster-name: {{ .Release.Name }} spec: releaseName: ingress-nginx - chart: - spec: - chart: cozy-ingress-nginx - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-ingress-nginx + namespace: cozy-system kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml b/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml index 8f914b08..45ebd4b4 100644 --- a/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml @@ -10,15 +10,10 @@ metadata: cozystack.io/target-cluster-name: {{ .Release.Name }} spec: releaseName: cozy-monitoring-agents - chart: - spec: - chart: cozy-monitoring-agents - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-monitoring-agents + namespace: cozy-system kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/velero.yaml b/packages/apps/kubernetes/templates/helmreleases/velero.yaml index 0c918da6..fa410f1e 100644 --- a/packages/apps/kubernetes/templates/helmreleases/velero.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/velero.yaml @@ -8,15 +8,10 @@ metadata: cozystack.io/target-cluster-name: {{ .Release.Name }} spec: releaseName: velero - chart: - spec: - chart: cozy-velero - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-velero + namespace: cozy-system kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml index 336c198b..96dbb46f 100644 --- a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml @@ -9,15 +9,10 @@ metadata: spec: interval: 5m releaseName: vertical-pod-autoscaler-crds - chart: - spec: - chart: cozy-vertical-pod-autoscaler-crds - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-vertical-pod-autoscaler-crds + namespace: cozy-system kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml index 8b615c9c..02a413c6 100644 --- a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml @@ -36,15 +36,10 @@ metadata: cozystack.io/target-cluster-name: {{ .Release.Name }} spec: releaseName: vertical-pod-autoscaler - chart: - spec: - chart: cozy-vertical-pod-autoscaler - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-vertical-pod-autoscaler + namespace: cozy-system kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml b/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml index dbb4d8dc..ac75530a 100644 --- a/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml @@ -8,15 +8,10 @@ metadata: cozystack.io/target-cluster-name: {{ .Release.Name }} spec: releaseName: cozy-victoria-metrics-operator - chart: - spec: - chart: cozy-victoria-metrics-operator - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-victoria-metrics-operator + namespace: cozy-system kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/volumesnapshot_crd.yaml b/packages/apps/kubernetes/templates/helmreleases/volumesnapshot_crd.yaml index 97cf06ad..5dace0fd 100644 --- a/packages/apps/kubernetes/templates/helmreleases/volumesnapshot_crd.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/volumesnapshot_crd.yaml @@ -7,15 +7,10 @@ metadata: cozystack.io/target-cluster-name: {{ .Release.Name }} spec: releaseName: vsnap-crd - chart: - spec: - chart: cozy-vsnap-crd - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-vsnap-crd + namespace: cozy-system kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/nats/templates/nats.yaml b/packages/apps/nats/templates/nats.yaml index b05c87b5..050411f8 100644 --- a/packages/apps/nats/templates/nats.yaml +++ b/packages/apps/nats/templates/nats.yaml @@ -35,15 +35,10 @@ kind: HelmRelease metadata: name: {{ .Release.Name }}-system spec: - chart: - spec: - chart: cozy-nats - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-nats + namespace: cozy-system interval: 5m timeout: 10m install: diff --git a/packages/apps/tenant/templates/etcd.yaml b/packages/apps/tenant/templates/etcd.yaml index 9db6ff6c..c06ff936 100644 --- a/packages/apps/tenant/templates/etcd.yaml +++ b/packages/apps/tenant/templates/etcd.yaml @@ -10,15 +10,10 @@ metadata: app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} spec: - chart: - spec: - chart: etcd - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: extra-etcd + namespace: cozy-public interval: 5m timeout: 10m install: diff --git a/packages/apps/tenant/templates/info.yaml b/packages/apps/tenant/templates/info.yaml index 4b6f2640..6b505de0 100644 --- a/packages/apps/tenant/templates/info.yaml +++ b/packages/apps/tenant/templates/info.yaml @@ -9,15 +9,10 @@ metadata: app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} spec: - chart: - spec: - chart: info - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: extra-info + namespace: cozy-public interval: 5m timeout: 10m install: diff --git a/packages/apps/tenant/templates/ingress.yaml b/packages/apps/tenant/templates/ingress.yaml index b866300f..f82a393a 100644 --- a/packages/apps/tenant/templates/ingress.yaml +++ b/packages/apps/tenant/templates/ingress.yaml @@ -10,15 +10,10 @@ metadata: app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} spec: - chart: - spec: - chart: ingress - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: extra-ingress + namespace: cozy-public interval: 5m timeout: 10m install: diff --git a/packages/apps/tenant/templates/monitoring.yaml b/packages/apps/tenant/templates/monitoring.yaml index edcc66d9..64d4e0bc 100644 --- a/packages/apps/tenant/templates/monitoring.yaml +++ b/packages/apps/tenant/templates/monitoring.yaml @@ -10,15 +10,10 @@ metadata: app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} spec: - chart: - spec: - chart: monitoring - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: extra-monitoring + namespace: cozy-public interval: 5m timeout: 10m install: diff --git a/packages/apps/tenant/templates/seaweedfs.yaml b/packages/apps/tenant/templates/seaweedfs.yaml index 936e294b..20792845 100644 --- a/packages/apps/tenant/templates/seaweedfs.yaml +++ b/packages/apps/tenant/templates/seaweedfs.yaml @@ -10,15 +10,10 @@ metadata: app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} spec: - chart: - spec: - chart: seaweedfs - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: extra-seaweedfs + namespace: cozy-public interval: 5m timeout: 10m install: diff --git a/packages/extra/ingress/templates/nginx-ingress.yaml b/packages/extra/ingress/templates/nginx-ingress.yaml index faa0b061..d15e00f4 100644 --- a/packages/extra/ingress/templates/nginx-ingress.yaml +++ b/packages/extra/ingress/templates/nginx-ingress.yaml @@ -6,15 +6,10 @@ kind: HelmRelease metadata: name: ingress-nginx-system spec: - chart: - spec: - chart: cozy-ingress-nginx - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-ingress-nginx + namespace: cozy-system interval: 5m timeout: 10m install: diff --git a/packages/extra/seaweedfs/templates/seaweedfs.yaml b/packages/extra/seaweedfs/templates/seaweedfs.yaml index 02bac375..303f4f34 100644 --- a/packages/extra/seaweedfs/templates/seaweedfs.yaml +++ b/packages/extra/seaweedfs/templates/seaweedfs.yaml @@ -42,15 +42,10 @@ kind: HelmRelease metadata: name: {{ .Release.Name }}-system spec: - chart: - spec: - chart: cozy-seaweedfs - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-cozy-seaweedfs + namespace: cozy-system interval: 5m timeout: 10m install: diff --git a/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml b/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml index 685d4ac5..91cfb7ec 100644 --- a/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml +++ b/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml @@ -297,7 +297,7 @@ spec: description: Release configuration properties: chart: - description: Helm chart configuration + description: Helm chart configuration (for HelmRepository source) properties: name: description: Name of the Helm chart @@ -325,6 +325,32 @@ spec: - name - sourceRef type: object + chartRef: + description: Chart reference configuration (for ExternalArtifact + source) + properties: + sourceRef: + description: Source reference for the chart (ExternalArtifact) + properties: + kind: + default: HelmRepository + description: Kind of the source reference + type: string + name: + description: Name of the source reference + type: string + namespace: + default: cozy-public + description: Namespace of the source reference + type: string + required: + - kind + - name + - namespace + type: object + required: + - sourceRef + type: object labels: additionalProperties: type: string @@ -334,9 +360,12 @@ spec: description: Prefix for the release name type: string required: - - chart - prefix type: object + x-kubernetes-validations: + - message: either chart or chartRef must be set, but not both + rule: (has(self.chart) && !has(self.chartRef)) || (!has(self.chart) + && has(self.chartRef)) secrets: description: Secret selectors properties: diff --git a/packages/system/cozystack-resource-definitions/cozyrds/bootbox.yaml b/packages/system/cozystack-resource-definitions/cozyrds/bootbox.yaml index f47bf8f6..de09a66b 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/bootbox.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/bootbox.yaml @@ -13,11 +13,10 @@ spec: prefix: "" labels: cozystack.io/ui: "true" - chart: - name: bootbox + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-extra + kind: ExternalArtifact + name: extra-bootbox namespace: cozy-public dashboard: category: Administration diff --git a/packages/system/cozystack-resource-definitions/cozyrds/bucket.yaml b/packages/system/cozystack-resource-definitions/cozyrds/bucket.yaml index 889a36b5..0528a585 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/bucket.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/bucket.yaml @@ -13,11 +13,10 @@ spec: prefix: bucket- labels: cozystack.io/ui: "true" - chart: - name: bucket + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-apps + kind: ExternalArtifact + name: apps-bucket namespace: cozy-public dashboard: singular: Bucket diff --git a/packages/system/cozystack-resource-definitions/cozyrds/clickhouse.yaml b/packages/system/cozystack-resource-definitions/cozyrds/clickhouse.yaml index 6948fce0..c62f0ade 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/clickhouse.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/clickhouse.yaml @@ -13,11 +13,10 @@ spec: prefix: clickhouse- labels: cozystack.io/ui: "true" - chart: - name: clickhouse + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-apps + kind: ExternalArtifact + name: apps-clickhouse namespace: cozy-public dashboard: category: PaaS diff --git a/packages/system/cozystack-resource-definitions/cozyrds/etcd.yaml b/packages/system/cozystack-resource-definitions/cozyrds/etcd.yaml index 7381469d..2305c92b 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/etcd.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/etcd.yaml @@ -14,11 +14,10 @@ spec: labels: cozystack.io/ui: "true" internal.cozystack.io/tenantmodule: "true" - chart: - name: etcd + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-extra + kind: ExternalArtifact + name: extra-etcd namespace: cozy-public dashboard: category: Administration diff --git a/packages/system/cozystack-resource-definitions/cozyrds/ferretdb.yaml b/packages/system/cozystack-resource-definitions/cozyrds/ferretdb.yaml index f7bdeb82..1ec63ad2 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/ferretdb.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/ferretdb.yaml @@ -13,11 +13,10 @@ spec: prefix: ferretdb- labels: cozystack.io/ui: "true" - chart: - name: ferretdb + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-apps + kind: ExternalArtifact + name: apps-ferretdb namespace: cozy-public dashboard: category: PaaS diff --git a/packages/system/cozystack-resource-definitions/cozyrds/foundationdb.yaml b/packages/system/cozystack-resource-definitions/cozyrds/foundationdb.yaml index e7759380..f1739214 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/foundationdb.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/foundationdb.yaml @@ -13,11 +13,10 @@ spec: prefix: foundationdb- labels: cozystack.io/ui: "true" - chart: - name: foundationdb + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-apps + kind: ExternalArtifact + name: apps-foundationdb namespace: cozy-public dashboard: category: PaaS @@ -27,4 +26,4 @@ spec: tags: - database icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX3JhZGlhbF84NThfMzA3MikiLz4KPHBhdGggZD0iTTEzNS43ODQgNzUuNjQ0NkwxMzUuOTM5IDg3Ljc2MzhMODkuNjg0NiA4MS41MzYyTDYyLjA4NjggODQuNTA3OUwzNS4zNDE3IDgxLjQzMjlMOC43NTE2NyA4NC41ODU0TDguNzI1ODMgODEuNTEwNEwzNS4zNjc2IDc3LjU4MjZWNjQuMTcxM0w2Mi4yOTM1IDcwLjczNDhMNjIuMzQ1MiA4MS4yNzc4TDg5LjQ3NzkgNzcuNjg2TDg5LjQwMDQgNjQuMTk3MkwxMzUuNzg0IDc1LjY0NDZaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNODkuNDc3OCA4Ni4wMzI1TDEzNS44ODggOTAuODM4OFYxMDIuNzI2SDguNjQ4MjVMOC41MTkwNCA5OS41NzNIMzUuMjY0MUMzNS4yNjQxIDk5LjU3MyAzNS4yNjQxIDkwLjczNTUgMzUuMjY0MSA4Ni4wNTgzQzQ0LjI1NjcgODYuOTM2OSA2Mi4wODY3IDg4LjY5NDEgNjIuMDg2NyA4OC42OTQxVjk5LjI2MjlIODkuNDc3OFY4Ni4wMzI1WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTYyLjI5MzQgNjYuODg0Nkw2Mi4yMTU4IDYzLjYyODZDNjIuMjE1OCA2My42Mjg2IDc5LjgxMzMgNTguMzU3MSA4OC45MDkyIDU1LjY2OTdDODguOTA5MiA1MS4zMDI2IDg4LjkwOTIgNDcuMDkwNiA4OC45MDkyIDQyQzEwNC44NzkgNDguNDA4NSAxMjAuMjI4IDU0LjYxMDIgMTM1LjczMyA2MC44Mzc4QzEzNS43MzMgNjQuNzEzOSAxMzUuNzMzIDY4LjQzNSAxMzUuNzMzIDcyLjU2OTVDMTE5Ljg0MSA2OC4yMDI0IDEwNC4yODQgNjMuOTEyOSA4OS4xNjc2IDU5Ljc1MjVDNzkuOTY4NCA2Mi4yMDc0IDYyLjI5MzQgNjYuODg0NiA2Mi4yOTM0IDY2Ljg4NDZaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMzUuMzk2MiA4MS43MDczTDguODA2MTIgODQuODU5OEw4Ljc4MDI3IDgxLjc4NDhMMzUuNDIyIDc3Ljg1N1Y2NC40NDU3TDYyLjM0OCA3MS4wMDkzTDYyLjM5OTYgODEuNTUyMkw4OS41MzIzIDc3Ljk2MDRMODkuNDU0OCA2NC40NzE2TDEzNS44MzkgNzUuOTE5TDEzNS45OTQgODguMDM4Mkw4OS43MzkxIDgxLjgxMDZMNjIuMTQxMiA4NC43ODIzTDM1LjM5NjIgODEuNzA3M1oiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik04OS41MzIzIDg2LjMwNjlMMTM1Ljk0MiA5MS4xMTMzVjEwM0g4LjcwMjdMOC41NzM0OSA5OS44NDc0SDM1LjMxODZDMzUuMzE4NiA5OS44NDc0IDM1LjMxODYgOTEuMDA5OSAzNS4zMTg2IDg2LjMzMjhDNDQuMzExMSA4Ny4yMTE0IDYyLjE0MTIgODguOTY4NSA2Mi4xNDEyIDg4Ljk2ODVWOTkuNTM3M0g4OS41MzIzVjg2LjMwNjlaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNNjIuMzQ4MyA2Ny4xNTlMNjIuMjcwOCA2My45MDMxQzYyLjI3MDggNjMuOTAzMSA3OS44NjgyIDU4LjYzMTYgODguOTY0MiA1NS45NDQyQzg4Ljk2NDIgNTEuNTc3MSA4OC45NjQyIDQ3LjM2NTEgODguOTY0MiA0Mi4yNzQ0QzEwNC45MzQgNDguNjgyOSAxMjAuMjgzIDU0Ljg4NDcgMTM1Ljc4NyA2MS4xMTIzQzEzNS43ODcgNjQuOTg4NCAxMzUuNzg3IDY4LjcwOTQgMTM1Ljc4NyA3Mi44NDM5QzExOS44OTUgNjguNDc2OSAxMDQuMzM5IDY0LjE4NzMgODkuMjIyNiA2MC4wMjdDODAuMDIzMyA2Mi40ODE4IDYyLjM0ODMgNjcuMTU5IDYyLjM0ODMgNjcuMTU5WiIgZmlsbD0id2hpdGUiLz4KPGRlZnM+CjxyYWRpYWxHcmFkaWVudCBpZD0icGFpbnQwX3JhZGlhbF84NThfMzA3MiIgY3g9IjAiIGN5PSIwIiByPSIxIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgtMjkuNSAtMTgpIHJvdGF0ZSgzOS42OTYzKSBzY2FsZSgzMDIuMTY4IDI3NS4yNzEpIj4KPHN0b3Agc3RvcC1jb2xvcj0iI0JFRERGRiIvPgo8c3RvcCBvZmZzZXQ9IjAuMjU5NjE1IiBzdG9wLWNvbG9yPSIjOUVDQ0ZEIi8+CjxzdG9wIG9mZnNldD0iMC41OTEzNDYiIHN0b3AtY29sb3I9IiMzRjlBRkIiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMEI3MEUwIi8+CjwvcmFkaWFsR3JhZGllbnQ+CjwvZGVmcz4KPC9zdmc+Cg== - # keysOrder: [] + # keysOrder: [] diff --git a/packages/system/cozystack-resource-definitions/cozyrds/http-cache.yaml b/packages/system/cozystack-resource-definitions/cozyrds/http-cache.yaml index 70de0418..f71126dd 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/http-cache.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/http-cache.yaml @@ -13,11 +13,10 @@ spec: prefix: http-cache- labels: cozystack.io/ui: "true" - chart: - name: http-cache + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-apps + kind: ExternalArtifact + name: apps-http-cache namespace: cozy-public dashboard: category: NaaS diff --git a/packages/system/cozystack-resource-definitions/cozyrds/info.yaml b/packages/system/cozystack-resource-definitions/cozyrds/info.yaml index 43cda091..1eece36b 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/info.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/info.yaml @@ -14,11 +14,10 @@ spec: labels: cozystack.io/ui: "true" internal.cozystack.io/tenantmodule: "true" - chart: - name: info + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-extra + kind: ExternalArtifact + name: extra-info namespace: cozy-public dashboard: name: info diff --git a/packages/system/cozystack-resource-definitions/cozyrds/ingress.yaml b/packages/system/cozystack-resource-definitions/cozyrds/ingress.yaml index 2e00f6ed..ceb7dc62 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/ingress.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/ingress.yaml @@ -14,11 +14,10 @@ spec: labels: cozystack.io/ui: "true" internal.cozystack.io/tenantmodule: "true" - chart: - name: ingress + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-extra + kind: ExternalArtifact + name: extra-ingress namespace: cozy-public dashboard: category: Administration diff --git a/packages/system/cozystack-resource-definitions/cozyrds/kafka.yaml b/packages/system/cozystack-resource-definitions/cozyrds/kafka.yaml index 7009d241..8e251f2e 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/kafka.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/kafka.yaml @@ -13,11 +13,10 @@ spec: prefix: kafka- labels: cozystack.io/ui: "true" - chart: - name: kafka + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-apps + kind: ExternalArtifact + name: apps-kafka namespace: cozy-public dashboard: category: PaaS diff --git a/packages/system/cozystack-resource-definitions/cozyrds/kubernetes.yaml b/packages/system/cozystack-resource-definitions/cozyrds/kubernetes.yaml index 86e8694d..ed13ad84 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/kubernetes.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/kubernetes.yaml @@ -13,11 +13,10 @@ spec: prefix: kubernetes- labels: cozystack.io/ui: "true" - chart: - name: kubernetes + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-apps + kind: ExternalArtifact + name: apps-kubernetes namespace: cozy-public dashboard: category: IaaS diff --git a/packages/system/cozystack-resource-definitions/cozyrds/monitoring.yaml b/packages/system/cozystack-resource-definitions/cozyrds/monitoring.yaml index 520e4671..c1aec607 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/monitoring.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/monitoring.yaml @@ -14,11 +14,10 @@ spec: labels: cozystack.io/ui: "true" internal.cozystack.io/tenantmodule: "true" - chart: - name: monitoring + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-extra + kind: ExternalArtifact + name: extra-monitoring namespace: cozy-public dashboard: category: Administration diff --git a/packages/system/cozystack-resource-definitions/cozyrds/mysql.yaml b/packages/system/cozystack-resource-definitions/cozyrds/mysql.yaml index 142b55b1..f0bcce8e 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/mysql.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/mysql.yaml @@ -13,11 +13,10 @@ spec: prefix: mysql- labels: cozystack.io/ui: "true" - chart: - name: mysql + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-apps + kind: ExternalArtifact + name: apps-mysql namespace: cozy-public dashboard: category: PaaS diff --git a/packages/system/cozystack-resource-definitions/cozyrds/nats.yaml b/packages/system/cozystack-resource-definitions/cozyrds/nats.yaml index 258f8f40..97b46f9f 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/nats.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/nats.yaml @@ -13,11 +13,10 @@ spec: prefix: nats- labels: cozystack.io/ui: "true" - chart: - name: nats + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-apps + kind: ExternalArtifact + name: apps-nats namespace: cozy-public dashboard: category: PaaS diff --git a/packages/system/cozystack-resource-definitions/cozyrds/postgres.yaml b/packages/system/cozystack-resource-definitions/cozyrds/postgres.yaml index 010586fe..debb60f3 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/postgres.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/postgres.yaml @@ -13,11 +13,10 @@ spec: prefix: postgres- labels: cozystack.io/ui: "true" - chart: - name: postgres + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-apps + kind: ExternalArtifact + name: apps-postgres namespace: cozy-public dashboard: category: PaaS diff --git a/packages/system/cozystack-resource-definitions/cozyrds/rabbitmq.yaml b/packages/system/cozystack-resource-definitions/cozyrds/rabbitmq.yaml index 092142ac..f33584f2 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/rabbitmq.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/rabbitmq.yaml @@ -13,11 +13,10 @@ spec: prefix: rabbitmq- labels: cozystack.io/ui: "true" - chart: - name: rabbitmq + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-apps + kind: ExternalArtifact + name: apps-rabbitmq namespace: cozy-public dashboard: category: PaaS diff --git a/packages/system/cozystack-resource-definitions/cozyrds/redis.yaml b/packages/system/cozystack-resource-definitions/cozyrds/redis.yaml index 1c5131d3..984972cf 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/redis.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/redis.yaml @@ -13,11 +13,10 @@ spec: prefix: redis- labels: cozystack.io/ui: "true" - chart: - name: redis + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-apps + kind: ExternalArtifact + name: apps-redis namespace: cozy-public dashboard: category: PaaS diff --git a/packages/system/cozystack-resource-definitions/cozyrds/seaweedfs.yaml b/packages/system/cozystack-resource-definitions/cozyrds/seaweedfs.yaml index 787b5448..b39260f9 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/seaweedfs.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/seaweedfs.yaml @@ -14,11 +14,10 @@ spec: labels: cozystack.io/ui: "true" internal.cozystack.io/tenantmodule: "true" - chart: - name: seaweedfs + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-extra + kind: ExternalArtifact + name: extra-seaweedfs namespace: cozy-public dashboard: category: Administration diff --git a/packages/system/cozystack-resource-definitions/cozyrds/tcp-balancer.yaml b/packages/system/cozystack-resource-definitions/cozyrds/tcp-balancer.yaml index 057bc922..7297fcbf 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/tcp-balancer.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/tcp-balancer.yaml @@ -13,11 +13,10 @@ spec: prefix: tcp-balancer- labels: cozystack.io/ui: "true" - chart: - name: tcp-balancer + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-apps + kind: ExternalArtifact + name: apps-tcp-balancer namespace: cozy-public dashboard: category: NaaS diff --git a/packages/system/cozystack-resource-definitions/cozyrds/tenant.yaml b/packages/system/cozystack-resource-definitions/cozyrds/tenant.yaml index a5c497ac..53336d56 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/tenant.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/tenant.yaml @@ -13,11 +13,10 @@ spec: prefix: tenant- labels: cozystack.io/ui: "true" - chart: - name: tenant + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-apps + kind: ExternalArtifact + name: apps-tenant namespace: cozy-public dashboard: category: Administration diff --git a/packages/system/cozystack-resource-definitions/cozyrds/virtual-machine.yaml b/packages/system/cozystack-resource-definitions/cozyrds/virtual-machine.yaml index a1e384c4..2438d761 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/virtual-machine.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/virtual-machine.yaml @@ -13,11 +13,10 @@ spec: prefix: virtual-machine- labels: cozystack.io/ui: "true" - chart: - name: virtual-machine + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-apps + kind: ExternalArtifact + name: apps-virtual-machine namespace: cozy-public dashboard: category: IaaS diff --git a/packages/system/cozystack-resource-definitions/cozyrds/virtualprivatecloud.yaml b/packages/system/cozystack-resource-definitions/cozyrds/virtualprivatecloud.yaml index 8d05a5b6..a1cc9b3d 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/virtualprivatecloud.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/virtualprivatecloud.yaml @@ -13,11 +13,10 @@ spec: prefix: "virtualprivatecloud-" labels: cozystack.io/ui: "true" - chart: - name: virtualprivatecloud + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-apps + kind: ExternalArtifact + name: apps-virtualprivatecloud namespace: cozy-public dashboard: category: IaaS diff --git a/packages/system/cozystack-resource-definitions/cozyrds/vm-disk.yaml b/packages/system/cozystack-resource-definitions/cozyrds/vm-disk.yaml index c3c1b830..42a34350 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/vm-disk.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/vm-disk.yaml @@ -13,11 +13,10 @@ spec: prefix: vm-disk- labels: cozystack.io/ui: "true" - chart: - name: vm-disk + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-apps + kind: ExternalArtifact + name: apps-vm-disk namespace: cozy-public dashboard: category: IaaS diff --git a/packages/system/cozystack-resource-definitions/cozyrds/vm-instance.yaml b/packages/system/cozystack-resource-definitions/cozyrds/vm-instance.yaml index 58eb5f9a..85a6604f 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/vm-instance.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/vm-instance.yaml @@ -13,11 +13,10 @@ spec: prefix: vm-instance- labels: cozystack.io/ui: "true" - chart: - name: vm-instance + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-apps + kind: ExternalArtifact + name: apps-vm-instance namespace: cozy-public dashboard: category: IaaS diff --git a/packages/system/cozystack-resource-definitions/cozyrds/vpn.yaml b/packages/system/cozystack-resource-definitions/cozyrds/vpn.yaml index 59d940c0..5a34e628 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/vpn.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/vpn.yaml @@ -13,11 +13,10 @@ spec: prefix: vpn- labels: cozystack.io/ui: "true" - chart: - name: vpn + chartRef: sourceRef: - kind: HelmRepository - name: cozystack-apps + kind: ExternalArtifact + name: apps-vpn namespace: cozy-public dashboard: category: NaaS diff --git a/pkg/config/apiserver.go b/pkg/config/apiserver.go index 390918a6..023cba73 100644 --- a/pkg/config/apiserver.go +++ b/pkg/config/apiserver.go @@ -38,17 +38,23 @@ type ApplicationConfig struct { // ReleaseConfig contains the release settings. type ReleaseConfig struct { - Prefix string `yaml:"prefix"` - Labels map[string]string `yaml:"labels"` - Chart ChartConfig `yaml:"chart"` + Prefix string `yaml:"prefix"` + Labels map[string]string `yaml:"labels"` + Chart *ChartConfig `yaml:"chart,omitempty"` + ChartRef *ChartRefConfig `yaml:"chartRef,omitempty"` } -// ChartConfig contains the chart settings. +// ChartConfig contains the chart settings (for HelmRepository source). type ChartConfig struct { Name string `yaml:"name"` SourceRef SourceRefConfig `yaml:"sourceRef"` } +// ChartRefConfig contains the chart reference settings (for ExternalArtifact source). +type ChartRefConfig struct { + SourceRef SourceRefConfig `yaml:"sourceRef"` +} + // SourceRefConfig contains the reference to the chart source. type SourceRefConfig struct { Kind string `yaml:"kind"` diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 4202bbac..ba5ab71b 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -2714,6 +2714,13 @@ func schema_pkg_apis_meta_v1_DeleteOptions(ref common.ReferenceCallback) common. }, }, }, + "ignoreStoreReadErrorWithClusterBreakingPotential": { + SchemaProps: spec.SchemaProps{ + Description: "if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it", + Type: []string{"boolean"}, + Format: "", + }, + }, }, }, }, @@ -4601,16 +4608,46 @@ func schema_k8sio_apimachinery_pkg_version_Info(ref common.ReferenceCallback) co Properties: map[string]spec.Schema{ "major": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "Major is the major version of the binary version", + Default: "", + Type: []string{"string"}, + Format: "", }, }, "minor": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "Minor is the minor version of the binary version", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "emulationMajor": { + SchemaProps: spec.SchemaProps{ + Description: "EmulationMajor is the major version of the emulation version", + Type: []string{"string"}, + Format: "", + }, + }, + "emulationMinor": { + SchemaProps: spec.SchemaProps{ + Description: "EmulationMinor is the minor version of the emulation version", + Type: []string{"string"}, + Format: "", + }, + }, + "minCompatibilityMajor": { + SchemaProps: spec.SchemaProps{ + Description: "MinCompatibilityMajor is the major version of the minimum compatibility version", + Type: []string{"string"}, + Format: "", + }, + }, + "minCompatibilityMinor": { + SchemaProps: spec.SchemaProps{ + Description: "MinCompatibilityMinor is the minor version of the minimum compatibility version", + Type: []string{"string"}, + Format: "", }, }, "gitVersion": { diff --git a/pkg/registry/apps/application/rest.go b/pkg/registry/apps/application/rest.go index 0c2dd3a9..29e941db 100644 --- a/pkg/registry/apps/application/rest.go +++ b/pkg/registry/apps/application/rest.go @@ -797,28 +797,38 @@ func (cw *customWatcher) ResultChan() <-chan watch.Event { // shouldIncludeHelmRelease determines if a HelmRelease should be included based on filtering criteria func (r *REST) shouldIncludeHelmRelease(hr *helmv2.HelmRelease) bool { - // Nil check for Chart field - if hr.Spec.Chart == nil { - klog.V(6).Infof("HelmRelease %s has nil spec.chart field", hr.GetName()) + // Check if using chart (HelmRepository) or chartRef (ExternalArtifact) + if hr.Spec.Chart != nil { + // Using chart (HelmRepository) + if r.releaseConfig.Chart == nil { + return false + } + // Filter by Chart Name + chartName := hr.Spec.Chart.Spec.Chart + if chartName == "" { + klog.V(6).Infof("HelmRelease %s missing spec.chart.spec.chart field", hr.GetName()) + return false + } + if chartName != r.releaseConfig.Chart.Name { + klog.V(6).Infof("HelmRelease %s chart name %s does not match expected %s", hr.GetName(), chartName, r.releaseConfig.Chart.Name) + return false + } + // Filter by SourceRefConfig and Prefix + return r.matchesSourceRefAndPrefix(hr) + } else if hr.Spec.ChartRef != nil { + // Using chartRef (ExternalArtifact) + if r.releaseConfig.ChartRef == nil { + return false + } + // Filter by ChartRef SourceRef and Prefix + return r.matchesChartRefAndPrefix(hr) + } else { + klog.V(6).Infof("HelmRelease %s has neither spec.chart nor spec.chartRef field", hr.GetName()) return false } - - // Filter by Chart Name - chartName := hr.Spec.Chart.Spec.Chart - if chartName == "" { - klog.V(6).Infof("HelmRelease %s missing spec.chart.spec.chart field", hr.GetName()) - return false - } - if chartName != r.releaseConfig.Chart.Name { - klog.V(6).Infof("HelmRelease %s chart name %s does not match expected %s", hr.GetName(), chartName, r.releaseConfig.Chart.Name) - return false - } - - // Filter by SourceRefConfig and Prefix - return r.matchesSourceRefAndPrefix(hr) } -// matchesSourceRefAndPrefix checks both SourceRefConfig and Prefix criteria +// matchesSourceRefAndPrefix checks both SourceRefConfig and Prefix criteria for chart (HelmRepository) func (r *REST) matchesSourceRefAndPrefix(hr *helmv2.HelmRelease) bool { // Nil check for Chart field (defensive) if hr.Spec.Chart == nil { @@ -863,6 +873,51 @@ func (r *REST) matchesSourceRefAndPrefix(hr *helmv2.HelmRelease) bool { return true } +// matchesChartRefAndPrefix checks both ChartRef SourceRef and Prefix criteria for chartRef (ExternalArtifact) +func (r *REST) matchesChartRefAndPrefix(hr *helmv2.HelmRelease) bool { + // Nil check for ChartRef field (defensive) + if hr.Spec.ChartRef == nil { + klog.V(6).Infof("HelmRelease %s has nil spec.chartRef field", hr.GetName()) + return false + } + + // Extract SourceRef fields + sourceRef := hr.Spec.ChartRef + sourceRefKind := sourceRef.Kind + sourceRefName := sourceRef.Name + sourceRefNamespace := sourceRef.Namespace + + if sourceRefKind == "" { + klog.V(6).Infof("HelmRelease %s missing spec.chartRef.kind field", hr.GetName()) + return false + } + if sourceRefName == "" { + klog.V(6).Infof("HelmRelease %s missing spec.chartRef.name field", hr.GetName()) + return false + } + if sourceRefNamespace == "" { + klog.V(6).Infof("HelmRelease %s missing spec.chartRef.namespace field", hr.GetName()) + return false + } + + // Check if SourceRef matches the configuration + if sourceRefKind != r.releaseConfig.ChartRef.SourceRef.Kind || + sourceRefName != r.releaseConfig.ChartRef.SourceRef.Name || + sourceRefNamespace != r.releaseConfig.ChartRef.SourceRef.Namespace { + klog.V(6).Infof("HelmRelease %s chartRef sourceRef does not match expected values", hr.GetName()) + return false + } + + // Additional filtering by Prefix + name := hr.GetName() + if !strings.HasPrefix(name, r.releaseConfig.Prefix) { + klog.V(6).Infof("HelmRelease %s does not have the expected prefix %s", name, r.releaseConfig.Prefix) + return false + } + + return true +} + // getNamespace extracts the namespace from the context func (r *REST) getNamespace(ctx context.Context) (string, error) { namespace, ok := request.NamespaceFrom(ctx) @@ -1016,18 +1071,6 @@ func (r *REST) convertApplicationToHelmRelease(app *appsv1alpha1.Application) (* UID: app.ObjectMeta.UID, }, Spec: helmv2.HelmReleaseSpec{ - Chart: &helmv2.HelmChartTemplate{ - Spec: helmv2.HelmChartTemplateSpec{ - Chart: r.releaseConfig.Chart.Name, - Version: ">= 0.0.0-0", - ReconcileStrategy: "Revision", - SourceRef: helmv2.CrossNamespaceObjectReference{ - Kind: r.releaseConfig.Chart.SourceRef.Kind, - Name: r.releaseConfig.Chart.SourceRef.Name, - Namespace: r.releaseConfig.Chart.SourceRef.Namespace, - }, - }, - }, Interval: metav1.Duration{Duration: 5 * time.Minute}, Install: &helmv2.Install{ Remediation: &helmv2.InstallRemediation{ @@ -1043,6 +1086,32 @@ func (r *REST) convertApplicationToHelmRelease(app *appsv1alpha1.Application) (* }, } + // Set Chart or ChartRef based on configuration + if r.releaseConfig.Chart != nil { + // Using chart (HelmRepository) + helmRelease.Spec.Chart = &helmv2.HelmChartTemplate{ + Spec: helmv2.HelmChartTemplateSpec{ + Chart: r.releaseConfig.Chart.Name, + Version: ">= 0.0.0-0", + ReconcileStrategy: "Revision", + SourceRef: helmv2.CrossNamespaceObjectReference{ + Kind: r.releaseConfig.Chart.SourceRef.Kind, + Name: r.releaseConfig.Chart.SourceRef.Name, + Namespace: r.releaseConfig.Chart.SourceRef.Namespace, + }, + }, + } + } else if r.releaseConfig.ChartRef != nil { + // Using chartRef (ExternalArtifact) + helmRelease.Spec.ChartRef = &helmv2.CrossNamespaceSourceReference{ + Kind: r.releaseConfig.ChartRef.SourceRef.Kind, + Name: r.releaseConfig.ChartRef.SourceRef.Name, + Namespace: r.releaseConfig.ChartRef.SourceRef.Namespace, + } + } else { + return nil, fmt.Errorf("either chart or chartRef must be specified in release config") + } + return helmRelease, nil } From 4b5d777b81110858307752b3c95acd2002228796 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 19 Nov 2025 09:47:27 +0100 Subject: [PATCH 06/46] [fluxcd] fix advertisning url for source-watcher Signed-off-by: Andrei Kvapil --- packages/system/fluxcd/values.yaml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/system/fluxcd/values.yaml b/packages/system/fluxcd/values.yaml index b07fe06a..7f5af0ff 100644 --- a/packages/system/fluxcd/values.yaml +++ b/packages/system/fluxcd/values.yaml @@ -34,17 +34,21 @@ flux-instance: memory: 2048Mi - target: kind: Deployment - name: (source-controller|source-watcher) + name: source-controller patch: | - op: add path: /spec/template/spec/containers/0/args/- value: --storage-adv-addr=source-controller.cozy-fluxcd.svc - - op: add - path: /spec/template/spec/containers/0/args/- - value: --events-addr=http://notification-controller.cozy-fluxcd.svc/ - target: kind: Deployment - name: (kustomize-controller|helm-controller|image-reflector-controller|image-automation-controller) + name: source-watcher + patch: | + - op: add + path: /spec/template/spec/containers/0/args/- + value: --storage-adv-addr=source-watcher.cozy-fluxcd.svc + - target: + kind: Deployment + name: (kustomize-controller|helm-controller|image-reflector-controller|image-automation-controller|source-controller|source-watcher) patch: | - op: add path: /spec/template/spec/containers/0/args/- From 4f97aef04c6e5e557baf6ab2bdaf06a8bf14c322 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 19 Nov 2025 09:49:02 +0100 Subject: [PATCH 07/46] Update apps to use ExternalArtifacts Signed-off-by: Andrei Kvapil --- cmd/cozystack-operator/main.go | 77 ++++- internal/operator/reconciler.go | 275 ++++++++++++------ .../apps/bucket/templates/helmrelease.yaml | 2 +- .../helmreleases/cert-manager-crds.yaml | 2 +- .../templates/helmreleases/cert-manager.yaml | 2 +- .../templates/helmreleases/cilium.yaml | 2 +- .../templates/helmreleases/coredns.yaml | 2 +- .../templates/helmreleases/csi.yaml | 2 +- .../templates/helmreleases/fluxcd.yaml | 4 +- .../helmreleases/gateway-api-crds.yaml | 2 +- .../templates/helmreleases/gpu-operator.yaml | 2 +- .../templates/helmreleases/ingress-nginx.yaml | 2 +- .../helmreleases/monitoring-agents.yaml | 2 +- .../templates/helmreleases/velero.yaml | 2 +- .../vertical-pod-autoscaler-crds.yaml | 2 +- .../helmreleases/vertical-pod-autoscaler.yaml | 2 +- .../victoria-metrics-operator.yaml | 2 +- .../helmreleases/volumesnapshot_crd.yaml | 2 +- packages/apps/nats/templates/nats.yaml | 2 +- .../installer/images/cozystack/Dockerfile | 2 +- packages/core/installer/values.yaml | 2 +- .../core/platform/bundles/distro-full.yaml | 72 ++--- .../core/platform/bundles/distro-hosted.yaml | 50 ++-- packages/core/platform/bundles/paas-full.yaml | 116 ++++---- .../core/platform/bundles/paas-hosted.yaml | 66 ++--- .../platform/templates/bundles-configmap.yaml | 8 +- .../ingress/templates/nginx-ingress.yaml | 2 +- .../extra/seaweedfs/templates/seaweedfs.yaml | 2 +- .../templates/vpa-for-vpa.yaml | 13 +- scripts/migrations/22 | 103 +++++++ 30 files changed, 540 insertions(+), 284 deletions(-) create mode 100755 scripts/migrations/22 diff --git a/cmd/cozystack-operator/main.go b/cmd/cozystack-operator/main.go index 6cefc090..9b549efa 100644 --- a/cmd/cozystack-operator/main.go +++ b/cmd/cozystack-operator/main.go @@ -146,10 +146,13 @@ func main() { } // Setup PlatformReconciler - if err = (&operator.PlatformReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { + firstReconcileDone := make(chan struct{}) + platformReconciler := &operator.PlatformReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + FirstReconcileDone: firstReconcileDone, + } + if err = platformReconciler.SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "Platform") os.Exit(1) } @@ -180,9 +183,51 @@ func main() { } }() - // Wait for manager to initialize before starting phase 2 + // Wait for manager to initialize <-mgrStarted + // Trigger a reconcile by creating/updating the ConfigMap to ensure first reconcile happens + // This ensures the controller processes the ConfigMap and completes its first reconcile cycle + setupLog.Info("Triggering first reconcile cycle") + reconcileCtx, reconcileCancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer reconcileCancel() + + // Get the ConfigMap to trigger reconcile + cm := &corev1.ConfigMap{} + cmKey := types.NamespacedName{Namespace: "cozy-system", Name: "cozystack"} + if err := bootstrapClient.Get(reconcileCtx, cmKey, cm); err == nil { + // ConfigMap exists, update it to trigger reconcile + cm.Labels = map[string]string{} + cm.Labels["cozystack.io/reconcile-trigger"] = strconv.FormatInt(time.Now().Unix(), 10) + if err := bootstrapClient.Update(reconcileCtx, cm); err != nil { + setupLog.Info("Failed to trigger reconcile via ConfigMap update, continuing anyway", "error", err) + } + } else if apierrors.IsNotFound(err) { + // ConfigMap doesn't exist yet, create it to trigger reconcile + cm.ObjectMeta = metav1.ObjectMeta{ + Name: "cozystack", + Namespace: "cozy-system", + Labels: map[string]string{ + "cozystack.io/reconcile-trigger": strconv.FormatInt(time.Now().Unix(), 10), + }, + } + cm.Data = map[string]string{ + "bundleName": "distro-full", + } + if err := bootstrapClient.Create(reconcileCtx, cm); err != nil { + setupLog.Info("Failed to trigger reconcile via ConfigMap creation, continuing anyway", "error", err) + } + } + + // Wait for first reconcile cycle to complete + setupLog.Info("Waiting for first reconcile cycle to complete") + select { + case <-firstReconcileDone: + setupLog.Info("First reconcile cycle completed") + case <-reconcileCtx.Done(): + setupLog.Info("Timeout waiting for first reconcile, proceeding with phase 2 anyway") + } + setupLog.Info("Starting bootstrap phase 2: basic charts installation") phase2Ctx, phase2Cancel := context.WithTimeout(context.Background(), 30*time.Minute) defer phase2Cancel() @@ -255,13 +300,20 @@ func runBootstrapPhase2(ctx context.Context, c client.Client) error { } setupLog.Info("Bundle detected", "bundle", bundle) - // Install basic charts (cilium, kubeovn) - // These are installed after controller manager has started - // The controller manager can now handle HelmReleases from these charts - setupLog.Info("Installing basic charts (controller manager is running)") - if err := installBasicCharts(ctx, c, bundle); err != nil { + // Install basic charts (cilium, kubeovn) only if fluxcd is not ready + // Basic charts are only needed during bootstrap when fluxcd is not ready yet + fluxOK, err := fluxIsOK(ctx, c) + if err != nil { return err } + if !fluxOK { + setupLog.Info("fluxcd is not ready, installing basic charts (controller manager is running)") + if err := installBasicCharts(ctx, c, bundle); err != nil { + return err + } + } else { + setupLog.Info("fluxcd is ready, skipping basic charts installation") + } // Unsuspend and update charts if err := unsuspendCozystackCharts(ctx, c); err != nil { @@ -487,7 +539,6 @@ func ensureFluxCD(ctx context.Context, c client.Client) error { err = c.Get(ctx, key, hr) if err == nil { // HelmRelease exists, apply and resume it - // This matches installer.sh: make -C packages/system/fluxcd-operator apply resume setupLog.Info("Applying and resuming fluxcd-operator helmrelease") cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd-operator", "apply", "resume") cmd.Stdout = os.Stdout @@ -497,7 +548,6 @@ func ensureFluxCD(ctx context.Context, c client.Client) error { } } else if apierrors.IsNotFound(err) { // HelmRelease doesn't exist, need to create it - // This matches installer.sh: make -C packages/system/fluxcd-operator apply-locally setupLog.Info("Creating fluxcd-operator using make (TODO: use helm-controller API)") cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd-operator", "apply-locally") cmd.Stdout = os.Stdout @@ -520,7 +570,6 @@ func ensureFluxCD(ctx context.Context, c client.Client) error { err = c.Get(ctx, key, hr) if err == nil { // HelmRelease exists, apply and resume it - // This matches installer.sh: make -C packages/system/fluxcd apply resume setupLog.Info("Applying and resuming fluxcd helmrelease") cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd", "apply", "resume") cmd.Stdout = os.Stdout @@ -530,7 +579,6 @@ func ensureFluxCD(ctx context.Context, c client.Client) error { } } else if apierrors.IsNotFound(err) { // HelmRelease doesn't exist, need to create it - // This matches installer.sh: make -C packages/system/fluxcd apply-locally setupLog.Info("Creating fluxcd using make (TODO: use helm-controller API)") cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd", "apply-locally") cmd.Stdout = os.Stdout @@ -582,7 +630,6 @@ func fluxIsOK(ctx context.Context, c client.Client) (bool, error) { } // Check fluxcd helmrelease is ready - // This matches installer.sh: kubectl wait --for=condition=ready -n cozy-fluxcd helmrelease/fluxcd --timeout=1s hr := &helmv2.HelmRelease{} key = types.NamespacedName{Namespace: "cozy-fluxcd", Name: "fluxcd"} if err := c.Get(ctx, key, hr); err != nil { diff --git a/internal/operator/reconciler.go b/internal/operator/reconciler.go index 5bbe2e01..1fbe6fba 100644 --- a/internal/operator/reconciler.go +++ b/internal/operator/reconciler.go @@ -20,6 +20,7 @@ import ( "context" "encoding/json" "fmt" + "strings" "gopkg.in/yaml.v3" @@ -46,10 +47,63 @@ const ( platformOperatorLabel = "cozystack.io/platform-operator" ) +var ( + // System packages list - packages that are in packages/system/ directory + systemPackagesList = map[string]bool{ + "bootbox": true, "bucket": true, "capi-operator": true, "capi-providers-bootstrap": true, + "capi-providers-core": true, "capi-providers-cpprovider": true, "capi-providers-infraprovider": true, + "cert-manager": true, "cert-manager-crds": true, "cert-manager-issuers": true, "cilium": true, + "cilium-networkpolicy": true, "clickhouse-operator": true, "coredns": true, "cozy-proxy": true, + "cozystack-api": true, "cozystack-controller": true, "cozystack-resource-definition-crd": true, + "cozystack-resource-definitions": true, "dashboard": true, "etcd-operator": true, "external-dns": true, + "external-secrets-operator": true, "fluxcd": true, "fluxcd-operator": true, "foundationdb-operator": true, + "gateway-api-crds": true, "goldpinger": true, "gpu-operator": true, "grafana-operator": true, + "hetzner-robotlb": true, "ingress-nginx": true, "kafka-operator": true, "kamaji": true, + "keycloak": true, "keycloak-configure": true, "keycloak-operator": true, "kubeovn": true, + "kubeovn-plunger": true, "kubeovn-webhook": true, "kubevirt": true, "kubevirt-cdi": true, + "kubevirt-cdi-operator": true, "kubevirt-csi-node": true, "kubevirt-instancetypes": true, + "kubevirt-operator": true, "lineage-controller-webhook": true, "linstor": true, "mariadb-operator": true, + "metallb": true, "monitoring-agents": true, "multus": true, "nats": true, "nfs-driver": true, + "objectstorage-controller": true, "opencost": true, "piraeus-operator": true, "postgres-operator": true, + "rabbitmq-operator": true, "redis-operator": true, "reloader": true, "seaweedfs": true, + "snapshot-controller": true, "telepresence": true, "velero": true, "vertical-pod-autoscaler": true, + "vertical-pod-autoscaler-crds": true, "victoria-metrics-operator": true, "vsnap-crd": true, + } + + // Apps packages list - packages that are in packages/apps/ directory + appsPackagesList = map[string]bool{ + "bucket": true, "clickhouse": true, "ferretdb": true, "foundationdb": true, "http-cache": true, + "kafka": true, "kubernetes": true, "mysql": true, "nats": true, "postgres": true, "rabbitmq": true, + "redis": true, "tcp-balancer": true, "tenant": true, "virtual-machine": true, "vm-disk": true, + "vm-instance": true, "vpc": true, "vpn": true, + } + + // Extra packages list - packages that are in packages/extra/ directory + extraPackagesList = map[string]bool{ + "bootbox": true, "etcd": true, "info": true, "ingress": true, "monitoring": true, "seaweedfs": true, + } +) + +// getArtifactPrefixAndNamespace determines the artifact prefix and namespace based on package category +// Returns: prefix, namespace, found +func getArtifactPrefixAndNamespace(chartName string) (string, string, bool) { + if systemPackagesList[chartName] { + return "system", "cozy-system", true + } + if appsPackagesList[chartName] { + return "apps", "cozy-public", true + } + if extraPackagesList[chartName] { + return "extra", "cozy-public", true + } + return "", "", false +} + // PlatformReconciler reconciles the platform configuration. type PlatformReconciler struct { client.Client - Scheme *runtime.Scheme + Scheme *runtime.Scheme + FirstReconcileDone chan struct{} } // +kubebuilder:rbac:groups=core,resources=configmaps,verbs=get;list;watch @@ -132,6 +186,17 @@ func (r *PlatformReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c return ctrl.Result{}, fmt.Errorf("failed to reconcile tenant-root: %w", err) } + // Signal that first reconcile is done (non-blocking) + if r.FirstReconcileDone != nil { + select { + case <-r.FirstReconcileDone: + // Already closed, do nothing + default: + // Close channel to signal first reconcile is done + close(r.FirstReconcileDone) + } + } + return ctrl.Result{}, nil } @@ -284,46 +349,27 @@ func (r *PlatformReconciler) reconcileArtifactGenerators(ctx context.Context) er packagesWithCozyLib := map[string]bool{ "bootbox": true, "bucket": true, "clickhouse": true, "etcd": true, "ferretdb": true, "foundationdb": true, "http-cache": true, "info": true, - "ingress": true, "kafka": true, "kubernetes": true, "monitoring": true, + "ingress": true, "kafka": true, "keycloak": true, "kubernetes": true, "monitoring": true, "mysql": true, "nats": true, "postgres": true, "rabbitmq": true, "redis": true, "seaweedfs": true, "tcp-balancer": true, "tenant": true, "virtual-machine": true, "vm-disk": true, "vm-instance": true, "vpc": true, "vpn": true, } - // System packages - systemPackages := []string{ - "bootbox", "bucket", "capi-operator", "capi-providers-bootstrap", - "capi-providers-core", "capi-providers-cpprovider", "capi-providers-infraprovider", - "cert-manager", "cert-manager-crds", "cert-manager-issuers", "cilium", - "cilium-networkpolicy", "clickhouse-operator", "coredns", "cozy-proxy", - "cozystack-api", "cozystack-controller", "cozystack-resource-definition-crd", - "cozystack-resource-definitions", "dashboard", "etcd-operator", "external-dns", - "external-secrets-operator", "fluxcd", "fluxcd-operator", "foundationdb-operator", - "gateway-api-crds", "goldpinger", "gpu-operator", "grafana-operator", - "hetzner-robotlb", "ingress-nginx", "kafka-operator", "kamaji", - "keycloak", "keycloak-configure", "keycloak-operator", "kubeovn", - "kubeovn-plunger", "kubeovn-webhook", "kubevirt", "kubevirt-cdi", - "kubevirt-cdi-operator", "kubevirt-csi-node", "kubevirt-instancetypes", - "kubevirt-operator", "lineage-controller-webhook", "linstor", "mariadb-operator", - "metallb", "monitoring-agents", "multus", "nats", "nfs-driver", - "objectstorage-controller", "opencost", "piraeus-operator", "postgres-operator", - "rabbitmq-operator", "redis-operator", "reloader", "seaweedfs", - "snapshot-controller", "telepresence", "velero", "vertical-pod-autoscaler", - "vertical-pod-autoscaler-crds", "victoria-metrics-operator", "vsnap-crd", + // Convert maps to slices for ArtifactGenerator + systemPackages := make([]string, 0, len(systemPackagesList)) + for pkg := range systemPackagesList { + systemPackages = append(systemPackages, pkg) } - // Apps packages - appsPackages := []string{ - "bucket", "clickhouse", "ferretdb", "foundationdb", "http-cache", - "kafka", "kubernetes", "mysql", "nats", "postgres", "rabbitmq", - "redis", "tcp-balancer", "tenant", "virtual-machine", "vm-disk", - "vm-instance", "vpc", "vpn", + appsPackages := make([]string, 0, len(appsPackagesList)) + for pkg := range appsPackagesList { + appsPackages = append(appsPackages, pkg) } - // Extra packages - extraPackages := []string{ - "bootbox", "etcd", "info", "ingress", "monitoring", "seaweedfs", + extraPackages := make([]string, 0, len(extraPackagesList)) + for pkg := range extraPackagesList { + extraPackages = append(extraPackages, pkg) } // Define desired ArtifactGenerators @@ -384,6 +430,42 @@ func (r *PlatformReconciler) reconcileArtifactGenerators(ctx context.Context) er func (r *PlatformReconciler) reconcileArtifactGenerator(ctx context.Context, name, namespace string, packages []string, packagesWithCozyLib map[string]bool) error { logger := log.FromContext(ctx) + // Load bundle to get valuesFiles for packages + cfg := &config.CozystackConfig{} + configMap := &corev1.ConfigMap{} + configMapKey := types.NamespacedName{Namespace: "cozy-system", Name: "cozystack"} + if err := r.Get(ctx, configMapKey, configMap); err == nil { + cfg = config.ParseConfigMapData(configMap.Data) + } + + var bundle *Bundle + var err error + if cfg.BundleName != "" { + bundle, err = loadBundle(ctx, r.Client, cfg.BundleName) + if err != nil { + logger.Info("failed to load bundle for valuesFiles, continuing without them", "error", err) + bundle = nil + } + } + + // Build map of chart -> valuesFiles from bundle + chartValuesFiles := make(map[string][]string) + if bundle != nil { + for _, release := range bundle.Releases { + // Check if release is disabled or optional + if cfg.IsComponentDisabled(release.Name) { + continue + } + if release.Optional && !cfg.IsComponentEnabled(release.Name) { + continue + } + // Store valuesFiles for this chart + if len(release.ValuesFiles) > 0 { + chartValuesFiles[release.Chart] = release.ValuesFiles + } + } + } + // Build output artifacts outputArtifacts := []sourcewatcherv1beta1.OutputArtifact{} for _, pkg := range packages { @@ -402,8 +484,30 @@ func (r *PlatformReconciler) reconcileArtifactGenerator(ctx context.Context, nam }) } + // Add valuesFiles if specified in bundle + if valuesFiles, ok := chartValuesFiles[pkg]; ok { + for i, valuesFile := range valuesFiles { + // Copy values file from GitRepository to artifact + // Path in GitRepository: packages/{name}/{pkg}/{valuesFile} + // Path in artifact: {pkg}/{valuesFile} + // First file should use Overwrite (to replace original values.yaml), others use Merge + strategy := "Merge" + if i == 0 { + strategy = "Overwrite" + } + copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ + From: fmt.Sprintf("@cozystack/packages/%s/%s/%s", name, pkg, valuesFile), + To: fmt.Sprintf("@artifact/%s/%s", pkg, valuesFile), + Strategy: strategy, + }) + logger.Info("Adding valuesFile copy operation", "package", pkg, "valuesFile", valuesFile, "strategy", strategy) + } + } + + artifactName := fmt.Sprintf("%s-%s", name, pkg) + logger.Info("Adding output artifact to ArtifactGenerator", "artifactName", artifactName, "generator", name, "package", pkg) outputArtifacts = append(outputArtifacts, sourcewatcherv1beta1.OutputArtifact{ - Name: fmt.Sprintf("%s-%s", name, pkg), + Name: artifactName, Copy: copyOps, }) } @@ -433,7 +537,8 @@ func (r *PlatformReconciler) reconcileArtifactGenerator(ctx context.Context, nam // Get existing resource to preserve resourceVersion existing := &sourcewatcherv1beta1.ArtifactGenerator{} key := client.ObjectKey{Name: name, Namespace: namespace} - if err := r.Get(ctx, key, existing); err == nil { + err = r.Get(ctx, key, existing) + if err == nil { ag.SetResourceVersion(existing.GetResourceVersion()) // Merge labels and annotations labels := ag.GetLabels() @@ -645,31 +750,6 @@ func (r *PlatformReconciler) reconcileTenantRoot(ctx context.Context, cfg *confi } logger.Info("reconciled tenant-root HelmRelease") - // List all tenant-root HelmReleases and delete unwanted ones - hrList := &helmv2.HelmReleaseList{} - if err := r.List(ctx, hrList, client.InNamespace("tenant-root"), client.MatchingLabels{ - "cozystack.io/ui": "true", - }); err != nil { - return fmt.Errorf("failed to list tenant-root HelmReleases: %w", err) - } - - desiredHRKey := types.NamespacedName{Name: desiredHR.Name, Namespace: desiredHR.Namespace} - for _, hr := range hrList.Items { - key := types.NamespacedName{Name: hr.Name, Namespace: hr.Namespace} - if key != desiredHRKey { - // Not desired, delete it - if err := r.Delete(ctx, &hr); err != nil { - if apierrors.IsNotFound(err) { - continue - } - logger.Error(err, "failed to delete tenant-root HelmRelease", "name", hr.Name) - // Continue with other deletions - } else { - logger.Info("deleted tenant-root HelmRelease (not in desired state)", "name", hr.Name) - } - } - } - return nil } @@ -731,30 +811,20 @@ func (r *PlatformReconciler) reconcileHelmReleases(ctx context.Context, cfg *con }, } - // Determine if this is a system resource (installed in cozy-system namespace) - // System resources use chartRef (ExternalArtifact), others use Chart (HelmRepository) - if release.Namespace == "cozy-system" { - // System resource: use chartRef with ExternalArtifact - // Artifact name format: system-{chart-name} - artifactName := fmt.Sprintf("system-%s", release.Chart) - hr.Spec.ChartRef = &helmv2.CrossNamespaceSourceReference{ - Kind: "ExternalArtifact", - Name: artifactName, - Namespace: "cozy-system", - } - } else { - // Non-system resource: use Chart with HelmRepository - hr.Spec.Chart = &helmv2.HelmChartTemplate{ - Spec: helmv2.HelmChartTemplateSpec{ - Chart: release.Chart, - Version: ">= 0.0.0-0", - SourceRef: helmv2.CrossNamespaceObjectReference{ - Kind: "HelmRepository", - Name: "cozystack-system", - Namespace: "cozy-system", - }, - }, - } + // All packages now use chartRef (ExternalArtifact) + // Determine artifact prefix and namespace based on package category + artifactPrefix, artifactNamespace, found := getArtifactPrefixAndNamespace(release.Chart) + if !found { + logger.Error(fmt.Errorf("unknown package category"), "skipping HelmRelease with unknown package", "name", release.Name, "namespace", release.Namespace, "chart", release.Chart) + continue + } + + artifactName := fmt.Sprintf("%s-%s", artifactPrefix, release.Chart) + logger.Info("Creating HelmRelease with chartRef", "name", release.Name, "namespace", release.Namespace, "chart", release.Chart, "artifactName", artifactName, "artifactNamespace", artifactNamespace) + hr.Spec.ChartRef = &helmv2.CrossNamespaceSourceReference{ + Kind: "ExternalArtifact", + Name: artifactName, + Namespace: artifactNamespace, } // Set values if provided @@ -797,6 +867,47 @@ func (r *PlatformReconciler) reconcileHelmReleases(ctx context.Context, cfg *con } } + // Set DependsOn if provided + // DependsOn is a list of release names, we need to convert them to HelmRelease references + if len(release.DependsOn) > 0 { + dependsOn := make([]helmv2.DependencyReference, 0, len(release.DependsOn)) + for _, depName := range release.DependsOn { + // Find the dependent release in the bundle to get its namespace + var depNamespace string + for _, depRelease := range bundle.Releases { + if depRelease.Name == depName { + depNamespace = depRelease.Namespace + break + } + } + // If namespace not found, use the same namespace as current release + if depNamespace == "" { + depNamespace = release.Namespace + logger.Info("dependent release not found in bundle, using same namespace", "name", release.Name, "dependsOn", depName) + } + dependsOn = append(dependsOn, helmv2.DependencyReference{ + Name: depName, + Namespace: depNamespace, + }) + } + hr.Spec.DependsOn = dependsOn + logger.Info("set DependsOn for HelmRelease", "name", release.Name, "dependsOn", release.DependsOn) + } + + // Set valuesFiles annotation for cozypkg + // Initialize annotations if needed + if hr.Annotations == nil { + hr.Annotations = make(map[string]string) + } + if len(release.ValuesFiles) > 0 { + // Format: comma-separated string, e.g., "values.yaml,values-cilium.yaml" + hr.Annotations["cozypkg.cozystack.io/values-files"] = strings.Join(release.ValuesFiles, ",") + logger.Info("set valuesFiles annotation for HelmRelease", "name", release.Name, "valuesFiles", release.ValuesFiles) + } else { + // Remove annotation if valuesFiles is empty + delete(hr.Annotations, "cozypkg.cozystack.io/values-files") + } + if err := r.CreateOrUpdate(ctx, hr); err != nil { logger.Error(err, "failed to reconcile HelmRelease", "name", release.Name, "namespace", release.Namespace) return err diff --git a/packages/apps/bucket/templates/helmrelease.yaml b/packages/apps/bucket/templates/helmrelease.yaml index 4255b21d..5832f051 100644 --- a/packages/apps/bucket/templates/helmrelease.yaml +++ b/packages/apps/bucket/templates/helmrelease.yaml @@ -5,7 +5,7 @@ metadata: spec: chartRef: kind: ExternalArtifact - name: system-cozy-bucket + name: system-bucket namespace: cozy-system interval: 5m timeout: 10m diff --git a/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml b/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml index 4ebc1212..3c1ae90d 100644 --- a/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml @@ -10,7 +10,7 @@ spec: releaseName: cert-manager-crds chartRef: kind: ExternalArtifact - name: system-cozy-cert-manager-crds + name: system-cert-manager-crds namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml b/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml index e2f67d08..b411d2e5 100644 --- a/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml @@ -10,7 +10,7 @@ spec: releaseName: cert-manager chartRef: kind: ExternalArtifact - name: system-cozy-cert-manager + name: system-cert-manager namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/cilium.yaml b/packages/apps/kubernetes/templates/helmreleases/cilium.yaml index 6a549f17..97c93f41 100644 --- a/packages/apps/kubernetes/templates/helmreleases/cilium.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/cilium.yaml @@ -24,7 +24,7 @@ spec: releaseName: cilium chartRef: kind: ExternalArtifact - name: system-cozy-cilium + name: system-cilium namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/coredns.yaml b/packages/apps/kubernetes/templates/helmreleases/coredns.yaml index 3629d881..e10dd741 100644 --- a/packages/apps/kubernetes/templates/helmreleases/coredns.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/coredns.yaml @@ -15,7 +15,7 @@ spec: releaseName: coredns chartRef: kind: ExternalArtifact - name: system-cozy-coredns + name: system-coredns namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/csi.yaml b/packages/apps/kubernetes/templates/helmreleases/csi.yaml index 8c389337..c150800e 100644 --- a/packages/apps/kubernetes/templates/helmreleases/csi.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/csi.yaml @@ -10,7 +10,7 @@ spec: releaseName: csi chartRef: kind: ExternalArtifact - name: system-cozy-kubevirt-csi-node + name: system-kubevirt-csi-node namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml b/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml index 5e091323..10fc8787 100644 --- a/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml @@ -10,7 +10,7 @@ spec: releaseName: fluxcd-operator chartRef: kind: ExternalArtifact - name: system-cozy-fluxcd-operator + name: system-fluxcd-operator namespace: cozy-system kubeConfig: secretRef: @@ -53,7 +53,7 @@ spec: releaseName: fluxcd chartRef: kind: ExternalArtifact - name: system-cozy-fluxcd + name: system-fluxcd namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml b/packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml index b847e0fc..144efd9e 100644 --- a/packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml @@ -10,7 +10,7 @@ spec: releaseName: gateway-api-crds chartRef: kind: ExternalArtifact - name: system-cozy-gateway-api-crds + name: system-gateway-api-crds namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml b/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml index 3bbb6590..8811eb8e 100644 --- a/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml @@ -10,7 +10,7 @@ spec: releaseName: gpu-operator chartRef: kind: ExternalArtifact - name: system-cozy-gpu-operator + name: system-gpu-operator namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml b/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml index 1f43f4fb..41f75912 100644 --- a/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml @@ -29,7 +29,7 @@ spec: releaseName: ingress-nginx chartRef: kind: ExternalArtifact - name: system-cozy-ingress-nginx + name: system-ingress-nginx namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml b/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml index 45ebd4b4..efce19f0 100644 --- a/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml @@ -12,7 +12,7 @@ spec: releaseName: cozy-monitoring-agents chartRef: kind: ExternalArtifact - name: system-cozy-monitoring-agents + name: system-monitoring-agents namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/velero.yaml b/packages/apps/kubernetes/templates/helmreleases/velero.yaml index fa410f1e..9a72a38a 100644 --- a/packages/apps/kubernetes/templates/helmreleases/velero.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/velero.yaml @@ -10,7 +10,7 @@ spec: releaseName: velero chartRef: kind: ExternalArtifact - name: system-cozy-velero + name: system-velero namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml index 96dbb46f..e052d175 100644 --- a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml @@ -11,7 +11,7 @@ spec: releaseName: vertical-pod-autoscaler-crds chartRef: kind: ExternalArtifact - name: system-cozy-vertical-pod-autoscaler-crds + name: system-vertical-pod-autoscaler-crds namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml index 02a413c6..cb995625 100644 --- a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml @@ -38,7 +38,7 @@ spec: releaseName: vertical-pod-autoscaler chartRef: kind: ExternalArtifact - name: system-cozy-vertical-pod-autoscaler + name: system-vertical-pod-autoscaler namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml b/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml index ac75530a..cd573aa7 100644 --- a/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml @@ -10,7 +10,7 @@ spec: releaseName: cozy-victoria-metrics-operator chartRef: kind: ExternalArtifact - name: system-cozy-victoria-metrics-operator + name: system-victoria-metrics-operator namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/volumesnapshot_crd.yaml b/packages/apps/kubernetes/templates/helmreleases/volumesnapshot_crd.yaml index 5dace0fd..a196e913 100644 --- a/packages/apps/kubernetes/templates/helmreleases/volumesnapshot_crd.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/volumesnapshot_crd.yaml @@ -9,7 +9,7 @@ spec: releaseName: vsnap-crd chartRef: kind: ExternalArtifact - name: system-cozy-vsnap-crd + name: system-vsnap-crd namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/nats/templates/nats.yaml b/packages/apps/nats/templates/nats.yaml index 050411f8..d6cd231e 100644 --- a/packages/apps/nats/templates/nats.yaml +++ b/packages/apps/nats/templates/nats.yaml @@ -37,7 +37,7 @@ metadata: spec: chartRef: kind: ExternalArtifact - name: system-cozy-nats + name: system-nats namespace: cozy-system interval: 5m timeout: 10m diff --git a/packages/core/installer/images/cozystack/Dockerfile b/packages/core/installer/images/cozystack/Dockerfile index 454cd934..bc92d712 100644 --- a/packages/core/installer/images/cozystack/Dockerfile +++ b/packages/core/installer/images/cozystack/Dockerfile @@ -19,7 +19,7 @@ RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \ FROM alpine:3.22 -RUN wget -O- https://github.com/cozystack/cozypkg/raw/refs/heads/main/hack/install.sh | sh -s -- -v 1.2.0 +RUN wget -O- https://github.com/cozystack/cozypkg/raw/refs/heads/main/hack/install.sh | sh -s -- -v 1.4.0 RUN apk add --no-cache make kubectl helm coreutils git jq ca-certificates diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index 72ba2f9a..ee60f15a 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:latest@sha256:a40c4e5216eee3a44936795df3ab2f3d62f321bd3262abe02c20c24972632a99 + image: ghcr.io/cozystack/cozystack/installer:latest@sha256:cf34dccce53c750f1589a8cd317b7fcac3bc1210fb948140e46281994176084b diff --git a/packages/core/platform/bundles/distro-full.yaml b/packages/core/platform/bundles/distro-full.yaml index ed52a83a..c17d829d 100644 --- a/packages/core/platform/bundles/distro-full.yaml +++ b/packages/core/platform/bundles/distro-full.yaml @@ -4,14 +4,14 @@ releases: - name: fluxcd-operator releaseName: fluxcd-operator - chart: cozy-fluxcd-operator + chart: fluxcd-operator namespace: cozy-fluxcd privileged: true dependsOn: [] - name: fluxcd releaseName: fluxcd - chart: cozy-fluxcd + chart: fluxcd namespace: cozy-fluxcd dependsOn: [fluxcd-operator,cilium] values: @@ -22,7 +22,7 @@ releases: - name: cilium releaseName: cilium - chart: cozy-cilium + chart: cilium namespace: cozy-cilium privileged: true dependsOn: [] @@ -39,27 +39,27 @@ releases: - name: cilium-networkpolicy releaseName: cilium-networkpolicy - chart: cozy-cilium-networkpolicy + chart: cilium-networkpolicy namespace: cozy-cilium privileged: true dependsOn: [cilium] - name: cozy-proxy releaseName: cozystack - chart: cozy-cozy-proxy + chart: cozy-proxy namespace: cozy-system optional: true dependsOn: [cilium] - name: cert-manager-crds releaseName: cert-manager-crds - chart: cozy-cert-manager-crds + chart: cert-manager-crds namespace: cozy-cert-manager dependsOn: [cilium] - name: cozystack-controller releaseName: cozystack-controller - chart: cozy-cozystack-controller + chart: cozystack-controller namespace: cozy-system dependsOn: [cilium] {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} @@ -70,33 +70,33 @@ releases: - name: lineage-controller-webhook releaseName: lineage-controller-webhook - chart: cozy-lineage-controller-webhook + chart: lineage-controller-webhook namespace: cozy-system dependsOn: [cozystack-controller,cilium,cert-manager] - name: cert-manager releaseName: cert-manager - chart: cozy-cert-manager + chart: cert-manager namespace: cozy-cert-manager dependsOn: [cert-manager-crds] - name: cert-manager-issuers releaseName: cert-manager-issuers - chart: cozy-cert-manager-issuers + chart: cert-manager-issuers namespace: cozy-cert-manager optional: true dependsOn: [cilium,cert-manager] - name: victoria-metrics-operator releaseName: victoria-metrics-operator - chart: cozy-victoria-metrics-operator + chart: victoria-metrics-operator namespace: cozy-victoria-metrics-operator optional: true dependsOn: [cilium,cert-manager] - name: monitoring-agents releaseName: monitoring-agents - chart: cozy-monitoring-agents + chart: monitoring-agents namespace: cozy-monitoring privileged: true optional: true @@ -108,28 +108,28 @@ releases: - name: metallb releaseName: metallb - chart: cozy-metallb + chart: metallb namespace: cozy-metallb privileged: true dependsOn: [cilium] - name: etcd-operator releaseName: etcd-operator - chart: cozy-etcd-operator + chart: etcd-operator namespace: cozy-etcd-operator optional: true dependsOn: [cilium,cert-manager] - name: grafana-operator releaseName: grafana-operator - chart: cozy-grafana-operator + chart: grafana-operator namespace: cozy-grafana-operator optional: true dependsOn: [cilium] - name: mariadb-operator releaseName: mariadb-operator - chart: cozy-mariadb-operator + chart: mariadb-operator namespace: cozy-mariadb-operator optional: true dependsOn: [cilium,cert-manager,victoria-metrics-operator] @@ -139,14 +139,14 @@ releases: - name: postgres-operator releaseName: postgres-operator - chart: cozy-postgres-operator + chart: postgres-operator namespace: cozy-postgres-operator optional: true dependsOn: [cilium,cert-manager,victoria-metrics-operator] - name: kafka-operator releaseName: kafka-operator - chart: cozy-kafka-operator + chart: kafka-operator namespace: cozy-kafka-operator optional: true dependsOn: [cilium,victoria-metrics-operator] @@ -156,61 +156,61 @@ releases: - name: clickhouse-operator releaseName: clickhouse-operator - chart: cozy-clickhouse-operator + chart: clickhouse-operator namespace: cozy-clickhouse-operator optional: true dependsOn: [cilium,victoria-metrics-operator] - name: foundationdb-operator releaseName: foundationdb-operator - chart: cozy-foundationdb-operator + chart: foundationdb-operator namespace: cozy-foundationdb-operator optional: true dependsOn: [cilium,cert-manager] - name: rabbitmq-operator releaseName: rabbitmq-operator - chart: cozy-rabbitmq-operator + chart: rabbitmq-operator namespace: cozy-rabbitmq-operator optional: true dependsOn: [cilium] - name: redis-operator releaseName: redis-operator - chart: cozy-redis-operator + chart: redis-operator namespace: cozy-redis-operator optional: true dependsOn: [cilium] - name: piraeus-operator releaseName: piraeus-operator - chart: cozy-piraeus-operator + chart: piraeus-operator namespace: cozy-linstor dependsOn: [cilium,cert-manager] - name: snapshot-controller releaseName: snapshot-controller - chart: cozy-snapshot-controller + chart: snapshot-controller namespace: cozy-snapshot-controller dependsOn: [cilium] - name: objectstorage-controller releaseName: objectstorage-controller - chart: cozy-objectstorage-controller + chart: objectstorage-controller namespace: cozy-objectstorage-controller optional: true dependsOn: [cilium] - name: linstor releaseName: linstor - chart: cozy-linstor + chart: linstor namespace: cozy-linstor privileged: true dependsOn: [piraeus-operator,cilium,cert-manager,snapshot-controller] - name: nfs-driver releaseName: nfs-driver - chart: cozy-nfs-driver + chart: nfs-driver namespace: cozy-nfs-driver privileged: true dependsOn: [cilium] @@ -218,42 +218,42 @@ releases: - name: telepresence releaseName: traffic-manager - chart: cozy-telepresence + chart: telepresence namespace: cozy-telepresence optional: true dependsOn: [] - name: external-dns releaseName: external-dns - chart: cozy-external-dns + chart: external-dns namespace: cozy-external-dns optional: true dependsOn: [cilium] - name: external-secrets-operator releaseName: external-secrets-operator - chart: cozy-external-secrets-operator + chart: external-secrets-operator namespace: cozy-external-secrets-operator optional: true dependsOn: [cilium] - name: keycloak releaseName: keycloak - chart: cozy-keycloak + chart: keycloak namespace: cozy-keycloak optional: true dependsOn: [postgres-operator] - name: keycloak-operator releaseName: keycloak-operator - chart: cozy-keycloak-operator + chart: keycloak-operator namespace: cozy-keycloak optional: true dependsOn: [keycloak] - name: bootbox releaseName: bootbox - chart: cozy-bootbox + chart: bootbox namespace: cozy-bootbox privileged: true optional: true @@ -261,12 +261,12 @@ releases: - name: reloader releaseName: reloader - chart: cozy-reloader + chart: reloader namespace: cozy-reloader - name: velero releaseName: velero - chart: cozy-velero + chart: velero namespace: cozy-velero privileged: true optional: true @@ -275,6 +275,6 @@ releases: - name: hetzner-robotlb releaseName: robotlb optional: true - chart: cozy-hetzner-robotlb + chart: hetzner-robotlb namespace: cozy-hetzner-robotlb dependsOn: [cilium] diff --git a/packages/core/platform/bundles/distro-hosted.yaml b/packages/core/platform/bundles/distro-hosted.yaml index 83aa81d9..c6ca13cc 100644 --- a/packages/core/platform/bundles/distro-hosted.yaml +++ b/packages/core/platform/bundles/distro-hosted.yaml @@ -4,14 +4,14 @@ releases: - name: fluxcd-operator releaseName: fluxcd-operator - chart: cozy-fluxcd-operator + chart: fluxcd-operator namespace: cozy-fluxcd privileged: true dependsOn: [] - name: fluxcd releaseName: fluxcd - chart: cozy-fluxcd + chart: fluxcd namespace: cozy-fluxcd dependsOn: [fluxcd-operator] values: @@ -22,13 +22,13 @@ releases: - name: cert-manager-crds releaseName: cert-manager-crds - chart: cozy-cert-manager-crds + chart: cert-manager-crds namespace: cozy-cert-manager dependsOn: [] - name: cozystack-controller releaseName: cozystack-controller - chart: cozy-cozystack-controller + chart: cozystack-controller namespace: cozy-system {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} values: @@ -38,33 +38,33 @@ releases: - name: lineage-controller-webhook releaseName: lineage-controller-webhook - chart: cozy-lineage-controller-webhook + chart: lineage-controller-webhook namespace: cozy-system dependsOn: [cozystack-controller,cert-manager] - name: cert-manager releaseName: cert-manager - chart: cozy-cert-manager + chart: cert-manager namespace: cozy-cert-manager dependsOn: [cert-manager-crds] - name: cert-manager-issuers releaseName: cert-manager-issuers - chart: cozy-cert-manager-issuers + chart: cert-manager-issuers namespace: cozy-cert-manager optional: true dependsOn: [cert-manager] - name: victoria-metrics-operator releaseName: victoria-metrics-operator - chart: cozy-victoria-metrics-operator + chart: victoria-metrics-operator namespace: cozy-victoria-metrics-operator optional: true dependsOn: [cert-manager] - name: monitoring-agents releaseName: monitoring-agents - chart: cozy-monitoring-agents + chart: monitoring-agents namespace: cozy-monitoring privileged: true optional: true @@ -76,21 +76,21 @@ releases: - name: etcd-operator releaseName: etcd-operator - chart: cozy-etcd-operator + chart: etcd-operator namespace: cozy-etcd-operator optional: true dependsOn: [cert-manager] - name: grafana-operator releaseName: grafana-operator - chart: cozy-grafana-operator + chart: grafana-operator namespace: cozy-grafana-operator optional: true dependsOn: [] - name: mariadb-operator releaseName: mariadb-operator - chart: cozy-mariadb-operator + chart: mariadb-operator namespace: cozy-mariadb-operator optional: true dependsOn: [victoria-metrics-operator] @@ -100,14 +100,14 @@ releases: - name: postgres-operator releaseName: postgres-operator - chart: cozy-postgres-operator + chart: postgres-operator namespace: cozy-postgres-operator optional: true dependsOn: [victoria-metrics-operator] - name: kafka-operator releaseName: kafka-operator - chart: cozy-kafka-operator + chart: kafka-operator namespace: cozy-kafka-operator optional: true dependsOn: [victoria-metrics-operator] @@ -117,70 +117,70 @@ releases: - name: clickhouse-operator releaseName: clickhouse-operator - chart: cozy-clickhouse-operator + chart: clickhouse-operator namespace: cozy-clickhouse-operator optional: true dependsOn: [victoria-metrics-operator] - name: foundationdb-operator releaseName: foundationdb-operator - chart: cozy-foundationdb-operator + chart: foundationdb-operator namespace: cozy-foundationdb-operator optional: true dependsOn: [cert-manager] - name: rabbitmq-operator releaseName: rabbitmq-operator - chart: cozy-rabbitmq-operator + chart: rabbitmq-operator namespace: cozy-rabbitmq-operator optional: true dependsOn: [] - name: redis-operator releaseName: redis-operator - chart: cozy-redis-operator + chart: redis-operator namespace: cozy-redis-operator optional: true dependsOn: [] - name: telepresence releaseName: traffic-manager - chart: cozy-telepresence + chart: telepresence namespace: cozy-telepresence optional: true dependsOn: [] - name: external-dns releaseName: external-dns - chart: cozy-external-dns + chart: external-dns namespace: cozy-external-dns optional: true dependsOn: [] - name: external-secrets-operator releaseName: external-secrets-operator - chart: cozy-external-secrets-operator + chart: external-secrets-operator namespace: cozy-external-secrets-operator optional: true dependsOn: [] - name: keycloak releaseName: keycloak - chart: cozy-keycloak + chart: keycloak namespace: cozy-keycloak optional: true dependsOn: [postgres-operator] - name: keycloak-operator releaseName: keycloak-operator - chart: cozy-keycloak-operator + chart: keycloak-operator namespace: cozy-keycloak optional: true dependsOn: [keycloak] - name: velero releaseName: velero - chart: cozy-velero + chart: velero namespace: cozy-velero privileged: true optional: true @@ -188,5 +188,5 @@ releases: - name: hetzner-robotlb releaseName: robotlb optional: true - chart: cozy-hetzner-robotlb + chart: hetzner-robotlb namespace: cozy-hetzner-robotlb diff --git a/packages/core/platform/bundles/paas-full.yaml b/packages/core/platform/bundles/paas-full.yaml index 4382bd62..be1c4b44 100644 --- a/packages/core/platform/bundles/paas-full.yaml +++ b/packages/core/platform/bundles/paas-full.yaml @@ -13,14 +13,14 @@ releases: - name: fluxcd-operator releaseName: fluxcd-operator - chart: cozy-fluxcd-operator + chart: fluxcd-operator namespace: cozy-fluxcd privileged: true dependsOn: [] - name: fluxcd releaseName: fluxcd - chart: cozy-fluxcd + chart: fluxcd namespace: cozy-fluxcd dependsOn: [fluxcd-operator,cilium,kubeovn] values: @@ -31,7 +31,7 @@ releases: - name: cilium releaseName: cilium - chart: cozy-cilium + chart: cilium namespace: cozy-cilium privileged: true dependsOn: [] @@ -42,14 +42,14 @@ releases: - name: cilium-networkpolicy releaseName: cilium-networkpolicy - chart: cozy-cilium-networkpolicy + chart: cilium-networkpolicy namespace: cozy-cilium privileged: true dependsOn: [cilium] - name: kubeovn releaseName: kubeovn - chart: cozy-kubeovn + chart: kubeovn namespace: cozy-kubeovn privileged: true dependsOn: [cilium] @@ -65,45 +65,45 @@ releases: - name: kubeovn-webhook releaseName: kubeovn-webhook - chart: cozy-kubeovn-webhook + chart: kubeovn-webhook namespace: cozy-kubeovn privileged: true dependsOn: [cilium,kubeovn,cert-manager] - name: kubeovn-plunger releaseName: kubeovn-plunger - chart: cozy-kubeovn-plunger + chart: kubeovn-plunger namespace: cozy-kubeovn dependsOn: [cilium,kubeovn] - name: multus releaseName: multus - chart: cozy-multus + chart: multus namespace: cozy-multus privileged: true dependsOn: [cilium,kubeovn] - name: cozy-proxy releaseName: cozystack - chart: cozy-cozy-proxy + chart: cozy-proxy namespace: cozy-system dependsOn: [cilium,kubeovn] - name: cert-manager-crds releaseName: cert-manager-crds - chart: cozy-cert-manager-crds + chart: cert-manager-crds namespace: cozy-cert-manager dependsOn: [cilium, kubeovn] - name: cozystack-api releaseName: cozystack-api - chart: cozy-cozystack-api + chart: cozystack-api namespace: cozy-system dependsOn: [cilium,kubeovn,cozystack-controller] - name: cozystack-controller releaseName: cozystack-controller - chart: cozy-cozystack-controller + chart: cozystack-controller namespace: cozy-system dependsOn: [cilium,kubeovn] {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} @@ -114,7 +114,7 @@ releases: - name: lineage-controller-webhook releaseName: lineage-controller-webhook - chart: cozy-lineage-controller-webhook + chart: lineage-controller-webhook namespace: cozy-system dependsOn: [cozystack-controller,cilium,kubeovn,cert-manager] @@ -132,25 +132,25 @@ releases: - name: cert-manager releaseName: cert-manager - chart: cozy-cert-manager + chart: cert-manager namespace: cozy-cert-manager dependsOn: [cert-manager-crds] - name: cert-manager-issuers releaseName: cert-manager-issuers - chart: cozy-cert-manager-issuers + chart: cert-manager-issuers namespace: cozy-cert-manager dependsOn: [cilium,kubeovn,cert-manager] - name: victoria-metrics-operator releaseName: victoria-metrics-operator - chart: cozy-victoria-metrics-operator + chart: victoria-metrics-operator namespace: cozy-victoria-metrics-operator dependsOn: [cilium,kubeovn,cert-manager] - name: monitoring-agents releaseName: monitoring-agents - chart: cozy-monitoring-agents + chart: monitoring-agents namespace: cozy-monitoring privileged: true dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] @@ -161,13 +161,13 @@ releases: - name: kubevirt-operator releaseName: kubevirt-operator - chart: cozy-kubevirt-operator + chart: kubevirt-operator namespace: cozy-kubevirt dependsOn: [cilium,kubeovn,victoria-metrics-operator] - name: kubevirt releaseName: kubevirt - chart: cozy-kubevirt + chart: kubevirt namespace: cozy-kubevirt privileged: true dependsOn: [cilium,kubeovn,kubevirt-operator] @@ -179,25 +179,25 @@ releases: - name: kubevirt-instancetypes releaseName: kubevirt-instancetypes - chart: cozy-kubevirt-instancetypes + chart: kubevirt-instancetypes namespace: cozy-kubevirt dependsOn: [cilium,kubeovn,kubevirt-operator,kubevirt] - name: kubevirt-cdi-operator releaseName: kubevirt-cdi-operator - chart: cozy-kubevirt-cdi-operator + chart: kubevirt-cdi-operator namespace: cozy-kubevirt-cdi dependsOn: [cilium,kubeovn] - name: kubevirt-cdi releaseName: kubevirt-cdi - chart: cozy-kubevirt-cdi + chart: kubevirt-cdi namespace: cozy-kubevirt-cdi dependsOn: [cilium,kubeovn,kubevirt-cdi-operator] - name: gpu-operator releaseName: gpu-operator - chart: cozy-gpu-operator + chart: gpu-operator namespace: cozy-gpu-operator privileged: true optional: true @@ -208,26 +208,26 @@ releases: - name: metallb releaseName: metallb - chart: cozy-metallb + chart: metallb namespace: cozy-metallb privileged: true dependsOn: [cilium,kubeovn] - name: etcd-operator releaseName: etcd-operator - chart: cozy-etcd-operator + chart: etcd-operator namespace: cozy-etcd-operator dependsOn: [cilium,kubeovn,cert-manager] - name: grafana-operator releaseName: grafana-operator - chart: cozy-grafana-operator + chart: grafana-operator namespace: cozy-grafana-operator dependsOn: [cilium,kubeovn] - name: mariadb-operator releaseName: mariadb-operator - chart: cozy-mariadb-operator + chart: mariadb-operator namespace: cozy-mariadb-operator dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] values: @@ -236,13 +236,13 @@ releases: - name: postgres-operator releaseName: postgres-operator - chart: cozy-postgres-operator + chart: postgres-operator namespace: cozy-postgres-operator dependsOn: [cilium,kubeovn,cert-manager] - name: kafka-operator releaseName: kafka-operator - chart: cozy-kafka-operator + chart: kafka-operator namespace: cozy-kafka-operator dependsOn: [cilium,kubeovn,victoria-metrics-operator] values: @@ -251,44 +251,44 @@ releases: - name: clickhouse-operator releaseName: clickhouse-operator - chart: cozy-clickhouse-operator + chart: clickhouse-operator namespace: cozy-clickhouse-operator dependsOn: [cilium,kubeovn,victoria-metrics-operator] - name: foundationdb-operator releaseName: foundationdb-operator - chart: cozy-foundationdb-operator + chart: foundationdb-operator namespace: cozy-foundationdb-operator dependsOn: [cilium,kubeovn,cert-manager] - name: rabbitmq-operator releaseName: rabbitmq-operator - chart: cozy-rabbitmq-operator + chart: rabbitmq-operator namespace: cozy-rabbitmq-operator dependsOn: [cilium,kubeovn] - name: redis-operator releaseName: redis-operator - chart: cozy-redis-operator + chart: redis-operator namespace: cozy-redis-operator dependsOn: [cilium,kubeovn] - name: piraeus-operator releaseName: piraeus-operator - chart: cozy-piraeus-operator + chart: piraeus-operator namespace: cozy-linstor dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] - name: linstor releaseName: linstor - chart: cozy-linstor + chart: linstor namespace: cozy-linstor privileged: true dependsOn: [piraeus-operator,cilium,kubeovn,cert-manager,snapshot-controller] - name: nfs-driver releaseName: nfs-driver - chart: cozy-nfs-driver + chart: nfs-driver namespace: cozy-nfs-driver privileged: true dependsOn: [cilium,kubeovn] @@ -296,26 +296,26 @@ releases: - name: snapshot-controller releaseName: snapshot-controller - chart: cozy-snapshot-controller + chart: snapshot-controller namespace: cozy-snapshot-controller dependsOn: [cilium,kubeovn,cert-manager-issuers] - name: objectstorage-controller releaseName: objectstorage-controller - chart: cozy-objectstorage-controller + chart: objectstorage-controller namespace: cozy-objectstorage-controller dependsOn: [cilium,kubeovn] - name: telepresence releaseName: traffic-manager - chart: cozy-telepresence + chart: telepresence namespace: cozy-telepresence optional: true dependsOn: [cilium,kubeovn] - name: dashboard releaseName: dashboard - chart: cozy-dashboard + chart: dashboard namespace: cozy-dashboard values: {{- $dashboardKCconfig := lookup "v1" "ConfigMap" "cozy-dashboard" "kubeapps-auth-config" }} @@ -330,62 +330,62 @@ releases: - name: kamaji releaseName: kamaji - chart: cozy-kamaji + chart: kamaji namespace: cozy-kamaji dependsOn: [cilium,kubeovn,cert-manager] - name: capi-operator releaseName: capi-operator - chart: cozy-capi-operator + chart: capi-operator namespace: cozy-cluster-api privileged: true dependsOn: [cilium,kubeovn,cert-manager] - name: capi-providers-bootstrap releaseName: capi-providers-bootstrap - chart: cozy-capi-providers-bootstrap + chart: capi-providers-bootstrap namespace: cozy-cluster-api privileged: true dependsOn: [cilium,kubeovn,capi-operator] - name: capi-providers-core releaseName: capi-providers-core - chart: cozy-capi-providers-core + chart: capi-providers-core namespace: cozy-cluster-api privileged: true dependsOn: [cilium,kubeovn,capi-operator] - name: capi-providers-cpprovider releaseName: capi-providers-cpprovider - chart: cozy-capi-providers-cpprovider + chart: capi-providers-cpprovider namespace: cozy-cluster-api privileged: true dependsOn: [cilium,kubeovn,capi-operator] - name: capi-providers-infraprovider releaseName: capi-providers-infraprovider - chart: cozy-capi-providers-infraprovider + chart: capi-providers-infraprovider namespace: cozy-cluster-api privileged: true dependsOn: [cilium,kubeovn,capi-operator] - name: external-dns releaseName: external-dns - chart: cozy-external-dns + chart: external-dns namespace: cozy-external-dns optional: true dependsOn: [cilium,kubeovn] - name: external-secrets-operator releaseName: external-secrets-operator - chart: cozy-external-secrets-operator + chart: external-secrets-operator namespace: cozy-external-secrets-operator optional: true dependsOn: [cilium,kubeovn] - name: bootbox releaseName: bootbox - chart: cozy-bootbox + chart: bootbox namespace: cozy-bootbox privileged: true optional: true @@ -394,19 +394,19 @@ releases: {{- if $oidcEnabled }} - name: keycloak releaseName: keycloak - chart: cozy-keycloak + chart: keycloak namespace: cozy-keycloak dependsOn: [postgres-operator] - name: keycloak-operator releaseName: keycloak-operator - chart: cozy-keycloak-operator + chart: keycloak-operator namespace: cozy-keycloak dependsOn: [keycloak] - name: keycloak-configure releaseName: keycloak-configure - chart: cozy-keycloak-configure + chart: keycloak-configure namespace: cozy-keycloak dependsOn: [keycloak-operator] values: @@ -416,14 +416,14 @@ releases: - name: goldpinger releaseName: goldpinger - chart: cozy-goldpinger + chart: goldpinger namespace: cozy-goldpinger privileged: true dependsOn: [monitoring-agents] - name: vertical-pod-autoscaler releaseName: vertical-pod-autoscaler - chart: cozy-vertical-pod-autoscaler + chart: vertical-pod-autoscaler namespace: cozy-vertical-pod-autoscaler privileged: true dependsOn: [monitoring-agents] @@ -435,19 +435,19 @@ releases: - name: vertical-pod-autoscaler-crds releaseName: vertical-pod-autoscaler-crds - chart: cozy-vertical-pod-autoscaler-crds + chart: vertical-pod-autoscaler-crds namespace: cozy-vertical-pod-autoscaler privileged: true dependsOn: [cilium, kubeovn] - name: reloader releaseName: reloader - chart: cozy-reloader + chart: reloader namespace: cozy-reloader - name: velero releaseName: velero - chart: cozy-velero + chart: velero namespace: cozy-velero privileged: true optional: true @@ -456,6 +456,6 @@ releases: - name: hetzner-robotlb releaseName: robotlb optional: true - chart: cozy-hetzner-robotlb + chart: hetzner-robotlb namespace: cozy-hetzner-robotlb dependsOn: [cilium, kubeovn] diff --git a/packages/core/platform/bundles/paas-hosted.yaml b/packages/core/platform/bundles/paas-hosted.yaml index 560578c7..3187c5a2 100644 --- a/packages/core/platform/bundles/paas-hosted.yaml +++ b/packages/core/platform/bundles/paas-hosted.yaml @@ -13,14 +13,14 @@ releases: - name: fluxcd-operator releaseName: fluxcd-operator - chart: cozy-fluxcd-operator + chart: fluxcd-operator namespace: cozy-fluxcd privileged: true dependsOn: [] - name: fluxcd releaseName: fluxcd - chart: cozy-fluxcd + chart: fluxcd namespace: cozy-fluxcd dependsOn: [fluxcd-operator] values: @@ -31,13 +31,13 @@ releases: - name: cert-manager-crds releaseName: cert-manager-crds - chart: cozy-cert-manager-crds + chart: cert-manager-crds namespace: cozy-cert-manager dependsOn: [] - name: cozystack-api releaseName: cozystack-api - chart: cozy-cozystack-api + chart: cozystack-api namespace: cozy-system dependsOn: [cozystack-controller] values: @@ -47,7 +47,7 @@ releases: - name: cozystack-controller releaseName: cozystack-controller - chart: cozy-cozystack-controller + chart: cozystack-controller namespace: cozy-system dependsOn: [] {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} @@ -58,7 +58,7 @@ releases: - name: lineage-controller-webhook releaseName: lineage-controller-webhook - chart: cozy-lineage-controller-webhook + chart: lineage-controller-webhook namespace: cozy-system dependsOn: [cozystack-controller,cert-manager] @@ -76,25 +76,25 @@ releases: - name: cert-manager releaseName: cert-manager - chart: cozy-cert-manager + chart: cert-manager namespace: cozy-cert-manager dependsOn: [cert-manager-crds] - name: cert-manager-issuers releaseName: cert-manager-issuers - chart: cozy-cert-manager-issuers + chart: cert-manager-issuers namespace: cozy-cert-manager dependsOn: [cert-manager] - name: victoria-metrics-operator releaseName: victoria-metrics-operator - chart: cozy-victoria-metrics-operator + chart: victoria-metrics-operator namespace: cozy-victoria-metrics-operator dependsOn: [cert-manager] - name: monitoring-agents releaseName: monitoring-agents - chart: cozy-monitoring-agents + chart: monitoring-agents namespace: cozy-monitoring privileged: true dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] @@ -105,19 +105,19 @@ releases: - name: etcd-operator releaseName: etcd-operator - chart: cozy-etcd-operator + chart: etcd-operator namespace: cozy-etcd-operator dependsOn: [cert-manager] - name: grafana-operator releaseName: grafana-operator - chart: cozy-grafana-operator + chart: grafana-operator namespace: cozy-grafana-operator dependsOn: [] - name: mariadb-operator releaseName: mariadb-operator - chart: cozy-mariadb-operator + chart: mariadb-operator namespace: cozy-mariadb-operator dependsOn: [cert-manager,victoria-metrics-operator] values: @@ -126,13 +126,13 @@ releases: - name: postgres-operator releaseName: postgres-operator - chart: cozy-postgres-operator + chart: postgres-operator namespace: cozy-postgres-operator dependsOn: [cert-manager,victoria-metrics-operator] - name: kafka-operator releaseName: kafka-operator - chart: cozy-kafka-operator + chart: kafka-operator namespace: cozy-kafka-operator dependsOn: [victoria-metrics-operator] values: @@ -141,64 +141,64 @@ releases: - name: clickhouse-operator releaseName: clickhouse-operator - chart: cozy-clickhouse-operator + chart: clickhouse-operator namespace: cozy-clickhouse-operator dependsOn: [victoria-metrics-operator] - name: foundationdb-operator releaseName: foundationdb-operator - chart: cozy-foundationdb-operator + chart: foundationdb-operator namespace: cozy-foundationdb-operator dependsOn: [cert-manager] - name: rabbitmq-operator releaseName: rabbitmq-operator - chart: cozy-rabbitmq-operator + chart: rabbitmq-operator namespace: cozy-rabbitmq-operator dependsOn: [] - name: redis-operator releaseName: redis-operator - chart: cozy-redis-operator + chart: redis-operator namespace: cozy-redis-operator dependsOn: [] - name: piraeus-operator releaseName: piraeus-operator - chart: cozy-piraeus-operator + chart: piraeus-operator namespace: cozy-linstor dependsOn: [cert-manager] - name: objectstorage-controller releaseName: objectstorage-controller - chart: cozy-objectstorage-controller + chart: objectstorage-controller namespace: cozy-objectstorage-controller dependsOn: [] - name: telepresence releaseName: traffic-manager - chart: cozy-telepresence + chart: telepresence namespace: cozy-telepresence optional: true dependsOn: [] - name: external-dns releaseName: external-dns - chart: cozy-external-dns + chart: external-dns namespace: cozy-external-dns optional: true dependsOn: [] - name: external-secrets-operator releaseName: external-secrets-operator - chart: cozy-external-secrets-operator + chart: external-secrets-operator namespace: cozy-external-secrets-operator optional: true dependsOn: [] - name: dashboard releaseName: dashboard - chart: cozy-dashboard + chart: dashboard namespace: cozy-dashboard values: {{- $dashboardKCconfig := lookup "v1" "ConfigMap" "cozy-dashboard" "kubeapps-auth-config" }} @@ -213,19 +213,19 @@ releases: {{- if $oidcEnabled }} - name: keycloak releaseName: keycloak - chart: cozy-keycloak + chart: keycloak namespace: cozy-keycloak dependsOn: [postgres-operator] - name: keycloak-operator releaseName: keycloak-operator - chart: cozy-keycloak-operator + chart: keycloak-operator namespace: cozy-keycloak dependsOn: [keycloak] - name: keycloak-configure releaseName: keycloak-configure - chart: cozy-keycloak-configure + chart: keycloak-configure namespace: cozy-keycloak dependsOn: [keycloak-operator] values: @@ -235,14 +235,14 @@ releases: - name: goldpinger releaseName: goldpinger - chart: cozy-goldpinger + chart: goldpinger namespace: cozy-goldpinger privileged: true dependsOn: [monitoring-agents] - name: vertical-pod-autoscaler releaseName: vertical-pod-autoscaler - chart: cozy-vertical-pod-autoscaler + chart: vertical-pod-autoscaler namespace: cozy-vertical-pod-autoscaler privileged: true dependsOn: [monitoring-agents] @@ -254,14 +254,14 @@ releases: - name: vertical-pod-autoscaler-crds releaseName: vertical-pod-autoscaler-crds - chart: cozy-vertical-pod-autoscaler-crds + chart: vertical-pod-autoscaler-crds namespace: cozy-vertical-pod-autoscaler privileged: true dependsOn: [] - name: velero releaseName: velero - chart: cozy-velero + chart: velero namespace: cozy-velero privileged: true optional: true @@ -270,5 +270,5 @@ releases: - name: hetzner-robotlb releaseName: robotlb optional: true - chart: cozy-hetzner-robotlb + chart: hetzner-robotlb namespace: cozy-hetzner-robotlb diff --git a/packages/core/platform/templates/bundles-configmap.yaml b/packages/core/platform/templates/bundles-configmap.yaml index d10811fb..7ac0285b 100644 --- a/packages/core/platform/templates/bundles-configmap.yaml +++ b/packages/core/platform/templates/bundles-configmap.yaml @@ -7,11 +7,11 @@ metadata: cozystack.io/system: "true" data: paas-full.yaml: | -{{- trim (tpl (.Files.Get "bundles/paas-full.yaml") .) | indent 4 }} + {{- trim (tpl (.Files.Get "bundles/paas-full.yaml") .) | nindent 4 }} paas-hosted.yaml: | -{{- trim (tpl (.Files.Get "bundles/paas-hosted.yaml") .) | indent 4 }} + {{- trim (tpl (.Files.Get "bundles/paas-hosted.yaml") .) | nindent 4 }} distro-full.yaml: | -{{- trim (tpl (.Files.Get "bundles/distro-full.yaml") .) | indent 4 }} + {{- trim (tpl (.Files.Get "bundles/distro-full.yaml") .) | nindent 4 }} distro-hosted.yaml: | -{{- trim (tpl (.Files.Get "bundles/distro-hosted.yaml") .) | indent 4 }} + {{- trim (tpl (.Files.Get "bundles/distro-hosted.yaml") .) | nindent 4 }} diff --git a/packages/extra/ingress/templates/nginx-ingress.yaml b/packages/extra/ingress/templates/nginx-ingress.yaml index d15e00f4..13a51494 100644 --- a/packages/extra/ingress/templates/nginx-ingress.yaml +++ b/packages/extra/ingress/templates/nginx-ingress.yaml @@ -8,7 +8,7 @@ metadata: spec: chartRef: kind: ExternalArtifact - name: system-cozy-ingress-nginx + name: system-ingress-nginx namespace: cozy-system interval: 5m timeout: 10m diff --git a/packages/extra/seaweedfs/templates/seaweedfs.yaml b/packages/extra/seaweedfs/templates/seaweedfs.yaml index 303f4f34..d57d15be 100644 --- a/packages/extra/seaweedfs/templates/seaweedfs.yaml +++ b/packages/extra/seaweedfs/templates/seaweedfs.yaml @@ -44,7 +44,7 @@ metadata: spec: chartRef: kind: ExternalArtifact - name: system-cozy-seaweedfs + name: system-seaweedfs namespace: cozy-system interval: 5m timeout: 10m diff --git a/packages/system/vertical-pod-autoscaler/templates/vpa-for-vpa.yaml b/packages/system/vertical-pod-autoscaler/templates/vpa-for-vpa.yaml index 5fb35fca..02c4cdc9 100644 --- a/packages/system/vertical-pod-autoscaler/templates/vpa-for-vpa.yaml +++ b/packages/system/vertical-pod-autoscaler/templates/vpa-for-vpa.yaml @@ -16,15 +16,10 @@ metadata: name: vpa-for-vpa namespace: cozy-vpa-for-vpa spec: - chart: - spec: - chart: cozy-vertical-pod-autoscaler - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' + chartRef: + kind: ExternalArtifact + name: system-vertical-pod-autoscaler + namespace: cozy-system dependsOn: - name: monitoring-agents namespace: cozy-monitoring diff --git a/scripts/migrations/22 b/scripts/migrations/22 new file mode 100755 index 00000000..8242b894 --- /dev/null +++ b/scripts/migrations/22 @@ -0,0 +1,103 @@ +#!/bin/sh +# Migration 22 --> 23 + +set -euo pipefail + +echo "Migrating HelmReleases from spec.chart to spec.chartRef" + +# Process all HelmReleases that still use spec.chart (old format) +kubectl get helmreleases --all-namespaces -o json -l cozystack.io/ui=true | \ + jq -r '.items[] | select(.spec.chart != null) | "\(.metadata.namespace)|\(.metadata.name)"' | \ + while IFS='|' read -r namespace name; do + echo "Processing HelmRelease $namespace/$name" + + # Get the HelmRelease again to extract fields safely + hr_json=$(kubectl get helmrelease -n "$namespace" "$name" -o json 2>/dev/null) + if [ -z "$hr_json" ]; then + echo "Skipping $namespace/$name: failed to get HelmRelease" + continue + fi + + # Extract chart name and sourceRef + chart_name=$(printf '%s' "$hr_json" | jq -r '.spec.chart.spec.chart // empty') + source_kind=$(printf '%s' "$hr_json" | jq -r '.spec.chart.spec.sourceRef.kind // empty') + source_name=$(printf '%s' "$hr_json" | jq -r '.spec.chart.spec.sourceRef.name // empty') + source_namespace=$(printf '%s' "$hr_json" | jq -r '.spec.chart.spec.sourceRef.namespace // empty') + + # Skip if already migrated or missing required fields + if [ -z "$chart_name" ] || [ -z "$source_name" ] || [ "$source_kind" != "HelmRepository" ]; then + echo "Skipping $namespace/$name: missing required fields or not using HelmRepository" + continue + fi + + # Skip cozystack-system repository + if [ "$source_name" = "cozystack-system" ]; then + echo "Skipping $namespace/$name: cozystack-system repository not supported for migration" + continue + fi + + # Determine artifact prefix and namespace based on repository name or namespace + artifact_prefix="" + artifact_namespace="cozy-public" + + if [ "$namespace" = "cozy-system" ]; then + # System resources always use system- prefix in cozy-system namespace + artifact_prefix="system" + artifact_namespace="cozy-system" + elif [ "$source_name" = "cozystack-apps" ]; then + # Apps repository -> apps- prefix in cozy-public namespace + artifact_prefix="apps" + artifact_namespace="cozy-public" + elif [ "$source_name" = "cozystack-extra" ]; then + # Extra repository -> extra- prefix in cozy-public namespace + artifact_prefix="extra" + artifact_namespace="cozy-public" + else + echo "Skipping $namespace/$name: unknown repository $source_name" + continue + fi + + # Build artifact name + artifact_name="${artifact_prefix}-${chart_name}" + + echo "Migrating $namespace/$name: $chart_name -> $artifact_name (from $source_name)" + + # Check if already migrated (has chartRef with correct artifact name) + current_chart_ref=$(printf '%s' "$hr_json" | jq -r '.spec.chartRef.name // empty') + if [ "$current_chart_ref" = "$artifact_name" ]; then + echo "Already migrated $namespace/$name, skipping" + continue + fi + + # Build JSON patch operations + # Remove spec.chart if it exists + # Add/replace spec.chartRef + patch_ops="[]" + has_chart=$(printf '%s' "$hr_json" | jq -e '.spec.chart != null' > /dev/null 2>&1 && echo "true" || echo "false") + has_chart_ref=$(printf '%s' "$hr_json" | jq -e '.spec.chartRef != null' > /dev/null 2>&1 && echo "true" || echo "false") + + if [ "$has_chart" = "true" ]; then + patch_ops=$(printf '%s' "$patch_ops" | jq ". + [{\"op\": \"remove\", \"path\": \"/spec/chart\"}]") + fi + + if [ "$has_chart_ref" = "true" ]; then + patch_ops=$(printf '%s' "$patch_ops" | jq ". + [{\"op\": \"replace\", \"path\": \"/spec/chartRef\", \"value\": {\"kind\": \"ExternalArtifact\", \"name\": \"$artifact_name\", \"namespace\": \"$artifact_namespace\"}}]") + else + patch_ops=$(printf '%s' "$patch_ops" | jq ". + [{\"op\": \"add\", \"path\": \"/spec/chartRef\", \"value\": {\"kind\": \"ExternalArtifact\", \"name\": \"$artifact_name\", \"namespace\": \"$artifact_namespace\"}}]") + fi + + # Apply patch if there are operations to perform + if printf '%s' "$patch_ops" | jq -e 'length > 0' > /dev/null 2>&1; then + printf '%s' "$patch_ops" | kubectl patch helmrelease -n "$namespace" "$name" --type json --patch-file /dev/stdin + echo "Migrated $namespace/$name" + else + echo "No changes needed for $namespace/$name" + fi + done + +echo "Migration completed" + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=23 --dry-run=client -o yaml | kubectl apply -f- + From 2113d17a542381ae8305d039229f6063cbf70b14 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 19 Nov 2025 14:47:15 +0100 Subject: [PATCH 08/46] fix dependencies Signed-off-by: Andrei Kvapil --- go.mod | 16 +-- go.sum | 115 ++++-------------- .../images/cozystack-api/Dockerfile | 2 +- .../images/cozystack-controller/Dockerfile | 2 +- .../lineage-controller-webhook/Dockerfile | 2 +- pkg/cmd/server/start.go | 96 +++++++-------- pkg/cmd/server/start_test.go | 30 +++-- 7 files changed, 95 insertions(+), 168 deletions(-) diff --git a/go.mod b/go.mod index 92fc3bc9..90b65a70 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ go 1.25.0 require ( 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 @@ -17,6 +18,7 @@ require ( github.com/stretchr/testify v1.11.1 go.uber.org/zap v1.27.0 gopkg.in/yaml.v2 v2.4.0 + gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.34.1 k8s.io/apiextensions-apiserver v0.34.1 k8s.io/apimachinery v0.34.1 @@ -34,14 +36,12 @@ require ( cel.dev/expr v0.24.0 // indirect github.com/NYTimes/gziphandler v1.1.1 // 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/blang/semver/v4 v4.0.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/cyphar/filepath-securejoin v0.4.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.12.2 // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect @@ -50,11 +50,6 @@ require ( github.com/fluxcd/pkg/apis/acl v0.9.0 // indirect github.com/fluxcd/pkg/apis/kustomize v1.13.0 // indirect github.com/fluxcd/pkg/apis/meta v1.22.0 // indirect - github.com/fluxcd/pkg/http/fetch v0.15.0 // indirect - github.com/fluxcd/pkg/runtime v0.60.0 // indirect - github.com/fluxcd/pkg/tar v0.12.0 // indirect - github.com/fluxcd/source-watcher v1.3.0 // indirect - github.com/fluxcd/source-watcher/api/v2 v2.0.2 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -73,12 +68,9 @@ require ( 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/grpc-gateway/v2 v2.26.3 // indirect - github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/moby/spdystream v0.5.0 // indirect @@ -86,8 +78,6 @@ require ( github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/go-digest/blake3 v0.0.0-20240426182413-22b78e47854a // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.1 // indirect @@ -96,7 +86,6 @@ require ( github.com/spf13/pflag v1.0.7 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect github.com/x448/float16 v0.8.4 // indirect - github.com/zeebo/blake3 v0.2.4 // indirect go.etcd.io/etcd/api/v3 v3.6.4 // indirect go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect go.etcd.io/etcd/client/v3 v3.6.4 // indirect @@ -131,7 +120,6 @@ require ( gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/kms v0.34.1 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect diff --git a/go.sum b/go.sum index 1da2dc3a..d69a78f6 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,6 @@ github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8 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/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/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= @@ -21,9 +19,6 @@ github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03V 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/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/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= -github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= 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.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -38,30 +33,16 @@ github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjT 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/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fluxcd/helm-controller/api v1.1.0 h1:NS5Wm3U6Kv4w7Cw2sDOV++vf2ecGfFV00x1+2Y3QcOY= -github.com/fluxcd/helm-controller/api v1.1.0/go.mod h1:BgHMgMY6CWynzl4KIbHpd6Wpn3FN9BqgkwmvoKCp6iE= github.com/fluxcd/helm-controller/api v1.4.3 h1:CdZwjL1liXmYCWyk2jscmFEB59tICIlnWB9PfDDW5q4= github.com/fluxcd/helm-controller/api v1.4.3/go.mod h1:0XrBhKEaqvxyDj/FziG1Q8Fmx2UATdaqLgYqmZh6wW4= github.com/fluxcd/pkg/apis/acl v0.9.0 h1:wBpgsKT+jcyZEcM//OmZr9RiF8klL3ebrDp2u2ThsnA= github.com/fluxcd/pkg/apis/acl v0.9.0/go.mod h1:TttNS+gocsGLwnvmgVi3/Yscwqrjc17+vhgYfqkfrV4= -github.com/fluxcd/pkg/apis/kustomize v1.6.1 h1:22FJc69Mq4i8aCxnKPlddHhSMyI4UPkQkqiAdWFcqe0= -github.com/fluxcd/pkg/apis/kustomize v1.6.1/go.mod h1:5dvQ4IZwz0hMGmuj8tTWGtarsuxW0rWsxJOwC6i+0V8= github.com/fluxcd/pkg/apis/kustomize v1.13.0 h1:GGf0UBVRIku+gebY944icVeEIhyg1P/KE3IrhOyJJnE= github.com/fluxcd/pkg/apis/kustomize v1.13.0/go.mod h1:TLKVqbtnzkhDuhWnAsN35977HvRfIjs+lgMuNro/LEc= github.com/fluxcd/pkg/apis/meta v1.22.0 h1:EHWQH5ZWml7i8eZ/AMjm1jxid3j/PQ31p+hIwCt6crM= github.com/fluxcd/pkg/apis/meta v1.22.0/go.mod h1:Kc1+bWe5p0doROzuV9XiTfV/oL3ddsemYXt8ZYWdVVg= -github.com/fluxcd/pkg/http/fetch v0.15.0 h1:AJ1JuE2asuK4QMfbHjxctFURke5FvZtyljjI1Qv4ArQ= -github.com/fluxcd/pkg/http/fetch v0.15.0/go.mod h1:feTESfETKU14jq+e/Ce8QnMBTCh9O79bLMSMe5t55fQ= -github.com/fluxcd/pkg/runtime v0.60.0 h1:d++EkV3FlycB+bzakB5NumwY4J8xts8i7lbvD6jBLeU= -github.com/fluxcd/pkg/runtime v0.60.0/go.mod h1:UeU0/eZLErYC/1bTmgzBfNXhiHy9fuQzjfLK0HxRgxY= -github.com/fluxcd/pkg/tar v0.12.0 h1:og6F+ivnWNRbNJSq0ukCTVs7YrGIlzjxSVZU+E8NprM= -github.com/fluxcd/pkg/tar v0.12.0/go.mod h1:Ra5Cj++MD5iCy7bZGKJJX3GpOeMPv+ZDkPO9bBwpDeU= -github.com/fluxcd/source-controller/api v1.4.1 h1:zV01D7xzHOXWbYXr36lXHWWYS7POARsjLt61Nbh3kVY= -github.com/fluxcd/source-controller/api v1.4.1/go.mod h1:gSjg57T+IG66SsBR0aquv+DFrm4YyBNpKIJVDnu3Ya8= github.com/fluxcd/source-controller/api v1.6.2 h1:UmodAeqLIeF29HdTqf2GiacZyO+hJydJlepDaYsMvhc= github.com/fluxcd/source-controller/api v1.6.2/go.mod h1:ZJcAi0nemsnBxjVgmJl0WQzNvB0rMETxQMTdoFosmMw= -github.com/fluxcd/source-watcher v1.3.0 h1:G88lVPkHvtx16mzhEE7oNaOtBoSpzYIsoIpFI709/A0= -github.com/fluxcd/source-watcher v1.3.0/go.mod h1:NHAT0zD/pNoPVtHRY712nffO+m9dtfqycIOrWQhboO8= 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= @@ -75,14 +56,10 @@ 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/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= 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/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.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= 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/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= @@ -90,8 +67,8 @@ 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/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 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/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= @@ -106,29 +83,24 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX 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/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= 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/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= 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 v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA= +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/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= -github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= -github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 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.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I= +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/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -137,19 +109,12 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 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/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= -github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 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/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= 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= @@ -164,16 +129,10 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq 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/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= -github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= -github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= -github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= -github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= -github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/go-digest/blake3 v0.0.0-20240426182413-22b78e47854a h1:xwooQrLddjfeKhucuLS4ElD3TtuuRwF8QWC9eHrnbxY= -github.com/opencontainers/go-digest/blake3 v0.0.0-20240426182413-22b78e47854a/go.mod h1:kqQaIc6bZstKgnGpL7GD5dWoLKbA6mH1Y9ULjGImBnM= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 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= @@ -196,7 +155,6 @@ github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/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= @@ -211,35 +169,30 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV 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.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= 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/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= 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/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk= +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.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= -github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= -go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= -go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= +go.etcd.io/bbolt v1.4.2 h1:IrUHp260R8c+zYx/Tm8QZr04CX+qWS5PGfPdevhdm1I= +go.etcd.io/bbolt v1.4.2/go.mod h1:Is8rSHO/b4f3XigBC0lL0+4FwAQv3HXEEIgFMuKHceM= go.etcd.io/etcd/api/v3 v3.6.4 h1:7F6N7toCKcV72QmoUKa23yYLiiljMrT4xCeBL9BmXdo= go.etcd.io/etcd/api/v3 v3.6.4/go.mod h1:eFhhvfR8Px1P6SEuLT600v+vrhdDTdcfMzmnxVXXSbk= go.etcd.io/etcd/client/pkg/v3 v3.6.4 h1:9HBYrjppeOfFjBjaMTRxT3R7xT0GLK8EJMVC4xg6ok0= 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/v2 v2.305.13/go.mod h1:iQnL7fepbiomdXMb3om1rHq96htNNGv2sJkEcZGDRRg= go.etcd.io/etcd/client/v3 v3.6.4 h1:YOMrCfMhRzY8NgtzUsHl8hC2EBSnuqbR3dh84Uryl7A= go.etcd.io/etcd/client/v3 v3.6.4/go.mod h1:jaNNHCyg2FdALyKWnd7hxZXZxZANb0+KGY+YQaEMISo= -go.etcd.io/etcd/pkg/v3 v3.5.13 h1:st9bDWNsKkBNpP4PR1MvM/9NqUPfvYZx/YXegsYEH8M= -go.etcd.io/etcd/pkg/v3 v3.5.13/go.mod h1:N+4PLrp7agI/Viy+dUYpX7iRtSPvKq+w8Y14d1vX+m0= -go.etcd.io/etcd/raft/v3 v3.5.13 h1:7r/NKAOups1YnKcfro2RvGGo2PTuizF/xh26Z2CTAzA= -go.etcd.io/etcd/raft/v3 v3.5.13/go.mod h1:uUFibGLn2Ksm2URMxN1fICGhk8Wu96EfDQyuLhAcAmw= -go.etcd.io/etcd/server/v3 v3.5.13 h1:V6KG+yMfMSqWt+lGnhFpP5z5dRUj1BDRJ5k1fQ9DFok= -go.etcd.io/etcd/server/v3 v3.5.13/go.mod h1:K/8nbsGupHqmr5MkgaZpLlH1QdX1pcNQLAkODy44XcQ= +go.etcd.io/etcd/pkg/v3 v3.6.4 h1:fy8bmXIec1Q35/jRZ0KOes8vuFxbvdN0aAFqmEfJZWA= +go.etcd.io/etcd/pkg/v3 v3.6.4/go.mod h1:kKcYWP8gHuBRcteyv6MXWSN0+bVMnfgqiHueIZnKMtE= +go.etcd.io/etcd/server/v3 v3.6.4 h1:LsCA7CzjVt+8WGrdsnh6RhC0XqCsLkBly3ve5rTxMAU= +go.etcd.io/etcd/server/v3 v3.6.4/go.mod h1:aYCL/h43yiONOv0QIR82kH/2xZ7m+IWYjzRmyQfnCAg= +go.etcd.io/raft/v3 v3.6.0 h1:5NtvbDVYpnfZWcIHgGRk9DyzkBIXOi8j+DDp1IcnUWQ= +go.etcd.io/raft/v3 v3.6.0/go.mod h1:nLvLevg6+xrVtHUmVaTcTz603gQPHfh7kUAwV6YpfGo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw= @@ -287,8 +240,6 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= -golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= -golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98= 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= @@ -307,16 +258,13 @@ 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.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= -golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= -golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= 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-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-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= -golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= +golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= 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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -324,8 +272,6 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T 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/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950= google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4= @@ -343,7 +289,6 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= 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/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/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -351,14 +296,11 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM= 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.31.2/go.mod h1:i+Geh+nGCJEGiCGR3MlBDkS7koHIIKWVfWeRFiOsUcM= k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI= k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc= k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4= k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/apiserver v0.31.2 h1:VUzOEUGRCDi6kX1OyQ801m4A7AUPglpsmGvdsekmcI4= -k8s.io/apiserver v0.31.2/go.mod h1:o3nKZR7lPlJqkU5I3Ove+Zx3JuoFjQobGX1Gctw6XuE= +k8s.io/apiserver v0.34.1 h1:U3JBGdgANK3dfFcyknWde1G6X1F4bg7PXuvlqt8lITA= k8s.io/apiserver v0.34.1/go.mod h1:eOOc9nrVqlBI1AFCvVzsob0OxtPZUCPiUJL45JOTBG0= k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY= k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8= @@ -370,25 +312,18 @@ k8s.io/kms v0.34.1 h1:iCFOvewDPzWM9fMTfyIPO+4MeuZ0tcZbugxLNSHFG4w= k8s.io/kms v0.34.1/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM= k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA= k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts= -k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y= -k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d h1:wAhiDyZ4Tdtt7e46e9M5ZSAJ/MnPGPs+Ki1gHw4w1R0= k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= -sigs.k8s.io/controller-runtime v0.19.7 h1:DLABZfMr20A+AwCZOHhcbcu+TqBXnJZaVBri9K3EO48= -sigs.k8s.io/controller-runtime v0.19.7/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/controller-runtime v0.22.2 h1:cK2l8BGWsSWkXz09tcS4rJh95iOLney5eawcK5A33r4= sigs.k8s.io/controller-runtime v0.22.2/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8= -sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= -sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/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= diff --git a/packages/system/cozystack-api/images/cozystack-api/Dockerfile b/packages/system/cozystack-api/images/cozystack-api/Dockerfile index ea7bdc10..b4b206a6 100644 --- a/packages/system/cozystack-api/images/cozystack-api/Dockerfile +++ b/packages/system/cozystack-api/images/cozystack-api/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.24-alpine AS builder +FROM golang:1.25-alpine AS builder ARG TARGETOS ARG TARGETARCH diff --git a/packages/system/cozystack-controller/images/cozystack-controller/Dockerfile b/packages/system/cozystack-controller/images/cozystack-controller/Dockerfile index c7ada9ef..bd6cfb38 100644 --- a/packages/system/cozystack-controller/images/cozystack-controller/Dockerfile +++ b/packages/system/cozystack-controller/images/cozystack-controller/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.24-alpine AS builder +FROM golang:1.25-alpine AS builder ARG TARGETOS ARG TARGETARCH diff --git a/packages/system/lineage-controller-webhook/images/lineage-controller-webhook/Dockerfile b/packages/system/lineage-controller-webhook/images/lineage-controller-webhook/Dockerfile index e043e472..d9232d98 100644 --- a/packages/system/lineage-controller-webhook/images/lineage-controller-webhook/Dockerfile +++ b/packages/system/lineage-controller-webhook/images/lineage-controller-webhook/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.24-alpine AS builder +FROM golang:1.25-alpine AS builder ARG TARGETOS ARG TARGETARCH diff --git a/pkg/cmd/server/start.go b/pkg/cmd/server/start.go index 3427e61d..764c2fab 100644 --- a/pkg/cmd/server/start.go +++ b/pkg/cmd/server/start.go @@ -35,14 +35,12 @@ import ( "github.com/spf13/cobra" "k8s.io/apimachinery/pkg/runtime" utilerrors "k8s.io/apimachinery/pkg/util/errors" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/version" "k8s.io/apiserver/pkg/endpoints/openapi" genericapiserver "k8s.io/apiserver/pkg/server" genericoptions "k8s.io/apiserver/pkg/server/options" + "k8s.io/apiserver/pkg/util/compatibility" utilfeature "k8s.io/apiserver/pkg/util/feature" - utilversionpkg "k8s.io/apiserver/pkg/util/version" - "k8s.io/component-base/featuregate" baseversion "k8s.io/component-base/version" netutils "k8s.io/utils/net" "sigs.k8s.io/controller-runtime/pkg/client" @@ -87,7 +85,7 @@ func NewCommandStartCozyServer(ctx context.Context, defaults *CozyServerOptions) Short: "Launch an Cozystack API server", Long: "Launch an Cozystack API server", PersistentPreRunE: func(*cobra.Command, []string) error { - return utilversionpkg.DefaultComponentGlobalsRegistry.Set() + return nil }, RunE: func(c *cobra.Command, args []string) error { if err := o.Complete(); err != nil { @@ -107,38 +105,8 @@ func NewCommandStartCozyServer(ctx context.Context, defaults *CozyServerOptions) flags := cmd.Flags() o.RecommendedOptions.AddFlags(flags) - // The following lines demonstrate how to configure version compatibility and feature gates - // for the "Cozy" component according to KEP-4330. - - // Create a default version object for the "Cozy" component. - defaultCozyVersion := "1.1" - // Register the "Cozy" component in the global component registry, - // associating it with its effective version and feature gate configuration. - _, appsFeatureGate := utilversionpkg.DefaultComponentGlobalsRegistry.ComponentGlobalsOrRegister( - apiserver.CozyComponentName, utilversionpkg.NewEffectiveVersion(defaultCozyVersion), - featuregate.NewVersionedFeatureGate(version.MustParse(defaultCozyVersion)), - ) - - // Add feature gate specifications for the "Cozy" component. - utilruntime.Must(appsFeatureGate.AddVersioned(map[featuregate.Feature]featuregate.VersionedSpecs{ - // Example of adding feature gates: - // "FeatureName": {{"v1", true}, {"v2", false}}, - })) - - // Register the standard kube component if it is not already registered in the global registry. - _, _ = utilversionpkg.DefaultComponentGlobalsRegistry.ComponentGlobalsOrRegister( - utilversionpkg.DefaultKubeComponent, - utilversionpkg.NewEffectiveVersion(baseversion.DefaultKubeBinaryVersion), - utilfeature.DefaultMutableFeatureGate, - ) - - // Set the version emulation mapping from the "Cozy" component to the kube component. - utilruntime.Must(utilversionpkg.DefaultComponentGlobalsRegistry.SetEmulationVersionMapping( - apiserver.CozyComponentName, utilversionpkg.DefaultKubeComponent, CozyVersionToKubeVersion, - )) - - // Add flags from the global component registry. - utilversionpkg.DefaultComponentGlobalsRegistry.AddFlags(flags) + // Note: KEP-4330 component versioning functionality (k8s.io/apiserver/pkg/util/version) + // is not available in Kubernetes v0.34.1. The component versioning code has been removed. return cmd } @@ -205,16 +173,29 @@ func (o *CozyServerOptions) Complete() error { Release: config.ReleaseConfig{ Prefix: crd.Spec.Release.Prefix, Labels: crd.Spec.Release.Labels, - Chart: config.ChartConfig{ - Name: crd.Spec.Release.Chart.Name, - SourceRef: config.SourceRefConfig{ - Kind: crd.Spec.Release.Chart.SourceRef.Kind, - Name: crd.Spec.Release.Chart.SourceRef.Name, - Namespace: crd.Spec.Release.Chart.SourceRef.Namespace, - }, - }, }, } + + // Handle either Chart or ChartRef (mutually exclusive per CRD validation) + if crd.Spec.Release.Chart != nil { + resource.Release.Chart = &config.ChartConfig{ + Name: crd.Spec.Release.Chart.Name, + SourceRef: config.SourceRefConfig{ + Kind: crd.Spec.Release.Chart.SourceRef.Kind, + Name: crd.Spec.Release.Chart.SourceRef.Name, + Namespace: crd.Spec.Release.Chart.SourceRef.Namespace, + }, + } + } else if crd.Spec.Release.ChartRef != nil { + resource.Release.ChartRef = &config.ChartRefConfig{ + SourceRef: config.SourceRefConfig{ + Kind: crd.Spec.Release.ChartRef.SourceRef.Kind, + Name: crd.Spec.Release.ChartRef.SourceRef.Name, + Namespace: crd.Spec.Release.ChartRef.SourceRef.Namespace, + }, + } + } + o.ResourceConfig.Resources = append(o.ResourceConfig.Resources, resource) } @@ -225,7 +206,6 @@ func (o *CozyServerOptions) Complete() error { func (o CozyServerOptions) Validate(args []string) error { var allErrors []error allErrors = append(allErrors, o.RecommendedOptions.Validate()...) - allErrors = append(allErrors, utilversionpkg.DefaultComponentGlobalsRegistry.Validate()...) return utilerrors.NewAggregate(allErrors) } @@ -281,12 +261,8 @@ func (o *CozyServerOptions) Config() (*apiserver.Config, error) { serverConfig.OpenAPIV3Config.PostProcessSpec = buildPostProcessV3(kindSchemas) - serverConfig.FeatureGate = utilversionpkg.DefaultComponentGlobalsRegistry.FeatureGateFor( - utilversionpkg.DefaultKubeComponent, - ) - serverConfig.EffectiveVersion = utilversionpkg.DefaultComponentGlobalsRegistry.EffectiveVersionFor( - apiserver.CozyComponentName, - ) + serverConfig.FeatureGate = utilfeature.DefaultMutableFeatureGate + serverConfig.EffectiveVersion = compatibility.DefaultBuildEffectiveVersion() if err := o.RecommendedOptions.ApplyTo(serverConfig); err != nil { return nil, err @@ -320,15 +296,27 @@ func (o CozyServerOptions) RunCozyServer(ctx context.Context) error { } // CozyVersionToKubeVersion defines the version mapping between the Cozy component and kube +// Note: This function is currently unused as KEP-4330 component versioning is not available +// in Kubernetes v0.34.1. It is kept for potential future use. func CozyVersionToKubeVersion(ver *version.Version) *version.Version { if ver.Major() != 1 { return nil } - kubeVer := utilversionpkg.DefaultKubeEffectiveVersion().BinaryVersion() + kubeVer, err := version.ParseSemantic(baseversion.DefaultKubeBinaryVersion) + if err != nil { + return nil + } // "1.2" corresponds to kubeVer offset := int(ver.Minor()) - 2 - mappedVer := kubeVer.OffsetMinor(offset) - if mappedVer.GreaterThan(kubeVer) { + mappedMinor := int(kubeVer.Minor()) + offset + if mappedMinor < 0 { + return nil + } + mappedVer, err := version.ParseSemantic(fmt.Sprintf("%d.%d.0", kubeVer.Major(), mappedMinor)) + if err != nil { + return nil + } + if mappedVer.AtLeast(kubeVer) { return kubeVer } return mappedVer diff --git a/pkg/cmd/server/start_test.go b/pkg/cmd/server/start_test.go index da96ed31..7a4bd259 100644 --- a/pkg/cmd/server/start_test.go +++ b/pkg/cmd/server/start_test.go @@ -17,16 +17,20 @@ limitations under the License. package server import ( + "fmt" "testing" "k8s.io/apimachinery/pkg/util/version" - utilversion "k8s.io/apiserver/pkg/util/version" + baseversion "k8s.io/component-base/version" "github.com/stretchr/testify/assert" ) func TestCozyEmulationVersionToKubeEmulationVersion(t *testing.T) { - defaultKubeEffectiveVersion := utilversion.DefaultKubeEffectiveVersion() + kubeVer, err := version.ParseSemantic(baseversion.DefaultKubeBinaryVersion) + if err != nil { + t.Fatalf("Failed to parse kube version: %v", err) + } testCases := []struct { desc string @@ -36,22 +40,22 @@ func TestCozyEmulationVersionToKubeEmulationVersion(t *testing.T) { { desc: "same version as than kube binary", appsEmulationVer: version.MajorMinor(1, 2), - expectedKubeEmulationVer: defaultKubeEffectiveVersion.BinaryVersion(), + expectedKubeEmulationVer: kubeVer, }, { desc: "1 version lower than kube binary", appsEmulationVer: version.MajorMinor(1, 1), - expectedKubeEmulationVer: defaultKubeEffectiveVersion.BinaryVersion().OffsetMinor(-1), + expectedKubeEmulationVer: mustParseVersion(t, kubeVer.Major(), kubeVer.Minor()-1), }, { desc: "2 versions lower than kube binary", appsEmulationVer: version.MajorMinor(1, 0), - expectedKubeEmulationVer: defaultKubeEffectiveVersion.BinaryVersion().OffsetMinor(-2), + expectedKubeEmulationVer: mustParseVersion(t, kubeVer.Major(), kubeVer.Minor()-2), }, { desc: "capped at kube binary", appsEmulationVer: version.MajorMinor(1, 3), - expectedKubeEmulationVer: defaultKubeEffectiveVersion.BinaryVersion(), + expectedKubeEmulationVer: kubeVer, }, { desc: "no mapping", @@ -62,7 +66,19 @@ func TestCozyEmulationVersionToKubeEmulationVersion(t *testing.T) { for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { mappedKubeEmulationVer := CozyVersionToKubeVersion(tc.appsEmulationVer) - assert.True(t, mappedKubeEmulationVer.EqualTo(tc.expectedKubeEmulationVer)) + if tc.expectedKubeEmulationVer == nil { + assert.Nil(t, mappedKubeEmulationVer) + } else { + assert.True(t, mappedKubeEmulationVer.EqualTo(tc.expectedKubeEmulationVer)) + } }) } } + +func mustParseVersion(t *testing.T, major, minor uint) *version.Version { + v, err := version.ParseSemantic(fmt.Sprintf("%d.%d.0", major, minor)) + if err != nil { + t.Fatalf("Failed to parse version: %v", err) + } + return v +} From 4b1525a5f88682c0f141db7aa34bc05e25f86ec5 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 19 Nov 2025 15:25:14 +0100 Subject: [PATCH 09/46] Cleanup Signed-off-by: Andrei Kvapil --- Makefile | 8 +-- internal/operator/reconciler.go | 9 +-- packages/apps/Makefile | 5 -- packages/core/platform/bundles/paas-full.yaml | 2 +- .../core/platform/bundles/paas-hosted.yaml | 4 +- packages/core/platform/templates/_helpers.tpl | 60 ------------------- packages/extra/Makefile | 5 -- packages/library/Makefile | 5 -- packages/system/Makefile | 5 -- 9 files changed, 9 insertions(+), 94 deletions(-) diff --git a/Makefile b/Makefile index bb5eb40e..fd4329af 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: manifests repos assets +.PHONY: manifests assets build-deps: @command -V find docker skopeo jq gh helm > /dev/null @@ -29,12 +29,6 @@ build: build-deps make -C packages/core/installer image make manifests -repos: - rm -rf _out - make -C packages/system repo - make -C packages/apps repo - make -C packages/extra repo - manifests: mkdir -p _out/assets (cd packages/core/installer/; helm template -n cozy-installer installer .) > _out/assets/cozystack-installer.yaml diff --git a/internal/operator/reconciler.go b/internal/operator/reconciler.go index 1fbe6fba..02c991f1 100644 --- a/internal/operator/reconciler.go +++ b/internal/operator/reconciler.go @@ -102,7 +102,7 @@ func getArtifactPrefixAndNamespace(chartName string) (string, string, bool) { // PlatformReconciler reconciles the platform configuration. type PlatformReconciler struct { client.Client - Scheme *runtime.Scheme + Scheme *runtime.Scheme FirstReconcileDone chan struct{} } @@ -295,7 +295,8 @@ func (r *PlatformReconciler) reconcileGitRepository(ctx context.Context) error { Interval: metav1.Duration{Duration: 1 * 60 * 1000000000}, // 1m Timeout: &metav1.Duration{Duration: 60 * 1000000000}, // 60s Reference: &sourcev1.GitRepositoryRef{ - Tag: "v0.38.0-alpha.2", + Branch: "refactor-engine", + //Tag: "v0.38.0-alpha.2", }, Ignore: func() *string { ignore := `# exclude all @@ -496,8 +497,8 @@ func (r *PlatformReconciler) reconcileArtifactGenerator(ctx context.Context, nam strategy = "Overwrite" } copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ - From: fmt.Sprintf("@cozystack/packages/%s/%s/%s", name, pkg, valuesFile), - To: fmt.Sprintf("@artifact/%s/%s", pkg, valuesFile), + From: fmt.Sprintf("@cozystack/packages/%s/%s/%s", name, pkg, valuesFile), + To: fmt.Sprintf("@artifact/%s/%s", pkg, valuesFile), Strategy: strategy, }) logger.Info("Adding valuesFile copy operation", "package", pkg, "valuesFile", valuesFile, "strategy", strategy) diff --git a/packages/apps/Makefile b/packages/apps/Makefile index b3917f20..7338318d 100644 --- a/packages/apps/Makefile +++ b/packages/apps/Makefile @@ -3,10 +3,5 @@ CHARTS := $(shell find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}') include ../../scripts/common-envs.mk -repo: - rm -rf "$(OUT)" - helm package -d "$(OUT)" $(CHARTS) --version $(COZYSTACK_VERSION) - helm repo index "$(OUT)" - 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 diff --git a/packages/core/platform/bundles/paas-full.yaml b/packages/core/platform/bundles/paas-full.yaml index be1c4b44..48b5c3a4 100644 --- a/packages/core/platform/bundles/paas-full.yaml +++ b/packages/core/platform/bundles/paas-full.yaml @@ -320,7 +320,7 @@ releases: values: {{- $dashboardKCconfig := lookup "v1" "ConfigMap" "cozy-dashboard" "kubeapps-auth-config" }} {{- $dashboardKCValues := dig "data" "values.yaml" "" $dashboardKCconfig | fromYaml }} - {{- toYaml (deepCopy $dashboardKCValues | mergeOverwrite (fromYaml (include "cozystack.defaultDashboardValues" .))) | nindent 4 }} + {{- toYaml $dashboardKCValues | nindent 4 }} dependsOn: - cilium - kubeovn diff --git a/packages/core/platform/bundles/paas-hosted.yaml b/packages/core/platform/bundles/paas-hosted.yaml index 3187c5a2..f8f28527 100644 --- a/packages/core/platform/bundles/paas-hosted.yaml +++ b/packages/core/platform/bundles/paas-hosted.yaml @@ -202,8 +202,8 @@ releases: namespace: cozy-dashboard values: {{- $dashboardKCconfig := lookup "v1" "ConfigMap" "cozy-dashboard" "kubeapps-auth-config" }} - {{- $dashboardKCValues := dig "data" "values.yaml" (dict) $dashboardKCconfig }} - {{- toYaml (deepCopy $dashboardKCValues | mergeOverwrite (fromYaml (include "cozystack.defaultDashboardValues" .))) | nindent 4 }} + {{- $dashboardKCValues := dig "data" "values.yaml" "" $dashboardKCconfig | fromYaml }} + {{- toYaml $dashboardKCValues | nindent 4 }} {{- if eq $oidcEnabled "true" }} dependsOn: [keycloak-configure,cozystack-api] {{- else }} diff --git a/packages/core/platform/templates/_helpers.tpl b/packages/core/platform/templates/_helpers.tpl index 73a4574c..b3ab6a86 100644 --- a/packages/core/platform/templates/_helpers.tpl +++ b/packages/core/platform/templates/_helpers.tpl @@ -16,63 +16,3 @@ Get IP-addresses of master nodes {{- end -}} {{ join "," $ips }} {{- end -}} - -{{- define "cozystack.defaultDashboardValues" -}} -kubeapps: -{{- if .Capabilities.APIVersions.Has "source.toolkit.fluxcd.io/v1" }} -{{- with (lookup "source.toolkit.fluxcd.io/v1" "HelmRepository" "cozy-public" "").items }} - redis: - master: - podAnnotations: - {{- range $index, $repo := . }} - {{- with (($repo.status).artifact).revision }} - repository.cozystack.io/{{ $repo.metadata.name }}: {{ quote . }} - {{- end }} - {{- end }} -{{- end }} -{{- end }} - frontend: - resourcesPreset: "none" - dashboard: - resourcesPreset: "none" - {{- $cozystackBranding:= lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} - {{- $branding := dig "data" "branding" "" $cozystackBranding }} - {{- if $branding }} - customLocale: - "Kubeapps": {{ $branding }} - {{- end }} - customStyle: | - {{- $logoImage := dig "data" "logo" "" $cozystackBranding }} - {{- if $logoImage }} - .kubeapps-logo { - background-image: {{ $logoImage }} - } - {{- end }} - #serviceaccount-selector { - display: none; - } - .login-moreinfo { - display: none; - } - a[href="#/docs"] { - display: none; - } - .login-group .clr-form-control .clr-control-label { - display: none; - } - .appview-separator div.appview-first-row div.center { - display: none; - } - .appview-separator div.appview-first-row section[aria-labelledby="app-secrets"] { - display: none; - } - .appview-first-row section[aria-labelledby="access-urls-title"] { - width: 100%; - } - .header-version { - display: none; - } - .label.label-info-secondary { - display: none; - } -{{- end }} diff --git a/packages/extra/Makefile b/packages/extra/Makefile index 5872855b..75b71a51 100644 --- a/packages/extra/Makefile +++ b/packages/extra/Makefile @@ -3,10 +3,5 @@ CHARTS := $(shell find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}') include ../../scripts/common-envs.mk -repo: - rm -rf "$(OUT)" - helm package -d "$(OUT)" $(CHARTS) --version $(COZYSTACK_VERSION) - helm repo index "$(OUT)" - 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 diff --git a/packages/library/Makefile b/packages/library/Makefile index da811e7e..e49767ce 100644 --- a/packages/library/Makefile +++ b/packages/library/Makefile @@ -3,10 +3,5 @@ CHARTS := $(shell find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}') include ../../scripts/common-envs.mk -repo: - rm -rf "$(OUT)" - helm package -d "$(OUT)" $(CHARTS) --version $(COZYSTACK_VERSION) - helm repo index "$(OUT)" - 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 diff --git a/packages/system/Makefile b/packages/system/Makefile index 2104647b..d0be85f7 100644 --- a/packages/system/Makefile +++ b/packages/system/Makefile @@ -3,10 +3,5 @@ CHARTS := $(shell find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}') include ../../scripts/common-envs.mk -repo: - rm -rf "$(OUT)" - helm package -d "$(OUT)" $(CHARTS) --version $(COZYSTACK_VERSION) - cd "$(OUT)" && helm repo index . - fix-charts: find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}' | while read i; do sed -i -e "s/^name: .*/name: cozy-$$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 From 7c2bec197b0dc3ccb76c56803d10bbbbda31851e Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 19 Nov 2025 15:48:58 +0100 Subject: [PATCH 10/46] [flux] disable network policies Signed-off-by: Andrei Kvapil --- packages/system/fluxcd/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/system/fluxcd/values.yaml b/packages/system/fluxcd/values.yaml index 7f5af0ff..e269b1fb 100644 --- a/packages/system/fluxcd/values.yaml +++ b/packages/system/fluxcd/values.yaml @@ -1,7 +1,7 @@ flux-instance: instance: cluster: - networkPolicy: true + networkPolicy: false # -- disable due to liveness/readiness probes issues with network policies domain: cozy.local # -- default value is overriden in patches distribution: artifact: "" From ea9d44b4af7793fdc55f18441bfd9a67c8e82619 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 19 Nov 2025 15:49:29 +0100 Subject: [PATCH 11/46] Refactor bundles (WIP) Signed-off-by: Andrei Kvapil --- .../installer/templates/bundle-config.yaml | 1150 +++++++++++++++++ packages/core/installer/values.yaml | 2 +- packages/extra/bootbox/images/matchbox.tag | 2 +- packages/system/cozystack-api/values.yaml | 2 +- .../system/cozystack-controller/values.yaml | 4 +- .../lineage-controller-webhook/values.yaml | 2 +- 6 files changed, 1156 insertions(+), 6 deletions(-) create mode 100644 packages/core/installer/templates/bundle-config.yaml diff --git a/packages/core/installer/templates/bundle-config.yaml b/packages/core/installer/templates/bundle-config.yaml new file mode 100644 index 00000000..a36a9ea8 --- /dev/null +++ b/packages/core/installer/templates/bundle-config.yaml @@ -0,0 +1,1150 @@ +--- +# Source: cozy-platform/templates/bundles-configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: system-bundle + namespace: cozy-system + labels: + cozystack.io/system: "true" +data: + paas-full.yaml: | + releases: + - name: fluxcd-operator + releaseName: fluxcd-operator + chart: fluxcd-operator + namespace: cozy-fluxcd + privileged: true + dependsOn: [] + + - name: fluxcd + releaseName: fluxcd + chart: fluxcd + namespace: cozy-fluxcd + dependsOn: [fluxcd-operator,cilium,kubeovn] + values: + flux-instance: + instance: + cluster: + domain: cozy.local + + - name: cilium + releaseName: cilium + chart: cilium + namespace: cozy-cilium + privileged: true + dependsOn: [] + valuesFiles: + - values.yaml + - values-talos.yaml + - values-kubeovn.yaml + + - name: cilium-networkpolicy + releaseName: cilium-networkpolicy + chart: cilium-networkpolicy + namespace: cozy-cilium + privileged: true + dependsOn: [cilium] + + - name: kubeovn + releaseName: kubeovn + chart: kubeovn + namespace: cozy-kubeovn + privileged: true + dependsOn: [cilium] + values: + cozystack: + nodesHash: 72edd7b4e36265096d329359e6aad6916382d17b7907de4cdb7d7de3e0a1e3b5 + kube-ovn: + ipv4: + POD_CIDR: "10.244.0.0/16" + POD_GATEWAY: "10.244.0.1" + SVC_CIDR: "10.96.0.0/16" + JOIN_CIDR: "100.64.0.0/16" + + - name: kubeovn-webhook + releaseName: kubeovn-webhook + chart: kubeovn-webhook + namespace: cozy-kubeovn + privileged: true + dependsOn: [cilium,kubeovn,cert-manager] + + - name: kubeovn-plunger + releaseName: kubeovn-plunger + chart: kubeovn-plunger + namespace: cozy-kubeovn + dependsOn: [cilium,kubeovn] + + - name: multus + releaseName: multus + chart: multus + namespace: cozy-multus + privileged: true + dependsOn: [cilium,kubeovn] + + - name: cozy-proxy + releaseName: cozystack + chart: cozy-proxy + namespace: cozy-system + dependsOn: [cilium,kubeovn] + + - name: cert-manager-crds + releaseName: cert-manager-crds + chart: cert-manager-crds + namespace: cozy-cert-manager + dependsOn: [cilium, kubeovn] + + - name: cozystack-api + releaseName: cozystack-api + chart: cozystack-api + namespace: cozy-system + dependsOn: [cilium,kubeovn,cozystack-controller] + + - name: cozystack-controller + releaseName: cozystack-controller + chart: cozystack-controller + namespace: cozy-system + dependsOn: [cilium,kubeovn] + + - name: lineage-controller-webhook + releaseName: lineage-controller-webhook + chart: lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller,cilium,kubeovn,cert-manager] + + - name: cozystack-resource-definition-crd + releaseName: cozystack-resource-definition-crd + chart: cozystack-resource-definition-crd + namespace: cozy-system + dependsOn: [cilium,kubeovn,cozystack-api,cozystack-controller] + + - name: cozystack-resource-definitions + releaseName: cozystack-resource-definitions + chart: cozystack-resource-definitions + namespace: cozy-system + dependsOn: [cilium,kubeovn,cozystack-api,cozystack-controller,cozystack-resource-definition-crd] + + - name: cert-manager + releaseName: cert-manager + chart: cert-manager + namespace: cozy-cert-manager + dependsOn: [cert-manager-crds] + + - name: cert-manager-issuers + releaseName: cert-manager-issuers + chart: cert-manager-issuers + namespace: cozy-cert-manager + dependsOn: [cilium,kubeovn,cert-manager] + + - name: victoria-metrics-operator + releaseName: victoria-metrics-operator + chart: victoria-metrics-operator + namespace: cozy-victoria-metrics-operator + dependsOn: [cilium,kubeovn,cert-manager] + + - name: monitoring-agents + releaseName: monitoring-agents + chart: monitoring-agents + namespace: cozy-monitoring + privileged: true + dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] + values: + scrapeRules: + etcd: + enabled: true + + - name: kubevirt-operator + releaseName: kubevirt-operator + chart: kubevirt-operator + namespace: cozy-kubevirt + dependsOn: [cilium,kubeovn,victoria-metrics-operator] + + - name: kubevirt + releaseName: kubevirt + chart: kubevirt + namespace: cozy-kubevirt + privileged: true + dependsOn: [cilium,kubeovn,kubevirt-operator] + + - name: kubevirt-instancetypes + releaseName: kubevirt-instancetypes + chart: kubevirt-instancetypes + namespace: cozy-kubevirt + dependsOn: [cilium,kubeovn,kubevirt-operator,kubevirt] + + - name: kubevirt-cdi-operator + releaseName: kubevirt-cdi-operator + chart: kubevirt-cdi-operator + namespace: cozy-kubevirt-cdi + dependsOn: [cilium,kubeovn] + + - name: kubevirt-cdi + releaseName: kubevirt-cdi + chart: kubevirt-cdi + namespace: cozy-kubevirt-cdi + dependsOn: [cilium,kubeovn,kubevirt-cdi-operator] + + - name: gpu-operator + releaseName: gpu-operator + chart: gpu-operator + namespace: cozy-gpu-operator + privileged: true + optional: true + dependsOn: [cilium,kubeovn] + valuesFiles: + - values.yaml + - values-talos.yaml + + - name: metallb + releaseName: metallb + chart: metallb + namespace: cozy-metallb + privileged: true + dependsOn: [cilium,kubeovn] + + - name: etcd-operator + releaseName: etcd-operator + chart: etcd-operator + namespace: cozy-etcd-operator + dependsOn: [cilium,kubeovn,cert-manager] + + - name: grafana-operator + releaseName: grafana-operator + chart: grafana-operator + namespace: cozy-grafana-operator + dependsOn: [cilium,kubeovn] + + - name: mariadb-operator + releaseName: mariadb-operator + chart: mariadb-operator + namespace: cozy-mariadb-operator + dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] + values: + mariadb-operator: + clusterName: cozy.local + + - name: postgres-operator + releaseName: postgres-operator + chart: postgres-operator + namespace: cozy-postgres-operator + dependsOn: [cilium,kubeovn,cert-manager] + + - name: kafka-operator + releaseName: kafka-operator + chart: kafka-operator + namespace: cozy-kafka-operator + dependsOn: [cilium,kubeovn,victoria-metrics-operator] + values: + strimzi-kafka-operator: + kubernetesServiceDnsDomain: cozy.local + + - name: clickhouse-operator + releaseName: clickhouse-operator + chart: clickhouse-operator + namespace: cozy-clickhouse-operator + dependsOn: [cilium,kubeovn,victoria-metrics-operator] + + - name: foundationdb-operator + releaseName: foundationdb-operator + chart: foundationdb-operator + namespace: cozy-foundationdb-operator + dependsOn: [cilium,kubeovn,cert-manager] + + - name: rabbitmq-operator + releaseName: rabbitmq-operator + chart: rabbitmq-operator + namespace: cozy-rabbitmq-operator + dependsOn: [cilium,kubeovn] + + - name: redis-operator + releaseName: redis-operator + chart: redis-operator + namespace: cozy-redis-operator + dependsOn: [cilium,kubeovn] + + - name: piraeus-operator + releaseName: piraeus-operator + chart: piraeus-operator + namespace: cozy-linstor + dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] + + - name: linstor + releaseName: linstor + chart: linstor + namespace: cozy-linstor + privileged: true + dependsOn: [piraeus-operator,cilium,kubeovn,cert-manager,snapshot-controller] + + - name: nfs-driver + releaseName: nfs-driver + chart: nfs-driver + namespace: cozy-nfs-driver + privileged: true + dependsOn: [cilium,kubeovn] + optional: true + + - name: snapshot-controller + releaseName: snapshot-controller + chart: snapshot-controller + namespace: cozy-snapshot-controller + dependsOn: [cilium,kubeovn,cert-manager-issuers] + + - name: objectstorage-controller + releaseName: objectstorage-controller + chart: objectstorage-controller + namespace: cozy-objectstorage-controller + dependsOn: [cilium,kubeovn] + + - name: telepresence + releaseName: traffic-manager + chart: telepresence + namespace: cozy-telepresence + optional: true + dependsOn: [cilium,kubeovn] + + - name: dashboard + releaseName: dashboard + chart: dashboard + namespace: cozy-dashboard + values: + {} + dependsOn: + - cilium + - kubeovn + - keycloak-configure + + - name: kamaji + releaseName: kamaji + chart: kamaji + namespace: cozy-kamaji + dependsOn: [cilium,kubeovn,cert-manager] + + - name: capi-operator + releaseName: capi-operator + chart: capi-operator + namespace: cozy-cluster-api + privileged: true + dependsOn: [cilium,kubeovn,cert-manager] + + - name: capi-providers-bootstrap + releaseName: capi-providers-bootstrap + chart: capi-providers-bootstrap + namespace: cozy-cluster-api + privileged: true + dependsOn: [cilium,kubeovn,capi-operator] + + - name: capi-providers-core + releaseName: capi-providers-core + chart: capi-providers-core + namespace: cozy-cluster-api + privileged: true + dependsOn: [cilium,kubeovn,capi-operator] + + - name: capi-providers-cpprovider + releaseName: capi-providers-cpprovider + chart: capi-providers-cpprovider + namespace: cozy-cluster-api + privileged: true + dependsOn: [cilium,kubeovn,capi-operator] + + - name: capi-providers-infraprovider + releaseName: capi-providers-infraprovider + chart: capi-providers-infraprovider + namespace: cozy-cluster-api + privileged: true + dependsOn: [cilium,kubeovn,capi-operator] + + - name: external-dns + releaseName: external-dns + chart: external-dns + namespace: cozy-external-dns + optional: true + dependsOn: [cilium,kubeovn] + + - name: external-secrets-operator + releaseName: external-secrets-operator + chart: external-secrets-operator + namespace: cozy-external-secrets-operator + optional: true + dependsOn: [cilium,kubeovn] + + - name: bootbox + releaseName: bootbox + chart: bootbox + namespace: cozy-bootbox + privileged: true + optional: true + dependsOn: [cilium,kubeovn] + - name: keycloak + releaseName: keycloak + chart: keycloak + namespace: cozy-keycloak + dependsOn: [postgres-operator] + + - name: keycloak-operator + releaseName: keycloak-operator + chart: keycloak-operator + namespace: cozy-keycloak + dependsOn: [keycloak] + + - name: keycloak-configure + releaseName: keycloak-configure + chart: keycloak-configure + namespace: cozy-keycloak + dependsOn: [keycloak-operator] + values: + cozystack: + configHash: 8f0c52dd632b8398f4e975cf7a50ea2153b094e70c84c0b7e768b9cfbc513f0c + + - name: goldpinger + releaseName: goldpinger + chart: goldpinger + namespace: cozy-goldpinger + privileged: true + dependsOn: [monitoring-agents] + + - name: vertical-pod-autoscaler + releaseName: vertical-pod-autoscaler + chart: vertical-pod-autoscaler + namespace: cozy-vertical-pod-autoscaler + privileged: true + dependsOn: [monitoring-agents] + values: + vertical-pod-autoscaler: + recommender: + extraArgs: + prometheus-address: http://vmselect-shortterm.tenant-root.svc.cozy.local:8481/select/0/prometheus/ + + - name: vertical-pod-autoscaler-crds + releaseName: vertical-pod-autoscaler-crds + chart: vertical-pod-autoscaler-crds + namespace: cozy-vertical-pod-autoscaler + privileged: true + dependsOn: [cilium, kubeovn] + + - name: reloader + releaseName: reloader + chart: reloader + namespace: cozy-reloader + + - name: velero + releaseName: velero + chart: velero + namespace: cozy-velero + privileged: true + optional: true + dependsOn: [monitoring-agents] + + - name: hetzner-robotlb + releaseName: robotlb + optional: true + chart: hetzner-robotlb + namespace: cozy-hetzner-robotlb + dependsOn: [cilium, kubeovn] + paas-hosted.yaml: | + releases: + - name: fluxcd-operator + releaseName: fluxcd-operator + chart: fluxcd-operator + namespace: cozy-fluxcd + privileged: true + dependsOn: [] + + - name: fluxcd + releaseName: fluxcd + chart: fluxcd + namespace: cozy-fluxcd + dependsOn: [fluxcd-operator] + values: + flux-instance: + instance: + cluster: + domain: cozy.local + + - name: cert-manager-crds + releaseName: cert-manager-crds + chart: cert-manager-crds + namespace: cozy-cert-manager + dependsOn: [] + + - name: cozystack-api + releaseName: cozystack-api + chart: cozystack-api + namespace: cozy-system + dependsOn: [cozystack-controller] + values: + cozystackAPI: + localK8sAPIEndpoint: + enabled: false + + - name: cozystack-controller + releaseName: cozystack-controller + chart: cozystack-controller + namespace: cozy-system + dependsOn: [] + + - name: lineage-controller-webhook + releaseName: lineage-controller-webhook + chart: lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller,cert-manager] + + - name: cozystack-resource-definition-crd + releaseName: cozystack-resource-definition-crd + chart: cozystack-resource-definition-crd + namespace: cozy-system + dependsOn: [cozystack-api,cozystack-controller] + + - name: cozystack-resource-definitions + releaseName: cozystack-resource-definitions + chart: cozystack-resource-definitions + namespace: cozy-system + dependsOn: [cozystack-api,cozystack-controller,cozystack-resource-definition-crd] + + - name: cert-manager + releaseName: cert-manager + chart: cert-manager + namespace: cozy-cert-manager + dependsOn: [cert-manager-crds] + + - name: cert-manager-issuers + releaseName: cert-manager-issuers + chart: cert-manager-issuers + namespace: cozy-cert-manager + dependsOn: [cert-manager] + + - name: victoria-metrics-operator + releaseName: victoria-metrics-operator + chart: victoria-metrics-operator + namespace: cozy-victoria-metrics-operator + dependsOn: [cert-manager] + + - name: monitoring-agents + releaseName: monitoring-agents + chart: monitoring-agents + namespace: cozy-monitoring + privileged: true + dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] + values: + scrapeRules: + etcd: + enabled: true + + - name: etcd-operator + releaseName: etcd-operator + chart: etcd-operator + namespace: cozy-etcd-operator + dependsOn: [cert-manager] + + - name: grafana-operator + releaseName: grafana-operator + chart: grafana-operator + namespace: cozy-grafana-operator + dependsOn: [] + + - name: mariadb-operator + releaseName: mariadb-operator + chart: mariadb-operator + namespace: cozy-mariadb-operator + dependsOn: [cert-manager,victoria-metrics-operator] + values: + mariadb-operator: + clusterName: cozy.local + + - name: postgres-operator + releaseName: postgres-operator + chart: postgres-operator + namespace: cozy-postgres-operator + dependsOn: [cert-manager,victoria-metrics-operator] + + - name: kafka-operator + releaseName: kafka-operator + chart: kafka-operator + namespace: cozy-kafka-operator + dependsOn: [victoria-metrics-operator] + values: + strimzi-kafka-operator: + kubernetesServiceDnsDomain: cozy.local + + - name: clickhouse-operator + releaseName: clickhouse-operator + chart: clickhouse-operator + namespace: cozy-clickhouse-operator + dependsOn: [victoria-metrics-operator] + + - name: foundationdb-operator + releaseName: foundationdb-operator + chart: foundationdb-operator + namespace: cozy-foundationdb-operator + dependsOn: [cert-manager] + + - name: rabbitmq-operator + releaseName: rabbitmq-operator + chart: rabbitmq-operator + namespace: cozy-rabbitmq-operator + dependsOn: [] + + - name: redis-operator + releaseName: redis-operator + chart: redis-operator + namespace: cozy-redis-operator + dependsOn: [] + + - name: piraeus-operator + releaseName: piraeus-operator + chart: piraeus-operator + namespace: cozy-linstor + dependsOn: [cert-manager] + + - name: objectstorage-controller + releaseName: objectstorage-controller + chart: objectstorage-controller + namespace: cozy-objectstorage-controller + dependsOn: [] + + - name: telepresence + releaseName: traffic-manager + chart: telepresence + namespace: cozy-telepresence + optional: true + dependsOn: [] + + - name: external-dns + releaseName: external-dns + chart: external-dns + namespace: cozy-external-dns + optional: true + dependsOn: [] + + - name: external-secrets-operator + releaseName: external-secrets-operator + chart: external-secrets-operator + namespace: cozy-external-secrets-operator + optional: true + dependsOn: [] + + - name: dashboard + releaseName: dashboard + chart: dashboard + namespace: cozy-dashboard + values: + {} + dependsOn: [keycloak-configure,cozystack-api] + - name: keycloak + releaseName: keycloak + chart: keycloak + namespace: cozy-keycloak + dependsOn: [postgres-operator] + + - name: keycloak-operator + releaseName: keycloak-operator + chart: keycloak-operator + namespace: cozy-keycloak + dependsOn: [keycloak] + + - name: keycloak-configure + releaseName: keycloak-configure + chart: keycloak-configure + namespace: cozy-keycloak + dependsOn: [keycloak-operator] + values: + cozystack: + configHash: 8f0c52dd632b8398f4e975cf7a50ea2153b094e70c84c0b7e768b9cfbc513f0c + + - name: goldpinger + releaseName: goldpinger + chart: goldpinger + namespace: cozy-goldpinger + privileged: true + dependsOn: [monitoring-agents] + + - name: vertical-pod-autoscaler + releaseName: vertical-pod-autoscaler + chart: vertical-pod-autoscaler + namespace: cozy-vertical-pod-autoscaler + privileged: true + dependsOn: [monitoring-agents] + values: + vertical-pod-autoscaler: + recommender: + extraArgs: + prometheus-address: http://vmselect-shortterm.tenant-root.svc.cozy.local:8481/select/0/prometheus/ + + - name: vertical-pod-autoscaler-crds + releaseName: vertical-pod-autoscaler-crds + chart: vertical-pod-autoscaler-crds + namespace: cozy-vertical-pod-autoscaler + privileged: true + dependsOn: [] + + - name: velero + releaseName: velero + chart: velero + namespace: cozy-velero + privileged: true + optional: true + dependsOn: [monitoring-agents] + + - name: hetzner-robotlb + releaseName: robotlb + optional: true + chart: hetzner-robotlb + namespace: cozy-hetzner-robotlb + distro-full.yaml: | + releases: + - name: fluxcd-operator + releaseName: fluxcd-operator + chart: fluxcd-operator + namespace: cozy-fluxcd + privileged: true + dependsOn: [] + + - name: fluxcd + releaseName: fluxcd + chart: fluxcd + namespace: cozy-fluxcd + dependsOn: [fluxcd-operator,cilium] + values: + flux-instance: + instance: + cluster: + domain: cozy.local + + - name: cilium + releaseName: cilium + chart: cilium + namespace: cozy-cilium + privileged: true + dependsOn: [] + valuesFiles: + - values.yaml + - values-talos.yaml + values: + cilium: + enableIPv4Masquerade: true + enableIdentityMark: true + ipv4NativeRoutingCIDR: "10.244.0.0/16" + autoDirectNodeRoutes: true + routingMode: native + + - name: cilium-networkpolicy + releaseName: cilium-networkpolicy + chart: cilium-networkpolicy + namespace: cozy-cilium + privileged: true + dependsOn: [cilium] + + - name: cozy-proxy + releaseName: cozystack + chart: cozy-proxy + namespace: cozy-system + optional: true + dependsOn: [cilium] + + - name: cert-manager-crds + releaseName: cert-manager-crds + chart: cert-manager-crds + namespace: cozy-cert-manager + dependsOn: [cilium] + + - name: cozystack-controller + releaseName: cozystack-controller + chart: cozystack-controller + namespace: cozy-system + dependsOn: [cilium] + + - name: lineage-controller-webhook + releaseName: lineage-controller-webhook + chart: lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller,cilium,cert-manager] + + - name: cert-manager + releaseName: cert-manager + chart: cert-manager + namespace: cozy-cert-manager + dependsOn: [cert-manager-crds] + + - name: cert-manager-issuers + releaseName: cert-manager-issuers + chart: cert-manager-issuers + namespace: cozy-cert-manager + optional: true + dependsOn: [cilium,cert-manager] + + - name: victoria-metrics-operator + releaseName: victoria-metrics-operator + chart: victoria-metrics-operator + namespace: cozy-victoria-metrics-operator + optional: true + dependsOn: [cilium,cert-manager] + + - name: monitoring-agents + releaseName: monitoring-agents + chart: monitoring-agents + namespace: cozy-monitoring + privileged: true + optional: true + dependsOn: [cilium,victoria-metrics-operator] + values: + scrapeRules: + etcd: + enabled: true + + - name: metallb + releaseName: metallb + chart: metallb + namespace: cozy-metallb + privileged: true + dependsOn: [cilium] + + - name: etcd-operator + releaseName: etcd-operator + chart: etcd-operator + namespace: cozy-etcd-operator + optional: true + dependsOn: [cilium,cert-manager] + + - name: grafana-operator + releaseName: grafana-operator + chart: grafana-operator + namespace: cozy-grafana-operator + optional: true + dependsOn: [cilium] + + - name: mariadb-operator + releaseName: mariadb-operator + chart: mariadb-operator + namespace: cozy-mariadb-operator + optional: true + dependsOn: [cilium,cert-manager,victoria-metrics-operator] + values: + mariadb-operator: + clusterName: cozy.local + + - name: postgres-operator + releaseName: postgres-operator + chart: postgres-operator + namespace: cozy-postgres-operator + optional: true + dependsOn: [cilium,cert-manager,victoria-metrics-operator] + + - name: kafka-operator + releaseName: kafka-operator + chart: kafka-operator + namespace: cozy-kafka-operator + optional: true + dependsOn: [cilium,victoria-metrics-operator] + values: + strimzi-kafka-operator: + kubernetesServiceDnsDomain: cozy.local + + - name: clickhouse-operator + releaseName: clickhouse-operator + chart: clickhouse-operator + namespace: cozy-clickhouse-operator + optional: true + dependsOn: [cilium,victoria-metrics-operator] + + - name: foundationdb-operator + releaseName: foundationdb-operator + chart: foundationdb-operator + namespace: cozy-foundationdb-operator + optional: true + dependsOn: [cilium,cert-manager] + + - name: rabbitmq-operator + releaseName: rabbitmq-operator + chart: rabbitmq-operator + namespace: cozy-rabbitmq-operator + optional: true + dependsOn: [cilium] + + - name: redis-operator + releaseName: redis-operator + chart: redis-operator + namespace: cozy-redis-operator + optional: true + dependsOn: [cilium] + + - name: piraeus-operator + releaseName: piraeus-operator + chart: piraeus-operator + namespace: cozy-linstor + dependsOn: [cilium,cert-manager] + + - name: snapshot-controller + releaseName: snapshot-controller + chart: snapshot-controller + namespace: cozy-snapshot-controller + dependsOn: [cilium] + + - name: objectstorage-controller + releaseName: objectstorage-controller + chart: objectstorage-controller + namespace: cozy-objectstorage-controller + optional: true + dependsOn: [cilium] + + - name: linstor + releaseName: linstor + chart: linstor + namespace: cozy-linstor + privileged: true + dependsOn: [piraeus-operator,cilium,cert-manager,snapshot-controller] + + - name: nfs-driver + releaseName: nfs-driver + chart: nfs-driver + namespace: cozy-nfs-driver + privileged: true + dependsOn: [cilium] + optional: true + + - name: telepresence + releaseName: traffic-manager + chart: telepresence + namespace: cozy-telepresence + optional: true + dependsOn: [] + + - name: external-dns + releaseName: external-dns + chart: external-dns + namespace: cozy-external-dns + optional: true + dependsOn: [cilium] + + - name: external-secrets-operator + releaseName: external-secrets-operator + chart: external-secrets-operator + namespace: cozy-external-secrets-operator + optional: true + dependsOn: [cilium] + + - name: keycloak + releaseName: keycloak + chart: keycloak + namespace: cozy-keycloak + optional: true + dependsOn: [postgres-operator] + + - name: keycloak-operator + releaseName: keycloak-operator + chart: keycloak-operator + namespace: cozy-keycloak + optional: true + dependsOn: [keycloak] + + - name: bootbox + releaseName: bootbox + chart: bootbox + namespace: cozy-bootbox + privileged: true + optional: true + dependsOn: [cilium] + + - name: reloader + releaseName: reloader + chart: reloader + namespace: cozy-reloader + + - name: velero + releaseName: velero + chart: velero + namespace: cozy-velero + privileged: true + optional: true + dependsOn: [cilium] + + - name: hetzner-robotlb + releaseName: robotlb + optional: true + chart: hetzner-robotlb + namespace: cozy-hetzner-robotlb + dependsOn: [cilium] + distro-hosted.yaml: | + releases: + - name: fluxcd-operator + releaseName: fluxcd-operator + chart: fluxcd-operator + namespace: cozy-fluxcd + privileged: true + dependsOn: [] + + - name: fluxcd + releaseName: fluxcd + chart: fluxcd + namespace: cozy-fluxcd + dependsOn: [fluxcd-operator] + values: + flux-instance: + instance: + cluster: + domain: cozy.local + + - name: cert-manager-crds + releaseName: cert-manager-crds + chart: cert-manager-crds + namespace: cozy-cert-manager + dependsOn: [] + + - name: cozystack-controller + releaseName: cozystack-controller + chart: cozystack-controller + namespace: cozy-system + + - name: lineage-controller-webhook + releaseName: lineage-controller-webhook + chart: lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller,cert-manager] + + - name: cert-manager + releaseName: cert-manager + chart: cert-manager + namespace: cozy-cert-manager + dependsOn: [cert-manager-crds] + + - name: cert-manager-issuers + releaseName: cert-manager-issuers + chart: cert-manager-issuers + namespace: cozy-cert-manager + optional: true + dependsOn: [cert-manager] + + - name: victoria-metrics-operator + releaseName: victoria-metrics-operator + chart: victoria-metrics-operator + namespace: cozy-victoria-metrics-operator + optional: true + dependsOn: [cert-manager] + + - name: monitoring-agents + releaseName: monitoring-agents + chart: monitoring-agents + namespace: cozy-monitoring + privileged: true + optional: true + dependsOn: [victoria-metrics-operator] + values: + scrapeRules: + etcd: + enabled: true + + - name: etcd-operator + releaseName: etcd-operator + chart: etcd-operator + namespace: cozy-etcd-operator + optional: true + dependsOn: [cert-manager] + + - name: grafana-operator + releaseName: grafana-operator + chart: grafana-operator + namespace: cozy-grafana-operator + optional: true + dependsOn: [] + + - name: mariadb-operator + releaseName: mariadb-operator + chart: mariadb-operator + namespace: cozy-mariadb-operator + optional: true + dependsOn: [victoria-metrics-operator] + values: + mariadb-operator: + clusterName: cozy.local + + - name: postgres-operator + releaseName: postgres-operator + chart: postgres-operator + namespace: cozy-postgres-operator + optional: true + dependsOn: [victoria-metrics-operator] + + - name: kafka-operator + releaseName: kafka-operator + chart: kafka-operator + namespace: cozy-kafka-operator + optional: true + dependsOn: [victoria-metrics-operator] + values: + strimzi-kafka-operator: + kubernetesServiceDnsDomain: cozy.local + + - name: clickhouse-operator + releaseName: clickhouse-operator + chart: clickhouse-operator + namespace: cozy-clickhouse-operator + optional: true + dependsOn: [victoria-metrics-operator] + + - name: foundationdb-operator + releaseName: foundationdb-operator + chart: foundationdb-operator + namespace: cozy-foundationdb-operator + optional: true + dependsOn: [cert-manager] + + - name: rabbitmq-operator + releaseName: rabbitmq-operator + chart: rabbitmq-operator + namespace: cozy-rabbitmq-operator + optional: true + dependsOn: [] + + - name: redis-operator + releaseName: redis-operator + chart: redis-operator + namespace: cozy-redis-operator + optional: true + dependsOn: [] + + - name: telepresence + releaseName: traffic-manager + chart: telepresence + namespace: cozy-telepresence + optional: true + dependsOn: [] + + - name: external-dns + releaseName: external-dns + chart: external-dns + namespace: cozy-external-dns + optional: true + dependsOn: [] + + - name: external-secrets-operator + releaseName: external-secrets-operator + chart: external-secrets-operator + namespace: cozy-external-secrets-operator + optional: true + dependsOn: [] + + - name: keycloak + releaseName: keycloak + chart: keycloak + namespace: cozy-keycloak + optional: true + dependsOn: [postgres-operator] + + - name: keycloak-operator + releaseName: keycloak-operator + chart: keycloak-operator + namespace: cozy-keycloak + optional: true + dependsOn: [keycloak] + + - name: velero + releaseName: velero + chart: velero + namespace: cozy-velero + privileged: true + optional: true + + - name: hetzner-robotlb + releaseName: robotlb + optional: true + chart: hetzner-robotlb + namespace: cozy-hetzner-robotlb diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index ee60f15a..0c0cc780 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:latest@sha256:cf34dccce53c750f1589a8cd317b7fcac3bc1210fb948140e46281994176084b + image: ghcr.io/cozystack/cozystack/installer:latest@sha256:8e542aac428a5518f6cf5ecedd949454b1dfd85ff3ac968f1a3a08d86472dd50 diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index a78176b5..ee8e7b89 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v0.38.0-alpha.1@sha256:5396b4a3cc652d35a9348ebf957c823c650c8a72ccea693fbbe72df675dc9317 +ghcr.io/cozystack/cozystack/matchbox:latest@sha256:73ffee1ba219cc23ba42c9420e0d25fd9ea289f30d26be17224fbafc8f213227 diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index f5d9b5b3..bfe1aeb6 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,5 +1,5 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.38.0-alpha.1@sha256:e4c028f802d2facbc1b9be0afc9856f5927a715edeaf7c004dd80ac8f00b2304 + image: ghcr.io/cozystack/cozystack/cozystack-api:latest@sha256:80a01eb6cbfdeea9f27921c6acd882b17ff6ac22455f70968944d382195d96d0 localK8sAPIEndpoint: enabled: true replicas: 2 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index 09d04053..cc1c6f0c 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,6 +1,6 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.38.0-alpha.1@sha256:971ca76078d9b81e3b02fd270147754af3eb5505b08aad0ead8d41ae9a3d0fae + image: ghcr.io/cozystack/cozystack/cozystack-controller:latest@sha256:f093adb7d67eaf020b79bd941deeaeb12bd613d871b5e77496702a0e1975d1f0 debug: false disableTelemetry: false - cozystackVersion: "v0.38.0-alpha.1" + cozystackVersion: "latest" cozystackAPIKind: "DaemonSet" diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index a9c8b202..9cf4b533 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,5 +1,5 @@ lineageControllerWebhook: - image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.38.0-alpha.1@sha256:590daccdafda652eea697c691f5695e9f322056971e5462351911bb8931d7573 + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:latest@sha256:4e60a1b13a2a28792ef1a5c4d7875dca2c869e09d7360f0766a7485937fe7977 debug: false localK8sAPIEndpoint: enabled: true From 17286ad213b6c2ddceef697bfc9f56264182fd66 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 19 Nov 2025 17:59:06 +0100 Subject: [PATCH 12/46] fix merging values.yaml Signed-off-by: Andrei Kvapil --- internal/operator/reconciler.go | 6 +++--- packages/core/installer/values.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/operator/reconciler.go b/internal/operator/reconciler.go index 02c991f1..283c4c0b 100644 --- a/internal/operator/reconciler.go +++ b/internal/operator/reconciler.go @@ -490,7 +490,7 @@ func (r *PlatformReconciler) reconcileArtifactGenerator(ctx context.Context, nam for i, valuesFile := range valuesFiles { // Copy values file from GitRepository to artifact // Path in GitRepository: packages/{name}/{pkg}/{valuesFile} - // Path in artifact: {pkg}/{valuesFile} + // All files should be merged into values.yaml in artifact // First file should use Overwrite (to replace original values.yaml), others use Merge strategy := "Merge" if i == 0 { @@ -498,10 +498,10 @@ func (r *PlatformReconciler) reconcileArtifactGenerator(ctx context.Context, nam } copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ From: fmt.Sprintf("@cozystack/packages/%s/%s/%s", name, pkg, valuesFile), - To: fmt.Sprintf("@artifact/%s/%s", pkg, valuesFile), + To: fmt.Sprintf("@artifact/%s/values.yaml", pkg), Strategy: strategy, }) - logger.Info("Adding valuesFile copy operation", "package", pkg, "valuesFile", valuesFile, "strategy", strategy) + logger.Info("Adding valuesFile copy operation", "package", pkg, "valuesFile", valuesFile, "strategy", strategy, "target", "values.yaml") } } diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index 0c0cc780..8f722558 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:latest@sha256:8e542aac428a5518f6cf5ecedd949454b1dfd85ff3ac968f1a3a08d86472dd50 + image: ghcr.io/cozystack/cozystack/installer:latest@sha256:06e47d65e0b9c9eebc72d9bcf63ad644a75b9b740c433ad7f1e3b0e703957f7d From 5dc9f590cfd199dc6e53626fd39c55400cbe0a39 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 19 Nov 2025 20:38:21 +0100 Subject: [PATCH 13/46] WIP WIP WIP WIP WIP WIP WIP WIP WIP Signed-off-by: Andrei Kvapil --- .../core/platform/bundles/distro-full.yaml | 280 ------------------ .../core/platform/bundles/distro-hosted.yaml | 192 ------------ .../bundles/iaas}/cozyrds/bucket.yaml | 0 .../bundles/iaas}/cozyrds/kubernetes.yaml | 0 .../iaas}/cozyrds/virtual-machine.yaml | 0 .../iaas}/cozyrds/virtualprivatecloud.yaml | 0 .../bundles/iaas}/cozyrds/vm-disk.yaml | 0 .../bundles/iaas}/cozyrds/vm-instance.yaml | 0 .../platform/bundles/iaas/system-iaas.yaml | 100 +++++++ .../platform/bundles/naas}/http-cache.yaml | 0 .../platform/bundles/naas}/tcp-balancer.yaml | 0 .../platform/bundles/naas}/vpn.yaml | 0 .../bundles/paas}/cozyrds/clickhouse.yaml | 0 .../bundles/paas}/cozyrds/ferretdb.yaml | 0 .../bundles/paas}/cozyrds/foundationdb.yaml | 0 .../platform/bundles/paas}/cozyrds/kafka.yaml | 0 .../platform/bundles/paas}/cozyrds/mysql.yaml | 0 .../platform/bundles/paas}/cozyrds/nats.yaml | 0 .../bundles/paas}/cozyrds/postgres.yaml | 0 .../bundles/paas}/cozyrds/rabbitmq.yaml | 0 .../platform/bundles/paas}/cozyrds/redis.yaml | 0 .../platform/bundles/paas/system-paas.yaml | 53 ++++ .../bundles/system}/cozyrds/bootbox.yaml | 0 .../bundles/system}/cozyrds/etcd.yaml | 0 .../bundles/system}/cozyrds/info.yaml | 0 .../bundles/system}/cozyrds/ingress.yaml | 0 .../bundles/system}/cozyrds/monitoring.yaml | 0 .../bundles/system}/cozyrds/seaweedfs.yaml | 0 .../bundles/system}/cozyrds/tenant.yaml | 0 .../system-full.yaml} | 130 -------- .../system-hosted.yaml} | 39 --- 31 files changed, 153 insertions(+), 641 deletions(-) delete mode 100644 packages/core/platform/bundles/distro-full.yaml delete mode 100644 packages/core/platform/bundles/distro-hosted.yaml rename packages/{system/cozystack-resource-definitions => core/platform/bundles/iaas}/cozyrds/bucket.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/iaas}/cozyrds/kubernetes.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/iaas}/cozyrds/virtual-machine.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/iaas}/cozyrds/virtualprivatecloud.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/iaas}/cozyrds/vm-disk.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/iaas}/cozyrds/vm-instance.yaml (100%) create mode 100644 packages/core/platform/bundles/iaas/system-iaas.yaml rename packages/{system/cozystack-resource-definitions/cozyrds => core/platform/bundles/naas}/http-cache.yaml (100%) rename packages/{system/cozystack-resource-definitions/cozyrds => core/platform/bundles/naas}/tcp-balancer.yaml (100%) rename packages/{system/cozystack-resource-definitions/cozyrds => core/platform/bundles/naas}/vpn.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/paas}/cozyrds/clickhouse.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/paas}/cozyrds/ferretdb.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/paas}/cozyrds/foundationdb.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/paas}/cozyrds/kafka.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/paas}/cozyrds/mysql.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/paas}/cozyrds/nats.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/paas}/cozyrds/postgres.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/paas}/cozyrds/rabbitmq.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/paas}/cozyrds/redis.yaml (100%) create mode 100644 packages/core/platform/bundles/paas/system-paas.yaml rename packages/{system/cozystack-resource-definitions => core/platform/bundles/system}/cozyrds/bootbox.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/system}/cozyrds/etcd.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/system}/cozyrds/info.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/system}/cozyrds/ingress.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/system}/cozyrds/monitoring.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/system}/cozyrds/seaweedfs.yaml (100%) rename packages/{system/cozystack-resource-definitions => core/platform/bundles/system}/cozyrds/tenant.yaml (100%) rename packages/core/platform/bundles/{paas-full.yaml => system/system-full.yaml} (71%) rename packages/core/platform/bundles/{paas-hosted.yaml => system/system-hosted.yaml} (86%) diff --git a/packages/core/platform/bundles/distro-full.yaml b/packages/core/platform/bundles/distro-full.yaml deleted file mode 100644 index c17d829d..00000000 --- a/packages/core/platform/bundles/distro-full.yaml +++ /dev/null @@ -1,280 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} - -releases: -- name: fluxcd-operator - releaseName: fluxcd-operator - chart: fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - -- name: fluxcd - releaseName: fluxcd - chart: fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator,cilium] - values: - flux-instance: - instance: - cluster: - domain: {{ $clusterDomain }} - -- name: cilium - releaseName: cilium - chart: cilium - namespace: cozy-cilium - privileged: true - dependsOn: [] - valuesFiles: - - values.yaml - - values-talos.yaml - values: - cilium: - enableIPv4Masquerade: true - enableIdentityMark: true - ipv4NativeRoutingCIDR: "{{ index $cozyConfig.data "ipv4-pod-cidr" }}" - autoDirectNodeRoutes: true - routingMode: native - -- name: cilium-networkpolicy - releaseName: cilium-networkpolicy - chart: cilium-networkpolicy - namespace: cozy-cilium - privileged: true - dependsOn: [cilium] - -- name: cozy-proxy - releaseName: cozystack - chart: cozy-proxy - namespace: cozy-system - optional: true - dependsOn: [cilium] - -- name: cert-manager-crds - releaseName: cert-manager-crds - chart: cert-manager-crds - namespace: cozy-cert-manager - dependsOn: [cilium] - -- name: cozystack-controller - releaseName: cozystack-controller - chart: cozystack-controller - namespace: cozy-system - dependsOn: [cilium] - {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} - values: - cozystackController: - disableTelemetry: true - {{- end }} - -- name: lineage-controller-webhook - releaseName: lineage-controller-webhook - chart: lineage-controller-webhook - namespace: cozy-system - dependsOn: [cozystack-controller,cilium,cert-manager] - -- name: cert-manager - releaseName: cert-manager - chart: cert-manager - namespace: cozy-cert-manager - dependsOn: [cert-manager-crds] - -- name: cert-manager-issuers - releaseName: cert-manager-issuers - chart: cert-manager-issuers - namespace: cozy-cert-manager - optional: true - dependsOn: [cilium,cert-manager] - -- name: victoria-metrics-operator - releaseName: victoria-metrics-operator - chart: victoria-metrics-operator - namespace: cozy-victoria-metrics-operator - optional: true - dependsOn: [cilium,cert-manager] - -- name: monitoring-agents - releaseName: monitoring-agents - chart: monitoring-agents - namespace: cozy-monitoring - privileged: true - optional: true - dependsOn: [cilium,victoria-metrics-operator] - values: - scrapeRules: - etcd: - enabled: true - -- name: metallb - releaseName: metallb - chart: metallb - namespace: cozy-metallb - privileged: true - dependsOn: [cilium] - -- name: etcd-operator - releaseName: etcd-operator - chart: etcd-operator - namespace: cozy-etcd-operator - optional: true - dependsOn: [cilium,cert-manager] - -- name: grafana-operator - releaseName: grafana-operator - chart: grafana-operator - namespace: cozy-grafana-operator - optional: true - dependsOn: [cilium] - -- name: mariadb-operator - releaseName: mariadb-operator - chart: mariadb-operator - namespace: cozy-mariadb-operator - optional: true - dependsOn: [cilium,cert-manager,victoria-metrics-operator] - values: - mariadb-operator: - clusterName: {{ $clusterDomain }} - -- name: postgres-operator - releaseName: postgres-operator - chart: postgres-operator - namespace: cozy-postgres-operator - optional: true - dependsOn: [cilium,cert-manager,victoria-metrics-operator] - -- name: kafka-operator - releaseName: kafka-operator - chart: kafka-operator - namespace: cozy-kafka-operator - optional: true - dependsOn: [cilium,victoria-metrics-operator] - values: - strimzi-kafka-operator: - kubernetesServiceDnsDomain: {{ $clusterDomain }} - -- name: clickhouse-operator - releaseName: clickhouse-operator - chart: clickhouse-operator - namespace: cozy-clickhouse-operator - optional: true - dependsOn: [cilium,victoria-metrics-operator] - -- name: foundationdb-operator - releaseName: foundationdb-operator - chart: foundationdb-operator - namespace: cozy-foundationdb-operator - optional: true - dependsOn: [cilium,cert-manager] - -- name: rabbitmq-operator - releaseName: rabbitmq-operator - chart: rabbitmq-operator - namespace: cozy-rabbitmq-operator - optional: true - dependsOn: [cilium] - -- name: redis-operator - releaseName: redis-operator - chart: redis-operator - namespace: cozy-redis-operator - optional: true - dependsOn: [cilium] - -- name: piraeus-operator - releaseName: piraeus-operator - chart: piraeus-operator - namespace: cozy-linstor - dependsOn: [cilium,cert-manager] - -- name: snapshot-controller - releaseName: snapshot-controller - chart: snapshot-controller - namespace: cozy-snapshot-controller - dependsOn: [cilium] - -- name: objectstorage-controller - releaseName: objectstorage-controller - chart: objectstorage-controller - namespace: cozy-objectstorage-controller - optional: true - dependsOn: [cilium] - -- name: linstor - releaseName: linstor - chart: linstor - namespace: cozy-linstor - privileged: true - dependsOn: [piraeus-operator,cilium,cert-manager,snapshot-controller] - -- name: nfs-driver - releaseName: nfs-driver - chart: nfs-driver - namespace: cozy-nfs-driver - privileged: true - dependsOn: [cilium] - optional: true - -- name: telepresence - releaseName: traffic-manager - chart: telepresence - namespace: cozy-telepresence - optional: true - dependsOn: [] - -- name: external-dns - releaseName: external-dns - chart: external-dns - namespace: cozy-external-dns - optional: true - dependsOn: [cilium] - -- name: external-secrets-operator - releaseName: external-secrets-operator - chart: external-secrets-operator - namespace: cozy-external-secrets-operator - optional: true - dependsOn: [cilium] - -- name: keycloak - releaseName: keycloak - chart: keycloak - namespace: cozy-keycloak - optional: true - dependsOn: [postgres-operator] - -- name: keycloak-operator - releaseName: keycloak-operator - chart: keycloak-operator - namespace: cozy-keycloak - optional: true - dependsOn: [keycloak] - -- name: bootbox - releaseName: bootbox - chart: bootbox - namespace: cozy-bootbox - privileged: true - optional: true - dependsOn: [cilium] - -- name: reloader - releaseName: reloader - chart: reloader - namespace: cozy-reloader - -- name: velero - releaseName: velero - chart: velero - namespace: cozy-velero - privileged: true - optional: true - dependsOn: [cilium] - -- name: hetzner-robotlb - releaseName: robotlb - optional: true - chart: hetzner-robotlb - namespace: cozy-hetzner-robotlb - dependsOn: [cilium] diff --git a/packages/core/platform/bundles/distro-hosted.yaml b/packages/core/platform/bundles/distro-hosted.yaml deleted file mode 100644 index c6ca13cc..00000000 --- a/packages/core/platform/bundles/distro-hosted.yaml +++ /dev/null @@ -1,192 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} - -releases: -- name: fluxcd-operator - releaseName: fluxcd-operator - chart: fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - -- name: fluxcd - releaseName: fluxcd - chart: fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator] - values: - flux-instance: - instance: - cluster: - domain: {{ $clusterDomain }} - -- name: cert-manager-crds - releaseName: cert-manager-crds - chart: cert-manager-crds - namespace: cozy-cert-manager - dependsOn: [] - -- name: cozystack-controller - releaseName: cozystack-controller - chart: cozystack-controller - namespace: cozy-system - {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} - values: - cozystackController: - disableTelemetry: true - {{- end }} - -- name: lineage-controller-webhook - releaseName: lineage-controller-webhook - chart: lineage-controller-webhook - namespace: cozy-system - dependsOn: [cozystack-controller,cert-manager] - -- name: cert-manager - releaseName: cert-manager - chart: cert-manager - namespace: cozy-cert-manager - dependsOn: [cert-manager-crds] - -- name: cert-manager-issuers - releaseName: cert-manager-issuers - chart: cert-manager-issuers - namespace: cozy-cert-manager - optional: true - dependsOn: [cert-manager] - -- name: victoria-metrics-operator - releaseName: victoria-metrics-operator - chart: victoria-metrics-operator - namespace: cozy-victoria-metrics-operator - optional: true - dependsOn: [cert-manager] - -- name: monitoring-agents - releaseName: monitoring-agents - chart: monitoring-agents - namespace: cozy-monitoring - privileged: true - optional: true - dependsOn: [victoria-metrics-operator] - values: - scrapeRules: - etcd: - enabled: true - -- name: etcd-operator - releaseName: etcd-operator - chart: etcd-operator - namespace: cozy-etcd-operator - optional: true - dependsOn: [cert-manager] - -- name: grafana-operator - releaseName: grafana-operator - chart: grafana-operator - namespace: cozy-grafana-operator - optional: true - dependsOn: [] - -- name: mariadb-operator - releaseName: mariadb-operator - chart: mariadb-operator - namespace: cozy-mariadb-operator - optional: true - dependsOn: [victoria-metrics-operator] - values: - mariadb-operator: - clusterName: {{ $clusterDomain }} - -- name: postgres-operator - releaseName: postgres-operator - chart: postgres-operator - namespace: cozy-postgres-operator - optional: true - dependsOn: [victoria-metrics-operator] - -- name: kafka-operator - releaseName: kafka-operator - chart: kafka-operator - namespace: cozy-kafka-operator - optional: true - dependsOn: [victoria-metrics-operator] - values: - strimzi-kafka-operator: - kubernetesServiceDnsDomain: {{ $clusterDomain }} - -- name: clickhouse-operator - releaseName: clickhouse-operator - chart: clickhouse-operator - namespace: cozy-clickhouse-operator - optional: true - dependsOn: [victoria-metrics-operator] - -- name: foundationdb-operator - releaseName: foundationdb-operator - chart: foundationdb-operator - namespace: cozy-foundationdb-operator - optional: true - dependsOn: [cert-manager] - -- name: rabbitmq-operator - releaseName: rabbitmq-operator - chart: rabbitmq-operator - namespace: cozy-rabbitmq-operator - optional: true - dependsOn: [] - -- name: redis-operator - releaseName: redis-operator - chart: redis-operator - namespace: cozy-redis-operator - optional: true - dependsOn: [] - -- name: telepresence - releaseName: traffic-manager - chart: telepresence - namespace: cozy-telepresence - optional: true - dependsOn: [] - -- name: external-dns - releaseName: external-dns - chart: external-dns - namespace: cozy-external-dns - optional: true - dependsOn: [] - -- name: external-secrets-operator - releaseName: external-secrets-operator - chart: external-secrets-operator - namespace: cozy-external-secrets-operator - optional: true - dependsOn: [] - -- name: keycloak - releaseName: keycloak - chart: keycloak - namespace: cozy-keycloak - optional: true - dependsOn: [postgres-operator] - -- name: keycloak-operator - releaseName: keycloak-operator - chart: keycloak-operator - namespace: cozy-keycloak - optional: true - dependsOn: [keycloak] - -- name: velero - releaseName: velero - chart: velero - namespace: cozy-velero - privileged: true - optional: true - -- name: hetzner-robotlb - releaseName: robotlb - optional: true - chart: hetzner-robotlb - namespace: cozy-hetzner-robotlb diff --git a/packages/system/cozystack-resource-definitions/cozyrds/bucket.yaml b/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/bucket.yaml rename to packages/core/platform/bundles/iaas/cozyrds/bucket.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/kubernetes.yaml b/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/kubernetes.yaml rename to packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/virtual-machine.yaml b/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/virtual-machine.yaml rename to packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/virtualprivatecloud.yaml b/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/virtualprivatecloud.yaml rename to packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/vm-disk.yaml b/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/vm-disk.yaml rename to packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/vm-instance.yaml b/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/vm-instance.yaml rename to packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml diff --git a/packages/core/platform/bundles/iaas/system-iaas.yaml b/packages/core/platform/bundles/iaas/system-iaas.yaml new file mode 100644 index 00000000..7286e0de --- /dev/null +++ b/packages/core/platform/bundles/iaas/system-iaas.yaml @@ -0,0 +1,100 @@ +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} +{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} +{{- $host := index $cozyConfig.data "root-host" }} +{{- if not $host }} +{{- fail "ERROR need root-host in cozystack ConfigMap" }} +{{- end }} +{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} +{{- if not $apiServerEndpoint }} +{{- fail "ERROR need api-server-endpoint in cozystack ConfigMap" }} +{{- end }} + +releases: +- name: kubevirt-operator + releaseName: kubevirt-operator + chart: kubevirt-operator + namespace: cozy-kubevirt + dependsOn: [cilium,kubeovn,victoria-metrics-operator] + +- name: kubevirt + releaseName: kubevirt + chart: kubevirt + namespace: cozy-kubevirt + privileged: true + dependsOn: [cilium,kubeovn,kubevirt-operator] + {{- $cpuAllocationRatio := index $cozyConfig.data "cpu-allocation-ratio" }} + {{- if $cpuAllocationRatio }} + values: + cpuAllocationRatio: {{ $cpuAllocationRatio }} + {{- end }} + +- name: kubevirt-instancetypes + releaseName: kubevirt-instancetypes + chart: kubevirt-instancetypes + namespace: cozy-kubevirt + dependsOn: [cilium,kubeovn,kubevirt-operator,kubevirt] + +- name: kubevirt-cdi-operator + releaseName: kubevirt-cdi-operator + chart: kubevirt-cdi-operator + namespace: cozy-kubevirt-cdi + dependsOn: [cilium,kubeovn] + +- name: kubevirt-cdi + releaseName: kubevirt-cdi + chart: kubevirt-cdi + namespace: cozy-kubevirt-cdi + dependsOn: [cilium,kubeovn,kubevirt-cdi-operator] + +- name: gpu-operator + releaseName: gpu-operator + chart: gpu-operator + namespace: cozy-gpu-operator + privileged: true + optional: true + dependsOn: [cilium,kubeovn] + valuesFiles: + - values.yaml + - values-talos.yaml + +- name: kamaji + releaseName: kamaji + chart: kamaji + namespace: cozy-kamaji + dependsOn: [cilium,kubeovn,cert-manager] + +- name: capi-operator + releaseName: capi-operator + chart: capi-operator + namespace: cozy-cluster-api + privileged: true + dependsOn: [cilium,kubeovn,cert-manager] + +- name: capi-providers-bootstrap + releaseName: capi-providers-bootstrap + chart: capi-providers-bootstrap + namespace: cozy-cluster-api + privileged: true + dependsOn: [cilium,kubeovn,capi-operator] + +- name: capi-providers-core + releaseName: capi-providers-core + chart: capi-providers-core + namespace: cozy-cluster-api + privileged: true + dependsOn: [cilium,kubeovn,capi-operator] + +- name: capi-providers-cpprovider + releaseName: capi-providers-cpprovider + chart: capi-providers-cpprovider + namespace: cozy-cluster-api + privileged: true + dependsOn: [cilium,kubeovn,capi-operator] + +- name: capi-providers-infraprovider + releaseName: capi-providers-infraprovider + chart: capi-providers-infraprovider + namespace: cozy-cluster-api + privileged: true + dependsOn: [cilium,kubeovn,capi-operator] diff --git a/packages/system/cozystack-resource-definitions/cozyrds/http-cache.yaml b/packages/core/platform/bundles/naas/http-cache.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/http-cache.yaml rename to packages/core/platform/bundles/naas/http-cache.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/tcp-balancer.yaml b/packages/core/platform/bundles/naas/tcp-balancer.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/tcp-balancer.yaml rename to packages/core/platform/bundles/naas/tcp-balancer.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/vpn.yaml b/packages/core/platform/bundles/naas/vpn.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/vpn.yaml rename to packages/core/platform/bundles/naas/vpn.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/clickhouse.yaml b/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/clickhouse.yaml rename to packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/ferretdb.yaml b/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/ferretdb.yaml rename to packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/foundationdb.yaml b/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/foundationdb.yaml rename to packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/kafka.yaml b/packages/core/platform/bundles/paas/cozyrds/kafka.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/kafka.yaml rename to packages/core/platform/bundles/paas/cozyrds/kafka.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/mysql.yaml b/packages/core/platform/bundles/paas/cozyrds/mysql.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/mysql.yaml rename to packages/core/platform/bundles/paas/cozyrds/mysql.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/nats.yaml b/packages/core/platform/bundles/paas/cozyrds/nats.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/nats.yaml rename to packages/core/platform/bundles/paas/cozyrds/nats.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/postgres.yaml b/packages/core/platform/bundles/paas/cozyrds/postgres.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/postgres.yaml rename to packages/core/platform/bundles/paas/cozyrds/postgres.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/rabbitmq.yaml b/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/rabbitmq.yaml rename to packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/redis.yaml b/packages/core/platform/bundles/paas/cozyrds/redis.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/redis.yaml rename to packages/core/platform/bundles/paas/cozyrds/redis.yaml diff --git a/packages/core/platform/bundles/paas/system-paas.yaml b/packages/core/platform/bundles/paas/system-paas.yaml new file mode 100644 index 00000000..119402bd --- /dev/null +++ b/packages/core/platform/bundles/paas/system-paas.yaml @@ -0,0 +1,53 @@ +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} +{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} +{{- $host := index $cozyConfig.data "root-host" }} +{{- if not $host }} +{{- fail "ERROR need root-host in cozystack ConfigMap" }} +{{- end }} +{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} +{{- if not $apiServerEndpoint }} +{{- fail "ERROR need api-server-endpoint in cozystack ConfigMap" }} +{{- end }} + +- name: mariadb-operator + releaseName: mariadb-operator + chart: mariadb-operator + namespace: cozy-mariadb-operator + dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] + values: + mariadb-operator: + clusterName: {{ $clusterDomain }} + +- name: kafka-operator + releaseName: kafka-operator + chart: kafka-operator + namespace: cozy-kafka-operator + dependsOn: [cilium,kubeovn,victoria-metrics-operator] + values: + strimzi-kafka-operator: + kubernetesServiceDnsDomain: {{ $clusterDomain }} + +- name: clickhouse-operator + releaseName: clickhouse-operator + chart: clickhouse-operator + namespace: cozy-clickhouse-operator + dependsOn: [cilium,kubeovn,victoria-metrics-operator] + +- name: foundationdb-operator + releaseName: foundationdb-operator + chart: foundationdb-operator + namespace: cozy-foundationdb-operator + dependsOn: [cilium,kubeovn,cert-manager] + +- name: rabbitmq-operator + releaseName: rabbitmq-operator + chart: rabbitmq-operator + namespace: cozy-rabbitmq-operator + dependsOn: [cilium,kubeovn] + +- name: redis-operator + releaseName: redis-operator + chart: redis-operator + namespace: cozy-redis-operator + dependsOn: [cilium,kubeovn] diff --git a/packages/system/cozystack-resource-definitions/cozyrds/bootbox.yaml b/packages/core/platform/bundles/system/cozyrds/bootbox.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/bootbox.yaml rename to packages/core/platform/bundles/system/cozyrds/bootbox.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/etcd.yaml b/packages/core/platform/bundles/system/cozyrds/etcd.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/etcd.yaml rename to packages/core/platform/bundles/system/cozyrds/etcd.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/info.yaml b/packages/core/platform/bundles/system/cozyrds/info.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/info.yaml rename to packages/core/platform/bundles/system/cozyrds/info.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/ingress.yaml b/packages/core/platform/bundles/system/cozyrds/ingress.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/ingress.yaml rename to packages/core/platform/bundles/system/cozyrds/ingress.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/monitoring.yaml b/packages/core/platform/bundles/system/cozyrds/monitoring.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/monitoring.yaml rename to packages/core/platform/bundles/system/cozyrds/monitoring.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/seaweedfs.yaml b/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/seaweedfs.yaml rename to packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml diff --git a/packages/system/cozystack-resource-definitions/cozyrds/tenant.yaml b/packages/core/platform/bundles/system/cozyrds/tenant.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/tenant.yaml rename to packages/core/platform/bundles/system/cozyrds/tenant.yaml diff --git a/packages/core/platform/bundles/paas-full.yaml b/packages/core/platform/bundles/system/system-full.yaml similarity index 71% rename from packages/core/platform/bundles/paas-full.yaml rename to packages/core/platform/bundles/system/system-full.yaml index 48b5c3a4..f66437d5 100644 --- a/packages/core/platform/bundles/paas-full.yaml +++ b/packages/core/platform/bundles/system/system-full.yaml @@ -159,53 +159,6 @@ releases: etcd: enabled: true -- name: kubevirt-operator - releaseName: kubevirt-operator - chart: kubevirt-operator - namespace: cozy-kubevirt - dependsOn: [cilium,kubeovn,victoria-metrics-operator] - -- name: kubevirt - releaseName: kubevirt - chart: kubevirt - namespace: cozy-kubevirt - privileged: true - dependsOn: [cilium,kubeovn,kubevirt-operator] - {{- $cpuAllocationRatio := index $cozyConfig.data "cpu-allocation-ratio" }} - {{- if $cpuAllocationRatio }} - values: - cpuAllocationRatio: {{ $cpuAllocationRatio }} - {{- end }} - -- name: kubevirt-instancetypes - releaseName: kubevirt-instancetypes - chart: kubevirt-instancetypes - namespace: cozy-kubevirt - dependsOn: [cilium,kubeovn,kubevirt-operator,kubevirt] - -- name: kubevirt-cdi-operator - releaseName: kubevirt-cdi-operator - chart: kubevirt-cdi-operator - namespace: cozy-kubevirt-cdi - dependsOn: [cilium,kubeovn] - -- name: kubevirt-cdi - releaseName: kubevirt-cdi - chart: kubevirt-cdi - namespace: cozy-kubevirt-cdi - dependsOn: [cilium,kubeovn,kubevirt-cdi-operator] - -- name: gpu-operator - releaseName: gpu-operator - chart: gpu-operator - namespace: cozy-gpu-operator - privileged: true - optional: true - dependsOn: [cilium,kubeovn] - valuesFiles: - - values.yaml - - values-talos.yaml - - name: metallb releaseName: metallb chart: metallb @@ -225,54 +178,12 @@ releases: namespace: cozy-grafana-operator dependsOn: [cilium,kubeovn] -- name: mariadb-operator - releaseName: mariadb-operator - chart: mariadb-operator - namespace: cozy-mariadb-operator - dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] - values: - mariadb-operator: - clusterName: {{ $clusterDomain }} - - name: postgres-operator releaseName: postgres-operator chart: postgres-operator namespace: cozy-postgres-operator dependsOn: [cilium,kubeovn,cert-manager] -- name: kafka-operator - releaseName: kafka-operator - chart: kafka-operator - namespace: cozy-kafka-operator - dependsOn: [cilium,kubeovn,victoria-metrics-operator] - values: - strimzi-kafka-operator: - kubernetesServiceDnsDomain: {{ $clusterDomain }} - -- name: clickhouse-operator - releaseName: clickhouse-operator - chart: clickhouse-operator - namespace: cozy-clickhouse-operator - dependsOn: [cilium,kubeovn,victoria-metrics-operator] - -- name: foundationdb-operator - releaseName: foundationdb-operator - chart: foundationdb-operator - namespace: cozy-foundationdb-operator - dependsOn: [cilium,kubeovn,cert-manager] - -- name: rabbitmq-operator - releaseName: rabbitmq-operator - chart: rabbitmq-operator - namespace: cozy-rabbitmq-operator - dependsOn: [cilium,kubeovn] - -- name: redis-operator - releaseName: redis-operator - chart: redis-operator - namespace: cozy-redis-operator - dependsOn: [cilium,kubeovn] - - name: piraeus-operator releaseName: piraeus-operator chart: piraeus-operator @@ -328,47 +239,6 @@ releases: - keycloak-configure {{- end }} -- name: kamaji - releaseName: kamaji - chart: kamaji - namespace: cozy-kamaji - dependsOn: [cilium,kubeovn,cert-manager] - -- name: capi-operator - releaseName: capi-operator - chart: capi-operator - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,cert-manager] - -- name: capi-providers-bootstrap - releaseName: capi-providers-bootstrap - chart: capi-providers-bootstrap - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] - -- name: capi-providers-core - releaseName: capi-providers-core - chart: capi-providers-core - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] - -- name: capi-providers-cpprovider - releaseName: capi-providers-cpprovider - chart: capi-providers-cpprovider - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] - -- name: capi-providers-infraprovider - releaseName: capi-providers-infraprovider - chart: capi-providers-infraprovider - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] - - name: external-dns releaseName: external-dns chart: external-dns diff --git a/packages/core/platform/bundles/paas-hosted.yaml b/packages/core/platform/bundles/system/system-hosted.yaml similarity index 86% rename from packages/core/platform/bundles/paas-hosted.yaml rename to packages/core/platform/bundles/system/system-hosted.yaml index f8f28527..1a06b6ee 100644 --- a/packages/core/platform/bundles/paas-hosted.yaml +++ b/packages/core/platform/bundles/system/system-hosted.yaml @@ -130,45 +130,6 @@ releases: namespace: cozy-postgres-operator dependsOn: [cert-manager,victoria-metrics-operator] -- name: kafka-operator - releaseName: kafka-operator - chart: kafka-operator - namespace: cozy-kafka-operator - dependsOn: [victoria-metrics-operator] - values: - strimzi-kafka-operator: - kubernetesServiceDnsDomain: {{ $clusterDomain }} - -- name: clickhouse-operator - releaseName: clickhouse-operator - chart: clickhouse-operator - namespace: cozy-clickhouse-operator - dependsOn: [victoria-metrics-operator] - -- name: foundationdb-operator - releaseName: foundationdb-operator - chart: foundationdb-operator - namespace: cozy-foundationdb-operator - dependsOn: [cert-manager] - -- name: rabbitmq-operator - releaseName: rabbitmq-operator - chart: rabbitmq-operator - namespace: cozy-rabbitmq-operator - dependsOn: [] - -- name: redis-operator - releaseName: redis-operator - chart: redis-operator - namespace: cozy-redis-operator - dependsOn: [] - -- name: piraeus-operator - releaseName: piraeus-operator - chart: piraeus-operator - namespace: cozy-linstor - dependsOn: [cert-manager] - - name: objectstorage-controller releaseName: objectstorage-controller chart: objectstorage-controller From 8a0935fb379416c5ac7eb60dcd936df26cff8b85 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 20 Nov 2025 00:49:26 +0100 Subject: [PATCH 14/46] Design CozystackBundle API Signed-off-by: Andrei Kvapil --- .../cozystackresourcedefinitions_types.go | 19 + api/v1alpha1/cozystacksystembundles_types.go | 156 +++ api/v1alpha1/zz_generated.deepcopy.go | 209 +++ cmd/cozystack-operator/main.go | 38 +- hack/update-codegen.sh | 2 + internal/operator/reconciler.go | 6 +- .../installer/templates/bundle-config.yaml | 1175 +---------------- packages/core/platform/Makefile | 19 +- .../core/platform/bundles/iaas/bundle.yaml | 116 ++ .../platform/bundles/iaas/cozyrds/bucket.yaml | 5 + .../bundles/iaas/cozyrds/kubernetes.yaml | 5 + .../bundles/iaas/cozyrds/virtual-machine.yaml | 5 + .../iaas/cozyrds/virtualprivatecloud.yaml | 5 + .../bundles/iaas/cozyrds/vm-disk.yaml | 5 + .../bundles/iaas/cozyrds/vm-instance.yaml | 5 + .../platform/bundles/iaas/system-iaas.yaml | 100 -- .../core/platform/bundles/naas/bundle.yaml | 17 + .../naas/{ => cozyrds}/http-cache.yaml | 5 + .../naas/{ => cozyrds}/tcp-balancer.yaml | 5 + .../bundles/naas/{ => cozyrds}/vpn.yaml | 5 + .../core/platform/bundles/paas/bundle.yaml | 71 + .../bundles/paas/cozyrds/clickhouse.yaml | 5 + .../bundles/paas/cozyrds/ferretdb.yaml | 5 + .../bundles/paas/cozyrds/foundationdb.yaml | 5 + .../platform/bundles/paas/cozyrds/kafka.yaml | 5 + .../platform/bundles/paas/cozyrds/mysql.yaml | 5 + .../platform/bundles/paas/cozyrds/nats.yaml | 5 + .../bundles/paas/cozyrds/postgres.yaml | 5 + .../bundles/paas/cozyrds/rabbitmq.yaml | 5 + .../platform/bundles/paas/cozyrds/redis.yaml | 5 + .../platform/bundles/paas/system-paas.yaml | 53 - .../platform/bundles/system/bundle-full.yaml | 349 +++++ .../bundles/system/bundle-hosted.yaml | 253 ++++ .../bundles/system/cozyrds/bootbox.yaml | 5 + .../platform/bundles/system/cozyrds/etcd.yaml | 5 + .../platform/bundles/system/cozyrds/info.yaml | 5 + .../bundles/system/cozyrds/ingress.yaml | 5 + .../bundles/system/cozyrds/monitoring.yaml | 5 + .../bundles/system/cozyrds/seaweedfs.yaml | 5 + .../bundles/system/cozyrds/tenant.yaml | 5 + .../platform/bundles/system/system-full.yaml | 331 ----- .../bundles/system/system-hosted.yaml | 235 ---- packages/core/platform/templates/_helpers.tpl | 24 + .../platform/templates/bundles-configmap.yaml | 58 +- packages/core/platform/values.yaml | 4 + .../Makefile | 3 + .../cozystack.io_cozystackbundles.yaml | 174 +++ ...stack.io_cozystackresourcedefinitions.yaml | 21 + .../templates/crd.yaml | 2 + .../cozystack-resource-definitions/Chart.yaml | 3 - .../cozystack-resource-definitions/Makefile | 4 - .../templates/cozyrds.yaml | 4 - .../values.yaml | 1 - 53 files changed, 1657 insertions(+), 1915 deletions(-) create mode 100644 api/v1alpha1/cozystacksystembundles_types.go create mode 100644 packages/core/platform/bundles/iaas/bundle.yaml delete mode 100644 packages/core/platform/bundles/iaas/system-iaas.yaml create mode 100644 packages/core/platform/bundles/naas/bundle.yaml rename packages/core/platform/bundles/naas/{ => cozyrds}/http-cache.yaml (98%) rename packages/core/platform/bundles/naas/{ => cozyrds}/tcp-balancer.yaml (99%) rename packages/core/platform/bundles/naas/{ => cozyrds}/vpn.yaml (98%) create mode 100644 packages/core/platform/bundles/paas/bundle.yaml delete mode 100644 packages/core/platform/bundles/paas/system-paas.yaml create mode 100644 packages/core/platform/bundles/system/bundle-full.yaml create mode 100644 packages/core/platform/bundles/system/bundle-hosted.yaml delete mode 100644 packages/core/platform/bundles/system/system-full.yaml delete mode 100644 packages/core/platform/bundles/system/system-hosted.yaml create mode 100644 packages/core/platform/values.yaml create mode 100644 packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackbundles.yaml delete mode 100644 packages/system/cozystack-resource-definitions/Chart.yaml delete mode 100644 packages/system/cozystack-resource-definitions/Makefile delete mode 100644 packages/system/cozystack-resource-definitions/templates/cozyrds.yaml delete mode 100644 packages/system/cozystack-resource-definitions/values.yaml diff --git a/api/v1alpha1/cozystackresourcedefinitions_types.go b/api/v1alpha1/cozystackresourcedefinitions_types.go index 6e71512d..6ca1008e 100644 --- a/api/v1alpha1/cozystackresourcedefinitions_types.go +++ b/api/v1alpha1/cozystackresourcedefinitions_types.go @@ -44,7 +44,26 @@ func init() { SchemeBuilder.Register(&CozystackResourceDefinition{}, &CozystackResourceDefinitionList{}) } +// CozystackResourceDefinitionSource defines the source configuration for bundle charts +type CozystackResourceDefinitionSource struct { + // BundleName is the name of the bundle that contains this chart + // +required + BundleName string `json:"bundleName"` + + // Path is the path to the directory containing the Helm chart + // +required + Path string `json:"path"` + + // Libraries is a list of library chart names used by this chart + // +optional + Libraries []string `json:"libraries,omitempty"` +} + type CozystackResourceDefinitionSpec struct { + // Source configuration for the bundle chart + // +optional + Source *CozystackResourceDefinitionSource `json:"source,omitempty"` + // Application configuration Application CozystackResourceDefinitionApplication `json:"application"` // Release configuration diff --git a/api/v1alpha1/cozystacksystembundles_types.go b/api/v1alpha1/cozystacksystembundles_types.go new file mode 100644 index 00000000..dfb6ab2c --- /dev/null +++ b/api/v1alpha1/cozystacksystembundles_types.go @@ -0,0 +1,156 @@ +/* +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 + +// CozystackBundle is the Schema for the cozystackbundles API +type CozystackBundle struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec CozystackBundleSpec `json:"spec,omitempty"` +} + +// +kubebuilder:object:root=true + +// CozystackBundleList contains a list of CozystackBundles +type CozystackBundleList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CozystackBundle `json:"items"` +} + +func init() { + SchemeBuilder.Register(&CozystackBundle{}, &CozystackBundleList{}) +} + +// CozystackBundleSpec defines the desired state of CozystackBundle +type CozystackBundleSpec 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"` + + // Packages is a list of Helm releases to be installed as part of this bundle + // +required + Packages []BundleRelease `json:"packages"` +} + +// 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"` +} + +// BundleSourceRef defines the source reference for bundle charts +type BundleSourceRef struct { + // Kind of the source reference + // +kubebuilder:validation:Enum=GitRepository + // +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"` +} + +// 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 + // +required + Path string `json:"path"` + + // 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"` +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 45b03556..f17c527a 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -21,10 +21,194 @@ limitations under the License. package v1alpha1 import ( + "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/api/resource" runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *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 *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) + } +} + +// 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 *CozystackBundle) DeepCopyInto(out *CozystackBundle) { + *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 CozystackBundle. +func (in *CozystackBundle) DeepCopy() *CozystackBundle { + if in == nil { + return nil + } + out := new(CozystackBundle) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CozystackBundle) 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 *CozystackBundleList) DeepCopyInto(out *CozystackBundleList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CozystackBundle, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackBundleList. +func (in *CozystackBundleList) DeepCopy() *CozystackBundleList { + if in == nil { + return nil + } + out := new(CozystackBundleList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CozystackBundleList) 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 *CozystackBundleSpec) DeepCopyInto(out *CozystackBundleSpec) { + *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.Packages != nil { + in, out := &in.Packages, &out.Packages + *out = make([]BundleRelease, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackBundleSpec. +func (in *CozystackBundleSpec) DeepCopy() *CozystackBundleSpec { + if in == nil { + return nil + } + out := new(CozystackBundleSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CozystackResourceDefinition) DeepCopyInto(out *CozystackResourceDefinition) { *out = *in @@ -256,9 +440,34 @@ func (in *CozystackResourceDefinitionResources) DeepCopy() *CozystackResourceDef return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CozystackResourceDefinitionSource) DeepCopyInto(out *CozystackResourceDefinitionSource) { + *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 CozystackResourceDefinitionSource. +func (in *CozystackResourceDefinitionSource) DeepCopy() *CozystackResourceDefinitionSource { + if in == nil { + return nil + } + out := new(CozystackResourceDefinitionSource) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CozystackResourceDefinitionSpec) DeepCopyInto(out *CozystackResourceDefinitionSpec) { *out = *in + if in.Source != nil { + in, out := &in.Source, &out.Source + *out = new(CozystackResourceDefinitionSource) + (*in).DeepCopyInto(*out) + } out.Application = in.Application in.Release.DeepCopyInto(&out.Release) in.Secrets.DeepCopyInto(&out.Secrets) diff --git a/cmd/cozystack-operator/main.go b/cmd/cozystack-operator/main.go index 9b549efa..a4df4e6f 100644 --- a/cmd/cozystack-operator/main.go +++ b/cmd/cozystack-operator/main.go @@ -242,7 +242,7 @@ func main() { <-mgrCtx.Done() } -// runBootstrapPhase1 installs fluxcd-operator and fluxcd, waits for CRDs +// runBootstrapPhase1 installs cozystack-resource-definition-crd, fluxcd-operator and fluxcd, waits for CRDs // This must complete before controller manager can start (manager needs CRDs registered) // Basic charts (cilium, kubeovn) are NOT installed here - they are installed in phase 2 after manager starts func runBootstrapPhase1(ctx context.Context, c client.Client) error { @@ -277,6 +277,12 @@ func runBootstrapPhase1(ctx context.Context, c client.Client) error { return fmt.Errorf("failed to create cozy-fluxcd namespace: %w", err) } + // Ensure cozystack-resource-definition-crd is installed + // This CRD is needed for the controller manager to start + if err := ensureCozystackResourceDefinitionCRD(ctx, c); err != nil { + return err + } + // Ensure fluxcd-operator and fluxcd are installed // This installs/resumes helmreleases and waits for CRDs to be registered // After CRDs are available, controller manager can start @@ -517,6 +523,36 @@ func runMigrations(ctx context.Context, c client.Client, targetVersion int) erro return nil } +// ensureCozystackResourceDefinitionCRD installs cozystack-resource-definition-crd and waits for CRD +// This CRD is needed for the controller manager to start +func ensureCozystackResourceDefinitionCRD(ctx context.Context, c client.Client) error { + // Check if CRD already exists + crd := &apiextensionsv1.CustomResourceDefinition{} + key := types.NamespacedName{Name: "cozystackresourcedefinitions.cozystack.io"} + if err := c.Get(ctx, key, crd); err == nil { + setupLog.Info("cozystack-resource-definition-crd CRD already exists, skipping installation") + return nil + } else if !apierrors.IsNotFound(err) { + return fmt.Errorf("failed to check cozystack-resource-definition-crd CRD: %w", err) + } + + // CRD doesn't exist, install it + setupLog.Info("Installing cozystack-resource-definition-crd") + cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/cozystack-resource-definition-crd", "apply-locally") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to install cozystack-resource-definition-crd: %w", err) + } + + // Wait for CRD + if err := waitForCRDs(ctx, c, "cozystackresourcedefinitions.cozystack.io"); err != nil { + return err + } + + return nil +} + func ensureFluxCD(ctx context.Context, c client.Client) error { fluxOK, err := fluxIsOK(ctx, c) if err != nil { diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index e181fc76..4eddab12 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -56,3 +56,5 @@ $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 mv packages/system/cozystack-controller/crds/cozystack.io_cozystackresourcedefinitions.yaml \ packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml +mv packages/system/cozystack-controller/crds/cozystack.io_cozystackbundles.yaml \ + packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackbundles.yaml diff --git a/internal/operator/reconciler.go b/internal/operator/reconciler.go index 283c4c0b..8e5b977e 100644 --- a/internal/operator/reconciler.go +++ b/internal/operator/reconciler.go @@ -720,11 +720,9 @@ func (r *PlatformReconciler) reconcileTenantRoot(ctx context.Context, cfg *confi ReleaseName: "tenant-root", Chart: &helmv2.HelmChartTemplate{ Spec: helmv2.HelmChartTemplateSpec{ - Chart: "tenant", - Version: ">= 0.0.0-0", SourceRef: helmv2.CrossNamespaceObjectReference{ - Kind: "HelmRepository", - Name: "cozystack-apps", + Kind: "ExternalArtifact", + Name: "apps-tenant", Namespace: "cozy-public", }, }, diff --git a/packages/core/installer/templates/bundle-config.yaml b/packages/core/installer/templates/bundle-config.yaml index a36a9ea8..0f04bfc0 100644 --- a/packages/core/installer/templates/bundle-config.yaml +++ b/packages/core/installer/templates/bundle-config.yaml @@ -1,1150 +1,33 @@ --- -# Source: cozy-platform/templates/bundles-configmap.yaml -apiVersion: v1 -kind: ConfigMap +apiVersion: source.toolkit.fluxcd.io/v1 +kind: GitRepository metadata: - name: system-bundle + name: cozystack namespace: cozy-system - labels: - cozystack.io/system: "true" -data: - paas-full.yaml: | - releases: - - name: fluxcd-operator - releaseName: fluxcd-operator - chart: fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - - - name: fluxcd - releaseName: fluxcd - chart: fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator,cilium,kubeovn] - values: - flux-instance: - instance: - cluster: - domain: cozy.local - - - name: cilium - releaseName: cilium - chart: cilium - namespace: cozy-cilium - privileged: true - dependsOn: [] - valuesFiles: - - values.yaml - - values-talos.yaml - - values-kubeovn.yaml - - - name: cilium-networkpolicy - releaseName: cilium-networkpolicy - chart: cilium-networkpolicy - namespace: cozy-cilium - privileged: true - dependsOn: [cilium] - - - name: kubeovn - releaseName: kubeovn - chart: kubeovn - namespace: cozy-kubeovn - privileged: true - dependsOn: [cilium] - values: - cozystack: - nodesHash: 72edd7b4e36265096d329359e6aad6916382d17b7907de4cdb7d7de3e0a1e3b5 - kube-ovn: - ipv4: - POD_CIDR: "10.244.0.0/16" - POD_GATEWAY: "10.244.0.1" - SVC_CIDR: "10.96.0.0/16" - JOIN_CIDR: "100.64.0.0/16" - - - name: kubeovn-webhook - releaseName: kubeovn-webhook - chart: kubeovn-webhook - namespace: cozy-kubeovn - privileged: true - dependsOn: [cilium,kubeovn,cert-manager] - - - name: kubeovn-plunger - releaseName: kubeovn-plunger - chart: kubeovn-plunger - namespace: cozy-kubeovn - dependsOn: [cilium,kubeovn] - - - name: multus - releaseName: multus - chart: multus - namespace: cozy-multus - privileged: true - dependsOn: [cilium,kubeovn] - - - name: cozy-proxy - releaseName: cozystack - chart: cozy-proxy +spec: + interval: 1m0s + ref: + branch: refactor-engine + timeout: 60s + url: https://github.com/cozystack/cozystack.git +--- +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: cozystack-platform + namespace: cozy-system +spec: + interval: 5m + targetNamespace: cozy-system + chart: + spec: + chart: ./packages/core/platform + sourceRef: + kind: GitRepository + name: cozystack + namespace: cozy-system + values: + sourceRef: + kind: GitRepository + name: cozystack namespace: cozy-system - dependsOn: [cilium,kubeovn] - - - name: cert-manager-crds - releaseName: cert-manager-crds - chart: cert-manager-crds - namespace: cozy-cert-manager - dependsOn: [cilium, kubeovn] - - - name: cozystack-api - releaseName: cozystack-api - chart: cozystack-api - namespace: cozy-system - dependsOn: [cilium,kubeovn,cozystack-controller] - - - name: cozystack-controller - releaseName: cozystack-controller - chart: cozystack-controller - namespace: cozy-system - dependsOn: [cilium,kubeovn] - - - name: lineage-controller-webhook - releaseName: lineage-controller-webhook - chart: lineage-controller-webhook - namespace: cozy-system - dependsOn: [cozystack-controller,cilium,kubeovn,cert-manager] - - - name: cozystack-resource-definition-crd - releaseName: cozystack-resource-definition-crd - chart: cozystack-resource-definition-crd - namespace: cozy-system - dependsOn: [cilium,kubeovn,cozystack-api,cozystack-controller] - - - name: cozystack-resource-definitions - releaseName: cozystack-resource-definitions - chart: cozystack-resource-definitions - namespace: cozy-system - dependsOn: [cilium,kubeovn,cozystack-api,cozystack-controller,cozystack-resource-definition-crd] - - - name: cert-manager - releaseName: cert-manager - chart: cert-manager - namespace: cozy-cert-manager - dependsOn: [cert-manager-crds] - - - name: cert-manager-issuers - releaseName: cert-manager-issuers - chart: cert-manager-issuers - namespace: cozy-cert-manager - dependsOn: [cilium,kubeovn,cert-manager] - - - name: victoria-metrics-operator - releaseName: victoria-metrics-operator - chart: victoria-metrics-operator - namespace: cozy-victoria-metrics-operator - dependsOn: [cilium,kubeovn,cert-manager] - - - name: monitoring-agents - releaseName: monitoring-agents - chart: monitoring-agents - namespace: cozy-monitoring - privileged: true - dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] - values: - scrapeRules: - etcd: - enabled: true - - - name: kubevirt-operator - releaseName: kubevirt-operator - chart: kubevirt-operator - namespace: cozy-kubevirt - dependsOn: [cilium,kubeovn,victoria-metrics-operator] - - - name: kubevirt - releaseName: kubevirt - chart: kubevirt - namespace: cozy-kubevirt - privileged: true - dependsOn: [cilium,kubeovn,kubevirt-operator] - - - name: kubevirt-instancetypes - releaseName: kubevirt-instancetypes - chart: kubevirt-instancetypes - namespace: cozy-kubevirt - dependsOn: [cilium,kubeovn,kubevirt-operator,kubevirt] - - - name: kubevirt-cdi-operator - releaseName: kubevirt-cdi-operator - chart: kubevirt-cdi-operator - namespace: cozy-kubevirt-cdi - dependsOn: [cilium,kubeovn] - - - name: kubevirt-cdi - releaseName: kubevirt-cdi - chart: kubevirt-cdi - namespace: cozy-kubevirt-cdi - dependsOn: [cilium,kubeovn,kubevirt-cdi-operator] - - - name: gpu-operator - releaseName: gpu-operator - chart: gpu-operator - namespace: cozy-gpu-operator - privileged: true - optional: true - dependsOn: [cilium,kubeovn] - valuesFiles: - - values.yaml - - values-talos.yaml - - - name: metallb - releaseName: metallb - chart: metallb - namespace: cozy-metallb - privileged: true - dependsOn: [cilium,kubeovn] - - - name: etcd-operator - releaseName: etcd-operator - chart: etcd-operator - namespace: cozy-etcd-operator - dependsOn: [cilium,kubeovn,cert-manager] - - - name: grafana-operator - releaseName: grafana-operator - chart: grafana-operator - namespace: cozy-grafana-operator - dependsOn: [cilium,kubeovn] - - - name: mariadb-operator - releaseName: mariadb-operator - chart: mariadb-operator - namespace: cozy-mariadb-operator - dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] - values: - mariadb-operator: - clusterName: cozy.local - - - name: postgres-operator - releaseName: postgres-operator - chart: postgres-operator - namespace: cozy-postgres-operator - dependsOn: [cilium,kubeovn,cert-manager] - - - name: kafka-operator - releaseName: kafka-operator - chart: kafka-operator - namespace: cozy-kafka-operator - dependsOn: [cilium,kubeovn,victoria-metrics-operator] - values: - strimzi-kafka-operator: - kubernetesServiceDnsDomain: cozy.local - - - name: clickhouse-operator - releaseName: clickhouse-operator - chart: clickhouse-operator - namespace: cozy-clickhouse-operator - dependsOn: [cilium,kubeovn,victoria-metrics-operator] - - - name: foundationdb-operator - releaseName: foundationdb-operator - chart: foundationdb-operator - namespace: cozy-foundationdb-operator - dependsOn: [cilium,kubeovn,cert-manager] - - - name: rabbitmq-operator - releaseName: rabbitmq-operator - chart: rabbitmq-operator - namespace: cozy-rabbitmq-operator - dependsOn: [cilium,kubeovn] - - - name: redis-operator - releaseName: redis-operator - chart: redis-operator - namespace: cozy-redis-operator - dependsOn: [cilium,kubeovn] - - - name: piraeus-operator - releaseName: piraeus-operator - chart: piraeus-operator - namespace: cozy-linstor - dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] - - - name: linstor - releaseName: linstor - chart: linstor - namespace: cozy-linstor - privileged: true - dependsOn: [piraeus-operator,cilium,kubeovn,cert-manager,snapshot-controller] - - - name: nfs-driver - releaseName: nfs-driver - chart: nfs-driver - namespace: cozy-nfs-driver - privileged: true - dependsOn: [cilium,kubeovn] - optional: true - - - name: snapshot-controller - releaseName: snapshot-controller - chart: snapshot-controller - namespace: cozy-snapshot-controller - dependsOn: [cilium,kubeovn,cert-manager-issuers] - - - name: objectstorage-controller - releaseName: objectstorage-controller - chart: objectstorage-controller - namespace: cozy-objectstorage-controller - dependsOn: [cilium,kubeovn] - - - name: telepresence - releaseName: traffic-manager - chart: telepresence - namespace: cozy-telepresence - optional: true - dependsOn: [cilium,kubeovn] - - - name: dashboard - releaseName: dashboard - chart: dashboard - namespace: cozy-dashboard - values: - {} - dependsOn: - - cilium - - kubeovn - - keycloak-configure - - - name: kamaji - releaseName: kamaji - chart: kamaji - namespace: cozy-kamaji - dependsOn: [cilium,kubeovn,cert-manager] - - - name: capi-operator - releaseName: capi-operator - chart: capi-operator - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,cert-manager] - - - name: capi-providers-bootstrap - releaseName: capi-providers-bootstrap - chart: capi-providers-bootstrap - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] - - - name: capi-providers-core - releaseName: capi-providers-core - chart: capi-providers-core - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] - - - name: capi-providers-cpprovider - releaseName: capi-providers-cpprovider - chart: capi-providers-cpprovider - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] - - - name: capi-providers-infraprovider - releaseName: capi-providers-infraprovider - chart: capi-providers-infraprovider - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] - - - name: external-dns - releaseName: external-dns - chart: external-dns - namespace: cozy-external-dns - optional: true - dependsOn: [cilium,kubeovn] - - - name: external-secrets-operator - releaseName: external-secrets-operator - chart: external-secrets-operator - namespace: cozy-external-secrets-operator - optional: true - dependsOn: [cilium,kubeovn] - - - name: bootbox - releaseName: bootbox - chart: bootbox - namespace: cozy-bootbox - privileged: true - optional: true - dependsOn: [cilium,kubeovn] - - name: keycloak - releaseName: keycloak - chart: keycloak - namespace: cozy-keycloak - dependsOn: [postgres-operator] - - - name: keycloak-operator - releaseName: keycloak-operator - chart: keycloak-operator - namespace: cozy-keycloak - dependsOn: [keycloak] - - - name: keycloak-configure - releaseName: keycloak-configure - chart: keycloak-configure - namespace: cozy-keycloak - dependsOn: [keycloak-operator] - values: - cozystack: - configHash: 8f0c52dd632b8398f4e975cf7a50ea2153b094e70c84c0b7e768b9cfbc513f0c - - - name: goldpinger - releaseName: goldpinger - chart: goldpinger - namespace: cozy-goldpinger - privileged: true - dependsOn: [monitoring-agents] - - - name: vertical-pod-autoscaler - releaseName: vertical-pod-autoscaler - chart: vertical-pod-autoscaler - namespace: cozy-vertical-pod-autoscaler - privileged: true - dependsOn: [monitoring-agents] - values: - vertical-pod-autoscaler: - recommender: - extraArgs: - prometheus-address: http://vmselect-shortterm.tenant-root.svc.cozy.local:8481/select/0/prometheus/ - - - name: vertical-pod-autoscaler-crds - releaseName: vertical-pod-autoscaler-crds - chart: vertical-pod-autoscaler-crds - namespace: cozy-vertical-pod-autoscaler - privileged: true - dependsOn: [cilium, kubeovn] - - - name: reloader - releaseName: reloader - chart: reloader - namespace: cozy-reloader - - - name: velero - releaseName: velero - chart: velero - namespace: cozy-velero - privileged: true - optional: true - dependsOn: [monitoring-agents] - - - name: hetzner-robotlb - releaseName: robotlb - optional: true - chart: hetzner-robotlb - namespace: cozy-hetzner-robotlb - dependsOn: [cilium, kubeovn] - paas-hosted.yaml: | - releases: - - name: fluxcd-operator - releaseName: fluxcd-operator - chart: fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - - - name: fluxcd - releaseName: fluxcd - chart: fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator] - values: - flux-instance: - instance: - cluster: - domain: cozy.local - - - name: cert-manager-crds - releaseName: cert-manager-crds - chart: cert-manager-crds - namespace: cozy-cert-manager - dependsOn: [] - - - name: cozystack-api - releaseName: cozystack-api - chart: cozystack-api - namespace: cozy-system - dependsOn: [cozystack-controller] - values: - cozystackAPI: - localK8sAPIEndpoint: - enabled: false - - - name: cozystack-controller - releaseName: cozystack-controller - chart: cozystack-controller - namespace: cozy-system - dependsOn: [] - - - name: lineage-controller-webhook - releaseName: lineage-controller-webhook - chart: lineage-controller-webhook - namespace: cozy-system - dependsOn: [cozystack-controller,cert-manager] - - - name: cozystack-resource-definition-crd - releaseName: cozystack-resource-definition-crd - chart: cozystack-resource-definition-crd - namespace: cozy-system - dependsOn: [cozystack-api,cozystack-controller] - - - name: cozystack-resource-definitions - releaseName: cozystack-resource-definitions - chart: cozystack-resource-definitions - namespace: cozy-system - dependsOn: [cozystack-api,cozystack-controller,cozystack-resource-definition-crd] - - - name: cert-manager - releaseName: cert-manager - chart: cert-manager - namespace: cozy-cert-manager - dependsOn: [cert-manager-crds] - - - name: cert-manager-issuers - releaseName: cert-manager-issuers - chart: cert-manager-issuers - namespace: cozy-cert-manager - dependsOn: [cert-manager] - - - name: victoria-metrics-operator - releaseName: victoria-metrics-operator - chart: victoria-metrics-operator - namespace: cozy-victoria-metrics-operator - dependsOn: [cert-manager] - - - name: monitoring-agents - releaseName: monitoring-agents - chart: monitoring-agents - namespace: cozy-monitoring - privileged: true - dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] - values: - scrapeRules: - etcd: - enabled: true - - - name: etcd-operator - releaseName: etcd-operator - chart: etcd-operator - namespace: cozy-etcd-operator - dependsOn: [cert-manager] - - - name: grafana-operator - releaseName: grafana-operator - chart: grafana-operator - namespace: cozy-grafana-operator - dependsOn: [] - - - name: mariadb-operator - releaseName: mariadb-operator - chart: mariadb-operator - namespace: cozy-mariadb-operator - dependsOn: [cert-manager,victoria-metrics-operator] - values: - mariadb-operator: - clusterName: cozy.local - - - name: postgres-operator - releaseName: postgres-operator - chart: postgres-operator - namespace: cozy-postgres-operator - dependsOn: [cert-manager,victoria-metrics-operator] - - - name: kafka-operator - releaseName: kafka-operator - chart: kafka-operator - namespace: cozy-kafka-operator - dependsOn: [victoria-metrics-operator] - values: - strimzi-kafka-operator: - kubernetesServiceDnsDomain: cozy.local - - - name: clickhouse-operator - releaseName: clickhouse-operator - chart: clickhouse-operator - namespace: cozy-clickhouse-operator - dependsOn: [victoria-metrics-operator] - - - name: foundationdb-operator - releaseName: foundationdb-operator - chart: foundationdb-operator - namespace: cozy-foundationdb-operator - dependsOn: [cert-manager] - - - name: rabbitmq-operator - releaseName: rabbitmq-operator - chart: rabbitmq-operator - namespace: cozy-rabbitmq-operator - dependsOn: [] - - - name: redis-operator - releaseName: redis-operator - chart: redis-operator - namespace: cozy-redis-operator - dependsOn: [] - - - name: piraeus-operator - releaseName: piraeus-operator - chart: piraeus-operator - namespace: cozy-linstor - dependsOn: [cert-manager] - - - name: objectstorage-controller - releaseName: objectstorage-controller - chart: objectstorage-controller - namespace: cozy-objectstorage-controller - dependsOn: [] - - - name: telepresence - releaseName: traffic-manager - chart: telepresence - namespace: cozy-telepresence - optional: true - dependsOn: [] - - - name: external-dns - releaseName: external-dns - chart: external-dns - namespace: cozy-external-dns - optional: true - dependsOn: [] - - - name: external-secrets-operator - releaseName: external-secrets-operator - chart: external-secrets-operator - namespace: cozy-external-secrets-operator - optional: true - dependsOn: [] - - - name: dashboard - releaseName: dashboard - chart: dashboard - namespace: cozy-dashboard - values: - {} - dependsOn: [keycloak-configure,cozystack-api] - - name: keycloak - releaseName: keycloak - chart: keycloak - namespace: cozy-keycloak - dependsOn: [postgres-operator] - - - name: keycloak-operator - releaseName: keycloak-operator - chart: keycloak-operator - namespace: cozy-keycloak - dependsOn: [keycloak] - - - name: keycloak-configure - releaseName: keycloak-configure - chart: keycloak-configure - namespace: cozy-keycloak - dependsOn: [keycloak-operator] - values: - cozystack: - configHash: 8f0c52dd632b8398f4e975cf7a50ea2153b094e70c84c0b7e768b9cfbc513f0c - - - name: goldpinger - releaseName: goldpinger - chart: goldpinger - namespace: cozy-goldpinger - privileged: true - dependsOn: [monitoring-agents] - - - name: vertical-pod-autoscaler - releaseName: vertical-pod-autoscaler - chart: vertical-pod-autoscaler - namespace: cozy-vertical-pod-autoscaler - privileged: true - dependsOn: [monitoring-agents] - values: - vertical-pod-autoscaler: - recommender: - extraArgs: - prometheus-address: http://vmselect-shortterm.tenant-root.svc.cozy.local:8481/select/0/prometheus/ - - - name: vertical-pod-autoscaler-crds - releaseName: vertical-pod-autoscaler-crds - chart: vertical-pod-autoscaler-crds - namespace: cozy-vertical-pod-autoscaler - privileged: true - dependsOn: [] - - - name: velero - releaseName: velero - chart: velero - namespace: cozy-velero - privileged: true - optional: true - dependsOn: [monitoring-agents] - - - name: hetzner-robotlb - releaseName: robotlb - optional: true - chart: hetzner-robotlb - namespace: cozy-hetzner-robotlb - distro-full.yaml: | - releases: - - name: fluxcd-operator - releaseName: fluxcd-operator - chart: fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - - - name: fluxcd - releaseName: fluxcd - chart: fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator,cilium] - values: - flux-instance: - instance: - cluster: - domain: cozy.local - - - name: cilium - releaseName: cilium - chart: cilium - namespace: cozy-cilium - privileged: true - dependsOn: [] - valuesFiles: - - values.yaml - - values-talos.yaml - values: - cilium: - enableIPv4Masquerade: true - enableIdentityMark: true - ipv4NativeRoutingCIDR: "10.244.0.0/16" - autoDirectNodeRoutes: true - routingMode: native - - - name: cilium-networkpolicy - releaseName: cilium-networkpolicy - chart: cilium-networkpolicy - namespace: cozy-cilium - privileged: true - dependsOn: [cilium] - - - name: cozy-proxy - releaseName: cozystack - chart: cozy-proxy - namespace: cozy-system - optional: true - dependsOn: [cilium] - - - name: cert-manager-crds - releaseName: cert-manager-crds - chart: cert-manager-crds - namespace: cozy-cert-manager - dependsOn: [cilium] - - - name: cozystack-controller - releaseName: cozystack-controller - chart: cozystack-controller - namespace: cozy-system - dependsOn: [cilium] - - - name: lineage-controller-webhook - releaseName: lineage-controller-webhook - chart: lineage-controller-webhook - namespace: cozy-system - dependsOn: [cozystack-controller,cilium,cert-manager] - - - name: cert-manager - releaseName: cert-manager - chart: cert-manager - namespace: cozy-cert-manager - dependsOn: [cert-manager-crds] - - - name: cert-manager-issuers - releaseName: cert-manager-issuers - chart: cert-manager-issuers - namespace: cozy-cert-manager - optional: true - dependsOn: [cilium,cert-manager] - - - name: victoria-metrics-operator - releaseName: victoria-metrics-operator - chart: victoria-metrics-operator - namespace: cozy-victoria-metrics-operator - optional: true - dependsOn: [cilium,cert-manager] - - - name: monitoring-agents - releaseName: monitoring-agents - chart: monitoring-agents - namespace: cozy-monitoring - privileged: true - optional: true - dependsOn: [cilium,victoria-metrics-operator] - values: - scrapeRules: - etcd: - enabled: true - - - name: metallb - releaseName: metallb - chart: metallb - namespace: cozy-metallb - privileged: true - dependsOn: [cilium] - - - name: etcd-operator - releaseName: etcd-operator - chart: etcd-operator - namespace: cozy-etcd-operator - optional: true - dependsOn: [cilium,cert-manager] - - - name: grafana-operator - releaseName: grafana-operator - chart: grafana-operator - namespace: cozy-grafana-operator - optional: true - dependsOn: [cilium] - - - name: mariadb-operator - releaseName: mariadb-operator - chart: mariadb-operator - namespace: cozy-mariadb-operator - optional: true - dependsOn: [cilium,cert-manager,victoria-metrics-operator] - values: - mariadb-operator: - clusterName: cozy.local - - - name: postgres-operator - releaseName: postgres-operator - chart: postgres-operator - namespace: cozy-postgres-operator - optional: true - dependsOn: [cilium,cert-manager,victoria-metrics-operator] - - - name: kafka-operator - releaseName: kafka-operator - chart: kafka-operator - namespace: cozy-kafka-operator - optional: true - dependsOn: [cilium,victoria-metrics-operator] - values: - strimzi-kafka-operator: - kubernetesServiceDnsDomain: cozy.local - - - name: clickhouse-operator - releaseName: clickhouse-operator - chart: clickhouse-operator - namespace: cozy-clickhouse-operator - optional: true - dependsOn: [cilium,victoria-metrics-operator] - - - name: foundationdb-operator - releaseName: foundationdb-operator - chart: foundationdb-operator - namespace: cozy-foundationdb-operator - optional: true - dependsOn: [cilium,cert-manager] - - - name: rabbitmq-operator - releaseName: rabbitmq-operator - chart: rabbitmq-operator - namespace: cozy-rabbitmq-operator - optional: true - dependsOn: [cilium] - - - name: redis-operator - releaseName: redis-operator - chart: redis-operator - namespace: cozy-redis-operator - optional: true - dependsOn: [cilium] - - - name: piraeus-operator - releaseName: piraeus-operator - chart: piraeus-operator - namespace: cozy-linstor - dependsOn: [cilium,cert-manager] - - - name: snapshot-controller - releaseName: snapshot-controller - chart: snapshot-controller - namespace: cozy-snapshot-controller - dependsOn: [cilium] - - - name: objectstorage-controller - releaseName: objectstorage-controller - chart: objectstorage-controller - namespace: cozy-objectstorage-controller - optional: true - dependsOn: [cilium] - - - name: linstor - releaseName: linstor - chart: linstor - namespace: cozy-linstor - privileged: true - dependsOn: [piraeus-operator,cilium,cert-manager,snapshot-controller] - - - name: nfs-driver - releaseName: nfs-driver - chart: nfs-driver - namespace: cozy-nfs-driver - privileged: true - dependsOn: [cilium] - optional: true - - - name: telepresence - releaseName: traffic-manager - chart: telepresence - namespace: cozy-telepresence - optional: true - dependsOn: [] - - - name: external-dns - releaseName: external-dns - chart: external-dns - namespace: cozy-external-dns - optional: true - dependsOn: [cilium] - - - name: external-secrets-operator - releaseName: external-secrets-operator - chart: external-secrets-operator - namespace: cozy-external-secrets-operator - optional: true - dependsOn: [cilium] - - - name: keycloak - releaseName: keycloak - chart: keycloak - namespace: cozy-keycloak - optional: true - dependsOn: [postgres-operator] - - - name: keycloak-operator - releaseName: keycloak-operator - chart: keycloak-operator - namespace: cozy-keycloak - optional: true - dependsOn: [keycloak] - - - name: bootbox - releaseName: bootbox - chart: bootbox - namespace: cozy-bootbox - privileged: true - optional: true - dependsOn: [cilium] - - - name: reloader - releaseName: reloader - chart: reloader - namespace: cozy-reloader - - - name: velero - releaseName: velero - chart: velero - namespace: cozy-velero - privileged: true - optional: true - dependsOn: [cilium] - - - name: hetzner-robotlb - releaseName: robotlb - optional: true - chart: hetzner-robotlb - namespace: cozy-hetzner-robotlb - dependsOn: [cilium] - distro-hosted.yaml: | - releases: - - name: fluxcd-operator - releaseName: fluxcd-operator - chart: fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - - - name: fluxcd - releaseName: fluxcd - chart: fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator] - values: - flux-instance: - instance: - cluster: - domain: cozy.local - - - name: cert-manager-crds - releaseName: cert-manager-crds - chart: cert-manager-crds - namespace: cozy-cert-manager - dependsOn: [] - - - name: cozystack-controller - releaseName: cozystack-controller - chart: cozystack-controller - namespace: cozy-system - - - name: lineage-controller-webhook - releaseName: lineage-controller-webhook - chart: lineage-controller-webhook - namespace: cozy-system - dependsOn: [cozystack-controller,cert-manager] - - - name: cert-manager - releaseName: cert-manager - chart: cert-manager - namespace: cozy-cert-manager - dependsOn: [cert-manager-crds] - - - name: cert-manager-issuers - releaseName: cert-manager-issuers - chart: cert-manager-issuers - namespace: cozy-cert-manager - optional: true - dependsOn: [cert-manager] - - - name: victoria-metrics-operator - releaseName: victoria-metrics-operator - chart: victoria-metrics-operator - namespace: cozy-victoria-metrics-operator - optional: true - dependsOn: [cert-manager] - - - name: monitoring-agents - releaseName: monitoring-agents - chart: monitoring-agents - namespace: cozy-monitoring - privileged: true - optional: true - dependsOn: [victoria-metrics-operator] - values: - scrapeRules: - etcd: - enabled: true - - - name: etcd-operator - releaseName: etcd-operator - chart: etcd-operator - namespace: cozy-etcd-operator - optional: true - dependsOn: [cert-manager] - - - name: grafana-operator - releaseName: grafana-operator - chart: grafana-operator - namespace: cozy-grafana-operator - optional: true - dependsOn: [] - - - name: mariadb-operator - releaseName: mariadb-operator - chart: mariadb-operator - namespace: cozy-mariadb-operator - optional: true - dependsOn: [victoria-metrics-operator] - values: - mariadb-operator: - clusterName: cozy.local - - - name: postgres-operator - releaseName: postgres-operator - chart: postgres-operator - namespace: cozy-postgres-operator - optional: true - dependsOn: [victoria-metrics-operator] - - - name: kafka-operator - releaseName: kafka-operator - chart: kafka-operator - namespace: cozy-kafka-operator - optional: true - dependsOn: [victoria-metrics-operator] - values: - strimzi-kafka-operator: - kubernetesServiceDnsDomain: cozy.local - - - name: clickhouse-operator - releaseName: clickhouse-operator - chart: clickhouse-operator - namespace: cozy-clickhouse-operator - optional: true - dependsOn: [victoria-metrics-operator] - - - name: foundationdb-operator - releaseName: foundationdb-operator - chart: foundationdb-operator - namespace: cozy-foundationdb-operator - optional: true - dependsOn: [cert-manager] - - - name: rabbitmq-operator - releaseName: rabbitmq-operator - chart: rabbitmq-operator - namespace: cozy-rabbitmq-operator - optional: true - dependsOn: [] - - - name: redis-operator - releaseName: redis-operator - chart: redis-operator - namespace: cozy-redis-operator - optional: true - dependsOn: [] - - - name: telepresence - releaseName: traffic-manager - chart: telepresence - namespace: cozy-telepresence - optional: true - dependsOn: [] - - - name: external-dns - releaseName: external-dns - chart: external-dns - namespace: cozy-external-dns - optional: true - dependsOn: [] - - - name: external-secrets-operator - releaseName: external-secrets-operator - chart: external-secrets-operator - namespace: cozy-external-secrets-operator - optional: true - dependsOn: [] - - - name: keycloak - releaseName: keycloak - chart: keycloak - namespace: cozy-keycloak - optional: true - dependsOn: [postgres-operator] - - - name: keycloak-operator - releaseName: keycloak-operator - chart: keycloak-operator - namespace: cozy-keycloak - optional: true - dependsOn: [keycloak] - - - name: velero - releaseName: velero - chart: velero - namespace: cozy-velero - privileged: true - optional: true - - - name: hetzner-robotlb - releaseName: robotlb - optional: true - chart: hetzner-robotlb - namespace: cozy-hetzner-robotlb diff --git a/packages/core/platform/Makefile b/packages/core/platform/Makefile index d3695c8a..b97d8532 100644 --- a/packages/core/platform/Makefile +++ b/packages/core/platform/Makefile @@ -1,19 +1,4 @@ -NAME=platform +NAME=cozystack-platform NAMESPACE=cozy-system -show: - cozypkg show -n $(NAMESPACE) $(NAME) --plain - -apply: - cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f- - -reconcile: apply - -namespaces-show: - cozypkg show -n $(NAMESPACE) $(NAME) --plain -s templates/namespaces.yaml - -namespaces-apply: - cozypkg show -n $(NAMESPACE) $(NAME) --plain -s templates/namespaces.yaml | kubectl apply -f- - -diff: - cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f- +include ../../../scripts/package.mk diff --git a/packages/core/platform/bundles/iaas/bundle.yaml b/packages/core/platform/bundles/iaas/bundle.yaml new file mode 100644 index 00000000..4c233dec --- /dev/null +++ b/packages/core/platform/bundles/iaas/bundle.yaml @@ -0,0 +1,116 @@ +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} +{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} +{{- $host := index $cozyConfig.data "root-host" }} +{{- if not $host }} +{{- fail "ERROR need root-host in cozystack ConfigMap" }} +{{- end }} +{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} +{{- if not $apiServerEndpoint }} +{{- fail "ERROR need api-server-endpoint in cozystack ConfigMap" }} +{{- end }} + +apiVersion: cozystack.io/v1alpha1 +kind: CozystackBundle +metadata: + name: cozystack-iaas +spec: + dependsOn: [cozystack-system/network] + + sourceRef: + kind: {{ .Values.sourceRef.kind }} + name: {{ .Values.sourceRef.name }} + namespace: {{ .Values.sourceRef.namespace }} + + libraries: + - name: cozy-lib + path: packages/library/cozy-lib + + packages: + - name: kubevirt-operator + releaseName: kubevirt-operator + path: packages/system/kubevirt-operator + namespace: cozy-kubevirt + dependsOn: [victoria-metrics-operator] + + - name: kubevirt + releaseName: kubevirt + path: packages/system/kubevirt + namespace: cozy-kubevirt + privileged: true + dependsOn: [kubevirt-operator] + {{- $cpuAllocationRatio := index $cozyConfig.data "cpu-allocation-ratio" }} + {{- if $cpuAllocationRatio }} + values: + cpuAllocationRatio: {{ $cpuAllocationRatio }} + {{- end }} + + - name: kubevirt-instancetypes + releaseName: kubevirt-instancetypes + path: packages/system/kubevirt-instancetypes + namespace: cozy-kubevirt + dependsOn: [kubevirt-operator,kubevirt] + + - name: kubevirt-cdi-operator + releaseName: kubevirt-cdi-operator + path: packages/system/kubevirt-cdi-operator + namespace: cozy-kubevirt-cdi + dependsOn: [] + + - name: kubevirt-cdi + releaseName: kubevirt-cdi + path: packages/system/kubevirt-cdi + namespace: cozy-kubevirt-cdi + dependsOn: [kubevirt-cdi-operator] + + - name: gpu-operator + releaseName: gpu-operator + path: packages/system/gpu-operator + namespace: cozy-gpu-operator + privileged: true + disabled: true + dependsOn: [] + valuesFiles: + - values.yaml + - values-talos.yaml + + - name: kamaji + releaseName: kamaji + path: packages/system/kamaji + namespace: cozy-kamaji + dependsOn: [] + + - name: capi-operator + releaseName: capi-operator + path: packages/system/capi-operator + namespace: cozy-cluster-api + privileged: true + dependsOn: [] + + - name: capi-providers-bootstrap + releaseName: capi-providers-bootstrap + path: packages/system/capi-providers-bootstrap + namespace: cozy-cluster-api + privileged: true + dependsOn: [capi-operator] + + - name: capi-providers-core + releaseName: capi-providers-core + path: packages/system/capi-providers-core + namespace: cozy-cluster-api + privileged: true + dependsOn: [capi-operator] + + - name: capi-providers-cpprovider + releaseName: capi-providers-cpprovider + path: packages/system/capi-providers-cpprovider + namespace: cozy-cluster-api + privileged: true + dependsOn: [capi-operator] + + - name: capi-providers-infraprovider + releaseName: capi-providers-infraprovider + path: packages/system/capi-providers-infraprovider + namespace: cozy-cluster-api + privileged: true + dependsOn: [capi-operator] diff --git a/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml b/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml index 0528a585..a9c38e49 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: bucket spec: + source: + bundleName: cozystack-iaas + path: packages/apps/bucket + libraries: [cozy-lib] + application: kind: Bucket plural: buckets diff --git a/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml b/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml index ed13ad84..aa2e7f15 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: kubernetes spec: + source: + bundleName: cozystack-iaas + path: packages/apps/kubernetes + libraries: [cozy-lib] + application: kind: Kubernetes singular: kubernetes diff --git a/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml b/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml index 2438d761..a537bfeb 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: virtual-machine spec: + source: + bundleName: cozystack-iaas + path: packages/apps/virtual-machine + libraries: [cozy-lib] + application: kind: VirtualMachine plural: virtualmachines diff --git a/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml b/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml index a1cc9b3d..49a1eebf 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: virtualprivatecloud spec: + source: + bundleName: cozystack-iaas + path: packages/apps/vpc + libraries: [cozy-lib] + application: kind: VirtualPrivateCloud plural: virtualprivateclouds diff --git a/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml b/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml index 42a34350..cd7c25fc 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: vm-disk spec: + source: + bundleName: cozystack-iaas + path: packages/apps/vm-disk + libraries: [cozy-lib] + application: kind: VMDisk singular: vmdisk diff --git a/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml b/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml index 85a6604f..c609aa6c 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: vm-instance spec: + source: + bundleName: cozystack-iaas + path: packages/apps/vm-instance + libraries: [cozy-lib] + application: kind: VMInstance singular: vminstance diff --git a/packages/core/platform/bundles/iaas/system-iaas.yaml b/packages/core/platform/bundles/iaas/system-iaas.yaml deleted file mode 100644 index 7286e0de..00000000 --- a/packages/core/platform/bundles/iaas/system-iaas.yaml +++ /dev/null @@ -1,100 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} -{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- if not $host }} -{{- fail "ERROR need root-host in cozystack ConfigMap" }} -{{- end }} -{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} -{{- if not $apiServerEndpoint }} -{{- fail "ERROR need api-server-endpoint in cozystack ConfigMap" }} -{{- end }} - -releases: -- name: kubevirt-operator - releaseName: kubevirt-operator - chart: kubevirt-operator - namespace: cozy-kubevirt - dependsOn: [cilium,kubeovn,victoria-metrics-operator] - -- name: kubevirt - releaseName: kubevirt - chart: kubevirt - namespace: cozy-kubevirt - privileged: true - dependsOn: [cilium,kubeovn,kubevirt-operator] - {{- $cpuAllocationRatio := index $cozyConfig.data "cpu-allocation-ratio" }} - {{- if $cpuAllocationRatio }} - values: - cpuAllocationRatio: {{ $cpuAllocationRatio }} - {{- end }} - -- name: kubevirt-instancetypes - releaseName: kubevirt-instancetypes - chart: kubevirt-instancetypes - namespace: cozy-kubevirt - dependsOn: [cilium,kubeovn,kubevirt-operator,kubevirt] - -- name: kubevirt-cdi-operator - releaseName: kubevirt-cdi-operator - chart: kubevirt-cdi-operator - namespace: cozy-kubevirt-cdi - dependsOn: [cilium,kubeovn] - -- name: kubevirt-cdi - releaseName: kubevirt-cdi - chart: kubevirt-cdi - namespace: cozy-kubevirt-cdi - dependsOn: [cilium,kubeovn,kubevirt-cdi-operator] - -- name: gpu-operator - releaseName: gpu-operator - chart: gpu-operator - namespace: cozy-gpu-operator - privileged: true - optional: true - dependsOn: [cilium,kubeovn] - valuesFiles: - - values.yaml - - values-talos.yaml - -- name: kamaji - releaseName: kamaji - chart: kamaji - namespace: cozy-kamaji - dependsOn: [cilium,kubeovn,cert-manager] - -- name: capi-operator - releaseName: capi-operator - chart: capi-operator - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,cert-manager] - -- name: capi-providers-bootstrap - releaseName: capi-providers-bootstrap - chart: capi-providers-bootstrap - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] - -- name: capi-providers-core - releaseName: capi-providers-core - chart: capi-providers-core - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] - -- name: capi-providers-cpprovider - releaseName: capi-providers-cpprovider - chart: capi-providers-cpprovider - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] - -- name: capi-providers-infraprovider - releaseName: capi-providers-infraprovider - chart: capi-providers-infraprovider - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] diff --git a/packages/core/platform/bundles/naas/bundle.yaml b/packages/core/platform/bundles/naas/bundle.yaml new file mode 100644 index 00000000..c9a55e6d --- /dev/null +++ b/packages/core/platform/bundles/naas/bundle.yaml @@ -0,0 +1,17 @@ +apiVersion: cozystack.io/v1alpha1 +kind: CozystackBundle +metadata: + name: cozystack-naas +spec: + dependsOn: [cozystack-system/network] + + sourceRef: + kind: {{ .Values.sourceRef.kind }} + name: {{ .Values.sourceRef.name }} + namespace: {{ .Values.sourceRef.namespace }} + + libraries: + - name: cozy-lib + path: packages/library/cozy-lib + + packages: [] diff --git a/packages/core/platform/bundles/naas/http-cache.yaml b/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml similarity index 98% rename from packages/core/platform/bundles/naas/http-cache.yaml rename to packages/core/platform/bundles/naas/cozyrds/http-cache.yaml index f71126dd..75ec6cea 100644 --- a/packages/core/platform/bundles/naas/http-cache.yaml +++ b/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: http-cache spec: + source: + bundleName: cozystack-naas + path: packages/apps/http-cache + libraries: [cozy-lib] + application: kind: HTTPCache plural: httpcaches diff --git a/packages/core/platform/bundles/naas/tcp-balancer.yaml b/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml similarity index 99% rename from packages/core/platform/bundles/naas/tcp-balancer.yaml rename to packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml index 7297fcbf..8c755dd3 100644 --- a/packages/core/platform/bundles/naas/tcp-balancer.yaml +++ b/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: tcp-balancer spec: + source: + bundleName: cozystack-naas + path: packages/apps/tcp-balancer + libraries: [cozy-lib] + application: kind: TCPBalancer plural: tcpbalancers diff --git a/packages/core/platform/bundles/naas/vpn.yaml b/packages/core/platform/bundles/naas/cozyrds/vpn.yaml similarity index 98% rename from packages/core/platform/bundles/naas/vpn.yaml rename to packages/core/platform/bundles/naas/cozyrds/vpn.yaml index 5a34e628..b095f281 100644 --- a/packages/core/platform/bundles/naas/vpn.yaml +++ b/packages/core/platform/bundles/naas/cozyrds/vpn.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: vpn spec: + source: + bundleName: cozystack-naas + path: packages/apps/vpn + libraries: [cozy-lib] + application: kind: VPN plural: vpns diff --git a/packages/core/platform/bundles/paas/bundle.yaml b/packages/core/platform/bundles/paas/bundle.yaml new file mode 100644 index 00000000..dd3cefd3 --- /dev/null +++ b/packages/core/platform/bundles/paas/bundle.yaml @@ -0,0 +1,71 @@ +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} +{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} +{{- $host := index $cozyConfig.data "root-host" }} +{{- if not $host }} +{{- fail "ERROR need root-host in cozystack ConfigMap" }} +{{- end }} +{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} +{{- if not $apiServerEndpoint }} +{{- fail "ERROR need api-server-endpoint in cozystack ConfigMap" }} +{{- end }} + +apiVersion: cozystack.io/v1alpha1 +kind: CozystackBundle +metadata: + name: cozystack-paas +spec: + + dependsOn: [cozystack-system/network] + + sourceRef: + kind: {{ .Values.sourceRef.kind }} + name: {{ .Values.sourceRef.name }} + namespace: {{ .Values.sourceRef.namespace }} + + libraries: + - name: cozy-lib + path: packages/library/cozy-lib + + packages: + - name: mariadb-operator + releaseName: mariadb-operator + path: packages/system/mariadb-operator + namespace: cozy-mariadb-operator + dependsOn: [cert-manager,victoria-metrics-operator] + values: + mariadb-operator: + clusterName: {{ $clusterDomain }} + + - name: kafka-operator + releaseName: kafka-operator + path: packages/system/kafka-operator + namespace: cozy-kafka-operator + dependsOn: [victoria-metrics-operator] + values: + strimzi-kafka-operator: + kubernetesServiceDnsDomain: {{ $clusterDomain }} + + - name: clickhouse-operator + releaseName: clickhouse-operator + path: packages/system/clickhouse-operator + namespace: cozy-clickhouse-operator + dependsOn: [victoria-metrics-operator] + + - name: foundationdb-operator + releaseName: foundationdb-operator + path: packages/system/foundationdb-operator + namespace: cozy-foundationdb-operator + dependsOn: [cert-manager] + + - name: rabbitmq-operator + releaseName: rabbitmq-operator + path: packages/system/rabbitmq-operator + namespace: cozy-rabbitmq-operator + dependsOn: [] + + - name: redis-operator + releaseName: redis-operator + path: packages/system/redis-operator + namespace: cozy-redis-operator + dependsOn: [] diff --git a/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml b/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml index c62f0ade..b912d58e 100644 --- a/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: clickhouse spec: + source: + bundleName: cozystack-paas + path: packages/apps/clickhouse + libraries: [cozy-lib] + application: kind: ClickHouse singular: clickhouse diff --git a/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml b/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml index 1ec63ad2..6ce828f7 100644 --- a/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: ferretdb spec: + source: + bundleName: cozystack-paas + path: packages/apps/ferretdb + libraries: [cozy-lib] + application: kind: FerretDB plural: ferretdbs diff --git a/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml b/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml index f1739214..7e1aa13e 100644 --- a/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: foundationdb spec: + source: + bundleName: cozystack-paas + path: packages/apps/foundationdb + libraries: [cozy-lib] + application: kind: FoundationDB singular: foundationdb diff --git a/packages/core/platform/bundles/paas/cozyrds/kafka.yaml b/packages/core/platform/bundles/paas/cozyrds/kafka.yaml index 8e251f2e..e8826516 100644 --- a/packages/core/platform/bundles/paas/cozyrds/kafka.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/kafka.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: kafka spec: + source: + bundleName: cozystack-paas + path: packages/apps/kafka + libraries: [cozy-lib] + application: kind: Kafka plural: kafkas diff --git a/packages/core/platform/bundles/paas/cozyrds/mysql.yaml b/packages/core/platform/bundles/paas/cozyrds/mysql.yaml index f0bcce8e..aa693d7a 100644 --- a/packages/core/platform/bundles/paas/cozyrds/mysql.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/mysql.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: mysql spec: + source: + bundleName: cozystack-paas + path: packages/apps/mysql + libraries: [cozy-lib] + application: kind: MySQL plural: mysqls diff --git a/packages/core/platform/bundles/paas/cozyrds/nats.yaml b/packages/core/platform/bundles/paas/cozyrds/nats.yaml index 97b46f9f..563226c2 100644 --- a/packages/core/platform/bundles/paas/cozyrds/nats.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/nats.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: nats spec: + source: + bundleName: cozystack-paas + path: packages/apps/nats + libraries: [cozy-lib] + application: kind: NATS plural: natses diff --git a/packages/core/platform/bundles/paas/cozyrds/postgres.yaml b/packages/core/platform/bundles/paas/cozyrds/postgres.yaml index debb60f3..ba403b3f 100644 --- a/packages/core/platform/bundles/paas/cozyrds/postgres.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/postgres.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: postgres spec: + source: + bundleName: cozystack-paas + path: packages/apps/postgres + libraries: [cozy-lib] + application: kind: Postgres singular: postgres diff --git a/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml b/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml index f33584f2..daa684fb 100644 --- a/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: rabbitmq spec: + source: + bundleName: cozystack-paas + path: packages/apps/rabbitmq + libraries: [cozy-lib] + application: kind: RabbitMQ plural: rabbitmqs diff --git a/packages/core/platform/bundles/paas/cozyrds/redis.yaml b/packages/core/platform/bundles/paas/cozyrds/redis.yaml index 984972cf..f9c8c6a3 100644 --- a/packages/core/platform/bundles/paas/cozyrds/redis.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/redis.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: redis spec: + source: + bundleName: cozystack-paas + path: packages/apps/redis + libraries: [cozy-lib] + application: kind: Redis plural: redises diff --git a/packages/core/platform/bundles/paas/system-paas.yaml b/packages/core/platform/bundles/paas/system-paas.yaml deleted file mode 100644 index 119402bd..00000000 --- a/packages/core/platform/bundles/paas/system-paas.yaml +++ /dev/null @@ -1,53 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} -{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- if not $host }} -{{- fail "ERROR need root-host in cozystack ConfigMap" }} -{{- end }} -{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} -{{- if not $apiServerEndpoint }} -{{- fail "ERROR need api-server-endpoint in cozystack ConfigMap" }} -{{- end }} - -- name: mariadb-operator - releaseName: mariadb-operator - chart: mariadb-operator - namespace: cozy-mariadb-operator - dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] - values: - mariadb-operator: - clusterName: {{ $clusterDomain }} - -- name: kafka-operator - releaseName: kafka-operator - chart: kafka-operator - namespace: cozy-kafka-operator - dependsOn: [cilium,kubeovn,victoria-metrics-operator] - values: - strimzi-kafka-operator: - kubernetesServiceDnsDomain: {{ $clusterDomain }} - -- name: clickhouse-operator - releaseName: clickhouse-operator - chart: clickhouse-operator - namespace: cozy-clickhouse-operator - dependsOn: [cilium,kubeovn,victoria-metrics-operator] - -- name: foundationdb-operator - releaseName: foundationdb-operator - chart: foundationdb-operator - namespace: cozy-foundationdb-operator - dependsOn: [cilium,kubeovn,cert-manager] - -- name: rabbitmq-operator - releaseName: rabbitmq-operator - chart: rabbitmq-operator - namespace: cozy-rabbitmq-operator - dependsOn: [cilium,kubeovn] - -- name: redis-operator - releaseName: redis-operator - chart: redis-operator - namespace: cozy-redis-operator - dependsOn: [cilium,kubeovn] diff --git a/packages/core/platform/bundles/system/bundle-full.yaml b/packages/core/platform/bundles/system/bundle-full.yaml new file mode 100644 index 00000000..d449a352 --- /dev/null +++ b/packages/core/platform/bundles/system/bundle-full.yaml @@ -0,0 +1,349 @@ +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} +{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} +{{- $host := index $cozyConfig.data "root-host" }} +{{- if not $host }} +{{- fail "ERROR need root-host in cozystack ConfigMap" }} +{{- end }} +{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} +{{- if not $apiServerEndpoint }} +{{- fail "ERROR need api-server-endpoint in cozystack ConfigMap" }} +{{- end }} + +apiVersion: cozystack.io/v1alpha1 +kind: CozystackBundle +metadata: + name: cozystack-system + finalizers: + - cozystack.io/system-bundle-protection +spec: + + dependencyTargets: + - name: network + packages: [cilium,kubeovn] + + sourceRef: + kind: {{ .Values.sourceRef.kind }} + name: {{ .Values.sourceRef.name }} + namespace: {{ .Values.sourceRef.namespace }} + + libraries: + - name: cozy-lib + path: packages/library/cozy-lib + + packages: + - name: fluxcd-operator + releaseName: fluxcd-operator + path: packages/system/fluxcd-operator + namespace: cozy-fluxcd + privileged: true + dependsOn: [] + + - name: fluxcd + releaseName: fluxcd + path: packages/system/fluxcd + namespace: cozy-fluxcd + dependsOn: [fluxcd-operator,cilium,kubeovn] + values: + flux-instance: + instance: + cluster: + domain: {{ $clusterDomain }} + + - name: cilium + releaseName: cilium + path: packages/system/cilium + namespace: cozy-cilium + privileged: true + dependsOn: [] + valuesFiles: + - values.yaml + - values-talos.yaml + - values-kubeovn.yaml + + - name: cilium-networkpolicy + releaseName: cilium-networkpolicy + path: packages/system/cilium-networkpolicy + namespace: cozy-cilium + privileged: true + dependsOn: [cilium] + + - name: kubeovn + releaseName: kubeovn + path: packages/system/kubeovn + namespace: cozy-kubeovn + privileged: true + dependsOn: [cilium] + values: + cozystack: + nodesHash: {{ include "cozystack.master-node-ips" . | sha256sum }} + kube-ovn: + ipv4: + POD_CIDR: "{{ index $cozyConfig.data "ipv4-pod-cidr" }}" + POD_GATEWAY: "{{ index $cozyConfig.data "ipv4-pod-gateway" }}" + SVC_CIDR: "{{ index $cozyConfig.data "ipv4-svc-cidr" }}" + JOIN_CIDR: "{{ index $cozyConfig.data "ipv4-join-cidr" }}" + + - name: kubeovn-webhook + releaseName: kubeovn-webhook + path: packages/system/kubeovn-webhook + namespace: cozy-kubeovn + privileged: true + dependsOn: [cilium,kubeovn,cert-manager] + + - name: kubeovn-plunger + releaseName: kubeovn-plunger + path: packages/system/kubeovn-plunger + namespace: cozy-kubeovn + dependsOn: [cilium,kubeovn] + + - name: multus + releaseName: multus + path: packages/system/multus + namespace: cozy-multus + privileged: true + dependsOn: [cilium,kubeovn] + + - name: cozy-proxy + releaseName: cozystack + path: packages/system/cozy-proxy + namespace: cozy-system + dependsOn: [cilium,kubeovn] + + - name: cert-manager-crds + releaseName: cert-manager-crds + path: packages/system/cert-manager-crds + namespace: cozy-cert-manager + dependsOn: [cilium, kubeovn] + + - name: cozystack-api + releaseName: cozystack-api + path: packages/system/cozystack-api + namespace: cozy-system + dependsOn: [cilium,kubeovn,cozystack-controller] + + - name: cozystack-controller + releaseName: cozystack-controller + path: packages/system/cozystack-controller + namespace: cozy-system + dependsOn: [cilium,kubeovn] + {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} + values: + cozystackController: + disableTelemetry: true + {{- end }} + + - name: lineage-controller-webhook + releaseName: lineage-controller-webhook + path: packages/system/lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller,cilium,kubeovn,cert-manager] + + - name: cozystack-resource-definition-crd + releaseName: cozystack-resource-definition-crd + path: packages/system/cozystack-resource-definition-crd + namespace: cozy-system + dependsOn: [cilium,kubeovn,cozystack-api,cozystack-controller] + + - name: cozystack-resource-definitions + releaseName: cozystack-resource-definitions + path: packages/system/cozystack-resource-definitions + namespace: cozy-system + dependsOn: [cilium,kubeovn,cozystack-api,cozystack-controller,cozystack-resource-definition-crd] + + - name: cert-manager + releaseName: cert-manager + path: packages/system/cert-manager + namespace: cozy-cert-manager + dependsOn: [cert-manager-crds] + + - name: cert-manager-issuers + releaseName: cert-manager-issuers + path: packages/system/cert-manager-issuers + namespace: cozy-cert-manager + dependsOn: [cilium,kubeovn,cert-manager] + + - name: victoria-metrics-operator + releaseName: victoria-metrics-operator + path: packages/system/victoria-metrics-operator + namespace: cozy-victoria-metrics-operator + dependsOn: [cilium,kubeovn,cert-manager] + + - name: monitoring-agents + releaseName: monitoring-agents + path: packages/system/monitoring-agents + namespace: cozy-monitoring + privileged: true + dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] + values: + scrapeRules: + etcd: + enabled: true + + - name: metallb + releaseName: metallb + path: packages/system/metallb + namespace: cozy-metallb + privileged: true + dependsOn: [cilium,kubeovn] + + - name: etcd-operator + releaseName: etcd-operator + path: packages/system/etcd-operator + namespace: cozy-etcd-operator + dependsOn: [cilium,kubeovn,cert-manager] + + - name: grafana-operator + releaseName: grafana-operator + path: packages/system/grafana-operator + namespace: cozy-grafana-operator + dependsOn: [cilium,kubeovn] + + - name: postgres-operator + releaseName: postgres-operator + path: packages/system/postgres-operator + namespace: cozy-postgres-operator + dependsOn: [cilium,kubeovn,cert-manager] + + - name: piraeus-operator + releaseName: piraeus-operator + path: packages/system/piraeus-operator + namespace: cozy-linstor + dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] + + - name: linstor + releaseName: linstor + path: packages/system/linstor + namespace: cozy-linstor + privileged: true + dependsOn: [piraeus-operator,cilium,kubeovn,cert-manager,snapshot-controller] + + - name: nfs-driver + releaseName: nfs-driver + path: packages/system/nfs-driver + namespace: cozy-nfs-driver + privileged: true + dependsOn: [cilium,kubeovn] + disabled: true + + - name: snapshot-controller + releaseName: snapshot-controller + path: packages/system/snapshot-controller + namespace: cozy-snapshot-controller + dependsOn: [cilium,kubeovn,cert-manager-issuers] + + - name: objectstorage-controller + releaseName: objectstorage-controller + path: packages/system/objectstorage-controller + namespace: cozy-objectstorage-controller + dependsOn: [cilium,kubeovn] + + - name: telepresence + releaseName: traffic-manager + path: packages/system/telepresence + namespace: cozy-telepresence + disabled: true + dependsOn: [cilium,kubeovn] + + - name: dashboard + releaseName: dashboard + path: packages/system/dashboard + namespace: cozy-dashboard + dependsOn: + - cilium + - kubeovn + {{- if eq $oidcEnabled "true" }} + - keycloak-configure + {{- end }} + + - name: external-dns + releaseName: external-dns + path: packages/system/external-dns + namespace: cozy-external-dns + disabled: true + dependsOn: [cilium,kubeovn] + + - name: external-secrets-operator + releaseName: external-secrets-operator + path: packages/system/external-secrets-operator + namespace: cozy-external-secrets-operator + disabled: true + dependsOn: [cilium,kubeovn] + + - name: bootbox + releaseName: bootbox + path: packages/system/bootbox + namespace: cozy-bootbox + privileged: true + disabled: true + dependsOn: [cilium,kubeovn] + + {{- if $oidcEnabled }} + - name: keycloak + releaseName: keycloak + path: packages/system/keycloak + namespace: cozy-keycloak + dependsOn: [postgres-operator] + libraries: [cozy-lib] + + - name: keycloak-operator + releaseName: keycloak-operator + path: packages/system/keycloak-operator + namespace: cozy-keycloak + dependsOn: [keycloak] + + - name: keycloak-configure + releaseName: keycloak-configure + path: packages/system/keycloak-configure + namespace: cozy-keycloak + dependsOn: [keycloak-operator] + values: + cozystack: + configHash: {{ $cozyConfig | toJson | sha256sum }} + {{- end }} + + - name: goldpinger + releaseName: goldpinger + path: packages/system/goldpinger + namespace: cozy-goldpinger + privileged: true + dependsOn: [monitoring-agents] + + - name: vertical-pod-autoscaler + releaseName: vertical-pod-autoscaler + path: packages/system/vertical-pod-autoscaler + namespace: cozy-vertical-pod-autoscaler + privileged: true + dependsOn: [monitoring-agents] + values: + vertical-pod-autoscaler: + recommender: + extraArgs: + prometheus-address: http://vmselect-shortterm.tenant-root.svc.{{ $clusterDomain }}:8481/select/0/prometheus/ + + - name: vertical-pod-autoscaler-crds + releaseName: vertical-pod-autoscaler-crds + path: packages/system/vertical-pod-autoscaler-crds + namespace: cozy-vertical-pod-autoscaler + privileged: true + dependsOn: [cilium, kubeovn] + + - name: reloader + releaseName: reloader + path: packages/system/reloader + namespace: cozy-reloader + + - name: velero + releaseName: velero + path: packages/system/velero + namespace: cozy-velero + privileged: true + disabled: true + dependsOn: [monitoring-agents] + + - name: hetzner-robotlb + releaseName: robotlb + disabled: true + path: packages/system/hetzner-robotlb + namespace: cozy-hetzner-robotlb + dependsOn: [cilium, kubeovn] diff --git a/packages/core/platform/bundles/system/bundle-hosted.yaml b/packages/core/platform/bundles/system/bundle-hosted.yaml new file mode 100644 index 00000000..41c67227 --- /dev/null +++ b/packages/core/platform/bundles/system/bundle-hosted.yaml @@ -0,0 +1,253 @@ +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} +{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} +{{- $host := index $cozyConfig.data "root-host" }} +{{- if not $host }} +{{- fail "ERROR need root-host in cozystack ConfigMap" }} +{{- end }} +{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} +{{- if not $apiServerEndpoint }} +{{- fail "ERROR need api-server-endpoint in cozystack ConfigMap" }} +{{- end }} + +apiVersion: cozystack.io/v1alpha1 +kind: CozystackBundle +metadata: + name: cozystack-system + finalizers: + - cozystack.io/system-bundle-protection +spec: + + dependencyTargets: + - name: network + packages: [] + + sourceRef: + kind: {{ .Values.sourceRef.kind }} + name: {{ .Values.sourceRef.name }} + namespace: {{ .Values.sourceRef.namespace }} + + libraries: + - name: cozy-lib + path: packages/library/cozy-lib + + packages: + - name: fluxcd-operator + releaseName: fluxcd-operator + path: packages/system/fluxcd-operator + namespace: cozy-fluxcd + privileged: true + dependsOn: [] + + - name: fluxcd + releaseName: fluxcd + path: packages/system/fluxcd + namespace: cozy-fluxcd + dependsOn: [fluxcd-operator] + values: + flux-instance: + instance: + cluster: + domain: {{ $clusterDomain }} + + - name: cert-manager-crds + releaseName: cert-manager-crds + path: packages/system/cert-manager-crds + namespace: cozy-cert-manager + dependsOn: [] + + - name: cozystack-api + releaseName: cozystack-api + path: packages/system/cozystack-api + namespace: cozy-system + dependsOn: [cozystack-controller] + values: + cozystackAPI: + localK8sAPIEndpoint: + enabled: false + + - name: cozystack-controller + releaseName: cozystack-controller + path: packages/system/cozystack-controller + namespace: cozy-system + dependsOn: [] + {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} + values: + cozystackController: + disableTelemetry: true + {{- end }} + + - name: lineage-controller-webhook + releaseName: lineage-controller-webhook + path: packages/system/lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller,cert-manager] + + - name: cozystack-resource-definition-crd + releaseName: cozystack-resource-definition-crd + path: packages/system/cozystack-resource-definition-crd + namespace: cozy-system + dependsOn: [cozystack-api,cozystack-controller] + + - name: cozystack-resource-definitions + releaseName: cozystack-resource-definitions + path: packages/system/cozystack-resource-definitions + namespace: cozy-system + dependsOn: [cozystack-api,cozystack-controller,cozystack-resource-definition-crd] + + - name: cert-manager + releaseName: cert-manager + path: packages/system/cert-manager + namespace: cozy-cert-manager + dependsOn: [cert-manager-crds] + + - name: cert-manager-issuers + releaseName: cert-manager-issuers + path: packages/system/cert-manager-issuers + namespace: cozy-cert-manager + dependsOn: [cert-manager] + + - name: victoria-metrics-operator + releaseName: victoria-metrics-operator + path: packages/system/victoria-metrics-operator + namespace: cozy-victoria-metrics-operator + dependsOn: [cert-manager] + + - name: monitoring-agents + releaseName: monitoring-agents + path: packages/system/monitoring-agents + namespace: cozy-monitoring + privileged: true + dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] + values: + scrapeRules: + etcd: + enabled: true + + - name: etcd-operator + releaseName: etcd-operator + path: packages/system/etcd-operator + namespace: cozy-etcd-operator + dependsOn: [cert-manager] + + - name: grafana-operator + releaseName: grafana-operator + path: packages/system/grafana-operator + namespace: cozy-grafana-operator + dependsOn: [] + + - name: mariadb-operator + releaseName: mariadb-operator + path: packages/system/mariadb-operator + namespace: cozy-mariadb-operator + dependsOn: [cert-manager,victoria-metrics-operator] + values: + mariadb-operator: + clusterName: {{ $clusterDomain }} + + - name: postgres-operator + releaseName: postgres-operator + path: packages/system/postgres-operator + namespace: cozy-postgres-operator + dependsOn: [cert-manager,victoria-metrics-operator] + + - name: objectstorage-controller + releaseName: objectstorage-controller + path: packages/system/objectstorage-controller + namespace: cozy-objectstorage-controller + dependsOn: [] + + - name: telepresence + releaseName: traffic-manager + path: packages/system/telepresence + namespace: cozy-telepresence + disabled: true + dependsOn: [] + + - name: external-dns + releaseName: external-dns + path: packages/system/external-dns + namespace: cozy-external-dns + disabled: true + dependsOn: [] + + - name: external-secrets-operator + releaseName: external-secrets-operator + path: packages/system/external-secrets-operator + namespace: cozy-external-secrets-operator + disabled: true + dependsOn: [] + + - name: dashboard + releaseName: dashboard + path: packages/system/dashboard + namespace: cozy-dashboard + {{- if eq $oidcEnabled "true" }} + dependsOn: [keycloak-configure,cozystack-api] + {{- else }} + dependsOn: [] + {{- end }} + + {{- if $oidcEnabled }} + - name: keycloak + releaseName: keycloak + path: packages/system/keycloak + namespace: cozy-keycloak + dependsOn: [postgres-operator] + libraries: [cozy-lib] + + - name: keycloak-operator + releaseName: keycloak-operator + path: packages/system/keycloak-operator + namespace: cozy-keycloak + dependsOn: [keycloak] + + - name: keycloak-configure + releaseName: keycloak-configure + path: packages/system/keycloak-configure + namespace: cozy-keycloak + dependsOn: [keycloak-operator] + values: + cozystack: + configHash: {{ $cozyConfig | toJson | sha256sum }} + {{- end }} + + - name: goldpinger + releaseName: goldpinger + path: packages/system/goldpinger + namespace: cozy-goldpinger + privileged: true + dependsOn: [monitoring-agents] + + - name: vertical-pod-autoscaler + releaseName: vertical-pod-autoscaler + path: packages/system/vertical-pod-autoscaler + namespace: cozy-vertical-pod-autoscaler + privileged: true + dependsOn: [monitoring-agents] + values: + vertical-pod-autoscaler: + recommender: + extraArgs: + prometheus-address: http://vmselect-shortterm.tenant-root.svc.{{ $clusterDomain }}:8481/select/0/prometheus/ + + - name: vertical-pod-autoscaler-crds + releaseName: vertical-pod-autoscaler-crds + path: packages/system/vertical-pod-autoscaler-crds + namespace: cozy-vertical-pod-autoscaler + privileged: true + dependsOn: [] + + - name: velero + releaseName: velero + path: packages/system/velero + namespace: cozy-velero + privileged: true + disabled: true + dependsOn: [monitoring-agents] + + - name: hetzner-robotlb + releaseName: robotlb + disabled: true + path: packages/system/hetzner-robotlb + namespace: cozy-hetzner-robotlb diff --git a/packages/core/platform/bundles/system/cozyrds/bootbox.yaml b/packages/core/platform/bundles/system/cozyrds/bootbox.yaml index de09a66b..874b1d24 100644 --- a/packages/core/platform/bundles/system/cozyrds/bootbox.yaml +++ b/packages/core/platform/bundles/system/cozyrds/bootbox.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: bootbox spec: + source: + bundleName: cozystack-system + path: packages/extra/bootbox + libraries: [cozy-lib] + application: kind: BootBox plural: bootboxes diff --git a/packages/core/platform/bundles/system/cozyrds/etcd.yaml b/packages/core/platform/bundles/system/cozyrds/etcd.yaml index 2305c92b..0a79be43 100644 --- a/packages/core/platform/bundles/system/cozyrds/etcd.yaml +++ b/packages/core/platform/bundles/system/cozyrds/etcd.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: etcd spec: + source: + bundleName: cozystack-system + path: packages/extra/etcd + libraries: [cozy-lib] + application: kind: Etcd plural: etcds diff --git a/packages/core/platform/bundles/system/cozyrds/info.yaml b/packages/core/platform/bundles/system/cozyrds/info.yaml index 1eece36b..00904992 100644 --- a/packages/core/platform/bundles/system/cozyrds/info.yaml +++ b/packages/core/platform/bundles/system/cozyrds/info.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: info spec: + source: + bundleName: cozystack-system + path: packages/extra/info + libraries: [cozy-lib] + application: kind: Info plural: infos diff --git a/packages/core/platform/bundles/system/cozyrds/ingress.yaml b/packages/core/platform/bundles/system/cozyrds/ingress.yaml index ceb7dc62..1f1e36a6 100644 --- a/packages/core/platform/bundles/system/cozyrds/ingress.yaml +++ b/packages/core/platform/bundles/system/cozyrds/ingress.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: ingress spec: + source: + bundleName: cozystack-system + path: packages/extra/ingress + libraries: [cozy-lib] + application: kind: Ingress plural: ingresses diff --git a/packages/core/platform/bundles/system/cozyrds/monitoring.yaml b/packages/core/platform/bundles/system/cozyrds/monitoring.yaml index c1aec607..b9b5ec25 100644 --- a/packages/core/platform/bundles/system/cozyrds/monitoring.yaml +++ b/packages/core/platform/bundles/system/cozyrds/monitoring.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: monitoring spec: + source: + bundleName: cozystack-system + path: packages/extra/monitoring + libraries: [cozy-lib] + application: kind: Monitoring singular: monitoring diff --git a/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml b/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml index b39260f9..f0cf5d0a 100644 --- a/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml +++ b/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: seaweedfs spec: + source: + bundleName: cozystack-system + path: packages/extra/seaweedfs + libraries: [cozy-lib] + application: kind: SeaweedFS singular: seaweedfs diff --git a/packages/core/platform/bundles/system/cozyrds/tenant.yaml b/packages/core/platform/bundles/system/cozyrds/tenant.yaml index 53336d56..aeaafcd0 100644 --- a/packages/core/platform/bundles/system/cozyrds/tenant.yaml +++ b/packages/core/platform/bundles/system/cozyrds/tenant.yaml @@ -3,6 +3,11 @@ kind: CozystackResourceDefinition metadata: name: tenant spec: + source: + bundleName: cozystack-system + path: packages/apps/tenant + libraries: [cozy-lib] + application: kind: Tenant singular: tenant diff --git a/packages/core/platform/bundles/system/system-full.yaml b/packages/core/platform/bundles/system/system-full.yaml deleted file mode 100644 index f66437d5..00000000 --- a/packages/core/platform/bundles/system/system-full.yaml +++ /dev/null @@ -1,331 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} -{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- if not $host }} -{{- fail "ERROR need root-host in cozystack ConfigMap" }} -{{- end }} -{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} -{{- if not $apiServerEndpoint }} -{{- fail "ERROR need api-server-endpoint in cozystack ConfigMap" }} -{{- end }} - -releases: -- name: fluxcd-operator - releaseName: fluxcd-operator - chart: fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - -- name: fluxcd - releaseName: fluxcd - chart: fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator,cilium,kubeovn] - values: - flux-instance: - instance: - cluster: - domain: {{ $clusterDomain }} - -- name: cilium - releaseName: cilium - chart: cilium - namespace: cozy-cilium - privileged: true - dependsOn: [] - valuesFiles: - - values.yaml - - values-talos.yaml - - values-kubeovn.yaml - -- name: cilium-networkpolicy - releaseName: cilium-networkpolicy - chart: cilium-networkpolicy - namespace: cozy-cilium - privileged: true - dependsOn: [cilium] - -- name: kubeovn - releaseName: kubeovn - chart: kubeovn - namespace: cozy-kubeovn - privileged: true - dependsOn: [cilium] - values: - cozystack: - nodesHash: {{ include "cozystack.master-node-ips" . | sha256sum }} - kube-ovn: - ipv4: - POD_CIDR: "{{ index $cozyConfig.data "ipv4-pod-cidr" }}" - POD_GATEWAY: "{{ index $cozyConfig.data "ipv4-pod-gateway" }}" - SVC_CIDR: "{{ index $cozyConfig.data "ipv4-svc-cidr" }}" - JOIN_CIDR: "{{ index $cozyConfig.data "ipv4-join-cidr" }}" - -- name: kubeovn-webhook - releaseName: kubeovn-webhook - chart: kubeovn-webhook - namespace: cozy-kubeovn - privileged: true - dependsOn: [cilium,kubeovn,cert-manager] - -- name: kubeovn-plunger - releaseName: kubeovn-plunger - chart: kubeovn-plunger - namespace: cozy-kubeovn - dependsOn: [cilium,kubeovn] - -- name: multus - releaseName: multus - chart: multus - namespace: cozy-multus - privileged: true - dependsOn: [cilium,kubeovn] - -- name: cozy-proxy - releaseName: cozystack - chart: cozy-proxy - namespace: cozy-system - dependsOn: [cilium,kubeovn] - -- name: cert-manager-crds - releaseName: cert-manager-crds - chart: cert-manager-crds - namespace: cozy-cert-manager - dependsOn: [cilium, kubeovn] - -- name: cozystack-api - releaseName: cozystack-api - chart: cozystack-api - namespace: cozy-system - dependsOn: [cilium,kubeovn,cozystack-controller] - -- name: cozystack-controller - releaseName: cozystack-controller - chart: cozystack-controller - namespace: cozy-system - dependsOn: [cilium,kubeovn] - {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} - values: - cozystackController: - disableTelemetry: true - {{- end }} - -- name: lineage-controller-webhook - releaseName: lineage-controller-webhook - chart: lineage-controller-webhook - namespace: cozy-system - dependsOn: [cozystack-controller,cilium,kubeovn,cert-manager] - -- name: cozystack-resource-definition-crd - releaseName: cozystack-resource-definition-crd - chart: cozystack-resource-definition-crd - namespace: cozy-system - dependsOn: [cilium,kubeovn,cozystack-api,cozystack-controller] - -- name: cozystack-resource-definitions - releaseName: cozystack-resource-definitions - chart: cozystack-resource-definitions - namespace: cozy-system - dependsOn: [cilium,kubeovn,cozystack-api,cozystack-controller,cozystack-resource-definition-crd] - -- name: cert-manager - releaseName: cert-manager - chart: cert-manager - namespace: cozy-cert-manager - dependsOn: [cert-manager-crds] - -- name: cert-manager-issuers - releaseName: cert-manager-issuers - chart: cert-manager-issuers - namespace: cozy-cert-manager - dependsOn: [cilium,kubeovn,cert-manager] - -- name: victoria-metrics-operator - releaseName: victoria-metrics-operator - chart: victoria-metrics-operator - namespace: cozy-victoria-metrics-operator - dependsOn: [cilium,kubeovn,cert-manager] - -- name: monitoring-agents - releaseName: monitoring-agents - chart: monitoring-agents - namespace: cozy-monitoring - privileged: true - dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] - values: - scrapeRules: - etcd: - enabled: true - -- name: metallb - releaseName: metallb - chart: metallb - namespace: cozy-metallb - privileged: true - dependsOn: [cilium,kubeovn] - -- name: etcd-operator - releaseName: etcd-operator - chart: etcd-operator - namespace: cozy-etcd-operator - dependsOn: [cilium,kubeovn,cert-manager] - -- name: grafana-operator - releaseName: grafana-operator - chart: grafana-operator - namespace: cozy-grafana-operator - dependsOn: [cilium,kubeovn] - -- name: postgres-operator - releaseName: postgres-operator - chart: postgres-operator - namespace: cozy-postgres-operator - dependsOn: [cilium,kubeovn,cert-manager] - -- name: piraeus-operator - releaseName: piraeus-operator - chart: piraeus-operator - namespace: cozy-linstor - dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] - -- name: linstor - releaseName: linstor - chart: linstor - namespace: cozy-linstor - privileged: true - dependsOn: [piraeus-operator,cilium,kubeovn,cert-manager,snapshot-controller] - -- name: nfs-driver - releaseName: nfs-driver - chart: nfs-driver - namespace: cozy-nfs-driver - privileged: true - dependsOn: [cilium,kubeovn] - optional: true - -- name: snapshot-controller - releaseName: snapshot-controller - chart: snapshot-controller - namespace: cozy-snapshot-controller - dependsOn: [cilium,kubeovn,cert-manager-issuers] - -- name: objectstorage-controller - releaseName: objectstorage-controller - chart: objectstorage-controller - namespace: cozy-objectstorage-controller - dependsOn: [cilium,kubeovn] - -- name: telepresence - releaseName: traffic-manager - chart: telepresence - namespace: cozy-telepresence - optional: true - dependsOn: [cilium,kubeovn] - -- name: dashboard - releaseName: dashboard - chart: dashboard - namespace: cozy-dashboard - values: - {{- $dashboardKCconfig := lookup "v1" "ConfigMap" "cozy-dashboard" "kubeapps-auth-config" }} - {{- $dashboardKCValues := dig "data" "values.yaml" "" $dashboardKCconfig | fromYaml }} - {{- toYaml $dashboardKCValues | nindent 4 }} - dependsOn: - - cilium - - kubeovn - {{- if eq $oidcEnabled "true" }} - - keycloak-configure - {{- end }} - -- name: external-dns - releaseName: external-dns - chart: external-dns - namespace: cozy-external-dns - optional: true - dependsOn: [cilium,kubeovn] - -- name: external-secrets-operator - releaseName: external-secrets-operator - chart: external-secrets-operator - namespace: cozy-external-secrets-operator - optional: true - dependsOn: [cilium,kubeovn] - -- name: bootbox - releaseName: bootbox - chart: bootbox - namespace: cozy-bootbox - privileged: true - optional: true - dependsOn: [cilium,kubeovn] - -{{- if $oidcEnabled }} -- name: keycloak - releaseName: keycloak - chart: keycloak - namespace: cozy-keycloak - dependsOn: [postgres-operator] - -- name: keycloak-operator - releaseName: keycloak-operator - chart: keycloak-operator - namespace: cozy-keycloak - dependsOn: [keycloak] - -- name: keycloak-configure - releaseName: keycloak-configure - chart: keycloak-configure - namespace: cozy-keycloak - dependsOn: [keycloak-operator] - values: - cozystack: - configHash: {{ $cozyConfig | toJson | sha256sum }} -{{- end }} - -- name: goldpinger - releaseName: goldpinger - chart: goldpinger - namespace: cozy-goldpinger - privileged: true - dependsOn: [monitoring-agents] - -- name: vertical-pod-autoscaler - releaseName: vertical-pod-autoscaler - chart: vertical-pod-autoscaler - namespace: cozy-vertical-pod-autoscaler - privileged: true - dependsOn: [monitoring-agents] - values: - vertical-pod-autoscaler: - recommender: - extraArgs: - prometheus-address: http://vmselect-shortterm.tenant-root.svc.{{ $clusterDomain }}:8481/select/0/prometheus/ - -- name: vertical-pod-autoscaler-crds - releaseName: vertical-pod-autoscaler-crds - chart: vertical-pod-autoscaler-crds - namespace: cozy-vertical-pod-autoscaler - privileged: true - dependsOn: [cilium, kubeovn] - -- name: reloader - releaseName: reloader - chart: reloader - namespace: cozy-reloader - -- name: velero - releaseName: velero - chart: velero - namespace: cozy-velero - privileged: true - optional: true - dependsOn: [monitoring-agents] - -- name: hetzner-robotlb - releaseName: robotlb - optional: true - chart: hetzner-robotlb - namespace: cozy-hetzner-robotlb - dependsOn: [cilium, kubeovn] diff --git a/packages/core/platform/bundles/system/system-hosted.yaml b/packages/core/platform/bundles/system/system-hosted.yaml deleted file mode 100644 index 1a06b6ee..00000000 --- a/packages/core/platform/bundles/system/system-hosted.yaml +++ /dev/null @@ -1,235 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} -{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- if not $host }} -{{- fail "ERROR need root-host in cozystack ConfigMap" }} -{{- end }} -{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} -{{- if not $apiServerEndpoint }} -{{- fail "ERROR need api-server-endpoint in cozystack ConfigMap" }} -{{- end }} - -releases: -- name: fluxcd-operator - releaseName: fluxcd-operator - chart: fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - -- name: fluxcd - releaseName: fluxcd - chart: fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator] - values: - flux-instance: - instance: - cluster: - domain: {{ $clusterDomain }} - -- name: cert-manager-crds - releaseName: cert-manager-crds - chart: cert-manager-crds - namespace: cozy-cert-manager - dependsOn: [] - -- name: cozystack-api - releaseName: cozystack-api - chart: cozystack-api - namespace: cozy-system - dependsOn: [cozystack-controller] - values: - cozystackAPI: - localK8sAPIEndpoint: - enabled: false - -- name: cozystack-controller - releaseName: cozystack-controller - chart: cozystack-controller - namespace: cozy-system - dependsOn: [] - {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} - values: - cozystackController: - disableTelemetry: true - {{- end }} - -- name: lineage-controller-webhook - releaseName: lineage-controller-webhook - chart: lineage-controller-webhook - namespace: cozy-system - dependsOn: [cozystack-controller,cert-manager] - -- name: cozystack-resource-definition-crd - releaseName: cozystack-resource-definition-crd - chart: cozystack-resource-definition-crd - namespace: cozy-system - dependsOn: [cozystack-api,cozystack-controller] - -- name: cozystack-resource-definitions - releaseName: cozystack-resource-definitions - chart: cozystack-resource-definitions - namespace: cozy-system - dependsOn: [cozystack-api,cozystack-controller,cozystack-resource-definition-crd] - -- name: cert-manager - releaseName: cert-manager - chart: cert-manager - namespace: cozy-cert-manager - dependsOn: [cert-manager-crds] - -- name: cert-manager-issuers - releaseName: cert-manager-issuers - chart: cert-manager-issuers - namespace: cozy-cert-manager - dependsOn: [cert-manager] - -- name: victoria-metrics-operator - releaseName: victoria-metrics-operator - chart: victoria-metrics-operator - namespace: cozy-victoria-metrics-operator - dependsOn: [cert-manager] - -- name: monitoring-agents - releaseName: monitoring-agents - chart: monitoring-agents - namespace: cozy-monitoring - privileged: true - dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] - values: - scrapeRules: - etcd: - enabled: true - -- name: etcd-operator - releaseName: etcd-operator - chart: etcd-operator - namespace: cozy-etcd-operator - dependsOn: [cert-manager] - -- name: grafana-operator - releaseName: grafana-operator - chart: grafana-operator - namespace: cozy-grafana-operator - dependsOn: [] - -- name: mariadb-operator - releaseName: mariadb-operator - chart: mariadb-operator - namespace: cozy-mariadb-operator - dependsOn: [cert-manager,victoria-metrics-operator] - values: - mariadb-operator: - clusterName: {{ $clusterDomain }} - -- name: postgres-operator - releaseName: postgres-operator - chart: postgres-operator - namespace: cozy-postgres-operator - dependsOn: [cert-manager,victoria-metrics-operator] - -- name: objectstorage-controller - releaseName: objectstorage-controller - chart: objectstorage-controller - namespace: cozy-objectstorage-controller - dependsOn: [] - -- name: telepresence - releaseName: traffic-manager - chart: telepresence - namespace: cozy-telepresence - optional: true - dependsOn: [] - -- name: external-dns - releaseName: external-dns - chart: external-dns - namespace: cozy-external-dns - optional: true - dependsOn: [] - -- name: external-secrets-operator - releaseName: external-secrets-operator - chart: external-secrets-operator - namespace: cozy-external-secrets-operator - optional: true - dependsOn: [] - -- name: dashboard - releaseName: dashboard - chart: dashboard - namespace: cozy-dashboard - values: - {{- $dashboardKCconfig := lookup "v1" "ConfigMap" "cozy-dashboard" "kubeapps-auth-config" }} - {{- $dashboardKCValues := dig "data" "values.yaml" "" $dashboardKCconfig | fromYaml }} - {{- toYaml $dashboardKCValues | nindent 4 }} - {{- if eq $oidcEnabled "true" }} - dependsOn: [keycloak-configure,cozystack-api] - {{- else }} - dependsOn: [] - {{- end }} - -{{- if $oidcEnabled }} -- name: keycloak - releaseName: keycloak - chart: keycloak - namespace: cozy-keycloak - dependsOn: [postgres-operator] - -- name: keycloak-operator - releaseName: keycloak-operator - chart: keycloak-operator - namespace: cozy-keycloak - dependsOn: [keycloak] - -- name: keycloak-configure - releaseName: keycloak-configure - chart: keycloak-configure - namespace: cozy-keycloak - dependsOn: [keycloak-operator] - values: - cozystack: - configHash: {{ $cozyConfig | toJson | sha256sum }} -{{- end }} - -- name: goldpinger - releaseName: goldpinger - chart: goldpinger - namespace: cozy-goldpinger - privileged: true - dependsOn: [monitoring-agents] - -- name: vertical-pod-autoscaler - releaseName: vertical-pod-autoscaler - chart: vertical-pod-autoscaler - namespace: cozy-vertical-pod-autoscaler - privileged: true - dependsOn: [monitoring-agents] - values: - vertical-pod-autoscaler: - recommender: - extraArgs: - prometheus-address: http://vmselect-shortterm.tenant-root.svc.{{ $clusterDomain }}:8481/select/0/prometheus/ - -- name: vertical-pod-autoscaler-crds - releaseName: vertical-pod-autoscaler-crds - chart: vertical-pod-autoscaler-crds - namespace: cozy-vertical-pod-autoscaler - privileged: true - dependsOn: [] - -- name: velero - releaseName: velero - chart: velero - namespace: cozy-velero - privileged: true - optional: true - dependsOn: [monitoring-agents] - -- name: hetzner-robotlb - releaseName: robotlb - optional: true - chart: hetzner-robotlb - namespace: cozy-hetzner-robotlb diff --git a/packages/core/platform/templates/_helpers.tpl b/packages/core/platform/templates/_helpers.tpl index b3ab6a86..eea49ccc 100644 --- a/packages/core/platform/templates/_helpers.tpl +++ b/packages/core/platform/templates/_helpers.tpl @@ -16,3 +16,27 @@ Get IP-addresses of master nodes {{- end -}} {{ join "," $ips }} {{- end -}} + +{{/* +Render a template file with tpl and trim +Usage: {{ include "cozystack.render-file" (list . "bundles/system/bundle-full.yaml") }} +*/}} +{{- define "cozystack.render-file" -}} +{{- $ := index . 0 }} +{{- $filePath := index . 1 }} +--- +{{ trim (tpl ($.Files.Get $filePath) $) }} +{{- end -}} + +{{/* +Render all files matching a glob pattern +Usage: {{ include "cozystack.render-glob" (list . "bundles/system/cozyrds/*.yaml") }} +*/}} +{{- define "cozystack.render-glob" -}} +{{- $ := index . 0 }} +{{- $pattern := index . 1 }} +{{- range $path, $_ := $.Files.Glob $pattern }} +--- +{{ $.Files.Get $path }} +{{- end }} +{{- end -}} diff --git a/packages/core/platform/templates/bundles-configmap.yaml b/packages/core/platform/templates/bundles-configmap.yaml index 7ac0285b..431cac41 100644 --- a/packages/core/platform/templates/bundles-configmap.yaml +++ b/packages/core/platform/templates/bundles-configmap.yaml @@ -1,17 +1,43 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: system-bundle - namespace: cozy-system - labels: - cozystack.io/system: "true" -data: - paas-full.yaml: | - {{- trim (tpl (.Files.Get "bundles/paas-full.yaml") .) | nindent 4 }} - paas-hosted.yaml: | - {{- trim (tpl (.Files.Get "bundles/paas-hosted.yaml") .) | nindent 4 }} - distro-full.yaml: | - {{- trim (tpl (.Files.Get "bundles/distro-full.yaml") .) | nindent 4 }} - distro-hosted.yaml: | - {{- trim (tpl (.Files.Get "bundles/distro-hosted.yaml") .) | nindent 4 }} +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- if not $cozyConfig }} + {{- fail "ERROR: cozystack ConfigMap not found in cozy-system namespace" }} +{{- end }} +{{- $bundleName := index $cozyConfig.data "bundle-name" }} +{{- if not $bundleName }} + {{- fail "ERROR: bundle-name not found in cozystack ConfigMap" }} +{{- end }} + +{{- if eq $bundleName "paas-full" }} + {{- /* Deploy system-full, iaas, paas, naas bundles */ -}} + {{ include "cozystack.render-file" (list . "bundles/system/bundle-full.yaml") }} + {{ include "cozystack.render-file" (list . "bundles/iaas/bundle.yaml") }} + {{ include "cozystack.render-file" (list . "bundles/paas/bundle.yaml") }} + {{ include "cozystack.render-file" (list . "bundles/naas/bundle.yaml") }} + + {{- /* Deploy all cozyrds */ -}} + {{ include "cozystack.render-glob" (list . "bundles/system/cozyrds/*.yaml") }} + {{ include "cozystack.render-glob" (list . "bundles/iaas/cozyrds/*.yaml") }} + {{ include "cozystack.render-glob" (list . "bundles/paas/cozyrds/*.yaml") }} + {{ include "cozystack.render-glob" (list . "bundles/naas/cozyrds/*.yaml") }} + +{{- else if eq $bundleName "paas-hosted" }} + {{- /* Deploy system-hosted, paas, naas bundles */ -}} + {{ include "cozystack.render-file" (list . "bundles/system/bundle-hosted.yaml") }} + {{ include "cozystack.render-file" (list . "bundles/paas/bundle.yaml") }} + {{ include "cozystack.render-file" (list . "bundles/naas/bundle.yaml") }} + + {{- /* Deploy cozyrds from system, paas, naas (not iaas) */ -}} + {{ include "cozystack.render-glob" (list . "bundles/system/cozyrds/*.yaml") }} + {{ include "cozystack.render-glob" (list . "bundles/paas/cozyrds/*.yaml") }} + {{ include "cozystack.render-glob" (list . "bundles/naas/cozyrds/*.yaml") }} + +{{- else if eq $bundleName "distro-full" }} + {{- fail "ERROR: bundle-name 'distro-full' is deprecated and has been removed. Please use 'paas-full' instead." }} + +{{- else if eq $bundleName "distro-hosted" }} + {{- fail "ERROR: bundle-name 'distro-hosted' is deprecated and has been removed. Please use 'paas-hosted' instead." }} + +{{- else }} + {{- fail (printf "ERROR: unknown bundle-name '%s'. Supported values: 'paas-full', 'paas-hosted'" $bundleName) }} +{{- end }} diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml new file mode 100644 index 00000000..448b5bf0 --- /dev/null +++ b/packages/core/platform/values.yaml @@ -0,0 +1,4 @@ +sourceRef: + kind: GitRepository + name: cozystack + namespace: cozy-system diff --git a/packages/system/cozystack-resource-definition-crd/Makefile b/packages/system/cozystack-resource-definition-crd/Makefile index ddb24aef..2b994a55 100644 --- a/packages/system/cozystack-resource-definition-crd/Makefile +++ b/packages/system/cozystack-resource-definition-crd/Makefile @@ -1,4 +1,7 @@ export NAME=cozystack-resource-definition-crd export NAMESPACE=cozy-system +apply-locally: + cozypkg apply --plain -n $(NAMESPACE) $(NAME) + include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackbundles.yaml b/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackbundles.yaml new file mode 100644 index 00000000..630bcd48 --- /dev/null +++ b/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackbundles.yaml @@ -0,0 +1,174 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: cozystackbundles.cozystack.io +spec: + group: cozystack.io + names: + kind: CozystackBundle + listKind: CozystackBundleList + plural: cozystackbundles + singular: cozystackbundle + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: CozystackBundle is the Schema for the cozystackbundles API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: CozystackBundleSpec defines the desired state of CozystackBundle + properties: + dependencyTargets: + description: |- + 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. + items: + description: |- + BundleDependencyTarget defines a named group of packages that can be referenced + by other bundles via dependsOn + properties: + name: + description: Name is the unique identifier for this dependency + target + type: string + packages: + description: |- + Packages is a list of package names that belong to this target + These packages will be added as dependencies when this target is referenced + items: + type: string + type: array + required: + - name + - packages + type: object + type: array + dependsOn: + description: |- + 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 + items: + type: string + type: array + libraries: + description: Libraries is a list of Helm library charts used by packages + items: + description: BundleLibrary defines a Helm library chart + properties: + name: + description: Name is the unique identifier for this library + type: string + path: + description: Path is the path to the library chart directory + type: string + required: + - name + - path + type: object + type: array + packages: + description: Packages is a list of Helm releases to be installed as + part of this bundle + items: + description: BundleRelease defines a single Helm release within + a bundle + properties: + dependsOn: + description: DependsOn is a list of release names that must + be installed before this release + items: + type: string + type: array + disabled: + description: Disabled indicates whether this release is disabled + (should not be installed) + type: boolean + libraries: + description: Libraries is a list of library names that this + package depends on + items: + type: string + type: array + name: + description: Name is the unique identifier for this release + within the bundle + type: string + namespace: + description: Namespace is the Kubernetes namespace where the + release will be installed + type: string + path: + description: Path is the path to the Helm chart directory + type: string + privileged: + description: Privileged indicates whether this release requires + privileged access + type: boolean + releaseName: + description: ReleaseName is the name of the HelmRelease resource + that will be created + type: string + values: + description: Values contains Helm chart values as a JSON object + x-kubernetes-preserve-unknown-fields: true + valuesFiles: + description: ValuesFiles is a list of values file names to use + items: + type: string + type: array + required: + - name + - namespace + - path + - releaseName + type: object + type: array + sourceRef: + description: SourceRef is the source reference for the bundle charts + properties: + kind: + description: Kind of the source reference + enum: + - GitRepository + type: string + name: + description: Name of the source reference + type: string + namespace: + description: Namespace of the source reference + type: string + required: + - kind + - name + - namespace + type: object + required: + - packages + - sourceRef + type: object + type: object + served: true + storage: true diff --git a/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml b/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml index 91cfb7ec..f55cdafc 100644 --- a/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml +++ b/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml @@ -700,6 +700,27 @@ spec: x-kubernetes-map-type: atomic type: array type: object + source: + description: Source configuration for the bundle chart + properties: + bundleName: + description: BundleName is the name of the bundle that contains + this chart + type: string + libraries: + description: Libraries is a list of library chart names used by + this chart + items: + type: string + type: array + path: + description: Path is the path to the directory containing the + Helm chart + type: string + required: + - bundleName + - path + type: object required: - application - release diff --git a/packages/system/cozystack-resource-definition-crd/templates/crd.yaml b/packages/system/cozystack-resource-definition-crd/templates/crd.yaml index 40a93ad3..770a239e 100644 --- a/packages/system/cozystack-resource-definition-crd/templates/crd.yaml +++ b/packages/system/cozystack-resource-definition-crd/templates/crd.yaml @@ -1,2 +1,4 @@ --- {{ .Files.Get "definition/cozystack.io_cozystackresourcedefinitions.yaml" }} +--- +{{ .Files.Get "definition/cozystack.io_cozystackbundles.yaml" }} diff --git a/packages/system/cozystack-resource-definitions/Chart.yaml b/packages/system/cozystack-resource-definitions/Chart.yaml deleted file mode 100644 index 39cb9431..00000000 --- a/packages/system/cozystack-resource-definitions/Chart.yaml +++ /dev/null @@ -1,3 +0,0 @@ -apiVersion: v2 -name: cozystack-resource-definitions -version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/cozystack-resource-definitions/Makefile b/packages/system/cozystack-resource-definitions/Makefile deleted file mode 100644 index 00e8bece..00000000 --- a/packages/system/cozystack-resource-definitions/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -export NAME=cozystack-resource-definitions -export NAMESPACE=cozy-system - -include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/templates/cozyrds.yaml b/packages/system/cozystack-resource-definitions/templates/cozyrds.yaml deleted file mode 100644 index e079ddcf..00000000 --- a/packages/system/cozystack-resource-definitions/templates/cozyrds.yaml +++ /dev/null @@ -1,4 +0,0 @@ -{{- range $path, $_ := .Files.Glob "cozyrds/*" }} ---- -{{ $.Files.Get $path }} -{{- end }} diff --git a/packages/system/cozystack-resource-definitions/values.yaml b/packages/system/cozystack-resource-definitions/values.yaml deleted file mode 100644 index 0967ef42..00000000 --- a/packages/system/cozystack-resource-definitions/values.yaml +++ /dev/null @@ -1 +0,0 @@ -{} From f98b429ad2d485d0bd8cb961084911da6b508887 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 20 Nov 2025 02:27:39 +0100 Subject: [PATCH 15/46] Implement business logic Signed-off-by: Andrei Kvapil --- cmd/cozystack-operator/main.go | 186 ++++- internal/operator/bundle_reconciler.go | 553 +++++++++++++ internal/operator/reconciler.go | 771 +----------------- .../operator/resourcedefinition_reconciler.go | 242 ++++++ packages/core/installer/values.yaml | 2 +- .../platform/bundles/system/bundle-full.yaml | 6 - .../bundles/system/bundle-hosted.yaml | 6 - 7 files changed, 997 insertions(+), 769 deletions(-) create mode 100644 internal/operator/bundle_reconciler.go create mode 100644 internal/operator/resourcedefinition_reconciler.go diff --git a/cmd/cozystack-operator/main.go b/cmd/cozystack-operator/main.go index a4df4e6f..ac328fba 100644 --- a/cmd/cozystack-operator/main.go +++ b/cmd/cozystack-operator/main.go @@ -31,6 +31,7 @@ import ( // 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" @@ -38,11 +39,14 @@ import ( corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/dynamic" clientgoscheme "k8s.io/client-go/kubernetes/scheme" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -63,6 +67,7 @@ var ( 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)) @@ -157,6 +162,24 @@ func main() { os.Exit(1) } + bundleReconciler := &operator.CozystackBundleReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + } + if err = bundleReconciler.SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "CozystackBundle") + os.Exit(1) + } + + resourceDefinitionReconciler := &operator.CozystackResourceDefinitionReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + } + if err = resourceDefinitionReconciler.SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "CozystackResourceDefinition") + os.Exit(1) + } + // +kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { @@ -444,8 +467,22 @@ func runMigrations(ctx context.Context, c client.Client, targetVersion int) erro err := c.Get(ctx, key, cm) if err != nil { if apierrors.IsNotFound(err) { - setupLog.Info("cozystack-version configmap does not exist, creating with version 0") - currentVersion = 0 + // First run: create ConfigMap with current version, skip migrations + setupLog.Info("cozystack-version configmap does not exist, creating with current version", "version", targetVersion) + newCM := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cozystack-version", + Namespace: "cozy-system", + }, + Data: map[string]string{ + "version": strconv.Itoa(targetVersion), + }, + } + if err := c.Create(ctx, newCM); err != nil { + return fmt.Errorf("failed to create version configmap: %w", err) + } + setupLog.Info("Created cozystack-version configmap with current version, skipping migrations") + return nil } else { return err } @@ -591,31 +628,85 @@ func ensureFluxCD(ctx context.Context, c client.Client) error { if err := cmd.Run(); err != nil { return fmt.Errorf("failed to install fluxcd-operator: %w", err) } + } else if meta.IsNoMatchError(err) { + // CRD for HelmRelease doesn't exist yet, need to install fluxcd-operator first + setupLog.Info("HelmRelease CRD not found, installing fluxcd-operator to create CRDs") + cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd-operator", "apply-locally") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to install fluxcd-operator: %w", err) + } } else { return fmt.Errorf("failed to check fluxcd-operator: %w", err) } - // Wait for CRD + // Wait for FluxInstance CRD (created by fluxcd-operator) if err := waitForCRDs(ctx, c, "fluxinstances.fluxcd.controlplane.io"); err != nil { return err } - // Install fluxcd - hr = &helmv2.HelmRelease{} - key = types.NamespacedName{Namespace: "cozy-fluxcd", Name: "fluxcd"} - err = c.Get(ctx, key, hr) + // Install fluxcd (flux-instance) via FluxInstance resource + // flux-instance is installed via FluxInstance, not HelmRelease + // We need to use unstructured client to check FluxInstance since it's not in our scheme yet + config := ctrl.GetConfigOrDie() + dyn, err := dynamic.NewForConfig(config) + if err != nil { + return fmt.Errorf("failed to create dynamic client: %w", err) + } + + fluxInstanceGVR := schema.GroupVersionResource{ + Group: "fluxcd.controlplane.io", + Version: "v1", + Resource: "fluxinstances", + } + + _, err = dyn.Resource(fluxInstanceGVR).Namespace("cozy-fluxcd").Get(ctx, "flux", metav1.GetOptions{}) if err == nil { - // HelmRelease exists, apply and resume it - setupLog.Info("Applying and resuming fluxcd helmrelease") - cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd", "apply", "resume") + // FluxInstance exists, check if HelmRelease exists before applying + // HelmRelease CRD might not exist yet, so we need to check carefully + helmReleaseGVR := schema.GroupVersionResource{ + Group: "helm.toolkit.fluxcd.io", + Version: "v2", + Resource: "helmreleases", + } + + // Try to get HelmRelease - if CRD doesn't exist, this will return IsNoMatchError + _, hrErr := dyn.Resource(helmReleaseGVR).Namespace("cozy-fluxcd").Get(ctx, "fluxcd", metav1.GetOptions{}) + if hrErr == nil { + // HelmRelease exists, apply and resume it via make + setupLog.Info("FluxInstance and HelmRelease exist, applying and resuming fluxcd") + cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd", "apply", "resume") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to apply and resume fluxcd: %w", err) + } + } else if apierrors.IsNotFound(hrErr) || meta.IsNoMatchError(hrErr) { + // HelmRelease doesn't exist or CRD not available, use apply-locally + setupLog.Info("FluxInstance exists but HelmRelease not found, creating fluxcd using apply-locally") + cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd", "apply-locally") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to install fluxcd: %w", err) + } + } else { + return fmt.Errorf("failed to check fluxcd HelmRelease: %w", hrErr) + } + } else if apierrors.IsNotFound(err) { + // FluxInstance doesn't exist, need to create it + setupLog.Info("Creating fluxcd (flux-instance) using make") + cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd", "apply-locally") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to apply and resume fluxcd: %w", err) + return fmt.Errorf("failed to install fluxcd: %w", err) } - } else if apierrors.IsNotFound(err) { - // HelmRelease doesn't exist, need to create it - setupLog.Info("Creating fluxcd using make (TODO: use helm-controller API)") + } else if meta.IsNoMatchError(err) { + // CRD for FluxInstance doesn't exist yet, but we already waited for it above + // This shouldn't happen, but if it does, try to install anyway + setupLog.Info("FluxInstance CRD not found (unexpected), trying to install fluxcd anyway") cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd", "apply-locally") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -623,7 +714,14 @@ func ensureFluxCD(ctx context.Context, c client.Client) error { return fmt.Errorf("failed to install fluxcd: %w", err) } } else { - return fmt.Errorf("failed to check fluxcd: %w", err) + return fmt.Errorf("failed to check fluxcd FluxInstance: %w", err) + } + + // Wait for HelmRelease CRD to be created by flux-instance + // flux-instance installs Flux which creates HelmRelease CRD + setupLog.Info("Waiting for HelmRelease CRD to be created by flux-instance") + if err := waitForCRDs(ctx, c, "helmreleases.helm.toolkit.fluxcd.io"); err != nil { + return fmt.Errorf("failed to wait for HelmRelease CRD: %w", err) } // Wait for CRDs @@ -739,28 +837,74 @@ func resumeHelmRelease(ctx context.Context, c client.Client, hr *helmv2.HelmRele } func installBasicCharts(ctx context.Context, c client.Client, bundle string) error { - if bundle == "paas-full" || bundle == "distro-full" { - // Install cilium + // Check if cilium and kubeovn are present in CozystackBundle resources + hasCilium := false + hasKubeovn := false + + // List all CozystackBundle resources + bundleList := &cozyv1alpha1.CozystackBundleList{} + if err := c.List(ctx, bundleList); err != nil { + setupLog.Info("Failed to list CozystackBundles, skipping component checks", "error", err) + // If bundle loading fails, fall back to old behavior for backward compatibility + if bundle == "paas-full" || bundle == "distro-full" { + setupLog.Info("Installing cilium using make (fallback mode)") + cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/cilium", "apply", "resume") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to install cilium: %w", err) + } + } + if bundle == "paas-full" { + setupLog.Info("Installing kubeovn using make (fallback mode)") + cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/kubeovn", "apply", "resume") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to install kubeovn: %w", err) + } + } + return nil + } + + // Check all bundles for cilium and kubeovn packages + for _, bundleResource := range bundleList.Items { + for _, pkg := range bundleResource.Spec.Packages { + if pkg.Name == "cilium" && !pkg.Disabled { + hasCilium = true + } + if pkg.Name == "kubeovn" && !pkg.Disabled { + hasKubeovn = true + } + } + } + + // Install cilium only if present in bundle + if hasCilium { // TODO: Create HelmRelease for cilium using helm-controller API - setupLog.Info("Installing cilium using make (TODO: use helm-controller API)") + setupLog.Info("Installing cilium using make (found in bundle)") cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/cilium", "apply", "resume") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { return fmt.Errorf("failed to install cilium: %w", err) } + } else { + setupLog.Info("Skipping cilium installation (not found in bundle)") } - if bundle == "paas-full" { - // Install kubeovn + // Install kubeovn only if present in bundle + if hasKubeovn { // TODO: Create HelmRelease for kubeovn using helm-controller API - setupLog.Info("Installing kubeovn using make (TODO: use helm-controller API)") + setupLog.Info("Installing kubeovn using make (found in bundle)") cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/kubeovn", "apply", "resume") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { return fmt.Errorf("failed to install kubeovn: %w", err) } + } else { + setupLog.Info("Skipping kubeovn installation (not found in bundle)") } return nil diff --git a/internal/operator/bundle_reconciler.go b/internal/operator/bundle_reconciler.go new file mode 100644 index 00000000..c0062fa2 --- /dev/null +++ b/internal/operator/bundle_reconciler.go @@ -0,0 +1,553 @@ +/* +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" + "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" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/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/log" +) + +// CozystackBundleReconciler reconciles CozystackBundle resources +type CozystackBundleReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackbundles,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackbundles/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 *CozystackBundleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + + bundle := &cozyv1alpha1.CozystackBundle{} + if err := r.Get(ctx, req.NamespacedName, bundle); err != nil { + if apierrors.IsNotFound(err) { + // Cleanup orphaned resources + return r.cleanupOrphanedResources(ctx, req.NamespacedName) + } + return ctrl.Result{}, err + } + + // Resolve dependencies from other bundles + resolvedPackages, err := r.resolveDependencies(ctx, bundle) + if err != nil { + logger.Error(err, "failed to resolve dependencies") + return ctrl.Result{}, err + } + + // Generate ArtifactGenerators for packages + if err := r.reconcileArtifactGenerators(ctx, bundle, resolvedPackages); err != nil { + logger.Error(err, "failed to reconcile ArtifactGenerators") + return ctrl.Result{}, err + } + + // Generate HelmReleases for packages + if err := r.reconcileHelmReleases(ctx, bundle, resolvedPackages); err != nil { + logger.Error(err, "failed to reconcile HelmReleases") + return ctrl.Result{}, err + } + + return ctrl.Result{}, nil +} + +// resolveDependencies resolves dependencies from other bundles +func (r *CozystackBundleReconciler) resolveDependencies(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle) ([]cozyv1alpha1.BundleRelease, error) { + resolved := make([]cozyv1alpha1.BundleRelease, 0, len(bundle.Spec.Packages)) + packageMap := make(map[string]bool) + + // Add all packages from this bundle + for _, pkg := range bundle.Spec.Packages { + if !pkg.Disabled { + resolved = append(resolved, pkg) + packageMap[pkg.Name] = true + } + } + + // Resolve dependencies from other bundles + for _, dependsOn := range bundle.Spec.DependsOn { + parts := strings.Split(dependsOn, "/") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid dependsOn format: %s (expected bundleName/target)", dependsOn) + } + + bundleName := parts[0] + targetName := parts[1] + + // Get the bundle + depBundle := &cozyv1alpha1.CozystackBundle{} + if err := r.Get(ctx, types.NamespacedName{Name: bundleName}, depBundle); err != nil { + return nil, fmt.Errorf("failed to get bundle %s: %w", bundleName, err) + } + + // Find the target + var target *cozyv1alpha1.BundleDependencyTarget + for i := range depBundle.Spec.DependencyTargets { + if depBundle.Spec.DependencyTargets[i].Name == targetName { + target = &depBundle.Spec.DependencyTargets[i] + break + } + } + + if target == nil { + return nil, fmt.Errorf("target %s not found in bundle %s", targetName, bundleName) + } + + // Add packages from target to all packages in this bundle + for i := range resolved { + // Add target packages to dependsOn + for _, targetPkg := range target.Packages { + // Check if already in dependsOn + found := false + for _, dep := range resolved[i].DependsOn { + if dep == targetPkg { + found = true + break + } + } + if !found { + resolved[i].DependsOn = append(resolved[i].DependsOn, targetPkg) + } + } + } + } + + return resolved, nil +} + +// reconcileArtifactGenerators generates ArtifactGenerators from bundle packages +func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle, packages []cozyv1alpha1.BundleRelease) error { + logger := log.FromContext(ctx) + + // Group packages by prefix (system, apps, extra) + packageGroups := make(map[string][]cozyv1alpha1.BundleRelease) + libraryMap := make(map[string]cozyv1alpha1.BundleLibrary) + for _, lib := range bundle.Spec.Libraries { + libraryMap[lib.Name] = lib + } + + for _, pkg := range packages { + // Determine prefix from path + prefix := r.getPackagePrefix(pkg.Path) + if prefix == "" { + logger.Info("skipping package with unknown prefix", "name", pkg.Name, "path", pkg.Path) + continue + } + + packageGroups[prefix] = append(packageGroups[prefix], pkg) + } + + // Create ArtifactGenerator for each group + for prefix, pkgs := range packageGroups { + namespace := r.getNamespaceForPrefix(prefix) + agName := fmt.Sprintf("%s-%s", bundle.Name, prefix) + + // Build output artifacts + outputArtifacts := []sourcewatcherv1beta1.OutputArtifact{} + for _, pkg := range pkgs { + // Extract package name from path (last component) + pkgName := r.getPackageNameFromPath(pkg.Path) + if pkgName == "" { + logger.Info("skipping package with invalid path", "name", pkg.Name, "path", pkg.Path) + continue + } + + copyOps := []sourcewatcherv1beta1.CopyOperation{ + { + From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, pkg.Path), + To: fmt.Sprintf("@artifact/%s/", pkgName), + }, + } + + // Add libraries if specified + for _, libName := range pkg.Libraries { + if lib, ok := libraryMap[libName]; ok { + copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ + From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, lib.Path), + To: fmt.Sprintf("@artifact/%s/charts/%s/", pkgName, libName), + }) + } + } + + // Add valuesFiles if specified + for i, valuesFile := range pkg.ValuesFiles { + strategy := "Merge" + if i == 0 { + strategy = "Overwrite" + } + copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ + From: fmt.Sprintf("@%s/%s/%s", bundle.Spec.SourceRef.Name, pkg.Path, valuesFile), + To: fmt.Sprintf("@artifact/%s/values.yaml", pkgName), + Strategy: strategy, + }) + } + + artifactName := fmt.Sprintf("%s-%s", prefix, pkgName) + outputArtifacts = append(outputArtifacts, sourcewatcherv1beta1.OutputArtifact{ + Name: artifactName, + Copy: copyOps, + }) + } + + // Create ArtifactGenerator + ag := &sourcewatcherv1beta1.ArtifactGenerator{ + ObjectMeta: metav1.ObjectMeta{ + Name: agName, + Namespace: namespace, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: bundle.APIVersion, + Kind: bundle.Kind, + Name: bundle.Name, + UID: bundle.UID, + Controller: func() *bool { b := true; return &b }(), + }, + }, + }, + Spec: sourcewatcherv1beta1.ArtifactGeneratorSpec{ + Sources: []sourcewatcherv1beta1.SourceReference{ + { + Alias: bundle.Spec.SourceRef.Name, + Kind: bundle.Spec.SourceRef.Kind, + Name: bundle.Spec.SourceRef.Name, + Namespace: bundle.Spec.SourceRef.Namespace, + }, + }, + OutputArtifacts: outputArtifacts, + }, + } + + if err := r.createOrUpdate(ctx, ag); err != nil { + return fmt.Errorf("failed to reconcile ArtifactGenerator %s: %w", agName, err) + } + logger.Info("reconciled ArtifactGenerator", "name", agName, "namespace", namespace) + } + + // Cleanup orphaned ArtifactGenerators + return r.cleanupOrphanedArtifactGenerators(ctx, bundle) +} + +// reconcileHelmReleases generates HelmReleases from bundle packages +func (r *CozystackBundleReconciler) reconcileHelmReleases(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle, packages []cozyv1alpha1.BundleRelease) error { + logger := log.FromContext(ctx) + + // Build package name map for dependency resolution + packageNameMap := make(map[string]cozyv1alpha1.BundleRelease) + for _, pkg := range packages { + packageNameMap[pkg.Name] = pkg + } + + // Create HelmRelease for each package + for _, pkg := range packages { + // Determine artifact name from path + prefix := r.getPackagePrefix(pkg.Path) + pkgName := r.getPackageNameFromPath(pkg.Path) + if prefix == "" || pkgName == "" { + logger.Info("skipping package with invalid path", "name", pkg.Name, "path", pkg.Path) + continue + } + + artifactName := fmt.Sprintf("%s-%s", prefix, pkgName) + artifactNamespace := r.getNamespaceForPrefix(prefix) + + // Create HelmRelease + hr := &helmv2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: pkg.Name, + Namespace: pkg.Namespace, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: bundle.APIVersion, + Kind: bundle.Kind, + Name: bundle.Name, + UID: bundle.UID, + Controller: func() *bool { b := true; return &b }(), + }, + }, + }, + Spec: helmv2.HelmReleaseSpec{ + Interval: metav1.Duration{Duration: 5 * 60 * 1000000000}, // 5m + ReleaseName: pkg.ReleaseName, + ChartRef: &helmv2.CrossNamespaceSourceReference{ + Kind: "ExternalArtifact", + Name: artifactName, + Namespace: artifactNamespace, + }, + Install: &helmv2.Install{ + Remediation: &helmv2.InstallRemediation{ + Retries: -1, + }, + }, + Upgrade: &helmv2.Upgrade{ + Remediation: &helmv2.UpgradeRemediation{ + Retries: -1, + }, + }, + }, + } + + // Set values if provided + if pkg.Values != nil { + hr.Spec.Values = pkg.Values + } + + // Set DependsOn + if len(pkg.DependsOn) > 0 { + dependsOn := make([]helmv2.DependencyReference, 0, len(pkg.DependsOn)) + for _, depName := range pkg.DependsOn { + depPkg, ok := packageNameMap[depName] + if !ok { + logger.Info("dependent package not found, using same namespace", "name", pkg.Name, "dependsOn", depName) + dependsOn = append(dependsOn, helmv2.DependencyReference{ + Name: depName, + Namespace: pkg.Namespace, + }) + } else { + dependsOn = append(dependsOn, helmv2.DependencyReference{ + Name: depPkg.Name, + Namespace: depPkg.Namespace, + }) + } + } + hr.Spec.DependsOn = dependsOn + } + + // Set valuesFiles annotation + if len(pkg.ValuesFiles) > 0 { + if hr.Annotations == nil { + hr.Annotations = make(map[string]string) + } + hr.Annotations["cozypkg.cozystack.io/values-files"] = strings.Join(pkg.ValuesFiles, ",") + } + + if err := r.createOrUpdate(ctx, hr); err != nil { + return fmt.Errorf("failed to reconcile HelmRelease %s: %w", pkg.Name, err) + } + logger.Info("reconciled HelmRelease", "name", pkg.Name, "namespace", pkg.Namespace) + } + + // Cleanup orphaned HelmReleases + return r.cleanupOrphanedHelmReleases(ctx, bundle) +} + +// createOrUpdate creates or updates a resource +func (r *CozystackBundleReconciler) 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) + + return r.Update(ctx, obj) +} + +// Helper functions +func (r *CozystackBundleReconciler) getPackagePrefix(path string) string { + if strings.HasPrefix(path, "packages/system/") { + return "system" + } + if strings.HasPrefix(path, "packages/apps/") { + return "apps" + } + if strings.HasPrefix(path, "packages/extra/") { + return "extra" + } + return "" +} + +func (r *CozystackBundleReconciler) getNamespaceForPrefix(prefix string) string { + if prefix == "system" { + return "cozy-system" + } + return "cozy-public" +} + +func (r *CozystackBundleReconciler) getPackageNameFromPath(path string) string { + parts := strings.Split(path, "/") + if len(parts) > 0 { + return parts[len(parts)-1] + } + return "" +} + +func (r *CozystackBundleReconciler) cleanupOrphanedArtifactGenerators(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle) error { + logger := log.FromContext(ctx) + + agList := &sourcewatcherv1beta1.ArtifactGeneratorList{} + if err := r.List(ctx, agList); err != nil { + if apierrors.IsNotFound(err) { + return nil + } + return err + } + + // Build desired names + desiredNames := make(map[string]bool) + for prefix := range map[string]bool{"system": true, "apps": true, "extra": true} { + desiredNames[fmt.Sprintf("%s-%s", bundle.Name, prefix)] = true + } + + // Find ArtifactGenerators owned by this bundle + for _, ag := range agList.Items { + isOwned := false + for _, ownerRef := range ag.OwnerReferences { + if ownerRef.Kind == "CozystackBundle" && ownerRef.Name == bundle.Name && ownerRef.UID == bundle.UID { + isOwned = true + break + } + } + + if isOwned && !desiredNames[ag.Name] { + if err := r.Delete(ctx, &ag); err != nil { + if !apierrors.IsNotFound(err) { + logger.Error(err, "failed to delete ArtifactGenerator", "name", ag.Name) + } + } else { + logger.Info("deleted orphaned ArtifactGenerator", "name", ag.Name) + } + } + } + + return nil +} + +func (r *CozystackBundleReconciler) cleanupOrphanedHelmReleases(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle) error { + logger := log.FromContext(ctx) + + hrList := &helmv2.HelmReleaseList{} + if err := r.List(ctx, hrList); err != nil { + return err + } + + // Build desired names + desiredNames := make(map[types.NamespacedName]bool) + for _, pkg := range bundle.Spec.Packages { + desiredNames[types.NamespacedName{Name: pkg.Name, Namespace: pkg.Namespace}] = true + } + + // Find HelmReleases owned by this bundle + for _, hr := range hrList.Items { + isOwned := false + for _, ownerRef := range hr.OwnerReferences { + if ownerRef.Kind == "CozystackBundle" && ownerRef.Name == bundle.Name && ownerRef.UID == bundle.UID { + isOwned = true + break + } + } + + if isOwned { + key := types.NamespacedName{Name: hr.Name, Namespace: hr.Namespace} + if !desiredNames[key] { + if err := r.Delete(ctx, &hr); err != nil { + if !apierrors.IsNotFound(err) { + logger.Error(err, "failed to delete HelmRelease", "name", hr.Name, "namespace", hr.Namespace) + } + } else { + logger.Info("deleted orphaned HelmRelease", "name", hr.Name, "namespace", hr.Namespace) + } + } + } + } + + return nil +} + +func (r *CozystackBundleReconciler) cleanupOrphanedResources(ctx context.Context, bundleKey types.NamespacedName) (ctrl.Result, error) { + logger := log.FromContext(ctx) + + // Cleanup ArtifactGenerators + agList := &sourcewatcherv1beta1.ArtifactGeneratorList{} + if err := r.List(ctx, agList); err == nil { + for _, ag := range agList.Items { + for _, ownerRef := range ag.OwnerReferences { + if ownerRef.Kind == "CozystackBundle" && ownerRef.Name == bundleKey.Name { + if err := r.Delete(ctx, &ag); err != nil && !apierrors.IsNotFound(err) { + logger.Error(err, "failed to delete orphaned ArtifactGenerator", "name", ag.Name) + } + } + } + } + } + + // Cleanup HelmReleases + hrList := &helmv2.HelmReleaseList{} + if err := r.List(ctx, hrList); err == nil { + for _, hr := range hrList.Items { + for _, ownerRef := range hr.OwnerReferences { + if ownerRef.Kind == "CozystackBundle" && ownerRef.Name == bundleKey.Name { + if err := r.Delete(ctx, &hr); err != nil && !apierrors.IsNotFound(err) { + logger.Error(err, "failed to delete orphaned HelmRelease", "name", hr.Name, "namespace", hr.Namespace) + } + } + } + } + } + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *CozystackBundleReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + Named("cozystack-bundle"). + For(&cozyv1alpha1.CozystackBundle{}). + Complete(r) +} + diff --git a/internal/operator/reconciler.go b/internal/operator/reconciler.go index 8e5b977e..f3273d22 100644 --- a/internal/operator/reconciler.go +++ b/internal/operator/reconciler.go @@ -18,21 +18,15 @@ package operator import ( "context" - "encoding/json" "fmt" - "strings" - - "gopkg.in/yaml.v3" + 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" corev1 "k8s.io/api/core/v1" 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" - "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" @@ -42,7 +36,6 @@ import ( const ( cozystackConfigMapName = "cozystack" - systemBundleConfigMapName = "system-bundle" cozystackConfigMapNamespace = "cozy-system" platformOperatorLabel = "cozystack.io/platform-operator" ) @@ -110,33 +103,23 @@ type PlatformReconciler struct { // +kubebuilder:rbac:groups=core,resources=configmaps/status,verbs=get // +kubebuilder:rbac:groups=core,resources=namespaces,verbs=get;list;watch;create;update;patch // +kubebuilder:rbac:groups=helm.toolkit.fluxcd.io,resources=helmreleases,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=helmrepositories,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=gitrepositories,verbs=get;list;watch;create;update;patch -// +kubebuilder:rbac:groups=source.extensions.fluxcd.io,resources=artifactgenerators,verbs=get;list;watch;create;update;patch +// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackbundles,verbs=get;list;watch // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. func (r *PlatformReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { logger := log.FromContext(ctx) - // Reconcile on changes to cozystack ConfigMap or system-bundle ConfigMap + // Reconcile on changes to cozystack ConfigMap if req.Namespace != cozystackConfigMapNamespace { return ctrl.Result{}, nil } // Reconcile on changes to cozystack ConfigMap - // Also reconcile when system-bundle changes (it will read bundle-name from cozystack ConfigMap) - if req.Name != cozystackConfigMapName && req.Name != systemBundleConfigMapName { + if req.Name != cozystackConfigMapName { return ctrl.Result{}, nil } - // If system-bundle changed, we still need to get the cozystack ConfigMap to read bundle-name - if req.Name == systemBundleConfigMapName { - logger.Info("system-bundle ConfigMap changed, reconciling platform") - // Continue to get cozystack ConfigMap to determine which bundle to use - req.Name = cozystackConfigMapName - } - // Get the cozystack ConfigMap configMap := &corev1.ConfigMap{} if err := r.Get(ctx, req.NamespacedName, configMap); err != nil { @@ -156,31 +139,11 @@ func (r *PlatformReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c logger.Info("Reconciling platform", "bundle", cfg.BundleName) - // Reconcile HelmRepositories (delete old ones, we no longer create them) - if err := r.reconcileHelmRepositories(ctx); err != nil { - return ctrl.Result{}, fmt.Errorf("failed to reconcile HelmRepositories: %w", err) - } - - // Reconcile GitRepository - if err := r.reconcileGitRepository(ctx); err != nil { - return ctrl.Result{}, fmt.Errorf("failed to reconcile GitRepository: %w", err) - } - - // Reconcile ArtifactGenerators - if err := r.reconcileArtifactGenerators(ctx); err != nil { - return ctrl.Result{}, fmt.Errorf("failed to reconcile ArtifactGenerators: %w", err) - } - // Reconcile namespaces if err := r.reconcileNamespaces(ctx, cfg); err != nil { return ctrl.Result{}, fmt.Errorf("failed to reconcile namespaces: %w", err) } - // Reconcile HelmReleases (from bundle) - if err := r.reconcileHelmReleases(ctx, cfg); err != nil { - return ctrl.Result{}, fmt.Errorf("failed to reconcile HelmReleases: %w", err) - } - // Reconcile tenant-root if err := r.reconcileTenantRoot(ctx, cfg); err != nil { return ctrl.Result{}, fmt.Errorf("failed to reconcile tenant-root: %w", err) @@ -208,410 +171,39 @@ func (r *PlatformReconciler) SetupWithManager(mgr ctrl.Manager) error { Complete(r) } -func (r *PlatformReconciler) reconcileHelmRepositories(ctx context.Context) error { - logger := log.FromContext(ctx) - - // We no longer create HelmRepositories, we use ArtifactGenerators instead - // Delete all old HelmRepositories that were managed by this operator - - desiredRepos := map[string]string{} // empty - we don't want any HelmRepositories - - // List all HelmRepositories that were managed by this operator - hrList := &sourcev1.HelmRepositoryList{} - if err := r.List(ctx, hrList, client.MatchingLabels{ - platformOperatorLabel: "true", - }); err != nil { - return fmt.Errorf("failed to list HelmRepositories: %w", err) - } - - // Also list by old labels for backward compatibility - oldLabels := []map[string]string{ - {"cozystack.io/repository": "system"}, - {"cozystack.io/repository": "apps"}, - {"cozystack.io/repository": "extra"}, - } - - reposToCheck := make(map[types.NamespacedName]bool) - for _, hr := range hrList.Items { - key := types.NamespacedName{Name: hr.Name, Namespace: hr.Namespace} - reposToCheck[key] = true - } - - for _, labels := range oldLabels { - oldList := &sourcev1.HelmRepositoryList{} - if err := r.List(ctx, oldList, client.MatchingLabels(labels)); err != nil { - logger.Error(err, "failed to list HelmRepositories by old labels") - continue - } - for _, hr := range oldList.Items { - key := types.NamespacedName{Name: hr.Name, Namespace: hr.Namespace} - reposToCheck[key] = true - } - } - - // Delete all HelmRepositories that are no longer desired - for key := range reposToCheck { - hr := &sourcev1.HelmRepository{} - if err := r.Get(ctx, key, hr); err != nil { - if apierrors.IsNotFound(err) { - continue - } - return fmt.Errorf("failed to get HelmRepository %s/%s: %w", key.Namespace, key.Name, err) - } - - // Check if this HelmRepository is still desired (none are desired now) - desiredKey := fmt.Sprintf("%s/%s", hr.Namespace, hr.Name) - if _, ok := desiredRepos[desiredKey]; !ok { - // Not desired anymore, delete it - if err := r.Delete(ctx, hr); err != nil { - if apierrors.IsNotFound(err) { - continue - } - logger.Error(err, "failed to delete HelmRepository", "name", hr.Name, "namespace", hr.Namespace) - // Continue with other deletions - } else { - logger.Info("deleted HelmRepository (no longer needed)", "name", hr.Name, "namespace", hr.Namespace) - } - } - } - - return nil -} - -func (r *PlatformReconciler) reconcileGitRepository(ctx context.Context) error { - logger := log.FromContext(ctx) - - // Define desired GitRepository - desiredGR := &sourcev1.GitRepository{ - ObjectMeta: metav1.ObjectMeta{ - Name: "cozystack", - Namespace: "cozy-system", - Labels: map[string]string{ - platformOperatorLabel: "true", - }, - }, - Spec: sourcev1.GitRepositorySpec{ - URL: "https://github.com/cozystack/cozystack.git", - Interval: metav1.Duration{Duration: 1 * 60 * 1000000000}, // 1m - Timeout: &metav1.Duration{Duration: 60 * 1000000000}, // 60s - Reference: &sourcev1.GitRepositoryRef{ - Branch: "refactor-engine", - //Tag: "v0.38.0-alpha.2", - }, - Ignore: func() *string { - ignore := `# exclude all -/* -# include packages dir -!/packages` - return &ignore - }(), - }, - } - - // Create or update desired GitRepository - if err := r.CreateOrUpdate(ctx, desiredGR); err != nil { - logger.Error(err, "failed to reconcile GitRepository") - return err - } - logger.Info("reconciled GitRepository", "name", "cozystack") - - // List all GitRepositories managed by this operator and delete unwanted ones - grList := &sourcev1.GitRepositoryList{} - if err := r.List(ctx, grList, client.MatchingLabels{ - platformOperatorLabel: "true", - }); err != nil { - return fmt.Errorf("failed to list GitRepositories: %w", err) - } - - for _, gr := range grList.Items { - key := types.NamespacedName{Name: gr.Name, Namespace: gr.Namespace} - desiredKey := types.NamespacedName{Name: desiredGR.Name, Namespace: desiredGR.Namespace} - if key != desiredKey { - // Not desired, delete it - if err := r.Delete(ctx, &gr); err != nil { - if apierrors.IsNotFound(err) { - continue - } - logger.Error(err, "failed to delete GitRepository", "name", gr.Name, "namespace", gr.Namespace) - // Continue with other deletions - } else { - logger.Info("deleted GitRepository (not in desired state)", "name", gr.Name, "namespace", gr.Namespace) - } - } - } - - return nil -} - -func (r *PlatformReconciler) reconcileArtifactGenerators(ctx context.Context) error { - logger := log.FromContext(ctx) - - // Packages that use cozy-lib - packagesWithCozyLib := map[string]bool{ - "bootbox": true, "bucket": true, "clickhouse": true, "etcd": true, - "ferretdb": true, "foundationdb": true, "http-cache": true, "info": true, - "ingress": true, "kafka": true, "keycloak": true, "kubernetes": true, "monitoring": true, - "mysql": true, "nats": true, "postgres": true, "rabbitmq": true, - "redis": true, "seaweedfs": true, "tcp-balancer": true, "tenant": true, - "virtual-machine": true, "vm-disk": true, "vm-instance": true, - "vpc": true, "vpn": true, - } - - // Convert maps to slices for ArtifactGenerator - systemPackages := make([]string, 0, len(systemPackagesList)) - for pkg := range systemPackagesList { - systemPackages = append(systemPackages, pkg) - } - - appsPackages := make([]string, 0, len(appsPackagesList)) - for pkg := range appsPackagesList { - appsPackages = append(appsPackages, pkg) - } - - extraPackages := make([]string, 0, len(extraPackagesList)) - for pkg := range extraPackagesList { - extraPackages = append(extraPackages, pkg) - } - - // Define desired ArtifactGenerators - desiredAGs := []struct { - name string - namespace string - packages []string - }{ - {"system", "cozy-system", systemPackages}, - {"apps", "cozy-public", appsPackages}, - {"extra", "cozy-public", extraPackages}, - } - - // Create or update desired ArtifactGenerators - for _, ag := range desiredAGs { - if err := r.reconcileArtifactGenerator(ctx, ag.name, ag.namespace, ag.packages, packagesWithCozyLib); err != nil { - logger.Error(err, "failed to reconcile ArtifactGenerator", "name", ag.name) - return err - } - } - - // List all ArtifactGenerators managed by this operator and delete unwanted ones - agList := &sourcewatcherv1beta1.ArtifactGeneratorList{} - if err := r.List(ctx, agList, client.MatchingLabels{ - platformOperatorLabel: "true", - }); err != nil { - // If CRD doesn't exist, just log and continue - logger.Info("ArtifactGenerator CRD may not exist, skipping cleanup", "error", err) - } else { - // Build desired map - desiredMap := make(map[types.NamespacedName]bool) - for _, ag := range desiredAGs { - key := types.NamespacedName{Name: ag.name, Namespace: ag.namespace} - desiredMap[key] = true - } - - // Delete unwanted ArtifactGenerators - for _, item := range agList.Items { - key := types.NamespacedName{Name: item.Name, Namespace: item.Namespace} - if !desiredMap[key] { - // Not desired, delete it - if err := r.Delete(ctx, &item); err != nil { - if apierrors.IsNotFound(err) { - continue - } - logger.Error(err, "failed to delete ArtifactGenerator", "name", item.Name, "namespace", item.Namespace) - // Continue with other deletions - } else { - logger.Info("deleted ArtifactGenerator (not in desired state)", "name", item.Name, "namespace", item.Namespace) - } - } - } - } - - return nil -} - -func (r *PlatformReconciler) reconcileArtifactGenerator(ctx context.Context, name, namespace string, packages []string, packagesWithCozyLib map[string]bool) error { - logger := log.FromContext(ctx) - - // Load bundle to get valuesFiles for packages - cfg := &config.CozystackConfig{} - configMap := &corev1.ConfigMap{} - configMapKey := types.NamespacedName{Namespace: "cozy-system", Name: "cozystack"} - if err := r.Get(ctx, configMapKey, configMap); err == nil { - cfg = config.ParseConfigMapData(configMap.Data) - } - - var bundle *Bundle - var err error - if cfg.BundleName != "" { - bundle, err = loadBundle(ctx, r.Client, cfg.BundleName) - if err != nil { - logger.Info("failed to load bundle for valuesFiles, continuing without them", "error", err) - bundle = nil - } - } - - // Build map of chart -> valuesFiles from bundle - chartValuesFiles := make(map[string][]string) - if bundle != nil { - for _, release := range bundle.Releases { - // Check if release is disabled or optional - if cfg.IsComponentDisabled(release.Name) { - continue - } - if release.Optional && !cfg.IsComponentEnabled(release.Name) { - continue - } - // Store valuesFiles for this chart - if len(release.ValuesFiles) > 0 { - chartValuesFiles[release.Chart] = release.ValuesFiles - } - } - } - - // Build output artifacts - outputArtifacts := []sourcewatcherv1beta1.OutputArtifact{} - for _, pkg := range packages { - copyOps := []sourcewatcherv1beta1.CopyOperation{ - { - From: fmt.Sprintf("@cozystack/packages/%s/%s/**", name, pkg), - To: fmt.Sprintf("@artifact/%s/", pkg), - }, - } - - // Add cozy-lib if package uses it - if packagesWithCozyLib[pkg] { - copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ - From: "@cozystack/packages/library/cozy-lib/**", - To: fmt.Sprintf("@artifact/%s/charts/cozy-lib/", pkg), - }) - } - - // Add valuesFiles if specified in bundle - if valuesFiles, ok := chartValuesFiles[pkg]; ok { - for i, valuesFile := range valuesFiles { - // Copy values file from GitRepository to artifact - // Path in GitRepository: packages/{name}/{pkg}/{valuesFile} - // All files should be merged into values.yaml in artifact - // First file should use Overwrite (to replace original values.yaml), others use Merge - strategy := "Merge" - if i == 0 { - strategy = "Overwrite" - } - copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ - From: fmt.Sprintf("@cozystack/packages/%s/%s/%s", name, pkg, valuesFile), - To: fmt.Sprintf("@artifact/%s/values.yaml", pkg), - Strategy: strategy, - }) - logger.Info("Adding valuesFile copy operation", "package", pkg, "valuesFile", valuesFile, "strategy", strategy, "target", "values.yaml") - } - } - - artifactName := fmt.Sprintf("%s-%s", name, pkg) - logger.Info("Adding output artifact to ArtifactGenerator", "artifactName", artifactName, "generator", name, "package", pkg) - outputArtifacts = append(outputArtifacts, sourcewatcherv1beta1.OutputArtifact{ - Name: artifactName, - Copy: copyOps, - }) - } - - // Define desired ArtifactGenerator - ag := &sourcewatcherv1beta1.ArtifactGenerator{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - Labels: map[string]string{ - platformOperatorLabel: "true", - }, - }, - Spec: sourcewatcherv1beta1.ArtifactGeneratorSpec{ - Sources: []sourcewatcherv1beta1.SourceReference{ - { - Alias: "cozystack", - Kind: "GitRepository", - Name: "cozystack", - Namespace: "cozy-system", - }, - }, - OutputArtifacts: outputArtifacts, - }, - } - - // Get existing resource to preserve resourceVersion - existing := &sourcewatcherv1beta1.ArtifactGenerator{} - key := client.ObjectKey{Name: name, Namespace: namespace} - err = r.Get(ctx, key, existing) - if err == nil { - ag.SetResourceVersion(existing.GetResourceVersion()) - // Merge labels and annotations - labels := ag.GetLabels() - if labels == nil { - labels = make(map[string]string) - } - for k, v := range existing.GetLabels() { - if _, ok := labels[k]; !ok { - labels[k] = v - } - } - ag.SetLabels(labels) - - annotations := ag.GetAnnotations() - if annotations == nil { - annotations = make(map[string]string) - } - for k, v := range existing.GetAnnotations() { - if _, ok := annotations[k]; !ok { - annotations[k] = v - } - } - ag.SetAnnotations(annotations) - - if err := r.Update(ctx, ag); err != nil { - return fmt.Errorf("failed to update ArtifactGenerator: %w", err) - } - logger.Info("updated ArtifactGenerator", "name", name, "namespace", namespace) - } else if apierrors.IsNotFound(err) { - if err := r.Create(ctx, ag); err != nil { - return fmt.Errorf("failed to create ArtifactGenerator: %w", err) - } - logger.Info("created ArtifactGenerator", "name", name, "namespace", namespace) - } else { - return fmt.Errorf("failed to get ArtifactGenerator: %w", err) - } - - return nil -} +// Removed reconcileHelmRepositories, reconcileGitRepository, reconcileArtifactGenerators, and reconcileHelmReleases +// These are now handled by CozystackBundleReconciler and CozystackResourceDefinitionReconciler func (r *PlatformReconciler) reconcileNamespaces(ctx context.Context, cfg *config.CozystackConfig) error { logger := log.FromContext(ctx) - // Load bundle to determine namespaces - bundle, err := loadBundle(ctx, r.Client, cfg.BundleName) - if err != nil { - logger.Error(err, "failed to load bundle, using default namespaces", "bundle", cfg.BundleName) - // Fallback to default namespaces if bundle loading fails - bundle = nil - } - - // Collect namespaces from bundle releases + // Collect namespaces from CozystackBundle resources namespacesMap := make(map[string]bool) - if bundle != nil { - for _, release := range bundle.Releases { - // Check if release is disabled - if cfg.IsComponentDisabled(release.Name) { - continue - } + // List all CozystackBundle resources + bundleList := &cozyv1alpha1.CozystackBundleList{} + if err := r.Client.List(ctx, bundleList); err != nil { + logger.Error(err, "failed to list CozystackBundles, using default namespaces") + } else { + for _, bundle := range bundleList.Items { + for _, pkg := range bundle.Spec.Packages { + // Check if package is disabled + if pkg.Disabled { + continue + } - // Check if optional release is enabled - if release.Optional && !cfg.IsComponentEnabled(release.Name) { - continue - } + // Check if component is disabled via config + if cfg.IsComponentDisabled(pkg.Name) { + continue + } - // If at least one release requires a privileged namespace, then it should be privileged - if release.Namespace != "" { - if release.Privileged { - namespacesMap[release.Namespace] = true - } else if _, exists := namespacesMap[release.Namespace]; !exists { - namespacesMap[release.Namespace] = false + // If at least one package requires a privileged namespace, then it should be privileged + if pkg.Namespace != "" { + if pkg.Privileged { + namespacesMap[pkg.Namespace] = true + } else if _, exists := namespacesMap[pkg.Namespace]; !exists { + namespacesMap[pkg.Namespace] = false + } } } } @@ -646,33 +238,9 @@ func (r *PlatformReconciler) reconcileNamespaces(ctx context.Context, cfg *confi logger.Info("reconciled Namespace", "name", nsName, "privileged", privileged) } - // List all namespaces managed by this operator and delete unwanted ones - nsList := &corev1.NamespaceList{} - if err := r.List(ctx, nsList, client.MatchingLabels{ - "cozystack.io/system": "true", - }); err != nil { - return fmt.Errorf("failed to list namespaces: %w", err) - } - - for _, ns := range nsList.Items { - // Skip tenant-root as it's managed separately - if ns.Name == "tenant-root" { - continue - } - - if _, ok := namespacesMap[ns.Name]; !ok { - // Not desired, delete it - if err := r.Delete(ctx, &ns); err != nil { - if apierrors.IsNotFound(err) { - continue - } - logger.Error(err, "failed to delete Namespace", "name", ns.Name) - // Continue with other deletions - } else { - logger.Info("deleted Namespace (not in desired state)", "name", ns.Name) - } - } - } + // Note: We no longer delete namespaces that are not in the desired state. + // Namespaces are managed by their respective HelmReleases and should not be + // deleted by the platform operator. return nil } @@ -718,14 +286,10 @@ func (r *PlatformReconciler) reconcileTenantRoot(ctx context.Context, cfg *confi Spec: helmv2.HelmReleaseSpec{ Interval: metav1.Duration{Duration: 0}, // 0s ReleaseName: "tenant-root", - Chart: &helmv2.HelmChartTemplate{ - Spec: helmv2.HelmChartTemplateSpec{ - SourceRef: helmv2.CrossNamespaceObjectReference{ - Kind: "ExternalArtifact", - Name: "apps-tenant", - Namespace: "cozy-public", - }, - }, + ChartRef: &helmv2.CrossNamespaceSourceReference{ + Kind: "ExternalArtifact", + Name: "apps-tenant", + Namespace: "cozy-public", }, Values: &apiextensionsv1.JSON{ Raw: []byte(fmt.Sprintf(`{"host":%q}`, host)), @@ -752,207 +316,6 @@ func (r *PlatformReconciler) reconcileTenantRoot(ctx context.Context, cfg *confi return nil } -func (r *PlatformReconciler) reconcileHelmReleases(ctx context.Context, cfg *config.CozystackConfig) error { - logger := log.FromContext(ctx) - - // Load bundle to determine desired HelmReleases - bundle, err := loadBundle(ctx, r.Client, cfg.BundleName) - if err != nil { - logger.Error(err, "failed to load bundle, skipping HelmReleases reconciliation", "bundle", cfg.BundleName) - return nil // Don't fail if bundle loading fails - } - - // Determine desired HelmReleases from bundle - desiredReleases := make(map[string]map[string]bool) // namespace -> name -> true - for _, release := range bundle.Releases { - // Check if release is disabled - if cfg.IsComponentDisabled(release.Name) { - continue - } - - // Check if optional release is enabled - if release.Optional && !cfg.IsComponentEnabled(release.Name) { - continue - } - - if release.Namespace == "" { - logger.Info("skipping release without namespace", "name", release.Name) - continue - } - - if desiredReleases[release.Namespace] == nil { - desiredReleases[release.Namespace] = make(map[string]bool) - } - desiredReleases[release.Namespace][release.Name] = true - - // Create or update HelmRelease - hr := &helmv2.HelmRelease{ - ObjectMeta: metav1.ObjectMeta{ - Name: release.Name, - Namespace: release.Namespace, - Labels: map[string]string{ - platformOperatorLabel: "true", - }, - }, - Spec: helmv2.HelmReleaseSpec{ - Interval: metav1.Duration{Duration: 5 * 60 * 1000000000}, // 5m - ReleaseName: release.ReleaseName, - Install: &helmv2.Install{ - Remediation: &helmv2.InstallRemediation{ - Retries: -1, - }, - }, - Upgrade: &helmv2.Upgrade{ - Remediation: &helmv2.UpgradeRemediation{ - Retries: -1, - }, - }, - }, - } - - // All packages now use chartRef (ExternalArtifact) - // Determine artifact prefix and namespace based on package category - artifactPrefix, artifactNamespace, found := getArtifactPrefixAndNamespace(release.Chart) - if !found { - logger.Error(fmt.Errorf("unknown package category"), "skipping HelmRelease with unknown package", "name", release.Name, "namespace", release.Namespace, "chart", release.Chart) - continue - } - - artifactName := fmt.Sprintf("%s-%s", artifactPrefix, release.Chart) - logger.Info("Creating HelmRelease with chartRef", "name", release.Name, "namespace", release.Namespace, "chart", release.Chart, "artifactName", artifactName, "artifactNamespace", artifactNamespace) - hr.Spec.ChartRef = &helmv2.CrossNamespaceSourceReference{ - Kind: "ExternalArtifact", - Name: artifactName, - Namespace: artifactNamespace, - } - - // Set values if provided - if len(release.Values) > 0 { - valuesJSON, err := json.Marshal(release.Values) - if err != nil { - logger.Error(err, "failed to marshal values for release", "name", release.Name) - return fmt.Errorf("failed to marshal values for release %s: %w", release.Name, err) - } - hr.Spec.Values = &apiextensionsv1.JSON{ - Raw: valuesJSON, - } - } - - // Get component-specific values from config if available - if componentValues, ok := cfg.GetComponentValues(release.Name); ok { - // Merge with existing values if any - mergedValues := make(map[string]interface{}) - if len(release.Values) > 0 { - mergedValues = release.Values - } - // Parse component values (they might be YAML or JSON string) - var componentValuesMap map[string]interface{} - if err := yaml.Unmarshal([]byte(componentValues), &componentValuesMap); err != nil { - logger.Error(err, "failed to parse component values for release", "name", release.Name) - return fmt.Errorf("failed to parse component values for release %s: %w", release.Name, err) - } - // Merge maps (component values override bundle values) - for k, v := range componentValuesMap { - mergedValues[k] = v - } - // Marshal merged values - valuesJSON, err := json.Marshal(mergedValues) - if err != nil { - logger.Error(err, "failed to marshal merged values for release", "name", release.Name) - return fmt.Errorf("failed to marshal merged values for release %s: %w", release.Name, err) - } - hr.Spec.Values = &apiextensionsv1.JSON{ - Raw: valuesJSON, - } - } - - // Set DependsOn if provided - // DependsOn is a list of release names, we need to convert them to HelmRelease references - if len(release.DependsOn) > 0 { - dependsOn := make([]helmv2.DependencyReference, 0, len(release.DependsOn)) - for _, depName := range release.DependsOn { - // Find the dependent release in the bundle to get its namespace - var depNamespace string - for _, depRelease := range bundle.Releases { - if depRelease.Name == depName { - depNamespace = depRelease.Namespace - break - } - } - // If namespace not found, use the same namespace as current release - if depNamespace == "" { - depNamespace = release.Namespace - logger.Info("dependent release not found in bundle, using same namespace", "name", release.Name, "dependsOn", depName) - } - dependsOn = append(dependsOn, helmv2.DependencyReference{ - Name: depName, - Namespace: depNamespace, - }) - } - hr.Spec.DependsOn = dependsOn - logger.Info("set DependsOn for HelmRelease", "name", release.Name, "dependsOn", release.DependsOn) - } - - // Set valuesFiles annotation for cozypkg - // Initialize annotations if needed - if hr.Annotations == nil { - hr.Annotations = make(map[string]string) - } - if len(release.ValuesFiles) > 0 { - // Format: comma-separated string, e.g., "values.yaml,values-cilium.yaml" - hr.Annotations["cozypkg.cozystack.io/values-files"] = strings.Join(release.ValuesFiles, ",") - logger.Info("set valuesFiles annotation for HelmRelease", "name", release.Name, "valuesFiles", release.ValuesFiles) - } else { - // Remove annotation if valuesFiles is empty - delete(hr.Annotations, "cozypkg.cozystack.io/values-files") - } - - if err := r.CreateOrUpdate(ctx, hr); err != nil { - logger.Error(err, "failed to reconcile HelmRelease", "name", release.Name, "namespace", release.Namespace) - return err - } - logger.Info("reconciled HelmRelease", "name", release.Name, "namespace", release.Namespace) - } - - // Find all HelmReleases managed by this operator - hrList := &helmv2.HelmReleaseList{} - if err := r.List(ctx, hrList, client.MatchingLabels{ - platformOperatorLabel: "true", - }); err != nil { - return fmt.Errorf("failed to list HelmReleases: %w", err) - } - - // Delete HelmReleases that are no longer desired - for _, hr := range hrList.Items { - // Skip tenant-root as it's managed separately - if hr.Name == "tenant-root" && hr.Namespace == "tenant-root" { - continue - } - - // Check if this HelmRelease is still desired - if desiredNamespaces, ok := desiredReleases[hr.Namespace]; ok { - if desiredNamespaces[hr.Name] { - // Still desired, keep it - continue - } - } - - // Not desired anymore, delete it - if err := r.Delete(ctx, &hr); err != nil { - if apierrors.IsNotFound(err) { - // Already deleted, ignore - continue - } - logger.Error(err, "failed to delete HelmRelease", "name", hr.Name, "namespace", hr.Namespace) - // Continue with other deletions - } else { - logger.Info("deleted HelmRelease (no longer in bundle)", "name", hr.Name, "namespace", hr.Namespace) - } - } - - return nil -} - // CreateOrUpdate creates or updates a resource. func (r *PlatformReconciler) CreateOrUpdate(ctx context.Context, obj client.Object) error { existing := obj.DeepCopyObject().(client.Object) @@ -992,65 +355,3 @@ func (r *PlatformReconciler) CreateOrUpdate(ctx context.Context, obj client.Obje return r.Update(ctx, obj) } - -// Bundle represents the structure of a bundle YAML file. -type Bundle struct { - Releases []BundleRelease `yaml:"releases"` -} - -// BundleRelease represents a single release in a bundle. -type BundleRelease struct { - Name string `yaml:"name"` - ReleaseName string `yaml:"releaseName"` - Chart string `yaml:"chart"` - Namespace string `yaml:"namespace"` - Privileged bool `yaml:"privileged,omitempty"` - Optional bool `yaml:"optional,omitempty"` - DependsOn []string `yaml:"dependsOn,omitempty"` - Values map[string]interface{} `yaml:"values,omitempty"` - ValuesFiles []string `yaml:"valuesFiles,omitempty"` -} - -// loadBundle loads a bundle from the system-bundle ConfigMap in cozy-system namespace. -// The ConfigMap contains all bundles as data keys: {bundleName}.yaml -func loadBundle(ctx context.Context, c client.Client, bundleName string) (*Bundle, error) { - if bundleName == "" { - return nil, fmt.Errorf("bundle name is empty") - } - - // Get the system-bundle ConfigMap - configMap := &corev1.ConfigMap{} - key := types.NamespacedName{Namespace: "cozy-system", Name: "system-bundle"} - if err := c.Get(ctx, key, configMap); err != nil { - if apierrors.IsNotFound(err) { - return nil, fmt.Errorf("system-bundle ConfigMap not found in cozy-system namespace") - } - return nil, fmt.Errorf("failed to get system-bundle ConfigMap: %w", err) - } - - // Get the bundle data from ConfigMap - bundleKey := bundleName + ".yaml" - bundleData, ok := configMap.Data[bundleKey] - if !ok { - return nil, fmt.Errorf("bundle %s not found in system-bundle ConfigMap (available keys: %v)", bundleName, getMapKeys(configMap.Data)) - } - - var bundle Bundle - // Note: bundle files contain Helm template syntax ({{ }}), but after Helm rendering - // they should be valid YAML. If template syntax remains, it will be treated as strings - // which is fine for extracting namespace and privileged fields - if err := yaml.Unmarshal([]byte(bundleData), &bundle); err != nil { - return nil, fmt.Errorf("failed to parse bundle %s from ConfigMap: %w", bundleName, err) - } - - return &bundle, nil -} - -// getMapKeys returns a slice of keys from a map for error messages -func getMapKeys(m map[string]string) []string { - keys := make([]string, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - return keys -} diff --git a/internal/operator/resourcedefinition_reconciler.go b/internal/operator/resourcedefinition_reconciler.go new file mode 100644 index 00000000..9ede6a73 --- /dev/null +++ b/internal/operator/resourcedefinition_reconciler.go @@ -0,0 +1,242 @@ +/* +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" + "fmt" + "strings" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + sourcewatcherv1beta1 "github.com/fluxcd/source-watcher/api/v2/v1beta1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/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/log" +) + +// CozystackResourceDefinitionReconciler reconciles CozystackResourceDefinition resources +type CozystackResourceDefinitionReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackresourcedefinitions,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackresourcedefinitions/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=source.extensions.fluxcd.io,resources=artifactgenerators,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackbundles,verbs=get;list;watch + +// Reconcile is part of the main kubernetes reconciliation loop +func (r *CozystackResourceDefinitionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + + crd := &cozyv1alpha1.CozystackResourceDefinition{} + if err := r.Get(ctx, req.NamespacedName, crd); err != nil { + if apierrors.IsNotFound(err) { + // Cleanup orphaned resources + return r.cleanupOrphanedResources(ctx, req.NamespacedName) + } + return ctrl.Result{}, err + } + + // Only process if source is specified + if crd.Spec.Source == nil { + return ctrl.Result{}, nil + } + + // Get the bundle to get sourceRef + bundle := &cozyv1alpha1.CozystackBundle{} + if err := r.Get(ctx, types.NamespacedName{Name: crd.Spec.Source.BundleName}, bundle); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to get bundle %s: %w", crd.Spec.Source.BundleName, err) + } + + // Generate ArtifactGenerator for this resource definition + if err := r.reconcileArtifactGenerator(ctx, crd, bundle); err != nil { + logger.Error(err, "failed to reconcile ArtifactGenerator") + return ctrl.Result{}, err + } + + return ctrl.Result{}, nil +} + +// reconcileArtifactGenerator generates ArtifactGenerator from CozystackResourceDefinition +func (r *CozystackResourceDefinitionReconciler) reconcileArtifactGenerator(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition, bundle *cozyv1alpha1.CozystackBundle) error { + logger := log.FromContext(ctx) + + // Determine artifact name from path + prefix := r.getPackagePrefix(crd.Spec.Source.Path) + pkgName := r.getPackageNameFromPath(crd.Spec.Source.Path) + if prefix == "" || pkgName == "" { + logger.Info("skipping resource definition with invalid path", "name", crd.Name, "path", crd.Spec.Source.Path) + return nil + } + + artifactName := fmt.Sprintf("%s-%s", prefix, pkgName) + namespace := r.getNamespaceForPrefix(prefix) + + // Build copy operations + copyOps := []sourcewatcherv1beta1.CopyOperation{ + { + From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, crd.Spec.Source.Path), + To: fmt.Sprintf("@artifact/%s/", pkgName), + }, + } + + // Add libraries if specified + libraryMap := make(map[string]cozyv1alpha1.BundleLibrary) + for _, lib := range bundle.Spec.Libraries { + libraryMap[lib.Name] = lib + } + + for _, libName := range crd.Spec.Source.Libraries { + if lib, ok := libraryMap[libName]; ok { + copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ + From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, lib.Path), + To: fmt.Sprintf("@artifact/%s/charts/%s/", pkgName, libName), + }) + } + } + + // Create or get ArtifactGenerator + agName := artifactName + ag := &sourcewatcherv1beta1.ArtifactGenerator{} + key := types.NamespacedName{Name: agName, Namespace: namespace} + + err := r.Get(ctx, key, ag) + if apierrors.IsNotFound(err) { + // Create new ArtifactGenerator + ag = &sourcewatcherv1beta1.ArtifactGenerator{ + ObjectMeta: metav1.ObjectMeta{ + Name: agName, + Namespace: namespace, + }, + Spec: sourcewatcherv1beta1.ArtifactGeneratorSpec{ + Sources: []sourcewatcherv1beta1.SourceReference{ + { + Alias: bundle.Spec.SourceRef.Name, + Kind: bundle.Spec.SourceRef.Kind, + Name: bundle.Spec.SourceRef.Name, + Namespace: bundle.Spec.SourceRef.Namespace, + }, + }, + OutputArtifacts: []sourcewatcherv1beta1.OutputArtifact{ + { + Name: artifactName, + Copy: copyOps, + }, + }, + }, + } + + if err := r.Create(ctx, ag); err != nil { + return fmt.Errorf("failed to create ArtifactGenerator: %w", err) + } + logger.Info("created ArtifactGenerator", "name", agName, "namespace", namespace) + } else if err != nil { + return fmt.Errorf("failed to get ArtifactGenerator: %w", err) + } else { + // Update existing ArtifactGenerator - add this output artifact if not present + found := false + for i, outputArtifact := range ag.Spec.OutputArtifacts { + if outputArtifact.Name == artifactName { + // Update existing artifact + ag.Spec.OutputArtifacts[i].Copy = copyOps + found = true + break + } + } + + if !found { + // Add new output artifact + ag.Spec.OutputArtifacts = append(ag.Spec.OutputArtifacts, sourcewatcherv1beta1.OutputArtifact{ + Name: artifactName, + Copy: copyOps, + }) + } + + // Ensure source reference exists + sourceFound := false + for _, source := range ag.Spec.Sources { + if source.Name == bundle.Spec.SourceRef.Name && source.Namespace == bundle.Spec.SourceRef.Namespace { + sourceFound = true + break + } + } + if !sourceFound { + ag.Spec.Sources = append(ag.Spec.Sources, sourcewatcherv1beta1.SourceReference{ + Alias: bundle.Spec.SourceRef.Name, + Kind: bundle.Spec.SourceRef.Kind, + Name: bundle.Spec.SourceRef.Name, + Namespace: bundle.Spec.SourceRef.Namespace, + }) + } + + if err := r.Update(ctx, ag); err != nil { + return fmt.Errorf("failed to update ArtifactGenerator: %w", err) + } + logger.Info("updated ArtifactGenerator", "name", agName, "namespace", namespace) + } + + return nil +} + +// Helper functions +func (r *CozystackResourceDefinitionReconciler) getPackagePrefix(path string) string { + if strings.HasPrefix(path, "packages/system/") { + return "system" + } + if strings.HasPrefix(path, "packages/apps/") { + return "apps" + } + if strings.HasPrefix(path, "packages/extra/") { + return "extra" + } + return "" +} + +func (r *CozystackResourceDefinitionReconciler) getNamespaceForPrefix(prefix string) string { + if prefix == "system" { + return "cozy-system" + } + return "cozy-public" +} + +func (r *CozystackResourceDefinitionReconciler) getPackageNameFromPath(path string) string { + parts := strings.Split(path, "/") + if len(parts) > 0 { + return parts[len(parts)-1] + } + return "" +} + +func (r *CozystackResourceDefinitionReconciler) cleanupOrphanedResources(ctx context.Context, crdKey types.NamespacedName) (ctrl.Result, error) { + // ArtifactGenerators are shared, so we don't delete them here + // They will be cleaned up when all referencing CRDs are deleted + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *CozystackResourceDefinitionReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + Named("cozystack-resource-definition"). + For(&cozyv1alpha1.CozystackResourceDefinition{}). + Complete(r) +} + diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index 8f722558..6696888f 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:latest@sha256:06e47d65e0b9c9eebc72d9bcf63ad644a75b9b740c433ad7f1e3b0e703957f7d + image: ghcr.io/cozystack/cozystack/installer:latest@sha256:2b7c313268ed7e047dd3ae6c7952f90bfca1d45d9dd880847430b4c1339e6a6a diff --git a/packages/core/platform/bundles/system/bundle-full.yaml b/packages/core/platform/bundles/system/bundle-full.yaml index d449a352..65e71be5 100644 --- a/packages/core/platform/bundles/system/bundle-full.yaml +++ b/packages/core/platform/bundles/system/bundle-full.yaml @@ -145,12 +145,6 @@ spec: namespace: cozy-system dependsOn: [cilium,kubeovn,cozystack-api,cozystack-controller] - - name: cozystack-resource-definitions - releaseName: cozystack-resource-definitions - path: packages/system/cozystack-resource-definitions - namespace: cozy-system - dependsOn: [cilium,kubeovn,cozystack-api,cozystack-controller,cozystack-resource-definition-crd] - - name: cert-manager releaseName: cert-manager path: packages/system/cert-manager diff --git a/packages/core/platform/bundles/system/bundle-hosted.yaml b/packages/core/platform/bundles/system/bundle-hosted.yaml index 41c67227..e0dd169a 100644 --- a/packages/core/platform/bundles/system/bundle-hosted.yaml +++ b/packages/core/platform/bundles/system/bundle-hosted.yaml @@ -89,12 +89,6 @@ spec: namespace: cozy-system dependsOn: [cozystack-api,cozystack-controller] - - name: cozystack-resource-definitions - releaseName: cozystack-resource-definitions - path: packages/system/cozystack-resource-definitions - namespace: cozy-system - dependsOn: [cozystack-api,cozystack-controller,cozystack-resource-definition-crd] - - name: cert-manager releaseName: cert-manager path: packages/system/cert-manager From 36119cec45fb3b235f86101c77b13def2198b1f0 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 20 Nov 2025 04:23:40 +0100 Subject: [PATCH 16/46] Introduce CozystackPlatformConfiguration Signed-off-by: Andrei Kvapil --- .../cozystackplatformconfiguration_types.go | 116 +++++++++ api/v1alpha1/zz_generated.deepcopy.go | 145 +++++++++++ cmd/cozystack-operator/main.go | 27 ++ hack/update-codegen.sh | 2 + internal/operator/bootstrap.go | 157 ++++++++++++ internal/operator/bundle_reconciler.go | 33 +++ .../platform_configuration_reconciler.go | 234 ++++++++++++++++++ .../installer/templates/bundle-config.yaml | 33 --- ...ck.io_cozystackplatformconfigurations.yaml | 197 +++++++++++++++ .../installer/templates/platform-config.yaml | 25 ++ packages/core/platform/values.yaml | 2 +- 11 files changed, 937 insertions(+), 34 deletions(-) create mode 100644 api/v1alpha1/cozystackplatformconfiguration_types.go create mode 100644 internal/operator/bootstrap.go create mode 100644 internal/operator/platform_configuration_reconciler.go delete mode 100644 packages/core/installer/templates/bundle-config.yaml create mode 100644 packages/core/installer/templates/cozystack.io_cozystackplatformconfigurations.yaml create mode 100644 packages/core/installer/templates/platform-config.yaml diff --git a/api/v1alpha1/cozystackplatformconfiguration_types.go b/api/v1alpha1/cozystackplatformconfiguration_types.go new file mode 100644 index 00000000..86f889eb --- /dev/null +++ b/api/v1alpha1/cozystackplatformconfiguration_types.go @@ -0,0 +1,116 @@ +/* +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 v1alpha1 + +import ( + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + sourcev1 "github.com/fluxcd/source-controller/api/v1" +) + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster + +// CozystackPlatformConfiguration is the Schema for the cozystackplatformconfigurations API +type CozystackPlatformConfiguration struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec CozystackPlatformConfigurationSpec `json:"spec,omitempty"` +} + +// +kubebuilder:object:root=true + +// CozystackPlatformConfigurationList contains a list of CozystackPlatformConfigurations +type CozystackPlatformConfigurationList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CozystackPlatformConfiguration `json:"items"` +} + +func init() { + SchemeBuilder.Register(&CozystackPlatformConfiguration{}, &CozystackPlatformConfigurationList{}) +} + +// CozystackPlatformConfigurationSpec defines the desired state of CozystackPlatformConfiguration +type CozystackPlatformConfigurationSpec struct { + // Source configuration for GitRepository + // +required + Source CozystackPlatformConfigurationSource `json:"source"` + + // Chart configuration for HelmRelease + // +required + Chart CozystackPlatformConfigurationChart `json:"chart"` + + // Values to pass to HelmRelease + // +optional + Values *apiextensionsv1.JSON `json:"values,omitempty"` +} + +// CozystackPlatformConfigurationSource defines the source configuration for GitRepository +// Reuses Flux GitRepositorySpec fields +type CozystackPlatformConfigurationSource struct { + // URL of the Git repository + // +required + URL string `json:"url"` + + // Git repository reference (branch, tag, semver, commit) + // +optional + Ref *sourcev1.GitRepositoryRef `json:"ref,omitempty"` + + // Interval at which to check for updates + // +kubebuilder:default:="1m0s" + Interval metav1.Duration `json:"interval,omitempty"` + + // Timeout for Git operations + // +optional + Timeout *metav1.Duration `json:"timeout,omitempty"` + + // Secret reference containing credentials + // +optional + SecretRef *corev1.LocalObjectReference `json:"secretRef,omitempty"` + + // Ignore overrides the set of patterns for ignoring files and folders + // +optional + Ignore *string `json:"ignore,omitempty"` + + // Include specifies a list of Git sub-paths to include + // +optional + Include []sourcev1.GitRepositoryInclude `json:"include,omitempty"` + + // RecurseSubmodules enables the initialization of all submodules + // +optional + RecurseSubmodules bool `json:"recurseSubmodules,omitempty"` + + // Verification specifies the Git commit signature verification configuration + // +optional + Verification *sourcev1.GitRepositoryVerification `json:"verification,omitempty"` +} + +// CozystackPlatformConfigurationChart defines the chart configuration for HelmRelease +type CozystackPlatformConfigurationChart struct { + // Path to the Helm chart directory in the Git repository + // +required + Path string `json:"path"` + + // Interval at which to reconcile the HelmRelease + // +kubebuilder:default:="5m" + Interval metav1.Duration `json:"interval,omitempty"` +} + diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index f17c527a..4ac77e97 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -21,8 +21,11 @@ limitations under the License. package v1alpha1 import ( + apiv1 "github.com/fluxcd/source-controller/api/v1" + corev1 "k8s.io/api/core/v1" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -209,6 +212,148 @@ func (in *CozystackBundleSpec) DeepCopy() *CozystackBundleSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CozystackPlatformConfiguration) DeepCopyInto(out *CozystackPlatformConfiguration) { + *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 CozystackPlatformConfiguration. +func (in *CozystackPlatformConfiguration) DeepCopy() *CozystackPlatformConfiguration { + if in == nil { + return nil + } + out := new(CozystackPlatformConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CozystackPlatformConfiguration) 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 *CozystackPlatformConfigurationChart) DeepCopyInto(out *CozystackPlatformConfigurationChart) { + *out = *in + out.Interval = in.Interval +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackPlatformConfigurationChart. +func (in *CozystackPlatformConfigurationChart) DeepCopy() *CozystackPlatformConfigurationChart { + if in == nil { + return nil + } + out := new(CozystackPlatformConfigurationChart) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CozystackPlatformConfigurationList) DeepCopyInto(out *CozystackPlatformConfigurationList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CozystackPlatformConfiguration, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackPlatformConfigurationList. +func (in *CozystackPlatformConfigurationList) DeepCopy() *CozystackPlatformConfigurationList { + if in == nil { + return nil + } + out := new(CozystackPlatformConfigurationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CozystackPlatformConfigurationList) 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 *CozystackPlatformConfigurationSource) DeepCopyInto(out *CozystackPlatformConfigurationSource) { + *out = *in + if in.Ref != nil { + in, out := &in.Ref, &out.Ref + *out = new(apiv1.GitRepositoryRef) + **out = **in + } + out.Interval = in.Interval + if in.Timeout != nil { + in, out := &in.Timeout, &out.Timeout + *out = new(metav1.Duration) + **out = **in + } + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(corev1.LocalObjectReference) + **out = **in + } + if in.Ignore != nil { + in, out := &in.Ignore, &out.Ignore + *out = new(string) + **out = **in + } + if in.Include != nil { + in, out := &in.Include, &out.Include + *out = make([]apiv1.GitRepositoryInclude, len(*in)) + copy(*out, *in) + } + if in.Verification != nil { + in, out := &in.Verification, &out.Verification + *out = new(apiv1.GitRepositoryVerification) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackPlatformConfigurationSource. +func (in *CozystackPlatformConfigurationSource) DeepCopy() *CozystackPlatformConfigurationSource { + if in == nil { + return nil + } + out := new(CozystackPlatformConfigurationSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CozystackPlatformConfigurationSpec) DeepCopyInto(out *CozystackPlatformConfigurationSpec) { + *out = *in + in.Source.DeepCopyInto(&out.Source) + out.Chart = in.Chart + 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 CozystackPlatformConfigurationSpec. +func (in *CozystackPlatformConfigurationSpec) DeepCopy() *CozystackPlatformConfigurationSpec { + if in == nil { + return nil + } + out := new(CozystackPlatformConfigurationSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CozystackResourceDefinition) DeepCopyInto(out *CozystackResourceDefinition) { *out = *in diff --git a/cmd/cozystack-operator/main.go b/cmd/cozystack-operator/main.go index ac328fba..f5b8e8a0 100644 --- a/cmd/cozystack-operator/main.go +++ b/cmd/cozystack-operator/main.go @@ -119,6 +119,13 @@ func main() { os.Exit(1) } + // Wait for GitRepository CRD (needed for PlatformConfiguration controller) + // HelmRelease CRD is already waited for in phase 1 + setupLog.Info("Waiting for GitRepository CRD (needed for PlatformConfiguration controller)") + if err := waitForCRDs(ctx, bootstrapClient, "gitrepositories.source.toolkit.fluxcd.io"); err != nil { + setupLog.Error(err, "failed to wait for GitRepository CRD, PlatformConfiguration controller will not be registered") + } + // Now that CRDs are available, we can start the controller manager // The controller manager needs CRDs to be registered in the scheme setupLog.Info("Starting controller manager (CRDs are now available)") @@ -180,6 +187,26 @@ func main() { os.Exit(1) } + // PlatformConfigurationReconciler needs GitRepository and HelmRelease CRDs + // These CRDs are created in phase 1, so we register the controller after phase 1 completes + // Check if CRDs are available (we already waited for them above) + crdCtx, crdCancel := context.WithTimeout(context.Background(), 10*time.Second) + defer crdCancel() + if err := waitForCRDs(crdCtx, bootstrapClient, "gitrepositories.source.toolkit.fluxcd.io", "helmreleases.helm.toolkit.fluxcd.io"); err == nil { + setupLog.Info("GitRepository and HelmRelease CRDs are available, registering PlatformConfiguration controller") + platformConfigurationReconciler := &operator.CozystackPlatformConfigurationReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + } + if err := platformConfigurationReconciler.SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "CozystackPlatformConfiguration") + } else { + setupLog.Info("PlatformConfiguration controller registered successfully") + } + } else { + setupLog.Info("CRDs not yet available, PlatformConfiguration controller will not be registered", "error", err) + } + // +kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 4eddab12..4934777f 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -58,3 +58,5 @@ mv packages/system/cozystack-controller/crds/cozystack.io_cozystackresourcedefin packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml mv packages/system/cozystack-controller/crds/cozystack.io_cozystackbundles.yaml \ packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackbundles.yaml +mv packages/system/cozystack-controller/crds/cozystack.io_cozystackplatformconfigurations.yaml \ + packages/core/installer/templates/cozystack.io_cozystackplatformconfigurations.yaml diff --git a/internal/operator/bootstrap.go b/internal/operator/bootstrap.go new file mode 100644 index 00000000..da5a545c --- /dev/null +++ b/internal/operator/bootstrap.go @@ -0,0 +1,157 @@ +/* +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" + "fmt" + "os/exec" + + 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" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +// FluxIsOK checks if FluxCD is ready and operational +func FluxIsOK(ctx context.Context, c client.Client) (bool, error) { + logger := log.FromContext(ctx) + + // Check source-controller deployment + sourceDeploy := &appsv1.Deployment{} + key := types.NamespacedName{Namespace: "cozy-fluxcd", Name: "source-controller"} + if err := c.Get(ctx, key, sourceDeploy); err != nil { + if apierrors.IsNotFound(err) { + logger.Info("fluxcd check: source-controller deployment not found") + return false, nil + } + return false, err + } + if !isDeploymentAvailable(sourceDeploy) { + logger.Info("fluxcd check: source-controller deployment not available") + return false, nil + } + + // Check helm-controller deployment + helmDeploy := &appsv1.Deployment{} + key = types.NamespacedName{Namespace: "cozy-fluxcd", Name: "helm-controller"} + if err := c.Get(ctx, key, helmDeploy); err != nil { + if apierrors.IsNotFound(err) { + logger.Info("fluxcd check: helm-controller deployment not found") + return false, nil + } + return false, err + } + if !isDeploymentAvailable(helmDeploy) { + logger.Info("fluxcd check: helm-controller deployment not available") + return false, nil + } + + // Check fluxcd helmrelease is ready + hr := &helmv2.HelmRelease{} + key = types.NamespacedName{Namespace: "cozy-fluxcd", Name: "fluxcd"} + if err := c.Get(ctx, key, hr); err != nil { + if apierrors.IsNotFound(err) { + logger.Info("fluxcd check: fluxcd helmrelease not found") + return false, nil + } + return false, err + } + + // Check if ready (this implicitly checks suspend, as suspended HelmRelease cannot be Ready) + if hr.Status.Conditions != nil { + for _, cond := range hr.Status.Conditions { + if cond.Type == "Ready" && cond.Status == metav1.ConditionTrue { + logger.Info("fluxcd check: fluxcd is ready") + return true, nil + } + } + } + + logger.Info("fluxcd check: fluxcd helmrelease not ready") + return false, nil +} + +func isDeploymentAvailable(deploy *appsv1.Deployment) bool { + for _, cond := range deploy.Status.Conditions { + if cond.Type == appsv1.DeploymentAvailable && cond.Status == corev1.ConditionTrue { + return true + } + } + return false +} + +// HasCiliumAndKubeovn checks if any CozystackBundle contains cilium and kubeovn packages +func HasCiliumAndKubeovn(ctx context.Context, c client.Client) (hasCilium, hasKubeovn bool, err error) { + bundleList := &cozyv1alpha1.CozystackBundleList{} + if err := c.List(ctx, bundleList); err != nil { + return false, false, fmt.Errorf("failed to list CozystackBundles: %w", err) + } + + for _, bundle := range bundleList.Items { + for _, pkg := range bundle.Spec.Packages { + if pkg.Name == "cilium" && !pkg.Disabled { + hasCilium = true + } + if pkg.Name == "kubeovn" && !pkg.Disabled { + hasKubeovn = true + } + } + } + + return hasCilium, hasKubeovn, nil +} + +// InstallBasicCharts installs cilium and kubeovn using make commands +func InstallBasicCharts(ctx context.Context, c client.Client) error { + logger := log.FromContext(ctx) + + hasCilium, hasKubeovn, err := HasCiliumAndKubeovn(ctx, c) + if err != nil { + logger.Error(err, "Failed to check bundles for cilium/kubeovn, skipping installation") + return nil // Don't fail, just skip + } + + // Install cilium only if present in bundle + if hasCilium { + logger.Info("Installing cilium using make (found in bundle)") + cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/cilium", "apply", "resume") + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to install cilium: %w", err) + } + } else { + logger.Info("Skipping cilium installation (not found in bundle)") + } + + // Install kubeovn only if present in bundle + if hasKubeovn { + logger.Info("Installing kubeovn using make (found in bundle)") + cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/kubeovn", "apply", "resume") + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to install kubeovn: %w", err) + } + } else { + logger.Info("Skipping kubeovn installation (not found in bundle)") + } + + return nil +} diff --git a/internal/operator/bundle_reconciler.go b/internal/operator/bundle_reconciler.go index c0062fa2..174e0be8 100644 --- a/internal/operator/bundle_reconciler.go +++ b/internal/operator/bundle_reconciler.go @@ -18,8 +18,10 @@ package operator import ( "context" + "errors" "fmt" "strings" + "time" cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" helmv2 "github.com/fluxcd/helm-controller/api/v2" @@ -60,6 +62,13 @@ func (r *CozystackBundleReconciler) Reconcile(ctx context.Context, req ctrl.Requ // Resolve dependencies from other bundles resolvedPackages, err := r.resolveDependencies(ctx, bundle) if err != nil { + // If dependency bundle is not found, requeue to try again later + // Check if the error is wrapped IsNotFound + unwrappedErr := errors.Unwrap(err) + if unwrappedErr != nil && apierrors.IsNotFound(unwrappedErr) { + logger.Info("Dependency bundle not found, requeuing", "bundle", bundle.Name, "error", err) + return ctrl.Result{RequeueAfter: 10 * time.Second}, nil + } logger.Error(err, "failed to resolve dependencies") return ctrl.Result{}, err } @@ -76,6 +85,26 @@ func (r *CozystackBundleReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{}, err } + // Check if we need to run phase2 (install basic charts) + // Phase2 should run when: + // 1. Any bundle contains cilium and kubeovn + // 2. Flux is not ready + hasCilium, hasKubeovn, err := HasCiliumAndKubeovn(ctx, r.Client) + if err != nil { + logger.Error(err, "failed to check bundles for cilium/kubeovn") + } else if hasCilium && hasKubeovn { + fluxOK, err := FluxIsOK(ctx, r.Client) + if err != nil { + logger.Error(err, "failed to check flux status") + } else if !fluxOK { + logger.Info("Bundles contain cilium and kubeovn, and flux is not ready, running phase2") + if err := InstallBasicCharts(ctx, r.Client); err != nil { + logger.Error(err, "failed to install basic charts in phase2") + // Don't return error, just log it - phase2 is best effort + } + } + } + return ctrl.Result{}, nil } @@ -105,6 +134,10 @@ func (r *CozystackBundleReconciler) resolveDependencies(ctx context.Context, bun // Get the bundle depBundle := &cozyv1alpha1.CozystackBundle{} if err := r.Get(ctx, types.NamespacedName{Name: bundleName}, depBundle); err != nil { + // If bundle is not found, return wrapped error so we can check it in Reconcile + if apierrors.IsNotFound(err) { + return nil, fmt.Errorf("failed to get bundle %s: %w", bundleName, err) + } return nil, fmt.Errorf("failed to get bundle %s: %w", bundleName, err) } diff --git a/internal/operator/platform_configuration_reconciler.go b/internal/operator/platform_configuration_reconciler.go new file mode 100644 index 00000000..24eb22cb --- /dev/null +++ b/internal/operator/platform_configuration_reconciler.go @@ -0,0 +1,234 @@ +/* +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" + "fmt" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + helmv2 "github.com/fluxcd/helm-controller/api/v2" + sourcev1 "github.com/fluxcd/source-controller/api/v1" + "github.com/fluxcd/pkg/apis/meta" + 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/client" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +// CozystackPlatformConfigurationReconciler reconciles CozystackPlatformConfiguration resources +type CozystackPlatformConfigurationReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackplatformconfigurations,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackplatformconfigurations/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=gitrepositories,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=helm.toolkit.fluxcd.io,resources=helmreleases,verbs=get;list;watch;create;update;patch;delete + +// Reconcile is part of the main kubernetes reconciliation loop +func (r *CozystackPlatformConfigurationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + + config := &cozyv1alpha1.CozystackPlatformConfiguration{} + if err := r.Get(ctx, req.NamespacedName, config); err != nil { + if apierrors.IsNotFound(err) { + // Resource deleted, cleanup will be handled by ownerReferences + return ctrl.Result{}, nil + } + return ctrl.Result{}, err + } + + // Reconcile GitRepository + if err := r.reconcileGitRepository(ctx, config); err != nil { + logger.Error(err, "failed to reconcile GitRepository") + return ctrl.Result{}, err + } + + // Reconcile HelmRelease + if err := r.reconcileHelmRelease(ctx, config); err != nil { + logger.Error(err, "failed to reconcile HelmRelease") + return ctrl.Result{}, err + } + + logger.Info("successfully reconciled CozystackPlatformConfiguration") + return ctrl.Result{}, nil +} + +// reconcileGitRepository creates or updates the GitRepository resource +func (r *CozystackPlatformConfigurationReconciler) reconcileGitRepository(ctx context.Context, config *cozyv1alpha1.CozystackPlatformConfiguration) error { + logger := log.FromContext(ctx) + + // GitRepository name is the same as the configuration name + gitRepoName := config.Name + // GitRepository namespace is cozy-system (hardcoded for platform configuration) + gitRepoNamespace := "cozy-system" + + desiredGitRepo := &sourcev1.GitRepository{ + ObjectMeta: metav1.ObjectMeta{ + Name: gitRepoName, + Namespace: gitRepoNamespace, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: config.APIVersion, + Kind: config.Kind, + Name: config.Name, + UID: config.UID, + Controller: func() *bool { b := true; return &b }(), + }, + }, + }, + Spec: sourcev1.GitRepositorySpec{ + URL: config.Spec.Source.URL, + Interval: config.Spec.Source.Interval, + Timeout: config.Spec.Source.Timeout, + Ignore: config.Spec.Source.Ignore, + Include: config.Spec.Source.Include, + RecurseSubmodules: config.Spec.Source.RecurseSubmodules, + Verification: config.Spec.Source.Verification, + }, + } + + // Set ref if provided + if config.Spec.Source.Ref != nil { + desiredGitRepo.Spec.Reference = config.Spec.Source.Ref + } + + // Set SecretRef if provided (convert from corev1.LocalObjectReference to meta.LocalObjectReference) + if config.Spec.Source.SecretRef != nil { + desiredGitRepo.Spec.SecretRef = &meta.LocalObjectReference{ + Name: config.Spec.Source.SecretRef.Name, + } + } + + if err := r.createOrUpdate(ctx, desiredGitRepo); err != nil { + return fmt.Errorf("failed to create or update GitRepository: %w", err) + } + + logger.Info("reconciled GitRepository", "name", gitRepoName, "namespace", gitRepoNamespace) + return nil +} + +// reconcileHelmRelease creates or updates the HelmRelease resource +func (r *CozystackPlatformConfigurationReconciler) reconcileHelmRelease(ctx context.Context, config *cozyv1alpha1.CozystackPlatformConfiguration) error { + logger := log.FromContext(ctx) + + // HelmRelease name is the same as the configuration name + hrName := config.Name + // HelmRelease namespace is cozy-system (hardcoded for platform configuration) + hrNamespace := "cozy-system" + + // GitRepository name (used in sourceRef) + gitRepoName := config.Name + gitRepoNamespace := "cozy-system" + + desiredHR := &helmv2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: hrName, + Namespace: hrNamespace, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: config.APIVersion, + Kind: config.Kind, + Name: config.Name, + UID: config.UID, + Controller: func() *bool { b := true; return &b }(), + }, + }, + }, + Spec: helmv2.HelmReleaseSpec{ + Interval: config.Spec.Chart.Interval, + ReleaseName: hrName, + TargetNamespace: hrNamespace, + Chart: &helmv2.HelmChartTemplate{ + Spec: helmv2.HelmChartTemplateSpec{ + Chart: config.Spec.Chart.Path, + SourceRef: helmv2.CrossNamespaceObjectReference{ + Kind: "GitRepository", + Name: gitRepoName, + Namespace: gitRepoNamespace, + }, + }, + }, + }, + } + + // Set values if provided + if config.Spec.Values != nil { + desiredHR.Spec.Values = config.Spec.Values + } + + if err := r.createOrUpdate(ctx, desiredHR); err != nil { + return fmt.Errorf("failed to create or update HelmRelease: %w", err) + } + + logger.Info("reconciled HelmRelease", "name", hrName, "namespace", hrNamespace) + return nil +} + +// createOrUpdate creates or updates a Kubernetes resource +func (r *CozystackPlatformConfigurationReconciler) 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()) + + // Owner references are set by the caller and should be preserved/updated + // 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) + + return r.Update(ctx, obj) +} + +// SetupWithManager sets up the controller with the Manager +func (r *CozystackPlatformConfigurationReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&cozyv1alpha1.CozystackPlatformConfiguration{}). + Complete(r) +} + diff --git a/packages/core/installer/templates/bundle-config.yaml b/packages/core/installer/templates/bundle-config.yaml deleted file mode 100644 index 0f04bfc0..00000000 --- a/packages/core/installer/templates/bundle-config.yaml +++ /dev/null @@ -1,33 +0,0 @@ ---- -apiVersion: source.toolkit.fluxcd.io/v1 -kind: GitRepository -metadata: - name: cozystack - namespace: cozy-system -spec: - interval: 1m0s - ref: - branch: refactor-engine - timeout: 60s - url: https://github.com/cozystack/cozystack.git ---- -apiVersion: helm.toolkit.fluxcd.io/v2 -kind: HelmRelease -metadata: - name: cozystack-platform - namespace: cozy-system -spec: - interval: 5m - targetNamespace: cozy-system - chart: - spec: - chart: ./packages/core/platform - sourceRef: - kind: GitRepository - name: cozystack - namespace: cozy-system - values: - sourceRef: - kind: GitRepository - name: cozystack - namespace: cozy-system diff --git a/packages/core/installer/templates/cozystack.io_cozystackplatformconfigurations.yaml b/packages/core/installer/templates/cozystack.io_cozystackplatformconfigurations.yaml new file mode 100644 index 00000000..a9869f7b --- /dev/null +++ b/packages/core/installer/templates/cozystack.io_cozystackplatformconfigurations.yaml @@ -0,0 +1,197 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: cozystackplatformconfigurations.cozystack.io +spec: + group: cozystack.io + names: + kind: CozystackPlatformConfiguration + listKind: CozystackPlatformConfigurationList + plural: cozystackplatformconfigurations + singular: cozystackplatformconfiguration + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: CozystackPlatformConfiguration is the Schema for the cozystackplatformconfigurations + API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: CozystackPlatformConfigurationSpec defines the desired state + of CozystackPlatformConfiguration + properties: + chart: + description: Chart configuration for HelmRelease + properties: + interval: + default: 5m + description: Interval at which to reconcile the HelmRelease + type: string + path: + description: Path to the Helm chart directory in the Git repository + type: string + required: + - path + type: object + source: + description: Source configuration for GitRepository + properties: + ignore: + description: Ignore overrides the set of patterns for ignoring + files and folders + type: string + include: + description: Include specifies a list of Git sub-paths to include + items: + description: |- + GitRepositoryInclude specifies a local reference to a GitRepository which + Artifact (sub-)contents must be included, and where they should be placed. + properties: + fromPath: + description: |- + FromPath specifies the path to copy contents from, defaults to the root + of the Artifact. + type: string + repository: + description: |- + GitRepositoryRef specifies the GitRepository which Artifact contents + must be included. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + toPath: + description: |- + ToPath specifies the path to copy contents to, defaults to the name of + the GitRepositoryRef. + type: string + required: + - repository + type: object + type: array + interval: + default: 1m0s + description: Interval at which to check for updates + type: string + recurseSubmodules: + description: RecurseSubmodules enables the initialization of all + submodules + type: boolean + ref: + description: Git repository reference (branch, tag, semver, commit) + properties: + branch: + description: Branch to check out, defaults to 'master' if + no other field is defined. + type: string + commit: + description: |- + Commit SHA to check out, takes precedence over all reference fields. + + This can be combined with Branch to shallow clone the branch, in which + the commit is expected to exist. + type: string + name: + description: |- + Name of the reference to check out; takes precedence over Branch, Tag and SemVer. + + It must be a valid Git reference: https://git-scm.com/docs/git-check-ref-format#_description + Examples: "refs/heads/main", "refs/tags/v0.1.0", "refs/pull/420/head", "refs/merge-requests/1/head" + type: string + semver: + description: SemVer tag expression to check out, takes precedence + over Tag. + type: string + tag: + description: Tag to check out, takes precedence over Branch. + type: string + type: object + secretRef: + description: Secret reference containing credentials + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + timeout: + description: Timeout for Git operations + type: string + url: + description: URL of the Git repository + type: string + verification: + description: Verification specifies the Git commit signature verification + configuration + properties: + mode: + default: HEAD + description: |- + Mode specifies which Git object(s) should be verified. + + The variants "head" and "HEAD" both imply the same thing, i.e. verify + the commit that the HEAD of the Git repository points to. The variant + "head" solely exists to ensure backwards compatibility. + enum: + - head + - HEAD + - Tag + - TagAndHEAD + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing the public keys of trusted Git + authors. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - secretRef + type: object + required: + - url + type: object + values: + description: Values to pass to HelmRelease + x-kubernetes-preserve-unknown-fields: true + required: + - chart + - source + type: object + type: object + served: true + storage: true diff --git a/packages/core/installer/templates/platform-config.yaml b/packages/core/installer/templates/platform-config.yaml new file mode 100644 index 00000000..d12c01b6 --- /dev/null +++ b/packages/core/installer/templates/platform-config.yaml @@ -0,0 +1,25 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: CozystackPlatformConfiguration +metadata: + name: cozystack-platform +spec: + # Source configuration for GitRepository + source: + url: https://github.com/cozystack/cozystack.git + ref: + branch: refactor-engine + interval: 1m0s + timeout: 60s + + # Chart configuration for HelmRelease + chart: + path: ./packages/core/platform + interval: 5m + + # Values to pass to HelmRelease + values: + sourceRef: + kind: GitRepository + name: cozystack-platform + namespace: cozy-system diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml index 448b5bf0..113056c7 100644 --- a/packages/core/platform/values.yaml +++ b/packages/core/platform/values.yaml @@ -1,4 +1,4 @@ sourceRef: kind: GitRepository - name: cozystack + name: cozystack-platform namespace: cozy-system From c23826efac030f1eb1bbd1e91902f18e0bf36426 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 20 Nov 2025 04:34:01 +0100 Subject: [PATCH 17/46] separate artifactgeenrators Signed-off-by: Andrei Kvapil --- internal/operator/bundle_reconciler.go | 125 ++++++++++++++----------- packages/core/installer/values.yaml | 2 +- 2 files changed, 70 insertions(+), 57 deletions(-) diff --git a/internal/operator/bundle_reconciler.go b/internal/operator/bundle_reconciler.go index 174e0be8..530a94a3 100644 --- a/internal/operator/bundle_reconciler.go +++ b/internal/operator/bundle_reconciler.go @@ -177,80 +177,70 @@ func (r *CozystackBundleReconciler) resolveDependencies(ctx context.Context, bun } // reconcileArtifactGenerators generates ArtifactGenerators from bundle packages +// Creates a separate ArtifactGenerator for each package func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle, packages []cozyv1alpha1.BundleRelease) error { logger := log.FromContext(ctx) - // Group packages by prefix (system, apps, extra) - packageGroups := make(map[string][]cozyv1alpha1.BundleRelease) libraryMap := make(map[string]cozyv1alpha1.BundleLibrary) for _, lib := range bundle.Spec.Libraries { libraryMap[lib.Name] = lib } + // Create ArtifactGenerator for each package for _, pkg := range packages { - // Determine prefix from path + // Determine prefix and namespace from path prefix := r.getPackagePrefix(pkg.Path) if prefix == "" { logger.Info("skipping package with unknown prefix", "name", pkg.Name, "path", pkg.Path) continue } - packageGroups[prefix] = append(packageGroups[prefix], pkg) - } - - // Create ArtifactGenerator for each group - for prefix, pkgs := range packageGroups { namespace := r.getNamespaceForPrefix(prefix) - agName := fmt.Sprintf("%s-%s", bundle.Name, prefix) + // ArtifactGenerator name: bundle-name-package-name + agName := fmt.Sprintf("%s-%s", bundle.Name, pkg.Name) - // Build output artifacts - outputArtifacts := []sourcewatcherv1beta1.OutputArtifact{} - for _, pkg := range pkgs { - // Extract package name from path (last component) - pkgName := r.getPackageNameFromPath(pkg.Path) - if pkgName == "" { - logger.Info("skipping package with invalid path", "name", pkg.Name, "path", pkg.Path) - continue - } + // Extract package name from path (last component) + pkgName := r.getPackageNameFromPath(pkg.Path) + if pkgName == "" { + logger.Info("skipping package with invalid path", "name", pkg.Name, "path", pkg.Path) + continue + } - copyOps := []sourcewatcherv1beta1.CopyOperation{ - { - From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, pkg.Path), - To: fmt.Sprintf("@artifact/%s/", pkgName), - }, - } + // Build copy operations + copyOps := []sourcewatcherv1beta1.CopyOperation{ + { + From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, pkg.Path), + To: fmt.Sprintf("@artifact/%s/", pkgName), + }, + } - // Add libraries if specified - for _, libName := range pkg.Libraries { - if lib, ok := libraryMap[libName]; ok { - copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ - From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, lib.Path), - To: fmt.Sprintf("@artifact/%s/charts/%s/", pkgName, libName), - }) - } - } - - // Add valuesFiles if specified - for i, valuesFile := range pkg.ValuesFiles { - strategy := "Merge" - if i == 0 { - strategy = "Overwrite" - } + // Add libraries if specified + for _, libName := range pkg.Libraries { + if lib, ok := libraryMap[libName]; ok { copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ - From: fmt.Sprintf("@%s/%s/%s", bundle.Spec.SourceRef.Name, pkg.Path, valuesFile), - To: fmt.Sprintf("@artifact/%s/values.yaml", pkgName), - Strategy: strategy, + From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, lib.Path), + To: fmt.Sprintf("@artifact/%s/charts/%s/", pkgName, libName), }) } + } - artifactName := fmt.Sprintf("%s-%s", prefix, pkgName) - outputArtifacts = append(outputArtifacts, sourcewatcherv1beta1.OutputArtifact{ - Name: artifactName, - Copy: copyOps, + // Add valuesFiles if specified + for i, valuesFile := range pkg.ValuesFiles { + strategy := "Merge" + if i == 0 { + strategy = "Overwrite" + } + copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ + From: fmt.Sprintf("@%s/%s/%s", bundle.Spec.SourceRef.Name, pkg.Path, valuesFile), + To: fmt.Sprintf("@artifact/%s/values.yaml", pkgName), + Strategy: strategy, }) } - // Create ArtifactGenerator + // Artifact name: prefix-package-name (e.g., system-cilium) + artifactName := fmt.Sprintf("%s-%s", prefix, pkgName) + + // Create ArtifactGenerator for this package ag := &sourcewatcherv1beta1.ArtifactGenerator{ ObjectMeta: metav1.ObjectMeta{ Name: agName, @@ -274,14 +264,19 @@ func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Cont Namespace: bundle.Spec.SourceRef.Namespace, }, }, - OutputArtifacts: outputArtifacts, + OutputArtifacts: []sourcewatcherv1beta1.OutputArtifact{ + { + Name: artifactName, + Copy: copyOps, + }, + }, }, } if err := r.createOrUpdate(ctx, ag); err != nil { return fmt.Errorf("failed to reconcile ArtifactGenerator %s: %w", agName, err) } - logger.Info("reconciled ArtifactGenerator", "name", agName, "namespace", namespace) + logger.Info("reconciled ArtifactGenerator", "name", agName, "namespace", namespace, "package", pkg.Name) } // Cleanup orphaned ArtifactGenerators @@ -292,12 +287,30 @@ func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Cont func (r *CozystackBundleReconciler) reconcileHelmReleases(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle, packages []cozyv1alpha1.BundleRelease) error { logger := log.FromContext(ctx) - // Build package name map for dependency resolution + // Build package name map for dependency resolution (from current bundle) packageNameMap := make(map[string]cozyv1alpha1.BundleRelease) for _, pkg := range packages { packageNameMap[pkg.Name] = pkg } + // Build global package name map from all bundles for finding dependencies + globalPackageMap := make(map[string]cozyv1alpha1.BundleRelease) + bundleList := &cozyv1alpha1.CozystackBundleList{} + if err := r.List(ctx, bundleList); err == nil { + for _, b := range bundleList.Items { + for _, pkg := range b.Spec.Packages { + // Only add if not already in map (first occurrence wins, or use current bundle's packages) + if _, exists := globalPackageMap[pkg.Name]; !exists { + globalPackageMap[pkg.Name] = pkg + } + } + } + } + // Override with packages from current bundle (they take precedence) + for _, pkg := range packages { + globalPackageMap[pkg.Name] = pkg + } + // Create HelmRelease for each package for _, pkg := range packages { // Determine artifact name from path @@ -356,9 +369,9 @@ func (r *CozystackBundleReconciler) reconcileHelmReleases(ctx context.Context, b if len(pkg.DependsOn) > 0 { dependsOn := make([]helmv2.DependencyReference, 0, len(pkg.DependsOn)) for _, depName := range pkg.DependsOn { - depPkg, ok := packageNameMap[depName] + depPkg, ok := globalPackageMap[depName] if !ok { - logger.Info("dependent package not found, using same namespace", "name", pkg.Name, "dependsOn", depName) + logger.Info("dependent package not found in any bundle, using same namespace", "name", pkg.Name, "dependsOn", depName) dependsOn = append(dependsOn, helmv2.DependencyReference{ Name: depName, Namespace: pkg.Namespace, @@ -471,10 +484,10 @@ func (r *CozystackBundleReconciler) cleanupOrphanedArtifactGenerators(ctx contex return err } - // Build desired names + // Build desired names: bundle-name-package-name for each package desiredNames := make(map[string]bool) - for prefix := range map[string]bool{"system": true, "apps": true, "extra": true} { - desiredNames[fmt.Sprintf("%s-%s", bundle.Name, prefix)] = true + for _, pkg := range bundle.Spec.Packages { + desiredNames[fmt.Sprintf("%s-%s", bundle.Name, pkg.Name)] = true } // Find ArtifactGenerators owned by this bundle diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index 6696888f..33d5a0ae 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:latest@sha256:2b7c313268ed7e047dd3ae6c7952f90bfca1d45d9dd880847430b4c1339e6a6a + image: ghcr.io/cozystack/cozystack/installer:latest@sha256:c31d55f20aee179eebafec8f07abba1bd01ae7d262b8a574aa6984fb8d63054a From 923dbd209ddef646c6df48744b9368649141253d Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 20 Nov 2025 18:40:31 +0100 Subject: [PATCH 18/46] Fix artifact sources processing Signed-off-by: Andrei Kvapil --- .../cozystackresourcedefinitions_types.go | 19 -- api/v1alpha1/cozystacksystembundles_types.go | 20 ++ api/v1alpha1/zz_generated.deepcopy.go | 52 ++-- cmd/cozystack-controller/main.go | 13 - cmd/cozystack-operator/main.go | 8 - internal/operator/bundle_reconciler.go | 146 ++++++++++- internal/operator/reconciler.go | 2 +- .../operator/resourcedefinition_reconciler.go | 242 ------------------ .../apps/bucket/templates/helmrelease.yaml | 2 +- .../helmreleases/cert-manager-crds.yaml | 2 +- .../templates/helmreleases/cert-manager.yaml | 2 +- .../templates/helmreleases/cilium.yaml | 2 +- .../templates/helmreleases/coredns.yaml | 2 +- .../templates/helmreleases/csi.yaml | 2 +- .../templates/helmreleases/fluxcd.yaml | 4 +- .../helmreleases/gateway-api-crds.yaml | 2 +- .../templates/helmreleases/gpu-operator.yaml | 2 +- .../templates/helmreleases/ingress-nginx.yaml | 2 +- .../helmreleases/monitoring-agents.yaml | 2 +- .../templates/helmreleases/velero.yaml | 2 +- .../vertical-pod-autoscaler-crds.yaml | 2 +- .../helmreleases/vertical-pod-autoscaler.yaml | 2 +- .../victoria-metrics-operator.yaml | 2 +- .../helmreleases/volumesnapshot_crd.yaml | 2 +- packages/apps/nats/templates/nats.yaml | 2 +- packages/apps/tenant/templates/etcd.yaml | 2 +- packages/apps/tenant/templates/info.yaml | 2 +- packages/apps/tenant/templates/ingress.yaml | 2 +- .../apps/tenant/templates/monitoring.yaml | 2 +- packages/apps/tenant/templates/seaweedfs.yaml | 2 +- packages/core/installer/values.yaml | 2 +- .../core/platform/bundles/iaas/bundle.yaml | 60 +++++ .../platform/bundles/iaas/cozyrds/bucket.yaml | 7 +- .../bundles/iaas/cozyrds/kubernetes.yaml | 7 +- .../bundles/iaas/cozyrds/virtual-machine.yaml | 7 +- .../iaas/cozyrds/virtualprivatecloud.yaml | 7 +- .../bundles/iaas/cozyrds/vm-disk.yaml | 7 +- .../bundles/iaas/cozyrds/vm-instance.yaml | 7 +- .../core/platform/bundles/naas/bundle.yaml | 13 + .../bundles/naas/cozyrds/http-cache.yaml | 7 +- .../bundles/naas/cozyrds/tcp-balancer.yaml | 7 +- .../platform/bundles/naas/cozyrds/vpn.yaml | 7 +- .../core/platform/bundles/paas/bundle.yaml | 39 +++ .../bundles/paas/cozyrds/clickhouse.yaml | 7 +- .../bundles/paas/cozyrds/ferretdb.yaml | 7 +- .../bundles/paas/cozyrds/foundationdb.yaml | 7 +- .../platform/bundles/paas/cozyrds/kafka.yaml | 7 +- .../platform/bundles/paas/cozyrds/mysql.yaml | 7 +- .../platform/bundles/paas/cozyrds/nats.yaml | 7 +- .../bundles/paas/cozyrds/postgres.yaml | 7 +- .../bundles/paas/cozyrds/rabbitmq.yaml | 7 +- .../platform/bundles/paas/cozyrds/redis.yaml | 7 +- .../platform/bundles/system/bundle-full.yaml | 27 ++ .../bundles/system/bundle-hosted.yaml | 27 ++ .../bundles/system/cozyrds/bootbox.yaml | 7 +- .../platform/bundles/system/cozyrds/etcd.yaml | 7 +- .../platform/bundles/system/cozyrds/info.yaml | 7 +- .../bundles/system/cozyrds/ingress.yaml | 7 +- .../bundles/system/cozyrds/monitoring.yaml | 7 +- .../bundles/system/cozyrds/seaweedfs.yaml | 7 +- .../bundles/system/cozyrds/tenant.yaml | 7 +- packages/extra/bootbox/images/matchbox.tag | 2 +- .../ingress/templates/nginx-ingress.yaml | 4 +- .../extra/seaweedfs/templates/seaweedfs.yaml | 4 +- .../system/bootbox/templates/bootbox.yaml | 4 +- .../cozystack.io_cozystackbundles.yaml | 26 ++ ...stack.io_cozystackresourcedefinitions.yaml | 21 -- .../templates/vpa-for-vpa.yaml | 2 +- 68 files changed, 440 insertions(+), 514 deletions(-) delete mode 100644 internal/operator/resourcedefinition_reconciler.go diff --git a/api/v1alpha1/cozystackresourcedefinitions_types.go b/api/v1alpha1/cozystackresourcedefinitions_types.go index 6ca1008e..6e71512d 100644 --- a/api/v1alpha1/cozystackresourcedefinitions_types.go +++ b/api/v1alpha1/cozystackresourcedefinitions_types.go @@ -44,26 +44,7 @@ func init() { SchemeBuilder.Register(&CozystackResourceDefinition{}, &CozystackResourceDefinitionList{}) } -// CozystackResourceDefinitionSource defines the source configuration for bundle charts -type CozystackResourceDefinitionSource struct { - // BundleName is the name of the bundle that contains this chart - // +required - BundleName string `json:"bundleName"` - - // Path is the path to the directory containing the Helm chart - // +required - Path string `json:"path"` - - // Libraries is a list of library chart names used by this chart - // +optional - Libraries []string `json:"libraries,omitempty"` -} - type CozystackResourceDefinitionSpec struct { - // Source configuration for the bundle chart - // +optional - Source *CozystackResourceDefinitionSource `json:"source,omitempty"` - // Application configuration Application CozystackResourceDefinitionApplication `json:"application"` // Release configuration diff --git a/api/v1alpha1/cozystacksystembundles_types.go b/api/v1alpha1/cozystacksystembundles_types.go index dfb6ab2c..b227c8ae 100644 --- a/api/v1alpha1/cozystacksystembundles_types.go +++ b/api/v1alpha1/cozystacksystembundles_types.go @@ -67,6 +67,11 @@ type CozystackBundleSpec struct { // +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 CozystackResourceDefinitions + // +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"` @@ -96,6 +101,21 @@ type BundleLibrary struct { 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 diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 4ac77e97..02c78d97 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -29,6 +29,26 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *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 @@ -193,6 +213,13 @@ func (in *CozystackBundleSpec) DeepCopyInto(out *CozystackBundleSpec) { *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)) @@ -585,34 +612,9 @@ func (in *CozystackResourceDefinitionResources) DeepCopy() *CozystackResourceDef return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CozystackResourceDefinitionSource) DeepCopyInto(out *CozystackResourceDefinitionSource) { - *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 CozystackResourceDefinitionSource. -func (in *CozystackResourceDefinitionSource) DeepCopy() *CozystackResourceDefinitionSource { - if in == nil { - return nil - } - out := new(CozystackResourceDefinitionSource) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CozystackResourceDefinitionSpec) DeepCopyInto(out *CozystackResourceDefinitionSpec) { *out = *in - if in.Source != nil { - in, out := &in.Source, &out.Source - *out = new(CozystackResourceDefinitionSource) - (*in).DeepCopyInto(*out) - } out.Application = in.Application in.Release.DeepCopyInto(&out.Release) in.Secrets.DeepCopyInto(&out.Secrets) diff --git a/cmd/cozystack-controller/main.go b/cmd/cozystack-controller/main.go index fc18a778..220c4da5 100644 --- a/cmd/cozystack-controller/main.go +++ b/cmd/cozystack-controller/main.go @@ -216,19 +216,6 @@ func main() { 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) - } - dashboardManager := &dashboard.Manager{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), diff --git a/cmd/cozystack-operator/main.go b/cmd/cozystack-operator/main.go index f5b8e8a0..bd3d7b6b 100644 --- a/cmd/cozystack-operator/main.go +++ b/cmd/cozystack-operator/main.go @@ -178,14 +178,6 @@ func main() { os.Exit(1) } - resourceDefinitionReconciler := &operator.CozystackResourceDefinitionReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - } - if err = resourceDefinitionReconciler.SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "CozystackResourceDefinition") - os.Exit(1) - } // PlatformConfigurationReconciler needs GitRepository and HelmRelease CRDs // These CRDs are created in phase 1, so we register the controller after phase 1 completes diff --git a/internal/operator/bundle_reconciler.go b/internal/operator/bundle_reconciler.go index 530a94a3..4db87d90 100644 --- a/internal/operator/bundle_reconciler.go +++ b/internal/operator/bundle_reconciler.go @@ -73,6 +73,12 @@ func (r *CozystackBundleReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{}, err } + // Generate ArtifactGenerators for artifacts + if err := r.reconcileArtifactArtifactGenerators(ctx, bundle); err != nil { + logger.Error(err, "failed to reconcile ArtifactGenerators for artifacts") + return ctrl.Result{}, err + } + // Generate ArtifactGenerators for packages if err := r.reconcileArtifactGenerators(ctx, bundle, resolvedPackages); err != nil { logger.Error(err, "failed to reconcile ArtifactGenerators") @@ -176,6 +182,94 @@ func (r *CozystackBundleReconciler) resolveDependencies(ctx context.Context, bun return resolved, nil } +// reconcileArtifactArtifactGenerators generates ArtifactGenerators from bundle artifacts +func (r *CozystackBundleReconciler) reconcileArtifactArtifactGenerators(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle) error { + logger := log.FromContext(ctx) + + libraryMap := make(map[string]cozyv1alpha1.BundleLibrary) + for _, lib := range bundle.Spec.Libraries { + libraryMap[lib.Name] = lib + } + + // Create ArtifactGenerator for each artifact + for _, artifact := range bundle.Spec.Artifacts { + // Extract artifact name from path (last component) + artifactPathName := r.getPackageNameFromPath(artifact.Path) + if artifactPathName == "" { + logger.Info("skipping artifact with invalid path", "name", artifact.Name, "path", artifact.Path) + continue + } + + // For artifacts: namespace is always cozy-public + namespace := "cozy-public" + // ArtifactGenerator name: bundle-name-artifact-name + agName := fmt.Sprintf("%s-artifact-%s", bundle.Name, artifact.Name) + + // Build copy operations + copyOps := []sourcewatcherv1beta1.CopyOperation{ + { + From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, artifact.Path), + To: fmt.Sprintf("@artifact/%s/", artifactPathName), + }, + } + + // Add libraries if specified + for _, libName := range artifact.Libraries { + if lib, ok := libraryMap[libName]; ok { + copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ + From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, lib.Path), + To: fmt.Sprintf("@artifact/%s/charts/%s/", artifactPathName, libName), + }) + } + } + + // Artifact name: {bundle-name}-{artifact-name} + // Bundle name already contains "cozystack-" prefix, so we just combine bundle name and artifact name + artifactName := fmt.Sprintf("%s-%s", bundle.Name, artifact.Name) + + // Create ArtifactGenerator for this artifact + ag := &sourcewatcherv1beta1.ArtifactGenerator{ + ObjectMeta: metav1.ObjectMeta{ + Name: agName, + Namespace: namespace, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: bundle.APIVersion, + Kind: bundle.Kind, + Name: bundle.Name, + UID: bundle.UID, + Controller: func() *bool { b := true; return &b }(), + }, + }, + }, + Spec: sourcewatcherv1beta1.ArtifactGeneratorSpec{ + Sources: []sourcewatcherv1beta1.SourceReference{ + { + Alias: bundle.Spec.SourceRef.Name, + Kind: bundle.Spec.SourceRef.Kind, + Name: bundle.Spec.SourceRef.Name, + Namespace: bundle.Spec.SourceRef.Namespace, + }, + }, + OutputArtifacts: []sourcewatcherv1beta1.OutputArtifact{ + { + Name: artifactName, + Copy: copyOps, + }, + }, + }, + } + + if err := r.createOrUpdate(ctx, ag); err != nil { + return fmt.Errorf("failed to reconcile ArtifactGenerator for artifact %s: %w", agName, err) + } + logger.Info("reconciled ArtifactGenerator for artifact", "name", agName, "namespace", namespace, "artifact", artifact.Name) + } + + // Cleanup orphaned ArtifactGenerators for artifacts + return r.cleanupOrphanedArtifactArtifactGenerators(ctx, bundle) +} + // reconcileArtifactGenerators generates ArtifactGenerators from bundle packages // Creates a separate ArtifactGenerator for each package func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle, packages []cozyv1alpha1.BundleRelease) error { @@ -188,14 +282,15 @@ func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Cont // Create ArtifactGenerator for each package for _, pkg := range packages { - // Determine prefix and namespace from path + // Determine prefix from path prefix := r.getPackagePrefix(pkg.Path) if prefix == "" { logger.Info("skipping package with unknown prefix", "name", pkg.Name, "path", pkg.Path) continue } - namespace := r.getNamespaceForPrefix(prefix) + // For packages: namespace is always cozy-system + namespace := "cozy-system" // ArtifactGenerator name: bundle-name-package-name agName := fmt.Sprintf("%s-%s", bundle.Name, pkg.Name) @@ -322,7 +417,8 @@ func (r *CozystackBundleReconciler) reconcileHelmReleases(ctx context.Context, b } artifactName := fmt.Sprintf("%s-%s", prefix, pkgName) - artifactNamespace := r.getNamespaceForPrefix(prefix) + // For packages: artifacts are always in cozy-system + artifactNamespace := "cozy-system" // Create HelmRelease hr := &helmv2.HelmRelease{ @@ -514,6 +610,50 @@ func (r *CozystackBundleReconciler) cleanupOrphanedArtifactGenerators(ctx contex return nil } +func (r *CozystackBundleReconciler) cleanupOrphanedArtifactArtifactGenerators(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle) error { + logger := log.FromContext(ctx) + + agList := &sourcewatcherv1beta1.ArtifactGeneratorList{} + if err := r.List(ctx, agList); err != nil { + if apierrors.IsNotFound(err) { + return nil + } + return err + } + + // Build desired names: bundle-name-artifact-name for each artifact + desiredNames := make(map[string]bool) + for _, artifact := range bundle.Spec.Artifacts { + desiredNames[fmt.Sprintf("%s-artifact-%s", bundle.Name, artifact.Name)] = true + } + + // Find ArtifactGenerators owned by this bundle for artifacts + for _, ag := range agList.Items { + if !strings.HasPrefix(ag.Name, fmt.Sprintf("%s-artifact-", bundle.Name)) { + continue + } + isOwned := false + for _, ownerRef := range ag.OwnerReferences { + if ownerRef.Kind == "CozystackBundle" && ownerRef.Name == bundle.Name && ownerRef.UID == bundle.UID { + isOwned = true + break + } + } + + if isOwned && !desiredNames[ag.Name] { + if err := r.Delete(ctx, &ag); err != nil { + if !apierrors.IsNotFound(err) { + logger.Error(err, "failed to delete ArtifactGenerator for artifact", "name", ag.Name) + } + } else { + logger.Info("deleted orphaned ArtifactGenerator for artifact", "name", ag.Name) + } + } + } + + return nil +} + func (r *CozystackBundleReconciler) cleanupOrphanedHelmReleases(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle) error { logger := log.FromContext(ctx) diff --git a/internal/operator/reconciler.go b/internal/operator/reconciler.go index f3273d22..73ba9e46 100644 --- a/internal/operator/reconciler.go +++ b/internal/operator/reconciler.go @@ -288,7 +288,7 @@ func (r *PlatformReconciler) reconcileTenantRoot(ctx context.Context, cfg *confi ReleaseName: "tenant-root", ChartRef: &helmv2.CrossNamespaceSourceReference{ Kind: "ExternalArtifact", - Name: "apps-tenant", + Name: "cozystack-system-tenant", Namespace: "cozy-public", }, Values: &apiextensionsv1.JSON{ diff --git a/internal/operator/resourcedefinition_reconciler.go b/internal/operator/resourcedefinition_reconciler.go deleted file mode 100644 index 9ede6a73..00000000 --- a/internal/operator/resourcedefinition_reconciler.go +++ /dev/null @@ -1,242 +0,0 @@ -/* -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" - "fmt" - "strings" - - cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" - sourcewatcherv1beta1 "github.com/fluxcd/source-watcher/api/v2/v1beta1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/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/log" -) - -// CozystackResourceDefinitionReconciler reconciles CozystackResourceDefinition resources -type CozystackResourceDefinitionReconciler struct { - client.Client - Scheme *runtime.Scheme -} - -// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackresourcedefinitions,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackresourcedefinitions/status,verbs=get;update;patch -// +kubebuilder:rbac:groups=source.extensions.fluxcd.io,resources=artifactgenerators,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackbundles,verbs=get;list;watch - -// Reconcile is part of the main kubernetes reconciliation loop -func (r *CozystackResourceDefinitionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - logger := log.FromContext(ctx) - - crd := &cozyv1alpha1.CozystackResourceDefinition{} - if err := r.Get(ctx, req.NamespacedName, crd); err != nil { - if apierrors.IsNotFound(err) { - // Cleanup orphaned resources - return r.cleanupOrphanedResources(ctx, req.NamespacedName) - } - return ctrl.Result{}, err - } - - // Only process if source is specified - if crd.Spec.Source == nil { - return ctrl.Result{}, nil - } - - // Get the bundle to get sourceRef - bundle := &cozyv1alpha1.CozystackBundle{} - if err := r.Get(ctx, types.NamespacedName{Name: crd.Spec.Source.BundleName}, bundle); err != nil { - return ctrl.Result{}, fmt.Errorf("failed to get bundle %s: %w", crd.Spec.Source.BundleName, err) - } - - // Generate ArtifactGenerator for this resource definition - if err := r.reconcileArtifactGenerator(ctx, crd, bundle); err != nil { - logger.Error(err, "failed to reconcile ArtifactGenerator") - return ctrl.Result{}, err - } - - return ctrl.Result{}, nil -} - -// reconcileArtifactGenerator generates ArtifactGenerator from CozystackResourceDefinition -func (r *CozystackResourceDefinitionReconciler) reconcileArtifactGenerator(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition, bundle *cozyv1alpha1.CozystackBundle) error { - logger := log.FromContext(ctx) - - // Determine artifact name from path - prefix := r.getPackagePrefix(crd.Spec.Source.Path) - pkgName := r.getPackageNameFromPath(crd.Spec.Source.Path) - if prefix == "" || pkgName == "" { - logger.Info("skipping resource definition with invalid path", "name", crd.Name, "path", crd.Spec.Source.Path) - return nil - } - - artifactName := fmt.Sprintf("%s-%s", prefix, pkgName) - namespace := r.getNamespaceForPrefix(prefix) - - // Build copy operations - copyOps := []sourcewatcherv1beta1.CopyOperation{ - { - From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, crd.Spec.Source.Path), - To: fmt.Sprintf("@artifact/%s/", pkgName), - }, - } - - // Add libraries if specified - libraryMap := make(map[string]cozyv1alpha1.BundleLibrary) - for _, lib := range bundle.Spec.Libraries { - libraryMap[lib.Name] = lib - } - - for _, libName := range crd.Spec.Source.Libraries { - if lib, ok := libraryMap[libName]; ok { - copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ - From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, lib.Path), - To: fmt.Sprintf("@artifact/%s/charts/%s/", pkgName, libName), - }) - } - } - - // Create or get ArtifactGenerator - agName := artifactName - ag := &sourcewatcherv1beta1.ArtifactGenerator{} - key := types.NamespacedName{Name: agName, Namespace: namespace} - - err := r.Get(ctx, key, ag) - if apierrors.IsNotFound(err) { - // Create new ArtifactGenerator - ag = &sourcewatcherv1beta1.ArtifactGenerator{ - ObjectMeta: metav1.ObjectMeta{ - Name: agName, - Namespace: namespace, - }, - Spec: sourcewatcherv1beta1.ArtifactGeneratorSpec{ - Sources: []sourcewatcherv1beta1.SourceReference{ - { - Alias: bundle.Spec.SourceRef.Name, - Kind: bundle.Spec.SourceRef.Kind, - Name: bundle.Spec.SourceRef.Name, - Namespace: bundle.Spec.SourceRef.Namespace, - }, - }, - OutputArtifacts: []sourcewatcherv1beta1.OutputArtifact{ - { - Name: artifactName, - Copy: copyOps, - }, - }, - }, - } - - if err := r.Create(ctx, ag); err != nil { - return fmt.Errorf("failed to create ArtifactGenerator: %w", err) - } - logger.Info("created ArtifactGenerator", "name", agName, "namespace", namespace) - } else if err != nil { - return fmt.Errorf("failed to get ArtifactGenerator: %w", err) - } else { - // Update existing ArtifactGenerator - add this output artifact if not present - found := false - for i, outputArtifact := range ag.Spec.OutputArtifacts { - if outputArtifact.Name == artifactName { - // Update existing artifact - ag.Spec.OutputArtifacts[i].Copy = copyOps - found = true - break - } - } - - if !found { - // Add new output artifact - ag.Spec.OutputArtifacts = append(ag.Spec.OutputArtifacts, sourcewatcherv1beta1.OutputArtifact{ - Name: artifactName, - Copy: copyOps, - }) - } - - // Ensure source reference exists - sourceFound := false - for _, source := range ag.Spec.Sources { - if source.Name == bundle.Spec.SourceRef.Name && source.Namespace == bundle.Spec.SourceRef.Namespace { - sourceFound = true - break - } - } - if !sourceFound { - ag.Spec.Sources = append(ag.Spec.Sources, sourcewatcherv1beta1.SourceReference{ - Alias: bundle.Spec.SourceRef.Name, - Kind: bundle.Spec.SourceRef.Kind, - Name: bundle.Spec.SourceRef.Name, - Namespace: bundle.Spec.SourceRef.Namespace, - }) - } - - if err := r.Update(ctx, ag); err != nil { - return fmt.Errorf("failed to update ArtifactGenerator: %w", err) - } - logger.Info("updated ArtifactGenerator", "name", agName, "namespace", namespace) - } - - return nil -} - -// Helper functions -func (r *CozystackResourceDefinitionReconciler) getPackagePrefix(path string) string { - if strings.HasPrefix(path, "packages/system/") { - return "system" - } - if strings.HasPrefix(path, "packages/apps/") { - return "apps" - } - if strings.HasPrefix(path, "packages/extra/") { - return "extra" - } - return "" -} - -func (r *CozystackResourceDefinitionReconciler) getNamespaceForPrefix(prefix string) string { - if prefix == "system" { - return "cozy-system" - } - return "cozy-public" -} - -func (r *CozystackResourceDefinitionReconciler) getPackageNameFromPath(path string) string { - parts := strings.Split(path, "/") - if len(parts) > 0 { - return parts[len(parts)-1] - } - return "" -} - -func (r *CozystackResourceDefinitionReconciler) cleanupOrphanedResources(ctx context.Context, crdKey types.NamespacedName) (ctrl.Result, error) { - // ArtifactGenerators are shared, so we don't delete them here - // They will be cleaned up when all referencing CRDs are deleted - return ctrl.Result{}, nil -} - -// SetupWithManager sets up the controller with the Manager. -func (r *CozystackResourceDefinitionReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - Named("cozystack-resource-definition"). - For(&cozyv1alpha1.CozystackResourceDefinition{}). - Complete(r) -} - diff --git a/packages/apps/bucket/templates/helmrelease.yaml b/packages/apps/bucket/templates/helmrelease.yaml index 5832f051..0aebdaf7 100644 --- a/packages/apps/bucket/templates/helmrelease.yaml +++ b/packages/apps/bucket/templates/helmrelease.yaml @@ -5,7 +5,7 @@ metadata: spec: chartRef: kind: ExternalArtifact - name: system-bucket + name: cozystack-iaas-bucket namespace: cozy-system interval: 5m timeout: 10m diff --git a/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml b/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml index 3c1ae90d..78fc1a6b 100644 --- a/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml @@ -10,7 +10,7 @@ spec: releaseName: cert-manager-crds chartRef: kind: ExternalArtifact - name: system-cert-manager-crds + name: cozystack-iaas-kubernetes-cert-manager-crds namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml b/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml index b411d2e5..d82eab88 100644 --- a/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml @@ -10,7 +10,7 @@ spec: releaseName: cert-manager chartRef: kind: ExternalArtifact - name: system-cert-manager + name: cozystack-iaas-kubernetes-cert-manager namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/cilium.yaml b/packages/apps/kubernetes/templates/helmreleases/cilium.yaml index 97c93f41..e9ca83d5 100644 --- a/packages/apps/kubernetes/templates/helmreleases/cilium.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/cilium.yaml @@ -24,7 +24,7 @@ spec: releaseName: cilium chartRef: kind: ExternalArtifact - name: system-cilium + name: cozystack-iaas-kubernetes-cilium namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/coredns.yaml b/packages/apps/kubernetes/templates/helmreleases/coredns.yaml index e10dd741..4b5e1334 100644 --- a/packages/apps/kubernetes/templates/helmreleases/coredns.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/coredns.yaml @@ -15,7 +15,7 @@ spec: releaseName: coredns chartRef: kind: ExternalArtifact - name: system-coredns + name: cozystack-iaas-kubernetes-coredns namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/csi.yaml b/packages/apps/kubernetes/templates/helmreleases/csi.yaml index c150800e..d4c58699 100644 --- a/packages/apps/kubernetes/templates/helmreleases/csi.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/csi.yaml @@ -10,7 +10,7 @@ spec: releaseName: csi chartRef: kind: ExternalArtifact - name: system-kubevirt-csi-node + name: cozystack-iaas-kubernetes-kubevirt-csi-node namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml b/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml index 10fc8787..5f179394 100644 --- a/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml @@ -10,7 +10,7 @@ spec: releaseName: fluxcd-operator chartRef: kind: ExternalArtifact - name: system-fluxcd-operator + name: cozystack-iaas-kubernetes-fluxcd-operator namespace: cozy-system kubeConfig: secretRef: @@ -53,7 +53,7 @@ spec: releaseName: fluxcd chartRef: kind: ExternalArtifact - name: system-fluxcd + name: cozystack-iaas-kubernetes-fluxcd namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml b/packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml index 144efd9e..e6c62765 100644 --- a/packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml @@ -10,7 +10,7 @@ spec: releaseName: gateway-api-crds chartRef: kind: ExternalArtifact - name: system-gateway-api-crds + name: cozystack-iaas-kubernetes-gateway-api-crds namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml b/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml index 8811eb8e..9c0df29c 100644 --- a/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml @@ -10,7 +10,7 @@ spec: releaseName: gpu-operator chartRef: kind: ExternalArtifact - name: system-gpu-operator + name: cozystack-iaas-kubernetes-gpu-operator namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml b/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml index 41f75912..17120e8f 100644 --- a/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml @@ -29,7 +29,7 @@ spec: releaseName: ingress-nginx chartRef: kind: ExternalArtifact - name: system-ingress-nginx + name: cozystack-iaas-kubernetes-ingress-nginx namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml b/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml index efce19f0..39c8e4df 100644 --- a/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml @@ -12,7 +12,7 @@ spec: releaseName: cozy-monitoring-agents chartRef: kind: ExternalArtifact - name: system-monitoring-agents + name: cozystack-iaas-kubernetes-monitoring-agents namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/velero.yaml b/packages/apps/kubernetes/templates/helmreleases/velero.yaml index 9a72a38a..dd3023f1 100644 --- a/packages/apps/kubernetes/templates/helmreleases/velero.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/velero.yaml @@ -10,7 +10,7 @@ spec: releaseName: velero chartRef: kind: ExternalArtifact - name: system-velero + name: cozystack-iaas-kubernetes-velero namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml index e052d175..543dc693 100644 --- a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml @@ -11,7 +11,7 @@ spec: releaseName: vertical-pod-autoscaler-crds chartRef: kind: ExternalArtifact - name: system-vertical-pod-autoscaler-crds + name: cozystack-iaas-kubernetes-vertical-pod-autoscaler-crds namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml index cb995625..bd4a3f02 100644 --- a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml @@ -38,7 +38,7 @@ spec: releaseName: vertical-pod-autoscaler chartRef: kind: ExternalArtifact - name: system-vertical-pod-autoscaler + name: cozystack-iaas-kubernetes-vertical-pod-autoscaler namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml b/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml index cd573aa7..367cbdb0 100644 --- a/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml @@ -10,7 +10,7 @@ spec: releaseName: cozy-victoria-metrics-operator chartRef: kind: ExternalArtifact - name: system-victoria-metrics-operator + name: cozystack-iaas-kubernetes-victoria-metrics-operator namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/kubernetes/templates/helmreleases/volumesnapshot_crd.yaml b/packages/apps/kubernetes/templates/helmreleases/volumesnapshot_crd.yaml index a196e913..31062608 100644 --- a/packages/apps/kubernetes/templates/helmreleases/volumesnapshot_crd.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/volumesnapshot_crd.yaml @@ -9,7 +9,7 @@ spec: releaseName: vsnap-crd chartRef: kind: ExternalArtifact - name: system-vsnap-crd + name: cozystack-iaas-kubernetes-volumesnapshot-crd namespace: cozy-system kubeConfig: secretRef: diff --git a/packages/apps/nats/templates/nats.yaml b/packages/apps/nats/templates/nats.yaml index d6cd231e..4a09e3c6 100644 --- a/packages/apps/nats/templates/nats.yaml +++ b/packages/apps/nats/templates/nats.yaml @@ -37,7 +37,7 @@ metadata: spec: chartRef: kind: ExternalArtifact - name: system-nats + name: cozystack-paas-nats namespace: cozy-system interval: 5m timeout: 10m diff --git a/packages/apps/tenant/templates/etcd.yaml b/packages/apps/tenant/templates/etcd.yaml index c06ff936..e463bb4b 100644 --- a/packages/apps/tenant/templates/etcd.yaml +++ b/packages/apps/tenant/templates/etcd.yaml @@ -12,7 +12,7 @@ metadata: spec: chartRef: kind: ExternalArtifact - name: extra-etcd + name: cozystack-system-etcd namespace: cozy-public interval: 5m timeout: 10m diff --git a/packages/apps/tenant/templates/info.yaml b/packages/apps/tenant/templates/info.yaml index 6b505de0..b7b0a002 100644 --- a/packages/apps/tenant/templates/info.yaml +++ b/packages/apps/tenant/templates/info.yaml @@ -11,7 +11,7 @@ metadata: spec: chartRef: kind: ExternalArtifact - name: extra-info + name: cozystack-system-info namespace: cozy-public interval: 5m timeout: 10m diff --git a/packages/apps/tenant/templates/ingress.yaml b/packages/apps/tenant/templates/ingress.yaml index f82a393a..06804903 100644 --- a/packages/apps/tenant/templates/ingress.yaml +++ b/packages/apps/tenant/templates/ingress.yaml @@ -12,7 +12,7 @@ metadata: spec: chartRef: kind: ExternalArtifact - name: extra-ingress + name: cozystack-system-ingress namespace: cozy-public interval: 5m timeout: 10m diff --git a/packages/apps/tenant/templates/monitoring.yaml b/packages/apps/tenant/templates/monitoring.yaml index 64d4e0bc..f36a3078 100644 --- a/packages/apps/tenant/templates/monitoring.yaml +++ b/packages/apps/tenant/templates/monitoring.yaml @@ -12,7 +12,7 @@ metadata: spec: chartRef: kind: ExternalArtifact - name: extra-monitoring + name: cozystack-system-monitoring namespace: cozy-public interval: 5m timeout: 10m diff --git a/packages/apps/tenant/templates/seaweedfs.yaml b/packages/apps/tenant/templates/seaweedfs.yaml index 20792845..693e6abe 100644 --- a/packages/apps/tenant/templates/seaweedfs.yaml +++ b/packages/apps/tenant/templates/seaweedfs.yaml @@ -12,7 +12,7 @@ metadata: spec: chartRef: kind: ExternalArtifact - name: extra-seaweedfs + name: cozystack-system-seaweedfs namespace: cozy-public interval: 5m timeout: 10m diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index 33d5a0ae..d6f9d392 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:latest@sha256:c31d55f20aee179eebafec8f07abba1bd01ae7d262b8a574aa6984fb8d63054a + image: ghcr.io/cozystack/cozystack/installer:latest@sha256:8cc66287f58ea175d7fa5601f4edee6a86454b133322f6b168d6fce801679986 diff --git a/packages/core/platform/bundles/iaas/bundle.yaml b/packages/core/platform/bundles/iaas/bundle.yaml index 4c233dec..0aa275f2 100644 --- a/packages/core/platform/bundles/iaas/bundle.yaml +++ b/packages/core/platform/bundles/iaas/bundle.yaml @@ -26,6 +26,66 @@ spec: - name: cozy-lib path: packages/library/cozy-lib + artifacts: + - name: bucket + path: packages/apps/bucket + libraries: [cozy-lib] + - name: bucket-system + path: packages/apps/bucket + libraries: [cozy-lib] + + - name: kubernetes + path: packages/apps/kubernetes + libraries: [cozy-lib] + - name: kubernetes-ingress-nginx + path: packages/system/ingress-nginx + - name: kubernetes-cert-manager-crds + path: packages/system/cert-manager-crds + - name: kubernetes-volumesnapshot-crd + path: packages/system/kubernetes-vsnap-crd + - name: kubernetes-velero + path: packages/system/kubernetes-velero + - name: kubernetes-gateway-api-crds + path: packages/system/kubernetes-gateway-api-crds + - name: kubernetes-victoria-metrics-operator + path: packages/system/victoria-metrics-operator + - name: kubernetes-kubevirt-csi-node + path: packages/system/kubevirt-csi-node + - name: kubernetes-vertical-pod-autoscaler-crds + path: packages/system/vertical-pod-autoscaler-crds + - name: kubernetes-coredns + path: packages/system/coredns + - name: kubernetes-cert-manager + path: packages/system/cert-manager + - name: kubernetes-fluxcd-operator + path: packages/system/fluxcd-operator + - name: kubernetes-fluxcd + path: packages/system/fluxcd + - name: kubernetes-monitoring-agents + path: packages/system/monitoring-agents + - name: kubernetes-cilium + path: packages/system/cilium + - name: kubernetes-gpu-operator + path: packages/system/gpu-operator + - name: kubernetes-vertical-pod-autoscaler + path: packages/system/vertical-pod-autoscaler + + - name: virtual-machine + path: packages/apps/virtual-machine + libraries: [cozy-lib] + + - name: vpc + path: packages/apps/vpc + libraries: [cozy-lib] + + - name: vm-disk + path: packages/apps/vm-disk + libraries: [cozy-lib] + + - name: vm-instance + path: packages/apps/vm-instance + libraries: [cozy-lib] + packages: - name: kubevirt-operator releaseName: kubevirt-operator diff --git a/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml b/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml index a9c38e49..af7f6355 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: bucket spec: - source: - bundleName: cozystack-iaas - path: packages/apps/bucket - libraries: [cozy-lib] - application: kind: Bucket plural: buckets @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: apps-bucket + name: cozystack-iaas-bucket namespace: cozy-public dashboard: singular: Bucket diff --git a/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml b/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml index aa2e7f15..ba9b1554 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: kubernetes spec: - source: - bundleName: cozystack-iaas - path: packages/apps/kubernetes - libraries: [cozy-lib] - application: kind: Kubernetes singular: kubernetes @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: apps-kubernetes + name: cozystack-iaas-kubernetes namespace: cozy-public dashboard: category: IaaS diff --git a/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml b/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml index a537bfeb..a7bafdd7 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: virtual-machine spec: - source: - bundleName: cozystack-iaas - path: packages/apps/virtual-machine - libraries: [cozy-lib] - application: kind: VirtualMachine plural: virtualmachines @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: apps-virtual-machine + name: cozystack-iaas-virtual-machine namespace: cozy-public dashboard: category: IaaS diff --git a/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml b/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml index 49a1eebf..1e488d85 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: virtualprivatecloud spec: - source: - bundleName: cozystack-iaas - path: packages/apps/vpc - libraries: [cozy-lib] - application: kind: VirtualPrivateCloud plural: virtualprivateclouds @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: apps-virtualprivatecloud + name: cozystack-iaas-vpc namespace: cozy-public dashboard: category: IaaS diff --git a/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml b/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml index cd7c25fc..c7099657 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: vm-disk spec: - source: - bundleName: cozystack-iaas - path: packages/apps/vm-disk - libraries: [cozy-lib] - application: kind: VMDisk singular: vmdisk @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: apps-vm-disk + name: cozystack-iaas-vm-disk namespace: cozy-public dashboard: category: IaaS diff --git a/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml b/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml index c609aa6c..00fdcfd3 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: vm-instance spec: - source: - bundleName: cozystack-iaas - path: packages/apps/vm-instance - libraries: [cozy-lib] - application: kind: VMInstance singular: vminstance @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: apps-vm-instance + name: cozystack-iaas-vm-instance namespace: cozy-public dashboard: category: IaaS diff --git a/packages/core/platform/bundles/naas/bundle.yaml b/packages/core/platform/bundles/naas/bundle.yaml index c9a55e6d..84550e17 100644 --- a/packages/core/platform/bundles/naas/bundle.yaml +++ b/packages/core/platform/bundles/naas/bundle.yaml @@ -14,4 +14,17 @@ spec: - name: cozy-lib path: packages/library/cozy-lib + artifacts: + - name: http-cache + path: packages/apps/http-cache + libraries: [cozy-lib] + + - name: tcp-balancer + path: packages/apps/tcp-balancer + libraries: [cozy-lib] + + - name: vpn + path: packages/apps/vpn + libraries: [cozy-lib] + packages: [] diff --git a/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml b/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml index 75ec6cea..423c5fef 100644 --- a/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml +++ b/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: http-cache spec: - source: - bundleName: cozystack-naas - path: packages/apps/http-cache - libraries: [cozy-lib] - application: kind: HTTPCache plural: httpcaches @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: apps-http-cache + name: cozystack-naas-http-cache namespace: cozy-public dashboard: category: NaaS diff --git a/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml b/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml index 8c755dd3..cf2bf24f 100644 --- a/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml +++ b/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: tcp-balancer spec: - source: - bundleName: cozystack-naas - path: packages/apps/tcp-balancer - libraries: [cozy-lib] - application: kind: TCPBalancer plural: tcpbalancers @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: apps-tcp-balancer + name: cozystack-naas-tcp-balancer namespace: cozy-public dashboard: category: NaaS diff --git a/packages/core/platform/bundles/naas/cozyrds/vpn.yaml b/packages/core/platform/bundles/naas/cozyrds/vpn.yaml index b095f281..268364e7 100644 --- a/packages/core/platform/bundles/naas/cozyrds/vpn.yaml +++ b/packages/core/platform/bundles/naas/cozyrds/vpn.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: vpn spec: - source: - bundleName: cozystack-naas - path: packages/apps/vpn - libraries: [cozy-lib] - application: kind: VPN plural: vpns @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: apps-vpn + name: cozystack-naas-vpn namespace: cozy-public dashboard: category: NaaS diff --git a/packages/core/platform/bundles/paas/bundle.yaml b/packages/core/platform/bundles/paas/bundle.yaml index dd3cefd3..3fac2506 100644 --- a/packages/core/platform/bundles/paas/bundle.yaml +++ b/packages/core/platform/bundles/paas/bundle.yaml @@ -27,6 +27,45 @@ spec: - name: cozy-lib path: packages/library/cozy-lib + artifacts: + - name: clickhouse + path: packages/apps/clickhouse + libraries: [cozy-lib] + + - name: ferretdb + path: packages/apps/ferretdb + libraries: [cozy-lib] + + - name: foundationdb + path: packages/apps/foundationdb + libraries: [cozy-lib] + + - name: kafka + path: packages/apps/kafka + libraries: [cozy-lib] + + - name: mysql + path: packages/apps/mysql + libraries: [cozy-lib] + + - name: nats + path: packages/apps/nats + libraries: [cozy-lib] + - name: nats-system + path: packages/system/nats + + - name: postgres + path: packages/apps/postgres + libraries: [cozy-lib] + + - name: rabbitmq + path: packages/apps/rabbitmq + libraries: [cozy-lib] + + - name: redis + path: packages/apps/redis + libraries: [cozy-lib] + packages: - name: mariadb-operator releaseName: mariadb-operator diff --git a/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml b/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml index b912d58e..dc93b3bf 100644 --- a/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: clickhouse spec: - source: - bundleName: cozystack-paas - path: packages/apps/clickhouse - libraries: [cozy-lib] - application: kind: ClickHouse singular: clickhouse @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: apps-clickhouse + name: cozystack-paas-clickhouse namespace: cozy-public dashboard: category: PaaS diff --git a/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml b/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml index 6ce828f7..9e9fb07f 100644 --- a/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: ferretdb spec: - source: - bundleName: cozystack-paas - path: packages/apps/ferretdb - libraries: [cozy-lib] - application: kind: FerretDB plural: ferretdbs @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: apps-ferretdb + name: cozystack-paas-ferretdb namespace: cozy-public dashboard: category: PaaS diff --git a/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml b/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml index 7e1aa13e..21e42287 100644 --- a/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: foundationdb spec: - source: - bundleName: cozystack-paas - path: packages/apps/foundationdb - libraries: [cozy-lib] - application: kind: FoundationDB singular: foundationdb @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: apps-foundationdb + name: cozystack-paas-foundationdb namespace: cozy-public dashboard: category: PaaS diff --git a/packages/core/platform/bundles/paas/cozyrds/kafka.yaml b/packages/core/platform/bundles/paas/cozyrds/kafka.yaml index e8826516..f9efe311 100644 --- a/packages/core/platform/bundles/paas/cozyrds/kafka.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/kafka.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: kafka spec: - source: - bundleName: cozystack-paas - path: packages/apps/kafka - libraries: [cozy-lib] - application: kind: Kafka plural: kafkas @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: apps-kafka + name: cozystack-paas-kafka namespace: cozy-public dashboard: category: PaaS diff --git a/packages/core/platform/bundles/paas/cozyrds/mysql.yaml b/packages/core/platform/bundles/paas/cozyrds/mysql.yaml index aa693d7a..1d4c1957 100644 --- a/packages/core/platform/bundles/paas/cozyrds/mysql.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/mysql.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: mysql spec: - source: - bundleName: cozystack-paas - path: packages/apps/mysql - libraries: [cozy-lib] - application: kind: MySQL plural: mysqls @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: apps-mysql + name: cozystack-paas-mysql namespace: cozy-public dashboard: category: PaaS diff --git a/packages/core/platform/bundles/paas/cozyrds/nats.yaml b/packages/core/platform/bundles/paas/cozyrds/nats.yaml index 563226c2..8ddaf563 100644 --- a/packages/core/platform/bundles/paas/cozyrds/nats.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/nats.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: nats spec: - source: - bundleName: cozystack-paas - path: packages/apps/nats - libraries: [cozy-lib] - application: kind: NATS plural: natses @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: apps-nats + name: cozystack-paas-nats namespace: cozy-public dashboard: category: PaaS diff --git a/packages/core/platform/bundles/paas/cozyrds/postgres.yaml b/packages/core/platform/bundles/paas/cozyrds/postgres.yaml index ba403b3f..d0a33201 100644 --- a/packages/core/platform/bundles/paas/cozyrds/postgres.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/postgres.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: postgres spec: - source: - bundleName: cozystack-paas - path: packages/apps/postgres - libraries: [cozy-lib] - application: kind: Postgres singular: postgres @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: apps-postgres + name: cozystack-paas-postgres namespace: cozy-public dashboard: category: PaaS diff --git a/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml b/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml index daa684fb..9779c895 100644 --- a/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: rabbitmq spec: - source: - bundleName: cozystack-paas - path: packages/apps/rabbitmq - libraries: [cozy-lib] - application: kind: RabbitMQ plural: rabbitmqs @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: apps-rabbitmq + name: cozystack-paas-rabbitmq namespace: cozy-public dashboard: category: PaaS diff --git a/packages/core/platform/bundles/paas/cozyrds/redis.yaml b/packages/core/platform/bundles/paas/cozyrds/redis.yaml index f9c8c6a3..9f78bd6f 100644 --- a/packages/core/platform/bundles/paas/cozyrds/redis.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/redis.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: redis spec: - source: - bundleName: cozystack-paas - path: packages/apps/redis - libraries: [cozy-lib] - application: kind: Redis plural: redises @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: apps-redis + name: cozystack-paas-redis namespace: cozy-public dashboard: category: PaaS diff --git a/packages/core/platform/bundles/system/bundle-full.yaml b/packages/core/platform/bundles/system/bundle-full.yaml index 65e71be5..84a46fe0 100644 --- a/packages/core/platform/bundles/system/bundle-full.yaml +++ b/packages/core/platform/bundles/system/bundle-full.yaml @@ -31,6 +31,33 @@ spec: - name: cozy-lib path: packages/library/cozy-lib + artifacts: + - name: tenant + path: packages/apps/tenant + libraries: [cozy-lib] + - name: bootbox + path: packages/extra/bootbox + libraries: [cozy-lib] + - name: etcd + path: packages/extra/etcd + libraries: [cozy-lib] + - name: ingress + path: packages/extra/ingress + libraries: [cozy-lib] + - name: ingress-system + path: packages/system/ingress + - name: seaweedfs + path: packages/extra/seaweedfs + libraries: [cozy-lib] + - name: seaweedfs-system + path: packages/system/seaweedfs + - name: info + path: packages/extra/info + libraries: [cozy-lib] + - name: monitoring + path: packages/extra/monitoring + libraries: [cozy-lib] + packages: - name: fluxcd-operator releaseName: fluxcd-operator diff --git a/packages/core/platform/bundles/system/bundle-hosted.yaml b/packages/core/platform/bundles/system/bundle-hosted.yaml index e0dd169a..eaad8de2 100644 --- a/packages/core/platform/bundles/system/bundle-hosted.yaml +++ b/packages/core/platform/bundles/system/bundle-hosted.yaml @@ -31,6 +31,33 @@ spec: - name: cozy-lib path: packages/library/cozy-lib + artifacts: + - name: tenant + path: packages/apps/tenant + libraries: [cozy-lib] + - name: bootbox + path: packages/extra/bootbox + libraries: [cozy-lib] + - name: etcd + path: packages/extra/etcd + libraries: [cozy-lib] + - name: ingress + path: packages/extra/ingress + libraries: [cozy-lib] + - name: ingress-system + path: packages/system/ingress + - name: seaweedfs + path: packages/extra/seaweedfs + libraries: [cozy-lib] + - name: seaweedfs-system + path: packages/system/seaweedfs + - name: info + path: packages/extra/info + libraries: [cozy-lib] + - name: monitoring + path: packages/extra/monitoring + libraries: [cozy-lib] + packages: - name: fluxcd-operator releaseName: fluxcd-operator diff --git a/packages/core/platform/bundles/system/cozyrds/bootbox.yaml b/packages/core/platform/bundles/system/cozyrds/bootbox.yaml index 874b1d24..3a593162 100644 --- a/packages/core/platform/bundles/system/cozyrds/bootbox.yaml +++ b/packages/core/platform/bundles/system/cozyrds/bootbox.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: bootbox spec: - source: - bundleName: cozystack-system - path: packages/extra/bootbox - libraries: [cozy-lib] - application: kind: BootBox plural: bootboxes @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: extra-bootbox + name: cozystack-system-bootbox namespace: cozy-public dashboard: category: Administration diff --git a/packages/core/platform/bundles/system/cozyrds/etcd.yaml b/packages/core/platform/bundles/system/cozyrds/etcd.yaml index 0a79be43..6381f6da 100644 --- a/packages/core/platform/bundles/system/cozyrds/etcd.yaml +++ b/packages/core/platform/bundles/system/cozyrds/etcd.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: etcd spec: - source: - bundleName: cozystack-system - path: packages/extra/etcd - libraries: [cozy-lib] - application: kind: Etcd plural: etcds @@ -22,7 +17,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: extra-etcd + name: cozystack-system-etcd namespace: cozy-public dashboard: category: Administration diff --git a/packages/core/platform/bundles/system/cozyrds/info.yaml b/packages/core/platform/bundles/system/cozyrds/info.yaml index 00904992..fed8d965 100644 --- a/packages/core/platform/bundles/system/cozyrds/info.yaml +++ b/packages/core/platform/bundles/system/cozyrds/info.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: info spec: - source: - bundleName: cozystack-system - path: packages/extra/info - libraries: [cozy-lib] - application: kind: Info plural: infos @@ -22,7 +17,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: extra-info + name: cozystack-system-info namespace: cozy-public dashboard: name: info diff --git a/packages/core/platform/bundles/system/cozyrds/ingress.yaml b/packages/core/platform/bundles/system/cozyrds/ingress.yaml index 1f1e36a6..9f5a22f1 100644 --- a/packages/core/platform/bundles/system/cozyrds/ingress.yaml +++ b/packages/core/platform/bundles/system/cozyrds/ingress.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: ingress spec: - source: - bundleName: cozystack-system - path: packages/extra/ingress - libraries: [cozy-lib] - application: kind: Ingress plural: ingresses @@ -22,7 +17,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: extra-ingress + name: cozystack-system-ingress namespace: cozy-public dashboard: category: Administration diff --git a/packages/core/platform/bundles/system/cozyrds/monitoring.yaml b/packages/core/platform/bundles/system/cozyrds/monitoring.yaml index b9b5ec25..b782cfaf 100644 --- a/packages/core/platform/bundles/system/cozyrds/monitoring.yaml +++ b/packages/core/platform/bundles/system/cozyrds/monitoring.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: monitoring spec: - source: - bundleName: cozystack-system - path: packages/extra/monitoring - libraries: [cozy-lib] - application: kind: Monitoring singular: monitoring @@ -22,7 +17,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: extra-monitoring + name: cozystack-system-monitoring namespace: cozy-public dashboard: category: Administration diff --git a/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml b/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml index f0cf5d0a..4b0bbbcf 100644 --- a/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml +++ b/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: seaweedfs spec: - source: - bundleName: cozystack-system - path: packages/extra/seaweedfs - libraries: [cozy-lib] - application: kind: SeaweedFS singular: seaweedfs @@ -22,7 +17,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: extra-seaweedfs + name: cozystack-system-seaweedfs namespace: cozy-public dashboard: category: Administration diff --git a/packages/core/platform/bundles/system/cozyrds/tenant.yaml b/packages/core/platform/bundles/system/cozyrds/tenant.yaml index aeaafcd0..797ed7be 100644 --- a/packages/core/platform/bundles/system/cozyrds/tenant.yaml +++ b/packages/core/platform/bundles/system/cozyrds/tenant.yaml @@ -3,11 +3,6 @@ kind: CozystackResourceDefinition metadata: name: tenant spec: - source: - bundleName: cozystack-system - path: packages/apps/tenant - libraries: [cozy-lib] - application: kind: Tenant singular: tenant @@ -21,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: apps-tenant + name: cozystack-system-tenant namespace: cozy-public dashboard: category: Administration diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index ee8e7b89..892fb951 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:latest@sha256:73ffee1ba219cc23ba42c9420e0d25fd9ea289f30d26be17224fbafc8f213227 +ghcr.io/cozystack/cozystack/matchbox:latest@sha256:d8664b707611f232fe375de932570f1a17d754a909e9cf999614191eb32e3853 diff --git a/packages/extra/ingress/templates/nginx-ingress.yaml b/packages/extra/ingress/templates/nginx-ingress.yaml index 13a51494..a50516ad 100644 --- a/packages/extra/ingress/templates/nginx-ingress.yaml +++ b/packages/extra/ingress/templates/nginx-ingress.yaml @@ -8,8 +8,8 @@ metadata: spec: chartRef: kind: ExternalArtifact - name: system-ingress-nginx - namespace: cozy-system + name: cozystack-system-ingress-system + namespace: cozy-public interval: 5m timeout: 10m install: diff --git a/packages/extra/seaweedfs/templates/seaweedfs.yaml b/packages/extra/seaweedfs/templates/seaweedfs.yaml index d57d15be..63a8b1b3 100644 --- a/packages/extra/seaweedfs/templates/seaweedfs.yaml +++ b/packages/extra/seaweedfs/templates/seaweedfs.yaml @@ -44,8 +44,8 @@ metadata: spec: chartRef: kind: ExternalArtifact - name: system-seaweedfs - namespace: cozy-system + name: cozystack-system-seaweedfs-system + namespace: cozy-public interval: 5m timeout: 10m install: diff --git a/packages/system/bootbox/templates/bootbox.yaml b/packages/system/bootbox/templates/bootbox.yaml index 496e42e5..9aa8f1ce 100644 --- a/packages/system/bootbox/templates/bootbox.yaml +++ b/packages/system/bootbox/templates/bootbox.yaml @@ -13,8 +13,8 @@ spec: chart: bootbox reconcileStrategy: Revision sourceRef: - kind: HelmRepository - name: cozystack-extra + kind: ExternalArtifact + name: cozystack-system-bootbox namespace: cozy-public version: '>= 0.0.0-0' interval: 1m0s diff --git a/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackbundles.yaml b/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackbundles.yaml index 630bcd48..851ca10f 100644 --- a/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackbundles.yaml +++ b/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackbundles.yaml @@ -39,6 +39,32 @@ spec: spec: description: CozystackBundleSpec defines the desired state of CozystackBundle properties: + artifacts: + description: |- + Artifacts is a list of Helm charts that will be built as ExternalArtifacts + These artifacts can be referenced by CozystackResourceDefinitions + items: + description: BundleArtifact defines a Helm chart artifact that will + be built as ExternalArtifact + properties: + libraries: + description: Libraries is a list of library names that this + artifact depends on + items: + type: string + type: array + name: + description: Name is the unique identifier for this artifact + (used as ExternalArtifact name) + type: string + path: + description: Path is the path to the Helm chart directory + type: string + required: + - name + - path + type: object + type: array dependencyTargets: description: |- DependencyTargets defines named groups of packages that can be referenced diff --git a/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml b/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml index f55cdafc..91cfb7ec 100644 --- a/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml +++ b/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml @@ -700,27 +700,6 @@ spec: x-kubernetes-map-type: atomic type: array type: object - source: - description: Source configuration for the bundle chart - properties: - bundleName: - description: BundleName is the name of the bundle that contains - this chart - type: string - libraries: - description: Libraries is a list of library chart names used by - this chart - items: - type: string - type: array - path: - description: Path is the path to the directory containing the - Helm chart - type: string - required: - - bundleName - - path - type: object required: - application - release diff --git a/packages/system/vertical-pod-autoscaler/templates/vpa-for-vpa.yaml b/packages/system/vertical-pod-autoscaler/templates/vpa-for-vpa.yaml index 02c4cdc9..6db521bc 100644 --- a/packages/system/vertical-pod-autoscaler/templates/vpa-for-vpa.yaml +++ b/packages/system/vertical-pod-autoscaler/templates/vpa-for-vpa.yaml @@ -18,7 +18,7 @@ metadata: spec: chartRef: kind: ExternalArtifact - name: system-vertical-pod-autoscaler + name: cozystack-iaas-vertical-pod-autoscaler namespace: cozy-system dependsOn: - name: monitoring-agents From 6c3a7b7efbc9b29f61ed56ec46b8df5e61af1cfb Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 21 Nov 2025 14:14:39 +0100 Subject: [PATCH 19/46] remove flux from bundles Signed-off-by: Andrei Kvapil --- .../cozystackplatformconfiguration_types.go | 116 - api/v1alpha1/zz_generated.deepcopy.go | 145 - cmd/cozystack-operator/main.go | 865 +- go.mod | 2 +- hack/update-codegen.sh | 2 - internal/fluxinstall/install.go | 231 + internal/fluxinstall/manifests.embed.go | 51 + internal/fluxinstall/manifests/fluxcd.yaml | 11951 ++++++++++++++++ internal/operator/bundle_reconciler.go | 20 - .../platform_configuration_reconciler.go | 234 - packages/core/fluxcd/Chart.yaml | 3 + packages/core/fluxcd/Makefile | 16 + packages/core/fluxcd/flux-aio.cue | 17 + packages/core/fluxcd/manifests | 1 + packages/core/fluxcd/values.yaml | 55 + ...ck.io_cozystackplatformconfigurations.yaml | 197 - .../installer/templates/platform-config.yaml | 25 - .../platform/bundles/system/bundle-full.yaml | 18 - .../bundles/system/bundle-hosted.yaml | 18 - 19 files changed, 12352 insertions(+), 1615 deletions(-) delete mode 100644 api/v1alpha1/cozystackplatformconfiguration_types.go create mode 100644 internal/fluxinstall/install.go create mode 100644 internal/fluxinstall/manifests.embed.go create mode 100644 internal/fluxinstall/manifests/fluxcd.yaml delete mode 100644 internal/operator/platform_configuration_reconciler.go create mode 100644 packages/core/fluxcd/Chart.yaml create mode 100644 packages/core/fluxcd/Makefile create mode 100644 packages/core/fluxcd/flux-aio.cue create mode 120000 packages/core/fluxcd/manifests create mode 100644 packages/core/fluxcd/values.yaml delete mode 100644 packages/core/installer/templates/cozystack.io_cozystackplatformconfigurations.yaml delete mode 100644 packages/core/installer/templates/platform-config.yaml diff --git a/api/v1alpha1/cozystackplatformconfiguration_types.go b/api/v1alpha1/cozystackplatformconfiguration_types.go deleted file mode 100644 index 86f889eb..00000000 --- a/api/v1alpha1/cozystackplatformconfiguration_types.go +++ /dev/null @@ -1,116 +0,0 @@ -/* -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 v1alpha1 - -import ( - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - sourcev1 "github.com/fluxcd/source-controller/api/v1" -) - -// +kubebuilder:object:root=true -// +kubebuilder:resource:scope=Cluster - -// CozystackPlatformConfiguration is the Schema for the cozystackplatformconfigurations API -type CozystackPlatformConfiguration struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec CozystackPlatformConfigurationSpec `json:"spec,omitempty"` -} - -// +kubebuilder:object:root=true - -// CozystackPlatformConfigurationList contains a list of CozystackPlatformConfigurations -type CozystackPlatformConfigurationList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []CozystackPlatformConfiguration `json:"items"` -} - -func init() { - SchemeBuilder.Register(&CozystackPlatformConfiguration{}, &CozystackPlatformConfigurationList{}) -} - -// CozystackPlatformConfigurationSpec defines the desired state of CozystackPlatformConfiguration -type CozystackPlatformConfigurationSpec struct { - // Source configuration for GitRepository - // +required - Source CozystackPlatformConfigurationSource `json:"source"` - - // Chart configuration for HelmRelease - // +required - Chart CozystackPlatformConfigurationChart `json:"chart"` - - // Values to pass to HelmRelease - // +optional - Values *apiextensionsv1.JSON `json:"values,omitempty"` -} - -// CozystackPlatformConfigurationSource defines the source configuration for GitRepository -// Reuses Flux GitRepositorySpec fields -type CozystackPlatformConfigurationSource struct { - // URL of the Git repository - // +required - URL string `json:"url"` - - // Git repository reference (branch, tag, semver, commit) - // +optional - Ref *sourcev1.GitRepositoryRef `json:"ref,omitempty"` - - // Interval at which to check for updates - // +kubebuilder:default:="1m0s" - Interval metav1.Duration `json:"interval,omitempty"` - - // Timeout for Git operations - // +optional - Timeout *metav1.Duration `json:"timeout,omitempty"` - - // Secret reference containing credentials - // +optional - SecretRef *corev1.LocalObjectReference `json:"secretRef,omitempty"` - - // Ignore overrides the set of patterns for ignoring files and folders - // +optional - Ignore *string `json:"ignore,omitempty"` - - // Include specifies a list of Git sub-paths to include - // +optional - Include []sourcev1.GitRepositoryInclude `json:"include,omitempty"` - - // RecurseSubmodules enables the initialization of all submodules - // +optional - RecurseSubmodules bool `json:"recurseSubmodules,omitempty"` - - // Verification specifies the Git commit signature verification configuration - // +optional - Verification *sourcev1.GitRepositoryVerification `json:"verification,omitempty"` -} - -// CozystackPlatformConfigurationChart defines the chart configuration for HelmRelease -type CozystackPlatformConfigurationChart struct { - // Path to the Helm chart directory in the Git repository - // +required - Path string `json:"path"` - - // Interval at which to reconcile the HelmRelease - // +kubebuilder:default:="5m" - Interval metav1.Duration `json:"interval,omitempty"` -} - diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 02c78d97..082922e7 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -21,11 +21,8 @@ limitations under the License. package v1alpha1 import ( - apiv1 "github.com/fluxcd/source-controller/api/v1" - corev1 "k8s.io/api/core/v1" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/api/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -239,148 +236,6 @@ func (in *CozystackBundleSpec) DeepCopy() *CozystackBundleSpec { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CozystackPlatformConfiguration) DeepCopyInto(out *CozystackPlatformConfiguration) { - *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 CozystackPlatformConfiguration. -func (in *CozystackPlatformConfiguration) DeepCopy() *CozystackPlatformConfiguration { - if in == nil { - return nil - } - out := new(CozystackPlatformConfiguration) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *CozystackPlatformConfiguration) 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 *CozystackPlatformConfigurationChart) DeepCopyInto(out *CozystackPlatformConfigurationChart) { - *out = *in - out.Interval = in.Interval -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackPlatformConfigurationChart. -func (in *CozystackPlatformConfigurationChart) DeepCopy() *CozystackPlatformConfigurationChart { - if in == nil { - return nil - } - out := new(CozystackPlatformConfigurationChart) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CozystackPlatformConfigurationList) DeepCopyInto(out *CozystackPlatformConfigurationList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]CozystackPlatformConfiguration, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackPlatformConfigurationList. -func (in *CozystackPlatformConfigurationList) DeepCopy() *CozystackPlatformConfigurationList { - if in == nil { - return nil - } - out := new(CozystackPlatformConfigurationList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *CozystackPlatformConfigurationList) 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 *CozystackPlatformConfigurationSource) DeepCopyInto(out *CozystackPlatformConfigurationSource) { - *out = *in - if in.Ref != nil { - in, out := &in.Ref, &out.Ref - *out = new(apiv1.GitRepositoryRef) - **out = **in - } - out.Interval = in.Interval - if in.Timeout != nil { - in, out := &in.Timeout, &out.Timeout - *out = new(metav1.Duration) - **out = **in - } - if in.SecretRef != nil { - in, out := &in.SecretRef, &out.SecretRef - *out = new(corev1.LocalObjectReference) - **out = **in - } - if in.Ignore != nil { - in, out := &in.Ignore, &out.Ignore - *out = new(string) - **out = **in - } - if in.Include != nil { - in, out := &in.Include, &out.Include - *out = make([]apiv1.GitRepositoryInclude, len(*in)) - copy(*out, *in) - } - if in.Verification != nil { - in, out := &in.Verification, &out.Verification - *out = new(apiv1.GitRepositoryVerification) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackPlatformConfigurationSource. -func (in *CozystackPlatformConfigurationSource) DeepCopy() *CozystackPlatformConfigurationSource { - if in == nil { - return nil - } - out := new(CozystackPlatformConfigurationSource) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CozystackPlatformConfigurationSpec) DeepCopyInto(out *CozystackPlatformConfigurationSpec) { - *out = *in - in.Source.DeepCopyInto(&out.Source) - out.Chart = in.Chart - 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 CozystackPlatformConfigurationSpec. -func (in *CozystackPlatformConfigurationSpec) DeepCopy() *CozystackPlatformConfigurationSpec { - if in == nil { - return nil - } - out := new(CozystackPlatformConfigurationSpec) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CozystackResourceDefinition) DeepCopyInto(out *CozystackResourceDefinition) { *out = *in diff --git a/cmd/cozystack-operator/main.go b/cmd/cozystack-operator/main.go index bd3d7b6b..211cc4b4 100644 --- a/cmd/cozystack-operator/main.go +++ b/cmd/cozystack-operator/main.go @@ -19,12 +19,7 @@ package main import ( "context" "flag" - "fmt" "os" - "os/exec" - "path/filepath" - "sort" - "strconv" "time" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) @@ -35,26 +30,17 @@ import ( 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" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/dynamic" 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/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" // +kubebuilder:scaffold:imports ) @@ -80,6 +66,7 @@ func main() { var probeAddr string var secureMetrics bool var enableHTTP2 bool + var installFlux bool 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.") @@ -90,6 +77,7 @@ func main() { "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") opts := zap.Options{ Development: true, @@ -101,34 +89,8 @@ func main() { config := ctrl.GetConfigOrDie() - // Phase 1: Install fluxcd-operator and fluxcd, wait for CRDs - // This allows controller manager to start (it needs CRDs to be registered) - // Use a direct (non-cached) client for bootstrap since manager cache is not started yet - bootstrapClient, err := client.New(config, client.Options{Scheme: scheme}) - if err != nil { - setupLog.Error(err, "failed to create bootstrap client") - os.Exit(1) - } - - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute) - defer cancel() - - setupLog.Info("Starting bootstrap phase 1: fluxcd installation") - if err := runBootstrapPhase1(ctx, bootstrapClient); err != nil { - setupLog.Error(err, "bootstrap phase 1 failed") - os.Exit(1) - } - - // Wait for GitRepository CRD (needed for PlatformConfiguration controller) - // HelmRelease CRD is already waited for in phase 1 - setupLog.Info("Waiting for GitRepository CRD (needed for PlatformConfiguration controller)") - if err := waitForCRDs(ctx, bootstrapClient, "gitrepositories.source.toolkit.fluxcd.io"); err != nil { - setupLog.Error(err, "failed to wait for GitRepository CRD, PlatformConfiguration controller will not be registered") - } - - // Now that CRDs are available, we can start the controller manager - // The controller manager needs CRDs to be registered in the scheme - setupLog.Info("Starting controller manager (CRDs are now available)") + // Start the controller manager + setupLog.Info("Starting controller manager") mgr, err := ctrl.NewManager(config, ctrl.Options{ Scheme: scheme, Metrics: metricsserver.Options{ @@ -157,12 +119,26 @@ func main() { 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()); 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") + } + } + // Setup PlatformReconciler - firstReconcileDone := make(chan struct{}) platformReconciler := &operator.PlatformReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - FirstReconcileDone: firstReconcileDone, + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), } if err = platformReconciler.SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "Platform") @@ -178,27 +154,6 @@ func main() { os.Exit(1) } - - // PlatformConfigurationReconciler needs GitRepository and HelmRelease CRDs - // These CRDs are created in phase 1, so we register the controller after phase 1 completes - // Check if CRDs are available (we already waited for them above) - crdCtx, crdCancel := context.WithTimeout(context.Background(), 10*time.Second) - defer crdCancel() - if err := waitForCRDs(crdCtx, bootstrapClient, "gitrepositories.source.toolkit.fluxcd.io", "helmreleases.helm.toolkit.fluxcd.io"); err == nil { - setupLog.Info("GitRepository and HelmRelease CRDs are available, registering PlatformConfiguration controller") - platformConfigurationReconciler := &operator.CozystackPlatformConfigurationReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - } - if err := platformConfigurationReconciler.SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "CozystackPlatformConfiguration") - } else { - setupLog.Info("PlatformConfiguration controller registered successfully") - } - } else { - setupLog.Info("CRDs not yet available, PlatformConfiguration controller will not be registered", "error", err) - } - // +kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { @@ -210,778 +165,10 @@ func main() { os.Exit(1) } - // Phase 2: Install basic charts and other components after controller manager is ready - // Start manager in a goroutine so we can proceed with phase 2 + setupLog.Info("Starting controller manager") mgrCtx := ctrl.SetupSignalHandler() - mgrStarted := make(chan struct{}) - go func() { - // Wait a bit for manager to initialize - time.Sleep(2 * time.Second) - close(mgrStarted) - setupLog.Info("starting manager") - if err := mgr.Start(mgrCtx); err != nil { - setupLog.Error(err, "problem running manager") - os.Exit(1) - } - }() - - // Wait for manager to initialize - <-mgrStarted - - // Trigger a reconcile by creating/updating the ConfigMap to ensure first reconcile happens - // This ensures the controller processes the ConfigMap and completes its first reconcile cycle - setupLog.Info("Triggering first reconcile cycle") - reconcileCtx, reconcileCancel := context.WithTimeout(context.Background(), 5*time.Minute) - defer reconcileCancel() - - // Get the ConfigMap to trigger reconcile - cm := &corev1.ConfigMap{} - cmKey := types.NamespacedName{Namespace: "cozy-system", Name: "cozystack"} - if err := bootstrapClient.Get(reconcileCtx, cmKey, cm); err == nil { - // ConfigMap exists, update it to trigger reconcile - cm.Labels = map[string]string{} - cm.Labels["cozystack.io/reconcile-trigger"] = strconv.FormatInt(time.Now().Unix(), 10) - if err := bootstrapClient.Update(reconcileCtx, cm); err != nil { - setupLog.Info("Failed to trigger reconcile via ConfigMap update, continuing anyway", "error", err) - } - } else if apierrors.IsNotFound(err) { - // ConfigMap doesn't exist yet, create it to trigger reconcile - cm.ObjectMeta = metav1.ObjectMeta{ - Name: "cozystack", - Namespace: "cozy-system", - Labels: map[string]string{ - "cozystack.io/reconcile-trigger": strconv.FormatInt(time.Now().Unix(), 10), - }, - } - cm.Data = map[string]string{ - "bundleName": "distro-full", - } - if err := bootstrapClient.Create(reconcileCtx, cm); err != nil { - setupLog.Info("Failed to trigger reconcile via ConfigMap creation, continuing anyway", "error", err) - } - } - - // Wait for first reconcile cycle to complete - setupLog.Info("Waiting for first reconcile cycle to complete") - select { - case <-firstReconcileDone: - setupLog.Info("First reconcile cycle completed") - case <-reconcileCtx.Done(): - setupLog.Info("Timeout waiting for first reconcile, proceeding with phase 2 anyway") - } - - setupLog.Info("Starting bootstrap phase 2: basic charts installation") - phase2Ctx, phase2Cancel := context.WithTimeout(context.Background(), 30*time.Minute) - defer phase2Cancel() - - if err := runBootstrapPhase2(phase2Ctx, bootstrapClient); err != nil { - setupLog.Error(err, "bootstrap phase 2 failed") + if err := mgr.Start(mgrCtx); err != nil { + setupLog.Error(err, "problem running manager") os.Exit(1) } - - setupLog.Info("Bootstrap completed, controller manager is running") - // Wait for manager (this blocks until context is cancelled) - <-mgrCtx.Done() -} - -// runBootstrapPhase1 installs cozystack-resource-definition-crd, fluxcd-operator and fluxcd, waits for CRDs -// This must complete before controller manager can start (manager needs CRDs registered) -// Basic charts (cilium, kubeovn) are NOT installed here - they are installed in phase 2 after manager starts -func runBootstrapPhase1(ctx context.Context, c client.Client) error { - // Create cozy-system and cozy-public namespaces first (needed for ConfigMap and HelmRepositories) - if err := ensureBootstrapNamespace(ctx, c, "cozy-system", true); err != nil { - return fmt.Errorf("failed to create cozy-system namespace: %w", err) - } - if err := ensureBootstrapNamespace(ctx, c, "cozy-public", false); err != nil { - return fmt.Errorf("failed to create cozy-public namespace: %w", err) - } - - // Get bundle name - bundle, err := getBundle(ctx, c) - if err != nil { - return err - } - setupLog.Info("Bundle detected", "bundle", bundle) - - // Calculate and run migrations - version, err := calculateVersion() - if err != nil { - return err - } - setupLog.Info("Target version", "version", version) - - if err := runMigrations(ctx, c, version); err != nil { - return err - } - - // Create cozy-fluxcd namespace (needed for fluxcd-operator and fluxcd) - if err := ensureBootstrapNamespace(ctx, c, "cozy-fluxcd", true); err != nil { - return fmt.Errorf("failed to create cozy-fluxcd namespace: %w", err) - } - - // Ensure cozystack-resource-definition-crd is installed - // This CRD is needed for the controller manager to start - if err := ensureCozystackResourceDefinitionCRD(ctx, c); err != nil { - return err - } - - // Ensure fluxcd-operator and fluxcd are installed - // This installs/resumes helmreleases and waits for CRDs to be registered - // After CRDs are available, controller manager can start - if err := ensureFluxCD(ctx, c); err != nil { - return err - } - - setupLog.Info("Bootstrap phase 1 completed: fluxcd installed, CRDs available") - return nil -} - -// runBootstrapPhase2 installs basic charts and performs post-fluxcd operations -// This runs after controller manager has started (CRDs are available for manager) -func runBootstrapPhase2(ctx context.Context, c client.Client) error { - setupLog.Info("Starting bootstrap phase 2: basic charts installation") - - // Get bundle name - bundle, err := getBundle(ctx, c) - if err != nil { - return err - } - setupLog.Info("Bundle detected", "bundle", bundle) - - // Install basic charts (cilium, kubeovn) only if fluxcd is not ready - // Basic charts are only needed during bootstrap when fluxcd is not ready yet - fluxOK, err := fluxIsOK(ctx, c) - if err != nil { - return err - } - if !fluxOK { - setupLog.Info("fluxcd is not ready, installing basic charts (controller manager is running)") - if err := installBasicCharts(ctx, c, bundle); err != nil { - return err - } - } else { - setupLog.Info("fluxcd is ready, skipping basic charts installation") - } - - // Unsuspend and update charts - if err := unsuspendCozystackCharts(ctx, c); err != nil { - return err - } - if err := updateCozystackCharts(ctx, c); err != nil { - return err - } - - setupLog.Info("Bootstrap phase 2 completed") - return nil -} - -// ensureBootstrapNamespace creates or updates a namespace for bootstrap operations -func ensureBootstrapNamespace(ctx context.Context, c client.Client, name string, privileged bool) error { - namespace := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Labels: map[string]string{ - "cozystack.io/system": "true", - }, - Annotations: map[string]string{ - "helm.sh/resource-policy": "keep", - }, - }, - } - - if privileged { - namespace.Labels["pod-security.kubernetes.io/enforce"] = "privileged" - } - - existingNs := &corev1.Namespace{} - err := c.Get(ctx, types.NamespacedName{Name: name}, existingNs) - if apierrors.IsNotFound(err) { - setupLog.Info("Creating namespace for bootstrap", "name", name, "privileged", privileged) - if err := c.Create(ctx, namespace); err != nil { - return fmt.Errorf("failed to create namespace %s: %w", name, err) - } - } else if err != nil { - return fmt.Errorf("failed to get namespace %s: %w", name, err) - } else { - // Update labels and annotations if needed - needsUpdate := false - if existingNs.Labels == nil { - existingNs.Labels = make(map[string]string) - needsUpdate = true - } - for k, v := range namespace.Labels { - if existingNs.Labels[k] != v { - existingNs.Labels[k] = v - needsUpdate = true - } - } - if existingNs.Annotations == nil { - existingNs.Annotations = make(map[string]string) - needsUpdate = true - } - for k, v := range namespace.Annotations { - if existingNs.Annotations[k] != v { - existingNs.Annotations[k] = v - needsUpdate = true - } - } - if needsUpdate { - setupLog.Info("Updating namespace for bootstrap", "name", name) - if err := c.Update(ctx, existingNs); err != nil { - return fmt.Errorf("failed to update namespace %s: %w", name, err) - } - } - } - - return nil -} - -// Bootstrap helper functions (moved from installer logic) - -func getBundle(ctx context.Context, c client.Client) (string, error) { - cm := &corev1.ConfigMap{} - key := types.NamespacedName{Namespace: "cozy-system", Name: "cozystack"} - if err := c.Get(ctx, key, cm); err != nil { - return "", err - } - bundle, ok := cm.Data["bundle-name"] - if !ok { - return "", fmt.Errorf("bundle-name not found in cozystack configmap") - } - return bundle, nil -} - -func calculateVersion() (int, error) { - migrationsDir := "scripts/migrations" - entries, err := os.ReadDir(migrationsDir) - if err != nil { - return 0, fmt.Errorf("failed to read migrations directory: %w", err) - } - - var versions []int - for _, entry := range entries { - if entry.IsDir() { - continue - } - version, err := strconv.Atoi(entry.Name()) - if err != nil { - continue - } - versions = append(versions, version) - } - - if len(versions) == 0 { - return 1, nil - } - - sort.Ints(versions) - return versions[len(versions)-1] + 1, nil -} - -func runMigrations(ctx context.Context, c client.Client, targetVersion int) error { - cm := &corev1.ConfigMap{} - key := types.NamespacedName{Namespace: "cozy-system", Name: "cozystack-version"} - var currentVersion int - - err := c.Get(ctx, key, cm) - if err != nil { - if apierrors.IsNotFound(err) { - // First run: create ConfigMap with current version, skip migrations - setupLog.Info("cozystack-version configmap does not exist, creating with current version", "version", targetVersion) - newCM := &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "cozystack-version", - Namespace: "cozy-system", - }, - Data: map[string]string{ - "version": strconv.Itoa(targetVersion), - }, - } - if err := c.Create(ctx, newCM); err != nil { - return fmt.Errorf("failed to create version configmap: %w", err) - } - setupLog.Info("Created cozystack-version configmap with current version, skipping migrations") - return nil - } else { - return err - } - } else { - versionStr, ok := cm.Data["version"] - if !ok { - currentVersion = 0 - } else { - currentVersion, err = strconv.Atoi(versionStr) - if err != nil { - setupLog.Info("Invalid version in configmap, starting from 0", "version", versionStr) - currentVersion = 0 - } - } - } - - for currentVersion < targetVersion { - nextVersion := currentVersion + 1 - setupLog.Info("Running migration", "from", currentVersion, "to", targetVersion) - - migrationPath := filepath.Join("scripts", "migrations", strconv.Itoa(currentVersion)) - if _, err := os.Stat(migrationPath); os.IsNotExist(err) { - setupLog.Info("Migration script does not exist, skipping", "path", migrationPath) - currentVersion = nextVersion - continue - } - - // Make script executable - if err := os.Chmod(migrationPath, 0755); err != nil { - return fmt.Errorf("failed to make migration script executable: %w", err) - } - - // Run migration script - cmd := exec.CommandContext(ctx, migrationPath) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return fmt.Errorf("migration %d failed: %w", currentVersion, err) - } - - // Update version in configmap - newCM := &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "cozystack-version", - Namespace: "cozy-system", - }, - Data: map[string]string{ - "version": strconv.Itoa(nextVersion), - }, - } - - // Try to update first - existingCM := &corev1.ConfigMap{} - err = c.Get(ctx, key, existingCM) - if err != nil { - if apierrors.IsNotFound(err) { - // Create if doesn't exist - if err := c.Create(ctx, newCM); err != nil { - return fmt.Errorf("failed to create version configmap: %w", err) - } - } else { - return fmt.Errorf("failed to get version configmap: %w", err) - } - } else { - // Update existing - newCM.ResourceVersion = existingCM.ResourceVersion - if err := c.Update(ctx, newCM); err != nil { - return fmt.Errorf("failed to update version configmap: %w", err) - } - } - - currentVersion = nextVersion - } - - return nil -} - -// ensureCozystackResourceDefinitionCRD installs cozystack-resource-definition-crd and waits for CRD -// This CRD is needed for the controller manager to start -func ensureCozystackResourceDefinitionCRD(ctx context.Context, c client.Client) error { - // Check if CRD already exists - crd := &apiextensionsv1.CustomResourceDefinition{} - key := types.NamespacedName{Name: "cozystackresourcedefinitions.cozystack.io"} - if err := c.Get(ctx, key, crd); err == nil { - setupLog.Info("cozystack-resource-definition-crd CRD already exists, skipping installation") - return nil - } else if !apierrors.IsNotFound(err) { - return fmt.Errorf("failed to check cozystack-resource-definition-crd CRD: %w", err) - } - - // CRD doesn't exist, install it - setupLog.Info("Installing cozystack-resource-definition-crd") - cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/cozystack-resource-definition-crd", "apply-locally") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to install cozystack-resource-definition-crd: %w", err) - } - - // Wait for CRD - if err := waitForCRDs(ctx, c, "cozystackresourcedefinitions.cozystack.io"); err != nil { - return err - } - - return nil -} - -func ensureFluxCD(ctx context.Context, c client.Client) error { - fluxOK, err := fluxIsOK(ctx, c) - if err != nil { - return err - } - if fluxOK { - setupLog.Info("fluxcd is already ready, skipping installation") - // Still need to ensure CRDs are available for controller manager - // Check if CRDs exist - if err := waitForCRDs(ctx, c, "helmreleases.helm.toolkit.fluxcd.io", "helmrepositories.source.toolkit.fluxcd.io"); err != nil { - return err - } - return nil - } - setupLog.Info("fluxcd is not ready, proceeding with installation/resume") - - // Install fluxcd-operator - hr := &helmv2.HelmRelease{} - key := types.NamespacedName{Namespace: "cozy-fluxcd", Name: "fluxcd-operator"} - err = c.Get(ctx, key, hr) - if err == nil { - // HelmRelease exists, apply and resume it - setupLog.Info("Applying and resuming fluxcd-operator helmrelease") - cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd-operator", "apply", "resume") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to apply and resume fluxcd-operator: %w", err) - } - } else if apierrors.IsNotFound(err) { - // HelmRelease doesn't exist, need to create it - setupLog.Info("Creating fluxcd-operator using make (TODO: use helm-controller API)") - cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd-operator", "apply-locally") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to install fluxcd-operator: %w", err) - } - } else if meta.IsNoMatchError(err) { - // CRD for HelmRelease doesn't exist yet, need to install fluxcd-operator first - setupLog.Info("HelmRelease CRD not found, installing fluxcd-operator to create CRDs") - cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd-operator", "apply-locally") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to install fluxcd-operator: %w", err) - } - } else { - return fmt.Errorf("failed to check fluxcd-operator: %w", err) - } - - // Wait for FluxInstance CRD (created by fluxcd-operator) - if err := waitForCRDs(ctx, c, "fluxinstances.fluxcd.controlplane.io"); err != nil { - return err - } - - // Install fluxcd (flux-instance) via FluxInstance resource - // flux-instance is installed via FluxInstance, not HelmRelease - // We need to use unstructured client to check FluxInstance since it's not in our scheme yet - config := ctrl.GetConfigOrDie() - dyn, err := dynamic.NewForConfig(config) - if err != nil { - return fmt.Errorf("failed to create dynamic client: %w", err) - } - - fluxInstanceGVR := schema.GroupVersionResource{ - Group: "fluxcd.controlplane.io", - Version: "v1", - Resource: "fluxinstances", - } - - _, err = dyn.Resource(fluxInstanceGVR).Namespace("cozy-fluxcd").Get(ctx, "flux", metav1.GetOptions{}) - if err == nil { - // FluxInstance exists, check if HelmRelease exists before applying - // HelmRelease CRD might not exist yet, so we need to check carefully - helmReleaseGVR := schema.GroupVersionResource{ - Group: "helm.toolkit.fluxcd.io", - Version: "v2", - Resource: "helmreleases", - } - - // Try to get HelmRelease - if CRD doesn't exist, this will return IsNoMatchError - _, hrErr := dyn.Resource(helmReleaseGVR).Namespace("cozy-fluxcd").Get(ctx, "fluxcd", metav1.GetOptions{}) - if hrErr == nil { - // HelmRelease exists, apply and resume it via make - setupLog.Info("FluxInstance and HelmRelease exist, applying and resuming fluxcd") - cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd", "apply", "resume") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to apply and resume fluxcd: %w", err) - } - } else if apierrors.IsNotFound(hrErr) || meta.IsNoMatchError(hrErr) { - // HelmRelease doesn't exist or CRD not available, use apply-locally - setupLog.Info("FluxInstance exists but HelmRelease not found, creating fluxcd using apply-locally") - cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd", "apply-locally") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to install fluxcd: %w", err) - } - } else { - return fmt.Errorf("failed to check fluxcd HelmRelease: %w", hrErr) - } - } else if apierrors.IsNotFound(err) { - // FluxInstance doesn't exist, need to create it - setupLog.Info("Creating fluxcd (flux-instance) using make") - cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd", "apply-locally") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to install fluxcd: %w", err) - } - } else if meta.IsNoMatchError(err) { - // CRD for FluxInstance doesn't exist yet, but we already waited for it above - // This shouldn't happen, but if it does, try to install anyway - setupLog.Info("FluxInstance CRD not found (unexpected), trying to install fluxcd anyway") - cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/fluxcd", "apply-locally") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to install fluxcd: %w", err) - } - } else { - return fmt.Errorf("failed to check fluxcd FluxInstance: %w", err) - } - - // Wait for HelmRelease CRD to be created by flux-instance - // flux-instance installs Flux which creates HelmRelease CRD - setupLog.Info("Waiting for HelmRelease CRD to be created by flux-instance") - if err := waitForCRDs(ctx, c, "helmreleases.helm.toolkit.fluxcd.io"); err != nil { - return fmt.Errorf("failed to wait for HelmRelease CRD: %w", err) - } - - // Wait for CRDs - // CRDs must be available before controller manager can start - // Controller manager needs CRDs to be registered in the scheme - if err := waitForCRDs(ctx, c, "helmreleases.helm.toolkit.fluxcd.io", "helmrepositories.source.toolkit.fluxcd.io"); err != nil { - return err - } - - // Note: We don't wait for fluxcd to be fully ready (source-controller, helm-controller deployments) - // We only wait for CRDs to be registered, then controller manager can start - // Basic charts will be installed in phase 2 after controller manager has started - - return nil -} - -func fluxIsOK(ctx context.Context, c client.Client) (bool, error) { - // Check source-controller deployment - sourceDeploy := &appsv1.Deployment{} - key := types.NamespacedName{Namespace: "cozy-fluxcd", Name: "source-controller"} - if err := c.Get(ctx, key, sourceDeploy); err != nil { - setupLog.Info("fluxcd check: source-controller deployment not found") - return false, nil - } - if !isDeploymentAvailable(sourceDeploy) { - setupLog.Info("fluxcd check: source-controller deployment not available") - return false, nil - } - - // Check helm-controller deployment - helmDeploy := &appsv1.Deployment{} - key = types.NamespacedName{Namespace: "cozy-fluxcd", Name: "helm-controller"} - if err := c.Get(ctx, key, helmDeploy); err != nil { - setupLog.Info("fluxcd check: helm-controller deployment not found") - return false, nil - } - if !isDeploymentAvailable(helmDeploy) { - setupLog.Info("fluxcd check: helm-controller deployment not available") - return false, nil - } - - // Check fluxcd helmrelease is ready - hr := &helmv2.HelmRelease{} - key = types.NamespacedName{Namespace: "cozy-fluxcd", Name: "fluxcd"} - if err := c.Get(ctx, key, hr); err != nil { - setupLog.Info("fluxcd check: fluxcd helmrelease not found") - return false, nil - } - - // Check if ready (this implicitly checks suspend, as suspended HelmRelease cannot be Ready) - if hr.Status.Conditions != nil { - for _, cond := range hr.Status.Conditions { - if cond.Type == "Ready" && cond.Status == metav1.ConditionTrue { - setupLog.Info("fluxcd check: fluxcd is ready") - return true, nil - } - } - } - - setupLog.Info("fluxcd check: fluxcd helmrelease not ready") - return false, nil -} - -func isDeploymentAvailable(deploy *appsv1.Deployment) bool { - for _, cond := range deploy.Status.Conditions { - if cond.Type == appsv1.DeploymentAvailable && cond.Status == corev1.ConditionTrue { - return true - } - } - return false -} - -func waitForCRDs(ctx context.Context, c client.Client, crdNames ...string) error { - for _, crdName := range crdNames { - setupLog.Info("Waiting for CRD", "crd", crdName) - - err := wait.PollUntilContextTimeout(ctx, 1*time.Second, 60*time.Second, true, func(ctx context.Context) (bool, error) { - crd := &apiextensionsv1.CustomResourceDefinition{} - key := types.NamespacedName{Name: crdName} - if err := c.Get(ctx, key, crd); err != nil { - if apierrors.IsNotFound(err) { - // CRD not found yet, continue waiting - return false, nil - } - // Other error, return it - return false, err - } - // CRD found - setupLog.Info("CRD found", "crd", crdName) - return true, nil - }) - - if err != nil { - return fmt.Errorf("timeout waiting for CRD %s: %w", crdName, err) - } - } - return nil -} - -func resumeHelmRelease(ctx context.Context, c client.Client, hr *helmv2.HelmRelease) error { - if !hr.Spec.Suspend { - return nil - } - - patch := client.MergeFrom(hr.DeepCopy()) - hr.Spec.Suspend = false - - if err := c.Patch(ctx, hr, patch); err != nil { - return fmt.Errorf("failed to patch HelmRelease: %w", err) - } - - return nil -} - -func installBasicCharts(ctx context.Context, c client.Client, bundle string) error { - // Check if cilium and kubeovn are present in CozystackBundle resources - hasCilium := false - hasKubeovn := false - - // List all CozystackBundle resources - bundleList := &cozyv1alpha1.CozystackBundleList{} - if err := c.List(ctx, bundleList); err != nil { - setupLog.Info("Failed to list CozystackBundles, skipping component checks", "error", err) - // If bundle loading fails, fall back to old behavior for backward compatibility - if bundle == "paas-full" || bundle == "distro-full" { - setupLog.Info("Installing cilium using make (fallback mode)") - cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/cilium", "apply", "resume") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to install cilium: %w", err) - } - } - if bundle == "paas-full" { - setupLog.Info("Installing kubeovn using make (fallback mode)") - cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/kubeovn", "apply", "resume") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to install kubeovn: %w", err) - } - } - return nil - } - - // Check all bundles for cilium and kubeovn packages - for _, bundleResource := range bundleList.Items { - for _, pkg := range bundleResource.Spec.Packages { - if pkg.Name == "cilium" && !pkg.Disabled { - hasCilium = true - } - if pkg.Name == "kubeovn" && !pkg.Disabled { - hasKubeovn = true - } - } - } - - // Install cilium only if present in bundle - if hasCilium { - // TODO: Create HelmRelease for cilium using helm-controller API - setupLog.Info("Installing cilium using make (found in bundle)") - cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/cilium", "apply", "resume") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to install cilium: %w", err) - } - } else { - setupLog.Info("Skipping cilium installation (not found in bundle)") - } - - // Install kubeovn only if present in bundle - if hasKubeovn { - // TODO: Create HelmRelease for kubeovn using helm-controller API - setupLog.Info("Installing kubeovn using make (found in bundle)") - cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/kubeovn", "apply", "resume") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to install kubeovn: %w", err) - } - } else { - setupLog.Info("Skipping kubeovn installation (not found in bundle)") - } - - return nil -} - -func unsuspendCozystackCharts(ctx context.Context, c client.Client) error { - hrList := &helmv2.HelmReleaseList{} - if err := c.List(ctx, hrList); err != nil { - return fmt.Errorf("failed to list HelmReleases: %w", err) - } - - for _, hr := range hrList.Items { - if !hr.Spec.Suspend { - continue - } - - // Check if it's from a Cozystack managed repository - if hr.Spec.Chart == nil || hr.Spec.Chart.Spec.SourceRef.Name == "" { - continue - } - - sourceRef := hr.Spec.Chart.Spec.SourceRef - repoKey := fmt.Sprintf("%s/%s", sourceRef.Namespace, sourceRef.Name) - - switch repoKey { - case "cozy-system/cozystack-system", "cozy-public/cozystack-extra", "cozy-public/cozystack-apps": - setupLog.Info("Unsuspending HelmRelease", "namespace", hr.Namespace, "name", hr.Name) - if err := resumeHelmRelease(ctx, c, &hr); err != nil { - setupLog.Error(err, "Failed to unsuspend HelmRelease", "namespace", hr.Namespace, "name", hr.Name) - continue - } - } - } - - return nil -} - -func updateCozystackCharts(ctx context.Context, c client.Client) error { - hrList := &helmv2.HelmReleaseList{} - if err := c.List(ctx, hrList, client.MatchingLabels{"cozystack.io/ui": "true"}); err != nil { - return fmt.Errorf("failed to list HelmReleases: %w", err) - } - - for _, hr := range hrList.Items { - if hr.Spec.Chart == nil { - continue - } - - // Update version to >= 0.0.0-0 - patch := client.MergeFrom(hr.DeepCopy()) - hr.Spec.Chart.Spec.Version = ">= 0.0.0-0" - - setupLog.Info("Updating HelmRelease to latest version", "namespace", hr.Namespace, "name", hr.Name) - if err := c.Patch(ctx, &hr, patch); err != nil { - setupLog.Error(err, "Failed to update HelmRelease", "namespace", hr.Namespace, "name", hr.Name) - continue - } - } - - return nil } diff --git a/go.mod b/go.mod index 90b65a70..1bad2023 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,6 @@ require ( github.com/stretchr/testify v1.11.1 go.uber.org/zap v1.27.0 gopkg.in/yaml.v2 v2.4.0 - gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.34.1 k8s.io/apiextensions-apiserver v0.34.1 k8s.io/apimachinery v0.34.1 @@ -120,6 +119,7 @@ require ( gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/kms v0.34.1 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 4934777f..4eddab12 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -58,5 +58,3 @@ mv packages/system/cozystack-controller/crds/cozystack.io_cozystackresourcedefin packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml mv packages/system/cozystack-controller/crds/cozystack.io_cozystackbundles.yaml \ packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackbundles.yaml -mv packages/system/cozystack-controller/crds/cozystack.io_cozystackplatformconfigurations.yaml \ - packages/core/installer/templates/cozystack.io_cozystackplatformconfigurations.yaml diff --git a/internal/fluxinstall/install.go b/internal/fluxinstall/install.go new file mode 100644 index 00000000..32875740 --- /dev/null +++ b/internal/fluxinstall/install.go @@ -0,0 +1,231 @@ +/* +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) 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") + } + + // 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" +} + diff --git a/internal/fluxinstall/manifests.embed.go b/internal/fluxinstall/manifests.embed.go new file mode 100644 index 00000000..f07d0618 --- /dev/null +++ b/internal/fluxinstall/manifests.embed.go @@ -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 +} + diff --git a/internal/fluxinstall/manifests/fluxcd.yaml b/internal/fluxinstall/manifests/fluxcd.yaml new file mode 100644 index 00000000..237db089 --- /dev/null +++ b/internal/fluxinstall/manifests/fluxcd.yaml @@ -0,0 +1,11951 @@ +--- +# Instance: flux +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: alerts.notification.toolkit.fluxcd.io +spec: + group: notification.toolkit.fluxcd.io + names: + kind: Alert + listKind: AlertList + plural: alerts + singular: alert + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + deprecated: true + deprecationWarning: v1beta2 Alert is deprecated, upgrade to v1beta3 + name: v1beta2 + schema: + openAPIV3Schema: + description: Alert is the Schema for the alerts API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: AlertSpec defines an alerting rule for events involving a list of objects. + properties: + eventMetadata: + additionalProperties: + type: string + description: |- + EventMetadata is an optional field for adding metadata to events dispatched by the + controller. This can be used for enhancing the context of the event. If a field + would override one already present on the original event as generated by the emitter, + then the override doesn't happen, i.e. the original value is preserved, and an info + log is printed. + type: object + eventSeverity: + default: info + description: |- + EventSeverity specifies how to filter events based on severity. + If set to 'info' no events will be filtered. + enum: + - info + - error + type: string + eventSources: + description: |- + EventSources specifies how to filter events based + on the involved object kind, name and namespace. + items: + description: |- + CrossNamespaceObjectReference contains enough information to let you locate the + typed referenced object at cluster level + properties: + apiVersion: + description: API version of the referent + type: string + kind: + description: Kind of the referent + enum: + - Bucket + - GitRepository + - Kustomization + - HelmRelease + - HelmChart + - HelmRepository + - ImageRepository + - ImagePolicy + - ImageUpdateAutomation + - OCIRepository + type: string + matchLabels: + additionalProperties: + type: string + description: |- + MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + MatchLabels requires the name to be set to `*`. + type: object + name: + description: |- + Name of the referent + If multiple resources are targeted `*` may be set. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: Namespace of the referent + maxLength: 253 + minLength: 1 + type: string + required: + - kind + - name + type: object + type: array + exclusionList: + description: |- + ExclusionList specifies a list of Golang regular expressions + to be used for excluding messages. + items: + type: string + type: array + inclusionList: + description: |- + InclusionList specifies a list of Golang regular expressions + to be used for including messages. + items: + type: string + type: array + providerRef: + description: ProviderRef specifies which Provider this Alert should use. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + summary: + description: Summary holds a short description of the impact and affected cluster. + maxLength: 255 + type: string + suspend: + description: |- + Suspend tells the controller to suspend subsequent + events handling for this Alert. + type: boolean + required: + - eventSources + - providerRef + type: object + status: + default: + observedGeneration: -1 + description: AlertStatus defines the observed state of the Alert. + properties: + conditions: + description: Conditions holds the conditions for the Alert. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta3 + schema: + openAPIV3Schema: + description: Alert is the Schema for the alerts API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: AlertSpec defines an alerting rule for events involving a list of objects. + properties: + eventMetadata: + additionalProperties: + type: string + description: |- + EventMetadata is an optional field for adding metadata to events dispatched by the + controller. This can be used for enhancing the context of the event. If a field + would override one already present on the original event as generated by the emitter, + then the override doesn't happen, i.e. the original value is preserved, and an info + log is printed. + type: object + eventSeverity: + default: info + description: |- + EventSeverity specifies how to filter events based on severity. + If set to 'info' no events will be filtered. + enum: + - info + - error + type: string + eventSources: + description: |- + EventSources specifies how to filter events based + on the involved object kind, name and namespace. + items: + description: |- + CrossNamespaceObjectReference contains enough information to let you locate the + typed referenced object at cluster level + properties: + apiVersion: + description: API version of the referent + type: string + kind: + description: Kind of the referent + enum: + - Bucket + - GitRepository + - Kustomization + - HelmRelease + - HelmChart + - HelmRepository + - ImageRepository + - ImagePolicy + - ImageUpdateAutomation + - OCIRepository + type: string + matchLabels: + additionalProperties: + type: string + description: |- + MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + MatchLabels requires the name to be set to `*`. + type: object + name: + description: |- + Name of the referent + If multiple resources are targeted `*` may be set. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: Namespace of the referent + maxLength: 253 + minLength: 1 + type: string + required: + - kind + - name + type: object + type: array + exclusionList: + description: |- + ExclusionList specifies a list of Golang regular expressions + to be used for excluding messages. + items: + type: string + type: array + inclusionList: + description: |- + InclusionList specifies a list of Golang regular expressions + to be used for including messages. + items: + type: string + type: array + providerRef: + description: ProviderRef specifies which Provider this Alert should use. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + summary: + description: |- + Summary holds a short description of the impact and affected cluster. + Deprecated: Use EventMetadata instead. + maxLength: 255 + type: string + suspend: + description: |- + Suspend tells the controller to suspend subsequent + events handling for this Alert. + type: boolean + required: + - eventSources + - providerRef + type: object + type: object + served: true + storage: true + subresources: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: artifactgenerators.source.extensions.fluxcd.io +spec: + group: source.extensions.fluxcd.io + names: + kind: ArtifactGenerator + listKind: ArtifactGeneratorList + plural: artifactgenerators + shortNames: + - ag + singular: artifactgenerator + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: ArtifactGenerator is the Schema for the artifactgenerators API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ArtifactGeneratorSpec defines the desired state of ArtifactGenerator. + properties: + artifacts: + description: OutputArtifacts is a list of output artifacts to be generated. + items: + description: |- + OutputArtifact defines the desired state of an ExternalArtifact + generated by the ArtifactGenerator. + properties: + copy: + description: |- + Copy defines a list of copy operations to perform from the sources to the generated artifact. + The copy operations are performed in the order they are listed with existing files + being overwritten by later copy operations. + items: + properties: + exclude: + description: |- + Exclude specifies a list of glob patterns to exclude + files and dirs matched by the 'From' field. + items: + type: string + maxItems: 100 + type: array + from: + description: |- + From specifies the source (by alias) and the glob pattern to match files. + The format is "@/". + maxLength: 1024 + pattern: ^@([a-z0-9]([a-z0-9_-]*[a-z0-9])?)/(.*)$ + type: string + strategy: + description: |- + Strategy specifies the copy strategy to use. + 'Overwrite' will overwrite existing files in the destination. + 'Merge' is for merging YAML files using Helm values merge strategy. + If not specified, defaults to 'Overwrite'. + enum: + - Overwrite + - Merge + type: string + to: + description: |- + To specifies the destination path within the artifact. + The format is "@artifact/path", the alias "artifact" + refers to the root path of the generated artifact. + maxLength: 1024 + pattern: ^@(artifact)/(.*)$ + type: string + required: + - from + - to + type: object + minItems: 1 + type: array + name: + description: Name is the name of the generated artifact. + maxLength: 253 + pattern: ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$ + type: string + originRevision: + description: |- + OriginRevision is used to set the 'org.opencontainers.image.revision' + annotation on the generated artifact metadata. + If specified, it must point to an existing source alias in the format "@". + If the referenced source has an origin revision (e.g. a Git commit SHA), + it will be used to set the annotation on the generated artifact. + If the referenced source does not have an origin revision, the field is ignored. + maxLength: 64 + pattern: ^@([a-z0-9]([a-z0-9_-]*[a-z0-9])?)$ + type: string + revision: + description: |- + Revision is the revision of the generated artifact. + If specified, it must point to an existing source alias in the format "@". + If not specified, the revision is automatically set to the digest of the artifact content. + maxLength: 64 + pattern: ^@([a-z0-9]([a-z0-9_-]*[a-z0-9])?)$ + type: string + required: + - copy + - name + type: object + maxItems: 1000 + minItems: 1 + type: array + sources: + description: |- + Sources is a list of references to the Flux source-controller + resources that will be used to generate the artifact. + items: + description: SourceReference contains the reference to a Flux source-controller resource. + properties: + alias: + description: |- + Alias of the source within the ArtifactGenerator context. + The alias must be unique per ArtifactGenerator, and must consist + of lower case alphanumeric characters, underscores, and hyphens. + It must start and end with an alphanumeric character. + maxLength: 63 + pattern: ^[a-z0-9]([a-z0-9_-]*[a-z0-9])?$ + type: string + kind: + description: Kind of the source. + enum: + - Bucket + - GitRepository + - OCIRepository + type: string + name: + description: Name of the source. + maxLength: 253 + pattern: ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$ + type: string + namespace: + description: |- + Namespace of the source. + If not provided, defaults to the same namespace as the ArtifactGenerator. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - alias + - kind + - name + type: object + maxItems: 1000 + minItems: 1 + type: array + required: + - artifacts + - sources + type: object + status: + description: ArtifactGeneratorStatus defines the observed state of ArtifactGenerator. + properties: + conditions: + description: Conditions holds the conditions for the ArtifactGenerator. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + inventory: + description: Inventory contains the list of generated ExternalArtifact references. + items: + description: |- + ExternalArtifactReference contains the reference to a + generated ExternalArtifact along with its digest. + properties: + digest: + description: Digest of the referent artifact. + type: string + filename: + description: Filename is the name of the artifact file. + type: string + name: + description: Name of the referent artifact. + type: string + namespace: + description: Namespace of the referent artifact. + type: string + required: + - digest + - filename + - name + - namespace + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedSourcesDigest: + description: |- + ObservedSourcesDigest is a hash representing the current state of + all the sources referenced by the ArtifactGenerator. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: buckets.source.toolkit.fluxcd.io +spec: + group: source.toolkit.fluxcd.io + names: + kind: Bucket + listKind: BucketList + plural: buckets + singular: bucket + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.endpoint + name: Endpoint + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + name: v1 + schema: + openAPIV3Schema: + description: Bucket is the Schema for the buckets API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + BucketSpec specifies the required configuration to produce an Artifact for + an object storage bucket. + properties: + bucketName: + description: BucketName is the name of the object storage bucket. + type: string + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + bucket. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + This field is only supported for the `generic` provider. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + endpoint: + description: Endpoint is the object storage address the BucketName is located at. + type: string + ignore: + description: |- + Ignore overrides the set of excluded patterns in the .sourceignore format + (which is the same as .gitignore). If not provided, a default will be used, + consult the documentation for your version to find out what those are. + type: string + insecure: + description: Insecure allows connecting to a non-TLS HTTP Endpoint. + type: boolean + interval: + description: |- + Interval at which the Bucket Endpoint is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + prefix: + description: Prefix to use for server-side filtering of files in the Bucket. + type: string + provider: + default: generic + description: |- + Provider of the object storage bucket. + Defaults to 'generic', which expects an S3 (API) compatible object + storage. + enum: + - generic + - aws + - gcp + - azure + type: string + proxySecretRef: + description: |- + ProxySecretRef specifies the Secret containing the proxy configuration + to use while communicating with the Bucket server. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + region: + description: Region of the Endpoint where the BucketName is located in. + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing authentication credentials + for the Bucket. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + serviceAccountName: + description: |- + ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + the bucket. This field is only supported for the 'gcp' and 'aws' providers. + For more information about workload identity: + https://fluxcd.io/flux/components/source/buckets/#workload-identity + type: string + sts: + description: |- + STS specifies the required configuration to use a Security Token + Service for fetching temporary credentials to authenticate in a + Bucket provider. + + This field is only supported for the `aws` and `generic` providers. + properties: + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + STS endpoint. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + This field is only supported for the `ldap` provider. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + endpoint: + description: |- + Endpoint is the HTTP/S endpoint of the Security Token Service from + where temporary credentials will be fetched. + pattern: ^(http|https)://.*$ + type: string + provider: + description: Provider of the Security Token Service. + enum: + - aws + - ldap + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing authentication credentials + for the STS endpoint. This Secret must contain the fields `username` + and `password` and is supported only for the `ldap` provider. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - endpoint + - provider + type: object + suspend: + description: |- + Suspend tells the controller to suspend the reconciliation of this + Bucket. + type: boolean + timeout: + default: 60s + description: Timeout for fetch operations, defaults to 60s. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + required: + - bucketName + - endpoint + - interval + type: object + x-kubernetes-validations: + - message: STS configuration is only supported for the 'aws' and 'generic' Bucket providers + rule: self.provider == 'aws' || self.provider == 'generic' || !has(self.sts) + - message: '''aws'' is the only supported STS provider for the ''aws'' Bucket provider' + rule: self.provider != 'aws' || !has(self.sts) || self.sts.provider == 'aws' + - message: '''ldap'' is the only supported STS provider for the ''generic'' Bucket provider' + rule: self.provider != 'generic' || !has(self.sts) || self.sts.provider == 'ldap' + - message: spec.sts.secretRef is not required for the 'aws' STS provider + rule: '!has(self.sts) || self.sts.provider != ''aws'' || !has(self.sts.secretRef)' + - message: spec.sts.certSecretRef is not required for the 'aws' STS provider + rule: '!has(self.sts) || self.sts.provider != ''aws'' || !has(self.sts.certSecretRef)' + - message: ServiceAccountName is not supported for the 'generic' Bucket provider + rule: self.provider != 'generic' || !has(self.serviceAccountName) + - message: cannot set both .spec.secretRef and .spec.serviceAccountName + rule: '!has(self.secretRef) || !has(self.serviceAccountName)' + status: + default: + observedGeneration: -1 + description: BucketStatus records the observed state of a Bucket. + properties: + artifact: + description: Artifact represents the last successful Bucket reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the Bucket. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation of the Bucket object. + format: int64 + type: integer + observedIgnore: + description: |- + ObservedIgnore is the observed exclusion patterns used for constructing + the source artifact. + type: string + url: + description: |- + URL is the dynamic fetch link for the latest Artifact. + It is provided on a "best effort" basis, and using the precise + BucketStatus.Artifact data is recommended. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.endpoint + name: Endpoint + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + deprecated: true + deprecationWarning: v1beta2 Bucket is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: Bucket is the Schema for the buckets API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + BucketSpec specifies the required configuration to produce an Artifact for + an object storage bucket. + properties: + accessFrom: + description: |- + AccessFrom specifies an Access Control List for allowing cross-namespace + references to this object. + NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092 + properties: + namespaceSelectors: + description: |- + NamespaceSelectors is the list of namespace selectors to which this ACL applies. + Items in this list are evaluated using a logical OR operation. + items: + description: |- + NamespaceSelector selects the namespaces to which this ACL applies. + An empty map of MatchLabels matches all namespaces in a cluster. + properties: + matchLabels: + additionalProperties: + type: string + description: |- + MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + type: array + required: + - namespaceSelectors + type: object + bucketName: + description: BucketName is the name of the object storage bucket. + type: string + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + bucket. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + This field is only supported for the `generic` provider. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + endpoint: + description: Endpoint is the object storage address the BucketName is located at. + type: string + ignore: + description: |- + Ignore overrides the set of excluded patterns in the .sourceignore format + (which is the same as .gitignore). If not provided, a default will be used, + consult the documentation for your version to find out what those are. + type: string + insecure: + description: Insecure allows connecting to a non-TLS HTTP Endpoint. + type: boolean + interval: + description: |- + Interval at which the Bucket Endpoint is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + prefix: + description: Prefix to use for server-side filtering of files in the Bucket. + type: string + provider: + default: generic + description: |- + Provider of the object storage bucket. + Defaults to 'generic', which expects an S3 (API) compatible object + storage. + enum: + - generic + - aws + - gcp + - azure + type: string + proxySecretRef: + description: |- + ProxySecretRef specifies the Secret containing the proxy configuration + to use while communicating with the Bucket server. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + region: + description: Region of the Endpoint where the BucketName is located in. + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing authentication credentials + for the Bucket. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + sts: + description: |- + STS specifies the required configuration to use a Security Token + Service for fetching temporary credentials to authenticate in a + Bucket provider. + + This field is only supported for the `aws` and `generic` providers. + properties: + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + STS endpoint. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + This field is only supported for the `ldap` provider. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + endpoint: + description: |- + Endpoint is the HTTP/S endpoint of the Security Token Service from + where temporary credentials will be fetched. + pattern: ^(http|https)://.*$ + type: string + provider: + description: Provider of the Security Token Service. + enum: + - aws + - ldap + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing authentication credentials + for the STS endpoint. This Secret must contain the fields `username` + and `password` and is supported only for the `ldap` provider. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - endpoint + - provider + type: object + suspend: + description: |- + Suspend tells the controller to suspend the reconciliation of this + Bucket. + type: boolean + timeout: + default: 60s + description: Timeout for fetch operations, defaults to 60s. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + required: + - bucketName + - endpoint + - interval + type: object + x-kubernetes-validations: + - message: STS configuration is only supported for the 'aws' and 'generic' Bucket providers + rule: self.provider == 'aws' || self.provider == 'generic' || !has(self.sts) + - message: '''aws'' is the only supported STS provider for the ''aws'' Bucket provider' + rule: self.provider != 'aws' || !has(self.sts) || self.sts.provider == 'aws' + - message: '''ldap'' is the only supported STS provider for the ''generic'' Bucket provider' + rule: self.provider != 'generic' || !has(self.sts) || self.sts.provider == 'ldap' + - message: spec.sts.secretRef is not required for the 'aws' STS provider + rule: '!has(self.sts) || self.sts.provider != ''aws'' || !has(self.sts.secretRef)' + - message: spec.sts.certSecretRef is not required for the 'aws' STS provider + rule: '!has(self.sts) || self.sts.provider != ''aws'' || !has(self.sts.certSecretRef)' + status: + default: + observedGeneration: -1 + description: BucketStatus records the observed state of a Bucket. + properties: + artifact: + description: Artifact represents the last successful Bucket reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the Bucket. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation of the Bucket object. + format: int64 + type: integer + observedIgnore: + description: |- + ObservedIgnore is the observed exclusion patterns used for constructing + the source artifact. + type: string + url: + description: |- + URL is the dynamic fetch link for the latest Artifact. + It is provided on a "best effort" basis, and using the precise + BucketStatus.Artifact data is recommended. + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: externalartifacts.source.toolkit.fluxcd.io +spec: + group: source.toolkit.fluxcd.io + names: + kind: ExternalArtifact + listKind: ExternalArtifactList + plural: externalartifacts + singular: externalartifact + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .spec.sourceRef.name + name: Source + type: string + name: v1 + schema: + openAPIV3Schema: + description: ExternalArtifact is the Schema for the external artifacts API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ExternalArtifactSpec defines the desired state of ExternalArtifact + properties: + sourceRef: + description: |- + SourceRef points to the Kubernetes custom resource for + which the artifact is generated. + properties: + apiVersion: + description: API version of the referent, if not specified the Kubernetes preferred version will be used. + type: string + kind: + description: Kind of the referent. + type: string + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, when not specified it acts as LocalObjectReference. + type: string + required: + - kind + - name + type: object + type: object + status: + description: ExternalArtifactStatus defines the observed state of ExternalArtifact + properties: + artifact: + description: Artifact represents the output of an ExternalArtifact reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the ExternalArtifact. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: gitrepositories.source.toolkit.fluxcd.io +spec: + group: source.toolkit.fluxcd.io + names: + kind: GitRepository + listKind: GitRepositoryList + plural: gitrepositories + shortNames: + - gitrepo + singular: gitrepository + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.url + name: URL + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + name: v1 + schema: + openAPIV3Schema: + description: GitRepository is the Schema for the gitrepositories API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + GitRepositorySpec specifies the required configuration to produce an + Artifact for a Git repository. + properties: + ignore: + description: |- + Ignore overrides the set of excluded patterns in the .sourceignore format + (which is the same as .gitignore). If not provided, a default will be used, + consult the documentation for your version to find out what those are. + type: string + include: + description: |- + Include specifies a list of GitRepository resources which Artifacts + should be included in the Artifact produced for this GitRepository. + items: + description: |- + GitRepositoryInclude specifies a local reference to a GitRepository which + Artifact (sub-)contents must be included, and where they should be placed. + properties: + fromPath: + description: |- + FromPath specifies the path to copy contents from, defaults to the root + of the Artifact. + type: string + repository: + description: |- + GitRepositoryRef specifies the GitRepository which Artifact contents + must be included. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + toPath: + description: |- + ToPath specifies the path to copy contents to, defaults to the name of + the GitRepositoryRef. + type: string + required: + - repository + type: object + type: array + interval: + description: |- + Interval at which the GitRepository URL is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + provider: + description: |- + Provider used for authentication, can be 'azure', 'github', 'generic'. + When not specified, defaults to 'generic'. + enum: + - generic + - azure + - github + type: string + proxySecretRef: + description: |- + ProxySecretRef specifies the Secret containing the proxy configuration + to use while communicating with the Git server. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + recurseSubmodules: + description: |- + RecurseSubmodules enables the initialization of all submodules within + the GitRepository as cloned from the URL, using their default settings. + type: boolean + ref: + description: |- + Reference specifies the Git reference to resolve and monitor for + changes, defaults to the 'master' branch. + properties: + branch: + description: Branch to check out, defaults to 'master' if no other field is defined. + type: string + commit: + description: |- + Commit SHA to check out, takes precedence over all reference fields. + + This can be combined with Branch to shallow clone the branch, in which + the commit is expected to exist. + type: string + name: + description: |- + Name of the reference to check out; takes precedence over Branch, Tag and SemVer. + + It must be a valid Git reference: https://git-scm.com/docs/git-check-ref-format#_description + Examples: "refs/heads/main", "refs/tags/v0.1.0", "refs/pull/420/head", "refs/merge-requests/1/head" + type: string + semver: + description: SemVer tag expression to check out, takes precedence over Tag. + type: string + tag: + description: Tag to check out, takes precedence over Branch. + type: string + type: object + secretRef: + description: |- + SecretRef specifies the Secret containing authentication credentials for + the GitRepository. + For HTTPS repositories the Secret must contain 'username' and 'password' + fields for basic auth or 'bearerToken' field for token auth. + For SSH repositories the Secret must contain 'identity' + and 'known_hosts' fields. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + serviceAccountName: + description: |- + ServiceAccountName is the name of the Kubernetes ServiceAccount used to + authenticate to the GitRepository. This field is only supported for 'azure' provider. + type: string + sparseCheckout: + description: |- + SparseCheckout specifies a list of directories to checkout when cloning + the repository. If specified, only these directories are included in the + Artifact produced for this GitRepository. + items: + type: string + type: array + suspend: + description: |- + Suspend tells the controller to suspend the reconciliation of this + GitRepository. + type: boolean + timeout: + default: 60s + description: Timeout for Git operations like cloning, defaults to 60s. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + url: + description: URL specifies the Git repository URL, it can be an HTTP/S or SSH address. + pattern: ^(http|https|ssh)://.*$ + type: string + verify: + description: |- + Verification specifies the configuration to verify the Git commit + signature(s). + properties: + mode: + default: HEAD + description: |- + Mode specifies which Git object(s) should be verified. + + The variants "head" and "HEAD" both imply the same thing, i.e. verify + the commit that the HEAD of the Git repository points to. The variant + "head" solely exists to ensure backwards compatibility. + enum: + - head + - HEAD + - Tag + - TagAndHEAD + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing the public keys of trusted Git + authors. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - secretRef + type: object + required: + - interval + - url + type: object + x-kubernetes-validations: + - message: serviceAccountName can only be set when provider is 'azure' + rule: '!has(self.serviceAccountName) || (has(self.provider) && self.provider == ''azure'')' + status: + default: + observedGeneration: -1 + description: GitRepositoryStatus records the observed state of a Git repository. + properties: + artifact: + description: Artifact represents the last successful GitRepository reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the GitRepository. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + includedArtifacts: + description: |- + IncludedArtifacts contains a list of the last successfully included + Artifacts as instructed by GitRepositorySpec.Include. + items: + description: Artifact represents the output of a Source reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: |- + ObservedGeneration is the last observed generation of the GitRepository + object. + format: int64 + type: integer + observedIgnore: + description: |- + ObservedIgnore is the observed exclusion patterns used for constructing + the source artifact. + type: string + observedInclude: + description: |- + ObservedInclude is the observed list of GitRepository resources used to + produce the current Artifact. + items: + description: |- + GitRepositoryInclude specifies a local reference to a GitRepository which + Artifact (sub-)contents must be included, and where they should be placed. + properties: + fromPath: + description: |- + FromPath specifies the path to copy contents from, defaults to the root + of the Artifact. + type: string + repository: + description: |- + GitRepositoryRef specifies the GitRepository which Artifact contents + must be included. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + toPath: + description: |- + ToPath specifies the path to copy contents to, defaults to the name of + the GitRepositoryRef. + type: string + required: + - repository + type: object + type: array + observedRecurseSubmodules: + description: |- + ObservedRecurseSubmodules is the observed resource submodules + configuration used to produce the current Artifact. + type: boolean + observedSparseCheckout: + description: |- + ObservedSparseCheckout is the observed list of directories used to + produce the current Artifact. + items: + type: string + type: array + sourceVerificationMode: + description: |- + SourceVerificationMode is the last used verification mode indicating + which Git object(s) have been verified. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.url + name: URL + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + deprecated: true + deprecationWarning: v1beta2 GitRepository is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: GitRepository is the Schema for the gitrepositories API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + GitRepositorySpec specifies the required configuration to produce an + Artifact for a Git repository. + properties: + accessFrom: + description: |- + AccessFrom specifies an Access Control List for allowing cross-namespace + references to this object. + NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092 + properties: + namespaceSelectors: + description: |- + NamespaceSelectors is the list of namespace selectors to which this ACL applies. + Items in this list are evaluated using a logical OR operation. + items: + description: |- + NamespaceSelector selects the namespaces to which this ACL applies. + An empty map of MatchLabels matches all namespaces in a cluster. + properties: + matchLabels: + additionalProperties: + type: string + description: |- + MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + type: array + required: + - namespaceSelectors + type: object + gitImplementation: + default: go-git + description: |- + GitImplementation specifies which Git client library implementation to + use. Defaults to 'go-git', valid values are ('go-git', 'libgit2'). + Deprecated: gitImplementation is deprecated now that 'go-git' is the + only supported implementation. + enum: + - go-git + - libgit2 + type: string + ignore: + description: |- + Ignore overrides the set of excluded patterns in the .sourceignore format + (which is the same as .gitignore). If not provided, a default will be used, + consult the documentation for your version to find out what those are. + type: string + include: + description: |- + Include specifies a list of GitRepository resources which Artifacts + should be included in the Artifact produced for this GitRepository. + items: + description: |- + GitRepositoryInclude specifies a local reference to a GitRepository which + Artifact (sub-)contents must be included, and where they should be placed. + properties: + fromPath: + description: |- + FromPath specifies the path to copy contents from, defaults to the root + of the Artifact. + type: string + repository: + description: |- + GitRepositoryRef specifies the GitRepository which Artifact contents + must be included. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + toPath: + description: |- + ToPath specifies the path to copy contents to, defaults to the name of + the GitRepositoryRef. + type: string + required: + - repository + type: object + type: array + interval: + description: Interval at which to check the GitRepository for updates. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + recurseSubmodules: + description: |- + RecurseSubmodules enables the initialization of all submodules within + the GitRepository as cloned from the URL, using their default settings. + type: boolean + ref: + description: |- + Reference specifies the Git reference to resolve and monitor for + changes, defaults to the 'master' branch. + properties: + branch: + description: Branch to check out, defaults to 'master' if no other field is defined. + type: string + commit: + description: |- + Commit SHA to check out, takes precedence over all reference fields. + + This can be combined with Branch to shallow clone the branch, in which + the commit is expected to exist. + type: string + name: + description: |- + Name of the reference to check out; takes precedence over Branch, Tag and SemVer. + + It must be a valid Git reference: https://git-scm.com/docs/git-check-ref-format#_description + Examples: "refs/heads/main", "refs/tags/v0.1.0", "refs/pull/420/head", "refs/merge-requests/1/head" + type: string + semver: + description: SemVer tag expression to check out, takes precedence over Tag. + type: string + tag: + description: Tag to check out, takes precedence over Branch. + type: string + type: object + secretRef: + description: |- + SecretRef specifies the Secret containing authentication credentials for + the GitRepository. + For HTTPS repositories the Secret must contain 'username' and 'password' + fields for basic auth or 'bearerToken' field for token auth. + For SSH repositories the Secret must contain 'identity' + and 'known_hosts' fields. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + suspend: + description: |- + Suspend tells the controller to suspend the reconciliation of this + GitRepository. + type: boolean + timeout: + default: 60s + description: Timeout for Git operations like cloning, defaults to 60s. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + url: + description: URL specifies the Git repository URL, it can be an HTTP/S or SSH address. + pattern: ^(http|https|ssh)://.*$ + type: string + verify: + description: |- + Verification specifies the configuration to verify the Git commit + signature(s). + properties: + mode: + description: Mode specifies what Git object should be verified, currently ('head'). + enum: + - head + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing the public keys of trusted Git + authors. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - mode + - secretRef + type: object + required: + - interval + - url + type: object + status: + default: + observedGeneration: -1 + description: GitRepositoryStatus records the observed state of a Git repository. + properties: + artifact: + description: Artifact represents the last successful GitRepository reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the GitRepository. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + contentConfigChecksum: + description: |- + ContentConfigChecksum is a checksum of all the configurations related to + the content of the source artifact: + - .spec.ignore + - .spec.recurseSubmodules + - .spec.included and the checksum of the included artifacts + observed in .status.observedGeneration version of the object. This can + be used to determine if the content of the included repository has + changed. + It has the format of `:`, for example: `sha256:`. + + Deprecated: Replaced with explicit fields for observed artifact content + config in the status. + type: string + includedArtifacts: + description: |- + IncludedArtifacts contains a list of the last successfully included + Artifacts as instructed by GitRepositorySpec.Include. + items: + description: Artifact represents the output of a Source reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: |- + ObservedGeneration is the last observed generation of the GitRepository + object. + format: int64 + type: integer + observedIgnore: + description: |- + ObservedIgnore is the observed exclusion patterns used for constructing + the source artifact. + type: string + observedInclude: + description: |- + ObservedInclude is the observed list of GitRepository resources used to + to produce the current Artifact. + items: + description: |- + GitRepositoryInclude specifies a local reference to a GitRepository which + Artifact (sub-)contents must be included, and where they should be placed. + properties: + fromPath: + description: |- + FromPath specifies the path to copy contents from, defaults to the root + of the Artifact. + type: string + repository: + description: |- + GitRepositoryRef specifies the GitRepository which Artifact contents + must be included. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + toPath: + description: |- + ToPath specifies the path to copy contents to, defaults to the name of + the GitRepositoryRef. + type: string + required: + - repository + type: object + type: array + observedRecurseSubmodules: + description: |- + ObservedRecurseSubmodules is the observed resource submodules + configuration used to produce the current Artifact. + type: boolean + url: + description: |- + URL is the dynamic fetch link for the latest Artifact. + It is provided on a "best effort" basis, and using the precise + GitRepositoryStatus.Artifact data is recommended. + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: helmcharts.source.toolkit.fluxcd.io +spec: + group: source.toolkit.fluxcd.io + names: + kind: HelmChart + listKind: HelmChartList + plural: helmcharts + shortNames: + - hc + singular: helmchart + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.chart + name: Chart + type: string + - jsonPath: .spec.version + name: Version + type: string + - jsonPath: .spec.sourceRef.kind + name: Source Kind + type: string + - jsonPath: .spec.sourceRef.name + name: Source Name + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + name: v1 + schema: + openAPIV3Schema: + description: HelmChart is the Schema for the helmcharts API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: HelmChartSpec specifies the desired state of a Helm chart. + properties: + chart: + description: |- + Chart is the name or path the Helm chart is available at in the + SourceRef. + type: string + ignoreMissingValuesFiles: + description: |- + IgnoreMissingValuesFiles controls whether to silently ignore missing values + files rather than failing. + type: boolean + interval: + description: |- + Interval at which the HelmChart SourceRef is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + reconcileStrategy: + default: ChartVersion + description: |- + ReconcileStrategy determines what enables the creation of a new artifact. + Valid values are ('ChartVersion', 'Revision'). + See the documentation of the values for an explanation on their behavior. + Defaults to ChartVersion when omitted. + enum: + - ChartVersion + - Revision + type: string + sourceRef: + description: SourceRef is the reference to the Source the chart is available at. + properties: + apiVersion: + description: APIVersion of the referent. + type: string + kind: + description: |- + Kind of the referent, valid values are ('HelmRepository', 'GitRepository', + 'Bucket'). + enum: + - HelmRepository + - GitRepository + - Bucket + type: string + name: + description: Name of the referent. + type: string + required: + - kind + - name + type: object + suspend: + description: |- + Suspend tells the controller to suspend the reconciliation of this + source. + type: boolean + valuesFiles: + description: |- + ValuesFiles is an alternative list of values files to use as the chart + values (values.yaml is not included by default), expected to be a + relative path in the SourceRef. + Values files are merged in the order of this list with the last file + overriding the first. Ignored when omitted. + items: + type: string + type: array + verify: + description: |- + Verify contains the secret name containing the trusted public keys + used to verify the signature and specifies which provider to use to check + whether OCI image is authentic. + This field is only supported when using HelmRepository source with spec.type 'oci'. + Chart dependencies, which are not bundled in the umbrella chart artifact, are not verified. + properties: + matchOIDCIdentity: + description: |- + MatchOIDCIdentity specifies the identity matching criteria to use + while verifying an OCI artifact which was signed using Cosign keyless + signing. The artifact's identity is deemed to be verified if any of the + specified matchers match against the identity. + items: + description: |- + OIDCIdentityMatch specifies options for verifying the certificate identity, + i.e. the issuer and the subject of the certificate. + properties: + issuer: + description: |- + Issuer specifies the regex pattern to match against to verify + the OIDC issuer in the Fulcio certificate. The pattern must be a + valid Go regular expression. + type: string + subject: + description: |- + Subject specifies the regex pattern to match against to verify + the identity subject in the Fulcio certificate. The pattern must + be a valid Go regular expression. + type: string + required: + - issuer + - subject + type: object + type: array + provider: + default: cosign + description: Provider specifies the technology used to sign the OCI Artifact. + enum: + - cosign + - notation + type: string + secretRef: + description: |- + SecretRef specifies the Kubernetes Secret containing the + trusted public keys. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - provider + type: object + version: + default: '*' + description: |- + Version is the chart version semver expression, ignored for charts from + GitRepository and Bucket sources. Defaults to latest when omitted. + type: string + required: + - chart + - interval + - sourceRef + type: object + status: + default: + observedGeneration: -1 + description: HelmChartStatus records the observed state of the HelmChart. + properties: + artifact: + description: Artifact represents the output of the last successful reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the HelmChart. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedChartName: + description: |- + ObservedChartName is the last observed chart name as specified by the + resolved chart reference. + type: string + observedGeneration: + description: |- + ObservedGeneration is the last observed generation of the HelmChart + object. + format: int64 + type: integer + observedSourceArtifactRevision: + description: |- + ObservedSourceArtifactRevision is the last observed Artifact.Revision + of the HelmChartSpec.SourceRef. + type: string + observedValuesFiles: + description: |- + ObservedValuesFiles are the observed value files of the last successful + reconciliation. + It matches the chart in the last successfully reconciled artifact. + items: + type: string + type: array + url: + description: |- + URL is the dynamic fetch link for the latest Artifact. + It is provided on a "best effort" basis, and using the precise + BucketStatus.Artifact data is recommended. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.chart + name: Chart + type: string + - jsonPath: .spec.version + name: Version + type: string + - jsonPath: .spec.sourceRef.kind + name: Source Kind + type: string + - jsonPath: .spec.sourceRef.name + name: Source Name + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + deprecated: true + deprecationWarning: v1beta2 HelmChart is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: HelmChart is the Schema for the helmcharts API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: HelmChartSpec specifies the desired state of a Helm chart. + properties: + accessFrom: + description: |- + AccessFrom specifies an Access Control List for allowing cross-namespace + references to this object. + NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092 + properties: + namespaceSelectors: + description: |- + NamespaceSelectors is the list of namespace selectors to which this ACL applies. + Items in this list are evaluated using a logical OR operation. + items: + description: |- + NamespaceSelector selects the namespaces to which this ACL applies. + An empty map of MatchLabels matches all namespaces in a cluster. + properties: + matchLabels: + additionalProperties: + type: string + description: |- + MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + type: array + required: + - namespaceSelectors + type: object + chart: + description: |- + Chart is the name or path the Helm chart is available at in the + SourceRef. + type: string + ignoreMissingValuesFiles: + description: |- + IgnoreMissingValuesFiles controls whether to silently ignore missing values + files rather than failing. + type: boolean + interval: + description: |- + Interval at which the HelmChart SourceRef is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + reconcileStrategy: + default: ChartVersion + description: |- + ReconcileStrategy determines what enables the creation of a new artifact. + Valid values are ('ChartVersion', 'Revision'). + See the documentation of the values for an explanation on their behavior. + Defaults to ChartVersion when omitted. + enum: + - ChartVersion + - Revision + type: string + sourceRef: + description: SourceRef is the reference to the Source the chart is available at. + properties: + apiVersion: + description: APIVersion of the referent. + type: string + kind: + description: |- + Kind of the referent, valid values are ('HelmRepository', 'GitRepository', + 'Bucket'). + enum: + - HelmRepository + - GitRepository + - Bucket + type: string + name: + description: Name of the referent. + type: string + required: + - kind + - name + type: object + suspend: + description: |- + Suspend tells the controller to suspend the reconciliation of this + source. + type: boolean + valuesFile: + description: |- + ValuesFile is an alternative values file to use as the default chart + values, expected to be a relative path in the SourceRef. Deprecated in + favor of ValuesFiles, for backwards compatibility the file specified here + is merged before the ValuesFiles items. Ignored when omitted. + type: string + valuesFiles: + description: |- + ValuesFiles is an alternative list of values files to use as the chart + values (values.yaml is not included by default), expected to be a + relative path in the SourceRef. + Values files are merged in the order of this list with the last file + overriding the first. Ignored when omitted. + items: + type: string + type: array + verify: + description: |- + Verify contains the secret name containing the trusted public keys + used to verify the signature and specifies which provider to use to check + whether OCI image is authentic. + This field is only supported when using HelmRepository source with spec.type 'oci'. + Chart dependencies, which are not bundled in the umbrella chart artifact, are not verified. + properties: + matchOIDCIdentity: + description: |- + MatchOIDCIdentity specifies the identity matching criteria to use + while verifying an OCI artifact which was signed using Cosign keyless + signing. The artifact's identity is deemed to be verified if any of the + specified matchers match against the identity. + items: + description: |- + OIDCIdentityMatch specifies options for verifying the certificate identity, + i.e. the issuer and the subject of the certificate. + properties: + issuer: + description: |- + Issuer specifies the regex pattern to match against to verify + the OIDC issuer in the Fulcio certificate. The pattern must be a + valid Go regular expression. + type: string + subject: + description: |- + Subject specifies the regex pattern to match against to verify + the identity subject in the Fulcio certificate. The pattern must + be a valid Go regular expression. + type: string + required: + - issuer + - subject + type: object + type: array + provider: + default: cosign + description: Provider specifies the technology used to sign the OCI Artifact. + enum: + - cosign + - notation + type: string + secretRef: + description: |- + SecretRef specifies the Kubernetes Secret containing the + trusted public keys. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - provider + type: object + version: + default: '*' + description: |- + Version is the chart version semver expression, ignored for charts from + GitRepository and Bucket sources. Defaults to latest when omitted. + type: string + required: + - chart + - interval + - sourceRef + type: object + status: + default: + observedGeneration: -1 + description: HelmChartStatus records the observed state of the HelmChart. + properties: + artifact: + description: Artifact represents the output of the last successful reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the HelmChart. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedChartName: + description: |- + ObservedChartName is the last observed chart name as specified by the + resolved chart reference. + type: string + observedGeneration: + description: |- + ObservedGeneration is the last observed generation of the HelmChart + object. + format: int64 + type: integer + observedSourceArtifactRevision: + description: |- + ObservedSourceArtifactRevision is the last observed Artifact.Revision + of the HelmChartSpec.SourceRef. + type: string + observedValuesFiles: + description: |- + ObservedValuesFiles are the observed value files of the last successful + reconciliation. + It matches the chart in the last successfully reconciled artifact. + items: + type: string + type: array + url: + description: |- + URL is the dynamic fetch link for the latest Artifact. + It is provided on a "best effort" basis, and using the precise + BucketStatus.Artifact data is recommended. + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: helmreleases.helm.toolkit.fluxcd.io +spec: + group: helm.toolkit.fluxcd.io + names: + kind: HelmRelease + listKind: HelmReleaseList + plural: helmreleases + shortNames: + - hr + singular: helmrelease + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + name: v2 + schema: + openAPIV3Schema: + description: HelmRelease is the Schema for the helmreleases API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: HelmReleaseSpec defines the desired state of a Helm release. + properties: + chart: + description: |- + Chart defines the template of the v1.HelmChart that should be created + for this HelmRelease. + properties: + metadata: + description: ObjectMeta holds the template for metadata like labels and annotations. + properties: + annotations: + additionalProperties: + type: string + description: |- + Annotations is an unstructured key value map stored with a resource that may be + set by external tools to store and retrieve arbitrary metadata. They are not + queryable and should be preserved when modifying objects. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + type: object + labels: + additionalProperties: + type: string + description: |- + Map of string keys and values that can be used to organize and categorize + (scope and select) objects. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + type: object + type: object + spec: + description: Spec holds the template for the v1.HelmChartSpec for this HelmRelease. + properties: + chart: + description: The name or path the Helm chart is available at in the SourceRef. + maxLength: 2048 + minLength: 1 + type: string + ignoreMissingValuesFiles: + description: IgnoreMissingValuesFiles controls whether to silently ignore missing values files rather than failing. + type: boolean + interval: + description: |- + Interval at which to check the v1.Source for updates. Defaults to + 'HelmReleaseSpec.Interval'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + reconcileStrategy: + default: ChartVersion + description: |- + Determines what enables the creation of a new artifact. Valid values are + ('ChartVersion', 'Revision'). + See the documentation of the values for an explanation on their behavior. + Defaults to ChartVersion when omitted. + enum: + - ChartVersion + - Revision + type: string + sourceRef: + description: The name and namespace of the v1.Source the chart is available at. + properties: + apiVersion: + description: APIVersion of the referent. + type: string + kind: + description: Kind of the referent. + enum: + - HelmRepository + - GitRepository + - Bucket + type: string + name: + description: Name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: Namespace of the referent. + maxLength: 63 + minLength: 1 + type: string + required: + - kind + - name + type: object + valuesFiles: + description: |- + Alternative list of values files to use as the chart values (values.yaml + is not included by default), expected to be a relative path in the SourceRef. + Values files are merged in the order of this list with the last file overriding + the first. Ignored when omitted. + items: + type: string + type: array + verify: + description: |- + Verify contains the secret name containing the trusted public keys + used to verify the signature and specifies which provider to use to check + whether OCI image is authentic. + This field is only supported for OCI sources. + Chart dependencies, which are not bundled in the umbrella chart artifact, + are not verified. + properties: + provider: + default: cosign + description: Provider specifies the technology used to sign the OCI Helm chart. + enum: + - cosign + - notation + type: string + secretRef: + description: |- + SecretRef specifies the Kubernetes Secret containing the + trusted public keys. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - provider + type: object + version: + default: '*' + description: |- + Version semver expression, ignored for charts from v1.GitRepository and + v1beta2.Bucket sources. Defaults to latest when omitted. + type: string + required: + - chart + - sourceRef + type: object + required: + - spec + type: object + chartRef: + description: |- + ChartRef holds a reference to a source controller resource containing the + Helm chart artifact. + properties: + apiVersion: + description: APIVersion of the referent. + type: string + kind: + description: Kind of the referent. + enum: + - OCIRepository + - HelmChart + - ExternalArtifact + type: string + name: + description: Name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace of the referent, defaults to the namespace of the Kubernetes + resource object that contains the reference. + maxLength: 63 + minLength: 1 + type: string + required: + - kind + - name + type: object + commonMetadata: + description: |- + CommonMetadata specifies the common labels and annotations that are + applied to all resources. Any existing label or annotation will be + overridden if its key matches a common one. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to the object's metadata. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to the object's metadata. + type: object + type: object + dependsOn: + description: |- + DependsOn may contain a DependencyReference slice with + references to HelmRelease resources that must be ready before this HelmRelease + can be reconciled. + items: + description: DependencyReference defines a HelmRelease dependency on another HelmRelease resource. + properties: + name: + description: Name of the referent. + type: string + namespace: + description: |- + Namespace of the referent, defaults to the namespace of the HelmRelease + resource object that contains the reference. + type: string + readyExpr: + description: |- + ReadyExpr is a CEL expression that can be used to assess the readiness + of a dependency. When specified, the built-in readiness check + is replaced by the logic defined in the CEL expression. + To make the CEL expression additive to the built-in readiness check, + the feature gate `AdditiveCELDependencyCheck` must be set to `true`. + type: string + required: + - name + type: object + type: array + driftDetection: + description: |- + DriftDetection holds the configuration for detecting and handling + differences between the manifest in the Helm storage and the resources + currently existing in the cluster. + properties: + ignore: + description: |- + Ignore contains a list of rules for specifying which changes to ignore + during diffing. + items: + description: |- + IgnoreRule defines a rule to selectively disregard specific changes during + the drift detection process. + properties: + paths: + description: |- + Paths is a list of JSON Pointer (RFC 6901) paths to be excluded from + consideration in a Kubernetes object. + items: + type: string + type: array + target: + description: |- + Target is a selector for specifying Kubernetes objects to which this + rule applies. + If Target is not set, the Paths will be ignored for all Kubernetes + objects within the manifest of the Helm release. + properties: + annotationSelector: + description: |- + AnnotationSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource annotations. + type: string + group: + description: |- + Group is the API group to select resources from. + Together with Version and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + kind: + description: |- + Kind of the API Group to select resources from. + Together with Group and Version it is capable of unambiguously + identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + labelSelector: + description: |- + LabelSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource labels. + type: string + name: + description: Name to match resources with. + type: string + namespace: + description: Namespace to select resources from. + type: string + version: + description: |- + Version of the API Group to select resources from. + Together with Group and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + type: object + required: + - paths + type: object + type: array + mode: + description: |- + Mode defines how differences should be handled between the Helm manifest + and the manifest currently applied to the cluster. + If not explicitly set, it defaults to DiffModeDisabled. + enum: + - enabled + - warn + - disabled + type: string + type: object + install: + description: Install holds the configuration for Helm install actions for this HelmRelease. + properties: + crds: + description: |- + CRDs upgrade CRDs from the Helm Chart's crds directory according + to the CRD upgrade policy provided here. Valid values are `Skip`, + `Create` or `CreateReplace`. Default is `Create` and if omitted + CRDs are installed but not updated. + + Skip: do neither install nor replace (update) any CRDs. + + Create: new CRDs are created, existing CRDs are neither updated nor deleted. + + CreateReplace: new CRDs are created, existing CRDs are updated (replaced) + but not deleted. + + By default, CRDs are applied (installed) during Helm install action. + With this option users can opt in to CRD replace existing CRDs on Helm + install actions, which is not (yet) natively supported by Helm. + https://helm.sh/docs/chart_best_practices/custom_resource_definitions. + enum: + - Skip + - Create + - CreateReplace + type: string + createNamespace: + description: |- + CreateNamespace tells the Helm install action to create the + HelmReleaseSpec.TargetNamespace if it does not exist yet. + On uninstall, the namespace will not be garbage collected. + type: boolean + disableHooks: + description: DisableHooks prevents hooks from running during the Helm install action. + type: boolean + disableOpenAPIValidation: + description: |- + DisableOpenAPIValidation prevents the Helm install action from validating + rendered templates against the Kubernetes OpenAPI Schema. + type: boolean + disableSchemaValidation: + description: |- + DisableSchemaValidation prevents the Helm install action from validating + the values against the JSON Schema. + type: boolean + disableTakeOwnership: + description: |- + DisableTakeOwnership disables taking ownership of existing resources + during the Helm install action. Defaults to false. + type: boolean + disableWait: + description: |- + DisableWait disables the waiting for resources to be ready after a Helm + install has been performed. + type: boolean + disableWaitForJobs: + description: |- + DisableWaitForJobs disables waiting for jobs to complete after a Helm + install has been performed. + type: boolean + remediation: + description: |- + Remediation holds the remediation configuration for when the Helm install + action for the HelmRelease fails. The default is to not perform any action. + properties: + ignoreTestFailures: + description: |- + IgnoreTestFailures tells the controller to skip remediation when the Helm + tests are run after an install action but fail. Defaults to + 'Test.IgnoreFailures'. + type: boolean + remediateLastFailure: + description: |- + RemediateLastFailure tells the controller to remediate the last failure, when + no retries remain. Defaults to 'false'. + type: boolean + retries: + description: |- + Retries is the number of retries that should be attempted on failures before + bailing. Remediation, using an uninstall, is performed between each attempt. + Defaults to '0', a negative integer equals to unlimited retries. + type: integer + type: object + replace: + description: |- + Replace tells the Helm install action to re-use the 'ReleaseName', but only + if that name is a deleted release which remains in the history. + type: boolean + skipCRDs: + description: |- + SkipCRDs tells the Helm install action to not install any CRDs. By default, + CRDs are installed if not already present. + + Deprecated use CRD policy (`crds`) attribute with value `Skip` instead. + type: boolean + strategy: + description: |- + Strategy defines the install strategy to use for this HelmRelease. + Defaults to 'RemediateOnFailure'. + properties: + name: + description: Name of the install strategy. + enum: + - RemediateOnFailure + - RetryOnFailure + type: string + retryInterval: + description: |- + RetryInterval is the interval at which to retry a failed install. + Can be used only when Name is set to RetryOnFailure. + Defaults to '5m'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + required: + - name + type: object + x-kubernetes-validations: + - message: .retryInterval cannot be set when .name is 'RemediateOnFailure' + rule: '!has(self.retryInterval) || self.name != ''RemediateOnFailure''' + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like + Jobs for hooks) during the performance of a Helm install action. Defaults to + 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + interval: + description: Interval at which to reconcile the Helm release. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + kubeConfig: + description: |- + KubeConfig for reconciling the HelmRelease on a remote cluster. + When used in combination with HelmReleaseSpec.ServiceAccountName, + forces the controller to act on behalf of that Service Account at the + target cluster. + If the --default-service-account flag is set, its value will be used as + a controller level fallback for when HelmReleaseSpec.ServiceAccountName + is empty. + properties: + configMapRef: + description: |- + ConfigMapRef holds an optional name of a ConfigMap that contains + the following keys: + + - `provider`: the provider to use. One of `aws`, `azure`, `gcp`, or + `generic`. Required. + - `cluster`: the fully qualified resource name of the Kubernetes + cluster in the cloud provider API. Not used by the `generic` + provider. Required when one of `address` or `ca.crt` is not set. + - `address`: the address of the Kubernetes API server. Required + for `generic`. For the other providers, if not specified, the + first address in the cluster resource will be used, and if + specified, it must match one of the addresses in the cluster + resource. + If audiences is not set, will be used as the audience for the + `generic` provider. + - `ca.crt`: the optional PEM-encoded CA certificate for the + Kubernetes API server. If not set, the controller will use the + CA certificate from the cluster resource. + - `audiences`: the optional audiences as a list of + line-break-separated strings for the Kubernetes ServiceAccount + token. Defaults to the `address` for the `generic` provider, or + to specific values for the other providers depending on the + provider. + - `serviceAccountName`: the optional name of the Kubernetes + ServiceAccount in the same namespace that should be used + for authentication. If not specified, the controller + ServiceAccount will be used. + + Mutually exclusive with SecretRef. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + secretRef: + description: |- + SecretRef holds an optional name of a secret that contains a key with + the kubeconfig file as the value. If no key is set, the key will default + to 'value'. Mutually exclusive with ConfigMapRef. + It is recommended that the kubeconfig is self-contained, and the secret + is regularly updated if credentials such as a cloud-access-token expire. + Cloud specific `cmd-path` auth helpers will not function without adding + binaries and credentials to the Pod that is responsible for reconciling + Kubernetes resources. Supported only for the generic provider. + properties: + key: + description: Key in the Secret, when not specified an implementation-specific default key is used. + type: string + name: + description: Name of the Secret. + type: string + required: + - name + type: object + type: object + x-kubernetes-validations: + - message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef must be specified + rule: has(self.configMapRef) || has(self.secretRef) + - message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef must be specified + rule: '!has(self.configMapRef) || !has(self.secretRef)' + maxHistory: + description: |- + MaxHistory is the number of revisions saved by Helm for this HelmRelease. + Use '0' for an unlimited number of revisions; defaults to '5'. + type: integer + persistentClient: + description: |- + PersistentClient tells the controller to use a persistent Kubernetes + client for this release. When enabled, the client will be reused for the + duration of the reconciliation, instead of being created and destroyed + for each (step of a) Helm action. + + This can improve performance, but may cause issues with some Helm charts + that for example do create Custom Resource Definitions during installation + outside Helm's CRD lifecycle hooks, which are then not observed to be + available by e.g. post-install hooks. + + If not set, it defaults to true. + type: boolean + postRenderers: + description: |- + PostRenderers holds an array of Helm PostRenderers, which will be applied in order + of their definition. + items: + description: PostRenderer contains a Helm PostRenderer specification. + properties: + kustomize: + description: Kustomization to apply as PostRenderer. + properties: + images: + description: |- + Images is a list of (image name, new name, new tag or digest) + for changing image names, tags or digests. This can also be achieved with a + patch, but this operator is simpler to specify. + items: + description: Image contains an image name, a new name, a new tag or digest, which will replace the original name and tag. + properties: + digest: + description: |- + Digest is the value used to replace the original image tag. + If digest is present NewTag value is ignored. + type: string + name: + description: Name is a tag-less image name. + type: string + newName: + description: NewName is the value used to replace the original name. + type: string + newTag: + description: NewTag is the value used to replace the original tag. + type: string + required: + - name + type: object + type: array + patches: + description: |- + Strategic merge and JSON patches, defined as inline YAML objects, + capable of targeting objects based on kind, label and annotation selectors. + items: + description: |- + Patch contains an inline StrategicMerge or JSON6902 patch, and the target the patch should + be applied to. + properties: + patch: + description: |- + Patch contains an inline StrategicMerge patch or an inline JSON6902 patch with + an array of operation objects. + type: string + target: + description: Target points to the resources that the patch document should be applied to. + properties: + annotationSelector: + description: |- + AnnotationSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource annotations. + type: string + group: + description: |- + Group is the API group to select resources from. + Together with Version and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + kind: + description: |- + Kind of the API Group to select resources from. + Together with Group and Version it is capable of unambiguously + identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + labelSelector: + description: |- + LabelSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource labels. + type: string + name: + description: Name to match resources with. + type: string + namespace: + description: Namespace to select resources from. + type: string + version: + description: |- + Version of the API Group to select resources from. + Together with Group and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + type: object + required: + - patch + type: object + type: array + type: object + type: object + type: array + releaseName: + description: |- + ReleaseName used for the Helm release. Defaults to a composition of + '[TargetNamespace-]Name'. + maxLength: 53 + minLength: 1 + type: string + rollback: + description: Rollback holds the configuration for Helm rollback actions for this HelmRelease. + properties: + cleanupOnFail: + description: |- + CleanupOnFail allows deletion of new resources created during the Helm + rollback action when it fails. + type: boolean + disableHooks: + description: DisableHooks prevents hooks from running during the Helm rollback action. + type: boolean + disableWait: + description: |- + DisableWait disables the waiting for resources to be ready after a Helm + rollback has been performed. + type: boolean + disableWaitForJobs: + description: |- + DisableWaitForJobs disables waiting for jobs to complete after a Helm + rollback has been performed. + type: boolean + force: + description: Force forces resource updates through a replacement strategy. + type: boolean + recreate: + description: Recreate performs pod restarts for the resource if applicable. + type: boolean + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like + Jobs for hooks) during the performance of a Helm rollback action. Defaults to + 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + serviceAccountName: + description: |- + The name of the Kubernetes service account to impersonate + when reconciling this HelmRelease. + maxLength: 253 + minLength: 1 + type: string + storageNamespace: + description: |- + StorageNamespace used for the Helm storage. + Defaults to the namespace of the HelmRelease. + maxLength: 63 + minLength: 1 + type: string + suspend: + description: |- + Suspend tells the controller to suspend reconciliation for this HelmRelease, + it does not apply to already started reconciliations. Defaults to false. + type: boolean + targetNamespace: + description: |- + TargetNamespace to target when performing operations for the HelmRelease. + Defaults to the namespace of the HelmRelease. + maxLength: 63 + minLength: 1 + type: string + test: + description: Test holds the configuration for Helm test actions for this HelmRelease. + properties: + enable: + description: |- + Enable enables Helm test actions for this HelmRelease after an Helm install + or upgrade action has been performed. + type: boolean + filters: + description: Filters is a list of tests to run or exclude from running. + items: + description: Filter holds the configuration for individual Helm test filters. + properties: + exclude: + description: Exclude specifies whether the named test should be excluded. + type: boolean + name: + description: Name is the name of the test. + maxLength: 253 + minLength: 1 + type: string + required: + - name + type: object + type: array + ignoreFailures: + description: |- + IgnoreFailures tells the controller to skip remediation when the Helm tests + are run but fail. Can be overwritten for tests run after install or upgrade + actions in 'Install.IgnoreTestFailures' and 'Upgrade.IgnoreTestFailures'. + type: boolean + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation during + the performance of a Helm test action. Defaults to 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like Jobs + for hooks) during the performance of a Helm action. Defaults to '5m0s'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + uninstall: + description: Uninstall holds the configuration for Helm uninstall actions for this HelmRelease. + properties: + deletionPropagation: + default: background + description: |- + DeletionPropagation specifies the deletion propagation policy when + a Helm uninstall is performed. + enum: + - background + - foreground + - orphan + type: string + disableHooks: + description: DisableHooks prevents hooks from running during the Helm rollback action. + type: boolean + disableWait: + description: |- + DisableWait disables waiting for all the resources to be deleted after + a Helm uninstall is performed. + type: boolean + keepHistory: + description: |- + KeepHistory tells Helm to remove all associated resources and mark the + release as deleted, but retain the release history. + type: boolean + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like + Jobs for hooks) during the performance of a Helm uninstall action. Defaults + to 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + upgrade: + description: Upgrade holds the configuration for Helm upgrade actions for this HelmRelease. + properties: + cleanupOnFail: + description: |- + CleanupOnFail allows deletion of new resources created during the Helm + upgrade action when it fails. + type: boolean + crds: + description: |- + CRDs upgrade CRDs from the Helm Chart's crds directory according + to the CRD upgrade policy provided here. Valid values are `Skip`, + `Create` or `CreateReplace`. Default is `Skip` and if omitted + CRDs are neither installed nor upgraded. + + Skip: do neither install nor replace (update) any CRDs. + + Create: new CRDs are created, existing CRDs are neither updated nor deleted. + + CreateReplace: new CRDs are created, existing CRDs are updated (replaced) + but not deleted. + + By default, CRDs are not applied during Helm upgrade action. With this + option users can opt-in to CRD upgrade, which is not (yet) natively supported by Helm. + https://helm.sh/docs/chart_best_practices/custom_resource_definitions. + enum: + - Skip + - Create + - CreateReplace + type: string + disableHooks: + description: DisableHooks prevents hooks from running during the Helm upgrade action. + type: boolean + disableOpenAPIValidation: + description: |- + DisableOpenAPIValidation prevents the Helm upgrade action from validating + rendered templates against the Kubernetes OpenAPI Schema. + type: boolean + disableSchemaValidation: + description: |- + DisableSchemaValidation prevents the Helm upgrade action from validating + the values against the JSON Schema. + type: boolean + disableTakeOwnership: + description: |- + DisableTakeOwnership disables taking ownership of existing resources + during the Helm upgrade action. Defaults to false. + type: boolean + disableWait: + description: |- + DisableWait disables the waiting for resources to be ready after a Helm + upgrade has been performed. + type: boolean + disableWaitForJobs: + description: |- + DisableWaitForJobs disables waiting for jobs to complete after a Helm + upgrade has been performed. + type: boolean + force: + description: Force forces resource updates through a replacement strategy. + type: boolean + preserveValues: + description: |- + PreserveValues will make Helm reuse the last release's values and merge in + overrides from 'Values'. Setting this flag makes the HelmRelease + non-declarative. + type: boolean + remediation: + description: |- + Remediation holds the remediation configuration for when the Helm upgrade + action for the HelmRelease fails. The default is to not perform any action. + properties: + ignoreTestFailures: + description: |- + IgnoreTestFailures tells the controller to skip remediation when the Helm + tests are run after an upgrade action but fail. + Defaults to 'Test.IgnoreFailures'. + type: boolean + remediateLastFailure: + description: |- + RemediateLastFailure tells the controller to remediate the last failure, when + no retries remain. Defaults to 'false' unless 'Retries' is greater than 0. + type: boolean + retries: + description: |- + Retries is the number of retries that should be attempted on failures before + bailing. Remediation, using 'Strategy', is performed between each attempt. + Defaults to '0', a negative integer equals to unlimited retries. + type: integer + strategy: + description: Strategy to use for failure remediation. Defaults to 'rollback'. + enum: + - rollback + - uninstall + type: string + type: object + strategy: + description: |- + Strategy defines the upgrade strategy to use for this HelmRelease. + Defaults to 'RemediateOnFailure'. + properties: + name: + description: Name of the upgrade strategy. + enum: + - RemediateOnFailure + - RetryOnFailure + type: string + retryInterval: + description: |- + RetryInterval is the interval at which to retry a failed upgrade. + Can be used only when Name is set to RetryOnFailure. + Defaults to '5m'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + required: + - name + type: object + x-kubernetes-validations: + - message: .retryInterval can only be set when .name is 'RetryOnFailure' + rule: '!has(self.retryInterval) || self.name == ''RetryOnFailure''' + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like + Jobs for hooks) during the performance of a Helm upgrade action. Defaults to + 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + values: + description: Values holds the values for this Helm release. + x-kubernetes-preserve-unknown-fields: true + valuesFrom: + description: |- + ValuesFrom holds references to resources containing Helm values for this HelmRelease, + and information about how they should be merged. + items: + description: |- + ValuesReference contains a reference to a resource containing Helm values, + and optionally the key they can be found at. + properties: + kind: + description: Kind of the values referent, valid values are ('Secret', 'ConfigMap'). + enum: + - Secret + - ConfigMap + type: string + name: + description: |- + Name of the values referent. Should reside in the same namespace as the + referring resource. + maxLength: 253 + minLength: 1 + type: string + optional: + description: |- + Optional marks this ValuesReference as optional. When set, a not found error + for the values reference is ignored, but any ValuesKey, TargetPath or + transient error will still result in a reconciliation failure. + type: boolean + targetPath: + description: |- + TargetPath is the YAML dot notation path the value should be merged at. When + set, the ValuesKey is expected to be a single flat value. Defaults to 'None', + which results in the values getting merged at the root. + maxLength: 250 + pattern: ^([a-zA-Z0-9_\-.\\\/]|\[[0-9]{1,5}\])+$ + type: string + valuesKey: + description: |- + ValuesKey is the data key where the values.yaml or a specific value can be + found at. Defaults to 'values.yaml'. + maxLength: 253 + pattern: ^[\-._a-zA-Z0-9]+$ + type: string + required: + - kind + - name + type: object + type: array + required: + - interval + type: object + x-kubernetes-validations: + - message: either chart or chartRef must be set + rule: (has(self.chart) && !has(self.chartRef)) || (!has(self.chart) && has(self.chartRef)) + status: + default: + observedGeneration: -1 + description: HelmReleaseStatus defines the observed state of a HelmRelease. + properties: + conditions: + description: Conditions holds the conditions for the HelmRelease. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + failures: + description: |- + Failures is the reconciliation failure count against the latest desired + state. It is reset after a successful reconciliation. + format: int64 + type: integer + helmChart: + description: |- + HelmChart is the namespaced name of the HelmChart resource created by + the controller for the HelmRelease. + type: string + history: + description: |- + History holds the history of Helm releases performed for this HelmRelease + up to the last successfully completed release. + items: + description: |- + Snapshot captures a point-in-time copy of the status information for a Helm release, + as managed by the controller. + properties: + apiVersion: + description: |- + APIVersion is the API version of the Snapshot. + Provisional: when the calculation method of the Digest field is changed, + this field will be used to distinguish between the old and new methods. + type: string + appVersion: + description: AppVersion is the chart app version of the release object in storage. + type: string + chartName: + description: ChartName is the chart name of the release object in storage. + type: string + chartVersion: + description: |- + ChartVersion is the chart version of the release object in + storage. + type: string + configDigest: + description: |- + ConfigDigest is the checksum of the config (better known as + "values") of the release object in storage. + It has the format of `:`. + type: string + deleted: + description: Deleted is when the release was deleted. + format: date-time + type: string + digest: + description: |- + Digest is the checksum of the release object in storage. + It has the format of `:`. + type: string + firstDeployed: + description: FirstDeployed is when the release was first deployed. + format: date-time + type: string + lastDeployed: + description: LastDeployed is when the release was last deployed. + format: date-time + type: string + name: + description: Name is the name of the release. + type: string + namespace: + description: Namespace is the namespace the release is deployed to. + type: string + ociDigest: + description: OCIDigest is the digest of the OCI artifact associated with the release. + type: string + status: + description: Status is the current state of the release. + type: string + testHooks: + additionalProperties: + description: |- + TestHookStatus holds the status information for a test hook as observed + to be run by the controller. + properties: + lastCompleted: + description: LastCompleted is the time the test hook last completed. + format: date-time + type: string + lastStarted: + description: LastStarted is the time the test hook was last started. + format: date-time + type: string + phase: + description: Phase the test hook was observed to be in. + type: string + type: object + description: |- + TestHooks is the list of test hooks for the release as observed to be + run by the controller. + type: object + version: + description: Version is the version of the release object in storage. + type: integer + required: + - chartName + - chartVersion + - configDigest + - digest + - firstDeployed + - lastDeployed + - name + - namespace + - status + - version + type: object + type: array + installFailures: + description: |- + InstallFailures is the install failure count against the latest desired + state. It is reset after a successful reconciliation. + format: int64 + type: integer + lastAttemptedConfigDigest: + description: |- + LastAttemptedConfigDigest is the digest for the config (better known as + "values") of the last reconciliation attempt. + type: string + lastAttemptedGeneration: + description: |- + LastAttemptedGeneration is the last generation the controller attempted + to reconcile. + format: int64 + type: integer + lastAttemptedReleaseAction: + description: |- + LastAttemptedReleaseAction is the last release action performed for this + HelmRelease. It is used to determine the active retry or remediation + strategy. + enum: + - install + - upgrade + type: string + lastAttemptedReleaseActionDuration: + description: |- + LastAttemptedReleaseActionDuration is the duration of the last + release action performed for this HelmRelease. + type: string + lastAttemptedRevision: + description: |- + LastAttemptedRevision is the Source revision of the last reconciliation + attempt. For OCIRepository sources, the 12 first characters of the digest are + appended to the chart version e.g. "1.2.3+1234567890ab". + type: string + lastAttemptedRevisionDigest: + description: |- + LastAttemptedRevisionDigest is the digest of the last reconciliation attempt. + This is only set for OCIRepository sources. + type: string + lastAttemptedValuesChecksum: + description: |- + LastAttemptedValuesChecksum is the SHA1 checksum for the values of the last + reconciliation attempt. + + Deprecated: Use LastAttemptedConfigDigest instead. + type: string + lastHandledForceAt: + description: |- + LastHandledForceAt holds the value of the most recent + force request value, so a change of the annotation value + can be detected. + type: string + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + lastHandledResetAt: + description: |- + LastHandledResetAt holds the value of the most recent reset request + value, so a change of the annotation value can be detected. + type: string + lastReleaseRevision: + description: |- + LastReleaseRevision is the revision of the last successful Helm release. + + Deprecated: Use History instead. + type: integer + observedCommonMetadataDigest: + description: |- + ObservedCommonMetadataDigest is the digest for the common metadata of + the last successful reconciliation attempt. + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + observedPostRenderersDigest: + description: |- + ObservedPostRenderersDigest is the digest for the post-renderers of + the last successful reconciliation attempt. + type: string + storageNamespace: + description: |- + StorageNamespace is the namespace of the Helm release storage for the + current release. + maxLength: 63 + minLength: 1 + type: string + upgradeFailures: + description: |- + UpgradeFailures is the upgrade failure count against the latest desired + state. It is reset after a successful reconciliation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + deprecated: true + deprecationWarning: v2beta2 HelmRelease is deprecated, upgrade to v2 + name: v2beta2 + schema: + openAPIV3Schema: + description: HelmRelease is the Schema for the helmreleases API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: HelmReleaseSpec defines the desired state of a Helm release. + properties: + chart: + description: |- + Chart defines the template of the v1beta2.HelmChart that should be created + for this HelmRelease. + properties: + metadata: + description: ObjectMeta holds the template for metadata like labels and annotations. + properties: + annotations: + additionalProperties: + type: string + description: |- + Annotations is an unstructured key value map stored with a resource that may be + set by external tools to store and retrieve arbitrary metadata. They are not + queryable and should be preserved when modifying objects. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + type: object + labels: + additionalProperties: + type: string + description: |- + Map of string keys and values that can be used to organize and categorize + (scope and select) objects. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + type: object + type: object + spec: + description: Spec holds the template for the v1beta2.HelmChartSpec for this HelmRelease. + properties: + chart: + description: The name or path the Helm chart is available at in the SourceRef. + maxLength: 2048 + minLength: 1 + type: string + ignoreMissingValuesFiles: + description: IgnoreMissingValuesFiles controls whether to silently ignore missing values files rather than failing. + type: boolean + interval: + description: |- + Interval at which to check the v1.Source for updates. Defaults to + 'HelmReleaseSpec.Interval'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + reconcileStrategy: + default: ChartVersion + description: |- + Determines what enables the creation of a new artifact. Valid values are + ('ChartVersion', 'Revision'). + See the documentation of the values for an explanation on their behavior. + Defaults to ChartVersion when omitted. + enum: + - ChartVersion + - Revision + type: string + sourceRef: + description: The name and namespace of the v1.Source the chart is available at. + properties: + apiVersion: + description: APIVersion of the referent. + type: string + kind: + description: Kind of the referent. + enum: + - HelmRepository + - GitRepository + - Bucket + type: string + name: + description: Name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: Namespace of the referent. + maxLength: 63 + minLength: 1 + type: string + required: + - kind + - name + type: object + valuesFile: + description: |- + Alternative values file to use as the default chart values, expected to + be a relative path in the SourceRef. Deprecated in favor of ValuesFiles, + for backwards compatibility the file defined here is merged before the + ValuesFiles items. Ignored when omitted. + type: string + valuesFiles: + description: |- + Alternative list of values files to use as the chart values (values.yaml + is not included by default), expected to be a relative path in the SourceRef. + Values files are merged in the order of this list with the last file overriding + the first. Ignored when omitted. + items: + type: string + type: array + verify: + description: |- + Verify contains the secret name containing the trusted public keys + used to verify the signature and specifies which provider to use to check + whether OCI image is authentic. + This field is only supported for OCI sources. + Chart dependencies, which are not bundled in the umbrella chart artifact, + are not verified. + properties: + provider: + default: cosign + description: Provider specifies the technology used to sign the OCI Helm chart. + enum: + - cosign + - notation + type: string + secretRef: + description: |- + SecretRef specifies the Kubernetes Secret containing the + trusted public keys. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - provider + type: object + version: + default: '*' + description: |- + Version semver expression, ignored for charts from v1beta2.GitRepository and + v1beta2.Bucket sources. Defaults to latest when omitted. + type: string + required: + - chart + - sourceRef + type: object + required: + - spec + type: object + chartRef: + description: |- + ChartRef holds a reference to a source controller resource containing the + Helm chart artifact. + + Note: this field is provisional to the v2 API, and not actively used + by v2beta2 HelmReleases. + properties: + apiVersion: + description: APIVersion of the referent. + type: string + kind: + description: Kind of the referent. + enum: + - OCIRepository + - HelmChart + type: string + name: + description: Name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace of the referent, defaults to the namespace of the Kubernetes + resource object that contains the reference. + maxLength: 63 + minLength: 1 + type: string + required: + - kind + - name + type: object + dependsOn: + description: |- + DependsOn may contain a meta.NamespacedObjectReference slice with + references to HelmRelease resources that must be ready before this HelmRelease + can be reconciled. + items: + description: |- + NamespacedObjectReference contains enough information to locate the referenced Kubernetes resource object in any + namespace. + properties: + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, when not specified it acts as LocalObjectReference. + type: string + required: + - name + type: object + type: array + driftDetection: + description: |- + DriftDetection holds the configuration for detecting and handling + differences between the manifest in the Helm storage and the resources + currently existing in the cluster. + properties: + ignore: + description: |- + Ignore contains a list of rules for specifying which changes to ignore + during diffing. + items: + description: |- + IgnoreRule defines a rule to selectively disregard specific changes during + the drift detection process. + properties: + paths: + description: |- + Paths is a list of JSON Pointer (RFC 6901) paths to be excluded from + consideration in a Kubernetes object. + items: + type: string + type: array + target: + description: |- + Target is a selector for specifying Kubernetes objects to which this + rule applies. + If Target is not set, the Paths will be ignored for all Kubernetes + objects within the manifest of the Helm release. + properties: + annotationSelector: + description: |- + AnnotationSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource annotations. + type: string + group: + description: |- + Group is the API group to select resources from. + Together with Version and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + kind: + description: |- + Kind of the API Group to select resources from. + Together with Group and Version it is capable of unambiguously + identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + labelSelector: + description: |- + LabelSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource labels. + type: string + name: + description: Name to match resources with. + type: string + namespace: + description: Namespace to select resources from. + type: string + version: + description: |- + Version of the API Group to select resources from. + Together with Group and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + type: object + required: + - paths + type: object + type: array + mode: + description: |- + Mode defines how differences should be handled between the Helm manifest + and the manifest currently applied to the cluster. + If not explicitly set, it defaults to DiffModeDisabled. + enum: + - enabled + - warn + - disabled + type: string + type: object + install: + description: Install holds the configuration for Helm install actions for this HelmRelease. + properties: + crds: + description: |- + CRDs upgrade CRDs from the Helm Chart's crds directory according + to the CRD upgrade policy provided here. Valid values are `Skip`, + `Create` or `CreateReplace`. Default is `Create` and if omitted + CRDs are installed but not updated. + + Skip: do neither install nor replace (update) any CRDs. + + Create: new CRDs are created, existing CRDs are neither updated nor deleted. + + CreateReplace: new CRDs are created, existing CRDs are updated (replaced) + but not deleted. + + By default, CRDs are applied (installed) during Helm install action. + With this option users can opt in to CRD replace existing CRDs on Helm + install actions, which is not (yet) natively supported by Helm. + https://helm.sh/docs/chart_best_practices/custom_resource_definitions. + enum: + - Skip + - Create + - CreateReplace + type: string + createNamespace: + description: |- + CreateNamespace tells the Helm install action to create the + HelmReleaseSpec.TargetNamespace if it does not exist yet. + On uninstall, the namespace will not be garbage collected. + type: boolean + disableHooks: + description: DisableHooks prevents hooks from running during the Helm install action. + type: boolean + disableOpenAPIValidation: + description: |- + DisableOpenAPIValidation prevents the Helm install action from validating + rendered templates against the Kubernetes OpenAPI Schema. + type: boolean + disableWait: + description: |- + DisableWait disables the waiting for resources to be ready after a Helm + install has been performed. + type: boolean + disableWaitForJobs: + description: |- + DisableWaitForJobs disables waiting for jobs to complete after a Helm + install has been performed. + type: boolean + remediation: + description: |- + Remediation holds the remediation configuration for when the Helm install + action for the HelmRelease fails. The default is to not perform any action. + properties: + ignoreTestFailures: + description: |- + IgnoreTestFailures tells the controller to skip remediation when the Helm + tests are run after an install action but fail. Defaults to + 'Test.IgnoreFailures'. + type: boolean + remediateLastFailure: + description: |- + RemediateLastFailure tells the controller to remediate the last failure, when + no retries remain. Defaults to 'false'. + type: boolean + retries: + description: |- + Retries is the number of retries that should be attempted on failures before + bailing. Remediation, using an uninstall, is performed between each attempt. + Defaults to '0', a negative integer equals to unlimited retries. + type: integer + type: object + replace: + description: |- + Replace tells the Helm install action to re-use the 'ReleaseName', but only + if that name is a deleted release which remains in the history. + type: boolean + skipCRDs: + description: |- + SkipCRDs tells the Helm install action to not install any CRDs. By default, + CRDs are installed if not already present. + + Deprecated use CRD policy (`crds`) attribute with value `Skip` instead. + type: boolean + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like + Jobs for hooks) during the performance of a Helm install action. Defaults to + 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + interval: + description: Interval at which to reconcile the Helm release. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + kubeConfig: + description: |- + KubeConfig for reconciling the HelmRelease on a remote cluster. + When used in combination with HelmReleaseSpec.ServiceAccountName, + forces the controller to act on behalf of that Service Account at the + target cluster. + If the --default-service-account flag is set, its value will be used as + a controller level fallback for when HelmReleaseSpec.ServiceAccountName + is empty. + properties: + configMapRef: + description: |- + ConfigMapRef holds an optional name of a ConfigMap that contains + the following keys: + + - `provider`: the provider to use. One of `aws`, `azure`, `gcp`, or + `generic`. Required. + - `cluster`: the fully qualified resource name of the Kubernetes + cluster in the cloud provider API. Not used by the `generic` + provider. Required when one of `address` or `ca.crt` is not set. + - `address`: the address of the Kubernetes API server. Required + for `generic`. For the other providers, if not specified, the + first address in the cluster resource will be used, and if + specified, it must match one of the addresses in the cluster + resource. + If audiences is not set, will be used as the audience for the + `generic` provider. + - `ca.crt`: the optional PEM-encoded CA certificate for the + Kubernetes API server. If not set, the controller will use the + CA certificate from the cluster resource. + - `audiences`: the optional audiences as a list of + line-break-separated strings for the Kubernetes ServiceAccount + token. Defaults to the `address` for the `generic` provider, or + to specific values for the other providers depending on the + provider. + - `serviceAccountName`: the optional name of the Kubernetes + ServiceAccount in the same namespace that should be used + for authentication. If not specified, the controller + ServiceAccount will be used. + + Mutually exclusive with SecretRef. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + secretRef: + description: |- + SecretRef holds an optional name of a secret that contains a key with + the kubeconfig file as the value. If no key is set, the key will default + to 'value'. Mutually exclusive with ConfigMapRef. + It is recommended that the kubeconfig is self-contained, and the secret + is regularly updated if credentials such as a cloud-access-token expire. + Cloud specific `cmd-path` auth helpers will not function without adding + binaries and credentials to the Pod that is responsible for reconciling + Kubernetes resources. Supported only for the generic provider. + properties: + key: + description: Key in the Secret, when not specified an implementation-specific default key is used. + type: string + name: + description: Name of the Secret. + type: string + required: + - name + type: object + type: object + x-kubernetes-validations: + - message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef must be specified + rule: has(self.configMapRef) || has(self.secretRef) + - message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef must be specified + rule: '!has(self.configMapRef) || !has(self.secretRef)' + maxHistory: + description: |- + MaxHistory is the number of revisions saved by Helm for this HelmRelease. + Use '0' for an unlimited number of revisions; defaults to '5'. + type: integer + persistentClient: + description: |- + PersistentClient tells the controller to use a persistent Kubernetes + client for this release. When enabled, the client will be reused for the + duration of the reconciliation, instead of being created and destroyed + for each (step of a) Helm action. + + This can improve performance, but may cause issues with some Helm charts + that for example do create Custom Resource Definitions during installation + outside Helm's CRD lifecycle hooks, which are then not observed to be + available by e.g. post-install hooks. + + If not set, it defaults to true. + type: boolean + postRenderers: + description: |- + PostRenderers holds an array of Helm PostRenderers, which will be applied in order + of their definition. + items: + description: PostRenderer contains a Helm PostRenderer specification. + properties: + kustomize: + description: Kustomization to apply as PostRenderer. + properties: + images: + description: |- + Images is a list of (image name, new name, new tag or digest) + for changing image names, tags or digests. This can also be achieved with a + patch, but this operator is simpler to specify. + items: + description: Image contains an image name, a new name, a new tag or digest, which will replace the original name and tag. + properties: + digest: + description: |- + Digest is the value used to replace the original image tag. + If digest is present NewTag value is ignored. + type: string + name: + description: Name is a tag-less image name. + type: string + newName: + description: NewName is the value used to replace the original name. + type: string + newTag: + description: NewTag is the value used to replace the original tag. + type: string + required: + - name + type: object + type: array + patches: + description: |- + Strategic merge and JSON patches, defined as inline YAML objects, + capable of targeting objects based on kind, label and annotation selectors. + items: + description: |- + Patch contains an inline StrategicMerge or JSON6902 patch, and the target the patch should + be applied to. + properties: + patch: + description: |- + Patch contains an inline StrategicMerge patch or an inline JSON6902 patch with + an array of operation objects. + type: string + target: + description: Target points to the resources that the patch document should be applied to. + properties: + annotationSelector: + description: |- + AnnotationSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource annotations. + type: string + group: + description: |- + Group is the API group to select resources from. + Together with Version and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + kind: + description: |- + Kind of the API Group to select resources from. + Together with Group and Version it is capable of unambiguously + identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + labelSelector: + description: |- + LabelSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource labels. + type: string + name: + description: Name to match resources with. + type: string + namespace: + description: Namespace to select resources from. + type: string + version: + description: |- + Version of the API Group to select resources from. + Together with Group and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + type: object + required: + - patch + type: object + type: array + patchesJson6902: + description: |- + JSON 6902 patches, defined as inline YAML objects. + + Deprecated: use Patches instead. + items: + description: JSON6902Patch contains a JSON6902 patch and the target the patch should be applied to. + properties: + patch: + description: Patch contains the JSON6902 patch document with an array of operation objects. + items: + description: |- + JSON6902 is a JSON6902 operation object. + https://datatracker.ietf.org/doc/html/rfc6902#section-4 + properties: + from: + description: |- + From contains a JSON-pointer value that references a location within the target document where the operation is + performed. The meaning of the value depends on the value of Op, and is NOT taken into account by all operations. + type: string + op: + description: |- + Op indicates the operation to perform. Its value MUST be one of "add", "remove", "replace", "move", "copy", or + "test". + https://datatracker.ietf.org/doc/html/rfc6902#section-4 + enum: + - test + - remove + - add + - replace + - move + - copy + type: string + path: + description: |- + Path contains the JSON-pointer value that references a location within the target document where the operation + is performed. The meaning of the value depends on the value of Op. + type: string + value: + description: |- + Value contains a valid JSON structure. The meaning of the value depends on the value of Op, and is NOT taken into + account by all operations. + x-kubernetes-preserve-unknown-fields: true + required: + - op + - path + type: object + type: array + target: + description: Target points to the resources that the patch document should be applied to. + properties: + annotationSelector: + description: |- + AnnotationSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource annotations. + type: string + group: + description: |- + Group is the API group to select resources from. + Together with Version and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + kind: + description: |- + Kind of the API Group to select resources from. + Together with Group and Version it is capable of unambiguously + identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + labelSelector: + description: |- + LabelSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource labels. + type: string + name: + description: Name to match resources with. + type: string + namespace: + description: Namespace to select resources from. + type: string + version: + description: |- + Version of the API Group to select resources from. + Together with Group and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + type: object + required: + - patch + - target + type: object + type: array + patchesStrategicMerge: + description: |- + Strategic merge patches, defined as inline YAML objects. + + Deprecated: use Patches instead. + items: + x-kubernetes-preserve-unknown-fields: true + type: array + type: object + type: object + type: array + releaseName: + description: |- + ReleaseName used for the Helm release. Defaults to a composition of + '[TargetNamespace-]Name'. + maxLength: 53 + minLength: 1 + type: string + rollback: + description: Rollback holds the configuration for Helm rollback actions for this HelmRelease. + properties: + cleanupOnFail: + description: |- + CleanupOnFail allows deletion of new resources created during the Helm + rollback action when it fails. + type: boolean + disableHooks: + description: DisableHooks prevents hooks from running during the Helm rollback action. + type: boolean + disableWait: + description: |- + DisableWait disables the waiting for resources to be ready after a Helm + rollback has been performed. + type: boolean + disableWaitForJobs: + description: |- + DisableWaitForJobs disables waiting for jobs to complete after a Helm + rollback has been performed. + type: boolean + force: + description: Force forces resource updates through a replacement strategy. + type: boolean + recreate: + description: Recreate performs pod restarts for the resource if applicable. + type: boolean + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like + Jobs for hooks) during the performance of a Helm rollback action. Defaults to + 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + serviceAccountName: + description: |- + The name of the Kubernetes service account to impersonate + when reconciling this HelmRelease. + maxLength: 253 + minLength: 1 + type: string + storageNamespace: + description: |- + StorageNamespace used for the Helm storage. + Defaults to the namespace of the HelmRelease. + maxLength: 63 + minLength: 1 + type: string + suspend: + description: |- + Suspend tells the controller to suspend reconciliation for this HelmRelease, + it does not apply to already started reconciliations. Defaults to false. + type: boolean + targetNamespace: + description: |- + TargetNamespace to target when performing operations for the HelmRelease. + Defaults to the namespace of the HelmRelease. + maxLength: 63 + minLength: 1 + type: string + test: + description: Test holds the configuration for Helm test actions for this HelmRelease. + properties: + enable: + description: |- + Enable enables Helm test actions for this HelmRelease after an Helm install + or upgrade action has been performed. + type: boolean + filters: + description: Filters is a list of tests to run or exclude from running. + items: + description: Filter holds the configuration for individual Helm test filters. + properties: + exclude: + description: Exclude specifies whether the named test should be excluded. + type: boolean + name: + description: Name is the name of the test. + maxLength: 253 + minLength: 1 + type: string + required: + - name + type: object + type: array + ignoreFailures: + description: |- + IgnoreFailures tells the controller to skip remediation when the Helm tests + are run but fail. Can be overwritten for tests run after install or upgrade + actions in 'Install.IgnoreTestFailures' and 'Upgrade.IgnoreTestFailures'. + type: boolean + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation during + the performance of a Helm test action. Defaults to 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like Jobs + for hooks) during the performance of a Helm action. Defaults to '5m0s'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + uninstall: + description: Uninstall holds the configuration for Helm uninstall actions for this HelmRelease. + properties: + deletionPropagation: + default: background + description: |- + DeletionPropagation specifies the deletion propagation policy when + a Helm uninstall is performed. + enum: + - background + - foreground + - orphan + type: string + disableHooks: + description: DisableHooks prevents hooks from running during the Helm rollback action. + type: boolean + disableWait: + description: |- + DisableWait disables waiting for all the resources to be deleted after + a Helm uninstall is performed. + type: boolean + keepHistory: + description: |- + KeepHistory tells Helm to remove all associated resources and mark the + release as deleted, but retain the release history. + type: boolean + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like + Jobs for hooks) during the performance of a Helm uninstall action. Defaults + to 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + upgrade: + description: Upgrade holds the configuration for Helm upgrade actions for this HelmRelease. + properties: + cleanupOnFail: + description: |- + CleanupOnFail allows deletion of new resources created during the Helm + upgrade action when it fails. + type: boolean + crds: + description: |- + CRDs upgrade CRDs from the Helm Chart's crds directory according + to the CRD upgrade policy provided here. Valid values are `Skip`, + `Create` or `CreateReplace`. Default is `Skip` and if omitted + CRDs are neither installed nor upgraded. + + Skip: do neither install nor replace (update) any CRDs. + + Create: new CRDs are created, existing CRDs are neither updated nor deleted. + + CreateReplace: new CRDs are created, existing CRDs are updated (replaced) + but not deleted. + + By default, CRDs are not applied during Helm upgrade action. With this + option users can opt-in to CRD upgrade, which is not (yet) natively supported by Helm. + https://helm.sh/docs/chart_best_practices/custom_resource_definitions. + enum: + - Skip + - Create + - CreateReplace + type: string + disableHooks: + description: DisableHooks prevents hooks from running during the Helm upgrade action. + type: boolean + disableOpenAPIValidation: + description: |- + DisableOpenAPIValidation prevents the Helm upgrade action from validating + rendered templates against the Kubernetes OpenAPI Schema. + type: boolean + disableWait: + description: |- + DisableWait disables the waiting for resources to be ready after a Helm + upgrade has been performed. + type: boolean + disableWaitForJobs: + description: |- + DisableWaitForJobs disables waiting for jobs to complete after a Helm + upgrade has been performed. + type: boolean + force: + description: Force forces resource updates through a replacement strategy. + type: boolean + preserveValues: + description: |- + PreserveValues will make Helm reuse the last release's values and merge in + overrides from 'Values'. Setting this flag makes the HelmRelease + non-declarative. + type: boolean + remediation: + description: |- + Remediation holds the remediation configuration for when the Helm upgrade + action for the HelmRelease fails. The default is to not perform any action. + properties: + ignoreTestFailures: + description: |- + IgnoreTestFailures tells the controller to skip remediation when the Helm + tests are run after an upgrade action but fail. + Defaults to 'Test.IgnoreFailures'. + type: boolean + remediateLastFailure: + description: |- + RemediateLastFailure tells the controller to remediate the last failure, when + no retries remain. Defaults to 'false' unless 'Retries' is greater than 0. + type: boolean + retries: + description: |- + Retries is the number of retries that should be attempted on failures before + bailing. Remediation, using 'Strategy', is performed between each attempt. + Defaults to '0', a negative integer equals to unlimited retries. + type: integer + strategy: + description: Strategy to use for failure remediation. Defaults to 'rollback'. + enum: + - rollback + - uninstall + type: string + type: object + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like + Jobs for hooks) during the performance of a Helm upgrade action. Defaults to + 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + values: + description: Values holds the values for this Helm release. + x-kubernetes-preserve-unknown-fields: true + valuesFrom: + description: |- + ValuesFrom holds references to resources containing Helm values for this HelmRelease, + and information about how they should be merged. + items: + description: |- + ValuesReference contains a reference to a resource containing Helm values, + and optionally the key they can be found at. + properties: + kind: + description: Kind of the values referent, valid values are ('Secret', 'ConfigMap'). + enum: + - Secret + - ConfigMap + type: string + name: + description: |- + Name of the values referent. Should reside in the same namespace as the + referring resource. + maxLength: 253 + minLength: 1 + type: string + optional: + description: |- + Optional marks this ValuesReference as optional. When set, a not found error + for the values reference is ignored, but any ValuesKey, TargetPath or + transient error will still result in a reconciliation failure. + type: boolean + targetPath: + description: |- + TargetPath is the YAML dot notation path the value should be merged at. When + set, the ValuesKey is expected to be a single flat value. Defaults to 'None', + which results in the values getting merged at the root. + maxLength: 250 + pattern: ^([a-zA-Z0-9_\-.\\\/]|\[[0-9]{1,5}\])+$ + type: string + valuesKey: + description: |- + ValuesKey is the data key where the values.yaml or a specific value can be + found at. Defaults to 'values.yaml'. + maxLength: 253 + pattern: ^[\-._a-zA-Z0-9]+$ + type: string + required: + - kind + - name + type: object + type: array + required: + - interval + type: object + x-kubernetes-validations: + - message: either chart or chartRef must be set + rule: (has(self.chart) && !has(self.chartRef)) || (!has(self.chart) && has(self.chartRef)) + status: + default: + observedGeneration: -1 + description: HelmReleaseStatus defines the observed state of a HelmRelease. + properties: + conditions: + description: Conditions holds the conditions for the HelmRelease. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + failures: + description: |- + Failures is the reconciliation failure count against the latest desired + state. It is reset after a successful reconciliation. + format: int64 + type: integer + helmChart: + description: |- + HelmChart is the namespaced name of the HelmChart resource created by + the controller for the HelmRelease. + type: string + history: + description: |- + History holds the history of Helm releases performed for this HelmRelease + up to the last successfully completed release. + items: + description: |- + Snapshot captures a point-in-time copy of the status information for a Helm release, + as managed by the controller. + properties: + apiVersion: + description: |- + APIVersion is the API version of the Snapshot. + Provisional: when the calculation method of the Digest field is changed, + this field will be used to distinguish between the old and new methods. + type: string + appVersion: + description: AppVersion is the chart app version of the release object in storage. + type: string + chartName: + description: ChartName is the chart name of the release object in storage. + type: string + chartVersion: + description: |- + ChartVersion is the chart version of the release object in + storage. + type: string + configDigest: + description: |- + ConfigDigest is the checksum of the config (better known as + "values") of the release object in storage. + It has the format of `:`. + type: string + deleted: + description: Deleted is when the release was deleted. + format: date-time + type: string + digest: + description: |- + Digest is the checksum of the release object in storage. + It has the format of `:`. + type: string + firstDeployed: + description: FirstDeployed is when the release was first deployed. + format: date-time + type: string + lastDeployed: + description: LastDeployed is when the release was last deployed. + format: date-time + type: string + name: + description: Name is the name of the release. + type: string + namespace: + description: Namespace is the namespace the release is deployed to. + type: string + ociDigest: + description: OCIDigest is the digest of the OCI artifact associated with the release. + type: string + status: + description: Status is the current state of the release. + type: string + testHooks: + additionalProperties: + description: |- + TestHookStatus holds the status information for a test hook as observed + to be run by the controller. + properties: + lastCompleted: + description: LastCompleted is the time the test hook last completed. + format: date-time + type: string + lastStarted: + description: LastStarted is the time the test hook was last started. + format: date-time + type: string + phase: + description: Phase the test hook was observed to be in. + type: string + type: object + description: |- + TestHooks is the list of test hooks for the release as observed to be + run by the controller. + type: object + version: + description: Version is the version of the release object in storage. + type: integer + required: + - chartName + - chartVersion + - configDigest + - digest + - firstDeployed + - lastDeployed + - name + - namespace + - status + - version + type: object + type: array + installFailures: + description: |- + InstallFailures is the install failure count against the latest desired + state. It is reset after a successful reconciliation. + format: int64 + type: integer + lastAppliedRevision: + description: |- + LastAppliedRevision is the revision of the last successfully applied + source. + + Deprecated: the revision can now be found in the History. + type: string + lastAttemptedConfigDigest: + description: |- + LastAttemptedConfigDigest is the digest for the config (better known as + "values") of the last reconciliation attempt. + type: string + lastAttemptedGeneration: + description: |- + LastAttemptedGeneration is the last generation the controller attempted + to reconcile. + format: int64 + type: integer + lastAttemptedReleaseAction: + description: |- + LastAttemptedReleaseAction is the last release action performed for this + HelmRelease. It is used to determine the active remediation strategy. + enum: + - install + - upgrade + type: string + lastAttemptedRevision: + description: |- + LastAttemptedRevision is the Source revision of the last reconciliation + attempt. For OCIRepository sources, the 12 first characters of the digest are + appended to the chart version e.g. "1.2.3+1234567890ab". + type: string + lastAttemptedRevisionDigest: + description: |- + LastAttemptedRevisionDigest is the digest of the last reconciliation attempt. + This is only set for OCIRepository sources. + type: string + lastAttemptedValuesChecksum: + description: |- + LastAttemptedValuesChecksum is the SHA1 checksum for the values of the last + reconciliation attempt. + + Deprecated: Use LastAttemptedConfigDigest instead. + type: string + lastHandledForceAt: + description: |- + LastHandledForceAt holds the value of the most recent force request + value, so a change of the annotation value can be detected. + type: string + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + lastHandledResetAt: + description: |- + LastHandledResetAt holds the value of the most recent reset request + value, so a change of the annotation value can be detected. + type: string + lastReleaseRevision: + description: |- + LastReleaseRevision is the revision of the last successful Helm release. + + Deprecated: Use History instead. + type: integer + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + observedPostRenderersDigest: + description: |- + ObservedPostRenderersDigest is the digest for the post-renderers of + the last successful reconciliation attempt. + type: string + storageNamespace: + description: |- + StorageNamespace is the namespace of the Helm release storage for the + current release. + maxLength: 63 + minLength: 1 + type: string + upgradeFailures: + description: |- + UpgradeFailures is the upgrade failure count against the latest desired + state. It is reset after a successful reconciliation. + format: int64 + type: integer + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: helmrepositories.source.toolkit.fluxcd.io +spec: + group: source.toolkit.fluxcd.io + names: + kind: HelmRepository + listKind: HelmRepositoryList + plural: helmrepositories + shortNames: + - helmrepo + singular: helmrepository + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.url + name: URL + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + name: v1 + schema: + openAPIV3Schema: + description: HelmRepository is the Schema for the helmrepositories API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + HelmRepositorySpec specifies the required configuration to produce an + Artifact for a Helm repository index YAML. + properties: + accessFrom: + description: |- + AccessFrom specifies an Access Control List for allowing cross-namespace + references to this object. + NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092 + properties: + namespaceSelectors: + description: |- + NamespaceSelectors is the list of namespace selectors to which this ACL applies. + Items in this list are evaluated using a logical OR operation. + items: + description: |- + NamespaceSelector selects the namespaces to which this ACL applies. + An empty map of MatchLabels matches all namespaces in a cluster. + properties: + matchLabels: + additionalProperties: + type: string + description: |- + MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + type: array + required: + - namespaceSelectors + type: object + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + registry. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + It takes precedence over the values specified in the Secret referred + to by `.spec.secretRef`. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + insecure: + description: |- + Insecure allows connecting to a non-TLS HTTP container registry. + This field is only taken into account if the .spec.type field is set to 'oci'. + type: boolean + interval: + description: |- + Interval at which the HelmRepository URL is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + passCredentials: + description: |- + PassCredentials allows the credentials from the SecretRef to be passed + on to a host that does not match the host as defined in URL. + This may be required if the host of the advertised chart URLs in the + index differ from the defined URL. + Enabling this should be done with caution, as it can potentially result + in credentials getting stolen in a MITM-attack. + type: boolean + provider: + default: generic + description: |- + Provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + This field is optional, and only taken into account if the .spec.type field is set to 'oci'. + When not specified, defaults to 'generic'. + enum: + - generic + - aws + - azure + - gcp + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing authentication credentials + for the HelmRepository. + For HTTP/S basic auth the secret must contain 'username' and 'password' + fields. + Support for TLS auth using the 'certFile' and 'keyFile', and/or 'caFile' + keys is deprecated. Please use `.spec.certSecretRef` instead. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + suspend: + description: |- + Suspend tells the controller to suspend the reconciliation of this + HelmRepository. + type: boolean + timeout: + description: |- + Timeout is used for the index fetch operation for an HTTPS helm repository, + and for remote OCI Repository operations like pulling for an OCI helm + chart by the associated HelmChart. + Its default value is 60s. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + type: + description: |- + Type of the HelmRepository. + When this field is set to "oci", the URL field value must be prefixed with "oci://". + enum: + - default + - oci + type: string + url: + description: |- + URL of the Helm repository, a valid URL contains at least a protocol and + host. + pattern: ^(http|https|oci)://.*$ + type: string + required: + - url + type: object + status: + default: + observedGeneration: -1 + description: HelmRepositoryStatus records the observed state of the HelmRepository. + properties: + artifact: + description: Artifact represents the last successful HelmRepository reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the HelmRepository. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: |- + ObservedGeneration is the last observed generation of the HelmRepository + object. + format: int64 + type: integer + url: + description: |- + URL is the dynamic fetch link for the latest Artifact. + It is provided on a "best effort" basis, and using the precise + HelmRepositoryStatus.Artifact data is recommended. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.url + name: URL + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + deprecated: true + deprecationWarning: v1beta2 HelmRepository is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: HelmRepository is the Schema for the helmrepositories API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + HelmRepositorySpec specifies the required configuration to produce an + Artifact for a Helm repository index YAML. + properties: + accessFrom: + description: |- + AccessFrom specifies an Access Control List for allowing cross-namespace + references to this object. + NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092 + properties: + namespaceSelectors: + description: |- + NamespaceSelectors is the list of namespace selectors to which this ACL applies. + Items in this list are evaluated using a logical OR operation. + items: + description: |- + NamespaceSelector selects the namespaces to which this ACL applies. + An empty map of MatchLabels matches all namespaces in a cluster. + properties: + matchLabels: + additionalProperties: + type: string + description: |- + MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + type: array + required: + - namespaceSelectors + type: object + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + registry. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + It takes precedence over the values specified in the Secret referred + to by `.spec.secretRef`. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + insecure: + description: |- + Insecure allows connecting to a non-TLS HTTP container registry. + This field is only taken into account if the .spec.type field is set to 'oci'. + type: boolean + interval: + description: |- + Interval at which the HelmRepository URL is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + passCredentials: + description: |- + PassCredentials allows the credentials from the SecretRef to be passed + on to a host that does not match the host as defined in URL. + This may be required if the host of the advertised chart URLs in the + index differ from the defined URL. + Enabling this should be done with caution, as it can potentially result + in credentials getting stolen in a MITM-attack. + type: boolean + provider: + default: generic + description: |- + Provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + This field is optional, and only taken into account if the .spec.type field is set to 'oci'. + When not specified, defaults to 'generic'. + enum: + - generic + - aws + - azure + - gcp + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing authentication credentials + for the HelmRepository. + For HTTP/S basic auth the secret must contain 'username' and 'password' + fields. + Support for TLS auth using the 'certFile' and 'keyFile', and/or 'caFile' + keys is deprecated. Please use `.spec.certSecretRef` instead. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + suspend: + description: |- + Suspend tells the controller to suspend the reconciliation of this + HelmRepository. + type: boolean + timeout: + description: |- + Timeout is used for the index fetch operation for an HTTPS helm repository, + and for remote OCI Repository operations like pulling for an OCI helm + chart by the associated HelmChart. + Its default value is 60s. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + type: + description: |- + Type of the HelmRepository. + When this field is set to "oci", the URL field value must be prefixed with "oci://". + enum: + - default + - oci + type: string + url: + description: |- + URL of the Helm repository, a valid URL contains at least a protocol and + host. + pattern: ^(http|https|oci)://.*$ + type: string + required: + - url + type: object + status: + default: + observedGeneration: -1 + description: HelmRepositoryStatus records the observed state of the HelmRepository. + properties: + artifact: + description: Artifact represents the last successful HelmRepository reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the HelmRepository. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: |- + ObservedGeneration is the last observed generation of the HelmRepository + object. + format: int64 + type: integer + url: + description: |- + URL is the dynamic fetch link for the latest Artifact. + It is provided on a "best effort" basis, and using the precise + HelmRepositoryStatus.Artifact data is recommended. + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: imagepolicies.image.toolkit.fluxcd.io +spec: + group: image.toolkit.fluxcd.io + names: + kind: ImagePolicy + listKind: ImagePolicyList + plural: imagepolicies + shortNames: + - imgpol + - imagepol + singular: imagepolicy + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.latestRef.name + name: Image + type: string + - jsonPath: .status.latestRef.tag + name: Tag + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: ImagePolicy is the Schema for the imagepolicies API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + ImagePolicySpec defines the parameters for calculating the + ImagePolicy. + properties: + digestReflectionPolicy: + default: Never + description: |- + DigestReflectionPolicy governs the setting of the `.status.latestRef.digest` field. + + Never: The digest field will always be set to the empty string. + + IfNotPresent: The digest field will be set to the digest of the elected + latest image if the field is empty and the image did not change. + + Always: The digest field will always be set to the digest of the elected + latest image. + + Default: Never. + enum: + - Always + - IfNotPresent + - Never + type: string + filterTags: + description: |- + FilterTags enables filtering for only a subset of tags based on a set of + rules. If no rules are provided, all the tags from the repository will be + ordered and compared. + properties: + extract: + description: |- + Extract allows a capture group to be extracted from the specified regular + expression pattern, useful before tag evaluation. + type: string + pattern: + description: |- + Pattern specifies a regular expression pattern used to filter for image + tags. + type: string + type: object + imageRepositoryRef: + description: |- + ImageRepositoryRef points at the object specifying the image + being scanned + properties: + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, when not specified it acts as LocalObjectReference. + type: string + required: + - name + type: object + interval: + description: |- + Interval is the length of time to wait between + refreshing the digest of the latest tag when the + reflection policy is set to "Always". + + Defaults to 10m. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + policy: + description: |- + Policy gives the particulars of the policy to be followed in + selecting the most recent image + properties: + alphabetical: + description: Alphabetical set of rules to use for alphabetical ordering of the tags. + properties: + order: + default: asc + description: |- + Order specifies the sorting order of the tags. Given the letters of the + alphabet as tags, ascending order would select Z, and descending order + would select A. + enum: + - asc + - desc + type: string + type: object + numerical: + description: Numerical set of rules to use for numerical ordering of the tags. + properties: + order: + default: asc + description: |- + Order specifies the sorting order of the tags. Given the integer values + from 0 to 9 as tags, ascending order would select 9, and descending order + would select 0. + enum: + - asc + - desc + type: string + type: object + semver: + description: |- + SemVer gives a semantic version range to check against the tags + available. + properties: + range: + description: |- + Range gives a semver range for the image tag; the highest + version within the range that's a tag yields the latest image. + type: string + required: + - range + type: object + type: object + suspend: + description: |- + This flag tells the controller to suspend subsequent policy reconciliations. + It does not apply to already started reconciliations. Defaults to false. + type: boolean + required: + - imageRepositoryRef + - policy + type: object + x-kubernetes-validations: + - message: spec.interval is only accepted when spec.digestReflectionPolicy is set to 'Always' + rule: '!has(self.interval) || (has(self.digestReflectionPolicy) && self.digestReflectionPolicy == ''Always'')' + - message: spec.interval must be set when spec.digestReflectionPolicy is set to 'Always' + rule: has(self.interval) || !has(self.digestReflectionPolicy) || self.digestReflectionPolicy != 'Always' + status: + default: + observedGeneration: -1 + description: ImagePolicyStatus defines the observed state of ImagePolicy + properties: + conditions: + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + latestRef: + description: |- + LatestRef gives the first in the list of images scanned by + the image repository, when filtered and ordered according + to the policy. + properties: + digest: + description: Digest is the image's digest. + type: string + name: + description: Name is the bare image's name. + type: string + tag: + description: Tag is the image's tag. + type: string + required: + - name + - tag + type: object + observedGeneration: + format: int64 + type: integer + observedPreviousRef: + description: |- + ObservedPreviousRef is the observed previous LatestRef. It is used + to keep track of the previous and current images. + properties: + digest: + description: Digest is the image's digest. + type: string + name: + description: Name is the bare image's name. + type: string + tag: + description: Tag is the image's tag. + type: string + required: + - name + - tag + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.latestRef.name + name: Image + type: string + - jsonPath: .status.latestRef.tag + name: Tag + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: v1beta2 ImagePolicy is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: ImagePolicy is the Schema for the imagepolicies API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + ImagePolicySpec defines the parameters for calculating the + ImagePolicy. + properties: + digestReflectionPolicy: + default: Never + description: |- + DigestReflectionPolicy governs the setting of the `.status.latestRef.digest` field. + + Never: The digest field will always be set to the empty string. + + IfNotPresent: The digest field will be set to the digest of the elected + latest image if the field is empty and the image did not change. + + Always: The digest field will always be set to the digest of the elected + latest image. + + Default: Never. + enum: + - Always + - IfNotPresent + - Never + type: string + filterTags: + description: |- + FilterTags enables filtering for only a subset of tags based on a set of + rules. If no rules are provided, all the tags from the repository will be + ordered and compared. + properties: + extract: + description: |- + Extract allows a capture group to be extracted from the specified regular + expression pattern, useful before tag evaluation. + type: string + pattern: + description: |- + Pattern specifies a regular expression pattern used to filter for image + tags. + type: string + type: object + imageRepositoryRef: + description: |- + ImageRepositoryRef points at the object specifying the image + being scanned + properties: + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, when not specified it acts as LocalObjectReference. + type: string + required: + - name + type: object + interval: + description: |- + Interval is the length of time to wait between + refreshing the digest of the latest tag when the + reflection policy is set to "Always". + + Defaults to 10m. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + policy: + description: |- + Policy gives the particulars of the policy to be followed in + selecting the most recent image + properties: + alphabetical: + description: Alphabetical set of rules to use for alphabetical ordering of the tags. + properties: + order: + default: asc + description: |- + Order specifies the sorting order of the tags. Given the letters of the + alphabet as tags, ascending order would select Z, and descending order + would select A. + enum: + - asc + - desc + type: string + type: object + numerical: + description: Numerical set of rules to use for numerical ordering of the tags. + properties: + order: + default: asc + description: |- + Order specifies the sorting order of the tags. Given the integer values + from 0 to 9 as tags, ascending order would select 9, and descending order + would select 0. + enum: + - asc + - desc + type: string + type: object + semver: + description: |- + SemVer gives a semantic version range to check against the tags + available. + properties: + range: + description: |- + Range gives a semver range for the image tag; the highest + version within the range that's a tag yields the latest image. + type: string + required: + - range + type: object + type: object + suspend: + description: |- + This flag tells the controller to suspend subsequent policy reconciliations. + It does not apply to already started reconciliations. Defaults to false. + type: boolean + required: + - imageRepositoryRef + - policy + type: object + x-kubernetes-validations: + - message: spec.interval is only accepted when spec.digestReflectionPolicy is set to 'Always' + rule: '!has(self.interval) || (has(self.digestReflectionPolicy) && self.digestReflectionPolicy == ''Always'')' + - message: spec.interval must be set when spec.digestReflectionPolicy is set to 'Always' + rule: has(self.interval) || !has(self.digestReflectionPolicy) || self.digestReflectionPolicy != 'Always' + status: + default: + observedGeneration: -1 + description: ImagePolicyStatus defines the observed state of ImagePolicy + properties: + conditions: + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + latestRef: + description: |- + LatestRef gives the first in the list of images scanned by + the image repository, when filtered and ordered according + to the policy. + properties: + digest: + description: Digest is the image's digest. + type: string + name: + description: Name is the bare image's name. + type: string + tag: + description: Tag is the image's tag. + type: string + required: + - name + - tag + type: object + observedGeneration: + format: int64 + type: integer + observedPreviousRef: + description: |- + ObservedPreviousRef is the observed previous LatestRef. It is used + to keep track of the previous and current images. + properties: + digest: + description: Digest is the image's digest. + type: string + name: + description: Name is the bare image's name. + type: string + tag: + description: Tag is the image's tag. + type: string + required: + - name + - tag + type: object + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: imagerepositories.image.toolkit.fluxcd.io +spec: + group: image.toolkit.fluxcd.io + names: + kind: ImageRepository + listKind: ImageRepositoryList + plural: imagerepositories + shortNames: + - imgrepo + - imagerepo + singular: imagerepository + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.image + name: Image + type: string + - jsonPath: .status.lastScanResult.tagCount + name: Tags + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .status.lastScanResult.scanTime + name: Last scan + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: ImageRepository is the Schema for the imagerepositories API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + ImageRepositorySpec defines the parameters for scanning an image + repository, e.g., `fluxcd/flux`. + properties: + accessFrom: + description: |- + AccessFrom defines an ACL for allowing cross-namespace references + to the ImageRepository object based on the caller's namespace labels. + properties: + namespaceSelectors: + description: |- + NamespaceSelectors is the list of namespace selectors to which this ACL applies. + Items in this list are evaluated using a logical OR operation. + items: + description: |- + NamespaceSelector selects the namespaces to which this ACL applies. + An empty map of MatchLabels matches all namespaces in a cluster. + properties: + matchLabels: + additionalProperties: + type: string + description: |- + MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + type: array + required: + - namespaceSelectors + type: object + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + registry. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + Note: Support for the `caFile`, `certFile` and `keyFile` keys has + been deprecated. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + exclusionList: + default: + - ^.*\.sig$ + description: |- + ExclusionList is a list of regex strings used to exclude certain tags + from being stored in the database. + items: + type: string + maxItems: 25 + type: array + image: + description: Image is the name of the image repository + type: string + insecure: + description: Insecure allows connecting to a non-TLS HTTP container registry. + type: boolean + interval: + description: |- + Interval is the length of time to wait between + scans of the image repository. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + provider: + default: generic + description: |- + The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + When not specified, defaults to 'generic'. + enum: + - generic + - aws + - azure + - gcp + type: string + proxySecretRef: + description: |- + ProxySecretRef specifies the Secret containing the proxy configuration + to use while communicating with the container registry. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + secretRef: + description: |- + SecretRef can be given the name of a secret containing + credentials to use for the image registry. The secret should be + created with `kubectl create secret docker-registry`, or the + equivalent. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + serviceAccountName: + description: |- + ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + the image pull if the service account has attached pull secrets. + maxLength: 253 + type: string + suspend: + description: |- + This flag tells the controller to suspend subsequent image scans. + It does not apply to already started scans. Defaults to false. + type: boolean + timeout: + description: |- + Timeout for image scanning. + Defaults to 'Interval' duration. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + required: + - image + - interval + type: object + status: + default: + observedGeneration: -1 + description: ImageRepositoryStatus defines the observed state of ImageRepository + properties: + canonicalImageName: + description: |- + CanonicalName is the name of the image repository with all the + implied bits made explicit; e.g., `docker.io/library/alpine` + rather than `alpine`. + type: string + conditions: + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + lastScanResult: + description: LastScanResult contains the number of fetched tags. + properties: + latestTags: + description: |- + LatestTags is a small sample of the tags found in the last scan. + It's the first 10 tags when sorting all the tags in descending + alphabetical order. + items: + type: string + type: array + revision: + description: Revision is a stable hash of the scanned tags. + type: string + scanTime: + description: ScanTime is the time when the last scan was performed. + format: date-time + type: string + tagCount: + description: TagCount is the number of tags found in the last scan. + type: integer + required: + - tagCount + type: object + observedExclusionList: + description: |- + ObservedExclusionList is a list of observed exclusion list. It reflects + the exclusion rules used for the observed scan result in + spec.lastScanResult. + items: + type: string + type: array + observedGeneration: + description: ObservedGeneration is the last reconciled generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.image + name: Image + type: string + - jsonPath: .status.lastScanResult.tagCount + name: Tags + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .status.lastScanResult.scanTime + name: Last scan + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: v1beta2 ImageRepository is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: ImageRepository is the Schema for the imagerepositories API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + ImageRepositorySpec defines the parameters for scanning an image + repository, e.g., `fluxcd/flux`. + properties: + accessFrom: + description: |- + AccessFrom defines an ACL for allowing cross-namespace references + to the ImageRepository object based on the caller's namespace labels. + properties: + namespaceSelectors: + description: |- + NamespaceSelectors is the list of namespace selectors to which this ACL applies. + Items in this list are evaluated using a logical OR operation. + items: + description: |- + NamespaceSelector selects the namespaces to which this ACL applies. + An empty map of MatchLabels matches all namespaces in a cluster. + properties: + matchLabels: + additionalProperties: + type: string + description: |- + MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + type: array + required: + - namespaceSelectors + type: object + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + registry. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + Note: Support for the `caFile`, `certFile` and `keyFile` keys has + been deprecated. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + exclusionList: + default: + - ^.*\.sig$ + description: |- + ExclusionList is a list of regex strings used to exclude certain tags + from being stored in the database. + items: + type: string + maxItems: 25 + type: array + image: + description: Image is the name of the image repository + type: string + insecure: + description: Insecure allows connecting to a non-TLS HTTP container registry. + type: boolean + interval: + description: |- + Interval is the length of time to wait between + scans of the image repository. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + provider: + default: generic + description: |- + The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + When not specified, defaults to 'generic'. + enum: + - generic + - aws + - azure + - gcp + type: string + proxySecretRef: + description: |- + ProxySecretRef specifies the Secret containing the proxy configuration + to use while communicating with the container registry. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + secretRef: + description: |- + SecretRef can be given the name of a secret containing + credentials to use for the image registry. The secret should be + created with `kubectl create secret docker-registry`, or the + equivalent. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + serviceAccountName: + description: |- + ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + the image pull if the service account has attached pull secrets. + maxLength: 253 + type: string + suspend: + description: |- + This flag tells the controller to suspend subsequent image scans. + It does not apply to already started scans. Defaults to false. + type: boolean + timeout: + description: |- + Timeout for image scanning. + Defaults to 'Interval' duration. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + required: + - image + - interval + type: object + status: + default: + observedGeneration: -1 + description: ImageRepositoryStatus defines the observed state of ImageRepository + properties: + canonicalImageName: + description: |- + CanonicalName is the name of the image repository with all the + implied bits made explicit; e.g., `docker.io/library/alpine` + rather than `alpine`. + type: string + conditions: + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + lastScanResult: + description: LastScanResult contains the number of fetched tags. + properties: + latestTags: + description: |- + LatestTags is a small sample of the tags found in the last scan. + It's the first 10 tags when sorting all the tags in descending + alphabetical order. + items: + type: string + type: array + revision: + description: Revision is a stable hash of the scanned tags. + type: string + scanTime: + description: ScanTime is the time when the last scan was performed. + format: date-time + type: string + tagCount: + description: TagCount is the number of tags found in the last scan. + type: integer + required: + - tagCount + type: object + observedExclusionList: + description: |- + ObservedExclusionList is a list of observed exclusion list. It reflects + the exclusion rules used for the observed scan result in + spec.lastScanResult. + items: + type: string + type: array + observedGeneration: + description: ObservedGeneration is the last reconciled generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: imageupdateautomations.image.toolkit.fluxcd.io +spec: + group: image.toolkit.fluxcd.io + names: + kind: ImageUpdateAutomation + listKind: ImageUpdateAutomationList + plural: imageupdateautomations + shortNames: + - iua + - imgupd + - imgauto + singular: imageupdateautomation + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .status.lastAutomationRunTime + name: Last run + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: ImageUpdateAutomation is the Schema for the imageupdateautomations API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ImageUpdateAutomationSpec defines the desired state of ImageUpdateAutomation + properties: + git: + description: |- + GitSpec contains all the git-specific definitions. This is + technically optional, but in practice mandatory until there are + other kinds of source allowed. + properties: + checkout: + description: |- + Checkout gives the parameters for cloning the git repository, + ready to make changes. If not present, the `spec.ref` field from the + referenced `GitRepository` or its default will be used. + properties: + ref: + description: |- + Reference gives a branch, tag or commit to clone from the Git + repository. + properties: + branch: + description: Branch to check out, defaults to 'master' if no other field is defined. + type: string + commit: + description: |- + Commit SHA to check out, takes precedence over all reference fields. + + This can be combined with Branch to shallow clone the branch, in which + the commit is expected to exist. + type: string + name: + description: |- + Name of the reference to check out; takes precedence over Branch, Tag and SemVer. + + It must be a valid Git reference: https://git-scm.com/docs/git-check-ref-format#_description + Examples: "refs/heads/main", "refs/tags/v0.1.0", "refs/pull/420/head", "refs/merge-requests/1/head" + type: string + semver: + description: SemVer tag expression to check out, takes precedence over Tag. + type: string + tag: + description: Tag to check out, takes precedence over Branch. + type: string + type: object + required: + - ref + type: object + commit: + description: Commit specifies how to commit to the git repository. + properties: + author: + description: |- + Author gives the email and optionally the name to use as the + author of commits. + properties: + email: + description: Email gives the email to provide when making a commit. + type: string + name: + description: Name gives the name to provide when making a commit. + type: string + required: + - email + type: object + messageTemplate: + description: |- + MessageTemplate provides a template for the commit message, + into which will be interpolated the details of the change made. + Note: The `Updated` template field has been removed. Use `Changed` instead. + type: string + messageTemplateValues: + additionalProperties: + type: string + description: |- + MessageTemplateValues provides additional values to be available to the + templating rendering. + type: object + signingKey: + description: SigningKey provides the option to sign commits with a GPG key + properties: + secretRef: + description: |- + SecretRef holds the name to a secret that contains a 'git.asc' key + corresponding to the ASCII Armored file containing the GPG signing + keypair as the value. It must be in the same namespace as the + ImageUpdateAutomation. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - secretRef + type: object + required: + - author + type: object + push: + description: |- + Push specifies how and where to push commits made by the + automation. If missing, commits are pushed (back) to + `.spec.checkout.branch` or its default. + properties: + branch: + description: |- + Branch specifies that commits should be pushed to the branch + named. The branch is created using `.spec.checkout.branch` as the + starting point, if it doesn't already exist. + type: string + options: + additionalProperties: + type: string + description: |- + Options specifies the push options that are sent to the Git + server when performing a push operation. For details, see: + https://git-scm.com/docs/git-push#Documentation/git-push.txt---push-optionltoptiongt + type: object + refspec: + description: |- + Refspec specifies the Git Refspec to use for a push operation. + If both Branch and Refspec are provided, then the commit is pushed + to the branch and also using the specified refspec. + For more details about Git Refspecs, see: + https://git-scm.com/book/en/v2/Git-Internals-The-Refspec + type: string + type: object + required: + - commit + type: object + interval: + description: |- + Interval gives an lower bound for how often the automation + run should be attempted. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + policySelector: + description: |- + PolicySelector allows to filter applied policies based on labels. + By default includes all policies in namespace. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + sourceRef: + description: |- + SourceRef refers to the resource giving access details + to a git repository. + properties: + apiVersion: + description: API version of the referent. + type: string + kind: + default: GitRepository + description: Kind of the referent. + enum: + - GitRepository + type: string + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, defaults to the namespace of the Kubernetes resource object that contains the reference. + type: string + required: + - kind + - name + type: object + suspend: + description: |- + Suspend tells the controller to not run this automation, until + it is unset (or set to false). Defaults to false. + type: boolean + update: + default: + strategy: Setters + description: |- + Update gives the specification for how to update the files in + the repository. This can be left empty, to use the default + value. + properties: + path: + description: |- + Path to the directory containing the manifests to be updated. + Defaults to 'None', which translates to the root path + of the GitRepositoryRef. + type: string + strategy: + default: Setters + description: Strategy names the strategy to be used. + enum: + - Setters + type: string + type: object + required: + - interval + - sourceRef + type: object + status: + default: + observedGeneration: -1 + description: ImageUpdateAutomationStatus defines the observed state of ImageUpdateAutomation + properties: + conditions: + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + lastAutomationRunTime: + description: |- + LastAutomationRunTime records the last time the controller ran + this automation through to completion (even if no updates were + made). + format: date-time + type: string + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + lastPushCommit: + description: |- + LastPushCommit records the SHA1 of the last commit made by the + controller, for this automation object + type: string + lastPushTime: + description: LastPushTime records the time of the last pushed change. + format: date-time + type: string + observedGeneration: + format: int64 + type: integer + observedPolicies: + additionalProperties: + description: ImageRef represents an image reference. + properties: + digest: + description: Digest is the image's digest. + type: string + name: + description: Name is the bare image's name. + type: string + tag: + description: Tag is the image's tag. + type: string + required: + - name + - tag + type: object + description: |- + ObservedPolicies is the list of observed ImagePolicies that were + considered by the ImageUpdateAutomation update process. + type: object + observedSourceRevision: + description: |- + ObservedPolicies []ObservedPolicy `json:"observedPolicies,omitempty"` + ObservedSourceRevision is the last observed source revision. This can be + used to determine if the source has been updated since last observation. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .status.lastAutomationRunTime + name: Last run + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: v1beta2 ImageUpdateAutomation is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: ImageUpdateAutomation is the Schema for the imageupdateautomations API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ImageUpdateAutomationSpec defines the desired state of ImageUpdateAutomation + properties: + git: + description: |- + GitSpec contains all the git-specific definitions. This is + technically optional, but in practice mandatory until there are + other kinds of source allowed. + properties: + checkout: + description: |- + Checkout gives the parameters for cloning the git repository, + ready to make changes. If not present, the `spec.ref` field from the + referenced `GitRepository` or its default will be used. + properties: + ref: + description: |- + Reference gives a branch, tag or commit to clone from the Git + repository. + properties: + branch: + description: Branch to check out, defaults to 'master' if no other field is defined. + type: string + commit: + description: |- + Commit SHA to check out, takes precedence over all reference fields. + + This can be combined with Branch to shallow clone the branch, in which + the commit is expected to exist. + type: string + name: + description: |- + Name of the reference to check out; takes precedence over Branch, Tag and SemVer. + + It must be a valid Git reference: https://git-scm.com/docs/git-check-ref-format#_description + Examples: "refs/heads/main", "refs/tags/v0.1.0", "refs/pull/420/head", "refs/merge-requests/1/head" + type: string + semver: + description: SemVer tag expression to check out, takes precedence over Tag. + type: string + tag: + description: Tag to check out, takes precedence over Branch. + type: string + type: object + required: + - ref + type: object + commit: + description: Commit specifies how to commit to the git repository. + properties: + author: + description: |- + Author gives the email and optionally the name to use as the + author of commits. + properties: + email: + description: Email gives the email to provide when making a commit. + type: string + name: + description: Name gives the name to provide when making a commit. + type: string + required: + - email + type: object + messageTemplate: + description: |- + MessageTemplate provides a template for the commit message, + into which will be interpolated the details of the change made. + Note: The `Updated` template field has been removed. Use `Changed` instead. + type: string + messageTemplateValues: + additionalProperties: + type: string + description: |- + MessageTemplateValues provides additional values to be available to the + templating rendering. + type: object + signingKey: + description: SigningKey provides the option to sign commits with a GPG key + properties: + secretRef: + description: |- + SecretRef holds the name to a secret that contains a 'git.asc' key + corresponding to the ASCII Armored file containing the GPG signing + keypair as the value. It must be in the same namespace as the + ImageUpdateAutomation. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - secretRef + type: object + required: + - author + type: object + push: + description: |- + Push specifies how and where to push commits made by the + automation. If missing, commits are pushed (back) to + `.spec.checkout.branch` or its default. + properties: + branch: + description: |- + Branch specifies that commits should be pushed to the branch + named. The branch is created using `.spec.checkout.branch` as the + starting point, if it doesn't already exist. + type: string + options: + additionalProperties: + type: string + description: |- + Options specifies the push options that are sent to the Git + server when performing a push operation. For details, see: + https://git-scm.com/docs/git-push#Documentation/git-push.txt---push-optionltoptiongt + type: object + refspec: + description: |- + Refspec specifies the Git Refspec to use for a push operation. + If both Branch and Refspec are provided, then the commit is pushed + to the branch and also using the specified refspec. + For more details about Git Refspecs, see: + https://git-scm.com/book/en/v2/Git-Internals-The-Refspec + type: string + type: object + required: + - commit + type: object + interval: + description: |- + Interval gives an lower bound for how often the automation + run should be attempted. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + policySelector: + description: |- + PolicySelector allows to filter applied policies based on labels. + By default includes all policies in namespace. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + sourceRef: + description: |- + SourceRef refers to the resource giving access details + to a git repository. + properties: + apiVersion: + description: API version of the referent. + type: string + kind: + default: GitRepository + description: Kind of the referent. + enum: + - GitRepository + type: string + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, defaults to the namespace of the Kubernetes resource object that contains the reference. + type: string + required: + - kind + - name + type: object + suspend: + description: |- + Suspend tells the controller to not run this automation, until + it is unset (or set to false). Defaults to false. + type: boolean + update: + default: + strategy: Setters + description: |- + Update gives the specification for how to update the files in + the repository. This can be left empty, to use the default + value. + properties: + path: + description: |- + Path to the directory containing the manifests to be updated. + Defaults to 'None', which translates to the root path + of the GitRepositoryRef. + type: string + strategy: + default: Setters + description: Strategy names the strategy to be used. + enum: + - Setters + type: string + type: object + required: + - interval + - sourceRef + type: object + status: + default: + observedGeneration: -1 + description: ImageUpdateAutomationStatus defines the observed state of ImageUpdateAutomation + properties: + conditions: + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + lastAutomationRunTime: + description: |- + LastAutomationRunTime records the last time the controller ran + this automation through to completion (even if no updates were + made). + format: date-time + type: string + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + lastPushCommit: + description: |- + LastPushCommit records the SHA1 of the last commit made by the + controller, for this automation object + type: string + lastPushTime: + description: LastPushTime records the time of the last pushed change. + format: date-time + type: string + observedGeneration: + format: int64 + type: integer + observedPolicies: + additionalProperties: + description: ImageRef represents an image reference. + properties: + digest: + description: Digest is the image's digest. + type: string + name: + description: Name is the bare image's name. + type: string + tag: + description: Tag is the image's tag. + type: string + required: + - name + - tag + type: object + description: |- + ObservedPolicies is the list of observed ImagePolicies that were + considered by the ImageUpdateAutomation update process. + type: object + observedSourceRevision: + description: |- + ObservedPolicies []ObservedPolicy `json:"observedPolicies,omitempty"` + ObservedSourceRevision is the last observed source revision. This can be + used to determine if the source has been updated since last observation. + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: kustomizations.kustomize.toolkit.fluxcd.io +spec: + group: kustomize.toolkit.fluxcd.io + names: + kind: Kustomization + listKind: KustomizationList + plural: kustomizations + shortNames: + - ks + singular: kustomization + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + name: v1 + schema: + openAPIV3Schema: + description: Kustomization is the Schema for the kustomizations API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + KustomizationSpec defines the configuration to calculate the desired state + from a Source using Kustomize. + properties: + commonMetadata: + description: |- + CommonMetadata specifies the common labels and annotations that are + applied to all resources. Any existing label or annotation will be + overridden if its key matches a common one. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to the object's metadata. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to the object's metadata. + type: object + type: object + components: + description: Components specifies relative paths to kustomize Components. + items: + type: string + type: array + decryption: + description: Decrypt Kubernetes secrets before applying them on the cluster. + properties: + provider: + description: Provider is the name of the decryption engine. + enum: + - sops + type: string + secretRef: + description: |- + The secret name containing the private OpenPGP keys used for decryption. + A static credential for a cloud provider defined inside the Secret + takes priority to secret-less authentication with the ServiceAccountName + field. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + serviceAccountName: + description: |- + ServiceAccountName is the name of the service account used to + authenticate with KMS services from cloud providers. If a + static credential for a given cloud provider is defined + inside the Secret referenced by SecretRef, that static + credential takes priority. + type: string + required: + - provider + type: object + deletionPolicy: + description: |- + DeletionPolicy can be used to control garbage collection when this + Kustomization is deleted. Valid values are ('MirrorPrune', 'Delete', + 'WaitForTermination', 'Orphan'). 'MirrorPrune' mirrors the Prune field + (orphan if false, delete if true). Defaults to 'MirrorPrune'. + enum: + - MirrorPrune + - Delete + - WaitForTermination + - Orphan + type: string + dependsOn: + description: |- + DependsOn may contain a DependencyReference slice + with references to Kustomization resources that must be ready before this + Kustomization can be reconciled. + items: + description: DependencyReference defines a Kustomization dependency on another Kustomization resource. + properties: + name: + description: Name of the referent. + type: string + namespace: + description: |- + Namespace of the referent, defaults to the namespace of the Kustomization + resource object that contains the reference. + type: string + readyExpr: + description: |- + ReadyExpr is a CEL expression that can be used to assess the readiness + of a dependency. When specified, the built-in readiness check + is replaced by the logic defined in the CEL expression. + To make the CEL expression additive to the built-in readiness check, + the feature gate `AdditiveCELDependencyCheck` must be set to `true`. + type: string + required: + - name + type: object + type: array + force: + default: false + description: |- + Force instructs the controller to recreate resources + when patching fails due to an immutable field change. + type: boolean + healthCheckExprs: + description: |- + HealthCheckExprs is a list of healthcheck expressions for evaluating the + health of custom resources using Common Expression Language (CEL). + The expressions are evaluated only when Wait or HealthChecks are specified. + items: + description: CustomHealthCheck defines the health check for custom resources. + properties: + apiVersion: + description: APIVersion of the custom resource under evaluation. + type: string + current: + description: |- + Current is the CEL expression that determines if the status + of the custom resource has reached the desired state. + type: string + failed: + description: |- + Failed is the CEL expression that determines if the status + of the custom resource has failed to reach the desired state. + type: string + inProgress: + description: |- + InProgress is the CEL expression that determines if the status + of the custom resource has not yet reached the desired state. + type: string + kind: + description: Kind of the custom resource under evaluation. + type: string + required: + - apiVersion + - current + - kind + type: object + type: array + healthChecks: + description: A list of resources to be included in the health assessment. + items: + description: |- + NamespacedObjectKindReference contains enough information to locate the typed referenced Kubernetes resource object + in any namespace. + properties: + apiVersion: + description: API version of the referent, if not specified the Kubernetes preferred version will be used. + type: string + kind: + description: Kind of the referent. + type: string + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, when not specified it acts as LocalObjectReference. + type: string + required: + - kind + - name + type: object + type: array + ignoreMissingComponents: + description: |- + IgnoreMissingComponents instructs the controller to ignore Components paths + not found in source by removing them from the generated kustomization.yaml + before running kustomize build. + type: boolean + images: + description: |- + Images is a list of (image name, new name, new tag or digest) + for changing image names, tags or digests. This can also be achieved with a + patch, but this operator is simpler to specify. + items: + description: Image contains an image name, a new name, a new tag or digest, which will replace the original name and tag. + properties: + digest: + description: |- + Digest is the value used to replace the original image tag. + If digest is present NewTag value is ignored. + type: string + name: + description: Name is a tag-less image name. + type: string + newName: + description: NewName is the value used to replace the original name. + type: string + newTag: + description: NewTag is the value used to replace the original tag. + type: string + required: + - name + type: object + type: array + interval: + description: |- + The interval at which to reconcile the Kustomization. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + kubeConfig: + description: |- + The KubeConfig for reconciling the Kustomization on a remote cluster. + When used in combination with KustomizationSpec.ServiceAccountName, + forces the controller to act on behalf of that Service Account at the + target cluster. + If the --default-service-account flag is set, its value will be used as + a controller level fallback for when KustomizationSpec.ServiceAccountName + is empty. + properties: + configMapRef: + description: |- + ConfigMapRef holds an optional name of a ConfigMap that contains + the following keys: + + - `provider`: the provider to use. One of `aws`, `azure`, `gcp`, or + `generic`. Required. + - `cluster`: the fully qualified resource name of the Kubernetes + cluster in the cloud provider API. Not used by the `generic` + provider. Required when one of `address` or `ca.crt` is not set. + - `address`: the address of the Kubernetes API server. Required + for `generic`. For the other providers, if not specified, the + first address in the cluster resource will be used, and if + specified, it must match one of the addresses in the cluster + resource. + If audiences is not set, will be used as the audience for the + `generic` provider. + - `ca.crt`: the optional PEM-encoded CA certificate for the + Kubernetes API server. If not set, the controller will use the + CA certificate from the cluster resource. + - `audiences`: the optional audiences as a list of + line-break-separated strings for the Kubernetes ServiceAccount + token. Defaults to the `address` for the `generic` provider, or + to specific values for the other providers depending on the + provider. + - `serviceAccountName`: the optional name of the Kubernetes + ServiceAccount in the same namespace that should be used + for authentication. If not specified, the controller + ServiceAccount will be used. + + Mutually exclusive with SecretRef. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + secretRef: + description: |- + SecretRef holds an optional name of a secret that contains a key with + the kubeconfig file as the value. If no key is set, the key will default + to 'value'. Mutually exclusive with ConfigMapRef. + It is recommended that the kubeconfig is self-contained, and the secret + is regularly updated if credentials such as a cloud-access-token expire. + Cloud specific `cmd-path` auth helpers will not function without adding + binaries and credentials to the Pod that is responsible for reconciling + Kubernetes resources. Supported only for the generic provider. + properties: + key: + description: Key in the Secret, when not specified an implementation-specific default key is used. + type: string + name: + description: Name of the Secret. + type: string + required: + - name + type: object + type: object + x-kubernetes-validations: + - message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef must be specified + rule: has(self.configMapRef) || has(self.secretRef) + - message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef must be specified + rule: '!has(self.configMapRef) || !has(self.secretRef)' + namePrefix: + description: NamePrefix will prefix the names of all managed resources. + maxLength: 200 + minLength: 1 + type: string + nameSuffix: + description: NameSuffix will suffix the names of all managed resources. + maxLength: 200 + minLength: 1 + type: string + patches: + description: |- + Strategic merge and JSON patches, defined as inline YAML objects, + capable of targeting objects based on kind, label and annotation selectors. + items: + description: |- + Patch contains an inline StrategicMerge or JSON6902 patch, and the target the patch should + be applied to. + properties: + patch: + description: |- + Patch contains an inline StrategicMerge patch or an inline JSON6902 patch with + an array of operation objects. + type: string + target: + description: Target points to the resources that the patch document should be applied to. + properties: + annotationSelector: + description: |- + AnnotationSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource annotations. + type: string + group: + description: |- + Group is the API group to select resources from. + Together with Version and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + kind: + description: |- + Kind of the API Group to select resources from. + Together with Group and Version it is capable of unambiguously + identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + labelSelector: + description: |- + LabelSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource labels. + type: string + name: + description: Name to match resources with. + type: string + namespace: + description: Namespace to select resources from. + type: string + version: + description: |- + Version of the API Group to select resources from. + Together with Group and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + type: object + required: + - patch + type: object + type: array + path: + description: |- + Path to the directory containing the kustomization.yaml file, or the + set of plain YAMLs a kustomization.yaml should be generated for. + Defaults to 'None', which translates to the root path of the SourceRef. + type: string + postBuild: + description: |- + PostBuild describes which actions to perform on the YAML manifest + generated by building the kustomize overlay. + properties: + substitute: + additionalProperties: + type: string + description: |- + Substitute holds a map of key/value pairs. + The variables defined in your YAML manifests that match any of the keys + defined in the map will be substituted with the set value. + Includes support for bash string replacement functions + e.g. ${var:=default}, ${var:position} and ${var/substring/replacement}. + type: object + substituteFrom: + description: |- + SubstituteFrom holds references to ConfigMaps and Secrets containing + the variables and their values to be substituted in the YAML manifests. + The ConfigMap and the Secret data keys represent the var names, and they + must match the vars declared in the manifests for the substitution to + happen. + items: + description: |- + SubstituteReference contains a reference to a resource containing + the variables name and value. + properties: + kind: + description: Kind of the values referent, valid values are ('Secret', 'ConfigMap'). + enum: + - Secret + - ConfigMap + type: string + name: + description: |- + Name of the values referent. Should reside in the same namespace as the + referring resource. + maxLength: 253 + minLength: 1 + type: string + optional: + default: false + description: |- + Optional indicates whether the referenced resource must exist, or whether to + tolerate its absence. If true and the referenced resource is absent, proceed + as if the resource was present but empty, without any variables defined. + type: boolean + required: + - kind + - name + type: object + type: array + type: object + prune: + description: Prune enables garbage collection. + type: boolean + retryInterval: + description: |- + The interval at which to retry a previously failed reconciliation. + When not specified, the controller uses the KustomizationSpec.Interval + value to retry failures. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + serviceAccountName: + description: |- + The name of the Kubernetes service account to impersonate + when reconciling this Kustomization. + type: string + sourceRef: + description: Reference of the source where the kustomization file is. + properties: + apiVersion: + description: API version of the referent. + type: string + kind: + description: Kind of the referent. + enum: + - OCIRepository + - GitRepository + - Bucket + - ExternalArtifact + type: string + name: + description: Name of the referent. + type: string + namespace: + description: |- + Namespace of the referent, defaults to the namespace of the Kubernetes + resource object that contains the reference. + type: string + required: + - kind + - name + type: object + suspend: + description: |- + This flag tells the controller to suspend subsequent kustomize executions, + it does not apply to already started executions. Defaults to false. + type: boolean + targetNamespace: + description: |- + TargetNamespace sets or overrides the namespace in the + kustomization.yaml file. + maxLength: 63 + minLength: 1 + type: string + timeout: + description: |- + Timeout for validation, apply and health checking operations. + Defaults to 'Interval' duration. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + wait: + description: |- + Wait instructs the controller to check the health of all the reconciled + resources. When enabled, the HealthChecks are ignored. Defaults to false. + type: boolean + required: + - interval + - prune + - sourceRef + type: object + status: + default: + observedGeneration: -1 + description: KustomizationStatus defines the observed state of a kustomization. + properties: + conditions: + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + history: + description: |- + History contains a set of snapshots of the last reconciliation attempts + tracking the revision, the state and the duration of each attempt. + items: + description: |- + Snapshot represents a point-in-time record of a group of resources reconciliation, + including timing information, status, and a unique digest identifier. + properties: + digest: + description: Digest is the checksum in the format `:` of the resources in this snapshot. + type: string + firstReconciled: + description: FirstReconciled is the time when this revision was first reconciled to the cluster. + format: date-time + type: string + lastReconciled: + description: LastReconciled is the time when this revision was last reconciled to the cluster. + format: date-time + type: string + lastReconciledDuration: + description: LastReconciledDuration is time it took to reconcile the resources in this revision. + type: string + lastReconciledStatus: + description: LastReconciledStatus is the status of the last reconciliation. + type: string + metadata: + additionalProperties: + type: string + description: Metadata contains additional information about the snapshot. + type: object + totalReconciliations: + description: TotalReconciliations is the total number of reconciliations that have occurred for this snapshot. + format: int64 + type: integer + required: + - digest + - firstReconciled + - lastReconciled + - lastReconciledDuration + - lastReconciledStatus + - totalReconciliations + type: object + type: array + inventory: + description: |- + Inventory contains the list of Kubernetes resource object references that + have been successfully applied. + properties: + entries: + description: Entries of Kubernetes resource object references. + items: + description: ResourceRef contains the information necessary to locate a resource within a cluster. + properties: + id: + description: |- + ID is the string representation of the Kubernetes resource object's metadata, + in the format '___'. + type: string + v: + description: Version is the API version of the Kubernetes resource object's kind. + type: string + required: + - id + - v + type: object + type: array + required: + - entries + type: object + lastAppliedOriginRevision: + description: |- + The last successfully applied origin revision. + Equals the origin revision of the applied Artifact from the referenced Source. + Usually present on the Metadata of the applied Artifact and depends on the + Source type, e.g. for OCI it's the value associated with the key + "org.opencontainers.image.revision". + type: string + lastAppliedRevision: + description: |- + The last successfully applied revision. + Equals the Revision of the applied Artifact from the referenced Source. + type: string + lastAttemptedRevision: + description: LastAttemptedRevision is the revision of the last reconciliation attempt. + type: string + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last reconciled generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + deprecated: true + deprecationWarning: v1beta2 Kustomization is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: Kustomization is the Schema for the kustomizations API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: KustomizationSpec defines the configuration to calculate the desired state from a Source using Kustomize. + properties: + commonMetadata: + description: |- + CommonMetadata specifies the common labels and annotations that are applied to all resources. + Any existing label or annotation will be overridden if its key matches a common one. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to the object's metadata. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to the object's metadata. + type: object + type: object + components: + description: Components specifies relative paths to specifications of other Components. + items: + type: string + type: array + decryption: + description: Decrypt Kubernetes secrets before applying them on the cluster. + properties: + provider: + description: Provider is the name of the decryption engine. + enum: + - sops + type: string + secretRef: + description: The secret name containing the private OpenPGP keys used for decryption. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - provider + type: object + dependsOn: + description: |- + DependsOn may contain a meta.NamespacedObjectReference slice + with references to Kustomization resources that must be ready before this + Kustomization can be reconciled. + items: + description: |- + NamespacedObjectReference contains enough information to locate the referenced Kubernetes resource object in any + namespace. + properties: + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, when not specified it acts as LocalObjectReference. + type: string + required: + - name + type: object + type: array + force: + default: false + description: |- + Force instructs the controller to recreate resources + when patching fails due to an immutable field change. + type: boolean + healthChecks: + description: A list of resources to be included in the health assessment. + items: + description: |- + NamespacedObjectKindReference contains enough information to locate the typed referenced Kubernetes resource object + in any namespace. + properties: + apiVersion: + description: API version of the referent, if not specified the Kubernetes preferred version will be used. + type: string + kind: + description: Kind of the referent. + type: string + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, when not specified it acts as LocalObjectReference. + type: string + required: + - kind + - name + type: object + type: array + images: + description: |- + Images is a list of (image name, new name, new tag or digest) + for changing image names, tags or digests. This can also be achieved with a + patch, but this operator is simpler to specify. + items: + description: Image contains an image name, a new name, a new tag or digest, which will replace the original name and tag. + properties: + digest: + description: |- + Digest is the value used to replace the original image tag. + If digest is present NewTag value is ignored. + type: string + name: + description: Name is a tag-less image name. + type: string + newName: + description: NewName is the value used to replace the original name. + type: string + newTag: + description: NewTag is the value used to replace the original tag. + type: string + required: + - name + type: object + type: array + interval: + description: The interval at which to reconcile the Kustomization. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + kubeConfig: + description: |- + The KubeConfig for reconciling the Kustomization on a remote cluster. + When used in combination with KustomizationSpec.ServiceAccountName, + forces the controller to act on behalf of that Service Account at the + target cluster. + If the --default-service-account flag is set, its value will be used as + a controller level fallback for when KustomizationSpec.ServiceAccountName + is empty. + properties: + configMapRef: + description: |- + ConfigMapRef holds an optional name of a ConfigMap that contains + the following keys: + + - `provider`: the provider to use. One of `aws`, `azure`, `gcp`, or + `generic`. Required. + - `cluster`: the fully qualified resource name of the Kubernetes + cluster in the cloud provider API. Not used by the `generic` + provider. Required when one of `address` or `ca.crt` is not set. + - `address`: the address of the Kubernetes API server. Required + for `generic`. For the other providers, if not specified, the + first address in the cluster resource will be used, and if + specified, it must match one of the addresses in the cluster + resource. + If audiences is not set, will be used as the audience for the + `generic` provider. + - `ca.crt`: the optional PEM-encoded CA certificate for the + Kubernetes API server. If not set, the controller will use the + CA certificate from the cluster resource. + - `audiences`: the optional audiences as a list of + line-break-separated strings for the Kubernetes ServiceAccount + token. Defaults to the `address` for the `generic` provider, or + to specific values for the other providers depending on the + provider. + - `serviceAccountName`: the optional name of the Kubernetes + ServiceAccount in the same namespace that should be used + for authentication. If not specified, the controller + ServiceAccount will be used. + + Mutually exclusive with SecretRef. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + secretRef: + description: |- + SecretRef holds an optional name of a secret that contains a key with + the kubeconfig file as the value. If no key is set, the key will default + to 'value'. Mutually exclusive with ConfigMapRef. + It is recommended that the kubeconfig is self-contained, and the secret + is regularly updated if credentials such as a cloud-access-token expire. + Cloud specific `cmd-path` auth helpers will not function without adding + binaries and credentials to the Pod that is responsible for reconciling + Kubernetes resources. Supported only for the generic provider. + properties: + key: + description: Key in the Secret, when not specified an implementation-specific default key is used. + type: string + name: + description: Name of the Secret. + type: string + required: + - name + type: object + type: object + x-kubernetes-validations: + - message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef must be specified + rule: has(self.configMapRef) || has(self.secretRef) + - message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef must be specified + rule: '!has(self.configMapRef) || !has(self.secretRef)' + patches: + description: |- + Strategic merge and JSON patches, defined as inline YAML objects, + capable of targeting objects based on kind, label and annotation selectors. + items: + description: |- + Patch contains an inline StrategicMerge or JSON6902 patch, and the target the patch should + be applied to. + properties: + patch: + description: |- + Patch contains an inline StrategicMerge patch or an inline JSON6902 patch with + an array of operation objects. + type: string + target: + description: Target points to the resources that the patch document should be applied to. + properties: + annotationSelector: + description: |- + AnnotationSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource annotations. + type: string + group: + description: |- + Group is the API group to select resources from. + Together with Version and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + kind: + description: |- + Kind of the API Group to select resources from. + Together with Group and Version it is capable of unambiguously + identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + labelSelector: + description: |- + LabelSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource labels. + type: string + name: + description: Name to match resources with. + type: string + namespace: + description: Namespace to select resources from. + type: string + version: + description: |- + Version of the API Group to select resources from. + Together with Group and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + type: object + required: + - patch + type: object + type: array + patchesJson6902: + description: |- + JSON 6902 patches, defined as inline YAML objects. + Deprecated: Use Patches instead. + items: + description: JSON6902Patch contains a JSON6902 patch and the target the patch should be applied to. + properties: + patch: + description: Patch contains the JSON6902 patch document with an array of operation objects. + items: + description: |- + JSON6902 is a JSON6902 operation object. + https://datatracker.ietf.org/doc/html/rfc6902#section-4 + properties: + from: + description: |- + From contains a JSON-pointer value that references a location within the target document where the operation is + performed. The meaning of the value depends on the value of Op, and is NOT taken into account by all operations. + type: string + op: + description: |- + Op indicates the operation to perform. Its value MUST be one of "add", "remove", "replace", "move", "copy", or + "test". + https://datatracker.ietf.org/doc/html/rfc6902#section-4 + enum: + - test + - remove + - add + - replace + - move + - copy + type: string + path: + description: |- + Path contains the JSON-pointer value that references a location within the target document where the operation + is performed. The meaning of the value depends on the value of Op. + type: string + value: + description: |- + Value contains a valid JSON structure. The meaning of the value depends on the value of Op, and is NOT taken into + account by all operations. + x-kubernetes-preserve-unknown-fields: true + required: + - op + - path + type: object + type: array + target: + description: Target points to the resources that the patch document should be applied to. + properties: + annotationSelector: + description: |- + AnnotationSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource annotations. + type: string + group: + description: |- + Group is the API group to select resources from. + Together with Version and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + kind: + description: |- + Kind of the API Group to select resources from. + Together with Group and Version it is capable of unambiguously + identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + labelSelector: + description: |- + LabelSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource labels. + type: string + name: + description: Name to match resources with. + type: string + namespace: + description: Namespace to select resources from. + type: string + version: + description: |- + Version of the API Group to select resources from. + Together with Group and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + type: object + required: + - patch + - target + type: object + type: array + patchesStrategicMerge: + description: |- + Strategic merge patches, defined as inline YAML objects. + Deprecated: Use Patches instead. + items: + x-kubernetes-preserve-unknown-fields: true + type: array + path: + description: |- + Path to the directory containing the kustomization.yaml file, or the + set of plain YAMLs a kustomization.yaml should be generated for. + Defaults to 'None', which translates to the root path of the SourceRef. + type: string + postBuild: + description: |- + PostBuild describes which actions to perform on the YAML manifest + generated by building the kustomize overlay. + properties: + substitute: + additionalProperties: + type: string + description: |- + Substitute holds a map of key/value pairs. + The variables defined in your YAML manifests + that match any of the keys defined in the map + will be substituted with the set value. + Includes support for bash string replacement functions + e.g. ${var:=default}, ${var:position} and ${var/substring/replacement}. + type: object + substituteFrom: + description: |- + SubstituteFrom holds references to ConfigMaps and Secrets containing + the variables and their values to be substituted in the YAML manifests. + The ConfigMap and the Secret data keys represent the var names and they + must match the vars declared in the manifests for the substitution to happen. + items: + description: |- + SubstituteReference contains a reference to a resource containing + the variables name and value. + properties: + kind: + description: Kind of the values referent, valid values are ('Secret', 'ConfigMap'). + enum: + - Secret + - ConfigMap + type: string + name: + description: |- + Name of the values referent. Should reside in the same namespace as the + referring resource. + maxLength: 253 + minLength: 1 + type: string + optional: + default: false + description: |- + Optional indicates whether the referenced resource must exist, or whether to + tolerate its absence. If true and the referenced resource is absent, proceed + as if the resource was present but empty, without any variables defined. + type: boolean + required: + - kind + - name + type: object + type: array + type: object + prune: + description: Prune enables garbage collection. + type: boolean + retryInterval: + description: |- + The interval at which to retry a previously failed reconciliation. + When not specified, the controller uses the KustomizationSpec.Interval + value to retry failures. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + serviceAccountName: + description: |- + The name of the Kubernetes service account to impersonate + when reconciling this Kustomization. + type: string + sourceRef: + description: Reference of the source where the kustomization file is. + properties: + apiVersion: + description: API version of the referent. + type: string + kind: + description: Kind of the referent. + enum: + - OCIRepository + - GitRepository + - Bucket + type: string + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, defaults to the namespace of the Kubernetes resource object that contains the reference. + type: string + required: + - kind + - name + type: object + suspend: + description: |- + This flag tells the controller to suspend subsequent kustomize executions, + it does not apply to already started executions. Defaults to false. + type: boolean + targetNamespace: + description: |- + TargetNamespace sets or overrides the namespace in the + kustomization.yaml file. + maxLength: 63 + minLength: 1 + type: string + timeout: + description: |- + Timeout for validation, apply and health checking operations. + Defaults to 'Interval' duration. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + validation: + description: 'Deprecated: Not used in v1beta2.' + enum: + - none + - client + - server + type: string + wait: + description: |- + Wait instructs the controller to check the health of all the reconciled resources. + When enabled, the HealthChecks are ignored. Defaults to false. + type: boolean + required: + - interval + - prune + - sourceRef + type: object + status: + default: + observedGeneration: -1 + description: KustomizationStatus defines the observed state of a kustomization. + properties: + conditions: + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + inventory: + description: Inventory contains the list of Kubernetes resource object references that have been successfully applied. + properties: + entries: + description: Entries of Kubernetes resource object references. + items: + description: ResourceRef contains the information necessary to locate a resource within a cluster. + properties: + id: + description: |- + ID is the string representation of the Kubernetes resource object's metadata, + in the format '___'. + type: string + v: + description: Version is the API version of the Kubernetes resource object's kind. + type: string + required: + - id + - v + type: object + type: array + required: + - entries + type: object + lastAppliedRevision: + description: |- + The last successfully applied revision. + Equals the Revision of the applied Artifact from the referenced Source. + type: string + lastAttemptedRevision: + description: LastAttemptedRevision is the revision of the last reconciliation attempt. + type: string + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last reconciled generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: ocirepositories.source.toolkit.fluxcd.io +spec: + group: source.toolkit.fluxcd.io + names: + kind: OCIRepository + listKind: OCIRepositoryList + plural: ocirepositories + shortNames: + - ocirepo + singular: ocirepository + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.url + name: URL + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: OCIRepository is the Schema for the ocirepositories API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: OCIRepositorySpec defines the desired state of OCIRepository + properties: + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + registry. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + ignore: + description: |- + Ignore overrides the set of excluded patterns in the .sourceignore format + (which is the same as .gitignore). If not provided, a default will be used, + consult the documentation for your version to find out what those are. + type: string + insecure: + description: Insecure allows connecting to a non-TLS HTTP container registry. + type: boolean + interval: + description: |- + Interval at which the OCIRepository URL is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + layerSelector: + description: |- + LayerSelector specifies which layer should be extracted from the OCI artifact. + When not specified, the first layer found in the artifact is selected. + properties: + mediaType: + description: |- + MediaType specifies the OCI media type of the layer + which should be extracted from the OCI Artifact. The + first layer matching this type is selected. + type: string + operation: + description: |- + Operation specifies how the selected layer should be processed. + By default, the layer compressed content is extracted to storage. + When the operation is set to 'copy', the layer compressed content + is persisted to storage as it is. + enum: + - extract + - copy + type: string + type: object + provider: + default: generic + description: |- + The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + When not specified, defaults to 'generic'. + enum: + - generic + - aws + - azure + - gcp + type: string + proxySecretRef: + description: |- + ProxySecretRef specifies the Secret containing the proxy configuration + to use while communicating with the container registry. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + ref: + description: |- + The OCI reference to pull and monitor for changes, + defaults to the latest tag. + properties: + digest: + description: |- + Digest is the image digest to pull, takes precedence over SemVer. + The value should be in the format 'sha256:'. + type: string + semver: + description: |- + SemVer is the range of tags to pull selecting the latest within + the range, takes precedence over Tag. + type: string + semverFilter: + description: SemverFilter is a regex pattern to filter the tags within the SemVer range. + type: string + tag: + description: Tag is the image tag to pull, defaults to latest. + type: string + type: object + secretRef: + description: |- + SecretRef contains the secret name containing the registry login + credentials to resolve image metadata. + The secret must be of type kubernetes.io/dockerconfigjson. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + serviceAccountName: + description: |- + ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + the image pull if the service account has attached pull secrets. For more information: + https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account + type: string + suspend: + description: This flag tells the controller to suspend the reconciliation of this source. + type: boolean + timeout: + default: 60s + description: The timeout for remote OCI Repository operations like pulling, defaults to 60s. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + url: + description: |- + URL is a reference to an OCI artifact repository hosted + on a remote container registry. + pattern: ^oci://.*$ + type: string + verify: + description: |- + Verify contains the secret name containing the trusted public keys + used to verify the signature and specifies which provider to use to check + whether OCI image is authentic. + properties: + matchOIDCIdentity: + description: |- + MatchOIDCIdentity specifies the identity matching criteria to use + while verifying an OCI artifact which was signed using Cosign keyless + signing. The artifact's identity is deemed to be verified if any of the + specified matchers match against the identity. + items: + description: |- + OIDCIdentityMatch specifies options for verifying the certificate identity, + i.e. the issuer and the subject of the certificate. + properties: + issuer: + description: |- + Issuer specifies the regex pattern to match against to verify + the OIDC issuer in the Fulcio certificate. The pattern must be a + valid Go regular expression. + type: string + subject: + description: |- + Subject specifies the regex pattern to match against to verify + the identity subject in the Fulcio certificate. The pattern must + be a valid Go regular expression. + type: string + required: + - issuer + - subject + type: object + type: array + provider: + default: cosign + description: Provider specifies the technology used to sign the OCI Artifact. + enum: + - cosign + - notation + type: string + secretRef: + description: |- + SecretRef specifies the Kubernetes Secret containing the + trusted public keys. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - provider + type: object + required: + - interval + - url + type: object + status: + default: + observedGeneration: -1 + description: OCIRepositoryStatus defines the observed state of OCIRepository + properties: + artifact: + description: Artifact represents the output of the last successful OCI Repository sync. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the OCIRepository. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + observedIgnore: + description: |- + ObservedIgnore is the observed exclusion patterns used for constructing + the source artifact. + type: string + observedLayerSelector: + description: |- + ObservedLayerSelector is the observed layer selector used for constructing + the source artifact. + properties: + mediaType: + description: |- + MediaType specifies the OCI media type of the layer + which should be extracted from the OCI Artifact. The + first layer matching this type is selected. + type: string + operation: + description: |- + Operation specifies how the selected layer should be processed. + By default, the layer compressed content is extracted to storage. + When the operation is set to 'copy', the layer compressed content + is persisted to storage as it is. + enum: + - extract + - copy + type: string + type: object + url: + description: URL is the download link for the artifact output of the last OCI Repository sync. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.url + name: URL + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: v1beta2 OCIRepository is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: OCIRepository is the Schema for the ocirepositories API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: OCIRepositorySpec defines the desired state of OCIRepository + properties: + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + registry. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + Note: Support for the `caFile`, `certFile` and `keyFile` keys have + been deprecated. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + ignore: + description: |- + Ignore overrides the set of excluded patterns in the .sourceignore format + (which is the same as .gitignore). If not provided, a default will be used, + consult the documentation for your version to find out what those are. + type: string + insecure: + description: Insecure allows connecting to a non-TLS HTTP container registry. + type: boolean + interval: + description: |- + Interval at which the OCIRepository URL is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + layerSelector: + description: |- + LayerSelector specifies which layer should be extracted from the OCI artifact. + When not specified, the first layer found in the artifact is selected. + properties: + mediaType: + description: |- + MediaType specifies the OCI media type of the layer + which should be extracted from the OCI Artifact. The + first layer matching this type is selected. + type: string + operation: + description: |- + Operation specifies how the selected layer should be processed. + By default, the layer compressed content is extracted to storage. + When the operation is set to 'copy', the layer compressed content + is persisted to storage as it is. + enum: + - extract + - copy + type: string + type: object + provider: + default: generic + description: |- + The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + When not specified, defaults to 'generic'. + enum: + - generic + - aws + - azure + - gcp + type: string + proxySecretRef: + description: |- + ProxySecretRef specifies the Secret containing the proxy configuration + to use while communicating with the container registry. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + ref: + description: |- + The OCI reference to pull and monitor for changes, + defaults to the latest tag. + properties: + digest: + description: |- + Digest is the image digest to pull, takes precedence over SemVer. + The value should be in the format 'sha256:'. + type: string + semver: + description: |- + SemVer is the range of tags to pull selecting the latest within + the range, takes precedence over Tag. + type: string + semverFilter: + description: SemverFilter is a regex pattern to filter the tags within the SemVer range. + type: string + tag: + description: Tag is the image tag to pull, defaults to latest. + type: string + type: object + secretRef: + description: |- + SecretRef contains the secret name containing the registry login + credentials to resolve image metadata. + The secret must be of type kubernetes.io/dockerconfigjson. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + serviceAccountName: + description: |- + ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + the image pull if the service account has attached pull secrets. For more information: + https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account + type: string + suspend: + description: This flag tells the controller to suspend the reconciliation of this source. + type: boolean + timeout: + default: 60s + description: The timeout for remote OCI Repository operations like pulling, defaults to 60s. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + url: + description: |- + URL is a reference to an OCI artifact repository hosted + on a remote container registry. + pattern: ^oci://.*$ + type: string + verify: + description: |- + Verify contains the secret name containing the trusted public keys + used to verify the signature and specifies which provider to use to check + whether OCI image is authentic. + properties: + matchOIDCIdentity: + description: |- + MatchOIDCIdentity specifies the identity matching criteria to use + while verifying an OCI artifact which was signed using Cosign keyless + signing. The artifact's identity is deemed to be verified if any of the + specified matchers match against the identity. + items: + description: |- + OIDCIdentityMatch specifies options for verifying the certificate identity, + i.e. the issuer and the subject of the certificate. + properties: + issuer: + description: |- + Issuer specifies the regex pattern to match against to verify + the OIDC issuer in the Fulcio certificate. The pattern must be a + valid Go regular expression. + type: string + subject: + description: |- + Subject specifies the regex pattern to match against to verify + the identity subject in the Fulcio certificate. The pattern must + be a valid Go regular expression. + type: string + required: + - issuer + - subject + type: object + type: array + provider: + default: cosign + description: Provider specifies the technology used to sign the OCI Artifact. + enum: + - cosign + - notation + type: string + secretRef: + description: |- + SecretRef specifies the Kubernetes Secret containing the + trusted public keys. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - provider + type: object + required: + - interval + - url + type: object + status: + default: + observedGeneration: -1 + description: OCIRepositoryStatus defines the observed state of OCIRepository + properties: + artifact: + description: Artifact represents the output of the last successful OCI Repository sync. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the OCIRepository. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + contentConfigChecksum: + description: |- + ContentConfigChecksum is a checksum of all the configurations related to + the content of the source artifact: + - .spec.ignore + - .spec.layerSelector + observed in .status.observedGeneration version of the object. This can + be used to determine if the content configuration has changed and the + artifact needs to be rebuilt. + It has the format of `:`, for example: `sha256:`. + + Deprecated: Replaced with explicit fields for observed artifact content + config in the status. + type: string + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + observedIgnore: + description: |- + ObservedIgnore is the observed exclusion patterns used for constructing + the source artifact. + type: string + observedLayerSelector: + description: |- + ObservedLayerSelector is the observed layer selector used for constructing + the source artifact. + properties: + mediaType: + description: |- + MediaType specifies the OCI media type of the layer + which should be extracted from the OCI Artifact. The + first layer matching this type is selected. + type: string + operation: + description: |- + Operation specifies how the selected layer should be processed. + By default, the layer compressed content is extracted to storage. + When the operation is set to 'copy', the layer compressed content + is persisted to storage as it is. + enum: + - extract + - copy + type: string + type: object + url: + description: URL is the download link for the artifact output of the last OCI Repository sync. + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: providers.notification.toolkit.fluxcd.io +spec: + group: notification.toolkit.fluxcd.io + names: + kind: Provider + listKind: ProviderList + plural: providers + singular: provider + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + deprecated: true + deprecationWarning: v1beta2 Provider is deprecated, upgrade to v1beta3 + name: v1beta2 + schema: + openAPIV3Schema: + description: Provider is the Schema for the providers API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ProviderSpec defines the desired state of the Provider. + properties: + address: + description: |- + Address specifies the endpoint, in a generic sense, to where alerts are sent. + What kind of endpoint depends on the specific Provider type being used. + For the generic Provider, for example, this is an HTTP/S address. + For other Provider types this could be a project ID or a namespace. + maxLength: 2048 + type: string + certSecretRef: + description: |- + CertSecretRef specifies the Secret containing + a PEM-encoded CA certificate (in the `ca.crt` key). + + Note: Support for the `caFile` key has + been deprecated. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + channel: + description: Channel specifies the destination channel where events should be posted. + maxLength: 2048 + type: string + interval: + description: Interval at which to reconcile the Provider with its Secret references. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + proxy: + description: Proxy the HTTP/S address of the proxy server. + maxLength: 2048 + pattern: ^(http|https)://.*$ + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing the authentication + credentials for this Provider. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + suspend: + description: |- + Suspend tells the controller to suspend subsequent + events handling for this Provider. + type: boolean + timeout: + description: Timeout for sending alerts to the Provider. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + type: + description: Type specifies which Provider implementation to use. + enum: + - slack + - discord + - msteams + - rocket + - generic + - generic-hmac + - github + - gitlab + - gitea + - bitbucketserver + - bitbucket + - azuredevops + - googlechat + - googlepubsub + - webex + - sentry + - azureeventhub + - telegram + - lark + - matrix + - opsgenie + - alertmanager + - grafana + - githubdispatch + - pagerduty + - datadog + type: string + username: + description: Username specifies the name under which events are posted. + maxLength: 2048 + type: string + required: + - type + type: object + status: + default: + observedGeneration: -1 + description: ProviderStatus defines the observed state of the Provider. + properties: + conditions: + description: Conditions holds the conditions for the Provider. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last reconciled generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta3 + schema: + openAPIV3Schema: + description: Provider is the Schema for the providers API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ProviderSpec defines the desired state of the Provider. + properties: + address: + description: |- + Address specifies the endpoint, in a generic sense, to where alerts are sent. + What kind of endpoint depends on the specific Provider type being used. + For the generic Provider, for example, this is an HTTP/S address. + For other Provider types this could be a project ID or a namespace. + maxLength: 2048 + type: string + certSecretRef: + description: |- + CertSecretRef specifies the Secret containing TLS certificates + for secure communication. + + Supported configurations: + - CA-only: Server authentication (provide ca.crt only) + - mTLS: Mutual authentication (provide ca.crt + tls.crt + tls.key) + - Client-only: Client authentication with system CA (provide tls.crt + tls.key only) + + Legacy keys "caFile", "certFile", "keyFile" are supported but deprecated. Use "ca.crt", "tls.crt", "tls.key" instead. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + channel: + description: Channel specifies the destination channel where events should be posted. + maxLength: 2048 + type: string + commitStatusExpr: + description: |- + CommitStatusExpr is a CEL expression that evaluates to a string value + that can be used to generate a custom commit status message for use + with eligible Provider types (github, gitlab, gitea, bitbucketserver, + bitbucket, azuredevops). Supported variables are: event, provider, + and alert. + type: string + interval: + description: |- + Interval at which to reconcile the Provider with its Secret references. + Deprecated and not used in v1beta3. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + proxy: + description: |- + Proxy the HTTP/S address of the proxy server. + Deprecated: Use ProxySecretRef instead. Will be removed in v1. + maxLength: 2048 + pattern: ^(http|https)://.*$ + type: string + proxySecretRef: + description: |- + ProxySecretRef specifies the Secret containing the proxy configuration + for this Provider. The Secret should contain an 'address' key with the + HTTP/S address of the proxy server. Optional 'username' and 'password' + keys can be provided for proxy authentication. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + secretRef: + description: |- + SecretRef specifies the Secret containing the authentication + credentials for this Provider. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + serviceAccountName: + description: |- + ServiceAccountName is the name of the Kubernetes ServiceAccount used to + authenticate with cloud provider services through workload identity. + This enables multi-tenant authentication without storing static credentials. + + Supported provider types: azureeventhub, azuredevops, googlepubsub + + When specified, the controller will: + 1. Create an OIDC token for the specified ServiceAccount + 2. Exchange it for cloud provider credentials via STS + 3. Use the obtained credentials for API authentication + + When unspecified, controller-level authentication is used (single-tenant). + + An error is thrown if static credentials are also defined in SecretRef. + This field requires the ObjectLevelWorkloadIdentity feature gate to be enabled. + type: string + suspend: + description: |- + Suspend tells the controller to suspend subsequent + events handling for this Provider. + type: boolean + timeout: + description: Timeout for sending alerts to the Provider. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + type: + description: Type specifies which Provider implementation to use. + enum: + - slack + - discord + - msteams + - rocket + - generic + - generic-hmac + - github + - gitlab + - gitea + - bitbucketserver + - bitbucket + - azuredevops + - googlechat + - googlepubsub + - webex + - sentry + - azureeventhub + - telegram + - lark + - matrix + - opsgenie + - alertmanager + - grafana + - githubdispatch + - pagerduty + - datadog + - nats + - zulip + - otel + type: string + username: + description: Username specifies the name under which events are posted. + maxLength: 2048 + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: spec.commitStatusExpr is only supported for the 'github', 'gitlab', 'gitea', 'bitbucketserver', 'bitbucket', 'azuredevops' provider types + rule: self.type == 'github' || self.type == 'gitlab' || self.type == 'gitea' || self.type == 'bitbucketserver' || self.type == 'bitbucket' || self.type == 'azuredevops' || !has(self.commitStatusExpr) + type: object + served: true + storage: true + subresources: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: receivers.notification.toolkit.fluxcd.io +spec: + group: notification.toolkit.fluxcd.io + names: + kind: Receiver + listKind: ReceiverList + plural: receivers + singular: receiver + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + name: v1 + schema: + openAPIV3Schema: + description: Receiver is the Schema for the receivers API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ReceiverSpec defines the desired state of the Receiver. + properties: + events: + description: |- + Events specifies the list of event types to handle, + e.g. 'push' for GitHub or 'Push Hook' for GitLab. + items: + type: string + type: array + interval: + default: 10m + description: Interval at which to reconcile the Receiver with its Secret references. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + resourceFilter: + description: |- + ResourceFilter is a CEL expression expected to return a boolean that is + evaluated for each resource referenced in the Resources field when a + webhook is received. If the expression returns false then the controller + will not request a reconciliation for the resource. + When the expression is specified the controller will parse it and mark + the object as terminally failed if the expression is invalid or does not + return a boolean. + type: string + resources: + description: A list of resources to be notified about changes. + items: + description: |- + CrossNamespaceObjectReference contains enough information to let you locate the + typed referenced object at cluster level + properties: + apiVersion: + description: API version of the referent + type: string + kind: + description: Kind of the referent + enum: + - Bucket + - GitRepository + - Kustomization + - HelmRelease + - HelmChart + - HelmRepository + - ImageRepository + - ImagePolicy + - ImageUpdateAutomation + - OCIRepository + type: string + matchLabels: + additionalProperties: + type: string + description: |- + MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + MatchLabels requires the name to be set to `*`. + type: object + name: + description: |- + Name of the referent + If multiple resources are targeted `*` may be set. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: Namespace of the referent + maxLength: 253 + minLength: 1 + type: string + required: + - kind + - name + type: object + type: array + secretRef: + description: |- + SecretRef specifies the Secret containing the token used + to validate the payload authenticity. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + suspend: + description: |- + Suspend tells the controller to suspend subsequent + events handling for this receiver. + type: boolean + type: + description: |- + Type of webhook sender, used to determine + the validation procedure and payload deserialization. + enum: + - generic + - generic-hmac + - github + - gitlab + - bitbucket + - harbor + - dockerhub + - quay + - gcr + - nexus + - acr + - cdevents + type: string + required: + - resources + - secretRef + - type + type: object + status: + default: + observedGeneration: -1 + description: ReceiverStatus defines the observed state of the Receiver. + properties: + conditions: + description: Conditions holds the conditions for the Receiver. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation of the Receiver object. + format: int64 + type: integer + webhookPath: + description: |- + WebhookPath is the generated incoming webhook address in the format + of '/hook/sha256sum(token+name+namespace)'. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + deprecated: true + deprecationWarning: v1beta2 Receiver is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: Receiver is the Schema for the receivers API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ReceiverSpec defines the desired state of the Receiver. + properties: + events: + description: |- + Events specifies the list of event types to handle, + e.g. 'push' for GitHub or 'Push Hook' for GitLab. + items: + type: string + type: array + interval: + description: Interval at which to reconcile the Receiver with its Secret references. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + resources: + description: A list of resources to be notified about changes. + items: + description: |- + CrossNamespaceObjectReference contains enough information to let you locate the + typed referenced object at cluster level + properties: + apiVersion: + description: API version of the referent + type: string + kind: + description: Kind of the referent + enum: + - Bucket + - GitRepository + - Kustomization + - HelmRelease + - HelmChart + - HelmRepository + - ImageRepository + - ImagePolicy + - ImageUpdateAutomation + - OCIRepository + type: string + matchLabels: + additionalProperties: + type: string + description: |- + MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + MatchLabels requires the name to be set to `*`. + type: object + name: + description: |- + Name of the referent + If multiple resources are targeted `*` may be set. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: Namespace of the referent + maxLength: 253 + minLength: 1 + type: string + required: + - kind + - name + type: object + type: array + secretRef: + description: |- + SecretRef specifies the Secret containing the token used + to validate the payload authenticity. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + suspend: + description: |- + Suspend tells the controller to suspend subsequent + events handling for this receiver. + type: boolean + type: + description: |- + Type of webhook sender, used to determine + the validation procedure and payload deserialization. + enum: + - generic + - generic-hmac + - github + - gitlab + - bitbucket + - harbor + - dockerhub + - quay + - gcr + - nexus + - acr + type: string + required: + - resources + - secretRef + - type + type: object + status: + default: + observedGeneration: -1 + description: ReceiverStatus defines the observed state of the Receiver. + properties: + conditions: + description: Conditions holds the conditions for the Receiver. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation of the Receiver object. + format: int64 + type: integer + url: + description: |- + URL is the generated incoming webhook address in the format + of '/hook/sha256sum(token+name+namespace)'. + Deprecated: Replaced by WebhookPath. + type: string + webhookPath: + description: |- + WebhookPath is the generated incoming webhook address in the format + of '/hook/sha256sum(token+name+namespace)'. + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: v1 +kind: Namespace +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + pod-security.kubernetes.io/enforce: privileged + name: cozy-fluxcd +--- +apiVersion: v1 +kind: ResourceQuota +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: flux + namespace: cozy-fluxcd +spec: + hard: + pods: "1000" + scopeSelector: + matchExpressions: + - operator: In + scopeName: PriorityClass + values: + - system-node-critical + - system-cluster-critical +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: flux + namespace: cozy-fluxcd +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" + rbac.authorization.k8s.io/aggregate-to-view: "true" + name: flux-view +rules: + - apiGroups: + - notification.toolkit.fluxcd.io + - source.toolkit.fluxcd.io + - helm.toolkit.fluxcd.io + - image.toolkit.fluxcd.io + - kustomize.toolkit.fluxcd.io + - source.extensions.fluxcd.io + resources: + - '*' + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: flux +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: + - kind: ServiceAccount + name: flux + namespace: cozy-fluxcd +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: flux + namespace: cozy-fluxcd +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: flux + strategy: + type: Recreate + template: + metadata: + annotations: + cluster-autoscaler.kubernetes.io/safe-to-evict: "true" + prometheus.io/scrape: "true" + labels: + app.kubernetes.io/name: flux + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/os + operator: In + values: + - linux + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - flux + topologyKey: kubernetes.io/hostname + containers: + - args: + - --watch-all-namespaces + - --log-level=info + - --log-encoding=json + - --enable-leader-election=false + - --metrics-addr=:9791 + - --health-addr=:9792 + - --storage-addr=:9790 + - --storage-path=/data + - --storage-adv-addr=flux.$(RUNTIME_NAMESPACE).svc + - --concurrent=5 + - --requeue-dependency=30s + - --watch-label-selector=!sharding.fluxcd.io/key + - --helm-cache-max-size=10 + - --helm-cache-ttl=60m + - --helm-cache-purge-interval=5m + - --events-addr=http://localhost:9690 + env: + - name: SOURCE_CONTROLLER_LOCALHOST + value: localhost:9790 + - name: SOURCE_WATCHER_LOCALHOST + value: localhost:9691 + - name: RUNTIME_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: GOMEMLIMIT + valueFrom: + resourceFieldRef: + resource: limits.memory + - name: TUF_ROOT + value: /tmp/.sigstore + - name: NO_PROXY + value: .svc + image: ghcr.io/fluxcd/source-controller:v1.7.3 + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: /healthz + port: healthz-sc + name: source-controller + ports: + - containerPort: 9790 + name: http-sc + protocol: TCP + - containerPort: 9791 + name: http-prom-sc + protocol: TCP + - containerPort: 9792 + name: healthz-sc + protocol: TCP + readinessProbe: + httpGet: + path: / + port: http-sc + resources: + limits: + memory: 1Gi + requests: + cpu: 100m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + volumeMounts: + - mountPath: /data + name: data + - mountPath: /tmp + name: tmp + - args: + - --watch-all-namespaces + - --log-level=info + - --log-encoding=json + - --enable-leader-election=false + - --metrics-addr=:9793 + - --health-addr=:9794 + - --watch-label-selector=!sharding.fluxcd.io/key + - --concurrent=5 + - --requeue-dependency=30s + - --events-addr=http://localhost:9690 + - --feature-gates=ExternalArtifact=true + env: + - name: SOURCE_CONTROLLER_LOCALHOST + value: localhost:9790 + - name: SOURCE_WATCHER_LOCALHOST + value: localhost:9691 + - name: RUNTIME_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: GOMEMLIMIT + valueFrom: + resourceFieldRef: + resource: limits.memory + - name: TUF_ROOT + value: /tmp/.sigstore + - name: NO_PROXY + value: .svc + image: ghcr.io/fluxcd/kustomize-controller:v1.7.2 + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: /healthz + port: healthz-kc + name: kustomize-controller + ports: + - containerPort: 9793 + name: http-prom-kc + protocol: TCP + - containerPort: 9794 + name: healthz-kc + protocol: TCP + readinessProbe: + httpGet: + path: /readyz + port: healthz-kc + resources: + limits: + memory: 1Gi + requests: + cpu: 100m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + volumeMounts: + - mountPath: /tmp + name: tmp + - args: + - --watch-all-namespaces + - --log-level=info + - --log-encoding=json + - --enable-leader-election=false + - --metrics-addr=:9795 + - --health-addr=:9796 + - --watch-label-selector=!sharding.fluxcd.io/key + - --concurrent=5 + - --requeue-dependency=30s + - --events-addr=http://localhost:9690 + - --feature-gates=ExternalArtifact=true + env: + - name: SOURCE_CONTROLLER_LOCALHOST + value: localhost:9790 + - name: SOURCE_WATCHER_LOCALHOST + value: localhost:9691 + - name: RUNTIME_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: GOMEMLIMIT + valueFrom: + resourceFieldRef: + resource: limits.memory + - name: TUF_ROOT + value: /tmp/.sigstore + - name: NO_PROXY + value: .svc + image: ghcr.io/fluxcd/helm-controller:v1.4.3 + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: /healthz + port: healthz-hc + name: helm-controller + ports: + - containerPort: 9795 + name: http-prom-hc + protocol: TCP + - containerPort: 9796 + name: healthz-hc + protocol: TCP + readinessProbe: + httpGet: + path: /readyz + port: healthz-hc + resources: + limits: + memory: 1Gi + requests: + cpu: 100m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + volumeMounts: + - mountPath: /tmp + name: tmp + - args: + - --watch-all-namespaces + - --log-level=info + - --log-encoding=json + - --enable-leader-election=false + - --receiverAddr=:9797 + - --metrics-addr=:9798 + - --health-addr=:9799 + - --events-addr=:9690 + env: + - name: SOURCE_CONTROLLER_LOCALHOST + value: localhost:9790 + - name: SOURCE_WATCHER_LOCALHOST + value: localhost:9691 + - name: RUNTIME_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: GOMEMLIMIT + valueFrom: + resourceFieldRef: + resource: limits.memory + - name: TUF_ROOT + value: /tmp/.sigstore + - name: NO_PROXY + value: .svc + image: ghcr.io/fluxcd/notification-controller:v1.7.4 + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: /healthz + port: healthz-nc + name: notification-controller + ports: + - containerPort: 9690 + name: http-nc + protocol: TCP + - containerPort: 9797 + name: http-webhook-nc + protocol: TCP + - containerPort: 9798 + name: http-prom-nc + protocol: TCP + - containerPort: 9799 + name: healthz-nc + protocol: TCP + readinessProbe: + httpGet: + path: /readyz + port: healthz-nc + resources: + limits: + memory: 1Gi + requests: + cpu: 100m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + volumeMounts: + - mountPath: /tmp + name: tmp + - args: + - --watch-all-namespaces + - --log-level=info + - --log-encoding=json + - --enable-leader-election=false + - --metrics-addr=:9692 + - --health-addr=:9693 + - --storage-addr=:9691 + - --storage-path=/data + - --storage-adv-addr=source-watcher.$(RUNTIME_NAMESPACE).svc + - --events-addr=http://localhost:9690 + env: + - name: SOURCE_CONTROLLER_LOCALHOST + value: localhost:9790 + - name: SOURCE_WATCHER_LOCALHOST + value: localhost:9691 + - name: RUNTIME_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: GOMEMLIMIT + valueFrom: + resourceFieldRef: + resource: limits.memory + - name: TUF_ROOT + value: /tmp/.sigstore + - name: NO_PROXY + value: .svc + image: ghcr.io/fluxcd/source-watcher:v2.0.2 + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: /healthz + port: healthz-sw + name: source-watcher + ports: + - containerPort: 9691 + name: http-sw + protocol: TCP + - containerPort: 9692 + name: http-prom-sw + protocol: TCP + - containerPort: 9693 + name: healthz-sw + protocol: TCP + readinessProbe: + httpGet: + path: / + port: http-sw + resources: + limits: + memory: 1Gi + requests: + cpu: 100m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + volumeMounts: + - mountPath: /data + name: data + - mountPath: /tmp + name: tmp + hostNetwork: true + priorityClassName: system-cluster-critical + securityContext: + fsGroup: 1337 + serviceAccountName: flux + terminationGracePeriodSeconds: 120 + tolerations: + - key: node.kubernetes.io/not-ready + operator: Exists + - effect: NoExecute + key: node.kubernetes.io/unreachable + operator: Exists + tolerationSeconds: 300 + volumes: + - emptyDir: {} + name: data + - emptyDir: {} + name: tmp diff --git a/internal/operator/bundle_reconciler.go b/internal/operator/bundle_reconciler.go index 4db87d90..adb0dcde 100644 --- a/internal/operator/bundle_reconciler.go +++ b/internal/operator/bundle_reconciler.go @@ -91,26 +91,6 @@ func (r *CozystackBundleReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{}, err } - // Check if we need to run phase2 (install basic charts) - // Phase2 should run when: - // 1. Any bundle contains cilium and kubeovn - // 2. Flux is not ready - hasCilium, hasKubeovn, err := HasCiliumAndKubeovn(ctx, r.Client) - if err != nil { - logger.Error(err, "failed to check bundles for cilium/kubeovn") - } else if hasCilium && hasKubeovn { - fluxOK, err := FluxIsOK(ctx, r.Client) - if err != nil { - logger.Error(err, "failed to check flux status") - } else if !fluxOK { - logger.Info("Bundles contain cilium and kubeovn, and flux is not ready, running phase2") - if err := InstallBasicCharts(ctx, r.Client); err != nil { - logger.Error(err, "failed to install basic charts in phase2") - // Don't return error, just log it - phase2 is best effort - } - } - } - return ctrl.Result{}, nil } diff --git a/internal/operator/platform_configuration_reconciler.go b/internal/operator/platform_configuration_reconciler.go deleted file mode 100644 index 24eb22cb..00000000 --- a/internal/operator/platform_configuration_reconciler.go +++ /dev/null @@ -1,234 +0,0 @@ -/* -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" - "fmt" - - cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" - helmv2 "github.com/fluxcd/helm-controller/api/v2" - sourcev1 "github.com/fluxcd/source-controller/api/v1" - "github.com/fluxcd/pkg/apis/meta" - 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/client" - "sigs.k8s.io/controller-runtime/pkg/log" -) - -// CozystackPlatformConfigurationReconciler reconciles CozystackPlatformConfiguration resources -type CozystackPlatformConfigurationReconciler struct { - client.Client - Scheme *runtime.Scheme -} - -// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackplatformconfigurations,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackplatformconfigurations/status,verbs=get;update;patch -// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=gitrepositories,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=helm.toolkit.fluxcd.io,resources=helmreleases,verbs=get;list;watch;create;update;patch;delete - -// Reconcile is part of the main kubernetes reconciliation loop -func (r *CozystackPlatformConfigurationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - logger := log.FromContext(ctx) - - config := &cozyv1alpha1.CozystackPlatformConfiguration{} - if err := r.Get(ctx, req.NamespacedName, config); err != nil { - if apierrors.IsNotFound(err) { - // Resource deleted, cleanup will be handled by ownerReferences - return ctrl.Result{}, nil - } - return ctrl.Result{}, err - } - - // Reconcile GitRepository - if err := r.reconcileGitRepository(ctx, config); err != nil { - logger.Error(err, "failed to reconcile GitRepository") - return ctrl.Result{}, err - } - - // Reconcile HelmRelease - if err := r.reconcileHelmRelease(ctx, config); err != nil { - logger.Error(err, "failed to reconcile HelmRelease") - return ctrl.Result{}, err - } - - logger.Info("successfully reconciled CozystackPlatformConfiguration") - return ctrl.Result{}, nil -} - -// reconcileGitRepository creates or updates the GitRepository resource -func (r *CozystackPlatformConfigurationReconciler) reconcileGitRepository(ctx context.Context, config *cozyv1alpha1.CozystackPlatformConfiguration) error { - logger := log.FromContext(ctx) - - // GitRepository name is the same as the configuration name - gitRepoName := config.Name - // GitRepository namespace is cozy-system (hardcoded for platform configuration) - gitRepoNamespace := "cozy-system" - - desiredGitRepo := &sourcev1.GitRepository{ - ObjectMeta: metav1.ObjectMeta{ - Name: gitRepoName, - Namespace: gitRepoNamespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: config.APIVersion, - Kind: config.Kind, - Name: config.Name, - UID: config.UID, - Controller: func() *bool { b := true; return &b }(), - }, - }, - }, - Spec: sourcev1.GitRepositorySpec{ - URL: config.Spec.Source.URL, - Interval: config.Spec.Source.Interval, - Timeout: config.Spec.Source.Timeout, - Ignore: config.Spec.Source.Ignore, - Include: config.Spec.Source.Include, - RecurseSubmodules: config.Spec.Source.RecurseSubmodules, - Verification: config.Spec.Source.Verification, - }, - } - - // Set ref if provided - if config.Spec.Source.Ref != nil { - desiredGitRepo.Spec.Reference = config.Spec.Source.Ref - } - - // Set SecretRef if provided (convert from corev1.LocalObjectReference to meta.LocalObjectReference) - if config.Spec.Source.SecretRef != nil { - desiredGitRepo.Spec.SecretRef = &meta.LocalObjectReference{ - Name: config.Spec.Source.SecretRef.Name, - } - } - - if err := r.createOrUpdate(ctx, desiredGitRepo); err != nil { - return fmt.Errorf("failed to create or update GitRepository: %w", err) - } - - logger.Info("reconciled GitRepository", "name", gitRepoName, "namespace", gitRepoNamespace) - return nil -} - -// reconcileHelmRelease creates or updates the HelmRelease resource -func (r *CozystackPlatformConfigurationReconciler) reconcileHelmRelease(ctx context.Context, config *cozyv1alpha1.CozystackPlatformConfiguration) error { - logger := log.FromContext(ctx) - - // HelmRelease name is the same as the configuration name - hrName := config.Name - // HelmRelease namespace is cozy-system (hardcoded for platform configuration) - hrNamespace := "cozy-system" - - // GitRepository name (used in sourceRef) - gitRepoName := config.Name - gitRepoNamespace := "cozy-system" - - desiredHR := &helmv2.HelmRelease{ - ObjectMeta: metav1.ObjectMeta{ - Name: hrName, - Namespace: hrNamespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: config.APIVersion, - Kind: config.Kind, - Name: config.Name, - UID: config.UID, - Controller: func() *bool { b := true; return &b }(), - }, - }, - }, - Spec: helmv2.HelmReleaseSpec{ - Interval: config.Spec.Chart.Interval, - ReleaseName: hrName, - TargetNamespace: hrNamespace, - Chart: &helmv2.HelmChartTemplate{ - Spec: helmv2.HelmChartTemplateSpec{ - Chart: config.Spec.Chart.Path, - SourceRef: helmv2.CrossNamespaceObjectReference{ - Kind: "GitRepository", - Name: gitRepoName, - Namespace: gitRepoNamespace, - }, - }, - }, - }, - } - - // Set values if provided - if config.Spec.Values != nil { - desiredHR.Spec.Values = config.Spec.Values - } - - if err := r.createOrUpdate(ctx, desiredHR); err != nil { - return fmt.Errorf("failed to create or update HelmRelease: %w", err) - } - - logger.Info("reconciled HelmRelease", "name", hrName, "namespace", hrNamespace) - return nil -} - -// createOrUpdate creates or updates a Kubernetes resource -func (r *CozystackPlatformConfigurationReconciler) 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()) - - // Owner references are set by the caller and should be preserved/updated - // 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) - - return r.Update(ctx, obj) -} - -// SetupWithManager sets up the controller with the Manager -func (r *CozystackPlatformConfigurationReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&cozyv1alpha1.CozystackPlatformConfiguration{}). - Complete(r) -} - diff --git a/packages/core/fluxcd/Chart.yaml b/packages/core/fluxcd/Chart.yaml new file mode 100644 index 00000000..2e625a16 --- /dev/null +++ b/packages/core/fluxcd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-fluxcd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/core/fluxcd/Makefile b/packages/core/fluxcd/Makefile new file mode 100644 index 00000000..4addf9e9 --- /dev/null +++ b/packages/core/fluxcd/Makefile @@ -0,0 +1,16 @@ +NAME=fluxcd +NAMESPACE=cozy-$(NAME) + +show: + kubectl apply -R -f manifests/ --dry-run=client -o yaml + +apply: + kubectl apply -R -f manifests/ --server-side --force-conflicts + +diff: + kubectl diff -R -f manifests/ + +update: + timoni bundle build -f flux-aio.cue > manifests/fluxcd.yaml + sed -e 's|\.cluster\.local\.,||g' -e 's|\.cluster\.local\,||g' -e 's|\.cluster\.local\.||g' -e '/timoni/d' -i manifests/fluxcd.yaml + yq eval '(select(.kind == "Namespace") | .metadata.labels."pod-security.kubernetes.io/enforce") = "privileged"' -i manifests/fluxcd.yaml diff --git a/packages/core/fluxcd/flux-aio.cue b/packages/core/fluxcd/flux-aio.cue new file mode 100644 index 00000000..c58461cc --- /dev/null +++ b/packages/core/fluxcd/flux-aio.cue @@ -0,0 +1,17 @@ +bundle: { + apiVersion: "v1alpha1" + name: "flux-aio" + instances: { + "flux": { + module: { + url: "oci://ghcr.io/stefanprodan/modules/flux-aio" + version: "latest" + } + namespace: "cozy-fluxcd" + values: { + hostNetwork: true + securityProfile: "privileged" + } + } + } +} diff --git a/packages/core/fluxcd/manifests b/packages/core/fluxcd/manifests new file mode 120000 index 00000000..9fcd0f80 --- /dev/null +++ b/packages/core/fluxcd/manifests @@ -0,0 +1 @@ +../../../cmd/cozystack-operator/manifests \ No newline at end of file diff --git a/packages/core/fluxcd/values.yaml b/packages/core/fluxcd/values.yaml new file mode 100644 index 00000000..e269b1fb --- /dev/null +++ b/packages/core/fluxcd/values.yaml @@ -0,0 +1,55 @@ +flux-instance: + instance: + cluster: + networkPolicy: false # -- disable due to liveness/readiness probes issues with network policies + domain: cozy.local # -- default value is overriden in patches + distribution: + artifact: "" + version: 2.7.x + registry: ghcr.io/fluxcd + components: + - source-controller + - source-watcher + - kustomize-controller + - helm-controller + - notification-controller + - image-reflector-controller + - image-automation-controller + kustomize: + patches: + - target: + kind: Deployment + name: "(kustomize-controller|helm-controller|source-controller)" + patch: | + - op: add + path: /spec/template/spec/containers/0/args/- + value: --concurrent=20 + - op: add + path: /spec/template/spec/containers/0/args/- + value: --requeue-dependency=5s + - op: replace + path: /spec/template/spec/containers/0/resources/limits + value: + cpu: 2000m + memory: 2048Mi + - target: + kind: Deployment + name: source-controller + patch: | + - op: add + path: /spec/template/spec/containers/0/args/- + value: --storage-adv-addr=source-controller.cozy-fluxcd.svc + - target: + kind: Deployment + name: source-watcher + patch: | + - op: add + path: /spec/template/spec/containers/0/args/- + value: --storage-adv-addr=source-watcher.cozy-fluxcd.svc + - target: + kind: Deployment + name: (kustomize-controller|helm-controller|image-reflector-controller|image-automation-controller|source-controller|source-watcher) + patch: | + - op: add + path: /spec/template/spec/containers/0/args/- + value: --events-addr=http://notification-controller.cozy-fluxcd.svc/ diff --git a/packages/core/installer/templates/cozystack.io_cozystackplatformconfigurations.yaml b/packages/core/installer/templates/cozystack.io_cozystackplatformconfigurations.yaml deleted file mode 100644 index a9869f7b..00000000 --- a/packages/core/installer/templates/cozystack.io_cozystackplatformconfigurations.yaml +++ /dev/null @@ -1,197 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.4 - name: cozystackplatformconfigurations.cozystack.io -spec: - group: cozystack.io - names: - kind: CozystackPlatformConfiguration - listKind: CozystackPlatformConfigurationList - plural: cozystackplatformconfigurations - singular: cozystackplatformconfiguration - scope: Cluster - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: CozystackPlatformConfiguration is the Schema for the cozystackplatformconfigurations - API - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: CozystackPlatformConfigurationSpec defines the desired state - of CozystackPlatformConfiguration - properties: - chart: - description: Chart configuration for HelmRelease - properties: - interval: - default: 5m - description: Interval at which to reconcile the HelmRelease - type: string - path: - description: Path to the Helm chart directory in the Git repository - type: string - required: - - path - type: object - source: - description: Source configuration for GitRepository - properties: - ignore: - description: Ignore overrides the set of patterns for ignoring - files and folders - type: string - include: - description: Include specifies a list of Git sub-paths to include - items: - description: |- - GitRepositoryInclude specifies a local reference to a GitRepository which - Artifact (sub-)contents must be included, and where they should be placed. - properties: - fromPath: - description: |- - FromPath specifies the path to copy contents from, defaults to the root - of the Artifact. - type: string - repository: - description: |- - GitRepositoryRef specifies the GitRepository which Artifact contents - must be included. - properties: - name: - description: Name of the referent. - type: string - required: - - name - type: object - toPath: - description: |- - ToPath specifies the path to copy contents to, defaults to the name of - the GitRepositoryRef. - type: string - required: - - repository - type: object - type: array - interval: - default: 1m0s - description: Interval at which to check for updates - type: string - recurseSubmodules: - description: RecurseSubmodules enables the initialization of all - submodules - type: boolean - ref: - description: Git repository reference (branch, tag, semver, commit) - properties: - branch: - description: Branch to check out, defaults to 'master' if - no other field is defined. - type: string - commit: - description: |- - Commit SHA to check out, takes precedence over all reference fields. - - This can be combined with Branch to shallow clone the branch, in which - the commit is expected to exist. - type: string - name: - description: |- - Name of the reference to check out; takes precedence over Branch, Tag and SemVer. - - It must be a valid Git reference: https://git-scm.com/docs/git-check-ref-format#_description - Examples: "refs/heads/main", "refs/tags/v0.1.0", "refs/pull/420/head", "refs/merge-requests/1/head" - type: string - semver: - description: SemVer tag expression to check out, takes precedence - over Tag. - type: string - tag: - description: Tag to check out, takes precedence over Branch. - type: string - type: object - secretRef: - description: Secret reference containing credentials - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - timeout: - description: Timeout for Git operations - type: string - url: - description: URL of the Git repository - type: string - verification: - description: Verification specifies the Git commit signature verification - configuration - properties: - mode: - default: HEAD - description: |- - Mode specifies which Git object(s) should be verified. - - The variants "head" and "HEAD" both imply the same thing, i.e. verify - the commit that the HEAD of the Git repository points to. The variant - "head" solely exists to ensure backwards compatibility. - enum: - - head - - HEAD - - Tag - - TagAndHEAD - type: string - secretRef: - description: |- - SecretRef specifies the Secret containing the public keys of trusted Git - authors. - properties: - name: - description: Name of the referent. - type: string - required: - - name - type: object - required: - - secretRef - type: object - required: - - url - type: object - values: - description: Values to pass to HelmRelease - x-kubernetes-preserve-unknown-fields: true - required: - - chart - - source - type: object - type: object - served: true - storage: true diff --git a/packages/core/installer/templates/platform-config.yaml b/packages/core/installer/templates/platform-config.yaml deleted file mode 100644 index d12c01b6..00000000 --- a/packages/core/installer/templates/platform-config.yaml +++ /dev/null @@ -1,25 +0,0 @@ ---- -apiVersion: cozystack.io/v1alpha1 -kind: CozystackPlatformConfiguration -metadata: - name: cozystack-platform -spec: - # Source configuration for GitRepository - source: - url: https://github.com/cozystack/cozystack.git - ref: - branch: refactor-engine - interval: 1m0s - timeout: 60s - - # Chart configuration for HelmRelease - chart: - path: ./packages/core/platform - interval: 5m - - # Values to pass to HelmRelease - values: - sourceRef: - kind: GitRepository - name: cozystack-platform - namespace: cozy-system diff --git a/packages/core/platform/bundles/system/bundle-full.yaml b/packages/core/platform/bundles/system/bundle-full.yaml index 84a46fe0..179c3219 100644 --- a/packages/core/platform/bundles/system/bundle-full.yaml +++ b/packages/core/platform/bundles/system/bundle-full.yaml @@ -59,24 +59,6 @@ spec: libraries: [cozy-lib] packages: - - name: fluxcd-operator - releaseName: fluxcd-operator - path: packages/system/fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - - - name: fluxcd - releaseName: fluxcd - path: packages/system/fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator,cilium,kubeovn] - values: - flux-instance: - instance: - cluster: - domain: {{ $clusterDomain }} - - name: cilium releaseName: cilium path: packages/system/cilium diff --git a/packages/core/platform/bundles/system/bundle-hosted.yaml b/packages/core/platform/bundles/system/bundle-hosted.yaml index eaad8de2..3c4a88cd 100644 --- a/packages/core/platform/bundles/system/bundle-hosted.yaml +++ b/packages/core/platform/bundles/system/bundle-hosted.yaml @@ -59,24 +59,6 @@ spec: libraries: [cozy-lib] packages: - - name: fluxcd-operator - releaseName: fluxcd-operator - path: packages/system/fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - - - name: fluxcd - releaseName: fluxcd - path: packages/system/fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator] - values: - flux-instance: - instance: - cluster: - domain: {{ $clusterDomain }} - - name: cert-manager-crds releaseName: cert-manager-crds path: packages/system/cert-manager-crds From 982727ac910b782da4d00ea65d240c875192b496 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 21 Nov 2025 18:18:16 +0100 Subject: [PATCH 20/46] refactor and install flux-aio Signed-off-by: Andrei Kvapil --- api/v1alpha1/cozystacksystembundles_types.go | 37 +- api/v1alpha1/zz_generated.deepcopy.go | 7 + cmd/cozystack-operator/main.go | 12 +- hack/update-codegen.sh | 4 +- internal/fluxinstall/install.go | 123 +++- internal/fluxinstall/manifests.embed.go | 4 +- internal/operator/bootstrap.go | 157 ---- internal/operator/bundle_reconciler.go | 694 +++++++++++------- internal/operator/reconciler.go | 357 --------- packages/apps/tenant/templates/etcd.yaml | 2 +- packages/apps/tenant/templates/info.yaml | 2 +- packages/apps/tenant/templates/ingress.yaml | 2 +- .../apps/tenant/templates/monitoring.yaml | 2 +- packages/apps/tenant/templates/seaweedfs.yaml | 2 +- packages/apps/tenant/templates/tenant.yaml | 4 +- .../apps/virtual-machine/templates/vm.yaml | 2 +- packages/apps/vm-disk/templates/dv.yaml | 4 +- packages/core/fluxcd/manifests | 2 +- .../crds}/cozystack.io_cozystackbundles.yaml | 37 +- ...stack.io_cozystackresourcedefinitions.yaml | 0 packages/core/installer/example/platform.yaml | 49 ++ .../installer/images/cozystack/Dockerfile | 2 - .../core/installer/templates/cozystack.yaml | 3 +- packages/core/installer/templates/crds.yaml | 4 + packages/core/installer/values.yaml | 2 +- .../core/platform/bundles/iaas/bundle.yaml | 6 +- .../platform/bundles/iaas/cozyrds/bucket.yaml | 2 +- .../bundles/iaas/cozyrds/kubernetes.yaml | 2 +- .../bundles/iaas/cozyrds/virtual-machine.yaml | 2 +- .../iaas/cozyrds/virtualprivatecloud.yaml | 2 +- .../bundles/iaas/cozyrds/vm-disk.yaml | 2 +- .../bundles/iaas/cozyrds/vm-instance.yaml | 2 +- .../bundles/naas/cozyrds/http-cache.yaml | 2 +- .../bundles/naas/cozyrds/tcp-balancer.yaml | 2 +- .../platform/bundles/naas/cozyrds/vpn.yaml | 2 +- .../bundles/paas/cozyrds/clickhouse.yaml | 2 +- .../bundles/paas/cozyrds/ferretdb.yaml | 2 +- .../bundles/paas/cozyrds/foundationdb.yaml | 2 +- .../platform/bundles/paas/cozyrds/kafka.yaml | 2 +- .../platform/bundles/paas/cozyrds/mysql.yaml | 2 +- .../platform/bundles/paas/cozyrds/nats.yaml | 2 +- .../bundles/paas/cozyrds/postgres.yaml | 2 +- .../bundles/paas/cozyrds/rabbitmq.yaml | 2 +- .../platform/bundles/paas/cozyrds/redis.yaml | 2 +- .../platform/bundles/system/bundle-full.yaml | 26 +- .../bundles/system/bundle-hosted.yaml | 397 +++++----- .../bundles/system/bundle-minimal.yaml | 70 ++ .../bundles/system/cozyrds/bootbox.yaml | 2 +- .../platform/bundles/system/cozyrds/etcd.yaml | 2 +- .../platform/bundles/system/cozyrds/info.yaml | 2 +- .../bundles/system/cozyrds/ingress.yaml | 2 +- .../bundles/system/cozyrds/monitoring.yaml | 2 +- .../bundles/system/cozyrds/seaweedfs.yaml | 2 +- .../bundles/system/cozyrds/tenant.yaml | 2 +- .../{bundles-configmap.yaml => bundles.yaml} | 6 +- packages/core/platform/values.yaml | 2 +- packages/extra/bootbox/images/matchbox.tag | 2 +- .../ingress/templates/nginx-ingress.yaml | 2 +- .../extra/seaweedfs/templates/seaweedfs.yaml | 2 +- .../system/bootbox/templates/bootbox.yaml | 2 +- .../Chart.yaml | 3 - .../Makefile | 7 - .../templates/crd.yaml | 4 - .../values.yaml | 1 - .../system/kubevirt-cdi/templates/cdi-cr.yaml | 2 +- .../templates/vpa-for-vpa.yaml | 2 +- scripts/migrations/20 | 4 +- scripts/migrations/22 | 34 +- 68 files changed, 1055 insertions(+), 1081 deletions(-) delete mode 100644 internal/operator/bootstrap.go delete mode 100644 internal/operator/reconciler.go rename packages/{system/cozystack-resource-definition-crd/definition => core/installer/crds}/cozystack.io_cozystackbundles.yaml (82%) rename packages/{system/cozystack-resource-definition-crd/definition => core/installer/crds}/cozystack.io_cozystackresourcedefinitions.yaml (100%) create mode 100644 packages/core/installer/example/platform.yaml create mode 100644 packages/core/installer/templates/crds.yaml create mode 100644 packages/core/platform/bundles/system/bundle-minimal.yaml rename packages/core/platform/templates/{bundles-configmap.yaml => bundles.yaml} (90%) delete mode 100644 packages/system/cozystack-resource-definition-crd/Chart.yaml delete mode 100644 packages/system/cozystack-resource-definition-crd/Makefile delete mode 100644 packages/system/cozystack-resource-definition-crd/templates/crd.yaml delete mode 100644 packages/system/cozystack-resource-definition-crd/values.yaml diff --git a/api/v1alpha1/cozystacksystembundles_types.go b/api/v1alpha1/cozystacksystembundles_types.go index b227c8ae..a2cf677b 100644 --- a/api/v1alpha1/cozystacksystembundles_types.go +++ b/api/v1alpha1/cozystacksystembundles_types.go @@ -75,8 +75,33 @@ type CozystackBundleSpec struct { // 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"` } +// 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 { @@ -132,6 +157,7 @@ type BundleSourceRef struct { 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 @@ -143,8 +169,15 @@ type BundleRelease struct { ReleaseName string `json:"releaseName"` // Path is the path to the Helm chart directory - // +required - Path string `json:"path"` + // 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 diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 082922e7..f18cfe52 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -224,6 +224,13 @@ func (in *CozystackBundleSpec) DeepCopyInto(out *CozystackBundleSpec) { (*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 CozystackBundleSpec. diff --git a/cmd/cozystack-operator/main.go b/cmd/cozystack-operator/main.go index 211cc4b4..41084719 100644 --- a/cmd/cozystack-operator/main.go +++ b/cmd/cozystack-operator/main.go @@ -126,7 +126,7 @@ func main() { defer installCancel() // The namespace will be automatically extracted from the embedded manifests - if err := fluxinstall.Install(installCtx, mgr.GetClient()); err != nil { + 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 @@ -135,16 +135,6 @@ func main() { } } - // Setup PlatformReconciler - 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) - } - bundleReconciler := &operator.CozystackBundleReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 4eddab12..87a46114 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -55,6 +55,6 @@ kube::codegen::gen_openapi \ $CONTROLLER_GEN object:headerFile="hack/boilerplate.go.txt" paths="./api/..." $CONTROLLER_GEN rbac:roleName=manager-role crd paths="./api/..." output:crd:artifacts:config=packages/system/cozystack-controller/crds mv packages/system/cozystack-controller/crds/cozystack.io_cozystackresourcedefinitions.yaml \ - packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml + packages/core/installer/crds/cozystack.io_cozystackresourcedefinitions.yaml mv packages/system/cozystack-controller/crds/cozystack.io_cozystackbundles.yaml \ - packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackbundles.yaml + packages/core/installer/crds/cozystack.io_cozystackbundles.yaml diff --git a/internal/fluxinstall/install.go b/internal/fluxinstall/install.go index 32875740..19cb346f 100644 --- a/internal/fluxinstall/install.go +++ b/internal/fluxinstall/install.go @@ -38,7 +38,7 @@ import ( // 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) error { +func Install(ctx context.Context, k8sClient client.Client, writeEmbeddedManifests func(string) error) error { logger := log.FromContext(ctx) // Create temporary directory for manifests @@ -84,6 +84,11 @@ func Install(ctx context.Context, k8sClient client.Client) error { 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 { @@ -229,3 +234,119 @@ func isClusterDefinition(obj *unstructured.Unstructured) bool { 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 +} + diff --git a/internal/fluxinstall/manifests.embed.go b/internal/fluxinstall/manifests.embed.go index f07d0618..e6a13a99 100644 --- a/internal/fluxinstall/manifests.embed.go +++ b/internal/fluxinstall/manifests.embed.go @@ -27,8 +27,8 @@ import ( //go:embed manifests/*.yaml var embeddedFluxManifests embed.FS -// writeEmbeddedManifests extracts embedded Flux manifests to a temporary directory. -func writeEmbeddedManifests(dir string) error { +// 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) diff --git a/internal/operator/bootstrap.go b/internal/operator/bootstrap.go deleted file mode 100644 index da5a545c..00000000 --- a/internal/operator/bootstrap.go +++ /dev/null @@ -1,157 +0,0 @@ -/* -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" - "fmt" - "os/exec" - - 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" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" -) - -// FluxIsOK checks if FluxCD is ready and operational -func FluxIsOK(ctx context.Context, c client.Client) (bool, error) { - logger := log.FromContext(ctx) - - // Check source-controller deployment - sourceDeploy := &appsv1.Deployment{} - key := types.NamespacedName{Namespace: "cozy-fluxcd", Name: "source-controller"} - if err := c.Get(ctx, key, sourceDeploy); err != nil { - if apierrors.IsNotFound(err) { - logger.Info("fluxcd check: source-controller deployment not found") - return false, nil - } - return false, err - } - if !isDeploymentAvailable(sourceDeploy) { - logger.Info("fluxcd check: source-controller deployment not available") - return false, nil - } - - // Check helm-controller deployment - helmDeploy := &appsv1.Deployment{} - key = types.NamespacedName{Namespace: "cozy-fluxcd", Name: "helm-controller"} - if err := c.Get(ctx, key, helmDeploy); err != nil { - if apierrors.IsNotFound(err) { - logger.Info("fluxcd check: helm-controller deployment not found") - return false, nil - } - return false, err - } - if !isDeploymentAvailable(helmDeploy) { - logger.Info("fluxcd check: helm-controller deployment not available") - return false, nil - } - - // Check fluxcd helmrelease is ready - hr := &helmv2.HelmRelease{} - key = types.NamespacedName{Namespace: "cozy-fluxcd", Name: "fluxcd"} - if err := c.Get(ctx, key, hr); err != nil { - if apierrors.IsNotFound(err) { - logger.Info("fluxcd check: fluxcd helmrelease not found") - return false, nil - } - return false, err - } - - // Check if ready (this implicitly checks suspend, as suspended HelmRelease cannot be Ready) - if hr.Status.Conditions != nil { - for _, cond := range hr.Status.Conditions { - if cond.Type == "Ready" && cond.Status == metav1.ConditionTrue { - logger.Info("fluxcd check: fluxcd is ready") - return true, nil - } - } - } - - logger.Info("fluxcd check: fluxcd helmrelease not ready") - return false, nil -} - -func isDeploymentAvailable(deploy *appsv1.Deployment) bool { - for _, cond := range deploy.Status.Conditions { - if cond.Type == appsv1.DeploymentAvailable && cond.Status == corev1.ConditionTrue { - return true - } - } - return false -} - -// HasCiliumAndKubeovn checks if any CozystackBundle contains cilium and kubeovn packages -func HasCiliumAndKubeovn(ctx context.Context, c client.Client) (hasCilium, hasKubeovn bool, err error) { - bundleList := &cozyv1alpha1.CozystackBundleList{} - if err := c.List(ctx, bundleList); err != nil { - return false, false, fmt.Errorf("failed to list CozystackBundles: %w", err) - } - - for _, bundle := range bundleList.Items { - for _, pkg := range bundle.Spec.Packages { - if pkg.Name == "cilium" && !pkg.Disabled { - hasCilium = true - } - if pkg.Name == "kubeovn" && !pkg.Disabled { - hasKubeovn = true - } - } - } - - return hasCilium, hasKubeovn, nil -} - -// InstallBasicCharts installs cilium and kubeovn using make commands -func InstallBasicCharts(ctx context.Context, c client.Client) error { - logger := log.FromContext(ctx) - - hasCilium, hasKubeovn, err := HasCiliumAndKubeovn(ctx, c) - if err != nil { - logger.Error(err, "Failed to check bundles for cilium/kubeovn, skipping installation") - return nil // Don't fail, just skip - } - - // Install cilium only if present in bundle - if hasCilium { - logger.Info("Installing cilium using make (found in bundle)") - cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/cilium", "apply", "resume") - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to install cilium: %w", err) - } - } else { - logger.Info("Skipping cilium installation (not found in bundle)") - } - - // Install kubeovn only if present in bundle - if hasKubeovn { - logger.Info("Installing kubeovn using make (found in bundle)") - cmd := exec.CommandContext(ctx, "make", "-C", "packages/system/kubeovn", "apply", "resume") - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to install kubeovn: %w", err) - } - } else { - logger.Info("Skipping kubeovn installation (not found in bundle)") - } - - return nil -} diff --git a/internal/operator/bundle_reconciler.go b/internal/operator/bundle_reconciler.go index adb0dcde..af842d1b 100644 --- a/internal/operator/bundle_reconciler.go +++ b/internal/operator/bundle_reconciler.go @@ -26,6 +26,7 @@ import ( cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" helmv2 "github.com/fluxcd/helm-controller/api/v2" sourcewatcherv1beta1 "github.com/fluxcd/source-watcher/api/v2/v1beta1" + corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -45,6 +46,7 @@ type CozystackBundleReconciler struct { // +kubebuilder:rbac:groups=cozystack.io,resources=cozystackbundles/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 +// +kubebuilder:rbac:groups=core,resources=namespaces,verbs=get;list;watch;create;update;patch // Reconcile is part of the main kubernetes reconciliation loop func (r *CozystackBundleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { @@ -73,15 +75,21 @@ func (r *CozystackBundleReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{}, err } - // Generate ArtifactGenerators for artifacts - if err := r.reconcileArtifactArtifactGenerators(ctx, bundle); err != nil { - logger.Error(err, "failed to reconcile ArtifactGenerators for artifacts") + // Reconcile namespaces from packages + if err := r.reconcileNamespaces(ctx, bundle, resolvedPackages); err != nil { + logger.Error(err, "failed to reconcile namespaces") return ctrl.Result{}, err } - // Generate ArtifactGenerators for packages + // Check for conflicts between packages with artifact and artifacts + if err := r.checkArtifactConflicts(ctx, bundle, resolvedPackages); err != nil { + logger.Error(err, "failed to check artifact conflicts") + return ctrl.Result{}, err + } + + // Generate ArtifactGenerator for bundle (one generator per bundle with all OutputArtifacts) if err := r.reconcileArtifactGenerators(ctx, bundle, resolvedPackages); err != nil { - logger.Error(err, "failed to reconcile ArtifactGenerators") + logger.Error(err, "failed to reconcile ArtifactGenerator") return ctrl.Result{}, err } @@ -162,96 +170,8 @@ func (r *CozystackBundleReconciler) resolveDependencies(ctx context.Context, bun return resolved, nil } -// reconcileArtifactArtifactGenerators generates ArtifactGenerators from bundle artifacts -func (r *CozystackBundleReconciler) reconcileArtifactArtifactGenerators(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle) error { - logger := log.FromContext(ctx) - - libraryMap := make(map[string]cozyv1alpha1.BundleLibrary) - for _, lib := range bundle.Spec.Libraries { - libraryMap[lib.Name] = lib - } - - // Create ArtifactGenerator for each artifact - for _, artifact := range bundle.Spec.Artifacts { - // Extract artifact name from path (last component) - artifactPathName := r.getPackageNameFromPath(artifact.Path) - if artifactPathName == "" { - logger.Info("skipping artifact with invalid path", "name", artifact.Name, "path", artifact.Path) - continue - } - - // For artifacts: namespace is always cozy-public - namespace := "cozy-public" - // ArtifactGenerator name: bundle-name-artifact-name - agName := fmt.Sprintf("%s-artifact-%s", bundle.Name, artifact.Name) - - // Build copy operations - copyOps := []sourcewatcherv1beta1.CopyOperation{ - { - From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, artifact.Path), - To: fmt.Sprintf("@artifact/%s/", artifactPathName), - }, - } - - // Add libraries if specified - for _, libName := range artifact.Libraries { - if lib, ok := libraryMap[libName]; ok { - copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ - From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, lib.Path), - To: fmt.Sprintf("@artifact/%s/charts/%s/", artifactPathName, libName), - }) - } - } - - // Artifact name: {bundle-name}-{artifact-name} - // Bundle name already contains "cozystack-" prefix, so we just combine bundle name and artifact name - artifactName := fmt.Sprintf("%s-%s", bundle.Name, artifact.Name) - - // Create ArtifactGenerator for this artifact - ag := &sourcewatcherv1beta1.ArtifactGenerator{ - ObjectMeta: metav1.ObjectMeta{ - Name: agName, - Namespace: namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: bundle.APIVersion, - Kind: bundle.Kind, - Name: bundle.Name, - UID: bundle.UID, - Controller: func() *bool { b := true; return &b }(), - }, - }, - }, - Spec: sourcewatcherv1beta1.ArtifactGeneratorSpec{ - Sources: []sourcewatcherv1beta1.SourceReference{ - { - Alias: bundle.Spec.SourceRef.Name, - Kind: bundle.Spec.SourceRef.Kind, - Name: bundle.Spec.SourceRef.Name, - Namespace: bundle.Spec.SourceRef.Namespace, - }, - }, - OutputArtifacts: []sourcewatcherv1beta1.OutputArtifact{ - { - Name: artifactName, - Copy: copyOps, - }, - }, - }, - } - - if err := r.createOrUpdate(ctx, ag); err != nil { - return fmt.Errorf("failed to reconcile ArtifactGenerator for artifact %s: %w", agName, err) - } - logger.Info("reconciled ArtifactGenerator for artifact", "name", agName, "namespace", namespace, "artifact", artifact.Name) - } - - // Cleanup orphaned ArtifactGenerators for artifacts - return r.cleanupOrphanedArtifactArtifactGenerators(ctx, bundle) -} - -// reconcileArtifactGenerators generates ArtifactGenerators from bundle packages -// Creates a separate ArtifactGenerator for each package +// reconcileArtifactGenerators generates a single ArtifactGenerator for the bundle +// Creates one ArtifactGenerator per bundle with all OutputArtifacts from packages and artifacts func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle, packages []cozyv1alpha1.BundleRelease) error { logger := log.FromContext(ctx) @@ -260,8 +180,21 @@ func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Cont libraryMap[lib.Name] = lib } - // Create ArtifactGenerator for each package + // Namespace is always cozy-system + namespace := "cozy-system" + // ArtifactGenerator name is the bundle name + agName := bundle.Name + + // Collect all OutputArtifacts + outputArtifacts := []sourcewatcherv1beta1.OutputArtifact{} + + // Process packages for _, pkg := range packages { + // Skip packages without path (they might use artifacts) + if pkg.Path == "" { + continue + } + // Determine prefix from path prefix := r.getPackagePrefix(pkg.Path) if prefix == "" { @@ -269,11 +202,6 @@ func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Cont continue } - // For packages: namespace is always cozy-system - namespace := "cozy-system" - // ArtifactGenerator name: bundle-name-package-name - agName := fmt.Sprintf("%s-%s", bundle.Name, pkg.Name) - // Extract package name from path (last component) pkgName := r.getPackageNameFromPath(pkg.Path) if pkgName == "" { @@ -312,48 +240,116 @@ func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Cont }) } - // Artifact name: prefix-package-name (e.g., system-cilium) - artifactName := fmt.Sprintf("%s-%s", prefix, pkgName) + // Artifact name: bundle-name-package-name (e.g., cozystack-system-cilium) + artifactName := fmt.Sprintf("%s-%s", bundle.Name, pkgName) - // Create ArtifactGenerator for this package - ag := &sourcewatcherv1beta1.ArtifactGenerator{ - ObjectMeta: metav1.ObjectMeta{ - Name: agName, - Namespace: namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: bundle.APIVersion, - Kind: bundle.Kind, - Name: bundle.Name, - UID: bundle.UID, - Controller: func() *bool { b := true; return &b }(), - }, - }, - }, - Spec: sourcewatcherv1beta1.ArtifactGeneratorSpec{ - Sources: []sourcewatcherv1beta1.SourceReference{ - { - Alias: bundle.Spec.SourceRef.Name, - Kind: bundle.Spec.SourceRef.Kind, - Name: bundle.Spec.SourceRef.Name, - Namespace: bundle.Spec.SourceRef.Namespace, - }, - }, - OutputArtifacts: []sourcewatcherv1beta1.OutputArtifact{ - { - Name: artifactName, - Copy: copyOps, - }, - }, - }, - } + outputArtifacts = append(outputArtifacts, sourcewatcherv1beta1.OutputArtifact{ + Name: artifactName, + Copy: copyOps, + }) - if err := r.createOrUpdate(ctx, ag); err != nil { - return fmt.Errorf("failed to reconcile ArtifactGenerator %s: %w", agName, err) - } - logger.Info("reconciled ArtifactGenerator", "name", agName, "namespace", namespace, "package", pkg.Name) + logger.Info("added OutputArtifact for package", "bundle", bundle.Name, "package", pkg.Name, "artifactName", artifactName) } + // Process artifacts + for _, artifact := range bundle.Spec.Artifacts { + logger.Info("processing artifact", "bundle", bundle.Name, "artifact", artifact.Name, "path", artifact.Path) + // Extract artifact name from path (last component) + artifactPathName := r.getPackageNameFromPath(artifact.Path) + if artifactPathName == "" { + logger.Info("skipping artifact with invalid path", "name", artifact.Name, "path", artifact.Path) + continue + } + + // Build copy operations + copyOps := []sourcewatcherv1beta1.CopyOperation{ + { + From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, artifact.Path), + To: fmt.Sprintf("@artifact/%s/", artifactPathName), + }, + } + + // Add libraries if specified + for _, libName := range artifact.Libraries { + if lib, ok := libraryMap[libName]; ok { + copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ + From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, lib.Path), + To: fmt.Sprintf("@artifact/%s/charts/%s/", artifactPathName, libName), + }) + } + } + + // Artifact name: {bundle-name}-{artifact-name} + artifactName := fmt.Sprintf("%s-%s", bundle.Name, artifact.Name) + + outputArtifacts = append(outputArtifacts, sourcewatcherv1beta1.OutputArtifact{ + Name: artifactName, + Copy: copyOps, + }) + + logger.Info("added OutputArtifact for artifact", "bundle", bundle.Name, "artifact", artifact.Name, "artifactName", artifactName) + } + + // If there are no OutputArtifacts, cleanup and return + if len(outputArtifacts) == 0 { + logger.Info("no OutputArtifacts to generate, skipping ArtifactGenerator creation", "bundle", bundle.Name) + // Cleanup orphaned ArtifactGenerators (to remove existing generator if it exists) + return r.cleanupOrphanedArtifactGenerators(ctx, bundle) + } + + // Build labels: merge bundle labels with default cozystack.io/bundle label + labels := make(map[string]string) + if bundle.Spec.Labels != nil { + for k, v := range bundle.Spec.Labels { + labels[k] = v + } + } + labels["cozystack.io/bundle"] = bundle.Name + + // Create single ArtifactGenerator for the bundle + ag := &sourcewatcherv1beta1.ArtifactGenerator{ + ObjectMeta: metav1.ObjectMeta{ + Name: agName, + Namespace: namespace, + Labels: labels, + }, + Spec: sourcewatcherv1beta1.ArtifactGeneratorSpec{ + Sources: []sourcewatcherv1beta1.SourceReference{ + { + Alias: bundle.Spec.SourceRef.Name, + Kind: bundle.Spec.SourceRef.Kind, + Name: bundle.Spec.SourceRef.Name, + Namespace: bundle.Spec.SourceRef.Namespace, + }, + }, + OutputArtifacts: outputArtifacts, + }, + } + + // Set ownerReference only if deletionPolicy is not Orphan + if bundle.Spec.DeletionPolicy != cozyv1alpha1.DeletionPolicyOrphan { + ag.OwnerReferences = []metav1.OwnerReference{ + { + APIVersion: bundle.APIVersion, + Kind: bundle.Kind, + Name: bundle.Name, + UID: bundle.UID, + Controller: func() *bool { b := true; return &b }(), + }, + } + } else { + // Explicitly set empty ownerReferences for Orphan policy + ag.OwnerReferences = []metav1.OwnerReference{} + } + + logger.Info("creating ArtifactGenerator for bundle", "bundle", bundle.Name, "agName", agName, "namespace", namespace, "outputArtifactCount", len(outputArtifacts)) + + if err := r.createOrUpdate(ctx, ag); err != nil { + return fmt.Errorf("failed to reconcile ArtifactGenerator %s: %w", agName, err) + } + + logger.Info("reconciled ArtifactGenerator for bundle", "name", agName, "namespace", namespace, "outputArtifactCount", len(outputArtifacts)) + // Cleanup orphaned ArtifactGenerators return r.cleanupOrphanedArtifactGenerators(ctx, bundle) } @@ -386,34 +382,56 @@ func (r *CozystackBundleReconciler) reconcileHelmReleases(ctx context.Context, b globalPackageMap[pkg.Name] = pkg } + // Build artifact name map from bundle artifacts for conflict checking + artifactNameMap := make(map[string]bool) + for _, artifact := range bundle.Spec.Artifacts { + artifactNameMap[artifact.Name] = true + } + // Create HelmRelease for each package for _, pkg := range packages { - // Determine artifact name from path - prefix := r.getPackagePrefix(pkg.Path) - pkgName := r.getPackageNameFromPath(pkg.Path) - if prefix == "" || pkgName == "" { - logger.Info("skipping package with invalid path", "name", pkg.Name, "path", pkg.Path) + var artifactName string + artifactNamespace := "cozy-system" + + if pkg.Artifact != "" { + // Package uses an artifact reference + // Check if artifact exists in bundle + if !artifactNameMap[pkg.Artifact] { + logger.Error(fmt.Errorf("artifact %s not found in bundle artifacts", pkg.Artifact), "skipping package", "name", pkg.Name) + continue + } + // Artifact name format: {bundle-name}-{artifact-name} + artifactName = fmt.Sprintf("%s-%s", bundle.Name, pkg.Artifact) + } else if pkg.Path != "" { + // Package uses a path (legacy behavior) + prefix := r.getPackagePrefix(pkg.Path) + pkgName := r.getPackageNameFromPath(pkg.Path) + if prefix == "" || pkgName == "" { + logger.Info("skipping package with invalid path", "name", pkg.Name, "path", pkg.Path) + continue + } + // Artifact name format: {bundle-name}-{package-name} + artifactName = fmt.Sprintf("%s-%s", bundle.Name, pkgName) + } else { + logger.Error(fmt.Errorf("neither artifact nor path specified"), "skipping package", "name", pkg.Name) continue } - artifactName := fmt.Sprintf("%s-%s", prefix, pkgName) - // For packages: artifacts are always in cozy-system - artifactNamespace := "cozy-system" + // Build labels: merge bundle labels with default cozystack.io/bundle label + hrLabels := make(map[string]string) + if bundle.Spec.Labels != nil { + for k, v := range bundle.Spec.Labels { + hrLabels[k] = v + } + } + hrLabels["cozystack.io/bundle"] = bundle.Name // Create HelmRelease hr := &helmv2.HelmRelease{ ObjectMeta: metav1.ObjectMeta{ Name: pkg.Name, Namespace: pkg.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: bundle.APIVersion, - Kind: bundle.Kind, - Name: bundle.Name, - UID: bundle.UID, - Controller: func() *bool { b := true; return &b }(), - }, - }, + Labels: hrLabels, }, Spec: helmv2.HelmReleaseSpec{ Interval: metav1.Duration{Duration: 5 * 60 * 1000000000}, // 5m @@ -436,6 +454,22 @@ func (r *CozystackBundleReconciler) reconcileHelmReleases(ctx context.Context, b }, } + // Set ownerReference only if deletionPolicy is not Orphan + if bundle.Spec.DeletionPolicy != cozyv1alpha1.DeletionPolicyOrphan { + hr.OwnerReferences = []metav1.OwnerReference{ + { + APIVersion: bundle.APIVersion, + Kind: bundle.Kind, + Name: bundle.Name, + UID: bundle.UID, + Controller: func() *bool { b := true; return &b }(), + }, + } + } else { + // Explicitly set empty ownerReferences for Orphan policy + hr.OwnerReferences = []metav1.OwnerReference{} + } + // Set values if provided if pkg.Values != nil { hr.Spec.Values = pkg.Values @@ -517,6 +551,24 @@ func (r *CozystackBundleReconciler) createOrUpdate(ctx context.Context, obj clie } obj.SetAnnotations(annotations) + // Update ownerReferences: always use the ones from obj + // This allows deletionPolicy = Orphan to work by setting empty ownerReferences array + // When ownerReferences field is set in obj (even as empty array), use it + // Empty array will clear ownerReferences (for deletionPolicy = Orphan or when policy changes) + // If ownerReferences field is not set in obj (nil), preserve existing ones + objOwnerRefs := obj.GetOwnerReferences() + if objOwnerRefs != nil { + // obj has ownerReferences set (either populated or empty array), use them + // Empty array (len == 0) means we want to remove all ownerReferences (deletionPolicy = Orphan) + // This handles policy changes from Delete to Orphan + // objOwnerRefs is already set in obj, so it will be used in Update + // No need to do anything else - Update will use the ownerReferences from obj + } else if len(existing.GetOwnerReferences()) > 0 { + // obj doesn't have ownerReferences set (nil), but existing does + // Preserve existing ones (they might be from other owners) + obj.SetOwnerReferences(existing.GetOwnerReferences()) + } + return r.Update(ctx, obj) } @@ -552,34 +604,32 @@ func (r *CozystackBundleReconciler) getPackageNameFromPath(path string) string { func (r *CozystackBundleReconciler) cleanupOrphanedArtifactGenerators(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle) error { logger := log.FromContext(ctx) + // Find ArtifactGenerators by label agList := &sourcewatcherv1beta1.ArtifactGeneratorList{} - if err := r.List(ctx, agList); err != nil { + if err := r.List(ctx, agList, client.MatchingLabels{ + "cozystack.io/bundle": bundle.Name, + }); err != nil { if apierrors.IsNotFound(err) { return nil } return err } - // Build desired names: bundle-name-package-name for each package - desiredNames := make(map[string]bool) - for _, pkg := range bundle.Spec.Packages { - desiredNames[fmt.Sprintf("%s-%s", bundle.Name, pkg.Name)] = true - } + // Desired name: bundle name (one ArtifactGenerator per bundle) + desiredName := bundle.Name - // Find ArtifactGenerators owned by this bundle + // Find ArtifactGenerators with this bundle label for _, ag := range agList.Items { - isOwned := false - for _, ownerRef := range ag.OwnerReferences { - if ownerRef.Kind == "CozystackBundle" && ownerRef.Name == bundle.Name && ownerRef.UID == bundle.UID { - isOwned = true - break - } - } + // Check if it's the desired name + isDesired := ag.Name == desiredName - if isOwned && !desiredNames[ag.Name] { + if !isDesired { + // Delete ArtifactGenerators that don't match the desired name + // This includes old pattern ArtifactGenerators (for migration from per-package/per-artifact to per-bundle) + logger.Info("deleting orphaned ArtifactGenerator", "name", ag.Name, "bundle", bundle.Name, "desiredName", desiredName) if err := r.Delete(ctx, &ag); err != nil { if !apierrors.IsNotFound(err) { - logger.Error(err, "failed to delete ArtifactGenerator", "name", ag.Name) + logger.Error(err, "failed to delete orphaned ArtifactGenerator", "name", ag.Name) } } else { logger.Info("deleted orphaned ArtifactGenerator", "name", ag.Name) @@ -590,55 +640,14 @@ func (r *CozystackBundleReconciler) cleanupOrphanedArtifactGenerators(ctx contex return nil } -func (r *CozystackBundleReconciler) cleanupOrphanedArtifactArtifactGenerators(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle) error { - logger := log.FromContext(ctx) - - agList := &sourcewatcherv1beta1.ArtifactGeneratorList{} - if err := r.List(ctx, agList); err != nil { - if apierrors.IsNotFound(err) { - return nil - } - return err - } - - // Build desired names: bundle-name-artifact-name for each artifact - desiredNames := make(map[string]bool) - for _, artifact := range bundle.Spec.Artifacts { - desiredNames[fmt.Sprintf("%s-artifact-%s", bundle.Name, artifact.Name)] = true - } - - // Find ArtifactGenerators owned by this bundle for artifacts - for _, ag := range agList.Items { - if !strings.HasPrefix(ag.Name, fmt.Sprintf("%s-artifact-", bundle.Name)) { - continue - } - isOwned := false - for _, ownerRef := range ag.OwnerReferences { - if ownerRef.Kind == "CozystackBundle" && ownerRef.Name == bundle.Name && ownerRef.UID == bundle.UID { - isOwned = true - break - } - } - - if isOwned && !desiredNames[ag.Name] { - if err := r.Delete(ctx, &ag); err != nil { - if !apierrors.IsNotFound(err) { - logger.Error(err, "failed to delete ArtifactGenerator for artifact", "name", ag.Name) - } - } else { - logger.Info("deleted orphaned ArtifactGenerator for artifact", "name", ag.Name) - } - } - } - - return nil -} - func (r *CozystackBundleReconciler) cleanupOrphanedHelmReleases(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle) error { logger := log.FromContext(ctx) + // Find HelmReleases by label hrList := &helmv2.HelmReleaseList{} - if err := r.List(ctx, hrList); err != nil { + if err := r.List(ctx, hrList, client.MatchingLabels{ + "cozystack.io/bundle": bundle.Name, + }); err != nil { return err } @@ -648,26 +657,17 @@ func (r *CozystackBundleReconciler) cleanupOrphanedHelmReleases(ctx context.Cont desiredNames[types.NamespacedName{Name: pkg.Name, Namespace: pkg.Namespace}] = true } - // Find HelmReleases owned by this bundle + // Find HelmReleases with this bundle label for _, hr := range hrList.Items { - isOwned := false - for _, ownerRef := range hr.OwnerReferences { - if ownerRef.Kind == "CozystackBundle" && ownerRef.Name == bundle.Name && ownerRef.UID == bundle.UID { - isOwned = true - break - } - } - - if isOwned { - key := types.NamespacedName{Name: hr.Name, Namespace: hr.Namespace} - if !desiredNames[key] { - if err := r.Delete(ctx, &hr); err != nil { - if !apierrors.IsNotFound(err) { - logger.Error(err, "failed to delete HelmRelease", "name", hr.Name, "namespace", hr.Namespace) - } - } else { - logger.Info("deleted orphaned HelmRelease", "name", hr.Name, "namespace", hr.Namespace) + key := types.NamespacedName{Name: hr.Name, Namespace: hr.Namespace} + if !desiredNames[key] { + logger.Info("deleting orphaned HelmRelease", "name", hr.Name, "namespace", hr.Namespace, "bundle", bundle.Name) + if err := r.Delete(ctx, &hr); err != nil { + if !apierrors.IsNotFound(err) { + logger.Error(err, "failed to delete HelmRelease", "name", hr.Name, "namespace", hr.Namespace) } + } else { + logger.Info("deleted orphaned HelmRelease", "name", hr.Name, "namespace", hr.Namespace) } } } @@ -678,30 +678,28 @@ func (r *CozystackBundleReconciler) cleanupOrphanedHelmReleases(ctx context.Cont func (r *CozystackBundleReconciler) cleanupOrphanedResources(ctx context.Context, bundleKey types.NamespacedName) (ctrl.Result, error) { logger := log.FromContext(ctx) - // Cleanup ArtifactGenerators + // Cleanup ArtifactGenerators by label agList := &sourcewatcherv1beta1.ArtifactGeneratorList{} - if err := r.List(ctx, agList); err == nil { + if err := r.List(ctx, agList, client.MatchingLabels{ + "cozystack.io/bundle": bundleKey.Name, + }); err == nil { for _, ag := range agList.Items { - for _, ownerRef := range ag.OwnerReferences { - if ownerRef.Kind == "CozystackBundle" && ownerRef.Name == bundleKey.Name { - if err := r.Delete(ctx, &ag); err != nil && !apierrors.IsNotFound(err) { - logger.Error(err, "failed to delete orphaned ArtifactGenerator", "name", ag.Name) - } - } + logger.Info("deleting orphaned ArtifactGenerator", "name", ag.Name, "bundle", bundleKey.Name) + if err := r.Delete(ctx, &ag); err != nil && !apierrors.IsNotFound(err) { + logger.Error(err, "failed to delete orphaned ArtifactGenerator", "name", ag.Name) } } } - // Cleanup HelmReleases + // Cleanup HelmReleases by label hrList := &helmv2.HelmReleaseList{} - if err := r.List(ctx, hrList); err == nil { + if err := r.List(ctx, hrList, client.MatchingLabels{ + "cozystack.io/bundle": bundleKey.Name, + }); err == nil { for _, hr := range hrList.Items { - for _, ownerRef := range hr.OwnerReferences { - if ownerRef.Kind == "CozystackBundle" && ownerRef.Name == bundleKey.Name { - if err := r.Delete(ctx, &hr); err != nil && !apierrors.IsNotFound(err) { - logger.Error(err, "failed to delete orphaned HelmRelease", "name", hr.Name, "namespace", hr.Namespace) - } - } + logger.Info("deleting orphaned HelmRelease", "name", hr.Name, "namespace", hr.Namespace, "bundle", bundleKey.Name) + if err := r.Delete(ctx, &hr); err != nil && !apierrors.IsNotFound(err) { + logger.Error(err, "failed to delete orphaned HelmRelease", "name", hr.Name, "namespace", hr.Namespace) } } } @@ -709,6 +707,199 @@ func (r *CozystackBundleReconciler) cleanupOrphanedResources(ctx context.Context return ctrl.Result{}, nil } +// reconcileNamespaces creates or updates namespaces based on packages in the bundle. +func (r *CozystackBundleReconciler) reconcileNamespaces(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle, packages []cozyv1alpha1.BundleRelease) error { + logger := log.FromContext(ctx) + + // Collect namespaces from packages + // Map: namespace -> isPrivileged (true if at least one package in this namespace is privileged) + namespacesMap := make(map[string]bool) + + for _, pkg := range packages { + // Skip disabled packages + if pkg.Disabled { + continue + } + + // Skip if namespace is empty + if pkg.Namespace == "" { + continue + } + + // If package is privileged, mark namespace as privileged + // If namespace already exists and is privileged, keep it privileged + if pkg.Privileged { + namespacesMap[pkg.Namespace] = true + } else { + // Only set to false if not already marked as privileged + if _, exists := namespacesMap[pkg.Namespace]; !exists { + namespacesMap[pkg.Namespace] = false + } + } + } + + // Create or update all namespaces + for nsName, privileged := range namespacesMap { + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: nsName, + Labels: map[string]string{ + "cozystack.io/system": "true", + }, + Annotations: map[string]string{ + "helm.sh/resource-policy": "keep", + }, + }, + } + + // Add privileged label if needed + if privileged { + namespace.Labels["pod-security.kubernetes.io/enforce"] = "privileged" + } + + if err := r.createOrUpdateNamespace(ctx, namespace); err != nil { + logger.Error(err, "failed to reconcile namespace", "name", nsName, "privileged", privileged) + return fmt.Errorf("failed to reconcile namespace %s: %w", nsName, err) + } + logger.Info("reconciled namespace", "name", nsName, "privileged", privileged) + } + + return nil +} + +// createOrUpdateNamespace creates or updates a namespace. +func (r *CozystackBundleReconciler) createOrUpdateNamespace(ctx context.Context, namespace *corev1.Namespace) error { + existing := &corev1.Namespace{} + key := types.NamespacedName{Name: namespace.Name} + + err := r.Get(ctx, key, existing) + if apierrors.IsNotFound(err) { + return r.Create(ctx, namespace) + } else if err != nil { + return err + } + + // Preserve resource version + namespace.SetResourceVersion(existing.GetResourceVersion()) + + // Merge labels + labels := namespace.GetLabels() + if labels == nil { + labels = make(map[string]string) + } + for k, v := range existing.GetLabels() { + if _, ok := labels[k]; !ok { + labels[k] = v + } + } + namespace.SetLabels(labels) + + // Merge annotations + annotations := namespace.GetAnnotations() + if annotations == nil { + annotations = make(map[string]string) + } + for k, v := range existing.GetAnnotations() { + if _, ok := annotations[k]; !ok { + annotations[k] = v + } + } + namespace.SetAnnotations(annotations) + + return r.Update(ctx, namespace) +} + +// checkArtifactConflicts checks for conflicts between packages using artifacts and bundle artifacts +func (r *CozystackBundleReconciler) checkArtifactConflicts(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle, packages []cozyv1alpha1.BundleRelease) error { + // Build artifact name map from bundle artifacts + artifactNameMap := make(map[string]bool) + for _, artifact := range bundle.Spec.Artifacts { + artifactNameMap[artifact.Name] = true + } + + // Check packages that use artifacts + for _, pkg := range packages { + if pkg.Artifact != "" { + if !artifactNameMap[pkg.Artifact] { + return fmt.Errorf("package %s references artifact %s which is not defined in bundle artifacts", pkg.Name, pkg.Artifact) + } + } + } + + return nil +} + +// removeOwnerReferences removes ownerReferences from all resources with bundle label +func (r *CozystackBundleReconciler) removeOwnerReferences(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle) error { + logger := log.FromContext(ctx) + + // Remove ownerReferences from ArtifactGenerators by label + agList := &sourcewatcherv1beta1.ArtifactGeneratorList{} + if err := r.List(ctx, agList, client.MatchingLabels{ + "cozystack.io/bundle": bundle.Name, + }); err == nil { + for i := range agList.Items { + ag := &agList.Items[i] + updated := false + newOwnerRefs := []metav1.OwnerReference{} + + for _, ownerRef := range ag.OwnerReferences { + if ownerRef.Kind == "CozystackBundle" && ownerRef.Name == bundle.Name { + // Skip this ownerReference (remove it) + // Check by name only, not UID, to handle bundle updates + updated = true + } else { + // Keep other ownerReferences + newOwnerRefs = append(newOwnerRefs, ownerRef) + } + } + + if updated { + ag.SetOwnerReferences(newOwnerRefs) + if err := r.Update(ctx, ag); err != nil { + logger.Error(err, "failed to remove ownerReference from ArtifactGenerator", "name", ag.Name, "namespace", ag.Namespace) + } else { + logger.Info("removed ownerReference from ArtifactGenerator", "name", ag.Name, "namespace", ag.Namespace) + } + } + } + } + + // Remove ownerReferences from HelmReleases by label + hrList := &helmv2.HelmReleaseList{} + if err := r.List(ctx, hrList, client.MatchingLabels{ + "cozystack.io/bundle": bundle.Name, + }); err == nil { + for i := range hrList.Items { + hr := &hrList.Items[i] + updated := false + newOwnerRefs := []metav1.OwnerReference{} + + for _, ownerRef := range hr.OwnerReferences { + if ownerRef.Kind == "CozystackBundle" && ownerRef.Name == bundle.Name { + // Skip this ownerReference (remove it) + // Check by name only, not UID, to handle bundle updates + updated = true + } else { + // Keep other ownerReferences + newOwnerRefs = append(newOwnerRefs, ownerRef) + } + } + + if updated { + hr.SetOwnerReferences(newOwnerRefs) + if err := r.Update(ctx, hr); err != nil { + logger.Error(err, "failed to remove ownerReference from HelmRelease", "name", hr.Name, "namespace", hr.Namespace) + } else { + logger.Info("removed ownerReference from HelmRelease", "name", hr.Name, "namespace", hr.Namespace) + } + } + } + } + + return nil +} + // SetupWithManager sets up the controller with the Manager. func (r *CozystackBundleReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). @@ -716,4 +907,3 @@ func (r *CozystackBundleReconciler) SetupWithManager(mgr ctrl.Manager) error { For(&cozyv1alpha1.CozystackBundle{}). Complete(r) } - diff --git a/internal/operator/reconciler.go b/internal/operator/reconciler.go deleted file mode 100644 index 73ba9e46..00000000 --- a/internal/operator/reconciler.go +++ /dev/null @@ -1,357 +0,0 @@ -/* -Copyright 2024 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" - "fmt" - - cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" - helmv2 "github.com/fluxcd/helm-controller/api/v2" - corev1 "k8s.io/api/core/v1" - 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/client" - "sigs.k8s.io/controller-runtime/pkg/log" - - "github.com/cozystack/cozystack/pkg/config" -) - -const ( - cozystackConfigMapName = "cozystack" - cozystackConfigMapNamespace = "cozy-system" - platformOperatorLabel = "cozystack.io/platform-operator" -) - -var ( - // System packages list - packages that are in packages/system/ directory - systemPackagesList = map[string]bool{ - "bootbox": true, "bucket": true, "capi-operator": true, "capi-providers-bootstrap": true, - "capi-providers-core": true, "capi-providers-cpprovider": true, "capi-providers-infraprovider": true, - "cert-manager": true, "cert-manager-crds": true, "cert-manager-issuers": true, "cilium": true, - "cilium-networkpolicy": true, "clickhouse-operator": true, "coredns": true, "cozy-proxy": true, - "cozystack-api": true, "cozystack-controller": true, "cozystack-resource-definition-crd": true, - "cozystack-resource-definitions": true, "dashboard": true, "etcd-operator": true, "external-dns": true, - "external-secrets-operator": true, "fluxcd": true, "fluxcd-operator": true, "foundationdb-operator": true, - "gateway-api-crds": true, "goldpinger": true, "gpu-operator": true, "grafana-operator": true, - "hetzner-robotlb": true, "ingress-nginx": true, "kafka-operator": true, "kamaji": true, - "keycloak": true, "keycloak-configure": true, "keycloak-operator": true, "kubeovn": true, - "kubeovn-plunger": true, "kubeovn-webhook": true, "kubevirt": true, "kubevirt-cdi": true, - "kubevirt-cdi-operator": true, "kubevirt-csi-node": true, "kubevirt-instancetypes": true, - "kubevirt-operator": true, "lineage-controller-webhook": true, "linstor": true, "mariadb-operator": true, - "metallb": true, "monitoring-agents": true, "multus": true, "nats": true, "nfs-driver": true, - "objectstorage-controller": true, "opencost": true, "piraeus-operator": true, "postgres-operator": true, - "rabbitmq-operator": true, "redis-operator": true, "reloader": true, "seaweedfs": true, - "snapshot-controller": true, "telepresence": true, "velero": true, "vertical-pod-autoscaler": true, - "vertical-pod-autoscaler-crds": true, "victoria-metrics-operator": true, "vsnap-crd": true, - } - - // Apps packages list - packages that are in packages/apps/ directory - appsPackagesList = map[string]bool{ - "bucket": true, "clickhouse": true, "ferretdb": true, "foundationdb": true, "http-cache": true, - "kafka": true, "kubernetes": true, "mysql": true, "nats": true, "postgres": true, "rabbitmq": true, - "redis": true, "tcp-balancer": true, "tenant": true, "virtual-machine": true, "vm-disk": true, - "vm-instance": true, "vpc": true, "vpn": true, - } - - // Extra packages list - packages that are in packages/extra/ directory - extraPackagesList = map[string]bool{ - "bootbox": true, "etcd": true, "info": true, "ingress": true, "monitoring": true, "seaweedfs": true, - } -) - -// getArtifactPrefixAndNamespace determines the artifact prefix and namespace based on package category -// Returns: prefix, namespace, found -func getArtifactPrefixAndNamespace(chartName string) (string, string, bool) { - if systemPackagesList[chartName] { - return "system", "cozy-system", true - } - if appsPackagesList[chartName] { - return "apps", "cozy-public", true - } - if extraPackagesList[chartName] { - return "extra", "cozy-public", true - } - return "", "", false -} - -// PlatformReconciler reconciles the platform configuration. -type PlatformReconciler struct { - client.Client - Scheme *runtime.Scheme - FirstReconcileDone chan struct{} -} - -// +kubebuilder:rbac:groups=core,resources=configmaps,verbs=get;list;watch -// +kubebuilder:rbac:groups=core,resources=configmaps/status,verbs=get -// +kubebuilder:rbac:groups=core,resources=namespaces,verbs=get;list;watch;create;update;patch -// +kubebuilder:rbac:groups=helm.toolkit.fluxcd.io,resources=helmreleases,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackbundles,verbs=get;list;watch - -// Reconcile is part of the main kubernetes reconciliation loop which aims to -// move the current state of the cluster closer to the desired state. -func (r *PlatformReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - logger := log.FromContext(ctx) - - // Reconcile on changes to cozystack ConfigMap - if req.Namespace != cozystackConfigMapNamespace { - return ctrl.Result{}, nil - } - - // Reconcile on changes to cozystack ConfigMap - if req.Name != cozystackConfigMapName { - return ctrl.Result{}, nil - } - - // Get the cozystack ConfigMap - configMap := &corev1.ConfigMap{} - if err := r.Get(ctx, req.NamespacedName, configMap); err != nil { - if apierrors.IsNotFound(err) { - logger.Info("cozystack ConfigMap not found") - return ctrl.Result{}, nil - } - return ctrl.Result{}, err - } - - // Parse ConfigMap data - cfg := config.ParseConfigMapData(configMap.Data) - if cfg.BundleName == "" { - logger.Info("bundle-name not set in cozystack ConfigMap") - return ctrl.Result{}, nil - } - - logger.Info("Reconciling platform", "bundle", cfg.BundleName) - - // Reconcile namespaces - if err := r.reconcileNamespaces(ctx, cfg); err != nil { - return ctrl.Result{}, fmt.Errorf("failed to reconcile namespaces: %w", err) - } - - // Reconcile tenant-root - if err := r.reconcileTenantRoot(ctx, cfg); err != nil { - return ctrl.Result{}, fmt.Errorf("failed to reconcile tenant-root: %w", err) - } - - // Signal that first reconcile is done (non-blocking) - if r.FirstReconcileDone != nil { - select { - case <-r.FirstReconcileDone: - // Already closed, do nothing - default: - // Close channel to signal first reconcile is done - close(r.FirstReconcileDone) - } - } - - return ctrl.Result{}, nil -} - -// SetupWithManager sets up the controller with the Manager. -func (r *PlatformReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - Named("platform-operator"). - For(&corev1.ConfigMap{}). - Complete(r) -} - -// Removed reconcileHelmRepositories, reconcileGitRepository, reconcileArtifactGenerators, and reconcileHelmReleases -// These are now handled by CozystackBundleReconciler and CozystackResourceDefinitionReconciler - -func (r *PlatformReconciler) reconcileNamespaces(ctx context.Context, cfg *config.CozystackConfig) error { - logger := log.FromContext(ctx) - - // Collect namespaces from CozystackBundle resources - namespacesMap := make(map[string]bool) - - // List all CozystackBundle resources - bundleList := &cozyv1alpha1.CozystackBundleList{} - if err := r.Client.List(ctx, bundleList); err != nil { - logger.Error(err, "failed to list CozystackBundles, using default namespaces") - } else { - for _, bundle := range bundleList.Items { - for _, pkg := range bundle.Spec.Packages { - // Check if package is disabled - if pkg.Disabled { - continue - } - - // Check if component is disabled via config - if cfg.IsComponentDisabled(pkg.Name) { - continue - } - - // If at least one package requires a privileged namespace, then it should be privileged - if pkg.Namespace != "" { - if pkg.Privileged { - namespacesMap[pkg.Namespace] = true - } else if _, exists := namespacesMap[pkg.Namespace]; !exists { - namespacesMap[pkg.Namespace] = false - } - } - } - } - } - - // Always add cozy-system (privileged) and cozy-public (non-privileged) - namespacesMap["cozy-system"] = true - namespacesMap["cozy-public"] = false - - // Create/update all desired namespaces - for nsName, privileged := range namespacesMap { - namespace := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: nsName, - Annotations: map[string]string{ - "helm.sh/resource-policy": "keep", - }, - Labels: map[string]string{ - "cozystack.io/system": "true", - }, - }, - } - - if privileged { - namespace.Labels["pod-security.kubernetes.io/enforce"] = "privileged" - } - - if err := r.CreateOrUpdate(ctx, namespace); err != nil { - logger.Error(err, "failed to reconcile Namespace", "name", nsName) - return err - } - logger.Info("reconciled Namespace", "name", nsName, "privileged", privileged) - } - - // Note: We no longer delete namespaces that are not in the desired state. - // Namespaces are managed by their respective HelmReleases and should not be - // deleted by the platform operator. - - return nil -} - -func (r *PlatformReconciler) reconcileTenantRoot(ctx context.Context, cfg *config.CozystackConfig) error { - logger := log.FromContext(ctx) - - host := cfg.RootHost - if host == "" { - host = "example.org" - } - - // Define desired tenant-root namespace - desiredNamespace := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: "tenant-root", - Annotations: map[string]string{ - "helm.sh/resource-policy": "keep", - "namespace.cozystack.io/etcd": "tenant-root", - "namespace.cozystack.io/monitoring": "tenant-root", - "namespace.cozystack.io/ingress": "tenant-root", - "namespace.cozystack.io/seaweedfs": "tenant-root", - "namespace.cozystack.io/host": host, - }, - }, - } - - if err := r.CreateOrUpdate(ctx, desiredNamespace); err != nil { - logger.Error(err, "failed to reconcile tenant-root Namespace") - return err - } - logger.Info("reconciled tenant-root Namespace") - - // Define desired tenant-root HelmRelease - desiredHR := &helmv2.HelmRelease{ - ObjectMeta: metav1.ObjectMeta{ - Name: "tenant-root", - Namespace: "tenant-root", - Labels: map[string]string{ - "cozystack.io/ui": "true", - }, - }, - Spec: helmv2.HelmReleaseSpec{ - Interval: metav1.Duration{Duration: 0}, // 0s - ReleaseName: "tenant-root", - ChartRef: &helmv2.CrossNamespaceSourceReference{ - Kind: "ExternalArtifact", - Name: "cozystack-system-tenant", - Namespace: "cozy-public", - }, - Values: &apiextensionsv1.JSON{ - Raw: []byte(fmt.Sprintf(`{"host":%q}`, host)), - }, - Install: &helmv2.Install{ - Remediation: &helmv2.InstallRemediation{ - Retries: -1, - }, - }, - Upgrade: &helmv2.Upgrade{ - Remediation: &helmv2.UpgradeRemediation{ - Retries: -1, - }, - }, - }, - } - - if err := r.CreateOrUpdate(ctx, desiredHR); err != nil { - logger.Error(err, "failed to reconcile tenant-root HelmRelease") - return err - } - logger.Info("reconciled tenant-root HelmRelease") - - 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) - - return r.Update(ctx, obj) -} diff --git a/packages/apps/tenant/templates/etcd.yaml b/packages/apps/tenant/templates/etcd.yaml index e463bb4b..d5f760c2 100644 --- a/packages/apps/tenant/templates/etcd.yaml +++ b/packages/apps/tenant/templates/etcd.yaml @@ -13,7 +13,7 @@ spec: chartRef: kind: ExternalArtifact name: cozystack-system-etcd - namespace: cozy-public + namespace: cozy-system interval: 5m timeout: 10m install: diff --git a/packages/apps/tenant/templates/info.yaml b/packages/apps/tenant/templates/info.yaml index b7b0a002..89d4403a 100644 --- a/packages/apps/tenant/templates/info.yaml +++ b/packages/apps/tenant/templates/info.yaml @@ -12,7 +12,7 @@ spec: chartRef: kind: ExternalArtifact name: cozystack-system-info - namespace: cozy-public + namespace: cozy-system interval: 5m timeout: 10m install: diff --git a/packages/apps/tenant/templates/ingress.yaml b/packages/apps/tenant/templates/ingress.yaml index 06804903..ea8f4953 100644 --- a/packages/apps/tenant/templates/ingress.yaml +++ b/packages/apps/tenant/templates/ingress.yaml @@ -13,7 +13,7 @@ spec: chartRef: kind: ExternalArtifact name: cozystack-system-ingress - namespace: cozy-public + namespace: cozy-system interval: 5m timeout: 10m install: diff --git a/packages/apps/tenant/templates/monitoring.yaml b/packages/apps/tenant/templates/monitoring.yaml index f36a3078..edf4a769 100644 --- a/packages/apps/tenant/templates/monitoring.yaml +++ b/packages/apps/tenant/templates/monitoring.yaml @@ -13,7 +13,7 @@ spec: chartRef: kind: ExternalArtifact name: cozystack-system-monitoring - namespace: cozy-public + namespace: cozy-system interval: 5m timeout: 10m install: diff --git a/packages/apps/tenant/templates/seaweedfs.yaml b/packages/apps/tenant/templates/seaweedfs.yaml index 693e6abe..4b5c9903 100644 --- a/packages/apps/tenant/templates/seaweedfs.yaml +++ b/packages/apps/tenant/templates/seaweedfs.yaml @@ -13,7 +13,7 @@ spec: chartRef: kind: ExternalArtifact name: cozystack-system-seaweedfs - namespace: cozy-public + namespace: cozy-system interval: 5m timeout: 10m install: diff --git a/packages/apps/tenant/templates/tenant.yaml b/packages/apps/tenant/templates/tenant.yaml index 6d325a07..06d70eae 100644 --- a/packages/apps/tenant/templates/tenant.yaml +++ b/packages/apps/tenant/templates/tenant.yaml @@ -385,7 +385,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: {{ include "tenant.name" . }} - namespace: cozy-public + namespace: cozy-system rules: - apiGroups: ["source.toolkit.fluxcd.io"] resources: ["helmrepositories"] @@ -398,7 +398,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: {{ include "tenant.name" . }} - namespace: cozy-public + namespace: cozy-system subjects: - kind: Group name: {{ include "tenant.name" . }}-super-admin diff --git a/packages/apps/virtual-machine/templates/vm.yaml b/packages/apps/virtual-machine/templates/vm.yaml index 92084acb..acaba6c6 100644 --- a/packages/apps/virtual-machine/templates/vm.yaml +++ b/packages/apps/virtual-machine/templates/vm.yaml @@ -43,7 +43,7 @@ spec: {{- if $dv }} pvc: name: vm-image-{{ .Values.systemDisk.image }} - namespace: cozy-public + namespace: cozy-system {{- else }} http: {{- if eq .Values.systemDisk.image "cirros" }} diff --git a/packages/apps/vm-disk/templates/dv.yaml b/packages/apps/vm-disk/templates/dv.yaml index 3d68e639..b4120189 100644 --- a/packages/apps/vm-disk/templates/dv.yaml +++ b/packages/apps/vm-disk/templates/dv.yaml @@ -21,10 +21,10 @@ spec: {{- end }} source: {{- if hasKey .Values.source "image" }} - {{- $dv := lookup "cdi.kubevirt.io/v1beta1" "DataVolume" "cozy-public" (printf "vm-image-%s" .Values.source.image.name) }} + {{- $dv := lookup "cdi.kubevirt.io/v1beta1" "DataVolume" "cozy-system" (printf "vm-image-%s" .Values.source.image.name) }} pvc: name: vm-image-{{ required "A valid .Values.source.image.name entry required!" .Values.source.image.name }} - namespace: cozy-public + namespace: cozy-system {{- else if hasKey .Values.source "http" }} http: url: {{ required "A valid .Values.source.http.url entry required!" .Values.source.http.url }} diff --git a/packages/core/fluxcd/manifests b/packages/core/fluxcd/manifests index 9fcd0f80..f9bb5aad 120000 --- a/packages/core/fluxcd/manifests +++ b/packages/core/fluxcd/manifests @@ -1 +1 @@ -../../../cmd/cozystack-operator/manifests \ No newline at end of file +../../../internal/fluxinstall/manifests \ No newline at end of file diff --git a/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackbundles.yaml b/packages/core/installer/crds/cozystack.io_cozystackbundles.yaml similarity index 82% rename from packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackbundles.yaml rename to packages/core/installer/crds/cozystack.io_cozystackbundles.yaml index 851ca10f..697c4ac4 100644 --- a/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackbundles.yaml +++ b/packages/core/installer/crds/cozystack.io_cozystackbundles.yaml @@ -65,6 +65,20 @@ spec: - path type: object type: array + deletionPolicy: + allOf: + - enum: + - Delete + - Orphan + - enum: + - Delete + - Orphan + default: Delete + description: |- + 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). + type: string dependencyTargets: description: |- DependencyTargets defines named groups of packages that can be referenced @@ -99,6 +113,14 @@ spec: items: type: string type: array + labels: + additionalProperties: + type: string + description: |- + 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. + type: object libraries: description: Libraries is a list of Helm library charts used by packages items: @@ -122,6 +144,12 @@ spec: description: BundleRelease defines a single Helm release within a bundle properties: + artifact: + description: |- + 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 + type: string dependsOn: description: DependsOn is a list of release names that must be installed before this release @@ -147,7 +175,9 @@ spec: release will be installed type: string path: - description: Path is the path to the Helm chart directory + description: |- + Path is the path to the Helm chart directory + Either Path or Artifact must be specified, but not both type: string privileged: description: Privileged indicates whether this release requires @@ -168,9 +198,12 @@ spec: required: - name - namespace - - path - releaseName type: object + x-kubernetes-validations: + - message: either path or artifact must be set, but not both + rule: (has(self.path) && !has(self.artifact)) || (!has(self.path) + && has(self.artifact)) type: array sourceRef: description: SourceRef is the source reference for the bundle charts diff --git a/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml b/packages/core/installer/crds/cozystack.io_cozystackresourcedefinitions.yaml similarity index 100% rename from packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml rename to packages/core/installer/crds/cozystack.io_cozystackresourcedefinitions.yaml diff --git a/packages/core/installer/example/platform.yaml b/packages/core/installer/example/platform.yaml new file mode 100644 index 00000000..fe0653e9 --- /dev/null +++ b/packages/core/installer/example/platform.yaml @@ -0,0 +1,49 @@ +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: GitRepository +metadata: + name: cozystack + namespace: cozy-system +spec: + interval: 1m0s + ref: + branch: refactor-engine + timeout: 60s + url: https://github.com/cozystack/cozystack.git +--- +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: cozystack-platform + namespace: cozy-system +spec: + interval: 5m + targetNamespace: cozy-system + releaseName: cozystack-platform + chart: + spec: + chart: ./packages/core/platform + sourceRef: + kind: GitRepository + name: cozystack + namespace: cozy-system + values: + sourceRef: + kind: GitRepository + name: cozystack + namespace: cozy-system +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cozystack + namespace: cozy-system +data: + bundle-name: "paas-full" + root-host: "example.org" + api-server-endpoint: "https://api.example.org:443" + expose-services: "dashboard,api" + ipv4-pod-cidr: "10.244.0.0/16" + ipv4-pod-gateway: "10.244.0.1" + ipv4-svc-cidr: "10.96.0.0/16" + ipv4-join-cidr: "100.64.0.0/16" diff --git a/packages/core/installer/images/cozystack/Dockerfile b/packages/core/installer/images/cozystack/Dockerfile index bc92d712..18e97900 100644 --- a/packages/core/installer/images/cozystack/Dockerfile +++ b/packages/core/installer/images/cozystack/Dockerfile @@ -24,8 +24,6 @@ RUN wget -O- https://github.com/cozystack/cozypkg/raw/refs/heads/main/hack/insta RUN apk add --no-cache make kubectl helm coreutils git jq ca-certificates COPY --from=builder /src/scripts /cozystack/scripts -COPY --from=builder /src/packages/core /cozystack/packages/core -COPY --from=builder /src/packages/system /cozystack/packages/system COPY --from=builder /cozystack-operator /usr/bin/cozystack-operator WORKDIR /cozystack diff --git a/packages/core/installer/templates/cozystack.yaml b/packages/core/installer/templates/cozystack.yaml index e98d2c8b..2fd4abb5 100644 --- a/packages/core/installer/templates/cozystack.yaml +++ b/packages/core/installer/templates/cozystack.yaml @@ -58,8 +58,9 @@ spec: value: "7445" args: - --leader-elect=true + - --install-flux=true - --metrics-bind-address=0 - - --health-probe-bind-address=:8082 + - --health-probe-bind-address= tolerations: - key: "node.kubernetes.io/not-ready" operator: "Exists" diff --git a/packages/core/installer/templates/crds.yaml b/packages/core/installer/templates/crds.yaml new file mode 100644 index 00000000..bd51938d --- /dev/null +++ b/packages/core/installer/templates/crds.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "crds/*.yaml" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index d6f9d392..9e295170 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:latest@sha256:8cc66287f58ea175d7fa5601f4edee6a86454b133322f6b168d6fce801679986 + image: ghcr.io/cozystack/cozystack/installer:latest@sha256:e0b73cfcfeae7c8cbccbad469a57dee0f1691a2726ad29eb9964972101b9a57b diff --git a/packages/core/platform/bundles/iaas/bundle.yaml b/packages/core/platform/bundles/iaas/bundle.yaml index 0aa275f2..77831cb4 100644 --- a/packages/core/platform/bundles/iaas/bundle.yaml +++ b/packages/core/platform/bundles/iaas/bundle.yaml @@ -42,11 +42,11 @@ spec: - name: kubernetes-cert-manager-crds path: packages/system/cert-manager-crds - name: kubernetes-volumesnapshot-crd - path: packages/system/kubernetes-vsnap-crd + path: packages/system/vsnap-crd - name: kubernetes-velero - path: packages/system/kubernetes-velero + path: packages/system/velero - name: kubernetes-gateway-api-crds - path: packages/system/kubernetes-gateway-api-crds + path: packages/system/gateway-api-crds - name: kubernetes-victoria-metrics-operator path: packages/system/victoria-metrics-operator - name: kubernetes-kubevirt-csi-node diff --git a/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml b/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml index af7f6355..351f6f9d 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-iaas-bucket - namespace: cozy-public + namespace: cozy-system dashboard: singular: Bucket plural: Buckets diff --git a/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml b/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml index ba9b1554..9aa990b8 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-iaas-kubernetes - namespace: cozy-public + namespace: cozy-system dashboard: category: IaaS singular: Kubernetes diff --git a/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml b/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml index a7bafdd7..87b1e937 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-iaas-virtual-machine - namespace: cozy-public + namespace: cozy-system dashboard: category: IaaS singular: Virtual Machine diff --git a/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml b/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml index 1e488d85..79ac1c14 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-iaas-vpc - namespace: cozy-public + namespace: cozy-system dashboard: category: IaaS singular: VPC diff --git a/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml b/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml index c7099657..5172c549 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-iaas-vm-disk - namespace: cozy-public + namespace: cozy-system dashboard: category: IaaS singular: VM Disk diff --git a/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml b/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml index 00fdcfd3..08cfa4e3 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-iaas-vm-instance - namespace: cozy-public + namespace: cozy-system dashboard: category: IaaS singular: VM Instance diff --git a/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml b/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml index 423c5fef..a90f4103 100644 --- a/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml +++ b/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-naas-http-cache - namespace: cozy-public + namespace: cozy-system dashboard: category: NaaS singular: HTTP Cache diff --git a/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml b/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml index cf2bf24f..47972a46 100644 --- a/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml +++ b/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-naas-tcp-balancer - namespace: cozy-public + namespace: cozy-system dashboard: category: NaaS singular: TCP Balancer diff --git a/packages/core/platform/bundles/naas/cozyrds/vpn.yaml b/packages/core/platform/bundles/naas/cozyrds/vpn.yaml index 268364e7..6c89eaac 100644 --- a/packages/core/platform/bundles/naas/cozyrds/vpn.yaml +++ b/packages/core/platform/bundles/naas/cozyrds/vpn.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-naas-vpn - namespace: cozy-public + namespace: cozy-system dashboard: category: NaaS singular: VPN diff --git a/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml b/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml index dc93b3bf..f284a652 100644 --- a/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-paas-clickhouse - namespace: cozy-public + namespace: cozy-system dashboard: category: PaaS singular: ClickHouse diff --git a/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml b/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml index 9e9fb07f..9bd8ec9e 100644 --- a/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-paas-ferretdb - namespace: cozy-public + namespace: cozy-system dashboard: category: PaaS singular: FerretDB diff --git a/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml b/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml index 21e42287..c0e832f8 100644 --- a/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-paas-foundationdb - namespace: cozy-public + namespace: cozy-system dashboard: category: PaaS singular: FoundationDB diff --git a/packages/core/platform/bundles/paas/cozyrds/kafka.yaml b/packages/core/platform/bundles/paas/cozyrds/kafka.yaml index f9efe311..c7a2014f 100644 --- a/packages/core/platform/bundles/paas/cozyrds/kafka.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/kafka.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-paas-kafka - namespace: cozy-public + namespace: cozy-system dashboard: category: PaaS singular: Kafka diff --git a/packages/core/platform/bundles/paas/cozyrds/mysql.yaml b/packages/core/platform/bundles/paas/cozyrds/mysql.yaml index 1d4c1957..3a0535f1 100644 --- a/packages/core/platform/bundles/paas/cozyrds/mysql.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/mysql.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-paas-mysql - namespace: cozy-public + namespace: cozy-system dashboard: category: PaaS singular: MySQL diff --git a/packages/core/platform/bundles/paas/cozyrds/nats.yaml b/packages/core/platform/bundles/paas/cozyrds/nats.yaml index 8ddaf563..5d81effc 100644 --- a/packages/core/platform/bundles/paas/cozyrds/nats.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/nats.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-paas-nats - namespace: cozy-public + namespace: cozy-system dashboard: category: PaaS singular: NATS diff --git a/packages/core/platform/bundles/paas/cozyrds/postgres.yaml b/packages/core/platform/bundles/paas/cozyrds/postgres.yaml index d0a33201..554dbd12 100644 --- a/packages/core/platform/bundles/paas/cozyrds/postgres.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/postgres.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-paas-postgres - namespace: cozy-public + namespace: cozy-system dashboard: category: PaaS singular: PostgreSQL diff --git a/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml b/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml index 9779c895..365979f5 100644 --- a/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-paas-rabbitmq - namespace: cozy-public + namespace: cozy-system dashboard: category: PaaS singular: RabbitMQ diff --git a/packages/core/platform/bundles/paas/cozyrds/redis.yaml b/packages/core/platform/bundles/paas/cozyrds/redis.yaml index 9f78bd6f..224a83c9 100644 --- a/packages/core/platform/bundles/paas/cozyrds/redis.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/redis.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-paas-redis - namespace: cozy-public + namespace: cozy-system dashboard: category: PaaS singular: Redis diff --git a/packages/core/platform/bundles/system/bundle-full.yaml b/packages/core/platform/bundles/system/bundle-full.yaml index 179c3219..f01cbebc 100644 --- a/packages/core/platform/bundles/system/bundle-full.yaml +++ b/packages/core/platform/bundles/system/bundle-full.yaml @@ -14,13 +14,12 @@ apiVersion: cozystack.io/v1alpha1 kind: CozystackBundle metadata: name: cozystack-system - finalizers: - - cozystack.io/system-bundle-protection spec: + deletionPolicy: Orphan dependencyTargets: - name: network - packages: [cilium,kubeovn] + packages: [cilium,kubeovn,cert-manager] sourceRef: kind: {{ .Values.sourceRef.kind }} @@ -45,7 +44,7 @@ spec: path: packages/extra/ingress libraries: [cozy-lib] - name: ingress-system - path: packages/system/ingress + path: packages/system/ingress-nginx - name: seaweedfs path: packages/extra/seaweedfs libraries: [cozy-lib] @@ -59,6 +58,15 @@ spec: libraries: [cozy-lib] packages: + - name: tenant-root + releaseName: tenant-root + artifact: tenant + namespace: tenant-root + labels: + cozystack.io/ui: "true" + values: + host: {{ $host }} + - name: cilium releaseName: cilium path: packages/system/cilium @@ -104,7 +112,7 @@ spec: releaseName: kubeovn-plunger path: packages/system/kubeovn-plunger namespace: cozy-kubeovn - dependsOn: [cilium,kubeovn] + dependsOn: [cilium,kubeovn,victoria-metrics-operator] - name: multus releaseName: multus @@ -148,12 +156,6 @@ spec: namespace: cozy-system dependsOn: [cozystack-controller,cilium,kubeovn,cert-manager] - - name: cozystack-resource-definition-crd - releaseName: cozystack-resource-definition-crd - path: packages/system/cozystack-resource-definition-crd - namespace: cozy-system - dependsOn: [cilium,kubeovn,cozystack-api,cozystack-controller] - - name: cert-manager releaseName: cert-manager path: packages/system/cert-manager @@ -255,6 +257,8 @@ spec: dependsOn: - cilium - kubeovn + - cozystack-api + - cozystack-controller {{- if eq $oidcEnabled "true" }} - keycloak-configure {{- end }} diff --git a/packages/core/platform/bundles/system/bundle-hosted.yaml b/packages/core/platform/bundles/system/bundle-hosted.yaml index 3c4a88cd..80d5d745 100644 --- a/packages/core/platform/bundles/system/bundle-hosted.yaml +++ b/packages/core/platform/bundles/system/bundle-hosted.yaml @@ -14,9 +14,8 @@ apiVersion: cozystack.io/v1alpha1 kind: CozystackBundle metadata: name: cozystack-system - finalizers: - - cozystack.io/system-bundle-protection spec: + deletionPolicy: Orphan dependencyTargets: - name: network @@ -59,198 +58,204 @@ spec: libraries: [cozy-lib] packages: - - name: cert-manager-crds - releaseName: cert-manager-crds - path: packages/system/cert-manager-crds - namespace: cozy-cert-manager - dependsOn: [] - - - name: cozystack-api - releaseName: cozystack-api - path: packages/system/cozystack-api - namespace: cozy-system - dependsOn: [cozystack-controller] - values: - cozystackAPI: - localK8sAPIEndpoint: - enabled: false - - - name: cozystack-controller - releaseName: cozystack-controller - path: packages/system/cozystack-controller - namespace: cozy-system - dependsOn: [] - {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} - values: - cozystackController: - disableTelemetry: true + - name: tenant-root + releaseName: tenant-root + artifact: tenant + namespace: tenant-root + labels: + cozystack.io/ui: "true" + values: + host: {{ $host }} + + - name: cert-manager-crds + releaseName: cert-manager-crds + path: packages/system/cert-manager-crds + namespace: cozy-cert-manager + dependsOn: [] + + - name: cozystack-api + releaseName: cozystack-api + path: packages/system/cozystack-api + namespace: cozy-system + dependsOn: [cozystack-controller] + values: + cozystackAPI: + localK8sAPIEndpoint: + enabled: false + + - name: cozystack-controller + releaseName: cozystack-controller + path: packages/system/cozystack-controller + namespace: cozy-system + dependsOn: [] + {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} + values: + cozystackController: + disableTelemetry: true + {{- end }} + + - name: lineage-controller-webhook + releaseName: lineage-controller-webhook + path: packages/system/lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller,cert-manager] + + - name: cert-manager + releaseName: cert-manager + path: packages/system/cert-manager + namespace: cozy-cert-manager + dependsOn: [cert-manager-crds] + + - name: cert-manager-issuers + releaseName: cert-manager-issuers + path: packages/system/cert-manager-issuers + namespace: cozy-cert-manager + dependsOn: [cert-manager] + + - name: victoria-metrics-operator + releaseName: victoria-metrics-operator + path: packages/system/victoria-metrics-operator + namespace: cozy-victoria-metrics-operator + dependsOn: [cert-manager] + + - name: monitoring-agents + releaseName: monitoring-agents + path: packages/system/monitoring-agents + namespace: cozy-monitoring + privileged: true + dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] + values: + scrapeRules: + etcd: + enabled: true + + - name: etcd-operator + releaseName: etcd-operator + path: packages/system/etcd-operator + namespace: cozy-etcd-operator + dependsOn: [cert-manager] + + - name: grafana-operator + releaseName: grafana-operator + path: packages/system/grafana-operator + namespace: cozy-grafana-operator + dependsOn: [] + + - name: mariadb-operator + releaseName: mariadb-operator + path: packages/system/mariadb-operator + namespace: cozy-mariadb-operator + dependsOn: [cert-manager,victoria-metrics-operator] + values: + mariadb-operator: + clusterName: {{ $clusterDomain }} + + - name: postgres-operator + releaseName: postgres-operator + path: packages/system/postgres-operator + namespace: cozy-postgres-operator + dependsOn: [cert-manager,victoria-metrics-operator] + + - name: objectstorage-controller + releaseName: objectstorage-controller + path: packages/system/objectstorage-controller + namespace: cozy-objectstorage-controller + dependsOn: [] + + - name: telepresence + releaseName: traffic-manager + path: packages/system/telepresence + namespace: cozy-telepresence + disabled: true + dependsOn: [] + + - name: external-dns + releaseName: external-dns + path: packages/system/external-dns + namespace: cozy-external-dns + disabled: true + dependsOn: [] + + - name: external-secrets-operator + releaseName: external-secrets-operator + path: packages/system/external-secrets-operator + namespace: cozy-external-secrets-operator + disabled: true + dependsOn: [] + + - name: dashboard + releaseName: dashboard + path: packages/system/dashboard + namespace: cozy-dashboard + dependsOn: + - cilium + - kubeovn + - cozystack-api + - cozystack-controller + {{- else }} + - keycloak-configure + {{- end }} + + {{- if $oidcEnabled }} + - name: keycloak + releaseName: keycloak + path: packages/system/keycloak + namespace: cozy-keycloak + dependsOn: [postgres-operator] + libraries: [cozy-lib] + + - name: keycloak-operator + releaseName: keycloak-operator + path: packages/system/keycloak-operator + namespace: cozy-keycloak + dependsOn: [keycloak] + + - name: keycloak-configure + releaseName: keycloak-configure + path: packages/system/keycloak-configure + namespace: cozy-keycloak + dependsOn: [keycloak-operator] + values: + cozystack: + configHash: {{ $cozyConfig | toJson | sha256sum }} {{- end }} - - - name: lineage-controller-webhook - releaseName: lineage-controller-webhook - path: packages/system/lineage-controller-webhook - namespace: cozy-system - dependsOn: [cozystack-controller,cert-manager] - - - name: cozystack-resource-definition-crd - releaseName: cozystack-resource-definition-crd - path: packages/system/cozystack-resource-definition-crd - namespace: cozy-system - dependsOn: [cozystack-api,cozystack-controller] - - - name: cert-manager - releaseName: cert-manager - path: packages/system/cert-manager - namespace: cozy-cert-manager - dependsOn: [cert-manager-crds] - - - name: cert-manager-issuers - releaseName: cert-manager-issuers - path: packages/system/cert-manager-issuers - namespace: cozy-cert-manager - dependsOn: [cert-manager] - - - name: victoria-metrics-operator - releaseName: victoria-metrics-operator - path: packages/system/victoria-metrics-operator - namespace: cozy-victoria-metrics-operator - dependsOn: [cert-manager] - - - name: monitoring-agents - releaseName: monitoring-agents - path: packages/system/monitoring-agents - namespace: cozy-monitoring - privileged: true - dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] - values: - scrapeRules: - etcd: - enabled: true - - - name: etcd-operator - releaseName: etcd-operator - path: packages/system/etcd-operator - namespace: cozy-etcd-operator - dependsOn: [cert-manager] - - - name: grafana-operator - releaseName: grafana-operator - path: packages/system/grafana-operator - namespace: cozy-grafana-operator - dependsOn: [] - - - name: mariadb-operator - releaseName: mariadb-operator - path: packages/system/mariadb-operator - namespace: cozy-mariadb-operator - dependsOn: [cert-manager,victoria-metrics-operator] - values: - mariadb-operator: - clusterName: {{ $clusterDomain }} - - - name: postgres-operator - releaseName: postgres-operator - path: packages/system/postgres-operator - namespace: cozy-postgres-operator - dependsOn: [cert-manager,victoria-metrics-operator] - - - name: objectstorage-controller - releaseName: objectstorage-controller - path: packages/system/objectstorage-controller - namespace: cozy-objectstorage-controller - dependsOn: [] - - - name: telepresence - releaseName: traffic-manager - path: packages/system/telepresence - namespace: cozy-telepresence - disabled: true - dependsOn: [] - - - name: external-dns - releaseName: external-dns - path: packages/system/external-dns - namespace: cozy-external-dns - disabled: true - dependsOn: [] - - - name: external-secrets-operator - releaseName: external-secrets-operator - path: packages/system/external-secrets-operator - namespace: cozy-external-secrets-operator - disabled: true - dependsOn: [] - - - name: dashboard - releaseName: dashboard - path: packages/system/dashboard - namespace: cozy-dashboard - {{- if eq $oidcEnabled "true" }} - dependsOn: [keycloak-configure,cozystack-api] - {{- else }} - dependsOn: [] - {{- end }} - - {{- if $oidcEnabled }} - - name: keycloak - releaseName: keycloak - path: packages/system/keycloak - namespace: cozy-keycloak - dependsOn: [postgres-operator] - libraries: [cozy-lib] - - - name: keycloak-operator - releaseName: keycloak-operator - path: packages/system/keycloak-operator - namespace: cozy-keycloak - dependsOn: [keycloak] - - - name: keycloak-configure - releaseName: keycloak-configure - path: packages/system/keycloak-configure - namespace: cozy-keycloak - dependsOn: [keycloak-operator] - values: - cozystack: - configHash: {{ $cozyConfig | toJson | sha256sum }} - {{- end }} - - - name: goldpinger - releaseName: goldpinger - path: packages/system/goldpinger - namespace: cozy-goldpinger - privileged: true - dependsOn: [monitoring-agents] - - - name: vertical-pod-autoscaler - releaseName: vertical-pod-autoscaler - path: packages/system/vertical-pod-autoscaler - namespace: cozy-vertical-pod-autoscaler - privileged: true - dependsOn: [monitoring-agents] - values: - vertical-pod-autoscaler: - recommender: - extraArgs: - prometheus-address: http://vmselect-shortterm.tenant-root.svc.{{ $clusterDomain }}:8481/select/0/prometheus/ - - - name: vertical-pod-autoscaler-crds - releaseName: vertical-pod-autoscaler-crds - path: packages/system/vertical-pod-autoscaler-crds - namespace: cozy-vertical-pod-autoscaler - privileged: true - dependsOn: [] - - - name: velero - releaseName: velero - path: packages/system/velero - namespace: cozy-velero - privileged: true - disabled: true - dependsOn: [monitoring-agents] - - - name: hetzner-robotlb - releaseName: robotlb - disabled: true - path: packages/system/hetzner-robotlb - namespace: cozy-hetzner-robotlb + + - name: goldpinger + releaseName: goldpinger + path: packages/system/goldpinger + namespace: cozy-goldpinger + privileged: true + dependsOn: [monitoring-agents] + + - name: vertical-pod-autoscaler + releaseName: vertical-pod-autoscaler + path: packages/system/vertical-pod-autoscaler + namespace: cozy-vertical-pod-autoscaler + privileged: true + dependsOn: [monitoring-agents] + values: + vertical-pod-autoscaler: + recommender: + extraArgs: + prometheus-address: http://vmselect-shortterm.tenant-root.svc.{{ $clusterDomain }}:8481/select/0/prometheus/ + + - name: vertical-pod-autoscaler-crds + releaseName: vertical-pod-autoscaler-crds + path: packages/system/vertical-pod-autoscaler-crds + namespace: cozy-vertical-pod-autoscaler + privileged: true + dependsOn: [] + + - name: velero + releaseName: velero + path: packages/system/velero + namespace: cozy-velero + privileged: true + disabled: true + dependsOn: [monitoring-agents] + + - name: hetzner-robotlb + releaseName: robotlb + disabled: true + path: packages/system/hetzner-robotlb + namespace: cozy-hetzner-robotlb diff --git a/packages/core/platform/bundles/system/bundle-minimal.yaml b/packages/core/platform/bundles/system/bundle-minimal.yaml new file mode 100644 index 00000000..1b32e894 --- /dev/null +++ b/packages/core/platform/bundles/system/bundle-minimal.yaml @@ -0,0 +1,70 @@ +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} +{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} +{{- $host := index $cozyConfig.data "root-host" }} +{{- if not $host }} +{{- fail "ERROR need root-host in cozystack ConfigMap" }} +{{- end }} +{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} +{{- if not $apiServerEndpoint }} +{{- fail "ERROR need api-server-endpoint in cozystack ConfigMap" }} +{{- end }} + +apiVersion: cozystack.io/v1alpha1 +kind: CozystackBundle +metadata: + name: cozystack-minimal +spec: + dependencyTargets: + - name: network + packages: [] + + sourceRef: + kind: {{ .Values.sourceRef.kind }} + name: {{ .Values.sourceRef.name }} + namespace: {{ .Values.sourceRef.namespace }} + + libraries: + - name: cozy-lib + path: packages/library/cozy-lib + + artifacts: + - name: tenant + path: packages/apps/tenant + libraries: [cozy-lib] + + packages: + - name: cozystack-api + releaseName: cozystack-api + path: packages/system/cozystack-api + namespace: cozy-system + dependsOn: [cozystack-controller] + values: + cozystackAPI: + localK8sAPIEndpoint: + enabled: false + + - name: cozystack-controller + releaseName: cozystack-controller + path: packages/system/cozystack-controller + namespace: cozy-system + dependsOn: [] + {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} + values: + cozystackController: + disableTelemetry: true + {{- end }} + + - name: lineage-controller-webhook + releaseName: lineage-controller-webhook + path: packages/system/lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller] + + - name: dashboard + releaseName: dashboard + path: packages/system/dashboard + namespace: cozy-dashboard + dependsOn: + - cozystack-api + - cozystack-controller diff --git a/packages/core/platform/bundles/system/cozyrds/bootbox.yaml b/packages/core/platform/bundles/system/cozyrds/bootbox.yaml index 3a593162..331f055a 100644 --- a/packages/core/platform/bundles/system/cozyrds/bootbox.yaml +++ b/packages/core/platform/bundles/system/cozyrds/bootbox.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-system-bootbox - namespace: cozy-public + namespace: cozy-system dashboard: category: Administration singular: BootBox diff --git a/packages/core/platform/bundles/system/cozyrds/etcd.yaml b/packages/core/platform/bundles/system/cozyrds/etcd.yaml index 6381f6da..0fd1505e 100644 --- a/packages/core/platform/bundles/system/cozyrds/etcd.yaml +++ b/packages/core/platform/bundles/system/cozyrds/etcd.yaml @@ -18,7 +18,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-system-etcd - namespace: cozy-public + namespace: cozy-system dashboard: category: Administration singular: Etcd diff --git a/packages/core/platform/bundles/system/cozyrds/info.yaml b/packages/core/platform/bundles/system/cozyrds/info.yaml index fed8d965..8e33cb33 100644 --- a/packages/core/platform/bundles/system/cozyrds/info.yaml +++ b/packages/core/platform/bundles/system/cozyrds/info.yaml @@ -18,7 +18,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-system-info - namespace: cozy-public + namespace: cozy-system dashboard: name: info category: Administration diff --git a/packages/core/platform/bundles/system/cozyrds/ingress.yaml b/packages/core/platform/bundles/system/cozyrds/ingress.yaml index 9f5a22f1..64de630b 100644 --- a/packages/core/platform/bundles/system/cozyrds/ingress.yaml +++ b/packages/core/platform/bundles/system/cozyrds/ingress.yaml @@ -18,7 +18,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-system-ingress - namespace: cozy-public + namespace: cozy-system dashboard: category: Administration singular: Ingress diff --git a/packages/core/platform/bundles/system/cozyrds/monitoring.yaml b/packages/core/platform/bundles/system/cozyrds/monitoring.yaml index b782cfaf..2d26d0fe 100644 --- a/packages/core/platform/bundles/system/cozyrds/monitoring.yaml +++ b/packages/core/platform/bundles/system/cozyrds/monitoring.yaml @@ -18,7 +18,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-system-monitoring - namespace: cozy-public + namespace: cozy-system dashboard: category: Administration singular: Monitoring diff --git a/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml b/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml index 4b0bbbcf..e9bfc444 100644 --- a/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml +++ b/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml @@ -18,7 +18,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-system-seaweedfs - namespace: cozy-public + namespace: cozy-system dashboard: category: Administration singular: SeaweedFS diff --git a/packages/core/platform/bundles/system/cozyrds/tenant.yaml b/packages/core/platform/bundles/system/cozyrds/tenant.yaml index 797ed7be..17ab6758 100644 --- a/packages/core/platform/bundles/system/cozyrds/tenant.yaml +++ b/packages/core/platform/bundles/system/cozyrds/tenant.yaml @@ -17,7 +17,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-system-tenant - namespace: cozy-public + namespace: cozy-system dashboard: category: Administration singular: Tenant diff --git a/packages/core/platform/templates/bundles-configmap.yaml b/packages/core/platform/templates/bundles.yaml similarity index 90% rename from packages/core/platform/templates/bundles-configmap.yaml rename to packages/core/platform/templates/bundles.yaml index 431cac41..024ef7eb 100644 --- a/packages/core/platform/templates/bundles-configmap.yaml +++ b/packages/core/platform/templates/bundles.yaml @@ -8,7 +8,9 @@ {{- fail "ERROR: bundle-name not found in cozystack ConfigMap" }} {{- end }} -{{- if eq $bundleName "paas-full" }} +{{- if eq $bundleName "minimal" }} + {{ include "cozystack.render-file" (list . "bundles/system/bundle-minimal.yaml") }} +{{- else if eq $bundleName "paas-full" }} {{- /* Deploy system-full, iaas, paas, naas bundles */ -}} {{ include "cozystack.render-file" (list . "bundles/system/bundle-full.yaml") }} {{ include "cozystack.render-file" (list . "bundles/iaas/bundle.yaml") }} @@ -39,5 +41,5 @@ {{- fail "ERROR: bundle-name 'distro-hosted' is deprecated and has been removed. Please use 'paas-hosted' instead." }} {{- else }} - {{- fail (printf "ERROR: unknown bundle-name '%s'. Supported values: 'paas-full', 'paas-hosted'" $bundleName) }} + {{- fail (printf "ERROR: unknown bundle-name '%s'. Supported values: 'minimal', 'paas-full', 'paas-hosted'" $bundleName) }} {{- end }} diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml index 113056c7..448b5bf0 100644 --- a/packages/core/platform/values.yaml +++ b/packages/core/platform/values.yaml @@ -1,4 +1,4 @@ sourceRef: kind: GitRepository - name: cozystack-platform + name: cozystack namespace: cozy-system diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index 892fb951..f69100b0 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:latest@sha256:d8664b707611f232fe375de932570f1a17d754a909e9cf999614191eb32e3853 +ghcr.io/cozystack/cozystack/matchbox:latest@sha256:4be61ac5c7206468795abf19caf52c949bd4684621edf9dbc3a20c7a0c2a2c34 diff --git a/packages/extra/ingress/templates/nginx-ingress.yaml b/packages/extra/ingress/templates/nginx-ingress.yaml index a50516ad..849c843f 100644 --- a/packages/extra/ingress/templates/nginx-ingress.yaml +++ b/packages/extra/ingress/templates/nginx-ingress.yaml @@ -9,7 +9,7 @@ spec: chartRef: kind: ExternalArtifact name: cozystack-system-ingress-system - namespace: cozy-public + namespace: cozy-system interval: 5m timeout: 10m install: diff --git a/packages/extra/seaweedfs/templates/seaweedfs.yaml b/packages/extra/seaweedfs/templates/seaweedfs.yaml index 63a8b1b3..3607eca3 100644 --- a/packages/extra/seaweedfs/templates/seaweedfs.yaml +++ b/packages/extra/seaweedfs/templates/seaweedfs.yaml @@ -45,7 +45,7 @@ spec: chartRef: kind: ExternalArtifact name: cozystack-system-seaweedfs-system - namespace: cozy-public + namespace: cozy-system interval: 5m timeout: 10m install: diff --git a/packages/system/bootbox/templates/bootbox.yaml b/packages/system/bootbox/templates/bootbox.yaml index 9aa8f1ce..9d062124 100644 --- a/packages/system/bootbox/templates/bootbox.yaml +++ b/packages/system/bootbox/templates/bootbox.yaml @@ -15,7 +15,7 @@ spec: sourceRef: kind: ExternalArtifact name: cozystack-system-bootbox - namespace: cozy-public + namespace: cozy-system version: '>= 0.0.0-0' interval: 1m0s timeout: 5m0s diff --git a/packages/system/cozystack-resource-definition-crd/Chart.yaml b/packages/system/cozystack-resource-definition-crd/Chart.yaml deleted file mode 100644 index 9924c7fa..00000000 --- a/packages/system/cozystack-resource-definition-crd/Chart.yaml +++ /dev/null @@ -1,3 +0,0 @@ -apiVersion: v2 -name: cozystack-resource-definition-crd -version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/cozystack-resource-definition-crd/Makefile b/packages/system/cozystack-resource-definition-crd/Makefile deleted file mode 100644 index 2b994a55..00000000 --- a/packages/system/cozystack-resource-definition-crd/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -export NAME=cozystack-resource-definition-crd -export NAMESPACE=cozy-system - -apply-locally: - cozypkg apply --plain -n $(NAMESPACE) $(NAME) - -include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definition-crd/templates/crd.yaml b/packages/system/cozystack-resource-definition-crd/templates/crd.yaml deleted file mode 100644 index 770a239e..00000000 --- a/packages/system/cozystack-resource-definition-crd/templates/crd.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -{{ .Files.Get "definition/cozystack.io_cozystackresourcedefinitions.yaml" }} ---- -{{ .Files.Get "definition/cozystack.io_cozystackbundles.yaml" }} diff --git a/packages/system/cozystack-resource-definition-crd/values.yaml b/packages/system/cozystack-resource-definition-crd/values.yaml deleted file mode 100644 index 0967ef42..00000000 --- a/packages/system/cozystack-resource-definition-crd/values.yaml +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/packages/system/kubevirt-cdi/templates/cdi-cr.yaml b/packages/system/kubevirt-cdi/templates/cdi-cr.yaml index 8f57ec43..69c8056e 100644 --- a/packages/system/kubevirt-cdi/templates/cdi-cr.yaml +++ b/packages/system/kubevirt-cdi/templates/cdi-cr.yaml @@ -35,7 +35,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: cdi-clone-dv - namespace: cozy-public + namespace: cozy-system subjects: - kind: Group name: system:serviceaccounts diff --git a/packages/system/vertical-pod-autoscaler/templates/vpa-for-vpa.yaml b/packages/system/vertical-pod-autoscaler/templates/vpa-for-vpa.yaml index 6db521bc..6a86d8ab 100644 --- a/packages/system/vertical-pod-autoscaler/templates/vpa-for-vpa.yaml +++ b/packages/system/vertical-pod-autoscaler/templates/vpa-for-vpa.yaml @@ -18,7 +18,7 @@ metadata: spec: chartRef: kind: ExternalArtifact - name: cozystack-iaas-vertical-pod-autoscaler + name: cozystack-system-vertical-pod-autoscaler namespace: cozy-system dependsOn: - name: monitoring-agents diff --git a/scripts/migrations/20 b/scripts/migrations/20 index 1a262ea7..6755cd65 100755 --- a/scripts/migrations/20 +++ b/scripts/migrations/20 @@ -25,8 +25,8 @@ sleep 5 cozypkg -n cozy-system -C packages/system/cozystack-resource-definition-crd apply cozystack-resource-definition-crd --plain cozypkg -n cozy-system -C packages/system/cozystack-resource-definitions apply cozystack-resource-definitions --plain cozypkg -n cozy-system -C packages/system/cozystack-api apply cozystack-api --plain -helm upgrade --install -n cozy-system cozystack-controller ./packages/system/cozystack-controller/ --take-ownership -helm upgrade --install -n cozy-system lineage-controller-webhook ./packages/system/lineage-controller-webhook/ --take-ownership +cozypkg -n cozy-system -C packages/system/cozystack-controller/ apply cozystack-api --plain --take-ownership +cozypkg -n cozy-system -C packages/system/lineage-controller-webhook/ apply cozystack-api --plain --take-ownership sleep 5 kubectl delete ns cozy-lineage-webhook-test --ignore-not-found && kubectl create ns cozy-lineage-webhook-test diff --git a/scripts/migrations/22 b/scripts/migrations/22 index 8242b894..4b43b23d 100755 --- a/scripts/migrations/22 +++ b/scripts/migrations/22 @@ -36,29 +36,25 @@ kubectl get helmreleases --all-namespaces -o json -l cozystack.io/ui=true | \ continue fi - # Determine artifact prefix and namespace based on repository name or namespace - artifact_prefix="" - artifact_namespace="cozy-public" + # Determine bundle name from label or ownerReference + bundle_name=$(printf '%s' "$hr_json" | jq -r '.metadata.labels["cozystack.io/bundle"] // empty') - if [ "$namespace" = "cozy-system" ]; then - # System resources always use system- prefix in cozy-system namespace - artifact_prefix="system" - artifact_namespace="cozy-system" - elif [ "$source_name" = "cozystack-apps" ]; then - # Apps repository -> apps- prefix in cozy-public namespace - artifact_prefix="apps" - artifact_namespace="cozy-public" - elif [ "$source_name" = "cozystack-extra" ]; then - # Extra repository -> extra- prefix in cozy-public namespace - artifact_prefix="extra" - artifact_namespace="cozy-public" - else - echo "Skipping $namespace/$name: unknown repository $source_name" + # If no label, try to get from ownerReferences + if [ -z "$bundle_name" ]; then + bundle_name=$(printf '%s' "$hr_json" | jq -r '.metadata.ownerReferences[]? | select(.kind == "CozystackBundle") | .name' | head -n 1) + fi + + # Skip if no bundle found + if [ -z "$bundle_name" ]; then + echo "Skipping $namespace/$name: no bundle label or ownerReference found" continue fi - # Build artifact name - artifact_name="${artifact_prefix}-${chart_name}" + # Determine artifact namespace (always cozy-system for ExternalArtifacts) + artifact_namespace="cozy-system" + + # Build artifact name: bundle-name-package-name (new format) + artifact_name="${bundle_name}-${chart_name}" echo "Migrating $namespace/$name: $chart_name -> $artifact_name (from $source_name)" From a4cb9ae30b6011d177aa671673fe907c02e7e15b Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Sat, 22 Nov 2025 22:52:43 +0100 Subject: [PATCH 21/46] Move migrations to platform package Signed-off-by: Andrei Kvapil --- Makefile | 1 + .../installer/images/cozystack/Dockerfile | 6 -- packages/core/platform/Makefile | 26 +++++++ .../platform/images/migrations/Dockerfile | 13 ++++ .../platform/images/migrations}/migrations/1 | 0 .../platform/images/migrations}/migrations/10 | 0 .../platform/images/migrations}/migrations/11 | 0 .../platform/images/migrations}/migrations/12 | 0 .../platform/images/migrations}/migrations/13 | 0 .../platform/images/migrations}/migrations/14 | 0 .../platform/images/migrations}/migrations/15 | 0 .../platform/images/migrations}/migrations/16 | 0 .../platform/images/migrations}/migrations/17 | 0 .../platform/images/migrations}/migrations/18 | 0 .../platform/images/migrations}/migrations/19 | 0 .../platform/images/migrations}/migrations/2 | 0 .../platform/images/migrations}/migrations/20 | 0 .../platform/images/migrations}/migrations/21 | 0 .../platform/images/migrations}/migrations/22 | 0 .../platform/images/migrations}/migrations/3 | 0 .../platform/images/migrations}/migrations/4 | 0 .../platform/images/migrations}/migrations/5 | 0 .../platform/images/migrations}/migrations/6 | 0 .../platform/images/migrations}/migrations/7 | 0 .../platform/images/migrations}/migrations/8 | 0 .../platform/images/migrations}/migrations/9 | 0 .../images/migrations/run-migrations.sh | 42 +++++++++++ .../platform/templates/migration-hook.yaml | 70 +++++++++++++++++++ packages/core/platform/values.yaml | 3 + 29 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 packages/core/platform/images/migrations/Dockerfile rename {scripts => packages/core/platform/images/migrations}/migrations/1 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/10 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/11 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/12 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/13 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/14 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/15 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/16 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/17 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/18 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/19 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/2 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/20 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/21 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/22 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/3 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/4 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/5 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/6 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/7 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/8 (100%) rename {scripts => packages/core/platform/images/migrations}/migrations/9 (100%) create mode 100755 packages/core/platform/images/migrations/run-migrations.sh create mode 100644 packages/core/platform/templates/migration-hook.yaml diff --git a/Makefile b/Makefile index fd4329af..3fc4eeeb 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,7 @@ build: build-deps make -C packages/system/objectstorage-controller image make -C packages/core/testing image make -C packages/core/installer image + make -C packages/core/platform image make manifests manifests: diff --git a/packages/core/installer/images/cozystack/Dockerfile b/packages/core/installer/images/cozystack/Dockerfile index 18e97900..c879df34 100644 --- a/packages/core/installer/images/cozystack/Dockerfile +++ b/packages/core/installer/images/cozystack/Dockerfile @@ -19,12 +19,6 @@ RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \ FROM alpine:3.22 -RUN wget -O- https://github.com/cozystack/cozypkg/raw/refs/heads/main/hack/install.sh | sh -s -- -v 1.4.0 - -RUN apk add --no-cache make kubectl helm coreutils git jq ca-certificates - -COPY --from=builder /src/scripts /cozystack/scripts COPY --from=builder /cozystack-operator /usr/bin/cozystack-operator -WORKDIR /cozystack ENTRYPOINT ["/usr/bin/cozystack-operator"] diff --git a/packages/core/platform/Makefile b/packages/core/platform/Makefile index b97d8532..cd6c0bf4 100644 --- a/packages/core/platform/Makefile +++ b/packages/core/platform/Makefile @@ -1,4 +1,30 @@ NAME=cozystack-platform NAMESPACE=cozy-system +include ../../../scripts/common-envs.mk include ../../../scripts/package.mk + +image: image-migrations + +image-migrations: + docker buildx build images/migrations \ + --tag $(REGISTRY)/migrations:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/migrations:latest \ + --cache-to type=inline \ + --metadata-file images/migrations.json \ + $(BUILDX_ARGS) + IMAGE="$(REGISTRY)/migrations:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/migrations.json -o json -r)" \ + yq -i '.migrations.image = strenv(IMAGE)' values.yaml + rm -f images/migrations.json + +generate: + @echo "Generating target version from migrations..." + @LAST_MIGRATION=$$(ls -1 images/migrations/migrations/ 2>/dev/null | grep -E '^[0-9]+$$' | sort -n | tail -1); \ + if [ -z "$$LAST_MIGRATION" ]; then \ + echo "Error: No migration files found" >&2; \ + exit 1; \ + fi; \ + TARGET_VERSION=$$((LAST_MIGRATION + 1)); \ + echo "Last migration: $$LAST_MIGRATION, Target version: $$TARGET_VERSION"; \ + yq -i '.migrations.targetVersion = $$TARGET_VERSION' values.yaml; \ + echo "Updated targetVersion to $$TARGET_VERSION in values.yaml" diff --git a/packages/core/platform/images/migrations/Dockerfile b/packages/core/platform/images/migrations/Dockerfile new file mode 100644 index 00000000..9acda394 --- /dev/null +++ b/packages/core/platform/images/migrations/Dockerfile @@ -0,0 +1,13 @@ +FROM alpine:3.22 + +RUN wget -O- https://github.com/cozystack/cozypkg/raw/refs/heads/main/hack/install.sh | sh -s -- -v 1.4.0 + +RUN apk add --no-cache kubectl helm coreutils git jq ca-certificates bash curl + +COPY migrations /migrations +COPY run-migrations.sh /usr/bin/run-migrations.sh + +WORKDIR /migrations + +ENTRYPOINT ["/usr/bin/run-migrations.sh"] + diff --git a/scripts/migrations/1 b/packages/core/platform/images/migrations/migrations/1 similarity index 100% rename from scripts/migrations/1 rename to packages/core/platform/images/migrations/migrations/1 diff --git a/scripts/migrations/10 b/packages/core/platform/images/migrations/migrations/10 similarity index 100% rename from scripts/migrations/10 rename to packages/core/platform/images/migrations/migrations/10 diff --git a/scripts/migrations/11 b/packages/core/platform/images/migrations/migrations/11 similarity index 100% rename from scripts/migrations/11 rename to packages/core/platform/images/migrations/migrations/11 diff --git a/scripts/migrations/12 b/packages/core/platform/images/migrations/migrations/12 similarity index 100% rename from scripts/migrations/12 rename to packages/core/platform/images/migrations/migrations/12 diff --git a/scripts/migrations/13 b/packages/core/platform/images/migrations/migrations/13 similarity index 100% rename from scripts/migrations/13 rename to packages/core/platform/images/migrations/migrations/13 diff --git a/scripts/migrations/14 b/packages/core/platform/images/migrations/migrations/14 similarity index 100% rename from scripts/migrations/14 rename to packages/core/platform/images/migrations/migrations/14 diff --git a/scripts/migrations/15 b/packages/core/platform/images/migrations/migrations/15 similarity index 100% rename from scripts/migrations/15 rename to packages/core/platform/images/migrations/migrations/15 diff --git a/scripts/migrations/16 b/packages/core/platform/images/migrations/migrations/16 similarity index 100% rename from scripts/migrations/16 rename to packages/core/platform/images/migrations/migrations/16 diff --git a/scripts/migrations/17 b/packages/core/platform/images/migrations/migrations/17 similarity index 100% rename from scripts/migrations/17 rename to packages/core/platform/images/migrations/migrations/17 diff --git a/scripts/migrations/18 b/packages/core/platform/images/migrations/migrations/18 similarity index 100% rename from scripts/migrations/18 rename to packages/core/platform/images/migrations/migrations/18 diff --git a/scripts/migrations/19 b/packages/core/platform/images/migrations/migrations/19 similarity index 100% rename from scripts/migrations/19 rename to packages/core/platform/images/migrations/migrations/19 diff --git a/scripts/migrations/2 b/packages/core/platform/images/migrations/migrations/2 similarity index 100% rename from scripts/migrations/2 rename to packages/core/platform/images/migrations/migrations/2 diff --git a/scripts/migrations/20 b/packages/core/platform/images/migrations/migrations/20 similarity index 100% rename from scripts/migrations/20 rename to packages/core/platform/images/migrations/migrations/20 diff --git a/scripts/migrations/21 b/packages/core/platform/images/migrations/migrations/21 similarity index 100% rename from scripts/migrations/21 rename to packages/core/platform/images/migrations/migrations/21 diff --git a/scripts/migrations/22 b/packages/core/platform/images/migrations/migrations/22 similarity index 100% rename from scripts/migrations/22 rename to packages/core/platform/images/migrations/migrations/22 diff --git a/scripts/migrations/3 b/packages/core/platform/images/migrations/migrations/3 similarity index 100% rename from scripts/migrations/3 rename to packages/core/platform/images/migrations/migrations/3 diff --git a/scripts/migrations/4 b/packages/core/platform/images/migrations/migrations/4 similarity index 100% rename from scripts/migrations/4 rename to packages/core/platform/images/migrations/migrations/4 diff --git a/scripts/migrations/5 b/packages/core/platform/images/migrations/migrations/5 similarity index 100% rename from scripts/migrations/5 rename to packages/core/platform/images/migrations/migrations/5 diff --git a/scripts/migrations/6 b/packages/core/platform/images/migrations/migrations/6 similarity index 100% rename from scripts/migrations/6 rename to packages/core/platform/images/migrations/migrations/6 diff --git a/scripts/migrations/7 b/packages/core/platform/images/migrations/migrations/7 similarity index 100% rename from scripts/migrations/7 rename to packages/core/platform/images/migrations/migrations/7 diff --git a/scripts/migrations/8 b/packages/core/platform/images/migrations/migrations/8 similarity index 100% rename from scripts/migrations/8 rename to packages/core/platform/images/migrations/migrations/8 diff --git a/scripts/migrations/9 b/packages/core/platform/images/migrations/migrations/9 similarity index 100% rename from scripts/migrations/9 rename to packages/core/platform/images/migrations/migrations/9 diff --git a/packages/core/platform/images/migrations/run-migrations.sh b/packages/core/platform/images/migrations/run-migrations.sh new file mode 100755 index 00000000..8e4cc1c6 --- /dev/null +++ b/packages/core/platform/images/migrations/run-migrations.sh @@ -0,0 +1,42 @@ +#!/bin/sh +set -euo pipefail + +NAMESPACE="${NAMESPACE:-cozy-system}" +CURRENT_VERSION="${CURRENT_VERSION:-0}" +TARGET_VERSION="${TARGET_VERSION:-0}" + +echo "Starting migrations from version $CURRENT_VERSION to $TARGET_VERSION" + +# Check if ConfigMap exists +if ! kubectl get configmap -n "$NAMESPACE" cozystack-version >/dev/null 2>&1; then + echo "ConfigMap cozystack-version does not exist, creating it with version $TARGET_VERSION" + kubectl create configmap -n "$NAMESPACE" cozystack-version \ + --from-literal=version="$TARGET_VERSION" \ + --dry-run=client -o yaml | kubectl apply -f- + echo "ConfigMap created with version $TARGET_VERSION" + exit 0 +fi + +# If current version is already at target, nothing to do +if [ "$CURRENT_VERSION" -ge "$TARGET_VERSION" ]; then + echo "Current version $CURRENT_VERSION is already at or above target version $TARGET_VERSION" + exit 0 +fi + +# Run migrations sequentially from current version to target version +for i in $(seq $((CURRENT_VERSION + 1)) $TARGET_VERSION); do + if [ -f "/migrations/$i" ]; then + echo "Running migration $i" + chmod +x /migrations/$i + /migrations/$i || { + echo "Migration $i failed" + exit 1 + } + echo "Migration $i completed successfully" + else + echo "Migration $i not found, skipping" + fi +done + +echo "All migrations completed successfully" + diff --git a/packages/core/platform/templates/migration-hook.yaml b/packages/core/platform/templates/migration-hook.yaml new file mode 100644 index 00000000..eeacf9d1 --- /dev/null +++ b/packages/core/platform/templates/migration-hook.yaml @@ -0,0 +1,70 @@ +{{- $shouldRunMigrationHook := false }} +{{- $currentVersion := 0 }} +{{- $targetVersion := .Values.migrations.targetVersion | int }} +{{- $configMap := lookup "v1" "ConfigMap" .Release.Namespace "cozystack-version" }} +{{- if $configMap }} + {{- $currentVersion = dig "data" "version" "0" $configMap | int }} + {{- if lt $currentVersion $targetVersion }} + {{- $shouldRunMigrationHook = true }} + {{- end }} +{{- else }} + {{- $shouldRunMigrationHook = true }} +{{- end }} + +{{- if $shouldRunMigrationHook }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: cozystack-migration-hook + annotations: + helm.sh/hook: pre-upgrade + helm.sh/hook-weight: "1" + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation +spec: + backoffLimit: 3 + template: + metadata: + labels: + policy.cozystack.io/allow-to-apiserver: "true" + spec: + serviceAccountName: cozystack-migration-hook + containers: + - name: migration + image: {{ .Values.migrations.image }} + env: + - name: NAMESPACE + value: {{ .Release.Namespace | quote }} + - name: CURRENT_VERSION + value: {{ $currentVersion | quote }} + - name: TARGET_VERSION + value: {{ $targetVersion | quote }} + restartPolicy: Never +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + annotations: + helm.sh/hook: pre-upgrade + helm.sh/hook-weight: "1" + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation + name: cozystack-migration-hook +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: + - kind: ServiceAccount + name: cozystack-migration-hook + namespace: {{ .Release.Namespace | quote }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: cozystack-migration-hook + annotations: + helm.sh/hook: pre-upgrade + helm.sh/hook-weight: "1" + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation +{{- end }} + diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml index 448b5bf0..ca053d20 100644 --- a/packages/core/platform/values.yaml +++ b/packages/core/platform/values.yaml @@ -2,3 +2,6 @@ sourceRef: kind: GitRepository name: cozystack namespace: cozy-system +migrations: + image: ghcr.io/cozystack/cozystack/migrations:latest@sha256:ab762997926290482633259f50b02277abb800c3a9ed5f2566282893f440578c + targetVersion: 23 # Auto-generated by 'make generate' From bb220647ad7193b3be92df29af4c3291383e567f Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Sat, 22 Nov 2025 23:20:17 +0100 Subject: [PATCH 22/46] Instruct Cozystack API server and lineage webhook logic to use labels Signed-off-by: Andrei Kvapil --- internal/lineagecontrollerwebhook/config.go | 73 +++++------------ .../lineagecontrollerwebhook/controller.go | 66 +--------------- internal/lineagecontrollerwebhook/webhook.go | 19 +---- .../platform/images/migrations/migrations/22 | 78 ++++++++++++++++++- pkg/registry/apps/application/rest.go | 56 +++++++++---- 5 files changed, 142 insertions(+), 150 deletions(-) diff --git a/internal/lineagecontrollerwebhook/config.go b/internal/lineagecontrollerwebhook/config.go index dbf29df0..1cb74442 100644 --- a/internal/lineagecontrollerwebhook/config.go +++ b/internal/lineagecontrollerwebhook/config.go @@ -2,73 +2,38 @@ package lineagecontrollerwebhook import ( "fmt" + "strings" - cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" helmv2 "github.com/fluxcd/helm-controller/api/v2" ) -type chartRef struct { - // For chart (HelmRepository): repo is SourceRef.Name, chart is Chart.Name - // For chartRef (ExternalArtifact): repo is empty, chart is SourceRef.Name - repo string - chart string - // isChartRef indicates if this is a chartRef (ExternalArtifact) reference - isChartRef bool - // namespace is used for chartRef (ExternalArtifact) - namespace 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() { - l.initOnce.Do(func() { - if l.config.Load() == nil { - l.config.Store(&runtimeConfig{ - chartAppMap: make(map[chartRef]*cozyv1alpha1.CozystackResourceDefinition), - appCRDMap: make(map[appRef]*cozyv1alpha1.CozystackResourceDefinition), - }) - } - }) + // No longer needed - we use labels directly from HelmRelease } 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 { - 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) } - var chRef chartRef - if hr.Spec.Chart != nil { - // Using chart (HelmRepository) - s := hr.Spec.Chart.Spec - chRef = chartRef{ - repo: s.SourceRef.Name, - chart: s.Chart, - isChartRef: false, - } - } else if hr.Spec.ChartRef != nil { - // Using chartRef (ExternalArtifact) - chRef = chartRef{ - repo: "", - chart: hr.Spec.ChartRef.Name, - isChartRef: true, - namespace: hr.Spec.ChartRef.Namespace, - } - } else { - return "", "", "", fmt.Errorf("cannot map helm release %s/%s to dynamic app: neither chart nor chartRef is set", hr.Namespace, hr.Name) + appGroup, ok := hr.Labels["apps.cozystack.io/application.group"] + if !ok { + return "", "", "", fmt.Errorf("cannot map helm release %s/%s to dynamic app: missing apps.cozystack.io/application.group label", hr.Namespace, hr.Name) } - val, ok := cfg.chartAppMap[chRef] + appName, ok := hr.Labels["apps.cozystack.io/application.name"] 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.name label", hr.Namespace, hr.Name) } - return "apps.cozystack.io/v1alpha1", val.Spec.Application.Kind, val.Spec.Release.Prefix, nil + + // 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 := strings.TrimSuffix(hr.Name, appName) + + return apiVersion, appKind, prefix, nil } diff --git a/internal/lineagecontrollerwebhook/controller.go b/internal/lineagecontrollerwebhook/controller.go index 2441c601..c423603b 100644 --- a/internal/lineagecontrollerwebhook/controller.go +++ b/internal/lineagecontrollerwebhook/controller.go @@ -1,71 +1,11 @@ package lineagecontrollerwebhook import ( - "context" - - cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" 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 CozystackResourceDefinitions func (c *LineageControllerWebhook) SetupWithManagerAsController(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&cozyv1alpha1.CozystackResourceDefinition{}). - 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 { - var chRef chartRef - if crd.Spec.Release.Chart != nil { - // Using chart (HelmRepository) - chRef = chartRef{ - repo: crd.Spec.Release.Chart.SourceRef.Name, - chart: crd.Spec.Release.Chart.Name, - isChartRef: false, - } - } else if crd.Spec.Release.ChartRef != nil { - // Using chartRef (ExternalArtifact) - chRef = chartRef{ - repo: "", - chart: crd.Spec.Release.ChartRef.SourceRef.Name, - isChartRef: true, - namespace: crd.Spec.Release.ChartRef.SourceRef.Namespace, - } - } else { - l.Info("CozystackResourceDefinition has neither chart nor chartRef, skipping", "name", crd.Name) - continue - } - - 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 + // No controller needed - we use labels directly from HelmRelease + return nil } diff --git a/internal/lineagecontrollerwebhook/webhook.go b/internal/lineagecontrollerwebhook/webhook.go index 0841c891..63df06f4 100644 --- a/internal/lineagecontrollerwebhook/webhook.go +++ b/internal/lineagecontrollerwebhook/webhook.go @@ -5,7 +5,6 @@ import ( "encoding/json" "errors" "fmt" - "strings" "github.com/cozystack/cozystack/pkg/lineage" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -156,21 +155,9 @@ func (h *LineageControllerWebhook) computeLabels(ctx context.Context, o *unstruc ManagerKindKey: obj.GetKind(), ManagerNameKey: obj.GetName(), } - templateLabels := map[string]string{ - "kind": strings.ToLower(obj.GetKind()), - "name": obj.GetName(), - "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)) + // Resource selectors are no longer needed since we don't use CozystackResourceDefinitions + // Set tenant resource label to false by default (can be overridden by other logic if needed) + labels[corev1alpha1.TenantResourceLabelKey] = "false" return labels, err } diff --git a/packages/core/platform/images/migrations/migrations/22 b/packages/core/platform/images/migrations/migrations/22 index 4b43b23d..53342c42 100755 --- a/packages/core/platform/images/migrations/migrations/22 +++ b/packages/core/platform/images/migrations/migrations/22 @@ -3,11 +3,11 @@ set -euo pipefail -echo "Migrating HelmReleases from spec.chart to spec.chartRef" +echo "Migrating HelmReleases: adding application labels and migrating from spec.chart to spec.chartRef" -# Process all HelmReleases that still use spec.chart (old format) +# Process all HelmReleases with cozystack.io/ui=true label kubectl get helmreleases --all-namespaces -o json -l cozystack.io/ui=true | \ - jq -r '.items[] | select(.spec.chart != null) | "\(.metadata.namespace)|\(.metadata.name)"' | \ + jq -r '.items[] | "\(.metadata.namespace)|\(.metadata.name)"' | \ while IFS='|' read -r namespace name; do echo "Processing HelmRelease $namespace/$name" @@ -86,8 +86,78 @@ kubectl get helmreleases --all-namespaces -o json -l cozystack.io/ui=true | \ if printf '%s' "$patch_ops" | jq -e 'length > 0' > /dev/null 2>&1; then printf '%s' "$patch_ops" | kubectl patch helmrelease -n "$namespace" "$name" --type json --patch-file /dev/stdin echo "Migrated $namespace/$name" + fi + + # Add application labels if missing + # Get CozystackResourceDefinition to determine application kind and group + app_kind="" + app_group="apps.cozystack.io" + app_name="" + + # Try to find CRD by chart or chartRef + if [ -n "$chart_name" ] && [ -n "$source_name" ]; then + # Try to find CRD by chart name and source + crd_json=$(kubectl get cozystackresourcedefinitions -n cozy-system -o json 2>/dev/null | \ + jq -r --arg chart "$chart_name" --arg source "$source_name" \ + '.items[] | select((.spec.release.chart.name == $chart and .spec.release.chart.sourceRef.name == $source) or (.spec.release.chartRef.sourceRef.name == $chart)) | .' | head -n 1) + + if [ -n "$crd_json" ]; then + app_kind=$(printf '%s' "$crd_json" | jq -r '.spec.application.kind // empty') + prefix=$(printf '%s' "$crd_json" | jq -r '.spec.release.prefix // empty') + + # Extract application name from HelmRelease name by removing prefix + if [ -n "$prefix" ] && [[ "$name" == "$prefix"* ]]; then + app_name="${name#$prefix}" + fi + fi + fi + + # If we couldn't determine from CRD, try to infer from HelmRelease name pattern + if [ -z "$app_name" ]; then + # Common prefixes to try + for prefix in "mysql-" "postgres-" "redis-" "clickhouse-" "kafka-" "nats-" "rabbitmq-" "ferretdb-" "foundationdb-" \ + "virtual-machine-" "vm-instance-" "vm-disk-" "virtualprivatecloud-" "bucket-" "kubernetes-" \ + "http-cache-" "tcp-balancer-" "vpn-" "tenant-" "monitoring-" "ingress-" "info-" "etcd-" "seaweedfs-" "bootbox-"; do + if [[ "$name" == "$prefix"* ]]; then + app_name="${name#$prefix}" + # Infer kind from prefix (capitalize and convert to CamelCase) + kind_part=$(echo "$prefix" | sed 's/-$//' | sed 's/-\([a-z]\)/\U\1/g' | sed 's/^\([a-z]\)/\U\1/g') + app_kind="$kind_part" + break + fi + done + fi + + # If still no app_name, use HelmRelease name as fallback + if [ -z "$app_name" ]; then + app_name="$name" + fi + + # Add labels if we have the information + if [ -n "$app_kind" ]; then + label_patch_ops="[]" + current_labels=$(printf '%s' "$hr_json" | jq -r '.metadata.labels // {}') + + # Check and add each label if missing + if [ "$(printf '%s' "$current_labels" | jq -r '.["apps.cozystack.io/application.kind"] // empty')" != "$app_kind" ]; then + label_patch_ops=$(printf '%s' "$label_patch_ops" | jq --arg kind "$app_kind" '. + [{"op": "add", "path": "/metadata/labels/apps.cozystack.io~1application.kind", "value": $kind}]') + fi + + if [ "$(printf '%s' "$current_labels" | jq -r '.["apps.cozystack.io/application.group"] // empty")" != "$app_group" ]; then + label_patch_ops=$(printf '%s' "$label_patch_ops" | jq --arg group "$app_group" '. + [{"op": "add", "path": "/metadata/labels/apps.cozystack.io~1application.group", "value": $group}]') + fi + + if [ "$(printf '%s' "$current_labels" | jq -r '.["apps.cozystack.io/application.name"] // empty")" != "$app_name" ]; then + label_patch_ops=$(printf '%s' "$label_patch_ops" | jq --arg name "$app_name" '. + [{"op": "add", "path": "/metadata/labels/apps.cozystack.io~1application.name", "value": $name}]') + fi + + # Apply label patch if there are operations + if printf '%s' "$label_patch_ops" | jq -e 'length > 0' > /dev/null 2>&1; then + printf '%s' "$label_patch_ops" | kubectl patch helmrelease -n "$namespace" "$name" --type json --patch-file /dev/stdin + echo "Added application labels to $namespace/$name (kind=$app_kind, group=$app_group, name=$app_name)" + fi else - echo "No changes needed for $namespace/$name" + echo "Warning: Could not determine application kind for $namespace/$name, skipping label addition" fi done diff --git a/pkg/registry/apps/application/rest.go b/pkg/registry/apps/application/rest.go index 29e941db..6fecdc17 100644 --- a/pkg/registry/apps/application/rest.go +++ b/pkg/registry/apps/application/rest.go @@ -31,6 +31,7 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" fields "k8s.io/apimachinery/pkg/fields" labels "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/duration" @@ -166,6 +167,13 @@ func (r *REST) Create(ctx context.Context, obj runtime.Object, createValidation helmRelease.Labels = mergeMaps(r.releaseConfig.Labels, helmRelease.Labels) // Merge user labels with prefix helmRelease.Labels = mergeMaps(helmRelease.Labels, addPrefixedMap(app.Labels, LabelPrefix)) + // Add application metadata labels + if helmRelease.Labels == nil { + helmRelease.Labels = make(map[string]string) + } + helmRelease.Labels["apps.cozystack.io/application.kind"] = r.kindName + helmRelease.Labels["apps.cozystack.io/application.group"] = r.gvk.Group + helmRelease.Labels["apps.cozystack.io/application.name"] = app.Name // Note: Annotations from config are not handled as r.releaseConfig.Annotations is undefined klog.V(6).Infof("Creating HelmRelease %s in namespace %s", helmRelease.Name, app.Namespace) @@ -224,9 +232,10 @@ func (r *REST) Get(ctx context.Context, name string, options *metav1.GetOptions) return nil, err } - // Check if HelmRelease meets the required chartName and sourceRef criteria - if !r.shouldIncludeHelmRelease(helmRelease) { - klog.Errorf("HelmRelease %s does not match the required chartName and sourceRef criteria", helmReleaseName) + // Check if HelmRelease has required labels + if helmRelease.Labels["apps.cozystack.io/application.kind"] != r.kindName || + helmRelease.Labels["apps.cozystack.io/application.group"] != r.gvk.Group { + klog.Errorf("HelmRelease %s does not match the required application labels", helmReleaseName) // Return a NotFound error for the Application resource return nil, apierrors.NewNotFound(r.gvr.GroupResource(), name) } @@ -299,6 +308,19 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption } // Process label.selector + // Always add application metadata label requirements + appKindReq, err := labels.NewRequirement("apps.cozystack.io/application.kind", selection.Equals, []string{r.kindName}) + if err != nil { + klog.Errorf("Error creating application kind label requirement: %v", err) + return nil, fmt.Errorf("error creating application kind label requirement: %v", err) + } + appGroupReq, err := labels.NewRequirement("apps.cozystack.io/application.group", selection.Equals, []string{r.gvk.Group}) + if err != nil { + klog.Errorf("Error creating application group label requirement: %v", err) + return nil, fmt.Errorf("error creating application group label requirement: %v", err) + } + labelRequirements := []labels.Requirement{*appKindReq, *appGroupReq} + if options.LabelSelector != nil { ls := options.LabelSelector.String() parsedLabels, err := labels.Parse(ls) @@ -318,9 +340,10 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption } prefixedReqs = append(prefixedReqs, *prefixedReq) } - helmLabelSelector = labels.NewSelector().Add(prefixedReqs...).String() + labelRequirements = append(labelRequirements, prefixedReqs...) } } + helmLabelSelector = labels.NewSelector().Add(labelRequirements...).String() // Set ListOptions for HelmRelease with selector mapping metaOptions := metav1.ListOptions{ @@ -343,10 +366,8 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption items := make([]unstructured.Unstructured, 0) // Iterate over HelmReleases and convert to Applications + // No need to filter by shouldIncludeHelmRelease since we're using label selectors for i := range hrList.Items { - if !r.shouldIncludeHelmRelease(&hrList.Items[i]) { - continue - } app, err := r.ConvertHelmReleaseToApplication(&hrList.Items[i]) if err != nil { @@ -482,14 +503,22 @@ func (r *REST) Update(ctx context.Context, name string, objInfo rest.UpdatedObje helmRelease.Labels = mergeMaps(r.releaseConfig.Labels, helmRelease.Labels) // Merge user labels with prefix helmRelease.Labels = mergeMaps(helmRelease.Labels, addPrefixedMap(app.Labels, LabelPrefix)) + // Add application metadata labels + if helmRelease.Labels == nil { + helmRelease.Labels = make(map[string]string) + } + helmRelease.Labels["apps.cozystack.io/application.kind"] = r.kindName + helmRelease.Labels["apps.cozystack.io/application.group"] = r.gvk.Group + helmRelease.Labels["apps.cozystack.io/application.name"] = app.Name // Note: Annotations from config are not handled as r.releaseConfig.Annotations is undefined klog.V(6).Infof("Updating HelmRelease %s in namespace %s", helmRelease.Name, helmRelease.Namespace) - // Before updating, ensure the HelmRelease meets the inclusion criteria + // Before updating, ensure the HelmRelease has required labels // This prevents updating HelmReleases that should not be managed as Applications - if !r.shouldIncludeHelmRelease(helmRelease) { - klog.Errorf("HelmRelease %s does not match the required chartName and sourceRef criteria", helmRelease.Name) + if helmRelease.Labels["apps.cozystack.io/application.kind"] != r.kindName || + helmRelease.Labels["apps.cozystack.io/application.group"] != r.gvk.Group { + klog.Errorf("HelmRelease %s does not match the required application labels", helmRelease.Name) // Return a NotFound error for the Application resource return nil, false, apierrors.NewNotFound(r.gvr.GroupResource(), name) } @@ -501,9 +530,10 @@ func (r *REST) Update(ctx context.Context, name string, objInfo rest.UpdatedObje return nil, false, fmt.Errorf("failed to update HelmRelease: %v", err) } - // After updating, ensure the updated HelmRelease still meets the inclusion criteria - if !r.shouldIncludeHelmRelease(helmRelease) { - klog.Errorf("Updated HelmRelease %s does not match the required chartName and sourceRef criteria", helmRelease.GetName()) + // After updating, ensure the updated HelmRelease still has required labels + if helmRelease.Labels["apps.cozystack.io/application.kind"] != r.kindName || + helmRelease.Labels["apps.cozystack.io/application.group"] != r.gvk.Group { + klog.Errorf("Updated HelmRelease %s does not match the required application labels", helmRelease.GetName()) // Return a NotFound error for the Application resource return nil, false, apierrors.NewNotFound(r.gvr.GroupResource(), name) } From 7fc458d136248c480d02e7334fb7667744c3651d Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Sat, 22 Nov 2025 23:32:15 +0100 Subject: [PATCH 23/46] [cozystack-api] Show revision Signed-off-by: Andrei Kvapil --- pkg/registry/apps/application/rest.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/pkg/registry/apps/application/rest.go b/pkg/registry/apps/application/rest.go index 6fecdc17..72f00eca 100644 --- a/pkg/registry/apps/application/rest.go +++ b/pkg/registry/apps/application/rest.go @@ -1059,7 +1059,7 @@ func (r *REST) convertHelmReleaseToApplication(hr *helmv2.HelmRelease) (appsv1al }, Spec: hr.Spec.Values, Status: appsv1alpha1.ApplicationStatus{ - Version: hr.Status.LastAttemptedRevision, + Version: extractRevision(hr.Status.LastAttemptedRevision), }, } @@ -1279,6 +1279,22 @@ func (r *REST) buildTableFromApplication(app appsv1alpha1.Application) metav1.Ta return table } +// extractRevision extracts only the revision part from a version string +// If version is in format "0.1.4+abcdef", returns "abcdef" +// Otherwise returns the original string +func extractRevision(version string) string { + if version == "" { + return "" + } + // Check if version contains "+" separator + if idx := strings.LastIndex(version, "+"); idx >= 0 && idx < len(version)-1 { + // Return only the part after "+" + return version[idx+1:] + } + // If no "+" found, return original version + return version +} + // getVersion returns the application version or a placeholder if unknown func getVersion(version string) string { if version == "" { From 167e85004c5a3f80d6cd89b09d9a5e08bd28b804 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Sun, 23 Nov 2025 00:30:19 +0100 Subject: [PATCH 24/46] rename packages Signed-off-by: Andrei Kvapil --- Makefile | 7 +++-- hack/update-codegen.sh | 4 +-- packages/apps/README.md | 8 ----- packages/core/cozystack-operator/Chart.yaml | 3 ++ packages/core/cozystack-operator/Makefile | 30 +++++++++++++++++++ .../crds/cozystack.io_cozystackbundles.yaml | 0 ...stack.io_cozystackresourcedefinitions.yaml | 0 .../example/platform.yaml | 0 .../images/cozystack-operator}/Dockerfile | 0 .../Dockerfile.dockerignore | 0 .../templates/cozystack-operator.yaml} | 14 ++++----- .../templates/crds.yaml | 0 packages/core/cozystack-operator/values.yaml | 2 ++ packages/core/{fluxcd => flux-aio}/Chart.yaml | 0 packages/core/{fluxcd => flux-aio}/Makefile | 2 +- .../core/{fluxcd => flux-aio}/flux-aio.cue | 1 - packages/core/{fluxcd => flux-aio}/manifests | 0 .../core/{fluxcd => flux-aio}/values.yaml | 0 packages/core/installer/values.yaml | 2 -- packages/core/{installer => talos}/Chart.yaml | 2 +- packages/core/{installer => talos}/Makefile | 27 ++--------------- .../{installer => talos}/hack/gen-profiles.sh | 0 .../{installer => talos}/hack/gen-versions.sh | 0 .../images/matchbox/Dockerfile | 4 +-- .../images/matchbox/groups/default.json | 0 .../images/matchbox/profiles/default.json | 0 .../images/talos/profiles/initramfs.yaml | 0 .../images/talos/profiles/installer.yaml | 0 .../images/talos/profiles/iso.yaml | 0 .../images/talos/profiles/kernel.yaml | 0 .../images/talos/profiles/metal.yaml | 0 .../images/talos/profiles/nocloud.yaml | 0 packages/core/talos/values.yaml | 2 ++ .../patches/kubernetesEnvs.diff | 12 -------- .../fluxcd-operator/templates/_helpers.tpl | 13 -------- packages/system/fluxcd-operator/values.yaml | 1 - 36 files changed, 56 insertions(+), 78 deletions(-) delete mode 100644 packages/apps/README.md create mode 100644 packages/core/cozystack-operator/Chart.yaml create mode 100644 packages/core/cozystack-operator/Makefile rename packages/core/{installer => cozystack-operator}/crds/cozystack.io_cozystackbundles.yaml (100%) rename packages/core/{installer => cozystack-operator}/crds/cozystack.io_cozystackresourcedefinitions.yaml (100%) rename packages/core/{installer => cozystack-operator}/example/platform.yaml (100%) rename packages/core/{installer/images/cozystack => cozystack-operator/images/cozystack-operator}/Dockerfile (100%) rename packages/core/{installer/images/cozystack => cozystack-operator/images/cozystack-operator}/Dockerfile.dockerignore (100%) rename packages/core/{installer/templates/cozystack.yaml => cozystack-operator/templates/cozystack-operator.yaml} (96%) rename packages/core/{installer => cozystack-operator}/templates/crds.yaml (100%) create mode 100644 packages/core/cozystack-operator/values.yaml rename packages/core/{fluxcd => flux-aio}/Chart.yaml (100%) rename packages/core/{fluxcd => flux-aio}/Makefile (97%) rename packages/core/{fluxcd => flux-aio}/flux-aio.cue (91%) rename packages/core/{fluxcd => flux-aio}/manifests (100%) rename packages/core/{fluxcd => flux-aio}/values.yaml (100%) delete mode 100644 packages/core/installer/values.yaml rename packages/core/{installer => talos}/Chart.yaml (84%) rename packages/core/{installer => talos}/Makefile (64%) rename packages/core/{installer => talos}/hack/gen-profiles.sh (100%) rename packages/core/{installer => talos}/hack/gen-versions.sh (100%) rename packages/core/{installer => talos}/images/matchbox/Dockerfile (53%) rename packages/core/{installer => talos}/images/matchbox/groups/default.json (100%) rename packages/core/{installer => talos}/images/matchbox/profiles/default.json (100%) rename packages/core/{installer => talos}/images/talos/profiles/initramfs.yaml (100%) rename packages/core/{installer => talos}/images/talos/profiles/installer.yaml (100%) rename packages/core/{installer => talos}/images/talos/profiles/iso.yaml (100%) rename packages/core/{installer => talos}/images/talos/profiles/kernel.yaml (100%) rename packages/core/{installer => talos}/images/talos/profiles/metal.yaml (100%) rename packages/core/{installer => talos}/images/talos/profiles/nocloud.yaml (100%) create mode 100644 packages/core/talos/values.yaml delete mode 100644 packages/system/fluxcd-operator/patches/kubernetesEnvs.diff delete mode 100644 packages/system/fluxcd-operator/templates/_helpers.tpl diff --git a/Makefile b/Makefile index 3fc4eeeb..11368365 100644 --- a/Makefile +++ b/Makefile @@ -26,16 +26,17 @@ build: build-deps make -C packages/system/bucket image make -C packages/system/objectstorage-controller image make -C packages/core/testing image - make -C packages/core/installer image + make -C packages/core/cozystack-operator image + make -C packages/core/talos image make -C packages/core/platform image make manifests manifests: mkdir -p _out/assets - (cd packages/core/installer/; helm template -n cozy-installer installer .) > _out/assets/cozystack-installer.yaml + (cd packages/core/cozystack-operator/; helm template -n cozy-installer talos .) > _out/assets/cozystack-installer.yaml assets: - make -C packages/core/installer assets + make -C packages/core/talos assets test: make -C packages/core/testing apply diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 87a46114..b30a7d82 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -55,6 +55,6 @@ kube::codegen::gen_openapi \ $CONTROLLER_GEN object:headerFile="hack/boilerplate.go.txt" paths="./api/..." $CONTROLLER_GEN rbac:roleName=manager-role crd paths="./api/..." output:crd:artifacts:config=packages/system/cozystack-controller/crds mv packages/system/cozystack-controller/crds/cozystack.io_cozystackresourcedefinitions.yaml \ - packages/core/installer/crds/cozystack.io_cozystackresourcedefinitions.yaml + packages/core/cozystack-operator/crds/cozystack.io_cozystackresourcedefinitions.yaml mv packages/system/cozystack-controller/crds/cozystack.io_cozystackbundles.yaml \ - packages/core/installer/crds/cozystack.io_cozystackbundles.yaml + packages/core/cozystack-operator/crds/cozystack.io_cozystackbundles.yaml diff --git a/packages/apps/README.md b/packages/apps/README.md deleted file mode 100644 index 8ee4c3ed..00000000 --- a/packages/apps/README.md +++ /dev/null @@ -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 -``` diff --git a/packages/core/cozystack-operator/Chart.yaml b/packages/core/cozystack-operator/Chart.yaml new file mode 100644 index 00000000..61cf32e6 --- /dev/null +++ b/packages/core/cozystack-operator/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-cozystack-operator +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/core/cozystack-operator/Makefile b/packages/core/cozystack-operator/Makefile new file mode 100644 index 00000000..dcac7028 --- /dev/null +++ b/packages/core/cozystack-operator/Makefile @@ -0,0 +1,30 @@ +NAME=cozystack-operator +NAMESPACE=cozy-system + +include ../../../scripts/common-envs.mk + +image: pre-checks image-cozystack-operator + +pre-checks: + ../../../hack/pre-checks.sh + +show: + cozypkg show -n $(NAMESPACE) $(NAME) --plain + +apply: + cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f- + +diff: + cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f - + +image-cozystack-operator: + docker buildx build -f images/cozystack-operator/Dockerfile ../../.. \ + --tag $(REGISTRY)/cozystack-operator:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/cozystack-operator:latest \ + --cache-to type=inline \ + --metadata-file images/cozystack-operator.json \ + $(BUILDX_ARGS) + IMAGE="$(REGISTRY)/cozystack-operator:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/cozystack-operator.json -o json -r)" \ + yq -i '.cozystackOperator.image = strenv(IMAGE)' values.yaml + rm -f images/cozystack-operator.json + diff --git a/packages/core/installer/crds/cozystack.io_cozystackbundles.yaml b/packages/core/cozystack-operator/crds/cozystack.io_cozystackbundles.yaml similarity index 100% rename from packages/core/installer/crds/cozystack.io_cozystackbundles.yaml rename to packages/core/cozystack-operator/crds/cozystack.io_cozystackbundles.yaml diff --git a/packages/core/installer/crds/cozystack.io_cozystackresourcedefinitions.yaml b/packages/core/cozystack-operator/crds/cozystack.io_cozystackresourcedefinitions.yaml similarity index 100% rename from packages/core/installer/crds/cozystack.io_cozystackresourcedefinitions.yaml rename to packages/core/cozystack-operator/crds/cozystack.io_cozystackresourcedefinitions.yaml diff --git a/packages/core/installer/example/platform.yaml b/packages/core/cozystack-operator/example/platform.yaml similarity index 100% rename from packages/core/installer/example/platform.yaml rename to packages/core/cozystack-operator/example/platform.yaml diff --git a/packages/core/installer/images/cozystack/Dockerfile b/packages/core/cozystack-operator/images/cozystack-operator/Dockerfile similarity index 100% rename from packages/core/installer/images/cozystack/Dockerfile rename to packages/core/cozystack-operator/images/cozystack-operator/Dockerfile diff --git a/packages/core/installer/images/cozystack/Dockerfile.dockerignore b/packages/core/cozystack-operator/images/cozystack-operator/Dockerfile.dockerignore similarity index 100% rename from packages/core/installer/images/cozystack/Dockerfile.dockerignore rename to packages/core/cozystack-operator/images/cozystack-operator/Dockerfile.dockerignore diff --git a/packages/core/installer/templates/cozystack.yaml b/packages/core/cozystack-operator/templates/cozystack-operator.yaml similarity index 96% rename from packages/core/installer/templates/cozystack.yaml rename to packages/core/cozystack-operator/templates/cozystack-operator.yaml index 2fd4abb5..10426640 100644 --- a/packages/core/installer/templates/cozystack.yaml +++ b/packages/core/cozystack-operator/templates/cozystack-operator.yaml @@ -46,21 +46,21 @@ spec: labels: app: cozystack-operator spec: - hostNetwork: true serviceAccountName: cozystack containers: - name: cozystack-operator - image: "{{ .Values.cozystack.image }}" - env: - - name: KUBERNETES_SERVICE_HOST - value: localhost - - name: KUBERNETES_SERVICE_PORT - value: "7445" + image: "{{ .Values.cozystackOperator.image }}" args: - --leader-elect=true - --install-flux=true - --metrics-bind-address=0 - --health-probe-bind-address= + env: + - name: KUBERNETES_SERVICE_HOST + value: localhost + - name: KUBERNETES_SERVICE_PORT + value: "7445" + hostNetwork: true tolerations: - key: "node.kubernetes.io/not-ready" operator: "Exists" diff --git a/packages/core/installer/templates/crds.yaml b/packages/core/cozystack-operator/templates/crds.yaml similarity index 100% rename from packages/core/installer/templates/crds.yaml rename to packages/core/cozystack-operator/templates/crds.yaml diff --git a/packages/core/cozystack-operator/values.yaml b/packages/core/cozystack-operator/values.yaml new file mode 100644 index 00000000..05d21e2e --- /dev/null +++ b/packages/core/cozystack-operator/values.yaml @@ -0,0 +1,2 @@ +cozystackOperator: + image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:5b2de1844a445ad3fa71898a607feca4b346ffc3a2a934809ff096b2eff49218 diff --git a/packages/core/fluxcd/Chart.yaml b/packages/core/flux-aio/Chart.yaml similarity index 100% rename from packages/core/fluxcd/Chart.yaml rename to packages/core/flux-aio/Chart.yaml diff --git a/packages/core/fluxcd/Makefile b/packages/core/flux-aio/Makefile similarity index 97% rename from packages/core/fluxcd/Makefile rename to packages/core/flux-aio/Makefile index 4addf9e9..29024c79 100644 --- a/packages/core/fluxcd/Makefile +++ b/packages/core/flux-aio/Makefile @@ -1,4 +1,4 @@ -NAME=fluxcd +NAME=flux-aio NAMESPACE=cozy-$(NAME) show: diff --git a/packages/core/fluxcd/flux-aio.cue b/packages/core/flux-aio/flux-aio.cue similarity index 91% rename from packages/core/fluxcd/flux-aio.cue rename to packages/core/flux-aio/flux-aio.cue index c58461cc..8c067c3b 100644 --- a/packages/core/fluxcd/flux-aio.cue +++ b/packages/core/flux-aio/flux-aio.cue @@ -9,7 +9,6 @@ bundle: { } namespace: "cozy-fluxcd" values: { - hostNetwork: true securityProfile: "privileged" } } diff --git a/packages/core/fluxcd/manifests b/packages/core/flux-aio/manifests similarity index 100% rename from packages/core/fluxcd/manifests rename to packages/core/flux-aio/manifests diff --git a/packages/core/fluxcd/values.yaml b/packages/core/flux-aio/values.yaml similarity index 100% rename from packages/core/fluxcd/values.yaml rename to packages/core/flux-aio/values.yaml diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml deleted file mode 100644 index 9e295170..00000000 --- a/packages/core/installer/values.yaml +++ /dev/null @@ -1,2 +0,0 @@ -cozystack: - image: ghcr.io/cozystack/cozystack/installer:latest@sha256:e0b73cfcfeae7c8cbccbad469a57dee0f1691a2726ad29eb9964972101b9a57b diff --git a/packages/core/installer/Chart.yaml b/packages/core/talos/Chart.yaml similarity index 84% rename from packages/core/installer/Chart.yaml rename to packages/core/talos/Chart.yaml index 91350467..7c10b8d7 100644 --- a/packages/core/installer/Chart.yaml +++ b/packages/core/talos/Chart.yaml @@ -1,3 +1,3 @@ apiVersion: v2 -name: cozy-installer +name: cozy-talos version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/core/installer/Makefile b/packages/core/talos/Makefile similarity index 64% rename from packages/core/installer/Makefile rename to packages/core/talos/Makefile index a51e7b61..ac89912f 100644 --- a/packages/core/installer/Makefile +++ b/packages/core/talos/Makefile @@ -1,37 +1,14 @@ -NAME=installer +NAME=talos NAMESPACE=cozy-system TALOS_VERSION=$(shell awk '/^version:/ {print $$2}' images/talos/profiles/installer.yaml) include ../../../scripts/common-envs.mk -pre-checks: - ../../../hack/pre-checks.sh - -show: - cozypkg show -n $(NAMESPACE) $(NAME) --plain - -apply: - cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f- - -diff: - cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f - - update: hack/gen-profiles.sh -image: pre-checks image-matchbox image-cozystack image-talos - -image-cozystack: - docker buildx build -f images/cozystack/Dockerfile ../../.. \ - --tag $(REGISTRY)/installer:$(call settag,$(TAG)) \ - --cache-from type=registry,ref=$(REGISTRY)/installer:latest \ - --cache-to type=inline \ - --metadata-file images/installer.json \ - $(BUILDX_ARGS) - IMAGE="$(REGISTRY)/installer:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/installer.json -o json -r)" \ - yq -i '.cozystack.image = strenv(IMAGE)' values.yaml - rm -f images/installer.json +image: image-matchbox image-talos image-talos: test -f ../../../_out/assets/installer-amd64.tar || make talos-installer diff --git a/packages/core/installer/hack/gen-profiles.sh b/packages/core/talos/hack/gen-profiles.sh similarity index 100% rename from packages/core/installer/hack/gen-profiles.sh rename to packages/core/talos/hack/gen-profiles.sh diff --git a/packages/core/installer/hack/gen-versions.sh b/packages/core/talos/hack/gen-versions.sh similarity index 100% rename from packages/core/installer/hack/gen-versions.sh rename to packages/core/talos/hack/gen-versions.sh diff --git a/packages/core/installer/images/matchbox/Dockerfile b/packages/core/talos/images/matchbox/Dockerfile similarity index 53% rename from packages/core/installer/images/matchbox/Dockerfile rename to packages/core/talos/images/matchbox/Dockerfile index 1083ab26..fbb6f3bf 100644 --- a/packages/core/installer/images/matchbox/Dockerfile +++ b/packages/core/talos/images/matchbox/Dockerfile @@ -2,5 +2,5 @@ FROM quay.io/poseidon/matchbox:v0.10.0 COPY _out/assets/initramfs-metal-amd64.xz /var/lib/matchbox/assets/initramfs.xz COPY _out/assets/kernel-amd64 /var/lib/matchbox/assets/vmlinuz -COPY packages/core/installer/images/matchbox/groups /var/lib/matchbox/groups -COPY packages/core/installer/images/matchbox/profiles /var/lib/matchbox/profiles +COPY packages/core/talos/images/matchbox/groups /var/lib/matchbox/groups +COPY packages/core/talos/images/matchbox/profiles /var/lib/matchbox/profiles diff --git a/packages/core/installer/images/matchbox/groups/default.json b/packages/core/talos/images/matchbox/groups/default.json similarity index 100% rename from packages/core/installer/images/matchbox/groups/default.json rename to packages/core/talos/images/matchbox/groups/default.json diff --git a/packages/core/installer/images/matchbox/profiles/default.json b/packages/core/talos/images/matchbox/profiles/default.json similarity index 100% rename from packages/core/installer/images/matchbox/profiles/default.json rename to packages/core/talos/images/matchbox/profiles/default.json diff --git a/packages/core/installer/images/talos/profiles/initramfs.yaml b/packages/core/talos/images/talos/profiles/initramfs.yaml similarity index 100% rename from packages/core/installer/images/talos/profiles/initramfs.yaml rename to packages/core/talos/images/talos/profiles/initramfs.yaml diff --git a/packages/core/installer/images/talos/profiles/installer.yaml b/packages/core/talos/images/talos/profiles/installer.yaml similarity index 100% rename from packages/core/installer/images/talos/profiles/installer.yaml rename to packages/core/talos/images/talos/profiles/installer.yaml diff --git a/packages/core/installer/images/talos/profiles/iso.yaml b/packages/core/talos/images/talos/profiles/iso.yaml similarity index 100% rename from packages/core/installer/images/talos/profiles/iso.yaml rename to packages/core/talos/images/talos/profiles/iso.yaml diff --git a/packages/core/installer/images/talos/profiles/kernel.yaml b/packages/core/talos/images/talos/profiles/kernel.yaml similarity index 100% rename from packages/core/installer/images/talos/profiles/kernel.yaml rename to packages/core/talos/images/talos/profiles/kernel.yaml diff --git a/packages/core/installer/images/talos/profiles/metal.yaml b/packages/core/talos/images/talos/profiles/metal.yaml similarity index 100% rename from packages/core/installer/images/talos/profiles/metal.yaml rename to packages/core/talos/images/talos/profiles/metal.yaml diff --git a/packages/core/installer/images/talos/profiles/nocloud.yaml b/packages/core/talos/images/talos/profiles/nocloud.yaml similarity index 100% rename from packages/core/installer/images/talos/profiles/nocloud.yaml rename to packages/core/talos/images/talos/profiles/nocloud.yaml diff --git a/packages/core/talos/values.yaml b/packages/core/talos/values.yaml new file mode 100644 index 00000000..6122038e --- /dev/null +++ b/packages/core/talos/values.yaml @@ -0,0 +1,2 @@ +# Talos installer values - no longer contains cozystack-operator +# cozystack-operator is now in packages/core/cozystack-operator diff --git a/packages/system/fluxcd-operator/patches/kubernetesEnvs.diff b/packages/system/fluxcd-operator/patches/kubernetesEnvs.diff deleted file mode 100644 index 1c9c1c39..00000000 --- a/packages/system/fluxcd-operator/patches/kubernetesEnvs.diff +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/packages/core/fluxcd/charts/flux-operator/templates/deployment.yaml b/packages/core/fluxcd/charts/flux-operator/templates/deployment.yaml -index 8ffd8d8..5ad96a8 100644 ---- a/charts/flux-operator/templates/deployment.yaml -+++ b/charts/flux-operator/templates/deployment.yaml -@@ -58,6 +58,7 @@ spec: - {{- if .Values.extraEnvs }} - {{- toYaml .Values.extraEnvs | nindent 12 }} - {{- end }} -+ {{- include "cozy.kubernetes_envs" . | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" diff --git a/packages/system/fluxcd-operator/templates/_helpers.tpl b/packages/system/fluxcd-operator/templates/_helpers.tpl deleted file mode 100644 index 0271a10f..00000000 --- a/packages/system/fluxcd-operator/templates/_helpers.tpl +++ /dev/null @@ -1,13 +0,0 @@ -{{- define "cozy.kubernetes_envs" }} -{{- $cozyDeployment := lookup "apps/v1" "Deployment" "cozy-system" "cozystack-operator" }} -{{- $cozyContainers := dig "spec" "template" "spec" "containers" dict $cozyDeployment }} -{{- range $cozyContainers }} -{{- if eq .name "cozystack-operator" }} -{{- range .env }} -{{- if has .name (list "KUBERNETES_SERVICE_HOST" "KUBERNETES_SERVICE_PORT") }} -- {{ toJson . }} -{{- end }} -{{- end }} -{{- end }} -{{- end }} -{{- end }} diff --git a/packages/system/fluxcd-operator/values.yaml b/packages/system/fluxcd-operator/values.yaml index 9053689a..81bc1924 100644 --- a/packages/system/fluxcd-operator/values.yaml +++ b/packages/system/fluxcd-operator/values.yaml @@ -4,7 +4,6 @@ flux-operator: - key: node.kubernetes.io/not-ready operator: Exists effect: NoSchedule - hostNetwork: true resources: limits: cpu: 100m From 5883fbf7eae10b3d6b03d32511ca2e31c8b813ee Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 24 Nov 2025 10:24:01 +0100 Subject: [PATCH 25/46] [cozystack-controller] Add reconciliation for CozystackResourceDefinitions Signed-off-by: Andrei Kvapil --- .../cozystackresource_controller.go | 134 ++++++++++++++++++ internal/controller/system_helm_reconciler.go | 6 +- .../system/cozystack-controller/values.yaml | 2 +- 3 files changed, 138 insertions(+), 4 deletions(-) diff --git a/internal/controller/cozystackresource_controller.go b/internal/controller/cozystackresource_controller.go index 46884418..1a41cbe7 100644 --- a/internal/controller/cozystackresource_controller.go +++ b/internal/controller/cozystackresource_controller.go @@ -10,6 +10,7 @@ import ( "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" @@ -23,6 +24,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" ) +// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackresourcedefinitions,verbs=get;list;watch +// +kubebuilder:rbac:groups=helm.toolkit.fluxcd.io,resources=helmreleases,verbs=get;list;watch;update;patch type CozystackResourceDefinitionReconciler struct { client.Client Scheme *runtime.Scheme @@ -37,6 +40,25 @@ type CozystackResourceDefinitionReconciler struct { } func (r *CozystackResourceDefinitionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + + // Get all CozystackResourceDefinitions + crdList := &cozyv1alpha1.CozystackResourceDefinitionList{} + if err := r.List(ctx, crdList); err != nil { + logger.Error(err, "failed to list CozystackResourceDefinitions") + return ctrl.Result{}, err + } + + // Update HelmReleases for each CRD + for i := range crdList.Items { + crd := &crdList.Items[i] + 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) } @@ -185,3 +207,115 @@ func sortCozyRDs(a, b cozyv1alpha1.CozystackResourceDefinition) int { } return 1 } + +// updateHelmReleasesForCRD updates all HelmReleases that match the labels from CozystackResourceDefinition +func (r *CozystackResourceDefinitionReconciler) updateHelmReleasesForCRD(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) error { + logger := log.FromContext(ctx) + + // Skip if no labels defined + if len(crd.Spec.Release.Labels) == 0 { + return nil + } + + // List all HelmReleases with matching labels + hrList := &helmv2.HelmReleaseList{} + labelSelector := client.MatchingLabels(crd.Spec.Release.Labels) + if err := r.List(ctx, hrList, labelSelector); err != nil { + return err + } + + logger.Info("Found HelmReleases to update", "crd", crd.Name, "count", len(hrList.Items)) + + // 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 in HelmRelease based on CozystackResourceDefinition +func (r *CozystackResourceDefinitionReconciler) updateHelmReleaseChart(ctx context.Context, hr *helmv2.HelmRelease, crd *cozyv1alpha1.CozystackResourceDefinition) 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 + } + } + } + + 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 chart/chartRef", "name", hr.Name, "namespace", hr.Namespace, "crd", crd.Name) + return nil +} diff --git a/internal/controller/system_helm_reconciler.go b/internal/controller/system_helm_reconciler.go index 6e40027c..ff25c480 100644 --- a/internal/controller/system_helm_reconciler.go +++ b/internal/controller/system_helm_reconciler.go @@ -57,11 +57,11 @@ func (r *CozystackConfigReconciler) Reconcile(ctx context.Context, _ ctrl.Reques } patchTarget := hr.DeepCopy() - if hr.Annotations == nil { - hr.Annotations = map[string]string{} + if patchTarget.Annotations == nil { + patchTarget.Annotations = make(map[string]string) } - if hr.Annotations[digestAnnotation] == digest { + if patchTarget.Annotations[digestAnnotation] == digest { continue } patchTarget.Annotations[digestAnnotation] = digest diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index cc1c6f0c..530c06e1 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,5 +1,5 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:latest@sha256:f093adb7d67eaf020b79bd941deeaeb12bd613d871b5e77496702a0e1975d1f0 + image: ghcr.io/cozystack/cozystack/cozystack-controller:latest@sha256:ce9ba2b773ce14cb408ccdd8397cc4d5ae9e6e12e732ff52bc1f18b594730807 debug: false disableTelemetry: false cozystackVersion: "latest" From 7b28139ad97c45e15c1cf045357c7db8792ffc37 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 24 Nov 2025 10:24:27 +0100 Subject: [PATCH 26/46] [platform] Add OCIRegistry with artefacts Signed-off-by: Andrei Kvapil --- Makefile | 4 +- api/v1alpha1/cozystacksystembundles_types.go | 8 +- internal/operator/bundle_reconciler.go | 98 ++-- .../crds/cozystack.io_cozystackbundles.yaml | 1 + .../cozystack-operator/example/platform.yaml | 49 -- packages/core/cozystack-operator/values.yaml | 2 +- packages/core/installer/Chart.yaml | 3 + packages/core/installer/Makefile | 31 ++ .../core/installer/templates/platform.yaml | 51 ++ packages/core/installer/values.yaml | 3 + packages/core/platform/Makefile | 6 +- .../core/platform/bundles/distro-full.yaml | 280 +++++++++++ .../core/platform/bundles/distro-hosted.yaml | 192 ++++++++ .../core/platform/bundles/iaas/bundle.yaml | 72 +-- .../core/platform/bundles/naas/bundle.yaml | 8 +- packages/core/platform/bundles/paas-full.yaml | 461 ++++++++++++++++++ .../core/platform/bundles/paas-hosted.yaml | 274 +++++++++++ .../core/platform/bundles/paas/bundle.yaml | 34 +- .../platform/bundles/system/bundle-full.yaml | 96 ++-- .../bundles/system/bundle-hosted.yaml | 70 +-- .../bundles/system/bundle-minimal.yaml | 12 +- .../platform/templates/migration-hook.yaml | 2 - .../core/platform/templates/platform.yaml | 48 ++ packages/core/platform/templates/version.yaml | 8 + packages/core/platform/values.yaml | 6 +- 25 files changed, 1578 insertions(+), 241 deletions(-) delete mode 100644 packages/core/cozystack-operator/example/platform.yaml create mode 100644 packages/core/installer/Chart.yaml create mode 100644 packages/core/installer/Makefile create mode 100644 packages/core/installer/templates/platform.yaml create mode 100644 packages/core/installer/values.yaml create mode 100644 packages/core/platform/bundles/distro-full.yaml create mode 100644 packages/core/platform/bundles/distro-hosted.yaml create mode 100644 packages/core/platform/bundles/paas-full.yaml create mode 100644 packages/core/platform/bundles/paas-hosted.yaml create mode 100644 packages/core/platform/templates/platform.yaml create mode 100644 packages/core/platform/templates/version.yaml diff --git a/Makefile b/Makefile index 11368365..4290d4cc 100644 --- a/Makefile +++ b/Makefile @@ -29,11 +29,13 @@ build: build-deps make -C packages/core/cozystack-operator image make -C packages/core/talos image make -C packages/core/platform image + make -C packages/core/installer image make manifests manifests: mkdir -p _out/assets - (cd packages/core/cozystack-operator/; helm template -n cozy-installer talos .) > _out/assets/cozystack-installer.yaml + (cd packages/core/cozystack-operator/; helm template -n cozy-system cozystack-operator .) > _out/assets/cozystack-operator.yaml + (cd packages/core/installer/; helm template -n cozy-system installer .) > _out/assets/cozystack-installer.yaml assets: make -C packages/core/talos assets diff --git a/api/v1alpha1/cozystacksystembundles_types.go b/api/v1alpha1/cozystacksystembundles_types.go index a2cf677b..378e23eb 100644 --- a/api/v1alpha1/cozystacksystembundles_types.go +++ b/api/v1alpha1/cozystacksystembundles_types.go @@ -89,6 +89,12 @@ type CozystackBundleSpec struct { // 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. @@ -144,7 +150,7 @@ type BundleArtifact struct { // BundleSourceRef defines the source reference for bundle charts type BundleSourceRef struct { // Kind of the source reference - // +kubebuilder:validation:Enum=GitRepository + // +kubebuilder:validation:Enum=GitRepository;OCIRepository // +required Kind string `json:"kind"` diff --git a/internal/operator/bundle_reconciler.go b/internal/operator/bundle_reconciler.go index af842d1b..7153b384 100644 --- a/internal/operator/bundle_reconciler.go +++ b/internal/operator/bundle_reconciler.go @@ -195,13 +195,6 @@ func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Cont continue } - // Determine prefix from path - prefix := r.getPackagePrefix(pkg.Path) - if prefix == "" { - logger.Info("skipping package with unknown prefix", "name", pkg.Name, "path", pkg.Path) - continue - } - // Extract package name from path (last component) pkgName := r.getPackageNameFromPath(pkg.Path) if pkgName == "" { @@ -209,10 +202,13 @@ func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Cont continue } + // Get basePath with default values + basePath := r.getBasePath(bundle) + // Build copy operations copyOps := []sourcewatcherv1beta1.CopyOperation{ { - From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, pkg.Path), + From: r.buildSourcePath(bundle.Spec.SourceRef.Name, basePath, pkg.Path), To: fmt.Sprintf("@artifact/%s/", pkgName), }, } @@ -221,7 +217,7 @@ func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Cont for _, libName := range pkg.Libraries { if lib, ok := libraryMap[libName]; ok { copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ - From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, lib.Path), + From: r.buildSourcePath(bundle.Spec.SourceRef.Name, basePath, lib.Path), To: fmt.Sprintf("@artifact/%s/charts/%s/", pkgName, libName), }) } @@ -234,7 +230,7 @@ func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Cont strategy = "Overwrite" } copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ - From: fmt.Sprintf("@%s/%s/%s", bundle.Spec.SourceRef.Name, pkg.Path, valuesFile), + From: r.buildSourceFilePath(bundle.Spec.SourceRef.Name, basePath, fmt.Sprintf("%s/%s", pkg.Path, valuesFile)), To: fmt.Sprintf("@artifact/%s/values.yaml", pkgName), Strategy: strategy, }) @@ -261,10 +257,13 @@ func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Cont continue } + // Get basePath with default values + basePath := r.getBasePath(bundle) + // Build copy operations copyOps := []sourcewatcherv1beta1.CopyOperation{ { - From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, artifact.Path), + From: r.buildSourcePath(bundle.Spec.SourceRef.Name, basePath, artifact.Path), To: fmt.Sprintf("@artifact/%s/", artifactPathName), }, } @@ -273,7 +272,7 @@ func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Cont for _, libName := range artifact.Libraries { if lib, ok := libraryMap[libName]; ok { copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ - From: fmt.Sprintf("@%s/%s/**", bundle.Spec.SourceRef.Name, lib.Path), + From: r.buildSourcePath(bundle.Spec.SourceRef.Name, basePath, lib.Path), To: fmt.Sprintf("@artifact/%s/charts/%s/", artifactPathName, libName), }) } @@ -403,10 +402,9 @@ func (r *CozystackBundleReconciler) reconcileHelmReleases(ctx context.Context, b // Artifact name format: {bundle-name}-{artifact-name} artifactName = fmt.Sprintf("%s-%s", bundle.Name, pkg.Artifact) } else if pkg.Path != "" { - // Package uses a path (legacy behavior) - prefix := r.getPackagePrefix(pkg.Path) + // Package uses a path pkgName := r.getPackageNameFromPath(pkg.Path) - if prefix == "" || pkgName == "" { + if pkgName == "" { logger.Info("skipping package with invalid path", "name", pkg.Name, "path", pkg.Path) continue } @@ -573,26 +571,6 @@ func (r *CozystackBundleReconciler) createOrUpdate(ctx context.Context, obj clie } // Helper functions -func (r *CozystackBundleReconciler) getPackagePrefix(path string) string { - if strings.HasPrefix(path, "packages/system/") { - return "system" - } - if strings.HasPrefix(path, "packages/apps/") { - return "apps" - } - if strings.HasPrefix(path, "packages/extra/") { - return "extra" - } - return "" -} - -func (r *CozystackBundleReconciler) getNamespaceForPrefix(prefix string) string { - if prefix == "system" { - return "cozy-system" - } - return "cozy-public" -} - func (r *CozystackBundleReconciler) getPackageNameFromPath(path string) string { parts := strings.Split(path, "/") if len(parts) > 0 { @@ -601,6 +579,56 @@ func (r *CozystackBundleReconciler) getPackageNameFromPath(path string) string { return "" } +// getBasePath returns the basePath with default values based on source kind +func (r *CozystackBundleReconciler) getBasePath(bundle *cozyv1alpha1.CozystackBundle) string { + // If basePath is explicitly set, use it + if bundle.Spec.BasePath != "" { + return bundle.Spec.BasePath + } + // Default values based on kind + if bundle.Spec.SourceRef.Kind == "OCIRepository" { + return "" // Root for OCI + } + // Default for GitRepository + return "packages" +} + +// buildSourcePath builds the full source path using basePath with glob pattern +func (r *CozystackBundleReconciler) buildSourcePath(sourceName, basePath, path string) string { + // Remove leading/trailing slashes and combine + parts := []string{} + if basePath != "" { + parts = append(parts, strings.Trim(basePath, "/")) + } + if path != "" { + parts = append(parts, strings.Trim(path, "/")) + } + + fullPath := strings.Join(parts, "/") + if fullPath == "" { + return fmt.Sprintf("@%s/**", sourceName) + } + return fmt.Sprintf("@%s/%s/**", sourceName, fullPath) +} + +// buildSourceFilePath builds the full source path for a specific file (without glob pattern) +func (r *CozystackBundleReconciler) buildSourceFilePath(sourceName, basePath, path string) string { + // Remove leading/trailing slashes and combine + parts := []string{} + if basePath != "" { + parts = append(parts, strings.Trim(basePath, "/")) + } + if path != "" { + parts = append(parts, strings.Trim(path, "/")) + } + + fullPath := strings.Join(parts, "/") + if fullPath == "" { + return fmt.Sprintf("@%s", sourceName) + } + return fmt.Sprintf("@%s/%s", sourceName, fullPath) +} + func (r *CozystackBundleReconciler) cleanupOrphanedArtifactGenerators(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle) error { logger := log.FromContext(ctx) diff --git a/packages/core/cozystack-operator/crds/cozystack.io_cozystackbundles.yaml b/packages/core/cozystack-operator/crds/cozystack.io_cozystackbundles.yaml index 697c4ac4..cd431eab 100644 --- a/packages/core/cozystack-operator/crds/cozystack.io_cozystackbundles.yaml +++ b/packages/core/cozystack-operator/crds/cozystack.io_cozystackbundles.yaml @@ -212,6 +212,7 @@ spec: description: Kind of the source reference enum: - GitRepository + - OCIRepository type: string name: description: Name of the source reference diff --git a/packages/core/cozystack-operator/example/platform.yaml b/packages/core/cozystack-operator/example/platform.yaml deleted file mode 100644 index fe0653e9..00000000 --- a/packages/core/cozystack-operator/example/platform.yaml +++ /dev/null @@ -1,49 +0,0 @@ ---- -apiVersion: source.toolkit.fluxcd.io/v1 -kind: GitRepository -metadata: - name: cozystack - namespace: cozy-system -spec: - interval: 1m0s - ref: - branch: refactor-engine - timeout: 60s - url: https://github.com/cozystack/cozystack.git ---- -apiVersion: helm.toolkit.fluxcd.io/v2 -kind: HelmRelease -metadata: - name: cozystack-platform - namespace: cozy-system -spec: - interval: 5m - targetNamespace: cozy-system - releaseName: cozystack-platform - chart: - spec: - chart: ./packages/core/platform - sourceRef: - kind: GitRepository - name: cozystack - namespace: cozy-system - values: - sourceRef: - kind: GitRepository - name: cozystack - namespace: cozy-system ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: cozystack - namespace: cozy-system -data: - bundle-name: "paas-full" - root-host: "example.org" - api-server-endpoint: "https://api.example.org:443" - expose-services: "dashboard,api" - ipv4-pod-cidr: "10.244.0.0/16" - ipv4-pod-gateway: "10.244.0.1" - ipv4-svc-cidr: "10.96.0.0/16" - ipv4-join-cidr: "100.64.0.0/16" diff --git a/packages/core/cozystack-operator/values.yaml b/packages/core/cozystack-operator/values.yaml index 05d21e2e..0e43b02c 100644 --- a/packages/core/cozystack-operator/values.yaml +++ b/packages/core/cozystack-operator/values.yaml @@ -1,2 +1,2 @@ cozystackOperator: - image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:5b2de1844a445ad3fa71898a607feca4b346ffc3a2a934809ff096b2eff49218 + image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:9f022d8086226ec3f6885ef3773f96104e7d43daa9f1deaec28e2c56967c60cd diff --git a/packages/core/installer/Chart.yaml b/packages/core/installer/Chart.yaml new file mode 100644 index 00000000..91350467 --- /dev/null +++ b/packages/core/installer/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-installer +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/core/installer/Makefile b/packages/core/installer/Makefile new file mode 100644 index 00000000..5c2e1577 --- /dev/null +++ b/packages/core/installer/Makefile @@ -0,0 +1,31 @@ +NAME=installer +NAMESPACE=cozy-system + +TALOS_VERSION=$(shell awk '/^version:/ {print $$2}' images/talos/profiles/installer.yaml) + +include ../../../scripts/common-envs.mk + +pre-checks: + ../../../hack/pre-checks.sh + +show: + cozypkg show -n $(NAMESPACE) $(NAME) --plain + +apply: + cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f- + +diff: + cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f - + +image: image-packages + +image-packages: + mkdir -p ../../../_out/assets images + flux push artifact \ + oci://$(REGISTRY)/platform-packages:$(call settag,$(TAG)) \ + --path=../../../packages \ + --source=https://github.com/cozystack/cozystack \ + --revision="$$(git describe --tags):$$(git rev-parse HEAD)" \ + 2>&1 | tee images/cozystack-packages.log + DIGEST=$$(awk -F@ '/artifact successfully pushed/ {print $$2}' images/cozystack-packages.log; rm -f images/cozystack-packages.log) \ + yq -i '.packagesDigest = strenv(DIGEST)' values.yaml diff --git a/packages/core/installer/templates/platform.yaml b/packages/core/installer/templates/platform.yaml new file mode 100644 index 00000000..7edbb757 --- /dev/null +++ b/packages/core/installer/templates/platform.yaml @@ -0,0 +1,51 @@ +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: cozystack-packages + namespace: cozy-system +spec: + interval: 5m0s + url: oci://ghcr.io/cozystack/cozystack/platform-packages + ref: + {{- if and .Values.packagesDigest (ne .Values.packagesDigest "") }} + digest: {{ .Values.packagesDigest }} + {{- else }} + tag: latest + {{- end }} +--- +apiVersion: source.extensions.fluxcd.io/v1beta1 +kind: ArtifactGenerator +metadata: + name: cozystack-packages + namespace: cozy-system +spec: + artifacts: + - copy: + - from: '@cozystack/core/platform/**' + to: '@artifact/platform/' + name: cozystack-core-platform + sources: + - alias: cozystack + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system +--- +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: cozystack-platform + namespace: cozy-system +spec: + interval: 5m + targetNamespace: cozy-system + releaseName: cozystack-platform + chartRef: + kind: ExternalArtifact + name: cozystack-core-platform + namespace: cozy-system + values: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml new file mode 100644 index 00000000..22c0e5c3 --- /dev/null +++ b/packages/core/installer/values.yaml @@ -0,0 +1,3 @@ +# Digest for OCIRepository cozystack-packages +# This value is automatically updated by Makefile when building the image +packagesDigest: "sha256:2350d296687097ca6f8b19337d998fdd581f607e454c634a147ef7cb7a3d2800" diff --git a/packages/core/platform/Makefile b/packages/core/platform/Makefile index cd6c0bf4..41b41eb7 100644 --- a/packages/core/platform/Makefile +++ b/packages/core/platform/Makefile @@ -8,12 +8,12 @@ image: image-migrations image-migrations: docker buildx build images/migrations \ - --tag $(REGISTRY)/migrations:$(call settag,$(TAG)) \ - --cache-from type=registry,ref=$(REGISTRY)/migrations:latest \ + --tag $(REGISTRY)/platform-migrations:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/platform-migrations:latest \ --cache-to type=inline \ --metadata-file images/migrations.json \ $(BUILDX_ARGS) - IMAGE="$(REGISTRY)/migrations:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/migrations.json -o json -r)" \ + IMAGE="$(REGISTRY)/platform-migrations:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/migrations.json -o json -r)" \ yq -i '.migrations.image = strenv(IMAGE)' values.yaml rm -f images/migrations.json diff --git a/packages/core/platform/bundles/distro-full.yaml b/packages/core/platform/bundles/distro-full.yaml new file mode 100644 index 00000000..ed52a83a --- /dev/null +++ b/packages/core/platform/bundles/distro-full.yaml @@ -0,0 +1,280 @@ +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} + +releases: +- name: fluxcd-operator + releaseName: fluxcd-operator + chart: cozy-fluxcd-operator + namespace: cozy-fluxcd + privileged: true + dependsOn: [] + +- name: fluxcd + releaseName: fluxcd + chart: cozy-fluxcd + namespace: cozy-fluxcd + dependsOn: [fluxcd-operator,cilium] + values: + flux-instance: + instance: + cluster: + domain: {{ $clusterDomain }} + +- name: cilium + releaseName: cilium + chart: cozy-cilium + namespace: cozy-cilium + privileged: true + dependsOn: [] + valuesFiles: + - values.yaml + - values-talos.yaml + values: + cilium: + enableIPv4Masquerade: true + enableIdentityMark: true + ipv4NativeRoutingCIDR: "{{ index $cozyConfig.data "ipv4-pod-cidr" }}" + autoDirectNodeRoutes: true + routingMode: native + +- name: cilium-networkpolicy + releaseName: cilium-networkpolicy + chart: cozy-cilium-networkpolicy + namespace: cozy-cilium + privileged: true + dependsOn: [cilium] + +- name: cozy-proxy + releaseName: cozystack + chart: cozy-cozy-proxy + namespace: cozy-system + optional: true + dependsOn: [cilium] + +- name: cert-manager-crds + releaseName: cert-manager-crds + chart: cozy-cert-manager-crds + namespace: cozy-cert-manager + dependsOn: [cilium] + +- name: cozystack-controller + releaseName: cozystack-controller + chart: cozy-cozystack-controller + namespace: cozy-system + dependsOn: [cilium] + {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} + values: + cozystackController: + disableTelemetry: true + {{- end }} + +- name: lineage-controller-webhook + releaseName: lineage-controller-webhook + chart: cozy-lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller,cilium,cert-manager] + +- name: cert-manager + releaseName: cert-manager + chart: cozy-cert-manager + namespace: cozy-cert-manager + dependsOn: [cert-manager-crds] + +- name: cert-manager-issuers + releaseName: cert-manager-issuers + chart: cozy-cert-manager-issuers + namespace: cozy-cert-manager + optional: true + dependsOn: [cilium,cert-manager] + +- name: victoria-metrics-operator + releaseName: victoria-metrics-operator + chart: cozy-victoria-metrics-operator + namespace: cozy-victoria-metrics-operator + optional: true + dependsOn: [cilium,cert-manager] + +- name: monitoring-agents + releaseName: monitoring-agents + chart: cozy-monitoring-agents + namespace: cozy-monitoring + privileged: true + optional: true + dependsOn: [cilium,victoria-metrics-operator] + values: + scrapeRules: + etcd: + enabled: true + +- name: metallb + releaseName: metallb + chart: cozy-metallb + namespace: cozy-metallb + privileged: true + dependsOn: [cilium] + +- name: etcd-operator + releaseName: etcd-operator + chart: cozy-etcd-operator + namespace: cozy-etcd-operator + optional: true + dependsOn: [cilium,cert-manager] + +- name: grafana-operator + releaseName: grafana-operator + chart: cozy-grafana-operator + namespace: cozy-grafana-operator + optional: true + dependsOn: [cilium] + +- name: mariadb-operator + releaseName: mariadb-operator + chart: cozy-mariadb-operator + namespace: cozy-mariadb-operator + optional: true + dependsOn: [cilium,cert-manager,victoria-metrics-operator] + values: + mariadb-operator: + clusterName: {{ $clusterDomain }} + +- name: postgres-operator + releaseName: postgres-operator + chart: cozy-postgres-operator + namespace: cozy-postgres-operator + optional: true + dependsOn: [cilium,cert-manager,victoria-metrics-operator] + +- name: kafka-operator + releaseName: kafka-operator + chart: cozy-kafka-operator + namespace: cozy-kafka-operator + optional: true + dependsOn: [cilium,victoria-metrics-operator] + values: + strimzi-kafka-operator: + kubernetesServiceDnsDomain: {{ $clusterDomain }} + +- name: clickhouse-operator + releaseName: clickhouse-operator + chart: cozy-clickhouse-operator + namespace: cozy-clickhouse-operator + optional: true + dependsOn: [cilium,victoria-metrics-operator] + +- name: foundationdb-operator + releaseName: foundationdb-operator + chart: cozy-foundationdb-operator + namespace: cozy-foundationdb-operator + optional: true + dependsOn: [cilium,cert-manager] + +- name: rabbitmq-operator + releaseName: rabbitmq-operator + chart: cozy-rabbitmq-operator + namespace: cozy-rabbitmq-operator + optional: true + dependsOn: [cilium] + +- name: redis-operator + releaseName: redis-operator + chart: cozy-redis-operator + namespace: cozy-redis-operator + optional: true + dependsOn: [cilium] + +- name: piraeus-operator + releaseName: piraeus-operator + chart: cozy-piraeus-operator + namespace: cozy-linstor + dependsOn: [cilium,cert-manager] + +- name: snapshot-controller + releaseName: snapshot-controller + chart: cozy-snapshot-controller + namespace: cozy-snapshot-controller + dependsOn: [cilium] + +- name: objectstorage-controller + releaseName: objectstorage-controller + chart: cozy-objectstorage-controller + namespace: cozy-objectstorage-controller + optional: true + dependsOn: [cilium] + +- name: linstor + releaseName: linstor + chart: cozy-linstor + namespace: cozy-linstor + privileged: true + dependsOn: [piraeus-operator,cilium,cert-manager,snapshot-controller] + +- name: nfs-driver + releaseName: nfs-driver + chart: cozy-nfs-driver + namespace: cozy-nfs-driver + privileged: true + dependsOn: [cilium] + optional: true + +- name: telepresence + releaseName: traffic-manager + chart: cozy-telepresence + namespace: cozy-telepresence + optional: true + dependsOn: [] + +- name: external-dns + releaseName: external-dns + chart: cozy-external-dns + namespace: cozy-external-dns + optional: true + dependsOn: [cilium] + +- name: external-secrets-operator + releaseName: external-secrets-operator + chart: cozy-external-secrets-operator + namespace: cozy-external-secrets-operator + optional: true + dependsOn: [cilium] + +- name: keycloak + releaseName: keycloak + chart: cozy-keycloak + namespace: cozy-keycloak + optional: true + dependsOn: [postgres-operator] + +- name: keycloak-operator + releaseName: keycloak-operator + chart: cozy-keycloak-operator + namespace: cozy-keycloak + optional: true + dependsOn: [keycloak] + +- name: bootbox + releaseName: bootbox + chart: cozy-bootbox + namespace: cozy-bootbox + privileged: true + optional: true + dependsOn: [cilium] + +- name: reloader + releaseName: reloader + chart: cozy-reloader + namespace: cozy-reloader + +- name: velero + releaseName: velero + chart: cozy-velero + namespace: cozy-velero + privileged: true + optional: true + dependsOn: [cilium] + +- name: hetzner-robotlb + releaseName: robotlb + optional: true + chart: cozy-hetzner-robotlb + namespace: cozy-hetzner-robotlb + dependsOn: [cilium] diff --git a/packages/core/platform/bundles/distro-hosted.yaml b/packages/core/platform/bundles/distro-hosted.yaml new file mode 100644 index 00000000..83aa81d9 --- /dev/null +++ b/packages/core/platform/bundles/distro-hosted.yaml @@ -0,0 +1,192 @@ +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} + +releases: +- name: fluxcd-operator + releaseName: fluxcd-operator + chart: cozy-fluxcd-operator + namespace: cozy-fluxcd + privileged: true + dependsOn: [] + +- name: fluxcd + releaseName: fluxcd + chart: cozy-fluxcd + namespace: cozy-fluxcd + dependsOn: [fluxcd-operator] + values: + flux-instance: + instance: + cluster: + domain: {{ $clusterDomain }} + +- name: cert-manager-crds + releaseName: cert-manager-crds + chart: cozy-cert-manager-crds + namespace: cozy-cert-manager + dependsOn: [] + +- name: cozystack-controller + releaseName: cozystack-controller + chart: cozy-cozystack-controller + namespace: cozy-system + {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} + values: + cozystackController: + disableTelemetry: true + {{- end }} + +- name: lineage-controller-webhook + releaseName: lineage-controller-webhook + chart: cozy-lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller,cert-manager] + +- name: cert-manager + releaseName: cert-manager + chart: cozy-cert-manager + namespace: cozy-cert-manager + dependsOn: [cert-manager-crds] + +- name: cert-manager-issuers + releaseName: cert-manager-issuers + chart: cozy-cert-manager-issuers + namespace: cozy-cert-manager + optional: true + dependsOn: [cert-manager] + +- name: victoria-metrics-operator + releaseName: victoria-metrics-operator + chart: cozy-victoria-metrics-operator + namespace: cozy-victoria-metrics-operator + optional: true + dependsOn: [cert-manager] + +- name: monitoring-agents + releaseName: monitoring-agents + chart: cozy-monitoring-agents + namespace: cozy-monitoring + privileged: true + optional: true + dependsOn: [victoria-metrics-operator] + values: + scrapeRules: + etcd: + enabled: true + +- name: etcd-operator + releaseName: etcd-operator + chart: cozy-etcd-operator + namespace: cozy-etcd-operator + optional: true + dependsOn: [cert-manager] + +- name: grafana-operator + releaseName: grafana-operator + chart: cozy-grafana-operator + namespace: cozy-grafana-operator + optional: true + dependsOn: [] + +- name: mariadb-operator + releaseName: mariadb-operator + chart: cozy-mariadb-operator + namespace: cozy-mariadb-operator + optional: true + dependsOn: [victoria-metrics-operator] + values: + mariadb-operator: + clusterName: {{ $clusterDomain }} + +- name: postgres-operator + releaseName: postgres-operator + chart: cozy-postgres-operator + namespace: cozy-postgres-operator + optional: true + dependsOn: [victoria-metrics-operator] + +- name: kafka-operator + releaseName: kafka-operator + chart: cozy-kafka-operator + namespace: cozy-kafka-operator + optional: true + dependsOn: [victoria-metrics-operator] + values: + strimzi-kafka-operator: + kubernetesServiceDnsDomain: {{ $clusterDomain }} + +- name: clickhouse-operator + releaseName: clickhouse-operator + chart: cozy-clickhouse-operator + namespace: cozy-clickhouse-operator + optional: true + dependsOn: [victoria-metrics-operator] + +- name: foundationdb-operator + releaseName: foundationdb-operator + chart: cozy-foundationdb-operator + namespace: cozy-foundationdb-operator + optional: true + dependsOn: [cert-manager] + +- name: rabbitmq-operator + releaseName: rabbitmq-operator + chart: cozy-rabbitmq-operator + namespace: cozy-rabbitmq-operator + optional: true + dependsOn: [] + +- name: redis-operator + releaseName: redis-operator + chart: cozy-redis-operator + namespace: cozy-redis-operator + optional: true + dependsOn: [] + +- name: telepresence + releaseName: traffic-manager + chart: cozy-telepresence + namespace: cozy-telepresence + optional: true + dependsOn: [] + +- name: external-dns + releaseName: external-dns + chart: cozy-external-dns + namespace: cozy-external-dns + optional: true + dependsOn: [] + +- name: external-secrets-operator + releaseName: external-secrets-operator + chart: cozy-external-secrets-operator + namespace: cozy-external-secrets-operator + optional: true + dependsOn: [] + +- name: keycloak + releaseName: keycloak + chart: cozy-keycloak + namespace: cozy-keycloak + optional: true + dependsOn: [postgres-operator] + +- name: keycloak-operator + releaseName: keycloak-operator + chart: cozy-keycloak-operator + namespace: cozy-keycloak + optional: true + dependsOn: [keycloak] + +- name: velero + releaseName: velero + chart: cozy-velero + namespace: cozy-velero + privileged: true + optional: true + +- name: hetzner-robotlb + releaseName: robotlb + optional: true + chart: cozy-hetzner-robotlb + namespace: cozy-hetzner-robotlb diff --git a/packages/core/platform/bundles/iaas/bundle.yaml b/packages/core/platform/bundles/iaas/bundle.yaml index 77831cb4..b070fa07 100644 --- a/packages/core/platform/bundles/iaas/bundle.yaml +++ b/packages/core/platform/bundles/iaas/bundle.yaml @@ -24,78 +24,78 @@ spec: libraries: - name: cozy-lib - path: packages/library/cozy-lib + path: library/cozy-lib artifacts: - name: bucket - path: packages/apps/bucket + path: apps/bucket libraries: [cozy-lib] - name: bucket-system - path: packages/apps/bucket + path: apps/bucket libraries: [cozy-lib] - name: kubernetes - path: packages/apps/kubernetes + path: apps/kubernetes libraries: [cozy-lib] - name: kubernetes-ingress-nginx - path: packages/system/ingress-nginx + path: system/ingress-nginx - name: kubernetes-cert-manager-crds - path: packages/system/cert-manager-crds + path: system/cert-manager-crds - name: kubernetes-volumesnapshot-crd - path: packages/system/vsnap-crd + path: system/vsnap-crd - name: kubernetes-velero - path: packages/system/velero + path: system/velero - name: kubernetes-gateway-api-crds - path: packages/system/gateway-api-crds + path: system/gateway-api-crds - name: kubernetes-victoria-metrics-operator - path: packages/system/victoria-metrics-operator + path: system/victoria-metrics-operator - name: kubernetes-kubevirt-csi-node - path: packages/system/kubevirt-csi-node + path: system/kubevirt-csi-node - name: kubernetes-vertical-pod-autoscaler-crds - path: packages/system/vertical-pod-autoscaler-crds + path: system/vertical-pod-autoscaler-crds - name: kubernetes-coredns - path: packages/system/coredns + path: system/coredns - name: kubernetes-cert-manager - path: packages/system/cert-manager + path: system/cert-manager - name: kubernetes-fluxcd-operator - path: packages/system/fluxcd-operator + path: system/fluxcd-operator - name: kubernetes-fluxcd - path: packages/system/fluxcd + path: system/fluxcd - name: kubernetes-monitoring-agents - path: packages/system/monitoring-agents + path: system/monitoring-agents - name: kubernetes-cilium - path: packages/system/cilium + path: system/cilium - name: kubernetes-gpu-operator - path: packages/system/gpu-operator + path: system/gpu-operator - name: kubernetes-vertical-pod-autoscaler - path: packages/system/vertical-pod-autoscaler + path: system/vertical-pod-autoscaler - name: virtual-machine - path: packages/apps/virtual-machine + path: apps/virtual-machine libraries: [cozy-lib] - name: vpc - path: packages/apps/vpc + path: apps/vpc libraries: [cozy-lib] - name: vm-disk - path: packages/apps/vm-disk + path: apps/vm-disk libraries: [cozy-lib] - name: vm-instance - path: packages/apps/vm-instance + path: apps/vm-instance libraries: [cozy-lib] packages: - name: kubevirt-operator releaseName: kubevirt-operator - path: packages/system/kubevirt-operator + path: system/kubevirt-operator namespace: cozy-kubevirt dependsOn: [victoria-metrics-operator] - name: kubevirt releaseName: kubevirt - path: packages/system/kubevirt + path: system/kubevirt namespace: cozy-kubevirt privileged: true dependsOn: [kubevirt-operator] @@ -107,25 +107,25 @@ spec: - name: kubevirt-instancetypes releaseName: kubevirt-instancetypes - path: packages/system/kubevirt-instancetypes + path: system/kubevirt-instancetypes namespace: cozy-kubevirt dependsOn: [kubevirt-operator,kubevirt] - name: kubevirt-cdi-operator releaseName: kubevirt-cdi-operator - path: packages/system/kubevirt-cdi-operator + path: system/kubevirt-cdi-operator namespace: cozy-kubevirt-cdi dependsOn: [] - name: kubevirt-cdi releaseName: kubevirt-cdi - path: packages/system/kubevirt-cdi + path: system/kubevirt-cdi namespace: cozy-kubevirt-cdi dependsOn: [kubevirt-cdi-operator] - name: gpu-operator releaseName: gpu-operator - path: packages/system/gpu-operator + path: system/gpu-operator namespace: cozy-gpu-operator privileged: true disabled: true @@ -136,41 +136,41 @@ spec: - name: kamaji releaseName: kamaji - path: packages/system/kamaji + path: system/kamaji namespace: cozy-kamaji dependsOn: [] - name: capi-operator releaseName: capi-operator - path: packages/system/capi-operator + path: system/capi-operator namespace: cozy-cluster-api privileged: true dependsOn: [] - name: capi-providers-bootstrap releaseName: capi-providers-bootstrap - path: packages/system/capi-providers-bootstrap + path: system/capi-providers-bootstrap namespace: cozy-cluster-api privileged: true dependsOn: [capi-operator] - name: capi-providers-core releaseName: capi-providers-core - path: packages/system/capi-providers-core + path: system/capi-providers-core namespace: cozy-cluster-api privileged: true dependsOn: [capi-operator] - name: capi-providers-cpprovider releaseName: capi-providers-cpprovider - path: packages/system/capi-providers-cpprovider + path: system/capi-providers-cpprovider namespace: cozy-cluster-api privileged: true dependsOn: [capi-operator] - name: capi-providers-infraprovider releaseName: capi-providers-infraprovider - path: packages/system/capi-providers-infraprovider + path: system/capi-providers-infraprovider namespace: cozy-cluster-api privileged: true dependsOn: [capi-operator] diff --git a/packages/core/platform/bundles/naas/bundle.yaml b/packages/core/platform/bundles/naas/bundle.yaml index 84550e17..a208c4be 100644 --- a/packages/core/platform/bundles/naas/bundle.yaml +++ b/packages/core/platform/bundles/naas/bundle.yaml @@ -12,19 +12,19 @@ spec: libraries: - name: cozy-lib - path: packages/library/cozy-lib + path: library/cozy-lib artifacts: - name: http-cache - path: packages/apps/http-cache + path: apps/http-cache libraries: [cozy-lib] - name: tcp-balancer - path: packages/apps/tcp-balancer + path: apps/tcp-balancer libraries: [cozy-lib] - name: vpn - path: packages/apps/vpn + path: apps/vpn libraries: [cozy-lib] packages: [] diff --git a/packages/core/platform/bundles/paas-full.yaml b/packages/core/platform/bundles/paas-full.yaml new file mode 100644 index 00000000..4382bd62 --- /dev/null +++ b/packages/core/platform/bundles/paas-full.yaml @@ -0,0 +1,461 @@ +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} +{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} +{{- $host := index $cozyConfig.data "root-host" }} +{{- if not $host }} +{{- fail "ERROR need root-host in cozystack ConfigMap" }} +{{- end }} +{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} +{{- if not $apiServerEndpoint }} +{{- fail "ERROR need api-server-endpoint in cozystack ConfigMap" }} +{{- end }} + +releases: +- name: fluxcd-operator + releaseName: fluxcd-operator + chart: cozy-fluxcd-operator + namespace: cozy-fluxcd + privileged: true + dependsOn: [] + +- name: fluxcd + releaseName: fluxcd + chart: cozy-fluxcd + namespace: cozy-fluxcd + dependsOn: [fluxcd-operator,cilium,kubeovn] + values: + flux-instance: + instance: + cluster: + domain: {{ $clusterDomain }} + +- name: cilium + releaseName: cilium + chart: cozy-cilium + namespace: cozy-cilium + privileged: true + dependsOn: [] + valuesFiles: + - values.yaml + - values-talos.yaml + - values-kubeovn.yaml + +- name: cilium-networkpolicy + releaseName: cilium-networkpolicy + chart: cozy-cilium-networkpolicy + namespace: cozy-cilium + privileged: true + dependsOn: [cilium] + +- name: kubeovn + releaseName: kubeovn + chart: cozy-kubeovn + namespace: cozy-kubeovn + privileged: true + dependsOn: [cilium] + values: + cozystack: + nodesHash: {{ include "cozystack.master-node-ips" . | sha256sum }} + kube-ovn: + ipv4: + POD_CIDR: "{{ index $cozyConfig.data "ipv4-pod-cidr" }}" + POD_GATEWAY: "{{ index $cozyConfig.data "ipv4-pod-gateway" }}" + SVC_CIDR: "{{ index $cozyConfig.data "ipv4-svc-cidr" }}" + JOIN_CIDR: "{{ index $cozyConfig.data "ipv4-join-cidr" }}" + +- name: kubeovn-webhook + releaseName: kubeovn-webhook + chart: cozy-kubeovn-webhook + namespace: cozy-kubeovn + privileged: true + dependsOn: [cilium,kubeovn,cert-manager] + +- name: kubeovn-plunger + releaseName: kubeovn-plunger + chart: cozy-kubeovn-plunger + namespace: cozy-kubeovn + dependsOn: [cilium,kubeovn] + +- name: multus + releaseName: multus + chart: cozy-multus + namespace: cozy-multus + privileged: true + dependsOn: [cilium,kubeovn] + +- name: cozy-proxy + releaseName: cozystack + chart: cozy-cozy-proxy + namespace: cozy-system + dependsOn: [cilium,kubeovn] + +- name: cert-manager-crds + releaseName: cert-manager-crds + chart: cozy-cert-manager-crds + namespace: cozy-cert-manager + dependsOn: [cilium, kubeovn] + +- name: cozystack-api + releaseName: cozystack-api + chart: cozy-cozystack-api + namespace: cozy-system + dependsOn: [cilium,kubeovn,cozystack-controller] + +- name: cozystack-controller + releaseName: cozystack-controller + chart: cozy-cozystack-controller + namespace: cozy-system + dependsOn: [cilium,kubeovn] + {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} + values: + cozystackController: + disableTelemetry: true + {{- end }} + +- name: lineage-controller-webhook + releaseName: lineage-controller-webhook + chart: cozy-lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller,cilium,kubeovn,cert-manager] + +- name: cozystack-resource-definition-crd + releaseName: cozystack-resource-definition-crd + chart: cozystack-resource-definition-crd + namespace: cozy-system + dependsOn: [cilium,kubeovn,cozystack-api,cozystack-controller] + +- name: cozystack-resource-definitions + releaseName: cozystack-resource-definitions + chart: cozystack-resource-definitions + namespace: cozy-system + dependsOn: [cilium,kubeovn,cozystack-api,cozystack-controller,cozystack-resource-definition-crd] + +- name: cert-manager + releaseName: cert-manager + chart: cozy-cert-manager + namespace: cozy-cert-manager + dependsOn: [cert-manager-crds] + +- name: cert-manager-issuers + releaseName: cert-manager-issuers + chart: cozy-cert-manager-issuers + namespace: cozy-cert-manager + dependsOn: [cilium,kubeovn,cert-manager] + +- name: victoria-metrics-operator + releaseName: victoria-metrics-operator + chart: cozy-victoria-metrics-operator + namespace: cozy-victoria-metrics-operator + dependsOn: [cilium,kubeovn,cert-manager] + +- name: monitoring-agents + releaseName: monitoring-agents + chart: cozy-monitoring-agents + namespace: cozy-monitoring + privileged: true + dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] + values: + scrapeRules: + etcd: + enabled: true + +- name: kubevirt-operator + releaseName: kubevirt-operator + chart: cozy-kubevirt-operator + namespace: cozy-kubevirt + dependsOn: [cilium,kubeovn,victoria-metrics-operator] + +- name: kubevirt + releaseName: kubevirt + chart: cozy-kubevirt + namespace: cozy-kubevirt + privileged: true + dependsOn: [cilium,kubeovn,kubevirt-operator] + {{- $cpuAllocationRatio := index $cozyConfig.data "cpu-allocation-ratio" }} + {{- if $cpuAllocationRatio }} + values: + cpuAllocationRatio: {{ $cpuAllocationRatio }} + {{- end }} + +- name: kubevirt-instancetypes + releaseName: kubevirt-instancetypes + chart: cozy-kubevirt-instancetypes + namespace: cozy-kubevirt + dependsOn: [cilium,kubeovn,kubevirt-operator,kubevirt] + +- name: kubevirt-cdi-operator + releaseName: kubevirt-cdi-operator + chart: cozy-kubevirt-cdi-operator + namespace: cozy-kubevirt-cdi + dependsOn: [cilium,kubeovn] + +- name: kubevirt-cdi + releaseName: kubevirt-cdi + chart: cozy-kubevirt-cdi + namespace: cozy-kubevirt-cdi + dependsOn: [cilium,kubeovn,kubevirt-cdi-operator] + +- name: gpu-operator + releaseName: gpu-operator + chart: cozy-gpu-operator + namespace: cozy-gpu-operator + privileged: true + optional: true + dependsOn: [cilium,kubeovn] + valuesFiles: + - values.yaml + - values-talos.yaml + +- name: metallb + releaseName: metallb + chart: cozy-metallb + namespace: cozy-metallb + privileged: true + dependsOn: [cilium,kubeovn] + +- name: etcd-operator + releaseName: etcd-operator + chart: cozy-etcd-operator + namespace: cozy-etcd-operator + dependsOn: [cilium,kubeovn,cert-manager] + +- name: grafana-operator + releaseName: grafana-operator + chart: cozy-grafana-operator + namespace: cozy-grafana-operator + dependsOn: [cilium,kubeovn] + +- name: mariadb-operator + releaseName: mariadb-operator + chart: cozy-mariadb-operator + namespace: cozy-mariadb-operator + dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] + values: + mariadb-operator: + clusterName: {{ $clusterDomain }} + +- name: postgres-operator + releaseName: postgres-operator + chart: cozy-postgres-operator + namespace: cozy-postgres-operator + dependsOn: [cilium,kubeovn,cert-manager] + +- name: kafka-operator + releaseName: kafka-operator + chart: cozy-kafka-operator + namespace: cozy-kafka-operator + dependsOn: [cilium,kubeovn,victoria-metrics-operator] + values: + strimzi-kafka-operator: + kubernetesServiceDnsDomain: {{ $clusterDomain }} + +- name: clickhouse-operator + releaseName: clickhouse-operator + chart: cozy-clickhouse-operator + namespace: cozy-clickhouse-operator + dependsOn: [cilium,kubeovn,victoria-metrics-operator] + +- name: foundationdb-operator + releaseName: foundationdb-operator + chart: cozy-foundationdb-operator + namespace: cozy-foundationdb-operator + dependsOn: [cilium,kubeovn,cert-manager] + +- name: rabbitmq-operator + releaseName: rabbitmq-operator + chart: cozy-rabbitmq-operator + namespace: cozy-rabbitmq-operator + dependsOn: [cilium,kubeovn] + +- name: redis-operator + releaseName: redis-operator + chart: cozy-redis-operator + namespace: cozy-redis-operator + dependsOn: [cilium,kubeovn] + +- name: piraeus-operator + releaseName: piraeus-operator + chart: cozy-piraeus-operator + namespace: cozy-linstor + dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] + +- name: linstor + releaseName: linstor + chart: cozy-linstor + namespace: cozy-linstor + privileged: true + dependsOn: [piraeus-operator,cilium,kubeovn,cert-manager,snapshot-controller] + +- name: nfs-driver + releaseName: nfs-driver + chart: cozy-nfs-driver + namespace: cozy-nfs-driver + privileged: true + dependsOn: [cilium,kubeovn] + optional: true + +- name: snapshot-controller + releaseName: snapshot-controller + chart: cozy-snapshot-controller + namespace: cozy-snapshot-controller + dependsOn: [cilium,kubeovn,cert-manager-issuers] + +- name: objectstorage-controller + releaseName: objectstorage-controller + chart: cozy-objectstorage-controller + namespace: cozy-objectstorage-controller + dependsOn: [cilium,kubeovn] + +- name: telepresence + releaseName: traffic-manager + chart: cozy-telepresence + namespace: cozy-telepresence + optional: true + dependsOn: [cilium,kubeovn] + +- name: dashboard + releaseName: dashboard + chart: cozy-dashboard + namespace: cozy-dashboard + values: + {{- $dashboardKCconfig := lookup "v1" "ConfigMap" "cozy-dashboard" "kubeapps-auth-config" }} + {{- $dashboardKCValues := dig "data" "values.yaml" "" $dashboardKCconfig | fromYaml }} + {{- toYaml (deepCopy $dashboardKCValues | mergeOverwrite (fromYaml (include "cozystack.defaultDashboardValues" .))) | nindent 4 }} + dependsOn: + - cilium + - kubeovn + {{- if eq $oidcEnabled "true" }} + - keycloak-configure + {{- end }} + +- name: kamaji + releaseName: kamaji + chart: cozy-kamaji + namespace: cozy-kamaji + dependsOn: [cilium,kubeovn,cert-manager] + +- name: capi-operator + releaseName: capi-operator + chart: cozy-capi-operator + namespace: cozy-cluster-api + privileged: true + dependsOn: [cilium,kubeovn,cert-manager] + +- name: capi-providers-bootstrap + releaseName: capi-providers-bootstrap + chart: cozy-capi-providers-bootstrap + namespace: cozy-cluster-api + privileged: true + dependsOn: [cilium,kubeovn,capi-operator] + +- name: capi-providers-core + releaseName: capi-providers-core + chart: cozy-capi-providers-core + namespace: cozy-cluster-api + privileged: true + dependsOn: [cilium,kubeovn,capi-operator] + +- name: capi-providers-cpprovider + releaseName: capi-providers-cpprovider + chart: cozy-capi-providers-cpprovider + namespace: cozy-cluster-api + privileged: true + dependsOn: [cilium,kubeovn,capi-operator] + +- name: capi-providers-infraprovider + releaseName: capi-providers-infraprovider + chart: cozy-capi-providers-infraprovider + namespace: cozy-cluster-api + privileged: true + dependsOn: [cilium,kubeovn,capi-operator] + +- name: external-dns + releaseName: external-dns + chart: cozy-external-dns + namespace: cozy-external-dns + optional: true + dependsOn: [cilium,kubeovn] + +- name: external-secrets-operator + releaseName: external-secrets-operator + chart: cozy-external-secrets-operator + namespace: cozy-external-secrets-operator + optional: true + dependsOn: [cilium,kubeovn] + +- name: bootbox + releaseName: bootbox + chart: cozy-bootbox + namespace: cozy-bootbox + privileged: true + optional: true + dependsOn: [cilium,kubeovn] + +{{- if $oidcEnabled }} +- name: keycloak + releaseName: keycloak + chart: cozy-keycloak + namespace: cozy-keycloak + dependsOn: [postgres-operator] + +- name: keycloak-operator + releaseName: keycloak-operator + chart: cozy-keycloak-operator + namespace: cozy-keycloak + dependsOn: [keycloak] + +- name: keycloak-configure + releaseName: keycloak-configure + chart: cozy-keycloak-configure + namespace: cozy-keycloak + dependsOn: [keycloak-operator] + values: + cozystack: + configHash: {{ $cozyConfig | toJson | sha256sum }} +{{- end }} + +- name: goldpinger + releaseName: goldpinger + chart: cozy-goldpinger + namespace: cozy-goldpinger + privileged: true + dependsOn: [monitoring-agents] + +- name: vertical-pod-autoscaler + releaseName: vertical-pod-autoscaler + chart: cozy-vertical-pod-autoscaler + namespace: cozy-vertical-pod-autoscaler + privileged: true + dependsOn: [monitoring-agents] + values: + vertical-pod-autoscaler: + recommender: + extraArgs: + prometheus-address: http://vmselect-shortterm.tenant-root.svc.{{ $clusterDomain }}:8481/select/0/prometheus/ + +- name: vertical-pod-autoscaler-crds + releaseName: vertical-pod-autoscaler-crds + chart: cozy-vertical-pod-autoscaler-crds + namespace: cozy-vertical-pod-autoscaler + privileged: true + dependsOn: [cilium, kubeovn] + +- name: reloader + releaseName: reloader + chart: cozy-reloader + namespace: cozy-reloader + +- name: velero + releaseName: velero + chart: cozy-velero + namespace: cozy-velero + privileged: true + optional: true + dependsOn: [monitoring-agents] + +- name: hetzner-robotlb + releaseName: robotlb + optional: true + chart: cozy-hetzner-robotlb + namespace: cozy-hetzner-robotlb + dependsOn: [cilium, kubeovn] diff --git a/packages/core/platform/bundles/paas-hosted.yaml b/packages/core/platform/bundles/paas-hosted.yaml new file mode 100644 index 00000000..560578c7 --- /dev/null +++ b/packages/core/platform/bundles/paas-hosted.yaml @@ -0,0 +1,274 @@ +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} +{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} +{{- $host := index $cozyConfig.data "root-host" }} +{{- if not $host }} +{{- fail "ERROR need root-host in cozystack ConfigMap" }} +{{- end }} +{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} +{{- if not $apiServerEndpoint }} +{{- fail "ERROR need api-server-endpoint in cozystack ConfigMap" }} +{{- end }} + +releases: +- name: fluxcd-operator + releaseName: fluxcd-operator + chart: cozy-fluxcd-operator + namespace: cozy-fluxcd + privileged: true + dependsOn: [] + +- name: fluxcd + releaseName: fluxcd + chart: cozy-fluxcd + namespace: cozy-fluxcd + dependsOn: [fluxcd-operator] + values: + flux-instance: + instance: + cluster: + domain: {{ $clusterDomain }} + +- name: cert-manager-crds + releaseName: cert-manager-crds + chart: cozy-cert-manager-crds + namespace: cozy-cert-manager + dependsOn: [] + +- name: cozystack-api + releaseName: cozystack-api + chart: cozy-cozystack-api + namespace: cozy-system + dependsOn: [cozystack-controller] + values: + cozystackAPI: + localK8sAPIEndpoint: + enabled: false + +- name: cozystack-controller + releaseName: cozystack-controller + chart: cozy-cozystack-controller + namespace: cozy-system + dependsOn: [] + {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} + values: + cozystackController: + disableTelemetry: true + {{- end }} + +- name: lineage-controller-webhook + releaseName: lineage-controller-webhook + chart: cozy-lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller,cert-manager] + +- name: cozystack-resource-definition-crd + releaseName: cozystack-resource-definition-crd + chart: cozystack-resource-definition-crd + namespace: cozy-system + dependsOn: [cozystack-api,cozystack-controller] + +- name: cozystack-resource-definitions + releaseName: cozystack-resource-definitions + chart: cozystack-resource-definitions + namespace: cozy-system + dependsOn: [cozystack-api,cozystack-controller,cozystack-resource-definition-crd] + +- name: cert-manager + releaseName: cert-manager + chart: cozy-cert-manager + namespace: cozy-cert-manager + dependsOn: [cert-manager-crds] + +- name: cert-manager-issuers + releaseName: cert-manager-issuers + chart: cozy-cert-manager-issuers + namespace: cozy-cert-manager + dependsOn: [cert-manager] + +- name: victoria-metrics-operator + releaseName: victoria-metrics-operator + chart: cozy-victoria-metrics-operator + namespace: cozy-victoria-metrics-operator + dependsOn: [cert-manager] + +- name: monitoring-agents + releaseName: monitoring-agents + chart: cozy-monitoring-agents + namespace: cozy-monitoring + privileged: true + dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] + values: + scrapeRules: + etcd: + enabled: true + +- name: etcd-operator + releaseName: etcd-operator + chart: cozy-etcd-operator + namespace: cozy-etcd-operator + dependsOn: [cert-manager] + +- name: grafana-operator + releaseName: grafana-operator + chart: cozy-grafana-operator + namespace: cozy-grafana-operator + dependsOn: [] + +- name: mariadb-operator + releaseName: mariadb-operator + chart: cozy-mariadb-operator + namespace: cozy-mariadb-operator + dependsOn: [cert-manager,victoria-metrics-operator] + values: + mariadb-operator: + clusterName: {{ $clusterDomain }} + +- name: postgres-operator + releaseName: postgres-operator + chart: cozy-postgres-operator + namespace: cozy-postgres-operator + dependsOn: [cert-manager,victoria-metrics-operator] + +- name: kafka-operator + releaseName: kafka-operator + chart: cozy-kafka-operator + namespace: cozy-kafka-operator + dependsOn: [victoria-metrics-operator] + values: + strimzi-kafka-operator: + kubernetesServiceDnsDomain: {{ $clusterDomain }} + +- name: clickhouse-operator + releaseName: clickhouse-operator + chart: cozy-clickhouse-operator + namespace: cozy-clickhouse-operator + dependsOn: [victoria-metrics-operator] + +- name: foundationdb-operator + releaseName: foundationdb-operator + chart: cozy-foundationdb-operator + namespace: cozy-foundationdb-operator + dependsOn: [cert-manager] + +- name: rabbitmq-operator + releaseName: rabbitmq-operator + chart: cozy-rabbitmq-operator + namespace: cozy-rabbitmq-operator + dependsOn: [] + +- name: redis-operator + releaseName: redis-operator + chart: cozy-redis-operator + namespace: cozy-redis-operator + dependsOn: [] + +- name: piraeus-operator + releaseName: piraeus-operator + chart: cozy-piraeus-operator + namespace: cozy-linstor + dependsOn: [cert-manager] + +- name: objectstorage-controller + releaseName: objectstorage-controller + chart: cozy-objectstorage-controller + namespace: cozy-objectstorage-controller + dependsOn: [] + +- name: telepresence + releaseName: traffic-manager + chart: cozy-telepresence + namespace: cozy-telepresence + optional: true + dependsOn: [] + +- name: external-dns + releaseName: external-dns + chart: cozy-external-dns + namespace: cozy-external-dns + optional: true + dependsOn: [] + +- name: external-secrets-operator + releaseName: external-secrets-operator + chart: cozy-external-secrets-operator + namespace: cozy-external-secrets-operator + optional: true + dependsOn: [] + +- name: dashboard + releaseName: dashboard + chart: cozy-dashboard + namespace: cozy-dashboard + values: + {{- $dashboardKCconfig := lookup "v1" "ConfigMap" "cozy-dashboard" "kubeapps-auth-config" }} + {{- $dashboardKCValues := dig "data" "values.yaml" (dict) $dashboardKCconfig }} + {{- toYaml (deepCopy $dashboardKCValues | mergeOverwrite (fromYaml (include "cozystack.defaultDashboardValues" .))) | nindent 4 }} + {{- if eq $oidcEnabled "true" }} + dependsOn: [keycloak-configure,cozystack-api] + {{- else }} + dependsOn: [] + {{- end }} + +{{- if $oidcEnabled }} +- name: keycloak + releaseName: keycloak + chart: cozy-keycloak + namespace: cozy-keycloak + dependsOn: [postgres-operator] + +- name: keycloak-operator + releaseName: keycloak-operator + chart: cozy-keycloak-operator + namespace: cozy-keycloak + dependsOn: [keycloak] + +- name: keycloak-configure + releaseName: keycloak-configure + chart: cozy-keycloak-configure + namespace: cozy-keycloak + dependsOn: [keycloak-operator] + values: + cozystack: + configHash: {{ $cozyConfig | toJson | sha256sum }} +{{- end }} + +- name: goldpinger + releaseName: goldpinger + chart: cozy-goldpinger + namespace: cozy-goldpinger + privileged: true + dependsOn: [monitoring-agents] + +- name: vertical-pod-autoscaler + releaseName: vertical-pod-autoscaler + chart: cozy-vertical-pod-autoscaler + namespace: cozy-vertical-pod-autoscaler + privileged: true + dependsOn: [monitoring-agents] + values: + vertical-pod-autoscaler: + recommender: + extraArgs: + prometheus-address: http://vmselect-shortterm.tenant-root.svc.{{ $clusterDomain }}:8481/select/0/prometheus/ + +- name: vertical-pod-autoscaler-crds + releaseName: vertical-pod-autoscaler-crds + chart: cozy-vertical-pod-autoscaler-crds + namespace: cozy-vertical-pod-autoscaler + privileged: true + dependsOn: [] + +- name: velero + releaseName: velero + chart: cozy-velero + namespace: cozy-velero + privileged: true + optional: true + dependsOn: [monitoring-agents] + +- name: hetzner-robotlb + releaseName: robotlb + optional: true + chart: cozy-hetzner-robotlb + namespace: cozy-hetzner-robotlb diff --git a/packages/core/platform/bundles/paas/bundle.yaml b/packages/core/platform/bundles/paas/bundle.yaml index 3fac2506..4de9e2a8 100644 --- a/packages/core/platform/bundles/paas/bundle.yaml +++ b/packages/core/platform/bundles/paas/bundle.yaml @@ -25,51 +25,51 @@ spec: libraries: - name: cozy-lib - path: packages/library/cozy-lib + path: library/cozy-lib artifacts: - name: clickhouse - path: packages/apps/clickhouse + path: apps/clickhouse libraries: [cozy-lib] - name: ferretdb - path: packages/apps/ferretdb + path: apps/ferretdb libraries: [cozy-lib] - name: foundationdb - path: packages/apps/foundationdb + path: apps/foundationdb libraries: [cozy-lib] - name: kafka - path: packages/apps/kafka + path: apps/kafka libraries: [cozy-lib] - name: mysql - path: packages/apps/mysql + path: apps/mysql libraries: [cozy-lib] - name: nats - path: packages/apps/nats + path: apps/nats libraries: [cozy-lib] - name: nats-system - path: packages/system/nats + path: system/nats - name: postgres - path: packages/apps/postgres + path: apps/postgres libraries: [cozy-lib] - name: rabbitmq - path: packages/apps/rabbitmq + path: apps/rabbitmq libraries: [cozy-lib] - name: redis - path: packages/apps/redis + path: apps/redis libraries: [cozy-lib] packages: - name: mariadb-operator releaseName: mariadb-operator - path: packages/system/mariadb-operator + path: system/mariadb-operator namespace: cozy-mariadb-operator dependsOn: [cert-manager,victoria-metrics-operator] values: @@ -78,7 +78,7 @@ spec: - name: kafka-operator releaseName: kafka-operator - path: packages/system/kafka-operator + path: system/kafka-operator namespace: cozy-kafka-operator dependsOn: [victoria-metrics-operator] values: @@ -87,24 +87,24 @@ spec: - name: clickhouse-operator releaseName: clickhouse-operator - path: packages/system/clickhouse-operator + path: system/clickhouse-operator namespace: cozy-clickhouse-operator dependsOn: [victoria-metrics-operator] - name: foundationdb-operator releaseName: foundationdb-operator - path: packages/system/foundationdb-operator + path: system/foundationdb-operator namespace: cozy-foundationdb-operator dependsOn: [cert-manager] - name: rabbitmq-operator releaseName: rabbitmq-operator - path: packages/system/rabbitmq-operator + path: system/rabbitmq-operator namespace: cozy-rabbitmq-operator dependsOn: [] - name: redis-operator releaseName: redis-operator - path: packages/system/redis-operator + path: system/redis-operator namespace: cozy-redis-operator dependsOn: [] diff --git a/packages/core/platform/bundles/system/bundle-full.yaml b/packages/core/platform/bundles/system/bundle-full.yaml index f01cbebc..9e187fd8 100644 --- a/packages/core/platform/bundles/system/bundle-full.yaml +++ b/packages/core/platform/bundles/system/bundle-full.yaml @@ -28,33 +28,33 @@ spec: libraries: - name: cozy-lib - path: packages/library/cozy-lib + path: library/cozy-lib artifacts: - name: tenant - path: packages/apps/tenant + path: apps/tenant libraries: [cozy-lib] - name: bootbox - path: packages/extra/bootbox + path: extra/bootbox libraries: [cozy-lib] - name: etcd - path: packages/extra/etcd + path: extra/etcd libraries: [cozy-lib] - name: ingress - path: packages/extra/ingress + path: extra/ingress libraries: [cozy-lib] - name: ingress-system - path: packages/system/ingress-nginx + path: system/ingress-nginx - name: seaweedfs - path: packages/extra/seaweedfs + path: extra/seaweedfs libraries: [cozy-lib] - name: seaweedfs-system - path: packages/system/seaweedfs + path: system/seaweedfs - name: info - path: packages/extra/info + path: extra/info libraries: [cozy-lib] - name: monitoring - path: packages/extra/monitoring + path: extra/monitoring libraries: [cozy-lib] packages: @@ -69,7 +69,7 @@ spec: - name: cilium releaseName: cilium - path: packages/system/cilium + path: system/cilium namespace: cozy-cilium privileged: true dependsOn: [] @@ -80,14 +80,14 @@ spec: - name: cilium-networkpolicy releaseName: cilium-networkpolicy - path: packages/system/cilium-networkpolicy + path: system/cilium-networkpolicy namespace: cozy-cilium privileged: true dependsOn: [cilium] - name: kubeovn releaseName: kubeovn - path: packages/system/kubeovn + path: system/kubeovn namespace: cozy-kubeovn privileged: true dependsOn: [cilium] @@ -103,45 +103,45 @@ spec: - name: kubeovn-webhook releaseName: kubeovn-webhook - path: packages/system/kubeovn-webhook + path: system/kubeovn-webhook namespace: cozy-kubeovn privileged: true dependsOn: [cilium,kubeovn,cert-manager] - name: kubeovn-plunger releaseName: kubeovn-plunger - path: packages/system/kubeovn-plunger + path: system/kubeovn-plunger namespace: cozy-kubeovn dependsOn: [cilium,kubeovn,victoria-metrics-operator] - name: multus releaseName: multus - path: packages/system/multus + path: system/multus namespace: cozy-multus privileged: true dependsOn: [cilium,kubeovn] - name: cozy-proxy releaseName: cozystack - path: packages/system/cozy-proxy + path: system/cozy-proxy namespace: cozy-system dependsOn: [cilium,kubeovn] - name: cert-manager-crds releaseName: cert-manager-crds - path: packages/system/cert-manager-crds + path: system/cert-manager-crds namespace: cozy-cert-manager dependsOn: [cilium, kubeovn] - name: cozystack-api releaseName: cozystack-api - path: packages/system/cozystack-api + path: system/cozystack-api namespace: cozy-system dependsOn: [cilium,kubeovn,cozystack-controller] - name: cozystack-controller releaseName: cozystack-controller - path: packages/system/cozystack-controller + path: system/cozystack-controller namespace: cozy-system dependsOn: [cilium,kubeovn] {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} @@ -152,31 +152,31 @@ spec: - name: lineage-controller-webhook releaseName: lineage-controller-webhook - path: packages/system/lineage-controller-webhook + path: system/lineage-controller-webhook namespace: cozy-system dependsOn: [cozystack-controller,cilium,kubeovn,cert-manager] - name: cert-manager releaseName: cert-manager - path: packages/system/cert-manager + path: system/cert-manager namespace: cozy-cert-manager dependsOn: [cert-manager-crds] - name: cert-manager-issuers releaseName: cert-manager-issuers - path: packages/system/cert-manager-issuers + path: system/cert-manager-issuers namespace: cozy-cert-manager dependsOn: [cilium,kubeovn,cert-manager] - name: victoria-metrics-operator releaseName: victoria-metrics-operator - path: packages/system/victoria-metrics-operator + path: system/victoria-metrics-operator namespace: cozy-victoria-metrics-operator dependsOn: [cilium,kubeovn,cert-manager] - name: monitoring-agents releaseName: monitoring-agents - path: packages/system/monitoring-agents + path: system/monitoring-agents namespace: cozy-monitoring privileged: true dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] @@ -187,45 +187,45 @@ spec: - name: metallb releaseName: metallb - path: packages/system/metallb + path: system/metallb namespace: cozy-metallb privileged: true dependsOn: [cilium,kubeovn] - name: etcd-operator releaseName: etcd-operator - path: packages/system/etcd-operator + path: system/etcd-operator namespace: cozy-etcd-operator dependsOn: [cilium,kubeovn,cert-manager] - name: grafana-operator releaseName: grafana-operator - path: packages/system/grafana-operator + path: system/grafana-operator namespace: cozy-grafana-operator dependsOn: [cilium,kubeovn] - name: postgres-operator releaseName: postgres-operator - path: packages/system/postgres-operator + path: system/postgres-operator namespace: cozy-postgres-operator dependsOn: [cilium,kubeovn,cert-manager] - name: piraeus-operator releaseName: piraeus-operator - path: packages/system/piraeus-operator + path: system/piraeus-operator namespace: cozy-linstor dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] - name: linstor releaseName: linstor - path: packages/system/linstor + path: system/linstor namespace: cozy-linstor privileged: true dependsOn: [piraeus-operator,cilium,kubeovn,cert-manager,snapshot-controller] - name: nfs-driver releaseName: nfs-driver - path: packages/system/nfs-driver + path: system/nfs-driver namespace: cozy-nfs-driver privileged: true dependsOn: [cilium,kubeovn] @@ -233,26 +233,26 @@ spec: - name: snapshot-controller releaseName: snapshot-controller - path: packages/system/snapshot-controller + path: system/snapshot-controller namespace: cozy-snapshot-controller dependsOn: [cilium,kubeovn,cert-manager-issuers] - name: objectstorage-controller releaseName: objectstorage-controller - path: packages/system/objectstorage-controller + path: system/objectstorage-controller namespace: cozy-objectstorage-controller dependsOn: [cilium,kubeovn] - name: telepresence releaseName: traffic-manager - path: packages/system/telepresence + path: system/telepresence namespace: cozy-telepresence disabled: true dependsOn: [cilium,kubeovn] - name: dashboard releaseName: dashboard - path: packages/system/dashboard + path: system/dashboard namespace: cozy-dashboard dependsOn: - cilium @@ -265,21 +265,21 @@ spec: - name: external-dns releaseName: external-dns - path: packages/system/external-dns + path: system/external-dns namespace: cozy-external-dns disabled: true dependsOn: [cilium,kubeovn] - name: external-secrets-operator releaseName: external-secrets-operator - path: packages/system/external-secrets-operator + path: system/external-secrets-operator namespace: cozy-external-secrets-operator disabled: true dependsOn: [cilium,kubeovn] - name: bootbox releaseName: bootbox - path: packages/system/bootbox + path: system/bootbox namespace: cozy-bootbox privileged: true disabled: true @@ -288,20 +288,20 @@ spec: {{- if $oidcEnabled }} - name: keycloak releaseName: keycloak - path: packages/system/keycloak + path: system/keycloak namespace: cozy-keycloak dependsOn: [postgres-operator] libraries: [cozy-lib] - name: keycloak-operator releaseName: keycloak-operator - path: packages/system/keycloak-operator + path: system/keycloak-operator namespace: cozy-keycloak dependsOn: [keycloak] - name: keycloak-configure releaseName: keycloak-configure - path: packages/system/keycloak-configure + path: system/keycloak-configure namespace: cozy-keycloak dependsOn: [keycloak-operator] values: @@ -311,14 +311,14 @@ spec: - name: goldpinger releaseName: goldpinger - path: packages/system/goldpinger + path: system/goldpinger namespace: cozy-goldpinger privileged: true dependsOn: [monitoring-agents] - name: vertical-pod-autoscaler releaseName: vertical-pod-autoscaler - path: packages/system/vertical-pod-autoscaler + path: system/vertical-pod-autoscaler namespace: cozy-vertical-pod-autoscaler privileged: true dependsOn: [monitoring-agents] @@ -330,19 +330,19 @@ spec: - name: vertical-pod-autoscaler-crds releaseName: vertical-pod-autoscaler-crds - path: packages/system/vertical-pod-autoscaler-crds + path: system/vertical-pod-autoscaler-crds namespace: cozy-vertical-pod-autoscaler privileged: true dependsOn: [cilium, kubeovn] - name: reloader releaseName: reloader - path: packages/system/reloader + path: system/reloader namespace: cozy-reloader - name: velero releaseName: velero - path: packages/system/velero + path: system/velero namespace: cozy-velero privileged: true disabled: true @@ -351,6 +351,6 @@ spec: - name: hetzner-robotlb releaseName: robotlb disabled: true - path: packages/system/hetzner-robotlb + path: system/hetzner-robotlb namespace: cozy-hetzner-robotlb dependsOn: [cilium, kubeovn] diff --git a/packages/core/platform/bundles/system/bundle-hosted.yaml b/packages/core/platform/bundles/system/bundle-hosted.yaml index 80d5d745..a3375aad 100644 --- a/packages/core/platform/bundles/system/bundle-hosted.yaml +++ b/packages/core/platform/bundles/system/bundle-hosted.yaml @@ -28,33 +28,33 @@ spec: libraries: - name: cozy-lib - path: packages/library/cozy-lib + path: library/cozy-lib artifacts: - name: tenant - path: packages/apps/tenant + path: apps/tenant libraries: [cozy-lib] - name: bootbox - path: packages/extra/bootbox + path: extra/bootbox libraries: [cozy-lib] - name: etcd - path: packages/extra/etcd + path: extra/etcd libraries: [cozy-lib] - name: ingress - path: packages/extra/ingress + path: extra/ingress libraries: [cozy-lib] - name: ingress-system - path: packages/system/ingress + path: system/ingress - name: seaweedfs - path: packages/extra/seaweedfs + path: extra/seaweedfs libraries: [cozy-lib] - name: seaweedfs-system - path: packages/system/seaweedfs + path: system/seaweedfs - name: info - path: packages/extra/info + path: extra/info libraries: [cozy-lib] - name: monitoring - path: packages/extra/monitoring + path: extra/monitoring libraries: [cozy-lib] packages: @@ -69,13 +69,13 @@ spec: - name: cert-manager-crds releaseName: cert-manager-crds - path: packages/system/cert-manager-crds + path: system/cert-manager-crds namespace: cozy-cert-manager dependsOn: [] - name: cozystack-api releaseName: cozystack-api - path: packages/system/cozystack-api + path: system/cozystack-api namespace: cozy-system dependsOn: [cozystack-controller] values: @@ -85,7 +85,7 @@ spec: - name: cozystack-controller releaseName: cozystack-controller - path: packages/system/cozystack-controller + path: system/cozystack-controller namespace: cozy-system dependsOn: [] {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} @@ -96,31 +96,31 @@ spec: - name: lineage-controller-webhook releaseName: lineage-controller-webhook - path: packages/system/lineage-controller-webhook + path: system/lineage-controller-webhook namespace: cozy-system dependsOn: [cozystack-controller,cert-manager] - name: cert-manager releaseName: cert-manager - path: packages/system/cert-manager + path: system/cert-manager namespace: cozy-cert-manager dependsOn: [cert-manager-crds] - name: cert-manager-issuers releaseName: cert-manager-issuers - path: packages/system/cert-manager-issuers + path: system/cert-manager-issuers namespace: cozy-cert-manager dependsOn: [cert-manager] - name: victoria-metrics-operator releaseName: victoria-metrics-operator - path: packages/system/victoria-metrics-operator + path: system/victoria-metrics-operator namespace: cozy-victoria-metrics-operator dependsOn: [cert-manager] - name: monitoring-agents releaseName: monitoring-agents - path: packages/system/monitoring-agents + path: system/monitoring-agents namespace: cozy-monitoring privileged: true dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] @@ -131,19 +131,19 @@ spec: - name: etcd-operator releaseName: etcd-operator - path: packages/system/etcd-operator + path: system/etcd-operator namespace: cozy-etcd-operator dependsOn: [cert-manager] - name: grafana-operator releaseName: grafana-operator - path: packages/system/grafana-operator + path: system/grafana-operator namespace: cozy-grafana-operator dependsOn: [] - name: mariadb-operator releaseName: mariadb-operator - path: packages/system/mariadb-operator + path: system/mariadb-operator namespace: cozy-mariadb-operator dependsOn: [cert-manager,victoria-metrics-operator] values: @@ -152,40 +152,40 @@ spec: - name: postgres-operator releaseName: postgres-operator - path: packages/system/postgres-operator + path: system/postgres-operator namespace: cozy-postgres-operator dependsOn: [cert-manager,victoria-metrics-operator] - name: objectstorage-controller releaseName: objectstorage-controller - path: packages/system/objectstorage-controller + path: system/objectstorage-controller namespace: cozy-objectstorage-controller dependsOn: [] - name: telepresence releaseName: traffic-manager - path: packages/system/telepresence + path: system/telepresence namespace: cozy-telepresence disabled: true dependsOn: [] - name: external-dns releaseName: external-dns - path: packages/system/external-dns + path: system/external-dns namespace: cozy-external-dns disabled: true dependsOn: [] - name: external-secrets-operator releaseName: external-secrets-operator - path: packages/system/external-secrets-operator + path: system/external-secrets-operator namespace: cozy-external-secrets-operator disabled: true dependsOn: [] - name: dashboard releaseName: dashboard - path: packages/system/dashboard + path: system/dashboard namespace: cozy-dashboard dependsOn: - cilium @@ -199,20 +199,20 @@ spec: {{- if $oidcEnabled }} - name: keycloak releaseName: keycloak - path: packages/system/keycloak + path: system/keycloak namespace: cozy-keycloak dependsOn: [postgres-operator] libraries: [cozy-lib] - name: keycloak-operator releaseName: keycloak-operator - path: packages/system/keycloak-operator + path: system/keycloak-operator namespace: cozy-keycloak dependsOn: [keycloak] - name: keycloak-configure releaseName: keycloak-configure - path: packages/system/keycloak-configure + path: system/keycloak-configure namespace: cozy-keycloak dependsOn: [keycloak-operator] values: @@ -222,14 +222,14 @@ spec: - name: goldpinger releaseName: goldpinger - path: packages/system/goldpinger + path: system/goldpinger namespace: cozy-goldpinger privileged: true dependsOn: [monitoring-agents] - name: vertical-pod-autoscaler releaseName: vertical-pod-autoscaler - path: packages/system/vertical-pod-autoscaler + path: system/vertical-pod-autoscaler namespace: cozy-vertical-pod-autoscaler privileged: true dependsOn: [monitoring-agents] @@ -241,14 +241,14 @@ spec: - name: vertical-pod-autoscaler-crds releaseName: vertical-pod-autoscaler-crds - path: packages/system/vertical-pod-autoscaler-crds + path: system/vertical-pod-autoscaler-crds namespace: cozy-vertical-pod-autoscaler privileged: true dependsOn: [] - name: velero releaseName: velero - path: packages/system/velero + path: system/velero namespace: cozy-velero privileged: true disabled: true @@ -257,5 +257,5 @@ spec: - name: hetzner-robotlb releaseName: robotlb disabled: true - path: packages/system/hetzner-robotlb + path: system/hetzner-robotlb namespace: cozy-hetzner-robotlb diff --git a/packages/core/platform/bundles/system/bundle-minimal.yaml b/packages/core/platform/bundles/system/bundle-minimal.yaml index 1b32e894..3cffad15 100644 --- a/packages/core/platform/bundles/system/bundle-minimal.yaml +++ b/packages/core/platform/bundles/system/bundle-minimal.yaml @@ -26,17 +26,17 @@ spec: libraries: - name: cozy-lib - path: packages/library/cozy-lib + path: library/cozy-lib artifacts: - name: tenant - path: packages/apps/tenant + path: apps/tenant libraries: [cozy-lib] packages: - name: cozystack-api releaseName: cozystack-api - path: packages/system/cozystack-api + path: system/cozystack-api namespace: cozy-system dependsOn: [cozystack-controller] values: @@ -46,7 +46,7 @@ spec: - name: cozystack-controller releaseName: cozystack-controller - path: packages/system/cozystack-controller + path: system/cozystack-controller namespace: cozy-system dependsOn: [] {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} @@ -57,13 +57,13 @@ spec: - name: lineage-controller-webhook releaseName: lineage-controller-webhook - path: packages/system/lineage-controller-webhook + path: system/lineage-controller-webhook namespace: cozy-system dependsOn: [cozystack-controller] - name: dashboard releaseName: dashboard - path: packages/system/dashboard + path: system/dashboard namespace: cozy-dashboard dependsOn: - cozystack-api diff --git a/packages/core/platform/templates/migration-hook.yaml b/packages/core/platform/templates/migration-hook.yaml index eeacf9d1..377a5502 100644 --- a/packages/core/platform/templates/migration-hook.yaml +++ b/packages/core/platform/templates/migration-hook.yaml @@ -7,8 +7,6 @@ {{- if lt $currentVersion $targetVersion }} {{- $shouldRunMigrationHook = true }} {{- end }} -{{- else }} - {{- $shouldRunMigrationHook = true }} {{- end }} {{- if $shouldRunMigrationHook }} diff --git a/packages/core/platform/templates/platform.yaml b/packages/core/platform/templates/platform.yaml new file mode 100644 index 00000000..a391ad4b --- /dev/null +++ b/packages/core/platform/templates/platform.yaml @@ -0,0 +1,48 @@ +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: cozystack-packages + namespace: cozy-system +spec: + interval: 5m0s + url: oci://ghcr.io/cozystack/cozystack/platform-packages + ref: + digest: sha256:ca54e8ef2073ed387aaf74fed4156cee365a7925c3c51174ff5115c95a1b9179 + #tag: latest +--- +apiVersion: source.extensions.fluxcd.io/v1beta1 +kind: ArtifactGenerator +metadata: + name: cozystack-packages + namespace: cozy-system +spec: + artifacts: + - copy: + - from: '@cozystack/core/platform/**' + to: '@artifact/platform/' + name: cozystack-core-platform + sources: + - alias: cozystack + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system +--- +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: cozystack-platform + namespace: cozy-system +spec: + interval: 5m + targetNamespace: cozy-system + releaseName: cozystack-platform + chartRef: + kind: ExternalArtifact + name: cozystack-core-platform + namespace: cozy-system + values: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system diff --git a/packages/core/platform/templates/version.yaml b/packages/core/platform/templates/version.yaml new file mode 100644 index 00000000..ebc5738f --- /dev/null +++ b/packages/core/platform/templates/version.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: cozystack-version + namespace: cozy-system +data: + version: "{{ .Values.migrations.targetVersion }}" + diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml index ca053d20..0a52a3d8 100644 --- a/packages/core/platform/values.yaml +++ b/packages/core/platform/values.yaml @@ -1,7 +1,7 @@ sourceRef: - kind: GitRepository - name: cozystack + kind: OCIRepository + name: cozystack-packages namespace: cozy-system migrations: - image: ghcr.io/cozystack/cozystack/migrations:latest@sha256:ab762997926290482633259f50b02277abb800c3a9ed5f2566282893f440578c + image: ghcr.io/cozystack/cozystack/platform-migrations:latest@sha256:a5abc7c70c58b0f7b5e3cfc03f19e5eb9121444299a3dd6e25411a015f28d0af targetVersion: 23 # Auto-generated by 'make generate' From 35086bc36297243fd5d50297089ae1abbe031626 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 24 Nov 2025 14:43:58 +0100 Subject: [PATCH 27/46] bug fixes and cleanup Signed-off-by: Andrei Kvapil --- internal/operator/bundle_reconciler.go | 67 ++- packages/core/cozystack-operator/values.yaml | 2 +- packages/core/installer/values.yaml | 2 +- .../core/platform/bundles/distro-full.yaml | 280 ----------- .../core/platform/bundles/distro-hosted.yaml | 192 -------- packages/core/platform/bundles/paas-full.yaml | 461 ------------------ .../core/platform/bundles/paas-hosted.yaml | 274 ----------- .../platform/images/migrations/migrations/2 | 4 +- .../platform/images/migrations/migrations/20 | 12 +- .../platform/images/migrations/migrations/22 | 13 +- .../platform/templates/migration-hook.yaml | 2 +- .../core/platform/templates/platform.yaml | 19 - packages/core/platform/values.yaml | 2 +- 13 files changed, 83 insertions(+), 1247 deletions(-) delete mode 100644 packages/core/platform/bundles/distro-full.yaml delete mode 100644 packages/core/platform/bundles/distro-hosted.yaml delete mode 100644 packages/core/platform/bundles/paas-full.yaml delete mode 100644 packages/core/platform/bundles/paas-hosted.yaml diff --git a/internal/operator/bundle_reconciler.go b/internal/operator/bundle_reconciler.go index 7153b384..42137a18 100644 --- a/internal/operator/bundle_reconciler.go +++ b/internal/operator/bundle_reconciler.go @@ -190,8 +190,11 @@ func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Cont // Process packages for _, pkg := range packages { + logger.V(1).Info("processing package for artifact", "bundle", bundle.Name, "package", pkg.Name, "path", pkg.Path, "disabled", pkg.Disabled) + // Skip packages without path (they might use artifacts) if pkg.Path == "" { + logger.V(1).Info("skipping package without path", "name", pkg.Name) continue } @@ -202,6 +205,8 @@ func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Cont continue } + logger.V(1).Info("extracted package name from path", "name", pkg.Name, "path", pkg.Path, "pkgName", pkgName) + // Get basePath with default values basePath := r.getBasePath(bundle) @@ -567,6 +572,24 @@ func (r *CozystackBundleReconciler) createOrUpdate(ctx context.Context, obj clie obj.SetOwnerReferences(existing.GetOwnerReferences()) } + // For ArtifactGenerator, explicitly update Spec (OutputArtifacts and Sources) + // This ensures that OutputArtifacts from both packages and artifacts are properly updated + 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, + "outputArtifactCount", len(ag.Spec.OutputArtifacts)) + // Update Spec from obj (which contains the desired state with all OutputArtifacts) + existingAG.Spec = ag.Spec + // Preserve metadata updates we made above + existingAG.SetLabels(ag.GetLabels()) + existingAG.SetAnnotations(ag.GetAnnotations()) + existingAG.SetOwnerReferences(ag.GetOwnerReferences()) + // Use existingAG for Update + obj = existingAG + } + } + return r.Update(ctx, obj) } @@ -707,27 +730,59 @@ func (r *CozystackBundleReconciler) cleanupOrphanedResources(ctx context.Context logger := log.FromContext(ctx) // Cleanup ArtifactGenerators by label + // Only delete if they have ownerReferences to this bundle (deletionPolicy != Orphan) agList := &sourcewatcherv1beta1.ArtifactGeneratorList{} if err := r.List(ctx, agList, client.MatchingLabels{ "cozystack.io/bundle": bundleKey.Name, }); err == nil { for _, ag := range agList.Items { - logger.Info("deleting orphaned ArtifactGenerator", "name", ag.Name, "bundle", bundleKey.Name) - if err := r.Delete(ctx, &ag); err != nil && !apierrors.IsNotFound(err) { - logger.Error(err, "failed to delete orphaned ArtifactGenerator", "name", ag.Name) + // Check if this resource has ownerReference to the deleted bundle + hasOwnerRef := false + for _, ownerRef := range ag.OwnerReferences { + if ownerRef.Kind == "CozystackBundle" && ownerRef.Name == bundleKey.Name { + hasOwnerRef = true + break + } + } + + // Only delete if it has ownerReference (deletionPolicy != Orphan) + // If no ownerReference, it means deletionPolicy was Orphan, so we should not delete it + if hasOwnerRef { + logger.Info("deleting orphaned ArtifactGenerator", "name", ag.Name, "bundle", bundleKey.Name) + if err := r.Delete(ctx, &ag); err != nil && !apierrors.IsNotFound(err) { + logger.Error(err, "failed to delete orphaned ArtifactGenerator", "name", ag.Name) + } + } else { + logger.Info("skipping ArtifactGenerator deletion (deletionPolicy=Orphan)", "name", ag.Name, "bundle", bundleKey.Name) } } } // Cleanup HelmReleases by label + // Only delete if they have ownerReferences to this bundle (deletionPolicy != Orphan) hrList := &helmv2.HelmReleaseList{} if err := r.List(ctx, hrList, client.MatchingLabels{ "cozystack.io/bundle": bundleKey.Name, }); err == nil { for _, hr := range hrList.Items { - logger.Info("deleting orphaned HelmRelease", "name", hr.Name, "namespace", hr.Namespace, "bundle", bundleKey.Name) - if err := r.Delete(ctx, &hr); err != nil && !apierrors.IsNotFound(err) { - logger.Error(err, "failed to delete orphaned HelmRelease", "name", hr.Name, "namespace", hr.Namespace) + // Check if this resource has ownerReference to the deleted bundle + hasOwnerRef := false + for _, ownerRef := range hr.OwnerReferences { + if ownerRef.Kind == "CozystackBundle" && ownerRef.Name == bundleKey.Name { + hasOwnerRef = true + break + } + } + + // Only delete if it has ownerReference (deletionPolicy != Orphan) + // If no ownerReference, it means deletionPolicy was Orphan, so we should not delete it + if hasOwnerRef { + logger.Info("deleting orphaned HelmRelease", "name", hr.Name, "namespace", hr.Namespace, "bundle", bundleKey.Name) + if err := r.Delete(ctx, &hr); err != nil && !apierrors.IsNotFound(err) { + logger.Error(err, "failed to delete orphaned HelmRelease", "name", hr.Name, "namespace", hr.Namespace) + } + } else { + logger.Info("skipping HelmRelease deletion (deletionPolicy=Orphan)", "name", hr.Name, "namespace", hr.Namespace, "bundle", bundleKey.Name) } } } diff --git a/packages/core/cozystack-operator/values.yaml b/packages/core/cozystack-operator/values.yaml index 0e43b02c..006b57a3 100644 --- a/packages/core/cozystack-operator/values.yaml +++ b/packages/core/cozystack-operator/values.yaml @@ -1,2 +1,2 @@ cozystackOperator: - image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:9f022d8086226ec3f6885ef3773f96104e7d43daa9f1deaec28e2c56967c60cd + image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:66da9dcf32cc391610781c1cee660eb11ecef9017b9d6c45667683ef5121b066 diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index 22c0e5c3..c9b76dfd 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,3 +1,3 @@ # Digest for OCIRepository cozystack-packages # This value is automatically updated by Makefile when building the image -packagesDigest: "sha256:2350d296687097ca6f8b19337d998fdd581f607e454c634a147ef7cb7a3d2800" +packagesDigest: "sha256:fe93dcef57426e82108b150b047e1860ed53a9cf65710bae9ef0fcda6c1bbf25" diff --git a/packages/core/platform/bundles/distro-full.yaml b/packages/core/platform/bundles/distro-full.yaml deleted file mode 100644 index ed52a83a..00000000 --- a/packages/core/platform/bundles/distro-full.yaml +++ /dev/null @@ -1,280 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} - -releases: -- name: fluxcd-operator - releaseName: fluxcd-operator - chart: cozy-fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - -- name: fluxcd - releaseName: fluxcd - chart: cozy-fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator,cilium] - values: - flux-instance: - instance: - cluster: - domain: {{ $clusterDomain }} - -- name: cilium - releaseName: cilium - chart: cozy-cilium - namespace: cozy-cilium - privileged: true - dependsOn: [] - valuesFiles: - - values.yaml - - values-talos.yaml - values: - cilium: - enableIPv4Masquerade: true - enableIdentityMark: true - ipv4NativeRoutingCIDR: "{{ index $cozyConfig.data "ipv4-pod-cidr" }}" - autoDirectNodeRoutes: true - routingMode: native - -- name: cilium-networkpolicy - releaseName: cilium-networkpolicy - chart: cozy-cilium-networkpolicy - namespace: cozy-cilium - privileged: true - dependsOn: [cilium] - -- name: cozy-proxy - releaseName: cozystack - chart: cozy-cozy-proxy - namespace: cozy-system - optional: true - dependsOn: [cilium] - -- name: cert-manager-crds - releaseName: cert-manager-crds - chart: cozy-cert-manager-crds - namespace: cozy-cert-manager - dependsOn: [cilium] - -- name: cozystack-controller - releaseName: cozystack-controller - chart: cozy-cozystack-controller - namespace: cozy-system - dependsOn: [cilium] - {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} - values: - cozystackController: - disableTelemetry: true - {{- end }} - -- name: lineage-controller-webhook - releaseName: lineage-controller-webhook - chart: cozy-lineage-controller-webhook - namespace: cozy-system - dependsOn: [cozystack-controller,cilium,cert-manager] - -- name: cert-manager - releaseName: cert-manager - chart: cozy-cert-manager - namespace: cozy-cert-manager - dependsOn: [cert-manager-crds] - -- name: cert-manager-issuers - releaseName: cert-manager-issuers - chart: cozy-cert-manager-issuers - namespace: cozy-cert-manager - optional: true - dependsOn: [cilium,cert-manager] - -- name: victoria-metrics-operator - releaseName: victoria-metrics-operator - chart: cozy-victoria-metrics-operator - namespace: cozy-victoria-metrics-operator - optional: true - dependsOn: [cilium,cert-manager] - -- name: monitoring-agents - releaseName: monitoring-agents - chart: cozy-monitoring-agents - namespace: cozy-monitoring - privileged: true - optional: true - dependsOn: [cilium,victoria-metrics-operator] - values: - scrapeRules: - etcd: - enabled: true - -- name: metallb - releaseName: metallb - chart: cozy-metallb - namespace: cozy-metallb - privileged: true - dependsOn: [cilium] - -- name: etcd-operator - releaseName: etcd-operator - chart: cozy-etcd-operator - namespace: cozy-etcd-operator - optional: true - dependsOn: [cilium,cert-manager] - -- name: grafana-operator - releaseName: grafana-operator - chart: cozy-grafana-operator - namespace: cozy-grafana-operator - optional: true - dependsOn: [cilium] - -- name: mariadb-operator - releaseName: mariadb-operator - chart: cozy-mariadb-operator - namespace: cozy-mariadb-operator - optional: true - dependsOn: [cilium,cert-manager,victoria-metrics-operator] - values: - mariadb-operator: - clusterName: {{ $clusterDomain }} - -- name: postgres-operator - releaseName: postgres-operator - chart: cozy-postgres-operator - namespace: cozy-postgres-operator - optional: true - dependsOn: [cilium,cert-manager,victoria-metrics-operator] - -- name: kafka-operator - releaseName: kafka-operator - chart: cozy-kafka-operator - namespace: cozy-kafka-operator - optional: true - dependsOn: [cilium,victoria-metrics-operator] - values: - strimzi-kafka-operator: - kubernetesServiceDnsDomain: {{ $clusterDomain }} - -- name: clickhouse-operator - releaseName: clickhouse-operator - chart: cozy-clickhouse-operator - namespace: cozy-clickhouse-operator - optional: true - dependsOn: [cilium,victoria-metrics-operator] - -- name: foundationdb-operator - releaseName: foundationdb-operator - chart: cozy-foundationdb-operator - namespace: cozy-foundationdb-operator - optional: true - dependsOn: [cilium,cert-manager] - -- name: rabbitmq-operator - releaseName: rabbitmq-operator - chart: cozy-rabbitmq-operator - namespace: cozy-rabbitmq-operator - optional: true - dependsOn: [cilium] - -- name: redis-operator - releaseName: redis-operator - chart: cozy-redis-operator - namespace: cozy-redis-operator - optional: true - dependsOn: [cilium] - -- name: piraeus-operator - releaseName: piraeus-operator - chart: cozy-piraeus-operator - namespace: cozy-linstor - dependsOn: [cilium,cert-manager] - -- name: snapshot-controller - releaseName: snapshot-controller - chart: cozy-snapshot-controller - namespace: cozy-snapshot-controller - dependsOn: [cilium] - -- name: objectstorage-controller - releaseName: objectstorage-controller - chart: cozy-objectstorage-controller - namespace: cozy-objectstorage-controller - optional: true - dependsOn: [cilium] - -- name: linstor - releaseName: linstor - chart: cozy-linstor - namespace: cozy-linstor - privileged: true - dependsOn: [piraeus-operator,cilium,cert-manager,snapshot-controller] - -- name: nfs-driver - releaseName: nfs-driver - chart: cozy-nfs-driver - namespace: cozy-nfs-driver - privileged: true - dependsOn: [cilium] - optional: true - -- name: telepresence - releaseName: traffic-manager - chart: cozy-telepresence - namespace: cozy-telepresence - optional: true - dependsOn: [] - -- name: external-dns - releaseName: external-dns - chart: cozy-external-dns - namespace: cozy-external-dns - optional: true - dependsOn: [cilium] - -- name: external-secrets-operator - releaseName: external-secrets-operator - chart: cozy-external-secrets-operator - namespace: cozy-external-secrets-operator - optional: true - dependsOn: [cilium] - -- name: keycloak - releaseName: keycloak - chart: cozy-keycloak - namespace: cozy-keycloak - optional: true - dependsOn: [postgres-operator] - -- name: keycloak-operator - releaseName: keycloak-operator - chart: cozy-keycloak-operator - namespace: cozy-keycloak - optional: true - dependsOn: [keycloak] - -- name: bootbox - releaseName: bootbox - chart: cozy-bootbox - namespace: cozy-bootbox - privileged: true - optional: true - dependsOn: [cilium] - -- name: reloader - releaseName: reloader - chart: cozy-reloader - namespace: cozy-reloader - -- name: velero - releaseName: velero - chart: cozy-velero - namespace: cozy-velero - privileged: true - optional: true - dependsOn: [cilium] - -- name: hetzner-robotlb - releaseName: robotlb - optional: true - chart: cozy-hetzner-robotlb - namespace: cozy-hetzner-robotlb - dependsOn: [cilium] diff --git a/packages/core/platform/bundles/distro-hosted.yaml b/packages/core/platform/bundles/distro-hosted.yaml deleted file mode 100644 index 83aa81d9..00000000 --- a/packages/core/platform/bundles/distro-hosted.yaml +++ /dev/null @@ -1,192 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} - -releases: -- name: fluxcd-operator - releaseName: fluxcd-operator - chart: cozy-fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - -- name: fluxcd - releaseName: fluxcd - chart: cozy-fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator] - values: - flux-instance: - instance: - cluster: - domain: {{ $clusterDomain }} - -- name: cert-manager-crds - releaseName: cert-manager-crds - chart: cozy-cert-manager-crds - namespace: cozy-cert-manager - dependsOn: [] - -- name: cozystack-controller - releaseName: cozystack-controller - chart: cozy-cozystack-controller - namespace: cozy-system - {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} - values: - cozystackController: - disableTelemetry: true - {{- end }} - -- name: lineage-controller-webhook - releaseName: lineage-controller-webhook - chart: cozy-lineage-controller-webhook - namespace: cozy-system - dependsOn: [cozystack-controller,cert-manager] - -- name: cert-manager - releaseName: cert-manager - chart: cozy-cert-manager - namespace: cozy-cert-manager - dependsOn: [cert-manager-crds] - -- name: cert-manager-issuers - releaseName: cert-manager-issuers - chart: cozy-cert-manager-issuers - namespace: cozy-cert-manager - optional: true - dependsOn: [cert-manager] - -- name: victoria-metrics-operator - releaseName: victoria-metrics-operator - chart: cozy-victoria-metrics-operator - namespace: cozy-victoria-metrics-operator - optional: true - dependsOn: [cert-manager] - -- name: monitoring-agents - releaseName: monitoring-agents - chart: cozy-monitoring-agents - namespace: cozy-monitoring - privileged: true - optional: true - dependsOn: [victoria-metrics-operator] - values: - scrapeRules: - etcd: - enabled: true - -- name: etcd-operator - releaseName: etcd-operator - chart: cozy-etcd-operator - namespace: cozy-etcd-operator - optional: true - dependsOn: [cert-manager] - -- name: grafana-operator - releaseName: grafana-operator - chart: cozy-grafana-operator - namespace: cozy-grafana-operator - optional: true - dependsOn: [] - -- name: mariadb-operator - releaseName: mariadb-operator - chart: cozy-mariadb-operator - namespace: cozy-mariadb-operator - optional: true - dependsOn: [victoria-metrics-operator] - values: - mariadb-operator: - clusterName: {{ $clusterDomain }} - -- name: postgres-operator - releaseName: postgres-operator - chart: cozy-postgres-operator - namespace: cozy-postgres-operator - optional: true - dependsOn: [victoria-metrics-operator] - -- name: kafka-operator - releaseName: kafka-operator - chart: cozy-kafka-operator - namespace: cozy-kafka-operator - optional: true - dependsOn: [victoria-metrics-operator] - values: - strimzi-kafka-operator: - kubernetesServiceDnsDomain: {{ $clusterDomain }} - -- name: clickhouse-operator - releaseName: clickhouse-operator - chart: cozy-clickhouse-operator - namespace: cozy-clickhouse-operator - optional: true - dependsOn: [victoria-metrics-operator] - -- name: foundationdb-operator - releaseName: foundationdb-operator - chart: cozy-foundationdb-operator - namespace: cozy-foundationdb-operator - optional: true - dependsOn: [cert-manager] - -- name: rabbitmq-operator - releaseName: rabbitmq-operator - chart: cozy-rabbitmq-operator - namespace: cozy-rabbitmq-operator - optional: true - dependsOn: [] - -- name: redis-operator - releaseName: redis-operator - chart: cozy-redis-operator - namespace: cozy-redis-operator - optional: true - dependsOn: [] - -- name: telepresence - releaseName: traffic-manager - chart: cozy-telepresence - namespace: cozy-telepresence - optional: true - dependsOn: [] - -- name: external-dns - releaseName: external-dns - chart: cozy-external-dns - namespace: cozy-external-dns - optional: true - dependsOn: [] - -- name: external-secrets-operator - releaseName: external-secrets-operator - chart: cozy-external-secrets-operator - namespace: cozy-external-secrets-operator - optional: true - dependsOn: [] - -- name: keycloak - releaseName: keycloak - chart: cozy-keycloak - namespace: cozy-keycloak - optional: true - dependsOn: [postgres-operator] - -- name: keycloak-operator - releaseName: keycloak-operator - chart: cozy-keycloak-operator - namespace: cozy-keycloak - optional: true - dependsOn: [keycloak] - -- name: velero - releaseName: velero - chart: cozy-velero - namespace: cozy-velero - privileged: true - optional: true - -- name: hetzner-robotlb - releaseName: robotlb - optional: true - chart: cozy-hetzner-robotlb - namespace: cozy-hetzner-robotlb diff --git a/packages/core/platform/bundles/paas-full.yaml b/packages/core/platform/bundles/paas-full.yaml deleted file mode 100644 index 4382bd62..00000000 --- a/packages/core/platform/bundles/paas-full.yaml +++ /dev/null @@ -1,461 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} -{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- if not $host }} -{{- fail "ERROR need root-host in cozystack ConfigMap" }} -{{- end }} -{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} -{{- if not $apiServerEndpoint }} -{{- fail "ERROR need api-server-endpoint in cozystack ConfigMap" }} -{{- end }} - -releases: -- name: fluxcd-operator - releaseName: fluxcd-operator - chart: cozy-fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - -- name: fluxcd - releaseName: fluxcd - chart: cozy-fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator,cilium,kubeovn] - values: - flux-instance: - instance: - cluster: - domain: {{ $clusterDomain }} - -- name: cilium - releaseName: cilium - chart: cozy-cilium - namespace: cozy-cilium - privileged: true - dependsOn: [] - valuesFiles: - - values.yaml - - values-talos.yaml - - values-kubeovn.yaml - -- name: cilium-networkpolicy - releaseName: cilium-networkpolicy - chart: cozy-cilium-networkpolicy - namespace: cozy-cilium - privileged: true - dependsOn: [cilium] - -- name: kubeovn - releaseName: kubeovn - chart: cozy-kubeovn - namespace: cozy-kubeovn - privileged: true - dependsOn: [cilium] - values: - cozystack: - nodesHash: {{ include "cozystack.master-node-ips" . | sha256sum }} - kube-ovn: - ipv4: - POD_CIDR: "{{ index $cozyConfig.data "ipv4-pod-cidr" }}" - POD_GATEWAY: "{{ index $cozyConfig.data "ipv4-pod-gateway" }}" - SVC_CIDR: "{{ index $cozyConfig.data "ipv4-svc-cidr" }}" - JOIN_CIDR: "{{ index $cozyConfig.data "ipv4-join-cidr" }}" - -- name: kubeovn-webhook - releaseName: kubeovn-webhook - chart: cozy-kubeovn-webhook - namespace: cozy-kubeovn - privileged: true - dependsOn: [cilium,kubeovn,cert-manager] - -- name: kubeovn-plunger - releaseName: kubeovn-plunger - chart: cozy-kubeovn-plunger - namespace: cozy-kubeovn - dependsOn: [cilium,kubeovn] - -- name: multus - releaseName: multus - chart: cozy-multus - namespace: cozy-multus - privileged: true - dependsOn: [cilium,kubeovn] - -- name: cozy-proxy - releaseName: cozystack - chart: cozy-cozy-proxy - namespace: cozy-system - dependsOn: [cilium,kubeovn] - -- name: cert-manager-crds - releaseName: cert-manager-crds - chart: cozy-cert-manager-crds - namespace: cozy-cert-manager - dependsOn: [cilium, kubeovn] - -- name: cozystack-api - releaseName: cozystack-api - chart: cozy-cozystack-api - namespace: cozy-system - dependsOn: [cilium,kubeovn,cozystack-controller] - -- name: cozystack-controller - releaseName: cozystack-controller - chart: cozy-cozystack-controller - namespace: cozy-system - dependsOn: [cilium,kubeovn] - {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} - values: - cozystackController: - disableTelemetry: true - {{- end }} - -- name: lineage-controller-webhook - releaseName: lineage-controller-webhook - chart: cozy-lineage-controller-webhook - namespace: cozy-system - dependsOn: [cozystack-controller,cilium,kubeovn,cert-manager] - -- name: cozystack-resource-definition-crd - releaseName: cozystack-resource-definition-crd - chart: cozystack-resource-definition-crd - namespace: cozy-system - dependsOn: [cilium,kubeovn,cozystack-api,cozystack-controller] - -- name: cozystack-resource-definitions - releaseName: cozystack-resource-definitions - chart: cozystack-resource-definitions - namespace: cozy-system - dependsOn: [cilium,kubeovn,cozystack-api,cozystack-controller,cozystack-resource-definition-crd] - -- name: cert-manager - releaseName: cert-manager - chart: cozy-cert-manager - namespace: cozy-cert-manager - dependsOn: [cert-manager-crds] - -- name: cert-manager-issuers - releaseName: cert-manager-issuers - chart: cozy-cert-manager-issuers - namespace: cozy-cert-manager - dependsOn: [cilium,kubeovn,cert-manager] - -- name: victoria-metrics-operator - releaseName: victoria-metrics-operator - chart: cozy-victoria-metrics-operator - namespace: cozy-victoria-metrics-operator - dependsOn: [cilium,kubeovn,cert-manager] - -- name: monitoring-agents - releaseName: monitoring-agents - chart: cozy-monitoring-agents - namespace: cozy-monitoring - privileged: true - dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] - values: - scrapeRules: - etcd: - enabled: true - -- name: kubevirt-operator - releaseName: kubevirt-operator - chart: cozy-kubevirt-operator - namespace: cozy-kubevirt - dependsOn: [cilium,kubeovn,victoria-metrics-operator] - -- name: kubevirt - releaseName: kubevirt - chart: cozy-kubevirt - namespace: cozy-kubevirt - privileged: true - dependsOn: [cilium,kubeovn,kubevirt-operator] - {{- $cpuAllocationRatio := index $cozyConfig.data "cpu-allocation-ratio" }} - {{- if $cpuAllocationRatio }} - values: - cpuAllocationRatio: {{ $cpuAllocationRatio }} - {{- end }} - -- name: kubevirt-instancetypes - releaseName: kubevirt-instancetypes - chart: cozy-kubevirt-instancetypes - namespace: cozy-kubevirt - dependsOn: [cilium,kubeovn,kubevirt-operator,kubevirt] - -- name: kubevirt-cdi-operator - releaseName: kubevirt-cdi-operator - chart: cozy-kubevirt-cdi-operator - namespace: cozy-kubevirt-cdi - dependsOn: [cilium,kubeovn] - -- name: kubevirt-cdi - releaseName: kubevirt-cdi - chart: cozy-kubevirt-cdi - namespace: cozy-kubevirt-cdi - dependsOn: [cilium,kubeovn,kubevirt-cdi-operator] - -- name: gpu-operator - releaseName: gpu-operator - chart: cozy-gpu-operator - namespace: cozy-gpu-operator - privileged: true - optional: true - dependsOn: [cilium,kubeovn] - valuesFiles: - - values.yaml - - values-talos.yaml - -- name: metallb - releaseName: metallb - chart: cozy-metallb - namespace: cozy-metallb - privileged: true - dependsOn: [cilium,kubeovn] - -- name: etcd-operator - releaseName: etcd-operator - chart: cozy-etcd-operator - namespace: cozy-etcd-operator - dependsOn: [cilium,kubeovn,cert-manager] - -- name: grafana-operator - releaseName: grafana-operator - chart: cozy-grafana-operator - namespace: cozy-grafana-operator - dependsOn: [cilium,kubeovn] - -- name: mariadb-operator - releaseName: mariadb-operator - chart: cozy-mariadb-operator - namespace: cozy-mariadb-operator - dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] - values: - mariadb-operator: - clusterName: {{ $clusterDomain }} - -- name: postgres-operator - releaseName: postgres-operator - chart: cozy-postgres-operator - namespace: cozy-postgres-operator - dependsOn: [cilium,kubeovn,cert-manager] - -- name: kafka-operator - releaseName: kafka-operator - chart: cozy-kafka-operator - namespace: cozy-kafka-operator - dependsOn: [cilium,kubeovn,victoria-metrics-operator] - values: - strimzi-kafka-operator: - kubernetesServiceDnsDomain: {{ $clusterDomain }} - -- name: clickhouse-operator - releaseName: clickhouse-operator - chart: cozy-clickhouse-operator - namespace: cozy-clickhouse-operator - dependsOn: [cilium,kubeovn,victoria-metrics-operator] - -- name: foundationdb-operator - releaseName: foundationdb-operator - chart: cozy-foundationdb-operator - namespace: cozy-foundationdb-operator - dependsOn: [cilium,kubeovn,cert-manager] - -- name: rabbitmq-operator - releaseName: rabbitmq-operator - chart: cozy-rabbitmq-operator - namespace: cozy-rabbitmq-operator - dependsOn: [cilium,kubeovn] - -- name: redis-operator - releaseName: redis-operator - chart: cozy-redis-operator - namespace: cozy-redis-operator - dependsOn: [cilium,kubeovn] - -- name: piraeus-operator - releaseName: piraeus-operator - chart: cozy-piraeus-operator - namespace: cozy-linstor - dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] - -- name: linstor - releaseName: linstor - chart: cozy-linstor - namespace: cozy-linstor - privileged: true - dependsOn: [piraeus-operator,cilium,kubeovn,cert-manager,snapshot-controller] - -- name: nfs-driver - releaseName: nfs-driver - chart: cozy-nfs-driver - namespace: cozy-nfs-driver - privileged: true - dependsOn: [cilium,kubeovn] - optional: true - -- name: snapshot-controller - releaseName: snapshot-controller - chart: cozy-snapshot-controller - namespace: cozy-snapshot-controller - dependsOn: [cilium,kubeovn,cert-manager-issuers] - -- name: objectstorage-controller - releaseName: objectstorage-controller - chart: cozy-objectstorage-controller - namespace: cozy-objectstorage-controller - dependsOn: [cilium,kubeovn] - -- name: telepresence - releaseName: traffic-manager - chart: cozy-telepresence - namespace: cozy-telepresence - optional: true - dependsOn: [cilium,kubeovn] - -- name: dashboard - releaseName: dashboard - chart: cozy-dashboard - namespace: cozy-dashboard - values: - {{- $dashboardKCconfig := lookup "v1" "ConfigMap" "cozy-dashboard" "kubeapps-auth-config" }} - {{- $dashboardKCValues := dig "data" "values.yaml" "" $dashboardKCconfig | fromYaml }} - {{- toYaml (deepCopy $dashboardKCValues | mergeOverwrite (fromYaml (include "cozystack.defaultDashboardValues" .))) | nindent 4 }} - dependsOn: - - cilium - - kubeovn - {{- if eq $oidcEnabled "true" }} - - keycloak-configure - {{- end }} - -- name: kamaji - releaseName: kamaji - chart: cozy-kamaji - namespace: cozy-kamaji - dependsOn: [cilium,kubeovn,cert-manager] - -- name: capi-operator - releaseName: capi-operator - chart: cozy-capi-operator - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,cert-manager] - -- name: capi-providers-bootstrap - releaseName: capi-providers-bootstrap - chart: cozy-capi-providers-bootstrap - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] - -- name: capi-providers-core - releaseName: capi-providers-core - chart: cozy-capi-providers-core - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] - -- name: capi-providers-cpprovider - releaseName: capi-providers-cpprovider - chart: cozy-capi-providers-cpprovider - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] - -- name: capi-providers-infraprovider - releaseName: capi-providers-infraprovider - chart: cozy-capi-providers-infraprovider - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] - -- name: external-dns - releaseName: external-dns - chart: cozy-external-dns - namespace: cozy-external-dns - optional: true - dependsOn: [cilium,kubeovn] - -- name: external-secrets-operator - releaseName: external-secrets-operator - chart: cozy-external-secrets-operator - namespace: cozy-external-secrets-operator - optional: true - dependsOn: [cilium,kubeovn] - -- name: bootbox - releaseName: bootbox - chart: cozy-bootbox - namespace: cozy-bootbox - privileged: true - optional: true - dependsOn: [cilium,kubeovn] - -{{- if $oidcEnabled }} -- name: keycloak - releaseName: keycloak - chart: cozy-keycloak - namespace: cozy-keycloak - dependsOn: [postgres-operator] - -- name: keycloak-operator - releaseName: keycloak-operator - chart: cozy-keycloak-operator - namespace: cozy-keycloak - dependsOn: [keycloak] - -- name: keycloak-configure - releaseName: keycloak-configure - chart: cozy-keycloak-configure - namespace: cozy-keycloak - dependsOn: [keycloak-operator] - values: - cozystack: - configHash: {{ $cozyConfig | toJson | sha256sum }} -{{- end }} - -- name: goldpinger - releaseName: goldpinger - chart: cozy-goldpinger - namespace: cozy-goldpinger - privileged: true - dependsOn: [monitoring-agents] - -- name: vertical-pod-autoscaler - releaseName: vertical-pod-autoscaler - chart: cozy-vertical-pod-autoscaler - namespace: cozy-vertical-pod-autoscaler - privileged: true - dependsOn: [monitoring-agents] - values: - vertical-pod-autoscaler: - recommender: - extraArgs: - prometheus-address: http://vmselect-shortterm.tenant-root.svc.{{ $clusterDomain }}:8481/select/0/prometheus/ - -- name: vertical-pod-autoscaler-crds - releaseName: vertical-pod-autoscaler-crds - chart: cozy-vertical-pod-autoscaler-crds - namespace: cozy-vertical-pod-autoscaler - privileged: true - dependsOn: [cilium, kubeovn] - -- name: reloader - releaseName: reloader - chart: cozy-reloader - namespace: cozy-reloader - -- name: velero - releaseName: velero - chart: cozy-velero - namespace: cozy-velero - privileged: true - optional: true - dependsOn: [monitoring-agents] - -- name: hetzner-robotlb - releaseName: robotlb - optional: true - chart: cozy-hetzner-robotlb - namespace: cozy-hetzner-robotlb - dependsOn: [cilium, kubeovn] diff --git a/packages/core/platform/bundles/paas-hosted.yaml b/packages/core/platform/bundles/paas-hosted.yaml deleted file mode 100644 index 560578c7..00000000 --- a/packages/core/platform/bundles/paas-hosted.yaml +++ /dev/null @@ -1,274 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} -{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- if not $host }} -{{- fail "ERROR need root-host in cozystack ConfigMap" }} -{{- end }} -{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} -{{- if not $apiServerEndpoint }} -{{- fail "ERROR need api-server-endpoint in cozystack ConfigMap" }} -{{- end }} - -releases: -- name: fluxcd-operator - releaseName: fluxcd-operator - chart: cozy-fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - -- name: fluxcd - releaseName: fluxcd - chart: cozy-fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator] - values: - flux-instance: - instance: - cluster: - domain: {{ $clusterDomain }} - -- name: cert-manager-crds - releaseName: cert-manager-crds - chart: cozy-cert-manager-crds - namespace: cozy-cert-manager - dependsOn: [] - -- name: cozystack-api - releaseName: cozystack-api - chart: cozy-cozystack-api - namespace: cozy-system - dependsOn: [cozystack-controller] - values: - cozystackAPI: - localK8sAPIEndpoint: - enabled: false - -- name: cozystack-controller - releaseName: cozystack-controller - chart: cozy-cozystack-controller - namespace: cozy-system - dependsOn: [] - {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} - values: - cozystackController: - disableTelemetry: true - {{- end }} - -- name: lineage-controller-webhook - releaseName: lineage-controller-webhook - chart: cozy-lineage-controller-webhook - namespace: cozy-system - dependsOn: [cozystack-controller,cert-manager] - -- name: cozystack-resource-definition-crd - releaseName: cozystack-resource-definition-crd - chart: cozystack-resource-definition-crd - namespace: cozy-system - dependsOn: [cozystack-api,cozystack-controller] - -- name: cozystack-resource-definitions - releaseName: cozystack-resource-definitions - chart: cozystack-resource-definitions - namespace: cozy-system - dependsOn: [cozystack-api,cozystack-controller,cozystack-resource-definition-crd] - -- name: cert-manager - releaseName: cert-manager - chart: cozy-cert-manager - namespace: cozy-cert-manager - dependsOn: [cert-manager-crds] - -- name: cert-manager-issuers - releaseName: cert-manager-issuers - chart: cozy-cert-manager-issuers - namespace: cozy-cert-manager - dependsOn: [cert-manager] - -- name: victoria-metrics-operator - releaseName: victoria-metrics-operator - chart: cozy-victoria-metrics-operator - namespace: cozy-victoria-metrics-operator - dependsOn: [cert-manager] - -- name: monitoring-agents - releaseName: monitoring-agents - chart: cozy-monitoring-agents - namespace: cozy-monitoring - privileged: true - dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] - values: - scrapeRules: - etcd: - enabled: true - -- name: etcd-operator - releaseName: etcd-operator - chart: cozy-etcd-operator - namespace: cozy-etcd-operator - dependsOn: [cert-manager] - -- name: grafana-operator - releaseName: grafana-operator - chart: cozy-grafana-operator - namespace: cozy-grafana-operator - dependsOn: [] - -- name: mariadb-operator - releaseName: mariadb-operator - chart: cozy-mariadb-operator - namespace: cozy-mariadb-operator - dependsOn: [cert-manager,victoria-metrics-operator] - values: - mariadb-operator: - clusterName: {{ $clusterDomain }} - -- name: postgres-operator - releaseName: postgres-operator - chart: cozy-postgres-operator - namespace: cozy-postgres-operator - dependsOn: [cert-manager,victoria-metrics-operator] - -- name: kafka-operator - releaseName: kafka-operator - chart: cozy-kafka-operator - namespace: cozy-kafka-operator - dependsOn: [victoria-metrics-operator] - values: - strimzi-kafka-operator: - kubernetesServiceDnsDomain: {{ $clusterDomain }} - -- name: clickhouse-operator - releaseName: clickhouse-operator - chart: cozy-clickhouse-operator - namespace: cozy-clickhouse-operator - dependsOn: [victoria-metrics-operator] - -- name: foundationdb-operator - releaseName: foundationdb-operator - chart: cozy-foundationdb-operator - namespace: cozy-foundationdb-operator - dependsOn: [cert-manager] - -- name: rabbitmq-operator - releaseName: rabbitmq-operator - chart: cozy-rabbitmq-operator - namespace: cozy-rabbitmq-operator - dependsOn: [] - -- name: redis-operator - releaseName: redis-operator - chart: cozy-redis-operator - namespace: cozy-redis-operator - dependsOn: [] - -- name: piraeus-operator - releaseName: piraeus-operator - chart: cozy-piraeus-operator - namespace: cozy-linstor - dependsOn: [cert-manager] - -- name: objectstorage-controller - releaseName: objectstorage-controller - chart: cozy-objectstorage-controller - namespace: cozy-objectstorage-controller - dependsOn: [] - -- name: telepresence - releaseName: traffic-manager - chart: cozy-telepresence - namespace: cozy-telepresence - optional: true - dependsOn: [] - -- name: external-dns - releaseName: external-dns - chart: cozy-external-dns - namespace: cozy-external-dns - optional: true - dependsOn: [] - -- name: external-secrets-operator - releaseName: external-secrets-operator - chart: cozy-external-secrets-operator - namespace: cozy-external-secrets-operator - optional: true - dependsOn: [] - -- name: dashboard - releaseName: dashboard - chart: cozy-dashboard - namespace: cozy-dashboard - values: - {{- $dashboardKCconfig := lookup "v1" "ConfigMap" "cozy-dashboard" "kubeapps-auth-config" }} - {{- $dashboardKCValues := dig "data" "values.yaml" (dict) $dashboardKCconfig }} - {{- toYaml (deepCopy $dashboardKCValues | mergeOverwrite (fromYaml (include "cozystack.defaultDashboardValues" .))) | nindent 4 }} - {{- if eq $oidcEnabled "true" }} - dependsOn: [keycloak-configure,cozystack-api] - {{- else }} - dependsOn: [] - {{- end }} - -{{- if $oidcEnabled }} -- name: keycloak - releaseName: keycloak - chart: cozy-keycloak - namespace: cozy-keycloak - dependsOn: [postgres-operator] - -- name: keycloak-operator - releaseName: keycloak-operator - chart: cozy-keycloak-operator - namespace: cozy-keycloak - dependsOn: [keycloak] - -- name: keycloak-configure - releaseName: keycloak-configure - chart: cozy-keycloak-configure - namespace: cozy-keycloak - dependsOn: [keycloak-operator] - values: - cozystack: - configHash: {{ $cozyConfig | toJson | sha256sum }} -{{- end }} - -- name: goldpinger - releaseName: goldpinger - chart: cozy-goldpinger - namespace: cozy-goldpinger - privileged: true - dependsOn: [monitoring-agents] - -- name: vertical-pod-autoscaler - releaseName: vertical-pod-autoscaler - chart: cozy-vertical-pod-autoscaler - namespace: cozy-vertical-pod-autoscaler - privileged: true - dependsOn: [monitoring-agents] - values: - vertical-pod-autoscaler: - recommender: - extraArgs: - prometheus-address: http://vmselect-shortterm.tenant-root.svc.{{ $clusterDomain }}:8481/select/0/prometheus/ - -- name: vertical-pod-autoscaler-crds - releaseName: vertical-pod-autoscaler-crds - chart: cozy-vertical-pod-autoscaler-crds - namespace: cozy-vertical-pod-autoscaler - privileged: true - dependsOn: [] - -- name: velero - releaseName: velero - chart: cozy-velero - namespace: cozy-velero - privileged: true - optional: true - dependsOn: [monitoring-agents] - -- name: hetzner-robotlb - releaseName: robotlb - optional: true - chart: cozy-hetzner-robotlb - namespace: cozy-hetzner-robotlb diff --git a/packages/core/platform/images/migrations/migrations/2 b/packages/core/platform/images/migrations/migrations/2 index 0c082452..a3bfd118 100755 --- a/packages/core/platform/images/migrations/migrations/2 +++ b/packages/core/platform/images/migrations/migrations/2 @@ -1,7 +1,9 @@ #!/bin/sh # Migration 2 --> 3 -kubectl apply -f packages/system/mariadb-operator/charts/mariadb-operator/crds/crds.yaml --server-side --force-conflicts +if [ -d packages/system ]; then + kubectl apply -f packages/system/mariadb-operator/charts/mariadb-operator/crds/crds.yaml --server-side --force-conflicts +fi # Fix mariadb-operator crds mariadb_crds=$(kubectl get crd -o name | grep '\.k8s\.mariadb\.com$') diff --git a/packages/core/platform/images/migrations/migrations/20 b/packages/core/platform/images/migrations/migrations/20 index 6755cd65..4e7c5c31 100755 --- a/packages/core/platform/images/migrations/migrations/20 +++ b/packages/core/platform/images/migrations/migrations/20 @@ -22,11 +22,13 @@ done kubectl delete helmrelease -n cozy-dashboard dashboard --ignore-not-found sleep 5 -cozypkg -n cozy-system -C packages/system/cozystack-resource-definition-crd apply cozystack-resource-definition-crd --plain -cozypkg -n cozy-system -C packages/system/cozystack-resource-definitions apply cozystack-resource-definitions --plain -cozypkg -n cozy-system -C packages/system/cozystack-api apply cozystack-api --plain -cozypkg -n cozy-system -C packages/system/cozystack-controller/ apply cozystack-api --plain --take-ownership -cozypkg -n cozy-system -C packages/system/lineage-controller-webhook/ apply cozystack-api --plain --take-ownership +if [ -d "packages/system" ]; then + cozypkg -n cozy-system -C packages/system/cozystack-resource-definition-crd apply cozystack-resource-definition-crd --plain + cozypkg -n cozy-system -C packages/system/cozystack-resource-definitions apply cozystack-resource-definitions --plain + cozypkg -n cozy-system -C packages/system/cozystack-api apply cozystack-api --plain + cozypkg -n cozy-system -C packages/system/cozystack-controller/ apply cozystack-api --plain --take-ownership + cozypkg -n cozy-system -C packages/system/lineage-controller-webhook/ apply cozystack-api --plain --take-ownership +fi sleep 5 kubectl delete ns cozy-lineage-webhook-test --ignore-not-found && kubectl create ns cozy-lineage-webhook-test diff --git a/packages/core/platform/images/migrations/migrations/22 b/packages/core/platform/images/migrations/migrations/22 index 53342c42..8e21d5b1 100755 --- a/packages/core/platform/images/migrations/migrations/22 +++ b/packages/core/platform/images/migrations/migrations/22 @@ -106,7 +106,7 @@ kubectl get helmreleases --all-namespaces -o json -l cozystack.io/ui=true | \ prefix=$(printf '%s' "$crd_json" | jq -r '.spec.release.prefix // empty') # Extract application name from HelmRelease name by removing prefix - if [ -n "$prefix" ] && [[ "$name" == "$prefix"* ]]; then + if [ -n "$prefix" ] && [ "${name#$prefix}" != "$name" ]; then app_name="${name#$prefix}" fi fi @@ -118,7 +118,7 @@ kubectl get helmreleases --all-namespaces -o json -l cozystack.io/ui=true | \ for prefix in "mysql-" "postgres-" "redis-" "clickhouse-" "kafka-" "nats-" "rabbitmq-" "ferretdb-" "foundationdb-" \ "virtual-machine-" "vm-instance-" "vm-disk-" "virtualprivatecloud-" "bucket-" "kubernetes-" \ "http-cache-" "tcp-balancer-" "vpn-" "tenant-" "monitoring-" "ingress-" "info-" "etcd-" "seaweedfs-" "bootbox-"; do - if [[ "$name" == "$prefix"* ]]; then + if [ "${name#$prefix}" != "$name" ]; then app_name="${name#$prefix}" # Infer kind from prefix (capitalize and convert to CamelCase) kind_part=$(echo "$prefix" | sed 's/-$//' | sed 's/-\([a-z]\)/\U\1/g' | sed 's/^\([a-z]\)/\U\1/g') @@ -139,15 +139,18 @@ kubectl get helmreleases --all-namespaces -o json -l cozystack.io/ui=true | \ current_labels=$(printf '%s' "$hr_json" | jq -r '.metadata.labels // {}') # Check and add each label if missing - if [ "$(printf '%s' "$current_labels" | jq -r '.["apps.cozystack.io/application.kind"] // empty')" != "$app_kind" ]; then + current_kind=$(printf '%s' "$current_labels" | jq -r '.["apps.cozystack.io/application.kind"] // empty') + if [ "$current_kind" != "$app_kind" ]; then label_patch_ops=$(printf '%s' "$label_patch_ops" | jq --arg kind "$app_kind" '. + [{"op": "add", "path": "/metadata/labels/apps.cozystack.io~1application.kind", "value": $kind}]') fi - if [ "$(printf '%s' "$current_labels" | jq -r '.["apps.cozystack.io/application.group"] // empty")" != "$app_group" ]; then + current_group=$(printf '%s' "$current_labels" | jq -r '.["apps.cozystack.io/application.group"] // empty') + if [ "$current_group" != "$app_group" ]; then label_patch_ops=$(printf '%s' "$label_patch_ops" | jq --arg group "$app_group" '. + [{"op": "add", "path": "/metadata/labels/apps.cozystack.io~1application.group", "value": $group}]') fi - if [ "$(printf '%s' "$current_labels" | jq -r '.["apps.cozystack.io/application.name"] // empty")" != "$app_name" ]; then + current_app_name=$(printf '%s' "$current_labels" | jq -r '.["apps.cozystack.io/application.name"] // empty') + if [ "$current_app_name" != "$app_name" ]; then label_patch_ops=$(printf '%s' "$label_patch_ops" | jq --arg name "$app_name" '. + [{"op": "add", "path": "/metadata/labels/apps.cozystack.io~1application.name", "value": $name}]') fi diff --git a/packages/core/platform/templates/migration-hook.yaml b/packages/core/platform/templates/migration-hook.yaml index 377a5502..d4b3869e 100644 --- a/packages/core/platform/templates/migration-hook.yaml +++ b/packages/core/platform/templates/migration-hook.yaml @@ -18,7 +18,7 @@ metadata: annotations: helm.sh/hook: pre-upgrade helm.sh/hook-weight: "1" - helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation + helm.sh/hook-delete-policy: before-hook-creation spec: backoffLimit: 3 template: diff --git a/packages/core/platform/templates/platform.yaml b/packages/core/platform/templates/platform.yaml index a391ad4b..d2e798b1 100644 --- a/packages/core/platform/templates/platform.yaml +++ b/packages/core/platform/templates/platform.yaml @@ -27,22 +27,3 @@ spec: kind: OCIRepository name: cozystack-packages namespace: cozy-system ---- -apiVersion: helm.toolkit.fluxcd.io/v2 -kind: HelmRelease -metadata: - name: cozystack-platform - namespace: cozy-system -spec: - interval: 5m - targetNamespace: cozy-system - releaseName: cozystack-platform - chartRef: - kind: ExternalArtifact - name: cozystack-core-platform - namespace: cozy-system - values: - sourceRef: - kind: OCIRepository - name: cozystack-packages - namespace: cozy-system diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml index 0a52a3d8..0ce82040 100644 --- a/packages/core/platform/values.yaml +++ b/packages/core/platform/values.yaml @@ -3,5 +3,5 @@ sourceRef: name: cozystack-packages namespace: cozy-system migrations: - image: ghcr.io/cozystack/cozystack/platform-migrations:latest@sha256:a5abc7c70c58b0f7b5e3cfc03f19e5eb9121444299a3dd6e25411a015f28d0af + image: ghcr.io/cozystack/cozystack/platform-migrations:latest@sha256:d096d9d5f9436f084bb2e83800a323ff1bda4c66d6480ecebbec11b61851e97a targetVersion: 23 # Auto-generated by 'make generate' From b328124be7ba580cbdd1d2f9a18e71a4ec8b4eee Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 24 Nov 2025 16:54:56 +0100 Subject: [PATCH 28/46] 1 Signed-off-by: Andrei Kvapil --- .../bundles/system/bundle-minimal.yaml | 2 + packages/core/platform/templates/_helpers.tpl | 107 ++++++++++++++++- packages/core/platform/templates/bundles.yaml | 77 ++++++------- .../templates/containerd-registry-secret.yaml | 35 ++++++ packages/core/platform/templates/cozyrds.yaml | 15 +++ packages/core/platform/values.yaml | 108 +++++++++++++++++- 6 files changed, 300 insertions(+), 44 deletions(-) create mode 100644 packages/core/platform/templates/containerd-registry-secret.yaml create mode 100644 packages/core/platform/templates/cozyrds.yaml diff --git a/packages/core/platform/bundles/system/bundle-minimal.yaml b/packages/core/platform/bundles/system/bundle-minimal.yaml index 3cffad15..1267a7ba 100644 --- a/packages/core/platform/bundles/system/bundle-minimal.yaml +++ b/packages/core/platform/bundles/system/bundle-minimal.yaml @@ -15,6 +15,8 @@ kind: CozystackBundle metadata: name: cozystack-minimal spec: + deletionPolicy: Orphan + dependencyTargets: - name: network packages: [] diff --git a/packages/core/platform/templates/_helpers.tpl b/packages/core/platform/templates/_helpers.tpl index eea49ccc..9da7b11f 100644 --- a/packages/core/platform/templates/_helpers.tpl +++ b/packages/core/platform/templates/_helpers.tpl @@ -18,14 +18,60 @@ Get IP-addresses of master nodes {{- end -}} {{/* -Render a template file with tpl and trim +Apply component overrides to a package and return modified package as YAML +Usage: {{ include "cozystack.apply-package-overrides" (list . $package) }} +*/}} +{{- define "cozystack.apply-package-overrides" -}} +{{- $ := index . 0 }} +{{- $package := index . 1 }} +{{- $packageCopy := deepCopy $package }} +{{- $componentName := $packageCopy.name }} +{{- $component := index $.Values.components $componentName }} +{{- if $component }} + {{- /* Apply enabled/disabled */}} + {{- if hasKey $component "enabled" }} + {{- if not $component.enabled }} + {{- $_ := set $packageCopy "disabled" true }} + {{- else if hasKey $packageCopy "disabled" }} + {{- $_ := unset $packageCopy "disabled" }} + {{- end }} + {{- end }} + {{- /* Apply values override */}} + {{- if $component.values }} + {{- if hasKey $packageCopy "values" }} + {{- $_ := set $packageCopy "values" (deepCopy $packageCopy.values | mergeOverwrite (deepCopy $component.values)) }} + {{- else }} + {{- $_ := set $packageCopy "values" (deepCopy $component.values) }} + {{- end }} + {{- end }} +{{- end }} +{{- $packageCopy | toYaml }} +{{- end -}} + +{{/* +Render a template file with tpl and trim, applying component overrides Usage: {{ include "cozystack.render-file" (list . "bundles/system/bundle-full.yaml") }} */}} {{- define "cozystack.render-file" -}} {{- $ := index . 0 }} {{- $filePath := index . 1 }} +{{- $rendered := trim (tpl ($.Files.Get $filePath) $) }} +{{- $bundle := $rendered | fromYaml }} +{{- if and $bundle $bundle.spec $bundle.spec.packages }} +{{- $modifiedPackages := list }} +{{- range $package := $bundle.spec.packages }} + {{- $modifiedPackageYaml := include "cozystack.apply-package-overrides" (list $ $package) }} + {{- $modifiedPackage := $modifiedPackageYaml | fromYaml }} + {{- $modifiedPackages = append $modifiedPackages $modifiedPackage }} +{{- end }} +{{- $bundleCopy := deepCopy $bundle }} +{{- $_ := set $bundleCopy.spec "packages" $modifiedPackages }} --- -{{ trim (tpl ($.Files.Get $filePath) $) }} +{{ $bundleCopy | toYaml }} +{{- else }} +--- +{{ $rendered }} +{{- end }} {{- end -}} {{/* @@ -40,3 +86,60 @@ Usage: {{ include "cozystack.render-glob" (list . "bundles/system/cozyrds/*.yaml {{ $.Files.Get $path }} {{- end }} {{- end -}} + +{{/* +Check if a component is enabled +Usage: {{ include "cozystack.component-enabled" (list . "metallb") }} +Returns: true if component is enabled, false otherwise +*/}} +{{- define "cozystack.component-enabled" -}} +{{- $ := index . 0 }} +{{- $componentName := index . 1 }} +{{- $component := index $.Values.components $componentName }} +{{- if $component }} + {{- if hasKey $component "enabled" }} + {{- $component.enabled }} + {{- else }} + {{- true }} + {{- end }} +{{- else }} + {{- true }} +{{- end }} +{{- end -}} + +{{/* +Get component values override +Usage: {{ include "cozystack.component-values" (list . "cilium") }} +Returns: YAML string with component values or empty string +*/}} +{{- define "cozystack.component-values" -}} +{{- $ := index . 0 }} +{{- $componentName := index . 1 }} +{{- $component := index $.Values.components $componentName }} +{{- if $component }} + {{- if $component.values }} + {{- toYaml $component.values | nindent 2 }} + {{- end }} +{{- end }} +{{- end -}} + +{{/* +Merge component values into existing values +Usage: {{ include "cozystack.merge-component-values" (list . "cilium" (dict "key" "value")) }} +Returns: Merged values dictionary +*/}} +{{- define "cozystack.merge-component-values" -}} +{{- $ := index . 0 }} +{{- $componentName := index . 1 }} +{{- $defaultValues := index . 2 }} +{{- $component := index $.Values.components $componentName }} +{{- if $component }} + {{- if $component.values }} + {{- mergeOverwrite $defaultValues $component.values }} + {{- else }} + {{- $defaultValues }} + {{- end }} +{{- else }} + {{- $defaultValues }} +{{- end }} +{{- end -}} diff --git a/packages/core/platform/templates/bundles.yaml b/packages/core/platform/templates/bundles.yaml index 024ef7eb..e05907e7 100644 --- a/packages/core/platform/templates/bundles.yaml +++ b/packages/core/platform/templates/bundles.yaml @@ -1,45 +1,40 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- if not $cozyConfig }} - {{- fail "ERROR: cozystack ConfigMap not found in cozy-system namespace" }} -{{- end }} +{{- $systemBundleType := .Values.bundles.system.type | default "full" }} -{{- $bundleName := index $cozyConfig.data "bundle-name" }} -{{- if not $bundleName }} - {{- fail "ERROR: bundle-name not found in cozystack ConfigMap" }} -{{- end }} - -{{- if eq $bundleName "minimal" }} - {{ include "cozystack.render-file" (list . "bundles/system/bundle-minimal.yaml") }} -{{- else if eq $bundleName "paas-full" }} - {{- /* Deploy system-full, iaas, paas, naas bundles */ -}} - {{ include "cozystack.render-file" (list . "bundles/system/bundle-full.yaml") }} - {{ include "cozystack.render-file" (list . "bundles/iaas/bundle.yaml") }} - {{ include "cozystack.render-file" (list . "bundles/paas/bundle.yaml") }} - {{ include "cozystack.render-file" (list . "bundles/naas/bundle.yaml") }} - - {{- /* Deploy all cozyrds */ -}} - {{ include "cozystack.render-glob" (list . "bundles/system/cozyrds/*.yaml") }} - {{ include "cozystack.render-glob" (list . "bundles/iaas/cozyrds/*.yaml") }} - {{ include "cozystack.render-glob" (list . "bundles/paas/cozyrds/*.yaml") }} - {{ include "cozystack.render-glob" (list . "bundles/naas/cozyrds/*.yaml") }} - -{{- else if eq $bundleName "paas-hosted" }} - {{- /* Deploy system-hosted, paas, naas bundles */ -}} - {{ include "cozystack.render-file" (list . "bundles/system/bundle-hosted.yaml") }} - {{ include "cozystack.render-file" (list . "bundles/paas/bundle.yaml") }} - {{ include "cozystack.render-file" (list . "bundles/naas/bundle.yaml") }} - - {{- /* Deploy cozyrds from system, paas, naas (not iaas) */ -}} - {{ include "cozystack.render-glob" (list . "bundles/system/cozyrds/*.yaml") }} - {{ include "cozystack.render-glob" (list . "bundles/paas/cozyrds/*.yaml") }} - {{ include "cozystack.render-glob" (list . "bundles/naas/cozyrds/*.yaml") }} - -{{- else if eq $bundleName "distro-full" }} - {{- fail "ERROR: bundle-name 'distro-full' is deprecated and has been removed. Please use 'paas-full' instead." }} - -{{- else if eq $bundleName "distro-hosted" }} - {{- fail "ERROR: bundle-name 'distro-hosted' is deprecated and has been removed. Please use 'paas-hosted' instead." }} +{{- /* ====================================================================== */}} +{{- /* System Bundle Deployment */}} +{{- /* ====================================================================== */}} +{{- if eq $systemBundleType "minimal" }} +{{ include "cozystack.render-file" (list . "bundles/system/bundle-minimal.yaml") }} +{{- else if eq $systemBundleType "full" }} +{{ include "cozystack.render-file" (list . "bundles/system/bundle-full.yaml") }} +{{- else if eq $systemBundleType "hosted" }} +{{ include "cozystack.render-file" (list . "bundles/system/bundle-hosted.yaml") }} {{- else }} - {{- fail (printf "ERROR: unknown bundle-name '%s'. Supported values: 'minimal', 'paas-full', 'paas-hosted'" $bundleName) }} +{{- fail (printf "ERROR: unknown system bundle type '%s'. Supported values: 'minimal', 'full', 'hosted'" $systemBundleType) }} {{- end }} + +{{- /* IaaS bundle: only available with system type "full" */}} +{{- if .Values.bundles.iaas.enabled }} +{{- if ne $systemBundleType "full" }} +{{- fail "ERROR: iaas bundle can only be used with system bundle type 'full'" }} +{{- end }} +{{ include "cozystack.render-file" (list . "bundles/iaas/bundle.yaml") }} +{{- end }} + +{{- /* PaaS bundle: only available with system type "full" or "hosted" */}} +{{- if .Values.bundles.paas.enabled }} +{{- if and (ne $systemBundleType "full") (ne $systemBundleType "hosted") }} +{{- fail "ERROR: paas bundle can only be used with system bundle type 'full' or 'hosted'" }} +{{- end }} +{{ include "cozystack.render-file" (list . "bundles/paas/bundle.yaml") }} +{{- end }} + +{{- /* NaaS bundle: only available with system type "full" or "hosted" */}} +{{- if .Values.bundles.naas.enabled }} +{{- if and (ne $systemBundleType "full") (ne $systemBundleType "hosted") }} +{{- fail "ERROR: naas bundle can only be used with system bundle type 'full' or 'hosted'" }} +{{- end }} +{{ include "cozystack.render-file" (list . "bundles/naas/bundle.yaml") }} +{{- end }} + diff --git a/packages/core/platform/templates/containerd-registry-secret.yaml b/packages/core/platform/templates/containerd-registry-secret.yaml new file mode 100644 index 00000000..6e9fb640 --- /dev/null +++ b/packages/core/platform/templates/containerd-registry-secret.yaml @@ -0,0 +1,35 @@ +{{- if .Values.registries.mirrors }} +apiVersion: v1 +kind: Secret +metadata: + name: patch-containerd + namespace: cozy-system +type: Opaque +stringData: +{{- range $registry, $mirror := .Values.registries.mirrors }} +{{- if $mirror.endpoints }} + {{ $registry }}.toml: | + server = "https://{{ $registry }}" +{{- range $endpoint := $mirror.endpoints }} + [host."{{ $endpoint }}"] + capabilities = ["pull", "resolve"] +{{- $endpointConfig := index $.Values.registries.config $endpoint }} +{{- if $endpointConfig }} +{{- if $endpointConfig.tls }} +{{- if $endpointConfig.tls.insecureSkipVerify }} + skip_verify = true +{{- end }} +{{- end }} +{{- if $endpointConfig.auth }} + [host."{{ $endpoint }}".auth] + username = "{{ $endpointConfig.auth.username }}" + password = "{{ $endpointConfig.auth.password }}" +{{- end }} +{{- else }} + skip_verify = true +{{- end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} + diff --git a/packages/core/platform/templates/cozyrds.yaml b/packages/core/platform/templates/cozyrds.yaml new file mode 100644 index 00000000..e838bd45 --- /dev/null +++ b/packages/core/platform/templates/cozyrds.yaml @@ -0,0 +1,15 @@ +{{- $systemBundleType := .Values.bundles.system.type | default "full" }} + +{{- if or (ne $systemBundleType "full") (ne $systemBundleType "hosted") }} +{{ include "cozystack.render-glob" (list . "bundles/system/cozyrds/*.yaml") }} +{{- end }} + +{{- if .Values.bundles.iaas.enabled }} +{{ include "cozystack.render-glob" (list . "bundles/iaas/cozyrds/*.yaml") }} +{{- end }} +{{- if .Values.bundles.paas.enabled }} +{{ include "cozystack.render-glob" (list . "bundles/paas/cozyrds/*.yaml") }} +{{- end }} +{{- if .Values.bundles.naas.enabled }} +{{ include "cozystack.render-glob" (list . "bundles/naas/cozyrds/*.yaml") }} +{{- end }} diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml index 0ce82040..ed7857f1 100644 --- a/packages/core/platform/values.yaml +++ b/packages/core/platform/values.yaml @@ -2,6 +2,112 @@ sourceRef: kind: OCIRepository name: cozystack-packages namespace: cozy-system + migrations: image: ghcr.io/cozystack/cozystack/platform-migrations:latest@sha256:d096d9d5f9436f084bb2e83800a323ff1bda4c66d6480ecebbec11b61851e97a - targetVersion: 23 # Auto-generated by 'make generate' + targetVersion: 23 + +# Bundle deployment configuration +bundles: + system: + type: "full" # "hosted", or "minimal" + iaas: + enabled: true + paas: + enabled: true + naas: + enabled: true + +# Infrastructure components configuration +components: + metallb: + enabled: false + hetzner-robotlb: + enabled: true + cilium: + enabled: true + values: + k8sServiceHost: "" + k8sServicePort: 6443 + +# Network configuration +networking: + clusterDomain: "cozy.local" + podCIDR: "10.244.0.0/16" + podGateway: "10.244.0.1" + serviceCIDR: "10.96.0.0/16" + joinCIDR: "100.64.0.0/16" + +# Service publishing and ingress configuration +publishing: + host: "example.org" + ingressName: tenant-root + exposedServices: + - api + - dashboard + - vm-exportproxy + - cdi-uploadproxy + apiServerEndpoint: "" + externalIPs: [] + certificates: + issuerType: http01 # "http01" or "cloudflare" + +# Telemetry configuration +telemetry: + enabled: true + +# Authentication configuration +authentication: + oidc: + enabled: false + dashboard: + extraRedirectUris: [] + +# Pod scheduling configuration +scheduling: + topologySpreadConstraints: [] + +# UI branding configuration +branding: + dashboard: + tenantText: "v0.38.0-alpha.1" + footerText: "Cozystack" + titleText: "Cozystack Dashboard" + logoText: "" + logoSvg: "" + iconSvg: "" + keycloak: + displayName: "" + displayHtmlName: "" + +# Container registry mirrors configuration +# +# Example: +# registries: +# mirrors: +# docker.io: +# endpoints: +# - http://10.0.0.1:8082 +# ghcr.io: +# endpoints: +# - http://10.0.0.1:8083 +# gcr.io: +# endpoints: +# - http://10.0.0.1:8084 +# registry.k8s.io: +# endpoints: +# - http://10.0.0.1:8085 +# quay.io: +# endpoints: +# - http://10.0.0.1:8086 +# cr.fluentbit.io: +# endpoints: +# - http://10.0.0.1:8087 +# docker-registry3.mariadb.com: +# endpoints: +# - http://10.0.0.1:8088 +# config: +# "10.0.0.1:8082": +# tls: +# insecureSkipVerify: true +registries: {} From 45bd323c6e655abc1526b7aa5511b8cc6f74d87f Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 24 Nov 2025 18:20:48 +0100 Subject: [PATCH 29/46] [platform] Get rid of lookups Signed-off-by: Andrei Kvapil --- api/v1alpha1/cozystacksystembundles_types.go | 5 + hack/update-crd.sh | 24 ++-- internal/operator/bundle_reconciler.go | 26 ++++- .../apps/tenant/templates/keycloakgroups.yaml | 8 +- packages/core/cozystack-operator/values.yaml | 2 +- packages/core/installer/values.yaml | 2 +- .../core/platform/bundles/iaas/bundle.yaml | 28 +++-- .../core/platform/bundles/paas/bundle.yaml | 12 +- .../platform/bundles/system/bundle-full.yaml | 68 +++++++++--- .../bundles/system/bundle-hosted.yaml | 59 ++++++++-- .../bundles/system/bundle-minimal.yaml | 35 ++++-- packages/core/platform/values.yaml | 63 +++++------ packages/system/bucket/templates/ingress.yaml | 6 +- .../templates/cluster-issuers.yaml | 6 +- .../cozystack-api/templates/api-ingress.yaml | 14 ++- .../system/dashboard/templates/configmap.yaml | 23 ++-- .../dashboard/templates/gatekeeper.yaml | 14 ++- .../system/dashboard/templates/ingress.yaml | 17 ++- .../dashboard/templates/keycloakclient.yaml | 17 ++- .../dashboard/templates/nginx-config.yaml | 8 +- .../templates/configure-kk.yaml | 27 +++-- packages/system/keycloak/templates/db.yaml | 14 ++- .../system/keycloak/templates/ingress.yaml | 13 ++- packages/system/keycloak/templates/sts.yaml | 11 +- packages/system/kubeovn/Makefile | 1 - .../kube-ovn/templates/controller-deploy.yaml | 38 +++++-- .../charts/kube-ovn/templates/ovncni-ds.yaml | 11 +- .../kubeovn/charts/kube-ovn/values.yaml | 4 + .../system/kubeovn/patches/cozyconfig.diff | 103 ------------------ .../templates/cdi-uploadproxy-ingress.yaml | 15 ++- .../templates/vm-exportproxy-ingress.yaml | 14 ++- 31 files changed, 391 insertions(+), 297 deletions(-) delete mode 100644 packages/system/kubeovn/patches/cozyconfig.diff diff --git a/api/v1alpha1/cozystacksystembundles_types.go b/api/v1alpha1/cozystacksystembundles_types.go index 378e23eb..b6cb9b08 100644 --- a/api/v1alpha1/cozystacksystembundles_types.go +++ b/api/v1alpha1/cozystacksystembundles_types.go @@ -212,4 +212,9 @@ type BundleRelease struct { // 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"` } diff --git a/hack/update-crd.sh b/hack/update-crd.sh index 4df190c5..b754006d 100755 --- a/hack/update-crd.sh +++ b/hack/update-crd.sh @@ -8,7 +8,7 @@ need yq; need jq; need base64 CHART_YAML="${CHART_YAML:-Chart.yaml}" VALUES_YAML="${VALUES_YAML:-values.yaml}" SCHEMA_JSON="${SCHEMA_JSON:-values.schema.json}" -CRD_DIR="../../system/cozystack-resource-definitions/cozyrds" +CRD_DIR="../../core/platform/bundles/*/cozyrds" [[ -f "$CHART_YAML" ]] || { echo "No $CHART_YAML found"; exit 1; } [[ -f "$SCHEMA_JSON" ]] || { echo "No $SCHEMA_JSON found"; exit 1; } @@ -54,20 +54,9 @@ fi # Base64 (portable: no -w / -b options) ICON_B64="$(base64 < "$ICON_PATH" | tr -d '\n' | tr -d '\r')" -# Decide which ExternalArtifact name to use based on path -# .../apps/... -> apps- -# .../extra/... -> extra- -# default: apps- -ARTIFACT_PREFIX="apps" -case "$PWD" in - *"/apps/"*) ARTIFACT_PREFIX="apps" ;; - *"/extra/"*) ARTIFACT_PREFIX="extra" ;; -esac -ARTIFACT_NAME="${ARTIFACT_PREFIX}-${NAME}" - -# If file doesn't exist, create a minimal skeleton -OUT="${OUT:-$CRD_DIR/$NAME.yaml}" -if [[ ! -f "$OUT" ]]; then +# Find path to output CRD YAML +OUT="$(find $CRD_DIR -type f -name "${NAME}.yaml" | head -n 1)" +if [[ ! -s "$OUT" ]]; then cat >"$OUT" < Date: Mon, 24 Nov 2025 22:38:46 +0100 Subject: [PATCH 30/46] [platform] Get rid of lookups for apps Signed-off-by: Andrei Kvapil --- ADOPTERS.md | 35 -- CODE_OF_CONDUCT.md | 22 -- CONTRIBUTING.md | 45 --- CONTRIBUTOR_LADDER.md | 151 --------- GOVERNANCE.md | 91 ------ MAINTAINERS.md | 12 - README.md | 75 ----- .../cozystackresourcedefinitions_types.go | 5 + api/v1alpha1/cozystacksystembundles_types.go | 5 + api/v1alpha1/zz_generated.deepcopy.go | 19 ++ cmd/cozystack-controller/main.go | 17 + .../cozystackresource_controller.go | 194 ++++++++++- .../controller/namespace_helm_reconciler.go | 188 +++++++++++ internal/operator/bundle_reconciler.go | 198 ++++++++++-- .../apps/bucket/templates/bucketclaim.yaml | 5 +- .../apps/clickhouse/templates/chkeeper.yaml | 4 +- .../apps/clickhouse/templates/clickhouse.yaml | 4 +- .../apps/ferretdb/templates/postgres.yaml | 16 +- .../apps/foundationdb/templates/cluster.yaml | 4 +- .../apps/kubernetes/templates/cluster.yaml | 22 +- .../helmreleases/monitoring-agents.yaml | 5 +- .../helmreleases/vertical-pod-autoscaler.yaml | 8 +- .../apps/kubernetes/templates/ingress.yaml | 5 +- packages/apps/nats/templates/nats.yaml | 4 +- packages/apps/postgres/templates/db.yaml | 16 +- packages/apps/tenant/templates/etcd.yaml | 3 + packages/apps/tenant/templates/info.yaml | 3 + packages/apps/tenant/templates/ingress.yaml | 3 + .../apps/tenant/templates/monitoring.yaml | 3 + packages/apps/tenant/templates/namespace.yaml | 19 +- packages/apps/tenant/templates/seaweedfs.yaml | 3 + packages/apps/vpn/templates/secret.yaml | 5 +- .../crds/cozystack.io_cozystackbundles.yaml | 20 ++ ...stack.io_cozystackresourcedefinitions.yaml | 5 + packages/core/cozystack-operator/values.yaml | 2 +- packages/core/installer/values.yaml | 2 +- .../platform/bundles/iaas/cozyrds/bucket.yaml | 3 + .../bundles/iaas/cozyrds/kubernetes.yaml | 3 + .../bundles/iaas/cozyrds/virtual-machine.yaml | 3 + .../iaas/cozyrds/virtualprivatecloud.yaml | 3 + .../bundles/iaas/cozyrds/vm-disk.yaml | 3 + .../bundles/iaas/cozyrds/vm-instance.yaml | 3 + .../bundles/naas/cozyrds/http-cache.yaml | 3 + .../bundles/naas/cozyrds/tcp-balancer.yaml | 3 + .../platform/bundles/naas/cozyrds/vpn.yaml | 3 + .../bundles/paas/cozyrds/clickhouse.yaml | 3 + .../bundles/paas/cozyrds/ferretdb.yaml | 3 + .../bundles/paas/cozyrds/foundationdb.yaml | 3 + .../platform/bundles/paas/cozyrds/kafka.yaml | 3 + .../platform/bundles/paas/cozyrds/mysql.yaml | 3 + .../platform/bundles/paas/cozyrds/nats.yaml | 3 + .../bundles/paas/cozyrds/postgres.yaml | 3 + .../bundles/paas/cozyrds/rabbitmq.yaml | 3 + .../platform/bundles/paas/cozyrds/redis.yaml | 3 + .../platform/bundles/system/bundle-full.yaml | 9 + .../bundles/system/bundle-hosted.yaml | 9 + .../bundles/system/cozyrds/bootbox.yaml | 3 + .../platform/bundles/system/cozyrds/etcd.yaml | 3 + .../platform/bundles/system/cozyrds/info.yaml | 3 + .../bundles/system/cozyrds/ingress.yaml | 3 + .../bundles/system/cozyrds/monitoring.yaml | 3 + .../bundles/system/cozyrds/seaweedfs.yaml | 3 + .../bundles/system/cozyrds/tenant.yaml | 3 + packages/core/platform/templates/_helpers.tpl | 37 ++- .../bootbox/templates/matchbox/ingress.yaml | 11 +- .../bootbox/templates/matchbox/machines.yaml | 10 +- .../extra/etcd/templates/etcd-cluster.yaml | 16 +- .../info/templates/dashboard-resourcemap.yaml | 4 +- packages/extra/info/templates/kubeconfig.yaml | 8 +- .../ingress/templates/nginx-ingress.yaml | 8 +- .../templates/alerta/alerta-db.yaml | 16 +- .../monitoring/templates/alerta/alerta.yaml | 11 +- .../monitoring/templates/grafana/db.yaml | 16 +- .../monitoring/templates/grafana/grafana.yaml | 11 +- .../templates/client/cosi-deployment.yaml | 7 +- .../extra/seaweedfs/templates/ingress.yaml | 11 +- .../extra/seaweedfs/templates/seaweedfs.yaml | 7 +- .../system/bootbox/templates/bootbox.yaml | 3 + packages/system/bucket/templates/ingress.yaml | 6 +- packages/system/cozystack-api/values.yaml | 2 +- .../system/cozystack-controller/values.yaml | 2 +- pkg/registry/apps/application/rest.go | 303 +++++++++++++++++- .../apps/application/rest_defaulting.go | 14 +- 83 files changed, 1212 insertions(+), 602 deletions(-) delete mode 100644 ADOPTERS.md delete mode 100644 CODE_OF_CONDUCT.md delete mode 100644 CONTRIBUTING.md delete mode 100644 CONTRIBUTOR_LADDER.md delete mode 100644 GOVERNANCE.md delete mode 100644 MAINTAINERS.md delete mode 100644 README.md create mode 100644 internal/controller/namespace_helm_reconciler.go diff --git a/ADOPTERS.md b/ADOPTERS.md deleted file mode 100644 index 542e984b..00000000 --- a/ADOPTERS.md +++ /dev/null @@ -1,35 +0,0 @@ -# Adopters - -Below you can find a list of organizations and users who have agreed to -tell the world that they are using Cozystack in a production environment. - -The goal of this list is to inspire others to do the same and to grow -this open source community and project. - -Please add your organization to this list. It takes 5 minutes of your time, -but it means a lot to us. - -## Updating this list - -To add your organization to this list, you can either: - -- [open a pull request](https://github.com/cozystack/cozystack/pulls) to directly update this file, or -- [edit this file](https://github.com/cozystack/cozystack/blob/main/ADOPTERS.md) directly in GitHub - -Feel free to ask in the Slack chat if you any questions and/or require -assistance with updating this list. - -## Cozystack Adopters - -This list is sorted in chronological order, based on the submission date. - -| Organization | Contact | Date | Description of Use | -| ------------ | ------- | ---- | ------------------ | -| [Ænix](https://aenix.io/) | @kvaps | 2024-02-14 | Ænix provides consulting services for cloud providers and uses Cozystack as the main tool for organizing managed services for them. | -| [Mediatech](https://mediatech.dev/) | @ugenk | 2024-05-01 | We're developing and hosting software for our and our custmer services. We're using cozystack as a kubernetes distribution for that. | -| [Bootstack](https://bootstack.app/) | @mrkhachaturov | 2024-08-01| At Bootstack, we utilize a Kubernetes operator specifically designed to simplify and streamline cloud infrastructure creation.| -| [gohost](https://gohost.kz/) | @karabass_off | 2024-02-01 | Our company has been working in the market of Kazakhstan for more than 15 years, providing clients with a standard set of services: VPS/VDC, IaaS, shared hosting, etc. Now we are expanding the lineup by introducing Bare Metal Kubenetes cluster under Cozystack management. | -| [Urmanac](https://urmanac.com) | @kingdonb | 2024-12-04 | Urmanac is the future home of a hosting platform for the knowledge base of a community of personal server enthusiasts. We use Cozystack to provide support services for web sites hosted using both conventional deployments and on SpinKube, with WASM. | -| [Hidora](https://hikube.cloud) | @matthieu-robin | 2025-09-17 | Hidora is a Swiss cloud provider delivering managed services and infrastructure solutions through datacenters located in Switzerland, ensuring data sovereignty and reliability. Its sovereign cloud platform, Hikube, is designed to run workloads with high availability across multiple datacenters, providing enterprises with a secure and scalable foundation for their applications based on Cozystack. | -| [QOSI](https://qosi.kz) | @tabu-a | 2025-10-04 | QOSI is a non-profit organization driving open-source adoption and digital sovereignty across Kazakhstan and Central Asia. We use Cozystack as a platform for deploying sovereign, GPU-enabled clouds and educational environments under the National AI Program. Our goal is to accelerate the region’s transition toward open, self-hosted cloud-native technologies | -| \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 47ffec55..00000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,22 +0,0 @@ -# Code of Conduct - -Cozystack follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). - -# Cozystack Vendor Neutrality Manifesto - -Cozystack exists for the cloud-native community. We are committed to a project culture where no single company, product, or commercial agenda directs our roadmap, governance, brand, or releases. Our North Star is user value, technical excellence, and open collaboration under the CNCF umbrella. - -## Our Commitments - -- **Community-first:** Decisions prioritize the broader community over any vendor interest. -- **Open collaboration:** Ideas, discussions, and outcomes happen in public spaces; contributions are welcomed from all. -- **Merit over affiliation:** Proposals are evaluated on technical merit and user impact, not on who submits them. -- **Inclusive stewardship:** Leadership and maintenance are open to contributors who demonstrate sustained, constructive impact. -- **Technology choice:** We prefer open, pluggable designs that interoperate with multiple ecosystems and providers. -- **Neutral brand & voice:** Our name, logo, website, and documentation do not imply endorsement or preference for any vendor. -- **Transparent practices:** Funding acknowledgments, partnerships, and potential conflicts are communicated openly. -- **User trust:** Security handling, releases, and communications aim to be timely, transparent, and fair to all users. - -By contributing to Cozystack, we affirm these principles and work together to keep the project open, welcoming, and vendor-neutral. - -*— The Cozystack community* diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index d0eb9b94..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,45 +0,0 @@ -# Contributing to Cozystack - -Welcome! We are glad that you want to contribute to our Cozystack project! 💖 - -As you get started, you are in the best position to give us feedbacks on areas of our project that we need help with, including: - -* Problems found while setting up the development environment -* Gaps in our documentation -* Bugs in our GitHub actions - -First, though, it is important that you read the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). - -The guidelines below are a starting point. We don't want to limit your -creativity, passion, and initiative. If you think there's a better way, please -feel free to bring it up in a GitHub discussion, or open a pull request. We're -certain there are always better ways to do things, we just need to start some -constructive dialogue! - -## Ways to contribute - -We welcome many types of contributions including: - -* New features -* Builds, CI/CD -* Bug fixes -* [Documentation](https://GitHub.com/cozystack/cozystack-website/tree/main) -* Issue Triage -* Answering questions on Slack or GitHub Discussions -* Web design -* Communications / Social Media / Blog Posts -* Events participation -* Release management - -## Ask for Help - -The best way to reach us with a question when contributing is to drop a line in -our [Telegram channel](https://t.me/cozystack), or start a new GitHub discussion. - -## Raising Issues - -When raising issues, please specify the following: - -- A scenario where the issue occurred (with details on how to reproduce it) -- Errors and log messages that are displayed by the involved software -- Any other detail that might be useful diff --git a/CONTRIBUTOR_LADDER.md b/CONTRIBUTOR_LADDER.md deleted file mode 100644 index e41f6a93..00000000 --- a/CONTRIBUTOR_LADDER.md +++ /dev/null @@ -1,151 +0,0 @@ -# Contributor Ladder - -* [Contributor Ladder](#contributor-ladder) - * [Community Participant](#community-participant) - * [Contributor](#contributor) - * [Reviewer](#reviewer) - * [Maintainer](#maintainer) -* [Inactivity](#inactivity) -* [Involuntary Removal](#involuntary-removal-or-demotion) -* [Stepping Down/Emeritus Process](#stepping-downemeritus-process) -* [Contact](#contact) - - -## Contributor Ladder - -Hello! We are excited that you want to learn more about our project contributor ladder! This contributor ladder outlines the different contributor roles within the project, along with the responsibilities and privileges that come with them. Community members generally start at the first levels of the "ladder" and advance up it as their involvement in the project grows. Our project members are happy to help you advance along the contributor ladder. - -Each of the contributor roles below is organized into lists of three types of things. "Responsibilities" are things that a contributor is expected to do. "Requirements" are qualifications a person needs to meet to be in that role, and "Privileges" are things contributors on that level are entitled to. - - -### Community Participant -Description: A Community Participant engages with the project and its community, contributing their time, thoughts, etc. Community participants are usually users who have stopped being anonymous and started being active in project discussions. - -* Responsibilities: - * Must follow the [CNCF CoC](https://github.com/cncf/foundation/blob/main/code-of-conduct.md) -* How users can get involved with the community: - * Participating in community discussions - * Helping other users - * Submitting bug reports - * Commenting on issues - * Trying out new releases - * Attending community events - - -### Contributor -Description: A Contributor contributes directly to the project and adds value to it. Contributions need not be code. People at the Contributor level may be new contributors, or they may only contribute occasionally. - -* Responsibilities include: - * Follow the [CNCF CoC](https://github.com/cncf/foundation/blob/main/code-of-conduct.md) - * Follow the project [contributing guide] (https://github.com/cozystack/cozystack/blob/main/CONTRIBUTING.md) -* Requirements (one or several of the below): - * Report and sometimes resolve issues - * Occasionally submit PRs - * Contribute to the documentation - * Show up at meetings, takes notes - * Answer questions from other community members - * Submit feedback on issues and PRs - * Test releases and patches and submit reviews - * Run or helps run events - * Promote the project in public - * Help run the project infrastructure -* Privileges: - * Invitations to contributor events - * Eligible to become a Maintainer - - -### Reviewer -Description: A Reviewer has responsibility for specific code, documentation, test, or other project areas. They are collectively responsible, with other Reviewers, for reviewing all changes to those areas and indicating whether those changes are ready to merge. They have a track record of contribution and review in the project. - -Reviewers are responsible for a "specific area." This can be a specific code directory, driver, chapter of the docs, test job, event, or other clearly-defined project component that is smaller than an entire repository or subproject. Most often it is one or a set of directories in one or more Git repositories. The "specific area" below refers to this area of responsibility. - -Reviewers have all the rights and responsibilities of a Contributor, plus: - -* Responsibilities include: - * Continues to contribute regularly, as demonstrated by having at least 15 PRs a year, as demonstrated by [Cozystack devstats](https://cozystack.devstats.cncf.io). - * Following the reviewing guide - * Reviewing most Pull Requests against their specific areas of responsibility - * Reviewing at least 40 PRs per year - * Helping other contributors become reviewers -* Requirements: - * Must have successful contributions to the project, including at least one of the following: - * 10 accepted PRs, - * Reviewed 20 PRs, - * Resolved and closed 20 Issues, - * Become responsible for a key project management area, - * Or some equivalent combination or contribution - * Must have been contributing for at least 6 months - * Must be actively contributing to at least one project area - * Must have two sponsors who are also Reviewers or Maintainers, at least one of whom does not work for the same employer - * Has reviewed, or helped review, at least 20 Pull Requests - * Has analyzed and resolved test failures in their specific area - * Has demonstrated an in-depth knowledge of the specific area - * Commits to being responsible for that specific area - * Is supportive of new and occasional contributors and helps get useful PRs in shape to commit -* Additional privileges: - * Has GitHub or CI/CD rights to approve pull requests in specific directories - * Can recommend and review other contributors to become Reviewers - * May be assigned Issues and Reviews - * May give commands to CI/CD automation - * Can recommend other contributors to become Reviewers - - -The process of becoming a Reviewer is: -1. The contributor is nominated by opening a PR against the appropriate repository, which adds their GitHub username to the OWNERS file for one or more directories. -2. At least two members of the team that owns that repository or main directory, who are already Approvers, approve the PR. - - -### Maintainer -Description: Maintainers are very established contributors who are responsible for the entire project. As such, they have the ability to approve PRs against any area of the project, and are expected to participate in making decisions about the strategy and priorities of the project. - -A Maintainer must meet the responsibilities and requirements of a Reviewer, plus: - -* Responsibilities include: - * Reviewing at least 40 PRs per year, especially PRs that involve multiple parts of the project - * Mentoring new Reviewers - * Writing refactoring PRs - * Participating in CNCF maintainer activities - * Determining strategy and policy for the project - * Participating in, and leading, community meetings -* Requirements - * Experience as a Reviewer for at least 6 months - * Demonstrates a broad knowledge of the project across multiple areas - * Is able to exercise judgment for the good of the project, independent of their employer, friends, or team - * Mentors other contributors - * Can commit to spending at least 10 hours per month working on the project -* Additional privileges: - * Approve PRs to any area of the project - * Represent the project in public as a Maintainer - * Communicate with the CNCF on behalf of the project - * Have a vote in Maintainer decision-making meetings - - -Process of becoming a maintainer: -1. Any current Maintainer may nominate a current Reviewer to become a new Maintainer, by opening a PR against the root of the cozystack repository adding the nominee as an Approver in the [MAINTAINERS](https://github.com/cozystack/cozystack/blob/main/MAINTAINERS.md) file. -2. The nominee will add a comment to the PR testifying that they agree to all requirements of becoming a Maintainer. -3. A majority of the current Maintainers must then approve the PR. - - -## Inactivity -It is important for contributors to be and stay active to set an example and show commitment to the project. Inactivity is harmful to the project as it may lead to unexpected delays, contributor attrition, and a lost of trust in the project. - -* Inactivity is measured by: - * Periods of no contributions for longer than 6 months - * Periods of no communication for longer than 3 months -* Consequences of being inactive include: - * Involuntary removal or demotion - * Being asked to move to Emeritus status - -## Involuntary Removal or Demotion - -Involuntary removal/demotion of a contributor happens when responsibilities and requirements aren't being met. This may include repeated patterns of inactivity, extended period of inactivity, a period of failing to meet the requirements of your role, and/or a violation of the Code of Conduct. This process is important because it protects the community and its deliverables while also opens up opportunities for new contributors to step in. - -Involuntary removal or demotion is handled through a vote by a majority of the current Maintainers. - -## Stepping Down/Emeritus Process -If and when contributors' commitment levels change, contributors can consider stepping down (moving down the contributor ladder) vs moving to emeritus status (completely stepping away from the project). - -Contact the Maintainers about changing to Emeritus status, or reducing your contributor level. - -## Contact -* For inquiries, please reach out to: @kvaps, @tym83 diff --git a/GOVERNANCE.md b/GOVERNANCE.md deleted file mode 100644 index 3fa81317..00000000 --- a/GOVERNANCE.md +++ /dev/null @@ -1,91 +0,0 @@ -# Cozystack Governance - -This document defines the governance structure of the Cozystack community, outlining how members collaborate to achieve shared goals. - -## Overview - -**Cozystack**, a Cloud Native Computing Foundation (CNCF) project, is committed -to building an open, inclusive, productive, and self-governing open source -community focused on building a high-quality open source PaaS and framework for building clouds. - -## Code Repositories - -The following code repositories are governed by the Cozystack community and -maintained under the `cozystack` namespace: - -* **[Cozystack](https://github.com/cozystack/cozystack):** Main Cozystack codebase -* **[website](https://github.com/cozystack/website):** Cozystack website and documentation sources -* **[Talm](https://github.com/cozystack/talm):** Tool for managing Talos Linux the GitOps way -* **[cozy-proxy](https://github.com/cozystack/cozy-proxy):** A simple kube-proxy addon for 1:1 NAT services in Kubernetes with NFT backend -* **[cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server):** Cozystack telemetry -* **[talos-bootstrap](https://github.com/cozystack/talos-bootstrap):** An interactive Talos Linux installer -* **[talos-meta-tool](https://github.com/cozystack/talos-meta-tool):** Tool for writing network metadata into META partition - -## Community Roles - -* **Users:** Members that engage with the Cozystack community via any medium, including Slack, Telegram, GitHub, and mailing lists. -* **Contributors:** Members contributing to the projects by contributing and reviewing code, writing documentation, - responding to issues, participating in proposal discussions, and so on. -* **Directors:** Non-technical project leaders. -* **Maintainers**: Technical project leaders. - -## Contributors - -Cozystack is for everyone. Anyone can become a Cozystack contributor simply by -contributing to the project, whether through code, documentation, blog posts, -community management, or other means. -As with all Cozystack community members, contributors are expected to follow the -[Cozystack Code of Conduct](https://github.com/cozystack/cozystack/blob/main/CODE_OF_CONDUCT.md). - -All contributions to Cozystack code, documentation, or other components in the -Cozystack GitHub organisation must follow the -[contributing guidelines](https://github.com/cozystack/cozystack/blob/main/CONTRIBUTING.md). -Whether these contributions are merged into the project is the prerogative of the maintainers. - -## Directors - -Directors are responsible for non-technical leadership functions within the project. -This includes representing Cozystack and its maintainers to the community, to the press, -and to the outside world; interfacing with CNCF and other governance entities; -and participating in project decision-making processes when appropriate. - -Directors are elected by a majority vote of the maintainers. - -## Maintainers - -Maintainers have the right to merge code into the project. -Anyone can become a Cozystack maintainer (see "Becoming a maintainer" below). - -### Expectations - -Cozystack maintainers are expected to: - -* Review pull requests, triage issues, and fix bugs in their areas of - expertise, ensuring that all changes go through the project's code review - and integration processes. -* Monitor cncf-cozystack-* emails, the Cozystack Slack channels in Kubernetes - and CNCF Slack workspaces, Telegram groups, and help out when possible. -* Rapidly respond to any time-sensitive security release processes. -* Attend Cozystack community meetings. - -If a maintainer is no longer interested in or cannot perform the duties -listed above, they should move themselves to emeritus status. -If necessary, this can also occur through the decision-making process outlined below. - -### Becoming a Maintainer - -Anyone can become a Cozystack maintainer. Maintainers should be extremely -proficient in cloud native technologies and/or Go; have relevant domain expertise; -have the time and ability to meet the maintainer's expectations above; -and demonstrate the ability to work with the existing maintainers and project processes. - -To become a maintainer, start by expressing interest to existing maintainers. -Existing maintainers will then ask you to demonstrate the qualifications above -by contributing PRs, doing code reviews, and other such tasks under their guidance. -After several months of working together, maintainers will decide whether to grant maintainer status. - -## Project Decision-making Process - -Ideally, all project decisions are resolved by consensus of maintainers and directors. -If this is not possible, a vote will be called. -The voting process is a simple majority in which each maintainer and director receives one vote. diff --git a/MAINTAINERS.md b/MAINTAINERS.md deleted file mode 100644 index 9c44daab..00000000 --- a/MAINTAINERS.md +++ /dev/null @@ -1,12 +0,0 @@ -# The Cozystack Maintainers - -| Maintainer | GitHub Username | Company | Responsibility | -| ---------- | --------------- | ------- | --------------------------------- | -| Andrei Kvapil | [@kvaps](https://github.com/kvaps) | Ænix | Core Maintainer | -| George Gaál | [@gecube](https://github.com/gecube) | Ænix | DevOps Practices in Platform, Developers Advocate | -| Kingdon Barrett | [@kingdonb](https://github.com/kingdonb) | Urmanac | FluxCD and flux-operator | -| Timofei Larkin | [@lllamnyp](https://github.com/lllamnyp) | 3commas | Etcd-operator Lead | -| Artem Bortnikov | [@aobort](https://github.com/aobort) | Timescale | Etcd-operator Lead | -| Timur Tukaev | [@tym83](https://github.com/tym83) | Ænix | Cozystack Website, Marketing, Community Management | -| Kirill Klinchenkov | [@klinch0](https://github.com/klinch0) | Ænix | Core Maintainer | -| Nikita Bykov | [@nbykov0](https://github.com/nbykov0) | Ænix | Maintainer of ARM and stuff | diff --git a/README.md b/README.md deleted file mode 100644 index b81af2a7..00000000 --- a/README.md +++ /dev/null @@ -1,75 +0,0 @@ -![Cozystack](img/cozystack-logo-black.svg#gh-light-mode-only) -![Cozystack](img/cozystack-logo-white.svg#gh-dark-mode-only) - -[![Open Source](https://img.shields.io/badge/Open-Source-brightgreen)](https://opensource.org/) -[![Apache-2.0 License](https://img.shields.io/github/license/cozystack/cozystack)](https://opensource.org/licenses/) -[![Support](https://img.shields.io/badge/$-support-12a0df.svg?style=flat)](https://cozystack.io/support/) -[![Active](http://img.shields.io/badge/Status-Active-green.svg)](https://github.com/cozystack/cozystack) -[![GitHub Release](https://img.shields.io/github/release/cozystack/cozystack.svg?style=flat)](https://github.com/cozystack/cozystack/releases/latest) -[![GitHub Commit](https://img.shields.io/github/commit-activity/y/cozystack/cozystack)](https://github.com/cozystack/cozystack/graphs/contributors) - -# Cozystack - -**Cozystack** is a free PaaS platform and framework for building clouds. - -Cozystack is a [CNCF Sandbox Level Project](https://www.cncf.io/sandbox-projects/) that was originally built and sponsored by [Ænix](https://aenix.io/). - -With Cozystack, you can transform a bunch of servers into an intelligent system with a simple REST API for spawning Kubernetes clusters, -Database-as-a-Service, virtual machines, load balancers, HTTP caching services, and other services with ease. - -Use Cozystack to build your own cloud or provide a cost-effective development environment. - -![Cozystack user interface](https://cozystack.io/img/screenshot-dark.png) - -## Use-Cases - -* [**Using Cozystack to build a public cloud**](https://cozystack.io/docs/guides/use-cases/public-cloud/) -You can use Cozystack as a backend for a public cloud - -* [**Using Cozystack to build a private cloud**](https://cozystack.io/docs/guides/use-cases/private-cloud/) -You can use Cozystack as a platform to build a private cloud powered by Infrastructure-as-Code approach - -* [**Using Cozystack as a Kubernetes distribution**](https://cozystack.io/docs/guides/use-cases/kubernetes-distribution/) -You can use Cozystack as a Kubernetes distribution for Bare Metal - - -## Documentation - -The documentation is located on the [cozystack.io](https://cozystack.io) website. - -Read the [Getting Started](https://cozystack.io/docs/getting-started/) section for a quick start. - -If you encounter any difficulties, start with the [troubleshooting guide](https://cozystack.io/docs/operations/troubleshooting/) and work your way through the process that we've outlined. - -## Versioning - -Versioning adheres to the [Semantic Versioning](http://semver.org/) principles. -A full list of the available releases is available in the GitHub repository's [Release](https://github.com/cozystack/cozystack/releases) section. - -- [Roadmap](https://cozystack.io/docs/roadmap/) - -## Contributions - -Contributions are highly appreciated and very welcomed! - -In case of bugs, please check if the issue has already been opened by checking the [GitHub Issues](https://github.com/cozystack/cozystack/issues) section. -If it isn't, you can open a new one. A detailed report will help us replicate it, assess it, and work on a fix. - -You can express your intention to on the fix on your own. -Commits are used to generate the changelog, and their author will be referenced in it. - -If you have **Feature Requests** please use the [Discussion's Feature Request section](https://github.com/cozystack/cozystack/discussions/categories/feature-requests). - -## Community - -You are welcome to join our [Telegram group](https://t.me/cozystack) and come to our weekly community meetings. -Add them to your [Google Calendar](https://calendar.google.com/calendar?cid=ZTQzZDIxZTVjOWI0NWE5NWYyOGM1ZDY0OWMyY2IxZTFmNDMzZTJlNjUzYjU2ZGJiZGE3NGNhMzA2ZjBkMGY2OEBncm91cC5jYWxlbmRhci5nb29nbGUuY29t) or [iCal](https://calendar.google.com/calendar/ical/e43d21e5c9b45a95f28c5d649c2cb1e1f433e2e653b56dbbda74ca306f0d0f68%40group.calendar.google.com/public/basic.ics) for convenience. - -## License - -Cozystack is licensed under Apache 2.0. -The code is provided as-is with no warranties. - -## Commercial Support - -A list of companies providing commercial support for this project can be found on [official site](https://cozystack.io/support/). diff --git a/api/v1alpha1/cozystackresourcedefinitions_types.go b/api/v1alpha1/cozystackresourcedefinitions_types.go index 6e71512d..ba035445 100644 --- a/api/v1alpha1/cozystackresourcedefinitions_types.go +++ b/api/v1alpha1/cozystackresourcedefinitions_types.go @@ -18,6 +18,7 @@ package v1alpha1 import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" ) // +kubebuilder:object:root=true @@ -102,6 +103,10 @@ type CozystackResourceDefinitionRelease struct { Labels map[string]string `json:"labels,omitempty"` // Prefix for the release name 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"` } type CozystackResourceDefinitionChartRef struct { diff --git a/api/v1alpha1/cozystacksystembundles_types.go b/api/v1alpha1/cozystacksystembundles_types.go index b6cb9b08..d859e884 100644 --- a/api/v1alpha1/cozystacksystembundles_types.go +++ b/api/v1alpha1/cozystacksystembundles_types.go @@ -217,4 +217,9 @@ type BundleRelease struct { // 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"` } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index f18cfe52..67e218c7 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -104,6 +104,20 @@ func (in *BundleRelease) DeepCopyInto(out *BundleRelease) { *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 + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleRelease. @@ -404,6 +418,11 @@ func (in *CozystackResourceDefinitionRelease) DeepCopyInto(out *CozystackResourc (*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. diff --git a/cmd/cozystack-controller/main.go b/cmd/cozystack-controller/main.go index 220c4da5..fe0fe77e 100644 --- a/cmd/cozystack-controller/main.go +++ b/cmd/cozystack-controller/main.go @@ -216,6 +216,23 @@ func main() { os.Exit(1) } + if err = (&controller.NamespaceHelmReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "NamespaceHelmReconciler") + os.Exit(1) + } + + if err = (&controller.CozystackResourceDefinitionReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + CozystackAPIKind: "Deployment", + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "CozystackResourceDefinitionReconciler") + os.Exit(1) + } + dashboardManager := &dashboard.Manager{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), diff --git a/internal/controller/cozystackresource_controller.go b/internal/controller/cozystackresource_controller.go index 1a41cbe7..3013a005 100644 --- a/internal/controller/cozystackresource_controller.go +++ b/internal/controller/cozystackresource_controller.go @@ -5,6 +5,7 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" + "fmt" "slices" "sync" "time" @@ -14,6 +15,7 @@ import ( 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" @@ -26,6 +28,7 @@ import ( // +kubebuilder:rbac:groups=cozystack.io,resources=cozystackresourcedefinitions,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 CozystackResourceDefinitionReconciler struct { client.Client Scheme *runtime.Scheme @@ -208,23 +211,37 @@ func sortCozyRDs(a, b cozyv1alpha1.CozystackResourceDefinition) int { return 1 } -// updateHelmReleasesForCRD updates all HelmReleases that match the labels from CozystackResourceDefinition +// updateHelmReleasesForCRD updates all HelmReleases that match the application labels from CozystackResourceDefinition func (r *CozystackResourceDefinitionReconciler) updateHelmReleasesForCRD(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) error { logger := log.FromContext(ctx) - // Skip if no labels defined - if len(crd.Spec.Release.Labels) == 0 { - return nil + // 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{} - labelSelector := client.MatchingLabels(crd.Spec.Release.Labels) 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, "count", len(hrList.Items)) + logger.Info("Found HelmReleases to update", "crd", crd.Name, "kind", applicationKind, "count", len(hrList.Items), "hasValues", crd.Spec.Release.Values != nil) + + // 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 { @@ -238,7 +255,7 @@ func (r *CozystackResourceDefinitionReconciler) updateHelmReleasesForCRD(ctx con return nil } -// updateHelmReleaseChart updates the chart/chartRef in HelmRelease based on CozystackResourceDefinition +// updateHelmReleaseChart updates the chart/chartRef and values in HelmRelease based on CozystackResourceDefinition func (r *CozystackResourceDefinitionReconciler) updateHelmReleaseChart(ctx context.Context, hr *helmv2.HelmRelease, crd *cozyv1alpha1.CozystackResourceDefinition) error { logger := log.FromContext(ctx) updated := false @@ -306,6 +323,32 @@ func (r *CozystackResourceDefinitionReconciler) updateHelmReleaseChart(ctx conte } } + // Update Values from CRD if specified + 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 := r.mergeHelmReleaseValues(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) + } + + // After merging, ensure namespace is set from namespace labels (top-level) + // This matches the behavior in cozystack-api and NamespaceHelmReconciler + mergedValues, err = r.injectNamespaceLabelsIntoValues(ctx, mergedValues, hrCopy.Namespace) + if err != nil { + logger.Error(err, "failed to inject namespace labels", "name", hr.Name, "namespace", hr.Namespace) + // Continue even if namespace labels injection fails + } + + // Always update values if CRD has values specified + // This ensures that CRD values are always applied, even if the merged result is the same + hrCopy.Spec.Values = mergedValues + updated = true + logger.Info("Updated values from CRD", "name", hr.Name, "namespace", hr.Namespace, "crd", crd.Name) + } else { + logger.V(4).Info("No values in CRD, skipping values update", "name", hr.Name, "namespace", hr.Namespace, "crd", crd.Name) + } + if !updated { return nil } @@ -316,6 +359,141 @@ func (r *CozystackResourceDefinitionReconciler) updateHelmReleaseChart(ctx conte return err } - logger.Info("Updated HelmRelease chart/chartRef", "name", hr.Name, "namespace", hr.Namespace, "crd", crd.Name) + 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" which is fully overwritten from CRD values +// Existing HelmRelease values (outside of cozystack) take precedence (user values override defaults) +func (r *CozystackResourceDefinitionReconciler) 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 CRD values (defaults) as base + // Then merge existing values on top (existing values override CRD defaults) + // This ensures user values have priority over CRD defaults + merged := deepMergeMaps(crdMap, existingMap) + + // 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) +} + +// injectNamespaceLabelsIntoValues injects namespace.cozystack.io/* labels into namespace (top-level) +// This matches the behavior in cozystack-api and NamespaceHelmReconciler +func (r *CozystackResourceDefinitionReconciler) injectNamespaceLabelsIntoValues(ctx context.Context, values *apiextensionsv1.JSON, namespaceName string) (*apiextensionsv1.JSON, error) { + // Get namespace to extract namespace.cozystack.io/* labels + namespace := &corev1.Namespace{} + if err := r.Get(ctx, client.ObjectKey{Name: namespaceName}, namespace); err != nil { + // If namespace not found, return values as-is + return values, nil + } + + // Extract namespace.cozystack.io/* labels + namespaceLabels := extractNamespaceLabelsFromNamespace(namespace) + if len(namespaceLabels) == 0 { + // No namespace labels, return values as-is + return values, nil + } + + // Parse values + var valuesMap map[string]interface{} + if values != nil && len(values.Raw) > 0 { + if err := json.Unmarshal(values.Raw, &valuesMap); err != nil { + return nil, fmt.Errorf("failed to unmarshal 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 + } + + // Namespace labels completely overwrite existing namespace field (top-level) + valuesMap["namespace"] = namespaceLabelsMap + + // Marshal back to JSON + mergedJSON, err := json.Marshal(valuesMap) + if err != nil { + return nil, fmt.Errorf("failed to marshal values with namespace labels: %w", err) + } + + return &apiextensionsv1.JSON{Raw: mergedJSON}, nil +} diff --git a/internal/controller/namespace_helm_reconciler.go b/internal/controller/namespace_helm_reconciler.go new file mode 100644 index 00000000..e7d60ce0 --- /dev/null +++ b/internal/controller/namespace_helm_reconciler.go @@ -0,0 +1,188 @@ +/* +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" + "strings" + + 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" +) + +// +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/* labels + namespaceLabels := extractNamespaceLabelsFromNamespace(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 +} + +// extractNamespaceLabelsFromNamespace extracts namespace.cozystack.io/* labels from namespace +func extractNamespaceLabelsFromNamespace(ns *corev1.Namespace) map[string]string { + namespaceLabels := make(map[string]string) + prefix := "namespace.cozystack.io/" + + if ns.Labels == nil { + return namespaceLabels + } + + for key, value := range ns.Labels { + if strings.HasPrefix(key, prefix) { + // Remove prefix and add to namespace labels + namespaceKey := strings.TrimPrefix(key, prefix) + namespaceLabels[namespaceKey] = value + } + } + + return namespaceLabels +} + +// 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) +} + diff --git a/internal/operator/bundle_reconciler.go b/internal/operator/bundle_reconciler.go index 56fff751..5698e1fe 100644 --- a/internal/operator/bundle_reconciler.go +++ b/internal/operator/bundle_reconciler.go @@ -18,6 +18,7 @@ package operator import ( "context" + "encoding/json" "errors" "fmt" "strings" @@ -27,13 +28,16 @@ import ( helmv2 "github.com/fluxcd/helm-controller/api/v2" sourcewatcherv1beta1 "github.com/fluxcd/source-watcher/api/v2/v1beta1" corev1 "k8s.io/api/core/v1" + 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" "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" ) // CozystackBundleReconciler reconciles CozystackBundle resources @@ -394,6 +398,12 @@ func (r *CozystackBundleReconciler) reconcileHelmReleases(ctx context.Context, b // Create HelmRelease for each package for _, pkg := range packages { + // Skip disabled packages + if pkg.Disabled { + logger.V(1).Info("skipping disabled package", "name", pkg.Name, "namespace", pkg.Namespace) + continue + } + var artifactName string artifactNamespace := "cozy-system" @@ -603,8 +613,45 @@ func (r *CozystackBundleReconciler) createOrUpdate(ctx context.Context, obj clie if existingHR, ok := existing.(*helmv2.HelmRelease); ok { logger := log.FromContext(ctx) logger.V(1).Info("updating HelmRelease Spec", "name", hr.Name, "namespace", hr.Namespace) - // Update Spec from obj (which contains the desired state with all values and dependsOn) - existingHR.Spec = hr.Spec + + // Check if this HelmRelease is managed through Application API + // If it has apps.cozystack.io/application.* labels, preserve user-modified values + isApplicationManaged := existingHR.Labels["apps.cozystack.io/application.kind"] != "" && + existingHR.Labels["apps.cozystack.io/application.group"] != "" + + if isApplicationManaged { + // For Application-managed HelmReleases, merge values but overwrite cozystack field + logger.V(1).Info("merging values for Application-managed HelmRelease, overwriting cozystack", "name", hr.Name, "namespace", hr.Namespace) + existingHR.Spec.Chart = hr.Spec.Chart + existingHR.Spec.ChartRef = hr.Spec.ChartRef + existingHR.Spec.Interval = hr.Spec.Interval + existingHR.Spec.Timeout = hr.Spec.Timeout + existingHR.Spec.ReleaseName = hr.Spec.ReleaseName + existingHR.Spec.DependsOn = hr.Spec.DependsOn + existingHR.Spec.Install = hr.Spec.Install + existingHR.Spec.Upgrade = hr.Spec.Upgrade + existingHR.Spec.Uninstall = hr.Spec.Uninstall + existingHR.Spec.Rollback = hr.Spec.Rollback + existingHR.Spec.StorageNamespace = hr.Spec.StorageNamespace + existingHR.Spec.KubeConfig = hr.Spec.KubeConfig + existingHR.Spec.TargetNamespace = hr.Spec.TargetNamespace + existingHR.Spec.PostRenderers = hr.Spec.PostRenderers + existingHR.Spec.ServiceAccountName = hr.Spec.ServiceAccountName + existingHR.Spec.Suspend = hr.Spec.Suspend + + // Merge values: merge all fields except cozystack, which is fully overwritten + mergedValues, err := mergeHelmReleaseValues(existingHR.Spec.Values, hr.Spec.Values) + if err != nil { + logger.Error(err, "failed to merge values, using bundle values", "name", hr.Name, "namespace", hr.Namespace) + existingHR.Spec.Values = hr.Spec.Values + } else { + existingHR.Spec.Values = mergedValues + } + } else { + // For bundle-managed HelmReleases, update everything including values + existingHR.Spec = hr.Spec + } + // Preserve metadata updates we made above existingHR.SetLabels(hr.GetLabels()) existingHR.SetAnnotations(hr.GetAnnotations()) @@ -617,6 +664,78 @@ func (r *CozystackBundleReconciler) createOrUpdate(ctx context.Context, obj clie return r.Update(ctx, obj) } +// mergeHelmReleaseValues merges two HelmRelease values JSON objects +// All fields are merged except "cozystack" which is fully overwritten from bundleValues +func mergeHelmReleaseValues(existingValues, bundleValues *apiextensionsv1.JSON) (*apiextensionsv1.JSON, error) { + // If bundle has no values, preserve existing + if bundleValues == nil || len(bundleValues.Raw) == 0 { + return existingValues, nil + } + + // If existing has no values, use bundle values + if existingValues == nil || len(existingValues.Raw) == 0 { + return bundleValues, nil + } + + // Parse both values + var existingMap map[string]interface{} + if err := json.Unmarshal(existingValues.Raw, &existingMap); err != nil { + return nil, fmt.Errorf("failed to unmarshal existing values: %w", err) + } + + var bundleMap map[string]interface{} + if err := json.Unmarshal(bundleValues.Raw, &bundleMap); err != nil { + return nil, fmt.Errorf("failed to unmarshal bundle values: %w", err) + } + + // Merge: start with existing values + mergedMap := deepMergeMaps(existingMap, bundleMap) + + // Overwrite cozystack field completely from bundle + if cozystackVal, exists := bundleMap["cozystack"]; exists { + mergedMap["cozystack"] = cozystackVal + } else { + // If bundle doesn't have cozystack, remove it from merged (optional - could also preserve) + delete(mergedMap, "cozystack") + } + + // Marshal back to JSON + mergedJSON, err := json.Marshal(mergedMap) + 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 +// Values from override map take precedence, but nested maps are merged recursively +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 for non-map values or new keys + result[k] = v + } + + return result +} + // Helper functions func (r *CozystackBundleReconciler) getPackageNameFromPath(path string) string { parts := strings.Split(path, "/") @@ -726,10 +845,13 @@ func (r *CozystackBundleReconciler) cleanupOrphanedHelmReleases(ctx context.Cont return err } - // Build desired names + // Build desired names (excluding disabled packages) desiredNames := make(map[types.NamespacedName]bool) for _, pkg := range bundle.Spec.Packages { - desiredNames[types.NamespacedName{Name: pkg.Name, Namespace: pkg.Namespace}] = true + // Only include non-disabled packages in desired names + if !pkg.Disabled { + desiredNames[types.NamespacedName{Name: pkg.Name, Namespace: pkg.Namespace}] = true + } } // Find HelmReleases with this bundle label @@ -819,8 +941,12 @@ func (r *CozystackBundleReconciler) reconcileNamespaces(ctx context.Context, bun logger := log.FromContext(ctx) // Collect namespaces from packages - // Map: namespace -> isPrivileged (true if at least one package in this namespace is privileged) - namespacesMap := make(map[string]bool) + // Map: namespace -> {isPrivileged, labels} + type namespaceInfo struct { + privileged bool + labels map[string]string + } + namespacesMap := make(map[string]namespaceInfo) for _, pkg := range packages { // Skip disabled packages @@ -833,20 +959,31 @@ func (r *CozystackBundleReconciler) reconcileNamespaces(ctx context.Context, bun continue } - // If package is privileged, mark namespace as privileged - // If namespace already exists and is privileged, keep it privileged - if pkg.Privileged { - namespacesMap[pkg.Namespace] = true - } else { - // Only set to false if not already marked as privileged - if _, exists := namespacesMap[pkg.Namespace]; !exists { - namespacesMap[pkg.Namespace] = false + info, exists := namespacesMap[pkg.Namespace] + if !exists { + info = namespaceInfo{ + privileged: false, + labels: make(map[string]string), } } + + // If package is privileged, mark namespace as privileged + if pkg.Privileged { + info.privileged = true + } + + // Merge namespace labels from package + if pkg.NamespaceLabels != nil { + for k, v := range pkg.NamespaceLabels { + info.labels[k] = v + } + } + + namespacesMap[pkg.Namespace] = info } // Create or update all namespaces - for nsName, privileged := range namespacesMap { + for nsName, info := range namespacesMap { namespace := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: nsName, @@ -860,15 +997,20 @@ func (r *CozystackBundleReconciler) reconcileNamespaces(ctx context.Context, bun } // Add privileged label if needed - if privileged { + if info.privileged { namespace.Labels["pod-security.kubernetes.io/enforce"] = "privileged" } + // Merge namespace labels from packages + for k, v := range info.labels { + namespace.Labels[k] = v + } + if err := r.createOrUpdateNamespace(ctx, namespace); err != nil { - logger.Error(err, "failed to reconcile namespace", "name", nsName, "privileged", privileged) + logger.Error(err, "failed to reconcile namespace", "name", nsName, "privileged", info.privileged) return fmt.Errorf("failed to reconcile namespace %s: %w", nsName, err) } - logger.Info("reconciled namespace", "name", nsName, "privileged", privileged) + logger.Info("reconciled namespace", "name", nsName, "privileged", info.privileged, "labels", info.labels) } return nil @@ -1012,5 +1154,25 @@ func (r *CozystackBundleReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). Named("cozystack-bundle"). For(&cozyv1alpha1.CozystackBundle{}). + Watches( + &helmv2.HelmRelease{}, + handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request { + hr, ok := obj.(*helmv2.HelmRelease) + if !ok { + return nil + } + // Find the bundle that owns this HelmRelease by label + bundleName := hr.Labels["cozystack.io/bundle"] + if bundleName == "" { + return nil + } + // Reconcile the bundle to recreate the HelmRelease if it was deleted + return []reconcile.Request{{ + NamespacedName: types.NamespacedName{ + Name: bundleName, + }, + }} + }), + ). Complete(r) } diff --git a/packages/apps/bucket/templates/bucketclaim.yaml b/packages/apps/bucket/templates/bucketclaim.yaml index cebf95b4..e0ce3b08 100644 --- a/packages/apps/bucket/templates/bucketclaim.yaml +++ b/packages/apps/bucket/templates/bucketclaim.yaml @@ -1,5 +1,6 @@ -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $seaweedfs := index $myNS.metadata.annotations "namespace.cozystack.io/seaweedfs" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $namespace := dig "namespace" (dict) .Values }} +{{- $seaweedfs := dig "seaweedfs" "" $namespace }} apiVersion: objectstorage.k8s.io/v1alpha1 kind: BucketClaim metadata: diff --git a/packages/apps/clickhouse/templates/chkeeper.yaml b/packages/apps/clickhouse/templates/chkeeper.yaml index 54824a44..e2301c6f 100644 --- a/packages/apps/clickhouse/templates/chkeeper.yaml +++ b/packages/apps/clickhouse/templates/chkeeper.yaml @@ -1,5 +1,5 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $clusterDomain := dig "networking" "clusterDomain" "cozy.local" $cozystack }} {{- if .Values.clickhouseKeeper.enabled }} apiVersion: "clickhouse-keeper.altinity.com/v1" diff --git a/packages/apps/clickhouse/templates/clickhouse.yaml b/packages/apps/clickhouse/templates/clickhouse.yaml index 47e5b56a..c78d282e 100644 --- a/packages/apps/clickhouse/templates/clickhouse.yaml +++ b/packages/apps/clickhouse/templates/clickhouse.yaml @@ -1,5 +1,5 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $clusterDomain := dig "networking" "clusterDomain" "cozy.local" $cozystack }} {{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-credentials" .Release.Name) }} {{- $passwords := dict }} {{- $users := .Values.users }} diff --git a/packages/apps/ferretdb/templates/postgres.yaml b/packages/apps/ferretdb/templates/postgres.yaml index 4d1d8e29..5d547a8a 100644 --- a/packages/apps/ferretdb/templates/postgres.yaml +++ b/packages/apps/ferretdb/templates/postgres.yaml @@ -50,15 +50,13 @@ spec: postgresUID: 999 postgresGID: 999 enableSuperuserAccess: true - {{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} - {{- if $configMap }} - {{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }} - {{- if $rawConstraints }} - {{- $rawConstraints | fromYaml | toYaml | nindent 2 }} - labelSelector: - matchLabels: - cnpg.io/cluster: {{ .Release.Name }}-postgres - {{- end }} + {{- $cozystack := .Values.cozystack | default dict }} + {{- $topologySpreadConstraints := dig "scheduling" "topologySpreadConstraints" (list) $cozystack }} + {{- if $topologySpreadConstraints }} + topologySpreadConstraints: + {{- range $topologySpreadConstraints }} + - {{- mergeOverwrite (dict "labelSelector" (dict "matchLabels" (dict "cnpg.io/cluster" (printf "%s-postgres" $.Release.Name)))) . | toYaml | nindent 6 | trim }} + {{- end }} {{- end }} minSyncReplicas: {{ .Values.quorum.minSyncReplicas }} maxSyncReplicas: {{ .Values.quorum.maxSyncReplicas }} diff --git a/packages/apps/foundationdb/templates/cluster.yaml b/packages/apps/foundationdb/templates/cluster.yaml index 06992cb5..0426e29d 100644 --- a/packages/apps/foundationdb/templates/cluster.yaml +++ b/packages/apps/foundationdb/templates/cluster.yaml @@ -1,5 +1,5 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" | default (dict "data" (dict)) }} -{{- $clusterDomain := index $cozyConfig.data "cluster-domain" | default "cozy.local" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $clusterDomain := dig "networking" "clusterDomain" "cozy.local" $cozystack }} --- apiVersion: apps.foundationdb.org/v1beta2 kind: FoundationDBCluster diff --git a/packages/apps/kubernetes/templates/cluster.yaml b/packages/apps/kubernetes/templates/cluster.yaml index 7edd07f5..d5eec651 100644 --- a/packages/apps/kubernetes/templates/cluster.yaml +++ b/packages/apps/kubernetes/templates/cluster.yaml @@ -1,7 +1,8 @@ -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $etcd := index $myNS.metadata.annotations "namespace.cozystack.io/etcd" }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $namespace := dig "namespace" (dict) .Values }} +{{- $etcd := dig "etcd" "" $namespace }} +{{- $ingress := dig "ingress" "" $namespace }} +{{- $host := dig "host" "" $namespace }} {{- $kubevirtmachinetemplateNames := list }} {{- define "kubevirtmachinetemplate" -}} spec: @@ -31,14 +32,11 @@ spec: {{- end }} cluster.x-k8s.io/deployment-name: {{ $.Release.Name }}-{{ .groupName }} spec: - {{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} - {{- if $configMap }} - {{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }} - {{- if $rawConstraints }} - {{- $rawConstraints | fromYaml | toYaml | nindent 10 }} - labelSelector: - matchLabels: - cluster.x-k8s.io/cluster-name: {{ $.Release.Name }} + {{- $cozystack := $.Values.cozystack | default dict }} + {{- $topologySpreadConstraints := dig "scheduling" "topologySpreadConstraints" (list) $cozystack }} + {{- if $topologySpreadConstraints }} + {{- range $topologySpreadConstraints }} + - {{- mergeOverwrite (dict "labelSelector" (dict "matchLabels" (dict "cluster.x-k8s.io/cluster-name" $.Release.Name))) . | toYaml | nindent 12 | trim }} {{- end }} {{- end }} domain: diff --git a/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml b/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml index 39c8e4df..4150f9ed 100644 --- a/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml @@ -1,5 +1,6 @@ -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $targetTenant := index $myNS.metadata.annotations "namespace.cozystack.io/monitoring" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $namespace := dig "namespace" (dict) .Values }} +{{- $targetTenant := dig "monitoring" "" $namespace }} {{- if .Values.addons.monitoringAgents.enabled }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease diff --git a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml index bd4a3f02..0fd7dca9 100644 --- a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml @@ -1,8 +1,8 @@ {{- define "cozystack.defaultVPAValues" -}} -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $targetTenant := index $myNS.metadata.annotations "namespace.cozystack.io/monitoring" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $clusterDomain := dig "networking" "clusterDomain" "cozy.local" $cozystack }} +{{- $namespace := dig "namespace" (dict) .Values }} +{{- $targetTenant := dig "monitoring" "" $namespace }} vpaForVPA: false vertical-pod-autoscaler: recommender: diff --git a/packages/apps/kubernetes/templates/ingress.yaml b/packages/apps/kubernetes/templates/ingress.yaml index 8dd244cb..7774e6dc 100644 --- a/packages/apps/kubernetes/templates/ingress.yaml +++ b/packages/apps/kubernetes/templates/ingress.yaml @@ -1,5 +1,6 @@ -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $namespace := dig "namespace" (dict) .Values }} +{{- $ingress := dig "ingress" "" $namespace }} {{- if and (eq .Values.addons.ingressNginx.exposeMethod "Proxied") .Values.addons.ingressNginx.hosts }} --- apiVersion: networking.k8s.io/v1 diff --git a/packages/apps/nats/templates/nats.yaml b/packages/apps/nats/templates/nats.yaml index 4a09e3c6..40bcbe45 100644 --- a/packages/apps/nats/templates/nats.yaml +++ b/packages/apps/nats/templates/nats.yaml @@ -1,5 +1,5 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $clusterDomain := dig "networking" "clusterDomain" "cozy.local" $cozystack }} {{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-credentials" .Release.Name) }} {{- $passwords := dict }} diff --git a/packages/apps/postgres/templates/db.yaml b/packages/apps/postgres/templates/db.yaml index de4f51a3..cf6d4966 100644 --- a/packages/apps/postgres/templates/db.yaml +++ b/packages/apps/postgres/templates/db.yaml @@ -45,15 +45,13 @@ spec: resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 4 }} enableSuperuserAccess: true - {{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} - {{- if $configMap }} - {{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }} - {{- if $rawConstraints }} - {{- $rawConstraints | fromYaml | toYaml | nindent 2 }} - labelSelector: - matchLabels: - cnpg.io/cluster: {{ .Release.Name }} - {{- end }} + {{- $cozystack := .Values.cozystack | default dict }} + {{- $topologySpreadConstraints := dig "scheduling" "topologySpreadConstraints" (list) $cozystack }} + {{- if $topologySpreadConstraints }} + topologySpreadConstraints: + {{- range $topologySpreadConstraints }} + - {{- mergeOverwrite (dict "labelSelector" (dict "matchLabels" (dict "cnpg.io/cluster" $.Release.Name))) . | toYaml | nindent 6 | trim }} + {{- end }} {{- end }} postgresql: parameters: diff --git a/packages/apps/tenant/templates/etcd.yaml b/packages/apps/tenant/templates/etcd.yaml index d5f760c2..05431fb9 100644 --- a/packages/apps/tenant/templates/etcd.yaml +++ b/packages/apps/tenant/templates/etcd.yaml @@ -9,6 +9,9 @@ metadata: internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} 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: chartRef: kind: ExternalArtifact diff --git a/packages/apps/tenant/templates/info.yaml b/packages/apps/tenant/templates/info.yaml index 89d4403a..41c0555b 100644 --- a/packages/apps/tenant/templates/info.yaml +++ b/packages/apps/tenant/templates/info.yaml @@ -8,6 +8,9 @@ metadata: internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} 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: chartRef: kind: ExternalArtifact diff --git a/packages/apps/tenant/templates/ingress.yaml b/packages/apps/tenant/templates/ingress.yaml index ea8f4953..a620685a 100644 --- a/packages/apps/tenant/templates/ingress.yaml +++ b/packages/apps/tenant/templates/ingress.yaml @@ -9,6 +9,9 @@ metadata: internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} 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: chartRef: kind: ExternalArtifact diff --git a/packages/apps/tenant/templates/monitoring.yaml b/packages/apps/tenant/templates/monitoring.yaml index edf4a769..aa1e1172 100644 --- a/packages/apps/tenant/templates/monitoring.yaml +++ b/packages/apps/tenant/templates/monitoring.yaml @@ -9,6 +9,9 @@ metadata: internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} 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: chartRef: kind: ExternalArtifact diff --git a/packages/apps/tenant/templates/namespace.yaml b/packages/apps/tenant/templates/namespace.yaml index d97ebf42..ef99bb25 100644 --- a/packages/apps/tenant/templates/namespace.yaml +++ b/packages/apps/tenant/templates/namespace.yaml @@ -1,15 +1,21 @@ {{- define "cozystack.namespace-anotations" }} {{- $context := index . 0 }} -{{- $existingNS := index . 1 }} +{{- $namespace := index . 1 }} {{- range $x := list "etcd" "monitoring" "ingress" "seaweedfs" }} {{- if (index $context.Values $x) }} namespace.cozystack.io/{{ $x }}: "{{ include "tenant.name" $context }}" {{- 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 }} +{{- $namespace := dig "namespace" (dict) .Values }} {{- $existingNS := lookup "v1" "Namespace" "" .Release.Namespace }} {{- if not $existingNS }} {{- fail (printf "error lookup existing namespace: %s" .Release.Namespace) }} @@ -26,10 +32,13 @@ metadata: {{- if .Values.host }} namespace.cozystack.io/host: "{{ .Values.host }}" {{- 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 }}" {{- end }} - {{- include "cozystack.namespace-anotations" (list . $existingNS) | nindent 4 }} + {{- include "cozystack.namespace-anotations" (list . $namespace) | nindent 4 }} labels: tenant.cozystack.io/{{ include "tenant.name" $ }}: "" {{- if hasPrefix "tenant-" .Release.Namespace }} @@ -40,7 +49,7 @@ metadata: {{- 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" ownerReferences: - apiVersion: v1 diff --git a/packages/apps/tenant/templates/seaweedfs.yaml b/packages/apps/tenant/templates/seaweedfs.yaml index 4b5c9903..44c0a66b 100644 --- a/packages/apps/tenant/templates/seaweedfs.yaml +++ b/packages/apps/tenant/templates/seaweedfs.yaml @@ -9,6 +9,9 @@ metadata: internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} 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: chartRef: kind: ExternalArtifact diff --git a/packages/apps/vpn/templates/secret.yaml b/packages/apps/vpn/templates/secret.yaml index 79960096..b1d3152f 100644 --- a/packages/apps/vpn/templates/secret.yaml +++ b/packages/apps/vpn/templates/secret.yaml @@ -1,5 +1,6 @@ -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $namespace := dig "namespace" (dict) .Values }} +{{- $host := dig "host" "" $namespace }} {{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-vpn" .Release.Name) }} {{- $accessKeys := list }} {{- $passwords := dict }} diff --git a/packages/core/cozystack-operator/crds/cozystack.io_cozystackbundles.yaml b/packages/core/cozystack-operator/crds/cozystack.io_cozystackbundles.yaml index cd431eab..54b8caac 100644 --- a/packages/core/cozystack-operator/crds/cozystack.io_cozystackbundles.yaml +++ b/packages/core/cozystack-operator/crds/cozystack.io_cozystackbundles.yaml @@ -65,6 +65,12 @@ spec: - path type: object type: array + basePath: + description: |- + 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. + type: string deletionPolicy: allOf: - enum: @@ -160,6 +166,13 @@ spec: description: Disabled indicates whether this release is disabled (should not be installed) type: boolean + labels: + additionalProperties: + type: string + description: |- + 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 + type: object libraries: description: Libraries is a list of library names that this package depends on @@ -174,6 +187,13 @@ spec: description: Namespace is the Kubernetes namespace where the release will be installed type: string + namespaceLabels: + additionalProperties: + type: string + description: |- + 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 + type: object path: description: |- Path is the path to the Helm chart directory diff --git a/packages/core/cozystack-operator/crds/cozystack.io_cozystackresourcedefinitions.yaml b/packages/core/cozystack-operator/crds/cozystack.io_cozystackresourcedefinitions.yaml index 91cfb7ec..fcf8fd72 100644 --- a/packages/core/cozystack-operator/crds/cozystack.io_cozystackresourcedefinitions.yaml +++ b/packages/core/cozystack-operator/crds/cozystack.io_cozystackresourcedefinitions.yaml @@ -359,6 +359,11 @@ spec: prefix: description: Prefix for the release name type: string + values: + description: |- + Default values to be merged into every HelmRelease created from this resource definition + User-specified values in Application spec will override these default values + x-kubernetes-preserve-unknown-fields: true required: - prefix type: object diff --git a/packages/core/cozystack-operator/values.yaml b/packages/core/cozystack-operator/values.yaml index 1e7333cc..74a310d0 100644 --- a/packages/core/cozystack-operator/values.yaml +++ b/packages/core/cozystack-operator/values.yaml @@ -1,2 +1,2 @@ cozystackOperator: - image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:820395301bc703efbbe4b06d480ceb65e6186abba54ed2adc9a09946bc71bac7 + image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:33294c84ea575ece5aa0d301b43a0a71b455668f8f1c60c992aa3f6b3c9a8c8f diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index d0afa64f..ec1e161f 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,3 +1,3 @@ # Digest for OCIRepository cozystack-packages # This value is automatically updated by Makefile when building the image -packagesDigest: "sha256:c9dd5657878db1eaf434875e951cf8c911d698a3e7d87e3820e6b174a120bf66" +packagesDigest: "sha256:a1c14def709ed07d4d0dc8a776143388115a36c30e3558d5c4974f55ef653f35" diff --git a/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml b/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml index 351f6f9d..13e2b9f8 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-iaas-bucket namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: singular: Bucket plural: Buckets diff --git a/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml b/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml index 9aa990b8..92a3cbb0 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-iaas-kubernetes namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: IaaS singular: Kubernetes diff --git a/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml b/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml index 87b1e937..0fed9d96 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-iaas-virtual-machine namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: IaaS singular: Virtual Machine diff --git a/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml b/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml index 79ac1c14..d7c39f6e 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-iaas-vpc namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: IaaS singular: VPC diff --git a/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml b/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml index 5172c549..35dae6b5 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-iaas-vm-disk namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: IaaS singular: VM Disk diff --git a/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml b/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml index 08cfa4e3..92f1d78d 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-iaas-vm-instance namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: IaaS singular: VM Instance diff --git a/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml b/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml index a90f4103..f313895f 100644 --- a/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml +++ b/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-naas-http-cache namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: NaaS singular: HTTP Cache diff --git a/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml b/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml index 47972a46..929bd4e4 100644 --- a/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml +++ b/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-naas-tcp-balancer namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: NaaS singular: TCP Balancer diff --git a/packages/core/platform/bundles/naas/cozyrds/vpn.yaml b/packages/core/platform/bundles/naas/cozyrds/vpn.yaml index 6c89eaac..fea7c682 100644 --- a/packages/core/platform/bundles/naas/cozyrds/vpn.yaml +++ b/packages/core/platform/bundles/naas/cozyrds/vpn.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-naas-vpn namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: NaaS singular: VPN diff --git a/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml b/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml index f284a652..54cc1c8c 100644 --- a/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-paas-clickhouse namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: PaaS singular: ClickHouse diff --git a/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml b/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml index 9bd8ec9e..7ce1f91a 100644 --- a/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-paas-ferretdb namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: PaaS singular: FerretDB diff --git a/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml b/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml index c0e832f8..31fe348a 100644 --- a/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-paas-foundationdb namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: PaaS singular: FoundationDB diff --git a/packages/core/platform/bundles/paas/cozyrds/kafka.yaml b/packages/core/platform/bundles/paas/cozyrds/kafka.yaml index c7a2014f..6b4f99ed 100644 --- a/packages/core/platform/bundles/paas/cozyrds/kafka.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/kafka.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-paas-kafka namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: PaaS singular: Kafka diff --git a/packages/core/platform/bundles/paas/cozyrds/mysql.yaml b/packages/core/platform/bundles/paas/cozyrds/mysql.yaml index 3a0535f1..3032b8f5 100644 --- a/packages/core/platform/bundles/paas/cozyrds/mysql.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/mysql.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-paas-mysql namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: PaaS singular: MySQL diff --git a/packages/core/platform/bundles/paas/cozyrds/nats.yaml b/packages/core/platform/bundles/paas/cozyrds/nats.yaml index 5d81effc..59fd98a6 100644 --- a/packages/core/platform/bundles/paas/cozyrds/nats.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/nats.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-paas-nats namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: PaaS singular: NATS diff --git a/packages/core/platform/bundles/paas/cozyrds/postgres.yaml b/packages/core/platform/bundles/paas/cozyrds/postgres.yaml index 554dbd12..396fcf30 100644 --- a/packages/core/platform/bundles/paas/cozyrds/postgres.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/postgres.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-paas-postgres namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: PaaS singular: PostgreSQL diff --git a/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml b/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml index 365979f5..fcf90f3d 100644 --- a/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-paas-rabbitmq namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: PaaS singular: RabbitMQ diff --git a/packages/core/platform/bundles/paas/cozyrds/redis.yaml b/packages/core/platform/bundles/paas/cozyrds/redis.yaml index 224a83c9..d8cc645d 100644 --- a/packages/core/platform/bundles/paas/cozyrds/redis.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/redis.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-paas-redis namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: PaaS singular: Redis diff --git a/packages/core/platform/bundles/system/bundle-full.yaml b/packages/core/platform/bundles/system/bundle-full.yaml index c0729a28..10134ba6 100644 --- a/packages/core/platform/bundles/system/bundle-full.yaml +++ b/packages/core/platform/bundles/system/bundle-full.yaml @@ -61,8 +61,17 @@ spec: releaseName: tenant-root artifact: tenant namespace: tenant-root + namespaceLabels: + namespace.cozystack.io/host: {{ $host }} + namespace.cozystack.io/etcd: tenant-root + namespace.cozystack.io/ingress: tenant-root + namespace.cozystack.io/monitoring: tenant-root + namespace.cozystack.io/seaweedfs: tenant-root labels: cozystack.io/ui: "true" + apps.cozystack.io/application.kind: Tenant + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.name: tenant-root values: host: {{ $host }} diff --git a/packages/core/platform/bundles/system/bundle-hosted.yaml b/packages/core/platform/bundles/system/bundle-hosted.yaml index ea92b45c..93010f2d 100644 --- a/packages/core/platform/bundles/system/bundle-hosted.yaml +++ b/packages/core/platform/bundles/system/bundle-hosted.yaml @@ -61,8 +61,17 @@ spec: releaseName: tenant-root artifact: tenant namespace: tenant-root + namespaceLabels: + namespace.cozystack.io/host: {{ $host }} + namespace.cozystack.io/etcd: tenant-root + namespace.cozystack.io/ingress: tenant-root + namespace.cozystack.io/monitoring: tenant-root + namespace.cozystack.io/seaweedfs: tenant-root labels: cozystack.io/ui: "true" + apps.cozystack.io/application.kind: Tenant + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.name: tenant-root values: host: {{ $host }} diff --git a/packages/core/platform/bundles/system/cozyrds/bootbox.yaml b/packages/core/platform/bundles/system/cozyrds/bootbox.yaml index 331f055a..d994fda4 100644 --- a/packages/core/platform/bundles/system/cozyrds/bootbox.yaml +++ b/packages/core/platform/bundles/system/cozyrds/bootbox.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-system-bootbox namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: Administration singular: BootBox diff --git a/packages/core/platform/bundles/system/cozyrds/etcd.yaml b/packages/core/platform/bundles/system/cozyrds/etcd.yaml index 0fd1505e..d70c27ce 100644 --- a/packages/core/platform/bundles/system/cozyrds/etcd.yaml +++ b/packages/core/platform/bundles/system/cozyrds/etcd.yaml @@ -19,6 +19,9 @@ spec: kind: ExternalArtifact name: cozystack-system-etcd namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: Administration singular: Etcd diff --git a/packages/core/platform/bundles/system/cozyrds/info.yaml b/packages/core/platform/bundles/system/cozyrds/info.yaml index 8e33cb33..33c31dda 100644 --- a/packages/core/platform/bundles/system/cozyrds/info.yaml +++ b/packages/core/platform/bundles/system/cozyrds/info.yaml @@ -19,6 +19,9 @@ spec: kind: ExternalArtifact name: cozystack-system-info namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: name: info category: Administration diff --git a/packages/core/platform/bundles/system/cozyrds/ingress.yaml b/packages/core/platform/bundles/system/cozyrds/ingress.yaml index 64de630b..5eb40bba 100644 --- a/packages/core/platform/bundles/system/cozyrds/ingress.yaml +++ b/packages/core/platform/bundles/system/cozyrds/ingress.yaml @@ -19,6 +19,9 @@ spec: kind: ExternalArtifact name: cozystack-system-ingress namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: Administration singular: Ingress diff --git a/packages/core/platform/bundles/system/cozyrds/monitoring.yaml b/packages/core/platform/bundles/system/cozyrds/monitoring.yaml index 2d26d0fe..0ee236ce 100644 --- a/packages/core/platform/bundles/system/cozyrds/monitoring.yaml +++ b/packages/core/platform/bundles/system/cozyrds/monitoring.yaml @@ -19,6 +19,9 @@ spec: kind: ExternalArtifact name: cozystack-system-monitoring namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: Administration singular: Monitoring diff --git a/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml b/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml index e9bfc444..5f064ec7 100644 --- a/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml +++ b/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml @@ -19,6 +19,9 @@ spec: kind: ExternalArtifact name: cozystack-system-seaweedfs namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: Administration singular: SeaweedFS diff --git a/packages/core/platform/bundles/system/cozyrds/tenant.yaml b/packages/core/platform/bundles/system/cozyrds/tenant.yaml index 17ab6758..57de7a92 100644 --- a/packages/core/platform/bundles/system/cozyrds/tenant.yaml +++ b/packages/core/platform/bundles/system/cozyrds/tenant.yaml @@ -18,6 +18,9 @@ spec: kind: ExternalArtifact name: cozystack-system-tenant namespace: cozy-system + values: + cozystack: + {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: Administration singular: Tenant diff --git a/packages/core/platform/templates/_helpers.tpl b/packages/core/platform/templates/_helpers.tpl index 9da7b11f..97fde361 100644 --- a/packages/core/platform/templates/_helpers.tpl +++ b/packages/core/platform/templates/_helpers.tpl @@ -75,15 +75,30 @@ Usage: {{ include "cozystack.render-file" (list . "bundles/system/bundle-full.ya {{- end -}} {{/* -Render all files matching a glob pattern +Render all files matching a glob pattern with template processing Usage: {{ include "cozystack.render-glob" (list . "bundles/system/cozyrds/*.yaml") }} +Escapes templates like {{ .name }} and {{ .namespace }} that should remain as-is */}} {{- define "cozystack.render-glob" -}} {{- $ := index . 0 }} {{- $pattern := index . 1 }} {{- range $path, $_ := $.Files.Glob $pattern }} +{{- $content := $.Files.Get $path }} +{{- /* Escape templates that should remain as-is using temporary markers */}} +{{- /* Process complex patterns first (longer matches) */}} +{{- $content = $content | replace "{{ slice .namespace 7 }}" "__TEMPLATE_SLICE_NAMESPACE_7__" }} +{{- $content = $content | replace "{{ slice .namespace" "__TEMPLATE_SLICE_NAMESPACE__" }} +{{- $content = $content | replace "{{ .namespace }}" "__TEMPLATE_DOT_NAMESPACE__" }} +{{- $content = $content | replace "{{ .name }}" "__TEMPLATE_DOT_NAME__" }} +{{- /* Render the template */}} +{{- $rendered := trim (tpl $content $) }} +{{- /* Restore escaped templates */}} +{{- $rendered = $rendered | replace "__TEMPLATE_DOT_NAME__" "{{ .name }}" }} +{{- $rendered = $rendered | replace "__TEMPLATE_DOT_NAMESPACE__" "{{ .namespace }}" }} +{{- $rendered = $rendered | replace "__TEMPLATE_SLICE_NAMESPACE__" "{{ slice .namespace" }} +{{- $rendered = $rendered | replace "__TEMPLATE_SLICE_NAMESPACE_7__" "{{ slice .namespace 7 }}" }} --- -{{ $.Files.Get $path }} +{{ $rendered }} {{- end }} {{- end -}} @@ -143,3 +158,21 @@ Returns: Merged values dictionary {{- $defaultValues }} {{- end }} {{- end -}} + +{{/* +Build cozystack values structure from root values +Usage: {{ include "cozystack.build-values" . | nindent 8 }} +Returns: YAML string with cozystack values structure +*/}} +{{- define "cozystack.build-values" -}} +{{- $cozystack := dict }} +{{- if .Values.networking }}{{ $_ := set $cozystack "networking" .Values.networking }}{{ end }} +{{- if .Values.publishing }}{{ $_ := set $cozystack "publishing" .Values.publishing }}{{ end }} +{{- if .Values.scheduling }}{{ $_ := set $cozystack "scheduling" .Values.scheduling }}{{ end }} +{{- if .Values.authentication }}{{ $_ := set $cozystack "authentication" .Values.authentication }}{{ end }} +{{- if .Values.telemetry }}{{ $_ := set $cozystack "telemetry" .Values.telemetry }}{{ end }} +{{- if .Values.branding }}{{ $_ := set $cozystack "branding" .Values.branding }}{{ end }} +{{- if .Values.registries }}{{ $_ := set $cozystack "registries" .Values.registries }}{{ end }} +{{- if .Values.resources }}{{ $_ := set $cozystack "resources" .Values.resources }}{{ end }} +{{- $cozystack | toYaml | trim }} +{{- end -}} diff --git a/packages/extra/bootbox/templates/matchbox/ingress.yaml b/packages/extra/bootbox/templates/matchbox/ingress.yaml index 31de7716..ce950222 100644 --- a/packages/extra/bootbox/templates/matchbox/ingress.yaml +++ b/packages/extra/bootbox/templates/matchbox/ingress.yaml @@ -1,9 +1,8 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} - -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $issuerType := dig "publishing" "certificates" "issuerType" "http01" $cozystack }} +{{- $namespace := dig "namespace" (dict) .Values }} +{{- $ingress := dig "ingress" "" $namespace }} +{{- $host := dig "host" "" $namespace }} apiVersion: networking.k8s.io/v1 kind: Ingress metadata: diff --git a/packages/extra/bootbox/templates/matchbox/machines.yaml b/packages/extra/bootbox/templates/matchbox/machines.yaml index e2733b89..aa2eb2c9 100644 --- a/packages/extra/bootbox/templates/matchbox/machines.yaml +++ b/packages/extra/bootbox/templates/matchbox/machines.yaml @@ -1,9 +1,7 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} - -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $namespace := dig "namespace" (dict) .Values }} +{{- $ingress := dig "ingress" "" $namespace }} +{{- $host := dig "host" "" $namespace }} {{ range $m := .Values.machines }} --- diff --git a/packages/extra/etcd/templates/etcd-cluster.yaml b/packages/extra/etcd/templates/etcd-cluster.yaml index 017a3178..ef686b9f 100644 --- a/packages/extra/etcd/templates/etcd-cluster.yaml +++ b/packages/extra/etcd/templates/etcd-cluster.yaml @@ -49,16 +49,12 @@ spec: {{- with .Values.resources }} resources: {{- include "cozy-lib.resources.sanitize" (list . $) | nindent 10 }} {{- end }} - {{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} - {{- $rawConstraints := "" }} - {{- if $configMap }} - {{- $rawConstraints = get $configMap.data "globalAppTopologySpreadConstraints" }} - {{- end }} - {{- if $rawConstraints }} - {{- $rawConstraints | fromYaml | toYaml | nindent 6 }} - labelSelector: - matchLabels: - app.kubernetes.io/instance: etcd + {{- $cozystack := .Values.cozystack | default dict }} + {{- $topologySpreadConstraints := dig "scheduling" "topologySpreadConstraints" (list) $cozystack }} + {{- if $topologySpreadConstraints }} + {{- range $topologySpreadConstraints }} + - {{- mergeOverwrite (dict "labelSelector" (dict "matchLabels" (dict "app.kubernetes.io/instance" "etcd"))) . | toYaml | nindent 8 | trim }} + {{- end }} {{- else }} topologySpreadConstraints: - maxSkew: 1 diff --git a/packages/extra/info/templates/dashboard-resourcemap.yaml b/packages/extra/info/templates/dashboard-resourcemap.yaml index 39da1b37..1a7aadc0 100644 --- a/packages/extra/info/templates/dashboard-resourcemap.yaml +++ b/packages/extra/info/templates/dashboard-resourcemap.yaml @@ -1,5 +1,5 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $oidcEnabled := dig "authentication" "oidc" "enabled" false $cozystack | toString }} apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: diff --git a/packages/extra/info/templates/kubeconfig.yaml b/packages/extra/info/templates/kubeconfig.yaml index d960a587..9899cf2a 100644 --- a/packages/extra/info/templates/kubeconfig.yaml +++ b/packages/extra/info/templates/kubeconfig.yaml @@ -1,10 +1,10 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $host := index $cozyConfig.data "root-host" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $host := dig "publishing" "host" "" $cozystack }} {{- $k8sClientSecret := lookup "v1" "Secret" "cozy-keycloak" "k8s-client" }} {{- if $k8sClientSecret }} -{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} -{{- $managementKubeconfigEndpoint := default "" (get $cozyConfig.data "management-kubeconfig-endpoint") }} +{{- $apiServerEndpoint := dig "publishing" "apiServerEndpoint" "" $cozystack }} +{{- $managementKubeconfigEndpoint := dig "publishing" "managementKubeconfigEndpoint" "" $cozystack }} {{- if and $managementKubeconfigEndpoint (ne $managementKubeconfigEndpoint "") }} {{- $apiServerEndpoint = $managementKubeconfigEndpoint }} {{- end }} diff --git a/packages/extra/ingress/templates/nginx-ingress.yaml b/packages/extra/ingress/templates/nginx-ingress.yaml index 849c843f..58daf1b8 100644 --- a/packages/extra/ingress/templates/nginx-ingress.yaml +++ b/packages/extra/ingress/templates/nginx-ingress.yaml @@ -1,6 +1,6 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $exposeIngress := index $cozyConfig.data "expose-ingress" | default "tenant-root" }} -{{- $exposeExternalIPs := (index $cozyConfig.data "expose-external-ips") | default "" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $exposeIngress := dig "namespaces" "ingress" "tenant-root" $cozystack }} +{{- $exposeExternalIPs := dig "publishing" "externalIPs" (list) $cozystack | join "," }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -39,7 +39,7 @@ spec: service: {{- if and (eq $exposeIngress .Release.Namespace) $exposeExternalIPs }} externalIPs: - {{- toYaml (splitList "," $exposeExternalIPs) | nindent 12 }} + {{- toYaml $exposeExternalIPs | nindent 12 }} type: ClusterIP externalTrafficPolicy: Cluster {{- else }} diff --git a/packages/extra/monitoring/templates/alerta/alerta-db.yaml b/packages/extra/monitoring/templates/alerta/alerta-db.yaml index a2cca187..849f2113 100644 --- a/packages/extra/monitoring/templates/alerta/alerta-db.yaml +++ b/packages/extra/monitoring/templates/alerta/alerta-db.yaml @@ -5,15 +5,13 @@ metadata: name: alerta-db spec: instances: 2 - {{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} - {{- if $configMap }} - {{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }} - {{- if $rawConstraints }} - {{- $rawConstraints | fromYaml | toYaml | nindent 2 }} - labelSelector: - matchLabels: - cnpg.io/cluster: alerta-db - {{- end }} + {{- $cozystack := .Values.cozystack | default dict }} + {{- $topologySpreadConstraints := dig "scheduling" "topologySpreadConstraints" (list) $cozystack }} + {{- if $topologySpreadConstraints }} + topologySpreadConstraints: + {{- range $topologySpreadConstraints }} + - {{- mergeOverwrite (dict "labelSelector" (dict "matchLabels" (dict "cnpg.io/cluster" "alerta-db"))) . | toYaml | nindent 6 | trim }} + {{- end }} {{- end }} storage: size: {{ required ".Values.alerta.storage is required" .Values.alerta.storage }} diff --git a/packages/extra/monitoring/templates/alerta/alerta.yaml b/packages/extra/monitoring/templates/alerta/alerta.yaml index 71336286..41549822 100644 --- a/packages/extra/monitoring/templates/alerta/alerta.yaml +++ b/packages/extra/monitoring/templates/alerta/alerta.yaml @@ -1,9 +1,8 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} - -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $issuerType := dig "publishing" "certificates" "issuerType" "http01" $cozystack }} +{{- $namespace := dig "namespace" (dict) .Values }} +{{- $ingress := dig "ingress" "" $namespace }} +{{- $host := dig "host" "" $namespace }} {{- $apiKey := randAlphaNum 32 }} {{- $existingSecret := lookup "v1" "Secret" .Release.Namespace "alerta" }} diff --git a/packages/extra/monitoring/templates/grafana/db.yaml b/packages/extra/monitoring/templates/grafana/db.yaml index f1781cff..414437ce 100644 --- a/packages/extra/monitoring/templates/grafana/db.yaml +++ b/packages/extra/monitoring/templates/grafana/db.yaml @@ -6,15 +6,13 @@ spec: instances: 2 storage: size: {{ .Values.grafana.db.size }} - {{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} - {{- if $configMap }} - {{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }} - {{- if $rawConstraints }} - {{- $rawConstraints | fromYaml | toYaml | nindent 2 }} - labelSelector: - matchLabels: - cnpg.io/cluster: grafana-db - {{- end }} + {{- $cozystack := .Values.cozystack | default dict }} + {{- $topologySpreadConstraints := dig "scheduling" "topologySpreadConstraints" (list) $cozystack }} + {{- if $topologySpreadConstraints }} + topologySpreadConstraints: + {{- range $topologySpreadConstraints }} + - {{- mergeOverwrite (dict "labelSelector" (dict "matchLabels" (dict "cnpg.io/cluster" "grafana-db"))) . | toYaml | nindent 6 | trim }} + {{- end }} {{- end }} monitoring: enablePodMonitor: true diff --git a/packages/extra/monitoring/templates/grafana/grafana.yaml b/packages/extra/monitoring/templates/grafana/grafana.yaml index 2397fd10..f8c238ee 100644 --- a/packages/extra/monitoring/templates/grafana/grafana.yaml +++ b/packages/extra/monitoring/templates/grafana/grafana.yaml @@ -1,9 +1,8 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} - -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $issuerType := dig "publishing" "certificates" "issuerType" "http01" $cozystack }} +{{- $namespace := dig "namespace" (dict) .Values }} +{{- $ingress := dig "ingress" "" $namespace }} +{{- $host := dig "host" "" $namespace }} --- apiVersion: grafana.integreatly.org/v1beta1 kind: Grafana diff --git a/packages/extra/seaweedfs/templates/client/cosi-deployment.yaml b/packages/extra/seaweedfs/templates/client/cosi-deployment.yaml index 5307a67f..4e04b48a 100644 --- a/packages/extra/seaweedfs/templates/client/cosi-deployment.yaml +++ b/packages/extra/seaweedfs/templates/client/cosi-deployment.yaml @@ -1,7 +1,8 @@ {{- if eq .Values.topology "Client" }} -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $namespace := dig "namespace" (dict) .Values }} +{{- $ingress := dig "ingress" "" $namespace }} +{{- $host := dig "host" "" $namespace }} --- apiVersion: apps/v1 kind: Deployment diff --git a/packages/extra/seaweedfs/templates/ingress.yaml b/packages/extra/seaweedfs/templates/ingress.yaml index 05bf201d..d37a9410 100644 --- a/packages/extra/seaweedfs/templates/ingress.yaml +++ b/packages/extra/seaweedfs/templates/ingress.yaml @@ -1,9 +1,8 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} - -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $issuerType := dig "publishing" "certificates" "issuerType" "http01" $cozystack }} +{{- $namespace := dig "namespace" (dict) .Values }} +{{- $ingress := dig "ingress" "" $namespace }} +{{- $host := dig "host" "" $namespace }} {{- if and (not (eq .Values.topology "Client")) (.Values.filer.grpcHost) }} --- apiVersion: networking.k8s.io/v1 diff --git a/packages/extra/seaweedfs/templates/seaweedfs.yaml b/packages/extra/seaweedfs/templates/seaweedfs.yaml index 3607eca3..774c4755 100644 --- a/packages/extra/seaweedfs/templates/seaweedfs.yaml +++ b/packages/extra/seaweedfs/templates/seaweedfs.yaml @@ -34,9 +34,10 @@ {{- end }} {{- if not (eq .Values.topology "Client") }} -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $cozystack := .Values.cozystack | default dict }} +{{- $namespace := dig "namespace" (dict) .Values }} +{{- $ingress := dig "ingress" "" $namespace }} +{{- $host := dig "host" "" $namespace }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: diff --git a/packages/system/bootbox/templates/bootbox.yaml b/packages/system/bootbox/templates/bootbox.yaml index 9d062124..3ea687df 100644 --- a/packages/system/bootbox/templates/bootbox.yaml +++ b/packages/system/bootbox/templates/bootbox.yaml @@ -5,6 +5,9 @@ metadata: helm.sh/resource-policy: keep labels: cozystack.io/ui: "true" + apps.cozystack.io/application.kind: BootBox + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.name: bootbox name: bootbox namespace: tenant-root spec: diff --git a/packages/system/bucket/templates/ingress.yaml b/packages/system/bucket/templates/ingress.yaml index e2ec632e..feee9a8c 100644 --- a/packages/system/bucket/templates/ingress.yaml +++ b/packages/system/bucket/templates/ingress.yaml @@ -2,9 +2,9 @@ {{- $publishing := $cozystack.publishing | default dict }} {{- $certificates := $publishing.certificates | default dict }} {{- $issuerType := $certificates.issuerType | default "http01" }} -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} +{{- $namespace := dig "namespace" (dict) .Values }} +{{- $host := dig "host" "" $namespace }} +{{- $ingress := dig "ingress" "" $namespace }} apiVersion: networking.k8s.io/v1 kind: Ingress diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index bfe1aeb6..2246e959 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,5 +1,5 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:latest@sha256:80a01eb6cbfdeea9f27921c6acd882b17ff6ac22455f70968944d382195d96d0 + image: ghcr.io/cozystack/cozystack/cozystack-api:latest@sha256:07f74496ef0625b7cf656650393cc54f09cb97fb893b671f01ebf133ee590576 localK8sAPIEndpoint: enabled: true replicas: 2 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index 530c06e1..bcf07b05 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,5 +1,5 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:latest@sha256:ce9ba2b773ce14cb408ccdd8397cc4d5ae9e6e12e732ff52bc1f18b594730807 + image: ghcr.io/cozystack/cozystack/cozystack-controller:latest@sha256:9758ee7556e9c8665eccad4d926e2e2e3b51d1a411b6c88bbb4fdc747731d671 debug: false disableTelemetry: false cozystackVersion: "latest" diff --git a/pkg/registry/apps/application/rest.go b/pkg/registry/apps/application/rest.go index 72f00eca..5659136b 100644 --- a/pkg/registry/apps/application/rest.go +++ b/pkg/registry/apps/application/rest.go @@ -31,9 +31,9 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" fields "k8s.io/apimachinery/pkg/fields" labels "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/selection" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/selection" "k8s.io/apimachinery/pkg/util/duration" "k8s.io/apimachinery/pkg/watch" "k8s.io/apiserver/pkg/endpoints/request" @@ -41,13 +41,16 @@ import ( "k8s.io/klog/v2" "sigs.k8s.io/controller-runtime/pkg/client" + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" "github.com/cozystack/cozystack/pkg/config" internalapiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" structuralschema "k8s.io/apiextensions-apiserver/pkg/apiserver/schema" // Importing API errors package to construct appropriate error responses + corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" ) @@ -345,6 +348,8 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption } helmLabelSelector = labels.NewSelector().Add(labelRequirements...).String() + klog.V(6).Infof("Using label selector: %s for kind: %s, group: %s", helmLabelSelector, r.kindName, r.gvk.Group) + // Set ListOptions for HelmRelease with selector mapping metaOptions := metav1.ListOptions{ FieldSelector: helmFieldSelector, @@ -362,16 +367,30 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption return nil, err } + klog.V(6).Infof("Found %d HelmReleases with label selector, filtering by labels...", len(hrList.Items)) + // Initialize unstructured items array items := make([]unstructured.Unstructured, 0) // Iterate over HelmReleases and convert to Applications - // No need to filter by shouldIncludeHelmRelease since we're using label selectors + // Filter by labels to ensure only relevant HelmReleases are included + // This is a safety check in case label selectors don't work perfectly or HelmReleases were created without labels for i := range hrList.Items { + hr := &hrList.Items[i] - app, err := r.ConvertHelmReleaseToApplication(&hrList.Items[i]) + // Verify that HelmRelease has the required labels + if hr.Labels["apps.cozystack.io/application.kind"] != r.kindName || + hr.Labels["apps.cozystack.io/application.group"] != r.gvk.Group { + klog.V(6).Infof("Skipping HelmRelease %s - missing or incorrect application labels (kind: %s, expected: %s, group: %s, expected: %s)", + hr.GetName(), + hr.Labels["apps.cozystack.io/application.kind"], r.kindName, + hr.Labels["apps.cozystack.io/application.group"], r.gvk.Group) + continue + } + + app, err := r.ConvertHelmReleaseToApplication(hr) if err != nil { - klog.Errorf("Error converting HelmRelease %s to Application: %v", hrList.Items[i].GetName(), err) + klog.Errorf("Error converting HelmRelease %s to Application: %v", hr.GetName(), err) continue } @@ -1016,6 +1035,180 @@ func filterPrefixedMap(original map[string]string, prefix string) map[string]str return processed } +// getCozystackResourceDefinition retrieves the CozystackResourceDefinition for this resource kind +func (r *REST) getCozystackResourceDefinition(ctx context.Context) (*cozyv1alpha1.CozystackResourceDefinition, error) { + crdList := &cozyv1alpha1.CozystackResourceDefinitionList{} + if err := r.c.List(ctx, crdList); err != nil { + return nil, fmt.Errorf("failed to list CozystackResourceDefinitions: %w", err) + } + + for i := range crdList.Items { + crd := &crdList.Items[i] + if crd.Spec.Application.Kind == r.kindName { + return crd, nil + } + } + + return nil, fmt.Errorf("CozystackResourceDefinition not found for kind %s", r.kindName) +} + +// extractNamespaceLabels extracts namespace.cozystack.io/* labels from namespace and converts them to cozystack.namespace values +func extractNamespaceLabels(ns *corev1.Namespace) map[string]interface{} { + namespaceValues := make(map[string]interface{}) + prefix := "namespace.cozystack.io/" + + if ns.Labels == nil { + return namespaceValues + } + + for key, value := range ns.Labels { + if strings.HasPrefix(key, prefix) { + // Remove prefix and add to namespace values + namespaceKey := strings.TrimPrefix(key, prefix) + namespaceValues[namespaceKey] = value + } + } + + return namespaceValues +} + +// mergeValues merges two JSON values, with userValues taking precedence +func mergeValues(defaultValues, userValues *apiextensionsv1.JSON) (*apiextensionsv1.JSON, error) { + var defaultMap, userMap map[string]interface{} + + if defaultValues != nil && len(defaultValues.Raw) > 0 { + if err := json.Unmarshal(defaultValues.Raw, &defaultMap); err != nil { + return nil, fmt.Errorf("failed to unmarshal default values: %w", err) + } + } else { + defaultMap = make(map[string]interface{}) + } + + if userValues != nil && len(userValues.Raw) > 0 { + if err := json.Unmarshal(userValues.Raw, &userMap); err != nil { + return nil, fmt.Errorf("failed to unmarshal user values: %w", err) + } + } else { + userMap = make(map[string]interface{}) + } + + // Deep merge: defaultValues first, then userValues (userValues override) + merged := deepMergeMaps(defaultMap, userMap) + + 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 +} + +// removeCozystackFromValues removes the cozystack and namespace fields from values +func removeCozystackFromValues(values *apiextensionsv1.JSON) (*apiextensionsv1.JSON, error) { + if values == nil || len(values.Raw) == 0 { + return values, nil + } + + var valuesMap map[string]interface{} + if err := json.Unmarshal(values.Raw, &valuesMap); err != nil { + return nil, fmt.Errorf("failed to unmarshal values: %w", err) + } + + // Check if cozystack or namespace field exists before removing + if _, exists := valuesMap["cozystack"]; exists { + klog.V(4).Infof("Removing cozystack field from values (found in values map)") + delete(valuesMap, "cozystack") + } else { + klog.V(6).Infof("cozystack field not found in values map") + } + if _, exists := valuesMap["namespace"]; exists { + klog.V(4).Infof("Removing namespace field from values (found in values map)") + delete(valuesMap, "namespace") + } else { + klog.V(6).Infof("namespace field not found in values map") + } + + // If map is empty, return empty JSON object instead of nil to ensure proper serialization + if len(valuesMap) == 0 { + klog.V(6).Infof("Values map is empty after removing cozystack/namespace, returning empty JSON object") + return &apiextensionsv1.JSON{Raw: []byte("{}")}, nil + } + + cleanedJSON, err := json.Marshal(valuesMap) + if err != nil { + return nil, fmt.Errorf("failed to marshal cleaned values: %w", err) + } + + // Verify cozystack and namespace were removed + var verifyMap map[string]interface{} + if err := json.Unmarshal(cleanedJSON, &verifyMap); err == nil { + cozystackRemoved := true + namespaceRemoved := true + if _, stillExists := verifyMap["cozystack"]; stillExists { + klog.Errorf("ERROR: cozystack field still exists after removal attempt!") + cozystackRemoved = false + } + if _, stillExists := verifyMap["namespace"]; stillExists { + klog.Errorf("ERROR: namespace field still exists after removal attempt!") + namespaceRemoved = false + } + if cozystackRemoved && namespaceRemoved { + klog.V(6).Infof("Verified: cozystack and namespace fields successfully removed") + } + } + + return &apiextensionsv1.JSON{Raw: cleanedJSON}, nil +} + +// checkCozystackInValues checks if cozystack or namespace field exists in user values and returns an error if it does +func checkCozystackInValues(values *apiextensionsv1.JSON) error { + if values == nil || len(values.Raw) == 0 { + return nil + } + + var valuesMap map[string]interface{} + if err := json.Unmarshal(values.Raw, &valuesMap); err != nil { + return fmt.Errorf("failed to unmarshal values: %w", err) + } + + if _, exists := valuesMap["cozystack"]; exists { + return fmt.Errorf("cozystack field is not allowed in user-specified values") + } + + if _, exists := valuesMap["namespace"]; exists { + return fmt.Errorf("namespace field is not allowed in user-specified values") + } + + return nil +} + // ConvertHelmReleaseToApplication converts a HelmRelease to an Application func (r *REST) ConvertHelmReleaseToApplication(hr *helmv2.HelmRelease) (appsv1alpha1.Application, error) { klog.V(6).Infof("Converting HelmRelease to Application for resource %s", hr.GetName()) @@ -1031,6 +1224,39 @@ func (r *REST) ConvertHelmReleaseToApplication(hr *helmv2.HelmRelease) (appsv1al return app, fmt.Errorf("defaulting error: %w", err) } + // Remove cozystack field after applying defaults to ensure it's not shown to user + // This must be done after applySpecDefaults because defaults might add it back + if app.Spec != nil && len(app.Spec.Raw) > 0 { + cleanedValues, err := removeCozystackFromValues(app.Spec) + if err != nil { + return app, fmt.Errorf("failed to remove cozystack from values: %w", err) + } + app.Spec = cleanedValues + + // Double-check that cozystack was removed + if app.Spec != nil && len(app.Spec.Raw) > 0 { + var verifyMap map[string]interface{} + if err := json.Unmarshal(app.Spec.Raw, &verifyMap); err == nil { + if _, stillExists := verifyMap["cozystack"]; stillExists { + klog.Errorf("CRITICAL: cozystack field still exists after removal! Attempting force removal...") + delete(verifyMap, "cozystack") + } + if _, stillExists := verifyMap["namespace"]; stillExists { + klog.Errorf("CRITICAL: namespace field still exists after removal! Attempting force removal...") + delete(verifyMap, "namespace") + } + if len(verifyMap) == 0 { + app.Spec = &apiextensionsv1.JSON{Raw: []byte("{}")} + } else { + forceCleanedJSON, err := json.Marshal(verifyMap) + if err == nil { + app.Spec = &apiextensionsv1.JSON{Raw: forceCleanedJSON} + } + } + } + } + } + klog.V(6).Infof("Successfully converted HelmRelease %s to Application", hr.GetName()) return app, nil } @@ -1087,6 +1313,73 @@ func (r *REST) convertHelmReleaseToApplication(hr *helmv2.HelmRelease) (appsv1al // convertApplicationToHelmRelease implements the actual conversion logic func (r *REST) convertApplicationToHelmRelease(app *appsv1alpha1.Application) (*helmv2.HelmRelease, error) { + ctx := context.Background() + + // Check if user specified cozystack field in values + if err := checkCozystackInValues(app.Spec); err != nil { + return nil, err + } + + // Get CozystackResourceDefinition to extract default values + crd, err := r.getCozystackResourceDefinition(ctx) + if err != nil { + klog.V(6).Infof("Could not find CozystackResourceDefinition for kind %s: %v", r.kindName, err) + // Continue without default values if CRD not found + crd = nil + } + + // Start with default values from CRD (if any) + var mergedValues *apiextensionsv1.JSON + if crd != nil && crd.Spec.Release.Values != nil { + mergedValues, err = mergeValues(crd.Spec.Release.Values, app.Spec) + if err != nil { + return nil, fmt.Errorf("failed to merge default values with user values: %w", err) + } + } else { + // No default values, use user values as-is + mergedValues = app.Spec + } + + // Get namespace to extract namespace.cozystack.io/* labels + namespace := &corev1.Namespace{} + if err := r.c.Get(ctx, client.ObjectKey{Name: app.Namespace}, namespace); err != nil { + klog.V(6).Infof("Could not get namespace %s: %v", app.Namespace, err) + // Continue without namespace labels if namespace not found + namespace = nil + } + + // Extract namespace labels and add to namespace (top-level) + if namespace != nil { + namespaceLabels := extractNamespaceLabels(namespace) + if len(namespaceLabels) > 0 { + // Parse merged values to add namespace labels + var valuesMap map[string]interface{} + if mergedValues != nil && len(mergedValues.Raw) > 0 { + if err := json.Unmarshal(mergedValues.Raw, &valuesMap); err != nil { + return nil, fmt.Errorf("failed to unmarshal merged values: %w", err) + } + } else { + valuesMap = make(map[string]interface{}) + } + + // Convert namespaceLabels to map[string]interface{} + namespaceLabelsMap := make(map[string]interface{}) + for k, v := range namespaceLabels { + namespaceLabelsMap[k] = v + } + + // Namespace labels completely overwrite existing namespace field (top-level) + valuesMap["namespace"] = namespaceLabelsMap + + // Marshal back to JSON + mergedJSON, err := json.Marshal(valuesMap) + if err != nil { + return nil, fmt.Errorf("failed to marshal values with namespace labels: %w", err) + } + mergedValues = &apiextensionsv1.JSON{Raw: mergedJSON} + } + } + helmRelease := &helmv2.HelmRelease{ TypeMeta: metav1.TypeMeta{ APIVersion: "helm.toolkit.fluxcd.io/v2", @@ -1112,7 +1405,7 @@ func (r *REST) convertApplicationToHelmRelease(app *appsv1alpha1.Application) (* Retries: -1, }, }, - Values: app.Spec, + Values: mergedValues, }, } diff --git a/pkg/registry/apps/application/rest_defaulting.go b/pkg/registry/apps/application/rest_defaulting.go index 6630a08b..0f9d776f 100644 --- a/pkg/registry/apps/application/rest_defaulting.go +++ b/pkg/registry/apps/application/rest_defaulting.go @@ -21,7 +21,7 @@ import ( "fmt" appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" - apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" structuralschema "k8s.io/apiextensions-apiserver/pkg/apiserver/schema" ) @@ -42,11 +42,21 @@ func (r *REST) applySpecDefaults(app *appsv1alpha1.Application) error { if err := defaultLikeKubernetes(&m, r.specSchema); err != nil { return err } + // Remove cozystack and namespace fields before marshaling to ensure they're never in the output + delete(m, "cozystack") + delete(m, "namespace") + + // Always return at least an empty JSON object, never nil + if len(m) == 0 { + app.Spec = &apiextensionsv1.JSON{Raw: []byte("{}")} + return nil + } + raw, err := json.Marshal(m) if err != nil { return err } - app.Spec = &apiextv1.JSON{Raw: raw} + app.Spec = &apiextensionsv1.JSON{Raw: raw} return nil } From aaf2d1326af6a11550837afab3f9b307d4a9cd4d Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 25 Nov 2025 02:17:05 +0100 Subject: [PATCH 31/46] Move telemetry from cozystack-controller to cozystack-operator Signed-off-by: Andrei Kvapil --- cmd/cozystack-controller/main.go | 58 ------- cmd/cozystack-operator/main.go | 41 +++++ internal/controller/system_helm_reconciler.go | 140 --------------- internal/controller/tenant_helm_reconciler.go | 159 ------------------ internal/telemetry/collector.go | 116 +++++++++---- packages/core/cozystack-operator/Makefile | 5 +- .../templates/cozystack-operator.yaml | 4 + packages/core/cozystack-operator/values.yaml | 2 + .../platform/bundles/system/bundle-full.yaml | 5 - .../bundles/system/bundle-hosted.yaml | 5 - .../bundles/system/bundle-minimal.yaml | 5 - packages/core/platform/templates/_helpers.tpl | 1 - packages/core/platform/values.yaml | 3 - packages/system/cozystack-controller/Makefile | 6 +- .../templates/deployment.yaml | 3 - .../system/cozystack-controller/values.yaml | 2 - 16 files changed, 132 insertions(+), 423 deletions(-) delete mode 100644 internal/controller/system_helm_reconciler.go delete mode 100644 internal/controller/tenant_helm_reconciler.go diff --git a/cmd/cozystack-controller/main.go b/cmd/cozystack-controller/main.go index fe0fe77e..ab551b6d 100644 --- a/cmd/cozystack-controller/main.go +++ b/cmd/cozystack-controller/main.go @@ -20,7 +20,6 @@ import ( "crypto/tls" "flag" "os" - "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. @@ -39,7 +38,6 @@ import ( cozystackiov1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" "github.com/cozystack/cozystack/internal/controller" "github.com/cozystack/cozystack/internal/controller/dashboard" - "github.com/cozystack/cozystack/internal/telemetry" helmv2 "github.com/fluxcd/helm-controller/api/v2" // +kubebuilder:scaffold:imports @@ -65,10 +63,6 @@ func main() { var probeAddr string var secureMetrics bool var enableHTTP2 bool - var disableTelemetry bool - var telemetryEndpoint string - var telemetryInterval string - var cozystackVersion string var reconcileDeployment bool var tlsOpts []func(*tls.Config) 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.") flag.BoolVar(&enableHTTP2, "enable-http2", false, "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, "If set, the Cozystack API server is assumed to run as a Deployment, else as a DaemonSet.") opts := zap.Options{ @@ -97,21 +83,6 @@ func main() { 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))) // if the enable-http2 flag is false (the default), http/2 should be disabled @@ -200,22 +171,6 @@ func main() { os.Exit(1) } - if err = (&controller.TenantHelmReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "TenantHelmReconciler") - os.Exit(1) - } - - if err = (&controller.CozystackConfigReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "CozystackConfigReconciler") - os.Exit(1) - } - if err = (&controller.NamespaceHelmReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), @@ -253,19 +208,6 @@ func main() { 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") ctx := ctrl.SetupSignalHandler() dashboardManager.InitializeStaticResources(ctx) diff --git a/cmd/cozystack-operator/main.go b/cmd/cozystack-operator/main.go index 41084719..fae18143 100644 --- a/cmd/cozystack-operator/main.go +++ b/cmd/cozystack-operator/main.go @@ -42,6 +42,7 @@ import ( "github.com/cozystack/cozystack/internal/fluxinstall" "github.com/cozystack/cozystack/internal/operator" + "github.com/cozystack/cozystack/internal/telemetry" // +kubebuilder:scaffold:imports ) @@ -67,6 +68,10 @@ func main() { var secureMetrics bool var enableHTTP2 bool var installFlux bool + var disableTelemetry bool + var telemetryEndpoint string + var telemetryInterval string + var cozystackVersion string 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.") @@ -78,6 +83,14 @@ func main() { 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.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, @@ -85,6 +98,21 @@ func main() { 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() @@ -155,6 +183,19 @@ func main() { 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 { diff --git a/internal/controller/system_helm_reconciler.go b/internal/controller/system_helm_reconciler.go deleted file mode 100644 index ff25c480..00000000 --- a/internal/controller/system_helm_reconciler.go +++ /dev/null @@ -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 patchTarget.Annotations == nil { - patchTarget.Annotations = make(map[string]string) - } - - if patchTarget.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 -} diff --git a/internal/controller/tenant_helm_reconciler.go b/internal/controller/tenant_helm_reconciler.go deleted file mode 100644 index 28b4ad16..00000000 --- a/internal/controller/tenant_helm_reconciler.go +++ /dev/null @@ -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 -} diff --git a/internal/telemetry/collector.go b/internal/telemetry/collector.go index 04d05d3a..4ecedd49 100644 --- a/internal/telemetry/collector.go +++ b/internal/telemetry/collector.go @@ -5,6 +5,7 @@ import ( "context" "fmt" "net/http" + "sort" "strings" "time" @@ -120,16 +121,50 @@ func (c *Collector) collect(ctx context.Context) { clusterID := string(kubeSystemNS.UID) - var cozystackCM corev1.ConfigMap - if err := c.client.Get(ctx, types.NamespacedName{Namespace: "cozy-system", Name: "cozystack"}, &cozystackCM); err != nil { - logger.Info(fmt.Sprintf("Failed to get cozystack configmap in cozy-system namespace: %v", err)) - return - } + // Get all CozystackBundles + var bundleList cozyv1alpha1.CozystackBundleList + bundleNameStr := "" + bundleEnable := "" + bundleDisable := "" + oidcEnabled := "false" - oidcEnabled := cozystackCM.Data["oidc-enabled"] - bundle := cozystackCM.Data["bundle-name"] - bundleEnable := cozystackCM.Data["bundle-enable"] - bundleDisable := cozystackCM.Data["bundle-disable"] + if err := c.client.List(ctx, &bundleList); err != nil { + logger.Info(fmt.Sprintf("Failed to list CozystackBundles: %v", err)) + // Continue with empty bundle data instead of returning + } 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 var nodeList corev1.NodeList @@ -143,32 +178,41 @@ func (c *Collector) collect(ctx context.Context) { // Add Cozystack info metric 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( - "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, k8sVersion, oidcEnabled, - bundle, + bundleNameStr, bundleEnable, bundleDisable, )) } // Collect node metrics - nodeOSCount := make(map[string]int) - for _, node := range nodeList.Items { - key := fmt.Sprintf("%s (%s)", node.Status.NodeInfo.OperatingSystem, node.Status.NodeInfo.OSImage) - nodeOSCount[key] = nodeOSCount[key] + 1 - } + if len(nodeList.Items) > 0 { + nodeOSCount := make(map[string]int) + kernelVersion := "unknown" + for _, node := range nodeList.Items { + key := fmt.Sprintf("%s (%s)", node.Status.NodeInfo.OperatingSystem, node.Status.NodeInfo.OSImage) + nodeOSCount[key] = nodeOSCount[key] + 1 + if kernelVersion == "unknown" && node.Status.NodeInfo.KernelVersion != "" { + kernelVersion = node.Status.NodeInfo.KernelVersion + } + } - for osKey, count := range nodeOSCount { - metrics.WriteString(fmt.Sprintf( - "cozy_nodes_count{os=\"%s\",kernel=\"%s\"} %d\n", - osKey, - nodeList.Items[0].Status.NodeInfo.KernelVersion, - count, - )) + for osKey, count := range nodeOSCount { + metrics.WriteString(fmt.Sprintf( + "cozy_nodes_count{os=\"%s\",kernel=\"%s\"} %d\n", + osKey, + kernelVersion, + count, + )) + } } // Collect LoadBalancer services metrics @@ -248,18 +292,18 @@ func (c *Collector) collect(ctx context.Context) { var monitorList cozyv1alpha1.WorkloadMonitorList if err := c.client.List(ctx, &monitorList); err != nil { logger.Info(fmt.Sprintf("Failed to list WorkloadMonitors: %v", err)) - return - } - - for _, monitor := range monitorList.Items { - metrics.WriteString(fmt.Sprintf( - "cozy_workloads_count{uid=\"%s\",kind=\"%s\",type=\"%s\",version=\"%s\"} %d\n", - monitor.UID, - monitor.Spec.Kind, - monitor.Spec.Type, - monitor.Spec.Version, - monitor.Status.ObservedReplicas, - )) + // Continue without workload metrics instead of returning + } else { + for _, monitor := range monitorList.Items { + metrics.WriteString(fmt.Sprintf( + "cozy_workloads_count{uid=\"%s\",kind=\"%s\",type=\"%s\",version=\"%s\"} %d\n", + monitor.UID, + monitor.Spec.Kind, + monitor.Spec.Type, + monitor.Spec.Version, + monitor.Status.ObservedReplicas, + )) + } } // Send metrics diff --git a/packages/core/cozystack-operator/Makefile b/packages/core/cozystack-operator/Makefile index dcac7028..5d23605a 100644 --- a/packages/core/cozystack-operator/Makefile +++ b/packages/core/cozystack-operator/Makefile @@ -3,7 +3,7 @@ NAMESPACE=cozy-system include ../../../scripts/common-envs.mk -image: pre-checks image-cozystack-operator +image: pre-checks image-cozystack-operator update-version pre-checks: ../../../hack/pre-checks.sh @@ -28,3 +28,6 @@ image-cozystack-operator: yq -i '.cozystackOperator.image = strenv(IMAGE)' values.yaml rm -f images/cozystack-operator.json +update-version: + TAG="$(call settag,$(TAG))" \ + yq -i '.cozystackOperator.cozystackVersion = strenv(TAG)' values.yaml diff --git a/packages/core/cozystack-operator/templates/cozystack-operator.yaml b/packages/core/cozystack-operator/templates/cozystack-operator.yaml index 10426640..8d13aff1 100644 --- a/packages/core/cozystack-operator/templates/cozystack-operator.yaml +++ b/packages/core/cozystack-operator/templates/cozystack-operator.yaml @@ -55,6 +55,10 @@ spec: - --install-flux=true - --metrics-bind-address=0 - --health-probe-bind-address= + - --cozystack-version={{ .Values.cozystackOperator.cozystackVersion }} + {{- if .Values.cozystackOperator.disableTelemetry }} + - --disable-telemetry + {{- end }} env: - name: KUBERNETES_SERVICE_HOST value: localhost diff --git a/packages/core/cozystack-operator/values.yaml b/packages/core/cozystack-operator/values.yaml index 74a310d0..0e72fe6c 100644 --- a/packages/core/cozystack-operator/values.yaml +++ b/packages/core/cozystack-operator/values.yaml @@ -1,2 +1,4 @@ cozystackOperator: image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:33294c84ea575ece5aa0d301b43a0a71b455668f8f1c60c992aa3f6b3c9a8c8f + disableTelemetry: false + cozystackVersion: "latest" diff --git a/packages/core/platform/bundles/system/bundle-full.yaml b/packages/core/platform/bundles/system/bundle-full.yaml index 10134ba6..590e1dbf 100644 --- a/packages/core/platform/bundles/system/bundle-full.yaml +++ b/packages/core/platform/bundles/system/bundle-full.yaml @@ -158,11 +158,6 @@ spec: path: system/cozystack-controller namespace: cozy-system dependsOn: [cilium,kubeovn] - {{- if not .Values.telemetry.enabled }} - values: - cozystackController: - disableTelemetry: true - {{- end }} - name: lineage-controller-webhook releaseName: lineage-controller-webhook diff --git a/packages/core/platform/bundles/system/bundle-hosted.yaml b/packages/core/platform/bundles/system/bundle-hosted.yaml index 93010f2d..7c9c2ea3 100644 --- a/packages/core/platform/bundles/system/bundle-hosted.yaml +++ b/packages/core/platform/bundles/system/bundle-hosted.yaml @@ -96,11 +96,6 @@ spec: path: system/cozystack-controller namespace: cozy-system dependsOn: [] - {{- if not .Values.telemetry.enabled }} - values: - cozystackController: - disableTelemetry: true - {{- end }} - name: lineage-controller-webhook releaseName: lineage-controller-webhook diff --git a/packages/core/platform/bundles/system/bundle-minimal.yaml b/packages/core/platform/bundles/system/bundle-minimal.yaml index 696bebd6..98fa754b 100644 --- a/packages/core/platform/bundles/system/bundle-minimal.yaml +++ b/packages/core/platform/bundles/system/bundle-minimal.yaml @@ -49,11 +49,6 @@ spec: path: system/cozystack-controller namespace: cozy-system dependsOn: [] - {{- if not .Values.telemetry.enabled }} - values: - cozystackController: - disableTelemetry: true - {{- end }} - name: lineage-controller-webhook releaseName: lineage-controller-webhook diff --git a/packages/core/platform/templates/_helpers.tpl b/packages/core/platform/templates/_helpers.tpl index 97fde361..b8eaaa78 100644 --- a/packages/core/platform/templates/_helpers.tpl +++ b/packages/core/platform/templates/_helpers.tpl @@ -170,7 +170,6 @@ Returns: YAML string with cozystack values structure {{- if .Values.publishing }}{{ $_ := set $cozystack "publishing" .Values.publishing }}{{ end }} {{- if .Values.scheduling }}{{ $_ := set $cozystack "scheduling" .Values.scheduling }}{{ end }} {{- if .Values.authentication }}{{ $_ := set $cozystack "authentication" .Values.authentication }}{{ end }} -{{- if .Values.telemetry }}{{ $_ := set $cozystack "telemetry" .Values.telemetry }}{{ end }} {{- if .Values.branding }}{{ $_ := set $cozystack "branding" .Values.branding }}{{ end }} {{- if .Values.registries }}{{ $_ := set $cozystack "registries" .Values.registries }}{{ end }} {{- if .Values.resources }}{{ $_ := set $cozystack "resources" .Values.resources }}{{ end }} diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml index 2d15ee34..d9d421a3 100644 --- a/packages/core/platform/values.yaml +++ b/packages/core/platform/values.yaml @@ -48,9 +48,6 @@ publishing: externalIPs: [] certificates: issuerType: http01 # "http01" or "cloudflare" -# Telemetry configuration -telemetry: - enabled: true # Authentication configuration authentication: oidc: diff --git a/packages/system/cozystack-controller/Makefile b/packages/system/cozystack-controller/Makefile index 9bbfb5a6..d7d899ac 100644 --- a/packages/system/cozystack-controller/Makefile +++ b/packages/system/cozystack-controller/Makefile @@ -4,7 +4,7 @@ NAMESPACE=cozy-system include ../../../scripts/common-envs.mk include ../../../scripts/package.mk -image: image-cozystack-controller update-version +image: image-cozystack-controller image-cozystack-controller: docker buildx build -f images/cozystack-controller/Dockerfile ../../.. \ @@ -16,7 +16,3 @@ image-cozystack-controller: IMAGE="$(REGISTRY)/cozystack-controller:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/cozystack-controller.json -o json -r)" \ yq -i '.cozystackController.image = strenv(IMAGE)' values.yaml rm -f images/cozystack-controller.json - -update-version: - TAG="$(call settag,$(TAG))" \ - yq -i '.cozystackController.cozystackVersion = strenv(TAG)' values.yaml diff --git a/packages/system/cozystack-controller/templates/deployment.yaml b/packages/system/cozystack-controller/templates/deployment.yaml index 6dc21b1c..7f1342d4 100644 --- a/packages/system/cozystack-controller/templates/deployment.yaml +++ b/packages/system/cozystack-controller/templates/deployment.yaml @@ -25,9 +25,6 @@ spec: {{- else }} - --zap-log-level=info {{- end }} - {{- if .Values.cozystackController.disableTelemetry }} - - --disable-telemetry - {{- end }} {{- if eq .Values.cozystackController.cozystackAPIKind "Deployment" }} - --reconcile-deployment {{- end }} diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index bcf07b05..fc7c4c5f 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,6 +1,4 @@ cozystackController: image: ghcr.io/cozystack/cozystack/cozystack-controller:latest@sha256:9758ee7556e9c8665eccad4d926e2e2e3b51d1a411b6c88bbb4fdc747731d671 debug: false - disableTelemetry: false - cozystackVersion: "latest" cozystackAPIKind: "DaemonSet" From 2077b0e51522ce45625fc7efd66d572a37edec42 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 25 Nov 2025 02:17:33 +0100 Subject: [PATCH 32/46] fix namespace Signed-off-by: Andrei Kvapil --- packages/apps/vm-disk/templates/dv.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/apps/vm-disk/templates/dv.yaml b/packages/apps/vm-disk/templates/dv.yaml index b4120189..3d68e639 100644 --- a/packages/apps/vm-disk/templates/dv.yaml +++ b/packages/apps/vm-disk/templates/dv.yaml @@ -21,10 +21,10 @@ spec: {{- end }} source: {{- if hasKey .Values.source "image" }} - {{- $dv := lookup "cdi.kubevirt.io/v1beta1" "DataVolume" "cozy-system" (printf "vm-image-%s" .Values.source.image.name) }} + {{- $dv := lookup "cdi.kubevirt.io/v1beta1" "DataVolume" "cozy-public" (printf "vm-image-%s" .Values.source.image.name) }} pvc: name: vm-image-{{ required "A valid .Values.source.image.name entry required!" .Values.source.image.name }} - namespace: cozy-system + namespace: cozy-public {{- else if hasKey .Values.source "http" }} http: url: {{ required "A valid .Values.source.http.url entry required!" .Values.source.http.url }} From 451ef73172e5233a6592089a10f50085529b6f13 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 25 Nov 2025 02:27:46 +0100 Subject: [PATCH 33/46] refactor escaping Signed-off-by: Andrei Kvapil --- Makefile | 4 +- api/v1alpha1/cozystackplatform_types.go | 71 +++ api/v1alpha1/zz_generated.deepcopy.go | 85 ++++ cmd/cozystack-operator/main.go | 107 +++++ examples/cozystackplatform-example.yaml | 31 ++ hack/update-codegen.sh | 6 +- .../cozystackresource_controller.go | 100 ++-- .../controller/namespace_helm_reconciler.go | 10 +- internal/lineagecontrollerwebhook/webhook.go | 8 +- internal/operator/bundle_reconciler.go | 71 ++- internal/operator/platform_reconciler.go | 441 ++++++++++++++++++ internal/telemetry/collector.go | 40 +- .../apps/bucket/templates/bucketclaim.yaml | 4 +- .../apps/clickhouse/templates/chkeeper.yaml | 2 +- .../apps/clickhouse/templates/clickhouse.yaml | 2 +- .../apps/ferretdb/templates/postgres.yaml | 2 +- .../apps/foundationdb/templates/cluster.yaml | 2 +- .../apps/kubernetes/templates/cluster.yaml | 6 +- .../helmreleases/monitoring-agents.yaml | 4 +- .../helmreleases/vertical-pod-autoscaler.yaml | 4 +- .../apps/kubernetes/templates/ingress.yaml | 4 +- packages/apps/nats/templates/nats.yaml | 2 +- packages/apps/postgres/templates/db.yaml | 2 +- .../apps/tenant/templates/keycloakgroups.yaml | 2 +- packages/apps/tenant/templates/namespace.yaml | 2 +- packages/apps/vpn/templates/secret.yaml | 4 +- packages/core/cozystack-operator/Chart.yaml | 3 - packages/core/cozystack-operator/Makefile | 33 -- packages/core/cozystack-operator/values.yaml | 4 - packages/core/installer/Chart.yaml | 2 +- packages/core/installer/Makefile | 23 +- .../crds/cozystack.io_cozystackbundles.yaml | 0 .../crds/cozystack.io_cozystackplatforms.yaml | 83 ++++ ...stack.io_cozystackresourcedefinitions.yaml | 0 packages/core/installer/example/platform.yaml | 30 ++ .../images/cozystack-operator/Dockerfile | 0 .../Dockerfile.dockerignore | 0 .../templates/cozystack-operator.yaml | 15 + .../templates/crds.yaml | 0 .../core/installer/templates/platform.yaml | 51 -- packages/core/installer/values.yaml | 8 +- .../platform/bundles/iaas/cozyrds/bucket.yaml | 8 +- .../bundles/iaas/cozyrds/kubernetes.yaml | 8 +- .../bundles/iaas/cozyrds/virtual-machine.yaml | 4 +- .../iaas/cozyrds/virtualprivatecloud.yaml | 2 +- .../bundles/iaas/cozyrds/vm-disk.yaml | 2 +- .../bundles/iaas/cozyrds/vm-instance.yaml | 2 +- .../bundles/naas/cozyrds/http-cache.yaml | 2 +- .../bundles/naas/cozyrds/tcp-balancer.yaml | 2 +- .../platform/bundles/naas/cozyrds/vpn.yaml | 6 +- .../bundles/paas/cozyrds/clickhouse.yaml | 6 +- .../bundles/paas/cozyrds/ferretdb.yaml | 6 +- .../bundles/paas/cozyrds/foundationdb.yaml | 2 +- .../platform/bundles/paas/cozyrds/kafka.yaml | 6 +- .../platform/bundles/paas/cozyrds/mysql.yaml | 8 +- .../platform/bundles/paas/cozyrds/nats.yaml | 6 +- .../bundles/paas/cozyrds/postgres.yaml | 12 +- .../bundles/paas/cozyrds/rabbitmq.yaml | 6 +- .../platform/bundles/paas/cozyrds/redis.yaml | 12 +- .../bundles/system/cozyrds/bootbox.yaml | 2 +- .../platform/bundles/system/cozyrds/etcd.yaml | 2 +- .../platform/bundles/system/cozyrds/info.yaml | 6 +- .../bundles/system/cozyrds/ingress.yaml | 4 +- .../bundles/system/cozyrds/monitoring.yaml | 2 +- .../bundles/system/cozyrds/seaweedfs.yaml | 6 +- .../bundles/system/cozyrds/tenant.yaml | 2 +- packages/core/platform/templates/_helpers.tpl | 18 +- packages/core/talos/values.yaml | 2 - .../bootbox/templates/matchbox/ingress.yaml | 4 +- .../bootbox/templates/matchbox/machines.yaml | 4 +- .../extra/etcd/templates/etcd-cluster.yaml | 2 +- .../info/templates/dashboard-resourcemap.yaml | 2 +- packages/extra/info/templates/kubeconfig.yaml | 6 +- .../ingress/templates/nginx-ingress.yaml | 6 +- .../templates/alerta/alerta-db.yaml | 2 +- .../monitoring/templates/alerta/alerta.yaml | 4 +- .../monitoring/templates/grafana/db.yaml | 2 +- .../monitoring/templates/grafana/grafana.yaml | 4 +- .../templates/client/cosi-deployment.yaml | 4 +- .../extra/seaweedfs/templates/ingress.yaml | 4 +- .../extra/seaweedfs/templates/seaweedfs.yaml | 4 +- .../cozy-lib/templates/_cozyconfig.tpl | 10 +- .../library/cozy-lib/templates/_network.tpl | 6 +- .../library/cozy-lib/templates/_resources.tpl | 24 +- packages/system/cozystack-api/values.yaml | 2 +- .../templates/deployment.yaml | 1 - .../system/cozystack-controller/values.yaml | 2 +- pkg/lineage/lineage.go | 4 + pkg/registry/apps/application/rest.go | 144 +++--- .../apps/application/rest_defaulting.go | 44 +- 90 files changed, 1315 insertions(+), 382 deletions(-) create mode 100644 api/v1alpha1/cozystackplatform_types.go create mode 100644 examples/cozystackplatform-example.yaml create mode 100644 internal/operator/platform_reconciler.go delete mode 100644 packages/core/cozystack-operator/Chart.yaml delete mode 100644 packages/core/cozystack-operator/Makefile delete mode 100644 packages/core/cozystack-operator/values.yaml rename packages/core/{cozystack-operator => installer}/crds/cozystack.io_cozystackbundles.yaml (100%) create mode 100644 packages/core/installer/crds/cozystack.io_cozystackplatforms.yaml rename packages/core/{cozystack-operator => installer}/crds/cozystack.io_cozystackresourcedefinitions.yaml (100%) create mode 100644 packages/core/installer/example/platform.yaml rename packages/core/{cozystack-operator => installer}/images/cozystack-operator/Dockerfile (100%) rename packages/core/{cozystack-operator => installer}/images/cozystack-operator/Dockerfile.dockerignore (100%) rename packages/core/{cozystack-operator => installer}/templates/cozystack-operator.yaml (77%) rename packages/core/{cozystack-operator => installer}/templates/crds.yaml (100%) delete mode 100644 packages/core/installer/templates/platform.yaml diff --git a/Makefile b/Makefile index 4290d4cc..016cf036 100644 --- a/Makefile +++ b/Makefile @@ -26,10 +26,10 @@ build: build-deps make -C packages/system/bucket image make -C packages/system/objectstorage-controller image make -C packages/core/testing image - make -C packages/core/cozystack-operator 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 + make -C packages/core/installer image-packages make manifests manifests: diff --git a/api/v1alpha1/cozystackplatform_types.go b/api/v1alpha1/cozystackplatform_types.go new file mode 100644 index 00000000..228d0061 --- /dev/null +++ b/api/v1alpha1/cozystackplatform_types.go @@ -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 + +// CozystackPlatform is the Schema for the cozystackplatforms API +type CozystackPlatform struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec CozystackPlatformSpec `json:"spec,omitempty"` +} + +// +kubebuilder:object:root=true + +// CozystackPlatformList contains a list of CozystackPlatform +type CozystackPlatformList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CozystackPlatform `json:"items"` +} + +func init() { + SchemeBuilder.Register(&CozystackPlatform{}, &CozystackPlatformList{}) +} + +// CozystackPlatformSpec defines the desired state of CozystackPlatform +type CozystackPlatformSpec 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"` +} + diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 67e218c7..4504086b 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -23,6 +23,7 @@ package v1alpha1 import ( "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -257,6 +258,90 @@ func (in *CozystackBundleSpec) DeepCopy() *CozystackBundleSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CozystackPlatform) DeepCopyInto(out *CozystackPlatform) { + *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 CozystackPlatform. +func (in *CozystackPlatform) DeepCopy() *CozystackPlatform { + if in == nil { + return nil + } + out := new(CozystackPlatform) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CozystackPlatform) 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 *CozystackPlatformList) DeepCopyInto(out *CozystackPlatformList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CozystackPlatform, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackPlatformList. +func (in *CozystackPlatformList) DeepCopy() *CozystackPlatformList { + if in == nil { + return nil + } + out := new(CozystackPlatformList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CozystackPlatformList) 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 *CozystackPlatformSpec) DeepCopyInto(out *CozystackPlatformSpec) { + *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 CozystackPlatformSpec. +func (in *CozystackPlatformSpec) DeepCopy() *CozystackPlatformSpec { + if in == nil { + return nil + } + out := new(CozystackPlatformSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CozystackResourceDefinition) DeepCopyInto(out *CozystackResourceDefinition) { *out = *in diff --git a/cmd/cozystack-operator/main.go b/cmd/cozystack-operator/main.go index fae18143..dca95b79 100644 --- a/cmd/cozystack-operator/main.go +++ b/cmd/cozystack-operator/main.go @@ -18,8 +18,11 @@ package main import ( "context" + "encoding/json" "flag" + "fmt" "os" + "strings" "time" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) @@ -31,11 +34,14 @@ import ( 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" @@ -51,6 +57,18 @@ var ( 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)) @@ -72,6 +90,7 @@ func main() { 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.") @@ -83,6 +102,7 @@ func main() { 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", @@ -163,6 +183,20 @@ func main() { } } + // 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.CozystackBundleReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), @@ -172,6 +206,15 @@ func main() { os.Exit(1) } + platformReconciler := &operator.CozystackPlatformReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + } + if err = platformReconciler.SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "CozystackPlatform") + os.Exit(1) + } + // +kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { @@ -203,3 +246,67 @@ func main() { 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 +} diff --git a/examples/cozystackplatform-example.yaml b/examples/cozystackplatform-example.yaml new file mode 100644 index 00000000..b1753ffa --- /dev/null +++ b/examples/cozystackplatform-example.yaml @@ -0,0 +1,31 @@ +apiVersion: cozystack.io/v1alpha1 +kind: CozystackPlatform +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 + diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index b30a7d82..f8a1bd6a 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -55,6 +55,8 @@ kube::codegen::gen_openapi \ $CONTROLLER_GEN object:headerFile="hack/boilerplate.go.txt" paths="./api/..." $CONTROLLER_GEN rbac:roleName=manager-role crd paths="./api/..." output:crd:artifacts:config=packages/system/cozystack-controller/crds mv packages/system/cozystack-controller/crds/cozystack.io_cozystackresourcedefinitions.yaml \ - packages/core/cozystack-operator/crds/cozystack.io_cozystackresourcedefinitions.yaml + packages/core/installer/crds/cozystack.io_cozystackresourcedefinitions.yaml mv packages/system/cozystack-controller/crds/cozystack.io_cozystackbundles.yaml \ - packages/core/cozystack-operator/crds/cozystack.io_cozystackbundles.yaml + packages/core/installer/crds/cozystack.io_cozystackbundles.yaml +mv packages/system/cozystack-controller/crds/cozystack.io_cozystackplatforms.yaml \ + packages/core/installer/crds/cozystack.io_cozystackplatforms.yaml diff --git a/internal/controller/cozystackresource_controller.go b/internal/controller/cozystackresource_controller.go index 3013a005..86c83270 100644 --- a/internal/controller/cozystackresource_controller.go +++ b/internal/controller/cozystackresource_controller.go @@ -44,6 +44,7 @@ type CozystackResourceDefinitionReconciler struct { func (r *CozystackResourceDefinitionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { logger := log.FromContext(ctx) + logger.Info("Reconciling CozystackResourceDefinitions", "request", req.NamespacedName) // Get all CozystackResourceDefinitions crdList := &cozyv1alpha1.CozystackResourceDefinitionList{} @@ -52,9 +53,12 @@ func (r *CozystackResourceDefinitionReconciler) Reconcile(ctx context.Context, r return ctrl.Result{}, err } + logger.Info("Found CozystackResourceDefinitions", "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 @@ -86,6 +90,29 @@ func (r *CozystackResourceDefinitionReconciler) SetupWithManager(mgr ctrl.Manage }} }), ). + 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) } @@ -236,6 +263,9 @@ func (r *CozystackResourceDefinitionReconciler) updateHelmReleasesForCRD(ctx con } 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 { @@ -324,29 +354,42 @@ func (r *CozystackResourceDefinitionReconciler) updateHelmReleaseChart(ctx conte } // 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 := r.mergeHelmReleaseValues(crd.Spec.Release.Values, hrCopy.Spec.Values) + mergedValues, err = r.mergeHelmReleaseValues(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 + } - // After merging, ensure namespace is set from namespace labels (top-level) - // This matches the behavior in cozystack-api and NamespaceHelmReconciler - mergedValues, err = r.injectNamespaceLabelsIntoValues(ctx, mergedValues, hrCopy.Namespace) - if err != nil { - logger.Error(err, "failed to inject namespace labels", "name", hr.Name, "namespace", hr.Namespace) - // Continue even if namespace labels injection fails - } + // Always inject namespace labels (top-level _namespace field) + // This matches the behavior in cozystack-api and NamespaceHelmReconciler + mergedValues, err = r.injectNamespaceLabelsIntoValues(ctx, mergedValues, hrCopy.Namespace) + if err != nil { + logger.Error(err, "failed to inject namespace labels", "name", hr.Name, "namespace", hr.Namespace) + // Continue even if namespace labels injection fails + } - // Always update values if CRD has values specified - // This ensures that CRD values are always applied, even if the merged result is the same + // 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 - logger.Info("Updated values from CRD", "name", hr.Name, "namespace", hr.Namespace, "crd", crd.Name) + 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 in CRD, skipping values update", "name", hr.Name, "namespace", hr.Namespace, "crd", crd.Name) + logger.V(4).Info("No values update needed", "name", hr.Name, "namespace", hr.Namespace, "crd", crd.Name) } if !updated { @@ -364,8 +407,8 @@ func (r *CozystackResourceDefinitionReconciler) updateHelmReleaseChart(ctx conte } // mergeHelmReleaseValues merges CRD default values with existing HelmRelease values -// All fields are merged except "cozystack" which is fully overwritten from CRD values -// Existing HelmRelease values (outside of cozystack) take precedence (user values override defaults) +// 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 *CozystackResourceDefinitionReconciler) mergeHelmReleaseValues(crdValues, existingValues *apiextensionsv1.JSON) (*apiextensionsv1.JSON, error) { // If CRD has no values, preserve existing if crdValues == nil || len(crdValues.Raw) == 0 { @@ -389,21 +432,20 @@ func (r *CozystackResourceDefinitionReconciler) mergeHelmReleaseValues(crdValues return nil, fmt.Errorf("failed to unmarshal existing values: %w", err) } - // Start with CRD values (defaults) as base - // Then merge existing values on top (existing values override CRD defaults) - // This ensures user values have priority over CRD defaults - merged := deepMergeMaps(crdMap, existingMap) + // 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 "_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 + // 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) @@ -453,7 +495,7 @@ func valuesEqual(a, b *apiextensionsv1.JSON) bool { return string(a.Raw) == string(b.Raw) } -// injectNamespaceLabelsIntoValues injects namespace.cozystack.io/* labels into namespace (top-level) +// injectNamespaceLabelsIntoValues injects namespace.cozystack.io/* labels into _namespace (top-level) // This matches the behavior in cozystack-api and NamespaceHelmReconciler func (r *CozystackResourceDefinitionReconciler) injectNamespaceLabelsIntoValues(ctx context.Context, values *apiextensionsv1.JSON, namespaceName string) (*apiextensionsv1.JSON, error) { // Get namespace to extract namespace.cozystack.io/* labels @@ -486,8 +528,8 @@ func (r *CozystackResourceDefinitionReconciler) injectNamespaceLabelsIntoValues( namespaceLabelsMap[k] = v } - // Namespace labels completely overwrite existing namespace field (top-level) - valuesMap["namespace"] = namespaceLabelsMap + // Namespace labels completely overwrite existing _namespace field (top-level) + valuesMap["_namespace"] = namespaceLabelsMap // Marshal back to JSON mergedJSON, err := json.Marshal(valuesMap) diff --git a/internal/controller/namespace_helm_reconciler.go b/internal/controller/namespace_helm_reconciler.go index e7d60ce0..8b30ecff 100644 --- a/internal/controller/namespace_helm_reconciler.go +++ b/internal/controller/namespace_helm_reconciler.go @@ -123,17 +123,17 @@ func (r *NamespaceHelmReconciler) updateHelmReleaseWithNamespaceLabels(ctx conte namespaceLabelsMap[k] = v } - // Check if namespace labels need to be updated (top-level namespace field) + // Check if namespace labels need to be updated (top-level _namespace field) needsUpdate := false - currentNamespace, exists := valuesMap["namespace"] + currentNamespace, exists := valuesMap["_namespace"] if !exists { needsUpdate = true - valuesMap["namespace"] = namespaceLabelsMap + valuesMap["_namespace"] = namespaceLabelsMap } else { currentNamespaceMap, ok := currentNamespace.(map[string]interface{}) if !ok { needsUpdate = true - valuesMap["namespace"] = namespaceLabelsMap + valuesMap["_namespace"] = namespaceLabelsMap } else { // Compare and update if different for k, v := range namespaceLabelsMap { @@ -150,7 +150,7 @@ func (r *NamespaceHelmReconciler) updateHelmReleaseWithNamespaceLabels(ctx conte } } if needsUpdate { - valuesMap["namespace"] = currentNamespaceMap + valuesMap["_namespace"] = currentNamespaceMap } } } diff --git a/internal/lineagecontrollerwebhook/webhook.go b/internal/lineagecontrollerwebhook/webhook.go index 63df06f4..2db21eab 100644 --- a/internal/lineagecontrollerwebhook/webhook.go +++ b/internal/lineagecontrollerwebhook/webhook.go @@ -87,13 +87,16 @@ func (h *LineageControllerWebhook) Handle(ctx context.Context, req admission.Req "name", req.Name, "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) obj := &unstructured.Unstructured{} 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)) } + logger.V(1).Info("decoded object", "labels", obj.GetLabels(), "ownerReferences", obj.GetOwnerReferences()) labels, err := h.computeLabels(ctx, obj) for { if err != nil && errors.Is(err, NoAncestors) { @@ -116,9 +119,10 @@ func (h *LineageControllerWebhook) Handle(ctx context.Context, req admission.Req mutated, err := json.Marshal(obj) 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...) } diff --git a/internal/operator/bundle_reconciler.go b/internal/operator/bundle_reconciler.go index 5698e1fe..343fd66f 100644 --- a/internal/operator/bundle_reconciler.go +++ b/internal/operator/bundle_reconciler.go @@ -614,14 +614,15 @@ func (r *CozystackBundleReconciler) createOrUpdate(ctx context.Context, obj clie logger := log.FromContext(ctx) logger.V(1).Info("updating HelmRelease Spec", "name", hr.Name, "namespace", hr.Namespace) - // Check if this HelmRelease is managed through Application API - // If it has apps.cozystack.io/application.* labels, preserve user-modified values + // Check if this HelmRelease is managed through Application API or Controller + // If it has apps.cozystack.io/application.* labels OR cozystack.io/ui=true label, merge values with bundle priority isApplicationManaged := existingHR.Labels["apps.cozystack.io/application.kind"] != "" && existingHR.Labels["apps.cozystack.io/application.group"] != "" + isControllerManaged := existingHR.Labels["cozystack.io/ui"] == "true" - if isApplicationManaged { - // For Application-managed HelmReleases, merge values but overwrite cozystack field - logger.V(1).Info("merging values for Application-managed HelmRelease, overwriting cozystack", "name", hr.Name, "namespace", hr.Namespace) + if isApplicationManaged || isControllerManaged { + // For Application/Controller-managed HelmReleases, merge values with bundle priority + logger.V(1).Info("merging values for Application/Controller-managed HelmRelease with bundle priority", "name", hr.Name, "namespace", hr.Namespace, "isApplicationManaged", isApplicationManaged, "isControllerManaged", isControllerManaged) existingHR.Spec.Chart = hr.Spec.Chart existingHR.Spec.ChartRef = hr.Spec.ChartRef existingHR.Spec.Interval = hr.Spec.Interval @@ -639,8 +640,8 @@ func (r *CozystackBundleReconciler) createOrUpdate(ctx context.Context, obj clie existingHR.Spec.ServiceAccountName = hr.Spec.ServiceAccountName existingHR.Spec.Suspend = hr.Spec.Suspend - // Merge values: merge all fields except cozystack, which is fully overwritten - mergedValues, err := mergeHelmReleaseValues(existingHR.Spec.Values, hr.Spec.Values) + // Merge values: bundle values have priority (override existing) + mergedValues, err := mergeHelmReleaseValuesWithBundlePriority(existingHR.Spec.Values, hr.Spec.Values) if err != nil { logger.Error(err, "failed to merge values, using bundle values", "name", hr.Name, "namespace", hr.Namespace) existingHR.Spec.Values = hr.Spec.Values @@ -665,7 +666,7 @@ func (r *CozystackBundleReconciler) createOrUpdate(ctx context.Context, obj clie } // mergeHelmReleaseValues merges two HelmRelease values JSON objects -// All fields are merged except "cozystack" which is fully overwritten from bundleValues +// Existing values have priority (bundle values are merged into existing) func mergeHelmReleaseValues(existingValues, bundleValues *apiextensionsv1.JSON) (*apiextensionsv1.JSON, error) { // If bundle has no values, preserve existing if bundleValues == nil || len(bundleValues.Raw) == 0 { @@ -688,17 +689,46 @@ func mergeHelmReleaseValues(existingValues, bundleValues *apiextensionsv1.JSON) return nil, fmt.Errorf("failed to unmarshal bundle values: %w", err) } - // Merge: start with existing values - mergedMap := deepMergeMaps(existingMap, bundleMap) + // Merge: existing values have priority (bundle is merged into existing) + mergedMap := deepMergeMaps(bundleMap, existingMap) - // Overwrite cozystack field completely from bundle - if cozystackVal, exists := bundleMap["cozystack"]; exists { - mergedMap["cozystack"] = cozystackVal - } else { - // If bundle doesn't have cozystack, remove it from merged (optional - could also preserve) - delete(mergedMap, "cozystack") + // Marshal back to JSON + mergedJSON, err := json.Marshal(mergedMap) + if err != nil { + return nil, fmt.Errorf("failed to marshal merged values: %w", err) } + return &apiextensionsv1.JSON{Raw: mergedJSON}, nil +} + +// mergeHelmReleaseValuesWithBundlePriority merges two HelmRelease values JSON objects +// Bundle values have priority (override existing values) +// All fields from bundle override existing, except nested merges for maps +func mergeHelmReleaseValuesWithBundlePriority(existingValues, bundleValues *apiextensionsv1.JSON) (*apiextensionsv1.JSON, error) { + // If bundle has no values, preserve existing + if bundleValues == nil || len(bundleValues.Raw) == 0 { + return existingValues, nil + } + + // If existing has no values, use bundle values + if existingValues == nil || len(existingValues.Raw) == 0 { + return bundleValues, nil + } + + // Parse both values + var existingMap map[string]interface{} + if err := json.Unmarshal(existingValues.Raw, &existingMap); err != nil { + return nil, fmt.Errorf("failed to unmarshal existing values: %w", err) + } + + var bundleMap map[string]interface{} + if err := json.Unmarshal(bundleValues.Raw, &bundleMap); err != nil { + return nil, fmt.Errorf("failed to unmarshal bundle values: %w", err) + } + + // Merge: start with existing values, then bundle values override (bundle has priority) + mergedMap := deepMergeMaps(existingMap, bundleMap) + // Marshal back to JSON mergedJSON, err := json.Marshal(mergedMap) if err != nil { @@ -987,15 +1017,18 @@ func (r *CozystackBundleReconciler) reconcileNamespaces(ctx context.Context, bun namespace := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: nsName, - Labels: map[string]string{ - "cozystack.io/system": "true", - }, + Labels: make(map[string]string), Annotations: map[string]string{ "helm.sh/resource-policy": "keep", }, }, } + // Add system label only for non-tenant namespaces + if !strings.HasPrefix(nsName, "tenant-") { + namespace.Labels["cozystack.io/system"] = "true" + } + // Add privileged label if needed if info.privileged { namespace.Labels["pod-security.kubernetes.io/enforce"] = "privileged" diff --git a/internal/operator/platform_reconciler.go b/internal/operator/platform_reconciler.go new file mode 100644 index 00000000..af79546f --- /dev/null +++ b/internal/operator/platform_reconciler.go @@ -0,0 +1,441 @@ +/* +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" +) + +// CozystackPlatformReconciler reconciles CozystackPlatform resources +type CozystackPlatformReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackplatforms,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackplatforms/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 *CozystackPlatformReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + + platform := &cozyv1alpha1.CozystackPlatform{} + 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 + } + + return ctrl.Result{}, nil +} + +// reconcileArtifactGenerator creates or updates the ArtifactGenerator for the platform +func (r *CozystackPlatformReconciler) reconcileArtifactGenerator(ctx context.Context, platform *cozyv1alpha1.CozystackPlatform) error { + logger := log.FromContext(ctx) + + // ArtifactGenerator name is the sourceRef name + agName := platform.Spec.SourceRef.Name + // 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: agName, + 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", agName, "namespace", namespace) + + if err := r.createOrUpdate(ctx, ag); err != nil { + return fmt.Errorf("failed to reconcile ArtifactGenerator %s: %w", agName, err) + } + + logger.Info("reconciled ArtifactGenerator", "name", agName, "namespace", namespace) + return nil +} + +// reconcileHelmRelease creates or updates the HelmRelease for the platform +func (r *CozystackPlatformReconciler) reconcileHelmRelease(ctx context.Context, platform *cozyv1alpha1.CozystackPlatform) error { + logger := log.FromContext(ctx) + + // HelmRelease name is fixed: cozystack-platform + hrName := "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: hrName, + 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", hrName, "namespace", namespace) + + if err := r.createOrUpdate(ctx, hr); err != nil { + return fmt.Errorf("failed to reconcile HelmRelease %s: %w", hrName, err) + } + + logger.Info("reconciled HelmRelease", "name", hrName, "namespace", namespace) + return nil +} + +// mergeValuesWithSourceRef merges platform values with sourceRef +func (r *CozystackPlatformReconciler) 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 *CozystackPlatformReconciler) getBasePath(platform *cozyv1alpha1.CozystackPlatform) 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 *CozystackPlatformReconciler) 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 CozystackPlatform is deleted +func (r *CozystackPlatformReconciler) cleanupOrphanedResources(ctx context.Context, name client.ObjectKey) (ctrl.Result, error) { + // OwnerReferences should handle cleanup automatically + // This function is kept for potential future cleanup logic + // Note: name is ObjectKey, but for cluster-scoped resources only Name is used + return ctrl.Result{}, nil +} + +// createOrUpdate creates or updates a resource +func (r *CozystackPlatformReconciler) 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 *CozystackPlatformReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + Named("cozystack-platform"). + For(&cozyv1alpha1.CozystackPlatform{}). + 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) +} + diff --git a/internal/telemetry/collector.go b/internal/telemetry/collector.go index 4ecedd49..743af47e 100644 --- a/internal/telemetry/collector.go +++ b/internal/telemetry/collector.go @@ -195,23 +195,23 @@ func (c *Collector) collect(ctx context.Context) { // 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 { - key := fmt.Sprintf("%s (%s)", node.Status.NodeInfo.OperatingSystem, node.Status.NodeInfo.OSImage) - nodeOSCount[key] = nodeOSCount[key] + 1 + for _, node := range nodeList.Items { + key := fmt.Sprintf("%s (%s)", node.Status.NodeInfo.OperatingSystem, node.Status.NodeInfo.OSImage) + nodeOSCount[key] = nodeOSCount[key] + 1 if kernelVersion == "unknown" && node.Status.NodeInfo.KernelVersion != "" { kernelVersion = node.Status.NodeInfo.KernelVersion } - } + } - for osKey, count := range nodeOSCount { - metrics.WriteString(fmt.Sprintf( - "cozy_nodes_count{os=\"%s\",kernel=\"%s\"} %d\n", - osKey, + for osKey, count := range nodeOSCount { + metrics.WriteString(fmt.Sprintf( + "cozy_nodes_count{os=\"%s\",kernel=\"%s\"} %d\n", + osKey, kernelVersion, - count, - )) + count, + )) } } @@ -294,15 +294,15 @@ func (c *Collector) collect(ctx context.Context) { logger.Info(fmt.Sprintf("Failed to list WorkloadMonitors: %v", err)) // Continue without workload metrics instead of returning } else { - for _, monitor := range monitorList.Items { - metrics.WriteString(fmt.Sprintf( - "cozy_workloads_count{uid=\"%s\",kind=\"%s\",type=\"%s\",version=\"%s\"} %d\n", - monitor.UID, - monitor.Spec.Kind, - monitor.Spec.Type, - monitor.Spec.Version, - monitor.Status.ObservedReplicas, - )) + for _, monitor := range monitorList.Items { + metrics.WriteString(fmt.Sprintf( + "cozy_workloads_count{uid=\"%s\",kind=\"%s\",type=\"%s\",version=\"%s\"} %d\n", + monitor.UID, + monitor.Spec.Kind, + monitor.Spec.Type, + monitor.Spec.Version, + monitor.Status.ObservedReplicas, + )) } } diff --git a/packages/apps/bucket/templates/bucketclaim.yaml b/packages/apps/bucket/templates/bucketclaim.yaml index e0ce3b08..1c5df452 100644 --- a/packages/apps/bucket/templates/bucketclaim.yaml +++ b/packages/apps/bucket/templates/bucketclaim.yaml @@ -1,5 +1,5 @@ -{{- $cozystack := .Values.cozystack | default dict }} -{{- $namespace := dig "namespace" (dict) .Values }} +{{- $cozystack := .Values._cozystack | default dict }} +{{- $namespace := .Values._namespace | default dict }} {{- $seaweedfs := dig "seaweedfs" "" $namespace }} apiVersion: objectstorage.k8s.io/v1alpha1 kind: BucketClaim diff --git a/packages/apps/clickhouse/templates/chkeeper.yaml b/packages/apps/clickhouse/templates/chkeeper.yaml index e2301c6f..2b6602b4 100644 --- a/packages/apps/clickhouse/templates/chkeeper.yaml +++ b/packages/apps/clickhouse/templates/chkeeper.yaml @@ -1,4 +1,4 @@ -{{- $cozystack := .Values.cozystack | default dict }} +{{- $cozystack := .Values._cozystack | default dict }} {{- $clusterDomain := dig "networking" "clusterDomain" "cozy.local" $cozystack }} {{- if .Values.clickhouseKeeper.enabled }} diff --git a/packages/apps/clickhouse/templates/clickhouse.yaml b/packages/apps/clickhouse/templates/clickhouse.yaml index c78d282e..86e5a699 100644 --- a/packages/apps/clickhouse/templates/clickhouse.yaml +++ b/packages/apps/clickhouse/templates/clickhouse.yaml @@ -1,4 +1,4 @@ -{{- $cozystack := .Values.cozystack | default dict }} +{{- $cozystack := .Values._cozystack | default dict }} {{- $clusterDomain := dig "networking" "clusterDomain" "cozy.local" $cozystack }} {{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-credentials" .Release.Name) }} {{- $passwords := dict }} diff --git a/packages/apps/ferretdb/templates/postgres.yaml b/packages/apps/ferretdb/templates/postgres.yaml index 5d547a8a..7712cb97 100644 --- a/packages/apps/ferretdb/templates/postgres.yaml +++ b/packages/apps/ferretdb/templates/postgres.yaml @@ -50,7 +50,7 @@ spec: postgresUID: 999 postgresGID: 999 enableSuperuserAccess: true - {{- $cozystack := .Values.cozystack | default dict }} + {{- $cozystack := .Values._cozystack | default dict }} {{- $topologySpreadConstraints := dig "scheduling" "topologySpreadConstraints" (list) $cozystack }} {{- if $topologySpreadConstraints }} topologySpreadConstraints: diff --git a/packages/apps/foundationdb/templates/cluster.yaml b/packages/apps/foundationdb/templates/cluster.yaml index 0426e29d..56bdb812 100644 --- a/packages/apps/foundationdb/templates/cluster.yaml +++ b/packages/apps/foundationdb/templates/cluster.yaml @@ -1,4 +1,4 @@ -{{- $cozystack := .Values.cozystack | default dict }} +{{- $cozystack := .Values._cozystack | default dict }} {{- $clusterDomain := dig "networking" "clusterDomain" "cozy.local" $cozystack }} --- apiVersion: apps.foundationdb.org/v1beta2 diff --git a/packages/apps/kubernetes/templates/cluster.yaml b/packages/apps/kubernetes/templates/cluster.yaml index d5eec651..28c601fe 100644 --- a/packages/apps/kubernetes/templates/cluster.yaml +++ b/packages/apps/kubernetes/templates/cluster.yaml @@ -1,5 +1,5 @@ -{{- $cozystack := .Values.cozystack | default dict }} -{{- $namespace := dig "namespace" (dict) .Values }} +{{- $cozystack := .Values._cozystack | default dict }} +{{- $namespace := .Values._namespace | default dict }} {{- $etcd := dig "etcd" "" $namespace }} {{- $ingress := dig "ingress" "" $namespace }} {{- $host := dig "host" "" $namespace }} @@ -32,7 +32,7 @@ spec: {{- end }} cluster.x-k8s.io/deployment-name: {{ $.Release.Name }}-{{ .groupName }} spec: - {{- $cozystack := $.Values.cozystack | default dict }} + {{- $cozystack := $.Values._cozystack | default dict }} {{- $topologySpreadConstraints := dig "scheduling" "topologySpreadConstraints" (list) $cozystack }} {{- if $topologySpreadConstraints }} {{- range $topologySpreadConstraints }} diff --git a/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml b/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml index 4150f9ed..5bfe9b89 100644 --- a/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml @@ -1,5 +1,5 @@ -{{- $cozystack := .Values.cozystack | default dict }} -{{- $namespace := dig "namespace" (dict) .Values }} +{{- $cozystack := .Values._cozystack | default dict }} +{{- $namespace := .Values._namespace | default dict }} {{- $targetTenant := dig "monitoring" "" $namespace }} {{- if .Values.addons.monitoringAgents.enabled }} apiVersion: helm.toolkit.fluxcd.io/v2 diff --git a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml index 0fd7dca9..82361057 100644 --- a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml @@ -1,7 +1,7 @@ {{- define "cozystack.defaultVPAValues" -}} -{{- $cozystack := .Values.cozystack | default dict }} +{{- $cozystack := .Values._cozystack | default dict }} {{- $clusterDomain := dig "networking" "clusterDomain" "cozy.local" $cozystack }} -{{- $namespace := dig "namespace" (dict) .Values }} +{{- $namespace := .Values._namespace | default dict }} {{- $targetTenant := dig "monitoring" "" $namespace }} vpaForVPA: false vertical-pod-autoscaler: diff --git a/packages/apps/kubernetes/templates/ingress.yaml b/packages/apps/kubernetes/templates/ingress.yaml index 7774e6dc..84df0300 100644 --- a/packages/apps/kubernetes/templates/ingress.yaml +++ b/packages/apps/kubernetes/templates/ingress.yaml @@ -1,5 +1,5 @@ -{{- $cozystack := .Values.cozystack | default dict }} -{{- $namespace := dig "namespace" (dict) .Values }} +{{- $cozystack := .Values._cozystack | default dict }} +{{- $namespace := .Values._namespace | default dict }} {{- $ingress := dig "ingress" "" $namespace }} {{- if and (eq .Values.addons.ingressNginx.exposeMethod "Proxied") .Values.addons.ingressNginx.hosts }} --- diff --git a/packages/apps/nats/templates/nats.yaml b/packages/apps/nats/templates/nats.yaml index 40bcbe45..da2a708f 100644 --- a/packages/apps/nats/templates/nats.yaml +++ b/packages/apps/nats/templates/nats.yaml @@ -1,4 +1,4 @@ -{{- $cozystack := .Values.cozystack | default dict }} +{{- $cozystack := .Values._cozystack | default dict }} {{- $clusterDomain := dig "networking" "clusterDomain" "cozy.local" $cozystack }} {{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-credentials" .Release.Name) }} {{- $passwords := dict }} diff --git a/packages/apps/postgres/templates/db.yaml b/packages/apps/postgres/templates/db.yaml index cf6d4966..233529d1 100644 --- a/packages/apps/postgres/templates/db.yaml +++ b/packages/apps/postgres/templates/db.yaml @@ -45,7 +45,7 @@ spec: resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 4 }} enableSuperuserAccess: true - {{- $cozystack := .Values.cozystack | default dict }} + {{- $cozystack := .Values._cozystack | default dict }} {{- $topologySpreadConstraints := dig "scheduling" "topologySpreadConstraints" (list) $cozystack }} {{- if $topologySpreadConstraints }} topologySpreadConstraints: diff --git a/packages/apps/tenant/templates/keycloakgroups.yaml b/packages/apps/tenant/templates/keycloakgroups.yaml index 9aeae6e3..53dbaac4 100644 --- a/packages/apps/tenant/templates/keycloakgroups.yaml +++ b/packages/apps/tenant/templates/keycloakgroups.yaml @@ -1,4 +1,4 @@ -{{- $cozystack := .Values.cozystack | default dict }} +{{- $cozystack := .Values._cozystack | default dict }} {{- $authentication := $cozystack.authentication | default dict }} {{- $oidc := $authentication.oidc | default dict }} {{- $oidcEnabled := $oidc.enabled | default false }} diff --git a/packages/apps/tenant/templates/namespace.yaml b/packages/apps/tenant/templates/namespace.yaml index ef99bb25..7533e0c8 100644 --- a/packages/apps/tenant/templates/namespace.yaml +++ b/packages/apps/tenant/templates/namespace.yaml @@ -15,7 +15,7 @@ namespace.cozystack.io/{{ $x }}: "{{ $value }}" {{- end }} {{- end }} -{{- $namespace := dig "namespace" (dict) .Values }} +{{- $namespace := .Values._namespace | default dict }} {{- $existingNS := lookup "v1" "Namespace" "" .Release.Namespace }} {{- if not $existingNS }} {{- fail (printf "error lookup existing namespace: %s" .Release.Namespace) }} diff --git a/packages/apps/vpn/templates/secret.yaml b/packages/apps/vpn/templates/secret.yaml index b1d3152f..d97d2a24 100644 --- a/packages/apps/vpn/templates/secret.yaml +++ b/packages/apps/vpn/templates/secret.yaml @@ -1,5 +1,5 @@ -{{- $cozystack := .Values.cozystack | default dict }} -{{- $namespace := dig "namespace" (dict) .Values }} +{{- $cozystack := .Values._cozystack | default dict }} +{{- $namespace := .Values._namespace | default dict }} {{- $host := dig "host" "" $namespace }} {{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-vpn" .Release.Name) }} {{- $accessKeys := list }} diff --git a/packages/core/cozystack-operator/Chart.yaml b/packages/core/cozystack-operator/Chart.yaml deleted file mode 100644 index 61cf32e6..00000000 --- a/packages/core/cozystack-operator/Chart.yaml +++ /dev/null @@ -1,3 +0,0 @@ -apiVersion: v2 -name: cozy-cozystack-operator -version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/core/cozystack-operator/Makefile b/packages/core/cozystack-operator/Makefile deleted file mode 100644 index 5d23605a..00000000 --- a/packages/core/cozystack-operator/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -NAME=cozystack-operator -NAMESPACE=cozy-system - -include ../../../scripts/common-envs.mk - -image: pre-checks image-cozystack-operator update-version - -pre-checks: - ../../../hack/pre-checks.sh - -show: - cozypkg show -n $(NAMESPACE) $(NAME) --plain - -apply: - cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f- - -diff: - cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f - - -image-cozystack-operator: - docker buildx build -f images/cozystack-operator/Dockerfile ../../.. \ - --tag $(REGISTRY)/cozystack-operator:$(call settag,$(TAG)) \ - --cache-from type=registry,ref=$(REGISTRY)/cozystack-operator:latest \ - --cache-to type=inline \ - --metadata-file images/cozystack-operator.json \ - $(BUILDX_ARGS) - IMAGE="$(REGISTRY)/cozystack-operator:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/cozystack-operator.json -o json -r)" \ - yq -i '.cozystackOperator.image = strenv(IMAGE)' values.yaml - rm -f images/cozystack-operator.json - -update-version: - TAG="$(call settag,$(TAG))" \ - yq -i '.cozystackOperator.cozystackVersion = strenv(TAG)' values.yaml diff --git a/packages/core/cozystack-operator/values.yaml b/packages/core/cozystack-operator/values.yaml deleted file mode 100644 index 0e72fe6c..00000000 --- a/packages/core/cozystack-operator/values.yaml +++ /dev/null @@ -1,4 +0,0 @@ -cozystackOperator: - image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:33294c84ea575ece5aa0d301b43a0a71b455668f8f1c60c992aa3f6b3c9a8c8f - disableTelemetry: false - cozystackVersion: "latest" diff --git a/packages/core/installer/Chart.yaml b/packages/core/installer/Chart.yaml index 91350467..61cf32e6 100644 --- a/packages/core/installer/Chart.yaml +++ b/packages/core/installer/Chart.yaml @@ -1,3 +1,3 @@ apiVersion: v2 -name: cozy-installer +name: cozy-cozystack-operator version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/core/installer/Makefile b/packages/core/installer/Makefile index 5c2e1577..1789699c 100644 --- a/packages/core/installer/Makefile +++ b/packages/core/installer/Makefile @@ -1,10 +1,10 @@ -NAME=installer +NAME=cozystack-operator NAMESPACE=cozy-system -TALOS_VERSION=$(shell awk '/^version:/ {print $$2}' images/talos/profiles/installer.yaml) - include ../../../scripts/common-envs.mk +image: pre-checks image-cozystack-operator image-packages update-version + pre-checks: ../../../hack/pre-checks.sh @@ -17,7 +17,20 @@ apply: diff: cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f - -image: image-packages +image-operator: + docker buildx build -f images/cozystack-operator/Dockerfile ../../.. \ + --tag $(REGISTRY)/cozystack-operator:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/cozystack-operator:latest \ + --cache-to type=inline \ + --metadata-file images/cozystack-operator.json \ + $(BUILDX_ARGS) + IMAGE="$(REGISTRY)/cozystack-operator:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/cozystack-operator.json -o json -r)" \ + yq -i '.cozystackOperator.image = strenv(IMAGE)' values.yaml + rm -f images/cozystack-operator.json + +update-version: + TAG="$(call settag,$(TAG))" \ + yq -i '.cozystackOperator.cozystackVersion = strenv(TAG)' values.yaml image-packages: mkdir -p ../../../_out/assets images @@ -28,4 +41,4 @@ image-packages: --revision="$$(git describe --tags):$$(git rev-parse HEAD)" \ 2>&1 | tee images/cozystack-packages.log DIGEST=$$(awk -F@ '/artifact successfully pushed/ {print $$2}' images/cozystack-packages.log; rm -f images/cozystack-packages.log) \ - yq -i '.packagesDigest = strenv(DIGEST)' values.yaml + yq -i '.cozystackOperator.packagesDigest = strenv(DIGEST)' values.yaml diff --git a/packages/core/cozystack-operator/crds/cozystack.io_cozystackbundles.yaml b/packages/core/installer/crds/cozystack.io_cozystackbundles.yaml similarity index 100% rename from packages/core/cozystack-operator/crds/cozystack.io_cozystackbundles.yaml rename to packages/core/installer/crds/cozystack.io_cozystackbundles.yaml diff --git a/packages/core/installer/crds/cozystack.io_cozystackplatforms.yaml b/packages/core/installer/crds/cozystack.io_cozystackplatforms.yaml new file mode 100644 index 00000000..1d54c233 --- /dev/null +++ b/packages/core/installer/crds/cozystack.io_cozystackplatforms.yaml @@ -0,0 +1,83 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: cozystackplatforms.cozystack.io +spec: + group: cozystack.io + names: + kind: CozystackPlatform + listKind: CozystackPlatformList + plural: cozystackplatforms + singular: cozystackplatform + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: CozystackPlatform is the Schema for the cozystackplatforms API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: CozystackPlatformSpec defines the desired state of CozystackPlatform + properties: + basePath: + description: |- + 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. + type: string + interval: + default: 5m + description: Interval is the interval at which to reconcile the HelmRelease + type: string + sourceRef: + description: |- + SourceRef is the source reference for the platform chart + This is used to generate the ArtifactGenerator + properties: + kind: + default: HelmRepository + description: Kind of the source reference + type: string + name: + description: Name of the source reference + type: string + namespace: + default: cozy-public + description: Namespace of the source reference + type: string + required: + - kind + - name + - namespace + type: object + values: + description: |- + Values contains Helm chart values as a JSON object + These values are passed directly to HelmRelease.values + x-kubernetes-preserve-unknown-fields: true + required: + - sourceRef + type: object + type: object + served: true + storage: true diff --git a/packages/core/cozystack-operator/crds/cozystack.io_cozystackresourcedefinitions.yaml b/packages/core/installer/crds/cozystack.io_cozystackresourcedefinitions.yaml similarity index 100% rename from packages/core/cozystack-operator/crds/cozystack.io_cozystackresourcedefinitions.yaml rename to packages/core/installer/crds/cozystack.io_cozystackresourcedefinitions.yaml diff --git a/packages/core/installer/example/platform.yaml b/packages/core/installer/example/platform.yaml new file mode 100644 index 00000000..7b0d51da --- /dev/null +++ b/packages/core/installer/example/platform.yaml @@ -0,0 +1,30 @@ +apiVersion: cozystack.io/v1alpha1 +kind: CozystackPlatform +metadata: + name: cozystack-platform +spec: + interval: 5m + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + values: + bundles: + system: + type: "full" + iaas: + enabled: true + paas: + enabled: true + naas: + enabled: false + publishing: + host: "dev5.infra.aenix.org" + apiServerEndpoint: "https://api.dev5.infra.aenix.org" + externalIPs: + - 10.4.0.246 + - 10.4.0.180 + - 10.4.0.46 + authentication: + oidc: + enabled: true diff --git a/packages/core/cozystack-operator/images/cozystack-operator/Dockerfile b/packages/core/installer/images/cozystack-operator/Dockerfile similarity index 100% rename from packages/core/cozystack-operator/images/cozystack-operator/Dockerfile rename to packages/core/installer/images/cozystack-operator/Dockerfile diff --git a/packages/core/cozystack-operator/images/cozystack-operator/Dockerfile.dockerignore b/packages/core/installer/images/cozystack-operator/Dockerfile.dockerignore similarity index 100% rename from packages/core/cozystack-operator/images/cozystack-operator/Dockerfile.dockerignore rename to packages/core/installer/images/cozystack-operator/Dockerfile.dockerignore diff --git a/packages/core/cozystack-operator/templates/cozystack-operator.yaml b/packages/core/installer/templates/cozystack-operator.yaml similarity index 77% rename from packages/core/cozystack-operator/templates/cozystack-operator.yaml rename to packages/core/installer/templates/cozystack-operator.yaml index 8d13aff1..3229b55d 100644 --- a/packages/core/cozystack-operator/templates/cozystack-operator.yaml +++ b/packages/core/installer/templates/cozystack-operator.yaml @@ -1,3 +1,15 @@ +{{- define "cozystack-operator.flux-resource" -}} +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: cozystack-packages + namespace: cozy-system +spec: + interval: 5m0s + url: oci://ghcr.io/cozystack/cozystack/platform-packages + ref: + digest: {{ .Values.cozystackOperator.packagesDigest }} +{{- end -}} --- apiVersion: v1 kind: Namespace @@ -59,6 +71,9 @@ spec: {{- if .Values.cozystackOperator.disableTelemetry }} - --disable-telemetry {{- end }} + {{- if .Values.cozystackOperator.packagesDigest }} + - --install-flux-resource={{ include "cozystack-operator.flux-resource" . | fromYaml | toJson }} + {{- end }} env: - name: KUBERNETES_SERVICE_HOST value: localhost diff --git a/packages/core/cozystack-operator/templates/crds.yaml b/packages/core/installer/templates/crds.yaml similarity index 100% rename from packages/core/cozystack-operator/templates/crds.yaml rename to packages/core/installer/templates/crds.yaml diff --git a/packages/core/installer/templates/platform.yaml b/packages/core/installer/templates/platform.yaml deleted file mode 100644 index 7edbb757..00000000 --- a/packages/core/installer/templates/platform.yaml +++ /dev/null @@ -1,51 +0,0 @@ ---- -apiVersion: source.toolkit.fluxcd.io/v1 -kind: OCIRepository -metadata: - name: cozystack-packages - namespace: cozy-system -spec: - interval: 5m0s - url: oci://ghcr.io/cozystack/cozystack/platform-packages - ref: - {{- if and .Values.packagesDigest (ne .Values.packagesDigest "") }} - digest: {{ .Values.packagesDigest }} - {{- else }} - tag: latest - {{- end }} ---- -apiVersion: source.extensions.fluxcd.io/v1beta1 -kind: ArtifactGenerator -metadata: - name: cozystack-packages - namespace: cozy-system -spec: - artifacts: - - copy: - - from: '@cozystack/core/platform/**' - to: '@artifact/platform/' - name: cozystack-core-platform - sources: - - alias: cozystack - kind: OCIRepository - name: cozystack-packages - namespace: cozy-system ---- -apiVersion: helm.toolkit.fluxcd.io/v2 -kind: HelmRelease -metadata: - name: cozystack-platform - namespace: cozy-system -spec: - interval: 5m - targetNamespace: cozy-system - releaseName: cozystack-platform - chartRef: - kind: ExternalArtifact - name: cozystack-core-platform - namespace: cozy-system - values: - sourceRef: - kind: OCIRepository - name: cozystack-packages - namespace: cozy-system diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index ec1e161f..53b51940 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,3 +1,5 @@ -# Digest for OCIRepository cozystack-packages -# This value is automatically updated by Makefile when building the image -packagesDigest: "sha256:a1c14def709ed07d4d0dc8a776143388115a36c30e3558d5c4974f55ef653f35" +cozystackOperator: + image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:ede9a0a6b7b1ad137ef1f75c1e954115da8ebdab110e47d920ae01ac62be93ec + disableTelemetry: false + cozystackVersion: "latest" + packagesDigest: sha256:e0b444176a041831f79fab0264e643171c16f8519b52854c27b1fad4b4abbf5e diff --git a/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml b/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml index 13e2b9f8..72c408d8 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-iaas-bucket namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: singular: Bucket @@ -35,10 +35,10 @@ spec: exclude: [] include: - resourceNames: - - bucket-{{ .name }} - - bucket-{{ .name }}-credentials + - "{{`bucket-{{ .name }}`}}" + - "{{`bucket-{{ .name }}-credentials`}}" ingresses: exclude: [] include: - resourceNames: - - bucket-{{ .name }}-ui + - "{{`bucket-{{ .name }}-ui`}}" diff --git a/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml b/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml index 92a3cbb0..279075cf 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-iaas-kubernetes namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: IaaS @@ -35,14 +35,14 @@ spec: exclude: [] include: - resourceNames: - - kubernetes-{{ .name }}-admin-kubeconfig + - "{{`kubernetes-{{ .name }}-admin-kubeconfig`}}" services: exclude: [] include: - resourceNames: - - kubernetes-{{ .name }} + - "{{`kubernetes-{{ .name }}`}}" ingresses: exclude: [] include: - resourceNames: - - kubernetes-{{ .name }} + - "{{`kubernetes-{{ .name }}`}}" diff --git a/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml b/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml index 0fed9d96..6c75685e 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-iaas-virtual-machine namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: IaaS @@ -38,4 +38,4 @@ spec: exclude: [] include: - resourceNames: - - virtual-machine-{{ .name }} + - "{{`virtual-machine-{{ .name }}`}}" diff --git a/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml b/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml index d7c39f6e..987fd00c 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-iaas-vpc namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: IaaS diff --git a/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml b/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml index 35dae6b5..e10b2f69 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-iaas-vm-disk namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: IaaS diff --git a/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml b/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml index 92f1d78d..d5dd2434 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml +++ b/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-iaas-vm-instance namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: IaaS diff --git a/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml b/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml index f313895f..1bbd091d 100644 --- a/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml +++ b/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-naas-http-cache namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: NaaS diff --git a/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml b/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml index 929bd4e4..e308a817 100644 --- a/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml +++ b/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-naas-tcp-balancer namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: NaaS diff --git a/packages/core/platform/bundles/naas/cozyrds/vpn.yaml b/packages/core/platform/bundles/naas/cozyrds/vpn.yaml index fea7c682..892ca9b7 100644 --- a/packages/core/platform/bundles/naas/cozyrds/vpn.yaml +++ b/packages/core/platform/bundles/naas/cozyrds/vpn.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-naas-vpn namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: NaaS @@ -34,9 +34,9 @@ spec: exclude: [] include: - resourceNames: - - vpn-{{ .name }}-urls + - "{{`vpn-{{ .name }}-urls`}}" services: exclude: [] include: - resourceNames: - - vpn-{{ .name }}-vpn + - "{{`vpn-{{ .name }}-vpn`}}" diff --git a/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml b/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml index 54cc1c8c..0c21c5b7 100644 --- a/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-paas-clickhouse namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: PaaS @@ -33,9 +33,9 @@ spec: exclude: [] include: - resourceNames: - - clickhouse-{{ .name }}-credentials + - "{{`clickhouse-{{ .name }}-credentials`}}" services: exclude: [] include: - resourceNames: - - chendpoint-clickhouse-{{ .name }} + - "{{`chendpoint-clickhouse-{{ .name }}`}}" diff --git a/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml b/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml index 7ce1f91a..d8be5c52 100644 --- a/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-paas-ferretdb namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: PaaS @@ -34,9 +34,9 @@ spec: exclude: [] include: - resourceNames: - - ferretdb-{{ .name }}-credentials + - "{{`ferretdb-{{ .name }}-credentials`}}" services: exclude: [] include: - resourceNames: - - ferretdb-{{ .name }} + - "{{`ferretdb-{{ .name }}`}}" diff --git a/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml b/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml index 31fe348a..49c1f25c 100644 --- a/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-paas-foundationdb namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: PaaS diff --git a/packages/core/platform/bundles/paas/cozyrds/kafka.yaml b/packages/core/platform/bundles/paas/cozyrds/kafka.yaml index 6b4f99ed..ebfe8e19 100644 --- a/packages/core/platform/bundles/paas/cozyrds/kafka.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/kafka.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-paas-kafka namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: PaaS @@ -34,9 +34,9 @@ spec: exclude: [] include: - resourceNames: - - kafka-{{ .name }}-clients-ca + - "{{`kafka-{{ .name }}-clients-ca`}}" services: exclude: [] include: - resourceNames: - - kafka-{{ .name }}-kafka-bootstrap + - "{{`kafka-{{ .name }}-kafka-bootstrap`}}" diff --git a/packages/core/platform/bundles/paas/cozyrds/mysql.yaml b/packages/core/platform/bundles/paas/cozyrds/mysql.yaml index 3032b8f5..957070b9 100644 --- a/packages/core/platform/bundles/paas/cozyrds/mysql.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/mysql.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-paas-mysql namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: PaaS @@ -34,10 +34,10 @@ spec: exclude: [] include: - resourceNames: - - mysql-{{ .name }}-credentials + - "{{`mysql-{{ .name }}-credentials`}}" services: exclude: [] include: - resourceNames: - - mysql-{{ .name }}-primary - - mysql-{{ .name }}-secondary + - "{{`mysql-{{ .name }}-primary`}}" + - "{{`mysql-{{ .name }}-secondary`}}" diff --git a/packages/core/platform/bundles/paas/cozyrds/nats.yaml b/packages/core/platform/bundles/paas/cozyrds/nats.yaml index 59fd98a6..a90bdb8a 100644 --- a/packages/core/platform/bundles/paas/cozyrds/nats.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/nats.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-paas-nats namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: PaaS @@ -34,9 +34,9 @@ spec: exclude: [] include: - resourceNames: - - nats-{{ .name }}-credentials + - "{{`nats-{{ .name }}-credentials`}}" services: exclude: [] include: - resourceNames: - - nats-{{ .name }} + - "{{`nats-{{ .name }}`}}" diff --git a/packages/core/platform/bundles/paas/cozyrds/postgres.yaml b/packages/core/platform/bundles/paas/cozyrds/postgres.yaml index 396fcf30..1c7583f8 100644 --- a/packages/core/platform/bundles/paas/cozyrds/postgres.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/postgres.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-paas-postgres namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: PaaS @@ -42,12 +42,12 @@ spec: exclude: [] include: - resourceNames: - - postgres-{{ .name }}-credentials + - "{{`postgres-{{ .name }}-credentials`}}" services: exclude: [] include: - resourceNames: - - postgres-{{ .name }}-r - - postgres-{{ .name }}-ro - - postgres-{{ .name }}-rw - - postgres-{{ .name }}-external-write + - "{{`postgres-{{ .name }}-r`}}" + - "{{`postgres-{{ .name }}-ro`}}" + - "{{`postgres-{{ .name }}-rw`}}" + - "{{`postgres-{{ .name }}-external-write`}}" diff --git a/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml b/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml index fcf90f3d..c521084c 100644 --- a/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-paas-rabbitmq namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: PaaS @@ -34,11 +34,11 @@ spec: exclude: [] include: - resourceNames: - - rabbitmq-{{ .name }}-default-user + - "{{`rabbitmq-{{ .name }}-default-user`}}" - matchLabels: apps.cozystack.io/user-secret: "true" services: exclude: [] include: - resourceNames: - - rabbitmq-{{ .name }} + - "{{`rabbitmq-{{ .name }}`}}" diff --git a/packages/core/platform/bundles/paas/cozyrds/redis.yaml b/packages/core/platform/bundles/paas/cozyrds/redis.yaml index d8cc645d..37c72dd8 100644 --- a/packages/core/platform/bundles/paas/cozyrds/redis.yaml +++ b/packages/core/platform/bundles/paas/cozyrds/redis.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-paas-redis namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: PaaS @@ -34,12 +34,12 @@ spec: exclude: [] include: - resourceNames: - - redis-{{ .name }}-auth + - "{{`redis-{{ .name }}-auth`}}" services: exclude: [] include: - resourceNames: - - rfs-redis-{{ .name }} - - rfrm-redis-{{ .name }} - - rfrs-redis-{{ .name }} - - redis-{{ .name }}-external-lb + - "{{`rfs-redis-{{ .name }}`}}" + - "{{`rfrm-redis-{{ .name }}`}}" + - "{{`rfrs-redis-{{ .name }}`}}" + - "{{`redis-{{ .name }}-external-lb`}}" diff --git a/packages/core/platform/bundles/system/cozyrds/bootbox.yaml b/packages/core/platform/bundles/system/cozyrds/bootbox.yaml index d994fda4..2ed082bf 100644 --- a/packages/core/platform/bundles/system/cozyrds/bootbox.yaml +++ b/packages/core/platform/bundles/system/cozyrds/bootbox.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-system-bootbox namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: Administration diff --git a/packages/core/platform/bundles/system/cozyrds/etcd.yaml b/packages/core/platform/bundles/system/cozyrds/etcd.yaml index d70c27ce..c8f1afb1 100644 --- a/packages/core/platform/bundles/system/cozyrds/etcd.yaml +++ b/packages/core/platform/bundles/system/cozyrds/etcd.yaml @@ -20,7 +20,7 @@ spec: name: cozystack-system-etcd namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: Administration diff --git a/packages/core/platform/bundles/system/cozyrds/info.yaml b/packages/core/platform/bundles/system/cozyrds/info.yaml index 33c31dda..d74d703c 100644 --- a/packages/core/platform/bundles/system/cozyrds/info.yaml +++ b/packages/core/platform/bundles/system/cozyrds/info.yaml @@ -20,7 +20,7 @@ spec: name: cozystack-system-info namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: name: info @@ -35,5 +35,5 @@ spec: exclude: [] include: - resourceNames: - - kubeconfig-{{ .namespace }} - - "{{ .namespace }}" + - "{{`kubeconfig-{{ .namespace }}`}}" + - "{{`{{ .namespace }}`}}" diff --git a/packages/core/platform/bundles/system/cozyrds/ingress.yaml b/packages/core/platform/bundles/system/cozyrds/ingress.yaml index 5eb40bba..effaeb74 100644 --- a/packages/core/platform/bundles/system/cozyrds/ingress.yaml +++ b/packages/core/platform/bundles/system/cozyrds/ingress.yaml @@ -20,7 +20,7 @@ spec: name: cozystack-system-ingress namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: Administration @@ -38,4 +38,4 @@ spec: exclude: [] include: - resourceNames: - - "{{ slice .namespace 7 }}-ingress-controller" + - "{{`{{ slice .namespace 7 }}-ingress-controller`}}" diff --git a/packages/core/platform/bundles/system/cozyrds/monitoring.yaml b/packages/core/platform/bundles/system/cozyrds/monitoring.yaml index 0ee236ce..d946fb06 100644 --- a/packages/core/platform/bundles/system/cozyrds/monitoring.yaml +++ b/packages/core/platform/bundles/system/cozyrds/monitoring.yaml @@ -20,7 +20,7 @@ spec: name: cozystack-system-monitoring namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: Administration diff --git a/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml b/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml index 5f064ec7..6568c712 100644 --- a/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml +++ b/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml @@ -20,7 +20,7 @@ spec: name: cozystack-system-seaweedfs namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: Administration @@ -38,9 +38,9 @@ spec: exclude: [] include: - resourceNames: - - seaweedfs-{{ .name }}-s3 + - "{{`seaweedfs-{{ .name }}-s3`}}" ingresses: exclude: [] include: - resourceNames: - - ingress-seaweedfs-{{ .name }}-s3 + - "{{`ingress-seaweedfs-{{ .name }}-s3`}}" diff --git a/packages/core/platform/bundles/system/cozyrds/tenant.yaml b/packages/core/platform/bundles/system/cozyrds/tenant.yaml index 57de7a92..e559790f 100644 --- a/packages/core/platform/bundles/system/cozyrds/tenant.yaml +++ b/packages/core/platform/bundles/system/cozyrds/tenant.yaml @@ -19,7 +19,7 @@ spec: name: cozystack-system-tenant namespace: cozy-system values: - cozystack: + _cozystack: {{- include "cozystack.build-values" . | nindent 8 }} dashboard: category: Administration diff --git a/packages/core/platform/templates/_helpers.tpl b/packages/core/platform/templates/_helpers.tpl index b8eaaa78..fb1ba54d 100644 --- a/packages/core/platform/templates/_helpers.tpl +++ b/packages/core/platform/templates/_helpers.tpl @@ -77,28 +77,13 @@ Usage: {{ include "cozystack.render-file" (list . "bundles/system/bundle-full.ya {{/* Render all files matching a glob pattern with template processing Usage: {{ include "cozystack.render-glob" (list . "bundles/system/cozyrds/*.yaml") }} -Escapes templates like {{ .name }} and {{ .namespace }} that should remain as-is */}} {{- define "cozystack.render-glob" -}} {{- $ := index . 0 }} {{- $pattern := index . 1 }} {{- range $path, $_ := $.Files.Glob $pattern }} -{{- $content := $.Files.Get $path }} -{{- /* Escape templates that should remain as-is using temporary markers */}} -{{- /* Process complex patterns first (longer matches) */}} -{{- $content = $content | replace "{{ slice .namespace 7 }}" "__TEMPLATE_SLICE_NAMESPACE_7__" }} -{{- $content = $content | replace "{{ slice .namespace" "__TEMPLATE_SLICE_NAMESPACE__" }} -{{- $content = $content | replace "{{ .namespace }}" "__TEMPLATE_DOT_NAMESPACE__" }} -{{- $content = $content | replace "{{ .name }}" "__TEMPLATE_DOT_NAME__" }} -{{- /* Render the template */}} -{{- $rendered := trim (tpl $content $) }} -{{- /* Restore escaped templates */}} -{{- $rendered = $rendered | replace "__TEMPLATE_DOT_NAME__" "{{ .name }}" }} -{{- $rendered = $rendered | replace "__TEMPLATE_DOT_NAMESPACE__" "{{ .namespace }}" }} -{{- $rendered = $rendered | replace "__TEMPLATE_SLICE_NAMESPACE__" "{{ slice .namespace" }} -{{- $rendered = $rendered | replace "__TEMPLATE_SLICE_NAMESPACE_7__" "{{ slice .namespace 7 }}" }} --- -{{ $rendered }} +{{ trim (tpl ($.Files.Get $path) $) }} {{- end }} {{- end -}} @@ -173,5 +158,6 @@ Returns: YAML string with cozystack values structure {{- if .Values.branding }}{{ $_ := set $cozystack "branding" .Values.branding }}{{ end }} {{- if .Values.registries }}{{ $_ := set $cozystack "registries" .Values.registries }}{{ end }} {{- if .Values.resources }}{{ $_ := set $cozystack "resources" .Values.resources }}{{ end }} +{{- if .Values.components }}{{ $_ := set $cozystack "components" .Values.components }}{{ end }} {{- $cozystack | toYaml | trim }} {{- end -}} diff --git a/packages/core/talos/values.yaml b/packages/core/talos/values.yaml index 6122038e..e69de29b 100644 --- a/packages/core/talos/values.yaml +++ b/packages/core/talos/values.yaml @@ -1,2 +0,0 @@ -# Talos installer values - no longer contains cozystack-operator -# cozystack-operator is now in packages/core/cozystack-operator diff --git a/packages/extra/bootbox/templates/matchbox/ingress.yaml b/packages/extra/bootbox/templates/matchbox/ingress.yaml index ce950222..9a2e31d0 100644 --- a/packages/extra/bootbox/templates/matchbox/ingress.yaml +++ b/packages/extra/bootbox/templates/matchbox/ingress.yaml @@ -1,6 +1,6 @@ -{{- $cozystack := .Values.cozystack | default dict }} +{{- $cozystack := .Values._cozystack | default dict }} {{- $issuerType := dig "publishing" "certificates" "issuerType" "http01" $cozystack }} -{{- $namespace := dig "namespace" (dict) .Values }} +{{- $namespace := .Values._namespace | default dict }} {{- $ingress := dig "ingress" "" $namespace }} {{- $host := dig "host" "" $namespace }} apiVersion: networking.k8s.io/v1 diff --git a/packages/extra/bootbox/templates/matchbox/machines.yaml b/packages/extra/bootbox/templates/matchbox/machines.yaml index aa2eb2c9..d00dd6a5 100644 --- a/packages/extra/bootbox/templates/matchbox/machines.yaml +++ b/packages/extra/bootbox/templates/matchbox/machines.yaml @@ -1,5 +1,5 @@ -{{- $cozystack := .Values.cozystack | default dict }} -{{- $namespace := dig "namespace" (dict) .Values }} +{{- $cozystack := .Values._cozystack | default dict }} +{{- $namespace := .Values._namespace | default dict }} {{- $ingress := dig "ingress" "" $namespace }} {{- $host := dig "host" "" $namespace }} diff --git a/packages/extra/etcd/templates/etcd-cluster.yaml b/packages/extra/etcd/templates/etcd-cluster.yaml index ef686b9f..de884b09 100644 --- a/packages/extra/etcd/templates/etcd-cluster.yaml +++ b/packages/extra/etcd/templates/etcd-cluster.yaml @@ -49,7 +49,7 @@ spec: {{- with .Values.resources }} resources: {{- include "cozy-lib.resources.sanitize" (list . $) | nindent 10 }} {{- end }} - {{- $cozystack := .Values.cozystack | default dict }} + {{- $cozystack := .Values._cozystack | default dict }} {{- $topologySpreadConstraints := dig "scheduling" "topologySpreadConstraints" (list) $cozystack }} {{- if $topologySpreadConstraints }} {{- range $topologySpreadConstraints }} diff --git a/packages/extra/info/templates/dashboard-resourcemap.yaml b/packages/extra/info/templates/dashboard-resourcemap.yaml index 1a7aadc0..cbf8a403 100644 --- a/packages/extra/info/templates/dashboard-resourcemap.yaml +++ b/packages/extra/info/templates/dashboard-resourcemap.yaml @@ -1,4 +1,4 @@ -{{- $cozystack := .Values.cozystack | default dict }} +{{- $cozystack := .Values._cozystack | default dict }} {{- $oidcEnabled := dig "authentication" "oidc" "enabled" false $cozystack | toString }} apiVersion: rbac.authorization.k8s.io/v1 kind: Role diff --git a/packages/extra/info/templates/kubeconfig.yaml b/packages/extra/info/templates/kubeconfig.yaml index 9899cf2a..3d406421 100644 --- a/packages/extra/info/templates/kubeconfig.yaml +++ b/packages/extra/info/templates/kubeconfig.yaml @@ -1,13 +1,9 @@ -{{- $cozystack := .Values.cozystack | default dict }} +{{- $cozystack := .Values._cozystack | default dict }} {{- $host := dig "publishing" "host" "" $cozystack }} {{- $k8sClientSecret := lookup "v1" "Secret" "cozy-keycloak" "k8s-client" }} {{- if $k8sClientSecret }} {{- $apiServerEndpoint := dig "publishing" "apiServerEndpoint" "" $cozystack }} -{{- $managementKubeconfigEndpoint := dig "publishing" "managementKubeconfigEndpoint" "" $cozystack }} -{{- if and $managementKubeconfigEndpoint (ne $managementKubeconfigEndpoint "") }} -{{- $apiServerEndpoint = $managementKubeconfigEndpoint }} -{{- end }} {{- $k8sClient := index $k8sClientSecret.data "client-secret-key" | b64dec }} {{- $rootSaConfigMap := lookup "v1" "ConfigMap" "kube-system" "kube-root-ca.crt" }} {{- $k8sCa := index $rootSaConfigMap.data "ca.crt" | b64enc }} diff --git a/packages/extra/ingress/templates/nginx-ingress.yaml b/packages/extra/ingress/templates/nginx-ingress.yaml index 58daf1b8..4bbcc37b 100644 --- a/packages/extra/ingress/templates/nginx-ingress.yaml +++ b/packages/extra/ingress/templates/nginx-ingress.yaml @@ -1,6 +1,6 @@ -{{- $cozystack := .Values.cozystack | default dict }} +{{- $cozystack := .Values._cozystack | default dict }} {{- $exposeIngress := dig "namespaces" "ingress" "tenant-root" $cozystack }} -{{- $exposeExternalIPs := dig "publishing" "externalIPs" (list) $cozystack | join "," }} +{{- $exposeExternalIPs := dig "publishing" "externalIPs" (list) $cozystack }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -37,7 +37,7 @@ spec: enabled: false {{- end }} service: - {{- if and (eq $exposeIngress .Release.Namespace) $exposeExternalIPs }} + {{- if and (eq $exposeIngress .Release.Namespace) (gt (len $exposeExternalIPs) 0) }} externalIPs: {{- toYaml $exposeExternalIPs | nindent 12 }} type: ClusterIP diff --git a/packages/extra/monitoring/templates/alerta/alerta-db.yaml b/packages/extra/monitoring/templates/alerta/alerta-db.yaml index 849f2113..0eb909a4 100644 --- a/packages/extra/monitoring/templates/alerta/alerta-db.yaml +++ b/packages/extra/monitoring/templates/alerta/alerta-db.yaml @@ -5,7 +5,7 @@ metadata: name: alerta-db spec: instances: 2 - {{- $cozystack := .Values.cozystack | default dict }} + {{- $cozystack := .Values._cozystack | default dict }} {{- $topologySpreadConstraints := dig "scheduling" "topologySpreadConstraints" (list) $cozystack }} {{- if $topologySpreadConstraints }} topologySpreadConstraints: diff --git a/packages/extra/monitoring/templates/alerta/alerta.yaml b/packages/extra/monitoring/templates/alerta/alerta.yaml index 41549822..a8708a52 100644 --- a/packages/extra/monitoring/templates/alerta/alerta.yaml +++ b/packages/extra/monitoring/templates/alerta/alerta.yaml @@ -1,6 +1,6 @@ -{{- $cozystack := .Values.cozystack | default dict }} +{{- $cozystack := .Values._cozystack | default dict }} {{- $issuerType := dig "publishing" "certificates" "issuerType" "http01" $cozystack }} -{{- $namespace := dig "namespace" (dict) .Values }} +{{- $namespace := .Values._namespace | default dict }} {{- $ingress := dig "ingress" "" $namespace }} {{- $host := dig "host" "" $namespace }} diff --git a/packages/extra/monitoring/templates/grafana/db.yaml b/packages/extra/monitoring/templates/grafana/db.yaml index 414437ce..bb90c477 100644 --- a/packages/extra/monitoring/templates/grafana/db.yaml +++ b/packages/extra/monitoring/templates/grafana/db.yaml @@ -6,7 +6,7 @@ spec: instances: 2 storage: size: {{ .Values.grafana.db.size }} - {{- $cozystack := .Values.cozystack | default dict }} + {{- $cozystack := .Values._cozystack | default dict }} {{- $topologySpreadConstraints := dig "scheduling" "topologySpreadConstraints" (list) $cozystack }} {{- if $topologySpreadConstraints }} topologySpreadConstraints: diff --git a/packages/extra/monitoring/templates/grafana/grafana.yaml b/packages/extra/monitoring/templates/grafana/grafana.yaml index f8c238ee..fbc6a017 100644 --- a/packages/extra/monitoring/templates/grafana/grafana.yaml +++ b/packages/extra/monitoring/templates/grafana/grafana.yaml @@ -1,6 +1,6 @@ -{{- $cozystack := .Values.cozystack | default dict }} +{{- $cozystack := .Values._cozystack | default dict }} {{- $issuerType := dig "publishing" "certificates" "issuerType" "http01" $cozystack }} -{{- $namespace := dig "namespace" (dict) .Values }} +{{- $namespace := .Values._namespace | default dict }} {{- $ingress := dig "ingress" "" $namespace }} {{- $host := dig "host" "" $namespace }} --- diff --git a/packages/extra/seaweedfs/templates/client/cosi-deployment.yaml b/packages/extra/seaweedfs/templates/client/cosi-deployment.yaml index 4e04b48a..c2541b8f 100644 --- a/packages/extra/seaweedfs/templates/client/cosi-deployment.yaml +++ b/packages/extra/seaweedfs/templates/client/cosi-deployment.yaml @@ -1,6 +1,6 @@ {{- if eq .Values.topology "Client" }} -{{- $cozystack := .Values.cozystack | default dict }} -{{- $namespace := dig "namespace" (dict) .Values }} +{{- $cozystack := .Values._cozystack | default dict }} +{{- $namespace := .Values._namespace | default dict }} {{- $ingress := dig "ingress" "" $namespace }} {{- $host := dig "host" "" $namespace }} --- diff --git a/packages/extra/seaweedfs/templates/ingress.yaml b/packages/extra/seaweedfs/templates/ingress.yaml index d37a9410..fce0997c 100644 --- a/packages/extra/seaweedfs/templates/ingress.yaml +++ b/packages/extra/seaweedfs/templates/ingress.yaml @@ -1,6 +1,6 @@ -{{- $cozystack := .Values.cozystack | default dict }} +{{- $cozystack := .Values._cozystack | default dict }} {{- $issuerType := dig "publishing" "certificates" "issuerType" "http01" $cozystack }} -{{- $namespace := dig "namespace" (dict) .Values }} +{{- $namespace := .Values._namespace | default dict }} {{- $ingress := dig "ingress" "" $namespace }} {{- $host := dig "host" "" $namespace }} {{- if and (not (eq .Values.topology "Client")) (.Values.filer.grpcHost) }} diff --git a/packages/extra/seaweedfs/templates/seaweedfs.yaml b/packages/extra/seaweedfs/templates/seaweedfs.yaml index 774c4755..b91be453 100644 --- a/packages/extra/seaweedfs/templates/seaweedfs.yaml +++ b/packages/extra/seaweedfs/templates/seaweedfs.yaml @@ -34,8 +34,8 @@ {{- end }} {{- if not (eq .Values.topology "Client") }} -{{- $cozystack := .Values.cozystack | default dict }} -{{- $namespace := dig "namespace" (dict) .Values }} +{{- $cozystack := .Values._cozystack | default dict }} +{{- $namespace := .Values._namespace | default dict }} {{- $ingress := dig "ingress" "" $namespace }} {{- $host := dig "host" "" $namespace }} apiVersion: helm.toolkit.fluxcd.io/v2 diff --git a/packages/library/cozy-lib/templates/_cozyconfig.tpl b/packages/library/cozy-lib/templates/_cozyconfig.tpl index 559f7415..e6eb19e0 100644 --- a/packages/library/cozy-lib/templates/_cozyconfig.tpl +++ b/packages/library/cozy-lib/templates/_cozyconfig.tpl @@ -1,7 +1,11 @@ {{- define "cozy-lib.loadCozyConfig" }} {{- include "cozy-lib.checkInput" . }} -{{- if not (hasKey (index . 1) "cozyConfig") }} -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $_ := set (index . 1) "cozyConfig" $cozyConfig }} +{{/* Root context is always the second element of the list */}} +{{- $root := index . 1 }} +{{- $target := index . 1 }} +{{- if not (hasKey $target "cozyConfig") }} +{{/* Use _cozystack values directly, no need for data wrapper */}} +{{- $cozyConfig := $root.Values._cozystack | default dict }} +{{- $_ := set $target "cozyConfig" $cozyConfig }} {{- end }} {{- end }} diff --git a/packages/library/cozy-lib/templates/_network.tpl b/packages/library/cozy-lib/templates/_network.tpl index 4908f7d5..5390dee9 100644 --- a/packages/library/cozy-lib/templates/_network.tpl +++ b/packages/library/cozy-lib/templates/_network.tpl @@ -17,7 +17,9 @@ in use and returns `true`. {{- if not $cozyConfig }} {{- include "cozy-lib.network.defaultDisableLoadBalancerNodePorts" . }} {{- else }} -{{- $enabledComponents := splitList "," ((index $cozyConfig.data "bundle-enable") | default "") }} -{{- not (has "robotlb" $enabledComponents) }} +{{- $components := $cozyConfig.components | default dict }} +{{- $robotlb := index $components "hetzner-robotlb" | default dict }} +{{- $robotlbEnabled := $robotlb.enabled | default false }} +{{- not $robotlbEnabled }} {{- end }} {{- end }} diff --git a/packages/library/cozy-lib/templates/_resources.tpl b/packages/library/cozy-lib/templates/_resources.tpl index f402ee02..2dcb0d4c 100644 --- a/packages/library/cozy-lib/templates/_resources.tpl +++ b/packages/library/cozy-lib/templates/_resources.tpl @@ -14,7 +14,7 @@ {{- if not $cozyConfig }} {{- include "cozy-lib.resources.defaultCpuAllocationRatio" . }} {{- else }} -{{- dig "data" "cpu-allocation-ratio" (include "cozy-lib.resources.defaultCpuAllocationRatio" dict) $cozyConfig }} +{{- dig "resources" "cpuAllocationRatio" (include "cozy-lib.resources.defaultCpuAllocationRatio" dict) $cozyConfig }} {{- end }} {{- end }} @@ -24,7 +24,7 @@ {{- if not $cozyConfig }} {{- include "cozy-lib.resources.defaultMemoryAllocationRatio" . }} {{- else }} -{{- dig "data" "memory-allocation-ratio" (include "cozy-lib.resources.defaultMemoryAllocationRatio" dict) $cozyConfig }} +{{- dig "resources" "memoryAllocationRatio" (include "cozy-lib.resources.defaultMemoryAllocationRatio" dict) $cozyConfig }} {{- end }} {{- end }} @@ -34,7 +34,7 @@ {{- if not $cozyConfig }} {{- include "cozy-lib.resources.defaultEphemeralStorageAllocationRatio" . }} {{- else }} -{{- dig "data" "ephemeral-storage-allocation-ratio" (include "cozy-lib.resources.defaultEphemeralStorageAllocationRatio" dict) $cozyConfig }} +{{- dig "resources" "ephemeralStorageAllocationRatio" (include "cozy-lib.resources.defaultEphemeralStorageAllocationRatio" dict) $cozyConfig }} {{- end }} {{- end }} @@ -85,9 +85,21 @@ devices.com/nvidia: "1" # = limit */}} {{- define "cozy-lib.resources.sanitize" }} -{{- $cpuAllocationRatio := include "cozy-lib.resources.cpuAllocationRatio" . | float64 }} -{{- $memoryAllocationRatio := include "cozy-lib.resources.memoryAllocationRatio" . | float64 }} -{{- $ephemeralStorageAllocationRatio := include "cozy-lib.resources.ephemeralStorageAllocationRatio" . | float64 }} +{{- $cpuAllocationRatioRaw := include "cozy-lib.resources.cpuAllocationRatio" . | float64 }} +{{- $cpuAllocationRatio := $cpuAllocationRatioRaw }} +{{- if eq $cpuAllocationRatio 0.0 }} +{{- $cpuAllocationRatio = 10.0 }} +{{- end }} +{{- $memoryAllocationRatioRaw := include "cozy-lib.resources.memoryAllocationRatio" . | float64 }} +{{- $memoryAllocationRatio := $memoryAllocationRatioRaw }} +{{- if eq $memoryAllocationRatio 0.0 }} +{{- $memoryAllocationRatio = 1.0 }} +{{- end }} +{{- $ephemeralStorageAllocationRatioRaw := include "cozy-lib.resources.ephemeralStorageAllocationRatio" . | float64 }} +{{- $ephemeralStorageAllocationRatio := $ephemeralStorageAllocationRatioRaw }} +{{- if eq $ephemeralStorageAllocationRatio 0.0 }} +{{- $ephemeralStorageAllocationRatio = 40.0 }} +{{- end }} {{- $args := index . 0 }} {{- $output := dict "requests" dict "limits" dict }} {{- if or (hasKey $args "limits") (hasKey $args "requests") }} diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index 2246e959..f5bbe1e8 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,5 +1,5 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:latest@sha256:07f74496ef0625b7cf656650393cc54f09cb97fb893b671f01ebf133ee590576 + image: ghcr.io/cozystack/cozystack/cozystack-api:latest@sha256:51cbc43b73e2f2608ae451c3c14b316f6df8508e2a53a6a4d5b577f3c698b5b3 localK8sAPIEndpoint: enabled: true replicas: 2 diff --git a/packages/system/cozystack-controller/templates/deployment.yaml b/packages/system/cozystack-controller/templates/deployment.yaml index 7f1342d4..175aa5ca 100644 --- a/packages/system/cozystack-controller/templates/deployment.yaml +++ b/packages/system/cozystack-controller/templates/deployment.yaml @@ -19,7 +19,6 @@ spec: - name: cozystack-controller image: "{{ .Values.cozystackController.image }}" args: - - --cozystack-version={{ .Values.cozystackController.cozystackVersion }} {{- if .Values.cozystackController.debug }} - --zap-log-level=debug {{- else }} diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index fc7c4c5f..c9044c04 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,4 +1,4 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:latest@sha256:9758ee7556e9c8665eccad4d926e2e2e3b51d1a411b6c88bbb4fdc747731d671 + image: ghcr.io/cozystack/cozystack/cozystack-controller:latest@sha256:44679c58a9a8d5431dba9b4b512ec97cb252750fd30914c5afa4addf00f50479 debug: false cozystackAPIKind: "DaemonSet" diff --git a/pkg/lineage/lineage.go b/pkg/lineage/lineage.go index 867e1aab..cb99a827 100644 --- a/pkg/lineage/lineage.go +++ b/pkg/lineage/lineage.go @@ -134,12 +134,16 @@ func WalkOwnershipGraph( labels := obj.GetLabels() name, ok := labels[HRLabel] if !ok { + l.V(1).Info("object does not have helm.toolkit.fluxcd.io/name label", "labels", labels) return } + l.V(1).Info("found helm.toolkit.fluxcd.io/name label", "name", name, "namespace", obj.GetNamespace()) ownerObj, err := getUnstructuredObject(ctx, client, mapper, HRAPIVersion, HRKind, obj.GetNamespace(), name) if err != nil { + l.Error(err, "failed to get HelmRelease", "name", name, "namespace", obj.GetNamespace()) return } + l.V(1).Info("found HelmRelease owner", "name", name, "namespace", obj.GetNamespace()) out = append(out, WalkOwnershipGraph(ctx, client, mapper, appMapper, ownerObj, visited)...) return diff --git a/pkg/registry/apps/application/rest.go b/pkg/registry/apps/application/rest.go index 5659136b..5ed64566 100644 --- a/pkg/registry/apps/application/rest.go +++ b/pkg/registry/apps/application/rest.go @@ -1130,8 +1130,8 @@ func deepMergeMaps(base, override map[string]interface{}) map[string]interface{} return result } -// removeCozystackFromValues removes the cozystack and namespace fields from values -func removeCozystackFromValues(values *apiextensionsv1.JSON) (*apiextensionsv1.JSON, error) { +// removeUnderscoreFields recursively removes all fields starting with "_" from values +func removeUnderscoreFields(values *apiextensionsv1.JSON) (*apiextensionsv1.JSON, error) { if values == nil || len(values.Raw) == 0 { return values, nil } @@ -1141,23 +1141,11 @@ func removeCozystackFromValues(values *apiextensionsv1.JSON) (*apiextensionsv1.J return nil, fmt.Errorf("failed to unmarshal values: %w", err) } - // Check if cozystack or namespace field exists before removing - if _, exists := valuesMap["cozystack"]; exists { - klog.V(4).Infof("Removing cozystack field from values (found in values map)") - delete(valuesMap, "cozystack") - } else { - klog.V(6).Infof("cozystack field not found in values map") - } - if _, exists := valuesMap["namespace"]; exists { - klog.V(4).Infof("Removing namespace field from values (found in values map)") - delete(valuesMap, "namespace") - } else { - klog.V(6).Infof("namespace field not found in values map") - } + // Recursively remove all fields starting with "_" + removeUnderscoreFieldsRecursive(valuesMap) // If map is empty, return empty JSON object instead of nil to ensure proper serialization if len(valuesMap) == 0 { - klog.V(6).Infof("Values map is empty after removing cozystack/namespace, returning empty JSON object") return &apiextensionsv1.JSON{Raw: []byte("{}")}, nil } @@ -1166,29 +1154,40 @@ func removeCozystackFromValues(values *apiextensionsv1.JSON) (*apiextensionsv1.J return nil, fmt.Errorf("failed to marshal cleaned values: %w", err) } - // Verify cozystack and namespace were removed - var verifyMap map[string]interface{} - if err := json.Unmarshal(cleanedJSON, &verifyMap); err == nil { - cozystackRemoved := true - namespaceRemoved := true - if _, stillExists := verifyMap["cozystack"]; stillExists { - klog.Errorf("ERROR: cozystack field still exists after removal attempt!") - cozystackRemoved = false - } - if _, stillExists := verifyMap["namespace"]; stillExists { - klog.Errorf("ERROR: namespace field still exists after removal attempt!") - namespaceRemoved = false - } - if cozystackRemoved && namespaceRemoved { - klog.V(6).Infof("Verified: cozystack and namespace fields successfully removed") - } - } - return &apiextensionsv1.JSON{Raw: cleanedJSON}, nil } -// checkCozystackInValues checks if cozystack or namespace field exists in user values and returns an error if it does -func checkCozystackInValues(values *apiextensionsv1.JSON) error { +// removeUnderscoreFieldsRecursive recursively removes all fields starting with "_" from a map +func removeUnderscoreFieldsRecursive(m map[string]interface{}) { + if m == nil { + return + } + // Collect keys to delete (we can't delete while iterating) + keysToDelete := make([]string, 0) + for k, v := range m { + if strings.HasPrefix(k, "_") { + keysToDelete = append(keysToDelete, k) + } else if nestedMap, ok := v.(map[string]interface{}); ok { + // Recursively process nested maps + removeUnderscoreFieldsRecursive(nestedMap) + } else if nestedArray, ok := v.([]interface{}); ok { + // Process arrays that might contain maps + for _, item := range nestedArray { + if itemMap, ok := item.(map[string]interface{}); ok { + removeUnderscoreFieldsRecursive(itemMap) + } + } + } + } + + // Delete collected keys + for _, k := range keysToDelete { + delete(m, k) + } +} + +// checkUnderscoreFields checks if any field starting with "_" exists in user values and returns an error if it does +func checkUnderscoreFields(values *apiextensionsv1.JSON) error { if values == nil || len(values.Raw) == 0 { return nil } @@ -1198,17 +1197,37 @@ func checkCozystackInValues(values *apiextensionsv1.JSON) error { return fmt.Errorf("failed to unmarshal values: %w", err) } - if _, exists := valuesMap["cozystack"]; exists { - return fmt.Errorf("cozystack field is not allowed in user-specified values") - } - - if _, exists := valuesMap["namespace"]; exists { - return fmt.Errorf("namespace field is not allowed in user-specified values") + // Check for any field starting with "_" + if found := findUnderscoreFields(valuesMap); found != "" { + return fmt.Errorf("field %s is not allowed in user-specified values (fields starting with '_' are reserved)", found) } return nil } +// findUnderscoreFields recursively finds the first field starting with "_" and returns its key path +func findUnderscoreFields(m map[string]interface{}) string { + for k, v := range m { + if strings.HasPrefix(k, "_") { + return k + } + if nestedMap, ok := v.(map[string]interface{}); ok { + if found := findUnderscoreFields(nestedMap); found != "" { + return k + "." + found + } + } else if nestedArray, ok := v.([]interface{}); ok { + for i, item := range nestedArray { + if itemMap, ok := item.(map[string]interface{}); ok { + if found := findUnderscoreFields(itemMap); found != "" { + return fmt.Sprintf("%s[%d].%s", k, i, found) + } + } + } + } + } + return "" +} + // ConvertHelmReleaseToApplication converts a HelmRelease to an Application func (r *REST) ConvertHelmReleaseToApplication(hr *helmv2.HelmRelease) (appsv1alpha1.Application, error) { klog.V(6).Infof("Converting HelmRelease to Application for resource %s", hr.GetName()) @@ -1224,27 +1243,27 @@ func (r *REST) ConvertHelmReleaseToApplication(hr *helmv2.HelmRelease) (appsv1al return app, fmt.Errorf("defaulting error: %w", err) } - // Remove cozystack field after applying defaults to ensure it's not shown to user - // This must be done after applySpecDefaults because defaults might add it back + // Remove all fields starting with "_" after applying defaults to ensure they're not shown to user + // This must be done after applySpecDefaults because defaults might add them back if app.Spec != nil && len(app.Spec.Raw) > 0 { - cleanedValues, err := removeCozystackFromValues(app.Spec) + cleanedValues, err := removeUnderscoreFields(app.Spec) if err != nil { - return app, fmt.Errorf("failed to remove cozystack from values: %w", err) + return app, fmt.Errorf("failed to remove underscore fields from values: %w", err) } app.Spec = cleanedValues - // Double-check that cozystack was removed + // Double-check that underscore fields were removed if app.Spec != nil && len(app.Spec.Raw) > 0 { var verifyMap map[string]interface{} if err := json.Unmarshal(app.Spec.Raw, &verifyMap); err == nil { - if _, stillExists := verifyMap["cozystack"]; stillExists { - klog.Errorf("CRITICAL: cozystack field still exists after removal! Attempting force removal...") - delete(verifyMap, "cozystack") - } - if _, stillExists := verifyMap["namespace"]; stillExists { - klog.Errorf("CRITICAL: namespace field still exists after removal! Attempting force removal...") - delete(verifyMap, "namespace") + // Check for any remaining underscore fields + for k := range verifyMap { + if strings.HasPrefix(k, "_") { + klog.Errorf("CRITICAL: Field %s still exists after removal! Removing forcefully...", k) + delete(verifyMap, k) + } } + // Re-marshal if we removed anything if len(verifyMap) == 0 { app.Spec = &apiextensionsv1.JSON{Raw: []byte("{}")} } else { @@ -1268,6 +1287,13 @@ func (r *REST) ConvertApplicationToHelmRelease(app *appsv1alpha1.Application) (* // convertHelmReleaseToApplication implements the actual conversion logic func (r *REST) convertHelmReleaseToApplication(hr *helmv2.HelmRelease) (appsv1alpha1.Application, error) { + // Remove all fields starting with "_" from values before setting spec to ensure they never appear in spec + cleanedValues, err := removeUnderscoreFields(hr.Spec.Values) + if err != nil { + // If removal fails, use original values (shouldn't happen, but be safe) + cleanedValues = hr.Spec.Values + } + app := appsv1alpha1.Application{ TypeMeta: metav1.TypeMeta{ APIVersion: "apps.cozystack.io/v1alpha1", @@ -1283,7 +1309,7 @@ func (r *REST) convertHelmReleaseToApplication(hr *helmv2.HelmRelease) (appsv1al Labels: filterPrefixedMap(hr.Labels, LabelPrefix), Annotations: filterPrefixedMap(hr.Annotations, AnnotationPrefix), }, - Spec: hr.Spec.Values, + Spec: cleanedValues, Status: appsv1alpha1.ApplicationStatus{ Version: extractRevision(hr.Status.LastAttemptedRevision), }, @@ -1315,8 +1341,8 @@ func (r *REST) convertHelmReleaseToApplication(hr *helmv2.HelmRelease) (appsv1al func (r *REST) convertApplicationToHelmRelease(app *appsv1alpha1.Application) (*helmv2.HelmRelease, error) { ctx := context.Background() - // Check if user specified cozystack field in values - if err := checkCozystackInValues(app.Spec); err != nil { + // Check if user specified any field starting with "_" in values + if err := checkUnderscoreFields(app.Spec); err != nil { return nil, err } @@ -1368,8 +1394,8 @@ func (r *REST) convertApplicationToHelmRelease(app *appsv1alpha1.Application) (* namespaceLabelsMap[k] = v } - // Namespace labels completely overwrite existing namespace field (top-level) - valuesMap["namespace"] = namespaceLabelsMap + // Namespace labels completely overwrite existing _namespace field (top-level) + valuesMap["_namespace"] = namespaceLabelsMap // Marshal back to JSON mergedJSON, err := json.Marshal(valuesMap) diff --git a/pkg/registry/apps/application/rest_defaulting.go b/pkg/registry/apps/application/rest_defaulting.go index 0f9d776f..82e48ab7 100644 --- a/pkg/registry/apps/application/rest_defaulting.go +++ b/pkg/registry/apps/application/rest_defaulting.go @@ -19,6 +19,7 @@ package application import ( "encoding/json" "fmt" + "strings" appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -39,12 +40,16 @@ func (r *REST) applySpecDefaults(app *appsv1alpha1.Application) error { if m == nil { m = map[string]any{} } + // Remove all fields starting with "_" BEFORE applying defaults to prevent them from being processed + removeUnderscoreFieldsFromMap(m) + if err := defaultLikeKubernetes(&m, r.specSchema); err != nil { return err } - // Remove cozystack and namespace fields before marshaling to ensure they're never in the output - delete(m, "cozystack") - delete(m, "namespace") + + // Remove all fields starting with "_" AFTER applying defaults to ensure they're never in the output + // This is a safety measure in case defaults added them back + removeUnderscoreFieldsFromMap(m) // Always return at least an empty JSON object, never nil if len(m) == 0 { @@ -60,6 +65,35 @@ func (r *REST) applySpecDefaults(app *appsv1alpha1.Application) error { return nil } +// removeUnderscoreFieldsFromMap recursively removes all fields starting with "_" from a map +func removeUnderscoreFieldsFromMap(m map[string]any) { + if m == nil { + return + } + // Collect keys to delete (we can't delete while iterating) + keysToDelete := make([]string, 0) + for k, v := range m { + if strings.HasPrefix(k, "_") { + keysToDelete = append(keysToDelete, k) + } else if nestedMap, ok := v.(map[string]any); ok { + // Recursively process nested maps + removeUnderscoreFieldsFromMap(nestedMap) + } else if nestedArray, ok := v.([]any); ok { + // Process arrays that might contain maps + for _, item := range nestedArray { + if itemMap, ok := item.(map[string]any); ok { + removeUnderscoreFieldsFromMap(itemMap) + } + } + } + } + + // Delete collected keys + for _, k := range keysToDelete { + delete(m, k) + } +} + func defaultLikeKubernetes(root *map[string]any, s *structuralschema.Structural) error { v := any(*root) nv, err := applyDefaults(v, s, true) @@ -126,6 +160,10 @@ func applyDefaults(v any, s *structuralschema.Structural, top bool) (any, error) if s.AdditionalProperties != nil && s.AdditionalProperties.Structural != nil { ap := s.AdditionalProperties.Structural for k, cur := range mv { + // Skip fields starting with "_" - they are internal and should not be processed + if strings.HasPrefix(k, "_") { + continue + } if _, isKnown := s.Properties[k]; isKnown { continue } From 15a9180b673521446572731518aa1c61a646214c Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 25 Nov 2025 15:34:08 +0100 Subject: [PATCH 34/46] do not require apiServerEndpoint Signed-off-by: Andrei Kvapil --- packages/core/platform/bundles/iaas/bundle.yaml | 4 ---- packages/core/platform/bundles/system/bundle-full.yaml | 4 ---- packages/core/platform/bundles/system/bundle-hosted.yaml | 4 ---- packages/core/platform/bundles/system/bundle-minimal.yaml | 4 ---- packages/core/platform/values.yaml | 2 +- 5 files changed, 1 insertion(+), 17 deletions(-) diff --git a/packages/core/platform/bundles/iaas/bundle.yaml b/packages/core/platform/bundles/iaas/bundle.yaml index 4ef67b23..2972efc1 100644 --- a/packages/core/platform/bundles/iaas/bundle.yaml +++ b/packages/core/platform/bundles/iaas/bundle.yaml @@ -3,10 +3,6 @@ {{- if not $host }} {{- fail "ERROR: publishing.host is required" }} {{- end }} -{{- $apiServerEndpoint := .Values.publishing.apiServerEndpoint }} -{{- if not $apiServerEndpoint }} -{{- fail "ERROR: publishing.apiServerEndpoint is required" }} -{{- end }} apiVersion: cozystack.io/v1alpha1 kind: CozystackBundle diff --git a/packages/core/platform/bundles/system/bundle-full.yaml b/packages/core/platform/bundles/system/bundle-full.yaml index 590e1dbf..2e0ea0e1 100644 --- a/packages/core/platform/bundles/system/bundle-full.yaml +++ b/packages/core/platform/bundles/system/bundle-full.yaml @@ -4,10 +4,6 @@ {{- end }} {{- $clusterDomain := .Values.networking.clusterDomain | default "cozy.local" }} {{- $oidcEnabled := .Values.authentication.oidc.enabled | default false }} -{{- $apiServerEndpoint := .Values.publishing.apiServerEndpoint }} -{{- if not $apiServerEndpoint }} -{{- fail "ERROR: publishing.apiServerEndpoint is required" }} -{{- end }} apiVersion: cozystack.io/v1alpha1 kind: CozystackBundle diff --git a/packages/core/platform/bundles/system/bundle-hosted.yaml b/packages/core/platform/bundles/system/bundle-hosted.yaml index 7c9c2ea3..dc3408ac 100644 --- a/packages/core/platform/bundles/system/bundle-hosted.yaml +++ b/packages/core/platform/bundles/system/bundle-hosted.yaml @@ -4,10 +4,6 @@ {{- end }} {{- $clusterDomain := .Values.networking.clusterDomain | default "cozy.local" }} {{- $oidcEnabled := .Values.authentication.oidc.enabled | default false }} -{{- $apiServerEndpoint := .Values.publishing.apiServerEndpoint }} -{{- if not $apiServerEndpoint }} -{{- fail "ERROR: publishing.apiServerEndpoint is required" }} -{{- end }} apiVersion: cozystack.io/v1alpha1 kind: CozystackBundle diff --git a/packages/core/platform/bundles/system/bundle-minimal.yaml b/packages/core/platform/bundles/system/bundle-minimal.yaml index 98fa754b..791131f9 100644 --- a/packages/core/platform/bundles/system/bundle-minimal.yaml +++ b/packages/core/platform/bundles/system/bundle-minimal.yaml @@ -3,10 +3,6 @@ {{- fail "ERROR: publishing.host is required" }} {{- end }} {{- $oidcEnabled := .Values.authentication.oidc.enabled | default false }} -{{- $apiServerEndpoint := .Values.publishing.apiServerEndpoint }} -{{- if not $apiServerEndpoint }} -{{- fail "ERROR: publishing.apiServerEndpoint is required" }} -{{- end }} apiVersion: cozystack.io/v1alpha1 kind: CozystackBundle diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml index d9d421a3..a869aacb 100644 --- a/packages/core/platform/values.yaml +++ b/packages/core/platform/values.yaml @@ -44,7 +44,7 @@ publishing: - dashboard - vm-exportproxy - cdi-uploadproxy - apiServerEndpoint: "https://api.example.org" + apiServerEndpoint: "" # example: "https://api.example.org" externalIPs: [] certificates: issuerType: http01 # "http01" or "cloudflare" From c69756de5118d9a76b7aed004b0e795e27eda060 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 25 Nov 2025 15:33:43 +0100 Subject: [PATCH 35/46] Update SA for tenants Signed-off-by: Andrei Kvapil --- .../info/templates/dashboard-resourcemap.yaml | 5 +- packages/extra/info/templates/kubeconfig.yaml | 50 ++++++++++++++++--- .../extra/info/templates/serviceaccount.yaml | 4 ++ 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/packages/extra/info/templates/dashboard-resourcemap.yaml b/packages/extra/info/templates/dashboard-resourcemap.yaml index cbf8a403..88603cfc 100644 --- a/packages/extra/info/templates/dashboard-resourcemap.yaml +++ b/packages/extra/info/templates/dashboard-resourcemap.yaml @@ -10,10 +10,11 @@ rules: resources: - secrets resourceNames: - {{- if eq $oidcEnabled "true" }} + {{- if $oidcEnabled }} - kubeconfig-{{ .Release.Namespace }} {{- else }} - {{ .Release.Namespace }} + - kubeconfig-{{ .Release.Namespace }} {{- end }} verbs: ["get", "list", "watch"] --- @@ -22,7 +23,7 @@ apiVersion: rbac.authorization.k8s.io/v1 metadata: name: {{ .Release.Name }}-dashboard-resources subjects: -{{- if eq $oidcEnabled "true" }} +{{- if $oidcEnabled }} {{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "view" .Release.Namespace) }} {{- else }} - kind: ServiceAccount diff --git a/packages/extra/info/templates/kubeconfig.yaml b/packages/extra/info/templates/kubeconfig.yaml index 3d406421..4cf14b18 100644 --- a/packages/extra/info/templates/kubeconfig.yaml +++ b/packages/extra/info/templates/kubeconfig.yaml @@ -1,12 +1,6 @@ {{- $cozystack := .Values._cozystack | default dict }} {{- $host := dig "publishing" "host" "" $cozystack }} -{{- $k8sClientSecret := lookup "v1" "Secret" "cozy-keycloak" "k8s-client" }} - -{{- if $k8sClientSecret }} -{{- $apiServerEndpoint := dig "publishing" "apiServerEndpoint" "" $cozystack }} -{{- $k8sClient := index $k8sClientSecret.data "client-secret-key" | b64dec }} -{{- $rootSaConfigMap := lookup "v1" "ConfigMap" "kube-system" "kube-root-ca.crt" }} -{{- $k8sCa := index $rootSaConfigMap.data "ca.crt" | b64enc }} +{{- $oidcEnabled := dig "authentication" "oidc" "enabled" false $cozystack | toString }} {{- if .Capabilities.APIVersions.Has "helm.toolkit.fluxcd.io/v2" }} {{- $tenantRoot := lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" "tenant-root" "tenant-root" }} @@ -14,6 +8,17 @@ {{- $host = $tenantRoot.spec.values.host }} {{- end }} {{- end }} + +{{- $apiServerEndpoint := dig "publishing" "apiServerEndpoint" "" $cozystack }} +{{- if not $apiServerEndpoint }} +{{- $apiServerEndpoint = printf "https://api.%s" $host }} +{{- end }} +{{- $rootSaConfigMap := lookup "v1" "ConfigMap" "kube-system" "kube-root-ca.crt" }} +{{- $k8sCa := index $rootSaConfigMap.data "ca.crt" | b64enc }} + +{{- $k8sClientSecret := lookup "v1" "Secret" "cozy-keycloak" "k8s-client" }} +{{- if and $oidcEnabled $k8sClientSecret }} +{{- $k8sClient := index $k8sClientSecret.data "client-secret-key" | b64dec }} --- apiVersion: v1 kind: Secret @@ -47,4 +52,35 @@ stringData: - --oidc-client-secret={{ $k8sClient }} - --skip-open-browser command: kubectl +{{- else }} +{{- $tenantRootSecret := lookup "v1" "Secret" "tenant-root" "tenant-root" }} +{{- if $tenantRootSecret }} +{{- $caCrt := index $tenantRootSecret.data "ca.crt" }} +{{- $token := index $tenantRootSecret.data "token" | b64dec }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: kubeconfig-{{ .Release.Namespace }} +stringData: + kubeconfig: | + apiVersion: v1 + kind: Config + clusters: + - name: cluster + cluster: + server: {{ $apiServerEndpoint }} + certificate-authority-data: {{ $caCrt }} + contexts: + - name: {{ .Release.Namespace }} + context: + cluster: cluster + namespace: {{ .Release.Namespace }} + user: {{ .Release.Namespace }} + current-context: {{ .Release.Namespace }} + users: + - name: {{ .Release.Namespace }} + user: + token: {{ $token }} +{{- end }} {{- end }} diff --git a/packages/extra/info/templates/serviceaccount.yaml b/packages/extra/info/templates/serviceaccount.yaml index 492f1b27..ee9b7a77 100644 --- a/packages/extra/info/templates/serviceaccount.yaml +++ b/packages/extra/info/templates/serviceaccount.yaml @@ -1,3 +1,6 @@ +{{- $cozystack := .Values._cozystack | default dict }} +{{- $oidcEnabled := dig "authentication" "oidc" "enabled" false $cozystack | toString }} +{{- if not $oidcEnabled }} --- apiVersion: v1 kind: Secret @@ -6,3 +9,4 @@ metadata: annotations: kubernetes.io/service-account.name: {{ .Release.Namespace }} type: kubernetes.io/service-account-token +{{- end }} From e046206d2b297866ce3b4aeb06da270b4cf4bebb Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 25 Nov 2025 16:24:08 +0100 Subject: [PATCH 36/46] refactor a bit Signed-off-by: Andrei Kvapil --- .../cozystackresource_controller.go | 61 +--- .../controller/namespace_helm_reconciler.go | 26 +- packages/core/installer/values.yaml | 2 +- packages/system/cozystack-api/values.yaml | 2 +- .../system/cozystack-controller/values.yaml | 2 +- pkg/cozylib/namespace.go | 96 +++++++ pkg/cozylib/values.go | 266 ++++++++++++++++++ pkg/registry/apps/application/rest.go | 218 +------------- .../apps/application/rest_defaulting.go | 34 +-- 9 files changed, 394 insertions(+), 313 deletions(-) create mode 100644 pkg/cozylib/namespace.go create mode 100644 pkg/cozylib/values.go diff --git a/internal/controller/cozystackresource_controller.go b/internal/controller/cozystackresource_controller.go index 86c83270..f7013c87 100644 --- a/internal/controller/cozystackresource_controller.go +++ b/internal/controller/cozystackresource_controller.go @@ -24,6 +24,8 @@ import ( "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=cozystackresourcedefinitions,verbs=get;list;watch @@ -358,7 +360,7 @@ func (r *CozystackResourceDefinitionReconciler) updateHelmReleaseChart(ctx conte 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 = r.mergeHelmReleaseValues(crd.Spec.Release.Values, hrCopy.Spec.Values) + 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) @@ -368,12 +370,15 @@ func (r *CozystackResourceDefinitionReconciler) updateHelmReleaseChart(ctx conte mergedValues = hrCopy.Spec.Values } - // Always inject namespace labels (top-level _namespace field) + // Always inject namespace annotations (top-level _namespace field) // This matches the behavior in cozystack-api and NamespaceHelmReconciler - mergedValues, err = r.injectNamespaceLabelsIntoValues(ctx, mergedValues, hrCopy.Namespace) - if err != nil { - logger.Error(err, "failed to inject namespace labels", "name", hr.Name, "namespace", hr.Namespace) - // Continue even if namespace labels injection fails + 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 @@ -495,47 +500,3 @@ func valuesEqual(a, b *apiextensionsv1.JSON) bool { return string(a.Raw) == string(b.Raw) } -// injectNamespaceLabelsIntoValues injects namespace.cozystack.io/* labels into _namespace (top-level) -// This matches the behavior in cozystack-api and NamespaceHelmReconciler -func (r *CozystackResourceDefinitionReconciler) injectNamespaceLabelsIntoValues(ctx context.Context, values *apiextensionsv1.JSON, namespaceName string) (*apiextensionsv1.JSON, error) { - // Get namespace to extract namespace.cozystack.io/* labels - namespace := &corev1.Namespace{} - if err := r.Get(ctx, client.ObjectKey{Name: namespaceName}, namespace); err != nil { - // If namespace not found, return values as-is - return values, nil - } - - // Extract namespace.cozystack.io/* labels - namespaceLabels := extractNamespaceLabelsFromNamespace(namespace) - if len(namespaceLabels) == 0 { - // No namespace labels, return values as-is - return values, nil - } - - // Parse values - var valuesMap map[string]interface{} - if values != nil && len(values.Raw) > 0 { - if err := json.Unmarshal(values.Raw, &valuesMap); err != nil { - return nil, fmt.Errorf("failed to unmarshal 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 - } - - // Namespace labels completely overwrite existing _namespace field (top-level) - valuesMap["_namespace"] = namespaceLabelsMap - - // Marshal back to JSON - mergedJSON, err := json.Marshal(valuesMap) - if err != nil { - return nil, fmt.Errorf("failed to marshal values with namespace labels: %w", err) - } - - return &apiextensionsv1.JSON{Raw: mergedJSON}, nil -} diff --git a/internal/controller/namespace_helm_reconciler.go b/internal/controller/namespace_helm_reconciler.go index 8b30ecff..57719ddd 100644 --- a/internal/controller/namespace_helm_reconciler.go +++ b/internal/controller/namespace_helm_reconciler.go @@ -20,7 +20,6 @@ import ( "context" "encoding/json" "fmt" - "strings" helmv2 "github.com/fluxcd/helm-controller/api/v2" corev1 "k8s.io/api/core/v1" @@ -29,6 +28,8 @@ import ( 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 @@ -49,8 +50,8 @@ func (r *NamespaceHelmReconciler) Reconcile(ctx context.Context, req ctrl.Reques return ctrl.Result{}, client.IgnoreNotFound(err) } - // Extract namespace.cozystack.io/* labels - namespaceLabels := extractNamespaceLabelsFromNamespace(namespace) + // Extract namespace.cozystack.io/* annotations + namespaceLabels := cozylib.ExtractNamespaceAnnotations(namespace) if len(namespaceLabels) == 0 { // No namespace labels to process, skip return ctrl.Result{}, nil @@ -83,25 +84,6 @@ func (r *NamespaceHelmReconciler) Reconcile(ctx context.Context, req ctrl.Reques return ctrl.Result{}, nil } -// extractNamespaceLabelsFromNamespace extracts namespace.cozystack.io/* labels from namespace -func extractNamespaceLabelsFromNamespace(ns *corev1.Namespace) map[string]string { - namespaceLabels := make(map[string]string) - prefix := "namespace.cozystack.io/" - - if ns.Labels == nil { - return namespaceLabels - } - - for key, value := range ns.Labels { - if strings.HasPrefix(key, prefix) { - // Remove prefix and add to namespace labels - namespaceKey := strings.TrimPrefix(key, prefix) - namespaceLabels[namespaceKey] = value - } - } - - return namespaceLabels -} // updateHelmReleaseWithNamespaceLabels updates HelmRelease values with namespace labels func (r *NamespaceHelmReconciler) updateHelmReleaseWithNamespaceLabels(ctx context.Context, hr *helmv2.HelmRelease, namespaceLabels map[string]string) error { diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index 53b51940..45585e76 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -2,4 +2,4 @@ cozystackOperator: image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:ede9a0a6b7b1ad137ef1f75c1e954115da8ebdab110e47d920ae01ac62be93ec disableTelemetry: false cozystackVersion: "latest" - packagesDigest: sha256:e0b444176a041831f79fab0264e643171c16f8519b52854c27b1fad4b4abbf5e + packagesDigest: sha256:da9d726066e8ee884210f01df4d59a29560ecda596cc01fba340c0f21ae36d7a diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index f5bbe1e8..8ffc37f5 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,5 +1,5 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:latest@sha256:51cbc43b73e2f2608ae451c3c14b316f6df8508e2a53a6a4d5b577f3c698b5b3 + image: ghcr.io/cozystack/cozystack/cozystack-api:latest@sha256:fa43ce97a77d4f2e4d877a1b525dabc91ec4d8a8b865c55d9d470992e9027405 localK8sAPIEndpoint: enabled: true replicas: 2 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index c9044c04..f6d5cdbd 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,4 +1,4 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:latest@sha256:44679c58a9a8d5431dba9b4b512ec97cb252750fd30914c5afa4addf00f50479 + image: ghcr.io/cozystack/cozystack/cozystack-controller:latest@sha256:196c769a58423f108ffca1760805f022155c63accab38c6a5bd736c6008b8b54 debug: false cozystackAPIKind: "DaemonSet" diff --git a/pkg/cozylib/namespace.go b/pkg/cozylib/namespace.go new file mode 100644 index 00000000..ea87f535 --- /dev/null +++ b/pkg/cozylib/namespace.go @@ -0,0 +1,96 @@ +/* +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 cozylib + +import ( + "encoding/json" + "fmt" + "strings" + + corev1 "k8s.io/api/core/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" +) + +const ( + // NamespaceAnnotationPrefix is the prefix for namespace annotations that should be copied to _namespace values + NamespaceAnnotationPrefix = "namespace.cozystack.io/" +) + +// ExtractNamespaceAnnotations extracts namespace.cozystack.io/* annotations from namespace +// and returns them as a map with the prefix removed. +// For example, "namespace.cozystack.io/host" becomes "host" in the returned map. +func ExtractNamespaceAnnotations(ns *corev1.Namespace) map[string]string { + result := make(map[string]string) + prefix := NamespaceAnnotationPrefix + + if ns.Annotations == nil { + return result + } + + for key, value := range ns.Annotations { + if strings.HasPrefix(key, prefix) { + // Remove prefix and add to result + namespaceKey := strings.TrimPrefix(key, prefix) + result[namespaceKey] = value + } + } + + return result +} + +// InjectNamespaceAnnotationsIntoValues injects namespace.cozystack.io/* annotations into _namespace (top-level) in values. +// This function extracts annotations from the namespace and adds them to the _namespace field in the values JSON. +// If namespace is nil or has no matching annotations, values are returned as-is. +func InjectNamespaceAnnotationsIntoValues(values *apiextensionsv1.JSON, ns *corev1.Namespace) (*apiextensionsv1.JSON, error) { + if ns == nil { + return values, nil + } + + // Extract namespace.cozystack.io/* annotations + namespaceLabels := ExtractNamespaceAnnotations(ns) + if len(namespaceLabels) == 0 { + // No namespace annotations, return values as-is + return values, nil + } + + // Parse values + var valuesMap map[string]interface{} + if values != nil && len(values.Raw) > 0 { + if err := json.Unmarshal(values.Raw, &valuesMap); err != nil { + return nil, fmt.Errorf("failed to unmarshal 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 + } + + // Namespace annotations completely overwrite existing _namespace field (top-level) + valuesMap["_namespace"] = namespaceLabelsMap + + // Marshal back to JSON + mergedJSON, err := json.Marshal(valuesMap) + if err != nil { + return nil, fmt.Errorf("failed to marshal values with namespace annotations: %w", err) + } + + return &apiextensionsv1.JSON{Raw: mergedJSON}, nil +} diff --git a/pkg/cozylib/values.go b/pkg/cozylib/values.go new file mode 100644 index 00000000..29a47d1e --- /dev/null +++ b/pkg/cozylib/values.go @@ -0,0 +1,266 @@ +/* +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 cozylib + +import ( + "encoding/json" + "fmt" + "strings" + + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" +) + +// DeepMergeMaps performs a deep merge of two maps. +// Values from override map take precedence, but nested maps are merged recursively. +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 for non-map values or new keys + result[k] = v + } + + return result +} + +// MergeValues merges two JSON values with deep merge. +// baseValues are merged first, then overrideValues (overrideValues take precedence). +func MergeValues(baseValues, overrideValues *apiextensionsv1.JSON) (*apiextensionsv1.JSON, error) { + var baseMap, overrideMap map[string]interface{} + + if baseValues != nil && len(baseValues.Raw) > 0 { + if err := json.Unmarshal(baseValues.Raw, &baseMap); err != nil { + return nil, fmt.Errorf("failed to unmarshal base values: %w", err) + } + } else { + baseMap = make(map[string]interface{}) + } + + if overrideValues != nil && len(overrideValues.Raw) > 0 { + if err := json.Unmarshal(overrideValues.Raw, &overrideMap); err != nil { + return nil, fmt.Errorf("failed to unmarshal override values: %w", err) + } + } else { + overrideMap = make(map[string]interface{}) + } + + // Deep merge: baseValues first, then overrideValues (overrideValues override) + merged := DeepMergeMaps(baseMap, overrideMap) + + 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 +} + +// MergeValuesWithCRDPriority merges CRD values with existing values. +// Existing values have priority (user values override defaults), but _cozystack and _namespace +// from CRD completely overwrite existing values. +func MergeValuesWithCRDPriority(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 +} + +// RemoveUnderscoreFields recursively removes all fields starting with "_" from values. +// This is used to hide internal fields from API responses. +func RemoveUnderscoreFields(values *apiextensionsv1.JSON) (*apiextensionsv1.JSON, error) { + if values == nil || len(values.Raw) == 0 { + return values, nil + } + + var valuesMap map[string]interface{} + if err := json.Unmarshal(values.Raw, &valuesMap); err != nil { + return nil, fmt.Errorf("failed to unmarshal values: %w", err) + } + + removeUnderscoreFieldsRecursive(valuesMap) + + // Always return at least an empty JSON object, never nil + if len(valuesMap) == 0 { + return &apiextensionsv1.JSON{Raw: []byte("{}")}, nil + } + + cleanedJSON, err := json.Marshal(valuesMap) + if err != nil { + return nil, fmt.Errorf("failed to marshal cleaned values: %w", err) + } + + return &apiextensionsv1.JSON{Raw: cleanedJSON}, nil +} + +// removeUnderscoreFieldsRecursive recursively removes all fields starting with "_" from a map +func removeUnderscoreFieldsRecursive(m map[string]interface{}) { + if m == nil { + return + } + // Collect keys to delete (we can't delete while iterating) + keysToDelete := make([]string, 0) + for k, v := range m { + if strings.HasPrefix(k, "_") { + keysToDelete = append(keysToDelete, k) + } else if nestedMap, ok := v.(map[string]interface{}); ok { + // Recursively process nested maps + removeUnderscoreFieldsRecursive(nestedMap) + } else if nestedArray, ok := v.([]interface{}); ok { + // Process arrays that might contain maps + for _, item := range nestedArray { + if itemMap, ok := item.(map[string]interface{}); ok { + removeUnderscoreFieldsRecursive(itemMap) + } + } + } + } + + // Delete collected keys + for _, k := range keysToDelete { + delete(m, k) + } +} + +// RemoveUnderscoreFieldsFromMap recursively removes all fields starting with "_" from a map. +// This is a variant that works directly with map[string]any (used in defaulting). +func RemoveUnderscoreFieldsFromMap(m map[string]any) { + if m == nil { + return + } + // Collect keys to delete (we can't delete while iterating) + keysToDelete := make([]string, 0) + for k, v := range m { + if strings.HasPrefix(k, "_") { + keysToDelete = append(keysToDelete, k) + } else if nestedMap, ok := v.(map[string]any); ok { + // Recursively process nested maps + RemoveUnderscoreFieldsFromMap(nestedMap) + } else if nestedArray, ok := v.([]any); ok { + // Process arrays that might contain maps + for _, item := range nestedArray { + if itemMap, ok := item.(map[string]any); ok { + RemoveUnderscoreFieldsFromMap(itemMap) + } + } + } + } + + // Delete collected keys + for _, k := range keysToDelete { + delete(m, k) + } +} + +// CheckUnderscoreFields checks if any field starting with "_" exists in user values and returns an error if it does. +// This prevents users from setting internal fields. +func CheckUnderscoreFields(values *apiextensionsv1.JSON) error { + if values == nil || len(values.Raw) == 0 { + return nil + } + + var valuesMap map[string]interface{} + if err := json.Unmarshal(values.Raw, &valuesMap); err != nil { + return fmt.Errorf("failed to unmarshal values: %w", err) + } + + if hasUnderscoreFields(valuesMap) { + return fmt.Errorf("fields starting with '_' are not allowed in user values") + } + + return nil +} + +// hasUnderscoreFields recursively checks if any field starting with "_" exists in a map +func hasUnderscoreFields(m map[string]interface{}) bool { + if m == nil { + return false + } + for k, v := range m { + if strings.HasPrefix(k, "_") { + return true + } + if nestedMap, ok := v.(map[string]interface{}); ok { + if hasUnderscoreFields(nestedMap) { + return true + } + } else if nestedArray, ok := v.([]interface{}); ok { + for _, item := range nestedArray { + if itemMap, ok := item.(map[string]interface{}); ok { + if hasUnderscoreFields(itemMap) { + return true + } + } + } + } + } + return false +} diff --git a/pkg/registry/apps/application/rest.go b/pkg/registry/apps/application/rest.go index 5ed64566..0081265d 100644 --- a/pkg/registry/apps/application/rest.go +++ b/pkg/registry/apps/application/rest.go @@ -44,6 +44,7 @@ import ( cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" "github.com/cozystack/cozystack/pkg/config" + "github.com/cozystack/cozystack/pkg/cozylib" internalapiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -1052,182 +1053,6 @@ func (r *REST) getCozystackResourceDefinition(ctx context.Context) (*cozyv1alpha return nil, fmt.Errorf("CozystackResourceDefinition not found for kind %s", r.kindName) } -// extractNamespaceLabels extracts namespace.cozystack.io/* labels from namespace and converts them to cozystack.namespace values -func extractNamespaceLabels(ns *corev1.Namespace) map[string]interface{} { - namespaceValues := make(map[string]interface{}) - prefix := "namespace.cozystack.io/" - - if ns.Labels == nil { - return namespaceValues - } - - for key, value := range ns.Labels { - if strings.HasPrefix(key, prefix) { - // Remove prefix and add to namespace values - namespaceKey := strings.TrimPrefix(key, prefix) - namespaceValues[namespaceKey] = value - } - } - - return namespaceValues -} - -// mergeValues merges two JSON values, with userValues taking precedence -func mergeValues(defaultValues, userValues *apiextensionsv1.JSON) (*apiextensionsv1.JSON, error) { - var defaultMap, userMap map[string]interface{} - - if defaultValues != nil && len(defaultValues.Raw) > 0 { - if err := json.Unmarshal(defaultValues.Raw, &defaultMap); err != nil { - return nil, fmt.Errorf("failed to unmarshal default values: %w", err) - } - } else { - defaultMap = make(map[string]interface{}) - } - - if userValues != nil && len(userValues.Raw) > 0 { - if err := json.Unmarshal(userValues.Raw, &userMap); err != nil { - return nil, fmt.Errorf("failed to unmarshal user values: %w", err) - } - } else { - userMap = make(map[string]interface{}) - } - - // Deep merge: defaultValues first, then userValues (userValues override) - merged := deepMergeMaps(defaultMap, userMap) - - 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 -} - -// removeUnderscoreFields recursively removes all fields starting with "_" from values -func removeUnderscoreFields(values *apiextensionsv1.JSON) (*apiextensionsv1.JSON, error) { - if values == nil || len(values.Raw) == 0 { - return values, nil - } - - var valuesMap map[string]interface{} - if err := json.Unmarshal(values.Raw, &valuesMap); err != nil { - return nil, fmt.Errorf("failed to unmarshal values: %w", err) - } - - // Recursively remove all fields starting with "_" - removeUnderscoreFieldsRecursive(valuesMap) - - // If map is empty, return empty JSON object instead of nil to ensure proper serialization - if len(valuesMap) == 0 { - return &apiextensionsv1.JSON{Raw: []byte("{}")}, nil - } - - cleanedJSON, err := json.Marshal(valuesMap) - if err != nil { - return nil, fmt.Errorf("failed to marshal cleaned values: %w", err) - } - - return &apiextensionsv1.JSON{Raw: cleanedJSON}, nil -} - -// removeUnderscoreFieldsRecursive recursively removes all fields starting with "_" from a map -func removeUnderscoreFieldsRecursive(m map[string]interface{}) { - if m == nil { - return - } - // Collect keys to delete (we can't delete while iterating) - keysToDelete := make([]string, 0) - for k, v := range m { - if strings.HasPrefix(k, "_") { - keysToDelete = append(keysToDelete, k) - } else if nestedMap, ok := v.(map[string]interface{}); ok { - // Recursively process nested maps - removeUnderscoreFieldsRecursive(nestedMap) - } else if nestedArray, ok := v.([]interface{}); ok { - // Process arrays that might contain maps - for _, item := range nestedArray { - if itemMap, ok := item.(map[string]interface{}); ok { - removeUnderscoreFieldsRecursive(itemMap) - } - } - } - } - - // Delete collected keys - for _, k := range keysToDelete { - delete(m, k) - } -} - -// checkUnderscoreFields checks if any field starting with "_" exists in user values and returns an error if it does -func checkUnderscoreFields(values *apiextensionsv1.JSON) error { - if values == nil || len(values.Raw) == 0 { - return nil - } - - var valuesMap map[string]interface{} - if err := json.Unmarshal(values.Raw, &valuesMap); err != nil { - return fmt.Errorf("failed to unmarshal values: %w", err) - } - - // Check for any field starting with "_" - if found := findUnderscoreFields(valuesMap); found != "" { - return fmt.Errorf("field %s is not allowed in user-specified values (fields starting with '_' are reserved)", found) - } - - return nil -} - -// findUnderscoreFields recursively finds the first field starting with "_" and returns its key path -func findUnderscoreFields(m map[string]interface{}) string { - for k, v := range m { - if strings.HasPrefix(k, "_") { - return k - } - if nestedMap, ok := v.(map[string]interface{}); ok { - if found := findUnderscoreFields(nestedMap); found != "" { - return k + "." + found - } - } else if nestedArray, ok := v.([]interface{}); ok { - for i, item := range nestedArray { - if itemMap, ok := item.(map[string]interface{}); ok { - if found := findUnderscoreFields(itemMap); found != "" { - return fmt.Sprintf("%s[%d].%s", k, i, found) - } - } - } - } - } - return "" -} - // ConvertHelmReleaseToApplication converts a HelmRelease to an Application func (r *REST) ConvertHelmReleaseToApplication(hr *helmv2.HelmRelease) (appsv1alpha1.Application, error) { klog.V(6).Infof("Converting HelmRelease to Application for resource %s", hr.GetName()) @@ -1246,7 +1071,7 @@ func (r *REST) ConvertHelmReleaseToApplication(hr *helmv2.HelmRelease) (appsv1al // Remove all fields starting with "_" after applying defaults to ensure they're not shown to user // This must be done after applySpecDefaults because defaults might add them back if app.Spec != nil && len(app.Spec.Raw) > 0 { - cleanedValues, err := removeUnderscoreFields(app.Spec) + cleanedValues, err := cozylib.RemoveUnderscoreFields(app.Spec) if err != nil { return app, fmt.Errorf("failed to remove underscore fields from values: %w", err) } @@ -1288,7 +1113,7 @@ func (r *REST) ConvertApplicationToHelmRelease(app *appsv1alpha1.Application) (* // convertHelmReleaseToApplication implements the actual conversion logic func (r *REST) convertHelmReleaseToApplication(hr *helmv2.HelmRelease) (appsv1alpha1.Application, error) { // Remove all fields starting with "_" from values before setting spec to ensure they never appear in spec - cleanedValues, err := removeUnderscoreFields(hr.Spec.Values) + cleanedValues, err := cozylib.RemoveUnderscoreFields(hr.Spec.Values) if err != nil { // If removal fails, use original values (shouldn't happen, but be safe) cleanedValues = hr.Spec.Values @@ -1342,7 +1167,7 @@ func (r *REST) convertApplicationToHelmRelease(app *appsv1alpha1.Application) (* ctx := context.Background() // Check if user specified any field starting with "_" in values - if err := checkUnderscoreFields(app.Spec); err != nil { + if err := cozylib.CheckUnderscoreFields(app.Spec); err != nil { return nil, err } @@ -1357,7 +1182,7 @@ func (r *REST) convertApplicationToHelmRelease(app *appsv1alpha1.Application) (* // Start with default values from CRD (if any) var mergedValues *apiextensionsv1.JSON if crd != nil && crd.Spec.Release.Values != nil { - mergedValues, err = mergeValues(crd.Spec.Release.Values, app.Spec) + mergedValues, err = cozylib.MergeValues(crd.Spec.Release.Values, app.Spec) if err != nil { return nil, fmt.Errorf("failed to merge default values with user values: %w", err) } @@ -1374,35 +1199,12 @@ func (r *REST) convertApplicationToHelmRelease(app *appsv1alpha1.Application) (* namespace = nil } - // Extract namespace labels and add to namespace (top-level) + // Extract namespace annotations and add to _namespace (top-level) if namespace != nil { - namespaceLabels := extractNamespaceLabels(namespace) - if len(namespaceLabels) > 0 { - // Parse merged values to add namespace labels - var valuesMap map[string]interface{} - if mergedValues != nil && len(mergedValues.Raw) > 0 { - if err := json.Unmarshal(mergedValues.Raw, &valuesMap); err != nil { - return nil, fmt.Errorf("failed to unmarshal merged values: %w", err) - } - } else { - valuesMap = make(map[string]interface{}) - } - - // Convert namespaceLabels to map[string]interface{} - namespaceLabelsMap := make(map[string]interface{}) - for k, v := range namespaceLabels { - namespaceLabelsMap[k] = v - } - - // Namespace labels completely overwrite existing _namespace field (top-level) - valuesMap["_namespace"] = namespaceLabelsMap - - // Marshal back to JSON - mergedJSON, err := json.Marshal(valuesMap) - if err != nil { - return nil, fmt.Errorf("failed to marshal values with namespace labels: %w", err) - } - mergedValues = &apiextensionsv1.JSON{Raw: mergedJSON} + var err error + mergedValues, err = cozylib.InjectNamespaceAnnotationsIntoValues(mergedValues, namespace) + if err != nil { + return nil, fmt.Errorf("failed to inject namespace annotations: %w", err) } } diff --git a/pkg/registry/apps/application/rest_defaulting.go b/pkg/registry/apps/application/rest_defaulting.go index 82e48ab7..dc0b31c0 100644 --- a/pkg/registry/apps/application/rest_defaulting.go +++ b/pkg/registry/apps/application/rest_defaulting.go @@ -24,6 +24,8 @@ import ( appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" structuralschema "k8s.io/apiextensions-apiserver/pkg/apiserver/schema" + + "github.com/cozystack/cozystack/pkg/cozylib" ) // applySpecDefaults applies default values to the Application spec based on the schema @@ -41,7 +43,7 @@ func (r *REST) applySpecDefaults(app *appsv1alpha1.Application) error { m = map[string]any{} } // Remove all fields starting with "_" BEFORE applying defaults to prevent them from being processed - removeUnderscoreFieldsFromMap(m) + cozylib.RemoveUnderscoreFieldsFromMap(m) if err := defaultLikeKubernetes(&m, r.specSchema); err != nil { return err @@ -49,7 +51,7 @@ func (r *REST) applySpecDefaults(app *appsv1alpha1.Application) error { // Remove all fields starting with "_" AFTER applying defaults to ensure they're never in the output // This is a safety measure in case defaults added them back - removeUnderscoreFieldsFromMap(m) + cozylib.RemoveUnderscoreFieldsFromMap(m) // Always return at least an empty JSON object, never nil if len(m) == 0 { @@ -65,34 +67,6 @@ func (r *REST) applySpecDefaults(app *appsv1alpha1.Application) error { return nil } -// removeUnderscoreFieldsFromMap recursively removes all fields starting with "_" from a map -func removeUnderscoreFieldsFromMap(m map[string]any) { - if m == nil { - return - } - // Collect keys to delete (we can't delete while iterating) - keysToDelete := make([]string, 0) - for k, v := range m { - if strings.HasPrefix(k, "_") { - keysToDelete = append(keysToDelete, k) - } else if nestedMap, ok := v.(map[string]any); ok { - // Recursively process nested maps - removeUnderscoreFieldsFromMap(nestedMap) - } else if nestedArray, ok := v.([]any); ok { - // Process arrays that might contain maps - for _, item := range nestedArray { - if itemMap, ok := item.(map[string]any); ok { - removeUnderscoreFieldsFromMap(itemMap) - } - } - } - } - - // Delete collected keys - for _, k := range keysToDelete { - delete(m, k) - } -} func defaultLikeKubernetes(root *map[string]any, s *structuralschema.Structural) error { v := any(*root) From 3d9cfee40156a880be963a88a906ed1bc726d829 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 25 Nov 2025 16:48:23 +0100 Subject: [PATCH 37/46] update migration Signed-off-by: Andrei Kvapil --- .../platform/images/migrations/migrations/21 | 6 +- .../platform/images/migrations/migrations/22 | 289 +++++++++--------- 2 files changed, 144 insertions(+), 151 deletions(-) diff --git a/packages/core/platform/images/migrations/migrations/21 b/packages/core/platform/images/migrations/migrations/21 index 86c6048d..c065d23c 100755 --- a/packages/core/platform/images/migrations/migrations/21 +++ b/packages/core/platform/images/migrations/migrations/21 @@ -11,7 +11,11 @@ do sleep 1 done +kubectl delete hr -n cozy-system cozystack-resource-definitions --ignore-not-found +kubectl delete hr -n cozy-system cozystack-resource-definition-crd --ignore-not-found +kubectl delete crd cozystackresourcedefinitions.cozycloud.io --ignore-not-found +kubectl delete hr -n cozy-fluxcd fluxcd --ignore-not-found + # Stamp version kubectl create configmap -n cozy-system cozystack-version \ --from-literal=version=22 --dry-run=client -o yaml | kubectl apply -f- - diff --git a/packages/core/platform/images/migrations/migrations/22 b/packages/core/platform/images/migrations/migrations/22 index 8e21d5b1..97beb6f0 100755 --- a/packages/core/platform/images/migrations/migrations/22 +++ b/packages/core/platform/images/migrations/migrations/22 @@ -3,165 +3,155 @@ set -euo pipefail -echo "Migrating HelmReleases: adding application labels and migrating from spec.chart to spec.chartRef" +echo "Migrating HelmReleases: adding application labels for tenant-* namespaces" -# Process all HelmReleases with cozystack.io/ui=true label -kubectl get helmreleases --all-namespaces -o json -l cozystack.io/ui=true | \ - jq -r '.items[] | "\(.metadata.namespace)|\(.metadata.name)"' | \ +# Function to determine application type from HelmRelease name +determine_app_type() { + local name="$1" + local app_kind="" + local app_name="" + + # Try to match by prefix (longest match first) + case "$name" in + virtual-machine-*) + app_kind="VirtualMachine" + app_name="${name#virtual-machine-}" + ;; + vm-instance-*) + app_kind="VMInstance" + app_name="${name#vm-instance-}" + ;; + vm-disk-*) + app_kind="VMDisk" + app_name="${name#vm-disk-}" + ;; + virtualprivatecloud-*) + app_kind="VirtualPrivateCloud" + app_name="${name#virtualprivatecloud-}" + ;; + http-cache-*) + app_kind="HTTPCache" + app_name="${name#http-cache-}" + ;; + tcp-balancer-*) + app_kind="TCPBalancer" + app_name="${name#tcp-balancer-}" + ;; + clickhouse-*) + app_kind="ClickHouse" + app_name="${name#clickhouse-}" + ;; + foundationdb-*) + app_kind="FoundationDB" + app_name="${name#foundationdb-}" + ;; + ferretdb-*) + app_kind="FerretDB" + app_name="${name#ferretdb-}" + ;; + rabbitmq-*) + app_kind="RabbitMQ" + app_name="${name#rabbitmq-}" + ;; + kubernetes-*) + app_kind="Kubernetes" + app_name="${name#kubernetes-}" + ;; + bucket-*) + app_kind="Bucket" + app_name="${name#bucket-}" + ;; + kafka-*) + app_kind="Kafka" + app_name="${name#kafka-}" + ;; + mysql-*) + app_kind="MySQL" + app_name="${name#mysql-}" + ;; + nats-*) + app_kind="NATS" + app_name="${name#nats-}" + ;; + postgres-*) + app_kind="PostgreSQL" + app_name="${name#postgres-}" + ;; + redis-*) + app_kind="Redis" + app_name="${name#redis-}" + ;; + tenant-*) + app_kind="Tenant" + app_name="${name#tenant-}" + ;; + vpn-*) + app_kind="VPN" + app_name="${name#vpn-}" + ;; + bootbox) + app_kind="BootBox" + app_name="bootbox" + ;; + etcd) + app_kind="Etcd" + app_name="etcd" + ;; + info) + app_kind="Info" + app_name="info" + ;; + ingress|ingress-*) + app_kind="Ingress" + if [ "$name" = "ingress" ]; then + app_name="ingress" + else + app_name="${name#ingress-}" + fi + ;; + monitoring) + app_kind="Monitoring" + app_name="monitoring" + ;; + seaweedfs) + app_kind="SeaweedFS" + app_name="seaweedfs" + ;; + *) + # Unknown type + return 1 + ;; + esac + + echo "$app_kind|$app_name" + return 0 +} + +# Process all HelmReleases in tenant-* namespaces with cozystack.io/ui=true label +kubectl get helmreleases --all-namespaces -l cozystack.io/ui=true -o json | \ + jq -r '.items[] | select(.metadata.namespace | startswith("tenant-")) | "\(.metadata.namespace)|\(.metadata.name)"' | \ while IFS='|' read -r namespace name; do echo "Processing HelmRelease $namespace/$name" - # Get the HelmRelease again to extract fields safely - hr_json=$(kubectl get helmrelease -n "$namespace" "$name" -o json 2>/dev/null) - if [ -z "$hr_json" ]; then - echo "Skipping $namespace/$name: failed to get HelmRelease" + # Determine application type + app_type=$(determine_app_type "$name") + if [ $? -ne 0 ] || [ -z "$app_type" ]; then + echo "Warning: Could not determine application type for $namespace/$name, skipping" continue fi - # Extract chart name and sourceRef - chart_name=$(printf '%s' "$hr_json" | jq -r '.spec.chart.spec.chart // empty') - source_kind=$(printf '%s' "$hr_json" | jq -r '.spec.chart.spec.sourceRef.kind // empty') - source_name=$(printf '%s' "$hr_json" | jq -r '.spec.chart.spec.sourceRef.name // empty') - source_namespace=$(printf '%s' "$hr_json" | jq -r '.spec.chart.spec.sourceRef.namespace // empty') - - # Skip if already migrated or missing required fields - if [ -z "$chart_name" ] || [ -z "$source_name" ] || [ "$source_kind" != "HelmRepository" ]; then - echo "Skipping $namespace/$name: missing required fields or not using HelmRepository" - continue - fi - - # Skip cozystack-system repository - if [ "$source_name" = "cozystack-system" ]; then - echo "Skipping $namespace/$name: cozystack-system repository not supported for migration" - continue - fi - - # Determine bundle name from label or ownerReference - bundle_name=$(printf '%s' "$hr_json" | jq -r '.metadata.labels["cozystack.io/bundle"] // empty') - - # If no label, try to get from ownerReferences - if [ -z "$bundle_name" ]; then - bundle_name=$(printf '%s' "$hr_json" | jq -r '.metadata.ownerReferences[]? | select(.kind == "CozystackBundle") | .name' | head -n 1) - fi - - # Skip if no bundle found - if [ -z "$bundle_name" ]; then - echo "Skipping $namespace/$name: no bundle label or ownerReference found" - continue - fi - - # Determine artifact namespace (always cozy-system for ExternalArtifacts) - artifact_namespace="cozy-system" - - # Build artifact name: bundle-name-package-name (new format) - artifact_name="${bundle_name}-${chart_name}" - - echo "Migrating $namespace/$name: $chart_name -> $artifact_name (from $source_name)" - - # Check if already migrated (has chartRef with correct artifact name) - current_chart_ref=$(printf '%s' "$hr_json" | jq -r '.spec.chartRef.name // empty') - if [ "$current_chart_ref" = "$artifact_name" ]; then - echo "Already migrated $namespace/$name, skipping" - continue - fi - - # Build JSON patch operations - # Remove spec.chart if it exists - # Add/replace spec.chartRef - patch_ops="[]" - has_chart=$(printf '%s' "$hr_json" | jq -e '.spec.chart != null' > /dev/null 2>&1 && echo "true" || echo "false") - has_chart_ref=$(printf '%s' "$hr_json" | jq -e '.spec.chartRef != null' > /dev/null 2>&1 && echo "true" || echo "false") - - if [ "$has_chart" = "true" ]; then - patch_ops=$(printf '%s' "$patch_ops" | jq ". + [{\"op\": \"remove\", \"path\": \"/spec/chart\"}]") - fi - - if [ "$has_chart_ref" = "true" ]; then - patch_ops=$(printf '%s' "$patch_ops" | jq ". + [{\"op\": \"replace\", \"path\": \"/spec/chartRef\", \"value\": {\"kind\": \"ExternalArtifact\", \"name\": \"$artifact_name\", \"namespace\": \"$artifact_namespace\"}}]") - else - patch_ops=$(printf '%s' "$patch_ops" | jq ". + [{\"op\": \"add\", \"path\": \"/spec/chartRef\", \"value\": {\"kind\": \"ExternalArtifact\", \"name\": \"$artifact_name\", \"namespace\": \"$artifact_namespace\"}}]") - fi - - # Apply patch if there are operations to perform - if printf '%s' "$patch_ops" | jq -e 'length > 0' > /dev/null 2>&1; then - printf '%s' "$patch_ops" | kubectl patch helmrelease -n "$namespace" "$name" --type json --patch-file /dev/stdin - echo "Migrated $namespace/$name" - fi - - # Add application labels if missing - # Get CozystackResourceDefinition to determine application kind and group - app_kind="" + app_kind=$(echo "$app_type" | cut -d'|' -f1) + app_name=$(echo "$app_type" | cut -d'|' -f2) app_group="apps.cozystack.io" - app_name="" - # Try to find CRD by chart or chartRef - if [ -n "$chart_name" ] && [ -n "$source_name" ]; then - # Try to find CRD by chart name and source - crd_json=$(kubectl get cozystackresourcedefinitions -n cozy-system -o json 2>/dev/null | \ - jq -r --arg chart "$chart_name" --arg source "$source_name" \ - '.items[] | select((.spec.release.chart.name == $chart and .spec.release.chart.sourceRef.name == $source) or (.spec.release.chartRef.sourceRef.name == $chart)) | .' | head -n 1) - - if [ -n "$crd_json" ]; then - app_kind=$(printf '%s' "$crd_json" | jq -r '.spec.application.kind // empty') - prefix=$(printf '%s' "$crd_json" | jq -r '.spec.release.prefix // empty') - - # Extract application name from HelmRelease name by removing prefix - if [ -n "$prefix" ] && [ "${name#$prefix}" != "$name" ]; then - app_name="${name#$prefix}" - fi - fi - fi + # Build labels string + labels="apps.cozystack.io/application.kind=$app_kind" + labels="$labels apps.cozystack.io/application.group=$app_group" + labels="$labels apps.cozystack.io/application.name=$app_name" - # If we couldn't determine from CRD, try to infer from HelmRelease name pattern - if [ -z "$app_name" ]; then - # Common prefixes to try - for prefix in "mysql-" "postgres-" "redis-" "clickhouse-" "kafka-" "nats-" "rabbitmq-" "ferretdb-" "foundationdb-" \ - "virtual-machine-" "vm-instance-" "vm-disk-" "virtualprivatecloud-" "bucket-" "kubernetes-" \ - "http-cache-" "tcp-balancer-" "vpn-" "tenant-" "monitoring-" "ingress-" "info-" "etcd-" "seaweedfs-" "bootbox-"; do - if [ "${name#$prefix}" != "$name" ]; then - app_name="${name#$prefix}" - # Infer kind from prefix (capitalize and convert to CamelCase) - kind_part=$(echo "$prefix" | sed 's/-$//' | sed 's/-\([a-z]\)/\U\1/g' | sed 's/^\([a-z]\)/\U\1/g') - app_kind="$kind_part" - break - fi - done - fi - - # If still no app_name, use HelmRelease name as fallback - if [ -z "$app_name" ]; then - app_name="$name" - fi - - # Add labels if we have the information - if [ -n "$app_kind" ]; then - label_patch_ops="[]" - current_labels=$(printf '%s' "$hr_json" | jq -r '.metadata.labels // {}') - - # Check and add each label if missing - current_kind=$(printf '%s' "$current_labels" | jq -r '.["apps.cozystack.io/application.kind"] // empty') - if [ "$current_kind" != "$app_kind" ]; then - label_patch_ops=$(printf '%s' "$label_patch_ops" | jq --arg kind "$app_kind" '. + [{"op": "add", "path": "/metadata/labels/apps.cozystack.io~1application.kind", "value": $kind}]') - fi - - current_group=$(printf '%s' "$current_labels" | jq -r '.["apps.cozystack.io/application.group"] // empty') - if [ "$current_group" != "$app_group" ]; then - label_patch_ops=$(printf '%s' "$label_patch_ops" | jq --arg group "$app_group" '. + [{"op": "add", "path": "/metadata/labels/apps.cozystack.io~1application.group", "value": $group}]') - fi - - current_app_name=$(printf '%s' "$current_labels" | jq -r '.["apps.cozystack.io/application.name"] // empty') - if [ "$current_app_name" != "$app_name" ]; then - label_patch_ops=$(printf '%s' "$label_patch_ops" | jq --arg name "$app_name" '. + [{"op": "add", "path": "/metadata/labels/apps.cozystack.io~1application.name", "value": $name}]') - fi - - # Apply label patch if there are operations - if printf '%s' "$label_patch_ops" | jq -e 'length > 0' > /dev/null 2>&1; then - printf '%s' "$label_patch_ops" | kubectl patch helmrelease -n "$namespace" "$name" --type json --patch-file /dev/stdin - echo "Added application labels to $namespace/$name (kind=$app_kind, group=$app_group, name=$app_name)" - fi - else - echo "Warning: Could not determine application kind for $namespace/$name, skipping label addition" - fi + # Apply labels using kubectl label --overwrite + kubectl label helmrelease -n "$namespace" "$name" --overwrite $labels + echo "Added application labels to $namespace/$name: $labels" done echo "Migration completed" @@ -169,4 +159,3 @@ echo "Migration completed" # Stamp version kubectl create configmap -n cozy-system cozystack-version \ --from-literal=version=23 --dry-run=client -o yaml | kubectl apply -f- - From b77791a5fe0dfe02b9e9cb685b68071d94c161ce Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 25 Nov 2025 17:17:03 +0100 Subject: [PATCH 38/46] return removed files Signed-off-by: Andrei Kvapil --- ADOPTERS.md | 35 ++++++++++ CODE_OF_CONDUCT.md | 22 ++++++ CONTRIBUTING.md | 45 +++++++++++++ CONTRIBUTOR_LADDER.md | 151 ++++++++++++++++++++++++++++++++++++++++++ GOVERNANCE.md | 91 +++++++++++++++++++++++++ MAINTAINERS.md | 12 ++++ README.md | 75 +++++++++++++++++++++ 7 files changed, 431 insertions(+) create mode 100644 ADOPTERS.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 CONTRIBUTOR_LADDER.md create mode 100644 GOVERNANCE.md create mode 100644 MAINTAINERS.md create mode 100644 README.md diff --git a/ADOPTERS.md b/ADOPTERS.md new file mode 100644 index 00000000..542e984b --- /dev/null +++ b/ADOPTERS.md @@ -0,0 +1,35 @@ +# Adopters + +Below you can find a list of organizations and users who have agreed to +tell the world that they are using Cozystack in a production environment. + +The goal of this list is to inspire others to do the same and to grow +this open source community and project. + +Please add your organization to this list. It takes 5 minutes of your time, +but it means a lot to us. + +## Updating this list + +To add your organization to this list, you can either: + +- [open a pull request](https://github.com/cozystack/cozystack/pulls) to directly update this file, or +- [edit this file](https://github.com/cozystack/cozystack/blob/main/ADOPTERS.md) directly in GitHub + +Feel free to ask in the Slack chat if you any questions and/or require +assistance with updating this list. + +## Cozystack Adopters + +This list is sorted in chronological order, based on the submission date. + +| Organization | Contact | Date | Description of Use | +| ------------ | ------- | ---- | ------------------ | +| [Ænix](https://aenix.io/) | @kvaps | 2024-02-14 | Ænix provides consulting services for cloud providers and uses Cozystack as the main tool for organizing managed services for them. | +| [Mediatech](https://mediatech.dev/) | @ugenk | 2024-05-01 | We're developing and hosting software for our and our custmer services. We're using cozystack as a kubernetes distribution for that. | +| [Bootstack](https://bootstack.app/) | @mrkhachaturov | 2024-08-01| At Bootstack, we utilize a Kubernetes operator specifically designed to simplify and streamline cloud infrastructure creation.| +| [gohost](https://gohost.kz/) | @karabass_off | 2024-02-01 | Our company has been working in the market of Kazakhstan for more than 15 years, providing clients with a standard set of services: VPS/VDC, IaaS, shared hosting, etc. Now we are expanding the lineup by introducing Bare Metal Kubenetes cluster under Cozystack management. | +| [Urmanac](https://urmanac.com) | @kingdonb | 2024-12-04 | Urmanac is the future home of a hosting platform for the knowledge base of a community of personal server enthusiasts. We use Cozystack to provide support services for web sites hosted using both conventional deployments and on SpinKube, with WASM. | +| [Hidora](https://hikube.cloud) | @matthieu-robin | 2025-09-17 | Hidora is a Swiss cloud provider delivering managed services and infrastructure solutions through datacenters located in Switzerland, ensuring data sovereignty and reliability. Its sovereign cloud platform, Hikube, is designed to run workloads with high availability across multiple datacenters, providing enterprises with a secure and scalable foundation for their applications based on Cozystack. | +| [QOSI](https://qosi.kz) | @tabu-a | 2025-10-04 | QOSI is a non-profit organization driving open-source adoption and digital sovereignty across Kazakhstan and Central Asia. We use Cozystack as a platform for deploying sovereign, GPU-enabled clouds and educational environments under the National AI Program. Our goal is to accelerate the region’s transition toward open, self-hosted cloud-native technologies | +| \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..47ffec55 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,22 @@ +# Code of Conduct + +Cozystack follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). + +# Cozystack Vendor Neutrality Manifesto + +Cozystack exists for the cloud-native community. We are committed to a project culture where no single company, product, or commercial agenda directs our roadmap, governance, brand, or releases. Our North Star is user value, technical excellence, and open collaboration under the CNCF umbrella. + +## Our Commitments + +- **Community-first:** Decisions prioritize the broader community over any vendor interest. +- **Open collaboration:** Ideas, discussions, and outcomes happen in public spaces; contributions are welcomed from all. +- **Merit over affiliation:** Proposals are evaluated on technical merit and user impact, not on who submits them. +- **Inclusive stewardship:** Leadership and maintenance are open to contributors who demonstrate sustained, constructive impact. +- **Technology choice:** We prefer open, pluggable designs that interoperate with multiple ecosystems and providers. +- **Neutral brand & voice:** Our name, logo, website, and documentation do not imply endorsement or preference for any vendor. +- **Transparent practices:** Funding acknowledgments, partnerships, and potential conflicts are communicated openly. +- **User trust:** Security handling, releases, and communications aim to be timely, transparent, and fair to all users. + +By contributing to Cozystack, we affirm these principles and work together to keep the project open, welcoming, and vendor-neutral. + +*— The Cozystack community* diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..d0eb9b94 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,45 @@ +# Contributing to Cozystack + +Welcome! We are glad that you want to contribute to our Cozystack project! 💖 + +As you get started, you are in the best position to give us feedbacks on areas of our project that we need help with, including: + +* Problems found while setting up the development environment +* Gaps in our documentation +* Bugs in our GitHub actions + +First, though, it is important that you read the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). + +The guidelines below are a starting point. We don't want to limit your +creativity, passion, and initiative. If you think there's a better way, please +feel free to bring it up in a GitHub discussion, or open a pull request. We're +certain there are always better ways to do things, we just need to start some +constructive dialogue! + +## Ways to contribute + +We welcome many types of contributions including: + +* New features +* Builds, CI/CD +* Bug fixes +* [Documentation](https://GitHub.com/cozystack/cozystack-website/tree/main) +* Issue Triage +* Answering questions on Slack or GitHub Discussions +* Web design +* Communications / Social Media / Blog Posts +* Events participation +* Release management + +## Ask for Help + +The best way to reach us with a question when contributing is to drop a line in +our [Telegram channel](https://t.me/cozystack), or start a new GitHub discussion. + +## Raising Issues + +When raising issues, please specify the following: + +- A scenario where the issue occurred (with details on how to reproduce it) +- Errors and log messages that are displayed by the involved software +- Any other detail that might be useful diff --git a/CONTRIBUTOR_LADDER.md b/CONTRIBUTOR_LADDER.md new file mode 100644 index 00000000..e41f6a93 --- /dev/null +++ b/CONTRIBUTOR_LADDER.md @@ -0,0 +1,151 @@ +# Contributor Ladder + +* [Contributor Ladder](#contributor-ladder) + * [Community Participant](#community-participant) + * [Contributor](#contributor) + * [Reviewer](#reviewer) + * [Maintainer](#maintainer) +* [Inactivity](#inactivity) +* [Involuntary Removal](#involuntary-removal-or-demotion) +* [Stepping Down/Emeritus Process](#stepping-downemeritus-process) +* [Contact](#contact) + + +## Contributor Ladder + +Hello! We are excited that you want to learn more about our project contributor ladder! This contributor ladder outlines the different contributor roles within the project, along with the responsibilities and privileges that come with them. Community members generally start at the first levels of the "ladder" and advance up it as their involvement in the project grows. Our project members are happy to help you advance along the contributor ladder. + +Each of the contributor roles below is organized into lists of three types of things. "Responsibilities" are things that a contributor is expected to do. "Requirements" are qualifications a person needs to meet to be in that role, and "Privileges" are things contributors on that level are entitled to. + + +### Community Participant +Description: A Community Participant engages with the project and its community, contributing their time, thoughts, etc. Community participants are usually users who have stopped being anonymous and started being active in project discussions. + +* Responsibilities: + * Must follow the [CNCF CoC](https://github.com/cncf/foundation/blob/main/code-of-conduct.md) +* How users can get involved with the community: + * Participating in community discussions + * Helping other users + * Submitting bug reports + * Commenting on issues + * Trying out new releases + * Attending community events + + +### Contributor +Description: A Contributor contributes directly to the project and adds value to it. Contributions need not be code. People at the Contributor level may be new contributors, or they may only contribute occasionally. + +* Responsibilities include: + * Follow the [CNCF CoC](https://github.com/cncf/foundation/blob/main/code-of-conduct.md) + * Follow the project [contributing guide] (https://github.com/cozystack/cozystack/blob/main/CONTRIBUTING.md) +* Requirements (one or several of the below): + * Report and sometimes resolve issues + * Occasionally submit PRs + * Contribute to the documentation + * Show up at meetings, takes notes + * Answer questions from other community members + * Submit feedback on issues and PRs + * Test releases and patches and submit reviews + * Run or helps run events + * Promote the project in public + * Help run the project infrastructure +* Privileges: + * Invitations to contributor events + * Eligible to become a Maintainer + + +### Reviewer +Description: A Reviewer has responsibility for specific code, documentation, test, or other project areas. They are collectively responsible, with other Reviewers, for reviewing all changes to those areas and indicating whether those changes are ready to merge. They have a track record of contribution and review in the project. + +Reviewers are responsible for a "specific area." This can be a specific code directory, driver, chapter of the docs, test job, event, or other clearly-defined project component that is smaller than an entire repository or subproject. Most often it is one or a set of directories in one or more Git repositories. The "specific area" below refers to this area of responsibility. + +Reviewers have all the rights and responsibilities of a Contributor, plus: + +* Responsibilities include: + * Continues to contribute regularly, as demonstrated by having at least 15 PRs a year, as demonstrated by [Cozystack devstats](https://cozystack.devstats.cncf.io). + * Following the reviewing guide + * Reviewing most Pull Requests against their specific areas of responsibility + * Reviewing at least 40 PRs per year + * Helping other contributors become reviewers +* Requirements: + * Must have successful contributions to the project, including at least one of the following: + * 10 accepted PRs, + * Reviewed 20 PRs, + * Resolved and closed 20 Issues, + * Become responsible for a key project management area, + * Or some equivalent combination or contribution + * Must have been contributing for at least 6 months + * Must be actively contributing to at least one project area + * Must have two sponsors who are also Reviewers or Maintainers, at least one of whom does not work for the same employer + * Has reviewed, or helped review, at least 20 Pull Requests + * Has analyzed and resolved test failures in their specific area + * Has demonstrated an in-depth knowledge of the specific area + * Commits to being responsible for that specific area + * Is supportive of new and occasional contributors and helps get useful PRs in shape to commit +* Additional privileges: + * Has GitHub or CI/CD rights to approve pull requests in specific directories + * Can recommend and review other contributors to become Reviewers + * May be assigned Issues and Reviews + * May give commands to CI/CD automation + * Can recommend other contributors to become Reviewers + + +The process of becoming a Reviewer is: +1. The contributor is nominated by opening a PR against the appropriate repository, which adds their GitHub username to the OWNERS file for one or more directories. +2. At least two members of the team that owns that repository or main directory, who are already Approvers, approve the PR. + + +### Maintainer +Description: Maintainers are very established contributors who are responsible for the entire project. As such, they have the ability to approve PRs against any area of the project, and are expected to participate in making decisions about the strategy and priorities of the project. + +A Maintainer must meet the responsibilities and requirements of a Reviewer, plus: + +* Responsibilities include: + * Reviewing at least 40 PRs per year, especially PRs that involve multiple parts of the project + * Mentoring new Reviewers + * Writing refactoring PRs + * Participating in CNCF maintainer activities + * Determining strategy and policy for the project + * Participating in, and leading, community meetings +* Requirements + * Experience as a Reviewer for at least 6 months + * Demonstrates a broad knowledge of the project across multiple areas + * Is able to exercise judgment for the good of the project, independent of their employer, friends, or team + * Mentors other contributors + * Can commit to spending at least 10 hours per month working on the project +* Additional privileges: + * Approve PRs to any area of the project + * Represent the project in public as a Maintainer + * Communicate with the CNCF on behalf of the project + * Have a vote in Maintainer decision-making meetings + + +Process of becoming a maintainer: +1. Any current Maintainer may nominate a current Reviewer to become a new Maintainer, by opening a PR against the root of the cozystack repository adding the nominee as an Approver in the [MAINTAINERS](https://github.com/cozystack/cozystack/blob/main/MAINTAINERS.md) file. +2. The nominee will add a comment to the PR testifying that they agree to all requirements of becoming a Maintainer. +3. A majority of the current Maintainers must then approve the PR. + + +## Inactivity +It is important for contributors to be and stay active to set an example and show commitment to the project. Inactivity is harmful to the project as it may lead to unexpected delays, contributor attrition, and a lost of trust in the project. + +* Inactivity is measured by: + * Periods of no contributions for longer than 6 months + * Periods of no communication for longer than 3 months +* Consequences of being inactive include: + * Involuntary removal or demotion + * Being asked to move to Emeritus status + +## Involuntary Removal or Demotion + +Involuntary removal/demotion of a contributor happens when responsibilities and requirements aren't being met. This may include repeated patterns of inactivity, extended period of inactivity, a period of failing to meet the requirements of your role, and/or a violation of the Code of Conduct. This process is important because it protects the community and its deliverables while also opens up opportunities for new contributors to step in. + +Involuntary removal or demotion is handled through a vote by a majority of the current Maintainers. + +## Stepping Down/Emeritus Process +If and when contributors' commitment levels change, contributors can consider stepping down (moving down the contributor ladder) vs moving to emeritus status (completely stepping away from the project). + +Contact the Maintainers about changing to Emeritus status, or reducing your contributor level. + +## Contact +* For inquiries, please reach out to: @kvaps, @tym83 diff --git a/GOVERNANCE.md b/GOVERNANCE.md new file mode 100644 index 00000000..3fa81317 --- /dev/null +++ b/GOVERNANCE.md @@ -0,0 +1,91 @@ +# Cozystack Governance + +This document defines the governance structure of the Cozystack community, outlining how members collaborate to achieve shared goals. + +## Overview + +**Cozystack**, a Cloud Native Computing Foundation (CNCF) project, is committed +to building an open, inclusive, productive, and self-governing open source +community focused on building a high-quality open source PaaS and framework for building clouds. + +## Code Repositories + +The following code repositories are governed by the Cozystack community and +maintained under the `cozystack` namespace: + +* **[Cozystack](https://github.com/cozystack/cozystack):** Main Cozystack codebase +* **[website](https://github.com/cozystack/website):** Cozystack website and documentation sources +* **[Talm](https://github.com/cozystack/talm):** Tool for managing Talos Linux the GitOps way +* **[cozy-proxy](https://github.com/cozystack/cozy-proxy):** A simple kube-proxy addon for 1:1 NAT services in Kubernetes with NFT backend +* **[cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server):** Cozystack telemetry +* **[talos-bootstrap](https://github.com/cozystack/talos-bootstrap):** An interactive Talos Linux installer +* **[talos-meta-tool](https://github.com/cozystack/talos-meta-tool):** Tool for writing network metadata into META partition + +## Community Roles + +* **Users:** Members that engage with the Cozystack community via any medium, including Slack, Telegram, GitHub, and mailing lists. +* **Contributors:** Members contributing to the projects by contributing and reviewing code, writing documentation, + responding to issues, participating in proposal discussions, and so on. +* **Directors:** Non-technical project leaders. +* **Maintainers**: Technical project leaders. + +## Contributors + +Cozystack is for everyone. Anyone can become a Cozystack contributor simply by +contributing to the project, whether through code, documentation, blog posts, +community management, or other means. +As with all Cozystack community members, contributors are expected to follow the +[Cozystack Code of Conduct](https://github.com/cozystack/cozystack/blob/main/CODE_OF_CONDUCT.md). + +All contributions to Cozystack code, documentation, or other components in the +Cozystack GitHub organisation must follow the +[contributing guidelines](https://github.com/cozystack/cozystack/blob/main/CONTRIBUTING.md). +Whether these contributions are merged into the project is the prerogative of the maintainers. + +## Directors + +Directors are responsible for non-technical leadership functions within the project. +This includes representing Cozystack and its maintainers to the community, to the press, +and to the outside world; interfacing with CNCF and other governance entities; +and participating in project decision-making processes when appropriate. + +Directors are elected by a majority vote of the maintainers. + +## Maintainers + +Maintainers have the right to merge code into the project. +Anyone can become a Cozystack maintainer (see "Becoming a maintainer" below). + +### Expectations + +Cozystack maintainers are expected to: + +* Review pull requests, triage issues, and fix bugs in their areas of + expertise, ensuring that all changes go through the project's code review + and integration processes. +* Monitor cncf-cozystack-* emails, the Cozystack Slack channels in Kubernetes + and CNCF Slack workspaces, Telegram groups, and help out when possible. +* Rapidly respond to any time-sensitive security release processes. +* Attend Cozystack community meetings. + +If a maintainer is no longer interested in or cannot perform the duties +listed above, they should move themselves to emeritus status. +If necessary, this can also occur through the decision-making process outlined below. + +### Becoming a Maintainer + +Anyone can become a Cozystack maintainer. Maintainers should be extremely +proficient in cloud native technologies and/or Go; have relevant domain expertise; +have the time and ability to meet the maintainer's expectations above; +and demonstrate the ability to work with the existing maintainers and project processes. + +To become a maintainer, start by expressing interest to existing maintainers. +Existing maintainers will then ask you to demonstrate the qualifications above +by contributing PRs, doing code reviews, and other such tasks under their guidance. +After several months of working together, maintainers will decide whether to grant maintainer status. + +## Project Decision-making Process + +Ideally, all project decisions are resolved by consensus of maintainers and directors. +If this is not possible, a vote will be called. +The voting process is a simple majority in which each maintainer and director receives one vote. diff --git a/MAINTAINERS.md b/MAINTAINERS.md new file mode 100644 index 00000000..9c44daab --- /dev/null +++ b/MAINTAINERS.md @@ -0,0 +1,12 @@ +# The Cozystack Maintainers + +| Maintainer | GitHub Username | Company | Responsibility | +| ---------- | --------------- | ------- | --------------------------------- | +| Andrei Kvapil | [@kvaps](https://github.com/kvaps) | Ænix | Core Maintainer | +| George Gaál | [@gecube](https://github.com/gecube) | Ænix | DevOps Practices in Platform, Developers Advocate | +| Kingdon Barrett | [@kingdonb](https://github.com/kingdonb) | Urmanac | FluxCD and flux-operator | +| Timofei Larkin | [@lllamnyp](https://github.com/lllamnyp) | 3commas | Etcd-operator Lead | +| Artem Bortnikov | [@aobort](https://github.com/aobort) | Timescale | Etcd-operator Lead | +| Timur Tukaev | [@tym83](https://github.com/tym83) | Ænix | Cozystack Website, Marketing, Community Management | +| Kirill Klinchenkov | [@klinch0](https://github.com/klinch0) | Ænix | Core Maintainer | +| Nikita Bykov | [@nbykov0](https://github.com/nbykov0) | Ænix | Maintainer of ARM and stuff | diff --git a/README.md b/README.md new file mode 100644 index 00000000..b81af2a7 --- /dev/null +++ b/README.md @@ -0,0 +1,75 @@ +![Cozystack](img/cozystack-logo-black.svg#gh-light-mode-only) +![Cozystack](img/cozystack-logo-white.svg#gh-dark-mode-only) + +[![Open Source](https://img.shields.io/badge/Open-Source-brightgreen)](https://opensource.org/) +[![Apache-2.0 License](https://img.shields.io/github/license/cozystack/cozystack)](https://opensource.org/licenses/) +[![Support](https://img.shields.io/badge/$-support-12a0df.svg?style=flat)](https://cozystack.io/support/) +[![Active](http://img.shields.io/badge/Status-Active-green.svg)](https://github.com/cozystack/cozystack) +[![GitHub Release](https://img.shields.io/github/release/cozystack/cozystack.svg?style=flat)](https://github.com/cozystack/cozystack/releases/latest) +[![GitHub Commit](https://img.shields.io/github/commit-activity/y/cozystack/cozystack)](https://github.com/cozystack/cozystack/graphs/contributors) + +# Cozystack + +**Cozystack** is a free PaaS platform and framework for building clouds. + +Cozystack is a [CNCF Sandbox Level Project](https://www.cncf.io/sandbox-projects/) that was originally built and sponsored by [Ænix](https://aenix.io/). + +With Cozystack, you can transform a bunch of servers into an intelligent system with a simple REST API for spawning Kubernetes clusters, +Database-as-a-Service, virtual machines, load balancers, HTTP caching services, and other services with ease. + +Use Cozystack to build your own cloud or provide a cost-effective development environment. + +![Cozystack user interface](https://cozystack.io/img/screenshot-dark.png) + +## Use-Cases + +* [**Using Cozystack to build a public cloud**](https://cozystack.io/docs/guides/use-cases/public-cloud/) +You can use Cozystack as a backend for a public cloud + +* [**Using Cozystack to build a private cloud**](https://cozystack.io/docs/guides/use-cases/private-cloud/) +You can use Cozystack as a platform to build a private cloud powered by Infrastructure-as-Code approach + +* [**Using Cozystack as a Kubernetes distribution**](https://cozystack.io/docs/guides/use-cases/kubernetes-distribution/) +You can use Cozystack as a Kubernetes distribution for Bare Metal + + +## Documentation + +The documentation is located on the [cozystack.io](https://cozystack.io) website. + +Read the [Getting Started](https://cozystack.io/docs/getting-started/) section for a quick start. + +If you encounter any difficulties, start with the [troubleshooting guide](https://cozystack.io/docs/operations/troubleshooting/) and work your way through the process that we've outlined. + +## Versioning + +Versioning adheres to the [Semantic Versioning](http://semver.org/) principles. +A full list of the available releases is available in the GitHub repository's [Release](https://github.com/cozystack/cozystack/releases) section. + +- [Roadmap](https://cozystack.io/docs/roadmap/) + +## Contributions + +Contributions are highly appreciated and very welcomed! + +In case of bugs, please check if the issue has already been opened by checking the [GitHub Issues](https://github.com/cozystack/cozystack/issues) section. +If it isn't, you can open a new one. A detailed report will help us replicate it, assess it, and work on a fix. + +You can express your intention to on the fix on your own. +Commits are used to generate the changelog, and their author will be referenced in it. + +If you have **Feature Requests** please use the [Discussion's Feature Request section](https://github.com/cozystack/cozystack/discussions/categories/feature-requests). + +## Community + +You are welcome to join our [Telegram group](https://t.me/cozystack) and come to our weekly community meetings. +Add them to your [Google Calendar](https://calendar.google.com/calendar?cid=ZTQzZDIxZTVjOWI0NWE5NWYyOGM1ZDY0OWMyY2IxZTFmNDMzZTJlNjUzYjU2ZGJiZGE3NGNhMzA2ZjBkMGY2OEBncm91cC5jYWxlbmRhci5nb29nbGUuY29t) or [iCal](https://calendar.google.com/calendar/ical/e43d21e5c9b45a95f28c5d649c2cb1e1f433e2e653b56dbbda74ca306f0d0f68%40group.calendar.google.com/public/basic.ics) for convenience. + +## License + +Cozystack is licensed under Apache 2.0. +The code is provided as-is with no warranties. + +## Commercial Support + +A list of companies providing commercial support for this project can be found on [official site](https://cozystack.io/support/). From e0ec967120ab00798b2d985b2f20a8015dcca96a Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 25 Nov 2025 17:29:47 +0100 Subject: [PATCH 39/46] Rename resources Signed-off-by: Andrei Kvapil --- ...pes.go => applicationdefinitions_types.go} | 56 +- ...ystembundles_types.go => bundles_types.go} | 22 +- ...ackplatform_types.go => platform_types.go} | 20 +- api/v1alpha1/zz_generated.deepcopy.go | 676 +++++++++--------- cmd/cozystack-controller/main.go | 4 +- cmd/cozystack-operator/main.go | 8 +- ...orm-example.yaml => platform-example.yaml} | 2 +- hack/update-codegen.sh | 12 +- hack/update-crd.sh | 6 +- ...go => applicationdefinition_controller.go} | 48 +- internal/controller/dashboard/breadcrumb.go | 2 +- .../controller/dashboard/customcolumns.go | 2 +- .../dashboard/customformsoverride.go | 2 +- .../dashboard/customformsprefill.go | 2 +- internal/controller/dashboard/factory.go | 4 +- internal/controller/dashboard/helpers.go | 4 +- internal/controller/dashboard/manager.go | 12 +- .../controller/dashboard/marketplacepanel.go | 2 +- internal/controller/dashboard/sidebar.go | 10 +- .../controller/dashboard/tableurimapping.go | 2 +- .../lineagecontrollerwebhook/controller.go | 2 +- internal/lineagecontrollerwebhook/matcher.go | 6 +- internal/lineagecontrollerwebhook/webhook.go | 6 +- internal/operator/bundle_reconciler.go | 58 +- internal/operator/platform_reconciler.go | 32 +- internal/shared/crdmem/memory.go | 16 +- internal/telemetry/collector.go | 6 +- ... cozystack.io_applicationdefinitions.yaml} | 26 +- ...bundles.yaml => cozystack.io_bundles.yaml} | 18 +- ...forms.yaml => cozystack.io_platforms.yaml} | 16 +- packages/core/installer/example/platform.yaml | 2 +- packages/core/installer/values.yaml | 4 +- .../bucket.yaml | 2 +- .../kubernetes.yaml | 2 +- .../virtual-machine.yaml | 2 +- .../virtualprivatecloud.yaml | 2 +- .../vm-disk.yaml | 2 +- .../vm-instance.yaml | 2 +- .../core/platform/bundles/iaas/bundle.yaml | 2 +- .../http-cache.yaml | 2 +- .../tcp-balancer.yaml | 2 +- .../vpn.yaml | 2 +- .../core/platform/bundles/naas/bundle.yaml | 2 +- .../clickhouse.yaml | 2 +- .../ferretdb.yaml | 2 +- .../foundationdb.yaml | 2 +- .../kafka.yaml | 2 +- .../mysql.yaml | 2 +- .../nats.yaml | 2 +- .../postgres.yaml | 2 +- .../rabbitmq.yaml | 2 +- .../redis.yaml | 2 +- .../core/platform/bundles/paas/bundle.yaml | 2 +- .../bootbox.yaml | 2 +- .../etcd.yaml | 2 +- .../info.yaml | 2 +- .../ingress.yaml | 2 +- .../monitoring.yaml | 2 +- .../seaweedfs.yaml | 2 +- .../tenant.yaml | 2 +- .../platform/bundles/system/bundle-full.yaml | 2 +- .../bundles/system/bundle-hosted.yaml | 2 +- .../bundles/system/bundle-minimal.yaml | 2 +- packages/core/platform/templates/_helpers.tpl | 2 +- .../templates/applicationdefinitions.yaml | 15 + packages/core/platform/templates/cozyrds.yaml | 8 +- packages/system/cozystack-api/values.yaml | 2 +- .../system/cozystack-controller/values.yaml | 2 +- .../lineage-controller-webhook/values.yaml | 2 +- pkg/cmd/server/start.go | 6 +- pkg/registry/apps/application/rest.go | 16 +- 71 files changed, 612 insertions(+), 591 deletions(-) rename api/v1alpha1/{cozystackresourcedefinitions_types.go => applicationdefinitions_types.go} (77%) rename api/v1alpha1/{cozystacksystembundles_types.go => bundles_types.go} (93%) rename api/v1alpha1/{cozystackplatform_types.go => platform_types.go} (77%) rename examples/{cozystackplatform-example.yaml => platform-example.yaml} (97%) rename internal/controller/{cozystackresource_controller.go => applicationdefinition_controller.go} (88%) rename packages/core/installer/crds/{cozystack.io_cozystackresourcedefinitions.yaml => cozystack.io_applicationdefinitions.yaml} (97%) rename packages/core/installer/crds/{cozystack.io_cozystackbundles.yaml => cozystack.io_bundles.yaml} (96%) rename packages/core/installer/crds/{cozystack.io_cozystackplatforms.yaml => cozystack.io_platforms.yaml} (89%) rename packages/core/platform/bundles/iaas/{cozyrds => applicationdefinitions}/bucket.yaml (98%) rename packages/core/platform/bundles/iaas/{cozyrds => applicationdefinitions}/kubernetes.yaml (99%) rename packages/core/platform/bundles/iaas/{cozyrds => applicationdefinitions}/virtual-machine.yaml (99%) rename packages/core/platform/bundles/iaas/{cozyrds => applicationdefinitions}/virtualprivatecloud.yaml (98%) rename packages/core/platform/bundles/iaas/{cozyrds => applicationdefinitions}/vm-disk.yaml (99%) rename packages/core/platform/bundles/iaas/{cozyrds => applicationdefinitions}/vm-instance.yaml (99%) rename packages/core/platform/bundles/naas/{cozyrds => applicationdefinitions}/http-cache.yaml (99%) rename packages/core/platform/bundles/naas/{cozyrds => applicationdefinitions}/tcp-balancer.yaml (99%) rename packages/core/platform/bundles/naas/{cozyrds => applicationdefinitions}/vpn.yaml (99%) rename packages/core/platform/bundles/paas/{cozyrds => applicationdefinitions}/clickhouse.yaml (99%) rename packages/core/platform/bundles/paas/{cozyrds => applicationdefinitions}/ferretdb.yaml (99%) rename packages/core/platform/bundles/paas/{cozyrds => applicationdefinitions}/foundationdb.yaml (99%) rename packages/core/platform/bundles/paas/{cozyrds => applicationdefinitions}/kafka.yaml (99%) rename packages/core/platform/bundles/paas/{cozyrds => applicationdefinitions}/mysql.yaml (99%) rename packages/core/platform/bundles/paas/{cozyrds => applicationdefinitions}/nats.yaml (99%) rename packages/core/platform/bundles/paas/{cozyrds => applicationdefinitions}/postgres.yaml (99%) rename packages/core/platform/bundles/paas/{cozyrds => applicationdefinitions}/rabbitmq.yaml (99%) rename packages/core/platform/bundles/paas/{cozyrds => applicationdefinitions}/redis.yaml (99%) rename packages/core/platform/bundles/system/{cozyrds => applicationdefinitions}/bootbox.yaml (99%) rename packages/core/platform/bundles/system/{cozyrds => applicationdefinitions}/etcd.yaml (99%) rename packages/core/platform/bundles/system/{cozyrds => applicationdefinitions}/info.yaml (98%) rename packages/core/platform/bundles/system/{cozyrds => applicationdefinitions}/ingress.yaml (99%) rename packages/core/platform/bundles/system/{cozyrds => applicationdefinitions}/monitoring.yaml (99%) rename packages/core/platform/bundles/system/{cozyrds => applicationdefinitions}/seaweedfs.yaml (99%) rename packages/core/platform/bundles/system/{cozyrds => applicationdefinitions}/tenant.yaml (99%) create mode 100644 packages/core/platform/templates/applicationdefinitions.yaml diff --git a/api/v1alpha1/cozystackresourcedefinitions_types.go b/api/v1alpha1/applicationdefinitions_types.go similarity index 77% rename from api/v1alpha1/cozystackresourcedefinitions_types.go rename to api/v1alpha1/applicationdefinitions_types.go index ba035445..c8b08795 100644 --- a/api/v1alpha1/cozystackresourcedefinitions_types.go +++ b/api/v1alpha1/applicationdefinitions_types.go @@ -22,47 +22,47 @@ import ( ) // +kubebuilder:object:root=true -// +kubebuilder:resource:scope=Cluster +// +kubebuilder:resource:scope=Cluster,shortName=appdef -// CozystackResourceDefinition is the Schema for the cozystackresourcedefinitions API -type CozystackResourceDefinition struct { +// ApplicationDefinition is the Schema for the applicationdefinitions API +type ApplicationDefinition struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec CozystackResourceDefinitionSpec `json:"spec,omitempty"` + Spec ApplicationDefinitionSpec `json:"spec,omitempty"` } // +kubebuilder:object:root=true -// CozystackResourceDefinitionList contains a list of CozystackResourceDefinitions -type CozystackResourceDefinitionList struct { +// ApplicationDefinitionList contains a list of ApplicationDefinitions +type ApplicationDefinitionList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []CozystackResourceDefinition `json:"items"` + Items []ApplicationDefinition `json:"items"` } func init() { - SchemeBuilder.Register(&CozystackResourceDefinition{}, &CozystackResourceDefinitionList{}) + SchemeBuilder.Register(&ApplicationDefinition{}, &ApplicationDefinitionList{}) } -type CozystackResourceDefinitionSpec struct { +type ApplicationDefinitionSpec struct { // Application configuration - Application CozystackResourceDefinitionApplication `json:"application"` + Application ApplicationDefinitionApplication `json:"application"` // Release configuration - Release CozystackResourceDefinitionRelease `json:"release"` + Release ApplicationDefinitionRelease `json:"release"` // Secret selectors - Secrets CozystackResourceDefinitionResources `json:"secrets,omitempty"` + Secrets ApplicationDefinitionResources `json:"secrets,omitempty"` // Service selectors - Services CozystackResourceDefinitionResources `json:"services,omitempty"` + Services ApplicationDefinitionResources `json:"services,omitempty"` // Ingress selectors - Ingresses CozystackResourceDefinitionResources `json:"ingresses,omitempty"` + Ingresses ApplicationDefinitionResources `json:"ingresses,omitempty"` // 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 string `json:"name"` // Source reference for the Helm chart @@ -80,7 +80,7 @@ type SourceRef struct { Namespace string `json:"namespace"` } -type CozystackResourceDefinitionApplication struct { +type ApplicationDefinitionApplication struct { // Kind of the application, used for UI and API Kind string `json:"kind"` // OpenAPI schema for the application, used for API validation @@ -92,13 +92,13 @@ type CozystackResourceDefinitionApplication 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" -type CozystackResourceDefinitionRelease struct { +type ApplicationDefinitionRelease struct { // Helm chart configuration (for HelmRepository source) // +optional - Chart *CozystackResourceDefinitionChart `json:"chart,omitempty"` + Chart *ApplicationDefinitionChart `json:"chart,omitempty"` // Chart reference configuration (for ExternalArtifact source) // +optional - ChartRef *CozystackResourceDefinitionChartRef `json:"chartRef,omitempty"` + ChartRef *ApplicationDefinitionChartRef `json:"chartRef,omitempty"` // Labels for the release Labels map[string]string `json:"labels,omitempty"` // Prefix for the release name @@ -109,12 +109,12 @@ type CozystackResourceDefinitionRelease struct { Values *apiextensionsv1.JSON `json:"values,omitempty"` } -type CozystackResourceDefinitionChartRef struct { +type ApplicationDefinitionChartRef struct { // Source reference for the chart (ExternalArtifact) SourceRef SourceRef `json:"sourceRef"` } -// CozystackResourceDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support. +// ApplicationDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support. // A resource matches this selector only if it satisfies ALL criteria: // - Label selector conditions (matchExpressions and matchLabels) // - AND has a name that matches one of the names in resourceNames (if specified) @@ -136,7 +136,7 @@ type CozystackResourceDefinitionChartRef struct { // - "{{ .name }}-secret" // - "{{ .kind }}-{{ .name }}-tls" // - "specificname" -type CozystackResourceDefinitionResourceSelector struct { +type ApplicationDefinitionResourceSelector struct { metav1.LabelSelector `json:",inline"` // ResourceNames is a list of resource names to match // If specified, the resource must have one of these exact names to match the selector @@ -144,16 +144,16 @@ type CozystackResourceDefinitionResourceSelector struct { ResourceNames []string `json:"resourceNames,omitempty"` } -type CozystackResourceDefinitionResources struct { +type ApplicationDefinitionResources struct { // 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 // 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. // 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 // as a tenant resource and is visible to users. - Include []*CozystackResourceDefinitionResourceSelector `json:"include,omitempty"` + Include []*ApplicationDefinitionResourceSelector `json:"include,omitempty"` } // ---- Dashboard types ---- @@ -170,8 +170,8 @@ const ( DashboardTabYAML DashboardTab = "yaml" ) -// CozystackResourceDefinitionDashboard describes how this resource appears in the UI. -type CozystackResourceDefinitionDashboard struct { +// ApplicationDefinitionDashboard describes how this resource appears in the UI. +type ApplicationDefinitionDashboard struct { // Human-readable name shown in the UI (e.g., "Bucket") Singular string `json:"singular"` // Plural human-readable name (e.g., "Buckets") diff --git a/api/v1alpha1/cozystacksystembundles_types.go b/api/v1alpha1/bundles_types.go similarity index 93% rename from api/v1alpha1/cozystacksystembundles_types.go rename to api/v1alpha1/bundles_types.go index d859e884..dc67edc8 100644 --- a/api/v1alpha1/cozystacksystembundles_types.go +++ b/api/v1alpha1/bundles_types.go @@ -22,31 +22,31 @@ import ( ) // +kubebuilder:object:root=true -// +kubebuilder:resource:scope=Cluster +// +kubebuilder:resource:scope=Cluster,shortName=bundle -// CozystackBundle is the Schema for the cozystackbundles API -type CozystackBundle struct { +// Bundle is the Schema for the bundles API +type Bundle struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec CozystackBundleSpec `json:"spec,omitempty"` + Spec BundleSpec `json:"spec,omitempty"` } // +kubebuilder:object:root=true -// CozystackBundleList contains a list of CozystackBundles -type CozystackBundleList struct { +// BundleList contains a list of Bundles +type BundleList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []CozystackBundle `json:"items"` + Items []Bundle `json:"items"` } func init() { - SchemeBuilder.Register(&CozystackBundle{}, &CozystackBundleList{}) + SchemeBuilder.Register(&Bundle{}, &BundleList{}) } -// CozystackBundleSpec defines the desired state of CozystackBundle -type CozystackBundleSpec struct { +// BundleSpec defines the desired state of Bundle +type BundleSpec struct { // SourceRef is the source reference for the bundle charts // +required SourceRef BundleSourceRef `json:"sourceRef"` @@ -68,7 +68,7 @@ type CozystackBundleSpec struct { Libraries []BundleLibrary `json:"libraries,omitempty"` // Artifacts is a list of Helm charts that will be built as ExternalArtifacts - // These artifacts can be referenced by CozystackResourceDefinitions + // These artifacts can be referenced by ApplicationDefinitions // +optional Artifacts []BundleArtifact `json:"artifacts,omitempty"` diff --git a/api/v1alpha1/cozystackplatform_types.go b/api/v1alpha1/platform_types.go similarity index 77% rename from api/v1alpha1/cozystackplatform_types.go rename to api/v1alpha1/platform_types.go index 228d0061..7300bc2c 100644 --- a/api/v1alpha1/cozystackplatform_types.go +++ b/api/v1alpha1/platform_types.go @@ -22,31 +22,31 @@ import ( ) // +kubebuilder:object:root=true -// +kubebuilder:resource:scope=Cluster +// +kubebuilder:resource:scope=Cluster,shortName=platform -// CozystackPlatform is the Schema for the cozystackplatforms API -type CozystackPlatform struct { +// Platform is the Schema for the platforms API +type Platform struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec CozystackPlatformSpec `json:"spec,omitempty"` + Spec PlatformSpec `json:"spec,omitempty"` } // +kubebuilder:object:root=true -// CozystackPlatformList contains a list of CozystackPlatform -type CozystackPlatformList struct { +// PlatformList contains a list of Platform +type PlatformList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []CozystackPlatform `json:"items"` + Items []Platform `json:"items"` } func init() { - SchemeBuilder.Register(&CozystackPlatform{}, &CozystackPlatformList{}) + SchemeBuilder.Register(&Platform{}, &PlatformList{}) } -// CozystackPlatformSpec defines the desired state of CozystackPlatform -type CozystackPlatformSpec struct { +// 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 diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 4504086b..eacc06d3 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -27,6 +27,293 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationDefinition) DeepCopyInto(out *ApplicationDefinition) { + *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 ApplicationDefinition. +func (in *ApplicationDefinition) DeepCopy() *ApplicationDefinition { + if in == nil { + return nil + } + out := new(ApplicationDefinition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ApplicationDefinition) 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 *ApplicationDefinitionApplication) DeepCopyInto(out *ApplicationDefinitionApplication) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionApplication. +func (in *ApplicationDefinitionApplication) DeepCopy() *ApplicationDefinitionApplication { + if in == nil { + return nil + } + out := new(ApplicationDefinitionApplication) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationDefinitionChart) DeepCopyInto(out *ApplicationDefinitionChart) { + *out = *in + out.SourceRef = in.SourceRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionChart. +func (in *ApplicationDefinitionChart) DeepCopy() *ApplicationDefinitionChart { + if in == nil { + return nil + } + out := new(ApplicationDefinitionChart) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +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 + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Tabs != nil { + in, out := &in.Tabs, &out.Tabs + *out = make([]DashboardTab, len(*in)) + copy(*out, *in) + } + if in.KeysOrder != nil { + in, out := &in.KeysOrder, &out.KeysOrder + *out = make([][]string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = make([]string, len(*in)) + copy(*out, *in) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionDashboard. +func (in *ApplicationDefinitionDashboard) DeepCopy() *ApplicationDefinitionDashboard { + if in == nil { + return nil + } + out := new(ApplicationDefinitionDashboard) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationDefinitionList) DeepCopyInto(out *ApplicationDefinitionList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ApplicationDefinition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionList. +func (in *ApplicationDefinitionList) DeepCopy() *ApplicationDefinitionList { + if in == nil { + return nil + } + out := new(ApplicationDefinitionList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ApplicationDefinitionList) 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 *ApplicationDefinitionRelease) DeepCopyInto(out *ApplicationDefinitionRelease) { + *out = *in + 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 { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*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 ApplicationDefinitionRelease. +func (in *ApplicationDefinitionRelease) DeepCopy() *ApplicationDefinitionRelease { + if in == nil { + return nil + } + out := new(ApplicationDefinitionRelease) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationDefinitionResourceSelector) DeepCopyInto(out *ApplicationDefinitionResourceSelector) { + *out = *in + in.LabelSelector.DeepCopyInto(&out.LabelSelector) + if in.ResourceNames != nil { + in, out := &in.ResourceNames, &out.ResourceNames + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionResourceSelector. +func (in *ApplicationDefinitionResourceSelector) DeepCopy() *ApplicationDefinitionResourceSelector { + if in == nil { + return nil + } + out := new(ApplicationDefinitionResourceSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationDefinitionResources) DeepCopyInto(out *ApplicationDefinitionResources) { + *out = *in + if in.Exclude != nil { + in, out := &in.Exclude, &out.Exclude + *out = make([]*ApplicationDefinitionResourceSelector, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(ApplicationDefinitionResourceSelector) + (*in).DeepCopyInto(*out) + } + } + } + if in.Include != nil { + in, out := &in.Include, &out.Include + *out = make([]*ApplicationDefinitionResourceSelector, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(ApplicationDefinitionResourceSelector) + (*in).DeepCopyInto(*out) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionResources. +func (in *ApplicationDefinitionResources) DeepCopy() *ApplicationDefinitionResources { + if in == nil { + return nil + } + out := new(ApplicationDefinitionResources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationDefinitionSpec) DeepCopyInto(out *ApplicationDefinitionSpec) { + *out = *in + out.Application = in.Application + in.Release.DeepCopyInto(&out.Release) + in.Secrets.DeepCopyInto(&out.Secrets) + in.Services.DeepCopyInto(&out.Services) + in.Ingresses.DeepCopyInto(&out.Ingresses) + if in.Dashboard != nil { + in, out := &in.Dashboard, &out.Dashboard + *out = new(ApplicationDefinitionDashboard) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionSpec. +func (in *ApplicationDefinitionSpec) DeepCopy() *ApplicationDefinitionSpec { + if in == nil { + return nil + } + 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 @@ -82,6 +369,38 @@ func (in *BundleLibrary) DeepCopy() *BundleLibrary { 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 @@ -147,65 +466,7 @@ func (in *BundleSourceRef) DeepCopy() *BundleSourceRef { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CozystackBundle) DeepCopyInto(out *CozystackBundle) { - *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 CozystackBundle. -func (in *CozystackBundle) DeepCopy() *CozystackBundle { - if in == nil { - return nil - } - out := new(CozystackBundle) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *CozystackBundle) 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 *CozystackBundleList) DeepCopyInto(out *CozystackBundleList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]CozystackBundle, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackBundleList. -func (in *CozystackBundleList) DeepCopy() *CozystackBundleList { - if in == nil { - return nil - } - out := new(CozystackBundleList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *CozystackBundleList) 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 *CozystackBundleSpec) DeepCopyInto(out *CozystackBundleSpec) { +func (in *BundleSpec) DeepCopyInto(out *BundleSpec) { *out = *in out.SourceRef = in.SourceRef if in.DependsOn != nil { @@ -248,36 +509,36 @@ func (in *CozystackBundleSpec) DeepCopyInto(out *CozystackBundleSpec) { } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackBundleSpec. -func (in *CozystackBundleSpec) DeepCopy() *CozystackBundleSpec { +// 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(CozystackBundleSpec) + 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 *CozystackPlatform) DeepCopyInto(out *CozystackPlatform) { +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 CozystackPlatform. -func (in *CozystackPlatform) DeepCopy() *CozystackPlatform { +// 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(CozystackPlatform) + out := new(Platform) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *CozystackPlatform) DeepCopyObject() runtime.Object { +func (in *Platform) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -285,31 +546,31 @@ func (in *CozystackPlatform) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CozystackPlatformList) DeepCopyInto(out *CozystackPlatformList) { +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([]CozystackPlatform, len(*in)) + *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 CozystackPlatformList. -func (in *CozystackPlatformList) DeepCopy() *CozystackPlatformList { +// 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(CozystackPlatformList) + out := new(PlatformList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *CozystackPlatformList) DeepCopyObject() runtime.Object { +func (in *PlatformList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -317,7 +578,7 @@ func (in *CozystackPlatformList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CozystackPlatformSpec) DeepCopyInto(out *CozystackPlatformSpec) { +func (in *PlatformSpec) DeepCopyInto(out *PlatformSpec) { *out = *in out.SourceRef = in.SourceRef if in.Values != nil { @@ -332,273 +593,12 @@ func (in *CozystackPlatformSpec) DeepCopyInto(out *CozystackPlatformSpec) { } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackPlatformSpec. -func (in *CozystackPlatformSpec) DeepCopy() *CozystackPlatformSpec { +// 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(CozystackPlatformSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CozystackResourceDefinition) DeepCopyInto(out *CozystackResourceDefinition) { - *out = *in - 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 CozystackResourceDefinition. -func (in *CozystackResourceDefinition) DeepCopy() *CozystackResourceDefinition { - if in == nil { - return nil - } - out := new(CozystackResourceDefinition) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *CozystackResourceDefinition) 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 *CozystackResourceDefinitionApplication) DeepCopyInto(out *CozystackResourceDefinitionApplication) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionApplication. -func (in *CozystackResourceDefinitionApplication) DeepCopy() *CozystackResourceDefinitionApplication { - if in == nil { - return nil - } - out := new(CozystackResourceDefinitionApplication) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CozystackResourceDefinitionChart) DeepCopyInto(out *CozystackResourceDefinitionChart) { - *out = *in - out.SourceRef = in.SourceRef -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionChart. -func (in *CozystackResourceDefinitionChart) DeepCopy() *CozystackResourceDefinitionChart { - if in == nil { - return nil - } - out := new(CozystackResourceDefinitionChart) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CozystackResourceDefinitionChartRef) DeepCopyInto(out *CozystackResourceDefinitionChartRef) { - *out = *in - out.SourceRef = in.SourceRef -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionChartRef. -func (in *CozystackResourceDefinitionChartRef) DeepCopy() *CozystackResourceDefinitionChartRef { - if in == nil { - return nil - } - out := new(CozystackResourceDefinitionChartRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CozystackResourceDefinitionDashboard) DeepCopyInto(out *CozystackResourceDefinitionDashboard) { - *out = *in - if in.Tags != nil { - in, out := &in.Tags, &out.Tags - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Tabs != nil { - in, out := &in.Tabs, &out.Tabs - *out = make([]DashboardTab, len(*in)) - copy(*out, *in) - } - if in.KeysOrder != nil { - in, out := &in.KeysOrder, &out.KeysOrder - *out = make([][]string, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = make([]string, len(*in)) - copy(*out, *in) - } - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionDashboard. -func (in *CozystackResourceDefinitionDashboard) DeepCopy() *CozystackResourceDefinitionDashboard { - if in == nil { - return nil - } - out := new(CozystackResourceDefinitionDashboard) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CozystackResourceDefinitionList) DeepCopyInto(out *CozystackResourceDefinitionList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]CozystackResourceDefinition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionList. -func (in *CozystackResourceDefinitionList) DeepCopy() *CozystackResourceDefinitionList { - if in == nil { - return nil - } - out := new(CozystackResourceDefinitionList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *CozystackResourceDefinitionList) 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 *CozystackResourceDefinitionRelease) DeepCopyInto(out *CozystackResourceDefinitionRelease) { - *out = *in - if in.Chart != nil { - in, out := &in.Chart, &out.Chart - *out = new(CozystackResourceDefinitionChart) - **out = **in - } - if in.ChartRef != nil { - in, out := &in.ChartRef, &out.ChartRef - *out = new(CozystackResourceDefinitionChartRef) - **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.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. -func (in *CozystackResourceDefinitionRelease) DeepCopy() *CozystackResourceDefinitionRelease { - if in == nil { - return nil - } - out := new(CozystackResourceDefinitionRelease) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CozystackResourceDefinitionResourceSelector) DeepCopyInto(out *CozystackResourceDefinitionResourceSelector) { - *out = *in - in.LabelSelector.DeepCopyInto(&out.LabelSelector) - if in.ResourceNames != nil { - in, out := &in.ResourceNames, &out.ResourceNames - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionResourceSelector. -func (in *CozystackResourceDefinitionResourceSelector) DeepCopy() *CozystackResourceDefinitionResourceSelector { - if in == nil { - return nil - } - out := new(CozystackResourceDefinitionResourceSelector) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CozystackResourceDefinitionResources) DeepCopyInto(out *CozystackResourceDefinitionResources) { - *out = *in - if in.Exclude != nil { - in, out := &in.Exclude, &out.Exclude - *out = make([]*CozystackResourceDefinitionResourceSelector, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(CozystackResourceDefinitionResourceSelector) - (*in).DeepCopyInto(*out) - } - } - } - if in.Include != nil { - in, out := &in.Include, &out.Include - *out = make([]*CozystackResourceDefinitionResourceSelector, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(CozystackResourceDefinitionResourceSelector) - (*in).DeepCopyInto(*out) - } - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionResources. -func (in *CozystackResourceDefinitionResources) DeepCopy() *CozystackResourceDefinitionResources { - if in == nil { - return nil - } - out := new(CozystackResourceDefinitionResources) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CozystackResourceDefinitionSpec) DeepCopyInto(out *CozystackResourceDefinitionSpec) { - *out = *in - out.Application = in.Application - in.Release.DeepCopyInto(&out.Release) - in.Secrets.DeepCopyInto(&out.Secrets) - in.Services.DeepCopyInto(&out.Services) - in.Ingresses.DeepCopyInto(&out.Ingresses) - if in.Dashboard != nil { - in, out := &in.Dashboard, &out.Dashboard - *out = new(CozystackResourceDefinitionDashboard) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionSpec. -func (in *CozystackResourceDefinitionSpec) DeepCopy() *CozystackResourceDefinitionSpec { - if in == nil { - return nil - } - out := new(CozystackResourceDefinitionSpec) + out := new(PlatformSpec) in.DeepCopyInto(out) return out } diff --git a/cmd/cozystack-controller/main.go b/cmd/cozystack-controller/main.go index ab551b6d..45f46e9c 100644 --- a/cmd/cozystack-controller/main.go +++ b/cmd/cozystack-controller/main.go @@ -179,12 +179,12 @@ func main() { os.Exit(1) } - if err = (&controller.CozystackResourceDefinitionReconciler{ + if err = (&controller.ApplicationDefinitionReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), CozystackAPIKind: "Deployment", }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "CozystackResourceDefinitionReconciler") + setupLog.Error(err, "unable to create controller", "controller", "ApplicationDefinitionReconciler") os.Exit(1) } diff --git a/cmd/cozystack-operator/main.go b/cmd/cozystack-operator/main.go index dca95b79..3cdb2371 100644 --- a/cmd/cozystack-operator/main.go +++ b/cmd/cozystack-operator/main.go @@ -197,21 +197,21 @@ func main() { } } - bundleReconciler := &operator.CozystackBundleReconciler{ + bundleReconciler := &operator.BundleReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), } if err = bundleReconciler.SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "CozystackBundle") + setupLog.Error(err, "unable to create controller", "controller", "Bundle") os.Exit(1) } - platformReconciler := &operator.CozystackPlatformReconciler{ + platformReconciler := &operator.PlatformReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), } if err = platformReconciler.SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "CozystackPlatform") + setupLog.Error(err, "unable to create controller", "controller", "Platform") os.Exit(1) } diff --git a/examples/cozystackplatform-example.yaml b/examples/platform-example.yaml similarity index 97% rename from examples/cozystackplatform-example.yaml rename to examples/platform-example.yaml index b1753ffa..6e1a13ee 100644 --- a/examples/cozystackplatform-example.yaml +++ b/examples/platform-example.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackPlatform +kind: Platform metadata: name: cozystack-platform # Cluster-scoped resource, no namespace needed diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index f8a1bd6a..664a8588 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -54,9 +54,9 @@ kube::codegen::gen_openapi \ $CONTROLLER_GEN object:headerFile="hack/boilerplate.go.txt" paths="./api/..." $CONTROLLER_GEN rbac:roleName=manager-role crd paths="./api/..." output:crd:artifacts:config=packages/system/cozystack-controller/crds -mv packages/system/cozystack-controller/crds/cozystack.io_cozystackresourcedefinitions.yaml \ - packages/core/installer/crds/cozystack.io_cozystackresourcedefinitions.yaml -mv packages/system/cozystack-controller/crds/cozystack.io_cozystackbundles.yaml \ - packages/core/installer/crds/cozystack.io_cozystackbundles.yaml -mv packages/system/cozystack-controller/crds/cozystack.io_cozystackplatforms.yaml \ - packages/core/installer/crds/cozystack.io_cozystackplatforms.yaml +mv packages/system/cozystack-controller/crds/cozystack.io_applicationdefinitions.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 diff --git a/hack/update-crd.sh b/hack/update-crd.sh index b754006d..38a03240 100755 --- a/hack/update-crd.sh +++ b/hack/update-crd.sh @@ -8,7 +8,7 @@ need yq; need jq; need base64 CHART_YAML="${CHART_YAML:-Chart.yaml}" VALUES_YAML="${VALUES_YAML:-values.yaml}" SCHEMA_JSON="${SCHEMA_JSON:-values.schema.json}" -CRD_DIR="../../core/platform/bundles/*/cozyrds" +CRD_DIR="../../core/platform/bundles/*/applicationdefinitions" [[ -f "$CHART_YAML" ]] || { echo "No $CHART_YAML found"; exit 1; } [[ -f "$SCHEMA_JSON" ]] || { echo "No $SCHEMA_JSON found"; exit 1; } @@ -59,7 +59,7 @@ OUT="$(find $CRD_DIR -type f -name "${NAME}.yaml" | head -n 1)" if [[ ! -s "$OUT" ]]; then cat >"$OUT" <.. // spec.id: stock-namespace-/// -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) plural := pickPlural(kind, crd) // Details page segment uses lowercase kind, mirroring your example diff --git a/internal/controller/dashboard/customformsoverride.go b/internal/controller/dashboard/customformsoverride.go index f88202bc..dee37d05 100644 --- a/internal/controller/dashboard/customformsoverride.go +++ b/internal/controller/dashboard/customformsoverride.go @@ -15,7 +15,7 @@ import ( ) // 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) plural := pickPlural(kind, crd) diff --git a/internal/controller/dashboard/customformsprefill.go b/internal/controller/dashboard/customformsprefill.go index d2761873..35d22ff1 100644 --- a/internal/controller/dashboard/customformsprefill.go +++ b/internal/controller/dashboard/customformsprefill.go @@ -16,7 +16,7 @@ import ( ) // 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) app := crd.Spec.Application diff --git a/internal/controller/dashboard/factory.go b/internal/controller/dashboard/factory.go index 4f1c9b1f..1201d103 100644 --- a/internal/controller/dashboard/factory.go +++ b/internal/controller/dashboard/factory.go @@ -15,7 +15,7 @@ import ( ) // 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) plural := pickPlural(kind, crd) @@ -524,7 +524,7 @@ type factoryFlags struct { // factoryFeatureFlags tries several conventional locations so you can evolve the API // without breaking the controller. Defaults are false (hidden). -func factoryFeatureFlags(crd *cozyv1alpha1.CozystackResourceDefinition) factoryFlags { +func factoryFeatureFlags(crd *cozyv1alpha1.ApplicationDefinition) factoryFlags { var f factoryFlags f.Workloads = true diff --git a/internal/controller/dashboard/helpers.go b/internal/controller/dashboard/helpers.go index a0023a05..2a35bbff 100644 --- a/internal/controller/dashboard/helpers.go +++ b/internal/controller/dashboard/helpers.go @@ -23,7 +23,7 @@ type fieldInfo struct { // 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. -func pickGVK(crd *cozyv1alpha1.CozystackResourceDefinition) (group, version, kind string) { +func pickGVK(crd *cozyv1alpha1.ApplicationDefinition) (group, version, kind string) { // Best guess based on your examples: if 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". -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 crd.Spec.Application.Plural != "" { return crd.Spec.Application.Plural diff --git a/internal/controller/dashboard/manager.go b/internal/controller/dashboard/manager.go index 12e50fbc..10da06bd 100644 --- a/internal/controller/dashboard/manager.go +++ b/internal/controller/dashboard/manager.go @@ -56,7 +56,7 @@ func NewManager(c client.Client, scheme *runtime.Scheme) *Manager { func (m *Manager) SetupWithManager(mgr ctrl.Manager) error { if err := ctrl.NewControllerManagedBy(mgr). Named("dashboard-reconciler"). - For(&cozyv1alpha1.CozystackResourceDefinition{}). + For(&cozyv1alpha1.ApplicationDefinition{}). Complete(m); err != nil { 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) { l := log.FromContext(ctx) - crd := &cozyv1alpha1.CozystackResourceDefinition{} + crd := &cozyv1alpha1.ApplicationDefinition{} err := m.Get(ctx, types.NamespacedName{Name: req.Name}, crd) if err != nil { @@ -99,7 +99,7 @@ func (m *Manager) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, // - ensureMarketplacePanel (implemented) // - ensureSidebar (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 if crd.Spec.Dashboard == 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 -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() if labels == nil { labels = make(map[string]string) @@ -197,7 +197,7 @@ func (m *Manager) getStaticResourceSelector() client.MatchingLabels { // CleanupOrphanedResources removes dashboard resources that are no longer needed // This should be called after cache warming to ensure all current resources are known 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 { return err } @@ -228,7 +228,7 @@ func (m *Manager) CleanupOrphanedResources(ctx context.Context) error { } // 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) // Initialize maps for each resource type diff --git a/internal/controller/dashboard/marketplacepanel.go b/internal/controller/dashboard/marketplacepanel.go index 82a8f336..6bfce752 100644 --- a/internal/controller/dashboard/marketplacepanel.go +++ b/internal/controller/dashboard/marketplacepanel.go @@ -16,7 +16,7 @@ import ( ) // 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) mp := &dashv1alpha1.MarketplacePanel{} diff --git a/internal/controller/dashboard/sidebar.go b/internal/controller/dashboard/sidebar.go index 97937921..b10cf5a2 100644 --- a/internal/controller/dashboard/sidebar.go +++ b/internal/controller/dashboard/sidebar.go @@ -28,12 +28,12 @@ import ( // - Categories are ordered strictly as: // Marketplace, IaaS, PaaS, NaaS, , Resources, Administration // - 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. // 1) Fetch all CRDs - var all []cozyv1alpha1.CozystackResourceDefinition - var crdList cozyv1alpha1.CozystackResourceDefinitionList + var all []cozyv1alpha1.ApplicationDefinition + var crdList cozyv1alpha1.ApplicationDefinitionList if err := m.List(ctx, &crdList, &client.ListOptions{}); err != nil { 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. func (m *Manager) upsertMultipleSidebars( ctx context.Context, - crd *cozyv1alpha1.CozystackResourceDefinition, + crd *cozyv1alpha1.ApplicationDefinition, ids []string, keysAndTags map[string]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. -func safeCategory(def *cozyv1alpha1.CozystackResourceDefinition) string { +func safeCategory(def *cozyv1alpha1.ApplicationDefinition) string { if def == nil || def.Spec.Dashboard == nil { return "Resources" } diff --git a/internal/controller/dashboard/tableurimapping.go b/internal/controller/dashboard/tableurimapping.go index 6e8a395d..e9a4849c 100644 --- a/internal/controller/dashboard/tableurimapping.go +++ b/internal/controller/dashboard/tableurimapping.go @@ -7,7 +7,7 @@ import ( ) // 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. return nil } diff --git a/internal/lineagecontrollerwebhook/controller.go b/internal/lineagecontrollerwebhook/controller.go index c423603b..d3465429 100644 --- a/internal/lineagecontrollerwebhook/controller.go +++ b/internal/lineagecontrollerwebhook/controller.go @@ -4,7 +4,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" ) -// SetupWithManagerAsController is no longer needed since we don't watch CozystackResourceDefinitions +// SetupWithManagerAsController is no longer needed since we don't watch ApplicationDefinitions func (c *LineageControllerWebhook) SetupWithManagerAsController(mgr ctrl.Manager) error { // No controller needed - we use labels directly from HelmRelease return nil diff --git a/internal/lineagecontrollerwebhook/matcher.go b/internal/lineagecontrollerwebhook/matcher.go index 7c756a49..6e7bd318 100644 --- a/internal/lineagecontrollerwebhook/matcher.go +++ b/internal/lineagecontrollerwebhook/matcher.go @@ -42,7 +42,7 @@ func matchName(ctx context.Context, name string, templateContext map[string]stri 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) if err != nil { 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 } -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 { if matchResourceToSelector(ctx, name, templateContext, l, s) { return true @@ -62,7 +62,7 @@ func matchResourceToSelectorArray(ctx context.Context, name string, templateCont 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 { return false } diff --git a/internal/lineagecontrollerwebhook/webhook.go b/internal/lineagecontrollerwebhook/webhook.go index 2db21eab..ba8a6830 100644 --- a/internal/lineagecontrollerwebhook/webhook.go +++ b/internal/lineagecontrollerwebhook/webhook.go @@ -32,8 +32,8 @@ const ( ManagerNameKey = "apps.cozystack.io/application.name" ) -// getResourceSelectors returns the appropriate CozystackResourceDefinitionResources for a given GroupKind -func (h *LineageControllerWebhook) getResourceSelectors(gk schema.GroupKind, crd *cozyv1alpha1.CozystackResourceDefinition) *cozyv1alpha1.CozystackResourceDefinitionResources { +// getResourceSelectors returns the appropriate ApplicationDefinitionResources for a given GroupKind +func (h *LineageControllerWebhook) getResourceSelectors(gk schema.GroupKind, crd *cozyv1alpha1.ApplicationDefinition) *cozyv1alpha1.ApplicationDefinitionResources { switch { case gk.Group == "" && gk.Kind == "Secret": return &crd.Spec.Secrets @@ -159,7 +159,7 @@ func (h *LineageControllerWebhook) computeLabels(ctx context.Context, o *unstruc ManagerKindKey: obj.GetKind(), ManagerNameKey: obj.GetName(), } - // Resource selectors are no longer needed since we don't use CozystackResourceDefinitions + // Resource selectors are no longer needed since we don't use ApplicationDefinitions // Set tenant resource label to false by default (can be overridden by other logic if needed) labels[corev1alpha1.TenantResourceLabelKey] = "false" return labels, err diff --git a/internal/operator/bundle_reconciler.go b/internal/operator/bundle_reconciler.go index 343fd66f..42716db1 100644 --- a/internal/operator/bundle_reconciler.go +++ b/internal/operator/bundle_reconciler.go @@ -40,23 +40,23 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" ) -// CozystackBundleReconciler reconciles CozystackBundle resources -type CozystackBundleReconciler struct { +// BundleReconciler reconciles Bundle resources +type BundleReconciler struct { client.Client Scheme *runtime.Scheme } -// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackbundles,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackbundles/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=cozystack.io,resources=bundles,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=cozystack.io,resources=bundles/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 // +kubebuilder:rbac:groups=core,resources=namespaces,verbs=get;list;watch;create;update;patch // Reconcile is part of the main kubernetes reconciliation loop -func (r *CozystackBundleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { +func (r *BundleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { logger := log.FromContext(ctx) - bundle := &cozyv1alpha1.CozystackBundle{} + bundle := &cozyv1alpha1.Bundle{} if err := r.Get(ctx, req.NamespacedName, bundle); err != nil { if apierrors.IsNotFound(err) { // Cleanup orphaned resources @@ -107,7 +107,7 @@ func (r *CozystackBundleReconciler) Reconcile(ctx context.Context, req ctrl.Requ } // resolveDependencies resolves dependencies from other bundles -func (r *CozystackBundleReconciler) resolveDependencies(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle) ([]cozyv1alpha1.BundleRelease, error) { +func (r *BundleReconciler) resolveDependencies(ctx context.Context, bundle *cozyv1alpha1.Bundle) ([]cozyv1alpha1.BundleRelease, error) { resolved := make([]cozyv1alpha1.BundleRelease, 0, len(bundle.Spec.Packages)) packageMap := make(map[string]bool) @@ -130,7 +130,7 @@ func (r *CozystackBundleReconciler) resolveDependencies(ctx context.Context, bun targetName := parts[1] // Get the bundle - depBundle := &cozyv1alpha1.CozystackBundle{} + depBundle := &cozyv1alpha1.Bundle{} if err := r.Get(ctx, types.NamespacedName{Name: bundleName}, depBundle); err != nil { // If bundle is not found, return wrapped error so we can check it in Reconcile if apierrors.IsNotFound(err) { @@ -176,7 +176,7 @@ func (r *CozystackBundleReconciler) resolveDependencies(ctx context.Context, bun // reconcileArtifactGenerators generates a single ArtifactGenerator for the bundle // Creates one ArtifactGenerator per bundle with all OutputArtifacts from packages and artifacts -func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle, packages []cozyv1alpha1.BundleRelease) error { +func (r *BundleReconciler) reconcileArtifactGenerators(ctx context.Context, bundle *cozyv1alpha1.Bundle, packages []cozyv1alpha1.BundleRelease) error { logger := log.FromContext(ctx) libraryMap := make(map[string]cozyv1alpha1.BundleLibrary) @@ -363,7 +363,7 @@ func (r *CozystackBundleReconciler) reconcileArtifactGenerators(ctx context.Cont } // reconcileHelmReleases generates HelmReleases from bundle packages -func (r *CozystackBundleReconciler) reconcileHelmReleases(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle, packages []cozyv1alpha1.BundleRelease) error { +func (r *BundleReconciler) reconcileHelmReleases(ctx context.Context, bundle *cozyv1alpha1.Bundle, packages []cozyv1alpha1.BundleRelease) error { logger := log.FromContext(ctx) // Build package name map for dependency resolution (from current bundle) @@ -374,7 +374,7 @@ func (r *CozystackBundleReconciler) reconcileHelmReleases(ctx context.Context, b // Build global package name map from all bundles for finding dependencies globalPackageMap := make(map[string]cozyv1alpha1.BundleRelease) - bundleList := &cozyv1alpha1.CozystackBundleList{} + bundleList := &cozyv1alpha1.BundleList{} if err := r.List(ctx, bundleList); err == nil { for _, b := range bundleList.Items { for _, pkg := range b.Spec.Packages { @@ -536,7 +536,7 @@ func (r *CozystackBundleReconciler) reconcileHelmReleases(ctx context.Context, b } // createOrUpdate creates or updates a resource -func (r *CozystackBundleReconciler) createOrUpdate(ctx context.Context, obj client.Object) error { +func (r *BundleReconciler) createOrUpdate(ctx context.Context, obj client.Object) error { existing := obj.DeepCopyObject().(client.Object) key := client.ObjectKeyFromObject(obj) @@ -767,7 +767,7 @@ func deepMergeMaps(base, override map[string]interface{}) map[string]interface{} } // Helper functions -func (r *CozystackBundleReconciler) getPackageNameFromPath(path string) string { +func (r *BundleReconciler) getPackageNameFromPath(path string) string { parts := strings.Split(path, "/") if len(parts) > 0 { return parts[len(parts)-1] @@ -776,7 +776,7 @@ func (r *CozystackBundleReconciler) getPackageNameFromPath(path string) string { } // getBasePath returns the basePath with default values based on source kind -func (r *CozystackBundleReconciler) getBasePath(bundle *cozyv1alpha1.CozystackBundle) string { +func (r *BundleReconciler) getBasePath(bundle *cozyv1alpha1.Bundle) string { // If basePath is explicitly set, use it if bundle.Spec.BasePath != "" { return bundle.Spec.BasePath @@ -790,7 +790,7 @@ func (r *CozystackBundleReconciler) getBasePath(bundle *cozyv1alpha1.CozystackBu } // buildSourcePath builds the full source path using basePath with glob pattern -func (r *CozystackBundleReconciler) buildSourcePath(sourceName, basePath, path string) string { +func (r *BundleReconciler) buildSourcePath(sourceName, basePath, path string) string { // Remove leading/trailing slashes and combine parts := []string{} if basePath != "" { @@ -808,7 +808,7 @@ func (r *CozystackBundleReconciler) buildSourcePath(sourceName, basePath, path s } // buildSourceFilePath builds the full source path for a specific file (without glob pattern) -func (r *CozystackBundleReconciler) buildSourceFilePath(sourceName, basePath, path string) string { +func (r *BundleReconciler) buildSourceFilePath(sourceName, basePath, path string) string { // Remove leading/trailing slashes and combine parts := []string{} if basePath != "" { @@ -825,7 +825,7 @@ func (r *CozystackBundleReconciler) buildSourceFilePath(sourceName, basePath, pa return fmt.Sprintf("@%s/%s", sourceName, fullPath) } -func (r *CozystackBundleReconciler) cleanupOrphanedArtifactGenerators(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle) error { +func (r *BundleReconciler) cleanupOrphanedArtifactGenerators(ctx context.Context, bundle *cozyv1alpha1.Bundle) error { logger := log.FromContext(ctx) // Find ArtifactGenerators by label @@ -864,7 +864,7 @@ func (r *CozystackBundleReconciler) cleanupOrphanedArtifactGenerators(ctx contex return nil } -func (r *CozystackBundleReconciler) cleanupOrphanedHelmReleases(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle) error { +func (r *BundleReconciler) cleanupOrphanedHelmReleases(ctx context.Context, bundle *cozyv1alpha1.Bundle) error { logger := log.FromContext(ctx) // Find HelmReleases by label @@ -902,7 +902,7 @@ func (r *CozystackBundleReconciler) cleanupOrphanedHelmReleases(ctx context.Cont return nil } -func (r *CozystackBundleReconciler) cleanupOrphanedResources(ctx context.Context, bundleKey types.NamespacedName) (ctrl.Result, error) { +func (r *BundleReconciler) cleanupOrphanedResources(ctx context.Context, bundleKey types.NamespacedName) (ctrl.Result, error) { logger := log.FromContext(ctx) // Cleanup ArtifactGenerators by label @@ -915,7 +915,7 @@ func (r *CozystackBundleReconciler) cleanupOrphanedResources(ctx context.Context // Check if this resource has ownerReference to the deleted bundle hasOwnerRef := false for _, ownerRef := range ag.OwnerReferences { - if ownerRef.Kind == "CozystackBundle" && ownerRef.Name == bundleKey.Name { + if ownerRef.Kind == "Bundle" && ownerRef.Name == bundleKey.Name { hasOwnerRef = true break } @@ -944,7 +944,7 @@ func (r *CozystackBundleReconciler) cleanupOrphanedResources(ctx context.Context // Check if this resource has ownerReference to the deleted bundle hasOwnerRef := false for _, ownerRef := range hr.OwnerReferences { - if ownerRef.Kind == "CozystackBundle" && ownerRef.Name == bundleKey.Name { + if ownerRef.Kind == "Bundle" && ownerRef.Name == bundleKey.Name { hasOwnerRef = true break } @@ -967,7 +967,7 @@ func (r *CozystackBundleReconciler) cleanupOrphanedResources(ctx context.Context } // reconcileNamespaces creates or updates namespaces based on packages in the bundle. -func (r *CozystackBundleReconciler) reconcileNamespaces(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle, packages []cozyv1alpha1.BundleRelease) error { +func (r *BundleReconciler) reconcileNamespaces(ctx context.Context, bundle *cozyv1alpha1.Bundle, packages []cozyv1alpha1.BundleRelease) error { logger := log.FromContext(ctx) // Collect namespaces from packages @@ -1050,7 +1050,7 @@ func (r *CozystackBundleReconciler) reconcileNamespaces(ctx context.Context, bun } // createOrUpdateNamespace creates or updates a namespace. -func (r *CozystackBundleReconciler) createOrUpdateNamespace(ctx context.Context, namespace *corev1.Namespace) error { +func (r *BundleReconciler) createOrUpdateNamespace(ctx context.Context, namespace *corev1.Namespace) error { existing := &corev1.Namespace{} key := types.NamespacedName{Name: namespace.Name} @@ -1092,7 +1092,7 @@ func (r *CozystackBundleReconciler) createOrUpdateNamespace(ctx context.Context, } // checkArtifactConflicts checks for conflicts between packages using artifacts and bundle artifacts -func (r *CozystackBundleReconciler) checkArtifactConflicts(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle, packages []cozyv1alpha1.BundleRelease) error { +func (r *BundleReconciler) checkArtifactConflicts(ctx context.Context, bundle *cozyv1alpha1.Bundle, packages []cozyv1alpha1.BundleRelease) error { // Build artifact name map from bundle artifacts artifactNameMap := make(map[string]bool) for _, artifact := range bundle.Spec.Artifacts { @@ -1112,7 +1112,7 @@ func (r *CozystackBundleReconciler) checkArtifactConflicts(ctx context.Context, } // removeOwnerReferences removes ownerReferences from all resources with bundle label -func (r *CozystackBundleReconciler) removeOwnerReferences(ctx context.Context, bundle *cozyv1alpha1.CozystackBundle) error { +func (r *BundleReconciler) removeOwnerReferences(ctx context.Context, bundle *cozyv1alpha1.Bundle) error { logger := log.FromContext(ctx) // Remove ownerReferences from ArtifactGenerators by label @@ -1126,7 +1126,7 @@ func (r *CozystackBundleReconciler) removeOwnerReferences(ctx context.Context, b newOwnerRefs := []metav1.OwnerReference{} for _, ownerRef := range ag.OwnerReferences { - if ownerRef.Kind == "CozystackBundle" && ownerRef.Name == bundle.Name { + if ownerRef.Kind == "Bundle" && ownerRef.Name == bundle.Name { // Skip this ownerReference (remove it) // Check by name only, not UID, to handle bundle updates updated = true @@ -1158,7 +1158,7 @@ func (r *CozystackBundleReconciler) removeOwnerReferences(ctx context.Context, b newOwnerRefs := []metav1.OwnerReference{} for _, ownerRef := range hr.OwnerReferences { - if ownerRef.Kind == "CozystackBundle" && ownerRef.Name == bundle.Name { + if ownerRef.Kind == "Bundle" && ownerRef.Name == bundle.Name { // Skip this ownerReference (remove it) // Check by name only, not UID, to handle bundle updates updated = true @@ -1183,10 +1183,10 @@ func (r *CozystackBundleReconciler) removeOwnerReferences(ctx context.Context, b } // SetupWithManager sets up the controller with the Manager. -func (r *CozystackBundleReconciler) SetupWithManager(mgr ctrl.Manager) error { +func (r *BundleReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). Named("cozystack-bundle"). - For(&cozyv1alpha1.CozystackBundle{}). + For(&cozyv1alpha1.Bundle{}). Watches( &helmv2.HelmRelease{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request { diff --git a/internal/operator/platform_reconciler.go b/internal/operator/platform_reconciler.go index af79546f..b196b507 100644 --- a/internal/operator/platform_reconciler.go +++ b/internal/operator/platform_reconciler.go @@ -38,22 +38,22 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" ) -// CozystackPlatformReconciler reconciles CozystackPlatform resources -type CozystackPlatformReconciler struct { +// PlatformReconciler reconciles Platform resources +type PlatformReconciler struct { client.Client Scheme *runtime.Scheme } -// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackplatforms,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackplatforms/status,verbs=get;update;patch +// +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 *CozystackPlatformReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { +func (r *PlatformReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { logger := log.FromContext(ctx) - platform := &cozyv1alpha1.CozystackPlatform{} + platform := &cozyv1alpha1.Platform{} if err := r.Get(ctx, req.NamespacedName, platform); err != nil { if apierrors.IsNotFound(err) { // Cleanup orphaned resources @@ -83,7 +83,7 @@ func (r *CozystackPlatformReconciler) Reconcile(ctx context.Context, req ctrl.Re } // reconcileArtifactGenerator creates or updates the ArtifactGenerator for the platform -func (r *CozystackPlatformReconciler) reconcileArtifactGenerator(ctx context.Context, platform *cozyv1alpha1.CozystackPlatform) error { +func (r *PlatformReconciler) reconcileArtifactGenerator(ctx context.Context, platform *cozyv1alpha1.Platform) error { logger := log.FromContext(ctx) // ArtifactGenerator name is the sourceRef name @@ -156,7 +156,7 @@ func (r *CozystackPlatformReconciler) reconcileArtifactGenerator(ctx context.Con } // reconcileHelmRelease creates or updates the HelmRelease for the platform -func (r *CozystackPlatformReconciler) reconcileHelmRelease(ctx context.Context, platform *cozyv1alpha1.CozystackPlatform) error { +func (r *PlatformReconciler) reconcileHelmRelease(ctx context.Context, platform *cozyv1alpha1.Platform) error { logger := log.FromContext(ctx) // HelmRelease name is fixed: cozystack-platform @@ -226,7 +226,7 @@ func (r *CozystackPlatformReconciler) reconcileHelmRelease(ctx context.Context, } // mergeValuesWithSourceRef merges platform values with sourceRef -func (r *CozystackPlatformReconciler) mergeValuesWithSourceRef(values *apiextensionsv1.JSON, sourceRef cozyv1alpha1.SourceRef) *apiextensionsv1.JSON { +func (r *PlatformReconciler) mergeValuesWithSourceRef(values *apiextensionsv1.JSON, sourceRef cozyv1alpha1.SourceRef) *apiextensionsv1.JSON { // Build sourceRef map sourceRefMap := map[string]interface{}{ "kind": sourceRef.Kind, @@ -268,7 +268,7 @@ func (r *CozystackPlatformReconciler) mergeValuesWithSourceRef(values *apiextens } // getBasePath returns the basePath with default values based on source kind -func (r *CozystackPlatformReconciler) getBasePath(platform *cozyv1alpha1.CozystackPlatform) string { +func (r *PlatformReconciler) getBasePath(platform *cozyv1alpha1.Platform) string { if platform.Spec.BasePath != "" { return platform.Spec.BasePath } @@ -281,7 +281,7 @@ func (r *CozystackPlatformReconciler) getBasePath(platform *cozyv1alpha1.Cozysta } // buildSourcePath builds the full source path from basePath and chart path -func (r *CozystackPlatformReconciler) buildSourcePath(sourceName, basePath, chartPath string) string { +func (r *PlatformReconciler) buildSourcePath(sourceName, basePath, chartPath string) string { // Remove leading/trailing slashes and combine parts := []string{} if basePath != "" { @@ -297,8 +297,8 @@ func (r *CozystackPlatformReconciler) buildSourcePath(sourceName, basePath, char return fmt.Sprintf("@%s/%s", sourceName, fullPath) } -// cleanupOrphanedResources removes ArtifactGenerator and HelmRelease when CozystackPlatform is deleted -func (r *CozystackPlatformReconciler) cleanupOrphanedResources(ctx context.Context, name client.ObjectKey) (ctrl.Result, error) { +// cleanupOrphanedResources removes ArtifactGenerator and HelmRelease when Platform is deleted +func (r *PlatformReconciler) cleanupOrphanedResources(ctx context.Context, name client.ObjectKey) (ctrl.Result, error) { // OwnerReferences should handle cleanup automatically // This function is kept for potential future cleanup logic // Note: name is ObjectKey, but for cluster-scoped resources only Name is used @@ -306,7 +306,7 @@ func (r *CozystackPlatformReconciler) cleanupOrphanedResources(ctx context.Conte } // createOrUpdate creates or updates a resource -func (r *CozystackPlatformReconciler) createOrUpdate(ctx context.Context, obj client.Object) error { +func (r *PlatformReconciler) createOrUpdate(ctx context.Context, obj client.Object) error { existing := obj.DeepCopyObject().(client.Object) key := client.ObjectKeyFromObject(obj) @@ -374,10 +374,10 @@ func (r *CozystackPlatformReconciler) createOrUpdate(ctx context.Context, obj cl } // SetupWithManager sets up the controller with the Manager -func (r *CozystackPlatformReconciler) SetupWithManager(mgr ctrl.Manager) error { +func (r *PlatformReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). Named("cozystack-platform"). - For(&cozyv1alpha1.CozystackPlatform{}). + For(&cozyv1alpha1.Platform{}). Watches( &helmv2.HelmRelease{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request { diff --git a/internal/shared/crdmem/memory.go b/internal/shared/crdmem/memory.go index fbfbeeea..f0446627 100644 --- a/internal/shared/crdmem/memory.go +++ b/internal/shared/crdmem/memory.go @@ -11,13 +11,13 @@ import ( type Memory struct { mu sync.RWMutex - data map[string]cozyv1alpha1.CozystackResourceDefinition + data map[string]cozyv1alpha1.ApplicationDefinition primed bool primeOnce sync.Once } func New() *Memory { - return &Memory{data: make(map[string]cozyv1alpha1.CozystackResourceDefinition)} + return &Memory{data: make(map[string]cozyv1alpha1.ApplicationDefinition)} } var ( @@ -30,7 +30,7 @@ func Global() *Memory { return global } -func (m *Memory) Upsert(obj *cozyv1alpha1.CozystackResourceDefinition) { +func (m *Memory) Upsert(obj *cozyv1alpha1.ApplicationDefinition) { if obj == nil { return } @@ -45,10 +45,10 @@ func (m *Memory) Delete(name string) { m.mu.Unlock() } -func (m *Memory) Snapshot() []cozyv1alpha1.CozystackResourceDefinition { +func (m *Memory) Snapshot() []cozyv1alpha1.ApplicationDefinition { m.mu.RLock() 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 { out = append(out, v) } @@ -72,7 +72,7 @@ func (m *Memory) EnsurePrimingWithManager(mgr ctrl.Manager) error { if ok := mgr.GetCache().WaitForCacheSync(ctx); !ok { return nil } - var list cozyv1alpha1.CozystackResourceDefinitionList + var list cozyv1alpha1.ApplicationDefinitionList if err := mgr.GetClient().List(ctx, &list); err == nil { for i := range list.Items { m.Upsert(&list.Items[i]) @@ -87,11 +87,11 @@ func (m *Memory) EnsurePrimingWithManager(mgr ctrl.Manager) error { 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() { return m.Snapshot(), nil } - var list cozyv1alpha1.CozystackResourceDefinitionList + var list cozyv1alpha1.ApplicationDefinitionList if err := c.List(ctx, &list); err != nil { return nil, err } diff --git a/internal/telemetry/collector.go b/internal/telemetry/collector.go index 743af47e..494361ce 100644 --- a/internal/telemetry/collector.go +++ b/internal/telemetry/collector.go @@ -121,15 +121,15 @@ func (c *Collector) collect(ctx context.Context) { clusterID := string(kubeSystemNS.UID) - // Get all CozystackBundles - var bundleList cozyv1alpha1.CozystackBundleList + // Get all Bundles + var bundleList cozyv1alpha1.BundleList bundleNameStr := "" bundleEnable := "" bundleDisable := "" oidcEnabled := "false" if err := c.client.List(ctx, &bundleList); err != nil { - logger.Info(fmt.Sprintf("Failed to list CozystackBundles: %v", err)) + logger.Info(fmt.Sprintf("Failed to list Bundles: %v", err)) // Continue with empty bundle data instead of returning } else { // Collect bundle names (sorted alphabetically) diff --git a/packages/core/installer/crds/cozystack.io_cozystackresourcedefinitions.yaml b/packages/core/installer/crds/cozystack.io_applicationdefinitions.yaml similarity index 97% rename from packages/core/installer/crds/cozystack.io_cozystackresourcedefinitions.yaml rename to packages/core/installer/crds/cozystack.io_applicationdefinitions.yaml index fcf8fd72..0aa8f7aa 100644 --- a/packages/core/installer/crds/cozystack.io_cozystackresourcedefinitions.yaml +++ b/packages/core/installer/crds/cozystack.io_applicationdefinitions.yaml @@ -4,20 +4,22 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.16.4 - name: cozystackresourcedefinitions.cozystack.io + name: applicationdefinitions.cozystack.io spec: group: cozystack.io names: - kind: CozystackResourceDefinition - listKind: CozystackResourceDefinitionList - plural: cozystackresourcedefinitions - singular: cozystackresourcedefinition + kind: ApplicationDefinition + listKind: ApplicationDefinitionList + plural: applicationdefinitions + shortNames: + - appdef + singular: applicationdefinition scope: Cluster versions: - name: v1alpha1 schema: openAPIV3Schema: - description: CozystackResourceDefinition is the Schema for the cozystackresourcedefinitions + description: ApplicationDefinition is the Schema for the applicationdefinitions API properties: apiVersion: @@ -136,7 +138,7 @@ spec: hidden from the user, regardless of the matches in the include array. items: description: |- - CozystackResourceDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support. + ApplicationDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support. A resource matches this selector only if it satisfies ALL criteria: - Label selector conditions (matchExpressions and matchLabels) - AND has a name that matches one of the names in resourceNames (if specified) @@ -218,7 +220,7 @@ spec: as a tenant resource and is visible to users. items: description: |- - CozystackResourceDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support. + ApplicationDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support. A resource matches this selector only if it satisfies ALL criteria: - Label selector conditions (matchExpressions and matchLabels) - AND has a name that matches one of the names in resourceNames (if specified) @@ -381,7 +383,7 @@ spec: hidden from the user, regardless of the matches in the include array. items: description: |- - CozystackResourceDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support. + ApplicationDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support. A resource matches this selector only if it satisfies ALL criteria: - Label selector conditions (matchExpressions and matchLabels) - AND has a name that matches one of the names in resourceNames (if specified) @@ -463,7 +465,7 @@ spec: as a tenant resource and is visible to users. items: description: |- - CozystackResourceDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support. + ApplicationDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support. A resource matches this selector only if it satisfies ALL criteria: - Label selector conditions (matchExpressions and matchLabels) - AND has a name that matches one of the names in resourceNames (if specified) @@ -548,7 +550,7 @@ spec: hidden from the user, regardless of the matches in the include array. items: description: |- - CozystackResourceDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support. + ApplicationDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support. A resource matches this selector only if it satisfies ALL criteria: - Label selector conditions (matchExpressions and matchLabels) - AND has a name that matches one of the names in resourceNames (if specified) @@ -630,7 +632,7 @@ spec: as a tenant resource and is visible to users. items: description: |- - CozystackResourceDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support. + ApplicationDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support. A resource matches this selector only if it satisfies ALL criteria: - Label selector conditions (matchExpressions and matchLabels) - AND has a name that matches one of the names in resourceNames (if specified) diff --git a/packages/core/installer/crds/cozystack.io_cozystackbundles.yaml b/packages/core/installer/crds/cozystack.io_bundles.yaml similarity index 96% rename from packages/core/installer/crds/cozystack.io_cozystackbundles.yaml rename to packages/core/installer/crds/cozystack.io_bundles.yaml index 54b8caac..57ba017d 100644 --- a/packages/core/installer/crds/cozystack.io_cozystackbundles.yaml +++ b/packages/core/installer/crds/cozystack.io_bundles.yaml @@ -4,20 +4,22 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.16.4 - name: cozystackbundles.cozystack.io + name: bundles.cozystack.io spec: group: cozystack.io names: - kind: CozystackBundle - listKind: CozystackBundleList - plural: cozystackbundles - singular: cozystackbundle + kind: Bundle + listKind: BundleList + plural: bundles + shortNames: + - bundle + singular: bundle scope: Cluster versions: - name: v1alpha1 schema: openAPIV3Schema: - description: CozystackBundle is the Schema for the cozystackbundles API + description: Bundle is the Schema for the bundles API properties: apiVersion: description: |- @@ -37,12 +39,12 @@ spec: metadata: type: object spec: - description: CozystackBundleSpec defines the desired state of CozystackBundle + description: BundleSpec defines the desired state of Bundle properties: artifacts: description: |- Artifacts is a list of Helm charts that will be built as ExternalArtifacts - These artifacts can be referenced by CozystackResourceDefinitions + These artifacts can be referenced by ApplicationDefinitions items: description: BundleArtifact defines a Helm chart artifact that will be built as ExternalArtifact diff --git a/packages/core/installer/crds/cozystack.io_cozystackplatforms.yaml b/packages/core/installer/crds/cozystack.io_platforms.yaml similarity index 89% rename from packages/core/installer/crds/cozystack.io_cozystackplatforms.yaml rename to packages/core/installer/crds/cozystack.io_platforms.yaml index 1d54c233..74364b34 100644 --- a/packages/core/installer/crds/cozystack.io_cozystackplatforms.yaml +++ b/packages/core/installer/crds/cozystack.io_platforms.yaml @@ -4,20 +4,22 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.16.4 - name: cozystackplatforms.cozystack.io + name: platforms.cozystack.io spec: group: cozystack.io names: - kind: CozystackPlatform - listKind: CozystackPlatformList - plural: cozystackplatforms - singular: cozystackplatform + kind: Platform + listKind: PlatformList + plural: platforms + shortNames: + - platform + singular: platform scope: Cluster versions: - name: v1alpha1 schema: openAPIV3Schema: - description: CozystackPlatform is the Schema for the cozystackplatforms API + description: Platform is the Schema for the platforms API properties: apiVersion: description: |- @@ -37,7 +39,7 @@ spec: metadata: type: object spec: - description: CozystackPlatformSpec defines the desired state of CozystackPlatform + description: PlatformSpec defines the desired state of Platform properties: basePath: description: |- diff --git a/packages/core/installer/example/platform.yaml b/packages/core/installer/example/platform.yaml index 7b0d51da..1982cbe6 100644 --- a/packages/core/installer/example/platform.yaml +++ b/packages/core/installer/example/platform.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackPlatform +kind: Platform metadata: name: cozystack-platform spec: diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index 45585e76..8572f41b 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,5 +1,5 @@ cozystackOperator: - image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:ede9a0a6b7b1ad137ef1f75c1e954115da8ebdab110e47d920ae01ac62be93ec + image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:5b25b3eb9bd85ba8843fe4f36af555cd0200d581f65ca711f9ccdd552e1aa258 disableTelemetry: false cozystackVersion: "latest" - packagesDigest: sha256:da9d726066e8ee884210f01df4d59a29560ecda596cc01fba340c0f21ae36d7a + packagesDigest: sha256:e89ff0473df1178e0c8a77dd6898892ca82d455c4d20e4afa5f649edf2d72218 diff --git a/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml b/packages/core/platform/bundles/iaas/applicationdefinitions/bucket.yaml similarity index 98% rename from packages/core/platform/bundles/iaas/cozyrds/bucket.yaml rename to packages/core/platform/bundles/iaas/applicationdefinitions/bucket.yaml index 72c408d8..9ed4a9c7 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/bucket.yaml +++ b/packages/core/platform/bundles/iaas/applicationdefinitions/bucket.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: bucket spec: diff --git a/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml b/packages/core/platform/bundles/iaas/applicationdefinitions/kubernetes.yaml similarity index 99% rename from packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml rename to packages/core/platform/bundles/iaas/applicationdefinitions/kubernetes.yaml index 279075cf..59a24e78 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/kubernetes.yaml +++ b/packages/core/platform/bundles/iaas/applicationdefinitions/kubernetes.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: kubernetes spec: diff --git a/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml b/packages/core/platform/bundles/iaas/applicationdefinitions/virtual-machine.yaml similarity index 99% rename from packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml rename to packages/core/platform/bundles/iaas/applicationdefinitions/virtual-machine.yaml index 6c75685e..0b3c48f8 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/virtual-machine.yaml +++ b/packages/core/platform/bundles/iaas/applicationdefinitions/virtual-machine.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: virtual-machine spec: diff --git a/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml b/packages/core/platform/bundles/iaas/applicationdefinitions/virtualprivatecloud.yaml similarity index 98% rename from packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml rename to packages/core/platform/bundles/iaas/applicationdefinitions/virtualprivatecloud.yaml index 987fd00c..8a9e1be1 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/virtualprivatecloud.yaml +++ b/packages/core/platform/bundles/iaas/applicationdefinitions/virtualprivatecloud.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: virtualprivatecloud spec: diff --git a/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml b/packages/core/platform/bundles/iaas/applicationdefinitions/vm-disk.yaml similarity index 99% rename from packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml rename to packages/core/platform/bundles/iaas/applicationdefinitions/vm-disk.yaml index e10b2f69..1cf255f0 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/vm-disk.yaml +++ b/packages/core/platform/bundles/iaas/applicationdefinitions/vm-disk.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: vm-disk spec: diff --git a/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml b/packages/core/platform/bundles/iaas/applicationdefinitions/vm-instance.yaml similarity index 99% rename from packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml rename to packages/core/platform/bundles/iaas/applicationdefinitions/vm-instance.yaml index d5dd2434..34b06c1b 100644 --- a/packages/core/platform/bundles/iaas/cozyrds/vm-instance.yaml +++ b/packages/core/platform/bundles/iaas/applicationdefinitions/vm-instance.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: vm-instance spec: diff --git a/packages/core/platform/bundles/iaas/bundle.yaml b/packages/core/platform/bundles/iaas/bundle.yaml index 2972efc1..a5bfc3aa 100644 --- a/packages/core/platform/bundles/iaas/bundle.yaml +++ b/packages/core/platform/bundles/iaas/bundle.yaml @@ -5,7 +5,7 @@ {{- end }} apiVersion: cozystack.io/v1alpha1 -kind: CozystackBundle +kind: Bundle metadata: name: cozystack-iaas spec: diff --git a/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml b/packages/core/platform/bundles/naas/applicationdefinitions/http-cache.yaml similarity index 99% rename from packages/core/platform/bundles/naas/cozyrds/http-cache.yaml rename to packages/core/platform/bundles/naas/applicationdefinitions/http-cache.yaml index 1bbd091d..788d7a06 100644 --- a/packages/core/platform/bundles/naas/cozyrds/http-cache.yaml +++ b/packages/core/platform/bundles/naas/applicationdefinitions/http-cache.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: http-cache spec: diff --git a/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml b/packages/core/platform/bundles/naas/applicationdefinitions/tcp-balancer.yaml similarity index 99% rename from packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml rename to packages/core/platform/bundles/naas/applicationdefinitions/tcp-balancer.yaml index e308a817..e6e7ca81 100644 --- a/packages/core/platform/bundles/naas/cozyrds/tcp-balancer.yaml +++ b/packages/core/platform/bundles/naas/applicationdefinitions/tcp-balancer.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: tcp-balancer spec: diff --git a/packages/core/platform/bundles/naas/cozyrds/vpn.yaml b/packages/core/platform/bundles/naas/applicationdefinitions/vpn.yaml similarity index 99% rename from packages/core/platform/bundles/naas/cozyrds/vpn.yaml rename to packages/core/platform/bundles/naas/applicationdefinitions/vpn.yaml index 892ca9b7..b1bff7bc 100644 --- a/packages/core/platform/bundles/naas/cozyrds/vpn.yaml +++ b/packages/core/platform/bundles/naas/applicationdefinitions/vpn.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: vpn spec: diff --git a/packages/core/platform/bundles/naas/bundle.yaml b/packages/core/platform/bundles/naas/bundle.yaml index a208c4be..0a5f86c6 100644 --- a/packages/core/platform/bundles/naas/bundle.yaml +++ b/packages/core/platform/bundles/naas/bundle.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackBundle +kind: Bundle metadata: name: cozystack-naas spec: diff --git a/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml b/packages/core/platform/bundles/paas/applicationdefinitions/clickhouse.yaml similarity index 99% rename from packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml rename to packages/core/platform/bundles/paas/applicationdefinitions/clickhouse.yaml index 0c21c5b7..746ceee7 100644 --- a/packages/core/platform/bundles/paas/cozyrds/clickhouse.yaml +++ b/packages/core/platform/bundles/paas/applicationdefinitions/clickhouse.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: clickhouse spec: diff --git a/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml b/packages/core/platform/bundles/paas/applicationdefinitions/ferretdb.yaml similarity index 99% rename from packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml rename to packages/core/platform/bundles/paas/applicationdefinitions/ferretdb.yaml index d8be5c52..31982d2c 100644 --- a/packages/core/platform/bundles/paas/cozyrds/ferretdb.yaml +++ b/packages/core/platform/bundles/paas/applicationdefinitions/ferretdb.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: ferretdb spec: diff --git a/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml b/packages/core/platform/bundles/paas/applicationdefinitions/foundationdb.yaml similarity index 99% rename from packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml rename to packages/core/platform/bundles/paas/applicationdefinitions/foundationdb.yaml index 49c1f25c..9f2b6c67 100644 --- a/packages/core/platform/bundles/paas/cozyrds/foundationdb.yaml +++ b/packages/core/platform/bundles/paas/applicationdefinitions/foundationdb.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: foundationdb spec: diff --git a/packages/core/platform/bundles/paas/cozyrds/kafka.yaml b/packages/core/platform/bundles/paas/applicationdefinitions/kafka.yaml similarity index 99% rename from packages/core/platform/bundles/paas/cozyrds/kafka.yaml rename to packages/core/platform/bundles/paas/applicationdefinitions/kafka.yaml index ebfe8e19..b369afae 100644 --- a/packages/core/platform/bundles/paas/cozyrds/kafka.yaml +++ b/packages/core/platform/bundles/paas/applicationdefinitions/kafka.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: kafka spec: diff --git a/packages/core/platform/bundles/paas/cozyrds/mysql.yaml b/packages/core/platform/bundles/paas/applicationdefinitions/mysql.yaml similarity index 99% rename from packages/core/platform/bundles/paas/cozyrds/mysql.yaml rename to packages/core/platform/bundles/paas/applicationdefinitions/mysql.yaml index 957070b9..ac2b0628 100644 --- a/packages/core/platform/bundles/paas/cozyrds/mysql.yaml +++ b/packages/core/platform/bundles/paas/applicationdefinitions/mysql.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: mysql spec: diff --git a/packages/core/platform/bundles/paas/cozyrds/nats.yaml b/packages/core/platform/bundles/paas/applicationdefinitions/nats.yaml similarity index 99% rename from packages/core/platform/bundles/paas/cozyrds/nats.yaml rename to packages/core/platform/bundles/paas/applicationdefinitions/nats.yaml index a90bdb8a..8dbe01e8 100644 --- a/packages/core/platform/bundles/paas/cozyrds/nats.yaml +++ b/packages/core/platform/bundles/paas/applicationdefinitions/nats.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: nats spec: diff --git a/packages/core/platform/bundles/paas/cozyrds/postgres.yaml b/packages/core/platform/bundles/paas/applicationdefinitions/postgres.yaml similarity index 99% rename from packages/core/platform/bundles/paas/cozyrds/postgres.yaml rename to packages/core/platform/bundles/paas/applicationdefinitions/postgres.yaml index 1c7583f8..f213b21c 100644 --- a/packages/core/platform/bundles/paas/cozyrds/postgres.yaml +++ b/packages/core/platform/bundles/paas/applicationdefinitions/postgres.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: postgres spec: diff --git a/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml b/packages/core/platform/bundles/paas/applicationdefinitions/rabbitmq.yaml similarity index 99% rename from packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml rename to packages/core/platform/bundles/paas/applicationdefinitions/rabbitmq.yaml index c521084c..3046a089 100644 --- a/packages/core/platform/bundles/paas/cozyrds/rabbitmq.yaml +++ b/packages/core/platform/bundles/paas/applicationdefinitions/rabbitmq.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: rabbitmq spec: diff --git a/packages/core/platform/bundles/paas/cozyrds/redis.yaml b/packages/core/platform/bundles/paas/applicationdefinitions/redis.yaml similarity index 99% rename from packages/core/platform/bundles/paas/cozyrds/redis.yaml rename to packages/core/platform/bundles/paas/applicationdefinitions/redis.yaml index 37c72dd8..27d748e1 100644 --- a/packages/core/platform/bundles/paas/cozyrds/redis.yaml +++ b/packages/core/platform/bundles/paas/applicationdefinitions/redis.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: redis spec: diff --git a/packages/core/platform/bundles/paas/bundle.yaml b/packages/core/platform/bundles/paas/bundle.yaml index ea661f42..ac31d462 100644 --- a/packages/core/platform/bundles/paas/bundle.yaml +++ b/packages/core/platform/bundles/paas/bundle.yaml @@ -1,7 +1,7 @@ {{- $clusterDomain := .Values.networking.clusterDomain | default "cozy.local" }} apiVersion: cozystack.io/v1alpha1 -kind: CozystackBundle +kind: Bundle metadata: name: cozystack-paas spec: diff --git a/packages/core/platform/bundles/system/cozyrds/bootbox.yaml b/packages/core/platform/bundles/system/applicationdefinitions/bootbox.yaml similarity index 99% rename from packages/core/platform/bundles/system/cozyrds/bootbox.yaml rename to packages/core/platform/bundles/system/applicationdefinitions/bootbox.yaml index 2ed082bf..7611944b 100644 --- a/packages/core/platform/bundles/system/cozyrds/bootbox.yaml +++ b/packages/core/platform/bundles/system/applicationdefinitions/bootbox.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: bootbox spec: diff --git a/packages/core/platform/bundles/system/cozyrds/etcd.yaml b/packages/core/platform/bundles/system/applicationdefinitions/etcd.yaml similarity index 99% rename from packages/core/platform/bundles/system/cozyrds/etcd.yaml rename to packages/core/platform/bundles/system/applicationdefinitions/etcd.yaml index c8f1afb1..ab30e50b 100644 --- a/packages/core/platform/bundles/system/cozyrds/etcd.yaml +++ b/packages/core/platform/bundles/system/applicationdefinitions/etcd.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: etcd spec: diff --git a/packages/core/platform/bundles/system/cozyrds/info.yaml b/packages/core/platform/bundles/system/applicationdefinitions/info.yaml similarity index 98% rename from packages/core/platform/bundles/system/cozyrds/info.yaml rename to packages/core/platform/bundles/system/applicationdefinitions/info.yaml index d74d703c..8e53ea46 100644 --- a/packages/core/platform/bundles/system/cozyrds/info.yaml +++ b/packages/core/platform/bundles/system/applicationdefinitions/info.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: info spec: diff --git a/packages/core/platform/bundles/system/cozyrds/ingress.yaml b/packages/core/platform/bundles/system/applicationdefinitions/ingress.yaml similarity index 99% rename from packages/core/platform/bundles/system/cozyrds/ingress.yaml rename to packages/core/platform/bundles/system/applicationdefinitions/ingress.yaml index effaeb74..9f720eab 100644 --- a/packages/core/platform/bundles/system/cozyrds/ingress.yaml +++ b/packages/core/platform/bundles/system/applicationdefinitions/ingress.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: ingress spec: diff --git a/packages/core/platform/bundles/system/cozyrds/monitoring.yaml b/packages/core/platform/bundles/system/applicationdefinitions/monitoring.yaml similarity index 99% rename from packages/core/platform/bundles/system/cozyrds/monitoring.yaml rename to packages/core/platform/bundles/system/applicationdefinitions/monitoring.yaml index d946fb06..3e9aa156 100644 --- a/packages/core/platform/bundles/system/cozyrds/monitoring.yaml +++ b/packages/core/platform/bundles/system/applicationdefinitions/monitoring.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: monitoring spec: diff --git a/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml b/packages/core/platform/bundles/system/applicationdefinitions/seaweedfs.yaml similarity index 99% rename from packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml rename to packages/core/platform/bundles/system/applicationdefinitions/seaweedfs.yaml index 6568c712..04312f9f 100644 --- a/packages/core/platform/bundles/system/cozyrds/seaweedfs.yaml +++ b/packages/core/platform/bundles/system/applicationdefinitions/seaweedfs.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: seaweedfs spec: diff --git a/packages/core/platform/bundles/system/cozyrds/tenant.yaml b/packages/core/platform/bundles/system/applicationdefinitions/tenant.yaml similarity index 99% rename from packages/core/platform/bundles/system/cozyrds/tenant.yaml rename to packages/core/platform/bundles/system/applicationdefinitions/tenant.yaml index e559790f..a1876ea7 100644 --- a/packages/core/platform/bundles/system/cozyrds/tenant.yaml +++ b/packages/core/platform/bundles/system/applicationdefinitions/tenant.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: CozystackResourceDefinition +kind: ApplicationDefinition metadata: name: tenant spec: diff --git a/packages/core/platform/bundles/system/bundle-full.yaml b/packages/core/platform/bundles/system/bundle-full.yaml index 2e0ea0e1..df22abdf 100644 --- a/packages/core/platform/bundles/system/bundle-full.yaml +++ b/packages/core/platform/bundles/system/bundle-full.yaml @@ -6,7 +6,7 @@ {{- $oidcEnabled := .Values.authentication.oidc.enabled | default false }} apiVersion: cozystack.io/v1alpha1 -kind: CozystackBundle +kind: Bundle metadata: name: cozystack-system spec: diff --git a/packages/core/platform/bundles/system/bundle-hosted.yaml b/packages/core/platform/bundles/system/bundle-hosted.yaml index dc3408ac..08459df6 100644 --- a/packages/core/platform/bundles/system/bundle-hosted.yaml +++ b/packages/core/platform/bundles/system/bundle-hosted.yaml @@ -6,7 +6,7 @@ {{- $oidcEnabled := .Values.authentication.oidc.enabled | default false }} apiVersion: cozystack.io/v1alpha1 -kind: CozystackBundle +kind: Bundle metadata: name: cozystack-system spec: diff --git a/packages/core/platform/bundles/system/bundle-minimal.yaml b/packages/core/platform/bundles/system/bundle-minimal.yaml index 791131f9..5383e4da 100644 --- a/packages/core/platform/bundles/system/bundle-minimal.yaml +++ b/packages/core/platform/bundles/system/bundle-minimal.yaml @@ -5,7 +5,7 @@ {{- $oidcEnabled := .Values.authentication.oidc.enabled | default false }} apiVersion: cozystack.io/v1alpha1 -kind: CozystackBundle +kind: Bundle metadata: name: cozystack-minimal spec: diff --git a/packages/core/platform/templates/_helpers.tpl b/packages/core/platform/templates/_helpers.tpl index fb1ba54d..38c84168 100644 --- a/packages/core/platform/templates/_helpers.tpl +++ b/packages/core/platform/templates/_helpers.tpl @@ -76,7 +76,7 @@ Usage: {{ include "cozystack.render-file" (list . "bundles/system/bundle-full.ya {{/* Render all files matching a glob pattern with template processing -Usage: {{ include "cozystack.render-glob" (list . "bundles/system/cozyrds/*.yaml") }} +Usage: {{ include "cozystack.render-glob" (list . "bundles/system/applicationdefinitions/*.yaml") }} */}} {{- define "cozystack.render-glob" -}} {{- $ := index . 0 }} diff --git a/packages/core/platform/templates/applicationdefinitions.yaml b/packages/core/platform/templates/applicationdefinitions.yaml new file mode 100644 index 00000000..c35dbd82 --- /dev/null +++ b/packages/core/platform/templates/applicationdefinitions.yaml @@ -0,0 +1,15 @@ +{{- $systemBundleType := .Values.bundles.system.type | default "full" }} + +{{- if or (ne $systemBundleType "full") (ne $systemBundleType "hosted") }} +{{ include "cozystack.render-glob" (list . "bundles/system/applicationdefinitions/*.yaml") }} +{{- end }} + +{{- if .Values.bundles.iaas.enabled }} +{{ include "cozystack.render-glob" (list . "bundles/iaas/applicationdefinitions/*.yaml") }} +{{- end }} +{{- if .Values.bundles.paas.enabled }} +{{ include "cozystack.render-glob" (list . "bundles/paas/applicationdefinitions/*.yaml") }} +{{- end }} +{{- if .Values.bundles.naas.enabled }} +{{ include "cozystack.render-glob" (list . "bundles/naas/applicationdefinitions/*.yaml") }} +{{- end }} diff --git a/packages/core/platform/templates/cozyrds.yaml b/packages/core/platform/templates/cozyrds.yaml index e838bd45..c35dbd82 100644 --- a/packages/core/platform/templates/cozyrds.yaml +++ b/packages/core/platform/templates/cozyrds.yaml @@ -1,15 +1,15 @@ {{- $systemBundleType := .Values.bundles.system.type | default "full" }} {{- if or (ne $systemBundleType "full") (ne $systemBundleType "hosted") }} -{{ include "cozystack.render-glob" (list . "bundles/system/cozyrds/*.yaml") }} +{{ include "cozystack.render-glob" (list . "bundles/system/applicationdefinitions/*.yaml") }} {{- end }} {{- if .Values.bundles.iaas.enabled }} -{{ include "cozystack.render-glob" (list . "bundles/iaas/cozyrds/*.yaml") }} +{{ include "cozystack.render-glob" (list . "bundles/iaas/applicationdefinitions/*.yaml") }} {{- end }} {{- if .Values.bundles.paas.enabled }} -{{ include "cozystack.render-glob" (list . "bundles/paas/cozyrds/*.yaml") }} +{{ include "cozystack.render-glob" (list . "bundles/paas/applicationdefinitions/*.yaml") }} {{- end }} {{- if .Values.bundles.naas.enabled }} -{{ include "cozystack.render-glob" (list . "bundles/naas/cozyrds/*.yaml") }} +{{ include "cozystack.render-glob" (list . "bundles/naas/applicationdefinitions/*.yaml") }} {{- end }} diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index 8ffc37f5..4314cab1 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,5 +1,5 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:latest@sha256:fa43ce97a77d4f2e4d877a1b525dabc91ec4d8a8b865c55d9d470992e9027405 + image: ghcr.io/cozystack/cozystack/cozystack-api:latest@sha256:19ea2a89dde4f6166231703317de7687be5b140d94f609f71e24b6ffcc46e0af localK8sAPIEndpoint: enabled: true replicas: 2 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index f6d5cdbd..14b594ed 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,4 +1,4 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:latest@sha256:196c769a58423f108ffca1760805f022155c63accab38c6a5bd736c6008b8b54 + image: ghcr.io/cozystack/cozystack/cozystack-controller:latest@sha256:b525651506d8f57cf8d81b733e444cb282d03e9e20f6f257515fc87e18484b2f debug: false cozystackAPIKind: "DaemonSet" diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index 9cf4b533..a49be0e9 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,5 +1,5 @@ lineageControllerWebhook: - image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:latest@sha256:4e60a1b13a2a28792ef1a5c4d7875dca2c869e09d7360f0766a7485937fe7977 + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:latest@sha256:452f8ab78ba28f5d3cf1631296bb911320a48e7e662046cb921b5ec9c95ef889 debug: false localK8sAPIEndpoint: enabled: true diff --git a/pkg/cmd/server/start.go b/pkg/cmd/server/start.go index 764c2fab..1f334cb9 100644 --- a/pkg/cmd/server/start.go +++ b/pkg/cmd/server/start.go @@ -128,7 +128,7 @@ func (o *CozyServerOptions) Complete() error { return fmt.Errorf("client initialization failed: %w", err) } - crdList := &v1alpha1.CozystackResourceDefinitionList{} + crdList := &v1alpha1.ApplicationDefinitionList{} // Retry with exponential backoff for at least 30 minutes const maxRetryDuration = 30 * time.Minute @@ -146,11 +146,11 @@ func (o *CozyServerOptions) Complete() error { // Check if we've exceeded the maximum retry duration if time.Since(startTime) >= maxRetryDuration { - return fmt.Errorf("failed to list CozystackResourceDefinitions after %v: %w", maxRetryDuration, err) + return fmt.Errorf("failed to list ApplicationDefinitions after %v: %w", maxRetryDuration, err) } // Log the error and wait before retrying - fmt.Printf("Failed to list CozystackResourceDefinitions (retrying in %v): %v\n", delay, err) + fmt.Printf("Failed to list ApplicationDefinitions (retrying in %v): %v\n", delay, err) time.Sleep(delay) delay = time.Duration(float64(delay) * 1.5) diff --git a/pkg/registry/apps/application/rest.go b/pkg/registry/apps/application/rest.go index 0081265d..4e96714f 100644 --- a/pkg/registry/apps/application/rest.go +++ b/pkg/registry/apps/application/rest.go @@ -1036,11 +1036,11 @@ func filterPrefixedMap(original map[string]string, prefix string) map[string]str return processed } -// getCozystackResourceDefinition retrieves the CozystackResourceDefinition for this resource kind -func (r *REST) getCozystackResourceDefinition(ctx context.Context) (*cozyv1alpha1.CozystackResourceDefinition, error) { - crdList := &cozyv1alpha1.CozystackResourceDefinitionList{} +// getApplicationDefinition retrieves the ApplicationDefinition for this resource kind +func (r *REST) getApplicationDefinition(ctx context.Context) (*cozyv1alpha1.ApplicationDefinition, error) { + crdList := &cozyv1alpha1.ApplicationDefinitionList{} if err := r.c.List(ctx, crdList); err != nil { - return nil, fmt.Errorf("failed to list CozystackResourceDefinitions: %w", err) + return nil, fmt.Errorf("failed to list ApplicationDefinitions: %w", err) } for i := range crdList.Items { @@ -1050,7 +1050,7 @@ func (r *REST) getCozystackResourceDefinition(ctx context.Context) (*cozyv1alpha } } - return nil, fmt.Errorf("CozystackResourceDefinition not found for kind %s", r.kindName) + return nil, fmt.Errorf("ApplicationDefinition not found for kind %s", r.kindName) } // ConvertHelmReleaseToApplication converts a HelmRelease to an Application @@ -1171,10 +1171,10 @@ func (r *REST) convertApplicationToHelmRelease(app *appsv1alpha1.Application) (* return nil, err } - // Get CozystackResourceDefinition to extract default values - crd, err := r.getCozystackResourceDefinition(ctx) + // Get ApplicationDefinition to extract default values + crd, err := r.getApplicationDefinition(ctx) if err != nil { - klog.V(6).Infof("Could not find CozystackResourceDefinition for kind %s: %v", r.kindName, err) + klog.V(6).Infof("Could not find ApplicationDefinition for kind %s: %v", r.kindName, err) // Continue without default values if CRD not found crd = nil } From 51d000158926010b492d751e8ff74bd7890545d0 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 25 Nov 2025 17:40:42 +0100 Subject: [PATCH 40/46] move Makefiles to hack Signed-off-by: Andrei Kvapil --- {scripts => hack}/common-envs.mk | 0 {scripts => hack}/package.mk | 0 packages/apps/Makefile | 2 +- packages/apps/bucket/Makefile | 2 +- packages/apps/clickhouse/Makefile | 4 ++-- packages/apps/ferretdb/Makefile | 2 +- packages/apps/foundationdb/Makefile | 2 +- packages/apps/http-cache/Makefile | 4 ++-- packages/apps/kafka/Makefile | 2 +- packages/apps/kubernetes/Makefile | 4 ++-- packages/apps/mysql/Makefile | 4 ++-- packages/apps/nats/Makefile | 2 +- packages/apps/postgres/Makefile | 2 +- packages/apps/rabbitmq/Makefile | 2 +- packages/apps/redis/Makefile | 2 +- packages/apps/tcp-balancer/Makefile | 2 +- packages/apps/tenant/Makefile | 2 +- packages/apps/virtual-machine/Makefile | 2 +- packages/apps/vm-disk/Makefile | 2 +- packages/apps/vm-instance/Makefile | 2 +- packages/apps/vpc/Makefile | 2 +- packages/apps/vpn/Makefile | 2 +- packages/core/installer/Makefile | 4 ++-- packages/core/platform/Makefile | 4 ++-- packages/core/talos/Makefile | 2 +- packages/core/testing/Makefile | 2 +- packages/extra/Makefile | 2 +- packages/extra/bootbox/Makefile | 2 +- packages/extra/etcd/Makefile | 2 +- packages/extra/info/Makefile | 2 +- packages/extra/ingress/Makefile | 2 +- packages/extra/monitoring/Makefile | 4 ++-- packages/extra/seaweedfs/Makefile | 2 +- packages/library/Makefile | 2 +- packages/library/cozy-lib/Makefile | 4 ++-- packages/system/Makefile | 2 +- packages/system/bootbox/Makefile | 2 +- packages/system/bucket/Makefile | 4 ++-- packages/system/capi-operator/Makefile | 2 +- packages/system/capi-providers-bootstrap/Makefile | 2 +- packages/system/capi-providers-core/Makefile | 2 +- packages/system/capi-providers-cpprovider/Makefile | 2 +- packages/system/capi-providers-infraprovider/Makefile | 2 +- packages/system/cert-manager-crds/Makefile | 2 +- packages/system/cert-manager-issuers/Makefile | 2 +- packages/system/cert-manager/Makefile | 2 +- packages/system/cilium-networkpolicy/Makefile | 4 ++-- packages/system/cilium/Makefile | 4 ++-- packages/system/clickhouse-operator/Makefile | 2 +- packages/system/coredns/Makefile | 2 +- packages/system/cozy-proxy/Makefile | 4 ++-- packages/system/cozystack-api/Makefile | 4 ++-- packages/system/cozystack-controller/Makefile | 4 ++-- packages/system/dashboard/Makefile | 4 ++-- packages/system/etcd-operator/Makefile | 2 +- packages/system/external-dns/Makefile | 2 +- packages/system/external-secrets-operator/Makefile | 2 +- packages/system/fluxcd-operator/Makefile | 2 +- packages/system/fluxcd/Makefile | 2 +- packages/system/foundationdb-operator/Makefile | 2 +- packages/system/gateway-api-crds/Makefile | 2 +- packages/system/goldpinger/Makefile | 2 +- packages/system/gpu-operator/Makefile | 4 ++-- packages/system/grafana-operator/Makefile | 4 ++-- packages/system/hetzner-robotlb/Makefile | 2 +- packages/system/ingress-nginx/Makefile | 2 +- packages/system/kafka-operator/Makefile | 2 +- packages/system/kamaji/Makefile | 4 ++-- packages/system/keycloak-configure/Makefile | 4 ++-- packages/system/keycloak-operator/Makefile | 4 ++-- packages/system/keycloak/Makefile | 4 ++-- packages/system/kubeovn-plunger/Makefile | 4 ++-- packages/system/kubeovn-webhook/Makefile | 4 ++-- packages/system/kubeovn/Makefile | 4 ++-- packages/system/kubevirt-cdi-operator/Makefile | 2 +- packages/system/kubevirt-cdi/Makefile | 2 +- packages/system/kubevirt-instancetypes/Makefile | 2 +- packages/system/kubevirt-operator/Makefile | 2 +- packages/system/kubevirt/Makefile | 2 +- packages/system/lineage-controller-webhook/Makefile | 4 ++-- packages/system/linstor/Makefile | 2 +- packages/system/mariadb-operator/Makefile | 2 +- packages/system/metallb/Makefile | 4 ++-- packages/system/monitoring-agents/Makefile | 2 +- packages/system/multus/Makefile | 4 ++-- packages/system/nats/Makefile | 2 +- packages/system/nfs-driver/Makefile | 4 ++-- packages/system/objectstorage-controller/Makefile | 4 ++-- packages/system/piraeus-operator/Makefile | 2 +- packages/system/postgres-operator/Makefile | 2 +- packages/system/rabbitmq-operator/Makefile | 2 +- packages/system/redis-operator/Makefile | 4 ++-- packages/system/reloader/Makefile | 2 +- packages/system/seaweedfs/Makefile | 4 ++-- packages/system/snapshot-controller/Makefile | 2 +- packages/system/telepresence/Makefile | 2 +- packages/system/velero/Makefile | 2 +- packages/system/vertical-pod-autoscaler-crds/Makefile | 2 +- packages/system/vertical-pod-autoscaler/Makefile | 2 +- packages/system/victoria-metrics-operator/Makefile | 2 +- packages/system/vsnap-crd/Makefile | 2 +- 101 files changed, 130 insertions(+), 130 deletions(-) rename {scripts => hack}/common-envs.mk (100%) rename {scripts => hack}/package.mk (100%) diff --git a/scripts/common-envs.mk b/hack/common-envs.mk similarity index 100% rename from scripts/common-envs.mk rename to hack/common-envs.mk diff --git a/scripts/package.mk b/hack/package.mk similarity index 100% rename from scripts/package.mk rename to hack/package.mk diff --git a/packages/apps/Makefile b/packages/apps/Makefile index 7338318d..59e3e61f 100644 --- a/packages/apps/Makefile +++ b/packages/apps/Makefile @@ -1,7 +1,7 @@ OUT=../../_out/repos/apps CHARTS := $(shell find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}') -include ../../scripts/common-envs.mk +include ../../hack/common-envs.mk 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 diff --git a/packages/apps/bucket/Makefile b/packages/apps/bucket/Makefile index d448d0c0..27cd199b 100644 --- a/packages/apps/bucket/Makefile +++ b/packages/apps/bucket/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/apps/clickhouse/Makefile b/packages/apps/clickhouse/Makefile index 44ac851f..2c77add9 100644 --- a/packages/apps/clickhouse/Makefile +++ b/packages/apps/clickhouse/Makefile @@ -1,7 +1,7 @@ CLICKHOUSE_BACKUP_TAG = $(shell awk '$$0 ~ /^version:/ {print $$2}' Chart.yaml) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/apps/ferretdb/Makefile b/packages/apps/ferretdb/Makefile index bd52fb05..40b7423f 100644 --- a/packages/apps/ferretdb/Makefile +++ b/packages/apps/ferretdb/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/apps/foundationdb/Makefile b/packages/apps/foundationdb/Makefile index b885e4b1..76c84980 100644 --- a/packages/apps/foundationdb/Makefile +++ b/packages/apps/foundationdb/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md \ No newline at end of file diff --git a/packages/apps/http-cache/Makefile b/packages/apps/http-cache/Makefile index 3237f634..2cc11f87 100644 --- a/packages/apps/http-cache/Makefile +++ b/packages/apps/http-cache/Makefile @@ -1,7 +1,7 @@ NGINX_CACHE_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk image: image-nginx diff --git a/packages/apps/kafka/Makefile b/packages/apps/kafka/Makefile index 0d71076e..2cffdfa7 100644 --- a/packages/apps/kafka/Makefile +++ b/packages/apps/kafka/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk PRESET_ENUM := ["nano","micro","small","medium","large","xlarge","2xlarge"] generate: diff --git a/packages/apps/kubernetes/Makefile b/packages/apps/kubernetes/Makefile index 799a19bc..198929b1 100644 --- a/packages/apps/kubernetes/Makefile +++ b/packages/apps/kubernetes/Makefile @@ -1,8 +1,8 @@ KUBERNETES_VERSION = v1.33 KUBERNETES_PKG_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/apps/mysql/Makefile b/packages/apps/mysql/Makefile index 08c57889..ba94d1b8 100644 --- a/packages/apps/mysql/Makefile +++ b/packages/apps/mysql/Makefile @@ -1,7 +1,7 @@ MARIADB_BACKUP_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/apps/nats/Makefile b/packages/apps/nats/Makefile index 8b1dce9d..d1cfda8e 100644 --- a/packages/apps/nats/Makefile +++ b/packages/apps/nats/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/apps/postgres/Makefile b/packages/apps/postgres/Makefile index 8b1dce9d..d1cfda8e 100644 --- a/packages/apps/postgres/Makefile +++ b/packages/apps/postgres/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/apps/rabbitmq/Makefile b/packages/apps/rabbitmq/Makefile index 8b1dce9d..d1cfda8e 100644 --- a/packages/apps/rabbitmq/Makefile +++ b/packages/apps/rabbitmq/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/apps/redis/Makefile b/packages/apps/redis/Makefile index 8b1dce9d..d1cfda8e 100644 --- a/packages/apps/redis/Makefile +++ b/packages/apps/redis/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/apps/tcp-balancer/Makefile b/packages/apps/tcp-balancer/Makefile index 8b1dce9d..d1cfda8e 100644 --- a/packages/apps/tcp-balancer/Makefile +++ b/packages/apps/tcp-balancer/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/apps/tenant/Makefile b/packages/apps/tenant/Makefile index 8b1dce9d..d1cfda8e 100644 --- a/packages/apps/tenant/Makefile +++ b/packages/apps/tenant/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/apps/virtual-machine/Makefile b/packages/apps/virtual-machine/Makefile index b70ac622..7c482228 100644 --- a/packages/apps/virtual-machine/Makefile +++ b/packages/apps/virtual-machine/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/apps/vm-disk/Makefile b/packages/apps/vm-disk/Makefile index 8b1dce9d..d1cfda8e 100644 --- a/packages/apps/vm-disk/Makefile +++ b/packages/apps/vm-disk/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/apps/vm-instance/Makefile b/packages/apps/vm-instance/Makefile index 105ca7db..3b6d471d 100644 --- a/packages/apps/vm-instance/Makefile +++ b/packages/apps/vm-instance/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/apps/vpc/Makefile b/packages/apps/vpc/Makefile index 8807454f..ea4f5d1b 100644 --- a/packages/apps/vpc/Makefile +++ b/packages/apps/vpc/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json diff --git a/packages/apps/vpn/Makefile b/packages/apps/vpn/Makefile index 8b1dce9d..d1cfda8e 100644 --- a/packages/apps/vpn/Makefile +++ b/packages/apps/vpn/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/core/installer/Makefile b/packages/core/installer/Makefile index 1789699c..910fcafb 100644 --- a/packages/core/installer/Makefile +++ b/packages/core/installer/Makefile @@ -1,9 +1,9 @@ NAME=cozystack-operator NAMESPACE=cozy-system -include ../../../scripts/common-envs.mk +include ../../../hack/common-envs.mk -image: pre-checks image-cozystack-operator image-packages update-version +image: pre-checks image-operator image-packages update-version pre-checks: ../../../hack/pre-checks.sh diff --git a/packages/core/platform/Makefile b/packages/core/platform/Makefile index 41b41eb7..4ffc95f2 100644 --- a/packages/core/platform/Makefile +++ b/packages/core/platform/Makefile @@ -1,8 +1,8 @@ NAME=cozystack-platform NAMESPACE=cozy-system -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk image: image-migrations diff --git a/packages/core/talos/Makefile b/packages/core/talos/Makefile index ac89912f..03cea20c 100644 --- a/packages/core/talos/Makefile +++ b/packages/core/talos/Makefile @@ -3,7 +3,7 @@ NAMESPACE=cozy-system TALOS_VERSION=$(shell awk '/^version:/ {print $$2}' images/talos/profiles/installer.yaml) -include ../../../scripts/common-envs.mk +include ../../../hack/common-envs.mk update: hack/gen-profiles.sh diff --git a/packages/core/testing/Makefile b/packages/core/testing/Makefile index f345d155..46705011 100755 --- a/packages/core/testing/Makefile +++ b/packages/core/testing/Makefile @@ -6,7 +6,7 @@ SANDBOX_NAME := cozy-e2e-sandbox-$(shell echo "$$(hostname):$$(pwd)" | sha256sum ROOT_DIR = $(dir $(abspath $(firstword $(MAKEFILE_LIST))/../../..)) -include ../../../scripts/common-envs.mk +include ../../../hack/common-envs.mk help: ## Show this help. diff --git a/packages/extra/Makefile b/packages/extra/Makefile index 75b71a51..01548800 100644 --- a/packages/extra/Makefile +++ b/packages/extra/Makefile @@ -1,7 +1,7 @@ OUT=../../_out/repos/extra CHARTS := $(shell find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}') -include ../../scripts/common-envs.mk +include ../../hack/common-envs.mk 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 diff --git a/packages/extra/bootbox/Makefile b/packages/extra/bootbox/Makefile index d9a1e261..57fa0a77 100644 --- a/packages/extra/bootbox/Makefile +++ b/packages/extra/bootbox/Makefile @@ -1,7 +1,7 @@ NAME=bootbox NAMESPACE=tenant-root -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/extra/etcd/Makefile b/packages/extra/etcd/Makefile index b309346c..f37d6e1e 100644 --- a/packages/extra/etcd/Makefile +++ b/packages/extra/etcd/Makefile @@ -1,6 +1,6 @@ NAME=etcd -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/extra/info/Makefile b/packages/extra/info/Makefile index e09b33a0..02e04d53 100644 --- a/packages/extra/info/Makefile +++ b/packages/extra/info/Makefile @@ -1,6 +1,6 @@ NAME=etcd -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/extra/ingress/Makefile b/packages/extra/ingress/Makefile index 8134cb22..958ce484 100644 --- a/packages/extra/ingress/Makefile +++ b/packages/extra/ingress/Makefile @@ -1,6 +1,6 @@ NAME=ingress -include ../../../scripts/package.mk +include ../../../hack/package.mk update: get-cloudflare-ips diff --git a/packages/extra/monitoring/Makefile b/packages/extra/monitoring/Makefile index b21607ab..1ae213b6 100644 --- a/packages/extra/monitoring/Makefile +++ b/packages/extra/monitoring/Makefile @@ -2,8 +2,8 @@ GRAFANA_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml) NAME=monitoring -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/extra/seaweedfs/Makefile b/packages/extra/seaweedfs/Makefile index be84180b..eaa1b906 100644 --- a/packages/extra/seaweedfs/Makefile +++ b/packages/extra/seaweedfs/Makefile @@ -1,6 +1,6 @@ NAME=seaweedfs -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/library/Makefile b/packages/library/Makefile index e49767ce..b16e31b2 100644 --- a/packages/library/Makefile +++ b/packages/library/Makefile @@ -1,7 +1,7 @@ OUT=../../_out/repos/library CHARTS := $(shell find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}') -include ../../scripts/common-envs.mk +include ../../hack/common-envs.mk 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 diff --git a/packages/library/cozy-lib/Makefile b/packages/library/cozy-lib/Makefile index a4cf622b..2bd53ad8 100644 --- a/packages/library/cozy-lib/Makefile +++ b/packages/library/cozy-lib/Makefile @@ -1,5 +1,5 @@ -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/system/Makefile b/packages/system/Makefile index d0be85f7..bc9346a6 100644 --- a/packages/system/Makefile +++ b/packages/system/Makefile @@ -1,7 +1,7 @@ OUT=../../_out/repos/system CHARTS := $(shell find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}') -include ../../scripts/common-envs.mk +include ../../hack/common-envs.mk fix-charts: find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}' | while read i; do sed -i -e "s/^name: .*/name: cozy-$$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 diff --git a/packages/system/bootbox/Makefile b/packages/system/bootbox/Makefile index ce4e1af0..2e666462 100644 --- a/packages/system/bootbox/Makefile +++ b/packages/system/bootbox/Makefile @@ -1,7 +1,7 @@ export NAME=bootbox export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/bucket/Makefile b/packages/system/bucket/Makefile index d555b71c..87944b28 100644 --- a/packages/system/bucket/Makefile +++ b/packages/system/bucket/Makefile @@ -2,8 +2,8 @@ S3MANAGER_TAG=v0.5.0 export NAME=s3manager-system -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: @echo Nothing to update diff --git a/packages/system/capi-operator/Makefile b/packages/system/capi-operator/Makefile index dc421cee..9349f549 100644 --- a/packages/system/capi-operator/Makefile +++ b/packages/system/capi-operator/Makefile @@ -5,7 +5,7 @@ export REPO_URL=https://kubernetes-sigs.github.io/cluster-api-operator export CHART_NAME=cluster-api-operator export CHART_VERSION=^0.19 -include ../../../scripts/package.mk +include ../../../hack/package.mk update: clean capi-operator-update rm -rf charts/cluster-api-operator/charts/ diff --git a/packages/system/capi-providers-bootstrap/Makefile b/packages/system/capi-providers-bootstrap/Makefile index f588e439..54d8ca8b 100644 --- a/packages/system/capi-providers-bootstrap/Makefile +++ b/packages/system/capi-providers-bootstrap/Makefile @@ -1,4 +1,4 @@ export NAME=capi-providers-bootstrap export NAMESPACE=cozy-cluster-api -include ../../../scripts/package.mk +include ../../../hack/package.mk diff --git a/packages/system/capi-providers-core/Makefile b/packages/system/capi-providers-core/Makefile index a9bae779..f5f038c1 100644 --- a/packages/system/capi-providers-core/Makefile +++ b/packages/system/capi-providers-core/Makefile @@ -1,4 +1,4 @@ export NAME=capi-providers-core export NAMESPACE=cozy-cluster-api -include ../../../scripts/package.mk +include ../../../hack/package.mk diff --git a/packages/system/capi-providers-cpprovider/Makefile b/packages/system/capi-providers-cpprovider/Makefile index 06f0dd6d..caec8d96 100644 --- a/packages/system/capi-providers-cpprovider/Makefile +++ b/packages/system/capi-providers-cpprovider/Makefile @@ -1,4 +1,4 @@ export NAME=capi-providers-cpprovider export NAMESPACE=cozy-cluster-api -include ../../../scripts/package.mk +include ../../../hack/package.mk diff --git a/packages/system/capi-providers-infraprovider/Makefile b/packages/system/capi-providers-infraprovider/Makefile index 8e4423f3..042a4f0e 100644 --- a/packages/system/capi-providers-infraprovider/Makefile +++ b/packages/system/capi-providers-infraprovider/Makefile @@ -1,4 +1,4 @@ export NAME=capi-providers-infraprovider export NAMESPACE=cozy-cluster-api -include ../../../scripts/package.mk +include ../../../hack/package.mk diff --git a/packages/system/cert-manager-crds/Makefile b/packages/system/cert-manager-crds/Makefile index 0d665914..48e5644c 100644 --- a/packages/system/cert-manager-crds/Makefile +++ b/packages/system/cert-manager-crds/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/cert-manager-issuers/Makefile b/packages/system/cert-manager-issuers/Makefile index a7a6ce10..8808dbfd 100644 --- a/packages/system/cert-manager-issuers/Makefile +++ b/packages/system/cert-manager-issuers/Makefile @@ -1,4 +1,4 @@ export NAME=cert-manager-issuers export NAMESPACE=cozy-cert-manager -include ../../../scripts/package.mk +include ../../../hack/package.mk diff --git a/packages/system/cert-manager/Makefile b/packages/system/cert-manager/Makefile index d48ad5be..2d256086 100644 --- a/packages/system/cert-manager/Makefile +++ b/packages/system/cert-manager/Makefile @@ -1,7 +1,7 @@ export NAME=cert-manager export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/cilium-networkpolicy/Makefile b/packages/system/cilium-networkpolicy/Makefile index c81b87e9..a24a54b5 100644 --- a/packages/system/cilium-networkpolicy/Makefile +++ b/packages/system/cilium-networkpolicy/Makefile @@ -1,5 +1,5 @@ export NAME=cilium-networkpolicy export NAMESPACE=cozy-$(NAME) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk diff --git a/packages/system/cilium/Makefile b/packages/system/cilium/Makefile index 269fb285..c22568e9 100644 --- a/packages/system/cilium/Makefile +++ b/packages/system/cilium/Makefile @@ -3,8 +3,8 @@ CILIUM_TAG=$(shell awk '$$1 == "version:" {print $$2}' charts/cilium/Chart.yaml) export NAME=cilium export NAMESPACE=cozy-$(NAME) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/clickhouse-operator/Makefile b/packages/system/clickhouse-operator/Makefile index e821b664..289631d6 100644 --- a/packages/system/clickhouse-operator/Makefile +++ b/packages/system/clickhouse-operator/Makefile @@ -1,7 +1,7 @@ export NAME=clickhouse-operator export NAMESPACE=cozy-clickhouse-operator -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/coredns/Makefile b/packages/system/coredns/Makefile index a610a862..4aca5b38 100644 --- a/packages/system/coredns/Makefile +++ b/packages/system/coredns/Makefile @@ -1,7 +1,7 @@ export NAME=coredns export NAMESPACE=kube-system -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/cozy-proxy/Makefile b/packages/system/cozy-proxy/Makefile index 8f4f6192..c1da95c7 100644 --- a/packages/system/cozy-proxy/Makefile +++ b/packages/system/cozy-proxy/Makefile @@ -1,8 +1,8 @@ NAME=cozy-proxy NAMESPACE=cozy-system -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/cozystack-api/Makefile b/packages/system/cozystack-api/Makefile index a3e0d931..c4e6f459 100644 --- a/packages/system/cozystack-api/Makefile +++ b/packages/system/cozystack-api/Makefile @@ -1,8 +1,8 @@ NAME=cozystack-api NAMESPACE=cozy-system -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk run-local: openssl req -nodes -new -x509 -keyout /tmp/ca.key -out /tmp/ca.crt -subj "/CN=kube-ca" diff --git a/packages/system/cozystack-controller/Makefile b/packages/system/cozystack-controller/Makefile index d7d899ac..117e26df 100644 --- a/packages/system/cozystack-controller/Makefile +++ b/packages/system/cozystack-controller/Makefile @@ -1,8 +1,8 @@ NAME=cozystack-controller NAMESPACE=cozy-system -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk image: image-cozystack-controller diff --git a/packages/system/dashboard/Makefile b/packages/system/dashboard/Makefile index f89cba0d..a9f680a3 100644 --- a/packages/system/dashboard/Makefile +++ b/packages/system/dashboard/Makefile @@ -1,8 +1,8 @@ export NAME=dashboard export NAMESPACE=cozy-$(NAME) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: update-crd update-dockerfiles image: image-openapi-ui image-openapi-ui-k8s-bff image-token-proxy update-tenant-text diff --git a/packages/system/etcd-operator/Makefile b/packages/system/etcd-operator/Makefile index a2154952..54a1edad 100644 --- a/packages/system/etcd-operator/Makefile +++ b/packages/system/etcd-operator/Makefile @@ -1,7 +1,7 @@ export NAME=etcd-operator export NAMESPACE=cozy-${NAME} -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/external-dns/Makefile b/packages/system/external-dns/Makefile index 1ddfa773..5b0197e1 100644 --- a/packages/system/external-dns/Makefile +++ b/packages/system/external-dns/Makefile @@ -1,7 +1,7 @@ export NAME=external-dns export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/external-secrets-operator/Makefile b/packages/system/external-secrets-operator/Makefile index f4d9215d..0e1cd83a 100644 --- a/packages/system/external-secrets-operator/Makefile +++ b/packages/system/external-secrets-operator/Makefile @@ -1,7 +1,7 @@ export NAME=external-secrets-operator export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/fluxcd-operator/Makefile b/packages/system/fluxcd-operator/Makefile index 84ffc6fe..432fb208 100644 --- a/packages/system/fluxcd-operator/Makefile +++ b/packages/system/fluxcd-operator/Makefile @@ -1,7 +1,7 @@ NAME=fluxcd-operator NAMESPACE=cozy-fluxcd -include ../../../scripts/package.mk +include ../../../hack/package.mk apply-locally: cozypkg apply --plain -n $(NAMESPACE) $(NAME) diff --git a/packages/system/fluxcd/Makefile b/packages/system/fluxcd/Makefile index b5af8680..46beb480 100644 --- a/packages/system/fluxcd/Makefile +++ b/packages/system/fluxcd/Makefile @@ -1,7 +1,7 @@ NAME=fluxcd NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk apply-locally: cozypkg apply --plain -n $(NAMESPACE) $(NAME) diff --git a/packages/system/foundationdb-operator/Makefile b/packages/system/foundationdb-operator/Makefile index f735e7c5..16ca953f 100644 --- a/packages/system/foundationdb-operator/Makefile +++ b/packages/system/foundationdb-operator/Makefile @@ -1,7 +1,7 @@ export NAME=foundationdb-operator export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/gateway-api-crds/Makefile b/packages/system/gateway-api-crds/Makefile index c4311662..ad51d591 100644 --- a/packages/system/gateway-api-crds/Makefile +++ b/packages/system/gateway-api-crds/Makefile @@ -1,7 +1,7 @@ export NAME=gateway-api-crds export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf templates diff --git a/packages/system/goldpinger/Makefile b/packages/system/goldpinger/Makefile index 3ddd79ba..0aeef2ad 100644 --- a/packages/system/goldpinger/Makefile +++ b/packages/system/goldpinger/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/gpu-operator/Makefile b/packages/system/gpu-operator/Makefile index 286451f3..49b26e26 100644 --- a/packages/system/gpu-operator/Makefile +++ b/packages/system/gpu-operator/Makefile @@ -1,8 +1,8 @@ export NAME=gpu-operator export NAMESPACE=cozy-$(NAME) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/grafana-operator/Makefile b/packages/system/grafana-operator/Makefile index b7cd9de2..b1e442f4 100644 --- a/packages/system/grafana-operator/Makefile +++ b/packages/system/grafana-operator/Makefile @@ -1,8 +1,8 @@ export NAME=grafana-operator export NAMESPACE=cozy-grafana-operator -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/hetzner-robotlb/Makefile b/packages/system/hetzner-robotlb/Makefile index 9cd69463..c5ea0e4d 100644 --- a/packages/system/hetzner-robotlb/Makefile +++ b/packages/system/hetzner-robotlb/Makefile @@ -1,7 +1,7 @@ export NAME=hetzner-robotlb export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/ingress-nginx/Makefile b/packages/system/ingress-nginx/Makefile index 9ad10ae1..573c253b 100644 --- a/packages/system/ingress-nginx/Makefile +++ b/packages/system/ingress-nginx/Makefile @@ -1,6 +1,6 @@ NAME=ingress-nginx-system -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/kafka-operator/Makefile b/packages/system/kafka-operator/Makefile index 32fa2207..0e4811e5 100644 --- a/packages/system/kafka-operator/Makefile +++ b/packages/system/kafka-operator/Makefile @@ -1,7 +1,7 @@ export NAME=kafka-operator export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/kamaji/Makefile b/packages/system/kamaji/Makefile index c24e2d4e..f82c4c7a 100644 --- a/packages/system/kamaji/Makefile +++ b/packages/system/kamaji/Makefile @@ -1,8 +1,8 @@ export NAME=kamaji export NAMESPACE=cozy-$(NAME) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/keycloak-configure/Makefile b/packages/system/keycloak-configure/Makefile index b9fd5c10..4cd5bd2e 100644 --- a/packages/system/keycloak-configure/Makefile +++ b/packages/system/keycloak-configure/Makefile @@ -1,5 +1,5 @@ export NAME=keycloak-configure export NAMESPACE=cozy-keycloak -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk diff --git a/packages/system/keycloak-operator/Makefile b/packages/system/keycloak-operator/Makefile index a4f50b67..9c8d63c1 100644 --- a/packages/system/keycloak-operator/Makefile +++ b/packages/system/keycloak-operator/Makefile @@ -1,8 +1,8 @@ export NAME=keycloak-operator export NAMESPACE=cozy-keycloak -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/keycloak/Makefile b/packages/system/keycloak/Makefile index 62f4e98d..09afc864 100644 --- a/packages/system/keycloak/Makefile +++ b/packages/system/keycloak/Makefile @@ -1,5 +1,5 @@ export NAME=keycloak export NAMESPACE=cozy-keycloak -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk diff --git a/packages/system/kubeovn-plunger/Makefile b/packages/system/kubeovn-plunger/Makefile index a80c7e06..f56d935b 100644 --- a/packages/system/kubeovn-plunger/Makefile +++ b/packages/system/kubeovn-plunger/Makefile @@ -1,8 +1,8 @@ export NAME=kubeovn-plunger export NAMESPACE=cozy-kubeovn -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk image: docker buildx build -f images/kubeovn-plunger/Dockerfile ../../../ \ diff --git a/packages/system/kubeovn-webhook/Makefile b/packages/system/kubeovn-webhook/Makefile index 9134d55f..9b2e2744 100644 --- a/packages/system/kubeovn-webhook/Makefile +++ b/packages/system/kubeovn-webhook/Makefile @@ -1,8 +1,8 @@ export NAME=kubeovn-webhook export NAMESPACE=cozy-kubeovn -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk image: docker buildx build images/kubeovn-webhook \ diff --git a/packages/system/kubeovn/Makefile b/packages/system/kubeovn/Makefile index 6a0b0117..988a5f5c 100644 --- a/packages/system/kubeovn/Makefile +++ b/packages/system/kubeovn/Makefile @@ -3,8 +3,8 @@ KUBEOVN_TAG=$(shell awk '$$1 == "version:" {print $$2}' charts/kube-ovn/Chart.ya export NAME=kubeovn export NAMESPACE=cozy-$(NAME) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts && mkdir -p charts/kube-ovn diff --git a/packages/system/kubevirt-cdi-operator/Makefile b/packages/system/kubevirt-cdi-operator/Makefile index 7022599f..7232216f 100644 --- a/packages/system/kubevirt-cdi-operator/Makefile +++ b/packages/system/kubevirt-cdi-operator/Makefile @@ -1,7 +1,7 @@ export NAME=kubevirt-cdi-operator export NAMESPACE=cozy-kubevirt-cdi -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf templates diff --git a/packages/system/kubevirt-cdi/Makefile b/packages/system/kubevirt-cdi/Makefile index 0b3791a1..709e4880 100644 --- a/packages/system/kubevirt-cdi/Makefile +++ b/packages/system/kubevirt-cdi/Makefile @@ -1,7 +1,7 @@ export NAME=kubevirt-cdi export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf templates diff --git a/packages/system/kubevirt-instancetypes/Makefile b/packages/system/kubevirt-instancetypes/Makefile index d0498f10..b9f84b83 100644 --- a/packages/system/kubevirt-instancetypes/Makefile +++ b/packages/system/kubevirt-instancetypes/Makefile @@ -1,7 +1,7 @@ export NAME=kubevirt-instancetypes export NAMESPACE=cozy-kubevirt -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf templates diff --git a/packages/system/kubevirt-operator/Makefile b/packages/system/kubevirt-operator/Makefile index 42bf80a7..69b6a692 100644 --- a/packages/system/kubevirt-operator/Makefile +++ b/packages/system/kubevirt-operator/Makefile @@ -1,7 +1,7 @@ export NAME=kubevirt-operator export NAMESPACE=cozy-kubevirt -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf templates diff --git a/packages/system/kubevirt/Makefile b/packages/system/kubevirt/Makefile index 2c2e57ab..246001d0 100644 --- a/packages/system/kubevirt/Makefile +++ b/packages/system/kubevirt/Makefile @@ -1,7 +1,7 @@ export NAME=kubevirt export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf templates diff --git a/packages/system/lineage-controller-webhook/Makefile b/packages/system/lineage-controller-webhook/Makefile index 04d81a12..d5bada31 100644 --- a/packages/system/lineage-controller-webhook/Makefile +++ b/packages/system/lineage-controller-webhook/Makefile @@ -1,8 +1,8 @@ NAME=lineage-controller-webhook NAMESPACE=cozy-system -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk image: image-lineage-controller-webhook diff --git a/packages/system/linstor/Makefile b/packages/system/linstor/Makefile index 5de22194..f0829ec0 100644 --- a/packages/system/linstor/Makefile +++ b/packages/system/linstor/Makefile @@ -1,4 +1,4 @@ export NAME=linstor export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk diff --git a/packages/system/mariadb-operator/Makefile b/packages/system/mariadb-operator/Makefile index ecbd51d9..905653ca 100644 --- a/packages/system/mariadb-operator/Makefile +++ b/packages/system/mariadb-operator/Makefile @@ -1,7 +1,7 @@ export NAME=mariadb-operator export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/metallb/Makefile b/packages/system/metallb/Makefile index 5323f414..5262e558 100644 --- a/packages/system/metallb/Makefile +++ b/packages/system/metallb/Makefile @@ -1,8 +1,8 @@ export NAME=metallb export NAMESPACE=cozy-$(NAME) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/monitoring-agents/Makefile b/packages/system/monitoring-agents/Makefile index 42e762c3..c8b58c7f 100644 --- a/packages/system/monitoring-agents/Makefile +++ b/packages/system/monitoring-agents/Makefile @@ -1,7 +1,7 @@ export NAME=monitoring-agents export NAMESPACE=cozy-monitoring -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/multus/Makefile b/packages/system/multus/Makefile index 7825bd5e..9261404d 100644 --- a/packages/system/multus/Makefile +++ b/packages/system/multus/Makefile @@ -1,8 +1,8 @@ export NAME=multus export NAMESPACE=cozy-$(NAME) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf templates diff --git a/packages/system/nats/Makefile b/packages/system/nats/Makefile index 25657a89..88883ab0 100644 --- a/packages/system/nats/Makefile +++ b/packages/system/nats/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/nfs-driver/Makefile b/packages/system/nfs-driver/Makefile index e3af6c03..2f14aa28 100644 --- a/packages/system/nfs-driver/Makefile +++ b/packages/system/nfs-driver/Makefile @@ -1,8 +1,8 @@ export NAME=nfs-driver export NAMESPACE=cozy-$(NAME) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/objectstorage-controller/Makefile b/packages/system/objectstorage-controller/Makefile index 54c195a0..dacc3353 100644 --- a/packages/system/objectstorage-controller/Makefile +++ b/packages/system/objectstorage-controller/Makefile @@ -1,8 +1,8 @@ export NAME=objectstorage-controller export NAMESPACE=cozy-$(NAME) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf templates diff --git a/packages/system/piraeus-operator/Makefile b/packages/system/piraeus-operator/Makefile index a10c7369..b46680f2 100644 --- a/packages/system/piraeus-operator/Makefile +++ b/packages/system/piraeus-operator/Makefile @@ -1,7 +1,7 @@ export NAME=piraeus-operator export NAMESPACE=cozy-linstor -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/postgres-operator/Makefile b/packages/system/postgres-operator/Makefile index f1a0bba0..f58f235f 100644 --- a/packages/system/postgres-operator/Makefile +++ b/packages/system/postgres-operator/Makefile @@ -1,7 +1,7 @@ export NAME=postgres-operator export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/rabbitmq-operator/Makefile b/packages/system/rabbitmq-operator/Makefile index 12eda697..a75e37cd 100644 --- a/packages/system/rabbitmq-operator/Makefile +++ b/packages/system/rabbitmq-operator/Makefile @@ -1,7 +1,7 @@ export NAME=rabbitmq-operator export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf templates/cluster-operator.yml diff --git a/packages/system/redis-operator/Makefile b/packages/system/redis-operator/Makefile index 650cbc72..9e21b1b4 100644 --- a/packages/system/redis-operator/Makefile +++ b/packages/system/redis-operator/Makefile @@ -2,8 +2,8 @@ REDIS_OPERATOR_TAG=$(shell grep -F 'ARG VERSION=' images/redis-operator/Dockerfi export NAME=redis-operator export NAMESPACE=cozy-$(NAME) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/reloader/Makefile b/packages/system/reloader/Makefile index 378dc23c..6dc1f004 100644 --- a/packages/system/reloader/Makefile +++ b/packages/system/reloader/Makefile @@ -1,7 +1,7 @@ export NAME=reloader export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/seaweedfs/Makefile b/packages/system/seaweedfs/Makefile index 9d1f47cd..e1f79d97 100644 --- a/packages/system/seaweedfs/Makefile +++ b/packages/system/seaweedfs/Makefile @@ -1,7 +1,7 @@ export NAME=seaweedfs-system -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/snapshot-controller/Makefile b/packages/system/snapshot-controller/Makefile index 65d37f1f..ca5d39e7 100644 --- a/packages/system/snapshot-controller/Makefile +++ b/packages/system/snapshot-controller/Makefile @@ -1,7 +1,7 @@ export NAME=snapshot-controller export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/telepresence/Makefile b/packages/system/telepresence/Makefile index 1aec8917..d7f83e05 100644 --- a/packages/system/telepresence/Makefile +++ b/packages/system/telepresence/Makefile @@ -1,7 +1,7 @@ export NAME=traffic-manager export NAMESPACE=cozy-telepresence -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/velero/Makefile b/packages/system/velero/Makefile index ca4ebd5e..44eba951 100644 --- a/packages/system/velero/Makefile +++ b/packages/system/velero/Makefile @@ -1,7 +1,7 @@ export NAME=velero export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/vertical-pod-autoscaler-crds/Makefile b/packages/system/vertical-pod-autoscaler-crds/Makefile index 9290640e..52b84278 100644 --- a/packages/system/vertical-pod-autoscaler-crds/Makefile +++ b/packages/system/vertical-pod-autoscaler-crds/Makefile @@ -1,7 +1,7 @@ export NAME=vertical-pod-autoscaler export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: curl -o ./templates/vpa-v1-crd-gen.yaml https://raw.githubusercontent.com/kubernetes/autoscaler/refs/heads/master/vertical-pod-autoscaler/deploy/vpa-v1-crd-gen.yaml diff --git a/packages/system/vertical-pod-autoscaler/Makefile b/packages/system/vertical-pod-autoscaler/Makefile index 389f9c6e..1e5372e1 100644 --- a/packages/system/vertical-pod-autoscaler/Makefile +++ b/packages/system/vertical-pod-autoscaler/Makefile @@ -1,7 +1,7 @@ export NAME=vertical-pod-autoscaler export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/victoria-metrics-operator/Makefile b/packages/system/victoria-metrics-operator/Makefile index 0f31d7b7..f95bf1db 100644 --- a/packages/system/victoria-metrics-operator/Makefile +++ b/packages/system/victoria-metrics-operator/Makefile @@ -1,7 +1,7 @@ export NAME=victoria-metrics-operator export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/vsnap-crd/Makefile b/packages/system/vsnap-crd/Makefile index 57e5a290..005eefbd 100644 --- a/packages/system/vsnap-crd/Makefile +++ b/packages/system/vsnap-crd/Makefile @@ -1,7 +1,7 @@ export NAME=vsnap-crd export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf templates From 657bddaeb99b555e2916f516300c44ecfe100a7b Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 25 Nov 2025 18:02:49 +0100 Subject: [PATCH 41/46] Update e2e Signed-off-by: Andrei Kvapil --- Makefile | 3 +- hack/e2e-install-cozystack.bats | 55 ++++++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index 016cf036..502837a9 100644 --- a/Makefile +++ b/Makefile @@ -34,8 +34,7 @@ build: build-deps manifests: mkdir -p _out/assets - (cd packages/core/cozystack-operator/; helm template -n cozy-system cozystack-operator .) > _out/assets/cozystack-operator.yaml - (cd packages/core/installer/; helm template -n cozy-system 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: make -C packages/core/talos assets diff --git a/hack/e2e-install-cozystack.bats b/hack/e2e-install-cozystack.bats index 2ecb2312..1fe2a348 100644 --- a/hack/e2e-install-cozystack.bats +++ b/hack/e2e-install-cozystack.bats @@ -8,24 +8,50 @@ } @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 kubectl apply -f _out/assets/cozystack-installer.yaml # Wait for the installer deployment to become available kubectl wait deployment/cozystack-operator -n cozy-system --timeout=1m --for=condition=Available + # Wait for Flux deployment + 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" + paas: + enabled: true + 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 timeout 60 sh -ec 'until kubectl get hr -A -l cozystack.io/system-app=true | grep -q cozys; do sleep 1; done' sleep 5 @@ -140,9 +166,8 @@ EOF kubectl wait hr/seaweedfs-system -n tenant-root --timeout=2m --for=condition=ready fi - # 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 timeout 60 sh -ec 'until kubectl get deploy root-ingress-controller -n tenant-root >/dev/null 2>&1; do sleep 1; done' @@ -169,7 +194,7 @@ EOF } @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' kubectl wait hr/keycloak hr/keycloak-configure hr/keycloak-operator -n cozy-keycloak --timeout=10m --for=condition=ready From a89dd819ff3577a7c7b899ba94a9d191ee41415b Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 25 Nov 2025 18:16:26 +0100 Subject: [PATCH 42/46] Return cozystack.io/system-app=true label Signed-off-by: Andrei Kvapil --- internal/operator/bundle_reconciler.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/internal/operator/bundle_reconciler.go b/internal/operator/bundle_reconciler.go index 42716db1..82d0f246 100644 --- a/internal/operator/bundle_reconciler.go +++ b/internal/operator/bundle_reconciler.go @@ -447,6 +447,11 @@ func (r *BundleReconciler) reconcileHelmReleases(ctx context.Context, bundle *co // Finally, add default bundle label (it always takes precedence) hrLabels["cozystack.io/bundle"] = bundle.Name + // Add system-app label if namespace starts with "cozy-" + if pkg.Namespace == "kube-system" || strings.HasPrefix(pkg.Namespace, "cozy-") { + hrLabels["cozystack.io/system-app"] = "true" + } + // Create HelmRelease hr := &helmv2.HelmRelease{ ObjectMeta: metav1.ObjectMeta{ @@ -496,6 +501,11 @@ func (r *BundleReconciler) reconcileHelmReleases(ctx context.Context, bundle *co hr.Spec.Values = pkg.Values } + // Add system-app label if TargetNamespace starts with "cozy-" + if hr.Spec.TargetNamespace != "" && (hr.Spec.TargetNamespace == "kube-system" || strings.HasPrefix(hr.Spec.TargetNamespace, "cozy-")) { + hr.Labels["cozystack.io/system-app"] = "true" + } + // Set DependsOn if len(pkg.DependsOn) > 0 { dependsOn := make([]helmv2.DependencyReference, 0, len(pkg.DependsOn)) @@ -1016,7 +1026,7 @@ func (r *BundleReconciler) reconcileNamespaces(ctx context.Context, bundle *cozy for nsName, info := range namespacesMap { namespace := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ - Name: nsName, + Name: nsName, Labels: make(map[string]string), Annotations: map[string]string{ "helm.sh/resource-policy": "keep", From 9db99f723301af8a05afcaae934cfb0661dfb197 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 25 Nov 2025 18:21:51 +0100 Subject: [PATCH 43/46] upd cozyreport Signed-off-by: Andrei Kvapil --- hack/cozyreport.sh | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/hack/cozyreport.sh b/hack/cozyreport.sh index 3174ed50..c7522e7e 100755 --- a/hack/cozyreport.sh +++ b/hack/cozyreport.sh @@ -12,13 +12,19 @@ command -V tar >/dev/null || exit $? echo "Collecting Cozystack information..." 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 cm -n cozy-system --no-headers | awk '$1 ~ /^cozystack/' | - while read NAME _; do - DIR=$REPORT_DIR/cozystack/configs - mkdir -p $DIR - kubectl get cm -n cozy-system $NAME -o yaml > $DIR/$NAME.yaml 2>&1 - done +kubectl get deploy -n cozy-system cozystack-operator cozystack-controller -o yaml > $REPORT_DIR/cozystack/deployments.yaml 2>&1 + +echo "Collecting platforms..." +kubectl get platforms.cozystack.io -A > $REPORT_DIR/cozystack/platforms.txt 2>&1 +kubectl get platforms.cozystack.io -A -o yaml > $REPORT_DIR/cozystack/platforms.yaml 2>&1 + +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 @@ -56,6 +62,16 @@ kubectl get hr -A --no-headers | awk '$4 != "True"' | \ kubectl describe hr -n $NAMESPACE $NAME > $DIR/describe.txt 2>&1 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 pods..." kubectl get pod -A -o wide > $REPORT_DIR/kubernetes/pods.txt 2>&1 kubectl get pod -A --no-headers | awk '$4 !~ /Running|Succeeded|Completed/' | From 2ca68eda699729206c47fad9451ed4a827589573 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 25 Nov 2025 18:26:35 +0100 Subject: [PATCH 44/46] rebuild images Signed-off-by: Andrei Kvapil --- packages/core/installer/values.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index 8572f41b..b8aa867c 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,5 +1,5 @@ cozystackOperator: - image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:5b25b3eb9bd85ba8843fe4f36af555cd0200d581f65ca711f9ccdd552e1aa258 + image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:f20a7380e72e377b233b349a8513314fe72617bbf7cceb2a9731cb8ec9ea33d4 disableTelemetry: false cozystackVersion: "latest" - packagesDigest: sha256:e89ff0473df1178e0c8a77dd6898892ca82d455c4d20e4afa5f649edf2d72218 + packagesDigest: sha256:73f930bdc12810604ccb116f1fb5df59ba3e03eab0b834c5b0e2f5e6327ab5e6 From cc52c699226eae1d41278d4b9f94f4d8bf581283 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 25 Nov 2025 18:43:45 +0100 Subject: [PATCH 45/46] rebuild images Signed-off-by: Andrei Kvapil --- packages/core/installer/values.yaml | 3 +++ packages/core/platform/values.yaml | 2 +- packages/system/cozystack-api/values.yaml | 2 +- packages/system/cozystack-controller/values.yaml | 2 +- packages/system/lineage-controller-webhook/values.yaml | 2 +- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index 3a9df20c..0dce1070 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,5 @@ cozystack: image: ghcr.io/cozystack/cozystack/installer:v0.38.0@sha256:1a902ebd15fe375079098c088dd5b40475926c8d9576faf6348433f0fd86a963 +cozystackOperator: + image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:f637d19a036d8c7b5af3e5badb760b3b2f7afaf479d3033ca98d0144f372ce42 + packagesDigest: sha256:cb4ec036ae5ba1ab7e875cf179cfb02f1d4a59d75c99db2c376d9ca032c4d96a diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml index a869aacb..61869e65 100644 --- a/packages/core/platform/values.yaml +++ b/packages/core/platform/values.yaml @@ -3,7 +3,7 @@ sourceRef: name: cozystack-packages namespace: cozy-system migrations: - image: ghcr.io/cozystack/cozystack/platform-migrations:latest@sha256:ce668a50982cc6954b95255bcb02d9fa5a2b17f34bd31f1d02c814ed02fcc7b2 + image: ghcr.io/cozystack/cozystack/platform-migrations:latest@sha256:390dff1ac16d99c7677a2b580e0dc41bcb2ffd50232ddf4adff81d6f86aae70b targetVersion: 23 # Bundle deployment configuration bundles: diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index 228ce9a4..3a60b561 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,5 +1,5 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.38.0@sha256:5eb5d6369c7c7ba0fa6b34b7c5022faa15c860b72e441b5fbde3eceda94efc88 + image: ghcr.io/cozystack/cozystack/cozystack-api:latest@sha256:fe1878ecb05e179e4bf43f75f3f3c134a759f56a4d0c3f1011b77df27f92b587 localK8sAPIEndpoint: enabled: true replicas: 2 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index b3862287..56410bb2 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,5 +1,5 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.38.0@sha256:4628a3711b6a6fc2e446255ee172cd268b28b07c65e98c302ea8897574dcbf22 + image: ghcr.io/cozystack/cozystack/cozystack-controller:latest@sha256:0197fd991c3f9372f26a86ef517dc43ccda88bb4018e38d82693adc807d2b74f debug: false disableTelemetry: false cozystackVersion: "v0.38.0" diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index e8e245b8..8431db67 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,5 +1,5 @@ lineageControllerWebhook: - image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.38.0@sha256:fc2b04f59757904ec1557a39529b84b595114b040ef95d677fd7f21ac3958e0a + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:latest@sha256:4b4afb13fa6e04871dc3d31ce406e5f06c2bb46f157da367f47a7da80ec1a0be debug: false localK8sAPIEndpoint: enabled: true From 66ab048612b0cbbde37b46ede23f409f5be1d786 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 25 Nov 2025 18:54:25 +0100 Subject: [PATCH 46/46] fix ci pipeline Signed-off-by: Andrei Kvapil --- .github/workflows/pull-requests.yaml | 2 +- api/v1alpha1/bundles_types.go | 5 + api/v1alpha1/zz_generated.deepcopy.go | 7 + hack/cozyreport.sh | 20 +++ hack/e2e-install-cozystack.bats | 6 +- hack/update-crd.sh | 62 +++++++- internal/operator/bundle_reconciler.go | 26 +++- internal/operator/platform_reconciler.go | 134 +++++++++++++++--- packages/core/installer/Makefile | 6 +- .../installer/crds/cozystack.io_bundles.yaml | 7 + .../templates/cozystack-operator.yaml | 2 +- packages/core/installer/values.yaml | 6 +- .../virtualprivatecloud.yaml | 2 +- .../core/platform/bundles/iaas/bundle.yaml | 4 + .../platform/bundles/system/bundle-full.yaml | 7 +- .../bundles/system/bundle-hosted.yaml | 7 +- packages/core/platform/templates/cozyrds.yaml | 15 -- .../images/kubeovn-plunger/Dockerfile | 2 +- 18 files changed, 266 insertions(+), 54 deletions(-) delete mode 100644 packages/core/platform/templates/cozyrds.yaml diff --git a/.github/workflows/pull-requests.yaml b/.github/workflows/pull-requests.yaml index 06b4f3d3..2de01160 100644 --- a/.github/workflows/pull-requests.yaml +++ b/.github/workflows/pull-requests.yaml @@ -58,7 +58,7 @@ jobs: DOCKER_CONFIG: ${{ runner.temp }}/.docker - 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 if: "!contains(github.event.pull_request.labels.*.name, 'release')" diff --git a/api/v1alpha1/bundles_types.go b/api/v1alpha1/bundles_types.go index dc67edc8..3dd6542c 100644 --- a/api/v1alpha1/bundles_types.go +++ b/api/v1alpha1/bundles_types.go @@ -222,4 +222,9 @@ type BundleRelease struct { // 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"` } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index eacc06d3..744101ec 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -438,6 +438,13 @@ func (in *BundleRelease) DeepCopyInto(out *BundleRelease) { (*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. diff --git a/hack/cozyreport.sh b/hack/cozyreport.sh index c7522e7e..3fde840d 100755 --- a/hack/cozyreport.sh +++ b/hack/cozyreport.sh @@ -72,6 +72,26 @@ kubectl get artifactgenerators.source.extensions.fluxcd.io -A --no-headers | awk 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..." kubectl get pod -A -o wide > $REPORT_DIR/kubernetes/pods.txt 2>&1 kubectl get pod -A --no-headers | awk '$4 !~ /Running|Succeeded|Completed/' | diff --git a/hack/e2e-install-cozystack.bats b/hack/e2e-install-cozystack.bats index 1fe2a348..73f4f0f1 100644 --- a/hack/e2e-install-cozystack.bats +++ b/hack/e2e-install-cozystack.bats @@ -14,7 +14,11 @@ # Wait for the installer deployment to become 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 @@ -32,8 +36,6 @@ spec: bundles: system: type: "full" - paas: - enabled: true networking: podCIDR: "10.244.0.0/16" podGateway: "10.244.0.1" diff --git a/hack/update-crd.sh b/hack/update-crd.sh index 38a03240..620aeac4 100755 --- a/hack/update-crd.sh +++ b/hack/update-crd.sh @@ -56,24 +56,65 @@ ICON_B64="$(base64 < "$ICON_PATH" | tr -d '\n' | tr -d '\r')" # Find path to output CRD YAML OUT="$(find $CRD_DIR -type f -name "${NAME}.yaml" | head -n 1)" +if [[ -z "$OUT" ]]; then + echo "Error: ApplicationDefinition file for '${NAME}' not found in ${CRD_DIR}" + echo "Please create the file first in one of the following directories:" + + # Auto-detect existing directories + BASE_DIR="../../core/platform/bundles" + 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 [[ ! -s "$OUT" ]]; then cat >"$OUT" < "${OUT}.tmp" && mv "${OUT}.tmp" "$OUT" +fi + # Update only necessary fields in-place # - openAPISchema is loaded from file as a multi-line string (block scalar) # - labels ensure cozystack.io/ui: "true" @@ -129,4 +176,11 @@ yq -i ' .spec.dashboard.keysOrder = env(KEYS_ORDER) ' "$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" diff --git a/internal/operator/bundle_reconciler.go b/internal/operator/bundle_reconciler.go index 82d0f246..ddaa1303 100644 --- a/internal/operator/bundle_reconciler.go +++ b/internal/operator/bundle_reconciler.go @@ -981,10 +981,11 @@ func (r *BundleReconciler) reconcileNamespaces(ctx context.Context, bundle *cozy logger := log.FromContext(ctx) // Collect namespaces from packages - // Map: namespace -> {isPrivileged, labels} + // Map: namespace -> {isPrivileged, labels, annotations} type namespaceInfo struct { - privileged bool - labels map[string]string + privileged bool + labels map[string]string + annotations map[string]string } namespacesMap := make(map[string]namespaceInfo) @@ -1002,8 +1003,9 @@ func (r *BundleReconciler) reconcileNamespaces(ctx context.Context, bundle *cozy info, exists := namespacesMap[pkg.Namespace] if !exists { info = namespaceInfo{ - privileged: false, - labels: make(map[string]string), + privileged: false, + labels: make(map[string]string), + annotations: make(map[string]string), } } @@ -1019,6 +1021,13 @@ func (r *BundleReconciler) reconcileNamespaces(ctx context.Context, bundle *cozy } } + // Merge namespace annotations from package + if pkg.NamespaceAnnotations != nil { + for k, v := range pkg.NamespaceAnnotations { + info.annotations[k] = v + } + } + namespacesMap[pkg.Namespace] = info } @@ -1049,11 +1058,16 @@ func (r *BundleReconciler) reconcileNamespaces(ctx context.Context, bundle *cozy namespace.Labels[k] = v } + // Merge namespace annotations from packages + for k, v := range info.annotations { + namespace.Annotations[k] = v + } + if err := r.createOrUpdateNamespace(ctx, namespace); err != nil { logger.Error(err, "failed to reconcile namespace", "name", nsName, "privileged", info.privileged) return fmt.Errorf("failed to reconcile namespace %s: %w", nsName, err) } - logger.Info("reconciled namespace", "name", nsName, "privileged", info.privileged, "labels", info.labels) + logger.Info("reconciled namespace", "name", nsName, "privileged", info.privileged, "labels", info.labels, "annotations", info.annotations) } return nil diff --git a/internal/operator/platform_reconciler.go b/internal/operator/platform_reconciler.go index b196b507..1a8c0aa5 100644 --- a/internal/operator/platform_reconciler.go +++ b/internal/operator/platform_reconciler.go @@ -79,6 +79,12 @@ func (r *PlatformReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c 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 } @@ -86,20 +92,18 @@ func (r *PlatformReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c func (r *PlatformReconciler) reconcileArtifactGenerator(ctx context.Context, platform *cozyv1alpha1.Platform) error { logger := log.FromContext(ctx) - // ArtifactGenerator name is the sourceRef name - agName := platform.Spec.SourceRef.Name // 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 + "/**", @@ -110,7 +114,7 @@ func (r *PlatformReconciler) reconcileArtifactGenerator(ctx context.Context, pla // Create ArtifactGenerator ag := &sourcewatcherv1beta1.ArtifactGenerator{ ObjectMeta: metav1.ObjectMeta{ - Name: agName, + Name: platform.Name, Namespace: namespace, Labels: map[string]string{ "cozystack.io/platform": platform.Name, @@ -145,13 +149,13 @@ func (r *PlatformReconciler) reconcileArtifactGenerator(ctx context.Context, pla }, } - logger.Info("reconciling ArtifactGenerator", "name", agName, "namespace", namespace) + 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", agName, err) + return fmt.Errorf("failed to reconcile ArtifactGenerator %s: %w", platform.Name, err) } - logger.Info("reconciled ArtifactGenerator", "name", agName, "namespace", namespace) + logger.Info("reconciled ArtifactGenerator", "name", platform.Name, "namespace", namespace) return nil } @@ -160,7 +164,6 @@ func (r *PlatformReconciler) reconcileHelmRelease(ctx context.Context, platform logger := log.FromContext(ctx) // HelmRelease name is fixed: cozystack-platform - hrName := "cozystack-platform" // Use fixed namespace for cluster-scoped resource namespace := "cozy-system" @@ -175,7 +178,7 @@ func (r *PlatformReconciler) reconcileHelmRelease(ctx context.Context, platform // Create HelmRelease hr := &helmv2.HelmRelease{ ObjectMeta: metav1.ObjectMeta{ - Name: hrName, + Name: platform.Name, Namespace: namespace, Labels: map[string]string{ "cozystack.io/platform": platform.Name, @@ -215,13 +218,13 @@ func (r *PlatformReconciler) reconcileHelmRelease(ctx context.Context, platform }, } - logger.Info("reconciling HelmRelease", "name", hrName, "namespace", namespace) + 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", hrName, err) + return fmt.Errorf("failed to reconcile HelmRelease %s: %w", platform.Name, err) } - logger.Info("reconciled HelmRelease", "name", hrName, "namespace", namespace) + logger.Info("reconciled HelmRelease", "name", platform.Name, "namespace", namespace) return nil } @@ -299,12 +302,110 @@ func (r *PlatformReconciler) buildSourcePath(sourceName, basePath, chartPath str // cleanupOrphanedResources removes ArtifactGenerator and HelmRelease when Platform is deleted func (r *PlatformReconciler) cleanupOrphanedResources(ctx context.Context, name client.ObjectKey) (ctrl.Result, error) { - // OwnerReferences should handle cleanup automatically - // This function is kept for potential future cleanup logic - // Note: name is ObjectKey, but for cluster-scoped resources only Name is used + 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) @@ -438,4 +539,3 @@ func (r *PlatformReconciler) SetupWithManager(mgr ctrl.Manager) error { ). Complete(r) } - diff --git a/packages/core/installer/Makefile b/packages/core/installer/Makefile index 910fcafb..0dc0f0c5 100644 --- a/packages/core/installer/Makefile +++ b/packages/core/installer/Makefile @@ -40,5 +40,7 @@ image-packages: --source=https://github.com/cozystack/cozystack \ --revision="$$(git describe --tags):$$(git rev-parse HEAD)" \ 2>&1 | tee images/cozystack-packages.log - DIGEST=$$(awk -F@ '/artifact successfully pushed/ {print $$2}' images/cozystack-packages.log; rm -f images/cozystack-packages.log) \ - yq -i '.cozystackOperator.packagesDigest = strenv(DIGEST)' values.yaml + REPO="oci://$(REGISTRY)/platform-packages" \ + yq -i '.cozystackOperator.packagesRepository = strenv(REPO)' values.yaml + export DIGEST=$$(awk -F@ '/artifact successfully pushed/ {print $$2}' images/cozystack-packages.log; rm -f images/cozystack-packages.log); \ + test -n "$$DIGEST" && yq -i '.cozystackOperator.packagesDigest = strenv(DIGEST)' values.yaml diff --git a/packages/core/installer/crds/cozystack.io_bundles.yaml b/packages/core/installer/crds/cozystack.io_bundles.yaml index 57ba017d..51c7e360 100644 --- a/packages/core/installer/crds/cozystack.io_bundles.yaml +++ b/packages/core/installer/crds/cozystack.io_bundles.yaml @@ -189,6 +189,13 @@ spec: description: Namespace is the Kubernetes namespace where the release will be installed type: string + namespaceAnnotations: + additionalProperties: + type: string + description: |- + 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 + type: object namespaceLabels: additionalProperties: type: string diff --git a/packages/core/installer/templates/cozystack-operator.yaml b/packages/core/installer/templates/cozystack-operator.yaml index 3229b55d..e3fa48b4 100644 --- a/packages/core/installer/templates/cozystack-operator.yaml +++ b/packages/core/installer/templates/cozystack-operator.yaml @@ -6,7 +6,7 @@ metadata: namespace: cozy-system spec: interval: 5m0s - url: oci://ghcr.io/cozystack/cozystack/platform-packages + url: {{ .Values.cozystackOperator.packagesRepository }} ref: digest: {{ .Values.cozystackOperator.packagesDigest }} {{- end -}} diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index 0dce1070..71bcc9e2 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,5 +1,7 @@ cozystack: image: ghcr.io/cozystack/cozystack/installer:v0.38.0@sha256:1a902ebd15fe375079098c088dd5b40475926c8d9576faf6348433f0fd86a963 cozystackOperator: - image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:f637d19a036d8c7b5af3e5badb760b3b2f7afaf479d3033ca98d0144f372ce42 - packagesDigest: sha256:cb4ec036ae5ba1ab7e875cf179cfb02f1d4a59d75c99db2c376d9ca032c4d96a + image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:446b4afe9ed160a850cc9b61dd6f34b2ae36d69d4cd974d6d35a25180bd73879 + packagesRepository: oci://ghcr.io/cozystack/cozystack/platform-packages + packagesDigest: sha256:39666735999e79f3b7b502ff46c642e13a17ce8860a47493af0912285d360ec9 + cozystackVersion: latest diff --git a/packages/core/platform/bundles/iaas/applicationdefinitions/virtualprivatecloud.yaml b/packages/core/platform/bundles/iaas/applicationdefinitions/virtualprivatecloud.yaml index 8a9e1be1..783f025b 100644 --- a/packages/core/platform/bundles/iaas/applicationdefinitions/virtualprivatecloud.yaml +++ b/packages/core/platform/bundles/iaas/applicationdefinitions/virtualprivatecloud.yaml @@ -16,7 +16,7 @@ spec: chartRef: sourceRef: kind: ExternalArtifact - name: cozystack-iaas-vpc + name: cozystack-iaas-virtualprivatecloud namespace: cozy-system values: _cozystack: diff --git a/packages/core/platform/bundles/iaas/bundle.yaml b/packages/core/platform/bundles/iaas/bundle.yaml index a5bfc3aa..c45bd74f 100644 --- a/packages/core/platform/bundles/iaas/bundle.yaml +++ b/packages/core/platform/bundles/iaas/bundle.yaml @@ -72,6 +72,10 @@ spec: path: apps/vpc libraries: [cozy-lib] + - name: virtualprivatecloud + path: apps/vpc + libraries: [cozy-lib] + - name: vm-disk path: apps/vm-disk libraries: [cozy-lib] diff --git a/packages/core/platform/bundles/system/bundle-full.yaml b/packages/core/platform/bundles/system/bundle-full.yaml index df22abdf..01d9dbb0 100644 --- a/packages/core/platform/bundles/system/bundle-full.yaml +++ b/packages/core/platform/bundles/system/bundle-full.yaml @@ -57,12 +57,17 @@ spec: releaseName: tenant-root artifact: tenant namespace: tenant-root - namespaceLabels: + namespaceAnnotations: namespace.cozystack.io/host: {{ $host }} namespace.cozystack.io/etcd: tenant-root namespace.cozystack.io/ingress: tenant-root namespace.cozystack.io/monitoring: tenant-root namespace.cozystack.io/seaweedfs: tenant-root + namespaceLabels: + namespace.cozystack.io/etcd: tenant-root + namespace.cozystack.io/ingress: tenant-root + namespace.cozystack.io/monitoring: tenant-root + namespace.cozystack.io/seaweedfs: tenant-root labels: cozystack.io/ui: "true" apps.cozystack.io/application.kind: Tenant diff --git a/packages/core/platform/bundles/system/bundle-hosted.yaml b/packages/core/platform/bundles/system/bundle-hosted.yaml index 08459df6..41f485aa 100644 --- a/packages/core/platform/bundles/system/bundle-hosted.yaml +++ b/packages/core/platform/bundles/system/bundle-hosted.yaml @@ -57,12 +57,17 @@ spec: releaseName: tenant-root artifact: tenant namespace: tenant-root - namespaceLabels: + namespaceAnnotations: namespace.cozystack.io/host: {{ $host }} namespace.cozystack.io/etcd: tenant-root namespace.cozystack.io/ingress: tenant-root namespace.cozystack.io/monitoring: tenant-root namespace.cozystack.io/seaweedfs: tenant-root + namespaceLabels: + namespace.cozystack.io/etcd: tenant-root + namespace.cozystack.io/ingress: tenant-root + namespace.cozystack.io/monitoring: tenant-root + namespace.cozystack.io/seaweedfs: tenant-root labels: cozystack.io/ui: "true" apps.cozystack.io/application.kind: Tenant diff --git a/packages/core/platform/templates/cozyrds.yaml b/packages/core/platform/templates/cozyrds.yaml deleted file mode 100644 index c35dbd82..00000000 --- a/packages/core/platform/templates/cozyrds.yaml +++ /dev/null @@ -1,15 +0,0 @@ -{{- $systemBundleType := .Values.bundles.system.type | default "full" }} - -{{- if or (ne $systemBundleType "full") (ne $systemBundleType "hosted") }} -{{ include "cozystack.render-glob" (list . "bundles/system/applicationdefinitions/*.yaml") }} -{{- end }} - -{{- if .Values.bundles.iaas.enabled }} -{{ include "cozystack.render-glob" (list . "bundles/iaas/applicationdefinitions/*.yaml") }} -{{- end }} -{{- if .Values.bundles.paas.enabled }} -{{ include "cozystack.render-glob" (list . "bundles/paas/applicationdefinitions/*.yaml") }} -{{- end }} -{{- if .Values.bundles.naas.enabled }} -{{ include "cozystack.render-glob" (list . "bundles/naas/applicationdefinitions/*.yaml") }} -{{- end }} diff --git a/packages/system/kubeovn-plunger/images/kubeovn-plunger/Dockerfile b/packages/system/kubeovn-plunger/images/kubeovn-plunger/Dockerfile index a6264ae1..b0473244 100644 --- a/packages/system/kubeovn-plunger/images/kubeovn-plunger/Dockerfile +++ b/packages/system/kubeovn-plunger/images/kubeovn-plunger/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.24-alpine AS builder +FROM golang:1.25-alpine AS builder ARG TARGETOS ARG TARGETARCH