From d26d3e1f40f8a3bd2dd775e5162c39ae66cb4413 Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Sun, 19 Oct 2025 16:00:51 +0300 Subject: [PATCH 01/33] [kubeovn] Package from external repo Previously, all system charts have had their versions bumped with every update of Cozystack, even if the underlying images and templates did not change. Additionally, some components would have their docker images rebuilt and get updated digests because of a changed docker context, even though no relevant code had been changed. This would cause an upgrade of several HelmReleases on every upgrade of Cozystack, even when in practice nothing had changed. This is especially noticeable for charts, such as kubeovn, which is a dependency for almost all other system HelmReleases. By moving kubeovn out of the monorepo and decoupling its release cycle from the release cycle of Cozystack, this issue can be resolved and is another step towards decomposing Cozystack. ```release-note [kubeovn] Decouple the release cycle of kubeovn from Cozystack's release cycle, preventing unnecessary redeployments of all Helm releases, when upgrading Cozystack. ``` Signed-off-by: Timofei Larkin --- packages/system/Makefile | 4 +- packages/system/kubeovn/Chart.yaml | 2 +- packages/system/kubeovn/Makefile | 31 +---- .../system/kubeovn/charts/kube-ovn/Chart.yaml | 4 +- .../kube-ovn/templates/kube-ovn-crd.yaml | 32 +++-- .../charts/kube-ovn/templates/ovncni-ds.yaml | 2 +- .../kubeovn/charts/kube-ovn/values.yaml | 3 +- .../system/kubeovn/images/kubeovn/Dockerfile | 47 -------- .../images/kubeovn/patches/northd_probe.diff | 109 ------------------ .../system/kubeovn/patches/cozyconfig.diff | 103 ----------------- packages/system/kubeovn/patches/mtu.diff | 14 --- 11 files changed, 34 insertions(+), 317 deletions(-) delete mode 100644 packages/system/kubeovn/images/kubeovn/Dockerfile delete mode 100644 packages/system/kubeovn/images/kubeovn/patches/northd_probe.diff delete mode 100644 packages/system/kubeovn/patches/cozyconfig.diff delete mode 100644 packages/system/kubeovn/patches/mtu.diff diff --git a/packages/system/Makefile b/packages/system/Makefile index 2104647b..e068be8a 100644 --- a/packages/system/Makefile +++ b/packages/system/Makefile @@ -1,11 +1,13 @@ OUT=../../_out/repos/system -CHARTS := $(shell find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}') +CHARTS := $(shell grep -F 'version: 0.0.0' */Chart.yaml | cut -f1 -d/) +VERSIONED_CHARTS := $(shell grep '^version:' */Chart.yaml | grep -Fv '0.0.0' | cut -f1 -d/) include ../../scripts/common-envs.mk repo: rm -rf "$(OUT)" helm package -d "$(OUT)" $(CHARTS) --version $(COZYSTACK_VERSION) + helm package -d "$(OUT)" $(VERSIONED_CHARTS) cd "$(OUT)" && helm repo index . fix-charts: diff --git a/packages/system/kubeovn/Chart.yaml b/packages/system/kubeovn/Chart.yaml index 16cb9dc5..a49c72e9 100644 --- a/packages/system/kubeovn/Chart.yaml +++ b/packages/system/kubeovn/Chart.yaml @@ -1,3 +1,3 @@ apiVersion: v2 name: cozy-kubeovn -version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process +version: 0.37.3 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/kubeovn/Makefile b/packages/system/kubeovn/Makefile index 15373d2f..bcf8aa47 100644 --- a/packages/system/kubeovn/Makefile +++ b/packages/system/kubeovn/Makefile @@ -1,4 +1,4 @@ -KUBEOVN_TAG=$(shell awk '$$1 == "version:" {print $$2}' charts/kube-ovn/Chart.yaml) +KUBEOVN_TAG=v0.37.3 export NAME=kubeovn export NAMESPACE=cozy-$(NAME) @@ -7,28 +7,7 @@ include ../../../scripts/common-envs.mk include ../../../scripts/package.mk update: - rm -rf charts && mkdir -p charts/kube-ovn - tag=$$(git ls-remote --tags --sort="v:refname" https://github.com/kubeovn/kube-ovn | awk -F'[/^]' '{print $$3}' | grep '^v1\.14\.' | tail -n1 ) && \ - curl -sSL https://github.com/kubeovn/kube-ovn/archive/refs/tags/$${tag}.tar.gz | \ - tar xzvf - --strip 1 kube-ovn-$${tag#*v}/charts/kube-ovn - patch --no-backup-if-mismatch -p4 < patches/cozyconfig.diff - patch --no-backup-if-mismatch -p4 < patches/mtu.diff - version=$$(awk '$$1 == "version:" {print $$2}' charts/kube-ovn/Chart.yaml) && \ - sed -i "s/ARG VERSION=.*/ARG VERSION=$${version}/" images/kubeovn/Dockerfile && \ - sed -i "s/ARG TAG=.*/ARG TAG=$${version}/" images/kubeovn/Dockerfile - -image: - docker buildx build images/kubeovn \ - --tag $(REGISTRY)/kubeovn:$(call settag,$(KUBEOVN_TAG)) \ - --tag $(REGISTRY)/kubeovn:$(call settag,$(KUBEOVN_TAG)-$(TAG)) \ - --cache-from type=registry,ref=$(REGISTRY)/kubeovn:latest \ - --cache-to type=inline \ - --metadata-file images/kubeovn.json \ - $(BUILDX_ARGS) - REGISTRY="$(REGISTRY)" \ - yq -i '.global.registry.address = strenv(REGISTRY)' values.yaml - REPOSITORY="kubeovn" \ - yq -i '.global.images.kubeovn.repository = strenv(REPOSITORY)' values.yaml - TAG="$(call settag,$(KUBEOVN_TAG))@$$(yq e '."containerimage.digest"' images/kubeovn.json -o json -r)" \ - yq -i '.global.images.kubeovn.tag = strenv(TAG)' values.yaml - rm -f images/kubeovn.json + rm -rf charts values.yaml Chart.yaml + tag=$(KUBEOVN_TAG) && \ + curl -sSL https://github.com/cozystack/kubeovn/archive/refs/tags/$${tag}.tar.gz | \ + tar xzvf - --strip 2 kubeovn-$${tag#*v}/chart diff --git a/packages/system/kubeovn/charts/kube-ovn/Chart.yaml b/packages/system/kubeovn/charts/kube-ovn/Chart.yaml index 44744459..f7be2d3b 100644 --- a/packages/system/kubeovn/charts/kube-ovn/Chart.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/Chart.yaml @@ -15,12 +15,12 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: v1.14.5 +version: v1.14.11 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "1.14.5" +appVersion: "1.14.11" kubeVersion: ">= 1.29.0-0" diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/kube-ovn-crd.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/kube-ovn-crd.yaml index 1f45c50c..3bddfbe1 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/kube-ovn-crd.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/kube-ovn-crd.yaml @@ -257,8 +257,9 @@ spec: type: array type: object weight: - format: int32 type: integer + minimum: 1 + maximum: 100 required: - preference - weight @@ -349,8 +350,9 @@ spec: - topologyKey type: object weight: - format: int32 type: integer + minimum: 1 + maximum: 100 required: - podAffinityTerm - weight @@ -437,8 +439,9 @@ spec: - topologyKey type: object weight: - format: int32 type: integer + minimum: 1 + maximum: 100 required: - podAffinityTerm - weight @@ -593,8 +596,9 @@ spec: type: array type: object weight: - format: int32 type: integer + minimum: 1 + maximum: 100 required: - preference - weight @@ -685,8 +689,9 @@ spec: - topologyKey type: object weight: - format: int32 type: integer + minimum: 1 + maximum: 100 required: - podAffinityTerm - weight @@ -773,8 +778,9 @@ spec: - topologyKey type: object weight: - format: int32 type: integer + minimum: 1 + maximum: 100 required: - podAffinityTerm - weight @@ -891,7 +897,8 @@ spec: properties: replicas: type: integer - format: int32 + minimum: 0 + maximum: 10 labelSelector: type: string conditions: @@ -907,7 +914,6 @@ spec: maxLength: 32768 type: string observedGeneration: - format: int64 minimum: 0 type: integer reason: @@ -988,7 +994,6 @@ spec: properties: replicas: type: integer - format: int32 default: 1 minimum: 0 maximum: 10 @@ -1036,16 +1041,19 @@ spec: default: false minRX: type: integer - format: int32 default: 1000 + minimum: 1 + maximum: 3600000 minTX: type: integer - format: int32 default: 1000 + minimum: 1 + maximum: 3600000 multiplier: type: integer - format: int32 default: 3 + minimum: 1 + maximum: 3600000 selectors: type: array items: diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml index 3a749f84..947ec454 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml @@ -272,5 +272,5 @@ spec: {{- if .Values.func.ENABLE_OVN_IPSEC }} - name: ovs-ipsec-keys hostPath: - path: {{ .Values.OPENVSWITCH_DIR }} + path: {{ .Values.OVN_IPSEC_KEY_DIR }} {{- end }} diff --git a/packages/system/kubeovn/charts/kube-ovn/values.yaml b/packages/system/kubeovn/charts/kube-ovn/values.yaml index 74a69133..3652386d 100644 --- a/packages/system/kubeovn/charts/kube-ovn/values.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/values.yaml @@ -9,7 +9,7 @@ global: kubeovn: repository: kube-ovn vpcRepository: vpc-nat-gateway - tag: v1.14.5 + tag: v1.14.11 support_arm: true thirdparty: true @@ -123,6 +123,7 @@ log_conf: LOG_DIR: "/var/log" OPENVSWITCH_DIR: "/etc/origin/openvswitch" +OVN_IPSEC_KEY_DIR: "/etc/origin/ovs_ipsec_keys" OVN_DIR: "/etc/origin/ovn" DISABLE_MODULES_MANAGEMENT: false diff --git a/packages/system/kubeovn/images/kubeovn/Dockerfile b/packages/system/kubeovn/images/kubeovn/Dockerfile deleted file mode 100644 index f4d1267c..00000000 --- a/packages/system/kubeovn/images/kubeovn/Dockerfile +++ /dev/null @@ -1,47 +0,0 @@ -# syntax = docker/dockerfile:experimental -ARG VERSION=v1.14.5 -ARG BASE_TAG=$VERSION - -FROM golang:1.24-bookworm as builder - -ARG TAG=v1.14.5 -RUN git clone --branch ${TAG} --depth 1 https://github.com/kubeovn/kube-ovn /source - -WORKDIR /source - -COPY patches /patches -RUN git apply /patches/*.diff -RUN make build-go - -WORKDIR /source/dist/images - -# imported from https://github.com/kubeovn/kube-ovn/blob/master/dist/images/Dockerfile -FROM kubeovn/kube-ovn-base:$BASE_TAG AS setcap - -COPY --from=builder /source/dist/images/*.sh /kube-ovn/ -COPY --from=builder /source/dist/images/kubectl-ko /kube-ovn/kubectl-ko -COPY --from=builder /source/dist/images/01-kube-ovn.conflist /kube-ovn/01-kube-ovn.conflist - -COPY --from=builder /source/dist/images/kube-ovn /kube-ovn/kube-ovn -COPY --from=builder /source/dist/images/kube-ovn-cmd /kube-ovn/kube-ovn-cmd -COPY --from=builder /source/dist/images/kube-ovn-daemon /kube-ovn/kube-ovn-daemon -COPY --from=builder /source/dist/images/kube-ovn-controller /kube-ovn/kube-ovn-controller -RUN ln -s /kube-ovn/kube-ovn-cmd /kube-ovn/kube-ovn-monitor && \ - ln -s /kube-ovn/kube-ovn-cmd /kube-ovn/kube-ovn-speaker && \ - ln -s /kube-ovn/kube-ovn-cmd /kube-ovn/kube-ovn-webhook && \ - ln -s /kube-ovn/kube-ovn-cmd /kube-ovn/kube-ovn-leader-checker && \ - ln -s /kube-ovn/kube-ovn-cmd /kube-ovn/kube-ovn-ic-controller && \ - ln -s /kube-ovn/kube-ovn-controller /kube-ovn/kube-ovn-pinger && \ - setcap CAP_NET_BIND_SERVICE+eip /kube-ovn/kube-ovn-cmd && \ - setcap CAP_NET_RAW,CAP_NET_BIND_SERVICE+eip /kube-ovn/kube-ovn-controller && \ - setcap CAP_NET_ADMIN,CAP_NET_RAW,CAP_NET_BIND_SERVICE,CAP_SYS_ADMIN+eip /kube-ovn/kube-ovn-daemon - -FROM kubeovn/kube-ovn-base:$BASE_TAG - -COPY --chmod=0644 --from=builder /source/dist/images/logrotate/* /etc/logrotate.d/ -COPY --from=builder /source/dist/images/grace_stop_ovn_controller /usr/share/ovn/scripts/grace_stop_ovn_controller - -COPY --from=setcap /kube-ovn /kube-ovn -RUN /kube-ovn/iptables-wrapper-installer.sh --no-sanity-check - -WORKDIR /kube-ovn diff --git a/packages/system/kubeovn/images/kubeovn/patches/northd_probe.diff b/packages/system/kubeovn/images/kubeovn/patches/northd_probe.diff deleted file mode 100644 index 93edd879..00000000 --- a/packages/system/kubeovn/images/kubeovn/patches/northd_probe.diff +++ /dev/null @@ -1,109 +0,0 @@ -diff --git a/pkg/ovn_leader_checker/ovn.go b/pkg/ovn_leader_checker/ovn.go -index 0f86a371d..8ddf7bca6 100755 ---- a/pkg/ovn_leader_checker/ovn.go -+++ b/pkg/ovn_leader_checker/ovn.go -@@ -10,6 +10,7 @@ import ( - "os/exec" - "strconv" - "strings" -+ "sync" - "syscall" - "time" - -@@ -271,19 +272,56 @@ func checkNorthdSvcExist(cfg *Configuration, namespace, svcName string) bool { - return true - } - --func checkNorthdEpAvailable(ip string) bool { -- address := net.JoinHostPort(ip, OvnNorthdPort) -- conn, err := net.DialTimeout("tcp", address, 3*time.Second) -- if err != nil { -- klog.Errorf("failed to connect to northd leader %s, err: %v", ip, err) -- failCount++ -- if failCount >= MaxFailCount { -- return false -- } -- } else { -+func checkNorthdEpAvailable(ips ...string) bool { -+ var wg sync.WaitGroup -+ success := make(chan struct{}, 1) -+ failure := make(chan struct{}) -+ ctx, cancel := context.WithCancel(context.Background()) -+ defer cancel() -+ d := net.Dialer{Timeout: 3 * time.Second} -+ for _, ip := range ips { -+ address := net.JoinHostPort(ip, OvnNorthdPort) -+ wg.Add(1) -+ go func() { -+ defer wg.Done() -+ conn, err := d.DialContext(ctx, "tcp", address) -+ if err != nil { -+ klog.Errorf("failed to connect to northd leader %s, err: %v", ip, err) -+ return -+ } else { -+ defer conn.Close() -+ select { -+ case success <- struct{}{}: -+ klog.V(5).Infof("succeed to connect to northd leader %s", ip) -+ cancel() -+ default: -+ // someone else already succeeded -+ } -+ } -+ }() -+ } -+ go func() { -+ wg.Wait() -+ close(failure) -+ }() -+ select { -+ case <-success: - failCount = 0 -- klog.V(5).Infof("succeed to connect to northd leader %s", ip) -- _ = conn.Close() -+ return true -+ case <-failure: -+ // if the last groroutine is the one to succeed, -+ // there's a small chance that failure is selected, -+ // this is a guard for this -+ select { -+ case <-success: -+ failCount = 0 -+ return true -+ default: -+ failCount++ -+ if failCount >= MaxFailCount { -+ return false -+ } -+ } - } - return true - } -@@ -295,6 +333,8 @@ func checkNorthdEpAlive(cfg *Configuration, namespace, service string) bool { - return false - } - -+ addresses := []string{} -+ - for _, eps := range epsList.Items { - for _, ep := range eps.Endpoints { - if (ep.Conditions.Ready != nil && !*ep.Conditions.Ready) || len(ep.Addresses) == 0 { -@@ -303,12 +343,15 @@ func checkNorthdEpAlive(cfg *Configuration, namespace, service string) bool { - - // Found an address, check its availability. We only need one. - klog.V(5).Infof("found address %s in endpoint slice %s/%s for service %s, checking availability", ep.Addresses[0], eps.Namespace, eps.Name, service) -- return checkNorthdEpAvailable(ep.Addresses[0]) -+ addresses = append(addresses, ep.Addresses[0]) // Addresses are fungible by k8s API design - } - } - -- klog.V(5).Infof("no address found in any endpoint slices for service %s/%s", namespace, service) -- return false -+ if len(addresses) == 0 { -+ klog.V(5).Infof("no address found in any endpoint slices for service %s/%s", namespace, service) -+ return false -+ } -+ return checkNorthdEpAvailable(addresses...) - } - - func compactOvnDatabase(db string) { diff --git a/packages/system/kubeovn/patches/cozyconfig.diff b/packages/system/kubeovn/patches/cozyconfig.diff deleted file mode 100644 index f7a683f7..00000000 --- a/packages/system/kubeovn/patches/cozyconfig.diff +++ /dev/null @@ -1,103 +0,0 @@ - -diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml -index d9a9a67..b2e12dd 100644 ---- a/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml -+++ b/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml -@@ -51,18 +51,15 @@ spec: - - bash - - /kube-ovn/start-cniserver.sh - args: -+ {{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} - - --enable-mirror={{- .Values.debug.ENABLE_MIRROR }} - - --mirror-iface={{- .Values.debug.MIRROR_IFACE }} - - --node-switch={{ .Values.networking.NODE_SUBNET }} - - --encap-checksum=true -- - --service-cluster-ip-range= -- {{- if eq .Values.networking.NET_STACK "dual_stack" -}} -- {{ .Values.dual_stack.SVC_CIDR }} -- {{- else if eq .Values.networking.NET_STACK "ipv4" -}} -- {{ .Values.ipv4.SVC_CIDR }} -- {{- else if eq .Values.networking.NET_STACK "ipv6" -}} -- {{ .Values.ipv6.SVC_CIDR }} -- {{- end }} -+ - --service-cluster-ip-range={{ index $cozyConfig.data "ipv4-svc-cidr" }} -+ {{- if .Values.global.logVerbosity }} -+ - --v={{ .Values.global.logVerbosity }} -+ {{- end }} - {{- if eq .Values.networking.NETWORK_TYPE "vlan" }} - - --iface= - {{- else}} -diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/controller-deploy.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/controller-deploy.yaml -index 0e69494..756eb7c 100644 ---- a/packages/system/kubeovn/charts/kube-ovn/templates/controller-deploy.yaml -+++ b/packages/system/kubeovn/charts/kube-ovn/templates/controller-deploy.yaml -@@ -52,46 +52,22 @@ spec: - image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} - imagePullPolicy: {{ .Values.image.pullPolicy }} - args: -+ {{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} - - /kube-ovn/start-controller.sh - - --default-ls={{ .Values.networking.DEFAULT_SUBNET }} -- - --default-cidr= -- {{- if eq .Values.networking.NET_STACK "dual_stack" -}} -- {{ .Values.dual_stack.POD_CIDR }} -- {{- else if eq .Values.networking.NET_STACK "ipv4" -}} -- {{ .Values.ipv4.POD_CIDR }} -- {{- else if eq .Values.networking.NET_STACK "ipv6" -}} -- {{ .Values.ipv6.POD_CIDR }} -- {{- end }} -- - --default-gateway= -- {{- if eq .Values.networking.NET_STACK "dual_stack" -}} -- {{ .Values.dual_stack.POD_GATEWAY }} -- {{- else if eq .Values.networking.NET_STACK "ipv4" -}} -- {{ .Values.ipv4.POD_GATEWAY }} -- {{- else if eq .Values.networking.NET_STACK "ipv6" -}} -- {{ .Values.ipv6.POD_GATEWAY }} -- {{- end }} -+ - --default-cidr={{ index $cozyConfig.data "ipv4-pod-cidr" }} -+ - --default-gateway={{ index $cozyConfig.data "ipv4-pod-gateway" }} - - --default-gateway-check={{- .Values.func.CHECK_GATEWAY }} - - --default-logical-gateway={{- .Values.func.LOGICAL_GATEWAY }} - - --default-u2o-interconnection={{- .Values.func.U2O_INTERCONNECTION }} - - --default-exclude-ips={{- .Values.networking.EXCLUDE_IPS }} - - --cluster-router={{ .Values.networking.DEFAULT_VPC }} - - --node-switch={{ .Values.networking.NODE_SUBNET }} -- - --node-switch-cidr= -- {{- if eq .Values.networking.NET_STACK "dual_stack" -}} -- {{ .Values.dual_stack.JOIN_CIDR }} -- {{- else if eq .Values.networking.NET_STACK "ipv4" -}} -- {{ .Values.ipv4.JOIN_CIDR }} -- {{- else if eq .Values.networking.NET_STACK "ipv6" -}} -- {{ .Values.ipv6.JOIN_CIDR }} -- {{- end }} -- - --service-cluster-ip-range= -- {{- if eq .Values.networking.NET_STACK "dual_stack" -}} -- {{ .Values.dual_stack.SVC_CIDR }} -- {{- else if eq .Values.networking.NET_STACK "ipv4" -}} -- {{ .Values.ipv4.SVC_CIDR }} -- {{- else if eq .Values.networking.NET_STACK "ipv6" -}} -- {{ .Values.ipv6.SVC_CIDR }} -- {{- end }} -+ - --node-switch-cidr={{ index $cozyConfig.data "ipv4-join-cidr" }} -+ - --service-cluster-ip-range={{ index $cozyConfig.data "ipv4-svc-cidr" }} -+ {{- if .Values.global.logVerbosity }} -+ - --v={{ .Values.global.logVerbosity }} -+ {{- end }} - - --network-type={{- .Values.networking.NETWORK_TYPE }} - - --default-provider-name={{ .Values.networking.vlan.PROVIDER_NAME }} - - --default-interface-name={{- .Values.networking.vlan.VLAN_INTERFACE_NAME }} -diff --git a/packages/system/kubeovn/charts/kube-ovn/values.yaml b/packages/system/kubeovn/charts/kube-ovn/values.yaml -index bfffc4d..b880749 100644 ---- a/packages/system/kubeovn/charts/kube-ovn/values.yaml -+++ b/packages/system/kubeovn/charts/kube-ovn/values.yaml -@@ -70,10 +70,6 @@ func: - ENABLE_TPROXY: false - - ipv4: -- POD_CIDR: "10.16.0.0/16" -- POD_GATEWAY: "10.16.0.1" -- SVC_CIDR: "10.96.0.0/12" -- JOIN_CIDR: "100.64.0.0/16" - PINGER_EXTERNAL_ADDRESS: "1.1.1.1" - PINGER_EXTERNAL_DOMAIN: "alauda.cn." - diff --git a/packages/system/kubeovn/patches/mtu.diff b/packages/system/kubeovn/patches/mtu.diff deleted file mode 100644 index da3de3aa..00000000 --- a/packages/system/kubeovn/patches/mtu.diff +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml -index 63f4258..dafe1fd 100644 ---- a/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml -+++ b/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml -@@ -112,6 +112,9 @@ spec: - - --secure-serving={{- .Values.func.SECURE_SERVING }} - - --enable-ovn-ipsec={{- .Values.func.ENABLE_OVN_IPSEC }} - - --set-vxlan-tx-off={{- .Values.func.SET_VXLAN_TX_OFF }} -+ {{- with .Values.mtu }} -+ - --mtu={{ . }} -+ {{- end }} - securityContext: - runAsUser: 0 - privileged: false From 38a4adfaa31e8dda954c707b7a4210852424035f Mon Sep 17 00:00:00 2001 From: Kingdon B Date: Sun, 23 Nov 2025 14:45:10 -0500 Subject: [PATCH 02/33] update flux-instance chart as well (v0.33.0) Signed-off-by: Kingdon B --- .../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 | 1 - .../fluxcd-operator/patches/networkPolicy.diff | 6 +++--- .../system/fluxcd/charts/flux-instance/Chart.yaml | 4 ++-- .../system/fluxcd/charts/flux-instance/README.md | 2 +- 7 files changed, 24 insertions(+), 10 deletions(-) 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/charts/flux-operator/templates/network-policy.yaml index 0a9db1cc..f97ddba3 100644 --- a/packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml +++ b/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: diff --git a/packages/system/fluxcd-operator/patches/networkPolicy.diff b/packages/system/fluxcd-operator/patches/networkPolicy.diff index a7bf3207..e074ae2f 100644 --- a/packages/system/fluxcd-operator/patches/networkPolicy.diff +++ b/packages/system/fluxcd-operator/patches/networkPolicy.diff @@ -1,8 +1,8 @@ -diff --git a/packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml b/packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml +diff --git a/charts/flux-operator/templates/network-policy.yaml b/packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml new file mode 100644 --- /dev/null (revision 52a23eacfc32430d8b008b765c64a81526521bae) -+++ b/packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml (revision 52a23eacfc32430d8b008b765c64a81526521bae) -@@ -0,0 +1,18 @@ ++++ b/charts/flux-operator/templates/network-policy.yaml (revision 52a23eacfc32430d8b008b765c64a81526521bae) +@@ -0,0 +1,20 @@ +{{- if .Capabilities.APIVersions.Has "cilium.io/v2/CiliumClusterwideNetworkPolicy" }} +apiVersion: cilium.io/v2 +kind: CiliumClusterwideNetworkPolicy 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) From 8e351f18270f47ac2dd63b9c2ef3607e3710afb4 Mon Sep 17 00:00:00 2001 From: Kingdon B Date: Sun, 23 Nov 2025 14:50:32 -0500 Subject: [PATCH 03/33] Upgrade Flux to 2.7 series Flux 2.7.3 is currently the latest release, (I think Flux 2.7.4 is still just around the corner.) Signed-off-by: Kingdon B --- 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 837be8d8..3559a330 100644 --- a/packages/system/fluxcd/values.yaml +++ b/packages/system/fluxcd/values.yaml @@ -5,7 +5,7 @@ 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 From 644d71eef79e36dff7a78f01363869e5e5ca7159 Mon Sep 17 00:00:00 2001 From: nbykov0 <166552198+nbykov0@users.noreply.github.com> Date: Mon, 1 Dec 2025 17:49:52 +0300 Subject: [PATCH 04/33] [system:monitoring-agents] rename coredns metrics service Signed-off-by: nbykov0 <166552198+nbykov0@users.noreply.github.com> --- .../system/monitoring-agents/templates/coredns-scrape.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/system/monitoring-agents/templates/coredns-scrape.yaml b/packages/system/monitoring-agents/templates/coredns-scrape.yaml index 9c7253eb..223d553f 100644 --- a/packages/system/monitoring-agents/templates/coredns-scrape.yaml +++ b/packages/system/monitoring-agents/templates/coredns-scrape.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: Service metadata: - name: coredns + name: coredns-metrics namespace: kube-system labels: app: coredns @@ -19,7 +19,7 @@ spec: apiVersion: operator.victoriametrics.com/v1beta1 kind: VMServiceScrape metadata: - name: coredns + name: coredns-metrics namespace: cozy-monitoring spec: selector: From df277b350cc053bf9d6fb1da4ae14962ccbde308 Mon Sep 17 00:00:00 2001 From: nbykov0 <166552198+nbykov0@users.noreply.github.com> Date: Mon, 1 Dec 2025 17:45:07 +0300 Subject: [PATCH 05/33] [system:coredns] update app coredns labels to match Talos coredns labels Signed-off-by: nbykov0 <166552198+nbykov0@users.noreply.github.com> --- packages/system/coredns/values.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/system/coredns/values.yaml b/packages/system/coredns/values.yaml index b52efda2..3b5740ad 100644 --- a/packages/system/coredns/values.yaml +++ b/packages/system/coredns/values.yaml @@ -3,3 +3,4 @@ coredns: repository: registry.k8s.io/coredns/coredns tag: v1.12.4 replicaCount: 2 + k8sAppLabelOverride: kube-dns From 67e47256e265a6f1a13628b3b2af1c914f59c673 Mon Sep 17 00:00:00 2001 From: nbykov0 <166552198+nbykov0@users.noreply.github.com> Date: Mon, 1 Dec 2025 20:51:26 +0300 Subject: [PATCH 06/33] [system:monitoring-agents] separate metrics-server Signed-off-by: nbykov0 <166552198+nbykov0@users.noreply.github.com> --- packages/system/metrics-server/.helmignore | 0 packages/system/metrics-server/Chart.yaml | 3 ++ packages/system/metrics-server/Makefile | 10 +++++++ .../charts/metrics-server/.helmignore | 0 .../charts/metrics-server/CHANGELOG.md | 0 .../charts/metrics-server/Chart.yaml | 0 .../charts/metrics-server/README.md | 0 .../charts/metrics-server/RELEASE.md | 0 .../charts/metrics-server/ci/ci-values.yaml | 0 .../charts/metrics-server/templates/NOTES.txt | 0 .../metrics-server/templates/_helpers.tpl | 0 .../metrics-server/templates/apiservice.yaml | 0 .../clusterrole-aggregated-reader.yaml | 0 .../templates/clusterrole-nanny.yaml | 0 .../metrics-server/templates/clusterrole.yaml | 0 .../clusterrolebinding-auth-delegator.yaml | 0 .../templates/clusterrolebinding-nanny.yaml | 0 .../templates/clusterrolebinding.yaml | 0 .../templates/configmaps-nanny.yaml | 0 .../metrics-server/templates/deployment.yaml | 0 .../charts/metrics-server/templates/pdb.yaml | 0 .../charts/metrics-server/templates/psp.yaml | 0 .../metrics-server/templates/role-nanny.yaml | 0 .../templates/rolebinding-nanny.yaml | 0 .../metrics-server/templates/rolebinding.yaml | 0 .../metrics-server/templates/service.yaml | 0 .../templates/serviceaccount.yaml | 0 .../templates/servicemonitor.yaml | 0 .../charts/metrics-server/values.yaml | 0 packages/system/metrics-server/values.yaml | 15 ++++++++++ packages/system/monitoring-agents/Makefile | 4 --- packages/system/monitoring-agents/values.yaml | 29 ------------------- 32 files changed, 28 insertions(+), 33 deletions(-) create mode 100644 packages/system/metrics-server/.helmignore create mode 100644 packages/system/metrics-server/Chart.yaml create mode 100644 packages/system/metrics-server/Makefile rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/.helmignore (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/CHANGELOG.md (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/Chart.yaml (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/README.md (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/RELEASE.md (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/ci/ci-values.yaml (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/templates/NOTES.txt (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/templates/_helpers.tpl (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/templates/apiservice.yaml (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/templates/clusterrole-aggregated-reader.yaml (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/templates/clusterrole-nanny.yaml (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/templates/clusterrole.yaml (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/templates/clusterrolebinding-auth-delegator.yaml (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/templates/clusterrolebinding-nanny.yaml (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/templates/clusterrolebinding.yaml (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/templates/configmaps-nanny.yaml (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/templates/deployment.yaml (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/templates/pdb.yaml (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/templates/psp.yaml (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/templates/role-nanny.yaml (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/templates/rolebinding-nanny.yaml (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/templates/rolebinding.yaml (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/templates/service.yaml (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/templates/serviceaccount.yaml (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/templates/servicemonitor.yaml (100%) rename packages/system/{monitoring-agents => metrics-server}/charts/metrics-server/values.yaml (100%) create mode 100644 packages/system/metrics-server/values.yaml diff --git a/packages/system/metrics-server/.helmignore b/packages/system/metrics-server/.helmignore new file mode 100644 index 00000000..e69de29b diff --git a/packages/system/metrics-server/Chart.yaml b/packages/system/metrics-server/Chart.yaml new file mode 100644 index 00000000..d035ddb3 --- /dev/null +++ b/packages/system/metrics-server/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-metrics-server +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/metrics-server/Makefile b/packages/system/metrics-server/Makefile new file mode 100644 index 00000000..fb89db64 --- /dev/null +++ b/packages/system/metrics-server/Makefile @@ -0,0 +1,10 @@ +export NAME=metrics-server +export NAMESPACE=cozy-monitoring + +include ../../../scripts/package.mk + +update: + rm -rf charts + helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/ + helm repo update metrics-server + helm pull metrics-server/metrics-server --untar --untardir charts diff --git a/packages/system/monitoring-agents/charts/metrics-server/.helmignore b/packages/system/metrics-server/charts/metrics-server/.helmignore similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/.helmignore rename to packages/system/metrics-server/charts/metrics-server/.helmignore diff --git a/packages/system/monitoring-agents/charts/metrics-server/CHANGELOG.md b/packages/system/metrics-server/charts/metrics-server/CHANGELOG.md similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/CHANGELOG.md rename to packages/system/metrics-server/charts/metrics-server/CHANGELOG.md diff --git a/packages/system/monitoring-agents/charts/metrics-server/Chart.yaml b/packages/system/metrics-server/charts/metrics-server/Chart.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/Chart.yaml rename to packages/system/metrics-server/charts/metrics-server/Chart.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/README.md b/packages/system/metrics-server/charts/metrics-server/README.md similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/README.md rename to packages/system/metrics-server/charts/metrics-server/README.md diff --git a/packages/system/monitoring-agents/charts/metrics-server/RELEASE.md b/packages/system/metrics-server/charts/metrics-server/RELEASE.md similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/RELEASE.md rename to packages/system/metrics-server/charts/metrics-server/RELEASE.md diff --git a/packages/system/monitoring-agents/charts/metrics-server/ci/ci-values.yaml b/packages/system/metrics-server/charts/metrics-server/ci/ci-values.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/ci/ci-values.yaml rename to packages/system/metrics-server/charts/metrics-server/ci/ci-values.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/NOTES.txt b/packages/system/metrics-server/charts/metrics-server/templates/NOTES.txt similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/NOTES.txt rename to packages/system/metrics-server/charts/metrics-server/templates/NOTES.txt diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/_helpers.tpl b/packages/system/metrics-server/charts/metrics-server/templates/_helpers.tpl similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/_helpers.tpl rename to packages/system/metrics-server/charts/metrics-server/templates/_helpers.tpl diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/apiservice.yaml b/packages/system/metrics-server/charts/metrics-server/templates/apiservice.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/apiservice.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/apiservice.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/clusterrole-aggregated-reader.yaml b/packages/system/metrics-server/charts/metrics-server/templates/clusterrole-aggregated-reader.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/clusterrole-aggregated-reader.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/clusterrole-aggregated-reader.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/clusterrole-nanny.yaml b/packages/system/metrics-server/charts/metrics-server/templates/clusterrole-nanny.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/clusterrole-nanny.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/clusterrole-nanny.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/clusterrole.yaml b/packages/system/metrics-server/charts/metrics-server/templates/clusterrole.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/clusterrole.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/clusterrole.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/clusterrolebinding-auth-delegator.yaml b/packages/system/metrics-server/charts/metrics-server/templates/clusterrolebinding-auth-delegator.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/clusterrolebinding-auth-delegator.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/clusterrolebinding-auth-delegator.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/clusterrolebinding-nanny.yaml b/packages/system/metrics-server/charts/metrics-server/templates/clusterrolebinding-nanny.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/clusterrolebinding-nanny.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/clusterrolebinding-nanny.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/clusterrolebinding.yaml b/packages/system/metrics-server/charts/metrics-server/templates/clusterrolebinding.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/clusterrolebinding.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/clusterrolebinding.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/configmaps-nanny.yaml b/packages/system/metrics-server/charts/metrics-server/templates/configmaps-nanny.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/configmaps-nanny.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/configmaps-nanny.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/deployment.yaml b/packages/system/metrics-server/charts/metrics-server/templates/deployment.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/deployment.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/deployment.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/pdb.yaml b/packages/system/metrics-server/charts/metrics-server/templates/pdb.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/pdb.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/pdb.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/psp.yaml b/packages/system/metrics-server/charts/metrics-server/templates/psp.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/psp.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/psp.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/role-nanny.yaml b/packages/system/metrics-server/charts/metrics-server/templates/role-nanny.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/role-nanny.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/role-nanny.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/rolebinding-nanny.yaml b/packages/system/metrics-server/charts/metrics-server/templates/rolebinding-nanny.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/rolebinding-nanny.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/rolebinding-nanny.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/rolebinding.yaml b/packages/system/metrics-server/charts/metrics-server/templates/rolebinding.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/rolebinding.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/rolebinding.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/service.yaml b/packages/system/metrics-server/charts/metrics-server/templates/service.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/service.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/service.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/serviceaccount.yaml b/packages/system/metrics-server/charts/metrics-server/templates/serviceaccount.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/serviceaccount.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/serviceaccount.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/servicemonitor.yaml b/packages/system/metrics-server/charts/metrics-server/templates/servicemonitor.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/servicemonitor.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/servicemonitor.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/values.yaml b/packages/system/metrics-server/charts/metrics-server/values.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/values.yaml rename to packages/system/metrics-server/charts/metrics-server/values.yaml diff --git a/packages/system/metrics-server/values.yaml b/packages/system/metrics-server/values.yaml new file mode 100644 index 00000000..98d74b6c --- /dev/null +++ b/packages/system/metrics-server/values.yaml @@ -0,0 +1,15 @@ +metrics-server: + defaultArgs: + - --cert-dir=/tmp + - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname + - --kubelet-use-node-status-port + - --metric-resolution=15s + - --kubelet-insecure-tls + + metrics: + enabled: true + + serviceMonitor: + enabled: true + + diff --git a/packages/system/monitoring-agents/Makefile b/packages/system/monitoring-agents/Makefile index 42e762c3..f324bfef 100644 --- a/packages/system/monitoring-agents/Makefile +++ b/packages/system/monitoring-agents/Makefile @@ -11,10 +11,6 @@ update: helm pull prometheus-community/kube-state-metrics --untar --untardir charts # Node-exporter helm pull prometheus-community/prometheus-node-exporter --untar --untardir charts - # Metrics-server - helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/ - helm repo update metrics-server - helm pull metrics-server/metrics-server --untar --untardir charts # Fluent-bit helm repo add fluent https://fluent.github.io/helm-charts helm repo update fluent diff --git a/packages/system/monitoring-agents/values.yaml b/packages/system/monitoring-agents/values.yaml index 8c13c079..7b095c6c 100644 --- a/packages/system/monitoring-agents/values.yaml +++ b/packages/system/monitoring-agents/values.yaml @@ -1,32 +1,3 @@ -metrics-server: - defaultArgs: - - --cert-dir=/tmp - - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname - - --kubelet-use-node-status-port - - --metric-resolution=15s - - --kubelet-insecure-tls - - metrics: - enabled: true - - serviceMonitor: - enabled: true - - victoria-logs-single: - server: - persistentVolume: - enabled: true - size: 10Gi - - grafana: - enabled: false - kube-state-metrics: - enabled: false - prometheus-node-exporter: - enabled: false - alertmanager: - name: vmalertmanager-alertmanager - kube-state-metrics: extraArgs: - --metric-labels-allowlist=pods=[*],deployments=[*] From 13e0501acdc49e9e46f9a8ecb449cbaabdaf039a Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 1 Dec 2025 22:15:24 +0100 Subject: [PATCH 07/33] Add changelogs for v0.38.2 Signed-off-by: Andrei Kvapil --- docs/changelogs/v0.38.2.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 docs/changelogs/v0.38.2.md diff --git a/docs/changelogs/v0.38.2.md b/docs/changelogs/v0.38.2.md new file mode 100644 index 00000000..feb80d1f --- /dev/null +++ b/docs/changelogs/v0.38.2.md @@ -0,0 +1,13 @@ + + + +## Fixes + +* **[api] Revert dynamic list kinds representation fix (fixes namespace deletion regression)**: Reverted changes from #1630 that caused a regression affecting namespace deletion and upgrades from previous versions. The regression caused namespace deletion failures with errors like "content is not a list: []unstructured.Unstructured" during namespace finalization. This revert restores compatibility with namespace deletion controller and fixes upgrade issues from previous versions, particularly when running migration 20 ([**@kvaps**](https://github.com/kvaps) in #1677). + +--- + +**Full Changelog**: [v0.38.1...v0.38.2](https://github.com/cozystack/cozystack/compare/v0.38.1...v0.38.2) + From 06a25c1c458eefcb5196636a9c6a043fc4e46eb5 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 28 Nov 2025 20:07:26 +0100 Subject: [PATCH 08/33] [kubernetes] Add version management system with automated version updates Signed-off-by: Andrei Kvapil --- .github/workflows/pre-commit.yml | 2 +- packages/apps/kubernetes/.helmignore | 1 + packages/apps/kubernetes/Makefile | 5 +- packages/apps/kubernetes/README.md | 2 +- packages/apps/kubernetes/files/versions.yaml | 10 +- .../apps/kubernetes/hack/update-versions.sh | 260 ++++++++++++++++++ packages/apps/kubernetes/values.schema.json | 16 +- packages/apps/kubernetes/values.yaml | 12 +- .../cozyrds/kubernetes.yaml | 2 +- 9 files changed, 292 insertions(+), 18 deletions(-) create mode 100755 packages/apps/kubernetes/hack/update-versions.sh diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 685d41fe..ef1ce088 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -28,7 +28,7 @@ jobs: - name: Install generate run: | - curl -sSL https://github.com/cozystack/cozyvalues-gen/releases/download/v1.0.5/cozyvalues-gen-linux-amd64.tar.gz | tar -xzvf- -C /usr/local/bin/ cozyvalues-gen + curl -sSL https://github.com/cozystack/cozyvalues-gen/releases/download/v1.0.6/cozyvalues-gen-linux-amd64.tar.gz | tar -xzvf- -C /usr/local/bin/ cozyvalues-gen - name: Run pre-commit hooks run: | diff --git a/packages/apps/kubernetes/.helmignore b/packages/apps/kubernetes/.helmignore index 1ea0ae84..3de7d4a5 100644 --- a/packages/apps/kubernetes/.helmignore +++ b/packages/apps/kubernetes/.helmignore @@ -1,3 +1,4 @@ .helmignore /logos /Makefile +/hack diff --git a/packages/apps/kubernetes/Makefile b/packages/apps/kubernetes/Makefile index 799a19bc..ae6dd757 100644 --- a/packages/apps/kubernetes/Makefile +++ b/packages/apps/kubernetes/Makefile @@ -6,9 +6,12 @@ include ../../../scripts/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md - yq -o=json -i '.properties.version.enum = (load("files/versions.yaml") | keys)' values.schema.json ../../../hack/update-crd.sh +update: + hack/update-versions.sh + make generate + image: image-ubuntu-container-disk image-kubevirt-cloud-provider image-kubevirt-csi-driver image-cluster-autoscaler image-ubuntu-container-disk: diff --git a/packages/apps/kubernetes/README.md b/packages/apps/kubernetes/README.md index 4bc344a2..8bff49aa 100644 --- a/packages/apps/kubernetes/README.md +++ b/packages/apps/kubernetes/README.md @@ -104,7 +104,7 @@ See the reference for components utilized in this service: | `nodeGroups[name].resources.memory` | Memory (RAM) available. | `quantity` | `""` | | `nodeGroups[name].gpus` | List of GPUs to attach (NVIDIA driver requires at least 4 GiB RAM). | `[]object` | `[]` | | `nodeGroups[name].gpus[i].name` | Name of GPU, such as "nvidia.com/AD102GL_L40S". | `string` | `""` | -| `version` | Kubernetes version (vMAJOR.MINOR). Supported: 1.28–1.33. | `string` | `v1.33` | +| `version` | Kubernetes major.minor version to deploy | `string` | `v1.33` | | `host` | External hostname for Kubernetes cluster. Defaults to `.` if empty. | `string` | `""` | diff --git a/packages/apps/kubernetes/files/versions.yaml b/packages/apps/kubernetes/files/versions.yaml index f9236751..51a36034 100644 --- a/packages/apps/kubernetes/files/versions.yaml +++ b/packages/apps/kubernetes/files/versions.yaml @@ -1,6 +1,6 @@ -"v1.28": "v1.28.15" -"v1.29": "v1.29.15" -"v1.30": "v1.30.14" -"v1.31": "v1.31.10" -"v1.32": "v1.32.6" "v1.33": "v1.33.0" +"v1.32": "v1.32.10" +"v1.31": "v1.31.14" +"v1.30": "v1.30.14" +"v1.29": "v1.29.15" +"v1.28": "v1.28.15" diff --git a/packages/apps/kubernetes/hack/update-versions.sh b/packages/apps/kubernetes/hack/update-versions.sh new file mode 100755 index 00000000..85c962c5 --- /dev/null +++ b/packages/apps/kubernetes/hack/update-versions.sh @@ -0,0 +1,260 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +KUBERNETES_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +VALUES_FILE="${KUBERNETES_DIR}/values.yaml" +VERSIONS_FILE="${KUBERNETES_DIR}/files/versions.yaml" +MAKEFILE="${KUBERNETES_DIR}/Makefile" +KAMAJI_DOCKERFILE="${KUBERNETES_DIR}/../../system/kamaji/images/kamaji/Dockerfile" + +# Check if skopeo is installed +if ! command -v skopeo &> /dev/null; then + echo "Error: skopeo is not installed. Please install skopeo and try again." >&2 + exit 1 +fi + +# Check if jq is installed +if ! command -v jq &> /dev/null; then + echo "Error: jq is not installed. Please install jq and try again." >&2 + exit 1 +fi + +# Get kamaji version from Dockerfile +echo "Reading kamaji version from Dockerfile..." +if [ ! -f "$KAMAJI_DOCKERFILE" ]; then + echo "Error: Kamaji Dockerfile not found at $KAMAJI_DOCKERFILE" >&2 + exit 1 +fi + +KAMAJI_VERSION=$(grep "^ARG VERSION=" "$KAMAJI_DOCKERFILE" | cut -d= -f2 | tr -d '"') +if [ -z "$KAMAJI_VERSION" ]; then + echo "Error: Could not extract kamaji version from Dockerfile" >&2 + exit 1 +fi + +echo "Kamaji version: $KAMAJI_VERSION" + +# Get Kubernetes version from kamaji repository +echo "Fetching Kubernetes version from kamaji repository..." +KUBERNETES_VERSION_FROM_KAMAJI=$(curl -sSL "https://raw.githubusercontent.com/clastix/kamaji/${KAMAJI_VERSION}/internal/upgrade/kubeadm_version.go" | grep "KubeadmVersion" | sed -E 's/.*KubeadmVersion = "([^"]+)".*/\1/') + +if [ -z "$KUBERNETES_VERSION_FROM_KAMAJI" ]; then + echo "Error: Could not fetch Kubernetes version from kamaji repository" >&2 + exit 1 +fi + +echo "Kubernetes version from kamaji: $KUBERNETES_VERSION_FROM_KAMAJI" + +# Extract major.minor version (e.g., "1.33" from "v1.33.0") +KUBERNETES_MAJOR_MINOR=$(echo "$KUBERNETES_VERSION_FROM_KAMAJI" | sed -E 's/v([0-9]+)\.([0-9]+)\.[0-9]+/\1.\2/') +KUBERNETES_MAJOR=$(echo "$KUBERNETES_MAJOR_MINOR" | cut -d. -f1) +KUBERNETES_MINOR=$(echo "$KUBERNETES_MAJOR_MINOR" | cut -d. -f2) + +echo "Kubernetes major.minor: $KUBERNETES_MAJOR_MINOR" + +# Get available image tags +echo "Fetching available image tags from registry..." +AVAILABLE_TAGS=$(skopeo list-tags docker://registry.k8s.io/kube-apiserver | jq -r '.Tags[] | select(test("^v[0-9]+\\.[0-9]+\\.[0-9]+$"))' | sort -V) + +if [ -z "$AVAILABLE_TAGS" ]; then + echo "Error: Could not fetch available image tags" >&2 + exit 1 +fi + +# Filter out versions higher than KUBERNETES_VERSION_FROM_KAMAJI +echo "Filtering versions above ${KUBERNETES_VERSION_FROM_KAMAJI}..." +FILTERED_TAGS=$(echo "$AVAILABLE_TAGS" | while read tag; do + if [ -n "$tag" ]; then + # Compare tag with KUBERNETES_VERSION_FROM_KAMAJI using version sort + # Include tag if it's less than or equal to KUBERNETES_VERSION_FROM_KAMAJI + if [ "$(printf '%s\n%s\n' "$tag" "$KUBERNETES_VERSION_FROM_KAMAJI" | sort -V | head -1)" = "$tag" ] || [ "$tag" = "$KUBERNETES_VERSION_FROM_KAMAJI" ]; then + echo "$tag" + fi + fi +done) + +if [ -z "$FILTERED_TAGS" ]; then + echo "Error: No versions found after filtering" >&2 + exit 1 +fi + +AVAILABLE_TAGS="$FILTERED_TAGS" +echo "Filtered to $(echo "$AVAILABLE_TAGS" | wc -l | tr -d ' ') versions" + +# Find the latest patch version for the supported major.minor version +echo "Finding latest patch version for ${KUBERNETES_MAJOR_MINOR}..." +SUPPORTED_PATCH_TAGS=$(echo "$AVAILABLE_TAGS" | grep "^v${KUBERNETES_MAJOR}\\.${KUBERNETES_MINOR}\\.") +if [ -z "$SUPPORTED_PATCH_TAGS" ]; then + echo "Error: Could not find any patch versions for ${KUBERNETES_MAJOR_MINOR}" >&2 + exit 1 +fi +KUBERNETES_VERSION=$(echo "$SUPPORTED_PATCH_TAGS" | tail -n1) +echo "Using latest patch version: $KUBERNETES_VERSION" + +# Build versions map: major.minor -> latest patch version +# First, collect all unique major.minor versions from available tags +echo "Collecting all available major.minor versions..." +ALL_MAJOR_MINOR_VERSIONS=$(echo "$AVAILABLE_TAGS" | sed -E 's/v([0-9]+)\.([0-9]+)\.[0-9]+/v\1.\2/' | sort -V -u) + +# Find the position of the supported version in the sorted list +SUPPORTED_MAJOR_MINOR="v${KUBERNETES_MAJOR}.${KUBERNETES_MINOR}" +echo "Looking for supported version: $SUPPORTED_MAJOR_MINOR" + +# Get all versions that are <= supported version +# Create a temporary file for filtering +TEMP_VERSIONS=$(mktemp) + +echo "$ALL_MAJOR_MINOR_VERSIONS" | while read version; do + # Compare versions using sort -V (version sort) + # If version <= supported, include it + if [ "$(printf '%s\n%s\n' "$version" "$SUPPORTED_MAJOR_MINOR" | sort -V | head -1)" = "$version" ] || [ "$version" = "$SUPPORTED_MAJOR_MINOR" ]; then + echo "$version" + fi +done > "$TEMP_VERSIONS" + +# Get the supported version and 5 previous versions (total 6 versions) +# First, find the position of supported version +SUPPORTED_POS=$(grep -n "^${SUPPORTED_MAJOR_MINOR}$" "$TEMP_VERSIONS" | cut -d: -f1) + +if [ -z "$SUPPORTED_POS" ]; then + echo "Error: Supported version $SUPPORTED_MAJOR_MINOR not found in available versions" >&2 + exit 1 +fi + +# Calculate start position (5 versions before supported, or from beginning if less than 5 available) +TOTAL_LINES=$(wc -l < "$TEMP_VERSIONS" | tr -d ' ') +START_POS=$((SUPPORTED_POS - 5)) +if [ $START_POS -lt 1 ]; then + START_POS=1 +fi + +# Extract versions from START_POS to SUPPORTED_POS (inclusive) +CANDIDATE_VERSIONS=$(sed -n "${START_POS},${SUPPORTED_POS}p" "$TEMP_VERSIONS") + +if [ -z "$CANDIDATE_VERSIONS" ]; then + echo "Error: Could not find supported version $SUPPORTED_MAJOR_MINOR in available versions" >&2 + exit 1 +fi + +declare -A VERSION_MAP +VERSIONS=() + +# Process each candidate version +for major_minor_key in $CANDIDATE_VERSIONS; do + # Extract major and minor for matching + major=$(echo "$major_minor_key" | sed -E 's/v([0-9]+)\.([0-9]+)/\1/') + minor=$(echo "$major_minor_key" | sed -E 's/v([0-9]+)\.([0-9]+)/\2/') + + # Find all tags that match this major.minor version + matching_tags=$(echo "$AVAILABLE_TAGS" | grep "^v${major}\\.${minor}\\.") + + if [ -n "$matching_tags" ]; then + # Get the latest patch version for this major.minor version + latest_tag=$(echo "$matching_tags" | tail -n1) + + VERSION_MAP["${major_minor_key}"]="${latest_tag}" + VERSIONS+=("${major_minor_key}") + echo "Found version: ${major_minor_key} -> ${latest_tag}" + fi +done + +if [ ${#VERSIONS[@]} -eq 0 ]; then + echo "Error: No matching versions found" >&2 + exit 1 +fi + +# Sort versions in descending order (newest first) +IFS=$'\n' VERSIONS=($(printf '%s\n' "${VERSIONS[@]}" | sort -V -r)) +unset IFS + +echo "Versions to add: ${VERSIONS[*]}" + +# Create/update versions.yaml file +echo "Updating $VERSIONS_FILE..." +{ + for ver in "${VERSIONS[@]}"; do + echo "\"${ver}\": \"${VERSION_MAP[$ver]}\"" + done +} > "$VERSIONS_FILE" + +echo "Successfully updated $VERSIONS_FILE" + +# Update values.yaml - enum with major.minor versions only +TEMP_FILE=$(mktemp) +trap "rm -f $TEMP_FILE $TEMP_VERSIONS" EXIT + +# Build new version section +NEW_VERSION_SECTION="## @enum {string} Version" +for ver in "${VERSIONS[@]}"; do + NEW_VERSION_SECTION="${NEW_VERSION_SECTION} +## @value $ver" +done +NEW_VERSION_SECTION="${NEW_VERSION_SECTION} + +## @param {Version} version - Kubernetes major.minor version to deploy +version: \"${VERSIONS[0]}\"" + +# Check if version section already exists +if grep -q "^## @enum {string} Version" "$VALUES_FILE"; then + # Version section exists, update it using awk + echo "Updating existing version section in $VALUES_FILE..." + + # Use awk to replace the section from "## @enum {string} Version" to "version: " (inclusive) + # Delete the old section and insert the new one + awk -v new_section="$NEW_VERSION_SECTION" ' + /^## @enum {string} Version/ { + in_section = 1 + print new_section + next + } + in_section && /^version: / { + in_section = 0 + next + } + in_section { + next + } + { print } + ' "$VALUES_FILE" > "$TEMP_FILE.tmp" + mv "$TEMP_FILE.tmp" "$VALUES_FILE" +else + # Version section doesn't exist, insert it before Application-specific parameters section + echo "Inserting new version section in $VALUES_FILE..." + + # Use awk to insert before "## @section Application-specific parameters" + awk -v new_section="$NEW_VERSION_SECTION" ' + /^## @section Application-specific parameters/ { + print new_section + print "" + } + { print } + ' "$VALUES_FILE" > "$TEMP_FILE.tmp" + mv "$TEMP_FILE.tmp" "$VALUES_FILE" +fi + +echo "Successfully updated $VALUES_FILE with versions: ${VERSIONS[*]}" + +# Update KUBERNETES_VERSION in Makefile +# Extract major.minor from KUBERNETES_VERSION (e.g., "v1.33" from "v1.33.4") +KUBERNETES_MAJOR_MINOR_FOR_MAKEFILE=$(echo "$KUBERNETES_VERSION" | sed -E 's/v([0-9]+)\.([0-9]+)\.[0-9]+/v\1.\2/') + +if grep -q "^KUBERNETES_VERSION" "$MAKEFILE"; then + # Update existing KUBERNETES_VERSION line using awk + echo "Updating KUBERNETES_VERSION in $MAKEFILE..." + awk -v new_version="${KUBERNETES_MAJOR_MINOR_FOR_MAKEFILE}" ' + /^KUBERNETES_VERSION = / { + print "KUBERNETES_VERSION = " new_version + next + } + { print } + ' "$MAKEFILE" > "$TEMP_FILE.tmp" + mv "$TEMP_FILE.tmp" "$MAKEFILE" + echo "Successfully updated KUBERNETES_VERSION in $MAKEFILE to ${KUBERNETES_MAJOR_MINOR_FOR_MAKEFILE}" +else + echo "Warning: KUBERNETES_VERSION not found in $MAKEFILE" >&2 +fi + diff --git a/packages/apps/kubernetes/values.schema.json b/packages/apps/kubernetes/values.schema.json index 6092d35e..9ec0c416 100644 --- a/packages/apps/kubernetes/values.schema.json +++ b/packages/apps/kubernetes/values.schema.json @@ -492,7 +492,7 @@ } }, "host": { - "description": "External hostname for Kubernetes cluster. Defaults to `.` if empty.", + "description": "External hostname for Kubernetes cluster. Defaults to `\u003ccluster-name\u003e.\u003ctenant-host\u003e` if empty.", "type": "string", "default": "" }, @@ -615,17 +615,17 @@ "default": "replicated" }, "version": { - "description": "Kubernetes version (vMAJOR.MINOR). Supported: 1.28–1.33.", + "description": "Kubernetes major.minor version to deploy", "type": "string", "default": "v1.33", "enum": [ - "v1.28", - "v1.29", - "v1.30", - "v1.31", + "v1.33", "v1.32", - "v1.33" + "v1.31", + "v1.30", + "v1.29", + "v1.28" ] } } -} +} \ No newline at end of file diff --git a/packages/apps/kubernetes/values.yaml b/packages/apps/kubernetes/values.yaml index 312e0634..567d2e02 100644 --- a/packages/apps/kubernetes/values.yaml +++ b/packages/apps/kubernetes/values.yaml @@ -46,9 +46,19 @@ nodeGroups: resources: {} gpus: [] -## @param {string} version - Kubernetes version (vMAJOR.MINOR). Supported: 1.28–1.33. +## +## @enum {string} Version +## @value v1.33 +## @value v1.32 +## @value v1.31 +## @value v1.30 +## @value v1.29 +## @value v1.28 + +## @param {Version} version - Kubernetes major.minor version to deploy version: "v1.33" + ## @param {string} host - External hostname for Kubernetes cluster. Defaults to `.` if empty. host: "" diff --git a/packages/system/cozystack-resource-definitions/cozyrds/kubernetes.yaml b/packages/system/cozystack-resource-definitions/cozyrds/kubernetes.yaml index 86e8694d..05ed110f 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/kubernetes.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/kubernetes.yaml @@ -8,7 +8,7 @@ spec: singular: kubernetes plural: kuberneteses openAPISchema: |- - {"title":"Chart Values","type":"object","properties":{"addons":{"description":"Cluster addons configuration.","type":"object","default":{},"required":["certManager","cilium","coredns","fluxcd","gatewayAPI","gpuOperator","ingressNginx","monitoringAgents","velero","verticalPodAutoscaler"],"properties":{"certManager":{"description":"Cert-manager addon.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable cert-manager.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"cilium":{"description":"Cilium CNI plugin.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"coredns":{"description":"CoreDNS addon.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"fluxcd":{"description":"FluxCD GitOps operator.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable FluxCD.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"gatewayAPI":{"description":"Gateway API addon.","type":"object","default":{},"required":["enabled"],"properties":{"enabled":{"description":"Enable Gateway API.","type":"boolean","default":false}}},"gpuOperator":{"description":"NVIDIA GPU Operator.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable GPU Operator.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"ingressNginx":{"description":"Ingress-NGINX controller.","type":"object","default":{},"required":["enabled","exposeMethod","valuesOverride"],"properties":{"enabled":{"description":"Enable the controller (requires nodes labeled `ingress-nginx`).","type":"boolean","default":false},"exposeMethod":{"description":"Method to expose the controller. Allowed values: `Proxied`, `LoadBalancer`.","type":"string","default":"Proxied"},"hosts":{"description":"Domains routed to this tenant cluster when `exposeMethod` is `Proxied`.","type":"array","default":[],"items":{"type":"string"}},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"monitoringAgents":{"description":"Monitoring agents.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable monitoring agents.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"velero":{"description":"Velero backup/restore addon.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable Velero.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"verticalPodAutoscaler":{"description":"Vertical Pod Autoscaler.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}}}},"controlPlane":{"description":"Kubernetes control-plane configuration.","type":"object","default":{},"required":["apiServer","controllerManager","konnectivity","replicas","scheduler"],"properties":{"apiServer":{"description":"API Server configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for API Server.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"medium","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"controllerManager":{"description":"Controller Manager configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Controller Manager.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"konnectivity":{"description":"Konnectivity configuration.","type":"object","default":{},"required":["server"],"properties":{"server":{"description":"Konnectivity Server configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Konnectivity.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}}}},"replicas":{"description":"Number of control-plane replicas.","type":"integer","default":2},"scheduler":{"description":"Scheduler configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Scheduler.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}}}},"host":{"description":"External hostname for Kubernetes cluster. Defaults to `.` if empty.","type":"string","default":""},"nodeGroups":{"description":"Worker nodes configuration map.","type":"object","default":{"md0":{"ephemeralStorage":"20Gi","gpus":[],"instanceType":"u1.medium","maxReplicas":10,"minReplicas":0,"resources":{},"roles":["ingress-nginx"]}},"additionalProperties":{"type":"object","required":["ephemeralStorage","instanceType","maxReplicas","minReplicas","resources"],"properties":{"ephemeralStorage":{"description":"Ephemeral storage size.","default":"20Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"gpus":{"description":"List of GPUs to attach (NVIDIA driver requires at least 4 GiB RAM).","type":"array","items":{"type":"object","required":["name"],"properties":{"name":{"description":"Name of GPU, such as \"nvidia.com/AD102GL_L40S\".","type":"string"}}}},"instanceType":{"description":"Virtual machine instance type.","type":"string","default":"u1.medium"},"maxReplicas":{"description":"Maximum number of replicas.","type":"integer","default":10},"minReplicas":{"description":"Minimum number of replicas.","type":"integer","default":0},"resources":{"description":"CPU and memory resources for each worker node.","type":"object","properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"roles":{"description":"List of node roles.","type":"array","items":{"type":"string"}}}}},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":"replicated"},"version":{"description":"Kubernetes version (vMAJOR.MINOR). Supported: 1.28–1.33.","type":"string","default":"v1.33","enum":["v1.28","v1.29","v1.30","v1.31","v1.32","v1.33"]}}} + {"title":"Chart Values","type":"object","properties":{"addons":{"description":"Cluster addons configuration.","type":"object","default":{},"required":["certManager","cilium","coredns","fluxcd","gatewayAPI","gpuOperator","ingressNginx","monitoringAgents","velero","verticalPodAutoscaler"],"properties":{"certManager":{"description":"Cert-manager addon.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable cert-manager.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"cilium":{"description":"Cilium CNI plugin.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"coredns":{"description":"CoreDNS addon.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"fluxcd":{"description":"FluxCD GitOps operator.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable FluxCD.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"gatewayAPI":{"description":"Gateway API addon.","type":"object","default":{},"required":["enabled"],"properties":{"enabled":{"description":"Enable Gateway API.","type":"boolean","default":false}}},"gpuOperator":{"description":"NVIDIA GPU Operator.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable GPU Operator.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"ingressNginx":{"description":"Ingress-NGINX controller.","type":"object","default":{},"required":["enabled","exposeMethod","valuesOverride"],"properties":{"enabled":{"description":"Enable the controller (requires nodes labeled `ingress-nginx`).","type":"boolean","default":false},"exposeMethod":{"description":"Method to expose the controller. Allowed values: `Proxied`, `LoadBalancer`.","type":"string","default":"Proxied"},"hosts":{"description":"Domains routed to this tenant cluster when `exposeMethod` is `Proxied`.","type":"array","default":[],"items":{"type":"string"}},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"monitoringAgents":{"description":"Monitoring agents.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable monitoring agents.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"velero":{"description":"Velero backup/restore addon.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable Velero.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"verticalPodAutoscaler":{"description":"Vertical Pod Autoscaler.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}}}},"controlPlane":{"description":"Kubernetes control-plane configuration.","type":"object","default":{},"required":["apiServer","controllerManager","konnectivity","replicas","scheduler"],"properties":{"apiServer":{"description":"API Server configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for API Server.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"medium","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"controllerManager":{"description":"Controller Manager configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Controller Manager.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"konnectivity":{"description":"Konnectivity configuration.","type":"object","default":{},"required":["server"],"properties":{"server":{"description":"Konnectivity Server configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Konnectivity.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}}}},"replicas":{"description":"Number of control-plane replicas.","type":"integer","default":2},"scheduler":{"description":"Scheduler configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Scheduler.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}}}},"host":{"description":"External hostname for Kubernetes cluster. Defaults to `.` if empty.","type":"string","default":""},"nodeGroups":{"description":"Worker nodes configuration map.","type":"object","default":{"md0":{"ephemeralStorage":"20Gi","gpus":[],"instanceType":"u1.medium","maxReplicas":10,"minReplicas":0,"resources":{},"roles":["ingress-nginx"]}},"additionalProperties":{"type":"object","required":["ephemeralStorage","instanceType","maxReplicas","minReplicas","resources"],"properties":{"ephemeralStorage":{"description":"Ephemeral storage size.","default":"20Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"gpus":{"description":"List of GPUs to attach (NVIDIA driver requires at least 4 GiB RAM).","type":"array","items":{"type":"object","required":["name"],"properties":{"name":{"description":"Name of GPU, such as \"nvidia.com/AD102GL_L40S\".","type":"string"}}}},"instanceType":{"description":"Virtual machine instance type.","type":"string","default":"u1.medium"},"maxReplicas":{"description":"Maximum number of replicas.","type":"integer","default":10},"minReplicas":{"description":"Minimum number of replicas.","type":"integer","default":0},"resources":{"description":"CPU and memory resources for each worker node.","type":"object","properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"roles":{"description":"List of node roles.","type":"array","items":{"type":"string"}}}}},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":"replicated"},"version":{"description":"Kubernetes major.minor version to deploy","type":"string","default":"v1.33","enum":["v1.33","v1.32","v1.31","v1.30","v1.29","v1.28"]}}} release: prefix: kubernetes- labels: From 3d5118f5b3c451d0d35729ecefede3bb3d2f2083 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 28 Nov 2025 15:27:35 +0100 Subject: [PATCH 09/33] [postgres] Add version management system with automated version updates Signed-off-by: Andrei Kvapil --- packages/apps/postgres/.helmignore | 1 + packages/apps/postgres/Makefile | 4 + packages/apps/postgres/README.md | 1 + packages/apps/postgres/files/versions.yaml | 6 + .../apps/postgres/hack/update-versions.sh | 138 ++++++++++++++++++ .../apps/postgres/templates/_versions.tpl | 8 + packages/apps/postgres/templates/db.yaml | 1 + .../apps/postgres/templates/init-job.yaml | 2 +- packages/apps/postgres/values.schema.json | 13 ++ packages/apps/postgres/values.yaml | 11 ++ .../cozyrds/postgres.yaml | 4 +- 11 files changed, 186 insertions(+), 3 deletions(-) create mode 100644 packages/apps/postgres/files/versions.yaml create mode 100755 packages/apps/postgres/hack/update-versions.sh create mode 100644 packages/apps/postgres/templates/_versions.tpl diff --git a/packages/apps/postgres/.helmignore b/packages/apps/postgres/.helmignore index 1ea0ae84..3de7d4a5 100644 --- a/packages/apps/postgres/.helmignore +++ b/packages/apps/postgres/.helmignore @@ -1,3 +1,4 @@ .helmignore /logos /Makefile +/hack diff --git a/packages/apps/postgres/Makefile b/packages/apps/postgres/Makefile index 8b1dce9d..a2ba188f 100644 --- a/packages/apps/postgres/Makefile +++ b/packages/apps/postgres/Makefile @@ -3,3 +3,7 @@ include ../../../scripts/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md ../../../hack/update-crd.sh + +update: + hack/update-versions.sh + make generate diff --git a/packages/apps/postgres/README.md b/packages/apps/postgres/README.md index 61e8e05f..5a550f7a 100644 --- a/packages/apps/postgres/README.md +++ b/packages/apps/postgres/README.md @@ -76,6 +76,7 @@ See: | `size` | Persistent Volume Claim size available for application data. | `quantity` | `10Gi` | | `storageClass` | StorageClass used to store the data. | `string` | `""` | | `external` | Enable external access from outside the cluster. | `bool` | `false` | +| `version` | PostgreSQL major version to deploy | `string` | `v18` | ### Application-specific parameters diff --git a/packages/apps/postgres/files/versions.yaml b/packages/apps/postgres/files/versions.yaml new file mode 100644 index 00000000..e4fe13ea --- /dev/null +++ b/packages/apps/postgres/files/versions.yaml @@ -0,0 +1,6 @@ +"v18": "v18.1" +"v17": "v17.7" +"v16": "v16.11" +"v15": "v15.15" +"v14": "v14.20" +"v13": "v13.22" diff --git a/packages/apps/postgres/hack/update-versions.sh b/packages/apps/postgres/hack/update-versions.sh new file mode 100755 index 00000000..c92b3895 --- /dev/null +++ b/packages/apps/postgres/hack/update-versions.sh @@ -0,0 +1,138 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +POSTGRES_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +VALUES_FILE="${POSTGRES_DIR}/values.yaml" +VERSIONS_FILE="${POSTGRES_DIR}/files/versions.yaml" + +# Get supported major versions from GitHub README +echo "Fetching supported major versions from GitHub..." +SUPPORTED_MAJOR_VERSIONS=$(curl -sSL 'https://raw.githubusercontent.com/cloudnative-pg/postgres-containers/refs/heads/main/README.md' | sed -n '/# CNPG PostgreSQL Container Images/,/#/p' | awk -F' +| +' '$4 ~ /[0-9]+\-[0-9]+\-[0-9]+/ && $6 ~ /[0-9]+\-[0-9]+\-[0-9]+/ {print $2}' | sort -u | xargs) + +if [ -z "$SUPPORTED_MAJOR_VERSIONS" ]; then + echo "Error: Could not fetch supported major versions" >&2 + exit 1 +fi + +echo "Supported major versions: $SUPPORTED_MAJOR_VERSIONS" + +# Check if skopeo is installed +if ! command -v skopeo &> /dev/null; then + echo "Error: skopeo is not installed. Please install skopeo and try again." >&2 + exit 1 +fi + +# Check if jq is installed +if ! command -v jq &> /dev/null; then + echo "Error: jq is not installed. Please install jq and try again." >&2 + exit 1 +fi + +# Get available image tags +echo "Fetching available image tags from registry..." +AVAILABLE_TAGS=$(skopeo list-tags docker://ghcr.io/cloudnative-pg/postgresql | jq -r '.Tags[] | select(test("^[0-9]+\\.[0-9]+$"))' | sort -V) + +if [ -z "$AVAILABLE_TAGS" ]; then + echo "Error: Could not fetch available image tags" >&2 + exit 1 +fi + +# Build versions map: major version -> latest minor version +declare -A VERSION_MAP +MAJOR_VERSIONS=() + +for major_version in $SUPPORTED_MAJOR_VERSIONS; do + # Extract major version number (e.g., "18" from "18.1") + major_num=$(echo "$major_version" | cut -d. -f1) + + # Find all tags that match this major version + matching_tags=$(echo "$AVAILABLE_TAGS" | grep "^${major_num}\\.") + + if [ -n "$matching_tags" ]; then + # Get the latest minor version for this major version + latest_tag=$(echo "$matching_tags" | tail -n1) + VERSION_MAP["v${major_num}"]="v${latest_tag}" + MAJOR_VERSIONS+=("v${major_num}") + echo "Found version: v${major_num} -> v${latest_tag}" + fi +done + +if [ ${#MAJOR_VERSIONS[@]} -eq 0 ]; then + echo "Error: No matching versions found" >&2 + exit 1 +fi + +# Sort major versions in descending order (newest first) +IFS=$'\n' MAJOR_VERSIONS=($(printf '%s\n' "${MAJOR_VERSIONS[@]}" | sort -V -r)) +unset IFS + +echo "Major versions to add: ${MAJOR_VERSIONS[*]}" + +# Create/update versions.yaml file +echo "Updating $VERSIONS_FILE..." +{ + for major_ver in "${MAJOR_VERSIONS[@]}"; do + echo "\"${major_ver}\": \"${VERSION_MAP[$major_ver]}\"" + done +} > "$VERSIONS_FILE" + +echo "Successfully updated $VERSIONS_FILE" + +# Update values.yaml - enum with major versions only +TEMP_FILE=$(mktemp) +trap "rm -f $TEMP_FILE" EXIT + +# Build new version section +NEW_VERSION_SECTION="## @enum {string} Version" +for major_ver in "${MAJOR_VERSIONS[@]}"; do + NEW_VERSION_SECTION="${NEW_VERSION_SECTION} +## @value $major_ver" +done +NEW_VERSION_SECTION="${NEW_VERSION_SECTION} + +## @param {Version} version - PostgreSQL major version to deploy +version: ${MAJOR_VERSIONS[0]}" + +# Check if version section already exists +if grep -q "^## @enum {string} Version" "$VALUES_FILE"; then + # Version section exists, update it using awk + echo "Updating existing version section in $VALUES_FILE..." + + # Use awk to replace the section from "## @enum {string} Version" to "version: " (inclusive) + # Delete the old section and insert the new one + awk -v new_section="$NEW_VERSION_SECTION" ' + /^## @enum {string} Version/ { + in_section = 1 + print new_section + next + } + in_section && /^version: / { + in_section = 0 + next + } + in_section { + next + } + { print } + ' "$VALUES_FILE" > "$TEMP_FILE.tmp" + mv "$TEMP_FILE.tmp" "$VALUES_FILE" +else + # Version section doesn't exist, insert it before Application-specific parameters section + echo "Inserting new version section in $VALUES_FILE..." + + # Use awk to insert before "## @section Application-specific parameters" + awk -v new_section="$NEW_VERSION_SECTION" ' + /^## @section Application-specific parameters/ { + print new_section + print "" + } + { print } + ' "$VALUES_FILE" > "$TEMP_FILE.tmp" + mv "$TEMP_FILE.tmp" "$VALUES_FILE" +fi + +echo "Successfully updated $VALUES_FILE with major versions: ${MAJOR_VERSIONS[*]}" diff --git a/packages/apps/postgres/templates/_versions.tpl b/packages/apps/postgres/templates/_versions.tpl new file mode 100644 index 00000000..ca0ff2a2 --- /dev/null +++ b/packages/apps/postgres/templates/_versions.tpl @@ -0,0 +1,8 @@ +{{- define "postgres.versionMap" }} +{{- $versionMap := .Files.Get "files/versions.yaml" | fromYaml }} +{{- if not (hasKey $versionMap .Values.version) }} + {{- printf `PostgreSQL version %s is not supported, allowed versions are %s` $.Values.version (keys $versionMap) | fail }} +{{- end }} +{{- index $versionMap .Values.version }} +{{- end }} + diff --git a/packages/apps/postgres/templates/db.yaml b/packages/apps/postgres/templates/db.yaml index de4f51a3..92fb34c6 100644 --- a/packages/apps/postgres/templates/db.yaml +++ b/packages/apps/postgres/templates/db.yaml @@ -44,6 +44,7 @@ spec: resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 4 }} + imageName: ghcr.io/cloudnative-pg/postgresql:{{ include "postgres.versionMap" $ | trimPrefix "v" }} enableSuperuserAccess: true {{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} {{- if $configMap }} diff --git a/packages/apps/postgres/templates/init-job.yaml b/packages/apps/postgres/templates/init-job.yaml index f6c42dbd..323bfcaf 100644 --- a/packages/apps/postgres/templates/init-job.yaml +++ b/packages/apps/postgres/templates/init-job.yaml @@ -16,7 +16,7 @@ spec: restartPolicy: Never containers: - name: postgres - image: ghcr.io/cloudnative-pg/postgresql:15.3 + image: ghcr.io/cloudnative-pg/postgresql:{{ include "postgres.versionMap" $ | trimPrefix "v" }} command: - bash - /scripts/init.sh diff --git a/packages/apps/postgres/values.schema.json b/packages/apps/postgres/values.schema.json index ba4f6b36..005ff26c 100644 --- a/packages/apps/postgres/values.schema.json +++ b/packages/apps/postgres/values.schema.json @@ -243,6 +243,19 @@ } } } + }, + "version": { + "description": "PostgreSQL major version to deploy", + "type": "string", + "default": "v18", + "enum": [ + "v18", + "v17", + "v16", + "v15", + "v14", + "v13" + ] } } } \ No newline at end of file diff --git a/packages/apps/postgres/values.yaml b/packages/apps/postgres/values.yaml index a0d5e741..b8f07f63 100644 --- a/packages/apps/postgres/values.yaml +++ b/packages/apps/postgres/values.yaml @@ -34,6 +34,17 @@ storageClass: "" external: false ## +## @enum {string} Version +## @value v18 +## @value v17 +## @value v16 +## @value v15 +## @value v14 +## @value v13 + +## @param {Version} version - PostgreSQL major version to deploy +version: v18 + ## @section Application-specific parameters ## diff --git a/packages/system/cozystack-resource-definitions/cozyrds/postgres.yaml b/packages/system/cozystack-resource-definitions/cozyrds/postgres.yaml index 010586fe..c3d16cb7 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/postgres.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/postgres.yaml @@ -8,7 +8,7 @@ spec: singular: postgres plural: postgreses openAPISchema: |- - {"title":"Chart Values","type":"object","properties":{"backup":{"description":"Backup configuration.","type":"object","default":{},"required":["enabled"],"properties":{"destinationPath":{"description":"Destination path for backups (e.g. s3://bucket/path/).","type":"string","default":"s3://bucket/path/to/folder/"},"enabled":{"description":"Enable regular backups.","type":"boolean","default":false},"endpointURL":{"description":"S3 endpoint URL for uploads.","type":"string","default":"http://minio-gateway-service:9000"},"retentionPolicy":{"description":"Retention policy (e.g. \"30d\").","type":"string","default":"30d"},"s3AccessKey":{"description":"Access key for S3 authentication.","type":"string","default":""},"s3SecretKey":{"description":"Secret key for S3 authentication.","type":"string","default":""},"schedule":{"description":"Cron schedule for automated backups.","type":"string","default":"0 2 * * * *"}}},"bootstrap":{"description":"Bootstrap configuration.","type":"object","default":{},"required":["enabled","oldName"],"properties":{"enabled":{"description":"Whether to restore from a backup.","type":"boolean","default":false},"oldName":{"description":"Previous cluster name before deletion.","type":"string","default":""},"recoveryTime":{"description":"Timestamp (RFC3339) for point-in-time recovery; empty means latest.","type":"string","default":""}}},"databases":{"description":"Databases configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"extensions":{"description":"List of enabled PostgreSQL extensions.","type":"array","items":{"type":"string"}},"roles":{"description":"Roles assigned to users.","type":"object","properties":{"admin":{"description":"List of users with admin privileges.","type":"array","items":{"type":"string"}},"readonly":{"description":"List of users with read-only privileges.","type":"array","items":{"type":"string"}}}}}}},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"postgresql":{"description":"PostgreSQL server configuration.","type":"object","default":{},"properties":{"parameters":{"description":"PostgreSQL server parameters.","type":"object","default":{},"properties":{"max_connections":{"description":"Maximum number of concurrent connections to the database server.","type":"integer","default":100}}}}},"quorum":{"description":"Quorum configuration for synchronous replication.","type":"object","default":{},"required":["maxSyncReplicas","minSyncReplicas"],"properties":{"maxSyncReplicas":{"description":"Maximum number of synchronous replicas allowed (must be less than total replicas).","type":"integer","default":0},"minSyncReplicas":{"description":"Minimum number of synchronous replicas required for commit.","type":"integer","default":0}}},"replicas":{"description":"Number of Postgres replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each PostgreSQL replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for application data.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"users":{"description":"Users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"password":{"description":"Password for the user.","type":"string"},"replication":{"description":"Whether the user has replication privileges.","type":"boolean"}}}}}} + {"title":"Chart Values","type":"object","properties":{"backup":{"description":"Backup configuration.","type":"object","default":{},"required":["enabled"],"properties":{"destinationPath":{"description":"Destination path for backups (e.g. s3://bucket/path/).","type":"string","default":"s3://bucket/path/to/folder/"},"enabled":{"description":"Enable regular backups.","type":"boolean","default":false},"endpointURL":{"description":"S3 endpoint URL for uploads.","type":"string","default":"http://minio-gateway-service:9000"},"retentionPolicy":{"description":"Retention policy (e.g. \"30d\").","type":"string","default":"30d"},"s3AccessKey":{"description":"Access key for S3 authentication.","type":"string","default":""},"s3SecretKey":{"description":"Secret key for S3 authentication.","type":"string","default":""},"schedule":{"description":"Cron schedule for automated backups.","type":"string","default":"0 2 * * * *"}}},"bootstrap":{"description":"Bootstrap configuration.","type":"object","default":{},"required":["enabled","oldName"],"properties":{"enabled":{"description":"Whether to restore from a backup.","type":"boolean","default":false},"oldName":{"description":"Previous cluster name before deletion.","type":"string","default":""},"recoveryTime":{"description":"Timestamp (RFC3339) for point-in-time recovery; empty means latest.","type":"string","default":""}}},"databases":{"description":"Databases configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"extensions":{"description":"List of enabled PostgreSQL extensions.","type":"array","items":{"type":"string"}},"roles":{"description":"Roles assigned to users.","type":"object","properties":{"admin":{"description":"List of users with admin privileges.","type":"array","items":{"type":"string"}},"readonly":{"description":"List of users with read-only privileges.","type":"array","items":{"type":"string"}}}}}}},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"postgresql":{"description":"PostgreSQL server configuration.","type":"object","default":{},"properties":{"parameters":{"description":"PostgreSQL server parameters.","type":"object","default":{},"properties":{"max_connections":{"description":"Maximum number of concurrent connections to the database server.","type":"integer","default":100}}}}},"quorum":{"description":"Quorum configuration for synchronous replication.","type":"object","default":{},"required":["maxSyncReplicas","minSyncReplicas"],"properties":{"maxSyncReplicas":{"description":"Maximum number of synchronous replicas allowed (must be less than total replicas).","type":"integer","default":0},"minSyncReplicas":{"description":"Minimum number of synchronous replicas required for commit.","type":"integer","default":0}}},"replicas":{"description":"Number of Postgres replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each PostgreSQL replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for application data.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"users":{"description":"Users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"password":{"description":"Password for the user.","type":"string"},"replication":{"description":"Whether the user has replication privileges.","type":"boolean"}}}},"version":{"description":"PostgreSQL major version to deploy","type":"string","default":"v18","enum":["v18","v17","v16","v15","v14","v13"]}}} release: prefix: postgres- labels: @@ -35,7 +35,7 @@ spec: # labelSelector: # helm.toolkit.fluxcd.io/name: "{reqs[0]['metadata','name']}" - keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "postgresql"], ["spec", "postgresql", "parameters"], ["spec", "postgresql", "parameters", "max_connections"], ["spec", "quorum"], ["spec", "quorum", "minSyncReplicas"], ["spec", "quorum", "maxSyncReplicas"], ["spec", "users"], ["spec", "databases"], ["spec", "backup"], ["spec", "backup", "enabled"], ["spec", "backup", "retentionPolicy"], ["spec", "backup", "destinationPath"], ["spec", "backup", "endpointURL"], ["spec", "backup", "schedule"], ["spec", "backup", "s3AccessKey"], ["spec", "backup", "s3SecretKey"], ["spec", "bootstrap"], ["spec", "bootstrap", "enabled"], ["spec", "bootstrap", "recoveryTime"], ["spec", "bootstrap", "oldName"]] + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "version"], ["spec", "postgresql"], ["spec", "postgresql", "parameters"], ["spec", "postgresql", "parameters", "max_connections"], ["spec", "quorum"], ["spec", "quorum", "minSyncReplicas"], ["spec", "quorum", "maxSyncReplicas"], ["spec", "users"], ["spec", "databases"], ["spec", "backup"], ["spec", "backup", "enabled"], ["spec", "backup", "retentionPolicy"], ["spec", "backup", "destinationPath"], ["spec", "backup", "endpointURL"], ["spec", "backup", "schedule"], ["spec", "backup", "s3AccessKey"], ["spec", "backup", "s3SecretKey"], ["spec", "bootstrap"], ["spec", "bootstrap", "enabled"], ["spec", "bootstrap", "recoveryTime"], ["spec", "bootstrap", "oldName"]] secrets: exclude: [] include: From 7e1cad26e7145f5d902bf5e339cc384a12a8509e Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 2 Dec 2025 00:30:38 +0100 Subject: [PATCH 10/33] [redis] Add version management system with automated version updates Signed-off-by: Andrei Kvapil --- .github/workflows/pre-commit.yml | 2 +- packages/apps/redis/.helmignore | 1 + packages/apps/redis/Makefile | 4 + packages/apps/redis/README.md | 1 + packages/apps/redis/files/versions.yaml | 2 + packages/apps/redis/hack/update-versions.sh | 161 ++++++++++++++++++ packages/apps/redis/templates/_versions.tpl | 8 + .../apps/redis/templates/redisfailover.yaml | 2 +- packages/apps/redis/values.schema.json | 9 + packages/apps/redis/values.yaml | 7 + .../cozyrds/redis.yaml | 4 +- 11 files changed, 197 insertions(+), 4 deletions(-) create mode 100644 packages/apps/redis/files/versions.yaml create mode 100755 packages/apps/redis/hack/update-versions.sh create mode 100644 packages/apps/redis/templates/_versions.tpl diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 685d41fe..ef1ce088 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -28,7 +28,7 @@ jobs: - name: Install generate run: | - curl -sSL https://github.com/cozystack/cozyvalues-gen/releases/download/v1.0.5/cozyvalues-gen-linux-amd64.tar.gz | tar -xzvf- -C /usr/local/bin/ cozyvalues-gen + curl -sSL https://github.com/cozystack/cozyvalues-gen/releases/download/v1.0.6/cozyvalues-gen-linux-amd64.tar.gz | tar -xzvf- -C /usr/local/bin/ cozyvalues-gen - name: Run pre-commit hooks run: | diff --git a/packages/apps/redis/.helmignore b/packages/apps/redis/.helmignore index 1ea0ae84..3de7d4a5 100644 --- a/packages/apps/redis/.helmignore +++ b/packages/apps/redis/.helmignore @@ -1,3 +1,4 @@ .helmignore /logos /Makefile +/hack diff --git a/packages/apps/redis/Makefile b/packages/apps/redis/Makefile index 8b1dce9d..a2ba188f 100644 --- a/packages/apps/redis/Makefile +++ b/packages/apps/redis/Makefile @@ -3,3 +3,7 @@ include ../../../scripts/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md ../../../hack/update-crd.sh + +update: + hack/update-versions.sh + make generate diff --git a/packages/apps/redis/README.md b/packages/apps/redis/README.md index 00f41d36..7f82d229 100644 --- a/packages/apps/redis/README.md +++ b/packages/apps/redis/README.md @@ -23,6 +23,7 @@ Service utilizes the Spotahome Redis Operator for efficient management and orche | `size` | Persistent Volume Claim size available for application data. | `quantity` | `1Gi` | | `storageClass` | StorageClass used to store the data. | `string` | `""` | | `external` | Enable external access from outside the cluster. | `bool` | `false` | +| `version` | Redis major version to deploy | `string` | `v8` | ### Application-specific parameters diff --git a/packages/apps/redis/files/versions.yaml b/packages/apps/redis/files/versions.yaml new file mode 100644 index 00000000..be1e42d6 --- /dev/null +++ b/packages/apps/redis/files/versions.yaml @@ -0,0 +1,2 @@ +"v8": "8.4.0" +"v7": "7.4.7" diff --git a/packages/apps/redis/hack/update-versions.sh b/packages/apps/redis/hack/update-versions.sh new file mode 100755 index 00000000..daad973e --- /dev/null +++ b/packages/apps/redis/hack/update-versions.sh @@ -0,0 +1,161 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REDIS_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +VALUES_FILE="${REDIS_DIR}/values.yaml" +VERSIONS_FILE="${REDIS_DIR}/files/versions.yaml" +REDIS_IMAGE="docker://docker.io/redis" + +# Check if skopeo is installed +if ! command -v skopeo &> /dev/null; then + echo "Error: skopeo is not installed. Please install skopeo and try again." >&2 + exit 1 +fi + +# Check if jq is installed +if ! command -v jq &> /dev/null; then + echo "Error: jq is not installed. Please install jq and try again." >&2 + exit 1 +fi + +# Get available image tags +echo "Fetching available image tags from registry..." +AVAILABLE_TAGS=$(skopeo list-tags "${REDIS_IMAGE}" | jq -r '.Tags[] | select(test("^[0-9]+\\.[0-9]+\\.[0-9]+$"))' | sort -V) + +if [ -z "$AVAILABLE_TAGS" ]; then + echo "Error: Could not fetch available image tags" >&2 + exit 1 +fi + +# Get all unique major versions and find Latest and Previous +echo "Finding Latest and Previous major versions..." +ALL_MAJOR_VERSIONS=$(echo "$AVAILABLE_TAGS" | cut -d. -f1 | sort -u -n -r) +MAJOR_VERSIONS_ARRAY=($ALL_MAJOR_VERSIONS) + +if [ ${#MAJOR_VERSIONS_ARRAY[@]} -lt 1 ]; then + echo "Error: Could not find any major versions" >&2 + exit 1 +fi + +# Get Latest and Previous major versions +LATEST_MAJOR=${MAJOR_VERSIONS_ARRAY[0]} +PREVIOUS_MAJOR="" + +if [ ${#MAJOR_VERSIONS_ARRAY[@]} -ge 2 ]; then + PREVIOUS_MAJOR=${MAJOR_VERSIONS_ARRAY[1]} +fi + +if [ -z "$PREVIOUS_MAJOR" ]; then + echo "Warning: Only one major version found (${LATEST_MAJOR}), using it as both Latest and Previous" + PREVIOUS_MAJOR=$LATEST_MAJOR +fi + +echo "Latest major version: ${LATEST_MAJOR}" +echo "Previous major version: ${PREVIOUS_MAJOR}" + +# Build versions map: major version -> latest patch version +declare -A VERSION_MAP +MAJOR_VERSIONS=() +PROCESSED_MAJORS=() + +for major_version in "$LATEST_MAJOR" "$PREVIOUS_MAJOR"; do + # Skip if we already processed this major version + if [[ " ${PROCESSED_MAJORS[@]} " =~ " ${major_version} " ]]; then + continue + fi + PROCESSED_MAJORS+=("${major_version}") + + # Find all tags that match this major version + matching_tags=$(echo "$AVAILABLE_TAGS" | grep "^${major_version}\\.") + + if [ -n "$matching_tags" ]; then + # Get the latest patch version for this major version + latest_tag=$(echo "$matching_tags" | tail -n1) + VERSION_MAP["v${major_version}"]="${latest_tag}" + MAJOR_VERSIONS+=("v${major_version}") + echo "Found version: v${major_version} -> ${latest_tag}" + else + echo "Warning: Could not find any patch versions for ${major_version}, skipping..." >&2 + fi +done + +if [ ${#MAJOR_VERSIONS[@]} -eq 0 ]; then + echo "Error: No matching versions found" >&2 + exit 1 +fi + +# Sort major versions in descending order (newest first) +IFS=$'\n' MAJOR_VERSIONS=($(printf '%s\n' "${MAJOR_VERSIONS[@]}" | sort -V -r)) +unset IFS + +echo "Major versions to add: ${MAJOR_VERSIONS[*]}" + +# Create/update versions.yaml file +echo "Updating $VERSIONS_FILE..." +{ + for major_ver in "${MAJOR_VERSIONS[@]}"; do + echo "\"${major_ver}\": \"${VERSION_MAP[$major_ver]}\"" + done +} > "$VERSIONS_FILE" + +echo "Successfully updated $VERSIONS_FILE" + +# Update values.yaml - enum with major versions only +TEMP_FILE=$(mktemp) +trap "rm -f $TEMP_FILE" EXIT + +# Build new version section +NEW_VERSION_SECTION="## @enum {string} Version" +for major_ver in "${MAJOR_VERSIONS[@]}"; do + NEW_VERSION_SECTION="${NEW_VERSION_SECTION} +## @value $major_ver" +done +NEW_VERSION_SECTION="${NEW_VERSION_SECTION} + +## @param {Version} version - Redis major version to deploy +version: ${MAJOR_VERSIONS[0]}" + +# Check if version section already exists +if grep -q "^## @enum {string} Version" "$VALUES_FILE"; then + # Version section exists, update it using awk + echo "Updating existing version section in $VALUES_FILE..." + + # Use awk to replace the section from "## @enum {string} Version" to "version: " (inclusive) + # Delete the old section and insert the new one + awk -v new_section="$NEW_VERSION_SECTION" ' + /^## @enum {string} Version/ { + in_section = 1 + print new_section + next + } + in_section && /^version: / { + in_section = 0 + next + } + in_section { + next + } + { print } + ' "$VALUES_FILE" > "$TEMP_FILE.tmp" + mv "$TEMP_FILE.tmp" "$VALUES_FILE" +else + # Version section doesn't exist, insert it before Application-specific parameters section + echo "Inserting new version section in $VALUES_FILE..." + + # Use awk to insert before "## @section Application-specific parameters" + awk -v new_section="$NEW_VERSION_SECTION" ' + /^## @section Application-specific parameters/ { + print new_section + print "" + } + { print } + ' "$VALUES_FILE" > "$TEMP_FILE.tmp" + mv "$TEMP_FILE.tmp" "$VALUES_FILE" +fi + +echo "Successfully updated $VALUES_FILE with major versions: ${MAJOR_VERSIONS[*]}" + diff --git a/packages/apps/redis/templates/_versions.tpl b/packages/apps/redis/templates/_versions.tpl new file mode 100644 index 00000000..758e3800 --- /dev/null +++ b/packages/apps/redis/templates/_versions.tpl @@ -0,0 +1,8 @@ +{{- define "redis.versionMap" }} +{{- $versionMap := .Files.Get "files/versions.yaml" | fromYaml }} +{{- if not (hasKey $versionMap .Values.version) }} + {{- printf `Redis version %s is not supported, allowed versions are %s` $.Values.version (keys $versionMap) | fail }} +{{- end }} +{{- index $versionMap .Values.version }} +{{- end }} + diff --git a/packages/apps/redis/templates/redisfailover.yaml b/packages/apps/redis/templates/redisfailover.yaml index 20e91646..936217a3 100644 --- a/packages/apps/redis/templates/redisfailover.yaml +++ b/packages/apps/redis/templates/redisfailover.yaml @@ -27,7 +27,7 @@ spec: replicas: 3 resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 6 }} redis: - image: "redis:8.2.0" + image: "redis:{{ include "redis.versionMap" $ }}" resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 6 }} replicas: {{ .Values.replicas }} {{- with .Values.size }} diff --git a/packages/apps/redis/values.schema.json b/packages/apps/redis/values.schema.json index db338803..5c01cc31 100644 --- a/packages/apps/redis/values.schema.json +++ b/packages/apps/redis/values.schema.json @@ -82,6 +82,15 @@ "description": "StorageClass used to store the data.", "type": "string", "default": "" + }, + "version": { + "description": "Redis major version to deploy", + "type": "string", + "default": "v8", + "enum": [ + "v8", + "v7" + ] } } } \ No newline at end of file diff --git a/packages/apps/redis/values.yaml b/packages/apps/redis/values.yaml index 87b01a57..efe80d07 100644 --- a/packages/apps/redis/values.yaml +++ b/packages/apps/redis/values.yaml @@ -33,6 +33,13 @@ storageClass: "" ## @param {bool} external - Enable external access from outside the cluster. external: false +## @enum {string} Version +## @value v8 +## @value v7 + +## @param {Version} version - Redis major version to deploy +version: v8 + ## ## @section Application-specific parameters ## diff --git a/packages/system/cozystack-resource-definitions/cozyrds/redis.yaml b/packages/system/cozystack-resource-definitions/cozyrds/redis.yaml index 1c5131d3..d23f8d2c 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/redis.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/redis.yaml @@ -8,7 +8,7 @@ spec: plural: redises singular: redis openAPISchema: |- - {"title":"Chart Values","type":"object","properties":{"authEnabled":{"description":"Enable password generation.","type":"boolean","default":true},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"replicas":{"description":"Number of Redis replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each Redis replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for application data.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""}}} + {"title":"Chart Values","type":"object","properties":{"authEnabled":{"description":"Enable password generation.","type":"boolean","default":true},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"replicas":{"description":"Number of Redis replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each Redis replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for application data.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"version":{"description":"Redis major version to deploy","type":"string","default":"v8","enum":["v8","v7"]}}} release: prefix: redis- labels: @@ -27,7 +27,7 @@ spec: tags: - cache icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODNfMzIxMykiLz4KPHBhdGggZD0iTTEyMC4xNDkgOTUuNTQ5MUMxMTQuNTg2IDk4LjQ0ODUgODUuNzcwOSAxMTAuMjk2IDc5LjYzNjMgMTEzLjQ5NUM3My41MDE2IDExNi42OTMgNzAuMDkzNyAxMTYuNjYyIDY1LjI0NzIgMTE0LjM0NkM2MC40MDEyIDExMi4wMjkgMjkuNzM2NCA5OS42NDIzIDI0LjIxMjUgOTcuMDAxOUMyMS40NTE5IDk1LjY4MjcgMjAgOTQuNTY4NyAyMCA5My41MTY2VjgyLjk4MDlDMjAgODIuOTgwOSA1OS45MjIgNzQuMjkwMSA2Ni4zNjY5IDcxLjk3NzhDNzIuODExNSA2OS42NjU2IDc1LjA0NzYgNjkuNTgyMSA4MC41MzIgNzEuNTkxQzg2LjAxNzMgNzMuNjAwOCAxMTguODEyIDc5LjUxNzYgMTI0LjIzMyA4MS41MDI5TDEyNC4yMyA5MS44ODk2QzEyNC4yMzEgOTIuOTMxMSAxMjIuOTggOTQuMDczNiAxMjAuMTQ5IDk1LjU0OTFaIiBmaWxsPSIjOTEyNjI2Ii8+CjxwYXRoIGQ9Ik0xMjAuMTQ3IDg1LjA3NTJDMTE0LjU4NSA4Ny45NzM0IDg1Ljc3IDk5LjgyMTggNzkuNjM1NCAxMDMuMDJDNzMuNTAxMSAxMDYuMjE5IDcwLjA5MzIgMTA2LjE4NyA2NS4yNDcyIDEwMy44NzFDNjAuNDAwNyAxMDEuNTU1IDI5LjczNzEgODkuMTY2OCAyNC4yMTM2IDg2LjUyOEMxOC42OTAxIDgzLjg4NzYgMTguNTc0NCA4Mi4wNzA0IDI0LjAwMDMgNzkuOTQ1OEMyOS40MjYxIDc3LjgyMDUgNTkuOTIxNSA2NS44NTYxIDY2LjM2NzIgNjMuNTQzOEM3Mi44MTE4IDYxLjIzMjQgNzUuMDQ3NSA2MS4xNDgxIDgwLjUzMTkgNjMuMTU3OEM4Ni4wMTY4IDY1LjE2NjggMTE0LjY2IDc2LjU2NzYgMTIwLjA3OSA3OC41NTI1QzEyNS41MDEgODAuNTM5OSAxMjUuNzA5IDgyLjE3NjMgMTIwLjE0NyA4NS4wNzUyWiIgZmlsbD0iI0M2MzAyQiIvPgo8cGF0aCBkPSJNMTIwLjE0OSA3OC41MDJDMTE0LjU4NiA4MS40MDE4IDg1Ljc3MDkgOTMuMjQ5MyA3OS42MzYzIDk2LjQ0ODhDNzMuNTAxNiA5OS42NDYyIDcwLjA5MzcgOTkuNjE1MiA2NS4yNDcyIDk3LjI5ODVDNjAuNDAwOCA5NC45ODMgMjkuNzM2NCA4Mi41OTUyIDI0LjIxMjUgNzkuOTU0N0MyMS40NTE5IDc4LjYzNTUgMjAgNzcuNTIzMiAyMCA3Ni40NzA3VjY1LjkzMzhDMjAgNjUuOTMzOCA1OS45MjIgNTcuMjQzNCA2Ni4zNjY5IDU0LjkzMTFDNzIuODExNSA1Mi42MTg5IDc1LjA0NzYgNTIuNTM1IDgwLjUzMiA1NC41NDQzQzg2LjAxNzcgNTYuNTUzNiAxMTguODEzIDYyLjQ2OTMgMTI0LjIzMyA2NC40NTVMMTI0LjIzIDc0Ljg0MjhDMTI0LjIzMSA3NS44ODQgMTIyLjk4IDc3LjAyNjQgMTIwLjE0OSA3OC41MDJaIiBmaWxsPSIjOTEyNjI2Ii8+CjxwYXRoIGQ9Ik0xMjAuMTQ3IDY4LjAyODJDMTE0LjU4NSA3MC45MjcxIDg1Ljc3IDgyLjc3NDcgNzkuNjM1NCA4NS45NzM3QzczLjUwMTEgODkuMTcxNiA3MC4wOTMyIDg5LjE0MDIgNjUuMjQ3MiA4Ni44MjM1QzYwLjQwMDcgODQuNTA4NCAyOS43MzcxIDcyLjEyMDEgMjQuMjEzNiA2OS40ODA5QzE4LjY5MDEgNjYuODQxMyAxOC41NzQ0IDY1LjAyMzcgMjQuMDAwMyA2Mi44OTg0QzI5LjQyNjEgNjAuNzc0MiA1OS45MjE5IDQ4LjgwOSA2Ni4zNjcyIDQ2LjQ5NzJDNzIuODExOCA0NC4xODUzIDc1LjA0NzUgNDQuMTAxNCA4MC41MzE5IDQ2LjExMDhDODYuMDE2OCA0OC4xMTk3IDExNC42NiA1OS41MTk3IDEyMC4wNzkgNjEuNTA1NUMxMjUuNTAxIDYzLjQ5MjQgMTI1LjcwOSA2NS4xMjkyIDEyMC4xNDcgNjguMDI4MloiIGZpbGw9IiNDNjMwMkIiLz4KPHBhdGggZD0iTTEyMC4xNDkgNjAuODIyNEMxMTQuNTg2IDYzLjcyMTQgODUuNzcwOSA3NS41Njk4IDc5LjYzNjMgNzguNzY5MkM3My41MDE2IDgxLjk2NzEgNzAuMDkzNyA4MS45MzU3IDY1LjI0NzIgNzkuNjE5QzYwLjQwMDggNzcuMzAzNSAyOS43MzY0IDY0LjkxNTIgMjQuMjEyNSA2Mi4yNzZDMjEuNDUxOSA2MC45NTU2IDIwIDU5Ljg0MjggMjAgNTguNzkxNVY0OC4yNTQyQzIwIDQ4LjI1NDIgNTkuOTIyIDM5LjU2NDIgNjYuMzY2OSAzNy4yNTI0QzcyLjgxMTUgMzQuOTM5NyA3NS4wNDc2IDM0Ljg1NjcgODAuNTMyIDM2Ljg2NTZDODYuMDE3NyAzOC44NzQ5IDExOC44MTMgNDQuNzkwNSAxMjQuMjMzIDQ2Ljc3NjNMMTI0LjIzIDU3LjE2MzdDMTI0LjIzMSA1OC4yMDQgMTIyLjk4IDU5LjM0NjUgMTIwLjE0OSA2MC44MjI0WiIgZmlsbD0iIzkxMjYyNiIvPgo8cGF0aCBkPSJNMTIwLjE0NyA1MC4zNDlDMTE0LjU4NSA1My4yNDc5IDg1Ljc2OTggNjUuMDk2MyA3OS42MzUyIDY4LjI5NDFDNzMuNTAwOSA3MS40OTIgNzAuMDkzIDcxLjQ2MDYgNjUuMjQ2OSA2OS4xNDUxQzYwLjQwMDkgNjYuODI4MyAyOS43MzY5IDU0LjQ0MDkgMjQuMjEzOCA1MS44MDEzQzE4LjY4OTkgNDkuMTYyMSAxOC41NzQ2IDQ3LjM0NDEgMjQgNDUuMjE5MkMyOS40MjU5IDQzLjA5NDYgNTkuOTIxNyAzMS4xMzEgNjYuMzY3IDI4LjgxODRDNzIuODExNiAyNi41MDYxIDc1LjA0NzMgMjYuNDIzIDgwLjUzMTcgMjguNDMyNEM4Ni4wMTY2IDMwLjQ0MTcgMTE0LjY1OSA0MS44NDE4IDEyMC4wNzkgNDMuODI3NUMxMjUuNTAxIDQ1LjgxMjggMTI1LjcwOSA0Ny40NSAxMjAuMTQ3IDUwLjM0OVoiIGZpbGw9IiNDNjMwMkIiLz4KPHBhdGggZD0iTTg0Ljg1NDEgNDAuMDk5NEw3NS44OTI2IDQxLjAyOThMNzMuODg2NSA0NS44NTdMNzAuNjQ2MyA0MC40NzAzTDYwLjI5ODMgMzkuNTQwNEw2OC4wMTk3IDM2Ljc1NThMNjUuNzAzIDMyLjQ4MTRMNzIuOTMyMSAzNS4zMDg4TDc5Ljc0NzEgMzMuMDc3NUw3Ny45MDUyIDM3LjQ5NzJMODQuODU0MSA0MC4wOTk0Wk03My4zNTE1IDYzLjUxODRMNTYuNjI2NiA1Ni41ODE2TDgwLjU5MiA1Mi45MDI5TDczLjM1MTUgNjMuNTE4NFpNNTAuMTYzNyA0Mi43ODI2QzU3LjIzODEgNDIuNzgyNiA2Mi45NzMgNDUuMDA1NyA2Mi45NzMgNDcuNzQ3NUM2Mi45NzMgNTAuNDkwMSA1Ny4yMzgxIDUyLjcxMjggNTAuMTYzNyA1Mi43MTI4QzQzLjA4OTMgNTIuNzEyOCAzNy4zNTQ1IDUwLjQ4OTcgMzcuMzU0NSA0Ny43NDc1QzM3LjM1NDUgNDUuMDA1NyA0My4wODkzIDQyLjc4MjYgNTAuMTYzNyA0Mi43ODI2WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTk1LjQ0MzQgNDEuNDE3NEwxMDkuNjI3IDQ3LjAyMjRMOTUuNDU1NiA1Mi42MjJMOTUuNDQzNCA0MS40MTc0WiIgZmlsbD0iIzYyMUIxQyIvPgo8cGF0aCBkPSJNNzkuNzUyOSA0Ny42MjYxTDk1LjQ0NDkgNDEuNDE4OUw5NS40NTcxIDUyLjYyMzZMOTMuOTE4NCA1My4yMjU0TDc5Ljc1MjkgNDcuNjI2MVoiIGZpbGw9IiM5QTI5MjgiLz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl82ODNfMzIxMyIgeDE9IjE4OSIgeTE9IjIxMC41IiB4Mj0iMCIgeTI9IjAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iI0E4MDAwMCIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNGRkNGQ0YiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K - keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "authEnabled"]] + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "version"], ["spec", "authEnabled"]] secrets: exclude: [] include: From 33128748e64c1e75c97b10ef8a1de40045d65fcb Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 2 Dec 2025 00:15:34 +0100 Subject: [PATCH 11/33] [mariadb] Add version management system with automated version updates Signed-off-by: Andrei Kvapil --- .github/workflows/pre-commit.yml | 2 +- packages/apps/mysql/.helmignore | 1 + packages/apps/mysql/Makefile | 4 + packages/apps/mysql/README.md | 1 + packages/apps/mysql/files/versions.yaml | 4 + packages/apps/mysql/hack/update-versions.sh | 151 ++++++++++++++++++ packages/apps/mysql/templates/_versions.tpl | 8 + packages/apps/mysql/templates/mariadb.yaml | 2 +- packages/apps/mysql/values.schema.json | 11 ++ packages/apps/mysql/values.yaml | 10 ++ .../cozyrds/mysql.yaml | 4 +- 11 files changed, 194 insertions(+), 4 deletions(-) create mode 100644 packages/apps/mysql/files/versions.yaml create mode 100755 packages/apps/mysql/hack/update-versions.sh create mode 100644 packages/apps/mysql/templates/_versions.tpl diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 685d41fe..ef1ce088 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -28,7 +28,7 @@ jobs: - name: Install generate run: | - curl -sSL https://github.com/cozystack/cozyvalues-gen/releases/download/v1.0.5/cozyvalues-gen-linux-amd64.tar.gz | tar -xzvf- -C /usr/local/bin/ cozyvalues-gen + curl -sSL https://github.com/cozystack/cozyvalues-gen/releases/download/v1.0.6/cozyvalues-gen-linux-amd64.tar.gz | tar -xzvf- -C /usr/local/bin/ cozyvalues-gen - name: Run pre-commit hooks run: | diff --git a/packages/apps/mysql/.helmignore b/packages/apps/mysql/.helmignore index 1ea0ae84..3de7d4a5 100644 --- a/packages/apps/mysql/.helmignore +++ b/packages/apps/mysql/.helmignore @@ -1,3 +1,4 @@ .helmignore /logos /Makefile +/hack diff --git a/packages/apps/mysql/Makefile b/packages/apps/mysql/Makefile index 08c57889..f4ea3f78 100644 --- a/packages/apps/mysql/Makefile +++ b/packages/apps/mysql/Makefile @@ -7,6 +7,10 @@ generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md ../../../hack/update-crd.sh +update: + hack/update-versions.sh + make generate + image: docker buildx build images/mariadb-backup \ --tag $(REGISTRY)/mariadb-backup:$(call settag,$(MARIADB_BACKUP_TAG)) \ diff --git a/packages/apps/mysql/README.md b/packages/apps/mysql/README.md index 6ea0352f..6d47a6d5 100644 --- a/packages/apps/mysql/README.md +++ b/packages/apps/mysql/README.md @@ -79,6 +79,7 @@ more details: | `size` | Persistent Volume Claim size available for application data. | `quantity` | `10Gi` | | `storageClass` | StorageClass used to store the data. | `string` | `""` | | `external` | Enable external access from outside the cluster. | `bool` | `false` | +| `version` | MariaDB major.minor version to deploy | `string` | `v11.8` | ### Application-specific parameters diff --git a/packages/apps/mysql/files/versions.yaml b/packages/apps/mysql/files/versions.yaml new file mode 100644 index 00000000..59c8814c --- /dev/null +++ b/packages/apps/mysql/files/versions.yaml @@ -0,0 +1,4 @@ +"v11.8": "11.8.5" +"v11.4": "11.4.9" +"v10.11": "10.11.15" +"v10.6": "10.6.24" diff --git a/packages/apps/mysql/hack/update-versions.sh b/packages/apps/mysql/hack/update-versions.sh new file mode 100755 index 00000000..1b58591a --- /dev/null +++ b/packages/apps/mysql/hack/update-versions.sh @@ -0,0 +1,151 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +MYSQL_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +VALUES_FILE="${MYSQL_DIR}/values.yaml" +VERSIONS_FILE="${MYSQL_DIR}/files/versions.yaml" +MARIADB_API_URL="https://downloads.mariadb.org/rest-api/mariadb/" + +# Check if jq is installed +if ! command -v jq &> /dev/null; then + echo "Error: jq is not installed. Please install jq and try again." >&2 + exit 1 +fi + +# Get LTS versions from MariaDB REST API +echo "Fetching LTS versions from MariaDB REST API..." +LTS_VERSIONS_JSON=$(curl -sSL "${MARIADB_API_URL}") + +if [ -z "$LTS_VERSIONS_JSON" ]; then + echo "Error: Could not fetch versions from MariaDB REST API" >&2 + exit 1 +fi + +# Extract LTS stable major versions +LTS_MAJOR_VERSIONS=$(echo "$LTS_VERSIONS_JSON" | jq -r '.major_releases[] | select(.release_support_type == "Long Term Support") | select(.release_status == "Stable") | .release_id' | sort -V -r) + +if [ -z "$LTS_MAJOR_VERSIONS" ]; then + echo "Error: Could not find any LTS stable versions" >&2 + exit 1 +fi + +echo "Found LTS major versions: $(echo "$LTS_MAJOR_VERSIONS" | tr '\n' ' ')" + +# Build versions map: major version -> latest patch version +declare -A VERSION_MAP +MAJOR_VERSIONS=() + +for major_version in $LTS_MAJOR_VERSIONS; do + echo "Fetching patch versions for ${major_version}..." + + # Get patch versions for this major version + PATCH_VERSIONS_JSON=$(curl -sSL "${MARIADB_API_URL}${major_version}") + + if [ -z "$PATCH_VERSIONS_JSON" ]; then + echo "Warning: Could not fetch patch versions for ${major_version}, skipping..." >&2 + continue + fi + + # Extract all stable patch version IDs (format: MAJOR.MINOR.PATCH) + # Filter only Stable releases + PATCH_VERSIONS=$(echo "$PATCH_VERSIONS_JSON" | jq -r --arg major "$major_version" '.releases | to_entries[] | select(.key | startswith($major + ".")) | select(.value.release_status == "Stable") | .key' | sort -V) + + # If no stable releases found, try to get any releases (for backwards compatibility) + if [ -z "$PATCH_VERSIONS" ]; then + PATCH_VERSIONS=$(echo "$PATCH_VERSIONS_JSON" | jq -r '.releases | keys[]' | grep -E "^${major_version}\." | sort -V) + fi + + if [ -z "$PATCH_VERSIONS" ]; then + echo "Warning: Could not find any patch versions for ${major_version}, skipping..." >&2 + continue + fi + + # Get the latest patch version + LATEST_PATCH=$(echo "$PATCH_VERSIONS" | tail -n1) + + # major_version already has format MAJOR.MINOR (e.g., "11.8") + VERSION_MAP["v${major_version}"]="${LATEST_PATCH}" + MAJOR_VERSIONS+=("v${major_version}") + echo "Found version: v${major_version} -> ${LATEST_PATCH}" +done + +if [ ${#MAJOR_VERSIONS[@]} -eq 0 ]; then + echo "Error: No matching versions found" >&2 + exit 1 +fi + +# Sort major versions in descending order (newest first) +IFS=$'\n' MAJOR_VERSIONS=($(printf '%s\n' "${MAJOR_VERSIONS[@]}" | sort -V -r)) +unset IFS + +echo "Major versions to add: ${MAJOR_VERSIONS[*]}" + +# Create/update versions.yaml file +echo "Updating $VERSIONS_FILE..." +{ + for major_ver in "${MAJOR_VERSIONS[@]}"; do + echo "\"${major_ver}\": \"${VERSION_MAP[$major_ver]}\"" + done +} > "$VERSIONS_FILE" + +echo "Successfully updated $VERSIONS_FILE" + +# Update values.yaml - enum with major.minor versions only +TEMP_FILE=$(mktemp) +trap "rm -f $TEMP_FILE" EXIT + +# Build new version section +NEW_VERSION_SECTION="## @enum {string} Version" +for major_ver in "${MAJOR_VERSIONS[@]}"; do + NEW_VERSION_SECTION="${NEW_VERSION_SECTION} +## @value $major_ver" +done +NEW_VERSION_SECTION="${NEW_VERSION_SECTION} + +## @param {Version} version - MariaDB major.minor version to deploy +version: ${MAJOR_VERSIONS[0]}" + +# Check if version section already exists +if grep -q "^## @enum {string} Version" "$VALUES_FILE"; then + # Version section exists, update it using awk + echo "Updating existing version section in $VALUES_FILE..." + + # Use awk to replace the section from "## @enum {string} Version" to "version: " (inclusive) + # Delete the old section and insert the new one + awk -v new_section="$NEW_VERSION_SECTION" ' + /^## @enum {string} Version/ { + in_section = 1 + print new_section + next + } + in_section && /^version: / { + in_section = 0 + next + } + in_section { + next + } + { print } + ' "$VALUES_FILE" > "$TEMP_FILE.tmp" + mv "$TEMP_FILE.tmp" "$VALUES_FILE" +else + # Version section doesn't exist, insert it before Application-specific parameters section + echo "Inserting new version section in $VALUES_FILE..." + + # Use awk to insert before "## @section Application-specific parameters" + awk -v new_section="$NEW_VERSION_SECTION" ' + /^## @section Application-specific parameters/ { + print new_section + print "" + } + { print } + ' "$VALUES_FILE" > "$TEMP_FILE.tmp" + mv "$TEMP_FILE.tmp" "$VALUES_FILE" +fi + +echo "Successfully updated $VALUES_FILE with major.minor versions: ${MAJOR_VERSIONS[*]}" + diff --git a/packages/apps/mysql/templates/_versions.tpl b/packages/apps/mysql/templates/_versions.tpl new file mode 100644 index 00000000..cd4ee0e1 --- /dev/null +++ b/packages/apps/mysql/templates/_versions.tpl @@ -0,0 +1,8 @@ +{{- define "mysql.versionMap" }} +{{- $versionMap := .Files.Get "files/versions.yaml" | fromYaml }} +{{- if not (hasKey $versionMap .Values.version) }} + {{- printf `MariaDB version %s is not supported, allowed versions are %s` $.Values.version (keys $versionMap) | fail }} +{{- end }} +{{- index $versionMap .Values.version }} +{{- end }} + diff --git a/packages/apps/mysql/templates/mariadb.yaml b/packages/apps/mysql/templates/mariadb.yaml index 1c95f9f5..b4a888d8 100644 --- a/packages/apps/mysql/templates/mariadb.yaml +++ b/packages/apps/mysql/templates/mariadb.yaml @@ -8,7 +8,7 @@ spec: name: {{ .Release.Name }}-credentials key: root - image: "mariadb:11.0.2" + image: "mariadb:{{ include "mysql.versionMap" $ }}" port: 3306 diff --git a/packages/apps/mysql/values.schema.json b/packages/apps/mysql/values.schema.json index d5db33ab..a36754b2 100644 --- a/packages/apps/mysql/values.schema.json +++ b/packages/apps/mysql/values.schema.json @@ -186,6 +186,17 @@ } } } + }, + "version": { + "description": "MariaDB major.minor version to deploy", + "type": "string", + "default": "v11.8", + "enum": [ + "v11.8", + "v11.4", + "v10.11", + "v10.6" + ] } } } \ No newline at end of file diff --git a/packages/apps/mysql/values.yaml b/packages/apps/mysql/values.yaml index 0d08ca58..c7726b7a 100644 --- a/packages/apps/mysql/values.yaml +++ b/packages/apps/mysql/values.yaml @@ -33,6 +33,16 @@ storageClass: "" ## @param {bool} external - Enable external access from outside the cluster. external: false +## +## @enum {string} Version +## @value v11.8 +## @value v11.4 +## @value v10.11 +## @value v10.6 + +## @param {Version} version - MariaDB major.minor version to deploy +version: v11.8 + ## ## @section Application-specific parameters ## diff --git a/packages/system/cozystack-resource-definitions/cozyrds/mysql.yaml b/packages/system/cozystack-resource-definitions/cozyrds/mysql.yaml index 142b55b1..ba8251b8 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/mysql.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/mysql.yaml @@ -8,7 +8,7 @@ spec: plural: mysqls singular: mysql openAPISchema: |- - {"title":"Chart Values","type":"object","properties":{"backup":{"description":"Backup configuration.","type":"object","default":{},"required":["cleanupStrategy","enabled","resticPassword","s3AccessKey","s3Bucket","s3Region","s3SecretKey","schedule"],"properties":{"cleanupStrategy":{"description":"Retention strategy for cleaning up old backups.","type":"string","default":"--keep-last=3 --keep-daily=3 --keep-within-weekly=1m"},"enabled":{"description":"Enable regular backups (default: false).","type":"boolean","default":false},"resticPassword":{"description":"Password for Restic backup encryption.","type":"string","default":""},"s3AccessKey":{"description":"Access key for S3 authentication.","type":"string","default":""},"s3Bucket":{"description":"S3 bucket used for storing backups.","type":"string","default":"s3.example.org/mysql-backups"},"s3Region":{"description":"AWS S3 region where backups are stored.","type":"string","default":"us-east-1"},"s3SecretKey":{"description":"Secret key for S3 authentication.","type":"string","default":""},"schedule":{"description":"Cron schedule for automated backups.","type":"string","default":"0 2 * * *"}}},"databases":{"description":"Databases configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"roles":{"description":"Roles assigned to users.","type":"object","properties":{"admin":{"description":"List of users with admin privileges.","type":"array","items":{"type":"string"}},"readonly":{"description":"List of users with read-only privileges.","type":"array","items":{"type":"string"}}}}}}},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"replicas":{"description":"Number of MariaDB replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each MariaDB replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for application data.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"users":{"description":"Users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","required":["maxUserConnections","password"],"properties":{"maxUserConnections":{"description":"Maximum number of connections.","type":"integer"},"password":{"description":"Password for the user.","type":"string"}}}}}} + {"title":"Chart Values","type":"object","properties":{"backup":{"description":"Backup configuration.","type":"object","default":{},"required":["cleanupStrategy","enabled","resticPassword","s3AccessKey","s3Bucket","s3Region","s3SecretKey","schedule"],"properties":{"cleanupStrategy":{"description":"Retention strategy for cleaning up old backups.","type":"string","default":"--keep-last=3 --keep-daily=3 --keep-within-weekly=1m"},"enabled":{"description":"Enable regular backups (default: false).","type":"boolean","default":false},"resticPassword":{"description":"Password for Restic backup encryption.","type":"string","default":""},"s3AccessKey":{"description":"Access key for S3 authentication.","type":"string","default":""},"s3Bucket":{"description":"S3 bucket used for storing backups.","type":"string","default":"s3.example.org/mysql-backups"},"s3Region":{"description":"AWS S3 region where backups are stored.","type":"string","default":"us-east-1"},"s3SecretKey":{"description":"Secret key for S3 authentication.","type":"string","default":""},"schedule":{"description":"Cron schedule for automated backups.","type":"string","default":"0 2 * * *"}}},"databases":{"description":"Databases configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"roles":{"description":"Roles assigned to users.","type":"object","properties":{"admin":{"description":"List of users with admin privileges.","type":"array","items":{"type":"string"}},"readonly":{"description":"List of users with read-only privileges.","type":"array","items":{"type":"string"}}}}}}},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"replicas":{"description":"Number of MariaDB replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each MariaDB replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for application data.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"users":{"description":"Users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","required":["maxUserConnections","password"],"properties":{"maxUserConnections":{"description":"Maximum number of connections.","type":"integer"},"password":{"description":"Password for the user.","type":"string"}}}},"version":{"description":"MariaDB major.minor version to deploy","type":"string","default":"v11.8","enum":["v11.8","v11.4","v10.11","v10.6"]}}} release: prefix: mysql- labels: @@ -27,7 +27,7 @@ spec: tags: - database icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHg9Ii0wLjAwMTk1MzEyIiB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgcng9IjI0IiBmaWxsPSJ1cmwoI3BhaW50MF9saW5lYXJfNjgzXzI5MzApIi8+CjxwYXRoIGQ9Ik0xMzMuMTkxIDI5LjAwMjJDMTMxLjIxMyAyOS4wNjU0IDEzMS44MzkgMjkuNjM1NCAxMjcuNTY0IDMwLjY4NzNDMTIzLjI0OCAzMS43NDk2IDExNy45NzUgMzEuNDIzOSAxMTMuMzI3IDMzLjM3MzNDOTkuNDUxNiAzOS4xOTI0IDk2LjY2NzYgNTkuMDgxMyA4NC4wNTM1IDY2LjIwNTlDNzQuNjI0NyA3MS41MzE4IDY1LjExMiA3MS45NTY1IDU2LjU1OTQgNzQuNjM2NUM1MC45Mzg5IDc2LjM5OSA0NC43OTA2IDgwLjAxMzUgMzkuNjk4MiA4NC40MDE4QzM1Ljc0NTUgODcuODA5MyAzNS42NDIzIDkwLjgwNTQgMzEuNTEyMyA5NS4wNzkxQzI3LjA5NDcgOTkuNjUwNCAxMy45NTUxIDk1LjE1NjQgOCAxMDIuMTUzQzkuOTE4MzUgMTA0LjA5MyAxMC43NTk0IDEwNC42MzYgMTQuNTM5OCAxMDQuMTMzQzEzLjc1NzEgMTA1LjYxNiA5LjE0MzMyIDEwNi44NjYgMTAuMDQ2NSAxMDkuMDQ5QzEwLjk5NjggMTExLjM0NSAyMi4xNTExIDExMi45MDEgMzIuMjkwOCAxMDYuNzhDMzcuMDEzMSAxMDMuOTI5IDQwLjc3NDMgOTkuODE5MyA0OC4xMjg4IDk4LjgzODRDNTcuNjQ1OSA5Ny41Njk5IDY4LjYwOTMgOTkuNjUyIDc5LjYyNjggMTAxLjI0MUM3Ny45OTMyIDEwNi4xMTIgNzQuNzEzMyAxMDkuMzUxIDcyLjA4NiAxMTMuMjMxQzcxLjI3MjQgMTE0LjEwNyA3My43MjAyIDExNC4yMDUgNzYuNTEyNiAxMTMuNjc1QzgxLjUzNTkgMTEyLjQzMyA4NS4xNTYxIDExMS40MzMgODguOTQ3MiAxMDkuMjI3QzkzLjYwNDcgMTA2LjUxNSA5NC4zMTA0IDk5LjU2MzkgMTAwLjAyNSA5OC4wNTk5QzEwMy4yMDkgMTAyLjk1NCAxMTEuODY5IDEwNC4xMSAxMTcuMjQyIDEwMC4xOTVDMTEyLjUyNyA5OC44NjA3IDExMS4yMjQgODguODI0NCAxMTIuODE1IDg0LjQwMThDMTE0LjMyMyA4MC4yMTU2IDExNS44MTMgNzMuNTE5MiAxMTcuMzMxIDY3Ljk4NTVDMTE4Ljk2MSA2Mi4wNDI1IDExOS41NjIgNTQuNTUxOSAxMjEuNTM1IDUxLjUyNDdDMTI0LjUwMyA0Ni45NzAxIDEyNy43ODMgNDUuNDA2IDEzMC42MyA0Mi44Mzc3QzEzMy40NzcgNDAuMjY5NSAxMzYuMDgzIDM3Ljc2OTQgMTM1Ljk5OCAzMS44OTI3QzEzNS45NyAyOS45OTk4IDEzNC45OTIgMjguOTQ0NyAxMzMuMTkxIDI5LjAwMjJaIiBmaWxsPSIjMDQyNDRFIi8+CjxwYXRoIGQ9Ik0xMjguOTUzIDMyLjQ4NDRDMTI5LjQyNyAzNC4xMDA0IDEzMC4xNjggMzQuODQyMSAxMzMuMzc1IDM1LjEzODdDMTMyLjkwNiAzOS4yMDQxIDEzMC4xOTUgNDEuNDI3NiAxMjcuMTU0IDQzLjU2MTFDMTI0LjQ3OSA0NS40Mzc2IDEyMS41NDcgNDcuMjQ0NSAxMTkuNjY0IDUwLjE3NTdDMTE3LjczNCA1My4xNzg1IDExNi41MDkgNjMuNDU1NCAxMTMuNTE3IDczLjYwNDRDMTEwLjkzMSA4Mi4zNzM4IDEwNy4wMjUgOTEuMDQ0NSAxMDAuMjA0IDk0Ljg0MzdDOTkuNDkxOSA5My4wNTAyIDEwMC4yOTUgODkuNzQgOTguODc4IDg4LjY1MkM5Ny45NjExIDkxLjI2NzQgOTYuOTI0MiA5My43NjI3IDk1LjcwOTggOTYuMDgyMUM5MS43MDc3IDEwMy43MzIgODUuNzgyMiAxMDkuNDU5IDc1Ljg4MDEgMTExLjIwOEM4MC41Nzg1IDEwNC44NSA4NS4wNzEgOTguMjg0NCA4NS4xNjgzIDg3LjMyNjJDODEuODYxNyA4OC4wNDE3IDgxLjkzMTkgOTUuODUyMiA3OC41MzQ1IDk3Ljk0MDJDNzYuMzU2MyA5OC4xNzcyIDc0LjE0OTggOTguMTc1OCA3MS45MjkxIDk4LjA0MjRDNjIuODA5MSA5Ny40OTU5IDUzLjQ1MzUgOTQuNzU0OSA0NC45MjE5IDk3LjQ5MjNDMzkuMTEyOCA5OS4zNTY4IDM0LjM2MTkgMTAzLjc1NSAyOS40NDI4IDEwNS44ODhDMjMuNjYxNCAxMDguMzk2IDE5LjI4MzEgMTA5LjQyNyAxMi4wODM2IDEwOC4zOTZDMTEuMTY5NSAxMDcuMTY0IDE3LjM1MjYgMTA1LjU3NSAxNi45ODI5IDEwMi45MDJDMTQuMTY1MyAxMDIuNTkgMTIuNTI5MyAxMDMuMjczIDEwLjA4MDEgMTAyLjE2QzEwLjM1MDUgMTAxLjY2MiAxMC43NDc5IDEwMS4yNDcgMTEuMjQ4MyAxMDAuOTAxQzE1LjczNzMgOTcuNzk0IDI4LjQ4ODIgMTAwLjE2NyAzMS45MDA2IDk2LjgxNjdDMzQuMDA3IDk0Ljc1IDM1LjM4ODkgOTIuNTg2NyAzNi44MTk3IDkwLjQ4MzhDMzguMjA3MiA4OC40NDM0IDM5LjY0MTUgODYuNDU5NyA0MS44MjY4IDg0LjY3MTlDNDIuNjMzNyA4NC4wMTE4IDQzLjUxMSA4My4zNTk2IDQ0LjQ0MjEgODIuNzIzQzQ4LjE2NiA4MC4xNzQzIDUyLjc3MjkgNzcuODYyOCA1Ny4zMDY2IDc2LjI2OTRDNjMuNDgyNiA3NC4wOTg0IDY5Ljc0MSA3My45MTk1IDc2LjMyMzcgNzEuNDA0M0M4MC4zOTA0IDY5Ljg1IDg0LjgxMjcgNjcuOTMwMiA4OC40MTc0IDY1LjI0MzlDODkuMjczMyA2NC42MDUxIDkwLjA4MzEgNjMuOTI0NSA5MC44MzE5IDYzLjE5NDlDMTAxLjEyNSA1My4xNjA4IDEwMy4xNjUgMzUuNDYxIDExOS4yMjQgMzMuODExNkMxMjEuMTY2IDMzLjYxMjEgMTIyLjc1NiAzMy42NzY3IDEyNC4yMDMgMzMuNjMyN0MxMjUuODcxIDMzLjU4MyAxMjcuMzQ3IDMzLjM4OTMgMTI4Ljk1MyAzMi40ODQ0Wk0xMDkuMzc1IDg5LjEzMzlDMTA5LjU2NyA5Mi4yMDEzIDExMS4zNDggOTguMjg3MiAxMTIuOTIgOTkuNzY2M0MxMDkuODQxIDEwMC41MTUgMTA0LjUzNyA5OS4yNzggMTAzLjE3NyA5Ny4xMDYyQzEwMy44NzYgOTMuOTcwNyAxMDcuNTE0IDkxLjEwNDEgMTA5LjM3NSA4OS4xMzM5WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTEzMC4xMDkgMzUuOTE4N0MxMjkuNDkgMzcuMjE2OSAxMjguMzA1IDM4Ljg5MDggMTI4LjMwNSA0Mi4xOTU2QzEyOC4zIDQyLjc2MyAxMjcuODc1IDQzLjE1MTcgMTI3Ljg2NyA0Mi4yNzdDMTI3Ljg5OSAzOS4wNDcgMTI4Ljc1NCAzNy42NTA3IDEyOS42NjIgMzUuODE1NUMxMzAuMDg1IDM1LjA2MzYgMTMwLjMzOSAzNS4zNzM4IDEzMC4xMDkgMzUuOTE4N1pNMTI5LjQ4NiAzNS40Mjk3QzEyOC43NTYgMzYuNjY4NCAxMjYuOTk4IDM4LjkyNzggMTI2LjcwNyA0Mi4yMjAzQzEyNi42NTMgNDIuNzg0OCAxMjYuMTk0IDQzLjEzNDMgMTI2LjI2NCA0Mi4yNjE4QzEyNi41ODEgMzkuMDQ3NyAxMjcuOTg2IDM3LjAzNiAxMjkuMDUyIDM1LjI4NzNDMTI5LjUzNiAzNC41NzYxIDEyOS43NjMgMzQuOTA3NCAxMjkuNDg2IDM1LjQyOTdaTTEyOC45MTggMzQuNzgxN0MxMjguMDg2IDM1Ljk1NDMgMTI1LjM4IDM4LjY2NzggMTI0LjgxNCA0MS45MjQ3QzEyNC43MTIgNDIuNDgxOSAxMjQuMjI1IDQyLjc5MjggMTI0LjM2OCA0MS45MjlDMTI0Ljk1NCAzOC43NTIgMTI3LjI4NyAzNi4yNTUgMTI4LjQ5NiAzNC42MDM3QzEyOS4wMzggMzMuOTM0NiAxMjkuMjM3IDM0LjI4NCAxMjguOTE4IDM0Ljc4MTdaTTEyOC40MTEgMzQuMDU4OEwxMjguMTM3IDM0LjM0OTlDMTI2LjkyNyAzNS42NDcyIDEyNC4xMTYgMzguODExNCAxMjMuMTc5IDQxLjcwNzRDMTIyLjk5OSA0Mi4yNDUgMTIyLjQ3NCA0Mi40ODQ4IDEyMi43MzcgNDEuNjQ5M0MxMjMuNzYzIDM4LjU4NjQgMTI2LjU4OSAzNS4yODczIDEyOC4wMTggMzMuODIyN0MxMjguNjUgMzMuMjM2NCAxMjguNzk2IDMzLjYxMDYgMTI4LjQxMSAzNC4wNTg4Wk0xMTMuODg2IDQwLjYxNjJDMTE0LjUxMyAzNy45MjMxIDExNi42MDcgMzYuNjk2IDEyMC4yMjMgMzYuOTk1M0MxMjEuMDk2IDQxLjAxNTEgMTE2LjIxMyA0Mi42MzY2IDExMy44ODYgNDAuNjE2MloiIGZpbGw9IiMwNDI0NEUiLz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl82ODNfMjkzMCIgeDE9IjE0MC41IiB5MT0iMTQxIiB4Mj0iNS45OTk5OSIgeTI9Ii01LjUwMjI4ZS0wNiIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjQzQ5QTZDIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI0U3QkY5MyIvPgo8L2xpbmVhckdyYWRpZW50Pgo8L2RlZnM+Cjwvc3ZnPgo= - keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "users"], ["spec", "databases"], ["spec", "backup"], ["spec", "backup", "enabled"], ["spec", "backup", "s3Region"], ["spec", "backup", "s3Bucket"], ["spec", "backup", "schedule"], ["spec", "backup", "cleanupStrategy"], ["spec", "backup", "s3AccessKey"], ["spec", "backup", "s3SecretKey"], ["spec", "backup", "resticPassword"]] + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "version"], ["spec", "users"], ["spec", "databases"], ["spec", "backup"], ["spec", "backup", "enabled"], ["spec", "backup", "s3Region"], ["spec", "backup", "s3Bucket"], ["spec", "backup", "schedule"], ["spec", "backup", "cleanupStrategy"], ["spec", "backup", "s3AccessKey"], ["spec", "backup", "s3SecretKey"], ["spec", "backup", "resticPassword"]] secrets: exclude: [] include: From f2a4f1b1c85021d99e37fd7c54e2c6e31baa6359 Mon Sep 17 00:00:00 2001 From: nbykov0 <166552198+nbykov0@users.noreply.github.com> Date: Tue, 2 Dec 2025 12:54:36 +0300 Subject: [PATCH 12/33] [system:coredns] rename service to kube-dns Signed-off-by: nbykov0 <166552198+nbykov0@users.noreply.github.com> --- packages/system/coredns/values.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/system/coredns/values.yaml b/packages/system/coredns/values.yaml index 3b5740ad..a1061a1e 100644 --- a/packages/system/coredns/values.yaml +++ b/packages/system/coredns/values.yaml @@ -4,3 +4,5 @@ coredns: tag: v1.12.4 replicaCount: 2 k8sAppLabelOverride: kube-dns + service: + name: kube-dns From 5314d61987d127005c7d4d984b566d2f76fcd832 Mon Sep 17 00:00:00 2001 From: nbykov0 <166552198+nbykov0@users.noreply.github.com> Date: Tue, 2 Dec 2025 17:33:42 +0300 Subject: [PATCH 13/33] [core:installer] Fix buildx warnings Signed-off-by: nbykov0 <166552198+nbykov0@users.noreply.github.com> --- packages/core/installer/images/cozystack/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/installer/images/cozystack/Dockerfile b/packages/core/installer/images/cozystack/Dockerfile index 7327698e..c964c027 100644 --- a/packages/core/installer/images/cozystack/Dockerfile +++ b/packages/core/installer/images/cozystack/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.24-alpine as k8s-await-election-builder +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 @@ -13,7 +13,7 @@ RUN git clone ${K8S_AWAIT_ELECTION_GITREPO} /usr/local/go/k8s-await-election/ \ && make \ && mv ./out/k8s-await-election-${TARGETARCH} /k8s-await-election -FROM golang:1.24-alpine as builder +FROM golang:1.24-alpine AS builder ARG TARGETOS ARG TARGETARCH From 50c1d1a0677f9ed3b5f701d70e62fddff6f6cc8a Mon Sep 17 00:00:00 2001 From: nbykov0 <166552198+nbykov0@users.noreply.github.com> Date: Mon, 1 Dec 2025 20:52:21 +0300 Subject: [PATCH 14/33] [core:bundles] separate metrics-server Signed-off-by: nbykov0 <166552198+nbykov0@users.noreply.github.com> --- packages/core/platform/bundles/distro-full.yaml | 8 +++++++- packages/core/platform/bundles/distro-hosted.yaml | 8 +++++++- packages/core/platform/bundles/paas-full.yaml | 8 +++++++- packages/core/platform/bundles/paas-hosted.yaml | 8 +++++++- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/packages/core/platform/bundles/distro-full.yaml b/packages/core/platform/bundles/distro-full.yaml index ed52a83a..e4032194 100644 --- a/packages/core/platform/bundles/distro-full.yaml +++ b/packages/core/platform/bundles/distro-full.yaml @@ -87,6 +87,12 @@ releases: optional: true dependsOn: [cilium,cert-manager] +- name: metrics-server + releaseName: metrics-server + chart: cozy-metrics-server + namespace: cozy-monitoring + dependsOn: [cilium] + - name: victoria-metrics-operator releaseName: victoria-metrics-operator chart: cozy-victoria-metrics-operator @@ -100,7 +106,7 @@ releases: namespace: cozy-monitoring privileged: true optional: true - dependsOn: [cilium,victoria-metrics-operator] + dependsOn: [cilium,victoria-metrics-operator,metrics-server] values: scrapeRules: etcd: diff --git a/packages/core/platform/bundles/distro-hosted.yaml b/packages/core/platform/bundles/distro-hosted.yaml index 83aa81d9..9de60f3d 100644 --- a/packages/core/platform/bundles/distro-hosted.yaml +++ b/packages/core/platform/bundles/distro-hosted.yaml @@ -55,6 +55,12 @@ releases: optional: true dependsOn: [cert-manager] +- name: metrics-server + releaseName: metrics-server + chart: cozy-metrics-server + namespace: cozy-monitoring + dependsOn: [] + - name: victoria-metrics-operator releaseName: victoria-metrics-operator chart: cozy-victoria-metrics-operator @@ -68,7 +74,7 @@ releases: namespace: cozy-monitoring privileged: true optional: true - dependsOn: [victoria-metrics-operator] + dependsOn: [victoria-metrics-operator, metrics-server] values: scrapeRules: etcd: diff --git a/packages/core/platform/bundles/paas-full.yaml b/packages/core/platform/bundles/paas-full.yaml index 4382bd62..c00c25ed 100644 --- a/packages/core/platform/bundles/paas-full.yaml +++ b/packages/core/platform/bundles/paas-full.yaml @@ -142,6 +142,12 @@ releases: namespace: cozy-cert-manager dependsOn: [cilium,kubeovn,cert-manager] +- name: metrics-server + releaseName: metrics-server + chart: cozy-metrics-server + namespace: cozy-monitoring + dependsOn: [cilium] + - name: victoria-metrics-operator releaseName: victoria-metrics-operator chart: cozy-victoria-metrics-operator @@ -153,7 +159,7 @@ releases: chart: cozy-monitoring-agents namespace: cozy-monitoring privileged: true - dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] + dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds, metrics-server] values: scrapeRules: etcd: diff --git a/packages/core/platform/bundles/paas-hosted.yaml b/packages/core/platform/bundles/paas-hosted.yaml index 560578c7..9a9fb17e 100644 --- a/packages/core/platform/bundles/paas-hosted.yaml +++ b/packages/core/platform/bundles/paas-hosted.yaml @@ -86,6 +86,12 @@ releases: namespace: cozy-cert-manager dependsOn: [cert-manager] +- name: metrics-server + releaseName: metrics-server + chart: cozy-metrics-server + namespace: cozy-monitoring + dependsOn: [] + - name: victoria-metrics-operator releaseName: victoria-metrics-operator chart: cozy-victoria-metrics-operator @@ -97,7 +103,7 @@ releases: chart: cozy-monitoring-agents namespace: cozy-monitoring privileged: true - dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] + dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds, metrics-server] values: scrapeRules: etcd: From fbb2ea095aec3afaf9c539671a31914eb574cf04 Mon Sep 17 00:00:00 2001 From: nbykov0 <166552198+nbykov0@users.noreply.github.com> Date: Tue, 2 Dec 2025 21:01:07 +0300 Subject: [PATCH 15/33] [apps:kubernetes] separate metrics-server Signed-off-by: nbykov0 <166552198+nbykov0@users.noreply.github.com> --- .../helmreleases/metrics-server.yaml | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 packages/apps/kubernetes/templates/helmreleases/metrics-server.yaml diff --git a/packages/apps/kubernetes/templates/helmreleases/metrics-server.yaml b/packages/apps/kubernetes/templates/helmreleases/metrics-server.yaml new file mode 100644 index 00000000..394e6bb4 --- /dev/null +++ b/packages/apps/kubernetes/templates/helmreleases/metrics-server.yaml @@ -0,0 +1,42 @@ +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: {{ .Release.Name }}-metrics-server + labels: + cozystack.io/repository: system + cozystack.io/target-cluster-name: {{ .Release.Name }} +spec: + releaseName: metrics-server + chart: + spec: + chart: cozy-metrics-server + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' + kubeConfig: + secretRef: + name: {{ .Release.Name }}-admin-kubeconfig + key: super-admin.svc + targetNamespace: cozy-monitoring + storageNamespace: cozy-monitoring + interval: 5m + timeout: 10m + install: + createNamespace: true + remediation: + retries: -1 + upgrade: + remediation: + retries: -1 + dependsOn: + {{- if lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" .Release.Namespace .Release.Name }} + - name: {{ .Release.Name }} + namespace: {{ .Release.Namespace }} + {{- end }} + - name: {{ .Release.Name }}-cilium + namespace: {{ .Release.Namespace }} + - name: {{ .Release.Name }}-prometheus-operator-crds + namespace: {{ .Release.Namespace }} From 153635379a2a762c2c65be8c89860145a69352a4 Mon Sep 17 00:00:00 2001 From: nbykov0 <166552198+nbykov0@users.noreply.github.com> Date: Wed, 3 Dec 2025 16:18:28 +0300 Subject: [PATCH 16/33] [system] separate prometheus-operator-crds Signed-off-by: nbykov0 <166552198+nbykov0@users.noreply.github.com> --- .../prometheus-operator-crds/Chart.yaml | 3 + .../system/prometheus-operator-crds/Makefile | 10 + .../prometheus-operator-crds/.helmignore | 0 .../prometheus-operator-crds/Chart.lock | 2 +- .../prometheus-operator-crds/Chart.yaml | 4 +- .../charts/prometheus-operator-crds/README.md | 27 +- .../charts/crds/Chart.yaml | 0 .../crds/templates/crd-podmonitors.yaml | 492 ++++++++++++------ .../charts/crds/templates/crd-probes.yaml | 480 ++++++++++++----- .../crds/templates/crd-prometheusrules.yaml | 272 ++++++++++ .../crds/templates/crd-servicemonitors.yaml | 476 +++++++++++------ .../prometheus-operator-crds/ci/lint.sh | 0 .../hack/renovate-post-upgrade-hook.sh | 7 + .../hack/update_crds.sh | 51 ++ .../prometheus-operator-crds/values.yaml | 55 ++ .../prometheus-operator-crds/values.yaml | 0 .../crds/templates/crd-prometheusrules.yaml | 163 ------ .../hack/update_crds.sh | 45 -- .../prometheus-operator-crds/values.yaml | 4 - 19 files changed, 1429 insertions(+), 662 deletions(-) create mode 100644 packages/system/prometheus-operator-crds/Chart.yaml create mode 100644 packages/system/prometheus-operator-crds/Makefile rename packages/system/{victoria-metrics-operator => prometheus-operator-crds}/charts/prometheus-operator-crds/.helmignore (100%) rename packages/system/{victoria-metrics-operator => prometheus-operator-crds}/charts/prometheus-operator-crds/Chart.lock (76%) rename packages/system/{victoria-metrics-operator => prometheus-operator-crds}/charts/prometheus-operator-crds/Chart.yaml (97%) rename packages/system/{victoria-metrics-operator => prometheus-operator-crds}/charts/prometheus-operator-crds/README.md (63%) rename packages/system/{victoria-metrics-operator => prometheus-operator-crds}/charts/prometheus-operator-crds/charts/crds/Chart.yaml (100%) rename packages/system/{victoria-metrics-operator => prometheus-operator-crds}/charts/prometheus-operator-crds/charts/crds/templates/crd-podmonitors.yaml (69%) rename packages/system/{victoria-metrics-operator => prometheus-operator-crds}/charts/prometheus-operator-crds/charts/crds/templates/crd-probes.yaml (69%) create mode 100644 packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-prometheusrules.yaml rename packages/system/{victoria-metrics-operator => prometheus-operator-crds}/charts/prometheus-operator-crds/charts/crds/templates/crd-servicemonitors.yaml (70%) rename packages/system/{victoria-metrics-operator => prometheus-operator-crds}/charts/prometheus-operator-crds/ci/lint.sh (100%) create mode 100644 packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/hack/renovate-post-upgrade-hook.sh create mode 100644 packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/hack/update_crds.sh create mode 100644 packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/values.yaml create mode 100644 packages/system/prometheus-operator-crds/values.yaml delete mode 100644 packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-prometheusrules.yaml delete mode 100644 packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/hack/update_crds.sh delete mode 100644 packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/values.yaml diff --git a/packages/system/prometheus-operator-crds/Chart.yaml b/packages/system/prometheus-operator-crds/Chart.yaml new file mode 100644 index 00000000..576c241f --- /dev/null +++ b/packages/system/prometheus-operator-crds/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-prometheus-operator-crds +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/prometheus-operator-crds/Makefile b/packages/system/prometheus-operator-crds/Makefile new file mode 100644 index 00000000..87dbe606 --- /dev/null +++ b/packages/system/prometheus-operator-crds/Makefile @@ -0,0 +1,10 @@ +export NAME=victoria-metrics-operator +export NAMESPACE=cozy-$(NAME) + +include ../../../scripts/package.mk + +update: + helm repo add prometheus-community https://prometheus-community.github.io/helm-charts + helm repo update prometheus-community + helm pull prometheus-community/prometheus-operator-crds --untar --untardir charts + rm -f -- `find charts/prometheus-operator-crds/charts/crds/templates -maxdepth 1 -mindepth 1 | grep -v 'servicemonitor\|podmonitor\|prometheusrule\|probe'` diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/.helmignore b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/.helmignore similarity index 100% rename from packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/.helmignore rename to packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/.helmignore diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/Chart.lock b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/Chart.lock similarity index 76% rename from packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/Chart.lock rename to packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/Chart.lock index f1acf647..336e8e35 100644 --- a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/Chart.lock +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/Chart.lock @@ -3,4 +3,4 @@ dependencies: repository: "" version: 0.0.0 digest: sha256:aeada3fbffa2565a325406ad014001fd2685f7c0c9cfc1167da4f10c75a1bd65 -generated: "2025-03-15T22:08:36.140314181Z" +generated: "2025-11-21T15:12:44.500376661Z" diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/Chart.yaml b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/Chart.yaml similarity index 97% rename from packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/Chart.yaml rename to packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/Chart.yaml index 6c0097f0..20e194ee 100644 --- a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/Chart.yaml +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/Chart.yaml @@ -10,7 +10,7 @@ annotations: - name: QuentinBisson email: quentin.bisson@gmail.com apiVersion: v2 -appVersion: v0.81.0 +appVersion: v0.87.0 dependencies: - name: crds repository: "" @@ -39,4 +39,4 @@ name: prometheus-operator-crds sources: - https://github.com/prometheus-community/helm-charts type: application -version: 19.0.0 +version: 25.0.0 diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/README.md b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/README.md similarity index 63% rename from packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/README.md rename to packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/README.md index b4dfcedd..21e979b5 100644 --- a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/README.md +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/README.md @@ -9,27 +9,26 @@ For more information on Prometheus Operator and CRDs, please, see [documentation - Kubernetes >= 1.16.0 - Helm 3 -## Get Repository Info - -```console -helm repo add prometheus-community https://prometheus-community.github.io/helm-charts -helm repo update -``` +## Usage -_See [`helm repo`](https://helm.sh/docs/helm/helm_repo/) for command documentation._ - +The chart is distributed as an [OCI Artifact](https://helm.sh/docs/topics/registries/) as well as via a traditional [Helm Repository](https://helm.sh/docs/topics/chart_repository/). -## Install Chart +- OCI Artifact: `oci://ghcr.io/prometheus-community/charts/prometheus-operator-crds` +- Helm Repository: `https://prometheus-community.github.io/helm-charts` with chart `prometheus-operator-crds` + +The installation instructions use the OCI registry. Refer to the [`helm repo`]([`helm repo`](https://helm.sh/docs/helm/helm_repo/)) command documentation for information on installing charts via the traditional repository. + +### Install Chart ```console -helm install [RELEASE_NAME] prometheus-community/prometheus-operator-crds +helm install [RELEASE_NAME] oci://ghcr.io/prometheus-community/charts/prometheus-operator-crds ``` _See [configuration](#configuring) below._ _See [helm install](https://helm.sh/docs/helm/helm_install/) for command documentation._ -## Uninstall Chart +### Uninstall Chart ```console helm uninstall [RELEASE_NAME] @@ -40,7 +39,7 @@ _including_ resources of Kind `Prometheus`, `Alertmanager`, `ServiceMonitor`, et _See [helm uninstall](https://helm.sh/docs/helm/helm_uninstall/) for command documentation._ -## Upgrading Chart +### Upgrading Chart ```console helm upgrade [RELEASE_NAME] [CHART] --install @@ -48,7 +47,7 @@ helm upgrade [RELEASE_NAME] [CHART] --install _See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documentation._ -## Upgrading to v6.0.0 +#### Upgrading to v6.0.0 The upgraded chart now the following changes: @@ -59,5 +58,5 @@ The upgraded chart now the following changes: See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). To see all configurable options with detailed comments, visit the chart's [values.yaml](./values.yaml), or run these configuration commands: ```console -helm show values prometheus-community/prometheus-operator-crds +helm show values oci://ghcr.io/prometheus-community/charts/prometheus-operator-crds ``` diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/Chart.yaml b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/Chart.yaml similarity index 100% rename from packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/Chart.yaml rename to packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/Chart.yaml diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-podmonitors.yaml b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-podmonitors.yaml similarity index 69% rename from packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-podmonitors.yaml rename to packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-podmonitors.yaml index dcb71f7c..608d53e5 100644 --- a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-podmonitors.yaml +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-podmonitors.yaml @@ -1,4 +1,5 @@ -# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.81.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +{{- if .Values.podmonitors.enabled -}} +# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.87.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -7,8 +8,8 @@ metadata: {{- with .Values.annotations }} {{- toYaml . | nindent 4 }} {{- end }} - controller-gen.kubebuilder.io/version: v0.17.2 - operator.prometheus.io/version: 0.81.0 + controller-gen.kubebuilder.io/version: v0.19.0 + operator.prometheus.io/version: 0.87.0 name: podmonitors.monitoring.coreos.com spec: group: monitoring.coreos.com @@ -54,19 +55,19 @@ spec: metadata: type: object spec: - description: Specification of desired Pod selection for target discovery - by Prometheus. + description: spec defines the specification of desired Pod selection for + target discovery by Prometheus. properties: attachMetadata: description: |- - `attachMetadata` defines additional metadata which is added to the + attachMetadata defines additional metadata which is added to the discovered targets. It requires Prometheus >= v2.35.0. properties: node: description: |- - When set to true, Prometheus attaches node metadata to the discovered + node when set to true, Prometheus attaches node metadata to the discovered targets. The Prometheus service account must have the `list` and `watch` @@ -75,15 +76,20 @@ spec: type: object bodySizeLimit: description: |- - When defined, bodySizeLimit specifies a job level limit on the size + bodySizeLimit when defined specifies a job level limit on the size of uncompressed response body that will be accepted by Prometheus. It requires Prometheus >= v2.28.0. pattern: (^0|([0-9]*[.])?[0-9]+((K|M|G|T|E|P)i?)?B)$ type: string + convertClassicHistogramsToNHCB: + description: |- + convertClassicHistogramsToNHCB defines whether to convert all scraped classic histograms into a native histogram with custom buckets. + It requires Prometheus >= v3.0.0. + type: boolean fallbackScrapeProtocol: description: |- - The protocol to use if a scrape returns blank, unparseable, or otherwise invalid Content-Type. + fallbackScrapeProtocol defines the protocol to use if a scrape returns blank, unparseable, or otherwise invalid Content-Type. It requires Prometheus >= v3.0.0. enum: @@ -95,7 +101,7 @@ spec: type: string jobLabel: description: |- - The label to use to retrieve the job name from. + jobLabel defines the label to use to retrieve the job name from. `jobLabel` selects the label from the associated Kubernetes `Pod` object which will be used as the `job` label for all metrics. @@ -108,7 +114,7 @@ spec: type: string keepDroppedTargets: description: |- - Per-scrape limit on the number of targets dropped by relabeling + keepDroppedTargets defines the per-scrape limit on the number of targets dropped by relabeling that will be kept in memory. 0 means no limit. It requires Prometheus >= v2.47.0. @@ -116,44 +122,45 @@ spec: type: integer labelLimit: description: |- - Per-scrape limit on number of labels that will be accepted for a sample. + labelLimit defines the per-scrape limit on number of labels that will be accepted for a sample. It requires Prometheus >= v2.27.0. format: int64 type: integer labelNameLengthLimit: description: |- - Per-scrape limit on length of labels name that will be accepted for a sample. + labelNameLengthLimit defines the per-scrape limit on length of labels name that will be accepted for a sample. It requires Prometheus >= v2.27.0. format: int64 type: integer labelValueLengthLimit: description: |- - Per-scrape limit on length of labels value that will be accepted for a sample. + labelValueLengthLimit defines the per-scrape limit on length of labels value that will be accepted for a sample. It requires Prometheus >= v2.27.0. format: int64 type: integer namespaceSelector: description: |- - `namespaceSelector` defines in which namespace(s) Prometheus should discover the pods. + namespaceSelector defines in which namespace(s) Prometheus should discover the pods. By default, the pods are discovered in the same namespace as the `PodMonitor` object but it is possible to select pods across different/all namespaces. properties: any: description: |- - Boolean describing whether all namespaces are selected in contrast to a + any defines the boolean describing whether all namespaces are selected in contrast to a list restricting them. type: boolean matchNames: - description: List of namespace names to select from. + description: matchNames defines the list of namespace names to + select from. items: type: string type: array type: object nativeHistogramBucketLimit: description: |- - If there are more than this many buckets in a native histogram, + nativeHistogramBucketLimit defines ff there are more than this many buckets in a native histogram, buckets will be merged to stay within the limit. It requires Prometheus >= v2.45.0. format: int64 @@ -163,13 +170,14 @@ spec: - type: integer - type: string description: |- - If the growth factor of one bucket to the next is smaller than this, + nativeHistogramMinBucketFactor defines if the growth factor of one bucket to the next is smaller than this, buckets will be merged to increase the factor sufficiently. It requires Prometheus >= v2.50.0. pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true podMetricsEndpoints: - description: Defines how to scrape metrics from the selected pods. + description: podMetricsEndpoints defines how to scrape metrics from + the selected pods. items: description: |- PodMetricsEndpoint defines an endpoint serving Prometheus metrics to be scraped by @@ -177,14 +185,14 @@ spec: properties: authorization: description: |- - `authorization` configures the Authorization header credentials to use when - scraping the target. + authorization configures the Authorization header credentials used by + the client. - Cannot be set at the same time as `basicAuth`, or `oauth2`. + Cannot be set at the same time as `basicAuth`, `bearerTokenSecret` or `oauth2`. properties: credentials: - description: Selects a key of a Secret in the namespace - that contains the credentials for authentication. + description: credentials defines a key of a Secret in the + namespace that contains the credentials for authentication. properties: key: description: The key of the secret to select from. Must @@ -209,7 +217,7 @@ spec: x-kubernetes-map-type: atomic type: description: |- - Defines the authentication type. The value is case-insensitive. + type defines the authentication type. The value is case-insensitive. "Basic" is not a supported value. @@ -218,14 +226,14 @@ spec: type: object basicAuth: description: |- - `basicAuth` configures the Basic Authentication credentials to use when - scraping the target. + basicAuth defines the Basic Authentication credentials used by the + client. - Cannot be set at the same time as `authorization`, or `oauth2`. + Cannot be set at the same time as `authorization`, `bearerTokenSecret` or `oauth2`. properties: password: description: |- - `password` specifies a key of a Secret containing the password for + password defines a key of a Secret containing the password for authentication. properties: key: @@ -251,7 +259,7 @@ spec: x-kubernetes-map-type: atomic username: description: |- - `username` specifies a key of a Secret containing the username for + username defines a key of a Secret containing the username for authentication. properties: key: @@ -278,9 +286,12 @@ spec: type: object bearerTokenSecret: description: |- - `bearerTokenSecret` specifies a key of a Secret containing the bearer - token for scraping targets. The secret needs to be in the same namespace - as the PodMonitor object and readable by the Prometheus Operator. + bearerTokenSecret defines a key of a Secret containing the bearer token + used by the client for authentication. The secret needs to be in the + same namespace as the custom resource and readable by the Prometheus + Operator. + + Cannot be set at the same time as `authorization`, `basicAuth` or `oauth2`. Deprecated: use `authorization` instead. properties: @@ -306,12 +317,11 @@ spec: type: object x-kubernetes-map-type: atomic enableHttp2: - description: '`enableHttp2` can be used to disable HTTP2 when - scraping the target.' + description: enableHttp2 can be used to disable HTTP2. type: boolean filterRunning: description: |- - When true, the pods which are not running (e.g. either in Failed or + filterRunning when true, the pods which are not running (e.g. either in Failed or Succeeded state) are dropped during the target discovery. If unset, the filtering is enabled. @@ -320,29 +330,29 @@ spec: type: boolean followRedirects: description: |- - `followRedirects` defines whether the scrape requests should follow HTTP - 3xx redirects. + followRedirects defines whether the client should follow HTTP 3xx + redirects. type: boolean honorLabels: description: |- - When true, `honorLabels` preserves the metric's labels when they collide + honorLabels when true preserves the metric's labels when they collide with the target's labels. type: boolean honorTimestamps: description: |- - `honorTimestamps` controls whether Prometheus preserves the timestamps + honorTimestamps defines whether Prometheus preserves the timestamps when exposed by the target. type: boolean interval: description: |- - Interval at which Prometheus scrapes the metrics from the target. + interval at which Prometheus scrapes the metrics from the target. If empty, Prometheus uses the global scrape interval. pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ type: string metricRelabelings: description: |- - `metricRelabelings` configures the relabeling rules to apply to the + metricRelabelings defines the relabeling rules to apply to the samples before ingestion. items: description: |- @@ -354,7 +364,7 @@ spec: action: default: replace description: |- - Action to perform based on the regex matching. + action to perform based on the regex matching. `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. @@ -386,41 +396,41 @@ spec: type: string modulus: description: |- - Modulus to take of the hash of the source label values. + modulus to take of the hash of the source label values. Only applicable when the action is `HashMod`. format: int64 type: integer regex: - description: Regular expression against which the extracted - value is matched. + description: regex defines the regular expression against + which the extracted value is matched. type: string replacement: description: |- - Replacement value against which a Replace action is performed if the + replacement value against which a Replace action is performed if the regular expression matches. Regex capture groups are available. type: string separator: - description: Separator is the string between concatenated + description: separator defines the string between concatenated SourceLabels. type: string sourceLabels: description: |- - The source labels select values from existing labels. Their content is + sourceLabels defines the source labels select values from existing labels. Their content is concatenated using the configured Separator and matched against the configured regular expression. items: description: |- - LabelName is a valid Prometheus label name which may only contain ASCII - letters, numbers, as well as underscores. - pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. type: string type: array targetLabel: description: |- - Label to which the resulting string is written in a replacement. + targetLabel defines the label to which the resulting string is written in a replacement. It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, `KeepEqual` and `DropEqual` actions. @@ -429,22 +439,30 @@ spec: type: string type: object type: array + noProxy: + description: |- + noProxy defines a comma-separated string that can contain IPs, CIDR notation, domain names + that should be excluded from proxying. IP and domain names can + contain port numbers. + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: string oauth2: description: |- - `oauth2` configures the OAuth2 settings to use when scraping the target. + oauth2 defines the OAuth2 settings used by the client. It requires Prometheus >= 2.27.0. - Cannot be set at the same time as `authorization`, or `basicAuth`. + Cannot be set at the same time as `authorization`, `basicAuth` or `bearerTokenSecret`. properties: clientId: description: |- - `clientId` specifies a key of a Secret or ConfigMap containing the + clientId defines a key of a Secret or ConfigMap containing the OAuth2 client's ID. properties: configMap: - description: ConfigMap containing data to use for the - targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -467,7 +485,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data + to use for the targets. properties: key: description: The key of the secret to select from. Must @@ -493,7 +512,7 @@ spec: type: object clientSecret: description: |- - `clientSecret` specifies a key of a Secret containing the OAuth2 + clientSecret defines a key of a Secret containing the OAuth2 client's secret. properties: key: @@ -521,16 +540,16 @@ spec: additionalProperties: type: string description: |- - `endpointParams` configures the HTTP parameters to append to the token + endpointParams configures the HTTP parameters to append to the token URL. type: object noProxy: description: |- - `noProxy` is a comma-separated string that can contain IPs, CIDR notation, domain names + noProxy defines a comma-separated string that can contain IPs, CIDR notation, domain names that should be excluded from proxying. IP and domain names can contain port numbers. - It requires Prometheus >= v2.43.0 or Alertmanager >= 0.25.0. + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. type: string proxyConnectHeader: additionalProperties: @@ -560,41 +579,40 @@ spec: x-kubernetes-map-type: atomic type: array description: |- - ProxyConnectHeader optionally specifies headers to send to + proxyConnectHeader optionally specifies headers to send to proxies during CONNECT requests. - It requires Prometheus >= v2.43.0 or Alertmanager >= 0.25.0. + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. type: object x-kubernetes-map-type: atomic proxyFromEnvironment: description: |- - Whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). + proxyFromEnvironment defines whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). - It requires Prometheus >= v2.43.0 or Alertmanager >= 0.25.0. + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. type: boolean proxyUrl: - description: '`proxyURL` defines the HTTP proxy server to - use.' - pattern: ^http(s)?://.+$ + description: proxyUrl defines the HTTP proxy server to use. + pattern: ^(http|https|socks5)://.+$ type: string scopes: - description: '`scopes` defines the OAuth2 scopes used for - the token request.' + description: scopes defines the OAuth2 scopes used for the + token request. items: type: string type: array tlsConfig: description: |- - TLS configuration to use when connecting to the OAuth2 server. + tlsConfig defines the TLS configuration to use when connecting to the OAuth2 server. It requires Prometheus >= v2.43.0. properties: ca: - description: Certificate authority used when verifying - server certificates. + description: ca defines the Certificate authority used + when verifying server certificates. properties: configMap: - description: ConfigMap containing data to use for - the targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -617,8 +635,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the - targets. + description: secret defines the Secret containing + data to use for the targets. properties: key: description: The key of the secret to select @@ -643,12 +661,12 @@ spec: x-kubernetes-map-type: atomic type: object cert: - description: Client certificate to present when doing - client-authentication. + description: cert defines the Client certificate to + present when doing client-authentication. properties: configMap: - description: ConfigMap containing data to use for - the targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -671,8 +689,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the - targets. + description: secret defines the Secret containing + data to use for the targets. properties: key: description: The key of the secret to select @@ -697,11 +715,12 @@ spec: x-kubernetes-map-type: atomic type: object insecureSkipVerify: - description: Disable target certificate validation. + description: insecureSkipVerify defines how to disable + target certificate validation. type: boolean keySecret: - description: Secret containing the client key file for - the targets. + description: keySecret defines the Secret containing + the client key file for the targets. properties: key: description: The key of the secret to select from. Must @@ -726,9 +745,9 @@ spec: x-kubernetes-map-type: atomic maxVersion: description: |- - Maximum acceptable TLS version. + maxVersion defines the maximum acceptable TLS version. - It requires Prometheus >= v2.41.0. + It requires Prometheus >= v2.41.0 or Thanos >= v0.31.0. enum: - TLS10 - TLS11 @@ -737,9 +756,9 @@ spec: type: string minVersion: description: |- - Minimum acceptable TLS version. + minVersion defines the minimum acceptable TLS version. - It requires Prometheus >= v2.35.0. + It requires Prometheus >= v2.35.0 or Thanos >= v0.28.0. enum: - TLS10 - TLS11 @@ -747,12 +766,13 @@ spec: - TLS13 type: string serverName: - description: Used to verify the hostname for the targets. + description: serverName is used to verify the hostname + for the targets. type: string type: object tokenUrl: - description: '`tokenURL` configures the URL to fetch the - token from.' + description: tokenUrl defines the URL to fetch the token + from. minLength: 1 type: string required: @@ -765,34 +785,92 @@ spec: items: type: string type: array - description: '`params` define optional HTTP URL parameters.' + description: params define optional HTTP URL parameters. type: object path: description: |- - HTTP path from which to scrape for metrics. + path defines the HTTP path from which to scrape for metrics. If empty, Prometheus uses the default value (e.g. `/metrics`). type: string port: description: |- - The `Pod` port name which exposes the endpoint. + port defines the `Pod` port name which exposes the endpoint. + + If the pod doesn't expose a port with the same name, it will result + in no targets being discovered. + + If a `Pod` has multiple `Port`s with the same name (which is not + recommended), one target instance per unique port number will be + generated. It takes precedence over the `portNumber` and `targetPort` fields. type: string portNumber: - description: The `Pod` port number which exposes the endpoint. + description: |- + portNumber defines the `Pod` port number which exposes the endpoint. + + The `Pod` must declare the specified `Port` in its spec or the + target will be dropped by Prometheus. + + This cannot be used to enable scraping of an undeclared port. + To scrape targets on a port which isn't exposed, you need to use + relabeling to override the `__address__` label (but beware of + duplicate targets if the `Pod` has other declared ports). + + In practice Prometheus will select targets for which the + matches the target's __meta_kubernetes_pod_container_port_number. format: int32 maximum: 65535 minimum: 1 type: integer - proxyUrl: + proxyConnectHeader: + additionalProperties: + items: + description: SecretKeySelector selects a key of a Secret. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + 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 + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: array description: |- - `proxyURL` configures the HTTP Proxy URL (e.g. - "http://proxyserver:2195") to go through when scraping the target. + proxyConnectHeader optionally specifies headers to send to + proxies during CONNECT requests. + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: object + x-kubernetes-map-type: atomic + proxyFromEnvironment: + description: |- + proxyFromEnvironment defines whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: boolean + proxyUrl: + description: proxyUrl defines the HTTP proxy server to use. + pattern: ^(http|https|socks5)://.+$ type: string relabelings: description: |- - `relabelings` configures the relabeling rules to apply the target's + relabelings defines the relabeling rules to apply the target's metadata labels. The Operator automatically adds relabelings for a few standard Kubernetes fields. @@ -810,7 +888,7 @@ spec: action: default: replace description: |- - Action to perform based on the regex matching. + action to perform based on the regex matching. `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. @@ -842,41 +920,41 @@ spec: type: string modulus: description: |- - Modulus to take of the hash of the source label values. + modulus to take of the hash of the source label values. Only applicable when the action is `HashMod`. format: int64 type: integer regex: - description: Regular expression against which the extracted - value is matched. + description: regex defines the regular expression against + which the extracted value is matched. type: string replacement: description: |- - Replacement value against which a Replace action is performed if the + replacement value against which a Replace action is performed if the regular expression matches. Regex capture groups are available. type: string separator: - description: Separator is the string between concatenated + description: separator defines the string between concatenated SourceLabels. type: string sourceLabels: description: |- - The source labels select values from existing labels. Their content is + sourceLabels defines the source labels select values from existing labels. Their content is concatenated using the configured Separator and matched against the configured regular expression. items: description: |- - LabelName is a valid Prometheus label name which may only contain ASCII - letters, numbers, as well as underscores. - pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. type: string type: array targetLabel: description: |- - Label to which the resulting string is written in a replacement. + targetLabel defines the label to which the resulting string is written in a replacement. It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, `KeepEqual` and `DropEqual` actions. @@ -886,20 +964,16 @@ spec: type: object type: array scheme: - description: |- - HTTP scheme to use for scraping. - - `http` and `https` are the expected values unless you rewrite the - `__scheme__` label via relabeling. - - If empty, Prometheus uses the default value `http`. + description: scheme defines the HTTP scheme to use for scraping. enum: - http - https + - HTTP + - HTTPS type: string scrapeTimeout: description: |- - Timeout after which Prometheus considers the scrape to be failed. + scrapeTimeout defines the timeout after which Prometheus considers the scrape to be failed. If empty, Prometheus uses the global scrape timeout unless it is less than the target's scrape interval value in which the latter is used. @@ -911,21 +985,22 @@ spec: - type: integer - type: string description: |- - Name or number of the target port of the `Pod` object behind the Service, the + targetPort defines the name or number of the target port of the `Pod` object behind the Service, the port must be specified with container port property. Deprecated: use 'port' or 'portNumber' instead. x-kubernetes-int-or-string: true tlsConfig: - description: TLS configuration to use when scraping the target. + description: tlsConfig defines the TLS configuration used by + the client. properties: ca: - description: Certificate authority used when verifying server - certificates. + description: ca defines the Certificate authority used when + verifying server certificates. properties: configMap: - description: ConfigMap containing data to use for the - targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -948,7 +1023,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data + to use for the targets. properties: key: description: The key of the secret to select from. Must @@ -973,11 +1049,12 @@ spec: x-kubernetes-map-type: atomic type: object cert: - description: Client certificate to present when doing client-authentication. + description: cert defines the Client certificate to present + when doing client-authentication. properties: configMap: - description: ConfigMap containing data to use for the - targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -1000,7 +1077,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data + to use for the targets. properties: key: description: The key of the secret to select from. Must @@ -1025,11 +1103,12 @@ spec: x-kubernetes-map-type: atomic type: object insecureSkipVerify: - description: Disable target certificate validation. + description: insecureSkipVerify defines how to disable target + certificate validation. type: boolean keySecret: - description: Secret containing the client key file for the - targets. + description: keySecret defines the Secret containing the + client key file for the targets. properties: key: description: The key of the secret to select from. Must @@ -1054,9 +1133,9 @@ spec: x-kubernetes-map-type: atomic maxVersion: description: |- - Maximum acceptable TLS version. + maxVersion defines the maximum acceptable TLS version. - It requires Prometheus >= v2.41.0. + It requires Prometheus >= v2.41.0 or Thanos >= v0.31.0. enum: - TLS10 - TLS11 @@ -1065,9 +1144,9 @@ spec: type: string minVersion: description: |- - Minimum acceptable TLS version. + minVersion defines the minimum acceptable TLS version. - It requires Prometheus >= v2.35.0. + It requires Prometheus >= v2.35.0 or Thanos >= v0.28.0. enum: - TLS10 - TLS11 @@ -1075,12 +1154,13 @@ spec: - TLS13 type: string serverName: - description: Used to verify the hostname for the targets. + description: serverName is used to verify the hostname for + the targets. type: string type: object trackTimestampsStaleness: description: |- - `trackTimestampsStaleness` defines whether Prometheus tracks staleness of + trackTimestampsStaleness defines whether Prometheus tracks staleness of the metrics that have an explicit timestamp present in scraped data. Has no effect if `honorTimestamps` is false. @@ -1090,29 +1170,31 @@ spec: type: array podTargetLabels: description: |- - `podTargetLabels` defines the labels which are transferred from the + podTargetLabels defines the labels which are transferred from the associated Kubernetes `Pod` object onto the ingested metrics. items: type: string type: array sampleLimit: description: |- - `sampleLimit` defines a per-scrape limit on the number of scraped samples + sampleLimit defines a per-scrape limit on the number of scraped samples that will be accepted. format: int64 type: integer scrapeClass: - description: The scrape class to apply. + description: scrapeClass defines the scrape class to apply. minLength: 1 type: string scrapeClassicHistograms: description: |- - Whether to scrape a classic histogram that is also exposed as a native histogram. + scrapeClassicHistograms defines whether to scrape a classic histogram that is also exposed as a native histogram. It requires Prometheus >= v2.45.0. + + Notice: `scrapeClassicHistograms` corresponds to the `always_scrape_classic_histograms` field in the Prometheus configuration. type: boolean scrapeProtocols: description: |- - `scrapeProtocols` defines the protocols to negotiate during a scrape. It tells clients the + scrapeProtocols defines the protocols to negotiate during a scrape. It tells clients the protocols supported by Prometheus in order of preference (from most to least preferred). If unset, Prometheus uses its default value. @@ -1137,8 +1219,8 @@ spec: type: array x-kubernetes-list-type: set selector: - description: Label selector to select the Kubernetes `Pod` objects - to scrape metrics from. + description: selector defines the label selector to select the Kubernetes + `Pod` objects to scrape metrics from. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. @@ -1185,7 +1267,7 @@ spec: x-kubernetes-map-type: atomic selectorMechanism: description: |- - Mechanism used to select the endpoints to scrape. + selectorMechanism defines the mechanism used to select the endpoints to scrape. By default, the selection process relies on relabel configurations to filter the discovered targets. Alternatively, you can opt in for role selectors, which may offer better efficiency in large clusters. Which strategy is best for your use case needs to be carefully evaluated. @@ -1197,15 +1279,121 @@ spec: type: string targetLimit: description: |- - `targetLimit` defines a limit on the number of scraped targets that will + targetLimit defines a limit on the number of scraped targets that will be accepted. format: int64 type: integer required: - selector type: object + status: + description: |- + status defines the status subresource. It is under active development and is updated only when the + "StatusForConfigurationResources" feature gate is enabled. + + Most recent observed status of the PodMonitor. Read-only. + More info: + https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + bindings: + description: bindings defines the list of workload resources (Prometheus, + PrometheusAgent, ThanosRuler or Alertmanager) which select the configuration + resource. + items: + description: WorkloadBinding is a link between a configuration resource + and a workload resource. + properties: + conditions: + description: conditions defines the current state of the configuration + resource when bound to the referenced Workload object. + items: + description: ConfigResourceCondition describes the status + of configuration resources linked to Prometheus, PrometheusAgent, + Alertmanager or ThanosRuler. + properties: + lastTransitionTime: + description: lastTransitionTime defines the time of the + last update to the current status property. + format: date-time + type: string + message: + description: message defines the human-readable message + indicating details for the condition's last transition. + type: string + observedGeneration: + description: |- + observedGeneration defines the .metadata.generation that the + condition was set based upon. For instance, if `.metadata.generation` is + currently 12, but the `.status.conditions[].observedGeneration` is 9, the + condition is out of date with respect to the current state of the object. + format: int64 + type: integer + reason: + description: reason for the condition's last transition. + type: string + status: + description: status of the condition. + minLength: 1 + type: string + type: + description: |- + type of the condition being reported. + Currently, only "Accepted" is supported. + enum: + - Accepted + minLength: 1 + type: string + required: + - lastTransitionTime + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + group: + description: group defines the group of the referenced resource. + enum: + - monitoring.coreos.com + type: string + name: + description: name defines the name of the referenced object. + minLength: 1 + type: string + namespace: + description: namespace defines the namespace of the referenced + object. + minLength: 1 + type: string + resource: + description: resource defines the type of resource being referenced + (e.g. Prometheus, PrometheusAgent, ThanosRuler or Alertmanager). + enum: + - prometheuses + - prometheusagents + - thanosrulers + - alertmanagers + type: string + required: + - group + - name + - namespace + - resource + type: object + type: array + x-kubernetes-list-map-keys: + - group + - resource + - name + - namespace + x-kubernetes-list-type: map + type: object required: - spec type: object served: true storage: true + subresources: + status: {} +{{- end -}} diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-probes.yaml b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-probes.yaml similarity index 69% rename from packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-probes.yaml rename to packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-probes.yaml index 05a75775..f2d06e03 100644 --- a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-probes.yaml +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-probes.yaml @@ -1,4 +1,5 @@ -# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.81.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +{{- if .Values.probes.enabled -}} +# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.87.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -7,8 +8,8 @@ metadata: {{- with .Values.annotations }} {{- toYaml . | nindent 4 }} {{- end }} - controller-gen.kubebuilder.io/version: v0.17.2 - operator.prometheus.io/version: 0.81.0 + controller-gen.kubebuilder.io/version: v0.19.0 + operator.prometheus.io/version: 0.87.0 name: probes.monitoring.coreos.com spec: group: monitoring.coreos.com @@ -53,15 +54,15 @@ spec: metadata: type: object spec: - description: Specification of desired Ingress selection for target discovery - by Prometheus. + description: spec defines the specification of desired Ingress selection + for target discovery by Prometheus. properties: authorization: - description: Authorization section for this endpoint + description: authorization section for this endpoint properties: credentials: - description: Selects a key of a Secret in the namespace that contains - the credentials for authentication. + description: credentials defines a key of a Secret in the namespace + that contains the credentials for authentication. properties: key: description: The key of the secret to select from. Must be @@ -86,7 +87,7 @@ spec: x-kubernetes-map-type: atomic type: description: |- - Defines the authentication type. The value is case-insensitive. + type defines the authentication type. The value is case-insensitive. "Basic" is not a supported value. @@ -95,12 +96,12 @@ spec: type: object basicAuth: description: |- - BasicAuth allow an endpoint to authenticate over basic authentication. + basicAuth allow an endpoint to authenticate over basic authentication. More info: https://prometheus.io/docs/operating/configuration/#endpoint properties: password: description: |- - `password` specifies a key of a Secret containing the password for + password defines a key of a Secret containing the password for authentication. properties: key: @@ -126,7 +127,7 @@ spec: x-kubernetes-map-type: atomic username: description: |- - `username` specifies a key of a Secret containing the username for + username defines a key of a Secret containing the username for authentication. properties: key: @@ -153,7 +154,7 @@ spec: type: object bearerTokenSecret: description: |- - Secret to mount to read bearer token for scraping targets. The secret + bearerTokenSecret defines the secret to mount to read bearer token for scraping targets. The secret needs to be in the same namespace as the probe and accessible by the Prometheus Operator. properties: @@ -177,9 +178,14 @@ spec: - key type: object x-kubernetes-map-type: atomic + convertClassicHistogramsToNHCB: + description: |- + convertClassicHistogramsToNHCB defines whether to convert all scraped classic histograms into a native histogram with custom buckets. + It requires Prometheus >= v3.0.0. + type: boolean fallbackScrapeProtocol: description: |- - The protocol to use if a scrape returns blank, unparseable, or otherwise invalid Content-Type. + fallbackScrapeProtocol defines the protocol to use if a scrape returns blank, unparseable, or otherwise invalid Content-Type. It requires Prometheus >= v3.0.0. enum: @@ -191,16 +197,16 @@ spec: type: string interval: description: |- - Interval at which targets are probed using the configured prober. + interval at which targets are probed using the configured prober. If not specified Prometheus' global scrape interval is used. pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ type: string jobName: - description: The job name assigned to scraped metrics by default. + description: jobName assigned to scraped metrics by default. type: string keepDroppedTargets: description: |- - Per-scrape limit on the number of targets dropped by relabeling + keepDroppedTargets defines the per-scrape limit on the number of targets dropped by relabeling that will be kept in memory. 0 means no limit. It requires Prometheus >= v2.47.0. @@ -208,24 +214,25 @@ spec: type: integer labelLimit: description: |- - Per-scrape limit on number of labels that will be accepted for a sample. + labelLimit defines the per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. format: int64 type: integer labelNameLengthLimit: description: |- - Per-scrape limit on length of labels name that will be accepted for a sample. + labelNameLengthLimit defines the per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. format: int64 type: integer labelValueLengthLimit: description: |- - Per-scrape limit on length of labels value that will be accepted for a sample. + labelValueLengthLimit defines the per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. format: int64 type: integer metricRelabelings: - description: MetricRelabelConfigs to apply to samples before ingestion. + description: metricRelabelings defines the RelabelConfig to apply + to samples before ingestion. items: description: |- RelabelConfig allows dynamic rewriting of the label set for targets, alerts, @@ -236,7 +243,7 @@ spec: action: default: replace description: |- - Action to perform based on the regex matching. + action to perform based on the regex matching. `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. @@ -268,40 +275,41 @@ spec: type: string modulus: description: |- - Modulus to take of the hash of the source label values. + modulus to take of the hash of the source label values. Only applicable when the action is `HashMod`. format: int64 type: integer regex: - description: Regular expression against which the extracted - value is matched. + description: regex defines the regular expression against which + the extracted value is matched. type: string replacement: description: |- - Replacement value against which a Replace action is performed if the + replacement value against which a Replace action is performed if the regular expression matches. Regex capture groups are available. type: string separator: - description: Separator is the string between concatenated SourceLabels. + description: separator defines the string between concatenated + SourceLabels. type: string sourceLabels: description: |- - The source labels select values from existing labels. Their content is + sourceLabels defines the source labels select values from existing labels. Their content is concatenated using the configured Separator and matched against the configured regular expression. items: description: |- - LabelName is a valid Prometheus label name which may only contain ASCII - letters, numbers, as well as underscores. - pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. type: string type: array targetLabel: description: |- - Label to which the resulting string is written in a replacement. + targetLabel defines the label to which the resulting string is written in a replacement. It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, `KeepEqual` and `DropEqual` actions. @@ -312,13 +320,13 @@ spec: type: array module: description: |- - The module to use for probing specifying how to probe the target. + module to use for probing specifying how to probe the target. Example module configuring in the blackbox exporter: https://github.com/prometheus/blackbox_exporter/blob/master/example.yml type: string nativeHistogramBucketLimit: description: |- - If there are more than this many buckets in a native histogram, + nativeHistogramBucketLimit defines ff there are more than this many buckets in a native histogram, buckets will be merged to stay within the limit. It requires Prometheus >= v2.45.0. format: int64 @@ -328,22 +336,23 @@ spec: - type: integer - type: string description: |- - If the growth factor of one bucket to the next is smaller than this, + nativeHistogramMinBucketFactor defines if the growth factor of one bucket to the next is smaller than this, buckets will be merged to increase the factor sufficiently. It requires Prometheus >= v2.50.0. pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true oauth2: - description: OAuth2 for the URL. Only valid in Prometheus versions + description: oauth2 for the URL. Only valid in Prometheus versions 2.27.0 and newer. properties: clientId: description: |- - `clientId` specifies a key of a Secret or ConfigMap containing the + clientId defines a key of a Secret or ConfigMap containing the OAuth2 client's ID. properties: configMap: - description: ConfigMap containing data to use for the targets. + description: configMap defines the ConfigMap containing data + to use for the targets. properties: key: description: The key to select. @@ -366,7 +375,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data to + use for the targets. properties: key: description: The key of the secret to select from. Must @@ -392,7 +402,7 @@ spec: type: object clientSecret: description: |- - `clientSecret` specifies a key of a Secret containing the OAuth2 + clientSecret defines a key of a Secret containing the OAuth2 client's secret. properties: key: @@ -420,16 +430,16 @@ spec: additionalProperties: type: string description: |- - `endpointParams` configures the HTTP parameters to append to the token + endpointParams configures the HTTP parameters to append to the token URL. type: object noProxy: description: |- - `noProxy` is a comma-separated string that can contain IPs, CIDR notation, domain names + noProxy defines a comma-separated string that can contain IPs, CIDR notation, domain names that should be excluded from proxying. IP and domain names can contain port numbers. - It requires Prometheus >= v2.43.0 or Alertmanager >= 0.25.0. + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. type: string proxyConnectHeader: additionalProperties: @@ -459,40 +469,40 @@ spec: x-kubernetes-map-type: atomic type: array description: |- - ProxyConnectHeader optionally specifies headers to send to + proxyConnectHeader optionally specifies headers to send to proxies during CONNECT requests. - It requires Prometheus >= v2.43.0 or Alertmanager >= 0.25.0. + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. type: object x-kubernetes-map-type: atomic proxyFromEnvironment: description: |- - Whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). + proxyFromEnvironment defines whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). - It requires Prometheus >= v2.43.0 or Alertmanager >= 0.25.0. + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. type: boolean proxyUrl: - description: '`proxyURL` defines the HTTP proxy server to use.' - pattern: ^http(s)?://.+$ + description: proxyUrl defines the HTTP proxy server to use. + pattern: ^(http|https|socks5)://.+$ type: string scopes: - description: '`scopes` defines the OAuth2 scopes used for the - token request.' + description: scopes defines the OAuth2 scopes used for the token + request. items: type: string type: array tlsConfig: description: |- - TLS configuration to use when connecting to the OAuth2 server. + tlsConfig defines the TLS configuration to use when connecting to the OAuth2 server. It requires Prometheus >= v2.43.0. properties: ca: - description: Certificate authority used when verifying server - certificates. + description: ca defines the Certificate authority used when + verifying server certificates. properties: configMap: - description: ConfigMap containing data to use for the - targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -515,7 +525,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data + to use for the targets. properties: key: description: The key of the secret to select from. Must @@ -540,11 +551,12 @@ spec: x-kubernetes-map-type: atomic type: object cert: - description: Client certificate to present when doing client-authentication. + description: cert defines the Client certificate to present + when doing client-authentication. properties: configMap: - description: ConfigMap containing data to use for the - targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -567,7 +579,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data + to use for the targets. properties: key: description: The key of the secret to select from. Must @@ -592,11 +605,12 @@ spec: x-kubernetes-map-type: atomic type: object insecureSkipVerify: - description: Disable target certificate validation. + description: insecureSkipVerify defines how to disable target + certificate validation. type: boolean keySecret: - description: Secret containing the client key file for the - targets. + description: keySecret defines the Secret containing the client + key file for the targets. properties: key: description: The key of the secret to select from. Must @@ -621,9 +635,9 @@ spec: x-kubernetes-map-type: atomic maxVersion: description: |- - Maximum acceptable TLS version. + maxVersion defines the maximum acceptable TLS version. - It requires Prometheus >= v2.41.0. + It requires Prometheus >= v2.41.0 or Thanos >= v0.31.0. enum: - TLS10 - TLS11 @@ -632,9 +646,9 @@ spec: type: string minVersion: description: |- - Minimum acceptable TLS version. + minVersion defines the minimum acceptable TLS version. - It requires Prometheus >= v2.35.0. + It requires Prometheus >= v2.35.0 or Thanos >= v0.28.0. enum: - TLS10 - TLS11 @@ -642,12 +656,12 @@ spec: - TLS13 type: string serverName: - description: Used to verify the hostname for the targets. + description: serverName is used to verify the hostname for + the targets. type: string type: object tokenUrl: - description: '`tokenURL` configures the URL to fetch the token - from.' + description: tokenUrl defines the URL to fetch the token from. minLength: 1 type: string required: @@ -655,52 +669,137 @@ spec: - clientSecret - tokenUrl type: object + params: + description: |- + params defines the list of HTTP query parameters for the scrape. + Please note that the `.spec.module` field takes precedence over the `module` parameter from this list when both are defined. + The module name must be added using Module under ProbeSpec. + items: + description: ProbeParam defines specification of extra parameters + for a Probe. + properties: + name: + description: name defines the parameter name + minLength: 1 + type: string + values: + description: values defines the parameter values + items: + minLength: 1 + type: string + minItems: 1 + type: array + required: + - name + type: object + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map prober: description: |- - Specification for the prober to use for probing targets. + prober defines the specification for the prober to use for probing targets. The prober.URL parameter is required. Targets cannot be probed if left empty. properties: + noProxy: + description: |- + noProxy defines a comma-separated string that can contain IPs, CIDR notation, domain names + that should be excluded from proxying. IP and domain names can + contain port numbers. + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: string path: default: /probe description: |- - Path to collect metrics from. + path to collect metrics from. Defaults to `/probe`. type: string + proxyConnectHeader: + additionalProperties: + items: + description: SecretKeySelector selects a key of a Secret. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + 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 + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: array + description: |- + proxyConnectHeader optionally specifies headers to send to + proxies during CONNECT requests. + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: object + x-kubernetes-map-type: atomic + proxyFromEnvironment: + description: |- + proxyFromEnvironment defines whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: boolean proxyUrl: - description: Optional ProxyURL. + description: proxyUrl defines the HTTP proxy server to use. + pattern: ^(http|https|socks5)://.+$ type: string scheme: - description: |- - HTTP scheme to use for scraping. - `http` and `https` are the expected values unless you rewrite the `__scheme__` label via relabeling. - If empty, Prometheus uses the default value `http`. + description: scheme defines the HTTP scheme to use when scraping + the prober. enum: - http - https + - HTTP + - HTTPS type: string url: - description: Mandatory URL of the prober. + description: |- + url defines the address of the prober. + + Unlike what the name indicates, the value should be in the form of + `address:port` without any scheme which should be specified in the + `scheme` field. + minLength: 1 type: string required: - url type: object sampleLimit: - description: SampleLimit defines per-scrape limit on number of scraped + description: sampleLimit defines per-scrape limit on number of scraped samples that will be accepted. format: int64 type: integer scrapeClass: - description: The scrape class to apply. + description: scrapeClass defines the scrape class to apply. minLength: 1 type: string scrapeClassicHistograms: description: |- - Whether to scrape a classic histogram that is also exposed as a native histogram. + scrapeClassicHistograms defines whether to scrape a classic histogram that is also exposed as a native histogram. It requires Prometheus >= v2.45.0. + + Notice: `scrapeClassicHistograms` corresponds to the `always_scrape_classic_histograms` field in the Prometheus configuration. type: boolean scrapeProtocols: description: |- - `scrapeProtocols` defines the protocols to negotiate during a scrape. It tells clients the + scrapeProtocols defines the protocols to negotiate during a scrape. It tells clients the protocols supported by Prometheus in order of preference (from most to least preferred). If unset, Prometheus uses its default value. @@ -726,18 +825,18 @@ spec: x-kubernetes-list-type: set scrapeTimeout: description: |- - Timeout for scraping metrics from the Prometheus exporter. + scrapeTimeout defines the timeout for scraping metrics from the Prometheus exporter. If not specified, the Prometheus global scrape timeout is used. The value cannot be greater than the scrape interval otherwise the operator will reject the resource. pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ type: string targetLimit: - description: TargetLimit defines a limit on the number of scraped + description: targetLimit defines a limit on the number of scraped targets that will be accepted. format: int64 type: integer targets: - description: Targets defines a set of static or dynamically discovered + description: targets defines a set of static or dynamically discovered targets to probe. properties: ingress: @@ -747,22 +846,24 @@ spec: If `staticConfig` is also defined, `staticConfig` takes precedence. properties: namespaceSelector: - description: From which namespaces to select Ingress objects. + description: namespaceSelector defines from which namespaces + to select Ingress objects. properties: any: description: |- - Boolean describing whether all namespaces are selected in contrast to a + any defines the boolean describing whether all namespaces are selected in contrast to a list restricting them. type: boolean matchNames: - description: List of namespace names to select from. + description: matchNames defines the list of namespace + names to select from. items: type: string type: array type: object relabelingConfigs: description: |- - RelabelConfigs to apply to the label set of the target before it gets + relabelingConfigs to apply to the label set of the target before it gets scraped. The original ingress address is available via the `__tmp_prometheus_ingress_address` label. It can be used to customize the @@ -779,7 +880,7 @@ spec: action: default: replace description: |- - Action to perform based on the regex matching. + action to perform based on the regex matching. `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. @@ -811,41 +912,41 @@ spec: type: string modulus: description: |- - Modulus to take of the hash of the source label values. + modulus to take of the hash of the source label values. Only applicable when the action is `HashMod`. format: int64 type: integer regex: - description: Regular expression against which the extracted - value is matched. + description: regex defines the regular expression against + which the extracted value is matched. type: string replacement: description: |- - Replacement value against which a Replace action is performed if the + replacement value against which a Replace action is performed if the regular expression matches. Regex capture groups are available. type: string separator: - description: Separator is the string between concatenated + description: separator defines the string between concatenated SourceLabels. type: string sourceLabels: description: |- - The source labels select values from existing labels. Their content is + sourceLabels defines the source labels select values from existing labels. Their content is concatenated using the configured Separator and matched against the configured regular expression. items: description: |- - LabelName is a valid Prometheus label name which may only contain ASCII - letters, numbers, as well as underscores. - pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. type: string type: array targetLabel: description: |- - Label to which the resulting string is written in a replacement. + targetLabel defines the label to which the resulting string is written in a replacement. It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, `KeepEqual` and `DropEqual` actions. @@ -855,7 +956,7 @@ spec: type: object type: array selector: - description: Selector to select the Ingress objects. + description: selector to select the Ingress objects. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -911,12 +1012,12 @@ spec: labels: additionalProperties: type: string - description: Labels assigned to all metrics scraped from the - targets. + description: labels defines all labels assigned to all metrics + scraped from the targets. type: object relabelingConfigs: description: |- - RelabelConfigs to apply to the label set of the targets before it gets + relabelingConfigs defines relabelings to be apply to the label set of the targets before it gets scraped. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config items: @@ -929,7 +1030,7 @@ spec: action: default: replace description: |- - Action to perform based on the regex matching. + action to perform based on the regex matching. `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. @@ -961,41 +1062,41 @@ spec: type: string modulus: description: |- - Modulus to take of the hash of the source label values. + modulus to take of the hash of the source label values. Only applicable when the action is `HashMod`. format: int64 type: integer regex: - description: Regular expression against which the extracted - value is matched. + description: regex defines the regular expression against + which the extracted value is matched. type: string replacement: description: |- - Replacement value against which a Replace action is performed if the + replacement value against which a Replace action is performed if the regular expression matches. Regex capture groups are available. type: string separator: - description: Separator is the string between concatenated + description: separator defines the string between concatenated SourceLabels. type: string sourceLabels: description: |- - The source labels select values from existing labels. Their content is + sourceLabels defines the source labels select values from existing labels. Their content is concatenated using the configured Separator and matched against the configured regular expression. items: description: |- - LabelName is a valid Prometheus label name which may only contain ASCII - letters, numbers, as well as underscores. - pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. type: string type: array targetLabel: description: |- - Label to which the resulting string is written in a replacement. + targetLabel defines the label to which the resulting string is written in a replacement. It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, `KeepEqual` and `DropEqual` actions. @@ -1005,21 +1106,23 @@ spec: type: object type: array static: - description: The list of hosts to probe. + description: static defines the list of hosts to probe. items: type: string type: array type: object type: object tlsConfig: - description: TLS configuration to use when scraping the endpoint. + description: tlsConfig defines the TLS configuration to use when scraping + the endpoint. properties: ca: - description: Certificate authority used when verifying server - certificates. + description: ca defines the Certificate authority used when verifying + server certificates. properties: configMap: - description: ConfigMap containing data to use for the targets. + description: configMap defines the ConfigMap containing data + to use for the targets. properties: key: description: The key to select. @@ -1042,7 +1145,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data to + use for the targets. properties: key: description: The key of the secret to select from. Must @@ -1067,10 +1171,12 @@ spec: x-kubernetes-map-type: atomic type: object cert: - description: Client certificate to present when doing client-authentication. + description: cert defines the Client certificate to present when + doing client-authentication. properties: configMap: - description: ConfigMap containing data to use for the targets. + description: configMap defines the ConfigMap containing data + to use for the targets. properties: key: description: The key to select. @@ -1093,7 +1199,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data to + use for the targets. properties: key: description: The key of the secret to select from. Must @@ -1118,10 +1225,12 @@ spec: x-kubernetes-map-type: atomic type: object insecureSkipVerify: - description: Disable target certificate validation. + description: insecureSkipVerify defines how to disable target + certificate validation. type: boolean keySecret: - description: Secret containing the client key file for the targets. + description: keySecret defines the Secret containing the client + key file for the targets. properties: key: description: The key of the secret to select from. Must be @@ -1146,9 +1255,9 @@ spec: x-kubernetes-map-type: atomic maxVersion: description: |- - Maximum acceptable TLS version. + maxVersion defines the maximum acceptable TLS version. - It requires Prometheus >= v2.41.0. + It requires Prometheus >= v2.41.0 or Thanos >= v0.31.0. enum: - TLS10 - TLS11 @@ -1157,9 +1266,9 @@ spec: type: string minVersion: description: |- - Minimum acceptable TLS version. + minVersion defines the minimum acceptable TLS version. - It requires Prometheus >= v2.35.0. + It requires Prometheus >= v2.35.0 or Thanos >= v0.28.0. enum: - TLS10 - TLS11 @@ -1167,12 +1276,119 @@ spec: - TLS13 type: string serverName: - description: Used to verify the hostname for the targets. + description: serverName is used to verify the hostname for the + targets. type: string type: object type: object + status: + description: |- + status defines the status subresource. It is under active development and is updated only when the + "StatusForConfigurationResources" feature gate is enabled. + + Most recent observed status of the Probe. Read-only. + More info: + https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + bindings: + description: bindings defines the list of workload resources (Prometheus, + PrometheusAgent, ThanosRuler or Alertmanager) which select the configuration + resource. + items: + description: WorkloadBinding is a link between a configuration resource + and a workload resource. + properties: + conditions: + description: conditions defines the current state of the configuration + resource when bound to the referenced Workload object. + items: + description: ConfigResourceCondition describes the status + of configuration resources linked to Prometheus, PrometheusAgent, + Alertmanager or ThanosRuler. + properties: + lastTransitionTime: + description: lastTransitionTime defines the time of the + last update to the current status property. + format: date-time + type: string + message: + description: message defines the human-readable message + indicating details for the condition's last transition. + type: string + observedGeneration: + description: |- + observedGeneration defines the .metadata.generation that the + condition was set based upon. For instance, if `.metadata.generation` is + currently 12, but the `.status.conditions[].observedGeneration` is 9, the + condition is out of date with respect to the current state of the object. + format: int64 + type: integer + reason: + description: reason for the condition's last transition. + type: string + status: + description: status of the condition. + minLength: 1 + type: string + type: + description: |- + type of the condition being reported. + Currently, only "Accepted" is supported. + enum: + - Accepted + minLength: 1 + type: string + required: + - lastTransitionTime + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + group: + description: group defines the group of the referenced resource. + enum: + - monitoring.coreos.com + type: string + name: + description: name defines the name of the referenced object. + minLength: 1 + type: string + namespace: + description: namespace defines the namespace of the referenced + object. + minLength: 1 + type: string + resource: + description: resource defines the type of resource being referenced + (e.g. Prometheus, PrometheusAgent, ThanosRuler or Alertmanager). + enum: + - prometheuses + - prometheusagents + - thanosrulers + - alertmanagers + type: string + required: + - group + - name + - namespace + - resource + type: object + type: array + x-kubernetes-list-map-keys: + - group + - resource + - name + - namespace + x-kubernetes-list-type: map + type: object required: - spec type: object served: true storage: true + subresources: + status: {} +{{- end -}} diff --git a/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-prometheusrules.yaml b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-prometheusrules.yaml new file mode 100644 index 00000000..cf13c7c3 --- /dev/null +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-prometheusrules.yaml @@ -0,0 +1,272 @@ +{{- if .Values.prometheusrules.enabled -}} +# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.87.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: +{{- with .Values.annotations }} +{{- toYaml . | nindent 4 }} +{{- end }} + controller-gen.kubebuilder.io/version: v0.19.0 + operator.prometheus.io/version: 0.87.0 + name: prometheusrules.monitoring.coreos.com +spec: + group: monitoring.coreos.com + names: + categories: + - prometheus-operator + kind: PrometheusRule + listKind: PrometheusRuleList + plural: prometheusrules + shortNames: + - promrule + singular: prometheusrule + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: |- + The `PrometheusRule` custom resource definition (CRD) defines [alerting](https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/) and [recording](https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/) rules to be evaluated by `Prometheus` or `ThanosRuler` objects. + + `Prometheus` and `ThanosRuler` objects select `PrometheusRule` objects using label and namespace selectors. + 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: spec defines the specification of desired alerting rule definitions + for Prometheus. + properties: + groups: + description: groups defines the content of Prometheus rule file + items: + description: RuleGroup is a list of sequentially evaluated recording + and alerting rules. + properties: + interval: + description: interval defines how often rules in the group are + evaluated. + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + labels: + additionalProperties: + type: string + description: |- + labels define the labels to add or overwrite before storing the result for its rules. + The labels defined at the rule level take precedence. + + It requires Prometheus >= 3.0.0. + The field is ignored for Thanos Ruler. + type: object + limit: + description: |- + limit defines the number of alerts an alerting rule and series a recording + rule can produce. + Limit is supported starting with Prometheus >= 2.31 and Thanos Ruler >= 0.24. + type: integer + name: + description: name defines the name of the rule group. + minLength: 1 + type: string + partial_response_strategy: + description: |- + partial_response_strategy is only used by ThanosRuler and will + be ignored by Prometheus instances. + More info: https://github.com/thanos-io/thanos/blob/main/docs/components/rule.md#partial-response + pattern: ^(?i)(abort|warn)?$ + type: string + query_offset: + description: |- + query_offset defines the offset the rule evaluation timestamp of this particular group by the specified duration into the past. + + It requires Prometheus >= v2.53.0. + It is not supported for ThanosRuler. + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + rules: + description: rules defines the list of alerting and recording + rules. + items: + description: |- + Rule describes an alerting or recording rule + See Prometheus documentation: [alerting](https://www.prometheus.io/docs/prometheus/latest/configuration/alerting_rules/) or [recording](https://www.prometheus.io/docs/prometheus/latest/configuration/recording_rules/#recording-rules) rule + properties: + alert: + description: |- + alert defines the name of the alert. Must be a valid label value. + Only one of `record` and `alert` must be set. + type: string + annotations: + additionalProperties: + type: string + description: |- + annotations defines annotations to add to each alert. + Only valid for alerting rules. + type: object + expr: + anyOf: + - type: integer + - type: string + description: expr defines the PromQL expression to evaluate. + x-kubernetes-int-or-string: true + for: + description: for defines how alerts are considered firing + once they have been returned for this long. + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + keep_firing_for: + description: keep_firing_for defines how long an alert + will continue firing after the condition that triggered + it has cleared. + minLength: 1 + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + labels: + additionalProperties: + type: string + description: labels defines labels to add or overwrite. + type: object + record: + description: |- + record defines the name of the time series to output to. Must be a valid metric name. + Only one of `record` and `alert` must be set. + type: string + required: + - expr + type: object + type: array + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + status: + description: |- + status defines the status subresource. It is under active development and is updated only when the + "StatusForConfigurationResources" feature gate is enabled. + + Most recent observed status of the PrometheusRule. Read-only. + More info: + https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + bindings: + description: bindings defines the list of workload resources (Prometheus, + PrometheusAgent, ThanosRuler or Alertmanager) which select the configuration + resource. + items: + description: WorkloadBinding is a link between a configuration resource + and a workload resource. + properties: + conditions: + description: conditions defines the current state of the configuration + resource when bound to the referenced Workload object. + items: + description: ConfigResourceCondition describes the status + of configuration resources linked to Prometheus, PrometheusAgent, + Alertmanager or ThanosRuler. + properties: + lastTransitionTime: + description: lastTransitionTime defines the time of the + last update to the current status property. + format: date-time + type: string + message: + description: message defines the human-readable message + indicating details for the condition's last transition. + type: string + observedGeneration: + description: |- + observedGeneration defines the .metadata.generation that the + condition was set based upon. For instance, if `.metadata.generation` is + currently 12, but the `.status.conditions[].observedGeneration` is 9, the + condition is out of date with respect to the current state of the object. + format: int64 + type: integer + reason: + description: reason for the condition's last transition. + type: string + status: + description: status of the condition. + minLength: 1 + type: string + type: + description: |- + type of the condition being reported. + Currently, only "Accepted" is supported. + enum: + - Accepted + minLength: 1 + type: string + required: + - lastTransitionTime + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + group: + description: group defines the group of the referenced resource. + enum: + - monitoring.coreos.com + type: string + name: + description: name defines the name of the referenced object. + minLength: 1 + type: string + namespace: + description: namespace defines the namespace of the referenced + object. + minLength: 1 + type: string + resource: + description: resource defines the type of resource being referenced + (e.g. Prometheus, PrometheusAgent, ThanosRuler or Alertmanager). + enum: + - prometheuses + - prometheusagents + - thanosrulers + - alertmanagers + type: string + required: + - group + - name + - namespace + - resource + type: object + type: array + x-kubernetes-list-map-keys: + - group + - resource + - name + - namespace + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +{{- end -}} diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-servicemonitors.yaml b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-servicemonitors.yaml similarity index 70% rename from packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-servicemonitors.yaml rename to packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-servicemonitors.yaml index 64e19e48..ff4472f2 100644 --- a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-servicemonitors.yaml +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-servicemonitors.yaml @@ -1,4 +1,5 @@ -# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.81.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +{{- if .Values.servicemonitors.enabled -}} +# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.87.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -7,8 +8,8 @@ metadata: {{- with .Values.annotations }} {{- toYaml . | nindent 4 }} {{- end }} - controller-gen.kubebuilder.io/version: v0.17.2 - operator.prometheus.io/version: 0.81.0 + controller-gen.kubebuilder.io/version: v0.19.0 + operator.prometheus.io/version: 0.87.0 name: servicemonitors.monitoring.coreos.com spec: group: monitoring.coreos.com @@ -55,19 +56,19 @@ spec: type: object spec: description: |- - Specification of desired Service selection for target discovery by + spec defines the specification of desired Service selection for target discovery by Prometheus. properties: attachMetadata: description: |- - `attachMetadata` defines additional metadata which is added to the + attachMetadata defines additional metadata which is added to the discovered targets. It requires Prometheus >= v2.37.0. properties: node: description: |- - When set to true, Prometheus attaches node metadata to the discovered + node when set to true, Prometheus attaches node metadata to the discovered targets. The Prometheus service account must have the `list` and `watch` @@ -76,15 +77,20 @@ spec: type: object bodySizeLimit: description: |- - When defined, bodySizeLimit specifies a job level limit on the size + bodySizeLimit when defined, bodySizeLimit specifies a job level limit on the size of uncompressed response body that will be accepted by Prometheus. It requires Prometheus >= v2.28.0. pattern: (^0|([0-9]*[.])?[0-9]+((K|M|G|T|E|P)i?)?B)$ type: string + convertClassicHistogramsToNHCB: + description: |- + convertClassicHistogramsToNHCB defines whether to convert all scraped classic histograms into a native histogram with custom buckets. + It requires Prometheus >= v3.0.0. + type: boolean endpoints: description: |- - List of endpoints part of this ServiceMonitor. + endpoints defines the list of endpoints part of this ServiceMonitor. Defines how to scrape metrics from Kubernetes [Endpoints](https://kubernetes.io/docs/concepts/services-networking/service/#endpoints) objects. In most cases, an Endpoints object is backed by a Kubernetes [Service](https://kubernetes.io/docs/concepts/services-networking/service/) object with the same name and labels. items: @@ -94,14 +100,14 @@ spec: properties: authorization: description: |- - `authorization` configures the Authorization header credentials to use when + authorization configures the Authorization header credentials to use when scraping the target. Cannot be set at the same time as `basicAuth`, or `oauth2`. properties: credentials: - description: Selects a key of a Secret in the namespace - that contains the credentials for authentication. + description: credentials defines a key of a Secret in the + namespace that contains the credentials for authentication. properties: key: description: The key of the secret to select from. Must @@ -126,7 +132,7 @@ spec: x-kubernetes-map-type: atomic type: description: |- - Defines the authentication type. The value is case-insensitive. + type defines the authentication type. The value is case-insensitive. "Basic" is not a supported value. @@ -135,14 +141,14 @@ spec: type: object basicAuth: description: |- - `basicAuth` configures the Basic Authentication credentials to use when + basicAuth defines the Basic Authentication credentials to use when scraping the target. Cannot be set at the same time as `authorization`, or `oauth2`. properties: password: description: |- - `password` specifies a key of a Secret containing the password for + password defines a key of a Secret containing the password for authentication. properties: key: @@ -168,7 +174,7 @@ spec: x-kubernetes-map-type: atomic username: description: |- - `username` specifies a key of a Secret containing the username for + username defines a key of a Secret containing the username for authentication. properties: key: @@ -195,13 +201,13 @@ spec: type: object bearerTokenFile: description: |- - File to read bearer token for scraping the target. + bearerTokenFile defines the file to read bearer token for scraping the target. Deprecated: use `authorization` instead. type: string bearerTokenSecret: description: |- - `bearerTokenSecret` specifies a key of a Secret containing the bearer + bearerTokenSecret defines a key of a Secret containing the bearer token for scraping targets. The secret needs to be in the same namespace as the ServiceMonitor object and readable by the Prometheus Operator. @@ -229,12 +235,12 @@ spec: type: object x-kubernetes-map-type: atomic enableHttp2: - description: '`enableHttp2` can be used to disable HTTP2 when - scraping the target.' + description: enableHttp2 can be used to disable HTTP2 when scraping + the target. type: boolean filterRunning: description: |- - When true, the pods which are not running (e.g. either in Failed or + filterRunning when true, the pods which are not running (e.g. either in Failed or Succeeded state) are dropped during the target discovery. If unset, the filtering is enabled. @@ -243,29 +249,29 @@ spec: type: boolean followRedirects: description: |- - `followRedirects` defines whether the scrape requests should follow HTTP + followRedirects defines whether the scrape requests should follow HTTP 3xx redirects. type: boolean honorLabels: description: |- - When true, `honorLabels` preserves the metric's labels when they collide + honorLabels defines when true the metric's labels when they collide with the target's labels. type: boolean honorTimestamps: description: |- - `honorTimestamps` controls whether Prometheus preserves the timestamps + honorTimestamps defines whether Prometheus preserves the timestamps when exposed by the target. type: boolean interval: description: |- - Interval at which Prometheus scrapes the metrics from the target. + interval at which Prometheus scrapes the metrics from the target. If empty, Prometheus uses the global scrape interval. pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ type: string metricRelabelings: description: |- - `metricRelabelings` configures the relabeling rules to apply to the + metricRelabelings defines the relabeling rules to apply to the samples before ingestion. items: description: |- @@ -277,7 +283,7 @@ spec: action: default: replace description: |- - Action to perform based on the regex matching. + action to perform based on the regex matching. `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. @@ -309,41 +315,41 @@ spec: type: string modulus: description: |- - Modulus to take of the hash of the source label values. + modulus to take of the hash of the source label values. Only applicable when the action is `HashMod`. format: int64 type: integer regex: - description: Regular expression against which the extracted - value is matched. + description: regex defines the regular expression against + which the extracted value is matched. type: string replacement: description: |- - Replacement value against which a Replace action is performed if the + replacement value against which a Replace action is performed if the regular expression matches. Regex capture groups are available. type: string separator: - description: Separator is the string between concatenated + description: separator defines the string between concatenated SourceLabels. type: string sourceLabels: description: |- - The source labels select values from existing labels. Their content is + sourceLabels defines the source labels select values from existing labels. Their content is concatenated using the configured Separator and matched against the configured regular expression. items: description: |- - LabelName is a valid Prometheus label name which may only contain ASCII - letters, numbers, as well as underscores. - pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. type: string type: array targetLabel: description: |- - Label to which the resulting string is written in a replacement. + targetLabel defines the label to which the resulting string is written in a replacement. It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, `KeepEqual` and `DropEqual` actions. @@ -352,9 +358,17 @@ spec: type: string type: object type: array + noProxy: + description: |- + noProxy defines a comma-separated string that can contain IPs, CIDR notation, domain names + that should be excluded from proxying. IP and domain names can + contain port numbers. + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: string oauth2: description: |- - `oauth2` configures the OAuth2 settings to use when scraping the target. + oauth2 defines the OAuth2 settings to use when scraping the target. It requires Prometheus >= 2.27.0. @@ -362,12 +376,12 @@ spec: properties: clientId: description: |- - `clientId` specifies a key of a Secret or ConfigMap containing the + clientId defines a key of a Secret or ConfigMap containing the OAuth2 client's ID. properties: configMap: - description: ConfigMap containing data to use for the - targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -390,7 +404,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data + to use for the targets. properties: key: description: The key of the secret to select from. Must @@ -416,7 +431,7 @@ spec: type: object clientSecret: description: |- - `clientSecret` specifies a key of a Secret containing the OAuth2 + clientSecret defines a key of a Secret containing the OAuth2 client's secret. properties: key: @@ -444,16 +459,16 @@ spec: additionalProperties: type: string description: |- - `endpointParams` configures the HTTP parameters to append to the token + endpointParams configures the HTTP parameters to append to the token URL. type: object noProxy: description: |- - `noProxy` is a comma-separated string that can contain IPs, CIDR notation, domain names + noProxy defines a comma-separated string that can contain IPs, CIDR notation, domain names that should be excluded from proxying. IP and domain names can contain port numbers. - It requires Prometheus >= v2.43.0 or Alertmanager >= 0.25.0. + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. type: string proxyConnectHeader: additionalProperties: @@ -483,41 +498,40 @@ spec: x-kubernetes-map-type: atomic type: array description: |- - ProxyConnectHeader optionally specifies headers to send to + proxyConnectHeader optionally specifies headers to send to proxies during CONNECT requests. - It requires Prometheus >= v2.43.0 or Alertmanager >= 0.25.0. + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. type: object x-kubernetes-map-type: atomic proxyFromEnvironment: description: |- - Whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). + proxyFromEnvironment defines whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). - It requires Prometheus >= v2.43.0 or Alertmanager >= 0.25.0. + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. type: boolean proxyUrl: - description: '`proxyURL` defines the HTTP proxy server to - use.' - pattern: ^http(s)?://.+$ + description: proxyUrl defines the HTTP proxy server to use. + pattern: ^(http|https|socks5)://.+$ type: string scopes: - description: '`scopes` defines the OAuth2 scopes used for - the token request.' + description: scopes defines the OAuth2 scopes used for the + token request. items: type: string type: array tlsConfig: description: |- - TLS configuration to use when connecting to the OAuth2 server. + tlsConfig defines the TLS configuration to use when connecting to the OAuth2 server. It requires Prometheus >= v2.43.0. properties: ca: - description: Certificate authority used when verifying - server certificates. + description: ca defines the Certificate authority used + when verifying server certificates. properties: configMap: - description: ConfigMap containing data to use for - the targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -540,8 +554,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the - targets. + description: secret defines the Secret containing + data to use for the targets. properties: key: description: The key of the secret to select @@ -566,12 +580,12 @@ spec: x-kubernetes-map-type: atomic type: object cert: - description: Client certificate to present when doing - client-authentication. + description: cert defines the Client certificate to + present when doing client-authentication. properties: configMap: - description: ConfigMap containing data to use for - the targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -594,8 +608,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the - targets. + description: secret defines the Secret containing + data to use for the targets. properties: key: description: The key of the secret to select @@ -620,11 +634,12 @@ spec: x-kubernetes-map-type: atomic type: object insecureSkipVerify: - description: Disable target certificate validation. + description: insecureSkipVerify defines how to disable + target certificate validation. type: boolean keySecret: - description: Secret containing the client key file for - the targets. + description: keySecret defines the Secret containing + the client key file for the targets. properties: key: description: The key of the secret to select from. Must @@ -649,9 +664,9 @@ spec: x-kubernetes-map-type: atomic maxVersion: description: |- - Maximum acceptable TLS version. + maxVersion defines the maximum acceptable TLS version. - It requires Prometheus >= v2.41.0. + It requires Prometheus >= v2.41.0 or Thanos >= v0.31.0. enum: - TLS10 - TLS11 @@ -660,9 +675,9 @@ spec: type: string minVersion: description: |- - Minimum acceptable TLS version. + minVersion defines the minimum acceptable TLS version. - It requires Prometheus >= v2.35.0. + It requires Prometheus >= v2.35.0 or Thanos >= v0.28.0. enum: - TLS10 - TLS11 @@ -670,12 +685,13 @@ spec: - TLS13 type: string serverName: - description: Used to verify the hostname for the targets. + description: serverName is used to verify the hostname + for the targets. type: string type: object tokenUrl: - description: '`tokenURL` configures the URL to fetch the - token from.' + description: tokenUrl defines the URL to fetch the token + from. minLength: 1 type: string required: @@ -692,24 +708,63 @@ spec: type: object path: description: |- - HTTP path from which to scrape for metrics. + path defines the HTTP path from which to scrape for metrics. If empty, Prometheus uses the default value (e.g. `/metrics`). type: string port: description: |- - Name of the Service port which this endpoint refers to. + port defines the name of the Service port which this endpoint refers to. It takes precedence over `targetPort`. type: string - proxyUrl: + proxyConnectHeader: + additionalProperties: + items: + description: SecretKeySelector selects a key of a Secret. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + 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 + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: array description: |- - `proxyURL` configures the HTTP Proxy URL (e.g. - "http://proxyserver:2195") to go through when scraping the target. + proxyConnectHeader optionally specifies headers to send to + proxies during CONNECT requests. + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: object + x-kubernetes-map-type: atomic + proxyFromEnvironment: + description: |- + proxyFromEnvironment defines whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: boolean + proxyUrl: + description: proxyUrl defines the HTTP proxy server to use. + pattern: ^(http|https|socks5)://.+$ type: string relabelings: description: |- - `relabelings` configures the relabeling rules to apply the target's + relabelings defines the relabeling rules to apply the target's metadata labels. The Operator automatically adds relabelings for a few standard Kubernetes fields. @@ -727,7 +782,7 @@ spec: action: default: replace description: |- - Action to perform based on the regex matching. + action to perform based on the regex matching. `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. @@ -759,41 +814,41 @@ spec: type: string modulus: description: |- - Modulus to take of the hash of the source label values. + modulus to take of the hash of the source label values. Only applicable when the action is `HashMod`. format: int64 type: integer regex: - description: Regular expression against which the extracted - value is matched. + description: regex defines the regular expression against + which the extracted value is matched. type: string replacement: description: |- - Replacement value against which a Replace action is performed if the + replacement value against which a Replace action is performed if the regular expression matches. Regex capture groups are available. type: string separator: - description: Separator is the string between concatenated + description: separator defines the string between concatenated SourceLabels. type: string sourceLabels: description: |- - The source labels select values from existing labels. Their content is + sourceLabels defines the source labels select values from existing labels. Their content is concatenated using the configured Separator and matched against the configured regular expression. items: description: |- - LabelName is a valid Prometheus label name which may only contain ASCII - letters, numbers, as well as underscores. - pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. type: string type: array targetLabel: description: |- - Label to which the resulting string is written in a replacement. + targetLabel defines the label to which the resulting string is written in a replacement. It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, `KeepEqual` and `DropEqual` actions. @@ -803,20 +858,17 @@ spec: type: object type: array scheme: - description: |- - HTTP scheme to use for scraping. - - `http` and `https` are the expected values unless you rewrite the - `__scheme__` label via relabeling. - - If empty, Prometheus uses the default value `http`. + description: scheme defines the HTTP scheme to use when scraping + the metrics. enum: - http - https + - HTTP + - HTTPS type: string scrapeTimeout: description: |- - Timeout after which Prometheus considers the scrape to be failed. + scrapeTimeout defines the timeout after which Prometheus considers the scrape to be failed. If empty, Prometheus uses the global scrape timeout unless it is less than the target's scrape interval value in which the latter is used. @@ -828,19 +880,20 @@ spec: - type: integer - type: string description: |- - Name or number of the target port of the `Pod` object behind the + targetPort defines the name or number of the target port of the `Pod` object behind the Service. The port must be specified with the container's port property. x-kubernetes-int-or-string: true tlsConfig: - description: TLS configuration to use when scraping the target. + description: tlsConfig defines the TLS configuration to use + when scraping the target. properties: ca: - description: Certificate authority used when verifying server - certificates. + description: ca defines the Certificate authority used when + verifying server certificates. properties: configMap: - description: ConfigMap containing data to use for the - targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -863,7 +916,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data + to use for the targets. properties: key: description: The key of the secret to select from. Must @@ -888,15 +942,16 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the Prometheus container - to use for the targets. + description: caFile defines the path to the CA cert in the + Prometheus container to use for the targets. type: string cert: - description: Client certificate to present when doing client-authentication. + description: cert defines the Client certificate to present + when doing client-authentication. properties: configMap: - description: ConfigMap containing data to use for the - targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -919,7 +974,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data + to use for the targets. properties: key: description: The key of the secret to select from. Must @@ -944,19 +1000,20 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the Prometheus - container for the targets. + description: certFile defines the path to the client cert + file in the Prometheus container for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. + description: insecureSkipVerify defines how to disable target + certificate validation. type: boolean keyFile: - description: Path to the client key file in the Prometheus - container for the targets. + description: keyFile defines the path to the client key + file in the Prometheus container for the targets. type: string keySecret: - description: Secret containing the client key file for the - targets. + description: keySecret defines the Secret containing the + client key file for the targets. properties: key: description: The key of the secret to select from. Must @@ -981,9 +1038,9 @@ spec: x-kubernetes-map-type: atomic maxVersion: description: |- - Maximum acceptable TLS version. + maxVersion defines the maximum acceptable TLS version. - It requires Prometheus >= v2.41.0. + It requires Prometheus >= v2.41.0 or Thanos >= v0.31.0. enum: - TLS10 - TLS11 @@ -992,9 +1049,9 @@ spec: type: string minVersion: description: |- - Minimum acceptable TLS version. + minVersion defines the minimum acceptable TLS version. - It requires Prometheus >= v2.35.0. + It requires Prometheus >= v2.35.0 or Thanos >= v0.28.0. enum: - TLS10 - TLS11 @@ -1002,12 +1059,13 @@ spec: - TLS13 type: string serverName: - description: Used to verify the hostname for the targets. + description: serverName is used to verify the hostname for + the targets. type: string type: object trackTimestampsStaleness: description: |- - `trackTimestampsStaleness` defines whether Prometheus tracks staleness of + trackTimestampsStaleness defines whether Prometheus tracks staleness of the metrics that have an explicit timestamp present in scraped data. Has no effect if `honorTimestamps` is false. @@ -1017,7 +1075,7 @@ spec: type: array fallbackScrapeProtocol: description: |- - The protocol to use if a scrape returns blank, unparseable, or otherwise invalid Content-Type. + fallbackScrapeProtocol defines the protocol to use if a scrape returns blank, unparseable, or otherwise invalid Content-Type. It requires Prometheus >= v3.0.0. enum: @@ -1029,7 +1087,7 @@ spec: type: string jobLabel: description: |- - `jobLabel` selects the label from the associated Kubernetes `Service` + jobLabel selects the label from the associated Kubernetes `Service` object which will be used as the `job` label for all metrics. For example if `jobLabel` is set to `foo` and the Kubernetes `Service` @@ -1042,7 +1100,7 @@ spec: type: string keepDroppedTargets: description: |- - Per-scrape limit on the number of targets dropped by relabeling + keepDroppedTargets defines the per-scrape limit on the number of targets dropped by relabeling that will be kept in memory. 0 means no limit. It requires Prometheus >= v2.47.0. @@ -1050,44 +1108,45 @@ spec: type: integer labelLimit: description: |- - Per-scrape limit on number of labels that will be accepted for a sample. + labelLimit defines the per-scrape limit on number of labels that will be accepted for a sample. It requires Prometheus >= v2.27.0. format: int64 type: integer labelNameLengthLimit: description: |- - Per-scrape limit on length of labels name that will be accepted for a sample. + labelNameLengthLimit defines the per-scrape limit on length of labels name that will be accepted for a sample. It requires Prometheus >= v2.27.0. format: int64 type: integer labelValueLengthLimit: description: |- - Per-scrape limit on length of labels value that will be accepted for a sample. + labelValueLengthLimit defines the per-scrape limit on length of labels value that will be accepted for a sample. It requires Prometheus >= v2.27.0. format: int64 type: integer namespaceSelector: description: |- - `namespaceSelector` defines in which namespace(s) Prometheus should discover the services. + namespaceSelector defines in which namespace(s) Prometheus should discover the services. By default, the services are discovered in the same namespace as the `ServiceMonitor` object but it is possible to select pods across different/all namespaces. properties: any: description: |- - Boolean describing whether all namespaces are selected in contrast to a + any defines the boolean describing whether all namespaces are selected in contrast to a list restricting them. type: boolean matchNames: - description: List of namespace names to select from. + description: matchNames defines the list of namespace names to + select from. items: type: string type: array type: object nativeHistogramBucketLimit: description: |- - If there are more than this many buckets in a native histogram, + nativeHistogramBucketLimit defines ff there are more than this many buckets in a native histogram, buckets will be merged to stay within the limit. It requires Prometheus >= v2.45.0. format: int64 @@ -1097,36 +1156,38 @@ spec: - type: integer - type: string description: |- - If the growth factor of one bucket to the next is smaller than this, + nativeHistogramMinBucketFactor defines if the growth factor of one bucket to the next is smaller than this, buckets will be merged to increase the factor sufficiently. It requires Prometheus >= v2.50.0. pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true podTargetLabels: description: |- - `podTargetLabels` defines the labels which are transferred from the + podTargetLabels defines the labels which are transferred from the associated Kubernetes `Pod` object onto the ingested metrics. items: type: string type: array sampleLimit: description: |- - `sampleLimit` defines a per-scrape limit on the number of scraped samples + sampleLimit defines a per-scrape limit on the number of scraped samples that will be accepted. format: int64 type: integer scrapeClass: - description: The scrape class to apply. + description: scrapeClass defines the scrape class to apply. minLength: 1 type: string scrapeClassicHistograms: description: |- - Whether to scrape a classic histogram that is also exposed as a native histogram. + scrapeClassicHistograms defines whether to scrape a classic histogram that is also exposed as a native histogram. It requires Prometheus >= v2.45.0. + + Notice: `scrapeClassicHistograms` corresponds to the `always_scrape_classic_histograms` field in the Prometheus configuration. type: boolean scrapeProtocols: description: |- - `scrapeProtocols` defines the protocols to negotiate during a scrape. It tells clients the + scrapeProtocols defines the protocols to negotiate during a scrape. It tells clients the protocols supported by Prometheus in order of preference (from most to least preferred). If unset, Prometheus uses its default value. @@ -1151,8 +1212,8 @@ spec: type: array x-kubernetes-list-type: set selector: - description: Label selector to select the Kubernetes `Endpoints` objects - to scrape metrics from. + description: selector defines the label selector to select the Kubernetes + `Endpoints` objects to scrape metrics from. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. @@ -1199,7 +1260,7 @@ spec: x-kubernetes-map-type: atomic selectorMechanism: description: |- - Mechanism used to select the endpoints to scrape. + selectorMechanism defines the mechanism used to select the endpoints to scrape. By default, the selection process relies on relabel configurations to filter the discovered targets. Alternatively, you can opt in for role selectors, which may offer better efficiency in large clusters. Which strategy is best for your use case needs to be carefully evaluated. @@ -1209,16 +1270,27 @@ spec: - RelabelConfig - RoleSelector type: string + serviceDiscoveryRole: + description: |- + serviceDiscoveryRole defines the service discovery role used to discover targets. + + If set, the value should be either "Endpoints" or "EndpointSlice". + Otherwise it defaults to the value defined in the + Prometheus/PrometheusAgent resource. + enum: + - Endpoints + - EndpointSlice + type: string targetLabels: description: |- - `targetLabels` defines the labels which are transferred from the + targetLabels defines the labels which are transferred from the associated Kubernetes `Service` object onto the ingested metrics. items: type: string type: array targetLimit: description: |- - `targetLimit` defines a limit on the number of scraped targets that will + targetLimit defines a limit on the number of scraped targets that will be accepted. format: int64 type: integer @@ -1226,8 +1298,114 @@ spec: - endpoints - selector type: object + status: + description: |- + status defines the status subresource. It is under active development and is updated only when the + "StatusForConfigurationResources" feature gate is enabled. + + Most recent observed status of the ServiceMonitor. Read-only. + More info: + https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + bindings: + description: bindings defines the list of workload resources (Prometheus, + PrometheusAgent, ThanosRuler or Alertmanager) which select the configuration + resource. + items: + description: WorkloadBinding is a link between a configuration resource + and a workload resource. + properties: + conditions: + description: conditions defines the current state of the configuration + resource when bound to the referenced Workload object. + items: + description: ConfigResourceCondition describes the status + of configuration resources linked to Prometheus, PrometheusAgent, + Alertmanager or ThanosRuler. + properties: + lastTransitionTime: + description: lastTransitionTime defines the time of the + last update to the current status property. + format: date-time + type: string + message: + description: message defines the human-readable message + indicating details for the condition's last transition. + type: string + observedGeneration: + description: |- + observedGeneration defines the .metadata.generation that the + condition was set based upon. For instance, if `.metadata.generation` is + currently 12, but the `.status.conditions[].observedGeneration` is 9, the + condition is out of date with respect to the current state of the object. + format: int64 + type: integer + reason: + description: reason for the condition's last transition. + type: string + status: + description: status of the condition. + minLength: 1 + type: string + type: + description: |- + type of the condition being reported. + Currently, only "Accepted" is supported. + enum: + - Accepted + minLength: 1 + type: string + required: + - lastTransitionTime + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + group: + description: group defines the group of the referenced resource. + enum: + - monitoring.coreos.com + type: string + name: + description: name defines the name of the referenced object. + minLength: 1 + type: string + namespace: + description: namespace defines the namespace of the referenced + object. + minLength: 1 + type: string + resource: + description: resource defines the type of resource being referenced + (e.g. Prometheus, PrometheusAgent, ThanosRuler or Alertmanager). + enum: + - prometheuses + - prometheusagents + - thanosrulers + - alertmanagers + type: string + required: + - group + - name + - namespace + - resource + type: object + type: array + x-kubernetes-list-map-keys: + - group + - resource + - name + - namespace + x-kubernetes-list-type: map + type: object required: - spec type: object served: true storage: true + subresources: + status: {} +{{- end -}} diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/ci/lint.sh b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/ci/lint.sh similarity index 100% rename from packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/ci/lint.sh rename to packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/ci/lint.sh diff --git a/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/hack/renovate-post-upgrade-hook.sh b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/hack/renovate-post-upgrade-hook.sh new file mode 100644 index 00000000..f7f3c35d --- /dev/null +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/hack/renovate-post-upgrade-hook.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${0}")" &>/dev/null && pwd)" + +"${SCRIPT_DIR}/update_crds.sh" diff --git a/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/hack/update_crds.sh b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/hack/update_crds.sh new file mode 100644 index 00000000..bfa576de --- /dev/null +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/hack/update_crds.sh @@ -0,0 +1,51 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) + +if [[ $(uname -s) = "Darwin" ]]; then + VERSION="$(grep ^appVersion "${SCRIPT_DIR}/../Chart.yaml" | sed 's/appVersion: //g')" +else + VERSION="$(grep ^appVersion "${SCRIPT_DIR}/../Chart.yaml" | sed 's/appVersion:\s//g')" +fi + +CRDS=( + "alertmanagerconfigs : monitoring.coreos.com_alertmanagerconfigs.yaml" + "alertmanagers : monitoring.coreos.com_alertmanagers.yaml" + "podmonitors : monitoring.coreos.com_podmonitors.yaml" + "probes : monitoring.coreos.com_probes.yaml" + "prometheusagents : monitoring.coreos.com_prometheusagents.yaml" + "prometheuses : monitoring.coreos.com_prometheuses.yaml" + "prometheusrules : monitoring.coreos.com_prometheusrules.yaml" + "scrapeconfigs : monitoring.coreos.com_scrapeconfigs.yaml" + "servicemonitors : monitoring.coreos.com_servicemonitors.yaml" + "thanosrulers : monitoring.coreos.com_thanosrulers.yaml" +) + +for line in "${CRDS[@]}"; do + CRD=$(echo "${line%%:*}" | xargs) + SOURCE=$(echo "${line##*:}" | xargs) + DESTINATION="crd-${CRD}".yaml + + URL="https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/$VERSION/example/prometheus-operator-crd/$SOURCE" + + echo -e "Downloading Prometheus Operator CRD with Version ${VERSION}:\n${URL}\n" + + echo "# ${URL}" >"${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" + + if ! curl --silent --retry-all-errors --fail --location "${URL}" >>"${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}"; then + echo -e "Failed to download ${URL}!" + exit 1 + fi + + # Update or insert annotations block + if yq -e '.metadata.annotations' "${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" >/dev/null; then + sed -i '/^ annotations:$/a {{- with .Values.annotations }}\n{{- toYaml . | nindent 4 }}\n{{- end }}' "${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" + else + sed -i '/^metadata:$/a {{- with .Values.annotations }}\n annotations:\n{{- toYaml . | nindent 4 }}\n{{- end }}' "${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" + fi + + # Insert enable option + sed -i "1i\{{- if .Values.${CRD}.enabled -}}" "${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" + echo "{{- end -}}" >>"${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" +done diff --git a/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/values.yaml b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/values.yaml new file mode 100644 index 00000000..f462daf0 --- /dev/null +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/values.yaml @@ -0,0 +1,55 @@ +## Settings for CRDs +## +crds: + ## annotations add additional annotations to all CRDs + annotations: {} + + ## alertmanagerconfigs configures the AlertManagerConfig CRD + alertmanagerconfigs: + ## enabled defines if the CRD should be installed + enabled: true + + ## alertmanagers configures the AlertManager CRD + alertmanagers: + ## enabled defines if the CRD should be installed + enabled: true + + ## podmonitors configures the PodMonitor CRD + podmonitors: + ## enabled defines if the CRD should be installed + enabled: true + + ## probes configures the Probe CRD + probes: + ## enabled defines if the CRD should be installed + enabled: true + + ## prometheusagents configures the PrometheusAgent CRD + prometheusagents: + ## enabled defines if the CRD should be installed + enabled: true + + ## prometheuses configures the Prometheus CRD + prometheuses: + ## enabled defines if the CRD should be installed + enabled: true + + ## prometheusrules configures the PrometheusRule CRD + prometheusrules: + ## enabled defines if the CRD should be installed + enabled: true + + ## prometheusrules configures the PrometheusRule CRD + scrapeconfigs: + ## enabled defines if the CRD should be installed + enabled: true + + ## servicemonitors configures the ServiceMonitor CRD + servicemonitors: + ## enabled defines if the CRD should be installed + enabled: true + + ## thanosrulers configures the ThanosRuler CRD + thanosrulers: + ## enabled defines if the CRD should be installed + enabled: true diff --git a/packages/system/prometheus-operator-crds/values.yaml b/packages/system/prometheus-operator-crds/values.yaml new file mode 100644 index 00000000..e69de29b diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-prometheusrules.yaml b/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-prometheusrules.yaml deleted file mode 100644 index dd13e8fd..00000000 --- a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-prometheusrules.yaml +++ /dev/null @@ -1,163 +0,0 @@ -# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.81.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: -{{- with .Values.annotations }} -{{- toYaml . | nindent 4 }} -{{- end }} - controller-gen.kubebuilder.io/version: v0.17.2 - operator.prometheus.io/version: 0.81.0 - name: prometheusrules.monitoring.coreos.com -spec: - group: monitoring.coreos.com - names: - categories: - - prometheus-operator - kind: PrometheusRule - listKind: PrometheusRuleList - plural: prometheusrules - shortNames: - - promrule - singular: prometheusrule - scope: Namespaced - versions: - - name: v1 - schema: - openAPIV3Schema: - description: |- - The `PrometheusRule` custom resource definition (CRD) defines [alerting](https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/) and [recording](https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/) rules to be evaluated by `Prometheus` or `ThanosRuler` objects. - - `Prometheus` and `ThanosRuler` objects select `PrometheusRule` objects using label and namespace selectors. - 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: Specification of desired alerting rule definitions for Prometheus. - properties: - groups: - description: Content of Prometheus rule file - items: - description: RuleGroup is a list of sequentially evaluated recording - and alerting rules. - properties: - interval: - description: Interval determines how often rules in the group - are evaluated. - pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ - type: string - labels: - additionalProperties: - type: string - description: |- - Labels to add or overwrite before storing the result for its rules. - The labels defined at the rule level take precedence. - - It requires Prometheus >= 3.0.0. - The field is ignored for Thanos Ruler. - type: object - limit: - description: |- - Limit the number of alerts an alerting rule and series a recording - rule can produce. - Limit is supported starting with Prometheus >= 2.31 and Thanos Ruler >= 0.24. - type: integer - name: - description: Name of the rule group. - minLength: 1 - type: string - partial_response_strategy: - description: |- - PartialResponseStrategy is only used by ThanosRuler and will - be ignored by Prometheus instances. - More info: https://github.com/thanos-io/thanos/blob/main/docs/components/rule.md#partial-response - pattern: ^(?i)(abort|warn)?$ - type: string - query_offset: - description: |- - Defines the offset the rule evaluation timestamp of this particular group by the specified duration into the past. - - It requires Prometheus >= v2.53.0. - It is not supported for ThanosRuler. - pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ - type: string - rules: - description: List of alerting and recording rules. - items: - description: |- - Rule describes an alerting or recording rule - See Prometheus documentation: [alerting](https://www.prometheus.io/docs/prometheus/latest/configuration/alerting_rules/) or [recording](https://www.prometheus.io/docs/prometheus/latest/configuration/recording_rules/#recording-rules) rule - properties: - alert: - description: |- - Name of the alert. Must be a valid label value. - Only one of `record` and `alert` must be set. - type: string - annotations: - additionalProperties: - type: string - description: |- - Annotations to add to each alert. - Only valid for alerting rules. - type: object - expr: - anyOf: - - type: integer - - type: string - description: PromQL expression to evaluate. - x-kubernetes-int-or-string: true - for: - description: Alerts are considered firing once they have - been returned for this long. - pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ - type: string - keep_firing_for: - description: KeepFiringFor defines how long an alert will - continue firing after the condition that triggered it - has cleared. - minLength: 1 - pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ - type: string - labels: - additionalProperties: - type: string - description: Labels to add or overwrite. - type: object - record: - description: |- - Name of the time series to output to. Must be a valid metric name. - Only one of `record` and `alert` must be set. - type: string - required: - - expr - type: object - type: array - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - required: - - spec - type: object - served: true - storage: true diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/hack/update_crds.sh b/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/hack/update_crds.sh deleted file mode 100644 index d950ec16..00000000 --- a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/hack/update_crds.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) - -if [[ $(uname -s) = "Darwin" ]]; then - VERSION="$(grep ^appVersion "${SCRIPT_DIR}/../Chart.yaml" | sed 's/appVersion: //g')" -else - VERSION="$(grep ^appVersion "${SCRIPT_DIR}/../Chart.yaml" | sed 's/appVersion:\s//g')" -fi - -FILES=( - "crd-alertmanagerconfigs.yaml : monitoring.coreos.com_alertmanagerconfigs.yaml" - "crd-alertmanagers.yaml : monitoring.coreos.com_alertmanagers.yaml" - "crd-podmonitors.yaml : monitoring.coreos.com_podmonitors.yaml" - "crd-probes.yaml : monitoring.coreos.com_probes.yaml" - "crd-prometheusagents.yaml : monitoring.coreos.com_prometheusagents.yaml" - "crd-prometheuses.yaml : monitoring.coreos.com_prometheuses.yaml" - "crd-prometheusrules.yaml : monitoring.coreos.com_prometheusrules.yaml" - "crd-scrapeconfigs.yaml : monitoring.coreos.com_scrapeconfigs.yaml" - "crd-servicemonitors.yaml : monitoring.coreos.com_servicemonitors.yaml" - "crd-thanosrulers.yaml : monitoring.coreos.com_thanosrulers.yaml" -) - -for line in "${FILES[@]}"; do - DESTINATION=$(echo "${line%%:*}" | xargs) - SOURCE=$(echo "${line##*:}" | xargs) - - URL="https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/$VERSION/example/prometheus-operator-crd/$SOURCE" - - echo -e "Downloading Prometheus Operator CRD with Version ${VERSION}:\n${URL}\n" - - echo "# ${URL}" > "${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" - - if ! curl --silent --retry-all-errors --fail --location "${URL}" >> "${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}"; then - echo -e "Failed to download ${URL}!" - exit 1 - fi - - # Update or insert annotations block - if yq -e '.metadata.annotations' "${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" >/dev/null; then - sed -i '/^ annotations:$/a {{- with .Values.annotations }}\n{{- toYaml . | nindent 4 }}\n{{- end }}' "${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" - else - sed -i '/^metadata:$/a {{- with .Values.annotations }}\n annotations:\n{{- toYaml . | nindent 4 }}\n{{- end }}' "${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" - fi -done diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/values.yaml b/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/values.yaml deleted file mode 100644 index 7990c631..00000000 --- a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/values.yaml +++ /dev/null @@ -1,4 +0,0 @@ -## Annotations for CRDs -## -crds: - annotations: {} From 8928731abf3284f527a6e55ce79716414799ebf1 Mon Sep 17 00:00:00 2001 From: IvanHunters Date: Wed, 3 Dec 2025 22:18:19 +0300 Subject: [PATCH 17/33] [monitoring] Improve tenant metrics collection This patch introduces vmagent support inside tenant-level monitoring stacks, ensuring that all tenant workloads have consistent and reliable metrics scraping. By deploying a vmagent per tenant and wiring it to the configured VictoriaMetrics short- and long-term storage, metrics are now properly collected, labeled, and remote-written. This resolves gaps where tenant environments previously missed metrics due to the absence of dedicated agents. ```release-note [monitoring,platform] Add vmagent integration into tenant monitoring stacks to ensure complete and correct metrics collection for all tenants. ``` Signed-off-by: IvanHunters --- packages/extra/monitoring/README.md | 9 ++++++ .../monitoring/templates/vm/vmagent.yaml | 30 +++++++++++++++++++ packages/extra/monitoring/values.schema.json | 22 ++++++++++++++ packages/extra/monitoring/values.yaml | 22 ++++++++++++++ 4 files changed, 83 insertions(+) create mode 100644 packages/extra/monitoring/templates/vm/vmagent.yaml diff --git a/packages/extra/monitoring/README.md b/packages/extra/monitoring/README.md index 3666765b..20327fd9 100644 --- a/packages/extra/monitoring/README.md +++ b/packages/extra/monitoring/README.md @@ -91,3 +91,12 @@ | `grafana.resources.limits.cpu` | CPU limit. | `quantity` | `1` | | `grafana.resources.limits.memory` | Memory limit. | `quantity` | `1Gi` | + +### Vmagent configuration + +| Name | Description | Type | Value | +| ------------------------ | ---------------------------------------- | -------- | ----- | +| `vmagent` | Configuration for VictoriaMetrics Agent. | `object` | `{}` | +| `vmagent.externalLabels` | External labels applied to all metrics. | `object` | `{}` | +| `vmagent.remoteWrite` | Remote write configuration. | `object` | `{}` | + diff --git a/packages/extra/monitoring/templates/vm/vmagent.yaml b/packages/extra/monitoring/templates/vm/vmagent.yaml new file mode 100644 index 00000000..2c6c391a --- /dev/null +++ b/packages/extra/monitoring/templates/vm/vmagent.yaml @@ -0,0 +1,30 @@ +{{- if ne .Release.Namespace "tenant-root" }} +apiVersion: operator.victoriametrics.com/v1beta1 +kind: VMAgent +metadata: + name: vmagent +spec: + podMetadata: + labels: + policy.cozystack.io/allow-to-apiserver: "true" + shardCount: 1 + externalLabels: + cluster: {{ .Values.vmagent.externalLabels.cluster }} + tenant: {{ .Release.Namespace }} + extraArgs: + promscrape.maxScrapeSize: "32MB" + promscrape.streamParse: "true" + remoteWrite: + {{- range .Values.vmagent.remoteWrite.urls }} + - url: {{ . | quote }} + {{- end }} + + scrapeInterval: 30s + selectAllByDefault: false + podScrapeNamespaceSelector: + matchLabels: + namespace.cozystack.io/monitoring: {{ .Release.Namespace }} + serviceScrapeNamespaceSelector: + matchLabels: + namespace.cozystack.io/monitoring: {{ .Release.Namespace }} +{{- end }} diff --git a/packages/extra/monitoring/values.schema.json b/packages/extra/monitoring/values.schema.json index de81acd1..21b3b798 100644 --- a/packages/extra/monitoring/values.schema.json +++ b/packages/extra/monitoring/values.schema.json @@ -560,6 +560,28 @@ } } } + }, + "vmagent": { + "description": "Configuration for VictoriaMetrics Agent.", + "type": "object", + "default": {}, + "properties": { + "externalLabels": { + "description": "External labels applied to all metrics.", + "default": { + "cluster": "cozystack" + } + }, + "remoteWrite": { + "description": "Remote write configuration.", + "default": { + "urls": [ + "http://vminsert-shortterm:8480/insert/0/prometheus", + "http://vminsert-longterm:8480/insert/0/prometheus" + ] + } + } + } } } } \ No newline at end of file diff --git a/packages/extra/monitoring/values.yaml b/packages/extra/monitoring/values.yaml index d687f213..f4e1043e 100644 --- a/packages/extra/monitoring/values.yaml +++ b/packages/extra/monitoring/values.yaml @@ -154,3 +154,25 @@ grafana: requests: cpu: 100m memory: 256Mi +## +## @section Vmagent configuration +## + +## @typedef {struct} VmagentRemoteWrite - Remote write configuration. +## @typedef {stringSlice} VmagentRemoteWriteURLs - List of remoteWrite endpoint URLs. + +## @typedef {struct} VmagentExternalLabels - External labels for metrics. +## @field {string} [] - Label value for the given key. + +## @typedef {struct} Vmagent - VictoriaMetrics Agent configuration. +## @field {VmagentExternalLabels} [externalLabels] - External labels applied to all metrics. +## @field {VmagentRemoteWrite} [remoteWrite] - Remote write configuration. + +## @param {Vmagent} vmagent - Configuration for VictoriaMetrics Agent. +vmagent: + externalLabels: + cluster: cozystack + remoteWrite: + urls: + - http://vminsert-shortterm:8480/insert/0/prometheus + - http://vminsert-longterm:8480/insert/0/prometheus From 09fd7c4094905eff5a33ff95becb691459d6e330 Mon Sep 17 00:00:00 2001 From: IvanHunters Date: Wed, 3 Dec 2025 22:30:29 +0300 Subject: [PATCH 18/33] fix crd Signed-off-by: IvanHunters --- .../cozystack-resource-definitions/cozyrds/monitoring.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/system/cozystack-resource-definitions/cozyrds/monitoring.yaml b/packages/system/cozystack-resource-definitions/cozyrds/monitoring.yaml index 520e4671..720dc161 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/monitoring.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/monitoring.yaml @@ -8,7 +8,7 @@ spec: singular: monitoring plural: monitorings openAPISchema: |- - {"title":"Chart Values","type":"object","properties":{"alerta":{"description":"Configuration for the Alerta service.","type":"object","default":{},"properties":{"alerts":{"description":"Alert routing configuration.","type":"object","default":{},"properties":{"slack":{"description":"Configuration for Slack alerts.","type":"object","default":{},"required":["url"],"properties":{"url":{"description":"Configuration uri for Slack alerts.","type":"string","default":""}}},"telegram":{"description":"Configuration for Telegram alerts.","type":"object","default":{},"required":["chatID","token"],"properties":{"chatID":{"description":"Telegram chat ID(s), separated by commas.","type":"string","default":""},"disabledSeverity":{"description":"List of severities without alerts (e.g. \"informational,warning\").","type":"string","default":""},"token":{"description":"Telegram bot token.","type":"string","default":""}}}}},"resources":{"description":"Resource configuration.","type":"object","default":{},"properties":{"limits":{"description":"Resource limits.","type":"object","default":{},"properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"requests":{"description":"Resource requests.","type":"object","default":{},"properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}},"storage":{"description":"Persistent volume size for the database.","type":"string","default":"10Gi"},"storageClassName":{"description":"StorageClass used for the database.","type":"string","default":""}}},"grafana":{"description":"Configuration for Grafana.","type":"object","default":{},"properties":{"db":{"description":"Database configuration.","type":"object","default":{},"properties":{"size":{"description":"Persistent volume size for the database.","type":"string","default":"10Gi"}}},"resources":{"description":"Resource configuration.","type":"object","default":{},"properties":{"limits":{"description":"Resource limits.","type":"object","default":{},"properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"requests":{"description":"Resource requests.","type":"object","default":{},"properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}}}},"host":{"description":"The hostname used to access Grafana externally (defaults to 'grafana' subdomain for the tenant host).","type":"string","default":""},"logsStorages":{"description":"Configuration of logs storage instances.","type":"array","default":[{"name":"generic","retentionPeriod":"1","storage":"10Gi","storageClassName":"replicated"}],"items":{"type":"object","required":["name","retentionPeriod","storage","storageClassName"],"properties":{"name":{"description":"Name of the storage instance.","type":"string"},"retentionPeriod":{"description":"Retention period for logs.","type":"string","default":"1"},"storage":{"description":"Persistent volume size.","type":"string","default":"10Gi"},"storageClassName":{"description":"StorageClass used to store the data.","type":"string","default":"replicated"}}}},"metricsStorages":{"description":"Configuration of metrics storage instances.","type":"array","default":[{"deduplicationInterval":"15s","name":"shortterm","retentionPeriod":"3d","storage":"10Gi","storageClassName":""},{"deduplicationInterval":"5m","name":"longterm","retentionPeriod":"14d","storage":"10Gi","storageClassName":""}],"items":{"type":"object","required":["deduplicationInterval","name","retentionPeriod","storage"],"properties":{"deduplicationInterval":{"description":"Deduplication interval for metrics.","type":"string"},"name":{"description":"Name of the storage instance.","type":"string"},"retentionPeriod":{"description":"Retention period for metrics.","type":"string"},"storage":{"description":"Persistent volume size.","type":"string","default":"10Gi"},"storageClassName":{"description":"StorageClass used for the data.","type":"string"},"vminsert":{"description":"Configuration for vminsert.","type":"object","properties":{"maxAllowed":{"description":"Maximum allowed resources.","type":"object","properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"minAllowed":{"description":"Minimum guaranteed resources.","type":"object","properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}},"vmselect":{"description":"Configuration for vmselect.","type":"object","properties":{"maxAllowed":{"description":"Maximum allowed resources.","type":"object","properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"minAllowed":{"description":"Minimum guaranteed resources.","type":"object","properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}},"vmstorage":{"description":"Configuration for vmstorage.","type":"object","properties":{"maxAllowed":{"description":"Maximum allowed resources.","type":"object","properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"minAllowed":{"description":"Minimum guaranteed resources.","type":"object","properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}}}}}}} + {"title":"Chart Values","type":"object","properties":{"alerta":{"description":"Configuration for the Alerta service.","type":"object","default":{},"properties":{"alerts":{"description":"Alert routing configuration.","type":"object","default":{},"properties":{"slack":{"description":"Configuration for Slack alerts.","type":"object","default":{},"required":["url"],"properties":{"url":{"description":"Configuration uri for Slack alerts.","type":"string","default":""}}},"telegram":{"description":"Configuration for Telegram alerts.","type":"object","default":{},"required":["chatID","token"],"properties":{"chatID":{"description":"Telegram chat ID(s), separated by commas.","type":"string","default":""},"disabledSeverity":{"description":"List of severities without alerts (e.g. \"informational,warning\").","type":"string","default":""},"token":{"description":"Telegram bot token.","type":"string","default":""}}}}},"resources":{"description":"Resource configuration.","type":"object","default":{},"properties":{"limits":{"description":"Resource limits.","type":"object","default":{},"properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"requests":{"description":"Resource requests.","type":"object","default":{},"properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}},"storage":{"description":"Persistent volume size for the database.","type":"string","default":"10Gi"},"storageClassName":{"description":"StorageClass used for the database.","type":"string","default":""}}},"grafana":{"description":"Configuration for Grafana.","type":"object","default":{},"properties":{"db":{"description":"Database configuration.","type":"object","default":{},"properties":{"size":{"description":"Persistent volume size for the database.","type":"string","default":"10Gi"}}},"resources":{"description":"Resource configuration.","type":"object","default":{},"properties":{"limits":{"description":"Resource limits.","type":"object","default":{},"properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"requests":{"description":"Resource requests.","type":"object","default":{},"properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}}}},"host":{"description":"The hostname used to access Grafana externally (defaults to 'grafana' subdomain for the tenant host).","type":"string","default":""},"logsStorages":{"description":"Configuration of logs storage instances.","type":"array","default":[{"name":"generic","retentionPeriod":"1","storage":"10Gi","storageClassName":"replicated"}],"items":{"type":"object","required":["name","retentionPeriod","storage","storageClassName"],"properties":{"name":{"description":"Name of the storage instance.","type":"string"},"retentionPeriod":{"description":"Retention period for logs.","type":"string","default":"1"},"storage":{"description":"Persistent volume size.","type":"string","default":"10Gi"},"storageClassName":{"description":"StorageClass used to store the data.","type":"string","default":"replicated"}}}},"metricsStorages":{"description":"Configuration of metrics storage instances.","type":"array","default":[{"deduplicationInterval":"15s","name":"shortterm","retentionPeriod":"3d","storage":"10Gi","storageClassName":""},{"deduplicationInterval":"5m","name":"longterm","retentionPeriod":"14d","storage":"10Gi","storageClassName":""}],"items":{"type":"object","required":["deduplicationInterval","name","retentionPeriod","storage"],"properties":{"deduplicationInterval":{"description":"Deduplication interval for metrics.","type":"string"},"name":{"description":"Name of the storage instance.","type":"string"},"retentionPeriod":{"description":"Retention period for metrics.","type":"string"},"storage":{"description":"Persistent volume size.","type":"string","default":"10Gi"},"storageClassName":{"description":"StorageClass used for the data.","type":"string"},"vminsert":{"description":"Configuration for vminsert.","type":"object","properties":{"maxAllowed":{"description":"Maximum allowed resources.","type":"object","properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"minAllowed":{"description":"Minimum guaranteed resources.","type":"object","properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}},"vmselect":{"description":"Configuration for vmselect.","type":"object","properties":{"maxAllowed":{"description":"Maximum allowed resources.","type":"object","properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"minAllowed":{"description":"Minimum guaranteed resources.","type":"object","properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}},"vmstorage":{"description":"Configuration for vmstorage.","type":"object","properties":{"maxAllowed":{"description":"Maximum allowed resources.","type":"object","properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"minAllowed":{"description":"Minimum guaranteed resources.","type":"object","properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}}}}},"vmagent":{"description":"Configuration for VictoriaMetrics Agent.","type":"object","default":{},"properties":{"externalLabels":{"description":"External labels applied to all metrics.","default":{"cluster":"cozystack"}},"remoteWrite":{"description":"Remote write configuration.","default":{"urls":["http://vminsert-shortterm:8480/insert/0/prometheus","http://vminsert-longterm:8480/insert/0/prometheus"]}}}}}} release: prefix: "" labels: @@ -28,7 +28,7 @@ spec: description: Monitoring and observability stack module: true icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODdfMzI2OCkiLz4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzY4N18zMjY4KSI+CjxwYXRoIGQ9Ik04OS41MDM5IDExMS43MDdINTQuNDk3QzU0LjE3MjcgMTExLjcwNyA1NC4wMTA4IDExMS4yMjEgNTQuMzM0OSAxMTEuMDU5TDU3LjI1MjIgMTA4Ljk1MkM2MC4zMzE0IDEwNi42ODMgNjEuOTUyMiAxMDIuNjMxIDYwLjk3OTcgOTguNzQxMkg4My4wMjFDODIuMDQ4NSAxMDIuNjMxIDgzLjY2OTMgMTA2LjY4MyA4Ni43NDg1IDEwOC45NTJMODkuNjY1OCAxMTEuMDU5Qzg5Ljk5IDExMS4yMjEgODkuODI3OSAxMTEuNzA3IDg5LjUwMzkgMTExLjcwN1oiIGZpbGw9IiNCMEI2QkIiLz4KPHBhdGggZD0iTTExMy4zMjggOTguNzQxSDMwLjY3MjVDMjcuNTkzMSA5OC43NDEgMjUgOTYuMTQ4IDI1IDkzLjA2ODdWMzMuMTAzMkMyNSAzMC4wMjM5IDI3LjU5MzEgMjcuNDMwNyAzMC42NzI1IDI3LjQzMDdIMTEzLjMyOEMxMTYuNDA3IDI3LjQzMDcgMTE5IDMwLjAyMzcgMTE5IDMzLjEwMzJWOTMuMDY4N0MxMTkgOTYuMTQ4IDExNi40MDcgOTguNzQxIDExMy4zMjggOTguNzQxWiIgZmlsbD0iI0U4RURFRSIvPgo8cGF0aCBkPSJNMTE5IDg0LjE1NDlIMjVWMzMuMTAzMkMyNSAzMC4wMjM5IDI3LjU5MzEgMjcuNDMwNyAzMC42NzI1IDI3LjQzMDdIMTEzLjMyOEMxMTYuNDA3IDI3LjQzMDcgMTE5IDMwLjAyMzcgMTE5IDMzLjEwMzJMMTE5IDg0LjE1NDlaIiBmaWxsPSIjMzg0NTRGIi8+CjxwYXRoIGQ9Ik05MC42Mzc0IDExNi41NjlINTMuMzYxNkM1Mi4wNjUxIDExNi41NjkgNTAuOTMwNyAxMTUuNDM1IDUwLjkzMDcgMTE0LjEzOEM1MC45MzA3IDExMi44NDEgNTIuMDY1MSAxMTEuNzA3IDUzLjM2MTYgMTExLjcwN0g5MC42Mzc0QzkxLjkzMzkgMTExLjcwNyA5My4wNjg0IDExMi44NDEgOTMuMDY4NCAxMTQuMTM4QzkzLjA2ODQgMTE1LjQzNSA5MS45MzM5IDExNi41NjkgOTAuNjM3NCAxMTYuNTY5WiIgZmlsbD0iI0U4RURFRSIvPgo8cGF0aCBkPSJNNTQuMTcyMiAzOC43NzU3SDMzLjEwMzJDMzIuMTMwNyAzOC43NzU3IDMxLjQ4MjQgMzguMTI3NCAzMS40ODI0IDM3LjE1NDlDMzEuNDgyNCAzNi4xODI0IDMyLjEzMDcgMzUuNTM0MiAzMy4xMDMyIDM1LjUzNDJINTQuMTcyMkM1NS4xNDQ3IDM1LjUzNDIgNTUuNzkzIDM2LjE4MjQgNTUuNzkzIDM3LjE1NDlDNTUuNzkyOCAzOC4xMjc0IDU1LjE0NDUgMzguNzc1NyA1NC4xNzIyIDM4Ljc3NTdaIiBmaWxsPSIjREQzNDJFIi8+CjxwYXRoIGQ9Ik02My44OTYzIDQ1LjI1OTFINDEuMjA2N0M0MC4yMzQyIDQ1LjI1OTEgMzkuNTg1OSA0NC42MTA4IDM5LjU4NTkgNDMuNjM4M0MzOS41ODU5IDQyLjY2NTggNDAuMjM0MiA0Mi4wMTc2IDQxLjIwNjcgNDIuMDE3Nkg2My44OTYzQzY0Ljg2ODggNDIuMDE3NiA2NS41MTcxIDQyLjY2NTggNjUuNTE3MSA0My42MzgzQzY1LjUxNzEgNDQuNjEwOCA2NC44Njg4IDQ1LjI1OTEgNjMuODk2MyA0NS4yNTkxWiIgZmlsbD0iIzczODNCRiIvPgo8cGF0aCBkPSJNMzQuNzI0IDQ1LjI1OTFIMzMuMTAzMkMzMi4xMzA3IDQ1LjI1OTEgMzEuNDgyNCA0NC42MTA4IDMxLjQ4MjQgNDMuNjM4M0MzMS40ODI0IDQyLjY2NTggMzIuMTMwNyA0Mi4wMTc2IDMzLjEwMzIgNDIuMDE3NkgzNC43MjRDMzUuNjk2NCA0Mi4wMTc2IDM2LjM0NDcgNDIuNjY1OCAzNi4zNDQ3IDQzLjYzODNDMzYuMzQ0NyA0NC42MTA4IDM1LjY5NjMgNDUuMjU5MSAzNC43MjQgNDUuMjU5MVoiIGZpbGw9IiM0MkIwNUMiLz4KPHBhdGggZD0iTTYzLjg5NjMgMzguNzc1N0g2MC42NTQ5QzU5LjY4MjQgMzguNzc1NyA1OS4wMzQyIDM4LjEyNzQgNTkuMDM0MiAzNy4xNTQ5QzU5LjAzNDIgMzYuMTgyNCA1OS42ODI0IDM1LjUzNDIgNjAuNjU0OSAzNS41MzQySDYzLjg5NjNDNjQuODY4OCAzNS41MzQyIDY1LjUxNzEgMzYuMTgyNCA2NS41MTcxIDM3LjE1NDlDNjUuNTE3MSAzOC4xMjc0IDY0Ljg2ODggMzguNzc1NyA2My44OTYzIDM4Ljc3NTdaIiBmaWxsPSIjRUNCQTE2Ii8+CjxwYXRoIGQ9Ik00Ny42ODkzIDUxLjc0MTNIMzMuMTAzMkMzMi4xMzA3IDUxLjc0MTMgMzEuNDgyNCA1MS4wOTMxIDMxLjQ4MjQgNTAuMTIwNkMzMS40ODI0IDQ5LjE0ODEgMzIuMTMwNyA0OC41IDMzLjEwMzIgNDguNUg0Ny42ODkzQzQ4LjY2MTggNDguNSA0OS4zMTAxIDQ5LjE0ODMgNDkuMzEwMSA1MC4xMjA4QzQ5LjMxMDEgNTEuMDkzMyA0OC42NjE4IDUxLjc0MTMgNDcuNjg5MyA1MS43NDEzWiIgZmlsbD0iI0REMzQyRSIvPgo8cGF0aCBkPSJNNjMuODk2OCA1MS43NDEzSDU0LjE3MjVDNTMuMiA1MS43NDEzIDUyLjU1MTggNTEuMDkzMSA1Mi41NTE4IDUwLjEyMDZDNTIuNTUxOCA0OS4xNDgxIDUzLjIwMDIgNDguNSA1NC4xNzI3IDQ4LjVINjMuODk2OUM2NC44Njk0IDQ4LjUgNjUuNTE3NyA0OS4xNDgzIDY1LjUxNzcgNTAuMTIwOEM2NS41MTc3IDUxLjA5MzMgNjQuODY5MiA1MS43NDEzIDYzLjg5NjggNTEuNzQxM1oiIGZpbGw9IiNFQ0JBMTYiLz4KPHBhdGggZD0iTTU0LjE3MjIgNTguMjI0SDMzLjEwMzJDMzIuMTMwNyA1OC4yMjQgMzEuNDgyNCA1Ny41NzU3IDMxLjQ4MjQgNTYuNjAzMkMzMS40ODI0IDU1LjYzMDcgMzIuMTMwNyA1NC45ODI0IDMzLjEwMzIgNTQuOTgyNEg1NC4xNzIyQzU1LjE0NDcgNTQuOTgyNCA1NS43OTMgNTUuNjMwNyA1NS43OTMgNTYuNjAzMkM1NS43OTMgNTcuNTc1NyA1NS4xNDQ1IDU4LjIyNCA1NC4xNzIyIDU4LjIyNFoiIGZpbGw9IiM0MkIwNUMiLz4KPHBhdGggZD0iTTYzLjg5NjMgNjQuNzA3NEg0MS4yMDY3QzQwLjIzNDIgNjQuNzA3NCAzOS41ODU5IDY0LjA1OTEgMzkuNTg1OSA2My4wODY2QzM5LjU4NTkgNjIuMTE0MSA0MC4yMzQyIDYxLjQ2NTggNDEuMjA2NyA2MS40NjU4SDYzLjg5NjNDNjQuODY4OCA2MS40NjU4IDY1LjUxNzEgNjIuMTE0MSA2NS41MTcxIDYzLjA4NjZDNjUuNTE3MSA2NC4wNTkxIDY0Ljg2ODggNjQuNzA3NCA2My44OTYzIDY0LjcwNzRaIiBmaWxsPSIjRUNCQTE2Ii8+CjxwYXRoIGQ9Ik0zNC43MjQgNjQuNzA3NEgzMy4xMDMyQzMyLjEzMDcgNjQuNzA3NCAzMS40ODI0IDY0LjA1OTEgMzEuNDgyNCA2My4wODY2QzMxLjQ4MjQgNjIuMTE0MSAzMi4xMzA3IDYxLjQ2NTggMzMuMTAzMiA2MS40NjU4SDM0LjcyNEMzNS42OTY0IDYxLjQ2NTggMzYuMzQ0NyA2Mi4xMTQxIDM2LjM0NDcgNjMuMDg2NkMzNi4zNDQ3IDY0LjA1OTEgMzUuNjk2MyA2NC43MDc0IDM0LjcyNCA2NC43MDc0WiIgZmlsbD0iI0REMzQyRSIvPgo8cGF0aCBkPSJNNDcuNjg5MyA3MS4xODk4SDMzLjEwMzJDMzIuMTMwNyA3MS4xODk4IDMxLjQ4MjQgNzAuNTQxNSAzMS40ODI0IDY5LjU2OUMzMS40ODI0IDY4LjU5NjUgMzIuMTMwNyA2Ny45NDgyIDMzLjEwMzIgNjcuOTQ4Mkg0Ny42ODkzQzQ4LjY2MTggNjcuOTQ4MiA0OS4zMTAxIDY4LjU5NjUgNDkuMzEwMSA2OS41NjlDNDkuMzEwMSA3MC41NDE1IDQ4LjY2MTggNzEuMTg5OCA0Ny42ODkzIDcxLjE4OThaIiBmaWxsPSIjNDJCMDVDIi8+CjxwYXRoIGQ9Ik02My44OTY4IDcxLjE4OThINTQuMTcyNUM1My4yIDcxLjE4OTggNTIuNTUxOCA3MC41NDE1IDUyLjU1MTggNjkuNTY5QzUyLjU1MTggNjguNTk2NSA1My4yIDY3Ljk0ODIgNTQuMTcyNSA2Ny45NDgySDYzLjg5NjhDNjQuODY5MiA2Ny45NDgyIDY1LjUxNzUgNjguNTk2NSA2NS41MTc1IDY5LjU2OUM2NS41MTc1IDcwLjU0MTUgNjQuODY5MiA3MS4xODk4IDYzLjg5NjggNzEuMTg5OFoiIGZpbGw9IiM3MzgzQkYiLz4KPHBhdGggZD0iTTU0LjE3MjIgNzcuNjcyMkgzMy4xMDMyQzMyLjEzMDcgNzcuNjcyMiAzMS40ODI0IDc3LjAyMzkgMzEuNDgyNCA3Ni4wNTE0QzMxLjQ4MjQgNzUuMDc4OSAzMi4xMzA3IDc0LjQzMDcgMzMuMTAzMiA3NC40MzA3SDU0LjE3MjJDNTUuMTQ0NyA3NC40MzA3IDU1Ljc5MyA3NS4wNzg5IDU1Ljc5MyA3Ni4wNTE0QzU1Ljc5MjggNzcuMDIzOSA1NS4xNDQ1IDc3LjY3MjIgNTQuMTcyMiA3Ny42NzIyWiIgZmlsbD0iI0VDQkExNiIvPgo8cGF0aCBkPSJNNjMuODk2MyA3Ny42NzIySDYwLjY1NDlDNTkuNjgyNCA3Ny42NzIyIDU5LjAzNDIgNzcuMDIzOSA1OS4wMzQyIDc2LjA1MTRDNTkuMDM0MiA3NS4wNzg5IDU5LjY4MjQgNzQuNDMwNyA2MC42NTQ5IDc0LjQzMDdINjMuODk2M0M2NC44Njg4IDc0LjQzMDcgNjUuNTE3MSA3NS4wNzg5IDY1LjUxNzEgNzYuMDUxNEM2NS41MTcxIDc3LjAyMzkgNjQuODY4OCA3Ny42NzIyIDYzLjg5NjMgNzcuNjcyMloiIGZpbGw9IiM0MkIwNUMiLz4KPHBhdGggZD0iTTEwMS4xNzIgNzcuNjcyMkg4MC4xMDMyQzc5LjEzMDcgNzcuNjcyMiA3OC40ODI0IDc3LjAyMzkgNzguNDgyNCA3Ni4wNTE0Qzc4LjQ4MjQgNzUuMDc4OSA3OS4xMzA3IDc0LjQzMDcgODAuMTAzMiA3NC40MzA3SDEwMS4xNzJDMTAyLjE0NSA3NC40MzA3IDEwMi43OTMgNzUuMDc4OSAxMDIuNzkzIDc2LjA1MTRDMTAyLjc5MyA3Ny4wMjM5IDEwMi4xNDUgNzcuNjcyMiAxMDEuMTcyIDc3LjY3MjJaIiBmaWxsPSIjREQzNDJFIi8+CjxwYXRoIGQ9Ik0xMTAuODk2IDc3LjY3MjJIMTA3LjY1NUMxMDYuNjgyIDc3LjY3MjIgMTA2LjAzNCA3Ny4wMjM5IDEwNi4wMzQgNzYuMDUxNEMxMDYuMDM0IDc1LjA3ODkgMTA2LjY4MiA3NC40MzA3IDEwNy42NTUgNzQuNDMwN0gxMTAuODk2QzExMS44NjkgNzQuNDMwNyAxMTIuNTE3IDc1LjA3ODkgMTEyLjUxNyA3Ni4wNTE0QzExMi41MTcgNzcuMDIzOSAxMTEuODY5IDc3LjY3MjIgMTEwLjg5NiA3Ny42NzIyWiIgZmlsbD0iIzQyQjA1QyIvPgo8cGF0aCBkPSJNNjMuODk2MyA1OC4yMjRINjAuNjU0OUM1OS42ODI0IDU4LjIyNCA1OS4wMzQyIDU3LjU3NTcgNTkuMDM0MiA1Ni42MDMyQzU5LjAzNDIgNTUuNjMwNyA1OS42ODI0IDU0Ljk4MjQgNjAuNjU0OSA1NC45ODI0SDYzLjg5NjNDNjQuODY4OCA1NC45ODI0IDY1LjUxNzEgNTUuNjMwNyA2NS41MTcxIDU2LjYwMzJDNjUuNTE3MSA1Ny41NzU3IDY0Ljg2ODggNTguMjI0IDYzLjg5NjMgNTguMjI0WiIgZmlsbD0iIzczODNCRiIvPgo8cGF0aCBkPSJNMTEyLjUxNyA1MS43NDExQzExMi41MTcgNjAuNjU0OSAxMDUuMjI0IDY3Ljk0OCA5Ni4zMTA0IDY3Ljk0OEM4Ny4zOTY2IDY3Ljk0OCA4MC4xMDM1IDYwLjY1NDkgODAuMTAzNSA1MS43NDExQzgwLjEwMzUgNDIuODI3MyA4Ny4zOTY2IDM1LjUzNDIgOTYuMzEwNCAzNS41MzQyQzEwNS4yMjQgMzUuNTM0MiAxMTIuNTE3IDQyLjgyNzMgMTEyLjUxNyA1MS43NDExWiIgZmlsbD0iI0VDQkExNiIvPgo8cGF0aCBkPSJNODAuMTAzNSA1MS43NDExQzgwLjEwMzUgNTIuMjI3MyA4MC4xMDM1IDUyLjg3NTUgODAuMTAzNSA1My4zNjE5SDk2LjMxMDRWMzUuNTM0MkM4Ny4zOTY2IDM1LjUzNDIgODAuMTAzNSA0Mi44MjczIDgwLjEwMzUgNTEuNzQxMVoiIGZpbGw9IiM0MkIwNUMiLz4KPC9nPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4N18zMjY4IiB4MT0iMS4yMzIzOWUtMDYiIHkxPSItOS41MDAwMSIgeDI9IjE2OCIgeTI9IjE2MiIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjOEZEREZGIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzAwNzVGRiIvPgo8L2xpbmVhckdyYWRpZW50Pgo8Y2xpcFBhdGggaWQ9ImNsaXAwXzY4N18zMjY4Ij4KPHJlY3Qgd2lkdGg9Ijk0IiBoZWlnaHQ9Ijk0IiBmaWxsPSJ3aGl0ZSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjUgMjUpIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg== - keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "host"], ["spec", "metricsStorages"], ["spec", "logsStorages"], ["spec", "alerta"], ["spec", "alerta", "storage"], ["spec", "alerta", "storageClassName"], ["spec", "alerta", "resources"], ["spec", "alerta", "resources", "limits"], ["spec", "alerta", "resources", "limits", "cpu"], ["spec", "alerta", "resources", "limits", "memory"], ["spec", "alerta", "resources", "requests"], ["spec", "alerta", "resources", "requests", "cpu"], ["spec", "alerta", "resources", "requests", "memory"], ["spec", "alerta", "alerts"], ["spec", "alerta", "alerts", "telegram"], ["spec", "alerta", "alerts", "telegram", "token"], ["spec", "alerta", "alerts", "telegram", "chatID"], ["spec", "alerta", "alerts", "telegram", "disabledSeverity"], ["spec", "alerta", "alerts", "slack"], ["spec", "alerta", "alerts", "slack", "url"], ["spec", "grafana"], ["spec", "grafana", "db"], ["spec", "grafana", "db", "size"], ["spec", "grafana", "resources"], ["spec", "grafana", "resources", "limits"], ["spec", "grafana", "resources", "limits", "cpu"], ["spec", "grafana", "resources", "limits", "memory"], ["spec", "grafana", "resources", "requests"], ["spec", "grafana", "resources", "requests", "cpu"], ["spec", "grafana", "resources", "requests", "memory"]] + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "host"], ["spec", "metricsStorages"], ["spec", "logsStorages"], ["spec", "alerta"], ["spec", "alerta", "storage"], ["spec", "alerta", "storageClassName"], ["spec", "alerta", "resources"], ["spec", "alerta", "resources", "limits"], ["spec", "alerta", "resources", "limits", "cpu"], ["spec", "alerta", "resources", "limits", "memory"], ["spec", "alerta", "resources", "requests"], ["spec", "alerta", "resources", "requests", "cpu"], ["spec", "alerta", "resources", "requests", "memory"], ["spec", "alerta", "alerts"], ["spec", "alerta", "alerts", "telegram"], ["spec", "alerta", "alerts", "telegram", "token"], ["spec", "alerta", "alerts", "telegram", "chatID"], ["spec", "alerta", "alerts", "telegram", "disabledSeverity"], ["spec", "alerta", "alerts", "slack"], ["spec", "alerta", "alerts", "slack", "url"], ["spec", "grafana"], ["spec", "grafana", "db"], ["spec", "grafana", "db", "size"], ["spec", "grafana", "resources"], ["spec", "grafana", "resources", "limits"], ["spec", "grafana", "resources", "limits", "cpu"], ["spec", "grafana", "resources", "limits", "memory"], ["spec", "grafana", "resources", "requests"], ["spec", "grafana", "resources", "requests", "cpu"], ["spec", "grafana", "resources", "requests", "memory"], ["spec", "vmagent"], ["spec", "vmagent", "externalLabels"], ["spec", "vmagent", "externalLabels", "cluster"], ["spec", "vmagent", "remoteWrite"], ["spec", "vmagent", "remoteWrite", "urls"]] secrets: exclude: [] include: From 825390c209be17b27658c81c6e892fe9cc1deae3 Mon Sep 17 00:00:00 2001 From: nbykov0 <166552198+nbykov0@users.noreply.github.com> Date: Wed, 3 Dec 2025 16:25:21 +0300 Subject: [PATCH 19/33] [core:bundles] separate prometheus-operator-crds Signed-off-by: nbykov0 <166552198+nbykov0@users.noreply.github.com> --- packages/core/platform/bundles/distro-full.yaml | 10 ++++++++-- packages/core/platform/bundles/distro-hosted.yaml | 10 ++++++++-- packages/core/platform/bundles/paas-full.yaml | 10 ++++++++-- packages/core/platform/bundles/paas-hosted.yaml | 10 ++++++++-- packages/system/prometheus-operator-crds/Makefile | 4 ++-- 5 files changed, 34 insertions(+), 10 deletions(-) diff --git a/packages/core/platform/bundles/distro-full.yaml b/packages/core/platform/bundles/distro-full.yaml index e4032194..3cd0df96 100644 --- a/packages/core/platform/bundles/distro-full.yaml +++ b/packages/core/platform/bundles/distro-full.yaml @@ -87,18 +87,24 @@ releases: optional: true dependsOn: [cilium,cert-manager] +- name: prometheus-operator-crds + releaseName: prometheus-operator-crds + chart: cozy-prometheus-operator-crds + namespace: cozy-victoria-metrics-operator + dependsOn: [] + - name: metrics-server releaseName: metrics-server chart: cozy-metrics-server namespace: cozy-monitoring - dependsOn: [cilium] + dependsOn: [cilium,prometheus-operator-crds] - name: victoria-metrics-operator releaseName: victoria-metrics-operator chart: cozy-victoria-metrics-operator namespace: cozy-victoria-metrics-operator optional: true - dependsOn: [cilium,cert-manager] + dependsOn: [cilium,cert-manager,prometheus-operator-crds] - name: monitoring-agents releaseName: monitoring-agents diff --git a/packages/core/platform/bundles/distro-hosted.yaml b/packages/core/platform/bundles/distro-hosted.yaml index 9de60f3d..02653a21 100644 --- a/packages/core/platform/bundles/distro-hosted.yaml +++ b/packages/core/platform/bundles/distro-hosted.yaml @@ -55,18 +55,24 @@ releases: optional: true dependsOn: [cert-manager] +- name: prometheus-operator-crds + releaseName: prometheus-operator-crds + chart: cozy-prometheus-operator-crds + namespace: cozy-victoria-metrics-operator + dependsOn: [] + - name: metrics-server releaseName: metrics-server chart: cozy-metrics-server namespace: cozy-monitoring - dependsOn: [] + dependsOn: [prometheus-operator-crds] - name: victoria-metrics-operator releaseName: victoria-metrics-operator chart: cozy-victoria-metrics-operator namespace: cozy-victoria-metrics-operator optional: true - dependsOn: [cert-manager] + dependsOn: [prometheus-operator-crds,cert-manager] - name: monitoring-agents releaseName: monitoring-agents diff --git a/packages/core/platform/bundles/paas-full.yaml b/packages/core/platform/bundles/paas-full.yaml index c00c25ed..96a7078f 100644 --- a/packages/core/platform/bundles/paas-full.yaml +++ b/packages/core/platform/bundles/paas-full.yaml @@ -142,17 +142,23 @@ releases: namespace: cozy-cert-manager dependsOn: [cilium,kubeovn,cert-manager] +- name: prometheus-operator-crds + releaseName: prometheus-operator-crds + chart: cozy-prometheus-operator-crds + namespace: cozy-victoria-metrics-operator + dependsOn: [] + - name: metrics-server releaseName: metrics-server chart: cozy-metrics-server namespace: cozy-monitoring - dependsOn: [cilium] + dependsOn: [cilium,kubeovn,prometheus-operator-crds] - name: victoria-metrics-operator releaseName: victoria-metrics-operator chart: cozy-victoria-metrics-operator namespace: cozy-victoria-metrics-operator - dependsOn: [cilium,kubeovn,cert-manager] + dependsOn: [cilium,kubeovn,cert-manager,prometheus-operator-crds] - name: monitoring-agents releaseName: monitoring-agents diff --git a/packages/core/platform/bundles/paas-hosted.yaml b/packages/core/platform/bundles/paas-hosted.yaml index 9a9fb17e..bc7f33d3 100644 --- a/packages/core/platform/bundles/paas-hosted.yaml +++ b/packages/core/platform/bundles/paas-hosted.yaml @@ -86,17 +86,23 @@ releases: namespace: cozy-cert-manager dependsOn: [cert-manager] +- name: prometheus-operator-crds + releaseName: prometheus-operator-crds + chart: cozy-prometheus-operator-crds + namespace: cozy-victoria-metrics-operator + dependsOn: [] + - name: metrics-server releaseName: metrics-server chart: cozy-metrics-server namespace: cozy-monitoring - dependsOn: [] + dependsOn: [prometheus-operator-crds] - name: victoria-metrics-operator releaseName: victoria-metrics-operator chart: cozy-victoria-metrics-operator namespace: cozy-victoria-metrics-operator - dependsOn: [cert-manager] + dependsOn: [cert-manager,prometheus-operator-crds] - name: monitoring-agents releaseName: monitoring-agents diff --git a/packages/system/prometheus-operator-crds/Makefile b/packages/system/prometheus-operator-crds/Makefile index 87dbe606..173da9c1 100644 --- a/packages/system/prometheus-operator-crds/Makefile +++ b/packages/system/prometheus-operator-crds/Makefile @@ -1,5 +1,5 @@ -export NAME=victoria-metrics-operator -export NAMESPACE=cozy-$(NAME) +export NAME=prometheus-operator-crds +export NAMESPACE=cozy-victoria-metrics-operator include ../../../scripts/package.mk From 8d14bcb598d459efd888bdba8a87fba0ade91c0f Mon Sep 17 00:00:00 2001 From: nbykov0 <166552198+nbykov0@users.noreply.github.com> Date: Wed, 3 Dec 2025 16:26:32 +0300 Subject: [PATCH 20/33] [system:victoria-metrics-operator] separate prometheus-operator-crds Signed-off-by: nbykov0 <166552198+nbykov0@users.noreply.github.com> --- packages/system/victoria-metrics-operator/Makefile | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/system/victoria-metrics-operator/Makefile b/packages/system/victoria-metrics-operator/Makefile index 0f31d7b7..a78b7b76 100644 --- a/packages/system/victoria-metrics-operator/Makefile +++ b/packages/system/victoria-metrics-operator/Makefile @@ -9,8 +9,3 @@ update: helm repo add vm https://victoriametrics.github.io/helm-charts/ helm repo update vm helm pull vm/victoria-metrics-operator --untar --untardir charts - # Prometheus CRDs - helm repo add prometheus-community https://prometheus-community.github.io/helm-charts - helm repo update prometheus-community - helm pull prometheus-community/prometheus-operator-crds --untar --untardir charts - rm -f -- `find charts/prometheus-operator-crds/charts/crds/templates -maxdepth 1 -mindepth 1 | grep -v 'servicemonitor\|podmonitor\|prometheusrule\|probe'` From 1e2b66131ca843fd238199b06b88d2166d3a6525 Mon Sep 17 00:00:00 2001 From: nbykov0 <166552198+nbykov0@users.noreply.github.com> Date: Wed, 3 Dec 2025 16:34:52 +0300 Subject: [PATCH 21/33] [apps:kubernetes] separate prometheus-operator-crds Signed-off-by: nbykov0 <166552198+nbykov0@users.noreply.github.com> --- .../prometheus-operator-crds.yaml | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 packages/apps/kubernetes/templates/helmreleases/prometheus-operator-crds.yaml diff --git a/packages/apps/kubernetes/templates/helmreleases/prometheus-operator-crds.yaml b/packages/apps/kubernetes/templates/helmreleases/prometheus-operator-crds.yaml new file mode 100644 index 00000000..63972126 --- /dev/null +++ b/packages/apps/kubernetes/templates/helmreleases/prometheus-operator-crds.yaml @@ -0,0 +1,37 @@ +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: {{ .Release.Name }}-prometheus-operator-crds + labels: + cozystack.io/repository: system + cozystack.io/target-cluster-name: {{ .Release.Name }} +spec: + releaseName: prometheus-operator-crds + chart: + spec: + chart: cozy-prometheus-operator-crds + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' + kubeConfig: + secretRef: + name: {{ .Release.Name }}-admin-kubeconfig + key: super-admin.svc + targetNamespace: cozy-victoria-metrics-operator + storageNamespace: cozy-victoria-metrics-operator + interval: 5m + install: + createNamespace: true + remediation: + retries: -1 + upgrade: + remediation: + retries: -1 + dependsOn: + {{- if lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" .Release.Namespace .Release.Name }} + - name: {{ .Release.Name }} + namespace: {{ .Release.Namespace }} + {{- end }} From fe9d334880cc456b6811ffd3d4e72a78daea8f97 Mon Sep 17 00:00:00 2001 From: nbykov0 <166552198+nbykov0@users.noreply.github.com> Date: Wed, 3 Dec 2025 18:00:37 +0300 Subject: [PATCH 22/33] [apps:kubernetes] update dependencies Signed-off-by: nbykov0 <166552198+nbykov0@users.noreply.github.com> --- .../kubernetes/templates/helmreleases/cert-manager-crds.yaml | 2 -- packages/apps/kubernetes/templates/helmreleases/csi.yaml | 2 ++ .../kubernetes/templates/helmreleases/monitoring-agents.yaml | 4 ++++ .../templates/helmreleases/vertical-pod-autoscaler-crds.yaml | 2 -- .../{volumesnapshot_crd.yaml => volumesnapshot-crd.yaml} | 2 -- 5 files changed, 6 insertions(+), 6 deletions(-) rename packages/apps/kubernetes/templates/helmreleases/{volumesnapshot_crd.yaml => volumesnapshot-crd.yaml} (92%) diff --git a/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml b/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml index 3bf7a5d2..73954e12 100644 --- a/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml @@ -45,8 +45,6 @@ spec: - name: {{ .Release.Name }} namespace: {{ .Release.Namespace }} {{- end }} - - name: {{ .Release.Name }}-cilium - namespace: {{ .Release.Namespace }} {{- if .Values.addons.certManager.valuesOverride }} --- apiVersion: v1 diff --git a/packages/apps/kubernetes/templates/helmreleases/csi.yaml b/packages/apps/kubernetes/templates/helmreleases/csi.yaml index 09927e8a..3ecbf1eb 100644 --- a/packages/apps/kubernetes/templates/helmreleases/csi.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/csi.yaml @@ -37,6 +37,8 @@ spec: dependsOn: - name: {{ .Release.Name }}-vsnap-crd namespace: {{ .Release.Namespace }} + - name: {{ .Release.Name }}-cilium + namespace: {{ .Release.Namespace }} {{- if lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" .Release.Namespace .Release.Name }} - name: {{ .Release.Name }} namespace: {{ .Release.Namespace }} diff --git a/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml b/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml index 8f914b08..cf93f233 100644 --- a/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml @@ -44,6 +44,10 @@ spec: namespace: {{ .Release.Namespace }} - name: {{ .Release.Name }}-vertical-pod-autoscaler-crds namespace: {{ .Release.Namespace }} + - name: {{ .Release.Name }}-prometheus-operator-crds + namespace: {{ .Release.Namespace }} + - name: {{ .Release.Name }}-metrics-server + namespace: {{ .Release.Namespace }} values: vmagent: externalLabels: 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..71bdc9ee 100644 --- a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml @@ -37,6 +37,4 @@ spec: - name: {{ .Release.Name }} namespace: {{ .Release.Namespace }} {{- end }} - - name: {{ .Release.Name }}-cilium - namespace: {{ .Release.Namespace }} {{- end }} diff --git a/packages/apps/kubernetes/templates/helmreleases/volumesnapshot_crd.yaml b/packages/apps/kubernetes/templates/helmreleases/volumesnapshot-crd.yaml similarity index 92% rename from packages/apps/kubernetes/templates/helmreleases/volumesnapshot_crd.yaml rename to packages/apps/kubernetes/templates/helmreleases/volumesnapshot-crd.yaml index 97cf06ad..83fa32d1 100644 --- a/packages/apps/kubernetes/templates/helmreleases/volumesnapshot_crd.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/volumesnapshot-crd.yaml @@ -37,5 +37,3 @@ spec: - name: {{ .Release.Name }} namespace: {{ .Release.Namespace }} {{- end }} - - name: {{ .Release.Name }}-cilium - namespace: {{ .Release.Namespace }} From b1a7e9560ef0d2f86ef0b95760323619d5186663 Mon Sep 17 00:00:00 2001 From: nbykov0 <166552198+nbykov0@users.noreply.github.com> Date: Wed, 3 Dec 2025 18:01:23 +0300 Subject: [PATCH 23/33] [apps:kubernetes] dont delete cleanup job on fail Signed-off-by: nbykov0 <166552198+nbykov0@users.noreply.github.com> --- packages/apps/kubernetes/templates/delete.yaml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/apps/kubernetes/templates/delete.yaml b/packages/apps/kubernetes/templates/delete.yaml index ae581226..702ba542 100644 --- a/packages/apps/kubernetes/templates/delete.yaml +++ b/packages/apps/kubernetes/templates/delete.yaml @@ -5,8 +5,8 @@ metadata: annotations: "helm.sh/hook": pre-delete "helm.sh/hook-weight": "10" - "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed - name: {{ .Release.Name }}-cleanup + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation + name: {{ .Release.Name }}-pre-cleanup spec: template: metadata: @@ -65,7 +65,6 @@ spec: echo "Cleanup completed successfully" - --- apiVersion: v1 kind: ServiceAccount @@ -73,7 +72,7 @@ metadata: name: {{ .Release.Name }}-cleanup annotations: helm.sh/hook: pre-delete - helm.sh/hook-delete-policy: before-hook-creation,hook-failed,hook-succeeded + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation,hook-failed helm.sh/hook-weight: "0" --- apiVersion: rbac.authorization.k8s.io/v1 From a7b423934f8b8da8c24339dc07bea5b00acaeb1a Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Tue, 18 Nov 2025 19:30:08 +0300 Subject: [PATCH 24/33] [backups] Implement core backup Plan controller ## What this PR does This patch creates a new backups.cozystack.io API group which includes backup-related resources owned exclusively by Cozystack core. A cronjob-like controller is implemented to create backup jobs that will be handled by appropriate third-party or external controllers. ### Release note ```release-note [backups] Implement the core backup API and an accompanying controller. ``` Signed-off-by: Timofei Larkin --- api/.gitattributes | 1 + api/backups/v1alpha1/DESIGN.md | 421 +++++++++++++++ api/backups/v1alpha1/backup_types.go | 102 ++++ api/backups/v1alpha1/backupjob_types.go | 93 ++++ api/backups/v1alpha1/groupversion_info.go | 53 ++ api/backups/v1alpha1/plan_types.go | 82 +++ api/backups/v1alpha1/restorejob_types.go | 80 +++ api/backups/v1alpha1/zz_generated.deepcopy.go | 478 ++++++++++++++++++ go.mod | 9 +- go.sum | 2 + hack/update-codegen.sh | 16 +- .../backupcontroller/factory/backupjob.go | 28 + internal/backupcontroller/plan_controller.go | 90 ++++ .../definitions/.gitattributes | 1 + .../backups.cozystack.io_backupjobs.yaml | 231 +++++++++ .../backups.cozystack.io_backups.yaml | 234 +++++++++ .../backups.cozystack.io_plans.yaml | 135 +++++ .../backups.cozystack.io_restorejobs.yaml | 168 ++++++ 18 files changed, 2217 insertions(+), 7 deletions(-) create mode 100644 api/.gitattributes create mode 100644 api/backups/v1alpha1/DESIGN.md create mode 100644 api/backups/v1alpha1/backup_types.go create mode 100644 api/backups/v1alpha1/backupjob_types.go create mode 100644 api/backups/v1alpha1/groupversion_info.go create mode 100644 api/backups/v1alpha1/plan_types.go create mode 100644 api/backups/v1alpha1/restorejob_types.go create mode 100644 api/backups/v1alpha1/zz_generated.deepcopy.go create mode 100644 internal/backupcontroller/factory/backupjob.go create mode 100644 internal/backupcontroller/plan_controller.go create mode 100644 packages/system/backup-controller/definitions/.gitattributes create mode 100644 packages/system/backup-controller/definitions/backups.cozystack.io_backupjobs.yaml create mode 100644 packages/system/backup-controller/definitions/backups.cozystack.io_backups.yaml create mode 100644 packages/system/backup-controller/definitions/backups.cozystack.io_plans.yaml create mode 100644 packages/system/backup-controller/definitions/backups.cozystack.io_restorejobs.yaml diff --git a/api/.gitattributes b/api/.gitattributes new file mode 100644 index 00000000..39e882c9 --- /dev/null +++ b/api/.gitattributes @@ -0,0 +1 @@ +zz_generated_deepcopy.go linguist-generated diff --git a/api/backups/v1alpha1/DESIGN.md b/api/backups/v1alpha1/DESIGN.md new file mode 100644 index 00000000..455dab59 --- /dev/null +++ b/api/backups/v1alpha1/DESIGN.md @@ -0,0 +1,421 @@ +# Cozystack Backups – Core API & Contracts (Draft) + +## 1. Overview + +Cozystack’s backup subsystem provides a generic, composable way to back up and restore managed applications: + +* Every **application instance** can have one or more **backup plans**. +* Backups are stored in configurable **storage locations**. +* The mechanics of *how* a backup/restore is performed are delegated to **strategy drivers**, each implementing driver-specific **BackupStrategy** CRDs. + +The core API: + +* Orchestrates **when** backups happen and **where** they’re stored. +* Tracks **what** backups exist and their status. +* Defines contracts with drivers via shared resources (`BackupJob`, `Backup`, `RestoreJob`). + +It does **not** implement the backup logic itself. + +This document covers only the **core** API and its contracts with drivers, not driver implementations. + +--- + +## 2. Goals and non-goals + +### Goals + +* Provide a **stable core API** for: + + * Declaring **backup plans** per application. + * Configuring **storage targets** (S3, in-cluster bucket, etc.). + * Tracking **backup artifacts**. + * Initiating and tracking **restores**. +* Allow multiple **strategy drivers** to plug in, each supporting specific kinds of applications and strategies. +* Let application/product authors implement backup for their kinds by: + + * Creating **Plan** objects referencing a **driver-specific strategy**. + * Not having to write a backup engine themselves. + +### Non-goals + +* Implement backup logic for any specific application or storage backend. +* Define the internal structure of driver-specific strategy CRDs. +* Handle tenant-facing UI/UX (that’s built on top of these APIs). + +--- + +## 3. Architecture + +High-level components: + +* **Core backups controller(s)** (Cozystack-owned): + + * Group: `backups.cozystack.io` + * Own: + + * `Plan` + * `BackupJob` + * `Backup` + * `RestoreJob` + * Responsibilities: + + * Schedule backups based on `Plan`. + * Create `BackupJob` objects when due. + * Provide stable contracts for drivers to: + + * Perform backups and create `Backup`s. + * Perform restores based on `Backup`s. + +* **Strategy drivers** (pluggable, possibly third-party): + + * Their own API groups, e.g. `jobdriver.backups.cozystack.io`. + * Own **strategy CRDs** (e.g. `JobBackupStrategy`). + * Implement controllers that: + + * Watch `BackupJob` / `RestoreJob`. + * Match runs whose `strategyRef` GVK they support. + * Execute backup/restore logic. + * Create and update `Backup` and run statuses. + +Strategy drivers and core communicate entirely via Kubernetes objects; there are no webhook/HTTP calls between them. + +* **Storage drivers** (pluggable, possibly third-party): + + * **TBD** + +--- + +## 4. Core API resources + +### 4.1 Plan + +**Group/Kind** +`backups.cozystack.io/v1alpha1, Kind=Plan` + +**Purpose** +Describe **when**, **how**, and **where** to back up a specific managed application. + +**Key fields (spec)** + +```go +type PlanSpec struct { + // Application to back up. + ApplicationRef corev1.TypedLocalObjectReference `json:"applicationRef"` + + // Where backups should be stored. + StorageRef corev1.TypedLocalObjectReference `json:"storageRef"` + + // Driver-specific BackupStrategy to use. + StrategyRef corev1.TypedLocalObjectReference `json:"strategyRef"` + + // When backups should run. + Schedule PlanSchedule `json:"schedule"` +} +``` + +`PlanSchedule` (initially) supports only cron: + +```go +type PlanScheduleType string + +const ( + PlanScheduleTypeEmpty PlanScheduleType = "" + PlanScheduleTypeCron PlanScheduleType = "cron" +) +``` + +```go +type PlanSchedule struct { + // Type is the schedule type. Currently only "cron" is supported. + // Defaults to "cron". + Type PlanScheduleType `json:"type,omitempty"` + + // Cron expression (required for cron type). + Cron string `json:"cron,omitempty"` +} +``` + +**Plan reconciliation contract** + +Core Plan controller: + +1. **Read schedule** from `spec.schedule` and compute the next fire time. +2. When due: + + * Create a `BackupJob` in the same namespace: + + * `spec.planRef.name = plan.Name` + * `spec.applicationRef = plan.spec.applicationRef` + * `spec.storageRef = plan.spec.storageRef` + * `spec.strategyRef = plan.spec.strategyRef` + * `spec.triggeredBy = "Plan"` + * Set `ownerReferences` so the `BackupJob` is owned by the `Plan`. + +The Plan controller does **not**: + +* Execute backups itself. +* Modify driver resources or `Backup` objects. +* Touch `BackupJob.spec` after creation. + +--- + +### 4.2 Storage + +**API Shape** + +TBD + +**Storage usage** + +* `Plan` and `BackupJob` reference `Storage` via `TypedLocalObjectReference`. +* Drivers read `Storage` to know how/where to store or read artifacts. +* Core treats `Storage` spec as opaque; it does not directly talk to S3 or buckets. + +--- + +### 4.3 BackupJob + +**Group/Kind** +`backups.cozystack.io/v1alpha1, Kind=BackupJob` + +**Purpose** +Represent a single **execution** of a backup operation, typically created when a `Plan` fires or when a user triggers an ad-hoc backup. + +**Key fields (spec)** + +```go +type BackupJobSpec struct { + // Plan that triggered this run, if any. + PlanRef *corev1.LocalObjectReference `json:"planRef,omitempty"` + + // Application to back up. + ApplicationRef corev1.TypedLocalObjectReference `json:"applicationRef"` + + // Storage to use. + StorageRef corev1.TypedLocalObjectReference `json:"storageRef"` + + // Driver-specific BackupStrategy to use. + StrategyRef corev1.TypedLocalObjectReference `json:"strategyRef"` + + // Informational: what triggered this run ("Plan", "Manual", etc.). + TriggeredBy string `json:"triggeredBy,omitempty"` +} +``` + +**Key fields (status)** + +```go +type BackupJobStatus struct { + Phase BackupJobPhase `json:"phase,omitempty"` + BackupRef *corev1.LocalObjectReference `json:"backupRef,omitempty"` + StartedAt *metav1.Time `json:"startedAt,omitempty"` + CompletedAt *metav1.Time `json:"completedAt,omitempty"` + Message string `json:"message,omitempty"` + Conditions []metav1.Condition `json:"conditions,omitempty"` +} +``` + +`BackupJobPhase` is one of: `Pending`, `Running`, `Succeeded`, `Failed`. + +**BackupJob contract with drivers** + +* Core **creates** `BackupJob` and must treat `spec` as immutable afterwards. +* Each driver controller: + + * Watches `BackupJob`. + * Reconciles runs where `spec.strategyRef.apiGroup/kind` matches its **strategy type(s)**. +* Driver responsibilities: + + 1. On first reconcile: + + * Set `status.startedAt` if unset. + * Set `status.phase = Running`. + 2. Resolve inputs: + + * Read `Strategy` (driver-owned CRD), `Storage`, `Application`, optionally `Plan`. + 3. Execute backup logic (implementation-specific). + 4. On success: + + * Create a `Backup` resource (see below). + * Set `status.backupRef` to the created `Backup`. + * Set `status.completedAt`. + * Set `status.phase = Succeeded`. + 5. On failure: + + * Set `status.completedAt`. + * Set `status.phase = Failed`. + * Set `status.message` and conditions. + +Drivers must **not** modify `BackupJob.spec` or delete `BackupJob` themselves. + +--- + +### 4.4 Backup + +**Group/Kind** +`backups.cozystack.io/v1alpha1, Kind=Backup` + +**Purpose** +Represent a single **backup artifact** for a given application, decoupled from a particular run. usable as a stable, listable “thing you can restore from”. + +**Key fields (spec)** + +```go +type BackupSpec struct { + ApplicationRef corev1.TypedLocalObjectReference `json:"applicationRef"` + PlanRef *corev1.LocalObjectReference `json:"planRef,omitempty"` + StorageRef corev1.TypedLocalObjectReference `json:"storageRef"` + StrategyRef corev1.TypedLocalObjectReference `json:"strategyRef"` + TakenAt metav1.Time `json:"takenAt"` + DriverMetadata map[string]string `json:"driverMetadata,omitempty"` +} +``` + +**Key fields (status)** + +```go +type BackupStatus struct { + Phase BackupPhase `json:"phase,omitempty"` // Pending, Ready, Failed, etc. + Artifact *BackupArtifact `json:"artifact,omitempty"` + Conditions []metav1.Condition `json:"conditions,omitempty"` +} +``` + +`BackupArtifact` describes the artifact (URI, size, checksum). + +**Backup contract with drivers** + +* On successful completion of a `BackupJob`, the **driver**: + + * Creates a `Backup` in the same namespace (typically owned by the `BackupJob`). + * Populates `spec` fields with: + + * The application, storage, strategy references. + * `takenAt`. + * Optional `driverMetadata`. + * Sets `status` with: + + * `phase = Ready` (or equivalent when fully usable). + * `artifact` describing the stored object. +* Core: + + * Treats `Backup` spec as mostly immutable and opaque. + * Uses it to: + + * List backups for a given application/plan. + * Anchor `RestoreJob` operations. + * Implement higher-level policies (retention) if needed. + +--- + +### 4.5 RestoreJob + +**Group/Kind** +`backups.cozystack.io/v1alpha1, Kind=RestoreJob` + +**Purpose** +Represent a single **restore operation** from a `Backup`, either back into the same application or into a new target application. + +**Key fields (spec)** + +```go +type RestoreJobSpec struct { + // Backup to restore from. + BackupRef corev1.LocalObjectReference `json:"backupRef"` + + // Target application; if omitted, drivers SHOULD restore into + // backup.spec.applicationRef. + TargetApplicationRef *corev1.TypedLocalObjectReference `json:"targetApplicationRef,omitempty"` +} +``` + +**Key fields (status)** + +```go +type RestoreJobStatus struct { + Phase RestoreJobPhase `json:"phase,omitempty"` // Pending, Running, Succeeded, Failed + StartedAt *metav1.Time `json:"startedAt,omitempty"` + CompletedAt *metav1.Time `json:"completedAt,omitempty"` + Message string `json:"message,omitempty"` + Conditions []metav1.Condition `json:"conditions,omitempty"` +} +``` + +**RestoreJob contract with drivers** + +* RestoreJob is created either manually or by core. +* Driver controller: + + 1. Watches `RestoreJob`. + 2. On reconcile: + + * Fetches the referenced `Backup`. + * Determines effective: + + * **Strategy**: `backup.spec.strategyRef`. + * **Storage**: `backup.spec.storageRef`. + * **Target application**: `spec.targetApplicationRef` or `backup.spec.applicationRef`. + * If effective strategy’s GVK is one of its supported strategy types → driver is responsible. + 3. Behaviour: + + * On first reconcile, set `status.startedAt` and `phase = Running`. + * Resolve `Backup`, `Storage`, `Strategy`, target application. + * Execute restore logic (implementation-specific). + * On success: + + * Set `status.completedAt`. + * Set `status.phase = Succeeded`. + * On failure: + + * Set `status.completedAt`. + * Set `status.phase = Failed`. + * Set `status.message` and conditions. + +Drivers must not modify `RestoreJob.spec` or delete `RestoreJob`. + +--- + +## 5. Strategy drivers (high-level) + +Strategy drivers are separate controllers that: + +* Define their own **strategy CRDs** (e.g. `JobBackupStrategy`) in their own API groups: + + * e.g. `jobdriver.backups.cozystack.io/v1alpha1, Kind=JobBackupStrategy` +* Implement the **BackupJob contract**: + + * Watch `BackupJob`. + * Filter by `spec.strategyRef.apiGroup/kind`. + * Execute backup logic. + * Create/update `Backup`. +* Implement the **RestoreJob contract**: + + * Watch `RestoreJob`. + * Resolve `Backup`, then effective `strategyRef`. + * Filter by effective strategy GVK. + * Execute restore logic. + +The core backups API **does not** dictate: + +* The fields and structure of driver strategy specs. +* How drivers implement backup/restore internally (Jobs, snapshots, native operator CRDs, etc.). + +Drivers are interchangeable as long as they respect: + +* The `BackupJob` and `RestoreJob` contracts. +* The shapes and semantics of `Backup` objects. + +--- + +## 6. Summary + +The Cozystack backups core API: + +* Uses a single group, `backups.cozystack.io`, for all core CRDs. +* Cleanly separates: + + * **When & where** (Plan + Storage) – core-owned. + * **What backup artifacts exist** (Backup) – driver-created but cluster-visible. + * **Execution lifecycle** (BackupJob, RestoreJob) – shared contract boundary. +* Allows multiple strategy drivers to implement backup/restore logic without entangling their implementation with the core API. + diff --git a/api/backups/v1alpha1/backup_types.go b/api/backups/v1alpha1/backup_types.go new file mode 100644 index 00000000..ff6a8612 --- /dev/null +++ b/api/backups/v1alpha1/backup_types.go @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: Apache-2.0 +// Package v1alpha1 defines backups.cozystack.io API types. +// +// Group: backups.cozystack.io +// Version: v1alpha1 +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// BackupPhase represents the lifecycle phase of a Backup. +type BackupPhase string + +const ( + BackupPhaseEmpty BackupPhase = "" + BackupPhasePending BackupPhase = "Pending" + BackupPhaseReady BackupPhase = "Ready" + BackupPhaseFailed BackupPhase = "Failed" +) + +// BackupArtifact describes the stored backup object (tarball, snapshot, etc.). +type BackupArtifact struct { + // URI is a driver-/storage-specific URI pointing to the backup artifact. + // For example: s3://bucket/prefix/file.tar.gz + URI string `json:"uri"` + + // SizeBytes is the size of the artifact in bytes, if known. + // +optional + SizeBytes int64 `json:"sizeBytes,omitempty"` + + // Checksum is the checksum of the artifact, if computed. + // For example: "sha256:". + // +optional + Checksum string `json:"checksum,omitempty"` +} + +// BackupSpec describes an immutable backup artifact produced by a BackupJob. +type BackupSpec struct { + // ApplicationRef refers to the application that was backed up. + ApplicationRef corev1.TypedLocalObjectReference `json:"applicationRef"` + + // PlanRef refers to the Plan that produced this backup, if any. + // For manually triggered backups, this can be omitted. + // +optional + PlanRef *corev1.LocalObjectReference `json:"planRef,omitempty"` + + // StorageRef refers to the Storage object that describes where the backup + // artifact is stored. + StorageRef corev1.TypedLocalObjectReference `json:"storageRef"` + + // StrategyRef refers to the driver-specific BackupStrategy that was used + // to create this backup. This allows the driver to later perform restores. + StrategyRef corev1.TypedLocalObjectReference `json:"strategyRef"` + + // TakenAt is the time at which the backup was taken (as reported by the + // driver). It may differ slightly from metadata.creationTimestamp. + TakenAt metav1.Time `json:"takenAt"` + + // DriverMetadata holds driver-specific, opaque metadata associated with + // this backup (for example snapshot IDs, schema versions, etc.). + // This data is not interpreted by the core backup controllers. + // +optional + DriverMetadata map[string]string `json:"driverMetadata,omitempty"` +} + +// BackupStatus represents the observed state of a Backup. +type BackupStatus struct { + // Phase is a simple, high-level summary of the backup's state. + // Typical values are: Pending, Ready, Failed. + // +optional + Phase BackupPhase `json:"phase,omitempty"` + + // Artifact describes the stored backup object, if available. + // +optional + Artifact *BackupArtifact `json:"artifact,omitempty"` + + // Conditions represents the latest available observations of a Backup's state. + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + +// +kubebuilder:object:root=true + +// Backup represents a single backup artifact for a given application. +type Backup struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec BackupSpec `json:"spec,omitempty"` + Status BackupStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// BackupList contains a list of Backups. +type BackupList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Backup `json:"items"` +} diff --git a/api/backups/v1alpha1/backupjob_types.go b/api/backups/v1alpha1/backupjob_types.go new file mode 100644 index 00000000..56b4ec89 --- /dev/null +++ b/api/backups/v1alpha1/backupjob_types.go @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: Apache-2.0 +// Package v1alpha1 defines backups.cozystack.io API types. +// +// Group: backups.cozystack.io +// Version: v1alpha1 +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// BackupJobPhase represents the lifecycle phase of a BackupJob. +type BackupJobPhase string + +const ( + BackupJobPhaseEmpty BackupJobPhase = "" + BackupJobPhasePending BackupJobPhase = "Pending" + BackupJobPhaseRunning BackupJobPhase = "Running" + BackupJobPhaseSucceeded BackupJobPhase = "Succeeded" + BackupJobPhaseFailed BackupJobPhase = "Failed" +) + +// BackupJobSpec describes the execution of a single backup operation. +type BackupJobSpec struct { + // PlanRef refers to the Plan that requested this backup run. + // For ad-hoc/manual backups, this can be omitted. + // +optional + PlanRef *corev1.LocalObjectReference `json:"planRef,omitempty"` + + // ApplicationRef holds a reference to the managed application whose state + // is being backed up. + ApplicationRef corev1.TypedLocalObjectReference `json:"applicationRef"` + + // StorageRef holds a reference to the Storage object that describes where + // the backup will be stored. + StorageRef corev1.TypedLocalObjectReference `json:"storageRef"` + + // StrategyRef holds a reference to the driver-specific BackupStrategy object + // that describes how the backup should be created. + StrategyRef corev1.TypedLocalObjectReference `json:"strategyRef"` +} + +// BackupJobStatus represents the observed state of a BackupJob. +type BackupJobStatus struct { + // Phase is a high-level summary of the run's state. + // Typical values: Pending, Running, Succeeded, Failed. + // +optional + Phase BackupJobPhase `json:"phase,omitempty"` + + // BackupRef refers to the Backup object created by this run, if any. + // +optional + BackupRef *corev1.LocalObjectReference `json:"backupRef,omitempty"` + + // StartedAt is the time at which the backup run started. + // +optional + StartedAt *metav1.Time `json:"startedAt,omitempty"` + + // CompletedAt is the time at which the backup run completed (successfully + // or otherwise). + // +optional + CompletedAt *metav1.Time `json:"completedAt,omitempty"` + + // Message is a human-readable message indicating details about why the + // backup run is in its current phase, if any. + // +optional + Message string `json:"message,omitempty"` + + // Conditions represents the latest available observations of a BackupJob's state. + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + +// +kubebuilder:object:root=true + +// BackupJob represents a single execution of a backup. +// It is typically created by a Plan controller when a schedule fires. +type BackupJob struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec BackupJobSpec `json:"spec,omitempty"` + Status BackupJobStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// BackupJobList contains a list of BackupJobs. +type BackupJobList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []BackupJob `json:"items"` +} diff --git a/api/backups/v1alpha1/groupversion_info.go b/api/backups/v1alpha1/groupversion_info.go new file mode 100644 index 00000000..a524c86d --- /dev/null +++ b/api/backups/v1alpha1/groupversion_info.go @@ -0,0 +1,53 @@ +/* +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 contains API Schema definitions for the v1alpha1 API group. +// +kubebuilder:object:generate=true +// +groupName=backups.cozystack.io +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var ( + // GroupVersion is group version used to register these objects. + GroupVersion = schema.GroupVersion{Group: "backups.cozystack.io", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme. + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) + +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes( + GroupVersion, + &Plan{}, + &PlanList{}, + &BackupJob{}, + &BackupJobList{}, + &Backup{}, + &BackupList{}, + &RestoreJob{}, + &RestoreJobList{}, + ) + metav1.AddToGroupVersion(scheme, GroupVersion) + return nil +} diff --git a/api/backups/v1alpha1/plan_types.go b/api/backups/v1alpha1/plan_types.go new file mode 100644 index 00000000..e73608aa --- /dev/null +++ b/api/backups/v1alpha1/plan_types.go @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: Apache-2.0 +// Package v1alpha1 defines backups.cozystack.io API types. +// +// Group: backups.cozystack.io +// Version: v1alpha1 +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type PlanScheduleType string + +const ( + PlanScheduleTypeEmpty PlanScheduleType = "" + PlanScheduleTypeCron PlanScheduleType = "cron" +) + +// Condtions +const ( + PlanConditionError = "Error" +) + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status + +// Plan describes the schedule, method and storage location for the +// backup of a given target application. +type Plan struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec PlanSpec `json:"spec,omitempty"` + Status PlanStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// PlanList contains a list of backup Plans. +type PlanList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Plan `json:"items"` +} + +// PlanSpec references the storage, the strategy, the application to be +// backed up and specifies the timetable on which the backups will run. +type PlanSpec struct { + // ApplicationRef holds a reference to the managed application, + // whose state and configuration must be backed up. + ApplicationRef corev1.TypedLocalObjectReference `json:"applicationRef"` + + // StorageRef holds a reference to the Storage object that + // describes the location where the backup will be stored. + StorageRef corev1.TypedLocalObjectReference `json:"storageRef"` + + // StrategyRef holds a reference to the Strategy object that + // describes, how a backup copy is to be created. + StrategyRef corev1.TypedLocalObjectReference `json:"strategyRef"` + + // Schedule specifies when backup copies are created. + Schedule PlanSchedule `json:"schedule"` +} + +// PlanSchedule specifies when backup copies are created. +type PlanSchedule struct { + // Type is the type of schedule specification. Supported values are + // [`cron`]. If omitted, defaults to `cron`. + // +optional + Type PlanScheduleType `json:"type,omitempty"` + + // Cron contains the cron spec for scheduling backups. Must be + // specified if the schedule type is `cron`. Since only `cron` is + // supported, omitting this field is not allowed. + // +optional + Cron string `json:"cron,omitempty"` +} + +type PlanStatus struct { + Conditions []metav1.Condition `json:"conditions,omitempty"` +} diff --git a/api/backups/v1alpha1/restorejob_types.go b/api/backups/v1alpha1/restorejob_types.go new file mode 100644 index 00000000..ddab2ff3 --- /dev/null +++ b/api/backups/v1alpha1/restorejob_types.go @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: Apache-2.0 +// Package v1alpha1 defines backups.cozystack.io API types. +// +// Group: backups.cozystack.io +// Version: v1alpha1 +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// RestoreJobPhase represents the lifecycle phase of a RestoreJob. +type RestoreJobPhase string + +const ( + RestoreJobPhaseEmpty RestoreJobPhase = "" + RestoreJobPhasePending RestoreJobPhase = "Pending" + RestoreJobPhaseRunning RestoreJobPhase = "Running" + RestoreJobPhaseSucceeded RestoreJobPhase = "Succeeded" + RestoreJobPhaseFailed RestoreJobPhase = "Failed" +) + +// RestoreJobSpec describes the execution of a single restore operation. +type RestoreJobSpec struct { + // BackupRef refers to the Backup that should be restored. + BackupRef corev1.LocalObjectReference `json:"backupRef"` + + // TargetApplicationRef refers to the application into which the backup + // should be restored. If omitted, the driver SHOULD restore into the same + // application as referenced by backup.spec.applicationRef. + // +optional + TargetApplicationRef *corev1.TypedLocalObjectReference `json:"targetApplicationRef,omitempty"` +} + +// RestoreJobStatus represents the observed state of a RestoreJob. +type RestoreJobStatus struct { + // Phase is a high-level summary of the run's state. + // Typical values: Pending, Running, Succeeded, Failed. + // +optional + Phase RestoreJobPhase `json:"phase,omitempty"` + + // StartedAt is the time at which the restore run started. + // +optional + StartedAt *metav1.Time `json:"startedAt,omitempty"` + + // CompletedAt is the time at which the restore run completed (successfully + // or otherwise). + // +optional + CompletedAt *metav1.Time `json:"completedAt,omitempty"` + + // Message is a human-readable message indicating details about why the + // restore run is in its current phase, if any. + // +optional + Message string `json:"message,omitempty"` + + // Conditions represents the latest available observations of a RestoreJob's state. + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + +// +kubebuilder:object:root=true + +// RestoreJob represents a single execution of a restore from a Backup. +type RestoreJob struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec RestoreJobSpec `json:"spec,omitempty"` + Status RestoreJobStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// RestoreJobList contains a list of RestoreJobs. +type RestoreJobList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []RestoreJob `json:"items"` +} diff --git a/api/backups/v1alpha1/zz_generated.deepcopy.go b/api/backups/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000..3fd7005c --- /dev/null +++ b/api/backups/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,478 @@ +//go:build !ignore_autogenerated + +/* +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. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Backup) DeepCopyInto(out *Backup) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Backup. +func (in *Backup) DeepCopy() *Backup { + if in == nil { + return nil + } + out := new(Backup) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Backup) 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 *BackupArtifact) DeepCopyInto(out *BackupArtifact) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupArtifact. +func (in *BackupArtifact) DeepCopy() *BackupArtifact { + if in == nil { + return nil + } + out := new(BackupArtifact) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackupJob) DeepCopyInto(out *BackupJob) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupJob. +func (in *BackupJob) DeepCopy() *BackupJob { + if in == nil { + return nil + } + out := new(BackupJob) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BackupJob) 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 *BackupJobList) DeepCopyInto(out *BackupJobList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]BackupJob, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupJobList. +func (in *BackupJobList) DeepCopy() *BackupJobList { + if in == nil { + return nil + } + out := new(BackupJobList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BackupJobList) 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 *BackupJobSpec) DeepCopyInto(out *BackupJobSpec) { + *out = *in + if in.PlanRef != nil { + in, out := &in.PlanRef, &out.PlanRef + *out = new(v1.LocalObjectReference) + **out = **in + } + in.ApplicationRef.DeepCopyInto(&out.ApplicationRef) + in.StorageRef.DeepCopyInto(&out.StorageRef) + in.StrategyRef.DeepCopyInto(&out.StrategyRef) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupJobSpec. +func (in *BackupJobSpec) DeepCopy() *BackupJobSpec { + if in == nil { + return nil + } + out := new(BackupJobSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackupJobStatus) DeepCopyInto(out *BackupJobStatus) { + *out = *in + if in.BackupRef != nil { + in, out := &in.BackupRef, &out.BackupRef + *out = new(v1.LocalObjectReference) + **out = **in + } + if in.StartedAt != nil { + in, out := &in.StartedAt, &out.StartedAt + *out = (*in).DeepCopy() + } + if in.CompletedAt != nil { + in, out := &in.CompletedAt, &out.CompletedAt + *out = (*in).DeepCopy() + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupJobStatus. +func (in *BackupJobStatus) DeepCopy() *BackupJobStatus { + if in == nil { + return nil + } + out := new(BackupJobStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackupList) DeepCopyInto(out *BackupList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Backup, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupList. +func (in *BackupList) DeepCopy() *BackupList { + if in == nil { + return nil + } + out := new(BackupList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BackupList) 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 *BackupSpec) DeepCopyInto(out *BackupSpec) { + *out = *in + in.ApplicationRef.DeepCopyInto(&out.ApplicationRef) + if in.PlanRef != nil { + in, out := &in.PlanRef, &out.PlanRef + *out = new(v1.LocalObjectReference) + **out = **in + } + in.StorageRef.DeepCopyInto(&out.StorageRef) + in.StrategyRef.DeepCopyInto(&out.StrategyRef) + in.TakenAt.DeepCopyInto(&out.TakenAt) + if in.DriverMetadata != nil { + in, out := &in.DriverMetadata, &out.DriverMetadata + *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 BackupSpec. +func (in *BackupSpec) DeepCopy() *BackupSpec { + if in == nil { + return nil + } + out := new(BackupSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackupStatus) DeepCopyInto(out *BackupStatus) { + *out = *in + if in.Artifact != nil { + in, out := &in.Artifact, &out.Artifact + *out = new(BackupArtifact) + **out = **in + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupStatus. +func (in *BackupStatus) DeepCopy() *BackupStatus { + if in == nil { + return nil + } + out := new(BackupStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Plan) DeepCopyInto(out *Plan) { + *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 Plan. +func (in *Plan) DeepCopy() *Plan { + if in == nil { + return nil + } + out := new(Plan) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Plan) 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 *PlanList) DeepCopyInto(out *PlanList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Plan, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlanList. +func (in *PlanList) DeepCopy() *PlanList { + if in == nil { + return nil + } + out := new(PlanList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PlanList) 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 *PlanSchedule) DeepCopyInto(out *PlanSchedule) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlanSchedule. +func (in *PlanSchedule) DeepCopy() *PlanSchedule { + if in == nil { + return nil + } + out := new(PlanSchedule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PlanSpec) DeepCopyInto(out *PlanSpec) { + *out = *in + in.ApplicationRef.DeepCopyInto(&out.ApplicationRef) + in.StorageRef.DeepCopyInto(&out.StorageRef) + in.StrategyRef.DeepCopyInto(&out.StrategyRef) + out.Schedule = in.Schedule +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlanSpec. +func (in *PlanSpec) DeepCopy() *PlanSpec { + if in == nil { + return nil + } + out := new(PlanSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RestoreJob) DeepCopyInto(out *RestoreJob) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RestoreJob. +func (in *RestoreJob) DeepCopy() *RestoreJob { + if in == nil { + return nil + } + out := new(RestoreJob) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RestoreJob) 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 *RestoreJobList) DeepCopyInto(out *RestoreJobList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]RestoreJob, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RestoreJobList. +func (in *RestoreJobList) DeepCopy() *RestoreJobList { + if in == nil { + return nil + } + out := new(RestoreJobList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RestoreJobList) 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 *RestoreJobSpec) DeepCopyInto(out *RestoreJobSpec) { + *out = *in + out.BackupRef = in.BackupRef + if in.TargetApplicationRef != nil { + in, out := &in.TargetApplicationRef, &out.TargetApplicationRef + *out = new(v1.TypedLocalObjectReference) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RestoreJobSpec. +func (in *RestoreJobSpec) DeepCopy() *RestoreJobSpec { + if in == nil { + return nil + } + out := new(RestoreJobSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RestoreJobStatus) DeepCopyInto(out *RestoreJobStatus) { + *out = *in + if in.StartedAt != nil { + in, out := &in.StartedAt, &out.StartedAt + *out = (*in).DeepCopy() + } + if in.CompletedAt != nil { + in, out := &in.CompletedAt, &out.CompletedAt + *out = (*in).DeepCopy() + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RestoreJobStatus. +func (in *RestoreJobStatus) DeepCopy() *RestoreJobStatus { + if in == nil { + return nil + } + out := new(RestoreJobStatus) + in.DeepCopyInto(out) + return out +} diff --git a/go.mod b/go.mod index 041aa96a..ee8d0bf0 100644 --- a/go.mod +++ b/go.mod @@ -6,11 +6,16 @@ go 1.23.0 require ( github.com/fluxcd/helm-controller/api v1.1.0 + github.com/go-logr/logr v1.4.2 + 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/prometheus/client_golang v1.19.1 + github.com/robfig/cron/v3 v3.0.1 github.com/spf13/cobra v1.8.1 github.com/stretchr/testify v1.9.0 + go.uber.org/zap v1.27.0 gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.31.2 k8s.io/apiextensions-apiserver v0.31.2 @@ -44,9 +49,7 @@ require ( 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/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 @@ -74,7 +77,6 @@ require ( 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/procfs v0.15.1 // indirect @@ -94,7 +96,6 @@ require ( go.opentelemetry.io/otel/trace v1.28.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // 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 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/net v0.33.0 // indirect diff --git a/go.sum b/go.sum index a1090f31..d36b86a8 100644 --- a/go.sum +++ b/go.sum @@ -145,6 +145,8 @@ github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= 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/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index e181fc76..0069651e 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -23,6 +23,11 @@ CODEGEN_PKG=${CODEGEN_PKG:-$(cd "${SCRIPT_ROOT}"; ls -d -1 ./vendor/k8s.io/code- API_KNOWN_VIOLATIONS_DIR="${API_KNOWN_VIOLATIONS_DIR:-"${SCRIPT_ROOT}/api/api-rules"}" UPDATE_API_KNOWN_VIOLATIONS="${UPDATE_API_KNOWN_VIOLATIONS:-true}" CONTROLLER_GEN="go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.16.4" +TMPDIR=$(mktemp -d) +COZY_CONTROLLER_CRDDIR=packages/system/cozystack-controller/crds +COZY_RD_CRDDIR=packages/system/cozystack-resource-definition-crd/definition +BACKUPS_CORE_CRDDIR=packages/system/backup-controller/definitions +trap 'rm -rf ${TMPDIR}' EXIT source "${CODEGEN_PKG}/kube_codegen.sh" @@ -53,6 +58,11 @@ kube::codegen::gen_openapi \ "${SCRIPT_ROOT}/pkg/apis" $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 +$CONTROLLER_GEN rbac:roleName=manager-role crd paths="./api/..." output:crd:artifacts:config=${TMPDIR} + +mv ${TMPDIR}/cozystack.io_cozystackresourcedefinitions.yaml \ + ${COZY_RD_CRDDIR}/cozystack.io_cozystackresourcedefinitions.yaml + +mv ${TMPDIR}/backups.cozystack.io*.yaml ${BACKUPS_CORE_CRDDIR}/ + +mv ${TMPDIR}/*.yaml ${COZY_CONTROLLER_CRDDIR}/ diff --git a/internal/backupcontroller/factory/backupjob.go b/internal/backupcontroller/factory/backupjob.go new file mode 100644 index 00000000..722e5d99 --- /dev/null +++ b/internal/backupcontroller/factory/backupjob.go @@ -0,0 +1,28 @@ +package factory + +import ( + "fmt" + "time" + + backupsv1alpha1 "github.com/cozystack/cozystack/api/backups/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func BackupJob(p *backupsv1alpha1.Plan, scheduledFor time.Time) *backupsv1alpha1.BackupJob { + job := &backupsv1alpha1.BackupJob{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-%d", p.Name, scheduledFor.Unix()/60), + Namespace: p.Namespace, + }, + Spec: backupsv1alpha1.BackupJobSpec{ + PlanRef: &corev1.LocalObjectReference{ + Name: p.Name, + }, + ApplicationRef: *p.Spec.ApplicationRef.DeepCopy(), + StorageRef: *p.Spec.StorageRef.DeepCopy(), + StrategyRef: *p.Spec.StrategyRef.DeepCopy(), + }, + } + return job +} diff --git a/internal/backupcontroller/plan_controller.go b/internal/backupcontroller/plan_controller.go new file mode 100644 index 00000000..fca5703b --- /dev/null +++ b/internal/backupcontroller/plan_controller.go @@ -0,0 +1,90 @@ +package backupcontroller + +import ( + "context" + "fmt" + "time" + + cron "github.com/robfig/cron/v3" + 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" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/log" + + backupsv1alpha1 "github.com/cozystack/cozystack/api/backups/v1alpha1" + "github.com/cozystack/cozystack/internal/backupcontroller/factory" +) + +const ( + minRequeueDelay = 30 * time.Second + startingDeadlineSeconds = 300 * time.Second +) + +// PlanReconciler reconciles a Plan object +type PlanReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +func (r *PlanReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := log.FromContext(ctx) + + log.V(2).Info("reconciling") + + p := &backupsv1alpha1.Plan{} + + if err := r.Get(ctx, client.ObjectKey{Namespace: req.Namespace, Name: req.Name}, p); err != nil { + if apierrors.IsNotFound(err) { + log.V(3).Info("Plan not found") + return ctrl.Result{}, nil + } + return ctrl.Result{}, err + } + + tCheck := time.Now().Add(-startingDeadlineSeconds) + sch, err := cron.ParseStandard(p.Spec.Schedule.Cron) + if err != nil { + errWrapped := fmt.Errorf("could not parse cron %s: %w", p.Spec.Schedule.Cron, err) + log.Error(err, "could not parse cron", "cron", p.Spec.Schedule.Cron) + meta.SetStatusCondition(&p.Status.Conditions, metav1.Condition{ + Type: backupsv1alpha1.PlanConditionError, + Status: metav1.ConditionTrue, + Reason: "Failed to parse cron spec", + Message: errWrapped.Error(), + }) + if err := r.Status().Update(ctx, p); err != nil { + return ctrl.Result{}, err + } + return ctrl.Result{}, nil + } + tNext := sch.Next(tCheck) + + if time.Now().Before(tNext) { + return ctrl.Result{RequeueAfter: tNext.Sub(time.Now())}, nil + } + + job := factory.BackupJob(p, tNext) + if err := controllerutil.SetControllerReference(p, job, r.Scheme); err != nil { + return ctrl.Result{}, err + } + + if err := r.Create(ctx, job); err != nil { + if apierrors.IsAlreadyExists(err) { + return ctrl.Result{RequeueAfter: startingDeadlineSeconds}, nil + } + return ctrl.Result{}, err + } + + return ctrl.Result{RequeueAfter: startingDeadlineSeconds}, nil +} + +// SetupWithManager registers our controller with the Manager and sets up watches. +func (r *PlanReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&backupsv1alpha1.Plan{}). + Complete(r) +} diff --git a/packages/system/backup-controller/definitions/.gitattributes b/packages/system/backup-controller/definitions/.gitattributes new file mode 100644 index 00000000..aae64e23 --- /dev/null +++ b/packages/system/backup-controller/definitions/.gitattributes @@ -0,0 +1 @@ +* linguist-generated diff --git a/packages/system/backup-controller/definitions/backups.cozystack.io_backupjobs.yaml b/packages/system/backup-controller/definitions/backups.cozystack.io_backupjobs.yaml new file mode 100644 index 00000000..794d8121 --- /dev/null +++ b/packages/system/backup-controller/definitions/backups.cozystack.io_backupjobs.yaml @@ -0,0 +1,231 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: backupjobs.backups.cozystack.io +spec: + group: backups.cozystack.io + names: + kind: BackupJob + listKind: BackupJobList + plural: backupjobs + singular: backupjob + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + BackupJob represents a single execution of a backup. + It is typically created by a Plan controller when a schedule fires. + 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: BackupJobSpec describes the execution of a single backup + operation. + properties: + applicationRef: + description: |- + ApplicationRef holds a reference to the managed application whose state + is being backed up. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + planRef: + description: |- + PlanRef refers to the Plan that requested this backup run. + For ad-hoc/manual backups, this can be omitted. + 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 + storageRef: + description: |- + StorageRef holds a reference to the Storage object that describes where + the backup will be stored. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + strategyRef: + description: |- + StrategyRef holds a reference to the driver-specific BackupStrategy object + that describes how the backup should be created. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + required: + - applicationRef + - storageRef + - strategyRef + type: object + status: + description: BackupJobStatus represents the observed state of a BackupJob. + properties: + backupRef: + description: BackupRef refers to the Backup object created by this + run, if any. + 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 + completedAt: + description: |- + CompletedAt is the time at which the backup run completed (successfully + or otherwise). + format: date-time + type: string + conditions: + description: Conditions represents the latest available observations + of a BackupJob's state. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + message: + description: |- + Message is a human-readable message indicating details about why the + backup run is in its current phase, if any. + type: string + phase: + description: |- + Phase is a high-level summary of the run's state. + Typical values: Pending, Running, Succeeded, Failed. + type: string + startedAt: + description: StartedAt is the time at which the backup run started. + format: date-time + type: string + type: object + type: object + served: true + storage: true diff --git a/packages/system/backup-controller/definitions/backups.cozystack.io_backups.yaml b/packages/system/backup-controller/definitions/backups.cozystack.io_backups.yaml new file mode 100644 index 00000000..1bae551f --- /dev/null +++ b/packages/system/backup-controller/definitions/backups.cozystack.io_backups.yaml @@ -0,0 +1,234 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: backups.backups.cozystack.io +spec: + group: backups.cozystack.io + names: + kind: Backup + listKind: BackupList + plural: backups + singular: backup + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Backup represents a single backup artifact for a given application. + 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: BackupSpec describes an immutable backup artifact produced + by a BackupJob. + properties: + applicationRef: + description: ApplicationRef refers to the application that was backed + up. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + driverMetadata: + additionalProperties: + type: string + description: |- + DriverMetadata holds driver-specific, opaque metadata associated with + this backup (for example snapshot IDs, schema versions, etc.). + This data is not interpreted by the core backup controllers. + type: object + planRef: + description: |- + PlanRef refers to the Plan that produced this backup, if any. + For manually triggered backups, this can be omitted. + 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 + storageRef: + description: |- + StorageRef refers to the Storage object that describes where the backup + artifact is stored. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + strategyRef: + description: |- + StrategyRef refers to the driver-specific BackupStrategy that was used + to create this backup. This allows the driver to later perform restores. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + takenAt: + description: |- + TakenAt is the time at which the backup was taken (as reported by the + driver). It may differ slightly from metadata.creationTimestamp. + format: date-time + type: string + required: + - applicationRef + - storageRef + - strategyRef + - takenAt + type: object + status: + description: BackupStatus represents the observed state of a Backup. + properties: + artifact: + description: Artifact describes the stored backup object, if available. + properties: + checksum: + description: |- + Checksum is the checksum of the artifact, if computed. + For example: "sha256:". + type: string + sizeBytes: + description: SizeBytes is the size of the artifact in bytes, if + known. + format: int64 + type: integer + uri: + description: |- + URI is a driver-/storage-specific URI pointing to the backup artifact. + For example: s3://bucket/prefix/file.tar.gz + type: string + required: + - uri + type: object + conditions: + description: Conditions represents the latest available observations + of a Backup's state. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + phase: + description: |- + Phase is a simple, high-level summary of the backup's state. + Typical values are: Pending, Ready, Failed. + type: string + type: object + type: object + served: true + storage: true diff --git a/packages/system/backup-controller/definitions/backups.cozystack.io_plans.yaml b/packages/system/backup-controller/definitions/backups.cozystack.io_plans.yaml new file mode 100644 index 00000000..b41d8e45 --- /dev/null +++ b/packages/system/backup-controller/definitions/backups.cozystack.io_plans.yaml @@ -0,0 +1,135 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: plans.backups.cozystack.io +spec: + group: backups.cozystack.io + names: + kind: Plan + listKind: PlanList + plural: plans + singular: plan + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + Plan describes the schedule, method and storage location for the + backup of a given target application. + 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: |- + PlanSpec references the storage, the strategy, the application to be + backed up and specifies the timetable on which the backups will run. + properties: + applicationRef: + description: |- + ApplicationRef holds a reference to the managed application, + whose state and configuration must be backed up. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + schedule: + description: Schedule specifies when backup copies are created. + properties: + cron: + description: |- + Cron contains the cron spec for scheduling backups. Must be + specified if the schedule type is `cron`. Since only `cron` is + supported, omitting this field is not allowed. + type: string + type: + description: |- + Type is the type of schedule specification. Supported values are + [`cron`]. If omitted, defaults to `cron`. + type: string + type: object + storageRef: + description: |- + StorageRef holds a reference to the Storage object that + describes the location where the backup will be stored. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + strategyRef: + description: |- + StrategyRef holds a reference to the Strategy object that + describes, how a backup copy is to be created. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + required: + - applicationRef + - schedule + - storageRef + - strategyRef + type: object + type: object + served: true + storage: true diff --git a/packages/system/backup-controller/definitions/backups.cozystack.io_restorejobs.yaml b/packages/system/backup-controller/definitions/backups.cozystack.io_restorejobs.yaml new file mode 100644 index 00000000..607a69b2 --- /dev/null +++ b/packages/system/backup-controller/definitions/backups.cozystack.io_restorejobs.yaml @@ -0,0 +1,168 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: restorejobs.backups.cozystack.io +spec: + group: backups.cozystack.io + names: + kind: RestoreJob + listKind: RestoreJobList + plural: restorejobs + singular: restorejob + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: RestoreJob represents a single execution of a restore from a + Backup. + 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: RestoreJobSpec describes the execution of a single restore + operation. + properties: + backupRef: + description: BackupRef refers to the Backup that should be restored. + 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 + targetApplicationRef: + description: |- + TargetApplicationRef refers to the application into which the backup + should be restored. If omitted, the driver SHOULD restore into the same + application as referenced by backup.spec.applicationRef. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + required: + - backupRef + type: object + status: + description: RestoreJobStatus represents the observed state of a RestoreJob. + properties: + completedAt: + description: |- + CompletedAt is the time at which the restore run completed (successfully + or otherwise). + format: date-time + type: string + conditions: + description: Conditions represents the latest available observations + of a RestoreJob's state. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + message: + description: |- + Message is a human-readable message indicating details about why the + restore run is in its current phase, if any. + type: string + phase: + description: |- + Phase is a high-level summary of the run's state. + Typical values: Pending, Running, Succeeded, Failed. + type: string + startedAt: + description: StartedAt is the time at which the restore run started. + format: date-time + type: string + type: object + type: object + served: true + storage: true From e50950b7a1711b09e226e8cd96eef847e8c5cb08 Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Wed, 19 Nov 2025 08:42:10 +0300 Subject: [PATCH 25/33] [kubeovn] Bump versions, drop build from Makefile Signed-off-by: Timofei Larkin --- Makefile | 1 - packages/system/kubeovn/Chart.yaml | 2 +- packages/system/kubeovn/Makefile | 2 +- packages/system/kubeovn/values.yaml | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index bb5eb40e..d59a8722 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,6 @@ build: build-deps make -C packages/system/cozystack-controller image make -C packages/system/lineage-controller-webhook image make -C packages/system/cilium image - make -C packages/system/kubeovn image make -C packages/system/kubeovn-webhook image make -C packages/system/kubeovn-plunger image make -C packages/system/dashboard image diff --git a/packages/system/kubeovn/Chart.yaml b/packages/system/kubeovn/Chart.yaml index a49c72e9..d1532794 100644 --- a/packages/system/kubeovn/Chart.yaml +++ b/packages/system/kubeovn/Chart.yaml @@ -1,3 +1,3 @@ apiVersion: v2 name: cozy-kubeovn -version: 0.37.3 # Placeholder, the actual version will be automatically set during the build process +version: 0.39.0 diff --git a/packages/system/kubeovn/Makefile b/packages/system/kubeovn/Makefile index bcf8aa47..a4a0d1ed 100644 --- a/packages/system/kubeovn/Makefile +++ b/packages/system/kubeovn/Makefile @@ -1,4 +1,4 @@ -KUBEOVN_TAG=v0.37.3 +KUBEOVN_TAG=v0.39.0 export NAME=kubeovn export NAMESPACE=cozy-$(NAME) diff --git a/packages/system/kubeovn/values.yaml b/packages/system/kubeovn/values.yaml index 0841fdfd..89f20e7c 100644 --- a/packages/system/kubeovn/values.yaml +++ b/packages/system/kubeovn/values.yaml @@ -65,4 +65,4 @@ global: images: kubeovn: repository: kubeovn - tag: v1.14.11@sha256:1130591435c808bd4c5a543eafce6ff4241f4babeaf85cd32b2119f0780f58db + tag: v1.14.11@sha256:0e3e9db960a9600d58c33c0787cabd0e9bf263930fd8c9fe65417e258c383d01 From da4d6053bb4949f31e67b6d12678f80b57976294 Mon Sep 17 00:00:00 2001 From: Apinant U-suwantim Date: Sun, 9 Nov 2025 20:36:41 +0700 Subject: [PATCH 26/33] fixed: missing component bundle `distro-full` Signed-off-by: Apinant U-suwantim --- packages/core/platform/bundles/distro-full.yaml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/core/platform/bundles/distro-full.yaml b/packages/core/platform/bundles/distro-full.yaml index 3cd0df96..8d4e82b3 100644 --- a/packages/core/platform/bundles/distro-full.yaml +++ b/packages/core/platform/bundles/distro-full.yaml @@ -74,6 +74,18 @@ releases: namespace: cozy-system dependsOn: [cozystack-controller,cilium,cert-manager] +- name: cozystack-resource-definition-crd + releaseName: cozystack-resource-definition-crd + chart: cozystack-resource-definition-crd + namespace: cozy-system + dependsOn: [cilium,cozystack-controller] + +- name: cozystack-resource-definitions + releaseName: cozystack-resource-definitions + chart: cozystack-resource-definitions + namespace: cozy-system + dependsOn: [cilium,cozystack-controller,cozystack-resource-definition-crd] + - name: cert-manager releaseName: cert-manager chart: cozy-cert-manager @@ -84,7 +96,6 @@ releases: releaseName: cert-manager-issuers chart: cozy-cert-manager-issuers namespace: cozy-cert-manager - optional: true dependsOn: [cilium,cert-manager] - name: prometheus-operator-crds @@ -204,7 +215,7 @@ releases: releaseName: snapshot-controller chart: cozy-snapshot-controller namespace: cozy-snapshot-controller - dependsOn: [cilium] + dependsOn: [cilium,cert-manager-issuers] - name: objectstorage-controller releaseName: objectstorage-controller From 0a93972c4f9776e76202280b52671b528bdb05de Mon Sep 17 00:00:00 2001 From: Apinant U-suwantim Date: Mon, 10 Nov 2025 17:25:27 +0700 Subject: [PATCH 27/33] fixed: correct dependsOn distro-full Signed-off-by: Apinant U-suwantim --- packages/core/platform/bundles/distro-full.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/platform/bundles/distro-full.yaml b/packages/core/platform/bundles/distro-full.yaml index 8d4e82b3..107cbb23 100644 --- a/packages/core/platform/bundles/distro-full.yaml +++ b/packages/core/platform/bundles/distro-full.yaml @@ -78,7 +78,7 @@ releases: releaseName: cozystack-resource-definition-crd chart: cozystack-resource-definition-crd namespace: cozy-system - dependsOn: [cilium,cozystack-controller] + dependsOn: [cilium] - name: cozystack-resource-definitions releaseName: cozystack-resource-definitions From 58dd1f5881d563af67cf4791f837f0c8467e7db1 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Sat, 6 Dec 2025 19:56:46 +0100 Subject: [PATCH 28/33] [linstor] Update piraeus-operator v2.10.2 Signed-off-by: Andrei Kvapil --- .../charts/piraeus/Chart.yaml | 4 +-- .../charts/piraeus/templates/config.yaml | 8 ++--- .../charts/piraeus/templates/crds.yaml | 35 +++++++++++++++++++ 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/packages/system/piraeus-operator/charts/piraeus/Chart.yaml b/packages/system/piraeus-operator/charts/piraeus/Chart.yaml index 38bd15db..777722f3 100644 --- a/packages/system/piraeus-operator/charts/piraeus/Chart.yaml +++ b/packages/system/piraeus-operator/charts/piraeus/Chart.yaml @@ -3,8 +3,8 @@ name: piraeus description: | The Piraeus Operator manages software defined storage clusters using LINSTOR in Kubernetes. type: application -version: 2.10.1 -appVersion: "v2.10.1" +version: 2.10.2 +appVersion: "v2.10.2" maintainers: - name: Piraeus Datastore url: https://piraeus.io diff --git a/packages/system/piraeus-operator/charts/piraeus/templates/config.yaml b/packages/system/piraeus-operator/charts/piraeus/templates/config.yaml index a57dffd3..2e6963f0 100644 --- a/packages/system/piraeus-operator/charts/piraeus/templates/config.yaml +++ b/packages/system/piraeus-operator/charts/piraeus/templates/config.yaml @@ -23,10 +23,10 @@ data: tag: v1.32.3 image: piraeus-server linstor-csi: - tag: v1.10.2 + tag: v1.10.3 image: piraeus-csi nfs-server: - tag: v1.10.2 + tag: v1.10.3 image: piraeus-csi-nfs-server drbd-reactor: tag: v1.10.0 @@ -44,7 +44,7 @@ data: tag: v1.3.0 image: linstor-affinity-controller drbd-module-loader: - tag: v9.2.15 + tag: v9.2.16 # The special "match" attribute is used to select an image based on the node's reported OS. # The operator will first check the k8s node's ".status.nodeInfo.osImage" field, and compare it against the list # here. If one matches, that specific image name will be used instead of the fallback image. @@ -99,7 +99,7 @@ data: tag: v2.17.0 image: livenessprobe csi-provisioner: - tag: v6.0.0 + tag: v6.1.0 image: csi-provisioner csi-snapshotter: tag: v8.4.0 diff --git a/packages/system/piraeus-operator/charts/piraeus/templates/crds.yaml b/packages/system/piraeus-operator/charts/piraeus/templates/crds.yaml index 1821cb61..5bd9212c 100644 --- a/packages/system/piraeus-operator/charts/piraeus/templates/crds.yaml +++ b/packages/system/piraeus-operator/charts/piraeus/templates/crds.yaml @@ -993,6 +993,24 @@ spec: - Retain - Delete type: string + evacuationStrategy: + description: EvacuationStrategy configures the evacuation of volumes + from a Satellite when DeletionPolicy "Evacuate" is used. + nullable: true + properties: + attachedVolumeReattachTimeout: + default: 5m + description: |- + AttachedVolumeReattachTimeout configures how long evacuation waits for attached volumes to reattach on + different nodes. Setting this to 0 disable this evacuation step. + type: string + unattachedVolumeAttachTimeout: + default: 5m + description: |- + UnattachedVolumeAttachTimeout configures how long evacuation waits for unattached volumes to attach on + different nodes. Setting this to 0 disable this evacuation step. + type: string + type: object internalTLS: description: |- InternalTLS configures secure communication for the LINSTOR Satellite. @@ -1683,6 +1701,23 @@ spec: - Retain - Delete type: string + evacuationStrategy: + description: EvacuationStrategy configures the evacuation of volumes + from a Satellite when DeletionPolicy "Evacuate" is used. + properties: + attachedVolumeReattachTimeout: + default: 5m + description: |- + AttachedVolumeReattachTimeout configures how long evacuation waits for attached volumes to reattach on + different nodes. Setting this to 0 disable this evacuation step. + type: string + unattachedVolumeAttachTimeout: + default: 5m + description: |- + UnattachedVolumeAttachTimeout configures how long evacuation waits for unattached volumes to attach on + different nodes. Setting this to 0 disable this evacuation step. + type: string + type: object internalTLS: description: |- InternalTLS configures secure communication for the LINSTOR Satellite. From 892855276b7fc26783ef87ca4117f436d222ee45 Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Thu, 4 Dec 2025 19:01:11 +0300 Subject: [PATCH 29/33] [backups] Build and deploy backup controller ## What this PR does This patch adds compilation and docker build steps for the backup controller as well as adding a Helm chart to deploy it as part of the PaaS bundles. ### Release note ```release-note [backups] Build and deploy backup controller ``` Signed-off-by: Timofei Larkin --- Makefile | 1 + cmd/backup-controller/main.go | 174 ++++++++++++++++++ internal/backupcontroller/plan_controller.go | 14 ++ packages/core/platform/bundles/paas-full.yaml | 6 + .../core/platform/bundles/paas-hosted.yaml | 5 + packages/system/backup-controller/Chart.yaml | 3 + packages/system/backup-controller/Makefile | 18 ++ .../images/backup-controller/Dockerfile | 23 +++ .../backup-controller/templates/crds.yaml | 4 + .../templates/deployment.yaml | 57 ++++++ .../templates/rbac-bind.yaml | 12 ++ .../backup-controller/templates/rbac.yaml | 11 ++ .../backup-controller/templates/sa.yaml | 4 + packages/system/backup-controller/values.yaml | 14 ++ 14 files changed, 346 insertions(+) create mode 100644 cmd/backup-controller/main.go create mode 100644 packages/system/backup-controller/Chart.yaml create mode 100644 packages/system/backup-controller/Makefile create mode 100644 packages/system/backup-controller/images/backup-controller/Dockerfile create mode 100644 packages/system/backup-controller/templates/crds.yaml create mode 100644 packages/system/backup-controller/templates/deployment.yaml create mode 100644 packages/system/backup-controller/templates/rbac-bind.yaml create mode 100644 packages/system/backup-controller/templates/rbac.yaml create mode 100644 packages/system/backup-controller/templates/sa.yaml create mode 100644 packages/system/backup-controller/values.yaml diff --git a/Makefile b/Makefile index 2038ff9f..182db8af 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,7 @@ build: build-deps make -C packages/extra/monitoring image make -C packages/system/cozystack-api image make -C packages/system/cozystack-controller image + make -C packages/system/backup-controller image make -C packages/system/lineage-controller-webhook image make -C packages/system/cilium image make -C packages/system/kubeovn image diff --git a/cmd/backup-controller/main.go b/cmd/backup-controller/main.go new file mode 100644 index 00000000..d8436659 --- /dev/null +++ b/cmd/backup-controller/main.go @@ -0,0 +1,174 @@ +/* +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 main + +import ( + "crypto/tls" + "flag" + "os" + + // 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" + + "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/healthz" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/metrics/filters" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "sigs.k8s.io/controller-runtime/pkg/webhook" + + backupsv1alpha1 "github.com/cozystack/cozystack/api/backups/v1alpha1" + "github.com/cozystack/cozystack/internal/backupcontroller" + // +kubebuilder:scaffold:imports +) + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + + utilruntime.Must(backupsv1alpha1.AddToScheme(scheme)) + // +kubebuilder:scaffold:scheme +} + +func main() { + var metricsAddr string + var enableLeaderElection bool + var probeAddr string + var secureMetrics bool + var enableHTTP2 bool + var tlsOpts []func(*tls.Config) + flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+ + "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.") + 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", true, + "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") + opts := zap.Options{ + Development: false, + } + opts.BindFlags(flag.CommandLine) + flag.Parse() + + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + + // if the enable-http2 flag is false (the default), http/2 should be disabled + // due to its vulnerabilities. More specifically, disabling http/2 will + // prevent from being vulnerable to the HTTP/2 Stream Cancellation and + // Rapid Reset CVEs. For more information see: + // - https://github.com/advisories/GHSA-qppj-fm5r-hxr3 + // - https://github.com/advisories/GHSA-4374-p667-p6c8 + disableHTTP2 := func(c *tls.Config) { + setupLog.Info("disabling http/2") + c.NextProtos = []string{"http/1.1"} + } + + if !enableHTTP2 { + tlsOpts = append(tlsOpts, disableHTTP2) + } + + webhookServer := webhook.NewServer(webhook.Options{ + TLSOpts: tlsOpts, + }) + + // Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server. + // More info: + // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/metrics/server + // - https://book.kubebuilder.io/reference/metrics.html + metricsServerOptions := metricsserver.Options{ + BindAddress: metricsAddr, + SecureServing: secureMetrics, + TLSOpts: tlsOpts, + } + + if secureMetrics { + // FilterProvider is used to protect the metrics endpoint with authn/authz. + // These configurations ensure that only authorized users and service accounts + // can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info: + // https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/metrics/filters#WithAuthenticationAndAuthorization + metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization + + // TODO(user): If CertDir, CertName, and KeyName are not specified, controller-runtime will automatically + // generate self-signed certificates for the metrics server. While convenient for development and testing, + // this setup is not recommended for production. + } + + // Configure rate limiting for the Kubernetes client + config := ctrl.GetConfigOrDie() + config.QPS = 50.0 // Increased from default 5.0 + config.Burst = 100 // Increased from default 10 + + mgr, err := ctrl.NewManager(config, ctrl.Options{ + Scheme: scheme, + Metrics: metricsServerOptions, + WebhookServer: webhookServer, + HealthProbeBindAddress: probeAddr, + LeaderElection: enableLeaderElection, + LeaderElectionID: "core.backups.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, this setting is unsafe. 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) + } + + if err = (&backupcontroller.PlanReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Plan") + 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) + } + + setupLog.Info("starting manager") + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + setupLog.Error(err, "problem running manager") + os.Exit(1) + } +} diff --git a/internal/backupcontroller/plan_controller.go b/internal/backupcontroller/plan_controller.go index fca5703b..046fdce4 100644 --- a/internal/backupcontroller/plan_controller.go +++ b/internal/backupcontroller/plan_controller.go @@ -61,6 +61,20 @@ func (r *PlanReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl. } return ctrl.Result{}, nil } + + // Clear error condition if cron parsing succeeds + if condition := meta.FindStatusCondition(p.Status.Conditions, backupsv1alpha1.PlanConditionError); condition != nil && condition.Status == metav1.ConditionTrue { + meta.SetStatusCondition(&p.Status.Conditions, metav1.Condition{ + Type: backupsv1alpha1.PlanConditionError, + Status: metav1.ConditionFalse, + Reason: "Cron spec is valid", + Message: "The cron schedule has been successfully parsed", + }) + if err := r.Status().Update(ctx, p); err != nil { + return ctrl.Result{}, err + } + } + tNext := sch.Next(tCheck) if time.Now().Before(tNext) { diff --git a/packages/core/platform/bundles/paas-full.yaml b/packages/core/platform/bundles/paas-full.yaml index 4382bd62..1c83c49c 100644 --- a/packages/core/platform/bundles/paas-full.yaml +++ b/packages/core/platform/bundles/paas-full.yaml @@ -112,6 +112,12 @@ releases: disableTelemetry: true {{- end }} +- name: backup-controller + releaseName: backup-controller + chart: cozy-backup-controller + namespace: cozy-backup-controller + dependsOn: [cilium,kubeovn] + - name: lineage-controller-webhook releaseName: lineage-controller-webhook chart: cozy-lineage-controller-webhook diff --git a/packages/core/platform/bundles/paas-hosted.yaml b/packages/core/platform/bundles/paas-hosted.yaml index 560578c7..c85bcb7b 100644 --- a/packages/core/platform/bundles/paas-hosted.yaml +++ b/packages/core/platform/bundles/paas-hosted.yaml @@ -56,6 +56,11 @@ releases: disableTelemetry: true {{- end }} +- name: backup-controller + releaseName: backup-controller + chart: cozy-backup-controller + namespace: cozy-backup-controller + - name: lineage-controller-webhook releaseName: lineage-controller-webhook chart: cozy-lineage-controller-webhook diff --git a/packages/system/backup-controller/Chart.yaml b/packages/system/backup-controller/Chart.yaml new file mode 100644 index 00000000..fd135712 --- /dev/null +++ b/packages/system/backup-controller/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-backup-controller +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/backup-controller/Makefile b/packages/system/backup-controller/Makefile new file mode 100644 index 00000000..56d58f20 --- /dev/null +++ b/packages/system/backup-controller/Makefile @@ -0,0 +1,18 @@ +NAME=backup-controller +NAMESPACE=cozy-backup-controller + +include ../../../scripts/common-envs.mk +include ../../../scripts/package.mk + +image: image-backup-controller + +image-backup-controller: + docker buildx build -f images/backup-controller/Dockerfile ../../.. \ + --tag $(REGISTRY)/backup-controller:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/backup-controller:latest \ + --cache-to type=inline \ + --metadata-file images/backup-controller.json \ + $(BUILDX_ARGS) + IMAGE="$(REGISTRY)/backup-controller:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/backup-controller.json -o json -r)" \ + yq -i '.backupController.image = strenv(IMAGE)' values.yaml + rm -f images/backup-controller.json diff --git a/packages/system/backup-controller/images/backup-controller/Dockerfile b/packages/system/backup-controller/images/backup-controller/Dockerfile new file mode 100644 index 00000000..cdf53c7b --- /dev/null +++ b/packages/system/backup-controller/images/backup-controller/Dockerfile @@ -0,0 +1,23 @@ +FROM golang:1.24-alpine AS builder + +ARG TARGETOS +ARG TARGETARCH + +WORKDIR /workspace + +COPY go.mod go.sum ./ +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go mod download + +COPY api api/ +COPY pkg pkg/ +COPY cmd cmd/ +COPY internal internal/ + +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -ldflags="-extldflags=-static" -o /backup-controller cmd/backup-controller/main.go + +FROM scratch + +COPY --from=builder /backup-controller /backup-controller +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt + +ENTRYPOINT ["/backup-controller"] diff --git a/packages/system/backup-controller/templates/crds.yaml b/packages/system/backup-controller/templates/crds.yaml new file mode 100644 index 00000000..2cf3183b --- /dev/null +++ b/packages/system/backup-controller/templates/crds.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "definitions/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/backup-controller/templates/deployment.yaml b/packages/system/backup-controller/templates/deployment.yaml new file mode 100644 index 00000000..a8c3d07e --- /dev/null +++ b/packages/system/backup-controller/templates/deployment.yaml @@ -0,0 +1,57 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: backup-controller + labels: + app: backup-controller +spec: + replicas: {{ .Values.backupController.replicas }} + selector: + matchLabels: + app: backup-controller + template: + metadata: + labels: + app: backup-controller + spec: + tolerations: + - key: "node-role.kubernetes.io/control-plane" + operator: "Exists" + effect: "NoSchedule" + - key: "node-role.kubernetes.io/master" + operator: "Exists" + effect: "NoSchedule" + serviceAccountName: backup-controller + containers: + - name: backup-controller + image: "{{ .Values.backupController.image }}" + args: + - --leader-elect + {{- if .Values.backupController.metrics.enable }} + - --metrics-bind-address={{ .Values.backupController.metrics.bindAddress }} + {{- end }} + {{- if .Values.backupController.debug }} + - --zap-log-level=debug + {{- else }} + - --zap-log-level=info + {{- end }} + ports: + - name: metrics + containerPort: {{ split ":" .Values.backupController.metrics.bindAddress | mustLast }} + - name: health + containerPort: 8081 + readinessProbe: + httpGet: + path: /readyz + port: health + initialDelaySeconds: 5 + periodSeconds: 10 + livenessProbe: + httpGet: + path: /healthz + port: health + initialDelaySeconds: 15 + periodSeconds: 20 + {{- with .Values.backupController.resources }} + resources: {{- . | toYaml | nindent 10 }} + {{- end }} diff --git a/packages/system/backup-controller/templates/rbac-bind.yaml b/packages/system/backup-controller/templates/rbac-bind.yaml new file mode 100644 index 00000000..cbe9b5b8 --- /dev/null +++ b/packages/system/backup-controller/templates/rbac-bind.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: backups.cozystack.io:core-controller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: backups.cozystack.io:core-controller +subjects: +- kind: ServiceAccount + name: backup-controller + namespace: {{ .Release.Namespace }} diff --git a/packages/system/backup-controller/templates/rbac.yaml b/packages/system/backup-controller/templates/rbac.yaml new file mode 100644 index 00000000..71c4af69 --- /dev/null +++ b/packages/system/backup-controller/templates/rbac.yaml @@ -0,0 +1,11 @@ +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: backups.cozystack.io:core-controller +rules: +- apiGroups: ["backups.cozystack.io"] + resources: ["plans"] + verbs: ["get", "list", "watch"] +- apiGroups: ["backups.cozystack.io"] + resources: ["backupjobs"] + verbs: ["create", "get", "list", "watch"] diff --git a/packages/system/backup-controller/templates/sa.yaml b/packages/system/backup-controller/templates/sa.yaml new file mode 100644 index 00000000..4a180dd2 --- /dev/null +++ b/packages/system/backup-controller/templates/sa.yaml @@ -0,0 +1,4 @@ +kind: ServiceAccount +apiVersion: v1 +metadata: + name: backup-controller diff --git a/packages/system/backup-controller/values.yaml b/packages/system/backup-controller/values.yaml new file mode 100644 index 00000000..557c201a --- /dev/null +++ b/packages/system/backup-controller/values.yaml @@ -0,0 +1,14 @@ +backupController: + image: "" + replicas: 2 + debug: false + metrics: + enabled: true + bindAddress: ":8443" + resources: + requests: + cpu: 10m + memory: 64Mi + limits: + cpu: 500m + memory: 128Mi From 578a810413c1521ff3f0e0b70c3da80ed31d851b Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 8 Dec 2025 23:27:24 +0100 Subject: [PATCH 30/33] [dashboard] Fix CustomFormsOverride schema to nest properties under spec.properties Signed-off-by: Andrei Kvapil --- .../dashboard/customformsoverride.go | 20 +++- .../dashboard/customformsoverride_test.go | 94 +++++++++++-------- 2 files changed, 74 insertions(+), 40 deletions(-) diff --git a/internal/controller/dashboard/customformsoverride.go b/internal/controller/dashboard/customformsoverride.go index f88202bc..2b0daa08 100644 --- a/internal/controller/dashboard/customformsoverride.go +++ b/internal/controller/dashboard/customformsoverride.go @@ -105,8 +105,26 @@ func buildMultilineStringSchema(openAPISchema string) (map[string]any, error) { "properties": map[string]any{}, } + // Check if there's a spec property + specProp, ok := props["spec"].(map[string]any) + if !ok { + return map[string]any{}, nil + } + + specProps, ok := specProp["properties"].(map[string]any) + if !ok { + return map[string]any{}, nil + } + + // Create spec.properties structure in schema + schemaProps := schema["properties"].(map[string]any) + specSchema := map[string]any{ + "properties": map[string]any{}, + } + schemaProps["spec"] = specSchema + // Process spec properties recursively - processSpecProperties(props, schema["properties"].(map[string]any)) + processSpecProperties(specProps, specSchema["properties"].(map[string]any)) return schema, nil } diff --git a/internal/controller/dashboard/customformsoverride_test.go b/internal/controller/dashboard/customformsoverride_test.go index 2766bf17..9f7babe9 100644 --- a/internal/controller/dashboard/customformsoverride_test.go +++ b/internal/controller/dashboard/customformsoverride_test.go @@ -9,41 +9,46 @@ func TestBuildMultilineStringSchema(t *testing.T) { // Test OpenAPI schema with various field types openAPISchema := `{ "properties": { - "simpleString": { - "type": "string", - "description": "A simple string field" - }, - "stringWithEnum": { - "type": "string", - "enum": ["option1", "option2"], - "description": "String with enum should be skipped" - }, - "numberField": { - "type": "number", - "description": "Number field should be skipped" - }, - "nestedObject": { + "spec": { "type": "object", "properties": { - "nestedString": { + "simpleString": { "type": "string", - "description": "Nested string should get multilineString" + "description": "A simple string field" }, - "nestedStringWithEnum": { + "stringWithEnum": { "type": "string", - "enum": ["a", "b"], - "description": "Nested string with enum should be skipped" - } - } - }, - "arrayOfObjects": { - "type": "array", - "items": { - "type": "object", - "properties": { - "itemString": { - "type": "string", - "description": "String in array item" + "enum": ["option1", "option2"], + "description": "String with enum should be skipped" + }, + "numberField": { + "type": "number", + "description": "Number field should be skipped" + }, + "nestedObject": { + "type": "object", + "properties": { + "nestedString": { + "type": "string", + "description": "Nested string should get multilineString" + }, + "nestedStringWithEnum": { + "type": "string", + "enum": ["a", "b"], + "description": "Nested string with enum should be skipped" + } + } + }, + "arrayOfObjects": { + "type": "array", + "items": { + "type": "object", + "properties": { + "itemString": { + "type": "string", + "description": "String in array item" + } + } } } } @@ -70,33 +75,44 @@ func TestBuildMultilineStringSchema(t *testing.T) { t.Fatal("schema.properties is not a map") } - // Check simpleString - simpleString, ok := props["simpleString"].(map[string]any) + // Check spec property exists + spec, ok := props["spec"].(map[string]any) if !ok { - t.Fatal("simpleString not found in properties") + t.Fatal("spec not found in properties") + } + + specProps, ok := spec["properties"].(map[string]any) + if !ok { + t.Fatal("spec.properties is not a map") + } + + // Check simpleString + simpleString, ok := specProps["simpleString"].(map[string]any) + if !ok { + t.Fatal("simpleString not found in spec.properties") } if simpleString["type"] != "multilineString" { t.Errorf("simpleString should have type multilineString, got %v", simpleString["type"]) } // Check stringWithEnum should not be present (or should not have multilineString) - if stringWithEnum, ok := props["stringWithEnum"].(map[string]any); ok { + if stringWithEnum, ok := specProps["stringWithEnum"].(map[string]any); ok { if stringWithEnum["type"] == "multilineString" { t.Error("stringWithEnum should not have multilineString type") } } // Check numberField should not be present - if numberField, ok := props["numberField"].(map[string]any); ok { + if numberField, ok := specProps["numberField"].(map[string]any); ok { if numberField["type"] != nil { t.Error("numberField should not have any type override") } } // Check nested object - nestedObject, ok := props["nestedObject"].(map[string]any) + nestedObject, ok := specProps["nestedObject"].(map[string]any) if !ok { - t.Fatal("nestedObject not found in properties") + t.Fatal("nestedObject not found in spec.properties") } nestedProps, ok := nestedObject["properties"].(map[string]any) if !ok { @@ -113,9 +129,9 @@ func TestBuildMultilineStringSchema(t *testing.T) { } // Check array of objects - arrayOfObjects, ok := props["arrayOfObjects"].(map[string]any) + arrayOfObjects, ok := specProps["arrayOfObjects"].(map[string]any) if !ok { - t.Fatal("arrayOfObjects not found in properties") + t.Fatal("arrayOfObjects not found in spec.properties") } items, ok := arrayOfObjects["items"].(map[string]any) if !ok { From 650e5290ea8fe88afd0c42157949b369be8a47d8 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 9 Dec 2025 13:45:10 +0100 Subject: [PATCH 31/33] [ci] Improve backport workflow with merge_commits skip and conflict resolution Signed-off-by: Andrei Kvapil --- .github/workflows/backport.yaml | 102 ++++++++++++++++++++++++++++---- 1 file changed, 89 insertions(+), 13 deletions(-) diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index 10968e38..5a1ca990 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -2,7 +2,7 @@ name: Automatic Backport on: pull_request_target: - types: [closed] # fires when PR is closed (merged) + types: [closed, labeled] # fires when PR is closed (merged) or labeled concurrency: group: backport-${{ github.workflow }}-${{ github.event.pull_request.number }} @@ -13,22 +13,46 @@ permissions: pull-requests: write jobs: - backport: + # Determine which backports are needed + prepare: if: | github.event.pull_request.merged == true && - contains(github.event.pull_request.labels.*.name, 'backport') + ( + contains(github.event.pull_request.labels.*.name, 'backport') || + contains(github.event.pull_request.labels.*.name, 'backport-previous') || + (github.event.action == 'labeled' && (github.event.label.name == 'backport' || github.event.label.name == 'backport-previous')) + ) runs-on: [self-hosted] - + outputs: + backport_current: ${{ steps.labels.outputs.backport }} + backport_previous: ${{ steps.labels.outputs.backport_previous }} + current_branch: ${{ steps.branches.outputs.current_branch }} + previous_branch: ${{ steps.branches.outputs.previous_branch }} steps: - # 1. Decide which maintenance branch should receive the back‑port - - name: Determine target maintenance branch - id: target + - name: Check which labels are present + id: labels uses: actions/github-script@v7 with: script: | - let rel; + const pr = context.payload.pull_request; + const labels = pr.labels.map(l => l.name); + const isBackport = labels.includes('backport'); + const isBackportPrevious = labels.includes('backport-previous'); + + core.setOutput('backport', isBackport ? 'true' : 'false'); + core.setOutput('backport_previous', isBackportPrevious ? 'true' : 'false'); + + console.log(`backport label: ${isBackport}, backport-previous label: ${isBackportPrevious}`); + + - name: Determine target branches + id: branches + uses: actions/github-script@v7 + with: + script: | + // Get latest release + let latestRelease; try { - rel = await github.rest.repos.getLatestRelease({ + latestRelease = await github.rest.repos.getLatestRelease({ owner: context.repo.owner, repo: context.repo.repo }); @@ -36,18 +60,70 @@ jobs: core.setFailed('No existing releases found; cannot determine backport target.'); return; } - const [maj, min] = rel.data.tag_name.replace(/^v/, '').split('.'); - const branch = `release-${maj}.${min}`; - core.setOutput('branch', branch); - console.log(`Latest release ${rel.data.tag_name}; backporting to ${branch}`); + + const [maj, min] = latestRelease.data.tag_name.replace(/^v/, '').split('.'); + const currentBranch = `release-${maj}.${min}`; + const prevMin = parseInt(min) - 1; + const previousBranch = prevMin >= 0 ? `release-${maj}.${prevMin}` : ''; + + core.setOutput('current_branch', currentBranch); + core.setOutput('previous_branch', previousBranch); + + console.log(`Current branch: ${currentBranch}, Previous branch: ${previousBranch || 'N/A'}`); + + // Verify previous branch exists if we need it + if (previousBranch && '${{ steps.labels.outputs.backport_previous }}' === 'true') { + try { + await github.rest.repos.getBranch({ + owner: context.repo.owner, + repo: context.repo.repo, + branch: previousBranch + }); + console.log(`Previous branch ${previousBranch} exists`); + } catch (e) { + core.setFailed(`Previous branch ${previousBranch} does not exist.`); + return; + } + } + + backport: + needs: prepare + if: | + github.event.pull_request.merged == true && + (needs.prepare.outputs.backport_current == 'true' || needs.prepare.outputs.backport_previous == 'true') + runs-on: [self-hosted] + strategy: + matrix: + backport_type: [current, previous] + steps: + # 1. Determine target branch based on matrix + - name: Set target branch + id: target + if: | + (matrix.backport_type == 'current' && needs.prepare.outputs.backport_current == 'true') || + (matrix.backport_type == 'previous' && needs.prepare.outputs.backport_previous == 'true') + run: | + if [ "${{ matrix.backport_type }}" == "current" ]; then + echo "branch=${{ needs.prepare.outputs.current_branch }}" >> $GITHUB_OUTPUT + echo "Target branch: ${{ needs.prepare.outputs.current_branch }}" + else + echo "branch=${{ needs.prepare.outputs.previous_branch }}" >> $GITHUB_OUTPUT + echo "Target branch: ${{ needs.prepare.outputs.previous_branch }}" + fi + # 2. Checkout (required by backport‑action) - name: Checkout repository + if: steps.target.outcome == 'success' uses: actions/checkout@v4 # 3. Create the back‑port pull request - name: Create back‑port PR + id: backport + if: steps.target.outcome == 'success' uses: korthout/backport-action@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} label_pattern: '' # don't read labels for targets target_branches: ${{ steps.target.outputs.branch }} + merge_commits: skip + conflict_resolution: draft_commit_conflicts From d079dd47319620bd5c506aabdc62e2916272a59c Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 9 Dec 2025 14:33:03 +0100 Subject: [PATCH 32/33] [ci] Update korthout/backport-action@v3.2.1 Signed-off-by: Andrei Kvapil --- .github/workflows/backport.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index 5a1ca990..ed427827 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -120,7 +120,7 @@ jobs: - name: Create back‑port PR id: backport if: steps.target.outcome == 'success' - uses: korthout/backport-action@v3 + uses: korthout/backport-action@v3.2.1 with: github_token: ${{ secrets.GITHUB_TOKEN }} label_pattern: '' # don't read labels for targets From 0bab8950266b30476824feb1ef72b91007f5e8ff Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 5 Dec 2025 17:18:01 +0100 Subject: [PATCH 33/33] [virtual-machine] Improve check for resizing job Signed-off-by: Andrei Kvapil --- .../virtual-machine/templates/vm-update-hook.yaml | 6 +++++- .../apps/vm-disk/templates/pvc-resize-hook.yaml | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/apps/virtual-machine/templates/vm-update-hook.yaml b/packages/apps/virtual-machine/templates/vm-update-hook.yaml index 74f76cc5..1197c027 100644 --- a/packages/apps/virtual-machine/templates/vm-update-hook.yaml +++ b/packages/apps/virtual-machine/templates/vm-update-hook.yaml @@ -27,7 +27,11 @@ {{- if and $existingPVC $desiredStorage -}} {{- $currentStorage := $existingPVC.spec.resources.requests.storage | toString -}} {{- if not (eq $currentStorage $desiredStorage) -}} - {{- $needResizePVC = true -}} + {{- $oldSize := (include "cozy-lib.resources.toFloat" $currentStorage) | float64 -}} + {{- $newSize := (include "cozy-lib.resources.toFloat" $desiredStorage) | float64 -}} + {{- if gt $newSize $oldSize -}} + {{- $needResizePVC = true -}} + {{- end -}} {{- end -}} {{- end -}} diff --git a/packages/apps/vm-disk/templates/pvc-resize-hook.yaml b/packages/apps/vm-disk/templates/pvc-resize-hook.yaml index 2619ed15..2454c599 100644 --- a/packages/apps/vm-disk/templates/pvc-resize-hook.yaml +++ b/packages/apps/vm-disk/templates/pvc-resize-hook.yaml @@ -1,5 +1,17 @@ {{- $existingPVC := lookup "v1" "PersistentVolumeClaim" .Release.Namespace .Release.Name }} -{{- if and $existingPVC (ne ($existingPVC.spec.resources.requests.storage | toString) .Values.storage) -}} +{{- $shouldResize := false -}} +{{- if and $existingPVC .Values.storage -}} + {{- $currentStorage := $existingPVC.spec.resources.requests.storage | toString -}} + {{- if ne $currentStorage .Values.storage -}} + {{- $oldSize := (include "cozy-lib.resources.toFloat" $currentStorage) | float64 -}} + {{- $newSize := (include "cozy-lib.resources.toFloat" .Values.storage) | float64 -}} + {{- if gt $newSize $oldSize -}} + {{- $shouldResize = true -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- if $shouldResize -}} apiVersion: batch/v1 kind: Job metadata: @@ -23,6 +35,7 @@ spec: command: ["sh", "-xec"] args: - | + echo "Resizing PVC to {{ .Values.storage }}..." kubectl patch pvc {{ .Release.Name }} -p '{"spec":{"resources":{"requests":{"storage":"{{ .Values.storage }}"}}}}' --- apiVersion: v1