From 21715c02bc4e7bd4717c8122d07f16f2975a68ef Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 13 Oct 2025 14:59:15 +0200 Subject: [PATCH 01/76] The Cozystack Kubernetes tests are now POSIX-compatible (#1509) This patch replaces bash-specific [[ ... ]] expressions in the run_kubernetes_test function with POSIX-compliant case and test constructs. It ensures that the Kubernetes version on each worker node is verified correctly and that required components (CoreDNS, Cilium, ingress-nginx, vsnap-crd) are ready before proceeding. Now the tests work reliably even when executed with /bin/sh, such as in Bats. ```release-note [tests] Make Kubernetes tests POSIX-compliant and more reliable: verify worker node versions and ensure required releases (CoreDNS, Cilium, ingress-nginx, vsnap-crd) are installed and ready. ``` ## What this PR does ### Release note ```release-note [] ``` ## Summary by CodeRabbit * **Bug Fixes** * Improved Kubernetes version detection to correctly handle 1.32 variants. * Made node readiness checks more reliable to reduce false failures during runs. * **Refactor** * Streamlined version matching logic for clearer, more predictable behavior across releases. * **Style** * Minor formatting cleanups with no functional impact. --- hack/e2e-apps/run-kubernetes.sh | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/hack/e2e-apps/run-kubernetes.sh b/hack/e2e-apps/run-kubernetes.sh index 7c7f347a..716b40dc 100644 --- a/hack/e2e-apps/run-kubernetes.sh +++ b/hack/e2e-apps/run-kubernetes.sh @@ -64,19 +64,19 @@ spec: EOF # Wait for the tenant-test namespace to be active kubectl wait namespace tenant-test --timeout=20s --for=jsonpath='{.status.phase}'=Active - + # Wait for the Kamaji control plane to be created (retry for up to 10 seconds) timeout 10 sh -ec 'until kubectl get kamajicontrolplane -n tenant-test kubernetes-'"${test_name}"'; do sleep 1; done' # Wait for the tenant control plane to be fully created (timeout after 4 minutes) kubectl wait --for=condition=TenantControlPlaneCreated kamajicontrolplane -n tenant-test kubernetes-${test_name} --timeout=4m - + # Wait for Kubernetes resources to be ready (timeout after 2 minutes) kubectl wait tcp -n tenant-test kubernetes-${test_name} --timeout=2m --for=jsonpath='{.status.kubernetesResources.version.status}'=Ready - + # Wait for all required deployments to be available (timeout after 4 minutes) kubectl wait deploy --timeout=4m --for=condition=available -n tenant-test kubernetes-${test_name} kubernetes-${test_name}-cluster-autoscaler kubernetes-${test_name}-kccm kubernetes-${test_name}-kcsi-controller - + # Wait for the machine deployment to scale to 2 replicas (timeout after 1 minute) kubectl wait machinedeployment kubernetes-${test_name}-md0 -n tenant-test --timeout=1m --for=jsonpath='{.status.replicas}'=2 # Get the admin kubeconfig and save it to a file @@ -105,9 +105,11 @@ EOF versions=$(kubectl --kubeconfig tenantkubeconfig get nodes -o jsonpath='{.items[*].status.nodeInfo.kubeletVersion}') node_ok=true - if [[ "$k8s_version" == v1.32* ]]; then - echo "⚠️ TODO: Temporary stub — allowing nodes with v1.33 while k8s_version is v1.32" - fi + case "$k8s_version" in + v1.32*) + echo "⚠️ TODO: Temporary stub — allowing nodes with v1.33 while k8s_version is v1.32" + ;; + esac for v in $versions; do case "$k8s_version" in @@ -134,7 +136,7 @@ EOF esac done - if ! $node_ok; then + if [ "$node_ok" != true ]; then echo "Kubelet versions did not match expected ${k8s_version}" >&2 exit 1 fi From 5dbdd0eafa1de588aede0206d622b14bd9bc35cf Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 13 Oct 2025 14:59:44 +0200 Subject: [PATCH 02/76] [api] Efficient listing of TenantNamespaces (#1507) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does The Cozystack API server lists TenantNamespaces by running a SubjectAccessReview against every single requested namespace to see if the user can create a WorkloadMonitor there. Will this is robust in terms of permissions, delegating the authorization decision to the k8s API, this is incredibly inefficient and has caused high latency to the API. This patch simplifies the logic by instead getting the user's groups and checking if the namespace contains a rolebinding for that group. That way listing TenantNamespaces is reduced to a list call to the k8s API for namespaces and another list call for rolebindings across all namespaces, while authorization is done on the Cozystack API server instead of making further calls to the k8s API. ### Release note ```release-note [api] Optimize listing of TenantNamespaces, fixes a bug causing very high latency to the k8s API. ``` ## Summary by CodeRabbit - Bug Fixes - TenantNamespace visibility now consistently reflects RBAC role bindings. Cluster administrators see all namespaces; users only see namespaces they’re permitted to access. - Refactor - Access evaluation simplified to rely on role/rolebinding membership, removing per-namespace authorization calls and improving listing performance. --- pkg/apiserver/apiserver.go | 3 +- pkg/registry/core/tenantnamespace/rest.go | 117 ++++++++-------------- 2 files changed, 43 insertions(+), 77 deletions(-) diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 80220964..e829d336 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -138,8 +138,7 @@ func (c completedConfig) New() (*CozyServer, error) { coreV1alpha1Storage["tenantnamespaces"] = cozyregistry.RESTInPeace( tenantnamespacestorage.NewREST( clientset.CoreV1(), - clientset.AuthorizationV1(), - 20, + clientset.RbacV1(), ), ) coreV1alpha1Storage["tenantsecrets"] = cozyregistry.RESTInPeace( diff --git a/pkg/registry/core/tenantnamespace/rest.go b/pkg/registry/core/tenantnamespace/rest.go index 3b18f3e3..a0b68357 100644 --- a/pkg/registry/core/tenantnamespace/rest.go +++ b/pkg/registry/core/tenantnamespace/rest.go @@ -7,13 +7,10 @@ package tenantnamespace import ( "context" "fmt" - "math" "net/http" "strings" - "sync" "time" - authorizationv1 "k8s.io/api/authorization/v1" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metainternal "k8s.io/apimachinery/pkg/apis/meta/internalversion" @@ -24,9 +21,8 @@ import ( "k8s.io/apimachinery/pkg/watch" "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" - authorizationv1client "k8s.io/client-go/kubernetes/typed/authorization/v1" corev1client "k8s.io/client-go/kubernetes/typed/core/v1" - "k8s.io/klog/v2" + rbacv1client "k8s.io/client-go/kubernetes/typed/rbac/v1" corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" ) @@ -50,21 +46,18 @@ var ( ) type REST struct { - core corev1client.CoreV1Interface - authClient authorizationv1client.AuthorizationV1Interface - maxWorkers int - gvr schema.GroupVersionResource + core corev1client.CoreV1Interface + rbac rbacv1client.RbacV1Interface + gvr schema.GroupVersionResource } func NewREST( coreCli corev1client.CoreV1Interface, - authCli authorizationv1client.AuthorizationV1Interface, - maxWorkers int, + rbacCli rbacv1client.RbacV1Interface, ) *REST { return &REST{ - core: coreCli, - authClient: authCli, - maxWorkers: maxWorkers, + core: coreCli, + rbac: rbacCli, gvr: schema.GroupVersionResource{ Group: corev1alpha1.GroupName, Version: "v1alpha1", @@ -271,76 +264,50 @@ func (r *REST) filterAccessible( ctx context.Context, names []string, ) ([]string, error) { - workers := int(math.Min(float64(r.maxWorkers), float64(len(names)))) - type job struct{ name string } - type res struct { - name string - allowed bool - err error + u, ok := request.UserFrom(ctx) + if !ok { + return []string{}, fmt.Errorf("user missing in context") } - jobs := make(chan job, workers) - out := make(chan res, workers) - - var wg sync.WaitGroup - for i := 0; i < workers; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := range jobs { - ok, err := r.sar(ctx, j.name) - out <- res{j.name, ok, err} - } - }() + groups := make(map[string]struct{}) + for _, group := range u.GetGroups() { + groups[group] = struct{}{} } - go func() { wg.Wait(); close(out) }() - - go func() { - for _, n := range names { - jobs <- job{n} - } - close(jobs) - }() - - var allowed []string - for r := range out { - if r.err != nil { - klog.Errorf("SAR failed for %s: %v", r.name, r.err) + if _, ok = groups["cozystack-cluster-admin"]; ok { + return names, nil + } + nameSet := make(map[string]struct{}) + for _, name := range names { + nameSet[name] = struct{}{} + } + rbs, err := r.rbac.RoleBindings("").List(ctx, metav1.ListOptions{}) + if err != nil { + return []string{}, fmt.Errorf("failed to list rolebindings") + } + allowedNameSet := make(map[string]struct{}) + for i := range rbs.Items { + if _, ok := allowedNameSet[rbs.Items[i].Namespace]; ok { continue } - if r.allowed { - allowed = append(allowed, r.name) + if _, ok := nameSet[rbs.Items[i].Namespace]; !ok { + continue + } + for j := range rbs.Items[i].Subjects { + if rbs.Items[i].Subjects[j].Kind != "Group" { + continue + } + if _, ok = groups[rbs.Items[i].Subjects[j].Name]; ok { + allowedNameSet[rbs.Items[i].Namespace] = struct{}{} + break + } } } + allowed := make([]string, 0, len(allowedNameSet)) + for name := range allowedNameSet { + allowed = append(allowed, name) + } return allowed, nil } -func (r *REST) sar(ctx context.Context, ns string) (bool, error) { - u, ok := request.UserFrom(ctx) - if !ok || u == nil { - return false, fmt.Errorf("user missing in context") - } - - sar := &authorizationv1.SubjectAccessReview{ - Spec: authorizationv1.SubjectAccessReviewSpec{ - User: u.GetName(), - Groups: u.GetGroups(), - ResourceAttributes: &authorizationv1.ResourceAttributes{ - Group: "cozystack.io", - Resource: "workloadmonitors", - Verb: "get", - Namespace: ns, - }, - }, - } - - rsp, err := r.authClient.SubjectAccessReviews(). - Create(ctx, sar, metav1.CreateOptions{}) - if err != nil { - return false, err - } - return rsp.Status.Allowed, nil -} - // ----------------------------------------------------------------------------- // Boiler-plate // ----------------------------------------------------------------------------- From b474c07c80cf76edacdbebfd049bdf6171782da5 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 13 Oct 2025 15:00:00 +0200 Subject: [PATCH 03/76] Add addtional check to wait for lineage-webhook (#1506) Signed-off-by: Andrei Kvapil ## What this PR does ### Release note ```release-note [] ``` ## Summary by CodeRabbit * **Chores** * Added a timeout-based step that repeatedly attempts server-side dry-run creation of a Kubernetes Service (headless) between controller upgrade and subsequent waits. * Inserts this validation step without altering existing flow or other behaviors. --- scripts/migrations/20 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/migrations/20 b/scripts/migrations/20 index 77abec8e..7e306126 100755 --- a/scripts/migrations/20 +++ b/scripts/migrations/20 @@ -28,6 +28,8 @@ cozypkg -n cozy-system -C packages/system/cozystack-api apply cozystack-api --pl helm upgrade --install -n cozy-system cozystack-controller ./packages/system/cozystack-controller/ --take-ownership sleep 5 +timeout 60 sh -c 'until kubectl create service clusterip lineage-webhook-test --clusterip="None" --dry-run=server; do sleep 1; done' + kubectl wait deployment/cozystack-api -n cozy-system --timeout=4m --for=condition=available || exit 1 kubectl wait deployment/cozystack-controller -n cozy-system --timeout=4m --for=condition=available || exit 1 From 0176ba5e959341b598c963199f73e2b2e0fe5b27 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 13 Oct 2025 15:00:18 +0200 Subject: [PATCH 04/76] [dashboard] Fix logout (#1510) Signed-off-by: Andrei Kvapil ## What this PR does ### Release note ```release-note [dashboard] Fix logout ``` ## Summary by CodeRabbit * **New Features** * Enhanced OIDC logout flow: backend logout is now supported, improving reliability of signing out across services. * Whitelisted the identity provider domain to enable seamless redirects during authentication and logout journeys. --- packages/system/dashboard/templates/gatekeeper.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/system/dashboard/templates/gatekeeper.yaml b/packages/system/dashboard/templates/gatekeeper.yaml index 0bf20b02..b4503f4f 100644 --- a/packages/system/dashboard/templates/gatekeeper.yaml +++ b/packages/system/dashboard/templates/gatekeeper.yaml @@ -55,6 +55,8 @@ spec: - --http-address=0.0.0.0:8000 - --redirect-url=https://dashboard.{{ $host }}/oauth2/callback - --oidc-issuer-url=https://keycloak.{{ $host }}/realms/cozy + - --backend-logout-url=https://keycloak.{{ $host }}/realms/cozy/protocol/openid-connect/logout?id_token_hint={id_token} + - --whitelist-domain=keycloak.{{ $host }} - --email-domain=* - --pass-access-token=true - --pass-authorization-header=true From 5a679e12ad734d16a9163a3b34ff9f12f4de4392 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 13 Oct 2025 15:20:16 +0200 Subject: [PATCH 05/76] [api] Fix RBAC for listing of TenantNamespaces and handle system:masters (#1511) Signed-off-by: Andrei Kvapil ## What this PR does Fix regression introduced by https://github.com/cozystack/cozystack/pull/1507 ### Release note ```release-note [api] Fix RBAC for listing of TenantNamespaces and handle system:masters ``` ## Summary by CodeRabbit - New Features - System-wide administrators now see all tenant namespaces without filtering. - Expanded read access for role bindings to improve visibility of access configurations. - Bug Fixes - Resolved cases where some authorized admins could not view all tenant namespaces due to RBAC filtering. --- packages/system/cozystack-api/templates/rbac.yaml | 3 +++ pkg/registry/core/tenantnamespace/rest.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/packages/system/cozystack-api/templates/rbac.yaml b/packages/system/cozystack-api/templates/rbac.yaml index 1a169d86..e4b3aca9 100644 --- a/packages/system/cozystack-api/templates/rbac.yaml +++ b/packages/system/cozystack-api/templates/rbac.yaml @@ -6,6 +6,9 @@ rules: - apiGroups: [""] resources: ["namespaces", "secrets"] verbs: ["get", "watch", "list"] +- apiGroups: ["rbac.authorization.k8s.io"] + resources: ["rolebindings"] + verbs: ["get", "watch", "list"] - apiGroups: [""] resources: ["secrets"] verbs: ["create", "update", "patch", "delete"] diff --git a/pkg/registry/core/tenantnamespace/rest.go b/pkg/registry/core/tenantnamespace/rest.go index a0b68357..f5196cad 100644 --- a/pkg/registry/core/tenantnamespace/rest.go +++ b/pkg/registry/core/tenantnamespace/rest.go @@ -272,6 +272,9 @@ func (r *REST) filterAccessible( for _, group := range u.GetGroups() { groups[group] = struct{}{} } + if _, ok = groups["system:masters"]; ok { + return names, nil + } if _, ok = groups["cozystack-cluster-admin"]; ok { return names, nil } From 2f8c6b72fe06f8e066cafc07397f2c6fc706661a Mon Sep 17 00:00:00 2001 From: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> Date: Mon, 13 Oct 2025 13:29:01 +0000 Subject: [PATCH 06/76] Prepare release v0.37.1 Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> --- packages/apps/http-cache/images/nginx-cache.tag | 2 +- packages/core/installer/values.yaml | 2 +- packages/core/testing/values.yaml | 2 +- packages/extra/bootbox/images/matchbox.tag | 2 +- packages/extra/seaweedfs/images/objectstorage-sidecar.tag | 2 +- packages/system/bucket/images/s3manager.tag | 2 +- packages/system/cozystack-api/values.yaml | 2 +- packages/system/cozystack-controller/values.yaml | 4 ++-- packages/system/dashboard/templates/configmap.yaml | 2 +- packages/system/dashboard/values.yaml | 6 +++--- packages/system/kamaji/values.yaml | 4 ++-- packages/system/kubeovn-plunger/values.yaml | 2 +- packages/system/kubeovn-webhook/values.yaml | 2 +- packages/system/kubeovn/values.yaml | 2 +- packages/system/objectstorage-controller/values.yaml | 2 +- packages/system/seaweedfs/values.yaml | 2 +- 16 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/apps/http-cache/images/nginx-cache.tag b/packages/apps/http-cache/images/nginx-cache.tag index 0970e11c..185dcc66 100644 --- a/packages/apps/http-cache/images/nginx-cache.tag +++ b/packages/apps/http-cache/images/nginx-cache.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:50ac1581e3100bd6c477a71161cb455a341ffaf9e5e2f6086802e4e25271e8af +ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:e0a07082bb6fc6aeaae2315f335386f1705a646c72f9e0af512aebbca5cb2b15 diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index fc7c81fa..b81a040a 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:v0.37.0@sha256:256c5a0f0ae2fc3ad6865b9fda74c42945b38a5384240fa29554617185b60556 + image: ghcr.io/cozystack/cozystack/installer:v0.37.1@sha256:67aa398836ad240a3af3c4108ef61c36c1ba11989ab9fbc1d5f003456dcc949c diff --git a/packages/core/testing/values.yaml b/packages/core/testing/values.yaml index bcc94ce3..6348000f 100755 --- a/packages/core/testing/values.yaml +++ b/packages/core/testing/values.yaml @@ -1,2 +1,2 @@ e2e: - image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.0@sha256:10afd0a6c39248ec41d0e59ff1bc6c29bd0075b7cc9a512b01cf603ef39c33ea + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.1@sha256:82e42c2416d6704786d37920d162416efc02083a1c30605d22b8213198b515a8 diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index 6060afa4..852bfa66 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v0.37.0@sha256:5cca5f56b755285aefa11b1052fe55e1aa83b25bae34aef80cdb77ff63091044 +ghcr.io/cozystack/cozystack/matchbox:v0.37.1@sha256:160c583a1c05ae06e304f7065dbf5ddad0bf9b59bf1a227f8a82f9d331d29c9d diff --git a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag index e16a832d..f018dee2 100644 --- a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag +++ b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.0@sha256:f166f09cdc9cdbb758209883819ab8261a3793bc1d7a6b6685efd5a2b2930847 +ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.1@sha256:f166f09cdc9cdbb758209883819ab8261a3793bc1d7a6b6685efd5a2b2930847 diff --git a/packages/system/bucket/images/s3manager.tag b/packages/system/bucket/images/s3manager.tag index 96054223..9b25469d 100644 --- a/packages/system/bucket/images/s3manager.tag +++ b/packages/system/bucket/images/s3manager.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:7348bec610f08bd902c88c9a9f28fdd644727e2728a1e4103f88f0c99febd5e7 +ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:26e241c285e3cf20c043545bf25517ec52f000a738b7ed9168656b58e59749a3 diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index 1b68eff4..7d24b1a4 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,2 +1,2 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.0@sha256:19d89e8afb90ce38ab7e42ecedfc28402f7c0b56f30957db957c5415132ff6ca + image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.1@sha256:dc8f90f7c9551f1487670e512734939bf1585568fec04e74e4c5cac0bcabb1b9 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index f651807e..a877142a 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,5 +1,5 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.0@sha256:845b8e68cbc277c2303080bcd55597e4334610d396dad258ad56fd906530acc3 + image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.1@sha256:a78f8f0796a4b56a36a8f0abd3a502b61cf2745a50b9d54fdb2e13b3e691509b debug: false disableTelemetry: false - cozystackVersion: "v0.37.0" + cozystackVersion: "v0.37.1" diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml index 5c541dff..7e61611e 100644 --- a/packages/system/dashboard/templates/configmap.yaml +++ b/packages/system/dashboard/templates/configmap.yaml @@ -1,6 +1,6 @@ {{- $brandingConfig:= lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} -{{- $tenantText := "v0.37.0" }} +{{- $tenantText := "v0.37.1" }} {{- $footerText := "Cozystack" }} {{- $titleText := "Cozystack Dashboard" }} {{- $logoText := "false" }} diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index 4cb8571b..dfe0afe2 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,6 +1,6 @@ openapiUI: - image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.0@sha256:13f38cf56830e899eb5e3d9dc8184965dd8dba9f8cd3c5ca10df0970355842d6 + image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.1@sha256:3fd556689816ac2a0a3af9c7a2e4025936f9fc716e57e9aabb8cc1b576819aae openapiUIK8sBff: - image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.0@sha256:2b626dbbf87241e8621ac5b0285f402edbc2c2069ba254ca2ace2dd5c9248ac8 + image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.1@sha256:fe3f570adf35798c5a46bee0737975b6d8432eb5b0c0e2a6d529eb330c4a29f9 tokenProxy: - image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.0@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b + image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.1@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b diff --git a/packages/system/kamaji/values.yaml b/packages/system/kamaji/values.yaml index 906d20bf..0fd36dc0 100644 --- a/packages/system/kamaji/values.yaml +++ b/packages/system/kamaji/values.yaml @@ -3,7 +3,7 @@ kamaji: deploy: false image: pullPolicy: IfNotPresent - tag: v0.37.0@sha256:9f4fd5045ede2909fbaf2572e4138fcbd8921071ecf8f08446257fddd0e6f655 + tag: v0.37.1@sha256:9f4fd5045ede2909fbaf2572e4138fcbd8921071ecf8f08446257fddd0e6f655 repository: ghcr.io/cozystack/cozystack/kamaji resources: limits: @@ -13,4 +13,4 @@ kamaji: cpu: 100m memory: 100Mi extraArgs: - - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.0@sha256:9f4fd5045ede2909fbaf2572e4138fcbd8921071ecf8f08446257fddd0e6f655 + - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.1@sha256:9f4fd5045ede2909fbaf2572e4138fcbd8921071ecf8f08446257fddd0e6f655 diff --git a/packages/system/kubeovn-plunger/values.yaml b/packages/system/kubeovn-plunger/values.yaml index 11595d48..b7c522e3 100644 --- a/packages/system/kubeovn-plunger/values.yaml +++ b/packages/system/kubeovn-plunger/values.yaml @@ -1,4 +1,4 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.0@sha256:9950614571ea77a55925eba0839b6b12c8e5a7a30b8858031a8c6050f261af1a +image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.1@sha256:ec5794c58ec4f6a6041555c91ae2e8be01c21af4f34bb1940551b9e7ee0eaf6f ovnCentralName: ovn-central diff --git a/packages/system/kubeovn-webhook/values.yaml b/packages/system/kubeovn-webhook/values.yaml index 116f077a..9931c3bf 100644 --- a/packages/system/kubeovn-webhook/values.yaml +++ b/packages/system/kubeovn-webhook/values.yaml @@ -1,3 +1,3 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.0@sha256:7e63205708e607ce2cedfe2a2cafd323ca51e3ebc71244a21ff6f9016c6c87bc +image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.1@sha256:f803cf5e7a2f1fa2bcf7003f8a5931e5d7bccddce7f92c88029292b4826c9050 diff --git a/packages/system/kubeovn/values.yaml b/packages/system/kubeovn/values.yaml index 74f21b52..628b9aa6 100644 --- a/packages/system/kubeovn/values.yaml +++ b/packages/system/kubeovn/values.yaml @@ -64,4 +64,4 @@ global: images: kubeovn: repository: kubeovn - tag: v1.14.5@sha256:af10da442a0c6dc7df47a0ef752e2eb5c247bb0b43069fdfcb2aa51511185ea2 + tag: v1.14.5@sha256:f9b88f3276b84c892853b42ca06edfc4e8bf53399d902f993459add03cb51a54 diff --git a/packages/system/objectstorage-controller/values.yaml b/packages/system/objectstorage-controller/values.yaml index 489052ac..fed50331 100644 --- a/packages/system/objectstorage-controller/values.yaml +++ b/packages/system/objectstorage-controller/values.yaml @@ -1,3 +1,3 @@ objectstorage: controller: - image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.0@sha256:5f2eed05d19ba971806374834cb16ca49282aac76130194c00b213c79ce3e10d" + image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.1@sha256:5f2eed05d19ba971806374834cb16ca49282aac76130194c00b213c79ce3e10d" diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index e12102e7..007de122 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -120,7 +120,7 @@ seaweedfs: bucketClassName: "seaweedfs" region: "" sidecar: - image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.0@sha256:f166f09cdc9cdbb758209883819ab8261a3793bc1d7a6b6685efd5a2b2930847" + image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.1@sha256:f166f09cdc9cdbb758209883819ab8261a3793bc1d7a6b6685efd5a2b2930847" certificates: commonName: "SeaweedFS CA" ipAddresses: [] From a09ed799e9e80923a406e7fc1322334f007f29f4 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 14 Oct 2025 12:37:47 +0200 Subject: [PATCH 07/76] [api] Fix listing tenantnamespaces for non-oidc users Signed-off-by: Andrei Kvapil (cherry picked from commit 671e13df7021663a721407f81fa496e195365865) --- pkg/registry/core/tenantnamespace/rest.go | 24 +++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/pkg/registry/core/tenantnamespace/rest.go b/pkg/registry/core/tenantnamespace/rest.go index f5196cad..56098740 100644 --- a/pkg/registry/core/tenantnamespace/rest.go +++ b/pkg/registry/core/tenantnamespace/rest.go @@ -294,13 +294,25 @@ func (r *REST) filterAccessible( if _, ok := nameSet[rbs.Items[i].Namespace]; !ok { continue } + subjectLoop: for j := range rbs.Items[i].Subjects { - if rbs.Items[i].Subjects[j].Kind != "Group" { - continue - } - if _, ok = groups[rbs.Items[i].Subjects[j].Name]; ok { - allowedNameSet[rbs.Items[i].Namespace] = struct{}{} - break + subj := rbs.Items[i].Subjects[j] + switch subj.Kind { + case "Group": + if _, ok = groups[subj.Name]; ok { + allowedNameSet[rbs.Items[i].Namespace] = struct{}{} + break subjectLoop + } + case "User": + if subj.Name == u.GetName() { + allowedNameSet[rbs.Items[i].Namespace] = struct{}{} + break subjectLoop + } + case "ServiceAccount": + if u.GetName() == fmt.Sprintf("system:serviceaccount:%s:%s", subj.Namespace, subj.Name) { + allowedNameSet[rbs.Items[i].Namespace] = struct{}{} + break subjectLoop + } } } } From 674b3963a7cf092507d0d2b71ec8219fc55bd89e Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Tue, 14 Oct 2025 12:30:43 +0400 Subject: [PATCH 08/76] [lineage] Separate webhook from cozy controller (#1515) ## What this PR does The lineage-controller-webhook makes a lot of outgoing API calls for every event it handles, contributing to a high API server latency, increasing the number of in-flight requests and generally degrading performance. This patch remedies this by separating the lineage component from the cozystack-controller and deploying it as a separate component on all control-plane nodes. Additionally, a new internal label is introduced to track if a resource has already been handled by the webhook. This label is used to exclude such resources from consideration. Addresses #1513. ### Release note ```release-note [lineage] Break webhook out into a separate daemonset. Reduce unnecessary webhook calls by marking handled resources and excluding them from consideration by the webhook's object selector. ``` ## Summary by CodeRabbit - **New Features** - Standalone Lineage Controller Webhook deployed as its own DaemonSet with a dedicated Helm chart and image build targets. - Dedicated TLS provisioning for the webhook via chart-managed certs. - **Changes** - Main controller no longer hosts webhook endpoints or certificates. - Webhook now excludes already-managed resources to reduce unnecessary invocations. - Platform bundles updated to include the new webhook release. - **Documentation** - Changelog updated to reflect the separation and optimization. --- Makefile | 1 + cmd/cozystack-controller/main.go | 15 -- cmd/lineage-controller-webhook/main.go | 179 ++++++++++++++++++ docs/changelogs/unreleased.md | 3 + internal/lineagecontrollerwebhook/webhook.go | 18 +- .../core/platform/bundles/distro-full.yaml | 6 + .../core/platform/bundles/distro-hosted.yaml | 6 + packages/core/platform/bundles/paas-full.yaml | 6 + .../core/platform/bundles/paas-hosted.yaml | 6 + .../templates/certmanager.yaml | 45 ----- .../templates/deployment.yaml | 12 -- .../lineage-controller-webhook/.gitignore | 27 +++ .../lineage-controller-webhook/Chart.yaml | 3 + .../lineage-controller-webhook/Makefile | 18 ++ .../lineage-controller-webhook/Dockerfile | 23 +++ .../templates/certmanager.yaml | 45 +++++ .../templates/daemonset.yaml | 46 +++++ .../mutatingwebhookconfiguration.yaml | 8 +- .../templates/rbac-bind.yaml | 12 ++ .../templates/rbac.yaml | 8 + .../templates/sa.yaml | 4 + .../templates/service.yaml | 7 +- .../lineage-controller-webhook/values.yaml | 3 + 23 files changed, 419 insertions(+), 82 deletions(-) create mode 100644 cmd/lineage-controller-webhook/main.go create mode 100644 docs/changelogs/unreleased.md delete mode 100644 packages/system/cozystack-controller/templates/certmanager.yaml create mode 100644 packages/system/lineage-controller-webhook/.gitignore create mode 100644 packages/system/lineage-controller-webhook/Chart.yaml create mode 100644 packages/system/lineage-controller-webhook/Makefile create mode 100644 packages/system/lineage-controller-webhook/images/lineage-controller-webhook/Dockerfile create mode 100644 packages/system/lineage-controller-webhook/templates/certmanager.yaml create mode 100644 packages/system/lineage-controller-webhook/templates/daemonset.yaml rename packages/system/{cozystack-controller => lineage-controller-webhook}/templates/mutatingwebhookconfiguration.yaml (81%) create mode 100644 packages/system/lineage-controller-webhook/templates/rbac-bind.yaml create mode 100644 packages/system/lineage-controller-webhook/templates/rbac.yaml create mode 100644 packages/system/lineage-controller-webhook/templates/sa.yaml rename packages/system/{cozystack-controller => lineage-controller-webhook}/templates/service.yaml (55%) create mode 100644 packages/system/lineage-controller-webhook/values.yaml diff --git a/Makefile b/Makefile index c941a9ff..bb5eb40e 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/lineage-controller-webhook image make -C packages/system/cilium image make -C packages/system/kubeovn image make -C packages/system/kubeovn-webhook image diff --git a/cmd/cozystack-controller/main.go b/cmd/cozystack-controller/main.go index f774284a..c2ceb451 100644 --- a/cmd/cozystack-controller/main.go +++ b/cmd/cozystack-controller/main.go @@ -39,7 +39,6 @@ import ( cozystackiov1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" "github.com/cozystack/cozystack/internal/controller" "github.com/cozystack/cozystack/internal/controller/dashboard" - lcw "github.com/cozystack/cozystack/internal/lineagecontrollerwebhook" "github.com/cozystack/cozystack/internal/telemetry" helmv2 "github.com/fluxcd/helm-controller/api/v2" @@ -222,20 +221,6 @@ func main() { os.Exit(1) } - // special one that's both a webhook and a reconciler - lineageControllerWebhook := &lcw.LineageControllerWebhook{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - } - if err := lineageControllerWebhook.SetupWithManagerAsController(mgr); err != nil { - setupLog.Error(err, "unable to setup controller", "controller", "LineageController") - os.Exit(1) - } - if err := lineageControllerWebhook.SetupWithManagerAsWebhook(mgr); err != nil { - setupLog.Error(err, "unable to setup webhook", "webhook", "LineageWebhook") - os.Exit(1) - } - // +kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/cmd/lineage-controller-webhook/main.go b/cmd/lineage-controller-webhook/main.go new file mode 100644 index 00000000..ffe0942b --- /dev/null +++ b/cmd/lineage-controller-webhook/main.go @@ -0,0 +1,179 @@ +/* +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" + + cozystackiov1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + lcw "github.com/cozystack/cozystack/internal/lineagecontrollerwebhook" + // +kubebuilder:scaffold:imports +) + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + + utilruntime.Must(cozystackiov1alpha1.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: "8796f12d.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) + } + + lineageControllerWebhook := &lcw.LineageControllerWebhook{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + } + if err := lineageControllerWebhook.SetupWithManagerAsController(mgr); err != nil { + setupLog.Error(err, "unable to setup controller", "controller", "LineageController") + os.Exit(1) + } + if err := lineageControllerWebhook.SetupWithManagerAsWebhook(mgr); err != nil { + setupLog.Error(err, "unable to setup webhook", "webhook", "LineageWebhook") + 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/docs/changelogs/unreleased.md b/docs/changelogs/unreleased.md new file mode 100644 index 00000000..1ea38313 --- /dev/null +++ b/docs/changelogs/unreleased.md @@ -0,0 +1,3 @@ +# Changes after v0.37.0 + +* [lineage] Break webhook out into a separate daemonset. Reduce unnecessary webhook calls by marking handled resources and excluding them from consideration by the webhook's object selector (@lllamnyp in #1515). diff --git a/internal/lineagecontrollerwebhook/webhook.go b/internal/lineagecontrollerwebhook/webhook.go index 1e7739b7..0841c891 100644 --- a/internal/lineagecontrollerwebhook/webhook.go +++ b/internal/lineagecontrollerwebhook/webhook.go @@ -26,6 +26,13 @@ var ( AncestryAmbiguous = fmt.Errorf("object ancestry is ambiguous") ) +const ( + ManagedObjectKey = "internal.cozystack.io/managed-by-cozystack" + ManagerGroupKey = "apps.cozystack.io/application.group" + ManagerKindKey = "apps.cozystack.io/application.kind" + ManagerNameKey = "apps.cozystack.io/application.name" +) + // getResourceSelectors returns the appropriate CozystackResourceDefinitionResources for a given GroupKind func (h *LineageControllerWebhook) getResourceSelectors(gk schema.GroupKind, crd *cozyv1alpha1.CozystackResourceDefinition) *cozyv1alpha1.CozystackResourceDefinitionResources { switch { @@ -91,7 +98,7 @@ func (h *LineageControllerWebhook) Handle(ctx context.Context, req admission.Req labels, err := h.computeLabels(ctx, obj) for { if err != nil && errors.Is(err, NoAncestors) { - return admission.Allowed("object not managed by app") + break // not a problem, mark object as unmanaged } if err != nil && errors.Is(err, AncestryAmbiguous) { warn = append(warn, "object ancestry ambiguous, using first ancestor found") @@ -119,7 +126,7 @@ func (h *LineageControllerWebhook) Handle(ctx context.Context, req admission.Req func (h *LineageControllerWebhook) computeLabels(ctx context.Context, o *unstructured.Unstructured) (map[string]string, error) { owners := lineage.WalkOwnershipGraph(ctx, h.dynClient, h.mapper, h, o) if len(owners) == 0 { - return nil, NoAncestors + return map[string]string{ManagedObjectKey: "false"}, NoAncestors } obj, err := owners[0].GetUnstructured(ctx, h.dynClient, h.mapper) if err != nil { @@ -135,7 +142,8 @@ func (h *LineageControllerWebhook) computeLabels(ctx context.Context, o *unstruc } labels := map[string]string{ // truncate apigroup to first 63 chars - "apps.cozystack.io/application.group": func(s string) string { + ManagedObjectKey: "true", + ManagerGroupKey: func(s string) string { if len(s) < 63 { return s } @@ -145,8 +153,8 @@ func (h *LineageControllerWebhook) computeLabels(ctx context.Context, o *unstruc } return s }(gv.Group), - "apps.cozystack.io/application.kind": obj.GetKind(), - "apps.cozystack.io/application.name": obj.GetName(), + ManagerKindKey: obj.GetKind(), + ManagerNameKey: obj.GetName(), } templateLabels := map[string]string{ "kind": strings.ToLower(obj.GetKind()), diff --git a/packages/core/platform/bundles/distro-full.yaml b/packages/core/platform/bundles/distro-full.yaml index fbcf2ba9..be35482a 100644 --- a/packages/core/platform/bundles/distro-full.yaml +++ b/packages/core/platform/bundles/distro-full.yaml @@ -68,6 +68,12 @@ releases: disableTelemetry: true {{- end }} +- name: lineage-controller-webhook + releaseName: lineage-controller-webhook + chart: cozy-lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller,cilium,cert-manager] + - name: cert-manager releaseName: cert-manager chart: cozy-cert-manager diff --git a/packages/core/platform/bundles/distro-hosted.yaml b/packages/core/platform/bundles/distro-hosted.yaml index c24232c6..d486399d 100644 --- a/packages/core/platform/bundles/distro-hosted.yaml +++ b/packages/core/platform/bundles/distro-hosted.yaml @@ -36,6 +36,12 @@ releases: disableTelemetry: true {{- end }} +- name: lineage-controller-webhook + releaseName: lineage-controller-webhook + chart: cozy-lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller,cert-manager] + - name: cert-manager releaseName: cert-manager chart: cozy-cert-manager diff --git a/packages/core/platform/bundles/paas-full.yaml b/packages/core/platform/bundles/paas-full.yaml index f4274eda..f02dbc40 100644 --- a/packages/core/platform/bundles/paas-full.yaml +++ b/packages/core/platform/bundles/paas-full.yaml @@ -105,6 +105,12 @@ releases: disableTelemetry: true {{- end }} +- name: lineage-controller-webhook + releaseName: lineage-controller-webhook + chart: cozy-lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller,cilium,kubeovn,cert-manager] + - name: cozystack-resource-definition-crd releaseName: cozystack-resource-definition-crd chart: cozystack-resource-definition-crd diff --git a/packages/core/platform/bundles/paas-hosted.yaml b/packages/core/platform/bundles/paas-hosted.yaml index 5526d2a7..a76b8b59 100644 --- a/packages/core/platform/bundles/paas-hosted.yaml +++ b/packages/core/platform/bundles/paas-hosted.yaml @@ -52,6 +52,12 @@ releases: disableTelemetry: true {{- end }} +- name: lineage-controller-webhook + releaseName: lineage-controller-webhook + chart: cozy-lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller,cert-manager] + - name: cozystack-resource-definition-crd releaseName: cozystack-resource-definition-crd chart: cozystack-resource-definition-crd diff --git a/packages/system/cozystack-controller/templates/certmanager.yaml b/packages/system/cozystack-controller/templates/certmanager.yaml deleted file mode 100644 index 6d9bce7d..00000000 --- a/packages/system/cozystack-controller/templates/certmanager.yaml +++ /dev/null @@ -1,45 +0,0 @@ -apiVersion: cert-manager.io/v1 -kind: Issuer -metadata: - name: cozystack-controller-webhook-selfsigned - namespace: {{ .Release.Namespace }} -spec: - selfSigned: {} ---- -apiVersion: cert-manager.io/v1 -kind: Certificate -metadata: - name: cozystack-controller-webhook-ca - namespace: {{ .Release.Namespace }} -spec: - secretName: cozystack-controller-webhook-ca - duration: 43800h # 5 years - commonName: cozystack-controller-webhook-ca - issuerRef: - name: cozystack-controller-webhook-selfsigned - isCA: true ---- -apiVersion: cert-manager.io/v1 -kind: Issuer -metadata: - name: cozystack-controller-webhook-ca - namespace: {{ .Release.Namespace }} -spec: - ca: - secretName: cozystack-controller-webhook-ca ---- -apiVersion: cert-manager.io/v1 -kind: Certificate -metadata: - name: cozystack-controller-webhook - namespace: {{ .Release.Namespace }} -spec: - secretName: cozystack-controller-webhook-cert - duration: 8760h - renewBefore: 720h - issuerRef: - name: cozystack-controller-webhook-ca - commonName: cozystack-controller - dnsNames: - - cozystack-controller - - cozystack-controller.{{ .Release.Namespace }}.svc diff --git a/packages/system/cozystack-controller/templates/deployment.yaml b/packages/system/cozystack-controller/templates/deployment.yaml index 318ec3b2..bac865ef 100644 --- a/packages/system/cozystack-controller/templates/deployment.yaml +++ b/packages/system/cozystack-controller/templates/deployment.yaml @@ -28,15 +28,3 @@ spec: {{- if .Values.cozystackController.disableTelemetry }} - --disable-telemetry {{- end }} - ports: - - name: webhook - containerPort: 9443 - volumeMounts: - - name: webhook-certs - mountPath: /tmp/k8s-webhook-server/serving-certs - readOnly: true - volumes: - - name: webhook-certs - secret: - secretName: cozystack-controller-webhook-cert - defaultMode: 0400 diff --git a/packages/system/lineage-controller-webhook/.gitignore b/packages/system/lineage-controller-webhook/.gitignore new file mode 100644 index 00000000..ada68ff0 --- /dev/null +++ b/packages/system/lineage-controller-webhook/.gitignore @@ -0,0 +1,27 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +bin/* +Dockerfile.cross + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Go workspace file +go.work + +# Kubernetes Generated files - skip generated files, except for vendored files +!vendor/**/zz_generated.* + +# editor and IDE paraphernalia +.idea +.vscode +*.swp +*.swo +*~ diff --git a/packages/system/lineage-controller-webhook/Chart.yaml b/packages/system/lineage-controller-webhook/Chart.yaml new file mode 100644 index 00000000..5b262f05 --- /dev/null +++ b/packages/system/lineage-controller-webhook/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-lineage-controller-webhook +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/lineage-controller-webhook/Makefile b/packages/system/lineage-controller-webhook/Makefile new file mode 100644 index 00000000..04d81a12 --- /dev/null +++ b/packages/system/lineage-controller-webhook/Makefile @@ -0,0 +1,18 @@ +NAME=lineage-controller-webhook +NAMESPACE=cozy-system + +include ../../../scripts/common-envs.mk +include ../../../scripts/package.mk + +image: image-lineage-controller-webhook + +image-lineage-controller-webhook: + docker buildx build -f images/lineage-controller-webhook/Dockerfile ../../.. \ + --tag $(REGISTRY)/lineage-controller-webhook:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/lineage-controller-webhook:latest \ + --cache-to type=inline \ + --metadata-file images/lineage-controller-webhook.json \ + $(BUILDX_ARGS) + IMAGE="$(REGISTRY)/lineage-controller-webhook:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/lineage-controller-webhook.json -o json -r)" \ + yq -i '.lineageControllerWebhook.image = strenv(IMAGE)' values.yaml + rm -f images/lineage-controller-webhook.json diff --git a/packages/system/lineage-controller-webhook/images/lineage-controller-webhook/Dockerfile b/packages/system/lineage-controller-webhook/images/lineage-controller-webhook/Dockerfile new file mode 100644 index 00000000..e043e472 --- /dev/null +++ b/packages/system/lineage-controller-webhook/images/lineage-controller-webhook/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 /lineage-controller-webhook cmd/lineage-controller-webhook/main.go + +FROM scratch + +COPY --from=builder /lineage-controller-webhook /lineage-controller-webhook +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt + +ENTRYPOINT ["/lineage-controller-webhook"] diff --git a/packages/system/lineage-controller-webhook/templates/certmanager.yaml b/packages/system/lineage-controller-webhook/templates/certmanager.yaml new file mode 100644 index 00000000..c2dc18d2 --- /dev/null +++ b/packages/system/lineage-controller-webhook/templates/certmanager.yaml @@ -0,0 +1,45 @@ +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: lineage-controller-webhook-selfsigned + namespace: {{ .Release.Namespace }} +spec: + selfSigned: {} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: lineage-controller-webhook-ca + namespace: {{ .Release.Namespace }} +spec: + secretName: lineage-controller-webhook-ca + duration: 43800h # 5 years + commonName: lineage-controller-webhook-ca + issuerRef: + name: lineage-controller-webhook-selfsigned + isCA: true +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: lineage-controller-webhook-ca + namespace: {{ .Release.Namespace }} +spec: + ca: + secretName: lineage-controller-webhook-ca +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: lineage-controller-webhook + namespace: {{ .Release.Namespace }} +spec: + secretName: lineage-controller-webhook-cert + duration: 8760h + renewBefore: 720h + issuerRef: + name: lineage-controller-webhook-ca + commonName: lineage-controller-webhook + dnsNames: + - lineage-controller-webhook + - lineage-controller-webhook.{{ .Release.Namespace }}.svc diff --git a/packages/system/lineage-controller-webhook/templates/daemonset.yaml b/packages/system/lineage-controller-webhook/templates/daemonset.yaml new file mode 100644 index 00000000..177bcd8b --- /dev/null +++ b/packages/system/lineage-controller-webhook/templates/daemonset.yaml @@ -0,0 +1,46 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: lineage-controller-webhook + labels: + app: lineage-controller-webhook +spec: + selector: + matchLabels: + app: lineage-controller-webhook + template: + metadata: + labels: + app: lineage-controller-webhook + spec: + nodeSelector: + node-role.kubernetes.io/control-plane: "" + tolerations: + - key: "node-role.kubernetes.io/control-plane" + operator: "Exists" + effect: "NoSchedule" + - key: "node-role.kubernetes.io/master" + operator: "Exists" + effect: "NoSchedule" + serviceAccountName: lineage-controller-webhook + containers: + - name: lineage-controller-webhook + image: "{{ .Values.lineageControllerWebhook.image }}" + args: + {{- if .Values.lineageControllerWebhook.debug }} + - --zap-log-level=debug + {{- else }} + - --zap-log-level=info + {{- end }} + ports: + - name: webhook + containerPort: 9443 + volumeMounts: + - name: webhook-certs + mountPath: /tmp/k8s-webhook-server/serving-certs + readOnly: true + volumes: + - name: webhook-certs + secret: + secretName: lineage-controller-webhook-cert + defaultMode: 0400 diff --git a/packages/system/cozystack-controller/templates/mutatingwebhookconfiguration.yaml b/packages/system/lineage-controller-webhook/templates/mutatingwebhookconfiguration.yaml similarity index 81% rename from packages/system/cozystack-controller/templates/mutatingwebhookconfiguration.yaml rename to packages/system/lineage-controller-webhook/templates/mutatingwebhookconfiguration.yaml index f246865c..88b62a21 100644 --- a/packages/system/cozystack-controller/templates/mutatingwebhookconfiguration.yaml +++ b/packages/system/lineage-controller-webhook/templates/mutatingwebhookconfiguration.yaml @@ -3,7 +3,7 @@ kind: MutatingWebhookConfiguration metadata: name: lineage annotations: - cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/cozystack-controller-webhook + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/lineage-controller-webhook labels: app: cozystack-controller webhooks: @@ -12,7 +12,7 @@ webhooks: sideEffects: None clientConfig: service: - name: cozystack-controller + name: lineage-controller-webhook namespace: {{ .Release.Namespace }} path: /mutate-lineage rules: @@ -40,3 +40,7 @@ webhooks: values: - kube-system - default + objectSelector: + matchExpressions: + - key: internal.cozystack.io/managed-by-cozystack + operator: DoesNotExist diff --git a/packages/system/lineage-controller-webhook/templates/rbac-bind.yaml b/packages/system/lineage-controller-webhook/templates/rbac-bind.yaml new file mode 100644 index 00000000..9a509d08 --- /dev/null +++ b/packages/system/lineage-controller-webhook/templates/rbac-bind.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: lineage-controller-webhook +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: lineage-controller-webhook +subjects: +- kind: ServiceAccount + name: lineage-controller-webhook + namespace: {{ .Release.Namespace }} diff --git a/packages/system/lineage-controller-webhook/templates/rbac.yaml b/packages/system/lineage-controller-webhook/templates/rbac.yaml new file mode 100644 index 00000000..d8b3f871 --- /dev/null +++ b/packages/system/lineage-controller-webhook/templates/rbac.yaml @@ -0,0 +1,8 @@ +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: lineage-controller-webhook +rules: +- apiGroups: ['*'] + resources: ['*'] + verbs: ["get", "list", "watch"] diff --git a/packages/system/lineage-controller-webhook/templates/sa.yaml b/packages/system/lineage-controller-webhook/templates/sa.yaml new file mode 100644 index 00000000..a17761f0 --- /dev/null +++ b/packages/system/lineage-controller-webhook/templates/sa.yaml @@ -0,0 +1,4 @@ +kind: ServiceAccount +apiVersion: v1 +metadata: + name: lineage-controller-webhook diff --git a/packages/system/cozystack-controller/templates/service.yaml b/packages/system/lineage-controller-webhook/templates/service.yaml similarity index 55% rename from packages/system/cozystack-controller/templates/service.yaml rename to packages/system/lineage-controller-webhook/templates/service.yaml index 8cc0eb61..c5df90fb 100644 --- a/packages/system/cozystack-controller/templates/service.yaml +++ b/packages/system/lineage-controller-webhook/templates/service.yaml @@ -1,10 +1,11 @@ apiVersion: v1 kind: Service metadata: - name: cozystack-controller + name: lineage-controller-webhook labels: - app: cozystack-controller + app: lineage-controller-webhook spec: + internalTrafficPolicy: Local type: ClusterIP ports: - port: 443 @@ -12,4 +13,4 @@ spec: protocol: TCP name: webhook selector: - app: cozystack-controller + app: lineage-controller-webhook diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml new file mode 100644 index 00000000..068de2d6 --- /dev/null +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -0,0 +1,3 @@ +lineageControllerWebhook: + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.0@sha256:845b8e68cbc277c2303080bcd55597e4334610d396dad258ad56fd906530acc3 + debug: false From 1b46ff3f6b90bd91fb311c5eb52f51da9822fb09 Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Wed, 15 Oct 2025 11:37:24 +0300 Subject: [PATCH 09/76] [platform] Better migration for 0.36.2->0.37.2+ For users upgrading from 0.36.2 directly to 0.37.2+, where the lineage-controller-webhook is broken out of the Cozystack controller into a separate daemonset, the existing migration script of 0.36->0.37.0 is insufficient. This patch ensures the presence of the new version of the lineage webhook and fixes a bug in the migration script where the readiness of the webhook was not appropriately verified. ```release-note [platform] Improved migration script when skipping versions 0.37.0 and 0.37.1 during upgrades. ``` Signed-off-by: Timofei Larkin (cherry picked from commit bf1ece5f7c4b8259d8be664607e64a52b07a501d) --- scripts/migrations/20 | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/migrations/20 b/scripts/migrations/20 index 7e306126..1a262ea7 100755 --- a/scripts/migrations/20 +++ b/scripts/migrations/20 @@ -26,9 +26,16 @@ cozypkg -n cozy-system -C packages/system/cozystack-resource-definition-crd appl cozypkg -n cozy-system -C packages/system/cozystack-resource-definitions apply cozystack-resource-definitions --plain cozypkg -n cozy-system -C packages/system/cozystack-api apply cozystack-api --plain helm upgrade --install -n cozy-system cozystack-controller ./packages/system/cozystack-controller/ --take-ownership +helm upgrade --install -n cozy-system lineage-controller-webhook ./packages/system/lineage-controller-webhook/ --take-ownership sleep 5 -timeout 60 sh -c 'until kubectl create service clusterip lineage-webhook-test --clusterip="None" --dry-run=server; do sleep 1; done' +kubectl delete ns cozy-lineage-webhook-test --ignore-not-found && kubectl create ns cozy-lineage-webhook-test +cleanup_test_ns() { + kubectl delete ns cozy-lineage-webhook-test --ignore-not-found +} +trap cleanup_test_ns ERR +timeout 60 sh -c 'until kubectl -n cozy-lineage-webhook-test create service clusterip lineage-webhook-test --clusterip="None" --dry-run=server; do sleep 1; done' +cleanup_test_ns kubectl wait deployment/cozystack-api -n cozy-system --timeout=4m --for=condition=available || exit 1 kubectl wait deployment/cozystack-controller -n cozy-system --timeout=4m --for=condition=available || exit 1 From ffcc55c58816cb4714b5b43e439f60e55bbdbfda Mon Sep 17 00:00:00 2001 From: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> Date: Wed, 15 Oct 2025 10:56:27 +0000 Subject: [PATCH 10/76] Prepare release v0.37.2 Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> --- packages/apps/kubernetes/images/kubevirt-csi-driver.tag | 2 +- packages/core/installer/values.yaml | 2 +- packages/core/testing/values.yaml | 2 +- packages/extra/bootbox/images/matchbox.tag | 2 +- packages/extra/seaweedfs/images/objectstorage-sidecar.tag | 2 +- packages/system/bucket/images/s3manager.tag | 2 +- packages/system/cozystack-api/values.yaml | 2 +- packages/system/cozystack-controller/values.yaml | 4 ++-- packages/system/dashboard/templates/configmap.yaml | 2 +- packages/system/dashboard/values.yaml | 6 +++--- packages/system/kamaji/values.yaml | 4 ++-- packages/system/kubeovn-plunger/values.yaml | 2 +- packages/system/kubeovn-webhook/values.yaml | 2 +- packages/system/kubeovn/values.yaml | 2 +- packages/system/kubevirt-csi-node/values.yaml | 2 +- packages/system/lineage-controller-webhook/values.yaml | 2 +- packages/system/objectstorage-controller/values.yaml | 2 +- packages/system/seaweedfs/values.yaml | 2 +- 18 files changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag index d0e37aee..67abc9d7 100644 --- a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag +++ b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:c8b08084a86251cdd18e237de89b695bca0e4f7eb1f1f6ddc2b903b4d74ea5ff +ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:01667d56186c33c0de75be6da82d0f1164a4592bfec86639cf571457b212075e diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index b81a040a..9d09e1fa 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:v0.37.1@sha256:67aa398836ad240a3af3c4108ef61c36c1ba11989ab9fbc1d5f003456dcc949c + image: ghcr.io/cozystack/cozystack/installer:v0.37.2@sha256:c7c2ed6f16c6db1797650b7a53b65c9db8d4f10cf0917f5ad4389b054ea25cba diff --git a/packages/core/testing/values.yaml b/packages/core/testing/values.yaml index 6348000f..ec882839 100755 --- a/packages/core/testing/values.yaml +++ b/packages/core/testing/values.yaml @@ -1,2 +1,2 @@ e2e: - image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.1@sha256:82e42c2416d6704786d37920d162416efc02083a1c30605d22b8213198b515a8 + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.2@sha256:2071441e9dbca15bd8fe4029d2e41be8fea6066f127969bd74b41a1c3d4ca3ef diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index 852bfa66..a869132a 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v0.37.1@sha256:160c583a1c05ae06e304f7065dbf5ddad0bf9b59bf1a227f8a82f9d331d29c9d +ghcr.io/cozystack/cozystack/matchbox:v0.37.2@sha256:dcd27eaff34a2b2425d34137d088d1b8d55e58b192ecb0d2dabde7e6a88d3fbf diff --git a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag index f018dee2..3ce2907e 100644 --- a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag +++ b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.1@sha256:f166f09cdc9cdbb758209883819ab8261a3793bc1d7a6b6685efd5a2b2930847 +ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.2@sha256:1a739164b518dc395375ce9057bb582b5c539555f0ee2f2df7f931b23a1c4a48 diff --git a/packages/system/bucket/images/s3manager.tag b/packages/system/bucket/images/s3manager.tag index 9b25469d..f9433692 100644 --- a/packages/system/bucket/images/s3manager.tag +++ b/packages/system/bucket/images/s3manager.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:26e241c285e3cf20c043545bf25517ec52f000a738b7ed9168656b58e59749a3 +ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:2ac8139c13d5a9816e5ea7c78da30777f7119ea0cd4f18f44048fa121f977902 diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index 7d24b1a4..edc5e060 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,2 +1,2 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.1@sha256:dc8f90f7c9551f1487670e512734939bf1585568fec04e74e4c5cac0bcabb1b9 + image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.2@sha256:1ce7d2658a4b705ef0a1c09b53d8708c78874775722558ae05aa77ed76cbe7ec diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index a877142a..7cf17f28 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,5 +1,5 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.1@sha256:a78f8f0796a4b56a36a8f0abd3a502b61cf2745a50b9d54fdb2e13b3e691509b + image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.2@sha256:26adefda0a0c23e6e2edd9fec681ec313b75436ec5ccfede88d772298fce3aa1 debug: false disableTelemetry: false - cozystackVersion: "v0.37.1" + cozystackVersion: "v0.37.2" diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml index 7e61611e..1abb473d 100644 --- a/packages/system/dashboard/templates/configmap.yaml +++ b/packages/system/dashboard/templates/configmap.yaml @@ -1,6 +1,6 @@ {{- $brandingConfig:= lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} -{{- $tenantText := "v0.37.1" }} +{{- $tenantText := "v0.37.2" }} {{- $footerText := "Cozystack" }} {{- $titleText := "Cozystack Dashboard" }} {{- $logoText := "false" }} diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index dfe0afe2..13b2ec7e 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,6 +1,6 @@ openapiUI: - image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.1@sha256:3fd556689816ac2a0a3af9c7a2e4025936f9fc716e57e9aabb8cc1b576819aae + image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.2@sha256:ea6f5c1632ad424b31ce329c20426bd04d520aa769aa0c78b35d730605564a60 openapiUIK8sBff: - image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.1@sha256:fe3f570adf35798c5a46bee0737975b6d8432eb5b0c0e2a6d529eb330c4a29f9 + image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.2@sha256:995bb28ee4fb0263c70267f63b20581b64666522f931333df90a58d4c327a19c tokenProxy: - image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.1@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b + image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.2@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b diff --git a/packages/system/kamaji/values.yaml b/packages/system/kamaji/values.yaml index 0fd36dc0..6400973e 100644 --- a/packages/system/kamaji/values.yaml +++ b/packages/system/kamaji/values.yaml @@ -3,7 +3,7 @@ kamaji: deploy: false image: pullPolicy: IfNotPresent - tag: v0.37.1@sha256:9f4fd5045ede2909fbaf2572e4138fcbd8921071ecf8f08446257fddd0e6f655 + tag: v0.37.2@sha256:ceefafb628e0500deccb5af7a3303e0b6348ac1bbdffaa6de7fd5ec004caadc6 repository: ghcr.io/cozystack/cozystack/kamaji resources: limits: @@ -13,4 +13,4 @@ kamaji: cpu: 100m memory: 100Mi extraArgs: - - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.1@sha256:9f4fd5045ede2909fbaf2572e4138fcbd8921071ecf8f08446257fddd0e6f655 + - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.2@sha256:ceefafb628e0500deccb5af7a3303e0b6348ac1bbdffaa6de7fd5ec004caadc6 diff --git a/packages/system/kubeovn-plunger/values.yaml b/packages/system/kubeovn-plunger/values.yaml index b7c522e3..bc1757ad 100644 --- a/packages/system/kubeovn-plunger/values.yaml +++ b/packages/system/kubeovn-plunger/values.yaml @@ -1,4 +1,4 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.1@sha256:ec5794c58ec4f6a6041555c91ae2e8be01c21af4f34bb1940551b9e7ee0eaf6f +image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.2@sha256:781e06992871a7e6e6522ecf68b1e2806c710821f85949c9141872cb92312208 ovnCentralName: ovn-central diff --git a/packages/system/kubeovn-webhook/values.yaml b/packages/system/kubeovn-webhook/values.yaml index 9931c3bf..dd5d1c8a 100644 --- a/packages/system/kubeovn-webhook/values.yaml +++ b/packages/system/kubeovn-webhook/values.yaml @@ -1,3 +1,3 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.1@sha256:f803cf5e7a2f1fa2bcf7003f8a5931e5d7bccddce7f92c88029292b4826c9050 +image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.2@sha256:a2e6c6619270769d56beb1166d09fdc541a7754757d567ede558e8ebdeae397a diff --git a/packages/system/kubeovn/values.yaml b/packages/system/kubeovn/values.yaml index 628b9aa6..5b91da02 100644 --- a/packages/system/kubeovn/values.yaml +++ b/packages/system/kubeovn/values.yaml @@ -64,4 +64,4 @@ global: images: kubeovn: repository: kubeovn - tag: v1.14.5@sha256:f9b88f3276b84c892853b42ca06edfc4e8bf53399d902f993459add03cb51a54 + tag: v1.14.5@sha256:0b98310bbe8c8f49f4b45d4cb12a52daa5f3e451ea9533db8d55c5d02434b31e diff --git a/packages/system/kubevirt-csi-node/values.yaml b/packages/system/kubevirt-csi-node/values.yaml index a7fb1e67..c681e727 100644 --- a/packages/system/kubevirt-csi-node/values.yaml +++ b/packages/system/kubevirt-csi-node/values.yaml @@ -1,3 +1,3 @@ storageClass: replicated csiDriver: - image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:c8b08084a86251cdd18e237de89b695bca0e4f7eb1f1f6ddc2b903b4d74ea5ff + image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:01667d56186c33c0de75be6da82d0f1164a4592bfec86639cf571457b212075e diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index 068de2d6..1cb539fe 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,3 +1,3 @@ lineageControllerWebhook: - image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.0@sha256:845b8e68cbc277c2303080bcd55597e4334610d396dad258ad56fd906530acc3 + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.2@sha256:b5f88cafe82809aeb06d92bb4127efa322aa666a56c22a4b664091160166cf55 debug: false diff --git a/packages/system/objectstorage-controller/values.yaml b/packages/system/objectstorage-controller/values.yaml index fed50331..4e03ee09 100644 --- a/packages/system/objectstorage-controller/values.yaml +++ b/packages/system/objectstorage-controller/values.yaml @@ -1,3 +1,3 @@ objectstorage: controller: - image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.1@sha256:5f2eed05d19ba971806374834cb16ca49282aac76130194c00b213c79ce3e10d" + image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.2@sha256:6d0ca2d95a9bfd29fb2f0e8b2b8a84b16c270830933457ed8c5c27ae3c6d2de7" diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index 007de122..420386c8 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -120,7 +120,7 @@ seaweedfs: bucketClassName: "seaweedfs" region: "" sidecar: - image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.1@sha256:f166f09cdc9cdbb758209883819ab8261a3793bc1d7a6b6685efd5a2b2930847" + image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.2@sha256:1a739164b518dc395375ce9057bb582b5c539555f0ee2f2df7f931b23a1c4a48" certificates: commonName: "SeaweedFS CA" ipAddresses: [] From ee95353342c8da48ca52a340dca0f78aec54cdcb Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Thu, 16 Oct 2025 16:58:47 +0400 Subject: [PATCH 11/76] [apps] Make VM service user facing (#1523) (cherry picked from commit c1edc5d7114470190cdcd8fc25c9a6cdab83a613) Signed-off-by: Timofei Larkin --- .../cozyrds/virtual-machine.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/system/cozystack-resource-definitions/cozyrds/virtual-machine.yaml b/packages/system/cozystack-resource-definitions/cozyrds/virtual-machine.yaml index f786678e..7a2a054a 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/virtual-machine.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/virtual-machine.yaml @@ -32,3 +32,8 @@ spec: secrets: exclude: [] include: [] + services: + exclude: [] + include: + - resourceNames: + - virtual-machine-{{ .name }} From 0e4fe7a33ecc56bb5d6f12c62253cf714fa8e204 Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Thu, 16 Oct 2025 17:35:16 +0400 Subject: [PATCH 12/76] [dashboard] Show service LB IP (#1524) Fix an incorrect JSON path that prevented Service LoadBalancer IPs from rendering in the table view. (cherry picked from commit 466f0fed52460b89c17053475220f64b26a70ba4) Signed-off-by: Timofei Larkin --- internal/controller/dashboard/static_refactored.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/controller/dashboard/static_refactored.go b/internal/controller/dashboard/static_refactored.go index 24a602d3..3caf8edb 100644 --- a/internal/controller/dashboard/static_refactored.go +++ b/internal/controller/dashboard/static_refactored.go @@ -142,7 +142,7 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid createCustomColumnsOverride("stock-namespace-/v1/services", []any{ createCustomColumnWithJsonPath("Name", ".metadata.name", "S", "service", getColorForType("service"), "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-service-details/{reqsJsonPath[0]['.metadata.name']['-']}"), createStringColumn("ClusterIP", ".spec.clusterIP"), - createStringColumn("LoadbalancerIP", ".spec.loadBalancerIP"), + createStringColumn("LoadbalancerIP", ".status.loadBalancer.ingress[0].ip"), createTimestampColumn("Created", ".metadata.creationTimestamp"), }), From a5cdaddbb4ab209634ee0d7da5343578a20d8834 Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Thu, 16 Oct 2025 18:06:14 +0400 Subject: [PATCH 13/76] [lineage] Check for nil chart in HelmRelease (#1525) ## What this PR does Some HelmReleases use `chartRef` instead of `chart`. If the lineage webhook finds such a HelmRelease, a nil pointer dereference happens. This patch adds a nil check to guard against this. ### Release note ```release-note [lineage] Add a nil check to guard against HelmReleases with a nil .spec.chart field when traversing the ownership tree. ``` (cherry picked from commit d57f9acc7a447babba13fb72138a52b31aa327d3) Signed-off-by: Timofei Larkin --- internal/lineagecontrollerwebhook/config.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/lineagecontrollerwebhook/config.go b/internal/lineagecontrollerwebhook/config.go index c10c5a77..4ca45c13 100644 --- a/internal/lineagecontrollerwebhook/config.go +++ b/internal/lineagecontrollerwebhook/config.go @@ -38,6 +38,9 @@ func (l *LineageControllerWebhook) Map(hr *helmv2.HelmRelease) (string, string, if !ok { return "", "", "", fmt.Errorf("failed to load chart-app mapping from config") } + if hr.Spec.Chart == nil { + return "", "", "", fmt.Errorf("cannot map helm release %s/%s to dynamic app", hr.Namespace, hr.Name) + } s := hr.Spec.Chart.Spec val, ok := cfg.chartAppMap[chartRef{s.SourceRef.Name, s.Chart}] if !ok { From 62f80f85b411b7beb36932149881c3eabc4e5c0d Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Fri, 17 Oct 2025 14:10:58 +0300 Subject: [PATCH 14/76] [kamaji] Respect 3rd party labels The Kamaji controller overwrites labels on many of the resources it owns (clastix/kamaji#991). This change applies PR clastix/kamaji#992 to Cozystack's build of Kamaji, so the lineage webhook doesn't fight the Kamaji controller, causing a non-stop reconciliation loop. ```release-note [kamaji] Do not clobber third party labels on resources controlled by Kamaji. ``` Signed-off-by: Timofei Larkin (cherry picked from commit b858745cdd94733accdfed69d60df24ff80be80e) --- .../kamaji/images/kamaji/patches/992.diff | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 packages/system/kamaji/images/kamaji/patches/992.diff diff --git a/packages/system/kamaji/images/kamaji/patches/992.diff b/packages/system/kamaji/images/kamaji/patches/992.diff new file mode 100644 index 00000000..cd9c2ad3 --- /dev/null +++ b/packages/system/kamaji/images/kamaji/patches/992.diff @@ -0,0 +1,156 @@ +diff --git a/internal/resources/api_server_certificate.go b/internal/resources/api_server_certificate.go +index 436cdf9..4702b6c 100644 +--- a/internal/resources/api_server_certificate.go ++++ b/internal/resources/api_server_certificate.go +@@ -108,6 +108,7 @@ func (r *APIServerCertificate) mutate(ctx context.Context, tenantControlPlane *k + } + + r.resource.SetLabels(utilities.MergeMaps( ++ r.resource.GetLabels(), + utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()), + map[string]string{ + constants.ControllerLabelResource: "x509", +diff --git a/internal/resources/api_server_kubelet_client_certificate.go b/internal/resources/api_server_kubelet_client_certificate.go +index 85b4d42..da18db4 100644 +--- a/internal/resources/api_server_kubelet_client_certificate.go ++++ b/internal/resources/api_server_kubelet_client_certificate.go +@@ -95,6 +95,7 @@ func (r *APIServerKubeletClientCertificate) mutate(ctx context.Context, tenantCo + } + + r.resource.SetLabels(utilities.MergeMaps( ++ r.resource.GetLabels(), + utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()), + map[string]string{ + constants.ControllerLabelResource: "x509", +diff --git a/internal/resources/ca_certificate.go b/internal/resources/ca_certificate.go +index 5425b0b..625273f 100644 +--- a/internal/resources/ca_certificate.go ++++ b/internal/resources/ca_certificate.go +@@ -137,7 +137,7 @@ func (r *CACertificate) mutate(ctx context.Context, tenantControlPlane *kamajiv1 + corev1.TLSPrivateKeyKey: ca.PrivateKey, + } + +- r.resource.SetLabels(utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName())) ++ r.resource.SetLabels(utilities.MergeMaps(r.resource.GetLabels(), utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()))) + + utilities.SetObjectChecksum(r.resource, r.resource.Data) + +diff --git a/internal/resources/datastore/datastore_certificate.go b/internal/resources/datastore/datastore_certificate.go +index dea45ae..8492a5e 100644 +--- a/internal/resources/datastore/datastore_certificate.go ++++ b/internal/resources/datastore/datastore_certificate.go +@@ -94,6 +94,7 @@ func (r *Certificate) mutate(ctx context.Context, tenantControlPlane *kamajiv1al + r.resource.Data["ca.crt"] = ca + + r.resource.SetLabels(utilities.MergeMaps( ++ r.resource.GetLabels(), + utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()), + map[string]string{ + constants.ControllerLabelResource: "x509", +diff --git a/internal/resources/datastore/datastore_storage_config.go b/internal/resources/datastore/datastore_storage_config.go +index 7d03420..4ea9e64 100644 +--- a/internal/resources/datastore/datastore_storage_config.go ++++ b/internal/resources/datastore/datastore_storage_config.go +@@ -181,7 +181,7 @@ func (r *Config) mutate(ctx context.Context, tenantControlPlane *kamajiv1alpha1. + + utilities.SetObjectChecksum(r.resource, r.resource.Data) + +- r.resource.SetLabels(utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName())) ++ r.resource.SetLabels(utilities.MergeMaps(r.resource.GetLabels(), utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()))) + + return ctrl.SetControllerReference(tenantControlPlane, r.resource, r.Client.Scheme()) + } +diff --git a/internal/resources/front-proxy-client-certificate.go b/internal/resources/front-proxy-client-certificate.go +index f5ed67c..2dd4eda 100644 +--- a/internal/resources/front-proxy-client-certificate.go ++++ b/internal/resources/front-proxy-client-certificate.go +@@ -95,6 +95,7 @@ func (r *FrontProxyClientCertificate) mutate(ctx context.Context, tenantControlP + } + + r.resource.SetLabels(utilities.MergeMaps( ++ r.resource.GetLabels(), + utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()), + map[string]string{ + constants.ControllerLabelResource: "x509", +diff --git a/internal/resources/front_proxy_ca_certificate.go b/internal/resources/front_proxy_ca_certificate.go +index d410720..ccadc70 100644 +--- a/internal/resources/front_proxy_ca_certificate.go ++++ b/internal/resources/front_proxy_ca_certificate.go +@@ -114,7 +114,7 @@ func (r *FrontProxyCACertificate) mutate(ctx context.Context, tenantControlPlane + kubeadmconstants.FrontProxyCAKeyName: ca.PrivateKey, + } + +- r.resource.SetLabels(utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName())) ++ r.resource.SetLabels(utilities.MergeMaps(r.resource.GetLabels(), utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()))) + + utilities.SetObjectChecksum(r.resource, r.resource.Data) + +diff --git a/internal/resources/k8s_ingress_resource.go b/internal/resources/k8s_ingress_resource.go +index f2e014f..e1aef59 100644 +--- a/internal/resources/k8s_ingress_resource.go ++++ b/internal/resources/k8s_ingress_resource.go +@@ -147,7 +147,7 @@ func (r *KubernetesIngressResource) Define(_ context.Context, tenantControlPlane + + func (r *KubernetesIngressResource) mutate(tenantControlPlane *kamajiv1alpha1.TenantControlPlane) controllerutil.MutateFn { + return func() error { +- labels := utilities.MergeMaps(utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()), tenantControlPlane.Spec.ControlPlane.Ingress.AdditionalMetadata.Labels) ++ labels := utilities.MergeMaps(r.resource.GetLabels(), utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()), tenantControlPlane.Spec.ControlPlane.Ingress.AdditionalMetadata.Labels) + r.resource.SetLabels(labels) + + annotations := utilities.MergeMaps(r.resource.GetAnnotations(), tenantControlPlane.Spec.ControlPlane.Ingress.AdditionalMetadata.Annotations) +diff --git a/internal/resources/k8s_service_resource.go b/internal/resources/k8s_service_resource.go +index 7e7f11f..9c30145 100644 +--- a/internal/resources/k8s_service_resource.go ++++ b/internal/resources/k8s_service_resource.go +@@ -76,7 +76,12 @@ func (r *KubernetesServiceResource) mutate(ctx context.Context, tenantControlPla + address, _ := tenantControlPlane.DeclaredControlPlaneAddress(ctx, r.Client) + + return func() error { +- labels := utilities.MergeMaps(utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()), tenantControlPlane.Spec.ControlPlane.Service.AdditionalMetadata.Labels) ++ labels := utilities.MergeMaps( ++ r.resource.GetLabels(), ++ utilities.KamajiLabels( ++ tenantControlPlane.GetName(), r.GetName()), ++ tenantControlPlane.Spec.ControlPlane.Service.AdditionalMetadata.Labels, ++ ) + r.resource.SetLabels(labels) + + annotations := utilities.MergeMaps(r.resource.GetAnnotations(), tenantControlPlane.Spec.ControlPlane.Service.AdditionalMetadata.Annotations) +diff --git a/internal/resources/kubeadm_config.go b/internal/resources/kubeadm_config.go +index ae4cfc0..98dc36d 100644 +--- a/internal/resources/kubeadm_config.go ++++ b/internal/resources/kubeadm_config.go +@@ -89,7 +89,7 @@ func (r *KubeadmConfigResource) mutate(ctx context.Context, tenantControlPlane * + return err + } + +- r.resource.SetLabels(utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName())) ++ r.resource.SetLabels(utilities.MergeMaps(r.resource.GetLabels(), utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()))) + + params := kubeadm.Parameters{ + TenantControlPlaneAddress: address, +diff --git a/internal/resources/kubeconfig.go b/internal/resources/kubeconfig.go +index a87da7f..bd77676 100644 +--- a/internal/resources/kubeconfig.go ++++ b/internal/resources/kubeconfig.go +@@ -163,6 +163,7 @@ func (r *KubeconfigResource) mutate(ctx context.Context, tenantControlPlane *kam + } + + r.resource.SetLabels(utilities.MergeMaps( ++ r.resource.GetLabels(), + utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()), + map[string]string{ + constants.ControllerLabelResource: "kubeconfig", +diff --git a/internal/resources/sa_certificate.go b/internal/resources/sa_certificate.go +index b53c7b0..4001eca 100644 +--- a/internal/resources/sa_certificate.go ++++ b/internal/resources/sa_certificate.go +@@ -113,7 +113,7 @@ func (r *SACertificate) mutate(ctx context.Context, tenantControlPlane *kamajiv1 + kubeadmconstants.ServiceAccountPrivateKeyName: sa.PrivateKey, + } + +- r.resource.SetLabels(utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName())) ++ r.resource.SetLabels(utilities.MergeMaps(r.resource.GetLabels(), utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()))) + + utilities.SetObjectChecksum(r.resource, r.resource.Data) + From 5703e16a80ff67c3903fb8dd95007edf839f39d2 Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Fri, 24 Oct 2025 10:33:08 +0400 Subject: [PATCH 15/76] [monitoring] add settings alert for slack (#1545) **What this PR does** This PR adds configuration for sending alerts from Alerta to Slack. **Key changes** Added Slack integration configuration in Alerta settings. --- packages/extra/monitoring/README.md | 2 ++ .../monitoring/templates/alerta/alerta.yaml | 18 +++++++++++++++++- packages/extra/monitoring/values.schema.json | 11 +++++++++++ packages/extra/monitoring/values.yaml | 5 +++++ .../cozyrds/monitoring.yaml | 4 ++-- 5 files changed, 37 insertions(+), 3 deletions(-) diff --git a/packages/extra/monitoring/README.md b/packages/extra/monitoring/README.md index c97b13de..06dbc97e 100644 --- a/packages/extra/monitoring/README.md +++ b/packages/extra/monitoring/README.md @@ -72,6 +72,8 @@ | `alerta.alerts.telegram.token` | Telegram token for your bot | `string` | `""` | | `alerta.alerts.telegram.chatID` | Specify multiple ID's separated by comma. Get yours in https://t.me/chatid_echo_bot | `string` | `""` | | `alerta.alerts.telegram.disabledSeverity` | List of severity without alerts, separated by comma like: "informational,warning" | `string` | `""` | +| `alerta.alerts.slack` | Configuration for Slack alerts | `*object` | `null` | +| `alerta.alerts.slack.url` | Configuration uri for Slack alerts | `*string` | `""` | ### Grafana configuration diff --git a/packages/extra/monitoring/templates/alerta/alerta.yaml b/packages/extra/monitoring/templates/alerta/alerta.yaml index bec7b825..71336286 100644 --- a/packages/extra/monitoring/templates/alerta/alerta.yaml +++ b/packages/extra/monitoring/templates/alerta/alerta.yaml @@ -109,9 +109,20 @@ spec: - name: AUTH_REQUIRED value: "True" + {{- $plugins := list }} {{- if and .Values.alerta.alerts.telegram.chatID .Values.alerta.alerts.telegram.token }} + {{- $plugins = append $plugins "telegram" }} + {{- end }} + {{- if .Values.alerta.alerts.slack.url }} + {{- $plugins = append $plugins "slack" }} + {{- end }} + + {{- if gt (len $plugins) 0 }} - name: "PLUGINS" - value: "telegram" + value: "{{ default "" (join "," $plugins) }}" + {{- end }} + + {{- if and .Values.alerta.alerts.telegram.chatID .Values.alerta.alerts.telegram.token }} - name: TELEGRAM_CHAT_ID value: "{{ .Values.alerta.alerts.telegram.chatID }}" - name: TELEGRAM_TOKEN @@ -122,6 +133,11 @@ spec: value: "{{ .Values.alerta.alerts.telegram.disabledSeverity }}" {{- end }} + {{- if .Values.alerta.alerts.slack.url }} + - name: "SLACK_WEBHOOK_URL" + value: "{{ .Values.alerta.alerts.slack.url }}" + {{- end }} + ports: - name: http containerPort: 8080 diff --git a/packages/extra/monitoring/values.schema.json b/packages/extra/monitoring/values.schema.json index 36f1c0c3..505b5bef 100644 --- a/packages/extra/monitoring/values.schema.json +++ b/packages/extra/monitoring/values.schema.json @@ -12,6 +12,17 @@ "type": "object", "default": {}, "properties": { + "slack": { + "description": "Configuration for Slack alerts", + "type": "object", + "default": {}, + "properties": { + "url": { + "description": "Configuration uri for Slack alerts", + "type": "string" + } + } + }, "telegram": { "description": "Configuration for Telegram alerts", "type": "object", diff --git a/packages/extra/monitoring/values.yaml b/packages/extra/monitoring/values.yaml index 02155ce0..72aab9a9 100644 --- a/packages/extra/monitoring/values.yaml +++ b/packages/extra/monitoring/values.yaml @@ -90,6 +90,8 @@ logsStorages: ## @field telegramAlerts.token {string} Telegram token for your bot ## @field telegramAlerts.chatID {string} Specify multiple ID's separated by comma. Get yours in https://t.me/chatid_echo_bot ## @field telegramAlerts.disabledSeverity {string} List of severity without alerts, separated by comma like: "informational,warning" +## @field alerts.slack {*slackAlerts} Configuration for Slack alerts +## @field slackAlerts.url {*string} Configuration uri for Slack alerts alerta: storage: 10Gi storageClassName: "" @@ -112,6 +114,9 @@ alerta: chatID: "" disabledSeverity: "" + slack: + url: "" + ## @section Grafana configuration ## @param grafana {grafana} Configuration for Grafana diff --git a/packages/system/cozystack-resource-definitions/cozyrds/monitoring.yaml b/packages/system/cozystack-resource-definitions/cozyrds/monitoring.yaml index af99f73c..82271a35 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 Alerta service","type":"object","default":{},"properties":{"alerts":{"description":"Configuration for alerts","type":"object","default":{},"properties":{"telegram":{"description":"Configuration for Telegram alerts","type":"object","default":{},"required":["chatID","disabledSeverity","token"],"properties":{"chatID":{"description":"Specify multiple ID's separated by comma. Get yours in https://t.me/chatid_echo_bot","type":"string"},"disabledSeverity":{"description":"List of severity without alerts, separated by comma like: \"informational,warning\"","type":"string"},"token":{"description":"Telegram token for your bot","type":"string"}}}}},"resources":{"description":"Resources configuration","type":"object","default":{},"properties":{"limits":{"type":"object","default":{},"properties":{"cpu":{"description":"CPU limit (maximum available CPU)","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 (maximum available memory)","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":{"type":"object","default":{},"properties":{"cpu":{"description":"CPU request (minimum available CPU)","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 (minimum available memory)","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 to store the data","type":"string"}}},"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":"Resources configuration","type":"object","default":{},"properties":{"limits":{"type":"object","default":{},"properties":{"cpu":{"description":"CPU limit (maximum available CPU)","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 (maximum available memory)","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":{"type":"object","default":{},"properties":{"cpu":{"description":"CPU request (minimum available CPU)","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 (minimum available memory)","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 the grafana externally (defaults to 'grafana' subdomain for the tenant host).","type":"string"},"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"],"properties":{"name":{"description":"Name of the storage instance","type":"string"},"retentionPeriod":{"description":"Retention period for the logs in the storage instance","type":"string","default":"1"},"storage":{"description":"Persistent Volume size for the storage instance","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 the metrics in the storage instance","type":"string"},"name":{"description":"Name of the storage instance","type":"string"},"retentionPeriod":{"description":"Retention period for the metrics in the storage instance","type":"string"},"storage":{"description":"Persistent Volume size for the storage instance","type":"string","default":"10Gi"},"storageClassName":{"description":"StorageClass used to store the data","type":"string"},"vminsert":{"description":"Configuration for vminsert component of the storage instance","type":"object","properties":{"maxAllowed":{"description":"Limits (maximum allowed/available resources )","type":"object","properties":{"cpu":{"description":"CPU limit (maximum available CPU)","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 (maximum available memory)","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":"Requests (minimum allowed/available resources)","type":"object","properties":{"cpu":{"description":"CPU request (minimum available CPU)","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 (minimum available memory)","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 component of the storage instance","type":"object","properties":{"maxAllowed":{"description":"Limits (maximum allowed/available resources )","type":"object","properties":{"cpu":{"description":"CPU limit (maximum available CPU)","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 (maximum available memory)","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":"Requests (minimum allowed/available resources)","type":"object","properties":{"cpu":{"description":"CPU request (minimum available CPU)","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 (minimum available memory)","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 component of the storage instance","type":"object","properties":{"maxAllowed":{"description":"Limits (maximum allowed/available resources )","type":"object","properties":{"cpu":{"description":"CPU limit (maximum available CPU)","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 (maximum available memory)","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":"Requests (minimum allowed/available resources)","type":"object","properties":{"cpu":{"description":"CPU request (minimum available CPU)","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 (minimum available memory)","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 Alerta service","type":"object","default":{},"properties":{"alerts":{"description":"Configuration for alerts","type":"object","default":{},"properties":{"slack":{"description":"Configuration for Slack alerts","type":"object","default":{},"properties":{"url":{"description":"Configuration uri for Slack alerts","type":"string"}}},"telegram":{"description":"Configuration for Telegram alerts","type":"object","default":{},"required":["chatID","disabledSeverity","token"],"properties":{"chatID":{"description":"Specify multiple ID's separated by comma. Get yours in https://t.me/chatid_echo_bot","type":"string"},"disabledSeverity":{"description":"List of severity without alerts, separated by comma like: \"informational,warning\"","type":"string"},"token":{"description":"Telegram token for your bot","type":"string"}}}}},"resources":{"description":"Resources configuration","type":"object","default":{},"properties":{"limits":{"type":"object","default":{},"properties":{"cpu":{"description":"CPU limit (maximum available CPU)","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 (maximum available memory)","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":{"type":"object","default":{},"properties":{"cpu":{"description":"CPU request (minimum available CPU)","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 (minimum available memory)","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 to store the data","type":"string"}}},"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":"Resources configuration","type":"object","default":{},"properties":{"limits":{"type":"object","default":{},"properties":{"cpu":{"description":"CPU limit (maximum available CPU)","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 (maximum available memory)","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":{"type":"object","default":{},"properties":{"cpu":{"description":"CPU request (minimum available CPU)","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 (minimum available memory)","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 the grafana externally (defaults to 'grafana' subdomain for the tenant host).","type":"string"},"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"],"properties":{"name":{"description":"Name of the storage instance","type":"string"},"retentionPeriod":{"description":"Retention period for the logs in the storage instance","type":"string","default":"1"},"storage":{"description":"Persistent Volume size for the storage instance","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 the metrics in the storage instance","type":"string"},"name":{"description":"Name of the storage instance","type":"string"},"retentionPeriod":{"description":"Retention period for the metrics in the storage instance","type":"string"},"storage":{"description":"Persistent Volume size for the storage instance","type":"string","default":"10Gi"},"storageClassName":{"description":"StorageClass used to store the data","type":"string"},"vminsert":{"description":"Configuration for vminsert component of the storage instance","type":"object","properties":{"maxAllowed":{"description":"Limits (maximum allowed/available resources )","type":"object","properties":{"cpu":{"description":"CPU limit (maximum available CPU)","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 (maximum available memory)","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":"Requests (minimum allowed/available resources)","type":"object","properties":{"cpu":{"description":"CPU request (minimum available CPU)","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 (minimum available memory)","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 component of the storage instance","type":"object","properties":{"maxAllowed":{"description":"Limits (maximum allowed/available resources )","type":"object","properties":{"cpu":{"description":"CPU limit (maximum available CPU)","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 (maximum available memory)","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":"Requests (minimum allowed/available resources)","type":"object","properties":{"cpu":{"description":"CPU request (minimum available CPU)","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 (minimum available memory)","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 component of the storage instance","type":"object","properties":{"maxAllowed":{"description":"Limits (maximum allowed/available resources )","type":"object","properties":{"cpu":{"description":"CPU limit (maximum available CPU)","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 (maximum available memory)","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":"Requests (minimum allowed/available resources)","type":"object","properties":{"cpu":{"description":"CPU request (minimum available CPU)","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 (minimum available memory)","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}}}}}}}}}} 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", "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"]] secrets: exclude: [] include: From 67a8fa91e8c2123b93c8f81ce40cbc30533948ff Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 31 Oct 2025 15:13:37 +0500 Subject: [PATCH 16/76] [seaweedfs] Allow users to discover their buckets (#1528) Signed-off-by: Andrei Kvapil ## What this PR does This PR enables building of `seaweedfs` image. Also backports patch from upstream https://github.com/seaweedfs/seaweedfs/pull/7335 ### Release note ```release-note [seaweedfs] Allow users to discover their buckets ``` ## Summary by CodeRabbit * **Bug Fixes** * S3 signature handling adjusted so signature verification focuses on authentication; permission checks are evaluated afterward. * **Chores** * Build process now discovers and uses remote release versions dynamically. * Introduced an optimized multi-stage container build with improved tagging and registry caching. * Added configurable image settings (global image name and image tag) for deployment. --- packages/system/seaweedfs/Makefile | 24 +++++++- .../seaweedfs/images/seaweedfs/Dockerfile | 58 +++++++++++++++++++ .../fix-signature-permission-check.diff | 58 +++++++++++++++++++ packages/system/seaweedfs/values.yaml | 3 + 4 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 packages/system/seaweedfs/images/seaweedfs/Dockerfile create mode 100644 packages/system/seaweedfs/images/seaweedfs/patches/fix-signature-permission-check.diff diff --git a/packages/system/seaweedfs/Makefile b/packages/system/seaweedfs/Makefile index c9fd7b74..a349ba82 100644 --- a/packages/system/seaweedfs/Makefile +++ b/packages/system/seaweedfs/Makefile @@ -1,12 +1,30 @@ -NAME=seaweedfs-system +export NAME=seaweedfs-system +include ../../../scripts/common-envs.mk include ../../../scripts/package.mk update: rm -rf charts mkdir -p charts - curl -sSL https://github.com/seaweedfs/seaweedfs/archive/refs/heads/master.tar.gz | \ - tar xzvf - --strip 3 -C charts seaweedfs-master/k8s/charts/seaweedfs + version=$$(git ls-remote --tags --sort="v:refname" https://github.com/seaweedfs/seaweedfs | grep -v '\^{}' | grep 'refs/tags/[0-9]' | awk -F'/' 'END{print $$3}') && \ + curl -sSL https://github.com/seaweedfs/seaweedfs/archive/refs/tags/$${version}.tar.gz | \ + tar xzvf - --strip 3 -C charts seaweedfs-$${version}/k8s/charts/seaweedfs && \ + sed -i.bak "/ARG VERSION/ s|=.*|=$${version}|g" images/seaweedfs/Dockerfile && \ + rm -f images/seaweedfs/Dockerfile.bak patch --no-backup-if-mismatch -p4 < patches/resize-api-server-annotation.diff patch --no-backup-if-mismatch -p4 < patches/fix-volume-servicemonitor.patch #patch --no-backup-if-mismatch -p4 < patches/retention-policy-delete.yaml + +image: + docker buildx build images/seaweedfs \ + --tag $(REGISTRY)/seaweedfs:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/seaweedfs:latest \ + --cache-to type=inline \ + --metadata-file images/seaweedfs.json \ + $(BUILDX_ARGS) + REGISTRY="$(REGISTRY)" \ + yq -i '.seaweedfs.image.registry = strenv(REGISTRY)' values.yaml + TAG=$(TAG)@$$(yq e '."containerimage.digest"' images/seaweedfs.json -o json -r) \ + yq -i '.seaweedfs.image.tag = strenv(TAG)' values.yaml + yq -i '.global.imageName = "seaweedfs"' values.yaml + rm -f images/seaweedfs.json diff --git a/packages/system/seaweedfs/images/seaweedfs/Dockerfile b/packages/system/seaweedfs/images/seaweedfs/Dockerfile new file mode 100644 index 00000000..43bf41cb --- /dev/null +++ b/packages/system/seaweedfs/images/seaweedfs/Dockerfile @@ -0,0 +1,58 @@ +FROM golang:1.24-alpine as builder + +ARG VERSION=3.97 +ARG TARGETOS +ARG TARGETARCH + +RUN apk add --no-cache git g++ fuse + +WORKDIR /workspace + +RUN git clone --depth 1 --branch ${VERSION} https://github.com/seaweedfs/seaweedfs.git . + +COPY patches /patches +RUN git apply /patches/*.diff + +RUN cd weed && \ + export LDFLAGS="-X github.com/seaweedfs/seaweedfs/weed/util/version.COMMIT=$(git rev-parse --short HEAD)" && \ + GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build \ + -tags "full" \ + -ldflags "-extldflags -static ${LDFLAGS}" \ + -o /usr/bin/weed + +FROM alpine AS final + +LABEL author="Chris Lu" + +COPY --from=builder /usr/bin/weed /usr/bin/ +RUN mkdir -p /etc/seaweedfs +COPY --from=builder /workspace/docker/filer.toml /etc/seaweedfs/filer.toml +COPY --from=builder /workspace/docker/entrypoint.sh /entrypoint.sh +RUN apk add --no-cache fuse + +# volume server gprc port +EXPOSE 18080 +# volume server http port +EXPOSE 8080 +# filer server gprc port +EXPOSE 18888 +# filer server http port +EXPOSE 8888 +# master server shared gprc port +EXPOSE 19333 +# master server shared http port +EXPOSE 9333 +# s3 server http port +EXPOSE 8333 +# webdav server http port +EXPOSE 7333 + +RUN mkdir -p /data/filerldb2 + +VOLUME /data +WORKDIR /data + +RUN chmod +x /entrypoint.sh + +ENTRYPOINT ["/entrypoint.sh"] + diff --git a/packages/system/seaweedfs/images/seaweedfs/patches/fix-signature-permission-check.diff b/packages/system/seaweedfs/images/seaweedfs/patches/fix-signature-permission-check.diff new file mode 100644 index 00000000..df30b0dc --- /dev/null +++ b/packages/system/seaweedfs/images/seaweedfs/patches/fix-signature-permission-check.diff @@ -0,0 +1,58 @@ +diff --git a/weed/s3api/auth_signature_v2.go b/weed/s3api/auth_signature_v2.go +index 4cdc07df0..b31c37a27 100644 +--- a/weed/s3api/auth_signature_v2.go ++++ b/weed/s3api/auth_signature_v2.go +@@ -116,11 +116,6 @@ func (iam *IdentityAccessManagement) doesSignV2Match(r *http.Request) (*Identity + return nil, s3err.ErrInvalidAccessKeyID + } + +- bucket, object := s3_constants.GetBucketAndObject(r) +- if !identity.canDo(s3_constants.ACTION_WRITE, bucket, object) { +- return nil, s3err.ErrAccessDenied +- } +- + expectedAuth := signatureV2(cred, r.Method, r.URL.Path, r.URL.Query().Encode(), r.Header) + if !compareSignatureV2(v2Auth, expectedAuth) { + return nil, s3err.ErrSignatureDoesNotMatch +@@ -163,11 +158,6 @@ func (iam *IdentityAccessManagement) doesPresignV2SignatureMatch(r *http.Request + return nil, s3err.ErrInvalidAccessKeyID + } + +- bucket, object := s3_constants.GetBucketAndObject(r) +- if !identity.canDo(s3_constants.ACTION_READ, bucket, object) { +- return nil, s3err.ErrAccessDenied +- } +- + expectedSignature := preSignatureV2(cred, r.Method, r.URL.Path, r.URL.Query().Encode(), r.Header, expires) + if !compareSignatureV2(signature, expectedSignature) { + return nil, s3err.ErrSignatureDoesNotMatch +diff --git a/weed/s3api/auth_signature_v4.go b/weed/s3api/auth_signature_v4.go +index a0417a922..c512f70cc 100644 +--- a/weed/s3api/auth_signature_v4.go ++++ b/weed/s3api/auth_signature_v4.go +@@ -190,12 +190,6 @@ func (iam *IdentityAccessManagement) doesSignatureMatch(hashedPayload string, r + return nil, s3err.ErrInvalidAccessKeyID + } + +- bucket, object := s3_constants.GetBucketAndObject(r) +- canDoResult := identity.canDo(s3_constants.ACTION_WRITE, bucket, object) +- if !canDoResult { +- return nil, s3err.ErrAccessDenied +- } +- + // Extract date, if not present throw error. + var dateStr string + if dateStr = req.Header.Get("x-amz-date"); dateStr == "" { +@@ -318,12 +312,6 @@ func (iam *IdentityAccessManagement) doesPresignedSignatureMatch(hashedPayload s + return nil, s3err.ErrInvalidAccessKeyID + } + +- // Check permissions +- bucket, object := s3_constants.GetBucketAndObject(r) +- if !identity.canDo(s3_constants.ACTION_READ, bucket, object) { +- return nil, s3err.ErrAccessDenied +- } +- + // Parse date + t, e := time.Parse(iso8601Format, dateStr) + if e != nil { diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index 420386c8..ffb50183 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -1,12 +1,15 @@ global: enableSecurity: true serviceAccountName: "tenant-foo-seaweedfs" + imageName: "ghcr.io/cozystack/cozystack/seaweedfs" extraEnvironmentVars: WEED_CLUSTER_SW_MASTER: "seaweedfs-master:9333" WEED_CLUSTER_SW_FILER: "seaweedfs-filer-client:8888" monitoring: enabled: true seaweedfs: + image: + tag: "latest@sha256:5ab64da9a0bc33c555f18d86a9664fe63617d48e5ea5192ef34822c24dcc5771" master: volumeSizeLimitMB: 30000 replicas: 3 From cfab053c666813d87573cc711386503e07503fd1 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 30 Oct 2025 23:21:48 +0500 Subject: [PATCH 17/76] [mariadb-operator] Add post-delete job to remove PVCs (#1553) ## What this PR does [mariadb-operator] Add post-delete job to remove PVCs This patch adds a Helm post-delete hook job that removes PersistentVolumeClaims left behind after Helm release deletion. The MariaDB Operator currently does not handle PVC cleanup, so this job ensures proper resource removal. ### Release note ```release-note [mariadb-operator] Add a post-delete hook job to clean up PVCs left after Helm release deletion. ``` ## Summary by CodeRabbit * **New Features** * Persistent storage volumes are now automatically cleaned up when the MySQL application is deleted, preventing orphaned storage resources from accumulating in your cluster. --- .../mysql/templates/hooks/cleanup-pvc.yaml | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 packages/apps/mysql/templates/hooks/cleanup-pvc.yaml diff --git a/packages/apps/mysql/templates/hooks/cleanup-pvc.yaml b/packages/apps/mysql/templates/hooks/cleanup-pvc.yaml new file mode 100644 index 00000000..e3fd5c32 --- /dev/null +++ b/packages/apps/mysql/templates/hooks/cleanup-pvc.yaml @@ -0,0 +1,74 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ .Release.Name }}-cleanup + labels: + app.kubernetes.io/instance: {{ .Release.Name }} + annotations: + "helm.sh/hook": post-delete + "helm.sh/hook-weight": "10" + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +spec: + template: + metadata: + labels: + app.kubernetes.io/instance: {{ .Release.Name }} + policy.cozystack.io/allow-to-apiserver: "true" + spec: + serviceAccountName: {{ .Release.Name }}-cleanup + restartPolicy: Never + containers: + - name: cleanup + image: docker.io/clastix/kubectl:v1.32 + command: + - /bin/sh + - -c + - | + echo "Deleting orphaned PVCs for {{ .Release.Name }}..." + kubectl delete pvc -n {{ .Release.Namespace }} -l app.kubernetes.io/instance={{ .Release.Name }} || true + echo "PVC cleanup complete." +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Release.Name }}-cleanup + labels: + app.kubernetes.io/instance: {{ .Release.Name }} + annotations: + "helm.sh/hook": post-delete + helm.sh/hook-weight: "0" + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ .Release.Name }}-cleanup + labels: + app.kubernetes.io/instance: {{ .Release.Name }} + annotations: + "helm.sh/hook": post-delete + "helm.sh/hook-weight": "5" + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +rules: + - apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: ["get", "list", "delete"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ .Release.Name }}-cleanup + labels: + app.kubernetes.io/instance: {{ .Release.Name }} + annotations: + "helm.sh/hook": post-delete + helm.sh/hook-weight: "5" + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ .Release.Name }}-cleanup +subjects: + - kind: ServiceAccount + name: {{ .Release.Name }}-cleanup From 0c50253e2c9fa66c3ccc9fc3fe76fc32566e4793 Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Wed, 29 Oct 2025 16:15:19 +0400 Subject: [PATCH 18/76] [kubernetes] Use controlPlane.replicas field (#1556) ## What this PR does The managed Kubernetes app accepts a .controPlane.replicas field, but this value was never used, instead being hardcoded in the KamajiControlPlane template to 2. This patch fixes this. ### Release note ```release-note [kubernetes] Pass the .controlPlane.replicas field into the KamajiControlPlane template, making the replica count of the controlplane pods user-configurable. ``` ## Summary by CodeRabbit * **New Features** * Control plane replica count is now configurable via Helm values, allowing flexible deployment scaling. --- packages/apps/kubernetes/templates/cluster.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/apps/kubernetes/templates/cluster.yaml b/packages/apps/kubernetes/templates/cluster.yaml index f275c979..2343a90a 100644 --- a/packages/apps/kubernetes/templates/cluster.yaml +++ b/packages/apps/kubernetes/templates/cluster.yaml @@ -147,7 +147,7 @@ spec: podAdditionalMetadata: labels: policy.cozystack.io/allow-to-etcd: "true" - replicas: 2 + replicas: {{ .Values.controlPlane.replicas }} version: {{ include "kubernetes.versionMap" $ }} --- apiVersion: cozystack.io/v1alpha1 From 39f51f7fbab9135f2a5ae7df94589aa1b4465754 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 31 Oct 2025 22:09:36 +0500 Subject: [PATCH 19/76] [dashboard] Update openapi-ui v1.0.3 + fixes (#1564) Signed-off-by: Andrei Kvapil - Update openapi-ui to v1.0.3 - Show YAML editor as readonly in YAML tab - Remove inside link from user menu - fix editing for tenantmodules, fixes https://github.com/cozystack/cozystack/issues/1550 - fix editing valuesOverride, fixes https://github.com/cozystack/cozystack/issues/1560 ```release-note [dashboard] Update openapi-ui v1.0.3 + fixes ``` * **Bug Fixes** * Made YAML editor read-only to prevent accidental modifications in details view * Fixed API request header handling to prevent stream abort issues * Updated resource API endpoint paths for correct data retrieval * Removed menu navigation item from user interface --- internal/controller/dashboard/factory.go | 1 + .../controller/dashboard/static_refactored.go | 1 + .../images/openapi-ui-k8s-bff/Dockerfile | 2 +- .../patches/namespaces.diff | 6 +-- .../dashboard/images/openapi-ui/Dockerfile | 11 ++-- .../patches/tenantmodules.diff | 50 +++++++++++++++++++ .../{ => openapi-ui}/patches/namespaces.diff | 10 ++-- .../patches/remove-inside-link.diff | 15 ++++++ 8 files changed, 84 insertions(+), 12 deletions(-) create mode 100644 packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/tenantmodules.diff rename packages/system/dashboard/images/openapi-ui/{ => openapi-ui}/patches/namespaces.diff (95%) create mode 100644 packages/system/dashboard/images/openapi-ui/openapi-ui/patches/remove-inside-link.diff diff --git a/internal/controller/dashboard/factory.go b/internal/controller/dashboard/factory.go index 798d338c..6cffecb6 100644 --- a/internal/controller/dashboard/factory.go +++ b/internal/controller/dashboard/factory.go @@ -324,6 +324,7 @@ func yamlTab(plural string) map[string]any { "type": "builtin", "typeName": plural, "prefillValuesRequestIndex": float64(0), + "readOnly": true, "substractHeight": float64(400), }, }, diff --git a/internal/controller/dashboard/static_refactored.go b/internal/controller/dashboard/static_refactored.go index 3caf8edb..af9c5449 100644 --- a/internal/controller/dashboard/static_refactored.go +++ b/internal/controller/dashboard/static_refactored.go @@ -796,6 +796,7 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory { "substractHeight": float64(400), "type": "builtin", "typeName": "secrets", + "readOnly": true, }, }, }, diff --git a/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile b/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile index e21829d2..d8447e7a 100644 --- a/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile +++ b/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile @@ -4,7 +4,7 @@ FROM node:${NODE_VERSION}-alpine AS builder RUN apk add git WORKDIR /src -ARG COMMIT_REF=22f9143f5109fb90332651c857d70b51bffccd9b +ARG COMMIT_REF=88531ed6881b4ce4808e56c00905951d7ba8031c RUN wget -O- https://github.com/PRO-Robotech/openapi-ui-k8s-bff/archive/${COMMIT_REF}.tar.gz | tar xzf - --strip-components=1 COPY patches /patches diff --git a/packages/system/dashboard/images/openapi-ui-k8s-bff/patches/namespaces.diff b/packages/system/dashboard/images/openapi-ui-k8s-bff/patches/namespaces.diff index 6a8ecbbe..3ed11a7c 100644 --- a/packages/system/dashboard/images/openapi-ui-k8s-bff/patches/namespaces.diff +++ b/packages/system/dashboard/images/openapi-ui-k8s-bff/patches/namespaces.diff @@ -1,7 +1,7 @@ -diff --git a/src/endpoints/forms/formPrepare/formPrepare.ts b/src/endpoints/forms/formPrepare/formPrepare.ts +diff --git a/src/endpoints/forms/prepareFormProps/prepareFormProps.ts b/src/endpoints/forms/prepareFormProps/prepareFormProps.ts index 7e437db..90c40f6 100644 ---- a/src/endpoints/forms/formPrepare/formPrepare.ts -+++ b/src/endpoints/forms/formPrepare/formPrepare.ts +--- a/src/endpoints/forms/prepareFormProps/prepareFormProps.ts ++++ b/src/endpoints/forms/prepareFormProps/prepareFormProps.ts @@ -15,6 +15,7 @@ export const prepareFormProps: RequestHandler = async (req: TPrepareFormReq, res const filteredHeaders = { ...req.headers } diff --git a/packages/system/dashboard/images/openapi-ui/Dockerfile b/packages/system/dashboard/images/openapi-ui/Dockerfile index ea10ac8a..af41cb65 100644 --- a/packages/system/dashboard/images/openapi-ui/Dockerfile +++ b/packages/system/dashboard/images/openapi-ui/Dockerfile @@ -3,9 +3,14 @@ ARG NODE_VERSION=20.18.1 # openapi-k8s-toolkit # imported from https://github.com/cozystack/openapi-k8s-toolkit FROM node:${NODE_VERSION}-alpine AS openapi-k8s-toolkit-builder +RUN apk add git WORKDIR /src -ARG COMMIT=4f57ab295b2a886eb294b0b987554194fbe67dcd +ARG COMMIT=e5f16b45de19f892de269cc4ef27e74aa62f4c92 RUN wget -O- https://github.com/cozystack/openapi-k8s-toolkit/archive/${COMMIT}.tar.gz | tar -xzvf- --strip-components=1 + +COPY openapi-k8s-toolkit/patches /patches +RUN git apply /patches/*.diff + RUN npm install RUN npm install --build-from-source @swc/core RUN npm run build @@ -17,10 +22,10 @@ FROM node:${NODE_VERSION}-alpine AS builder RUN apk add git WORKDIR /src -ARG COMMIT_REF=65e7fa8b3dc530a36e94c8435622bb09961aef97 +ARG COMMIT_REF=9ce4367657f49c0032d8016b1d9491f8abbd2b15 RUN wget -O- https://github.com/PRO-Robotech/openapi-ui/archive/${COMMIT_REF}.tar.gz | tar xzf - --strip-components=1 -COPY patches /patches +COPY openapi-ui/patches /patches RUN git apply /patches/*.diff ENV PATH=/src/node_modules/.bin:$PATH diff --git a/packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/tenantmodules.diff b/packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/tenantmodules.diff new file mode 100644 index 00000000..2817a8e0 --- /dev/null +++ b/packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/tenantmodules.diff @@ -0,0 +1,50 @@ +diff --git a/src/components/molecules/EnrichedTable/organisms/EnrichedTable/utils.tsx b/src/components/molecules/EnrichedTable/organisms/EnrichedTable/utils.tsx +index 8bcef4d..2551e92 100644 +--- a/src/components/molecules/EnrichedTable/organisms/EnrichedTable/utils.tsx ++++ b/src/components/molecules/EnrichedTable/organisms/EnrichedTable/utils.tsx +@@ -22,6 +22,15 @@ import { TableFactory } from '../../molecules' + import { ShortenedTextWithTooltip, FilterDropdown, TrimmedTags, TextAlignContainer, TinyButton } from './atoms' + import { TInternalDataForControls } from './types' + ++const getPluralForm = (singular: string): string => { ++ // If already ends with 's', add 'es' ++ if (singular.endsWith('s')) { ++ return `${singular}es` ++ } ++ // Otherwise just add 's' ++ return `${singular}s` ++} ++ + export const getCellRender = ({ + value, + record, +@@ -255,7 +264,7 @@ export const getEnrichedColumnsWithControls = ({ + key: 'controls', + className: 'controls', + width: 60, +- render: (value: TInternalDataForControls) => { ++ render: (value: TInternalDataForControls, record: unknown) => { + return ( + // + +@@ -279,10 +288,19 @@ export const getEnrichedColumnsWithControls = ({ + domEvent.stopPropagation() + domEvent.preventDefault() + if (key === 'edit') { ++ // Special case: redirect tenantmodules from core.cozystack.io to apps.cozystack.io with plural form ++ let apiGroupAndVersion = value.apiGroupAndVersion ++ let typeName = value.typeName ++ if (apiGroupAndVersion?.startsWith('core.cozystack.io/') && typeName === 'tenantmodules') { ++ const appsApiVersion = apiGroupAndVersion.replace('core.cozystack.io/', 'apps.cozystack.io/') ++ const pluralTypeName = getPluralForm(value.entryName) ++ apiGroupAndVersion = appsApiVersion ++ typeName = pluralTypeName ++ } + navigate( + `${baseprefix}/${value.cluster}${value.namespace ? `/${value.namespace}` : ''}${ + value.syntheticProject ? `/${value.syntheticProject}` : '' +- }/${value.pathPrefix}/${value.apiGroupAndVersion}/${value.typeName}/${value.entryName}?backlink=${ ++ }/${value.pathPrefix}/${apiGroupAndVersion}/${typeName}/${value.entryName}?backlink=${ + value.backlink + }`, + ) diff --git a/packages/system/dashboard/images/openapi-ui/patches/namespaces.diff b/packages/system/dashboard/images/openapi-ui/openapi-ui/patches/namespaces.diff similarity index 95% rename from packages/system/dashboard/images/openapi-ui/patches/namespaces.diff rename to packages/system/dashboard/images/openapi-ui/openapi-ui/patches/namespaces.diff index 66bce93a..b76c86d3 100644 --- a/packages/system/dashboard/images/openapi-ui/patches/namespaces.diff +++ b/packages/system/dashboard/images/openapi-ui/openapi-ui/patches/namespaces.diff @@ -1,5 +1,5 @@ diff --git a/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx b/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx -index 577ba0f..018df9c 100644 +index b6fb99f..965bac0 100644 --- a/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx +++ b/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx @@ -1,11 +1,16 @@ @@ -26,16 +26,16 @@ index 577ba0f..018df9c 100644 - const namespacesData = useBuiltinResources({ + const namespacesData = useApiResources({ - clusterName: cluster, + clusterName: selectedCluster || '', - typeName: 'namespaces', + apiGroup: BASE_PROJECTS_API_GROUP, + apiVersion: BASE_PROJECTS_VERSION, + typeName: BASE_PROJECTS_RESOURCE_NAME, limit: null, + isEnabled: selectedCluster !== undefined, }) - diff --git a/src/hooks/useNavSelectorInside.ts b/src/hooks/useNavSelectorInside.ts -index d69405e..5adbd5d 100644 +index 5736e2b..1ec0f71 100644 --- a/src/hooks/useNavSelectorInside.ts +++ b/src/hooks/useNavSelectorInside.ts @@ -1,6 +1,11 @@ @@ -63,8 +63,8 @@ index d69405e..5adbd5d 100644 + apiVersion: BASE_PROJECTS_VERSION, + typeName: BASE_PROJECTS_RESOURCE_NAME, limit: null, + isEnabled: Boolean(clusterName), }) - diff --git a/src/utils/getBacklink.ts b/src/utils/getBacklink.ts index a862354..f24e2bc 100644 --- a/src/utils/getBacklink.ts diff --git a/packages/system/dashboard/images/openapi-ui/openapi-ui/patches/remove-inside-link.diff b/packages/system/dashboard/images/openapi-ui/openapi-ui/patches/remove-inside-link.diff new file mode 100644 index 00000000..b131b53d --- /dev/null +++ b/packages/system/dashboard/images/openapi-ui/openapi-ui/patches/remove-inside-link.diff @@ -0,0 +1,15 @@ +diff --git a/src/components/organisms/Header/organisms/User/User.tsx b/src/components/organisms/Header/organisms/User/User.tsx +index efe7ac3..80b715c 100644 +--- a/src/components/organisms/Header/organisms/User/User.tsx ++++ b/src/components/organisms/Header/organisms/User/User.tsx +@@ -23,10 +23,6 @@ export const User: FC = () => { + // key: '1', + // label: , + // }, +- { +- key: '2', +- label:
navigate(`${baseprefix}/inside/clusters`)}>Inside
, +- }, + { + key: '3', + label: ( From 2ee2bf55ed950674f464f1e4ca6ccc121b048e3e Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 21 Oct 2025 17:44:50 +0200 Subject: [PATCH 20/76] [velero] Set defaultItemOperationTimeout=24h (#1542) Signed-off-by: Andrei Kvapil ## What this PR does This PR changes default timeout for Velero to copy single item. Default value 4h is not enough for copying large block volumes of virtual machines. ### Release note ```release-note [velero] Set defaultItemOperationTimeout=24h ``` ## Summary by CodeRabbit * **Chores** * Extended default operation timeout to 24 hours to provide increased time for operations to complete. --- packages/system/velero/values.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/system/velero/values.yaml b/packages/system/velero/values.yaml index d78a69c5..62f13c1f 100644 --- a/packages/system/velero/values.yaml +++ b/packages/system/velero/values.yaml @@ -13,3 +13,6 @@ velero: volumeSnapshotLocation: null namespace: cozy-velero features: EnableCSI + # Increase timeout for item operations to 24 hours to prevent timeouts + # during backups of very large volumes. The Velero default is 4 hours. + defaultItemOperationTimeout: 24h From 13b294c9a7feb5793a3fed029603e70bed60cef0 Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Mon, 27 Oct 2025 18:22:29 +0400 Subject: [PATCH 21/76] [redis-operator] Build patched operator in-tree (#1547) ## What this PR does This patch moves the build of the Redis operator into the Cozystack organization and patches it to prevent overwriting third-party labels on owned resources. ### Release note ```release-note [redis-operator] Move operator into tree and patch it to retain third-party labels on owned resources, reducing noisy traffic to the API server. ``` ## Summary by CodeRabbit * **Chores** * Implemented automated Docker image build pipeline with version tracking and caching. * Updated image configuration to include repository reference and digest for reproducibility. * **Bug Fixes** * Improved label and annotation handling to preserve existing Kubernetes resource metadata instead of overwriting it. --- packages/system/redis-operator/Makefile | 15 +++++++++++ .../images/redis-operator/Dockerfile | 27 +++++++++++++++++++ .../images/redis-operator/patches/labels.diff | 23 ++++++++++++++++ packages/system/redis-operator/values.yaml | 3 ++- 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 packages/system/redis-operator/images/redis-operator/Dockerfile create mode 100644 packages/system/redis-operator/images/redis-operator/patches/labels.diff diff --git a/packages/system/redis-operator/Makefile b/packages/system/redis-operator/Makefile index 9ea964dd..650cbc72 100644 --- a/packages/system/redis-operator/Makefile +++ b/packages/system/redis-operator/Makefile @@ -1,6 +1,8 @@ +REDIS_OPERATOR_TAG=$(shell grep -F 'ARG VERSION=' images/redis-operator/Dockerfile | cut -f2 -d=) export NAME=redis-operator export NAMESPACE=cozy-$(NAME) +include ../../../scripts/common-envs.mk include ../../../scripts/package.mk update: @@ -9,3 +11,16 @@ update: helm repo update redis-operator helm pull redis-operator/redis-operator --untar --untardir charts sed -i '/{{/d' charts/redis-operator/crds/databases.spotahome.com_redisfailovers.yaml + +image: + docker buildx build images/redis-operator \ + --tag $(REGISTRY)/redis-operator:$(REDIS_OPERATOR_TAG) \ + --cache-from type=registry,ref=$(REGISTRY)/redis-operator:latest \ + --cache-to type=inline \ + --metadata-file images/redis-operator.json \ + $(BUILDX_ARGS) + REPOSITORY="$(REGISTRY)/redis-operator" \ + yq -i '.redis-operator.image.repository = strenv(REPOSITORY)' values.yaml + TAG=$(REDIS_OPERATOR_TAG)@$$(yq e '."containerimage.digest"' images/redis-operator.json -o json -r) \ + yq -i '.redis-operator.image.tag = strenv(TAG)' values.yaml + rm -f images/redis-operator.json diff --git a/packages/system/redis-operator/images/redis-operator/Dockerfile b/packages/system/redis-operator/images/redis-operator/Dockerfile new file mode 100644 index 00000000..d0d6b682 --- /dev/null +++ b/packages/system/redis-operator/images/redis-operator/Dockerfile @@ -0,0 +1,27 @@ +FROM golang:1.20 AS builder + +ARG VERSION=v1.3.0-rc1 + +ARG TARGETOS +ARG TARGETARCH + +WORKDIR /workspace + +RUN curl -sSL https://github.com/spotahome/redis-operator/archive/refs/tags/${VERSION}.tar.gz | tar -xzvf- --strip=1 + +COPY patches /patches +RUN git apply /patches/*.diff + +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH VERSION=$VERSION ./scripts/build.sh + +FROM alpine:latest +RUN apk --no-cache add \ + ca-certificates +COPY --from=builder /workspace/bin/redis-operator /usr/local/bin +RUN addgroup -g 1000 rf && \ + adduser -D -u 1000 -G rf rf && \ + chown rf:rf /usr/local/bin/redis-operator +USER rf + +ENTRYPOINT ["/usr/local/bin/redis-operator"] + diff --git a/packages/system/redis-operator/images/redis-operator/patches/labels.diff b/packages/system/redis-operator/images/redis-operator/patches/labels.diff new file mode 100644 index 00000000..fe4c4254 --- /dev/null +++ b/packages/system/redis-operator/images/redis-operator/patches/labels.diff @@ -0,0 +1,23 @@ +diff --git a/service/k8s/service.go b/service/k8s/service.go +index 712cc4c0..e84afc92 100644 +--- a/service/k8s/service.go ++++ b/service/k8s/service.go +@@ -10,6 +10,7 @@ import ( + + "github.com/spotahome/redis-operator/log" + "github.com/spotahome/redis-operator/metrics" ++ "github.com/spotahome/redis-operator/operator/redisfailover/util" + ) + + // Service the ServiceAccount service that knows how to interact with k8s to manage them +@@ -95,6 +96,10 @@ func (s *ServiceService) CreateOrUpdateService(namespace string, service *corev1 + // namespace is our spec(https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#concurrency-control-and-consistency), + // we will replace the current namespace state. + service.ResourceVersion = storedService.ResourceVersion ++ newLabels := util.MergeLabels(storedService.GetLabels(), service.GetLabels()) ++ newAnnotations := util.MergeAnnotations(storedService.GetAnnotations(), service.GetAnnotations()) ++ service.SetLabels(newLabels) ++ service.SetAnnotations(newAnnotations) + return s.UpdateService(namespace, service) + } + diff --git a/packages/system/redis-operator/values.yaml b/packages/system/redis-operator/values.yaml index eb8c61a9..77e91011 100644 --- a/packages/system/redis-operator/values.yaml +++ b/packages/system/redis-operator/values.yaml @@ -1,3 +1,4 @@ redis-operator: image: - tag: v1.3.0-rc1 + repository: ghcr.io/cozystack/cozystack/redis-operator + tag: v1.3.0-rc1@sha256:a4012e6a1b5daaedb57cc27edfdbff52124de4164b5ec0ee53c5ce5710ef4c25 From 31d87671a1c48681ca549356271f1eab138cefa5 Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Mon, 27 Oct 2025 18:25:41 +0400 Subject: [PATCH 22/76] [system] kube-ovn: turn off enableLb (#1548) ## What this PR does Turns off kubeovn enableLb, kube-proxy implementation of kube-ovn. ### Release note ```release-note [system] kube-ovn: turn off kube-proxy implementation ``` ## Summary by CodeRabbit * **Chores** * Added a new load balancing configuration option to system settings (disabled by default). --- packages/system/kubeovn/values.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/system/kubeovn/values.yaml b/packages/system/kubeovn/values.yaml index 5b91da02..db8f9918 100644 --- a/packages/system/kubeovn/values.yaml +++ b/packages/system/kubeovn/values.yaml @@ -2,6 +2,7 @@ kube-ovn: namespace: cozy-kubeovn func: ENABLE_NP: false + ENABLE_LB: false ipv4: POD_CIDR: "10.244.0.0/16" POD_GATEWAY: "10.244.0.1" From f645a5d8fc635d6ac04ecc3c37476e2aeff9c5cd Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Sat, 1 Nov 2025 01:21:49 +0500 Subject: [PATCH 23/76] Update LINSTOR v1.32.3 (#1565) Signed-off-by: Andrei Kvapil ## What this PR does ### Release note ```release-note Update LINSTOR v1.32.3 ``` --- .../charts/piraeus/Chart.yaml | 4 +- .../charts/piraeus/templates/config.yaml | 44 +- .../charts/piraeus/templates/rbac.yaml | 724 +++++++----------- .../piraeus/templates/rolebindings.yaml | 33 + .../piraeus/templates/serviceaccount.yaml | 9 + 5 files changed, 344 insertions(+), 470 deletions(-) create mode 100644 packages/system/piraeus-operator/charts/piraeus/templates/rolebindings.yaml create mode 100644 packages/system/piraeus-operator/charts/piraeus/templates/serviceaccount.yaml diff --git a/packages/system/piraeus-operator/charts/piraeus/Chart.yaml b/packages/system/piraeus-operator/charts/piraeus/Chart.yaml index 9cadb1b9..96393c85 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.9.0 -appVersion: "v2.9.0" +version: 2.9.1 +appVersion: "v2.9.1" 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 7bd14541..62bdb444 100644 --- a/packages/system/piraeus-operator/charts/piraeus/templates/config.yaml +++ b/packages/system/piraeus-operator/charts/piraeus/templates/config.yaml @@ -1,4 +1,4 @@ -# DO NOT EDIT; Automatically created by hack/copy-image-config-to-chart.sh +# DO NOT EDIT; Automatically created by tools/copy-image-config-to-chart.sh apiVersion: v1 kind: ConfigMap metadata: @@ -17,16 +17,16 @@ data: # quay.io/piraeusdatastore/piraeus-server:v1.24.2 components: linstor-controller: - tag: v1.31.3 + tag: v1.32.3 image: piraeus-server linstor-satellite: - tag: v1.31.3 + tag: v1.32.3 image: piraeus-server linstor-csi: - tag: v1.8.0 + tag: v1.9.0 image: piraeus-csi drbd-reactor: - tag: v1.8.0 + tag: v1.9.0 image: drbd-reactor ha-controller: tag: v1.3.0 @@ -35,45 +35,45 @@ data: tag: v1.0.0 image: drbd-shutdown-guard ktls-utils: - tag: v1.1.0 + tag: v1.2.1 image: ktls-utils drbd-module-loader: - tag: v9.2.14 + tag: v9.2.15 # 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. image: drbd9-noble # Fallback image: chose a recent kernel, which can hopefully compile whatever config is actually in use match: - - osImage: Red Hat Enterprise Linux Server 7\. - image: drbd9-centos7 - osImage: Red Hat Enterprise Linux 8\. image: drbd9-almalinux8 - osImage: Red Hat Enterprise Linux 9\. image: drbd9-almalinux9 + - osImage: Red Hat Enterprise Linux 10\. + image: drbd9-almalinux10 - osImage: "Red Hat Enterprise Linux CoreOS 41[3-9]" image: drbd9-almalinux9 - osImage: Red Hat Enterprise Linux CoreOS image: drbd9-almalinux8 - - osImage: CentOS Linux 7 - image: drbd9-centos7 - osImage: CentOS Linux 8 image: drbd9-almalinux8 - osImage: AlmaLinux 8 image: drbd9-almalinux8 - osImage: AlmaLinux 9 image: drbd9-almalinux9 + - osImage: AlmaLinux 10 + image: drbd9-almalinux10 - osImage: Oracle Linux Server 8\. image: drbd9-almalinux8 - osImage: Oracle Linux Server 9\. image: drbd9-almalinux9 + - osImage: Oracle Linux Server 10\. + image: drbd9-almalinux10 - osImage: Rocky Linux 8 image: drbd9-almalinux8 - osImage: Rocky Linux 9 image: drbd9-almalinux9 - - osImage: Ubuntu 18\.04 - image: drbd9-bionic - - osImage: Ubuntu 20\.04 - image: drbd9-focal + - osImage: Rocky Linux 10 + image: drbd9-almalinux10 - osImage: Ubuntu 22\.04 image: drbd9-jammy - osImage: Ubuntu 24\.04 @@ -82,32 +82,30 @@ data: image: drbd9-bookworm - osImage: Debian GNU/Linux 11 image: drbd9-bullseye - - osImage: Debian GNU/Linux 10 - image: drbd9-buster 0_sig_storage_images.yaml: | --- base: registry.k8s.io/sig-storage components: csi-attacher: - tag: v4.9.0 + tag: v4.10.0 image: csi-attacher csi-livenessprobe: - tag: v2.16.0 + tag: v2.17.0 image: livenessprobe csi-provisioner: tag: v5.3.0 image: csi-provisioner csi-snapshotter: - tag: v8.2.1 + tag: v8.3.0 image: csi-snapshotter csi-resizer: - tag: v1.13.2 + tag: v1.14.0 image: csi-resizer csi-external-health-monitor-controller: - tag: v0.15.0 + tag: v0.16.0 image: csi-external-health-monitor-controller csi-node-driver-registrar: - tag: v2.14.0 + tag: v2.15.0 image: csi-node-driver-registrar {{- range $idx, $value := .Values.imageConfigOverride }} {{ add $idx 1 }}_helm_override.yaml: | diff --git a/packages/system/piraeus-operator/charts/piraeus/templates/rbac.yaml b/packages/system/piraeus-operator/charts/piraeus/templates/rbac.yaml index e487114c..5d49c6e6 100644 --- a/packages/system/piraeus-operator/charts/piraeus/templates/rbac.yaml +++ b/packages/system/piraeus-operator/charts/piraeus/templates/rbac.yaml @@ -1,11 +1,5 @@ -{{ if .Values.serviceAccount.create }} ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "piraeus-operator.serviceAccountName" . }} - labels: - {{- include "piraeus-operator.labels" . | nindent 4 }} +# DO NOT EDIT; Automatically created by tools/copy-rbac-config-to-chart.sh +{{ if .Values.rbac.create }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -14,448 +8,288 @@ metadata: labels: {{- include "piraeus-operator.labels" . | nindent 4 }} rules: - - apiGroups: - - "" - resources: - - configmaps - - events - - persistentvolumes - - secrets - - serviceaccounts - - services - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - "" - resources: - - configmaps - - pods - - secrets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - "" - resources: - - nodes - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - nodes - - persistentvolumeclaims - verbs: - - get - - list - - patch - - update - - watch - - apiGroups: - - "" - resources: - - persistentvolumeclaims/status - verbs: - - patch - - apiGroups: - - "" - resources: - - pods - verbs: - - delete - - list - - watch - - apiGroups: - - "" - resources: - - pods/eviction - verbs: - - create - - apiGroups: - - apiextensions.k8s.io - resources: - - customresourcedefinitions - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - apps - resources: - - daemonsets - - deployments - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - apps - resources: - - replicasets - verbs: - - get - - apiGroups: - - cert-manager.io - resources: - - certificates - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - events.k8s.io - resources: - - events - verbs: - - create - - get - - list - - patch - - update - - watch - - apiGroups: - - internal.linstor.linbit.com - resources: - - '*' - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch - - apiGroups: - - piraeus.io - resources: - - linstorclusters - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - piraeus.io - resources: - - linstorclusters/finalizers - verbs: - - update - - apiGroups: - - piraeus.io - resources: - - linstorclusters/status - verbs: - - get - - patch - - update - - apiGroups: - - piraeus.io - resources: - - linstornodeconnections - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - piraeus.io - resources: - - linstornodeconnections/finalizers - verbs: - - update - - apiGroups: - - piraeus.io - resources: - - linstornodeconnections/status - verbs: - - get - - patch - - update - - apiGroups: - - piraeus.io - resources: - - linstorsatelliteconfigurations - verbs: - - get - - list - - watch - - apiGroups: - - piraeus.io - resources: - - linstorsatelliteconfigurations/status - verbs: - - get - - patch - - update - - apiGroups: - - piraeus.io - resources: - - linstorsatellites - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - piraeus.io - resources: - - linstorsatellites/finalizers - verbs: - - update - - apiGroups: - - piraeus.io - resources: - - linstorsatellites/status - verbs: - - get - - patch - - update - - apiGroups: - - rbac.authorization.k8s.io - resources: - - clusterrolebindings - - clusterroles - - rolebindings - - roles - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - security.openshift.io - resourceNames: - - privileged - resources: - - securitycontextconstraints - verbs: - - use - - apiGroups: - - snapshot.storage.k8s.io - resources: - - volumesnapshotclasses - - volumesnapshots - verbs: - - get - - list - - watch - - apiGroups: - - snapshot.storage.k8s.io - resources: - - volumesnapshotcontents - verbs: - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - snapshot.storage.k8s.io - resources: - - volumesnapshotcontents/status - verbs: - - patch - - update - - apiGroups: - - storage.k8s.io - resources: - - csidrivers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - storage.k8s.io - resources: - - csinodes - verbs: - - get - - list - - patch - - watch - - apiGroups: - - storage.k8s.io - resources: - - csistoragecapacities - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - storage.k8s.io - resources: - - storageclasses - verbs: - - get - - list - - watch - - apiGroups: - - storage.k8s.io - resources: - - volumeattachments - verbs: - - delete - - get - - list - - patch - - watch - - apiGroups: - - storage.k8s.io - resources: - - volumeattachments/status - verbs: - - patch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ include "piraeus-operator.fullname" . }}-manager-rolebinding - labels: - {{- include "piraeus-operator.labels" . | nindent 4 }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: '{{ include "piraeus-operator.fullname" . }}-controller-manager' -subjects: - - kind: ServiceAccount - name: '{{ include "piraeus-operator.serviceAccountName" . }}' - namespace: '{{ .Release.Namespace }}' -{{ end }} -{{ if.Values.rbac.create }} ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ include "piraeus-operator.fullname" . }}-proxy-role - labels: - {{- include "piraeus-operator.labels" . | nindent 4 }} -rules: - - apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create - - apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ include "piraeus-operator.fullname" . }}-proxy-rolebinding - labels: - {{- include "piraeus-operator.labels" . | nindent 4 }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: '{{ include "piraeus-operator.fullname" . }}-proxy-role' -subjects: - - kind: ServiceAccount - name: {{ include "piraeus-operator.serviceAccountName" . }} - namespace: '{{ .Release.Namespace }}' +- apiGroups: + - "" + resources: + - configmaps + - events + - persistentvolumes + - pods + - secrets + - serviceaccounts + - services + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - nodes + - persistentvolumeclaims + verbs: + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - persistentvolumeclaims/status + verbs: + - patch +- apiGroups: + - "" + resources: + - pods/eviction + verbs: + - create +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - apps + resources: + - daemonsets + - deployments + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - apps + resources: + - replicasets + verbs: + - get +- apiGroups: + - cert-manager.io + resources: + - certificates + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - events.k8s.io + resources: + - events + verbs: + - create + - get + - list + - patch + - update + - watch +- apiGroups: + - internal.linstor.linbit.com + resources: + - '*' + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch +- apiGroups: + - piraeus.io + resources: + - linstorclusters + - linstornodeconnections + - linstorsatellites + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - piraeus.io + resources: + - linstorclusters/finalizers + - linstornodeconnections/finalizers + - linstorsatellites/finalizers + verbs: + - update +- apiGroups: + - piraeus.io + resources: + - linstorclusters/status + - linstornodeconnections/status + - linstorsatelliteconfigurations/status + - linstorsatellites/status + verbs: + - get + - patch + - update +- apiGroups: + - piraeus.io + resources: + - linstorsatelliteconfigurations + verbs: + - get + - list + - watch +- apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterrolebindings + - clusterroles + - rolebindings + - roles + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - security.openshift.io + resourceNames: + - privileged + resources: + - securitycontextconstraints + verbs: + - use +- apiGroups: + - snapshot.storage.k8s.io + resources: + - volumesnapshotclasses + - volumesnapshots + verbs: + - get + - list + - watch +- apiGroups: + - snapshot.storage.k8s.io + resources: + - volumesnapshotcontents + verbs: + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - snapshot.storage.k8s.io + resources: + - volumesnapshotcontents/status + verbs: + - patch + - update +- apiGroups: + - storage.k8s.io + resources: + - csidrivers + - csistoragecapacities + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - storage.k8s.io + resources: + - csinodes + verbs: + - get + - list + - patch + - watch +- apiGroups: + - storage.k8s.io + resources: + - storageclasses + verbs: + - get + - list + - watch +- apiGroups: + - storage.k8s.io + resources: + - volumeattachments + verbs: + - delete + - get + - list + - patch + - watch +- apiGroups: + - storage.k8s.io + resources: + - volumeattachments/status + verbs: + - patch --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - name: {{ include "piraeus-operator.fullname" . }}-leader-election-role + name: {{ include "piraeus-operator.fullname" . }}-leader-election labels: {{- include "piraeus-operator.labels" . | nindent 4 }} rules: - - apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - apiGroups: - - "" - resources: - - events - verbs: - - create - - patch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: {{ include "piraeus-operator.fullname" . }}-leader-election-rolebinding - labels: - {{- include "piraeus-operator.labels" . | nindent 4 }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: '{{ include "piraeus-operator.fullname" . }}-leader-election-role' -subjects: - - kind: ServiceAccount - name: {{ include "piraeus-operator.serviceAccountName" . }} - namespace: '{{ .Release.Namespace }}' +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch {{ end }} diff --git a/packages/system/piraeus-operator/charts/piraeus/templates/rolebindings.yaml b/packages/system/piraeus-operator/charts/piraeus/templates/rolebindings.yaml new file mode 100644 index 00000000..97e53b95 --- /dev/null +++ b/packages/system/piraeus-operator/charts/piraeus/templates/rolebindings.yaml @@ -0,0 +1,33 @@ +{{ if .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "piraeus-operator.fullname" . }}-leader-election + namespace: {{ .Release.Namespace }} + labels: + {{- include "piraeus-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "piraeus-operator.fullname" . }}-leader-election +subjects: +- kind: ServiceAccount + name: {{ include "piraeus-operator.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "piraeus-operator.fullname" . }}-controller-manager + labels: + {{- include "piraeus-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "piraeus-operator.fullname" . }}-controller-manager +subjects: +- kind: ServiceAccount + name: {{ include "piraeus-operator.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{ end }} diff --git a/packages/system/piraeus-operator/charts/piraeus/templates/serviceaccount.yaml b/packages/system/piraeus-operator/charts/piraeus/templates/serviceaccount.yaml new file mode 100644 index 00000000..89315de9 --- /dev/null +++ b/packages/system/piraeus-operator/charts/piraeus/templates/serviceaccount.yaml @@ -0,0 +1,9 @@ +{{ if .Values.serviceAccount.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "piraeus-operator.serviceAccountName" . }} + labels: + {{- include "piraeus-operator.labels" . | nindent 4 }} +{{ end }} From b8604b8ec564956f4033ac5510b4531da61b6c4a Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 31 Oct 2025 20:13:09 +0500 Subject: [PATCH 24/76] [seaweedfs] Update SeaweedFS v3.99 and deploy S3 as stacked service (#1562) Signed-off-by: Andrei Kvapil ## What this PR does ### Release note ```release-note [] ``` ## Summary by CodeRabbit * **New Features** * Helm values now control ingress paths; computed cluster endpoint env vars are injected. * Optional container securityContext for volume init containers added. * Node architecture-specific targeting disabled by default. * **Refactor** * Image configuration reorganized with separate registry field; container image build simplified. * **Bug Fixes / Behavior** * S3-related authorization and signature handling changed; S3 gateway toggled. --- packages/system/seaweedfs/Makefile | 1 - .../seaweedfs/charts/seaweedfs/Chart.yaml | 4 +- .../all-in-one/all-in-one-deployment.yaml | 15 +++++ .../templates/cosi/cosi-deployment.yaml | 1 - .../templates/filer/filer-ingress.yaml | 4 +- .../templates/master/master-ingress.yaml | 4 +- .../seaweedfs/templates/s3/s3-ingress.yaml | 4 +- .../seaweedfs/templates/shared/_helpers.tpl | 33 +++++++++- .../volume/volume-servicemonitor.yaml | 4 +- .../templates/volume/volume-statefulset.yaml | 3 + .../seaweedfs/charts/seaweedfs/values.yaml | 32 ++++++---- .../seaweedfs/images/seaweedfs/Dockerfile | 60 +------------------ .../fix-signature-permission-check.diff | 58 ------------------ .../patches/fix-volume-servicemonitor.patch | 15 ----- packages/system/seaweedfs/values.yaml | 7 ++- 15 files changed, 83 insertions(+), 162 deletions(-) delete mode 100644 packages/system/seaweedfs/images/seaweedfs/patches/fix-signature-permission-check.diff delete mode 100644 packages/system/seaweedfs/patches/fix-volume-servicemonitor.patch diff --git a/packages/system/seaweedfs/Makefile b/packages/system/seaweedfs/Makefile index a349ba82..9d1f47cd 100644 --- a/packages/system/seaweedfs/Makefile +++ b/packages/system/seaweedfs/Makefile @@ -12,7 +12,6 @@ update: sed -i.bak "/ARG VERSION/ s|=.*|=$${version}|g" images/seaweedfs/Dockerfile && \ rm -f images/seaweedfs/Dockerfile.bak patch --no-backup-if-mismatch -p4 < patches/resize-api-server-annotation.diff - patch --no-backup-if-mismatch -p4 < patches/fix-volume-servicemonitor.patch #patch --no-backup-if-mismatch -p4 < patches/retention-policy-delete.yaml image: diff --git a/packages/system/seaweedfs/charts/seaweedfs/Chart.yaml b/packages/system/seaweedfs/charts/seaweedfs/Chart.yaml index cd0f27a0..c595d65e 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/Chart.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v1 description: SeaweedFS name: seaweedfs -appVersion: "3.97" +appVersion: "3.99" # Dev note: Trigger a helm chart release by `git tag -a helm-` -version: 4.0.397 +version: 4.0.399 diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-deployment.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-deployment.yaml index 86bb45a8..8700a8a6 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-deployment.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-deployment.yaml @@ -79,6 +79,12 @@ spec: image: {{ template "master.image" . }} imagePullPolicy: {{ default "IfNotPresent" .Values.global.imagePullPolicy }} env: + {{- /* Determine default cluster alias and the corresponding env var keys to avoid conflicts */}} + {{- $envMerged := merge (.Values.global.extraEnvironmentVars | default dict) (.Values.allInOne.extraEnvironmentVars | default dict) }} + {{- $clusterDefault := default "sw" (index $envMerged "WEED_CLUSTER_DEFAULT") }} + {{- $clusterUpper := upper $clusterDefault }} + {{- $clusterMasterKey := printf "WEED_CLUSTER_%s_MASTER" $clusterUpper }} + {{- $clusterFilerKey := printf "WEED_CLUSTER_%s_FILER" $clusterUpper }} - name: POD_IP valueFrom: fieldRef: @@ -95,6 +101,7 @@ spec: value: "{{ template "seaweedfs.name" . }}" {{- if .Values.allInOne.extraEnvironmentVars }} {{- range $key, $value := .Values.allInOne.extraEnvironmentVars }} + {{- if and (ne $key $clusterMasterKey) (ne $key $clusterFilerKey) }} - name: {{ $key }} {{- if kindIs "string" $value }} value: {{ $value | quote }} @@ -104,8 +111,10 @@ spec: {{- end }} {{- end }} {{- end }} + {{- end }} {{- if .Values.global.extraEnvironmentVars }} {{- range $key, $value := .Values.global.extraEnvironmentVars }} + {{- if and (ne $key $clusterMasterKey) (ne $key $clusterFilerKey) }} - name: {{ $key }} {{- if kindIs "string" $value }} value: {{ $value | quote }} @@ -115,6 +124,12 @@ spec: {{- end }} {{- end }} {{- end }} + {{- end }} + # Inject computed cluster endpoints for the default cluster + - name: {{ $clusterMasterKey }} + value: {{ include "seaweedfs.cluster.masterAddress" . | quote }} + - name: {{ $clusterFilerKey }} + value: {{ include "seaweedfs.cluster.filerAddress" . | quote }} command: - "/bin/sh" - "-ec" diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/cosi/cosi-deployment.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cosi/cosi-deployment.yaml index b200c89a..813af850 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/cosi/cosi-deployment.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/cosi/cosi-deployment.yaml @@ -15,7 +15,6 @@ spec: selector: matchLabels: app.kubernetes.io/name: {{ template "seaweedfs.name" . }} - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/component: objectstorage-provisioner template: diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-ingress.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-ingress.yaml index 7a7c9886..9ce15ae9 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-ingress.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-ingress.yaml @@ -28,8 +28,8 @@ spec: rules: - http: paths: - - path: /sw-filer/?(.*) - pathType: ImplementationSpecific + - path: {{ .Values.filer.ingress.path | quote }} + pathType: {{ .Values.filer.ingress.pathType | quote }} backend: {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} service: diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-ingress.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-ingress.yaml index 62d7f7a5..ac1cb339 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-ingress.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-ingress.yaml @@ -28,8 +28,8 @@ spec: rules: - http: paths: - - path: /sw-master/?(.*) - pathType: ImplementationSpecific + - path: {{ .Values.master.ingress.path | quote }} + pathType: {{ .Values.master.ingress.pathType | quote }} backend: {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} service: diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-ingress.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-ingress.yaml index f9c36206..a856923e 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-ingress.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-ingress.yaml @@ -27,8 +27,8 @@ spec: rules: - http: paths: - - path: / - pathType: ImplementationSpecific + - path: {{ .Values.s3.ingress.path | quote }} + pathType: {{ .Values.s3.ingress.pathType | quote }} backend: {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} service: diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/shared/_helpers.tpl b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/_helpers.tpl index b15b07fa..d22d1422 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/shared/_helpers.tpl +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/_helpers.tpl @@ -96,13 +96,16 @@ Inject extra environment vars in the format key:value, if populated {{/* Computes the container image name for all components (if they are not overridden) */}} {{- define "common.image" -}} {{- $registryName := default .Values.image.registry .Values.global.registry | toString -}} -{{- $repositoryName := .Values.image.repository | toString -}} +{{- $repositoryName := default .Values.image.repository .Values.global.repository | toString -}} {{- $name := .Values.global.imageName | toString -}} {{- $tag := default .Chart.AppVersion .Values.image.tag | toString -}} +{{- if $repositoryName -}} +{{- $name = printf "%s/%s" (trimSuffix "/" $repositoryName) (base $name) -}} +{{- end -}} {{- if $registryName -}} -{{- printf "%s/%s%s:%s" $registryName $repositoryName $name $tag -}} +{{- printf "%s/%s:%s" $registryName $name $tag -}} {{- else -}} -{{- printf "%s%s:%s" $repositoryName $name $tag -}} +{{- printf "%s:%s" $name $tag -}} {{- end -}} {{- end -}} @@ -219,3 +222,27 @@ or generate a new random password if it doesn't exist. {{- randAlphaNum $length -}} {{- end -}} {{- end -}} + +{{/* +Compute the master service address to be used in cluster env vars. +If allInOne is enabled, point to the all-in-one service; otherwise, point to the master service. +*/}} +{{- define "seaweedfs.cluster.masterAddress" -}} +{{- $serviceNameSuffix := "-master" -}} +{{- if .Values.allInOne.enabled -}} +{{- $serviceNameSuffix = "-all-in-one" -}} +{{- end -}} +{{- printf "%s%s.%s:%d" (include "seaweedfs.name" .) $serviceNameSuffix .Release.Namespace (int .Values.master.port) -}} +{{- end -}} + +{{/* +Compute the filer service address to be used in cluster env vars. +If allInOne is enabled, point to the all-in-one service; otherwise, point to the filer-client service. +*/}} +{{- define "seaweedfs.cluster.filerAddress" -}} +{{- $serviceNameSuffix := "-filer-client" -}} +{{- if .Values.allInOne.enabled -}} +{{- $serviceNameSuffix = "-all-in-one" -}} +{{- end -}} +{{- printf "%s%s.%s:%d" (include "seaweedfs.name" .) $serviceNameSuffix .Release.Namespace (int .Values.filer.port) -}} +{{- end -}} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-servicemonitor.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-servicemonitor.yaml index b60e9e44..ac82eb57 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-servicemonitor.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-servicemonitor.yaml @@ -21,9 +21,9 @@ metadata: {{- with $.Values.global.monitoring.additionalLabels }} {{- toYaml . | nindent 4 }} {{- end }} -{{- if $.Values.volume.annotations }} +{{- with $volume.annotations }} annotations: - {{- toYaml $.Values.volume.annotations | nindent 4 }} + {{- toYaml . | nindent 4 }} {{- end }} spec: endpoints: diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-statefulset.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-statefulset.yaml index 19740160..29a035a2 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-statefulset.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-statefulset.yaml @@ -88,6 +88,9 @@ spec: - name: {{ $dir.name }} mountPath: /{{ $dir.name }} {{- end }} + {{- if $volume.containerSecurityContext.enabled }} + securityContext: {{- omit $volume.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} {{- end }} {{- if $volume.initContainers }} {{ tpl (printf "{{ $volumeName := \"%s\" }}%s" $volumeName $volume.initContainers) $ | indent 8 | trim }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/values.yaml b/packages/system/seaweedfs/charts/seaweedfs/values.yaml index 351cb966..cf16623c 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/values.yaml @@ -3,6 +3,7 @@ global: createClusterRole: true registry: "" + # if repository is set, it overrides the namespace part of imageName repository: "" imageName: chrislusf/seaweedfs imagePullPolicy: IfNotPresent @@ -201,8 +202,7 @@ master: # nodeSelector labels for master pod assignment, formatted as a muli-line string. # ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector # Example: - nodeSelector: | - kubernetes.io/arch: amd64 + nodeSelector: "" # nodeSelector: | # sw-backend: "true" @@ -238,6 +238,8 @@ master: className: "nginx" # host: false for "*" hostname host: "master.seaweedfs.local" + path: "/sw-master/?(.*)" + pathType: ImplementationSpecific annotations: nginx.ingress.kubernetes.io/auth-type: "basic" nginx.ingress.kubernetes.io/auth-secret: "default/ingress-basic-auth-secret" @@ -478,8 +480,7 @@ volume: # nodeSelector labels for server pod assignment, formatted as a muli-line string. # ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector # Example: - nodeSelector: | - kubernetes.io/arch: amd64 + nodeSelector: "" # nodeSelector: | # sw-volume: "true" @@ -735,8 +736,7 @@ filer: # nodeSelector labels for server pod assignment, formatted as a muli-line string. # ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector # Example: - nodeSelector: | - kubernetes.io/arch: amd64 + nodeSelector: "" # nodeSelector: | # sw-backend: "true" @@ -772,6 +772,8 @@ filer: className: "nginx" # host: false for "*" hostname host: "seaweedfs.cluster.local" + path: "/sw-filer/?(.*)" + pathType: ImplementationSpecific annotations: nginx.ingress.kubernetes.io/backend-protocol: GRPC nginx.ingress.kubernetes.io/auth-type: "basic" @@ -871,7 +873,7 @@ filer: # anonymousRead: false s3: - enabled: false + enabled: true imageOverride: null restartPolicy: null replicas: 1 @@ -932,8 +934,7 @@ s3: # nodeSelector labels for server pod assignment, formatted as a muli-line string. # ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector # Example: - nodeSelector: | - kubernetes.io/arch: amd64 + nodeSelector: "" # nodeSelector: | # sw-backend: "true" @@ -975,6 +976,11 @@ s3: extraEnvironmentVars: + # Custom command line arguments to add to the s3 command + # Example to fix connection idle seconds: + extraArgs: ["-idleTimeout=30"] + # extraArgs: [] + # used to configure livenessProbe on s3 containers # livenessProbe: @@ -1006,6 +1012,8 @@ s3: className: "nginx" # host: false for "*" hostname host: "seaweedfs.cluster.local" + path: "/" + pathType: Prefix # additional ingress annotations for the s3 endpoint annotations: {} tls: [] @@ -1051,8 +1059,7 @@ sftp: annotations: {} resources: {} tolerations: "" - nodeSelector: | - kubernetes.io/arch: amd64 + nodeSelector: "" priorityClassName: "" serviceAccountName: "" podSecurityContext: {} @@ -1179,8 +1186,7 @@ allInOne: # nodeSelector labels for master pod assignment, formatted as a muli-line string. # ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector - nodeSelector: | - kubernetes.io/arch: amd64 + nodeSelector: "" # Used to assign priority to master pods # ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ diff --git a/packages/system/seaweedfs/images/seaweedfs/Dockerfile b/packages/system/seaweedfs/images/seaweedfs/Dockerfile index 43bf41cb..48776a56 100644 --- a/packages/system/seaweedfs/images/seaweedfs/Dockerfile +++ b/packages/system/seaweedfs/images/seaweedfs/Dockerfile @@ -1,58 +1,2 @@ -FROM golang:1.24-alpine as builder - -ARG VERSION=3.97 -ARG TARGETOS -ARG TARGETARCH - -RUN apk add --no-cache git g++ fuse - -WORKDIR /workspace - -RUN git clone --depth 1 --branch ${VERSION} https://github.com/seaweedfs/seaweedfs.git . - -COPY patches /patches -RUN git apply /patches/*.diff - -RUN cd weed && \ - export LDFLAGS="-X github.com/seaweedfs/seaweedfs/weed/util/version.COMMIT=$(git rev-parse --short HEAD)" && \ - GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build \ - -tags "full" \ - -ldflags "-extldflags -static ${LDFLAGS}" \ - -o /usr/bin/weed - -FROM alpine AS final - -LABEL author="Chris Lu" - -COPY --from=builder /usr/bin/weed /usr/bin/ -RUN mkdir -p /etc/seaweedfs -COPY --from=builder /workspace/docker/filer.toml /etc/seaweedfs/filer.toml -COPY --from=builder /workspace/docker/entrypoint.sh /entrypoint.sh -RUN apk add --no-cache fuse - -# volume server gprc port -EXPOSE 18080 -# volume server http port -EXPOSE 8080 -# filer server gprc port -EXPOSE 18888 -# filer server http port -EXPOSE 8888 -# master server shared gprc port -EXPOSE 19333 -# master server shared http port -EXPOSE 9333 -# s3 server http port -EXPOSE 8333 -# webdav server http port -EXPOSE 7333 - -RUN mkdir -p /data/filerldb2 - -VOLUME /data -WORKDIR /data - -RUN chmod +x /entrypoint.sh - -ENTRYPOINT ["/entrypoint.sh"] - +ARG VERSION=3.99 +FROM chrislusf/seaweedfs:${VERSION} diff --git a/packages/system/seaweedfs/images/seaweedfs/patches/fix-signature-permission-check.diff b/packages/system/seaweedfs/images/seaweedfs/patches/fix-signature-permission-check.diff deleted file mode 100644 index df30b0dc..00000000 --- a/packages/system/seaweedfs/images/seaweedfs/patches/fix-signature-permission-check.diff +++ /dev/null @@ -1,58 +0,0 @@ -diff --git a/weed/s3api/auth_signature_v2.go b/weed/s3api/auth_signature_v2.go -index 4cdc07df0..b31c37a27 100644 ---- a/weed/s3api/auth_signature_v2.go -+++ b/weed/s3api/auth_signature_v2.go -@@ -116,11 +116,6 @@ func (iam *IdentityAccessManagement) doesSignV2Match(r *http.Request) (*Identity - return nil, s3err.ErrInvalidAccessKeyID - } - -- bucket, object := s3_constants.GetBucketAndObject(r) -- if !identity.canDo(s3_constants.ACTION_WRITE, bucket, object) { -- return nil, s3err.ErrAccessDenied -- } -- - expectedAuth := signatureV2(cred, r.Method, r.URL.Path, r.URL.Query().Encode(), r.Header) - if !compareSignatureV2(v2Auth, expectedAuth) { - return nil, s3err.ErrSignatureDoesNotMatch -@@ -163,11 +158,6 @@ func (iam *IdentityAccessManagement) doesPresignV2SignatureMatch(r *http.Request - return nil, s3err.ErrInvalidAccessKeyID - } - -- bucket, object := s3_constants.GetBucketAndObject(r) -- if !identity.canDo(s3_constants.ACTION_READ, bucket, object) { -- return nil, s3err.ErrAccessDenied -- } -- - expectedSignature := preSignatureV2(cred, r.Method, r.URL.Path, r.URL.Query().Encode(), r.Header, expires) - if !compareSignatureV2(signature, expectedSignature) { - return nil, s3err.ErrSignatureDoesNotMatch -diff --git a/weed/s3api/auth_signature_v4.go b/weed/s3api/auth_signature_v4.go -index a0417a922..c512f70cc 100644 ---- a/weed/s3api/auth_signature_v4.go -+++ b/weed/s3api/auth_signature_v4.go -@@ -190,12 +190,6 @@ func (iam *IdentityAccessManagement) doesSignatureMatch(hashedPayload string, r - return nil, s3err.ErrInvalidAccessKeyID - } - -- bucket, object := s3_constants.GetBucketAndObject(r) -- canDoResult := identity.canDo(s3_constants.ACTION_WRITE, bucket, object) -- if !canDoResult { -- return nil, s3err.ErrAccessDenied -- } -- - // Extract date, if not present throw error. - var dateStr string - if dateStr = req.Header.Get("x-amz-date"); dateStr == "" { -@@ -318,12 +312,6 @@ func (iam *IdentityAccessManagement) doesPresignedSignatureMatch(hashedPayload s - return nil, s3err.ErrInvalidAccessKeyID - } - -- // Check permissions -- bucket, object := s3_constants.GetBucketAndObject(r) -- if !identity.canDo(s3_constants.ACTION_READ, bucket, object) { -- return nil, s3err.ErrAccessDenied -- } -- - // Parse date - t, e := time.Parse(iso8601Format, dateStr) - if e != nil { diff --git a/packages/system/seaweedfs/patches/fix-volume-servicemonitor.patch b/packages/system/seaweedfs/patches/fix-volume-servicemonitor.patch deleted file mode 100644 index 3ca91c8b..00000000 --- a/packages/system/seaweedfs/patches/fix-volume-servicemonitor.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-servicemonitor.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-servicemonitor.yaml ---- a/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-servicemonitor.yaml (revision 8951bc13d7d02b5e6982a239570ed58ed7cb025a) -+++ b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-servicemonitor.yaml (revision fa4fff2292c4b79a92db5cd654a3c6bf590252a6) -@@ -21,9 +21,9 @@ - {{- with $.Values.global.monitoring.additionalLabels }} - {{- toYaml . | nindent 4 }} - {{- end }} --{{- if .Values.volume.annotations }} -+{{- if $.Values.volume.annotations }} - annotations: -- {{- toYaml .Values.volume.annotations | nindent 4 }} -+ {{- toYaml $.Values.volume.annotations | nindent 4 }} - {{- end }} - spec: - endpoints: diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index ffb50183..026b9e3e 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -1,7 +1,7 @@ global: enableSecurity: true serviceAccountName: "tenant-foo-seaweedfs" - imageName: "ghcr.io/cozystack/cozystack/seaweedfs" + imageName: "seaweedfs" extraEnvironmentVars: WEED_CLUSTER_SW_MASTER: "seaweedfs-master:9333" WEED_CLUSTER_SW_FILER: "seaweedfs-filer-client:8888" @@ -9,7 +9,8 @@ global: enabled: true seaweedfs: image: - tag: "latest@sha256:5ab64da9a0bc33c555f18d86a9664fe63617d48e5ea5192ef34822c24dcc5771" + tag: "latest@sha256:944e9bff98b088773847270238b63ce57dc5291054814d08e0226a139b3affb2" + registry: ghcr.io/cozystack/cozystack master: volumeSizeLimitMB: 30000 replicas: 3 @@ -86,7 +87,7 @@ seaweedfs: existingConfigSecret: null auditLogConfig: {} s3: - enabled: true + enabled: false extraArgs: - -idleTimeout=60 enableAuth: false From 2cb80079d1d77a957c940781f2ece0f8c2bfc0cb Mon Sep 17 00:00:00 2001 From: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> Date: Fri, 31 Oct 2025 20:39:20 +0000 Subject: [PATCH 25/76] Prepare release v0.37.3 Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> --- packages/apps/http-cache/images/nginx-cache.tag | 2 +- packages/apps/kubernetes/images/kubevirt-csi-driver.tag | 2 +- packages/core/installer/values.yaml | 2 +- packages/core/testing/values.yaml | 2 +- packages/extra/bootbox/images/matchbox.tag | 2 +- packages/extra/seaweedfs/images/objectstorage-sidecar.tag | 2 +- packages/system/bucket/images/s3manager.tag | 2 +- packages/system/cozystack-api/values.yaml | 2 +- packages/system/cozystack-controller/values.yaml | 4 ++-- packages/system/dashboard/templates/configmap.yaml | 2 +- packages/system/dashboard/values.yaml | 6 +++--- packages/system/kamaji/values.yaml | 4 ++-- packages/system/kubeovn-plunger/values.yaml | 2 +- packages/system/kubeovn-webhook/values.yaml | 2 +- packages/system/kubeovn/values.yaml | 2 +- packages/system/kubevirt-csi-node/values.yaml | 2 +- packages/system/lineage-controller-webhook/values.yaml | 2 +- packages/system/objectstorage-controller/values.yaml | 2 +- packages/system/seaweedfs/values.yaml | 2 +- 19 files changed, 23 insertions(+), 23 deletions(-) diff --git a/packages/apps/http-cache/images/nginx-cache.tag b/packages/apps/http-cache/images/nginx-cache.tag index 185dcc66..0970e11c 100644 --- a/packages/apps/http-cache/images/nginx-cache.tag +++ b/packages/apps/http-cache/images/nginx-cache.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:e0a07082bb6fc6aeaae2315f335386f1705a646c72f9e0af512aebbca5cb2b15 +ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:50ac1581e3100bd6c477a71161cb455a341ffaf9e5e2f6086802e4e25271e8af diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag index 67abc9d7..af215d39 100644 --- a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag +++ b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:01667d56186c33c0de75be6da82d0f1164a4592bfec86639cf571457b212075e +ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:10a265bde566618c801882bb16cd5c6da24314b342bba178c78785364ef53d5f diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index 9d09e1fa..fa830d41 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:v0.37.2@sha256:c7c2ed6f16c6db1797650b7a53b65c9db8d4f10cf0917f5ad4389b054ea25cba + image: ghcr.io/cozystack/cozystack/installer:v0.37.3@sha256:f89f7085d16fa10c933b12568a390f92bcd6b942a7efbe3c2ea94316730b5052 diff --git a/packages/core/testing/values.yaml b/packages/core/testing/values.yaml index ec882839..f595efc6 100755 --- a/packages/core/testing/values.yaml +++ b/packages/core/testing/values.yaml @@ -1,2 +1,2 @@ e2e: - image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.2@sha256:2071441e9dbca15bd8fe4029d2e41be8fea6066f127969bd74b41a1c3d4ca3ef + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.3@sha256:01e2e18cf5255091863199a66f35a1acebc2e28a935c9ac747ceb3b3af9c3cf3 diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index a869132a..93268ba5 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v0.37.2@sha256:dcd27eaff34a2b2425d34137d088d1b8d55e58b192ecb0d2dabde7e6a88d3fbf +ghcr.io/cozystack/cozystack/matchbox:v0.37.3@sha256:27f64c3bbc8a440cc820247aff6d93a3bbe2f42a27560436749d6fd5e662a583 diff --git a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag index 3ce2907e..af2e5a7d 100644 --- a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag +++ b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.2@sha256:1a739164b518dc395375ce9057bb582b5c539555f0ee2f2df7f931b23a1c4a48 +ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.3@sha256:9d5cf652534f9e59ad181740f146439ef04ed20ffee958141d66897fc192604f diff --git a/packages/system/bucket/images/s3manager.tag b/packages/system/bucket/images/s3manager.tag index f9433692..dca14cc6 100644 --- a/packages/system/bucket/images/s3manager.tag +++ b/packages/system/bucket/images/s3manager.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:2ac8139c13d5a9816e5ea7c78da30777f7119ea0cd4f18f44048fa121f977902 +ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:2b00d2357ae507fabf19ed0b01d707b503195983c8063515aabafbe1cb267877 diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index edc5e060..76c2f8f0 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,2 +1,2 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.2@sha256:1ce7d2658a4b705ef0a1c09b53d8708c78874775722558ae05aa77ed76cbe7ec + image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.3@sha256:bf366c6ad4d71246160a59519409554e817ccb397c7f28eac514ea5838c17c76 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index 7cf17f28..263a897e 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,5 +1,5 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.2@sha256:26adefda0a0c23e6e2edd9fec681ec313b75436ec5ccfede88d772298fce3aa1 + image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.3@sha256:d32e84565abcf91297afd98f0fd36578ccfe7c6ae56b982c1ba8934fedf5a33f debug: false disableTelemetry: false - cozystackVersion: "v0.37.2" + cozystackVersion: "v0.37.3" diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml index 1abb473d..9415898c 100644 --- a/packages/system/dashboard/templates/configmap.yaml +++ b/packages/system/dashboard/templates/configmap.yaml @@ -1,6 +1,6 @@ {{- $brandingConfig:= lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} -{{- $tenantText := "v0.37.2" }} +{{- $tenantText := "v0.37.3" }} {{- $footerText := "Cozystack" }} {{- $titleText := "Cozystack Dashboard" }} {{- $logoText := "false" }} diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index 13b2ec7e..2c052416 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,6 +1,6 @@ openapiUI: - image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.2@sha256:ea6f5c1632ad424b31ce329c20426bd04d520aa769aa0c78b35d730605564a60 + image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.3@sha256:5a7d4ce1f1a7d9b712c92d80a91d02b4783c2a2a0caa8096e8d92efa07a0f905 openapiUIK8sBff: - image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.2@sha256:995bb28ee4fb0263c70267f63b20581b64666522f931333df90a58d4c327a19c + image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.3@sha256:fc53077fdfdc3340b169758b88ec6501405388f3aa9d483c14afeffb645100d6 tokenProxy: - image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.2@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b + image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.3@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b diff --git a/packages/system/kamaji/values.yaml b/packages/system/kamaji/values.yaml index 6400973e..47af73cc 100644 --- a/packages/system/kamaji/values.yaml +++ b/packages/system/kamaji/values.yaml @@ -3,7 +3,7 @@ kamaji: deploy: false image: pullPolicy: IfNotPresent - tag: v0.37.2@sha256:ceefafb628e0500deccb5af7a3303e0b6348ac1bbdffaa6de7fd5ec004caadc6 + tag: v0.37.3@sha256:a879979f0defcd21c8c26c0276496f25c06adae674bb0057c30dec35dd18c2b1 repository: ghcr.io/cozystack/cozystack/kamaji resources: limits: @@ -13,4 +13,4 @@ kamaji: cpu: 100m memory: 100Mi extraArgs: - - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.2@sha256:ceefafb628e0500deccb5af7a3303e0b6348ac1bbdffaa6de7fd5ec004caadc6 + - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.3@sha256:a879979f0defcd21c8c26c0276496f25c06adae674bb0057c30dec35dd18c2b1 diff --git a/packages/system/kubeovn-plunger/values.yaml b/packages/system/kubeovn-plunger/values.yaml index bc1757ad..44654144 100644 --- a/packages/system/kubeovn-plunger/values.yaml +++ b/packages/system/kubeovn-plunger/values.yaml @@ -1,4 +1,4 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.2@sha256:781e06992871a7e6e6522ecf68b1e2806c710821f85949c9141872cb92312208 +image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.3@sha256:c57607c12bb03d2d644a51dab46c0f488f5dc81c9fb84403b4f688e73114e7c2 ovnCentralName: ovn-central diff --git a/packages/system/kubeovn-webhook/values.yaml b/packages/system/kubeovn-webhook/values.yaml index dd5d1c8a..23b80f79 100644 --- a/packages/system/kubeovn-webhook/values.yaml +++ b/packages/system/kubeovn-webhook/values.yaml @@ -1,3 +1,3 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.2@sha256:a2e6c6619270769d56beb1166d09fdc541a7754757d567ede558e8ebdeae397a +image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.3@sha256:c0490a48b715f30c606ec4f237043da04f79239ff1afe3f7b3c6ef7a71154274 diff --git a/packages/system/kubeovn/values.yaml b/packages/system/kubeovn/values.yaml index db8f9918..1d51f40f 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.5@sha256:0b98310bbe8c8f49f4b45d4cb12a52daa5f3e451ea9533db8d55c5d02434b31e + tag: v1.14.5@sha256:706824bb883de73a7949f1909ed5963084b4ff144426ddc759b67a6fee3b2cb7 diff --git a/packages/system/kubevirt-csi-node/values.yaml b/packages/system/kubevirt-csi-node/values.yaml index c681e727..f120cd4a 100644 --- a/packages/system/kubevirt-csi-node/values.yaml +++ b/packages/system/kubevirt-csi-node/values.yaml @@ -1,3 +1,3 @@ storageClass: replicated csiDriver: - image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:01667d56186c33c0de75be6da82d0f1164a4592bfec86639cf571457b212075e + image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:10a265bde566618c801882bb16cd5c6da24314b342bba178c78785364ef53d5f diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index 1cb539fe..111f41ed 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,3 +1,3 @@ lineageControllerWebhook: - image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.2@sha256:b5f88cafe82809aeb06d92bb4127efa322aa666a56c22a4b664091160166cf55 + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.3@sha256:794ec4cf3d5ea86e5cbc7d22d94acbba7560f4434f7b3c808a81a4352ec80fcc debug: false diff --git a/packages/system/objectstorage-controller/values.yaml b/packages/system/objectstorage-controller/values.yaml index 4e03ee09..b22408e9 100644 --- a/packages/system/objectstorage-controller/values.yaml +++ b/packages/system/objectstorage-controller/values.yaml @@ -1,3 +1,3 @@ objectstorage: controller: - image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.2@sha256:6d0ca2d95a9bfd29fb2f0e8b2b8a84b16c270830933457ed8c5c27ae3c6d2de7" + image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.3@sha256:5511b39fc4000f538f474d849c506dc7d2dd22561ea92256ea5bde1e84b82eca" diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index 026b9e3e..58f67ebd 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -124,7 +124,7 @@ seaweedfs: bucketClassName: "seaweedfs" region: "" sidecar: - image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.2@sha256:1a739164b518dc395375ce9057bb582b5c539555f0ee2f2df7f931b23a1c4a48" + image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.3@sha256:9d5cf652534f9e59ad181740f146439ef04ed20ffee958141d66897fc192604f" certificates: commonName: "SeaweedFS CA" ipAddresses: [] From 682a93315683a33ffcb3c1c33f70e2d2a6edc1c8 Mon Sep 17 00:00:00 2001 From: IvanHunters Date: Mon, 3 Nov 2025 10:53:47 +0300 Subject: [PATCH 26/76] [e2e] Increase Kubernetes connection timeouts This patch increases the connection and request timeouts used in the E2E tests when communicating with the Kubernetes API. The change improves test stability under high load and slow cluster response conditions. ```release-note [e2e] Increase connection and request timeouts for Kubernetes API calls in E2E tests to improve stability. ``` Signed-off-by: IvanHunters (cherry picked from commit e2eb1e267bb4772c860c55d36471131e8e1c8d66) --- hack/e2e-apps/run-kubernetes.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hack/e2e-apps/run-kubernetes.sh b/hack/e2e-apps/run-kubernetes.sh index 716b40dc..1446b093 100644 --- a/hack/e2e-apps/run-kubernetes.sh +++ b/hack/e2e-apps/run-kubernetes.sh @@ -87,14 +87,14 @@ EOF # Set up port forwarding to the Kubernetes API server for a 200 second timeout - bash -c 'timeout 200s kubectl port-forward service/kubernetes-'"${test_name}"' -n tenant-test '"${port}"':6443 > /dev/null 2>&1 &' + bash -c 'timeout 300s kubectl port-forward service/kubernetes-'"${test_name}"' -n tenant-test '"${port}"':6443 > /dev/null 2>&1 &' # Verify the Kubernetes version matches what we expect (retry for up to 20 seconds) timeout 20 sh -ec 'until kubectl --kubeconfig tenantkubeconfig version 2>/dev/null | grep -Fq "Server Version: ${k8s_version}"; do sleep 5; done' # Wait for the nodes to be ready (timeout after 2 minutes) - timeout 2m bash -c ' + timeout 3m bash -c ' until [ "$(kubectl --kubeconfig tenantkubeconfig get nodes -o jsonpath="{.items[*].metadata.name}" | wc -w)" -eq 2 ]; do - sleep 3 + sleep 2 done ' # Verify the nodes are ready From 83505f50c7244a2a314971fbe3d84b4880bb92e5 Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Mon, 3 Nov 2025 12:37:56 +0300 Subject: [PATCH 27/76] [nats] Merge container spec, not podTemplate ## What this PR does The NATS chart incorrectly used podTemplate+merge instead of container+merge to add resource requests and limits to the NATS container in the statefulset, but as a result it just completely wiped out the default container spec. By moving the overrides under the container key, the upstream chart now correctly merges the resource requests, instead of overwriting the container spec. ### Release note ```release-note [nats] Fix incorrect path to container resources in the NATS chart. ``` Signed-off-by: Timofei Larkin (cherry picked from commit 8b95db06ee53508eb9afa23170191ebecd6b5d12) --- packages/apps/nats/templates/nats.yaml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/apps/nats/templates/nats.yaml b/packages/apps/nats/templates/nats.yaml index 9994332f..55e0bd85 100644 --- a/packages/apps/nats/templates/nats.yaml +++ b/packages/apps/nats/templates/nats.yaml @@ -47,13 +47,9 @@ spec: retries: -1 values: nats: - podTemplate: + container: merge: - spec: - containers: - - name: nats - image: nats:2.10.17-alpine - resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 22 }} + resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 12 }} fullnameOverride: {{ .Release.Name }} config: {{- if or (gt (len $passwords) 0) (gt (len .Values.config.merge) 0) }} From 7f646d84bb79a0adec0d65d275d81f19689a8089 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 3 Nov 2025 10:41:39 +0100 Subject: [PATCH 28/76] [seaweedfs] Fix migration to v3.99 Signed-off-by: Andrei Kvapil (cherry picked from commit 42e6f0e3f2db927850121428baf5fcada08c1d37) --- packages/system/seaweedfs/templates/hook.yaml | 2 +- packages/system/seaweedfs/templates/version.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/system/seaweedfs/templates/hook.yaml b/packages/system/seaweedfs/templates/hook.yaml index 407d180f..ef02f4ee 100644 --- a/packages/system/seaweedfs/templates/hook.yaml +++ b/packages/system/seaweedfs/templates/hook.yaml @@ -2,7 +2,7 @@ {{- $configMap := lookup "v1" "ConfigMap" .Release.Namespace "seaweedfs-deployed-version" }} {{- if $configMap }} {{- $deployedVersion := dig "data" "version" "0" $configMap }} - {{- if ge $deployedVersion "2" }} + {{- if ge $deployedVersion "3" }} {{- $shouldRunUpdateHook = false }} {{- end }} {{- end }} diff --git a/packages/system/seaweedfs/templates/version.yaml b/packages/system/seaweedfs/templates/version.yaml index 4b7298b2..69b6762f 100644 --- a/packages/system/seaweedfs/templates/version.yaml +++ b/packages/system/seaweedfs/templates/version.yaml @@ -3,4 +3,4 @@ kind: ConfigMap metadata: name: seaweedfs-deployed-version data: - version: "2" + version: "3" From 9fae1b17b835879fa2cbd544c34ed9a6b2f98139 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 3 Nov 2025 11:55:21 +0100 Subject: [PATCH 29/76] [tenant] Allow listing workloads Signed-off-by: Andrei Kvapil (cherry picked from commit 93a92418998e4761382b314fa79d0e7202110a5c) --- packages/apps/tenant/templates/tenant.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/apps/tenant/templates/tenant.yaml b/packages/apps/tenant/templates/tenant.yaml index d58c37d4..9845b644 100644 --- a/packages/apps/tenant/templates/tenant.yaml +++ b/packages/apps/tenant/templates/tenant.yaml @@ -28,6 +28,7 @@ rules: - cozystack.io resources: - workloadmonitors + - workloads verbs: ["get", "list", "watch"] - apiGroups: - core.cozystack.io @@ -113,6 +114,7 @@ rules: - cozystack.io resources: - workloadmonitors + - workloads verbs: ["get", "list", "watch"] --- kind: RoleBinding @@ -184,6 +186,7 @@ rules: - cozystack.io resources: - workloadmonitors + - workloads verbs: ["get", "list", "watch"] - apiGroups: - core.cozystack.io @@ -282,6 +285,7 @@ rules: - cozystack.io resources: - workloadmonitors + - workloads verbs: ["get", "list", "watch"] - apiGroups: - core.cozystack.io @@ -356,6 +360,7 @@ rules: - cozystack.io resources: - workloadmonitors + - workloads verbs: ["get", "list", "watch"] - apiGroups: - core.cozystack.io From 39db2c141af189e40ba2c5ad11e482bf7b4e612e Mon Sep 17 00:00:00 2001 From: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> Date: Mon, 3 Nov 2025 11:03:59 +0000 Subject: [PATCH 30/76] Prepare release v0.37.4 Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> --- packages/apps/http-cache/images/nginx-cache.tag | 2 +- packages/core/installer/values.yaml | 2 +- packages/core/testing/values.yaml | 2 +- packages/extra/bootbox/images/matchbox.tag | 2 +- packages/extra/seaweedfs/images/objectstorage-sidecar.tag | 2 +- packages/system/bucket/images/s3manager.tag | 2 +- packages/system/cozystack-api/values.yaml | 2 +- packages/system/cozystack-controller/values.yaml | 4 ++-- packages/system/dashboard/templates/configmap.yaml | 2 +- packages/system/dashboard/values.yaml | 6 +++--- packages/system/kamaji/values.yaml | 4 ++-- packages/system/kubeovn-plunger/values.yaml | 2 +- packages/system/kubeovn-webhook/values.yaml | 2 +- packages/system/kubeovn/values.yaml | 2 +- packages/system/lineage-controller-webhook/values.yaml | 2 +- packages/system/objectstorage-controller/values.yaml | 2 +- packages/system/seaweedfs/values.yaml | 2 +- 17 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/apps/http-cache/images/nginx-cache.tag b/packages/apps/http-cache/images/nginx-cache.tag index 0970e11c..a5e4ca7b 100644 --- a/packages/apps/http-cache/images/nginx-cache.tag +++ b/packages/apps/http-cache/images/nginx-cache.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:50ac1581e3100bd6c477a71161cb455a341ffaf9e5e2f6086802e4e25271e8af +ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:b7633717cd7449c0042ae92d8ca9b36e4d69566561f5c7d44e21058e7d05c6d5 diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index fa830d41..bc1b7347 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:v0.37.3@sha256:f89f7085d16fa10c933b12568a390f92bcd6b942a7efbe3c2ea94316730b5052 + image: ghcr.io/cozystack/cozystack/installer:v0.37.4@sha256:b3e8f5156d953b704e1d70d13ba7cc8d27ae2a2c1c0e35eeb4efe9e2889e5512 diff --git a/packages/core/testing/values.yaml b/packages/core/testing/values.yaml index f595efc6..a923101e 100755 --- a/packages/core/testing/values.yaml +++ b/packages/core/testing/values.yaml @@ -1,2 +1,2 @@ e2e: - image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.3@sha256:01e2e18cf5255091863199a66f35a1acebc2e28a935c9ac747ceb3b3af9c3cf3 + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.4@sha256:5fa8b8d86a2ec52ecb2cf8159d863ba7b123bcdf19da2cd13eede9b6c6154d87 diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index 93268ba5..065a4185 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v0.37.3@sha256:27f64c3bbc8a440cc820247aff6d93a3bbe2f42a27560436749d6fd5e662a583 +ghcr.io/cozystack/cozystack/matchbox:v0.37.4@sha256:ca339988bd86480962dcbc0209252173eb347d1ac750d8f96bc06c41df3a9358 diff --git a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag index af2e5a7d..20b30c76 100644 --- a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag +++ b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.3@sha256:9d5cf652534f9e59ad181740f146439ef04ed20ffee958141d66897fc192604f +ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.4@sha256:b805dc391cde74f0e9a8b9df15aba5209f0faa73bb0523b5b0292083405e0b08 diff --git a/packages/system/bucket/images/s3manager.tag b/packages/system/bucket/images/s3manager.tag index dca14cc6..3f830cdb 100644 --- a/packages/system/bucket/images/s3manager.tag +++ b/packages/system/bucket/images/s3manager.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:2b00d2357ae507fabf19ed0b01d707b503195983c8063515aabafbe1cb267877 +ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:13340fa712e398cc788fb86107f5ce2f415516d015aa68cd66ce5eabb266e77b diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index 76c2f8f0..ef5b5d28 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,2 +1,2 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.3@sha256:bf366c6ad4d71246160a59519409554e817ccb397c7f28eac514ea5838c17c76 + image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.4@sha256:be1ff731b64ec0e8b9f04e01cb21b069f4e340389da4abb6612477562a0500c8 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index 263a897e..8694b07b 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,5 +1,5 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.3@sha256:d32e84565abcf91297afd98f0fd36578ccfe7c6ae56b982c1ba8934fedf5a33f + image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.4@sha256:fdd9481ccb60789930412febde2c9970d720b02522f0709ab0211e7cbdaed447 debug: false disableTelemetry: false - cozystackVersion: "v0.37.3" + cozystackVersion: "v0.37.4" diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml index 9415898c..ec40fbb1 100644 --- a/packages/system/dashboard/templates/configmap.yaml +++ b/packages/system/dashboard/templates/configmap.yaml @@ -1,6 +1,6 @@ {{- $brandingConfig:= lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} -{{- $tenantText := "v0.37.3" }} +{{- $tenantText := "v0.37.4" }} {{- $footerText := "Cozystack" }} {{- $titleText := "Cozystack Dashboard" }} {{- $logoText := "false" }} diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index 2c052416..8bb72e30 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,6 +1,6 @@ openapiUI: - image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.3@sha256:5a7d4ce1f1a7d9b712c92d80a91d02b4783c2a2a0caa8096e8d92efa07a0f905 + image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.4@sha256:f472e678e9869494ab3aa99247f3e5c80f2b543ab5708af2d5451d45934d3925 openapiUIK8sBff: - image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.3@sha256:fc53077fdfdc3340b169758b88ec6501405388f3aa9d483c14afeffb645100d6 + image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.4@sha256:b780da469bf879d4a05a80781a2bbfeefc2570fe4129bd8857b216d3bf5902fb tokenProxy: - image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.3@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b + image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.4@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b diff --git a/packages/system/kamaji/values.yaml b/packages/system/kamaji/values.yaml index 47af73cc..167926af 100644 --- a/packages/system/kamaji/values.yaml +++ b/packages/system/kamaji/values.yaml @@ -3,7 +3,7 @@ kamaji: deploy: false image: pullPolicy: IfNotPresent - tag: v0.37.3@sha256:a879979f0defcd21c8c26c0276496f25c06adae674bb0057c30dec35dd18c2b1 + tag: v0.37.4@sha256:8d5343b12c98f3b8456d53cbb5ae2048ff67aebc2a6091bfc338756adda848ed repository: ghcr.io/cozystack/cozystack/kamaji resources: limits: @@ -13,4 +13,4 @@ kamaji: cpu: 100m memory: 100Mi extraArgs: - - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.3@sha256:a879979f0defcd21c8c26c0276496f25c06adae674bb0057c30dec35dd18c2b1 + - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.4@sha256:8d5343b12c98f3b8456d53cbb5ae2048ff67aebc2a6091bfc338756adda848ed diff --git a/packages/system/kubeovn-plunger/values.yaml b/packages/system/kubeovn-plunger/values.yaml index 44654144..b388ed05 100644 --- a/packages/system/kubeovn-plunger/values.yaml +++ b/packages/system/kubeovn-plunger/values.yaml @@ -1,4 +1,4 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.3@sha256:c57607c12bb03d2d644a51dab46c0f488f5dc81c9fb84403b4f688e73114e7c2 +image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.4@sha256:4f9168b2667879d006d2a4f6f3fca600ab3853dd8ac4c79b3fc8cb114f7a7632 ovnCentralName: ovn-central diff --git a/packages/system/kubeovn-webhook/values.yaml b/packages/system/kubeovn-webhook/values.yaml index 23b80f79..6b6da720 100644 --- a/packages/system/kubeovn-webhook/values.yaml +++ b/packages/system/kubeovn-webhook/values.yaml @@ -1,3 +1,3 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.3@sha256:c0490a48b715f30c606ec4f237043da04f79239ff1afe3f7b3c6ef7a71154274 +image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.4@sha256:f803cf5e7a2f1fa2bcf7003f8a5931e5d7bccddce7f92c88029292b4826c9050 diff --git a/packages/system/kubeovn/values.yaml b/packages/system/kubeovn/values.yaml index 1d51f40f..0053e491 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.5@sha256:706824bb883de73a7949f1909ed5963084b4ff144426ddc759b67a6fee3b2cb7 + tag: v1.14.5@sha256:47fa31963539180f8e9a340ea60d7756e200762d22f3589d207f89309e4e19c3 diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index 111f41ed..ff31cc35 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,3 +1,3 @@ lineageControllerWebhook: - image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.3@sha256:794ec4cf3d5ea86e5cbc7d22d94acbba7560f4434f7b3c808a81a4352ec80fcc + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.4@sha256:fb739bf575a93bb76c65b46f415e0f8343df824155c53207690420f00a98a598 debug: false diff --git a/packages/system/objectstorage-controller/values.yaml b/packages/system/objectstorage-controller/values.yaml index b22408e9..495c3e80 100644 --- a/packages/system/objectstorage-controller/values.yaml +++ b/packages/system/objectstorage-controller/values.yaml @@ -1,3 +1,3 @@ objectstorage: controller: - image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.3@sha256:5511b39fc4000f538f474d849c506dc7d2dd22561ea92256ea5bde1e84b82eca" + image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.4@sha256:5511b39fc4000f538f474d849c506dc7d2dd22561ea92256ea5bde1e84b82eca" diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index 58f67ebd..10d19401 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -124,7 +124,7 @@ seaweedfs: bucketClassName: "seaweedfs" region: "" sidecar: - image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.3@sha256:9d5cf652534f9e59ad181740f146439ef04ed20ffee958141d66897fc192604f" + image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.4@sha256:b805dc391cde74f0e9a8b9df15aba5209f0faa73bb0523b5b0292083405e0b08" certificates: commonName: "SeaweedFS CA" ipAddresses: [] From 82e5a0d403e07cd9630b3e314eff96df9b437a5c Mon Sep 17 00:00:00 2001 From: IvanHunters Date: Tue, 4 Nov 2025 02:29:24 +0300 Subject: [PATCH 31/76] [ingress] Enforce HTTPS-only for API This patch updates the default API Ingress to add the nginx.ingress.kubernetes.io/force-ssl-redirect annotation, ensuring all HTTP traffic (port 80) is redirected to HTTPS (port 443). This prevents unencrypted external access and improves security. ```release-note [ingress] Force HTTPS access for api.dev3.infra.aenix.org and block direct HTTP. ``` Signed-off-by: IvanHunters (cherry picked from commit 667c778f27b5460ffc07713f8639ff8b07a108f7) --- packages/system/cozystack-api/templates/api-ingress.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/system/cozystack-api/templates/api-ingress.yaml b/packages/system/cozystack-api/templates/api-ingress.yaml index d7670e71..54fdf54b 100644 --- a/packages/system/cozystack-api/templates/api-ingress.yaml +++ b/packages/system/cozystack-api/templates/api-ingress.yaml @@ -10,6 +10,7 @@ metadata: annotations: nginx.ingress.kubernetes.io/backend-protocol: HTTPS nginx.ingress.kubernetes.io/ssl-passthrough: "true" + nginx.ingress.kubernetes.io/force-ssl-redirect: "true" name: kubernetes namespace: default spec: From 70cb6b586aa9cdb3870ba2fadf5a5eff8ae66b66 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 4 Nov 2025 10:17:51 +0100 Subject: [PATCH 32/76] [redis] Bump Redis image version for security fixes (#1580) This patch updates the RedisFailover Helm template to use a newer, secure Redis version (8.2.0). This addresses known security issues in the previous Redis version and ensures safer deployments. ```release-note [redis] Upgrade Redis to a secure version (8.2.0) to fix security vulnerabilities. ``` ## What this PR does ### Release note ## Summary by CodeRabbit * **New Features** * Redis deployments can now specify the container image via a new configurable value (default: redis:8.2.0), allowing easy override of the Redis image used. * **Schema** * Values schema and resource definition schemas updated to include and validate the new image setting. * **Documentation** * README updated to document the new image parameter. --- packages/apps/redis/templates/redisfailover.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/apps/redis/templates/redisfailover.yaml b/packages/apps/redis/templates/redisfailover.yaml index f6d1ae05..20e91646 100644 --- a/packages/apps/redis/templates/redisfailover.yaml +++ b/packages/apps/redis/templates/redisfailover.yaml @@ -27,6 +27,7 @@ spec: replicas: 3 resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 6 }} redis: + image: "redis:8.2.0" resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 6 }} replicas: {{ .Values.replicas }} {{- with .Values.size }} From 0e5aad85889e3923e1822c1f20907aac1a6504d3 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 4 Nov 2025 10:13:15 +0100 Subject: [PATCH 33/76] [kubevirt] Fix: kubevirt metrics rule Signed-off-by: Andrei Kvapil (cherry picked from commit 6443a1264ea39471f39b1451db0ead77cc95cc6f) --- packages/system/kubevirt-operator/alerts/PrometheusRule.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/system/kubevirt-operator/alerts/PrometheusRule.yaml b/packages/system/kubevirt-operator/alerts/PrometheusRule.yaml index f20762df..73ef3ce4 100644 --- a/packages/system/kubevirt-operator/alerts/PrometheusRule.yaml +++ b/packages/system/kubevirt-operator/alerts/PrometheusRule.yaml @@ -10,7 +10,7 @@ spec: expr: | max_over_time( kubevirt_vm_info{ - status!="Running", + status!="running", exported_namespace=~".+", name=~".+" }[10m] @@ -27,7 +27,7 @@ spec: expr: | max_over_time( kubevirt_vmi_info{ - phase!="running", + phase!="Running", exported_namespace=~".+", name=~".+" }[10m] From 25edc1f54b2760ed93d03debf535b4992a43d29c Mon Sep 17 00:00:00 2001 From: Nikita <166552198+nbykov0@users.noreply.github.com> Date: Tue, 4 Nov 2025 13:52:33 +0300 Subject: [PATCH 34/76] [core] rm talos lldp extension (#1586) Removes Talos lldp extension. Please build a custom talos image with factory.talos.dev if you need it. ```release-note Talos lldp extension removed. ``` * **Chores** * Removed LLDPD (Link Layer Discovery Protocol Daemon) system extension from cluster configuration. This eliminates the LLDPD kernel module from cluster setups, removes LLDPD references from build processes, and updates installation profiles across all supported deployment methods including bare metal, cloud environments, and ISO installations, resulting in a reduced system footprint. --- hack/e2e-prepare-cluster.bats | 1 - packages/core/installer/hack/gen-profiles.sh | 3 +-- packages/core/installer/images/talos/profiles/initramfs.yaml | 1 - packages/core/installer/images/talos/profiles/installer.yaml | 1 - packages/core/installer/images/talos/profiles/iso.yaml | 1 - packages/core/installer/images/talos/profiles/kernel.yaml | 1 - packages/core/installer/images/talos/profiles/metal.yaml | 1 - packages/core/installer/images/talos/profiles/nocloud.yaml | 1 - 8 files changed, 1 insertion(+), 9 deletions(-) diff --git a/hack/e2e-prepare-cluster.bats b/hack/e2e-prepare-cluster.bats index 38620532..650ca643 100644 --- a/hack/e2e-prepare-cluster.bats +++ b/hack/e2e-prepare-cluster.bats @@ -132,7 +132,6 @@ machine: - usermode_helper=disabled - name: zfs - name: spl - - name: lldpd registries: mirrors: docker.io: diff --git a/packages/core/installer/hack/gen-profiles.sh b/packages/core/installer/hack/gen-profiles.sh index 2325b45f..bbe932d7 100755 --- a/packages/core/installer/hack/gen-profiles.sh +++ b/packages/core/installer/hack/gen-profiles.sh @@ -5,7 +5,7 @@ set -u TMPDIR=$(mktemp -d) PROFILES="initramfs kernel iso installer nocloud metal" FIRMWARES="amd-ucode amdgpu bnx2-bnx2x i915 intel-ice-firmware intel-ucode qlogic-firmware" -EXTENSIONS="drbd zfs lldpd" +EXTENSIONS="drbd zfs" mkdir -p images/talos/profiles @@ -90,7 +90,6 @@ input: - imageRef: ${QLOGIC_FIRMWARE_IMAGE} - imageRef: ${DRBD_IMAGE} - imageRef: ${ZFS_IMAGE} - - imageRef: ${LLDPD_IMAGE} output: kind: ${kind} imageOptions: ${image_options} diff --git a/packages/core/installer/images/talos/profiles/initramfs.yaml b/packages/core/installer/images/talos/profiles/initramfs.yaml index 7e2bdf1d..aec0e7e2 100644 --- a/packages/core/installer/images/talos/profiles/initramfs.yaml +++ b/packages/core/installer/images/talos/profiles/initramfs.yaml @@ -21,7 +21,6 @@ input: - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250708@sha256:97124ee3594ab1529c8153b633f85f2d2de1252ee8222a77f81904dcabd76815 - imageRef: ghcr.io/siderolabs/drbd:9.2.14-v1.10.6@sha256:ca7fba878c5acb8fdfe130a39472a6c0a5c9dd74d65ba7507c09780a873b29c7 - imageRef: ghcr.io/siderolabs/zfs:2.3.3-v1.10.6@sha256:4952ef7306cf014823b6a66cf6d29840f4c6b7b362e36f9d6e853846c7dd0025 - - imageRef: ghcr.io/siderolabs/lldpd:1.0.19@sha256:73caa3c3a6c325970d0f527963f982698154d5f39c8c045b0fc2eb51d7da7b85 output: kind: initramfs imageOptions: {} diff --git a/packages/core/installer/images/talos/profiles/installer.yaml b/packages/core/installer/images/talos/profiles/installer.yaml index 7ad604a2..848224ee 100644 --- a/packages/core/installer/images/talos/profiles/installer.yaml +++ b/packages/core/installer/images/talos/profiles/installer.yaml @@ -21,7 +21,6 @@ input: - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250708@sha256:97124ee3594ab1529c8153b633f85f2d2de1252ee8222a77f81904dcabd76815 - imageRef: ghcr.io/siderolabs/drbd:9.2.14-v1.10.6@sha256:ca7fba878c5acb8fdfe130a39472a6c0a5c9dd74d65ba7507c09780a873b29c7 - imageRef: ghcr.io/siderolabs/zfs:2.3.3-v1.10.6@sha256:4952ef7306cf014823b6a66cf6d29840f4c6b7b362e36f9d6e853846c7dd0025 - - imageRef: ghcr.io/siderolabs/lldpd:1.0.19@sha256:73caa3c3a6c325970d0f527963f982698154d5f39c8c045b0fc2eb51d7da7b85 output: kind: installer imageOptions: {} diff --git a/packages/core/installer/images/talos/profiles/iso.yaml b/packages/core/installer/images/talos/profiles/iso.yaml index 326917e4..7c1aaf9a 100644 --- a/packages/core/installer/images/talos/profiles/iso.yaml +++ b/packages/core/installer/images/talos/profiles/iso.yaml @@ -21,7 +21,6 @@ input: - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250708@sha256:97124ee3594ab1529c8153b633f85f2d2de1252ee8222a77f81904dcabd76815 - imageRef: ghcr.io/siderolabs/drbd:9.2.14-v1.10.6@sha256:ca7fba878c5acb8fdfe130a39472a6c0a5c9dd74d65ba7507c09780a873b29c7 - imageRef: ghcr.io/siderolabs/zfs:2.3.3-v1.10.6@sha256:4952ef7306cf014823b6a66cf6d29840f4c6b7b362e36f9d6e853846c7dd0025 - - imageRef: ghcr.io/siderolabs/lldpd:1.0.19@sha256:73caa3c3a6c325970d0f527963f982698154d5f39c8c045b0fc2eb51d7da7b85 output: kind: iso imageOptions: {} diff --git a/packages/core/installer/images/talos/profiles/kernel.yaml b/packages/core/installer/images/talos/profiles/kernel.yaml index 89cf5371..86079632 100644 --- a/packages/core/installer/images/talos/profiles/kernel.yaml +++ b/packages/core/installer/images/talos/profiles/kernel.yaml @@ -21,7 +21,6 @@ input: - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250708@sha256:97124ee3594ab1529c8153b633f85f2d2de1252ee8222a77f81904dcabd76815 - imageRef: ghcr.io/siderolabs/drbd:9.2.14-v1.10.6@sha256:ca7fba878c5acb8fdfe130a39472a6c0a5c9dd74d65ba7507c09780a873b29c7 - imageRef: ghcr.io/siderolabs/zfs:2.3.3-v1.10.6@sha256:4952ef7306cf014823b6a66cf6d29840f4c6b7b362e36f9d6e853846c7dd0025 - - imageRef: ghcr.io/siderolabs/lldpd:1.0.19@sha256:73caa3c3a6c325970d0f527963f982698154d5f39c8c045b0fc2eb51d7da7b85 output: kind: kernel imageOptions: {} diff --git a/packages/core/installer/images/talos/profiles/metal.yaml b/packages/core/installer/images/talos/profiles/metal.yaml index 8e1f1ebb..2619fd63 100644 --- a/packages/core/installer/images/talos/profiles/metal.yaml +++ b/packages/core/installer/images/talos/profiles/metal.yaml @@ -21,7 +21,6 @@ input: - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250708@sha256:97124ee3594ab1529c8153b633f85f2d2de1252ee8222a77f81904dcabd76815 - imageRef: ghcr.io/siderolabs/drbd:9.2.14-v1.10.6@sha256:ca7fba878c5acb8fdfe130a39472a6c0a5c9dd74d65ba7507c09780a873b29c7 - imageRef: ghcr.io/siderolabs/zfs:2.3.3-v1.10.6@sha256:4952ef7306cf014823b6a66cf6d29840f4c6b7b362e36f9d6e853846c7dd0025 - - imageRef: ghcr.io/siderolabs/lldpd:1.0.19@sha256:73caa3c3a6c325970d0f527963f982698154d5f39c8c045b0fc2eb51d7da7b85 output: kind: image imageOptions: { diskSize: 1306525696, diskFormat: raw } diff --git a/packages/core/installer/images/talos/profiles/nocloud.yaml b/packages/core/installer/images/talos/profiles/nocloud.yaml index c9604759..8db68208 100644 --- a/packages/core/installer/images/talos/profiles/nocloud.yaml +++ b/packages/core/installer/images/talos/profiles/nocloud.yaml @@ -21,7 +21,6 @@ input: - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250708@sha256:97124ee3594ab1529c8153b633f85f2d2de1252ee8222a77f81904dcabd76815 - imageRef: ghcr.io/siderolabs/drbd:9.2.14-v1.10.6@sha256:ca7fba878c5acb8fdfe130a39472a6c0a5c9dd74d65ba7507c09780a873b29c7 - imageRef: ghcr.io/siderolabs/zfs:2.3.3-v1.10.6@sha256:4952ef7306cf014823b6a66cf6d29840f4c6b7b362e36f9d6e853846c7dd0025 - - imageRef: ghcr.io/siderolabs/lldpd:1.0.19@sha256:73caa3c3a6c325970d0f527963f982698154d5f39c8c045b0fc2eb51d7da7b85 output: kind: image imageOptions: { diskSize: 1306525696, diskFormat: raw } From 7058e404cfff4f57bd4aa8c529bd5cb4d09bd2c6 Mon Sep 17 00:00:00 2001 From: Isaiah Olson Date: Mon, 3 Nov 2025 23:59:12 -0600 Subject: [PATCH 35/76] Fixes for NATS App Helm chart, fix template issues with config.merge value Signed-off-by: Isaiah Olson (cherry picked from commit b1ebc9cc85a3cfe737b21a079e86d98b01edd2d0) --- packages/apps/nats/templates/nats.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/apps/nats/templates/nats.yaml b/packages/apps/nats/templates/nats.yaml index 55e0bd85..d44c0bcf 100644 --- a/packages/apps/nats/templates/nats.yaml +++ b/packages/apps/nats/templates/nats.yaml @@ -52,7 +52,7 @@ spec: resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 12 }} fullnameOverride: {{ .Release.Name }} config: - {{- if or (gt (len $passwords) 0) (gt (len .Values.config.merge) 0) }} + {{- if or (gt (len $passwords) 0) (and .Values.config (hasKey .Values.config "merge") (gt (len .Values.config.merge) 0)) }} merge: {{- if gt (len $passwords) 0 }} accounts: @@ -63,8 +63,8 @@ spec: password: "{{ $password }}" {{- end }} {{- end }} - {{- if and .Values.config (hasKey .Values.config "merge") }} - {{ toYaml .Values.config.merge | nindent 12 }} + {{- if and .Values.config (hasKey .Values.config "merge") (gt (len .Values.config.merge) 0) }} + {{ toYaml .Values.config.merge | nindent 10 }} {{- end }} {{- end }} {{- if and .Values.config (hasKey .Values.config "resolver") }} From b0beb6edf904261d4b7f42844452f9e0a61de73b Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Tue, 4 Nov 2025 18:22:43 +0300 Subject: [PATCH 36/76] [nats] Terser checks using `with` This patch makes the fixes from `b1ebc9cc` by @insignia96 terser by making use of Helm's `with` blocks. Signed-off-by: Timofei Larkin (cherry picked from commit 172774b6cd2e01b206a5f6fa9fe4c3a3b0df0394) --- packages/apps/nats/templates/nats.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/apps/nats/templates/nats.yaml b/packages/apps/nats/templates/nats.yaml index d44c0bcf..b5cfd6e4 100644 --- a/packages/apps/nats/templates/nats.yaml +++ b/packages/apps/nats/templates/nats.yaml @@ -52,9 +52,9 @@ spec: resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 12 }} fullnameOverride: {{ .Release.Name }} config: - {{- if or (gt (len $passwords) 0) (and .Values.config (hasKey .Values.config "merge") (gt (len .Values.config.merge) 0)) }} + {{- if or $passwords .Values.config.merge }} merge: - {{- if gt (len $passwords) 0 }} + {{- if $passwords }} accounts: A: users: @@ -63,13 +63,13 @@ spec: password: "{{ $password }}" {{- end }} {{- end }} - {{- if and .Values.config (hasKey .Values.config "merge") (gt (len .Values.config.merge) 0) }} - {{ toYaml .Values.config.merge | nindent 10 }} + {{- with .Values.config.merge }} + {{- toYaml . | nindent 10 }} {{- end }} {{- end }} - {{- if and .Values.config (hasKey .Values.config "resolver") }} + {{- with .Values.config.resolver }} resolver: - {{ toYaml .Values.config.resolver | nindent 12 }} + {{- toYaml . | nindent 10 }} {{- end }} cluster: enabled: true From d7b5636f23a6402d13e004d22f4d713a7de6d8df Mon Sep 17 00:00:00 2001 From: IvanHunters Date: Tue, 4 Nov 2025 01:59:16 +0300 Subject: [PATCH 37/76] [flux] Close Flux Operator ports to external access This patch updates the Flux Operator Deployment to remove hostPort and hostNetwork, ensuring that ports 8080 and 8081 are only accessible within the cluster. This prevents external exposure and improves security. ```release-note [flux] Close Flux Operator ports (8080/8081) to external access for improved security. ``` Signed-off-by: IvanHunters (cherry picked from commit eea685065a2261caa93f87075cfa5fd5b86e6152) --- packages/system/fluxcd-operator/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/system/fluxcd-operator/values.yaml b/packages/system/fluxcd-operator/values.yaml index 9053689a..250c19c4 100644 --- a/packages/system/fluxcd-operator/values.yaml +++ b/packages/system/fluxcd-operator/values.yaml @@ -4,7 +4,7 @@ flux-operator: - key: node.kubernetes.io/not-ready operator: Exists effect: NoSchedule - hostNetwork: true + hostNetwork: false resources: limits: cpu: 100m From 65ea7116ce7b5773e94f1f3d35863b03cd0e9a48 Mon Sep 17 00:00:00 2001 From: IvanHunters Date: Tue, 4 Nov 2025 12:00:30 +0300 Subject: [PATCH 38/76] close metrics port for external Signed-off-by: IvanHunters (cherry picked from commit 52a23eacfc32430d8b008b765c64a81526521bae) --- .../templates/network-policy.yaml | 18 ++++++++++++++++++ packages/system/fluxcd-operator/values.yaml | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml 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 new file mode 100644 index 00000000..fc7fa004 --- /dev/null +++ b/packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml @@ -0,0 +1,18 @@ +apiVersion: cilium.io/v2 +kind: CiliumClusterwideNetworkPolicy +metadata: + name: {{ include "flux-operator.fullname" . }}-restrict +spec: + nodeSelector: {} + ingressDeny: + - fromEntities: + - world + toPorts: + - ports: + - port: "8080" + protocol: TCP + - port: "8081" + protocol: TCP + ingress: + - fromEntities: + - cluster diff --git a/packages/system/fluxcd-operator/values.yaml b/packages/system/fluxcd-operator/values.yaml index 250c19c4..9053689a 100644 --- a/packages/system/fluxcd-operator/values.yaml +++ b/packages/system/fluxcd-operator/values.yaml @@ -4,7 +4,7 @@ flux-operator: - key: node.kubernetes.io/not-ready operator: Exists effect: NoSchedule - hostNetwork: false + hostNetwork: true resources: limits: cpu: 100m From 71c32d91a787f325e07fdb3e37cf63c2092b3e70 Mon Sep 17 00:00:00 2001 From: IvanHunters Date: Tue, 4 Nov 2025 12:14:43 +0300 Subject: [PATCH 39/76] add patch Signed-off-by: IvanHunters (cherry picked from commit f60e2555c990a2cb2766802e512a15d890bb15fa) --- packages/system/fluxcd-operator/Makefile | 1 + .../patches/networkPolicy.diff | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 packages/system/fluxcd-operator/patches/networkPolicy.diff diff --git a/packages/system/fluxcd-operator/Makefile b/packages/system/fluxcd-operator/Makefile index f41360ee..84ffc6fe 100644 --- a/packages/system/fluxcd-operator/Makefile +++ b/packages/system/fluxcd-operator/Makefile @@ -10,3 +10,4 @@ update: rm -rf charts helm pull oci://ghcr.io/controlplaneio-fluxcd/charts/flux-operator --untar --untardir charts patch --no-backup-if-mismatch -p1 < patches/kubernetesEnvs.diff + patch --no-backup-if-mismatch -p1 < patches/networkPolicy.diff diff --git a/packages/system/fluxcd-operator/patches/networkPolicy.diff b/packages/system/fluxcd-operator/patches/networkPolicy.diff new file mode 100644 index 00000000..d2adc974 --- /dev/null +++ b/packages/system/fluxcd-operator/patches/networkPolicy.diff @@ -0,0 +1,23 @@ +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 +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 @@ ++apiVersion: cilium.io/v2 ++kind: CiliumClusterwideNetworkPolicy ++metadata: ++ name: {{ include "flux-operator.fullname" . }}-restrict ++spec: ++ nodeSelector: {} ++ ingressDeny: ++ - fromEntities: ++ - world ++ toPorts: ++ - ports: ++ - port: "8080" ++ protocol: TCP ++ - port: "8081" ++ protocol: TCP ++ ingress: ++ - fromEntities: ++ - cluster From c1ec2a2fc34bbbbeaba97e358b7b4c557c1c874c Mon Sep 17 00:00:00 2001 From: IvanHunters Date: Tue, 4 Nov 2025 17:56:49 +0300 Subject: [PATCH 40/76] add rule for success installing Signed-off-by: IvanHunters (cherry picked from commit 48c6e23ca017393c3725775be04dee4f9ca1e926) --- .../charts/flux-operator/templates/network-policy.yaml | 3 +++ packages/system/fluxcd-operator/patches/networkPolicy.diff | 2 ++ 2 files changed, 5 insertions(+) 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 fc7fa004..0a9db1cc 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,3 +1,5 @@ +{{- if .Capabilities.APIVersions.Has "cilium.io/v2/CiliumClusterwideNetworkPolicy" }} +--- apiVersion: cilium.io/v2 kind: CiliumClusterwideNetworkPolicy metadata: @@ -16,3 +18,4 @@ spec: ingress: - fromEntities: - cluster +{{- end }} diff --git a/packages/system/fluxcd-operator/patches/networkPolicy.diff b/packages/system/fluxcd-operator/patches/networkPolicy.diff index d2adc974..a7bf3207 100644 --- a/packages/system/fluxcd-operator/patches/networkPolicy.diff +++ b/packages/system/fluxcd-operator/patches/networkPolicy.diff @@ -3,6 +3,7 @@ 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 @@ ++{{- if .Capabilities.APIVersions.Has "cilium.io/v2/CiliumClusterwideNetworkPolicy" }} +apiVersion: cilium.io/v2 +kind: CiliumClusterwideNetworkPolicy +metadata: @@ -21,3 +22,4 @@ new file mode 100644 + ingress: + - fromEntities: + - cluster ++{{- end }} From 3b027a7da94648f8264e95bc1d94eb0841d20218 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Sat, 1 Nov 2025 17:38:08 +0100 Subject: [PATCH 41/76] [dashboard-controller] Move bages generation logic to internal dashboard component Signed-off-by: Andrei Kvapil (cherry picked from commit af460f1c41321704cb02856909faf778b88cf0b6) --- .../controller/dashboard/customcolumns.go | 24 +-- internal/controller/dashboard/factory.go | 3 +- internal/controller/dashboard/helpers.go | 100 ------------ .../controller/dashboard/static_helpers.go | 150 ++++++++++-------- .../controller/dashboard/static_refactored.go | 57 ++++--- internal/controller/dashboard/ui_helpers.go | 6 +- .../controller/dashboard/unified_helpers.go | 148 +++++------------ 7 files changed, 155 insertions(+), 333 deletions(-) diff --git a/internal/controller/dashboard/customcolumns.go b/internal/controller/dashboard/customcolumns.go index 441787fe..78f2dd6a 100644 --- a/internal/controller/dashboard/customcolumns.go +++ b/internal/controller/dashboard/customcolumns.go @@ -30,10 +30,6 @@ func (m *Manager) ensureCustomColumnsOverride(ctx context.Context, crd *cozyv1al name := fmt.Sprintf("stock-namespace-%s.%s.%s", g, v, plural) id := fmt.Sprintf("stock-namespace-/%s/%s/%s", g, v, plural) - // Badge content & color derived from kind - badgeText := initialsFromKind(kind) // e.g., "VirtualMachine" -> "VM", "Bucket" -> "B" - badgeColor := hexColorForKind(kind) // deterministic, dark enough for white text - obj := &dashv1alpha1.CustomColumnsOverride{} obj.SetName(name) @@ -62,25 +58,11 @@ func (m *Manager) ensureCustomColumnsOverride(ctx context.Context, crd *cozyv1al }, "children": []any{ map[string]any{ - "type": "antdText", + "type": "ResourceBadge", "data": map[string]any{ "id": "header-badge", - "text": badgeText, - "title": strings.ToLower(kind), // optional tooltip - "style": map[string]any{ - "backgroundColor": badgeColor, - "borderRadius": "20px", - "color": "#fff", - "display": "inline-block", - "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", - "fontSize": "15px", - "fontWeight": 400, - "lineHeight": "24px", - "minWidth": 24, - "padding": "0 9px", - "textAlign": "center", - "whiteSpace": "nowrap", - }, + "value": kind, + // abbreviation auto-generated by ResourceBadge from value }, }, map[string]any{ diff --git a/internal/controller/dashboard/factory.go b/internal/controller/dashboard/factory.go index 6cffecb6..6a847e52 100644 --- a/internal/controller/dashboard/factory.go +++ b/internal/controller/dashboard/factory.go @@ -53,7 +53,6 @@ func (m *Manager) ensureFactory(ctx context.Context, crd *cozyv1alpha1.Cozystack Kind: kind, Plural: plural, Title: strings.ToLower(plural), - Size: BadgeSizeLarge, } spec := createUnifiedFactory(config, tabs, []any{resourceFetch}) @@ -115,7 +114,7 @@ func detailsTab(kind, endpoint, schemaJSON string, keysOrder [][]string) map[str "gap": float64(6), }, "children": []any{ - createUnifiedBadgeFromKind("ns-badge", "Namespace", "namespace", BadgeSizeMedium), + createUnifiedBadgeFromKind("ns-badge", "Namespace"), antdLink("namespace-link", "{reqsJsonPath[0]['.metadata.namespace']['-']}", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace", diff --git a/internal/controller/dashboard/helpers.go b/internal/controller/dashboard/helpers.go index e5361c53..a0023a05 100644 --- a/internal/controller/dashboard/helpers.go +++ b/internal/controller/dashboard/helpers.go @@ -1,12 +1,9 @@ package dashboard import ( - "crypto/sha1" - "encoding/hex" "encoding/json" "fmt" "reflect" - "regexp" "sort" "strings" @@ -57,97 +54,6 @@ func pickPlural(kind string, crd *cozyv1alpha1.CozystackResourceDefinition) stri return k + "s" } -// initialsFromKind splits CamelCase and returns the first letters in upper case. -// "VirtualMachine" -> "VM"; "Bucket" -> "B". -func initialsFromKind(kind string) string { - parts := splitCamel(kind) - if len(parts) == 0 { - return strings.ToUpper(kind) - } - var b strings.Builder - for _, p := range parts { - if p == "" { - continue - } - b.WriteString(strings.ToUpper(string(p[0]))) - // Limit to 3 chars to keep the badge compact (VM, PVC, etc.) - if b.Len() >= 3 { - break - } - } - return b.String() -} - -// hexColorForKind returns a dark, saturated color (hex) derived from a stable hash of the kind. -// We map the hash to an HSL hue; fix S/L for consistent readability with white text. -func hexColorForKind(kind string) string { - // Stable short hash (sha1 → bytes → hue) - sum := sha1.Sum([]byte(kind)) - // Use first two bytes for hue [0..359] - hue := int(sum[0])<<8 | int(sum[1]) - hue = hue % 360 - - // Fixed S/L chosen to contrast with white text: - // S = 80%, L = 35% (dark enough so #fff is readable) - r, g, b := hslToRGB(float64(hue), 0.80, 0.35) - - return fmt.Sprintf("#%02x%02x%02x", r, g, b) -} - -// hslToRGB converts HSL (0..360, 0..1, 0..1) to sRGB (0..255). -func hslToRGB(h float64, s float64, l float64) (uint8, uint8, uint8) { - c := (1 - absFloat(2*l-1)) * s - hp := h / 60.0 - x := c * (1 - absFloat(modFloat(hp, 2)-1)) - var r1, g1, b1 float64 - switch { - case 0 <= hp && hp < 1: - r1, g1, b1 = c, x, 0 - case 1 <= hp && hp < 2: - r1, g1, b1 = x, c, 0 - case 2 <= hp && hp < 3: - r1, g1, b1 = 0, c, x - case 3 <= hp && hp < 4: - r1, g1, b1 = 0, x, c - case 4 <= hp && hp < 5: - r1, g1, b1 = x, 0, c - default: - r1, g1, b1 = c, 0, x - } - m := l - c/2 - r := uint8(clamp01(r1+m) * 255.0) - g := uint8(clamp01(g1+m) * 255.0) - b := uint8(clamp01(b1+m) * 255.0) - return r, g, b -} - -func absFloat(v float64) float64 { - if v < 0 { - return -v - } - return v -} - -func modFloat(a, b float64) float64 { - return a - b*float64(int(a/b)) -} - -func clamp01(v float64) float64 { - if v < 0 { - return 0 - } - if v > 1 { - return 1 - } - return v -} - -// optional: tiny helper to expose the compact color hash (useful for debugging) -func shortHashHex(s string) string { - sum := sha1.Sum([]byte(s)) - return hex.EncodeToString(sum[:4]) -} - // ----------------------- Helpers (OpenAPI → values) ----------------------- // defaultOrZero returns the schema default if present; otherwise a reasonable zero value. @@ -295,12 +201,6 @@ func normalizeJSON(v any) any { } } -var camelSplitter = regexp.MustCompile(`(?m)([A-Z]+[a-z0-9]*|[a-z0-9]+)`) - -func splitCamel(s string) []string { - return camelSplitter.FindAllString(s, -1) -} - // --- helpers for schema inspection --- func isScalarType(n map[string]any) bool { diff --git a/internal/controller/dashboard/static_helpers.go b/internal/controller/dashboard/static_helpers.go index 469e9f8f..5affc1c1 100644 --- a/internal/controller/dashboard/static_helpers.go +++ b/internal/controller/dashboard/static_helpers.go @@ -531,7 +531,6 @@ func createBreadcrumbItem(key, label string, link ...string) map[string]any { // createCustomColumn creates a custom column with factory type and badge func createCustomColumn(name, kind, plural, href string) map[string]any { - badge := createUnifiedBadgeFromKind("header-badge", kind, plural, BadgeSizeMedium) link := antdLink("name-link", "{reqsJsonPath[0]['.metadata.name']['-']}", href) return map[string]any{ @@ -541,8 +540,18 @@ func createCustomColumn(name, kind, plural, href string) map[string]any { "disableEventBubbling": true, "items": []any{ map[string]any{ - "children": []any{badge, link}, - "type": "antdFlex", + "children": []any{ + map[string]any{ + "type": "ResourceBadge", + "data": map[string]any{ + "id": "header-badge", + "value": kind, + // abbreviation auto-generated by ResourceBadge from value + }, + }, + link, + }, + "type": "antdFlex", "data": map[string]any{ "align": "center", "gap": float64(6), @@ -554,16 +563,16 @@ func createCustomColumn(name, kind, plural, href string) map[string]any { } // createCustomColumnWithBadge creates a custom column with a specific badge -func createCustomColumnWithBadge(name, badgeText, badgeColor, title, href string) map[string]any { - config := BadgeConfig{ - Text: badgeText, - Color: badgeColor, - Title: title, - Size: BadgeSizeMedium, - } - badge := createUnifiedBadge("header-badge", config) +// badgeValue should be the kind in PascalCase (e.g., "Service", "Pod") +// abbreviation is auto-generated by ResourceBadge from badgeValue +func createCustomColumnWithBadge(name, badgeValue, href string) map[string]any { link := antdLink("name-link", "{reqsJsonPath[0]['.metadata.name']['-']}", href) + badgeData := map[string]any{ + "id": "header-badge", + "value": badgeValue, + } + return map[string]any{ "name": name, "type": "factory", @@ -571,8 +580,14 @@ func createCustomColumnWithBadge(name, badgeText, badgeColor, title, href string "disableEventBubbling": true, "items": []any{ map[string]any{ - "children": []any{badge, link}, - "type": "antdFlex", + "children": []any{ + map[string]any{ + "type": "ResourceBadge", + "data": badgeData, + }, + link, + }, + "type": "antdFlex", "data": map[string]any{ "align": "center", "gap": float64(6), @@ -583,17 +598,22 @@ func createCustomColumnWithBadge(name, badgeText, badgeColor, title, href string } } -// createCustomColumnWithSpecificColor creates a custom column with a specific color -func createCustomColumnWithSpecificColor(name, kind, title, color, href string) map[string]any { - config := BadgeConfig{ - Text: initialsFromKind(kind), - Color: color, - Title: title, - Size: BadgeSizeMedium, - } - badge := createUnifiedBadge("header-badge", config) +// createCustomColumnWithSpecificColor creates a custom column with a specific kind and optional color +// badgeValue should be the kind in PascalCase (e.g., "Service", "Pod") +func createCustomColumnWithSpecificColor(name, kind, color, href string) map[string]any { link := antdLink("name-link", "{reqsJsonPath[0]['.metadata.name']['-']}", href) + badgeData := map[string]any{ + "id": "header-badge", + "value": kind, + } + // Add custom color if specified + if color != "" { + badgeData["style"] = map[string]any{ + "backgroundColor": color, + } + } + return map[string]any{ "name": name, "type": "factory", @@ -602,8 +622,14 @@ func createCustomColumnWithSpecificColor(name, kind, title, color, href string) "disableEventBubbling": true, "items": []any{ map[string]any{ - "children": []any{badge, link}, - "type": "antdFlex", + "children": []any{ + map[string]any{ + "type": "ResourceBadge", + "data": badgeData, + }, + link, + }, + "type": "antdFlex", "data": map[string]any{ "align": "center", "gap": float64(6), @@ -668,7 +694,7 @@ func createTimestampColumn(name, jsonPath string) map[string]any { // createFactoryHeader creates a header for factory resources func createFactoryHeader(kind, plural string) map[string]any { lowerKind := strings.ToLower(kind) - badge := createUnifiedBadgeFromKind("badge-"+lowerKind, kind, plural, BadgeSizeLarge) + badge := createUnifiedBadgeFromKind("badge-"+lowerKind, kind) nameText := parsedText(lowerKind+"-name", "{reqsJsonPath[0]['.metadata.name']['-']}", map[string]any{ "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", "fontSize": float64(20), @@ -718,13 +744,26 @@ func createFactorySpec(key string, sidebarTags []any, urlsToFetch []any, header } // createCustomColumnWithJsonPath creates a column with a custom badge and link using jsonPath -func createCustomColumnWithJsonPath(name, jsonPath, badgeText, badgeTitle, badgeColor, linkHref string) map[string]any { +// badgeValue should be the kind in PascalCase (e.g., "Service", "VirtualMachine") +// abbreviation is auto-generated by ResourceBadge from badgeValue +func createCustomColumnWithJsonPath(name, jsonPath, badgeValue, badgeColor, linkHref string) map[string]any { // Determine link ID based on jsonPath linkId := "name-link" if jsonPath == ".metadata.namespace" { linkId = "namespace-link" } + badgeData := map[string]any{ + "id": "header-badge", + "value": badgeValue, + } + // Add custom color if specified + if badgeColor != "" { + badgeData["style"] = map[string]any{ + "backgroundColor": badgeColor, + } + } + return map[string]any{ "name": name, "type": "factory", @@ -741,26 +780,8 @@ func createCustomColumnWithJsonPath(name, jsonPath, badgeText, badgeTitle, badge }, "children": []any{ map[string]any{ - "type": "antdText", - "data": map[string]any{ - "id": "header-badge", - "text": badgeText, - "title": badgeTitle, - "style": map[string]any{ - "backgroundColor": badgeColor, - "borderRadius": "20px", - "color": "#fff", - "display": "inline-block", - "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", - "fontSize": "15px", - "fontWeight": 400, - "lineHeight": "24px", - "minWidth": 24, - "padding": "0 9px", - "textAlign": "center", - "whiteSpace": "nowrap", - }, - }, + "type": "ResourceBadge", + "data": badgeData, }, map[string]any{ "type": "antdLink", @@ -778,7 +799,20 @@ func createCustomColumnWithJsonPath(name, jsonPath, badgeText, badgeTitle, badge } // createCustomColumnWithoutJsonPath creates a column with a custom badge and link without jsonPath -func createCustomColumnWithoutJsonPath(name, badgeText, badgeTitle, badgeColor, linkHref string) map[string]any { +// badgeValue should be the kind in PascalCase (e.g., "Node", "Pod") +// abbreviation is auto-generated by ResourceBadge from badgeValue +func createCustomColumnWithoutJsonPath(name, badgeValue, badgeColor, linkHref string) map[string]any { + badgeData := map[string]any{ + "id": "header-badge", + "value": badgeValue, + } + // Add custom color if specified + if badgeColor != "" { + badgeData["style"] = map[string]any{ + "backgroundColor": badgeColor, + } + } + return map[string]any{ "name": name, "type": "factory", @@ -794,26 +828,8 @@ func createCustomColumnWithoutJsonPath(name, badgeText, badgeTitle, badgeColor, }, "children": []any{ map[string]any{ - "type": "antdText", - "data": map[string]any{ - "id": "header-badge", - "text": badgeText, - "title": badgeTitle, - "style": map[string]any{ - "backgroundColor": badgeColor, - "borderRadius": "20px", - "color": "#fff", - "display": "inline-block", - "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", - "fontSize": "15px", - "fontWeight": 400, - "lineHeight": "24px", - "minWidth": 24, - "padding": "0 9px", - "textAlign": "center", - "whiteSpace": "nowrap", - }, - }, + "type": "ResourceBadge", + "data": badgeData, }, map[string]any{ "type": "antdLink", diff --git a/internal/controller/dashboard/static_refactored.go b/internal/controller/dashboard/static_refactored.go index af9c5449..9ad923e7 100644 --- a/internal/controller/dashboard/static_refactored.go +++ b/internal/controller/dashboard/static_refactored.go @@ -132,7 +132,7 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid return []*dashboardv1alpha1.CustomColumnsOverride{ // Factory details v1 services createCustomColumnsOverride("factory-details-v1.services", []any{ - createCustomColumnWithSpecificColor("Name", "Service", "service", getColorForType("service"), "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-service-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithSpecificColor("Name", "Service", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-service-details/{reqsJsonPath[0]['.metadata.name']['-']}"), createStringColumn("ClusterIP", ".spec.clusterIP"), createStringColumn("LoadbalancerIP", ".spec.loadBalancerIP"), createTimestampColumn("Created", ".metadata.creationTimestamp"), @@ -140,7 +140,7 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid // Stock namespace v1 services createCustomColumnsOverride("stock-namespace-/v1/services", []any{ - createCustomColumnWithJsonPath("Name", ".metadata.name", "S", "service", getColorForType("service"), "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-service-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithJsonPath("Name", ".metadata.name", "Service", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-service-details/{reqsJsonPath[0]['.metadata.name']['-']}"), createStringColumn("ClusterIP", ".spec.clusterIP"), createStringColumn("LoadbalancerIP", ".status.loadBalancer.ingress[0].ip"), createTimestampColumn("Created", ".metadata.creationTimestamp"), @@ -148,7 +148,7 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid // Stock namespace core cozystack io v1alpha1 tenantmodules createCustomColumnsOverride("stock-namespace-/core.cozystack.io/v1alpha1/tenantmodules", []any{ - createCustomColumnWithJsonPath("Name", ".metadata.name", "M", "module", getColorForType("module"), "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/{reqsJsonPath[0]['.metadata.name']['-']}-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithJsonPath("Name", ".metadata.name", "Module", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/{reqsJsonPath[0]['.metadata.name']['-']}-details/{reqsJsonPath[0]['.metadata.name']['-']}"), createReadyColumn(), createTimestampColumn("Created", ".metadata.creationTimestamp"), createStringColumn("Version", ".status.version"), @@ -164,7 +164,7 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid // Factory details v1alpha1 cozystack io workloadmonitors createCustomColumnsOverride("factory-details-v1alpha1.cozystack.io.workloadmonitors", []any{ - createCustomColumnWithJsonPath("Name", ".metadata.name", "W", "workloadmonitor", getColorForType("workloadmonitor"), "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/workloadmonitor-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithJsonPath("Name", ".metadata.name", "WorkloadMonitor", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/workloadmonitor-details/{reqsJsonPath[0]['.metadata.name']['-']}"), createStringColumn("TYPE", ".spec.type"), createStringColumn("VERSION", ".spec.version"), createStringColumn("REPLICAS", ".spec.replicas"), @@ -175,7 +175,7 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid // Factory details v1alpha1 core cozystack io tenantsecretstables createCustomColumnsOverride("factory-details-v1alpha1.core.cozystack.io.tenantsecretstables", []any{ - createCustomColumnWithJsonPath("Name", ".metadata.name", "S", "secret", getColorForType("secret"), "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-secret-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithJsonPath("Name", ".metadata.name", "Secret", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-secret-details/{reqsJsonPath[0]['.metadata.name']['-']}"), createStringColumn("Key", ".data.key"), createSecretBase64Column("Value", ".data.value"), createTimestampColumn("Created", ".metadata.creationTimestamp"), @@ -184,7 +184,7 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid // Factory ingress details rules createCustomColumnsOverride("factory-kube-ingress-details-rules", []any{ createStringColumn("Host", ".host"), - createCustomColumnWithJsonPath("Service", ".http.paths[0].backend.service.name", "S", "service", getColorForType("service"), "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-service-details/{reqsJsonPath[0]['.http.paths[0].backend.service.name']['-']}"), + createCustomColumnWithJsonPath("Service", ".http.paths[0].backend.service.name", "Service", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-service-details/{reqsJsonPath[0]['.http.paths[0].backend.service.name']['-']}"), createStringColumn("Port", ".http.paths[0].backend.service.port.number"), createStringColumn("Path", ".http.paths[0].path"), }), @@ -250,7 +250,7 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid // Factory details networking k8s io v1 ingresses createCustomColumnsOverride("factory-details-networking.k8s.io.v1.ingresses", []any{ - createCustomColumnWithJsonPath("Name", ".metadata.name", "I", "ingress", getColorForType("ingress"), "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-ingress-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithJsonPath("Name", ".metadata.name", "Ingress", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-ingress-details/{reqsJsonPath[0]['.metadata.name']['-']}"), createStringColumn("Hosts", ".spec.rules[*].host"), createStringColumn("Address", ".status.loadBalancer.ingress[0].ip"), createStringColumn("Port", ".spec.defaultBackend.service.port.number"), @@ -259,7 +259,7 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid // Stock namespace networking k8s io v1 ingresses createCustomColumnsOverride("stock-namespace-/networking.k8s.io/v1/ingresses", []any{ - createCustomColumnWithJsonPath("Name", ".metadata.name", "I", "ingress", getColorForType("ingress"), "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-ingress-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithJsonPath("Name", ".metadata.name", "Ingress", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-ingress-details/{reqsJsonPath[0]['.metadata.name']['-']}"), createStringColumn("Hosts", ".spec.rules[*].host"), createStringColumn("Address", ".status.loadBalancer.ingress[0].ip"), createStringColumn("Port", ".spec.defaultBackend.service.port.number"), @@ -268,34 +268,34 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid // Stock cluster v1 configmaps createCustomColumnsOverride("stock-cluster-/v1/configmaps", []any{ - createCustomColumnWithJsonPath("Name", ".metadata.name", "CM", "configmap", getColorForType("configmap"), "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/configmap-details/{reqsJsonPath[0]['.metadata.name']['-']}"), - createCustomColumnWithJsonPath("Namespace", ".metadata.namespace", "NS", "namespace", getColorForType("namespace"), "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace"), + createCustomColumnWithJsonPath("Name", ".metadata.name", "ConfigMap", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/configmap-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithJsonPath("Namespace", ".metadata.namespace", "Namespace", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace"), createTimestampColumn("Created", ".metadata.creationTimestamp"), }), // Stock namespace v1 configmaps createCustomColumnsOverride("stock-namespace-/v1/configmaps", []any{ - createCustomColumnWithJsonPath("Name", ".metadata.name", "CM", "configmap", getColorForType("configmap"), "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/configmap-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithJsonPath("Name", ".metadata.name", "ConfigMap", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/configmap-details/{reqsJsonPath[0]['.metadata.name']['-']}"), createTimestampColumn("Created", ".metadata.creationTimestamp"), }), // Cluster v1 configmaps createCustomColumnsOverride("cluster-/v1/configmaps", []any{ - createCustomColumnWithJsonPath("Name", ".metadata.name", "CM", "configmap", getColorForType("configmap"), "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/configmap-details/{reqsJsonPath[0]['.metadata.name']['-']}"), - createCustomColumnWithJsonPath("Namespace", ".metadata.namespace", "NS", "namespace", getColorForType("namespace"), "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace"), + createCustomColumnWithJsonPath("Name", ".metadata.name", "ConfigMap", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/configmap-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithJsonPath("Namespace", ".metadata.namespace", "Namespace", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace"), createTimestampColumn("Created", ".metadata.creationTimestamp"), }), // Stock cluster v1 nodes createCustomColumnsOverride("stock-cluster-/v1/nodes", []any{ - createCustomColumnWithJsonPath("Name", ".metadata.name", "N", "node", getColorForType("node"), "/openapi-ui/{2}/factory/node-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithJsonPath("Name", ".metadata.name", "Node", "", "/openapi-ui/{2}/factory/node-details/{reqsJsonPath[0]['.metadata.name']['-']}"), createSimpleStatusColumn("Status", "node-status"), }), // Factory node details v1 pods createCustomColumnsOverride("factory-node-details-v1.pods", []any{ - createCustomColumnWithJsonPath("Name", ".metadata.name", "P", "pod", getColorForType("pod"), "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/pod-details/{reqsJsonPath[0]['.metadata.name']['-']}"), - createCustomColumnWithJsonPath("Namespace", ".metadata.namespace", "NS", "namespace", getColorForType("namespace"), "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace"), + createCustomColumnWithJsonPath("Name", ".metadata.name", "Pod", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/pod-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithJsonPath("Namespace", ".metadata.namespace", "Namespace", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace"), createStringColumn("Restart Policy", ".spec.restartPolicy"), createStringColumn("Pod IP", ".status.podIP"), createStringColumn("QOS", ".status.qosClass"), @@ -304,8 +304,8 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid // Factory v1 pods createCustomColumnsOverride("factory-v1.pods", []any{ - createCustomColumnWithJsonPath("Name", ".metadata.name", "P", "pod", getColorForType("pod"), "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/pod-details/{reqsJsonPath[0]['.metadata.name']['-']}"), - createCustomColumnWithoutJsonPath("Node", "N", "node", getColorForType("node"), "/openapi-ui/{2}/factory/node-details/{reqsJsonPath[0]['.spec.nodeName']['-']}"), + createCustomColumnWithJsonPath("Name", ".metadata.name", "Pod", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/pod-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithoutJsonPath("Node", "Node", "", "/openapi-ui/{2}/factory/node-details/{reqsJsonPath[0]['.spec.nodeName']['-']}"), createStringColumn("Restart Policy", ".spec.restartPolicy"), createStringColumn("Pod IP", ".status.podIP"), createStringColumn("QOS", ".status.qosClass"), @@ -314,9 +314,9 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid // Stock cluster v1 pods createCustomColumnsOverride("stock-cluster-/v1/pods", []any{ - createCustomColumnWithJsonPath("Name", ".metadata.name", "P", "pod", "#009596", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/pod-details/{reqsJsonPath[0]['.metadata.name']['-']}"), - createCustomColumnWithJsonPath("Namespace", ".metadata.namespace", "NS", "namespace", "#a25792ff", "/openapi-ui/{2}/factory/tenantnamespace/{reqsJsonPath[0]['.metadata.namespace']['-']}"), - createCustomColumnWithJsonPath("Node", ".spec.nodeName", "N", "node", "#8476d1", "/openapi-ui/{2}/factory/node-details/{reqsJsonPath[0]['.spec.nodeName']['-']}"), + createCustomColumnWithJsonPath("Name", ".metadata.name", "Pod", "#009596", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/pod-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithJsonPath("Namespace", ".metadata.namespace", "Namespace", "#a25792ff", "/openapi-ui/{2}/factory/tenantnamespace/{reqsJsonPath[0]['.metadata.namespace']['-']}"), + createCustomColumnWithJsonPath("Node", ".spec.nodeName", "Node", "#8476d1", "/openapi-ui/{2}/factory/node-details/{reqsJsonPath[0]['.spec.nodeName']['-']}"), createStringColumn("Restart Policy", ".spec.restartPolicy"), createStringColumn("Pod IP", ".status.podIP"), createStringColumn("QOS", ".status.qosClass"), @@ -325,8 +325,8 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid // Stock namespace v1 pods createCustomColumnsOverride("stock-namespace-/v1/pods", []any{ - createCustomColumnWithJsonPath("Name", ".metadata.name", "P", "pod", "#009596", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/pod-details/{reqsJsonPath[0]['.metadata.name']['-']}"), - createCustomColumnWithoutJsonPath("Node", "N", "node", "#8476d1", "/openapi-ui/{2}/factory/node-details/{reqsJsonPath[0]['.spec.nodeName']['-']}"), + createCustomColumnWithJsonPath("Name", ".metadata.name", "Pod", "#009596", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/pod-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithoutJsonPath("Node", "Node", "#8476d1", "/openapi-ui/{2}/factory/node-details/{reqsJsonPath[0]['.spec.nodeName']['-']}"), createStringColumn("Restart Policy", ".spec.restartPolicy"), createStringColumn("Pod IP", ".status.podIP"), createStringColumn("QOS", ".status.qosClass"), @@ -335,15 +335,15 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid // Stock cluster v1 secrets createCustomColumnsOverride("stock-cluster-/v1/secrets", []any{ - createCustomColumnWithJsonPath("Name", ".metadata.name", "S", "secret", "#c46100", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-secret-details/{reqsJsonPath[0]['.metadata.name']['-']}"), - createCustomColumnWithJsonPath("Namespace", ".metadata.namespace", "NS", "namespace", "#a25792ff", "/openapi-ui/{2}/factory/tenantnamespace/{reqsJsonPath[0]['.metadata.namespace']['-']}"), + createCustomColumnWithJsonPath("Name", ".metadata.name", "Secret", "#c46100", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-secret-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithJsonPath("Namespace", ".metadata.namespace", "Namespace", "#a25792ff", "/openapi-ui/{2}/factory/tenantnamespace/{reqsJsonPath[0]['.metadata.namespace']['-']}"), createStringColumn("Type", ".type"), createTimestampColumn("Created", ".metadata.creationTimestamp"), }), // Stock namespace v1 secrets createCustomColumnsOverride("stock-namespace-/v1/secrets", []any{ - createCustomColumnWithJsonPath("Name", ".metadata.name", "S", "secret", "#c46100", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-secret-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithJsonPath("Name", ".metadata.name", "Secret", "#c46100", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-secret-details/{reqsJsonPath[0]['.metadata.name']['-']}"), createStringColumn("Type", ".type"), createTimestampColumn("Created", ".metadata.creationTimestamp"), }), @@ -360,7 +360,7 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid // Stock cluster core cozystack io v1alpha1 tenantnamespaces createCustomColumnsOverride("stock-cluster-/core.cozystack.io/v1alpha1/tenantnamespaces", []any{ - createCustomColumnWithJsonPath("Name", ".metadata.name", "TN", "tenantnamespace", getColorForType("tenantnamespace"), "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.name']['-']}/factory/marketplace"), + createCustomColumnWithJsonPath("Name", ".metadata.name", "TenantNamespace", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.name']['-']}/factory/marketplace"), createTimestampColumn("Created", ".metadata.creationTimestamp"), }), } @@ -496,7 +496,6 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory { Kind: "Namespace", Plural: "namespaces", Title: "namespace", - Size: BadgeSizeLarge, } namespaceSpec := createUnifiedFactory(namespaceConfig, nil, []any{"/api/clusters/{2}/k8s/api/v1/namespaces/{5}"}) @@ -1202,7 +1201,7 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory { "gap": 6, }, "children": []any{ - createUnifiedBadgeFromKind("ns-badge", "Namespace", "namespace", BadgeSizeMedium), + createUnifiedBadgeFromKind("ns-badge", "Namespace"), antdLink("namespace-link", "{reqsJsonPath[0]['.metadata.namespace']['-']}", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace", diff --git a/internal/controller/dashboard/ui_helpers.go b/internal/controller/dashboard/ui_helpers.go index 4066fd36..fb29a608 100644 --- a/internal/controller/dashboard/ui_helpers.go +++ b/internal/controller/dashboard/ui_helpers.go @@ -1,7 +1,5 @@ package dashboard -import "strings" - // ---------------- UI helpers (use float64 for numeric fields) ---------------- func contentCard(id string, style map[string]any, children []any) map[string]any { @@ -200,10 +198,10 @@ func createBadge(id, text, color, title string) map[string]any { // createBadgeFromKind creates a badge using the existing badge generation functions func createBadgeFromKind(id, kind, title string) map[string]any { - return createUnifiedBadgeFromKind(id, kind, title, BadgeSizeMedium) + return createUnifiedBadgeFromKind(id, kind) } // createHeaderBadge creates a badge specifically for headers with consistent styling func createHeaderBadge(id, kind, plural string) map[string]any { - return createUnifiedBadgeFromKind(id, kind, strings.ToLower(plural), BadgeSizeLarge) + return createUnifiedBadgeFromKind(id, kind) } diff --git a/internal/controller/dashboard/unified_helpers.go b/internal/controller/dashboard/unified_helpers.go index 7bdea2b5..b25d5b65 100644 --- a/internal/controller/dashboard/unified_helpers.go +++ b/internal/controller/dashboard/unified_helpers.go @@ -81,86 +81,47 @@ func isAlphanumeric(c byte) bool { // BadgeConfig holds configuration for badge generation type BadgeConfig struct { - Text string - Color string - Title string - Size BadgeSize + Kind string // Resource kind in PascalCase (e.g., "VirtualMachine") - used for value and auto-generation + Text string // Optional abbreviation override (if empty, ResourceBadge auto-generates from Kind) + Color string // Optional custom backgroundColor override } -// BadgeSize represents the size of the badge -type BadgeSize int - -const ( - BadgeSizeSmall BadgeSize = iota - BadgeSizeMedium - BadgeSizeLarge -) - -// generateBadgeConfig creates a BadgeConfig from kind and optional custom values -func generateBadgeConfig(kind string, customText, customColor, customTitle string) BadgeConfig { - config := BadgeConfig{ - Text: initialsFromKind(kind), - Color: hexColorForKind(kind), - Title: strings.ToLower(kind), - Size: BadgeSizeMedium, - } - - // Override with custom values if provided - if customText != "" { - config.Text = customText - } - if customColor != "" { - config.Color = customColor - } - if customTitle != "" { - config.Title = customTitle - } - - return config -} - -// createUnifiedBadge creates a badge using the unified BadgeConfig +// createUnifiedBadge creates a badge using the unified BadgeConfig with ResourceBadge component func createUnifiedBadge(id string, config BadgeConfig) map[string]any { - fontSize := "15px" - if config.Size == BadgeSizeLarge { - fontSize = "20px" - } else if config.Size == BadgeSizeSmall { - fontSize = "12px" + data := map[string]any{ + "id": id, + "value": config.Kind, + } + + // Add abbreviation override if specified (otherwise ResourceBadge auto-generates from Kind) + if config.Text != "" { + data["abbreviation"] = config.Text + } + + // Add custom color if specified + if config.Color != "" { + data["style"] = map[string]any{ + "backgroundColor": config.Color, + } } return map[string]any{ - "type": "antdText", - "data": map[string]any{ - "id": id, - "text": config.Text, - "title": config.Title, - "style": map[string]any{ - "backgroundColor": config.Color, - "borderRadius": "20px", - "color": "#fff", - "display": "inline-block", - "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", - "fontSize": fontSize, - "fontWeight": float64(400), - "lineHeight": "24px", - "minWidth": float64(24), - "padding": "0 9px", - "textAlign": "center", - "whiteSpace": "nowrap", - }, - }, + "type": "ResourceBadge", + "data": data, } } -// createUnifiedBadgeFromKind creates a badge from kind with automatic color generation -func createUnifiedBadgeFromKind(id, kind, title string, size BadgeSize) map[string]any { - config := BadgeConfig{ - Text: initialsFromKind(kind), - Color: hexColorForKind(kind), - Title: title, - Size: size, +// createUnifiedBadgeFromKind creates a badge from kind with ResourceBadge component +// Abbreviation is auto-generated by ResourceBadge from kind, but can be customized if needed +func createUnifiedBadgeFromKind(id, kind string) map[string]any { + return map[string]any{ + "type": "ResourceBadge", + "data": map[string]any{ + "id": id, + "value": kind, + // abbreviation is optional - ResourceBadge auto-generates from value + }, } - return createUnifiedBadge(id, config) } // ---------------- Resource creation helpers with unified approach ---------------- @@ -183,7 +144,9 @@ func createResourceConfig(components []string, kind, title string) ResourceConfi metadataName := generateMetadataName(specID) // Generate badge config - badgeConfig := generateBadgeConfig(kind, "", "", title) + badgeConfig := BadgeConfig{ + Kind: kind, + } return ResourceConfig{ SpecID: specID, @@ -196,35 +159,6 @@ func createResourceConfig(components []string, kind, title string) ResourceConfi // ---------------- Enhanced color generation ---------------- -// getColorForKind returns a color for a specific kind with improved distribution -func getColorForKind(kind string) string { - // Use existing hexColorForKind function - return hexColorForKind(kind) -} - -// getColorForType returns a color for a specific type (like "namespace", "service", etc.) -func getColorForType(typeName string) string { - // Map common types to specific colors for consistency - colorMap := map[string]string{ - "namespace": "#a25792ff", - "service": "#6ca100", - "pod": "#009596", - "node": "#8476d1", - "secret": "#c46100", - "configmap": "#b48c78ff", - "ingress": "#2e7dff", - "workloadmonitor": "#c46100", - "module": "#8b5cf6", - } - - if color, exists := colorMap[strings.ToLower(typeName)]; exists { - return color - } - - // Fall back to hash-based color generation - return hexColorForKind(typeName) -} - // ---------------- Automatic ID generation for UI elements ---------------- // generateElementID creates an ID for UI elements based on context and type @@ -282,7 +216,6 @@ type UnifiedResourceConfig struct { Title string Color string BadgeText string - Size BadgeSize } // createUnifiedFactory creates a factory using unified approach @@ -292,16 +225,9 @@ func createUnifiedFactory(config UnifiedResourceConfig, tabs []any, urlsToFetch // Create header with unified badge badgeConfig := BadgeConfig{ + Kind: config.Kind, Text: config.BadgeText, Color: config.Color, - Title: config.Title, - Size: config.Size, - } - if badgeConfig.Text == "" { - badgeConfig.Text = initialsFromKind(config.Kind) - } - if badgeConfig.Color == "" { - badgeConfig.Color = getColorForKind(config.Kind) } badge := createUnifiedBadge(generateBadgeID("header", config.Kind), badgeConfig) @@ -348,7 +274,9 @@ func createUnifiedFactory(config UnifiedResourceConfig, tabs []any, urlsToFetch // createUnifiedCustomColumn creates a custom column using unified approach func createUnifiedCustomColumn(name, jsonPath, kind, title, href string) map[string]any { - badgeConfig := generateBadgeConfig(kind, "", "", title) + badgeConfig := BadgeConfig{ + Kind: kind, + } badge := createUnifiedBadge(generateBadgeID("column", kind), badgeConfig) linkID := generateLinkID("column", "name") From 181fc3cc40fe72da7c1bbb492975b4daafaf90e8 Mon Sep 17 00:00:00 2001 From: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> Date: Tue, 4 Nov 2025 17:19:31 +0000 Subject: [PATCH 42/76] Prepare release v0.37.5 Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> --- packages/apps/kubernetes/images/kubevirt-csi-driver.tag | 2 +- packages/core/installer/values.yaml | 2 +- packages/core/testing/values.yaml | 2 +- packages/extra/bootbox/images/matchbox.tag | 2 +- packages/extra/seaweedfs/images/objectstorage-sidecar.tag | 2 +- packages/system/bucket/images/s3manager.tag | 2 +- packages/system/cozystack-api/values.yaml | 2 +- packages/system/cozystack-controller/values.yaml | 4 ++-- packages/system/dashboard/templates/configmap.yaml | 2 +- packages/system/dashboard/values.yaml | 6 +++--- packages/system/kamaji/values.yaml | 4 ++-- packages/system/kubeovn-plunger/values.yaml | 2 +- packages/system/kubeovn-webhook/values.yaml | 2 +- packages/system/kubeovn/values.yaml | 2 +- packages/system/kubevirt-csi-node/values.yaml | 2 +- packages/system/lineage-controller-webhook/values.yaml | 2 +- packages/system/objectstorage-controller/values.yaml | 2 +- packages/system/seaweedfs/values.yaml | 2 +- 18 files changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag index af215d39..d6e3eb37 100644 --- a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag +++ b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:10a265bde566618c801882bb16cd5c6da24314b342bba178c78785364ef53d5f +ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:e7c575b0068cf78fae8730fe8d1919799e93356b14f0b645789645bd975878b9 diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index bc1b7347..5d9da6d8 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:v0.37.4@sha256:b3e8f5156d953b704e1d70d13ba7cc8d27ae2a2c1c0e35eeb4efe9e2889e5512 + image: ghcr.io/cozystack/cozystack/installer:v0.37.5@sha256:b821a5375271a4192af8d63da5281f8f994831085bd99155665742a13da0c35e diff --git a/packages/core/testing/values.yaml b/packages/core/testing/values.yaml index a923101e..33f32e35 100755 --- a/packages/core/testing/values.yaml +++ b/packages/core/testing/values.yaml @@ -1,2 +1,2 @@ e2e: - image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.4@sha256:5fa8b8d86a2ec52ecb2cf8159d863ba7b123bcdf19da2cd13eede9b6c6154d87 + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.5@sha256:16c3c05956cb5a69bcff4f18fff9ba0d19b41b88c1cb01c013877ba90f613dc6 diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index 065a4185..d2a8945d 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v0.37.4@sha256:ca339988bd86480962dcbc0209252173eb347d1ac750d8f96bc06c41df3a9358 +ghcr.io/cozystack/cozystack/matchbox:v0.37.5@sha256:6a53b95bc53ed79d7f5bb4fe1c4f3f4f789238e7e91ec2ce8df66ce3b4970891 diff --git a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag index 20b30c76..e3303ab7 100644 --- a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag +++ b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.4@sha256:b805dc391cde74f0e9a8b9df15aba5209f0faa73bb0523b5b0292083405e0b08 +ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.5@sha256:ac6380462d791bae88a1dc842ec5b2e6d7e1054c2255614e573c3997df64b463 diff --git a/packages/system/bucket/images/s3manager.tag b/packages/system/bucket/images/s3manager.tag index 3f830cdb..3f1d8278 100644 --- a/packages/system/bucket/images/s3manager.tag +++ b/packages/system/bucket/images/s3manager.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:13340fa712e398cc788fb86107f5ce2f415516d015aa68cd66ce5eabb266e77b +ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:a5bb5014842d3deb551c707552721c2cfe8f6211f9fc8bc060f1bbf79a36e47e diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index ef5b5d28..2928457d 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,2 +1,2 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.4@sha256:be1ff731b64ec0e8b9f04e01cb21b069f4e340389da4abb6612477562a0500c8 + image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.5@sha256:1166252a96f14f4bcf4369577151aa3c372dabf171da9a8dbd28bab81889ac87 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index 8694b07b..d1f163ec 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,5 +1,5 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.4@sha256:fdd9481ccb60789930412febde2c9970d720b02522f0709ab0211e7cbdaed447 + image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.5@sha256:0d339b30ce2d07634dd19176e6966c5bd722872b12e47176b4243abb5704a11f debug: false disableTelemetry: false - cozystackVersion: "v0.37.4" + cozystackVersion: "v0.37.5" diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml index ec40fbb1..36554996 100644 --- a/packages/system/dashboard/templates/configmap.yaml +++ b/packages/system/dashboard/templates/configmap.yaml @@ -1,6 +1,6 @@ {{- $brandingConfig:= lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} -{{- $tenantText := "v0.37.4" }} +{{- $tenantText := "v0.37.5" }} {{- $footerText := "Cozystack" }} {{- $titleText := "Cozystack Dashboard" }} {{- $logoText := "false" }} diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index 8bb72e30..79e3d58b 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,6 +1,6 @@ openapiUI: - image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.4@sha256:f472e678e9869494ab3aa99247f3e5c80f2b543ab5708af2d5451d45934d3925 + image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.5@sha256:5c66e9aebbf6b435b75f1607ab800028a22d0e99a1acc5cf405f07581ce414f8 openapiUIK8sBff: - image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.4@sha256:b780da469bf879d4a05a80781a2bbfeefc2570fe4129bd8857b216d3bf5902fb + image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.5@sha256:194ff92c584a950f22067220436e6d8705e614422227e9cac7e889a704b709de tokenProxy: - image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.4@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b + image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.5@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b diff --git a/packages/system/kamaji/values.yaml b/packages/system/kamaji/values.yaml index 167926af..23305230 100644 --- a/packages/system/kamaji/values.yaml +++ b/packages/system/kamaji/values.yaml @@ -3,7 +3,7 @@ kamaji: deploy: false image: pullPolicy: IfNotPresent - tag: v0.37.4@sha256:8d5343b12c98f3b8456d53cbb5ae2048ff67aebc2a6091bfc338756adda848ed + tag: v0.37.5@sha256:9d076f9a6cfcf25a22a1d366ff7129439688ae8cb07f5a81eab77df3968155ef repository: ghcr.io/cozystack/cozystack/kamaji resources: limits: @@ -13,4 +13,4 @@ kamaji: cpu: 100m memory: 100Mi extraArgs: - - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.4@sha256:8d5343b12c98f3b8456d53cbb5ae2048ff67aebc2a6091bfc338756adda848ed + - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.5@sha256:9d076f9a6cfcf25a22a1d366ff7129439688ae8cb07f5a81eab77df3968155ef diff --git a/packages/system/kubeovn-plunger/values.yaml b/packages/system/kubeovn-plunger/values.yaml index b388ed05..0bbeb83d 100644 --- a/packages/system/kubeovn-plunger/values.yaml +++ b/packages/system/kubeovn-plunger/values.yaml @@ -1,4 +1,4 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.4@sha256:4f9168b2667879d006d2a4f6f3fca600ab3853dd8ac4c79b3fc8cb114f7a7632 +image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.5@sha256:3443a6ddc9a1e087b27f21937385f40699cdf1763ae7e2350f13610fecb1195c ovnCentralName: ovn-central diff --git a/packages/system/kubeovn-webhook/values.yaml b/packages/system/kubeovn-webhook/values.yaml index 6b6da720..db117fc1 100644 --- a/packages/system/kubeovn-webhook/values.yaml +++ b/packages/system/kubeovn-webhook/values.yaml @@ -1,3 +1,3 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.4@sha256:f803cf5e7a2f1fa2bcf7003f8a5931e5d7bccddce7f92c88029292b4826c9050 +image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.5@sha256:7e63205708e607ce2cedfe2a2cafd323ca51e3ebc71244a21ff6f9016c6c87bc diff --git a/packages/system/kubeovn/values.yaml b/packages/system/kubeovn/values.yaml index 0053e491..70e1f4eb 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.5@sha256:47fa31963539180f8e9a340ea60d7756e200762d22f3589d207f89309e4e19c3 + tag: v1.14.5@sha256:0bbd4688ea73c6e9e08b1b3fecec39a051395fa50bf7afedbc93254cb1216df1 diff --git a/packages/system/kubevirt-csi-node/values.yaml b/packages/system/kubevirt-csi-node/values.yaml index f120cd4a..a626a0ed 100644 --- a/packages/system/kubevirt-csi-node/values.yaml +++ b/packages/system/kubevirt-csi-node/values.yaml @@ -1,3 +1,3 @@ storageClass: replicated csiDriver: - image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:10a265bde566618c801882bb16cd5c6da24314b342bba178c78785364ef53d5f + image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:e7c575b0068cf78fae8730fe8d1919799e93356b14f0b645789645bd975878b9 diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index ff31cc35..53570a7c 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,3 +1,3 @@ lineageControllerWebhook: - image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.4@sha256:fb739bf575a93bb76c65b46f415e0f8343df824155c53207690420f00a98a598 + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.5@sha256:df3bd847e9a733a9e9e4b4ebb6a48a95405c68c663837a72f613ace2904242bd debug: false diff --git a/packages/system/objectstorage-controller/values.yaml b/packages/system/objectstorage-controller/values.yaml index 495c3e80..98e7e62b 100644 --- a/packages/system/objectstorage-controller/values.yaml +++ b/packages/system/objectstorage-controller/values.yaml @@ -1,3 +1,3 @@ objectstorage: controller: - image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.4@sha256:5511b39fc4000f538f474d849c506dc7d2dd22561ea92256ea5bde1e84b82eca" + image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.5@sha256:7ee2109d9279c33507505f6b1a12173018749ead39229b642043b25621e63455" diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index 10d19401..c7c6bb94 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -124,7 +124,7 @@ seaweedfs: bucketClassName: "seaweedfs" region: "" sidecar: - image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.4@sha256:b805dc391cde74f0e9a8b9df15aba5209f0faa73bb0523b5b0292083405e0b08" + image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.5@sha256:ac6380462d791bae88a1dc842ec5b2e6d7e1054c2255614e573c3997df64b463" certificates: commonName: "SeaweedFS CA" ipAddresses: [] From 46c1116f0791edd26ed308b7de0a7c060139fa3d Mon Sep 17 00:00:00 2001 From: Isaiah Olson Date: Wed, 5 Nov 2025 01:08:13 -0600 Subject: [PATCH 43/76] Fix NATS app chart to use existing secret credentials when present Signed-off-by: Isaiah Olson (cherry picked from commit 1e8a9ee9800a09ba30519b31993ac166d650cbc4) --- packages/apps/nats/templates/nats.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/apps/nats/templates/nats.yaml b/packages/apps/nats/templates/nats.yaml index b5cfd6e4..02209377 100644 --- a/packages/apps/nats/templates/nats.yaml +++ b/packages/apps/nats/templates/nats.yaml @@ -1,6 +1,14 @@ {{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} {{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} +{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-credentials" .Release.Name) }} {{- $passwords := dict }} + +{{- with (index $existingSecret "data") }} + {{- range $k, $v := . }} + {{- $_ := set $passwords $k (b64dec $v) }} + {{- end }} +{{- end }} + {{- range $user, $u := .Values.users }} {{- if $u.password }} {{- $_ := set $passwords $user $u.password }} From 3a1a69e10bed13001cc952aec1c46ed189d5aaa4 Mon Sep 17 00:00:00 2001 From: Isaiah Olson Date: Wed, 5 Nov 2025 18:12:05 -0600 Subject: [PATCH 44/76] Use dig function to check for existing secret in NATS app template and prevent nil indexing Signed-off-by: Isaiah Olson (cherry picked from commit 627022972d7937204f0e402d49e956c899141ef0) --- packages/apps/nats/templates/nats.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/apps/nats/templates/nats.yaml b/packages/apps/nats/templates/nats.yaml index 02209377..b05c87b5 100644 --- a/packages/apps/nats/templates/nats.yaml +++ b/packages/apps/nats/templates/nats.yaml @@ -3,7 +3,7 @@ {{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-credentials" .Release.Name) }} {{- $passwords := dict }} -{{- with (index $existingSecret "data") }} +{{- with (dig "data" (dict) $existingSecret) }} {{- range $k, $v := . }} {{- $_ := set $passwords $k (b64dec $v) }} {{- end }} From edbccafd49da1a2b8c2d963fd238772f66441a02 Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Thu, 6 Nov 2025 15:01:06 +0300 Subject: [PATCH 45/76] [kubernetes] Helm hooks for cleanup ## What this PR does When deleting a Kubernetes, some resources may linger post deletion because of a race to remove HelmReleases deployed inside the tenant cluster and the removal of the cluster and its controlplane itself. This patch modifies the existing pre-delete hook to remove those helmreleases instead of simply suspending them. Similarly, datavolumes may also remain. These are now delete with a post-delete hook. ### Release note ```release-note [kubernetes] Use Helm hooks to clean up HelmReleases deployed in tenant clusters and DataVolumes backing the tenant clusters' PVCs when deleting a tenant Kubernetes. ``` Signed-off-by: Timofei Larkin (cherry picked from commit 63db8ca009aa84c3ce2769ebd278cc8b0a48fe7b) --- .../apps/kubernetes/templates/csi/delete.yaml | 76 +++++++++++++++++++ .../templates/helmreleases/delete.yaml | 43 ++++++----- 2 files changed, 98 insertions(+), 21 deletions(-) create mode 100644 packages/apps/kubernetes/templates/csi/delete.yaml diff --git a/packages/apps/kubernetes/templates/csi/delete.yaml b/packages/apps/kubernetes/templates/csi/delete.yaml new file mode 100644 index 00000000..53a11af7 --- /dev/null +++ b/packages/apps/kubernetes/templates/csi/delete.yaml @@ -0,0 +1,76 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + "helm.sh/hook": post-delete + "helm.sh/hook-weight": "10" + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed + name: {{ .Release.Name }}-datavolume-cleanup +spec: + template: + spec: + serviceAccountName: {{ .Release.Name }}-datavolume-cleanup + restartPolicy: Never + tolerations: + - key: CriticalAddonsOnly + operator: Exists + - key: node-role.kubernetes.io/control-plane + operator: Exists + effect: "NoSchedule" + containers: + - name: kubectl + image: docker.io/clastix/kubectl:v1.32 + command: + - /bin/sh + - -c + - kubectl -n {{ .Release.Namespace }} delete datavolumes + -l "cluster.x-k8s.io/cluster-name={{ .Release.Name }}" + --ignore-not-found=true + + +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Release.Name }}-datavolume-cleanup + annotations: + helm.sh/hook: post-delete + helm.sh/hook-delete-policy: before-hook-creation,hook-failed,hook-succeeded + helm.sh/hook-weight: "0" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + annotations: + "helm.sh/hook": post-delete + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed + "helm.sh/hook-weight": "5" + name: {{ .Release.Name }}-datavolume-cleanup +rules: + - apiGroups: + - "cdi.kubevirt.io" + resources: + - datavolumes + verbs: + - get + - list + - delete +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + annotations: + "helm.sh/hook": post-delete + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed + "helm.sh/hook-weight": "5" + name: {{ .Release.Name }}-datavolume-cleanup +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ .Release.Name }}-datavolume-cleanup +subjects: + - kind: ServiceAccount + name: {{ .Release.Name }}-datavolume-cleanup + namespace: {{ .Release.Namespace }} + diff --git a/packages/apps/kubernetes/templates/helmreleases/delete.yaml b/packages/apps/kubernetes/templates/helmreleases/delete.yaml index 5db40503..ac15be9b 100644 --- a/packages/apps/kubernetes/templates/helmreleases/delete.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/delete.yaml @@ -24,26 +24,26 @@ spec: command: - /bin/sh - -c - - | - kubectl - --namespace={{ .Release.Namespace }} - patch - helmrelease - {{ .Release.Name }}-cilium - {{ .Release.Name }}-gateway-api-crds - {{ .Release.Name }}-csi - {{ .Release.Name }}-cert-manager - {{ .Release.Name }}-cert-manager-crds - {{ .Release.Name }}-vertical-pod-autoscaler - {{ .Release.Name }}-vertical-pod-autoscaler-crds - {{ .Release.Name }}-ingress-nginx - {{ .Release.Name }}-fluxcd-operator - {{ .Release.Name }}-fluxcd - {{ .Release.Name }}-gpu-operator - {{ .Release.Name }}-velero - {{ .Release.Name }}-coredns - -p '{"spec": {"suspend": true}}' - --type=merge --field-manager=flux-client-side-apply || true + - >- + kubectl + --namespace={{ .Release.Namespace }} + patch + helmrelease + {{ .Release.Name }}-cilium + {{ .Release.Name }}-gateway-api-crds + {{ .Release.Name }}-csi + {{ .Release.Name }}-cert-manager + {{ .Release.Name }}-cert-manager-crds + {{ .Release.Name }}-vertical-pod-autoscaler + {{ .Release.Name }}-vertical-pod-autoscaler-crds + {{ .Release.Name }}-ingress-nginx + {{ .Release.Name }}-fluxcd-operator + {{ .Release.Name }}-fluxcd + {{ .Release.Name }}-gpu-operator + {{ .Release.Name }}-velero + {{ .Release.Name }}-coredns + -p '{"spec": {"suspend": true}}' + --type=merge --field-manager=flux-client-side-apply || true --- apiVersion: v1 kind: ServiceAccount @@ -51,7 +51,7 @@ metadata: name: {{ .Release.Name }}-flux-teardown annotations: helm.sh/hook: pre-delete - helm.sh/hook-delete-policy: before-hook-creation,hook-failed + helm.sh/hook-delete-policy: before-hook-creation,hook-failed,hook-succeeded helm.sh/hook-weight: "0" --- apiVersion: rbac.authorization.k8s.io/v1 @@ -75,6 +75,7 @@ rules: - {{ .Release.Name }}-csi - {{ .Release.Name }}-cert-manager - {{ .Release.Name }}-cert-manager-crds + - {{ .Release.Name }}-gateway-api-crds - {{ .Release.Name }}-vertical-pod-autoscaler - {{ .Release.Name }}-vertical-pod-autoscaler-crds - {{ .Release.Name }}-ingress-nginx From b7e7b0ac547e5c8b7ffc56ea733bebb0982b2bd3 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 6 Nov 2025 16:09:03 +0100 Subject: [PATCH 46/76] [cozy-lib] Fix: handling resources=nil Signed-off-by: Andrei Kvapil Co-authored-by: Timofei Larkin (cherry picked from commit 00328c8a31ed2e2d4a3cf4c7d45356c045c741b3) --- packages/library/cozy-lib/templates/_resources.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/library/cozy-lib/templates/_resources.tpl b/packages/library/cozy-lib/templates/_resources.tpl index 637d04f6..f402ee02 100644 --- a/packages/library/cozy-lib/templates/_resources.tpl +++ b/packages/library/cozy-lib/templates/_resources.tpl @@ -154,7 +154,7 @@ {{- $resources := index . 1 }} {{- $global := index . 2 }} {{- $presetMap := include "cozy-lib.resources.unsanitizedPreset" $preset | fromYaml }} -{{- $mergedMap := deepCopy $resources | mergeOverwrite $presetMap }} +{{- $mergedMap := deepCopy (default (dict) $resources) | mergeOverwrite $presetMap }} {{- include "cozy-lib.resources.sanitize" (list $mergedMap $global) }} {{- end }} From 8d91fcddd45ce48ba0e1d88be44ccc3f70cc9095 Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Wed, 29 Oct 2025 14:22:54 +0400 Subject: [PATCH 47/76] [controller] Remove crdmem, handle DaemonSet (#1555) This patch drops the custom caching of the Cozystack resource definitions in favor of the informer cache and adds a flag to the Cozystack controller to select, whether it restarts the cozystack-api deployment or the cozystack-api daemonset. As with the new default behavior of using a local endpoint for the k8s API by the lineage webhook and the Cozystack API, the Cozystack controller now also defaults to restarting a Cozystack API DaemonSet instead of a Deployment. To revert to the old behavior, disable the local k8s API endpoint on the webhook and cozystack API and set the `cozystackController.cozystackAPIKind` value in the Cozystack controller system Helm chart to "Deployment". ```release-note [controller] Use informer cache instead of the older bespoke implementation and add support for running the Cozystack API as a DaemonSet. ``` --- cmd/cozystack-controller/main.go | 12 +- .../cozystackresource_controller.go | 201 +++++------------- .../templates/deployment.yaml | 3 + .../cozystack-controller/templates/role.yaml | 2 +- .../system/cozystack-controller/values.yaml | 1 + 5 files changed, 72 insertions(+), 147 deletions(-) diff --git a/cmd/cozystack-controller/main.go b/cmd/cozystack-controller/main.go index c2ceb451..737c7775 100644 --- a/cmd/cozystack-controller/main.go +++ b/cmd/cozystack-controller/main.go @@ -69,6 +69,7 @@ func main() { var telemetryEndpoint string var telemetryInterval string var cozystackVersion string + var reconcileDeployment bool var tlsOpts []func(*tls.Config) flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+ "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.") @@ -88,6 +89,8 @@ func main() { "Interval between telemetry data collection (e.g. 15m, 1h)") flag.StringVar(&cozystackVersion, "cozystack-version", "unknown", "Version of Cozystack") + flag.BoolVar(&reconcileDeployment, "reconcile-deployment", false, + "If set, the Cozystack API server is assumed to run as a Deployment, else as a DaemonSet.") opts := zap.Options{ Development: false, } @@ -213,9 +216,14 @@ func main() { os.Exit(1) } + cozyAPIKind := "DaemonSet" + if reconcileDeployment { + cozyAPIKind = "Deployment" + } if err = (&controller.CozystackResourceDefinitionReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + CozystackAPIKind: cozyAPIKind, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "CozystackResourceDefinitionReconciler") os.Exit(1) diff --git a/internal/controller/cozystackresource_controller.go b/internal/controller/cozystackresource_controller.go index 0f02b610..46884418 100644 --- a/internal/controller/cozystackresource_controller.go +++ b/internal/controller/cozystackresource_controller.go @@ -5,28 +5,21 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" - "sort" + "slices" "sync" "time" - "github.com/cozystack/cozystack/internal/controller/dashboard" - "github.com/cozystack/cozystack/internal/shared/crdmem" - cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" - "github.com/go-logr/logr" appsv1 "k8s.io/api/apps/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/reconcile" ) @@ -40,128 +33,20 @@ type CozystackResourceDefinitionReconciler struct { lastEvent time.Time lastHandled time.Time - mem *crdmem.Memory - - // Track static resources initialization - staticResourcesInitialized bool - staticResourcesMutex sync.Mutex + CozystackAPIKind string } func (r *CozystackResourceDefinitionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - logger := log.FromContext(ctx) - - crd := &cozyv1alpha1.CozystackResourceDefinition{} - err := r.Get(ctx, types.NamespacedName{Name: req.Name}, crd) - if err == nil { - if r.mem != nil { - r.mem.Upsert(crd) - } - - mgr := dashboard.NewManager( - r.Client, - r.Scheme, - dashboard.WithCRDListFunc(func(c context.Context) ([]cozyv1alpha1.CozystackResourceDefinition, error) { - if r.mem != nil { - return r.mem.ListFromCacheOrAPI(c, r.Client) - } - var list cozyv1alpha1.CozystackResourceDefinitionList - if err := r.Client.List(c, &list); err != nil { - return nil, err - } - return list.Items, nil - }), - ) - - if res, derr := mgr.EnsureForCRD(ctx, crd); derr != nil || res.Requeue || res.RequeueAfter > 0 { - return res, derr - } - - // After processing CRD, perform cleanup of orphaned resources - // This should be done after cache warming to ensure all current resources are known - if cleanupErr := mgr.CleanupOrphanedResources(ctx); cleanupErr != nil { - logger.Error(cleanupErr, "Failed to cleanup orphaned dashboard resources") - // Don't fail the reconciliation, just log the error - } - - r.mu.Lock() - r.lastEvent = time.Now() - r.mu.Unlock() - return ctrl.Result{}, nil - } - - // Handle error cases (err is guaranteed to be non-nil here) - if !apierrors.IsNotFound(err) { - return ctrl.Result{}, err - } - // If resource is not found, clean up from memory - if r.mem != nil { - r.mem.Delete(req.Name) - } - if req.Namespace == "cozy-system" && req.Name == "cozystack-api" { - return r.debouncedRestart(ctx, logger) - } - return ctrl.Result{}, nil -} - -// initializeStaticResourcesOnce ensures static resources are created only once -func (r *CozystackResourceDefinitionReconciler) initializeStaticResourcesOnce(ctx context.Context) error { - r.staticResourcesMutex.Lock() - defer r.staticResourcesMutex.Unlock() - - if r.staticResourcesInitialized { - return nil // Already initialized - } - - // Create dashboard manager and initialize static resources - mgr := dashboard.NewManager( - r.Client, - r.Scheme, - dashboard.WithCRDListFunc(func(c context.Context) ([]cozyv1alpha1.CozystackResourceDefinition, error) { - if r.mem != nil { - return r.mem.ListFromCacheOrAPI(c, r.Client) - } - var list cozyv1alpha1.CozystackResourceDefinitionList - if err := r.Client.List(c, &list); err != nil { - return nil, err - } - return list.Items, nil - }), - ) - - if err := mgr.InitializeStaticResources(ctx); err != nil { - return err - } - - r.staticResourcesInitialized = true - log.FromContext(ctx).Info("Static dashboard resources initialized successfully") - return nil + return r.debouncedRestart(ctx) } func (r *CozystackResourceDefinitionReconciler) SetupWithManager(mgr ctrl.Manager) error { if r.Debounce == 0 { r.Debounce = 5 * time.Second } - if r.mem == nil { - r.mem = crdmem.Global() - } - if err := r.mem.EnsurePrimingWithManager(mgr); err != nil { - return err - } - - // Initialize static resources once during controller startup using manager.Runnable - if err := mgr.Add(manager.RunnableFunc(func(ctx context.Context) error { - if err := r.initializeStaticResourcesOnce(ctx); err != nil { - log.FromContext(ctx).Error(err, "Failed to initialize static resources") - return err - } - return nil - })); err != nil { - return err - } return ctrl.NewControllerManagedBy(mgr). Named("cozystackresource-controller"). - For(&cozyv1alpha1.CozystackResourceDefinition{}, builder.WithPredicates()). Watches( &cozyv1alpha1.CozystackResourceDefinition{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request { @@ -176,9 +61,6 @@ func (r *CozystackResourceDefinitionReconciler) SetupWithManager(mgr ctrl.Manage }} }), ). - WithOptions(controller.Options{ - MaxConcurrentReconciles: 5, // Allow more concurrent reconciles with proper rate limiting - }). Complete(r) } @@ -188,22 +70,18 @@ type crdHashView struct { } func (r *CozystackResourceDefinitionReconciler) computeConfigHash(ctx context.Context) (string, error) { - var items []cozyv1alpha1.CozystackResourceDefinition - if r.mem != nil { - list, err := r.mem.ListFromCacheOrAPI(ctx, r.Client) - if err != nil { - return "", err - } - items = list + list := &cozyv1alpha1.CozystackResourceDefinitionList{} + if err := r.List(ctx, list); err != nil { + return "", err } - sort.Slice(items, func(i, j int) bool { return items[i].Name < items[j].Name }) + slices.SortFunc(list.Items, sortCozyRDs) - views := make([]crdHashView, 0, len(items)) - for i := range items { + views := make([]crdHashView, 0, len(list.Items)) + for i := range list.Items { views = append(views, crdHashView{ - Name: items[i].Name, - Spec: items[i].Spec, + Name: list.Items[i].Name, + Spec: list.Items[i].Spec, }) } b, err := json.Marshal(views) @@ -214,7 +92,9 @@ func (r *CozystackResourceDefinitionReconciler) computeConfigHash(ctx context.Co return hex.EncodeToString(sum[:]), nil } -func (r *CozystackResourceDefinitionReconciler) debouncedRestart(ctx context.Context, logger logr.Logger) (ctrl.Result, error) { +func (r *CozystackResourceDefinitionReconciler) debouncedRestart(ctx context.Context) (ctrl.Result, error) { + logger := log.FromContext(ctx) + r.mu.Lock() le := r.lastEvent lh := r.lastHandled @@ -239,15 +119,12 @@ func (r *CozystackResourceDefinitionReconciler) debouncedRestart(ctx context.Con return ctrl.Result{}, err } - deploy := &appsv1.Deployment{} - if err := r.Get(ctx, types.NamespacedName{Namespace: "cozy-system", Name: "cozystack-api"}, deploy); err != nil { + tpl, obj, patch, err := r.getWorkload(ctx, types.NamespacedName{Namespace: "cozy-system", Name: "cozystack-api"}) + if err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) } - if deploy.Spec.Template.Annotations == nil { - deploy.Spec.Template.Annotations = map[string]string{} - } - oldHash := deploy.Spec.Template.Annotations["cozystack.io/config-hash"] + oldHash := tpl.Annotations["cozystack.io/config-hash"] if oldHash == newHash && oldHash != "" { r.mu.Lock() @@ -257,10 +134,9 @@ func (r *CozystackResourceDefinitionReconciler) debouncedRestart(ctx context.Con return ctrl.Result{}, nil } - patch := client.MergeFrom(deploy.DeepCopy()) - deploy.Spec.Template.Annotations["cozystack.io/config-hash"] = newHash + tpl.Annotations["cozystack.io/config-hash"] = newHash - if err := r.Patch(ctx, deploy, patch); err != nil { + if err := r.Patch(ctx, obj, patch); err != nil { return ctrl.Result{}, err } @@ -272,3 +148,40 @@ func (r *CozystackResourceDefinitionReconciler) debouncedRestart(ctx context.Con "old", oldHash, "new", newHash) return ctrl.Result{}, nil } + +func (r *CozystackResourceDefinitionReconciler) getWorkload( + ctx context.Context, + key types.NamespacedName, +) (tpl *corev1.PodTemplateSpec, obj client.Object, patch client.Patch, err error) { + if r.CozystackAPIKind == "Deployment" { + dep := &appsv1.Deployment{} + if err := r.Get(ctx, key, dep); err != nil { + return nil, nil, nil, err + } + obj = dep + tpl = &dep.Spec.Template + patch = client.MergeFrom(dep.DeepCopy()) + } else { + ds := &appsv1.DaemonSet{} + if err := r.Get(ctx, key, ds); err != nil { + return nil, nil, nil, err + } + obj = ds + tpl = &ds.Spec.Template + patch = client.MergeFrom(ds.DeepCopy()) + } + if tpl.Annotations == nil { + tpl.Annotations = make(map[string]string) + } + return tpl, obj, patch, nil +} + +func sortCozyRDs(a, b cozyv1alpha1.CozystackResourceDefinition) int { + if a.Name == b.Name { + return 0 + } + if a.Name < b.Name { + return -1 + } + return 1 +} diff --git a/packages/system/cozystack-controller/templates/deployment.yaml b/packages/system/cozystack-controller/templates/deployment.yaml index bac865ef..6dc21b1c 100644 --- a/packages/system/cozystack-controller/templates/deployment.yaml +++ b/packages/system/cozystack-controller/templates/deployment.yaml @@ -28,3 +28,6 @@ spec: {{- if .Values.cozystackController.disableTelemetry }} - --disable-telemetry {{- end }} + {{- if eq .Values.cozystackController.cozystackAPIKind "Deployment" }} + - --reconcile-deployment + {{- end }} diff --git a/packages/system/cozystack-controller/templates/role.yaml b/packages/system/cozystack-controller/templates/role.yaml index 96bfc9a5..734ba95b 100644 --- a/packages/system/cozystack-controller/templates/role.yaml +++ b/packages/system/cozystack-controller/templates/role.yaml @@ -5,7 +5,7 @@ metadata: namespace: cozy-system rules: - apiGroups: ["apps"] - resources: ["deployments"] + resources: ["deployments", "daemonsets"] resourceNames: ["cozystack-api"] verbs: ["patch", "update"] diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index d1f163ec..999cbb18 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -3,3 +3,4 @@ cozystackController: debug: false disableTelemetry: false cozystackVersion: "v0.37.5" + cozystackAPIKind: "DaemonSet" From c1ac876ff70f39735bcc047c6874c9207da580cf Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Fri, 31 Oct 2025 12:59:13 +0400 Subject: [PATCH 48/76] [dashboard] Revert reconciler removal (#1559) ## What this PR does In a previous patch (#1555) the reconciliation loop for the OpenAPI UI resources was accidentally removed. This patch reintroduces a separate controller, which handles updates to CozystackResourceDefinitions and creates, updates, or deletes the dashboard's custom resources. ### Release note ```release-note [dashboard] Reintroduce the accidentally removed reconciler that autoconfigures custom dashboard resources for the OpenAPI UI. ``` --- cmd/cozystack-controller/main.go | 13 ++- internal/controller/dashboard/breadcrumb.go | 4 +- .../controller/dashboard/customcolumns.go | 4 +- .../dashboard/customformsoverride.go | 4 +- .../dashboard/customformsprefill.go | 4 +- internal/controller/dashboard/factory.go | 4 +- internal/controller/dashboard/manager.go | 84 ++++++++++--------- .../controller/dashboard/marketplacepanel.go | 12 +-- internal/controller/dashboard/sidebar.go | 20 ++--- .../controller/dashboard/static_processor.go | 2 +- 10 files changed, 80 insertions(+), 71 deletions(-) diff --git a/cmd/cozystack-controller/main.go b/cmd/cozystack-controller/main.go index 737c7775..fc18a778 100644 --- a/cmd/cozystack-controller/main.go +++ b/cmd/cozystack-controller/main.go @@ -229,6 +229,15 @@ func main() { os.Exit(1) } + dashboardManager := &dashboard.Manager{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + } + if err = dashboardManager.SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "DashboardReconciler") + os.Exit(1) + } + // +kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { @@ -254,7 +263,9 @@ func main() { } setupLog.Info("starting manager") - if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + ctx := ctrl.SetupSignalHandler() + dashboardManager.InitializeStaticResources(ctx) + if err := mgr.Start(ctx); err != nil { setupLog.Error(err, "problem running manager") os.Exit(1) } diff --git a/internal/controller/dashboard/breadcrumb.go b/internal/controller/dashboard/breadcrumb.go index 0ad53ddb..5122f605 100644 --- a/internal/controller/dashboard/breadcrumb.go +++ b/internal/controller/dashboard/breadcrumb.go @@ -58,8 +58,8 @@ func (m *Manager) ensureBreadcrumb(ctx context.Context, crd *cozyv1alpha1.Cozyst "breadcrumbItems": items, } - _, err := controllerutil.CreateOrUpdate(ctx, m.client, obj, func() error { - if err := controllerutil.SetOwnerReference(crd, obj, m.scheme); err != nil { + _, err := controllerutil.CreateOrUpdate(ctx, m.Client, obj, func() error { + if err := controllerutil.SetOwnerReference(crd, obj, m.Scheme); err != nil { return err } // Add dashboard labels to dynamic resources diff --git a/internal/controller/dashboard/customcolumns.go b/internal/controller/dashboard/customcolumns.go index 78f2dd6a..6c23d68b 100644 --- a/internal/controller/dashboard/customcolumns.go +++ b/internal/controller/dashboard/customcolumns.go @@ -127,8 +127,8 @@ func (m *Manager) ensureCustomColumnsOverride(ctx context.Context, crd *cozyv1al }, } - _, err := controllerutil.CreateOrUpdate(ctx, m.client, obj, func() error { - if err := controllerutil.SetOwnerReference(crd, obj, m.scheme); err != nil { + _, err := controllerutil.CreateOrUpdate(ctx, m.Client, obj, func() error { + if err := controllerutil.SetOwnerReference(crd, obj, m.Scheme); err != nil { return err } // Add dashboard labels to dynamic resources diff --git a/internal/controller/dashboard/customformsoverride.go b/internal/controller/dashboard/customformsoverride.go index c06a21f3..ae637fa1 100644 --- a/internal/controller/dashboard/customformsoverride.go +++ b/internal/controller/dashboard/customformsoverride.go @@ -53,8 +53,8 @@ func (m *Manager) ensureCustomFormsOverride(ctx context.Context, crd *cozyv1alph "strategy": "merge", } - _, err := controllerutil.CreateOrUpdate(ctx, m.client, obj, func() error { - if err := controllerutil.SetOwnerReference(crd, obj, m.scheme); err != nil { + _, err := controllerutil.CreateOrUpdate(ctx, m.Client, obj, func() error { + if err := controllerutil.SetOwnerReference(crd, obj, m.Scheme); err != nil { return err } // Add dashboard labels to dynamic resources diff --git a/internal/controller/dashboard/customformsprefill.go b/internal/controller/dashboard/customformsprefill.go index b4dd2491..d2761873 100644 --- a/internal/controller/dashboard/customformsprefill.go +++ b/internal/controller/dashboard/customformsprefill.go @@ -56,8 +56,8 @@ func (m *Manager) ensureCustomFormsPrefill(ctx context.Context, crd *cozyv1alpha return reconcile.Result{}, err } - _, err = controllerutil.CreateOrUpdate(ctx, m.client, cfp, func() error { - if err := controllerutil.SetOwnerReference(crd, cfp, m.scheme); err != nil { + _, err = controllerutil.CreateOrUpdate(ctx, m.Client, cfp, func() error { + if err := controllerutil.SetOwnerReference(crd, cfp, m.Scheme); err != nil { return err } // Add dashboard labels to dynamic resources diff --git a/internal/controller/dashboard/factory.go b/internal/controller/dashboard/factory.go index 6a847e52..6f3e8f4c 100644 --- a/internal/controller/dashboard/factory.go +++ b/internal/controller/dashboard/factory.go @@ -60,8 +60,8 @@ func (m *Manager) ensureFactory(ctx context.Context, crd *cozyv1alpha1.Cozystack obj := &dashv1alpha1.Factory{} obj.SetName(factoryName) - _, err := controllerutil.CreateOrUpdate(ctx, m.client, obj, func() error { - if err := controllerutil.SetOwnerReference(crd, obj, m.scheme); err != nil { + _, err := controllerutil.CreateOrUpdate(ctx, m.Client, obj, func() error { + if err := controllerutil.SetOwnerReference(crd, obj, m.Scheme); err != nil { return err } // Add dashboard labels to dynamic resources diff --git a/internal/controller/dashboard/manager.go b/internal/controller/dashboard/manager.go index 4b5c2fb3..9c5d7e9d 100644 --- a/internal/controller/dashboard/manager.go +++ b/internal/controller/dashboard/manager.go @@ -10,7 +10,9 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -40,28 +42,42 @@ func AddToScheme(s *runtime.Scheme) error { // Manager owns logic for creating/updating dashboard resources derived from CRDs. // It’s easy to extend: add new ensure* methods and wire them into EnsureForCRD. type Manager struct { - client client.Client - scheme *runtime.Scheme - crdListFn func(context.Context) ([]cozyv1alpha1.CozystackResourceDefinition, error) -} - -// Option pattern so callers can inject a custom lister. -type Option func(*Manager) - -// WithCRDListFunc overrides how Manager lists all CozystackResourceDefinitions. -func WithCRDListFunc(fn func(context.Context) ([]cozyv1alpha1.CozystackResourceDefinition, error)) Option { - return func(m *Manager) { m.crdListFn = fn } + client.Client + Scheme *runtime.Scheme } // NewManager constructs a dashboard Manager. -func NewManager(c client.Client, scheme *runtime.Scheme, opts ...Option) *Manager { - m := &Manager{client: c, scheme: scheme} - for _, o := range opts { - o(m) - } +func NewManager(c client.Client, scheme *runtime.Scheme) *Manager { + m := &Manager{Client: c, Scheme: scheme} return m } +func (m *Manager) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + Named("dashboard-reconciler"). + For(&cozyv1alpha1.CozystackResourceDefinition{}). + Complete(m) +} + +func (m *Manager) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + l := log.FromContext(ctx) + + crd := &cozyv1alpha1.CozystackResourceDefinition{} + + err := m.Get(ctx, types.NamespacedName{Name: req.Name}, crd) + if err != nil { + if apierrors.IsNotFound(err) { + if err := m.CleanupOrphanedResources(ctx); err != nil { + l.Error(err, "Failed to cleanup orphaned dashboard resources") + } + return ctrl.Result{}, nil // no point in requeuing here + } + return ctrl.Result{}, err + } + + return m.EnsureForCRD(ctx, crd) +} + // EnsureForCRD is the single entry-point used by the controller. // Add more ensure* calls here as you implement support for other resources: // @@ -171,21 +187,11 @@ func (m *Manager) getStaticResourceSelector() client.MatchingLabels { // CleanupOrphanedResources removes dashboard resources that are no longer needed // This should be called after cache warming to ensure all current resources are known func (m *Manager) CleanupOrphanedResources(ctx context.Context) error { - // Get all current CRDs to determine which resources should exist - var allCRDs []cozyv1alpha1.CozystackResourceDefinition - if m.crdListFn != nil { - s, err := m.crdListFn(ctx) - if err != nil { - return err - } - allCRDs = s - } else { - var crdList cozyv1alpha1.CozystackResourceDefinitionList - if err := m.client.List(ctx, &crdList, &client.ListOptions{}); err != nil { - return err - } - allCRDs = crdList.Items + var crdList cozyv1alpha1.CozystackResourceDefinitionList + if err := m.List(ctx, &crdList, &client.ListOptions{}); err != nil { + return err } + allCRDs := crdList.Items // Build a set of expected resource names for each type expectedResources := m.buildExpectedResourceSet(allCRDs) @@ -349,7 +355,7 @@ func (m *Manager) cleanupResourceType(ctx context.Context, resourceType client.O } // List with dashboard labels - if err := m.client.List(ctx, list, m.getDashboardResourceSelector()); err != nil { + if err := m.List(ctx, list, m.getDashboardResourceSelector()); err != nil { return err } @@ -358,7 +364,7 @@ func (m *Manager) cleanupResourceType(ctx context.Context, resourceType client.O case *dashv1alpha1.CustomColumnsOverrideList: for _, item := range l.Items { if !expected[item.Name] { - if err := m.client.Delete(ctx, &item); err != nil { + if err := m.Delete(ctx, &item); err != nil { if !apierrors.IsNotFound(err) { return err } @@ -369,7 +375,7 @@ func (m *Manager) cleanupResourceType(ctx context.Context, resourceType client.O case *dashv1alpha1.CustomFormsOverrideList: for _, item := range l.Items { if !expected[item.Name] { - if err := m.client.Delete(ctx, &item); err != nil { + if err := m.Delete(ctx, &item); err != nil { if !apierrors.IsNotFound(err) { return err } @@ -380,7 +386,7 @@ func (m *Manager) cleanupResourceType(ctx context.Context, resourceType client.O case *dashv1alpha1.CustomFormsPrefillList: for _, item := range l.Items { if !expected[item.Name] { - if err := m.client.Delete(ctx, &item); err != nil { + if err := m.Delete(ctx, &item); err != nil { if !apierrors.IsNotFound(err) { return err } @@ -391,7 +397,7 @@ func (m *Manager) cleanupResourceType(ctx context.Context, resourceType client.O case *dashv1alpha1.MarketplacePanelList: for _, item := range l.Items { if !expected[item.Name] { - if err := m.client.Delete(ctx, &item); err != nil { + if err := m.Delete(ctx, &item); err != nil { if !apierrors.IsNotFound(err) { return err } @@ -402,7 +408,7 @@ func (m *Manager) cleanupResourceType(ctx context.Context, resourceType client.O case *dashv1alpha1.SidebarList: for _, item := range l.Items { if !expected[item.Name] { - if err := m.client.Delete(ctx, &item); err != nil { + if err := m.Delete(ctx, &item); err != nil { if !apierrors.IsNotFound(err) { return err } @@ -413,7 +419,7 @@ func (m *Manager) cleanupResourceType(ctx context.Context, resourceType client.O case *dashv1alpha1.TableUriMappingList: for _, item := range l.Items { if !expected[item.Name] { - if err := m.client.Delete(ctx, &item); err != nil { + if err := m.Delete(ctx, &item); err != nil { if !apierrors.IsNotFound(err) { return err } @@ -426,7 +432,7 @@ func (m *Manager) cleanupResourceType(ctx context.Context, resourceType client.O if !expected[item.Name] { logger := log.FromContext(ctx) logger.Info("Deleting orphaned Breadcrumb resource", "name", item.Name) - if err := m.client.Delete(ctx, &item); err != nil { + if err := m.Delete(ctx, &item); err != nil { if !apierrors.IsNotFound(err) { return err } @@ -438,7 +444,7 @@ func (m *Manager) cleanupResourceType(ctx context.Context, resourceType client.O if !expected[item.Name] { logger := log.FromContext(ctx) logger.Info("Deleting orphaned Factory resource", "name", item.Name) - if err := m.client.Delete(ctx, &item); err != nil { + if err := m.Delete(ctx, &item); err != nil { if !apierrors.IsNotFound(err) { return err } diff --git a/internal/controller/dashboard/marketplacepanel.go b/internal/controller/dashboard/marketplacepanel.go index e58232f5..82a8f336 100644 --- a/internal/controller/dashboard/marketplacepanel.go +++ b/internal/controller/dashboard/marketplacepanel.go @@ -24,14 +24,14 @@ func (m *Manager) ensureMarketplacePanel(ctx context.Context, crd *cozyv1alpha1. // If dashboard is not set, delete the panel if it exists. if crd.Spec.Dashboard == nil { - err := m.client.Get(ctx, client.ObjectKey{Name: mp.Name}, mp) + err := m.Get(ctx, client.ObjectKey{Name: mp.Name}, mp) if apierrors.IsNotFound(err) { return reconcile.Result{}, nil } if err != nil { return reconcile.Result{}, err } - if err := m.client.Delete(ctx, mp); err != nil && !apierrors.IsNotFound(err) { + if err := m.Delete(ctx, mp); err != nil && !apierrors.IsNotFound(err) { return reconcile.Result{}, err } logger.Info("Deleted MarketplacePanel because dashboard is not set", "name", mp.Name) @@ -40,14 +40,14 @@ func (m *Manager) ensureMarketplacePanel(ctx context.Context, crd *cozyv1alpha1. // Skip module and tenant resources (they don't need MarketplacePanel) if crd.Spec.Dashboard.Module || crd.Spec.Application.Kind == "Tenant" { - err := m.client.Get(ctx, client.ObjectKey{Name: mp.Name}, mp) + err := m.Get(ctx, client.ObjectKey{Name: mp.Name}, mp) if apierrors.IsNotFound(err) { return reconcile.Result{}, nil } if err != nil { return reconcile.Result{}, err } - if err := m.client.Delete(ctx, mp); err != nil && !apierrors.IsNotFound(err) { + if err := m.Delete(ctx, mp); err != nil && !apierrors.IsNotFound(err) { return reconcile.Result{}, err } logger.Info("Deleted MarketplacePanel because resource is a module", "name", mp.Name) @@ -86,8 +86,8 @@ func (m *Manager) ensureMarketplacePanel(ctx context.Context, crd *cozyv1alpha1. return reconcile.Result{}, err } - _, err = controllerutil.CreateOrUpdate(ctx, m.client, mp, func() error { - if err := controllerutil.SetOwnerReference(crd, mp, m.scheme); err != nil { + _, err = controllerutil.CreateOrUpdate(ctx, m.Client, mp, func() error { + if err := controllerutil.SetOwnerReference(crd, mp, m.Scheme); err != nil { return err } // Add dashboard labels to dynamic resources diff --git a/internal/controller/dashboard/sidebar.go b/internal/controller/dashboard/sidebar.go index 3edd6aca..97937921 100644 --- a/internal/controller/dashboard/sidebar.go +++ b/internal/controller/dashboard/sidebar.go @@ -33,19 +33,11 @@ func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.Cozystack // 1) Fetch all CRDs var all []cozyv1alpha1.CozystackResourceDefinition - if m.crdListFn != nil { - s, err := m.crdListFn(ctx) - if err != nil { - return err - } - all = s - } else { - var crdList cozyv1alpha1.CozystackResourceDefinitionList - if err := m.client.List(ctx, &crdList, &client.ListOptions{}); err != nil { - return err - } - all = crdList.Items + var crdList cozyv1alpha1.CozystackResourceDefinitionList + if err := m.List(ctx, &crdList, &client.ListOptions{}); err != nil { + return err } + all = crdList.Items // 2) Build category -> []item map (only for CRDs with spec.dashboard != nil) type item struct { @@ -251,7 +243,7 @@ func (m *Manager) upsertMultipleSidebars( obj := &dashv1alpha1.Sidebar{} obj.SetName(id) - if _, err := controllerutil.CreateOrUpdate(ctx, m.client, obj, func() error { + if _, err := controllerutil.CreateOrUpdate(ctx, m.Client, obj, func() error { // Only set owner reference for dynamic sidebars (stock-project-factory-{kind}-details) // Static sidebars (stock-instance-*, stock-project-*) should not have owner references if strings.HasPrefix(id, "stock-project-factory-") && strings.HasSuffix(id, "-details") { @@ -260,7 +252,7 @@ func (m *Manager) upsertMultipleSidebars( lowerKind := strings.ToLower(kind) expectedID := fmt.Sprintf("stock-project-factory-%s-details", lowerKind) if id == expectedID { - if err := controllerutil.SetOwnerReference(crd, obj, m.scheme); err != nil { + if err := controllerutil.SetOwnerReference(crd, obj, m.Scheme); err != nil { return err } // Add dashboard labels to dynamic resources diff --git a/internal/controller/dashboard/static_processor.go b/internal/controller/dashboard/static_processor.go index ef2e0341..902e3818 100644 --- a/internal/controller/dashboard/static_processor.go +++ b/internal/controller/dashboard/static_processor.go @@ -32,7 +32,7 @@ func (m *Manager) ensureStaticResource(ctx context.Context, obj client.Object) e // Add dashboard labels to static resources m.addDashboardLabels(resource, nil, ResourceTypeStatic) - _, err := controllerutil.CreateOrUpdate(ctx, m.client, resource, func() error { + _, err := controllerutil.CreateOrUpdate(ctx, m.Client, resource, func() error { // For static resources, we don't need to set owner references // as they are meant to be persistent across CRD changes // Copy Spec from the original object to the live object From 4b395d758e7c7d97407b1f375895a0867c64d8fc Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Mon, 27 Oct 2025 18:00:20 +0400 Subject: [PATCH 49/76] [api] Use shared informer cache (#1539) ## What this PR does This patch changes all clients in the Cozystack API server to typed ones from the controller runtime. This should improve the performance of the API server and simplifies the code by removing work with unstructured objects and dynamic clients. ### Release note ```release-note [api] Use typed and cache-backed k8s clients in the Cozystack API to improve performance. Get rid of operations on unstructured objects and use of dynamic clients. ``` ## Summary by CodeRabbit * **Refactor** * Backend migrated to a controller-runtime manager with typed clients for Kubernetes resources, improving watch reliability and cache sync. * Storage paths for applications, tenant modules, namespaces, and secrets now use strongly-typed resource handling for more consistent behavior. * **Chores** * Cluster role expanded to include services in core API permissions. * **Notes** * No user-facing API schema changes. --- .../system/cozystack-api/templates/rbac.yaml | 2 +- pkg/apiserver/apiserver.go | 86 +++++--- pkg/registry/apps/application/rest.go | 187 ++++++++---------- pkg/registry/core/tenantmodule/rest.go | 98 ++++----- pkg/registry/core/tenantnamespace/rest.go | 44 ++--- pkg/registry/core/tenantsecret/rest.go | 70 ++++--- pkg/registry/core/tenantsecretstable/rest.go | 36 +++- 7 files changed, 283 insertions(+), 240 deletions(-) diff --git a/packages/system/cozystack-api/templates/rbac.yaml b/packages/system/cozystack-api/templates/rbac.yaml index e4b3aca9..0429b9ef 100644 --- a/packages/system/cozystack-api/templates/rbac.yaml +++ b/packages/system/cozystack-api/templates/rbac.yaml @@ -4,7 +4,7 @@ metadata: name: cozystack-api rules: - apiGroups: [""] - resources: ["namespaces", "secrets"] + resources: ["namespaces", "secrets", "services"] verbs: ["get", "watch", "list"] - apiGroups: ["rbac.authorization.k8s.io"] resources: ["rolebindings"] diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index e829d336..d5814ee7 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -17,18 +17,22 @@ limitations under the License. package apiserver import ( + "context" "fmt" + "time" helmv2 "github.com/fluxcd/helm-controller/api/v2" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apiserver/pkg/registry/rest" genericapiserver "k8s.io/apiserver/pkg/server" - "k8s.io/client-go/dynamic" - "k8s.io/client-go/kubernetes" - restclient "k8s.io/client-go/rest" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/client" "github.com/cozystack/cozystack/pkg/apis/apps" appsinstall "github.com/cozystack/cozystack/pkg/apis/apps/install" @@ -50,6 +54,7 @@ var ( // versions and content types. Codecs = serializer.NewCodecFactory(Scheme) CozyComponentName = "cozy" + syncPeriod = 5 * time.Minute ) func init() { @@ -58,9 +63,15 @@ func init() { // Register HelmRelease types. if err := helmv2.AddToScheme(Scheme); err != nil { - panic(fmt.Sprintf("Failed to add HelmRelease types to scheme: %v", err)) + panic(fmt.Errorf("Failed to add HelmRelease types to scheme: %w", err)) } + if err := corev1.AddToScheme(Scheme); err != nil { + panic(fmt.Errorf("Failed to add core types to scheme: %w", err)) + } + if err := rbacv1.AddToScheme(Scheme); err != nil { + panic(fmt.Errorf("Failed to add RBAC types to scheme: %w", err)) + } // Add unversioned types. metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) @@ -118,43 +129,59 @@ func (c completedConfig) New() (*CozyServer, error) { } // Create a dynamic client for HelmRelease using InClusterConfig. - inClusterConfig, err := restclient.InClusterConfig() + cfg, err := ctrl.GetConfig() if err != nil { - return nil, fmt.Errorf("unable to get in-cluster config: %v", err) + return nil, fmt.Errorf("failed to get kubeconfig: %w", err) } - dynamicClient, err := dynamic.NewForConfig(inClusterConfig) + mgr, err := ctrl.NewManager(cfg, ctrl.Options{ + Scheme: Scheme, + Cache: cache.Options{SyncPeriod: &syncPeriod}, + }) if err != nil { - return nil, fmt.Errorf("unable to create dynamic client: %v", err) + return nil, fmt.Errorf("failed to build manager: %w", err) } - clientset, err := kubernetes.NewForConfig(inClusterConfig) - if err != nil { - return nil, fmt.Errorf("create kube clientset: %v", err) + ctx := ctrl.SetupSignalHandler() + + if err = mustGetInformers(ctx, mgr, + &helmv2.HelmRelease{}, + &corev1.Secret{}, + &corev1.Namespace{}, + &corev1.Service{}, + &rbacv1.RoleBinding{}, + ); err != nil { + return nil, fmt.Errorf("failed to get informers: %w", err) } + go func() { + if err := mgr.Start(ctx); err != nil { + panic(fmt.Errorf("manager start failed: %w", err)) + } + }() + + if ok := mgr.GetCache().WaitForCacheSync(ctx); !ok { + return nil, fmt.Errorf("cache sync failed") + } + + cli := mgr.GetClient() + watchCli, err := client.NewWithWatch(cfg, client.Options{Scheme: Scheme}) + if err != nil { + return nil, fmt.Errorf("failed to build watch client: %w", err) + } // --- static, cluster-scoped resource for core group --- coreV1alpha1Storage := map[string]rest.Storage{} coreV1alpha1Storage["tenantnamespaces"] = cozyregistry.RESTInPeace( - tenantnamespacestorage.NewREST( - clientset.CoreV1(), - clientset.RbacV1(), - ), + tenantnamespacestorage.NewREST(cli, watchCli), ) coreV1alpha1Storage["tenantsecrets"] = cozyregistry.RESTInPeace( - tenantsecretstorage.NewREST( - clientset.CoreV1(), - ), + tenantsecretstorage.NewREST(cli, watchCli), ) coreV1alpha1Storage["tenantsecretstables"] = cozyregistry.RESTInPeace( - tenantsecretstablestorage.NewREST( - clientset.CoreV1(), - ), + tenantsecretstablestorage.NewREST(cli, watchCli), ) coreV1alpha1Storage["tenantmodules"] = cozyregistry.RESTInPeace( - tenantmodulestorage.NewREST( - dynamicClient, - ), + tenantmodulestorage.NewREST(cli, watchCli), ) coreApiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(core.GroupName, Scheme, metav1.ParameterCodec, Codecs) @@ -166,7 +193,7 @@ func (c completedConfig) New() (*CozyServer, error) { // --- dynamically-configured, per-tenant resources --- appsV1alpha1Storage := map[string]rest.Storage{} for _, resConfig := range c.ResourceConfig.Resources { - storage := applicationstorage.NewREST(dynamicClient, &resConfig) + storage := applicationstorage.NewREST(cli, watchCli, &resConfig) appsV1alpha1Storage[resConfig.Application.Plural] = cozyregistry.RESTInPeace(storage) } appsApiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(apps.GroupName, Scheme, metav1.ParameterCodec, Codecs) @@ -177,3 +204,12 @@ func (c completedConfig) New() (*CozyServer, error) { return s, nil } + +func mustGetInformers(ctx context.Context, mgr ctrl.Manager, types ...client.Object) error { + for i := range types { + if _, err := mgr.GetCache().GetInformer(ctx, types[i]); err != nil { + return fmt.Errorf("failed to get informer for %T: %w", types[i], err) + } + } + return nil +} diff --git a/pkg/registry/apps/application/rest.go b/pkg/registry/apps/application/rest.go index 388d741f..37a5d9a5 100644 --- a/pkg/registry/apps/application/rest.go +++ b/pkg/registry/apps/application/rest.go @@ -37,8 +37,8 @@ import ( "k8s.io/apimachinery/pkg/watch" "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" - "k8s.io/client-go/dynamic" "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/client" appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" "github.com/cozystack/cozystack/pkg/config" @@ -76,7 +76,8 @@ var helmReleaseGVR = schema.GroupVersionResource{ // REST implements the RESTStorage interface for Application resources type REST struct { - dynamicClient dynamic.Interface + c client.Client + w client.WithWatch gvr schema.GroupVersionResource gvk schema.GroupVersionKind kindName string @@ -86,7 +87,7 @@ type REST struct { } // NewREST creates a new REST storage for Application with specific configuration -func NewREST(dynamicClient dynamic.Interface, config *config.Resource) *REST { +func NewREST(c client.Client, w client.WithWatch, config *config.Resource) *REST { var specSchema *structuralschema.Structural if raw := strings.TrimSpace(config.Application.OpenAPISchema); raw != "" { @@ -110,7 +111,8 @@ func NewREST(dynamicClient dynamic.Interface, config *config.Resource) *REST { } return &REST{ - dynamicClient: dynamicClient, + c: c, + w: w, gvr: schema.GroupVersionResource{ Group: appsv1alpha1.GroupName, Version: "v1alpha1", @@ -158,30 +160,23 @@ func (r *REST) Create(ctx context.Context, obj runtime.Object, createValidation helmRelease.Labels = mergeMaps(helmRelease.Labels, addPrefixedMap(app.Labels, LabelPrefix)) // Note: Annotations from config are not handled as r.releaseConfig.Annotations is undefined - // Convert HelmRelease to unstructured format - unstructuredHR, err := runtime.DefaultUnstructuredConverter.ToUnstructured(helmRelease) - if err != nil { - klog.Errorf("Failed to convert HelmRelease to unstructured: %v", err) - return nil, fmt.Errorf("failed to convert HelmRelease to unstructured: %v", err) - } - klog.V(6).Infof("Creating HelmRelease %s in namespace %s", helmRelease.Name, app.Namespace) // Create HelmRelease in Kubernetes - createdHR, err := r.dynamicClient.Resource(helmReleaseGVR).Namespace(app.Namespace).Create(ctx, &unstructured.Unstructured{Object: unstructuredHR}, *options) + err = r.c.Create(ctx, helmRelease, &client.CreateOptions{Raw: options}) if err != nil { klog.Errorf("Failed to create HelmRelease %s: %v", helmRelease.Name, err) return nil, fmt.Errorf("failed to create HelmRelease: %v", err) } // Convert the created HelmRelease back to Application - convertedApp, err := r.ConvertHelmReleaseToApplication(createdHR) + convertedApp, err := r.ConvertHelmReleaseToApplication(helmRelease) if err != nil { - klog.Errorf("Conversion error from HelmRelease to Application for resource %s: %v", createdHR.GetName(), err) + klog.Errorf("Conversion error from HelmRelease to Application for resource %s: %v", helmRelease.GetName(), err) return nil, fmt.Errorf("conversion error: %v", err) } - klog.V(6).Infof("Successfully created and converted HelmRelease %s to Application", createdHR.GetName()) + klog.V(6).Infof("Successfully created and converted HelmRelease %s to Application", helmRelease.GetName()) // Convert Application to unstructured format unstructuredApp, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&convertedApp) @@ -206,7 +201,8 @@ func (r *REST) Get(ctx context.Context, name string, options *metav1.GetOptions) // Get the corresponding HelmRelease using the new prefix helmReleaseName := r.releaseConfig.Prefix + name - hr, err := r.dynamicClient.Resource(helmReleaseGVR).Namespace(namespace).Get(ctx, helmReleaseName, *options) + helmRelease := &helmv2.HelmRelease{} + err = r.c.Get(ctx, client.ObjectKey{Namespace: namespace, Name: helmReleaseName}, helmRelease, &client.GetOptions{Raw: options}) if err != nil { klog.Errorf("Error retrieving HelmRelease for resource %s: %v", name, err) @@ -221,14 +217,14 @@ func (r *REST) Get(ctx context.Context, name string, options *metav1.GetOptions) } // Check if HelmRelease meets the required chartName and sourceRef criteria - if !r.shouldIncludeHelmRelease(hr) { + if !r.shouldIncludeHelmRelease(helmRelease) { klog.Errorf("HelmRelease %s does not match the required chartName and sourceRef criteria", helmReleaseName) // Return a NotFound error for the Application resource return nil, apierrors.NewNotFound(r.gvr.GroupResource(), name) } // Convert HelmRelease to Application - convertedApp, err := r.ConvertHelmReleaseToApplication(hr) + convertedApp, err := r.ConvertHelmReleaseToApplication(helmRelease) if err != nil { klog.Errorf("Conversion error from HelmRelease to Application for resource %s: %v", name, err) return nil, fmt.Errorf("conversion error: %v", err) @@ -325,7 +321,11 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption } // List HelmReleases with mapped selectors - hrList, err := r.dynamicClient.Resource(helmReleaseGVR).Namespace(namespace).List(ctx, metaOptions) + hrList := &helmv2.HelmReleaseList{} + err = r.c.List(ctx, hrList, &client.ListOptions{ + Namespace: namespace, + Raw: &metaOptions, + }) if err != nil { klog.Errorf("Error listing HelmReleases: %v", err) return nil, err @@ -335,14 +335,14 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption items := make([]unstructured.Unstructured, 0) // Iterate over HelmReleases and convert to Applications - for _, hr := range hrList.Items { - if !r.shouldIncludeHelmRelease(&hr) { + for i := range hrList.Items { + if !r.shouldIncludeHelmRelease(&hrList.Items[i]) { continue } - app, err := r.ConvertHelmReleaseToApplication(&hr) + app, err := r.ConvertHelmReleaseToApplication(&hrList.Items[i]) if err != nil { - klog.Errorf("Error converting HelmRelease %s to Application: %v", hr.GetName(), err) + klog.Errorf("Error converting HelmRelease %s to Application: %v", hrList.Items[i].GetName(), err) continue } @@ -457,7 +457,8 @@ func (r *REST) Update(ctx context.Context, name string, objInfo rest.UpdatedObje // Ensure ResourceVersion if helmRelease.ResourceVersion == "" { - cur, err := r.dynamicClient.Resource(helmReleaseGVR).Namespace(helmRelease.Namespace).Get(ctx, helmRelease.Name, metav1.GetOptions{}) + cur := &helmv2.HelmRelease{} + err := r.c.Get(ctx, client.ObjectKey{Namespace: helmRelease.Namespace, Name: helmRelease.Name}, cur, &client.GetOptions{Raw: &metav1.GetOptions{}}) if err != nil { return nil, false, fmt.Errorf("failed to fetch current HelmRelease: %w", err) } @@ -470,53 +471,38 @@ func (r *REST) Update(ctx context.Context, name string, objInfo rest.UpdatedObje helmRelease.Labels = mergeMaps(helmRelease.Labels, addPrefixedMap(app.Labels, LabelPrefix)) // Note: Annotations from config are not handled as r.releaseConfig.Annotations is undefined - // Convert HelmRelease to unstructured format - unstructuredHR, err := runtime.DefaultUnstructuredConverter.ToUnstructured(helmRelease) - if err != nil { - klog.Errorf("Failed to convert HelmRelease to unstructured: %v", err) - return nil, false, fmt.Errorf("failed to convert HelmRelease to unstructured: %v", err) - } - - // Retrieve metadata from unstructured object - metadata, found, err := unstructured.NestedMap(unstructuredHR, "metadata") - if err != nil || !found { - klog.Errorf("Failed to retrieve metadata from HelmRelease: %v, found: %v", err, found) - return nil, false, fmt.Errorf("failed to retrieve metadata from HelmRelease: %v", err) - } - klog.V(6).Infof("HelmRelease Metadata: %+v", metadata) - klog.V(6).Infof("Updating HelmRelease %s in namespace %s", helmRelease.Name, helmRelease.Namespace) // Before updating, ensure the HelmRelease meets the inclusion criteria // This prevents updating HelmReleases that should not be managed as Applications - if !r.shouldIncludeHelmRelease(&unstructured.Unstructured{Object: unstructuredHR}) { + if !r.shouldIncludeHelmRelease(helmRelease) { klog.Errorf("HelmRelease %s does not match the required chartName and sourceRef criteria", helmRelease.Name) // Return a NotFound error for the Application resource return nil, false, apierrors.NewNotFound(r.gvr.GroupResource(), name) } // Update the HelmRelease in Kubernetes - resultHR, err := r.dynamicClient.Resource(helmReleaseGVR).Namespace(helmRelease.Namespace).Update(ctx, &unstructured.Unstructured{Object: unstructuredHR}, metav1.UpdateOptions{}) + err = r.c.Update(ctx, helmRelease, &client.UpdateOptions{Raw: &metav1.UpdateOptions{}}) if err != nil { klog.Errorf("Failed to update HelmRelease %s: %v", helmRelease.Name, err) return nil, false, fmt.Errorf("failed to update HelmRelease: %v", err) } // After updating, ensure the updated HelmRelease still meets the inclusion criteria - if !r.shouldIncludeHelmRelease(resultHR) { - klog.Errorf("Updated HelmRelease %s does not match the required chartName and sourceRef criteria", resultHR.GetName()) + if !r.shouldIncludeHelmRelease(helmRelease) { + klog.Errorf("Updated HelmRelease %s does not match the required chartName and sourceRef criteria", helmRelease.GetName()) // Return a NotFound error for the Application resource return nil, false, apierrors.NewNotFound(r.gvr.GroupResource(), name) } // Convert the updated HelmRelease back to Application - convertedApp, err := r.ConvertHelmReleaseToApplication(resultHR) + convertedApp, err := r.ConvertHelmReleaseToApplication(helmRelease) if err != nil { - klog.Errorf("Conversion error from HelmRelease to Application for resource %s: %v", resultHR.GetName(), err) + klog.Errorf("Conversion error from HelmRelease to Application for resource %s: %v", helmRelease.GetName(), err) return nil, false, fmt.Errorf("conversion error: %v", err) } - klog.V(6).Infof("Successfully updated and converted HelmRelease %s to Application", resultHR.GetName()) + klog.V(6).Infof("Successfully updated and converted HelmRelease %s to Application", helmRelease.GetName()) // Explicitly set apiVersion and kind for Application convertedApp.TypeMeta = metav1.TypeMeta{ @@ -554,7 +540,8 @@ func (r *REST) Delete(ctx context.Context, name string, deleteValidation rest.Va helmReleaseName := r.releaseConfig.Prefix + name // Retrieve the HelmRelease before attempting to delete - hr, err := r.dynamicClient.Resource(helmReleaseGVR).Namespace(namespace).Get(ctx, helmReleaseName, metav1.GetOptions{}) + helmRelease := &helmv2.HelmRelease{} + err = r.c.Get(ctx, client.ObjectKey{Namespace: namespace, Name: helmReleaseName}, helmRelease, &client.GetOptions{Raw: &metav1.GetOptions{}}) if err != nil { if apierrors.IsNotFound(err) { // If HelmRelease does not exist, return NotFound error for Application @@ -567,7 +554,7 @@ func (r *REST) Delete(ctx context.Context, name string, deleteValidation rest.Va } // Validate that the HelmRelease meets the inclusion criteria - if !r.shouldIncludeHelmRelease(hr) { + if !r.shouldIncludeHelmRelease(helmRelease) { klog.Errorf("HelmRelease %s does not match the required chartName and sourceRef criteria", helmReleaseName) // Return NotFound error for Application resource return nil, false, apierrors.NewNotFound(r.gvr.GroupResource(), name) @@ -576,7 +563,7 @@ func (r *REST) Delete(ctx context.Context, name string, deleteValidation rest.Va klog.V(6).Infof("Deleting HelmRelease %s in namespace %s", helmReleaseName, namespace) // Delete the HelmRelease corresponding to the Application - err = r.dynamicClient.Resource(helmReleaseGVR).Namespace(namespace).Delete(ctx, helmReleaseName, *options) + err = r.c.Delete(ctx, helmRelease, &client.DeleteOptions{Raw: options}) if err != nil { klog.Errorf("Failed to delete HelmRelease %s: %v", helmReleaseName, err) return nil, false, fmt.Errorf("failed to delete HelmRelease: %v", err) @@ -659,7 +646,11 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio } // Start watch on HelmRelease with mapped selectors - helmWatcher, err := r.dynamicClient.Resource(helmReleaseGVR).Namespace(namespace).Watch(ctx, metaOptions) + hrList := &helmv2.HelmReleaseList{} + helmWatcher, err := r.w.Watch(ctx, hrList, &client.ListOptions{ + Namespace: namespace, + Raw: &metaOptions, + }) if err != nil { klog.Errorf("Error setting up watch for HelmReleases: %v", err) return nil, err @@ -669,13 +660,15 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio customW := &customWatcher{ resultChan: make(chan watch.Event), stopChan: make(chan struct{}), + underlying: helmWatcher, } go func() { defer close(customW.resultChan) + defer customW.underlying.Stop() for { select { - case event, ok := <-helmWatcher.ResultChan(): + case event, ok := <-customW.underlying.ResultChan(): if !ok { // The watcher has been closed, attempt to re-establish the watch klog.Warning("HelmRelease watcher closed, attempting to re-establish") @@ -689,19 +682,19 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio continue // Skip processing this event } - // Proceed with processing Unstructured objects - matches, err := r.isRelevantHelmRelease(&event) - if err != nil { - klog.V(4).Infof("Non-critical error filtering HelmRelease event: %v", err) + // Proceed with processing HelmRelease objects + hr, ok := event.Object.(*helmv2.HelmRelease) + if !ok { + klog.V(4).Infof("Expected HelmRelease object, got %T", event.Object) continue } - if !matches { + if !r.shouldIncludeHelmRelease(hr) { continue } // Convert HelmRelease to Application - app, err := r.ConvertHelmReleaseToApplication(event.Object.(*unstructured.Unstructured)) + app, err := r.ConvertHelmReleaseToApplication(hr) if err != nil { klog.Errorf("Error converting HelmRelease to Application: %v", err) continue @@ -771,12 +764,16 @@ type customWatcher struct { resultChan chan watch.Event stopChan chan struct{} stopOnce sync.Once + underlying watch.Interface } // Stop terminates the watch func (cw *customWatcher) Stop() { cw.stopOnce.Do(func() { close(cw.stopChan) + if cw.underlying != nil { + cw.underlying.Stop() + } }) } @@ -785,34 +782,18 @@ func (cw *customWatcher) ResultChan() <-chan watch.Event { return cw.resultChan } -// isRelevantHelmRelease checks if the HelmRelease meets the sourceRef and prefix criteria -func (r *REST) isRelevantHelmRelease(event *watch.Event) (bool, error) { - if event.Object == nil { - return false, nil - } - - // Check if the object is a *v1.Status - if status, ok := event.Object.(*metav1.Status); ok { - // Log at a less severe level or handle specific status errors if needed - klog.V(4).Infof("Received Status object in HelmRelease watch: %v", status.Message) - return false, nil // Not relevant for processing as a HelmRelease - } - - // Proceed if it's an Unstructured object - hr, ok := event.Object.(*unstructured.Unstructured) - if !ok { - return false, fmt.Errorf("expected Unstructured object, got %T", event.Object) - } - - return r.shouldIncludeHelmRelease(hr), nil -} - // shouldIncludeHelmRelease determines if a HelmRelease should be included based on filtering criteria -func (r *REST) shouldIncludeHelmRelease(hr *unstructured.Unstructured) bool { +func (r *REST) shouldIncludeHelmRelease(hr *helmv2.HelmRelease) bool { + // Nil check for Chart field + if hr.Spec.Chart == nil { + klog.V(6).Infof("HelmRelease %s has nil spec.chart field", hr.GetName()) + return false + } + // Filter by Chart Name - chartName, found, err := unstructured.NestedString(hr.Object, "spec", "chart", "spec", "chart") - if err != nil || !found { - klog.V(6).Infof("HelmRelease %s missing spec.chart.spec.chart field: %v", hr.GetName(), err) + chartName := hr.Spec.Chart.Spec.Chart + if chartName == "" { + klog.V(6).Infof("HelmRelease %s missing spec.chart.spec.chart field", hr.GetName()) return false } if chartName != r.releaseConfig.Chart.Name { @@ -825,21 +806,29 @@ func (r *REST) shouldIncludeHelmRelease(hr *unstructured.Unstructured) bool { } // matchesSourceRefAndPrefix checks both SourceRefConfig and Prefix criteria -func (r *REST) matchesSourceRefAndPrefix(hr *unstructured.Unstructured) bool { +func (r *REST) matchesSourceRefAndPrefix(hr *helmv2.HelmRelease) bool { + // Nil check for Chart field (defensive) + if hr.Spec.Chart == nil { + klog.V(6).Infof("HelmRelease %s has nil spec.chart field", hr.GetName()) + return false + } + // Extract SourceRef fields - sourceRefKind, found, err := unstructured.NestedString(hr.Object, "spec", "chart", "spec", "sourceRef", "kind") - if err != nil || !found { - klog.V(6).Infof("HelmRelease %s missing spec.chart.spec.sourceRef.kind field: %v", hr.GetName(), err) + sourceRef := hr.Spec.Chart.Spec.SourceRef + sourceRefKind := sourceRef.Kind + sourceRefName := sourceRef.Name + sourceRefNamespace := sourceRef.Namespace + + if sourceRefKind == "" { + klog.V(6).Infof("HelmRelease %s missing spec.chart.spec.sourceRef.kind field", hr.GetName()) return false } - sourceRefName, found, err := unstructured.NestedString(hr.Object, "spec", "chart", "spec", "sourceRef", "name") - if err != nil || !found { - klog.V(6).Infof("HelmRelease %s missing spec.chart.spec.sourceRef.name field: %v", hr.GetName(), err) + if sourceRefName == "" { + klog.V(6).Infof("HelmRelease %s missing spec.chart.spec.sourceRef.name field", hr.GetName()) return false } - sourceRefNamespace, found, err := unstructured.NestedString(hr.Object, "spec", "chart", "spec", "sourceRef", "namespace") - if err != nil || !found { - klog.V(6).Infof("HelmRelease %s missing spec.chart.spec.sourceRef.namespace field: %v", hr.GetName(), err) + if sourceRefNamespace == "" { + klog.V(6).Infof("HelmRelease %s missing spec.chart.spec.sourceRef.namespace field", hr.GetName()) return false } @@ -930,19 +919,11 @@ func filterPrefixedMap(original map[string]string, prefix string) map[string]str } // ConvertHelmReleaseToApplication converts a HelmRelease to an Application -func (r *REST) ConvertHelmReleaseToApplication(hr *unstructured.Unstructured) (appsv1alpha1.Application, error) { +func (r *REST) ConvertHelmReleaseToApplication(hr *helmv2.HelmRelease) (appsv1alpha1.Application, error) { klog.V(6).Infof("Converting HelmRelease to Application for resource %s", hr.GetName()) - var helmRelease helmv2.HelmRelease - // Convert unstructured to HelmRelease struct - err := runtime.DefaultUnstructuredConverter.FromUnstructured(hr.Object, &helmRelease) - if err != nil { - klog.Errorf("Error converting from unstructured to HelmRelease: %v", err) - return appsv1alpha1.Application{}, err - } - // Convert HelmRelease struct to Application struct - app, err := r.convertHelmReleaseToApplication(&helmRelease) + app, err := r.convertHelmReleaseToApplication(hr) if err != nil { klog.Errorf("Error converting from HelmRelease to Application: %v", err) return appsv1alpha1.Application{}, err diff --git a/pkg/registry/core/tenantmodule/rest.go b/pkg/registry/core/tenantmodule/rest.go index aa7d4eeb..852a0b64 100644 --- a/pkg/registry/core/tenantmodule/rest.go +++ b/pkg/registry/core/tenantmodule/rest.go @@ -32,12 +32,13 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/selection" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/duration" "k8s.io/apimachinery/pkg/watch" "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" - "k8s.io/client-go/dynamic" "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/client" corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -69,17 +70,19 @@ var helmReleaseGVR = schema.GroupVersionResource{ // REST implements the RESTStorage interface for TenantModule resources type REST struct { - dynamicClient dynamic.Interface - gvr schema.GroupVersionResource - gvk schema.GroupVersionKind - kindName string - singularName string + c client.Client + w client.WithWatch + gvr schema.GroupVersionResource + gvk schema.GroupVersionKind + kindName string + singularName string } // NewREST creates a new REST storage for TenantModule -func NewREST(dynamicClient dynamic.Interface) *REST { +func NewREST(c client.Client, w client.WithWatch) *REST { return &REST{ - dynamicClient: dynamicClient, + c: c, + w: w, gvr: schema.GroupVersionResource{ Group: corev1alpha1.GroupName, Version: "v1alpha1", @@ -115,7 +118,8 @@ func (r *REST) Get(ctx context.Context, name string, options *metav1.GetOptions) klog.V(6).Infof("Attempting to retrieve TenantModule %s in namespace %s", name, namespace) // Get the corresponding HelmRelease - hr, err := r.dynamicClient.Resource(helmReleaseGVR).Namespace(namespace).Get(ctx, name, *options) + hr := &helmv2.HelmRelease{} + err = r.c.Get(ctx, types.NamespacedName{Namespace: namespace, Name: name}, hr, &client.GetOptions{Raw: options}) if err != nil { klog.Errorf("Error retrieving HelmRelease for TenantModule %s: %v", name, err) @@ -231,7 +235,11 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption } // List HelmReleases with mapped selectors - hrList, err := r.dynamicClient.Resource(helmReleaseGVR).Namespace(namespace).List(ctx, metaOptions) + hrList := &helmv2.HelmReleaseList{} + err = r.c.List(ctx, hrList, &client.ListOptions{ + Namespace: namespace, + Raw: &metaOptions, + }) if err != nil { klog.Errorf("Error listing HelmReleases: %v", err) return nil, err @@ -241,15 +249,15 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption items := make([]unstructured.Unstructured, 0) // Iterate over HelmReleases and convert to TenantModules - for _, hr := range hrList.Items { + for i := range hrList.Items { // Double-check the label requirement - if !r.hasTenantModuleLabel(&hr) { + if !r.hasTenantModuleLabel(&hrList.Items[i]) { continue } - module, err := r.ConvertHelmReleaseToTenantModule(&hr) + module, err := r.ConvertHelmReleaseToTenantModule(&hrList.Items[i]) if err != nil { - klog.Errorf("Error converting HelmRelease %s to TenantModule: %v", hr.GetName(), err) + klog.Errorf("Error converting HelmRelease %s to TenantModule: %v", hrList.Items[i].GetName(), err) continue } @@ -376,7 +384,11 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio } // Start watch on HelmRelease with mapped selectors - helmWatcher, err := r.dynamicClient.Resource(helmReleaseGVR).Namespace(namespace).Watch(ctx, metaOptions) + hrList := &helmv2.HelmReleaseList{} + helmWatcher, err := r.w.Watch(ctx, hrList, &client.ListOptions{ + Namespace: namespace, + Raw: &metaOptions, + }) if err != nil { klog.Errorf("Error setting up watch for HelmReleases: %v", err) return nil, err @@ -386,13 +398,15 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio customW := &customWatcher{ resultChan: make(chan watch.Event), stopChan: make(chan struct{}), + underlying: helmWatcher, } go func() { defer close(customW.resultChan) + defer customW.underlying.Stop() for { select { - case event, ok := <-helmWatcher.ResultChan(): + case event, ok := <-customW.underlying.ResultChan(): if !ok { // The watcher has been closed, attempt to re-establish the watch klog.Warning("HelmRelease watcher closed, attempting to re-establish") @@ -406,19 +420,19 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio continue // Skip processing this event } - // Proceed with processing Unstructured objects - matches, err := r.isRelevantHelmRelease(&event) - if err != nil { - klog.V(4).Infof("Non-critical error filtering HelmRelease event: %v", err) + // Proceed with processing HelmRelease objects + hr, ok := event.Object.(*helmv2.HelmRelease) + if !ok { + klog.V(4).Infof("Expected HelmRelease object, got %T", event.Object) continue } - if !matches { + if !r.hasTenantModuleLabel(hr) { continue } // Convert HelmRelease to TenantModule - module, err := r.ConvertHelmReleaseToTenantModule(event.Object.(*unstructured.Unstructured)) + module, err := r.ConvertHelmReleaseToTenantModule(hr) if err != nil { klog.Errorf("Error converting HelmRelease to TenantModule: %v", err) continue @@ -480,12 +494,16 @@ type customWatcher struct { resultChan chan watch.Event stopChan chan struct{} stopOnce sync.Once + underlying watch.Interface } // Stop terminates the watch func (cw *customWatcher) Stop() { cw.stopOnce.Do(func() { close(cw.stopChan) + if cw.underlying != nil { + cw.underlying.Stop() + } }) } @@ -494,30 +512,8 @@ func (cw *customWatcher) ResultChan() <-chan watch.Event { return cw.resultChan } -// isRelevantHelmRelease checks if the HelmRelease has the tenant module label -func (r *REST) isRelevantHelmRelease(event *watch.Event) (bool, error) { - if event.Object == nil { - return false, nil - } - - // Check if the object is a *v1.Status - if status, ok := event.Object.(*metav1.Status); ok { - // Log at a less severe level or handle specific status errors if needed - klog.V(4).Infof("Received Status object in HelmRelease watch: %v", status.Message) - return false, nil // Not relevant for processing as a HelmRelease - } - - // Proceed if it's an Unstructured object - hr, ok := event.Object.(*unstructured.Unstructured) - if !ok { - return false, fmt.Errorf("expected Unstructured object, got %T", event.Object) - } - - return r.hasTenantModuleLabel(hr), nil -} - // hasTenantModuleLabel checks if a HelmRelease has the required tenant module label -func (r *REST) hasTenantModuleLabel(hr *unstructured.Unstructured) bool { +func (r *REST) hasTenantModuleLabel(hr *helmv2.HelmRelease) bool { labels := hr.GetLabels() if labels == nil { return false @@ -554,19 +550,11 @@ func (r *REST) getNamespace(ctx context.Context) (string, error) { } // ConvertHelmReleaseToTenantModule converts a HelmRelease to a TenantModule -func (r *REST) ConvertHelmReleaseToTenantModule(hr *unstructured.Unstructured) (corev1alpha1.TenantModule, error) { +func (r *REST) ConvertHelmReleaseToTenantModule(hr *helmv2.HelmRelease) (corev1alpha1.TenantModule, error) { klog.V(6).Infof("Converting HelmRelease to TenantModule for resource %s", hr.GetName()) - var helmRelease helmv2.HelmRelease - // Convert unstructured to HelmRelease struct - err := runtime.DefaultUnstructuredConverter.FromUnstructured(hr.Object, &helmRelease) - if err != nil { - klog.Errorf("Error converting from unstructured to HelmRelease: %v", err) - return corev1alpha1.TenantModule{}, err - } - // Convert HelmRelease struct to TenantModule struct - module, err := r.convertHelmReleaseToTenantModule(&helmRelease) + module, err := r.convertHelmReleaseToTenantModule(hr) if err != nil { klog.Errorf("Error converting from HelmRelease to TenantModule: %v", err) return corev1alpha1.TenantModule{}, err diff --git a/pkg/registry/core/tenantnamespace/rest.go b/pkg/registry/core/tenantnamespace/rest.go index 56098740..68d9fe3c 100644 --- a/pkg/registry/core/tenantnamespace/rest.go +++ b/pkg/registry/core/tenantnamespace/rest.go @@ -12,17 +12,18 @@ import ( "time" corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metainternal "k8s.io/apimachinery/pkg/apis/meta/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/duration" "k8s.io/apimachinery/pkg/watch" "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" - corev1client "k8s.io/client-go/kubernetes/typed/core/v1" - rbacv1client "k8s.io/client-go/kubernetes/typed/rbac/v1" + "sigs.k8s.io/controller-runtime/pkg/client" corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" ) @@ -46,18 +47,18 @@ var ( ) type REST struct { - core corev1client.CoreV1Interface - rbac rbacv1client.RbacV1Interface - gvr schema.GroupVersionResource + c client.Client + w client.WithWatch + gvr schema.GroupVersionResource } func NewREST( - coreCli corev1client.CoreV1Interface, - rbacCli rbacv1client.RbacV1Interface, + c client.Client, + w client.WithWatch, ) *REST { return &REST{ - core: coreCli, - rbac: rbacCli, + c: c, + w: w, gvr: schema.GroupVersionResource{ Group: corev1alpha1.GroupName, Version: "v1alpha1", @@ -89,7 +90,8 @@ func (r *REST) List( ctx context.Context, _ *metainternal.ListOptions, ) (runtime.Object, error) { - nsList, err := r.core.Namespaces().List(ctx, metav1.ListOptions{}) + nsList := &corev1.NamespaceList{} + err := r.c.List(ctx, nsList) if err != nil { return nil, err } @@ -118,7 +120,8 @@ func (r *REST) Get( return nil, apierrors.NewNotFound(r.gvr.GroupResource(), name) } - ns, err := r.core.Namespaces().Get(ctx, name, *opts) + ns := &corev1.Namespace{} + err := r.c.Get(ctx, types.NamespacedName{Namespace: "", Name: name}, ns, &client.GetOptions{Raw: opts}) if err != nil { return nil, err } @@ -128,14 +131,7 @@ func (r *REST) Get( APIVersion: corev1alpha1.SchemeGroupVersion.String(), Kind: "TenantNamespace", }, - ObjectMeta: metav1.ObjectMeta{ - Name: ns.Name, - UID: ns.UID, - ResourceVersion: ns.ResourceVersion, - CreationTimestamp: ns.CreationTimestamp, - Labels: ns.Labels, - Annotations: ns.Annotations, - }, + ObjectMeta: ns.ObjectMeta, }, nil } @@ -144,10 +140,11 @@ func (r *REST) Get( // ----------------------------------------------------------------------------- func (r *REST) Watch(ctx context.Context, opts *metainternal.ListOptions) (watch.Interface, error) { - nsWatch, err := r.core.Namespaces().Watch(ctx, metav1.ListOptions{ + nsList := &corev1.NamespaceList{} + nsWatch, err := r.w.Watch(ctx, nsList, &client.ListOptions{Raw: &metav1.ListOptions{ Watch: true, ResourceVersion: opts.ResourceVersion, - }) + }}) if err != nil { return nil, err } @@ -282,9 +279,10 @@ func (r *REST) filterAccessible( for _, name := range names { nameSet[name] = struct{}{} } - rbs, err := r.rbac.RoleBindings("").List(ctx, metav1.ListOptions{}) + rbs := &rbacv1.RoleBindingList{} + err := r.c.List(ctx, rbs) if err != nil { - return []string{}, fmt.Errorf("failed to list rolebindings") + return []string{}, fmt.Errorf("failed to list rolebindings: %w", err) } allowedNameSet := make(map[string]struct{}) for i := range rbs.Items { diff --git a/pkg/registry/core/tenantsecret/rest.go b/pkg/registry/core/tenantsecret/rest.go index ad477527..a13426e6 100644 --- a/pkg/registry/core/tenantsecret/rest.go +++ b/pkg/registry/core/tenantsecret/rest.go @@ -25,7 +25,7 @@ import ( "k8s.io/apimachinery/pkg/watch" "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" - corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" ) @@ -157,13 +157,15 @@ var ( ) type REST struct { - core corev1client.CoreV1Interface - gvr schema.GroupVersionResource + c client.Client + w client.WithWatch + gvr schema.GroupVersionResource } -func NewREST(coreCli corev1client.CoreV1Interface) *REST { +func NewREST(c client.Client, w client.WithWatch) *REST { return &REST{ - core: coreCli, + c: c, + w: w, gvr: schema.GroupVersionResource{ Group: corev1alpha1.GroupName, Version: "v1alpha1", @@ -203,11 +205,11 @@ func (r *REST) Create( } sec := tenantToSecret(in, nil) - out, err := r.core.Secrets(sec.Namespace).Create(ctx, sec, *opts) + err := r.c.Create(ctx, sec, &client.CreateOptions{Raw: opts}) if err != nil { return nil, err } - return secretToTenant(out), nil + return secretToTenant(sec), nil } func (r *REST) Get( @@ -219,7 +221,8 @@ func (r *REST) Get( if err != nil { return nil, err } - sec, err := r.core.Secrets(ns).Get(ctx, name, *opts) + sec := &corev1.Secret{} + err = r.c.Get(ctx, types.NamespacedName{Namespace: ns, Name: name}, sec, &client.GetOptions{Raw: opts}) if err != nil { return nil, err } @@ -247,10 +250,14 @@ func (r *REST) List(ctx context.Context, opts *metainternal.ListOptions) (runtim fieldSel = opts.FieldSelector.String() } - list, err := r.core.Secrets(ns).List(ctx, metav1.ListOptions{ - LabelSelector: ls.String(), - FieldSelector: fieldSel, - }) + list := &corev1.SecretList{} + err = r.c.List(ctx, list, + &client.ListOptions{ + Namespace: ns, + Raw: &metav1.ListOptions{ + LabelSelector: ls.String(), + FieldSelector: fieldSel, + }}) if err != nil { return nil, err } @@ -284,7 +291,8 @@ func (r *REST) Update( return nil, false, err } - cur, err := r.core.Secrets(ns).Get(ctx, name, metav1.GetOptions{}) + cur := &corev1.Secret{} + err = r.c.Get(ctx, types.NamespacedName{Namespace: ns, Name: name}, cur, &client.GetOptions{Raw: &metav1.GetOptions{}}) if err != nil && !apierrors.IsNotFound(err) { return nil, false, err } @@ -296,17 +304,18 @@ func (r *REST) Update( in := newObj.(*corev1alpha1.TenantSecret) newSec := tenantToSecret(in, cur) + newSec.Namespace = ns if cur == nil { if !forceCreate && err == nil { return nil, false, apierrors.NewNotFound(r.gvr.GroupResource(), name) } - out, err := r.core.Secrets(ns).Create(ctx, newSec, metav1.CreateOptions{}) - return secretToTenant(out), true, err + err := r.c.Create(ctx, newSec, &client.CreateOptions{Raw: &metav1.CreateOptions{}}) + return secretToTenant(newSec), true, err } newSec.ResourceVersion = cur.ResourceVersion - out, err := r.core.Secrets(ns).Update(ctx, newSec, *opts) - return secretToTenant(out), false, err + err = r.c.Update(ctx, newSec, &client.UpdateOptions{Raw: opts}) + return secretToTenant(newSec), false, err } func (r *REST) Delete( @@ -319,7 +328,7 @@ func (r *REST) Delete( if err != nil { return nil, false, err } - err = r.core.Secrets(ns).Delete(ctx, name, *opts) + err = r.c.Delete(ctx, &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Namespace: ns, Name: name}}, &client.DeleteOptions{Raw: opts}) return nil, err == nil, err } @@ -331,21 +340,33 @@ func (r *REST) Patch( opts *metav1.PatchOptions, subresources ...string, ) (runtime.Object, error) { + if len(subresources) > 0 { + return nil, fmt.Errorf("TenantSecret does not have subresources") + } ns, err := nsFrom(ctx) if err != nil { return nil, err } - - out, err := r.core.Secrets(ns). - Patch(ctx, name, pt, data, *opts, subresources...) + out := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + Name: name, + }, + } + patch := client.RawPatch(pt, data) + err = r.c.Patch(ctx, out, patch, &client.PatchOptions{Raw: opts}) if err != nil { return nil, err } // Ensure tenant secret label is preserved + if out.Labels == nil { + out.Labels = make(map[string]string) + } + if out.Labels[tsLabelKey] != tsLabelValue { out.Labels[tsLabelKey] = tsLabelValue - out, _ = r.core.Secrets(ns).Update(ctx, out, metav1.UpdateOptions{}) + _ = r.c.Update(ctx, out, &client.UpdateOptions{Raw: &metav1.UpdateOptions{}}) } return secretToTenant(out), nil @@ -361,12 +382,13 @@ func (r *REST) Watch(ctx context.Context, opts *metainternal.ListOptions) (watch return nil, err } + secList := &corev1.SecretList{} ls := labels.Set{tsLabelKey: tsLabelValue}.AsSelector().String() - base, err := r.core.Secrets(ns).Watch(ctx, metav1.ListOptions{ + base, err := r.w.Watch(ctx, secList, &client.ListOptions{Namespace: ns, Raw: &metav1.ListOptions{ Watch: true, LabelSelector: ls, ResourceVersion: opts.ResourceVersion, - }) + }}) if err != nil { return nil, err } diff --git a/pkg/registry/core/tenantsecretstable/rest.go b/pkg/registry/core/tenantsecretstable/rest.go index 841bfa32..de2604ca 100644 --- a/pkg/registry/core/tenantsecretstable/rest.go +++ b/pkg/registry/core/tenantsecretstable/rest.go @@ -23,7 +23,7 @@ import ( "k8s.io/apimachinery/pkg/watch" "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" - corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" ) @@ -38,13 +38,15 @@ const ( ) type REST struct { - core corev1client.CoreV1Interface - gvr schema.GroupVersionResource + c client.Client + w client.WithWatch + gvr schema.GroupVersionResource } -func NewREST(coreCli corev1client.CoreV1Interface) *REST { +func NewREST(c client.Client, w client.WithWatch) *REST { return &REST{ - core: coreCli, + c: c, + w: w, gvr: schema.GroupVersionResource{ Group: corev1alpha1.GroupName, Version: "v1alpha1", @@ -95,7 +97,14 @@ func (r *REST) Get(ctx context.Context, name string, opts *metav1.GetOptions) (r // We need to identify secret name and key. Iterate secrets in namespace with tenant secret label // and return the matching composed object. - list, err := r.core.Secrets(ns).List(ctx, metav1.ListOptions{LabelSelector: labels.Set{tsLabelKey: tsLabelValue}.AsSelector().String()}) + list := &corev1.SecretList{} + err = r.c.List(ctx, list, + &client.ListOptions{ + Namespace: ns, + Raw: &metav1.ListOptions{ + LabelSelector: labels.Set{tsLabelKey: tsLabelValue}.AsSelector().String(), + }, + }) if err != nil { return nil, err } @@ -130,7 +139,15 @@ func (r *REST) List(ctx context.Context, opts *metainternal.ListOptions) (runtim fieldSel = opts.FieldSelector.String() } - list, err := r.core.Secrets(ns).List(ctx, metav1.ListOptions{LabelSelector: sel.String(), FieldSelector: fieldSel}) + list := &corev1.SecretList{} + err = r.c.List(ctx, list, + &client.ListOptions{ + Namespace: ns, + Raw: &metav1.ListOptions{ + LabelSelector: labels.Set{tsLabelKey: tsLabelValue}.AsSelector().String(), + FieldSelector: fieldSel, + }, + }) if err != nil { return nil, err } @@ -169,12 +186,13 @@ func (r *REST) Watch(ctx context.Context, opts *metainternal.ListOptions) (watch return nil, err } + secList := &corev1.SecretList{} ls := labels.Set{tsLabelKey: tsLabelValue}.AsSelector().String() - base, err := r.core.Secrets(ns).Watch(ctx, metav1.ListOptions{ + base, err := r.w.Watch(ctx, secList, &client.ListOptions{Namespace: ns, Raw: &metav1.ListOptions{ Watch: true, LabelSelector: ls, ResourceVersion: opts.ResourceVersion, - }) + }}) if err != nil { return nil, err } From 625f35d66f6ea7acefb7d3fb5872ee2f46b86139 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 6 Nov 2025 16:23:39 +0100 Subject: [PATCH 50/76] [dashboard] sync with upstream & enhancements (#1603) Signed-off-by: Andrei Kvapil - Move patches to upstream: `namespaces` and `hide inside` - Introduce flatMap logic - Remove `tenantsecretstables` resource - Extend dashboard-controller to specify `multilineString` for any string without enum in spec (previusly it was for all strings) ```release-note [dashboard] sync with upstream & enhancements ``` * **New Features** * Enhanced OpenAPI form handling: string fields now better support multiline input. * **Improvements** * Secrets UI and API alignment: secrets display and data keys updated for consistency. * Form generation improved for nested objects and arrays. * Deployment defaults adjusted (logger flags normalized; inside feature hidden via env). * **Removed** * Removed the "Inside" header menu item and the legacy secrets-table API/resource. --- .../dashboard/customformsoverride.go | 105 +++++- .../dashboard/customformsoverride_test.go | 155 ++++++++ internal/controller/dashboard/factory.go | 4 +- .../controller/dashboard/static_helpers.go | 11 +- .../controller/dashboard/static_refactored.go | 9 +- packages/apps/tenant/templates/tenant.yaml | 4 - .../images/openapi-ui-k8s-bff/Dockerfile | 6 +- .../dashboard/images/openapi-ui/Dockerfile | 10 +- .../openapi-ui/patches/namespaces.diff | 89 ----- .../patches/remove-inside-link.diff | 15 - .../system/dashboard/templates/configmap.yaml | 8 +- packages/system/dashboard/templates/web.yaml | 22 +- packages/system/dashboard/values.yaml | 6 +- pkg/apis/core/v1alpha1/register.go | 4 +- .../core/v1alpha1/tenantsecretstable_types.go | 34 -- .../core/v1alpha1/zz_generated.deepcopy.go | 76 ---- pkg/apiserver/apiserver.go | 4 - pkg/generated/openapi/zz_generated.openapi.go | 123 ------- pkg/registry/core/tenantsecretstable/rest.go | 335 ------------------ 19 files changed, 305 insertions(+), 715 deletions(-) create mode 100644 internal/controller/dashboard/customformsoverride_test.go delete mode 100644 packages/system/dashboard/images/openapi-ui/openapi-ui/patches/namespaces.diff delete mode 100644 packages/system/dashboard/images/openapi-ui/openapi-ui/patches/remove-inside-link.diff delete mode 100644 pkg/apis/core/v1alpha1/tenantsecretstable_types.go delete mode 100644 pkg/registry/core/tenantsecretstable/rest.go diff --git a/internal/controller/dashboard/customformsoverride.go b/internal/controller/dashboard/customformsoverride.go index ae637fa1..f88202bc 100644 --- a/internal/controller/dashboard/customformsoverride.go +++ b/internal/controller/dashboard/customformsoverride.go @@ -11,6 +11,7 @@ import ( apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/log" ) // ensureCustomFormsOverride creates or updates a CustomFormsOverride resource for the given CRD @@ -45,15 +46,24 @@ func (m *Manager) ensureCustomFormsOverride(ctx context.Context, crd *cozyv1alph } } + // Build schema with multilineString for string fields without enum + l := log.FromContext(ctx) + schema, err := buildMultilineStringSchema(crd.Spec.Application.OpenAPISchema) + if err != nil { + // If schema parsing fails, log the error and use an empty schema + l.Error(err, "failed to build multiline string schema, using empty schema", "crd", crd.Name) + schema = map[string]any{} + } + spec := map[string]any{ "customizationId": customizationID, "hidden": hidden, "sort": sort, - "schema": map[string]any{}, // {} + "schema": schema, "strategy": "merge", } - _, err := controllerutil.CreateOrUpdate(ctx, m.Client, obj, func() error { + _, err = controllerutil.CreateOrUpdate(ctx, m.Client, obj, func() error { if err := controllerutil.SetOwnerReference(crd, obj, m.Scheme); err != nil { return err } @@ -73,3 +83,94 @@ func (m *Manager) ensureCustomFormsOverride(ctx context.Context, crd *cozyv1alph }) return err } + +// buildMultilineStringSchema parses OpenAPI schema and creates schema with multilineString +// for all string fields inside spec that don't have enum +func buildMultilineStringSchema(openAPISchema string) (map[string]any, error) { + if openAPISchema == "" { + return map[string]any{}, nil + } + + var root map[string]any + if err := json.Unmarshal([]byte(openAPISchema), &root); err != nil { + return nil, fmt.Errorf("cannot parse openAPISchema: %w", err) + } + + props, _ := root["properties"].(map[string]any) + if props == nil { + return map[string]any{}, nil + } + + schema := map[string]any{ + "properties": map[string]any{}, + } + + // Process spec properties recursively + processSpecProperties(props, schema["properties"].(map[string]any)) + + return schema, nil +} + +// processSpecProperties recursively processes spec properties and adds multilineString type +// for string fields without enum +func processSpecProperties(props map[string]any, schemaProps map[string]any) { + for pname, raw := range props { + sub, ok := raw.(map[string]any) + if !ok { + continue + } + + typ, _ := sub["type"].(string) + + switch typ { + case "string": + // Check if this string field has enum + if !hasEnum(sub) { + // Add multilineString type for this field + if schemaProps[pname] == nil { + schemaProps[pname] = map[string]any{} + } + fieldSchema := schemaProps[pname].(map[string]any) + fieldSchema["type"] = "multilineString" + } + case "object": + // Recursively process nested objects + if childProps, ok := sub["properties"].(map[string]any); ok { + fieldSchema, ok := schemaProps[pname].(map[string]any) + if !ok { + fieldSchema = map[string]any{} + schemaProps[pname] = fieldSchema + } + nestedSchemaProps, ok := fieldSchema["properties"].(map[string]any) + if !ok { + nestedSchemaProps = map[string]any{} + fieldSchema["properties"] = nestedSchemaProps + } + processSpecProperties(childProps, nestedSchemaProps) + } + case "array": + // Check if array items are objects with properties + if items, ok := sub["items"].(map[string]any); ok { + if itemProps, ok := items["properties"].(map[string]any); ok { + // Create array item schema + fieldSchema, ok := schemaProps[pname].(map[string]any) + if !ok { + fieldSchema = map[string]any{} + schemaProps[pname] = fieldSchema + } + itemSchema, ok := fieldSchema["items"].(map[string]any) + if !ok { + itemSchema = map[string]any{} + fieldSchema["items"] = itemSchema + } + itemSchemaProps, ok := itemSchema["properties"].(map[string]any) + if !ok { + itemSchemaProps = map[string]any{} + itemSchema["properties"] = itemSchemaProps + } + processSpecProperties(itemProps, itemSchemaProps) + } + } + } + } +} diff --git a/internal/controller/dashboard/customformsoverride_test.go b/internal/controller/dashboard/customformsoverride_test.go new file mode 100644 index 00000000..2766bf17 --- /dev/null +++ b/internal/controller/dashboard/customformsoverride_test.go @@ -0,0 +1,155 @@ +package dashboard + +import ( + "encoding/json" + "testing" +) + +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": { + "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" + } + } + } + } + } + }` + + schema, err := buildMultilineStringSchema(openAPISchema) + if err != nil { + t.Fatalf("buildMultilineStringSchema failed: %v", err) + } + + // Marshal to JSON for easier inspection + schemaJSON, err := json.MarshalIndent(schema, "", " ") + if err != nil { + t.Fatalf("Failed to marshal schema: %v", err) + } + + t.Logf("Generated schema:\n%s", schemaJSON) + + // Verify that simpleString has multilineString type + props, ok := schema["properties"].(map[string]any) + if !ok { + t.Fatal("schema.properties is not a map") + } + + // Check simpleString + simpleString, ok := props["simpleString"].(map[string]any) + if !ok { + t.Fatal("simpleString not found in 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["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["type"] != nil { + t.Error("numberField should not have any type override") + } + } + + // Check nested object + nestedObject, ok := props["nestedObject"].(map[string]any) + if !ok { + t.Fatal("nestedObject not found in properties") + } + nestedProps, ok := nestedObject["properties"].(map[string]any) + if !ok { + t.Fatal("nestedObject.properties is not a map") + } + + // Check nestedString + nestedString, ok := nestedProps["nestedString"].(map[string]any) + if !ok { + t.Fatal("nestedString not found in nestedObject.properties") + } + if nestedString["type"] != "multilineString" { + t.Errorf("nestedString should have type multilineString, got %v", nestedString["type"]) + } + + // Check array of objects + arrayOfObjects, ok := props["arrayOfObjects"].(map[string]any) + if !ok { + t.Fatal("arrayOfObjects not found in properties") + } + items, ok := arrayOfObjects["items"].(map[string]any) + if !ok { + t.Fatal("arrayOfObjects.items is not a map") + } + itemProps, ok := items["properties"].(map[string]any) + if !ok { + t.Fatal("arrayOfObjects.items.properties is not a map") + } + itemString, ok := itemProps["itemString"].(map[string]any) + if !ok { + t.Fatal("itemString not found in arrayOfObjects.items.properties") + } + if itemString["type"] != "multilineString" { + t.Errorf("itemString should have type multilineString, got %v", itemString["type"]) + } +} + +func TestBuildMultilineStringSchemaEmpty(t *testing.T) { + schema, err := buildMultilineStringSchema("") + if err != nil { + t.Fatalf("buildMultilineStringSchema failed on empty string: %v", err) + } + if len(schema) != 0 { + t.Errorf("Expected empty schema for empty input, got %v", schema) + } +} + +func TestBuildMultilineStringSchemaInvalidJSON(t *testing.T) { + schema, err := buildMultilineStringSchema("{invalid json") + if err == nil { + t.Error("Expected error for invalid JSON") + } + if schema != nil { + t.Errorf("Expected nil schema for invalid JSON, got %v", schema) + } +} diff --git a/internal/controller/dashboard/factory.go b/internal/controller/dashboard/factory.go index 6f3e8f4c..c23bac4a 100644 --- a/internal/controller/dashboard/factory.go +++ b/internal/controller/dashboard/factory.go @@ -293,10 +293,10 @@ func secretsTab(kind string) map[string]any { "type": "EnrichedTable", "data": map[string]any{ "id": "secrets-table", - "fetchUrl": "/api/clusters/{2}/k8s/apis/core.cozystack.io/v1alpha1/namespaces/{3}/tenantsecretstables", + "fetchUrl": "/api/clusters/{2}/k8s/apis/core.cozystack.io/v1alpha1/namespaces/{3}/tenantsecrets", "clusterNamePartOfUrl": "{2}", "baseprefix": "/openapi-ui", - "customizationId": "factory-details-v1alpha1.core.cozystack.io.tenantsecretstables", + "customizationId": "factory-details-v1alpha1.core.cozystack.io.tenantsecrets", "pathToItems": []any{"items"}, "labelsSelector": map[string]any{ "apps.cozystack.io/application.group": "apps.cozystack.io", diff --git a/internal/controller/dashboard/static_helpers.go b/internal/controller/dashboard/static_helpers.go index 5affc1c1..4c8aae30 100644 --- a/internal/controller/dashboard/static_helpers.go +++ b/internal/controller/dashboard/static_helpers.go @@ -122,7 +122,7 @@ func createCustomColumnsOverride(id string, additionalPrinterColumns []any) *das } } - if name == "factory-details-v1alpha1.core.cozystack.io.tenantsecretstables" { + if name == "factory-details-v1alpha1.core.cozystack.io.tenantsecrets" { data["additionalPrinterColumnsTrimLengths"] = []any{ map[string]any{ "key": "Name", @@ -1046,6 +1046,15 @@ func createConverterBytesColumn(name, jsonPath string) map[string]any { } } +// createFlatMapColumn creates a flatMap column that expands a map into separate rows +func createFlatMapColumn(name, jsonPath string) map[string]any { + return map[string]any{ + "name": name, + "type": "flatMap", + "jsonPath": jsonPath, + } +} + // ---------------- Factory UI helper functions ---------------- // labelsEditor creates a Labels editor component diff --git a/internal/controller/dashboard/static_refactored.go b/internal/controller/dashboard/static_refactored.go index 9ad923e7..31db0377 100644 --- a/internal/controller/dashboard/static_refactored.go +++ b/internal/controller/dashboard/static_refactored.go @@ -173,11 +173,12 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid createStringColumn("OBSERVED", ".status.observedReplicas"), }), - // Factory details v1alpha1 core cozystack io tenantsecretstables - createCustomColumnsOverride("factory-details-v1alpha1.core.cozystack.io.tenantsecretstables", []any{ + // Factory details v1alpha1 core cozystack io tenantsecrets + createCustomColumnsOverride("factory-details-v1alpha1.core.cozystack.io.tenantsecrets", []any{ createCustomColumnWithJsonPath("Name", ".metadata.name", "Secret", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-secret-details/{reqsJsonPath[0]['.metadata.name']['-']}"), - createStringColumn("Key", ".data.key"), - createSecretBase64Column("Value", ".data.value"), + createFlatMapColumn("Data", ".data"), + createStringColumn("Key", "_flatMapData_Key"), + createSecretBase64Column("Value", "_flatMapData_Value"), createTimestampColumn("Created", ".metadata.creationTimestamp"), }), diff --git a/packages/apps/tenant/templates/tenant.yaml b/packages/apps/tenant/templates/tenant.yaml index 9845b644..571a989d 100644 --- a/packages/apps/tenant/templates/tenant.yaml +++ b/packages/apps/tenant/templates/tenant.yaml @@ -35,7 +35,6 @@ rules: resources: - tenantmodules - tenantsecrets - - tenantsecretstables verbs: ["get", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 @@ -193,7 +192,6 @@ rules: resources: - tenantmodules - tenantsecrets - - tenantsecretstables verbs: ["get", "list", "watch"] --- kind: RoleBinding @@ -292,7 +290,6 @@ rules: resources: - tenantmodules - tenantsecrets - - tenantsecretstables verbs: ["get", "list", "watch"] --- kind: RoleBinding @@ -367,7 +364,6 @@ rules: resources: - tenantmodules - tenantsecrets - - tenantsecretstables verbs: ["get", "list", "watch"] --- kind: RoleBinding diff --git a/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile b/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile index d8447e7a..51444ad0 100644 --- a/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile +++ b/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile @@ -1,15 +1,11 @@ # imported from https://github.com/cozystack/openapi-ui-k8s-bff ARG NODE_VERSION=20.18.1 FROM node:${NODE_VERSION}-alpine AS builder -RUN apk add git WORKDIR /src -ARG COMMIT_REF=88531ed6881b4ce4808e56c00905951d7ba8031c +ARG COMMIT_REF=ba56271739505284aee569f914fc90e6a9c670da RUN wget -O- https://github.com/PRO-Robotech/openapi-ui-k8s-bff/archive/${COMMIT_REF}.tar.gz | tar xzf - --strip-components=1 -COPY patches /patches -RUN git apply /patches/*.diff - ENV PATH=/src/node_modules/.bin:$PATH RUN npm install RUN npm run build diff --git a/packages/system/dashboard/images/openapi-ui/Dockerfile b/packages/system/dashboard/images/openapi-ui/Dockerfile index af41cb65..a33be863 100644 --- a/packages/system/dashboard/images/openapi-ui/Dockerfile +++ b/packages/system/dashboard/images/openapi-ui/Dockerfile @@ -5,7 +5,7 @@ ARG NODE_VERSION=20.18.1 FROM node:${NODE_VERSION}-alpine AS openapi-k8s-toolkit-builder RUN apk add git WORKDIR /src -ARG COMMIT=e5f16b45de19f892de269cc4ef27e74aa62f4c92 +ARG COMMIT=7bd5380c6c4606640dd3bac68bf9dce469470518 RUN wget -O- https://github.com/cozystack/openapi-k8s-toolkit/archive/${COMMIT}.tar.gz | tar -xzvf- --strip-components=1 COPY openapi-k8s-toolkit/patches /patches @@ -19,14 +19,14 @@ RUN npm run build # openapi-ui # imported from https://github.com/cozystack/openapi-ui FROM node:${NODE_VERSION}-alpine AS builder -RUN apk add git +#RUN apk add git WORKDIR /src -ARG COMMIT_REF=9ce4367657f49c0032d8016b1d9491f8abbd2b15 +ARG COMMIT_REF=0c3629b2ce8545e81f7ece4d65372a188c802dfc RUN wget -O- https://github.com/PRO-Robotech/openapi-ui/archive/${COMMIT_REF}.tar.gz | tar xzf - --strip-components=1 -COPY openapi-ui/patches /patches -RUN git apply /patches/*.diff +#COPY openapi-ui/patches /patches +#RUN git apply /patches/*.diff ENV PATH=/src/node_modules/.bin:$PATH diff --git a/packages/system/dashboard/images/openapi-ui/openapi-ui/patches/namespaces.diff b/packages/system/dashboard/images/openapi-ui/openapi-ui/patches/namespaces.diff deleted file mode 100644 index b76c86d3..00000000 --- a/packages/system/dashboard/images/openapi-ui/openapi-ui/patches/namespaces.diff +++ /dev/null @@ -1,89 +0,0 @@ -diff --git a/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx b/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx -index b6fb99f..965bac0 100644 ---- a/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx -+++ b/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx -@@ -1,11 +1,16 @@ - import React, { FC, useState } from 'react' - import { Button, Alert, Spin, Typography } from 'antd' --import { filterSelectOptions, Spacer, useBuiltinResources } from '@prorobotech/openapi-k8s-toolkit' -+import { filterSelectOptions, Spacer, useApiResources } from '@prorobotech/openapi-k8s-toolkit' - import { useNavigate } from 'react-router-dom' - import { useSelector, useDispatch } from 'react-redux' - import { RootState } from 'store/store' - import { setCluster } from 'store/cluster/cluster/cluster' - import { Styled } from './styled' -+import { -+ BASE_PROJECTS_API_GROUP, -+ BASE_PROJECTS_VERSION, -+ BASE_PROJECTS_RESOURCE_NAME, -+} from 'constants/customizationApiGroupAndVersion' - - export const ListInsideClusterAndNs: FC = () => { - const clusterList = useSelector((state: RootState) => state.clusterList.clusterList) -@@ -17,9 +22,11 @@ export const ListInsideClusterAndNs: FC = () => { - const [selectedCluster, setSelectedCluster] = useState() - const [selectedNamespace, setSelectedNamespace] = useState() - -- const namespacesData = useBuiltinResources({ -+ const namespacesData = useApiResources({ - clusterName: selectedCluster || '', -- typeName: 'namespaces', -+ apiGroup: BASE_PROJECTS_API_GROUP, -+ apiVersion: BASE_PROJECTS_VERSION, -+ typeName: BASE_PROJECTS_RESOURCE_NAME, - limit: null, - isEnabled: selectedCluster !== undefined, - }) -diff --git a/src/hooks/useNavSelectorInside.ts b/src/hooks/useNavSelectorInside.ts -index 5736e2b..1ec0f71 100644 ---- a/src/hooks/useNavSelectorInside.ts -+++ b/src/hooks/useNavSelectorInside.ts -@@ -1,6 +1,11 @@ --import { TClusterList, TSingleResource, useBuiltinResources } from '@prorobotech/openapi-k8s-toolkit' -+import { TClusterList, TSingleResource, useApiResources } from '@prorobotech/openapi-k8s-toolkit' - import { useSelector } from 'react-redux' - import { RootState } from 'store/store' -+import { -+ BASE_PROJECTS_API_GROUP, -+ BASE_PROJECTS_VERSION, -+ BASE_PROJECTS_RESOURCE_NAME, -+} from 'constants/customizationApiGroupAndVersion' - - const mappedClusterToOptionInSidebar = ({ name }: TClusterList[number]): { value: string; label: string } => ({ - value: name, -@@ -15,9 +20,11 @@ const mappedNamespaceToOptionInSidebar = ({ metadata }: TSingleResource): { valu - export const useNavSelectorInside = (clusterName?: string) => { - const clusterList = useSelector((state: RootState) => state.clusterList.clusterList) - -- const { data: namespaces } = useBuiltinResources({ -+ const { data: namespaces } = useApiResources({ - clusterName: clusterName || '', -- typeName: 'namespaces', -+ apiGroup: BASE_PROJECTS_API_GROUP, -+ apiVersion: BASE_PROJECTS_VERSION, -+ typeName: BASE_PROJECTS_RESOURCE_NAME, - limit: null, - isEnabled: Boolean(clusterName), - }) -diff --git a/src/utils/getBacklink.ts b/src/utils/getBacklink.ts -index a862354..f24e2bc 100644 ---- a/src/utils/getBacklink.ts -+++ b/src/utils/getBacklink.ts -@@ -28,7 +28,7 @@ export const getFormsBackLink = ({ - } - - if (namespacesMode) { -- return `${baseprefix}/${clusterName}/builtin-table/namespaces` -+ return `${baseprefix}/${clusterName}/api-table/core.cozystack.io/v1alpha1/tenantnamespaces` - } - - if (possibleProject) { -@@ -64,7 +64,7 @@ export const getTablesBackLink = ({ - } - - if (namespacesMode) { -- return `${baseprefix}/${clusterName}/builtin-table/namespaces` -+ return `${baseprefix}/${clusterName}/api-table/core.cozystack.io/v1alpha1/tenantnamespaces` - } - - if (possibleProject) { diff --git a/packages/system/dashboard/images/openapi-ui/openapi-ui/patches/remove-inside-link.diff b/packages/system/dashboard/images/openapi-ui/openapi-ui/patches/remove-inside-link.diff deleted file mode 100644 index b131b53d..00000000 --- a/packages/system/dashboard/images/openapi-ui/openapi-ui/patches/remove-inside-link.diff +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/src/components/organisms/Header/organisms/User/User.tsx b/src/components/organisms/Header/organisms/User/User.tsx -index efe7ac3..80b715c 100644 ---- a/src/components/organisms/Header/organisms/User/User.tsx -+++ b/src/components/organisms/Header/organisms/User/User.tsx -@@ -23,10 +23,6 @@ export const User: FC = () => { - // key: '1', - // label: , - // }, -- { -- key: '2', -- label:
navigate(`${baseprefix}/inside/clusters`)}>Inside
, -- }, - { - key: '3', - label: ( diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml index 36554996..96550a35 100644 --- a/packages/system/dashboard/templates/configmap.yaml +++ b/packages/system/dashboard/templates/configmap.yaml @@ -1,9 +1,9 @@ {{- $brandingConfig:= lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} -{{- $tenantText := "v0.37.5" }} +{{- $tenantText := "latest" }} {{- $footerText := "Cozystack" }} {{- $titleText := "Cozystack Dashboard" }} -{{- $logoText := "false" }} +{{- $logoText := "" }} {{- $logoSvg := "PHN2ZyB3aWR0aD0iMTUwIiBoZWlnaHQ9IjMwIiB2aWV3Qm94PSIwIDAgMTUwIDMwIiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxwYXRoIGQ9Ik0xMzMuMzMxMDkgMjIuMzczOTg3VjQuNzk1Mjc2OWgyLjA0NDUyVjEyLjc3Mzg5aC4wNDk5bDguNTI3NzEtNy45NzkxNjcyaDIuNjE4MjdsLTkuNzc0NjQgOS4xMDExNTgyLjAyNDktMS4wOTcwNTkgMTAuMjk4MjQgOS41NzQ4ODloLTIuNjkyNzlsLTkuMDAxNjktOC4yNzgzNjNoLS4wNDk5djguMjc4MzYzem0tOS4xNzIzNi4yMjQzOTljLTEuNzI4NjkuMC0zLjIwODA1LS4zNjU2ODYtNC40MzgxLTEuMDk3MDU5LTEuMjMwNTktLjczMTM3My0yLjE3ODA0LTEuNzcwMjU0LTIuODQyOTMtMy4xMTY2NDUtLjY0ODI3LTEuMzQ2NjY3LS45NzIzOS0yLjk1MDk3OC0uOTcyMzktNC44MTI2NTQuMC0xLjg2MTY3Ny4zMjQxMi0zLjQ1NzM5OS45NzIzOS00Ljc4NzQ0NS42NjQ4OS0xLjM0NjM5MDYgMS42MTIzNC0yLjM4NTI3MjUgMi44NDI2Ni0zLjExNjkyMjQgMS4yMzAwMy0uNzMxMzcyOSAyLjcwOTQxLTEuMDk3MDU5MiA0LjQzODM3LTEuMDk3MDU5MiAxLjIxMzQyLjAgMi4zMzU0MS4xOTExNTQzIDMuMzY2MjYuNTczNDYyOCAxLjAzMDU3LjM4MjMwODUgMS44OTQ5My45MzkxNDkxIDIuNTkzMDUgMS42NzA1MjE5bC0uNzk3ODYgMS42NzA1MjE5Yy0uNzY0NjItLjcxNDc1LTEuNTYyNDgtMS4yMzAwMzYtMi4zOTM1OS0xLjU0NTg1NjEtLjgxNDQ3LS4zMzI0NDIxLTEuNzIwMzgtLjQ5ODY2MzItMi43MTc3MS0uNDk4NjYzMi0xLjk3ODU5LjAtMy40OTEyLjYyMzMyOS00LjUzODM4IDEuODY5OTg4My0xLjA0NzIxIDEuMjQ2NjU3LTEuNTcwOCAzLjAwMDU2Ni0xLjU3MDggNS4yNjE0NTEuMCAyLjI2MDYwNi41MjM1OSA0LjAyMjU0OSAxLjU3MDggNS4yODYxMDggMS4wNDcxOCAxLjI0NjY1NyAyLjU1OTc5IDEuODY5OTg2IDQuNTM4MDkgMS44Njk5ODYuOTk3MzQuMCAxLjkwMzI0LS4xNTc5MDkgMi43MTc3My0uNDczNzMuODMxMzgtLjMzMjQ0MiAxLjYyOTI0LS44NTYwMzggMi4zOTM4Ni0xLjU3MDc4OWwuNzk3ODYgMS42NzA1MjJjLS42OTgxMi43MTQ3NTEtMS41NjI0OCAxLjI3MTg2OS0yLjU5MzA1IDEuNjcwNzk5LTEuMDMwNTguMzgyMzA5LTIuMTUyNTcuNTczNDYyLTMuMzY1OTcuNTczNDYyek05Ni45ODQ2MzEgMjIuMzczOTg3IDEwNC43Mzk0IDQuNzk0OTk5OWgxLjc0NTMzbDcuNzU0NzYgMTcuNTc4OTg3MWgtMi4xMTkzMmwtMi4xNjkxOS01LjAxMTg0MS45OTczMy41MjM1OTVoLTEwLjcyMjA5bDEuMDIyMjctLjUyMzU5NS0yLjE0NDI1NCA1LjAxMTg0MXptOC42MDI0OTktMTUuMTg1NDAzNC00LjAxNDI0IDkuNDUwNTAwNC0uNTk4NC0uNDczNzNoOS4yMjU1NWwtLjU0ODUzLjQ3MzczLTQuMDE0MjUtOS40NTA1MDA0ek04OS44OTM5MjEgMjIuMzczOTg3VjYuNTY1NTMxNkg4My41MTAyMDJWNC43OTUyNzY5aDE0LjgzNjMzVjYuNTY1NTMxNkg5MS45NjMzNjZWMjIuMzc0MjY1eiIgZmlsbD17dG9rZW4uY29sb3JUZXh0fT48L3BhdGg+CiAgPHBhdGggZD0ibTY3Ljg1NDM4NSA0Ljc3MzExNDJoMTQuMDgwODd2MS43NjAwMDQyaC0xNC4wODA4N3ptMCAxNS44NDA4Njk4aDE0LjA4MDg3djEuNzYwMDAzaC0xNC4wODA4N3ptMTQuMDgwODctNy45MjA0MzVoLTE0LjA4MDg3djEuNzYwMDA1aDE0LjA4MDg3eiIgZmlsbD17dG9rZW4uY29sb3JUZXh0fT48L3BhdGg+CiAgPHBhdGggZD0ibTU3LjY2NDQ3MyAyMi4zNzM5ODd2LTkuMTAxMTU4bC40NDg4MDQgMS40MjExOTEtNy4xODEzMDktOS44OTkwMjAxaDIuMzkzODYxbDUuNjYwMTA5IDcuODI5NTY3MWgtLjUyMzYwNmw1LjY2MDM5MS03LjgyOTU2NzFoMi4zMTg3ODdsLTcuMTU2MzczIDkuODk4NzQyMS40MjQxNC0xLjQyMTE4OXY5LjEwMTE1OHptLTIwLjE4ODEwMi4wVjIwLjg1MzA2NUw0OC4xNDg1OTYgNS43NjczOTMydi43OTc4NjEzSDM3LjQ3NjM3MVY0Ljc5NDk5OTlINTAuMDY4NDVWNi4zMTU5MjI4TDM5LjM5NjUwMSAyMS4zNzY2NjF2LS43NzI5MjdoMTEuMDIxMjl2MS43NzAyNTN6bS0xMC4zOTYyOTguMjI0Mzk5Yy0xLjIxMzQxNC4wLTIuMzE5MDYyLS4yMDc3NzYtMy4zMTYzODktLjYyMzMyOC0uOTk3MzI3LS40MzIxNzUtMS44NDUwNTUtMS4wMzg4ODItMi41NDMxODQtMS44MjAxMjEtLjY5ODQwNi0uNzgxMjM5LTEuMjM4NjI0LTEuNzI4Ny0xLjYyMDkzMy0yLjg0MjY1OC0uMzY1Njg2LTEuMTEzNjgyLS41NDg1MjktMi4zNjAzMzktLjU0ODUyOS0zLjc0MDI1MS4wLTEuMzk2MjU3LjE4Mjg0My0yLjY0MjkxNy41NDg1MjktMy43NDAyNTIuMzgyMzA5LTEuMTEzNjgyLjkyMjUyNy0yLjA1MjgzMDkgMS42MjA2NTYtMi44MTc0NDc1LjY5ODEyOS0uNzgxMjM5MiAxLjUzNzU0NS0xLjM3OTkxMjEgMi41MTgyNS0xLjc5NTQ2NDguOTk3NjA0LS40MzIxNzQ5IDIuMTExMjg3LS42NDgyNjIzIDMuMzQxNi0uNjQ4MjYyMyAxLjI0NjY1Ny4wIDIuMzYwMzM5LjIwNzc3NjMgMy4zNDEwNDQuNjIzMzI5MS45OTczMjcuNDE1NTUyNyAxLjg0NTA1NSAxLjAxMzk0ODYgMi41NDM0NTkgMS43OTUxODc3LjcxNDc1MS43ODEyMzk4IDEuMjU0OTY5IDEuNzI4Njk5OCAxLjYyMDY1NSAyLjg0MjY1NzguMzgyMzEgMS4wOTcwNTkuNTczNDY0IDIuMzM1NDA2LjU3MzQ2NCAzLjcxNTA0Mi4wIDEuMzk2NTMzLS4xOTExNTQgMi42NTE3NzktLjU3MzQ2NCAzLjc2NTQ2MS0uMzgyMzA4IDEuMTEzNjgyLS45MjI1MjYgMi4wNjExNDItMS42MjA2NTUgMi44NDIzODFzLTEuNTQ1ODU2IDEuMzg3OTQ2LTIuNTQzMTgzIDEuODIwMzk4Yy0uOTgwNzA0LjQxNTU1Mi0yLjA5NDY2My42MjMzMjgtMy4zNDEzMi42MjMzMjh6bTAtMS44MjAxMmMxLjI2MzI3OS4wIDIuMzI3MDk0LS4yODI1NzYgMy4xOTE0NDMtLjg0NzcyOC44ODA5NzMtLjU2NTE1MiAxLjU1NDE2OS0xLjM4Nzk0NiAyLjAxOTU4OC0yLjQ2ODY2LjQ2NTY5Ni0xLjA4MDQzNy42OTg0MDYtMi4zNzY5NjEuNjk4NDA2LTMuODg5ODUuMC0xLjUyOTIzNC0uMjMyNzEtMi44MjU3NTgtLjY5ODEyOS0zLjg4OTg1MS0uNDY1NDE5LTEuMDYzODE1LTEuMTM4NjE0LTEuODc4Mjk3OC0yLjAxOTU4Ny0yLjQ0MzQ1LS44NjQzNS0uNTY1MTUxOC0xLjkyODQ0Mi0uODQ3NzI3Ni0zLjE5MTcyMS0uODQ3NzI3Ni0xLjIzMDAzOC4wLTIuMjg1ODE4LjI4MjU3NTgtMy4xNjY3OTEuODQ3NzI3Ni0uODY0MzUuNTY1MTUyMi0xLjUyOTIzNCAxLjM4Nzk0Ni0xLjk5NDY1MyAyLjQ2ODM4My0uNDY1NDE5IDEuMDYzODE1LS42OTgxMjkgMi4zNTIwMjktLjY5ODEyOSAzLjg2NDY0MS4wIDEuNTEyODg5LjIzMjcxIDIuODA5NjkuNjk4MTI5IDMuODkwMTI3LjQ2NTQxOSAxLjA2MzgxNSAxLjEzMDMwMyAxLjg4NjYwOSAxLjk5NDY1MyAyLjQ2ODM4My44ODA5NzMuNTY1MTUxIDEuOTM2NDc4Ljg0NzcyNyAzLjE2NjUxMy44NDc3Mjd6bS0xNi4wNDE3MjQgMS44MjAxMmMtMS43Mjg2OTgxLjAtMy4yMDgzNDE3LS4zNjU2ODYtNC40Mzg2NTYxLTEuMDk3MDU5QzUuMzY5NjU3MSAyMC43Njk5NTQgNC40MjIxOTY2IDE5LjczMTA3MyAzLjc1NzMxMzEgMTguMzg0NjgyYy0uNjQ4MjYzLTEuMzQ2NjY3LS45NzIzOTM2LTIuOTUwOTc4LS45NzIzOTM2LTQuODEyNjU0LjAtMS44NjE2NzcuMzI0MTMwNi0zLjQ1NzM5OS45NzIzOTM2LTQuNzg3NDQ1LjY2NDg4MzUtMS4zNDYzOTA2IDEuNjEyMzQ0LTIuMzg1MjcyNSAyLjg0MjM3OTgtMy4xMTY5MjI0QzcuODI5NzI5OCA0LjkzNjI4NzcgOS4zMDkzNzM0IDQuNTcwNjAxNCAxMS4wMzgzNDkgNC41NzA2MDE0YzEuMjEzNDE0LjAgMi4zMzU0MDguMTkxMTU0MyAzLjM2NTk3OC41NzM0NjI4IDEuMDMwNTcyLjM4MjMwODUgMS44OTQ5MjIuOTM5MTQ5MSAyLjU5MzMyNiAxLjY3MDUyMTlMMTYuMTk5NzkxIDguNDg1MTA4QzE1LjQzNTE3NSA3Ljc3MDM1OCAxNC42MzczMTMgNy4yNTUwNzIgMTMuODA2MjA5IDYuOTM5MjUxOSAxMi45OTE0NDcgNi42MDY4MDk4IDEyLjA4NTU0MyA2LjQ0MDU4ODcgMTEuMDg4MjE2IDYuNDQwNTg4N2MtMS45NzgwMzA0LjAtMy40OTA5MTg4LjYyMzMyOS00LjUzODM4OTIgMS44Njk5ODgzLTEuMDQ3MTkyNyAxLjI0NjY1Ny0xLjU3MDc4ODYgMy4wMDA1NjYtMS41NzA3ODg2IDUuMjYxNDUxLjAgMi4yNjA2MDYuNTIzNTk1OSA0LjAyMjU0OSAxLjU3MDc4ODYgNS4yODYxMDggMS4wNDcxOTI5IDEuMjQ2NjU3IDIuNTYwMDgyMyAxLjg2OTk4NiA0LjUzODM4OTIgMS44Njk5ODYuOTk3MzI3LjAgMS45MDMyMzEtLjE1NzkwOSAyLjcxNzcxNS0uNDczNzMuODMxMTA2LS4zMzI0NDIgMS42Mjg5NjgtLjg1NjAzOCAyLjM5MzU4NC0xLjU3MDc4OWwuNzk4MTM4IDEuNjcwNTIyYy0uNjk4MTI4LjcxNDc1MS0xLjU2MjQ3OCAxLjI3MTg2OS0yLjU5MzA0OCAxLjY3MDc5OS0xLjAzMDU3Mi4zODIzMDktMi4xNTI4NDIuNTczNDYyLTMuMzY2MjU2LjU3MzQ2MnoiIGZpbGw9e3Rva2VuLmNvbG9yVGV4dH0+PC9wYXRoPgo8L3N2Zz4K" }} {{- $iconSvg := "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgd2lkdGg9IjkxIgogICBoZWlnaHQ9IjkxIgogICB2aWV3Qm94PSIwIDAgNjguMjUwMDI0IDY4LjI1MDAyNCIKICAgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgbWVldCIKICAgdmVyc2lvbj0iMS4xIgogICBpZD0ic3ZnODI2IgogICBzb2RpcG9kaTpkb2NuYW1lPSJmYXZpY29uLnN2ZyIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMS4xLjEgKGMzMDg0ZWYsIDIwMjEtMDktMjIpIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxkZWZzCiAgICAgaWQ9ImRlZnM4MzAiIC8+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJuYW1lZHZpZXc4MjgiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZWNoZWNrZXJib2FyZD0iMCIKICAgICBzaG93Z3JpZD0iZmFsc2UiCiAgICAgaW5rc2NhcGU6em9vbT0iMC43NzAzNTc0MSIKICAgICBpbmtzY2FwZTpjeD0iNDM2LjgxMDIzIgogICAgIGlua3NjYXBlOmN5PSI1NDEuOTU2MjMiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxNzIwIgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzODciCiAgICAgaW5rc2NhcGU6d2luZG93LXg9IjE3MjAiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjI1IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjAiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnODI2IiAvPgogIDxyZWN0CiAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC42MTc5MDUiCiAgICAgaWQ9InJlY3Q5MzgiCiAgICAgd2lkdGg9IjY4LjI1MDAyMyIKICAgICBoZWlnaHQ9IjY4LjI1MDAyMyIKICAgICB4PSIwIgogICAgIHk9Ii0xLjc3NjM1NjhlLTE1IiAvPgogIDxwYXRoCiAgICAgZmlsbC1ydWxlPSJldmVub2RkIgogICAgIGNsaXAtcnVsZT0iZXZlbm9kZCIKICAgICBkPSJtIDE2LjYwMTU5OCwxMy45MjY5MSBjIDAsLTEuMjgwMTE1IDEuMDE1MDUxLC0yLjMxNzg2MSAyLjI2NzQyNCwtMi4zMTc4NjEgaCAzMS43NDM5MzcgYyAxLjI1MjM3OCwwIDIuMjY3NDIsMS4wMzc3NDYgMi4yNjc0MiwyLjMxNzg2MSB2IDAgYyAwLDEuMjgwMTMzIC0xLjAxNTA0MiwyLjMxNzg3IC0yLjI2NzQyLDIuMzE3ODcgSCAxOC44NjkwMjIgYyAtMS4yNTIzNzMsMCAtMi4yNjc0MjQsLTEuMDM3NzM3IC0yLjI2NzQyNCwtMi4zMTc4NyB6IG0gMCw0MS43MjE1NzIgYyAwLC0xLjI4MDA4MSAxLjAxNTA1MSwtMi4zMTc4NjUgMi4yNjc0MjQsLTIuMzE3ODY1IGggMzEuNzQzOTM3IGMgMS4yNTIzNzgsMCAyLjI2NzQyLDEuMDM3Nzg0IDIuMjY3NDIsMi4zMTc4NjUgdiAwIGMgMCwxLjI4MDE1OCAtMS4wMTUwNDIsMi4zMTc4NjYgLTIuMjY3NDIsMi4zMTc4NjYgSCAxOC44NjkwMjIgYyAtMS4yNTIzNzMsMCAtMi4yNjc0MjQsLTEuMDM3NzA4IC0yLjI2NzQyNCwtMi4zMTc4NjYgeiBtIDM2LjI3ODc4MSwtMjAuODYwOCBjIDAsLTEuMjgwMDggLTEuMDE1MDQyLC0yLjMxNzg2NSAtMi4yNjc0MiwtMi4zMTc4NjUgSCAxOC44NjkwMjIgYyAtMS4yNTIzNzMsMCAtMi4yNjc0MjQsMS4wMzc3ODUgLTIuMjY3NDI0LDIuMzE3ODY1IHYgMCBjIDAsMS4yODAxNTggMS4wMTUwNTEsMi4zMTc4NjYgMi4yNjc0MjQsMi4zMTc4NjYgaCAzMS43NDM5MzcgYyAxLjI1MjM3OCwwIDIuMjY3NDIsLTEuMDM3NzA4IDIuMjY3NDIsLTIuMzE3ODY2IHoiCiAgICAgZmlsbD0iI2ZmZmZmZiIKICAgICBpZD0icGF0aDg0MCIKICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjAuNzY0MTYzIiAvPgo8L3N2Zz4K" }} @@ -16,9 +16,9 @@ metadata: app.kubernetes.io/instance: incloud-web app.kubernetes.io/name: web data: - TENANT_TEXT: {{ $brandingConfig | dig "data" "tenantText" $tenantText | quote }} + CUSTOM_TENANT_TEXT: {{ $brandingConfig | dig "data" "tenantText" $tenantText | quote }} FOOTER_TEXT: {{ $brandingConfig | dig "data" "footerText" $footerText | quote }} TITLE_TEXT: {{ $brandingConfig | dig "data" "titleText" $titleText | quote }} LOGO_TEXT: {{ $brandingConfig | dig "data" "logoText" $logoText | quote }} - LOGO_SVG: {{ $brandingConfig | dig "data" "logoSvg" $logoSvg | quote }} + CUSTOM_LOGO_SVG: {{ $brandingConfig | dig "data" "logoSvg" $logoSvg | quote }} ICON_SVG: {{ $brandingConfig | dig "data" "iconSvg" $iconSvg | quote }} diff --git a/packages/system/dashboard/templates/web.yaml b/packages/system/dashboard/templates/web.yaml index 8a12d3f5..b647c743 100644 --- a/packages/system/dashboard/templates/web.yaml +++ b/packages/system/dashboard/templates/web.yaml @@ -42,10 +42,12 @@ spec: value: dashboard.cozystack.io - name: BASE_API_VERSION value: v1alpha1 + - name: BASE_NAMESPACE_FULL_PATH + value: "/apis/core.cozystack.io/v1alpha1/tenantnamespaces" - name: LOGGER - value: "TRUE" + value: "true" - name: LOGGER_WITH_HEADERS - value: "TRUE" + value: "false" - name: PORT value: "64231" image: {{ .Values.openapiUIK8sBff.image | quote }} @@ -92,6 +94,8 @@ spec: - env: - name: BASEPREFIX value: /openapi-ui + - name: HIDE_INSIDE + value: "true" - name: CUSTOMIZATION_API_GROUP value: dashboard.cozystack.io - name: CUSTOMIZATION_API_VERSION @@ -122,6 +126,12 @@ spec: value: tenantnamespaces - name: PROJECTS_VERSION value: v1alpha1 + - name: CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP + value: core.cozystack.io + - name: CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION + value: v1alpha1 + - name: CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME + value: tenantnamespaces - name: USE_NAMESPACE_NAV value: "true" - name: LOGIN_URL @@ -140,21 +150,21 @@ spec: configMapKeyRef: name: incloud-web-dashboard-config key: TITLE_TEXT - - name: TENANT_TEXT + - name: CUSTOM_TENANT_TEXT valueFrom: configMapKeyRef: name: incloud-web-dashboard-config - key: TENANT_TEXT + key: CUSTOM_TENANT_TEXT - name: LOGO_TEXT valueFrom: configMapKeyRef: name: incloud-web-dashboard-config key: LOGO_TEXT - - name: LOGO_SVG + - name: CUSTOM_LOGO_SVG valueFrom: configMapKeyRef: name: incloud-web-dashboard-config - key: LOGO_SVG + key: CUSTOM_LOGO_SVG - name: ICON_SVG valueFrom: configMapKeyRef: diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index 79e3d58b..71501fe0 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,6 +1,6 @@ openapiUI: - image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.5@sha256:5c66e9aebbf6b435b75f1607ab800028a22d0e99a1acc5cf405f07581ce414f8 + image: ghcr.io/cozystack/cozystack/openapi-ui:latest@sha256:77991f2482c0026d082582b22a8ffb191f3ba6fc948b2f125ef9b1081538f865 openapiUIK8sBff: - image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.5@sha256:194ff92c584a950f22067220436e6d8705e614422227e9cac7e889a704b709de + image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:latest@sha256:8386f0747266726afb2b30db662092d66b0af0370e3becd8bee9684125fa9cc9 tokenProxy: - image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.5@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b + image: ghcr.io/cozystack/cozystack/token-proxy:latest@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b diff --git a/pkg/apis/core/v1alpha1/register.go b/pkg/apis/core/v1alpha1/register.go index 39976e39..84923d29 100644 --- a/pkg/apis/core/v1alpha1/register.go +++ b/pkg/apis/core/v1alpha1/register.go @@ -59,11 +59,9 @@ func RegisterStaticTypes(scheme *runtime.Scheme) { &TenantNamespaceList{}, &TenantSecret{}, &TenantSecretList{}, - &TenantSecretsTable{}, - &TenantSecretsTableList{}, &TenantModule{}, &TenantModuleList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) - klog.V(1).Info("Registered static kinds: TenantNamespace, TenantSecret, TenantSecretsTable, TenantModule") + klog.V(1).Info("Registered static kinds: TenantNamespace, TenantSecret, TenantModule") } diff --git a/pkg/apis/core/v1alpha1/tenantsecretstable_types.go b/pkg/apis/core/v1alpha1/tenantsecretstable_types.go deleted file mode 100644 index 94119696..00000000 --- a/pkg/apis/core/v1alpha1/tenantsecretstable_types.go +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -package v1alpha1 - -import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - -// TenantSecretEntry represents a single key from a Secret's data. -type TenantSecretEntry struct { - Name string `json:"name,omitempty"` - Key string `json:"key,omitempty"` - Value string `json:"value,omitempty"` -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// TenantSecretsTable is a virtual, namespaced resource that exposes every key -// of Secrets labelled cozystack.io/ui=true as a separate object. -type TenantSecretsTable struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Data TenantSecretEntry `json:"data,omitempty"` -} - -// DeepCopy methods are generated by deepcopy-gen - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -type TenantSecretsTableList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []TenantSecretsTable `json:"items"` -} - -// DeepCopy methods are generated by deepcopy-gen diff --git a/pkg/apis/core/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/core/v1alpha1/zz_generated.deepcopy.go index 54a7f1e6..a19b1d1a 100644 --- a/pkg/apis/core/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/core/v1alpha1/zz_generated.deepcopy.go @@ -216,22 +216,6 @@ func (in *TenantSecret) DeepCopyObject() runtime.Object { return nil } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TenantSecretEntry) DeepCopyInto(out *TenantSecretEntry) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantSecretEntry. -func (in *TenantSecretEntry) DeepCopy() *TenantSecretEntry { - if in == nil { - return nil - } - out := new(TenantSecretEntry) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TenantSecretList) DeepCopyInto(out *TenantSecretList) { *out = *in @@ -264,63 +248,3 @@ func (in *TenantSecretList) DeepCopyObject() runtime.Object { } return nil } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TenantSecretsTable) DeepCopyInto(out *TenantSecretsTable) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Data = in.Data - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantSecretsTable. -func (in *TenantSecretsTable) DeepCopy() *TenantSecretsTable { - if in == nil { - return nil - } - out := new(TenantSecretsTable) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *TenantSecretsTable) 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 *TenantSecretsTableList) DeepCopyInto(out *TenantSecretsTableList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]TenantSecretsTable, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantSecretsTableList. -func (in *TenantSecretsTableList) DeepCopy() *TenantSecretsTableList { - if in == nil { - return nil - } - out := new(TenantSecretsTableList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *TenantSecretsTableList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index d5814ee7..ba5cee5b 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -44,7 +44,6 @@ import ( tenantmodulestorage "github.com/cozystack/cozystack/pkg/registry/core/tenantmodule" tenantnamespacestorage "github.com/cozystack/cozystack/pkg/registry/core/tenantnamespace" tenantsecretstorage "github.com/cozystack/cozystack/pkg/registry/core/tenantsecret" - tenantsecretstablestorage "github.com/cozystack/cozystack/pkg/registry/core/tenantsecretstable" ) var ( @@ -177,9 +176,6 @@ func (c completedConfig) New() (*CozyServer, error) { coreV1alpha1Storage["tenantsecrets"] = cozyregistry.RESTInPeace( tenantsecretstorage.NewREST(cli, watchCli), ) - coreV1alpha1Storage["tenantsecretstables"] = cozyregistry.RESTInPeace( - tenantsecretstablestorage.NewREST(cli, watchCli), - ) coreV1alpha1Storage["tenantmodules"] = cozyregistry.RESTInPeace( tenantmodulestorage.NewREST(cli, watchCli), ) diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index a88f259f..4202bbac 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -39,10 +39,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantNamespace": schema_pkg_apis_core_v1alpha1_TenantNamespace(ref), "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantNamespaceList": schema_pkg_apis_core_v1alpha1_TenantNamespaceList(ref), "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantSecret": schema_pkg_apis_core_v1alpha1_TenantSecret(ref), - "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantSecretEntry": schema_pkg_apis_core_v1alpha1_TenantSecretEntry(ref), "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantSecretList": schema_pkg_apis_core_v1alpha1_TenantSecretList(ref), - "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantSecretsTable": schema_pkg_apis_core_v1alpha1_TenantSecretsTable(ref), - "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantSecretsTableList": schema_pkg_apis_core_v1alpha1_TenantSecretsTableList(ref), "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.ConversionRequest": schema_pkg_apis_apiextensions_v1_ConversionRequest(ref), "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.ConversionResponse": schema_pkg_apis_apiextensions_v1_ConversionResponse(ref), "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.ConversionReview": schema_pkg_apis_apiextensions_v1_ConversionReview(ref), @@ -557,37 +554,6 @@ func schema_pkg_apis_core_v1alpha1_TenantSecret(ref common.ReferenceCallback) co } } -func schema_pkg_apis_core_v1alpha1_TenantSecretEntry(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "TenantSecretEntry represents a single key from a Secret's data.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "name": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "key": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "value": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - func schema_pkg_apis_core_v1alpha1_TenantSecretList(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -636,95 +602,6 @@ func schema_pkg_apis_core_v1alpha1_TenantSecretList(ref common.ReferenceCallback } } -func schema_pkg_apis_core_v1alpha1_TenantSecretsTable(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "TenantSecretsTable is a virtual, namespaced resource that exposes every key of Secrets labelled cozystack.io/ui=true as a separate object.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - 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{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - 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{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), - }, - }, - "data": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantSecretEntry"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantSecretEntry", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, - } -} - -func schema_pkg_apis_core_v1alpha1_TenantSecretsTableList(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - 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{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - 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{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), - }, - }, - "items": { - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantSecretsTable"), - }, - }, - }, - }, - }, - }, - Required: []string{"items"}, - }, - }, - Dependencies: []string{ - "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantSecretsTable", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, - } -} - func schema_pkg_apis_apiextensions_v1_ConversionRequest(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/pkg/registry/core/tenantsecretstable/rest.go b/pkg/registry/core/tenantsecretstable/rest.go deleted file mode 100644 index de2604ca..00000000 --- a/pkg/registry/core/tenantsecretstable/rest.go +++ /dev/null @@ -1,335 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// TenantSecretsTable registry – namespaced, read-only flattened view over -// Secrets labelled "internal.cozystack.io/tenantresource=true". Each data key is a separate object. - -package tenantsecretstable - -import ( - "context" - "encoding/base64" - "fmt" - "net/http" - "sort" - "time" - - corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metainternal "k8s.io/apimachinery/pkg/apis/meta/internalversion" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/selection" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/apiserver/pkg/registry/rest" - "sigs.k8s.io/controller-runtime/pkg/client" - - corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" -) - -const ( - tsLabelKey = corev1alpha1.TenantResourceLabelKey - tsLabelValue = corev1alpha1.TenantResourceLabelValue - kindObj = "TenantSecretsTable" - kindObjList = "TenantSecretsTableList" - singularName = "tenantsecretstable" - resourcePlural = "tenantsecretstables" -) - -type REST struct { - c client.Client - w client.WithWatch - gvr schema.GroupVersionResource -} - -func NewREST(c client.Client, w client.WithWatch) *REST { - return &REST{ - c: c, - w: w, - gvr: schema.GroupVersionResource{ - Group: corev1alpha1.GroupName, - Version: "v1alpha1", - Resource: resourcePlural, - }, - } -} - -var ( - _ rest.Getter = &REST{} - _ rest.Lister = &REST{} - _ rest.Watcher = &REST{} - _ rest.TableConvertor = &REST{} - _ rest.Scoper = &REST{} - _ rest.SingularNameProvider = &REST{} - _ rest.Storage = &REST{} -) - -func (*REST) NamespaceScoped() bool { return true } -func (*REST) New() runtime.Object { return &corev1alpha1.TenantSecretsTable{} } -func (*REST) NewList() runtime.Object { - return &corev1alpha1.TenantSecretsTableList{} -} -func (*REST) Kind() string { return kindObj } -func (r *REST) GroupVersionKind(_ schema.GroupVersion) schema.GroupVersionKind { - return r.gvr.GroupVersion().WithKind(kindObj) -} -func (*REST) GetSingularName() string { return singularName } -func (*REST) Destroy() {} - -func nsFrom(ctx context.Context) (string, error) { - ns, ok := request.NamespaceFrom(ctx) - if !ok { - return "", fmt.Errorf("namespace required") - } - return ns, nil -} - -// ----------------------- -// Get/List -// ----------------------- - -func (r *REST) Get(ctx context.Context, name string, opts *metav1.GetOptions) (runtime.Object, error) { - ns, err := nsFrom(ctx) - if err != nil { - return nil, err - } - - // We need to identify secret name and key. Iterate secrets in namespace with tenant secret label - // and return the matching composed object. - list := &corev1.SecretList{} - err = r.c.List(ctx, list, - &client.ListOptions{ - Namespace: ns, - Raw: &metav1.ListOptions{ - LabelSelector: labels.Set{tsLabelKey: tsLabelValue}.AsSelector().String(), - }, - }) - if err != nil { - return nil, err - } - for i := range list.Items { - sec := &list.Items[i] - for k, v := range sec.Data { - composed := composedName(sec.Name, k) - if composed == name { - return secretKeyToObj(sec, k, v), nil - } - } - } - return nil, apierrors.NewNotFound(r.gvr.GroupResource(), name) -} - -func (r *REST) List(ctx context.Context, opts *metainternal.ListOptions) (runtime.Object, error) { - ns, err := nsFrom(ctx) - if err != nil { - return nil, err - } - - sel := labels.NewSelector() - req, _ := labels.NewRequirement(tsLabelKey, selection.Equals, []string{tsLabelValue}) - sel = sel.Add(*req) - if opts.LabelSelector != nil { - if reqs, _ := opts.LabelSelector.Requirements(); len(reqs) > 0 { - sel = sel.Add(reqs...) - } - } - fieldSel := "" - if opts.FieldSelector != nil { - fieldSel = opts.FieldSelector.String() - } - - list := &corev1.SecretList{} - err = r.c.List(ctx, list, - &client.ListOptions{ - Namespace: ns, - Raw: &metav1.ListOptions{ - LabelSelector: labels.Set{tsLabelKey: tsLabelValue}.AsSelector().String(), - FieldSelector: fieldSel, - }, - }) - if err != nil { - return nil, err - } - - out := &corev1alpha1.TenantSecretsTableList{ - TypeMeta: metav1.TypeMeta{APIVersion: corev1alpha1.SchemeGroupVersion.String(), Kind: kindObjList}, - ListMeta: list.ListMeta, - } - - for i := range list.Items { - sec := &list.Items[i] - // Ensure stable ordering of keys - keys := make([]string, 0, len(sec.Data)) - for k := range sec.Data { - keys = append(keys, k) - } - sort.Strings(keys) - for _, k := range keys { - v := sec.Data[k] - o := secretKeyToObj(sec, k, v) - out.Items = append(out.Items, *o) - } - } - - sort.Slice(out.Items, func(i, j int) bool { return out.Items[i].Name < out.Items[j].Name }) - return out, nil -} - -// ----------------------- -// Watch -// ----------------------- - -func (r *REST) Watch(ctx context.Context, opts *metainternal.ListOptions) (watch.Interface, error) { - ns, err := nsFrom(ctx) - if err != nil { - return nil, err - } - - secList := &corev1.SecretList{} - ls := labels.Set{tsLabelKey: tsLabelValue}.AsSelector().String() - base, err := r.w.Watch(ctx, secList, &client.ListOptions{Namespace: ns, Raw: &metav1.ListOptions{ - Watch: true, - LabelSelector: ls, - ResourceVersion: opts.ResourceVersion, - }}) - if err != nil { - return nil, err - } - - ch := make(chan watch.Event) - proxy := watch.NewProxyWatcher(ch) - - go func() { - defer proxy.Stop() - for ev := range base.ResultChan() { - sec, ok := ev.Object.(*corev1.Secret) - if !ok || sec == nil { - continue - } - // Emit an event per key - for k, v := range sec.Data { - obj := secretKeyToObj(sec, k, v) - ch <- watch.Event{Type: ev.Type, Object: obj} - } - } - }() - - return proxy, nil -} - -// ----------------------- -// TableConvertor -// ----------------------- - -func (r *REST) ConvertToTable(_ context.Context, obj runtime.Object, _ runtime.Object) (*metav1.Table, error) { - now := time.Now() - row := func(o *corev1alpha1.TenantSecretsTable) metav1.TableRow { - return metav1.TableRow{ - Cells: []interface{}{o.Name, o.Data.Name, o.Data.Key, humanAge(o.CreationTimestamp.Time, now)}, - Object: runtime.RawExtension{Object: o}, - } - } - tbl := &metav1.Table{ - TypeMeta: metav1.TypeMeta{APIVersion: "meta.k8s.io/v1", Kind: "Table"}, - ColumnDefinitions: []metav1.TableColumnDefinition{ - {Name: "NAME", Type: "string"}, - {Name: "SECRET", Type: "string"}, - {Name: "KEY", Type: "string"}, - {Name: "AGE", Type: "string"}, - }, - } - switch v := obj.(type) { - case *corev1alpha1.TenantSecretsTableList: - for i := range v.Items { - tbl.Rows = append(tbl.Rows, row(&v.Items[i])) - } - tbl.ListMeta.ResourceVersion = v.ListMeta.ResourceVersion - case *corev1alpha1.TenantSecretsTable: - tbl.Rows = append(tbl.Rows, row(v)) - tbl.ListMeta.ResourceVersion = v.ResourceVersion - default: - return nil, notAcceptable{r.gvr.GroupResource(), fmt.Sprintf("unexpected %T", obj)} - } - return tbl, nil -} - -// ----------------------- -// Helpers -// ----------------------- - -func composedName(secretName, key string) string { - return secretName + "-" + key -} - -func humanAge(t time.Time, now time.Time) string { - d := now.Sub(t) - // simple human duration - if d.Hours() >= 24 { - return fmt.Sprintf("%dd", int(d.Hours()/24)) - } - if d.Hours() >= 1 { - return fmt.Sprintf("%dh", int(d.Hours())) - } - if d.Minutes() >= 1 { - return fmt.Sprintf("%dm", int(d.Minutes())) - } - return fmt.Sprintf("%ds", int(d.Seconds())) -} - -func secretKeyToObj(sec *corev1.Secret, key string, val []byte) *corev1alpha1.TenantSecretsTable { - return &corev1alpha1.TenantSecretsTable{ - TypeMeta: metav1.TypeMeta{APIVersion: corev1alpha1.SchemeGroupVersion.String(), Kind: kindObj}, - ObjectMeta: metav1.ObjectMeta{ - Name: sec.Name, - Namespace: sec.Namespace, - UID: sec.UID, - ResourceVersion: sec.ResourceVersion, - CreationTimestamp: sec.CreationTimestamp, - Labels: filterUserLabels(sec.Labels), - Annotations: sec.Annotations, - }, - Data: corev1alpha1.TenantSecretEntry{ - Name: sec.Name, - Key: key, - Value: toBase64String(val), - }, - } -} - -func filterUserLabels(m map[string]string) map[string]string { - if m == nil { - return nil - } - out := make(map[string]string, len(m)) - for k, v := range m { - if k == tsLabelKey { - continue - } - out[k] = v - } - return out -} - -func toBase64String(b []byte) string { - const enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" - // Minimal base64 encoder to avoid extra deps; for readability we could use stdlib encoding/base64 - // but keeping inline is fine; however using stdlib is clearer. - // Using stdlib: - return base64.StdEncoding.EncodeToString(b) -} - -type notAcceptable struct { - resource schema.GroupResource - message string -} - -func (e notAcceptable) Error() string { return e.message } -func (e notAcceptable) Status() metav1.Status { - return metav1.Status{ - Status: metav1.StatusFailure, - Code: http.StatusNotAcceptable, - Reason: metav1.StatusReason("NotAcceptable"), - Message: e.message, - } -} From d8c45db0755b3f9d2e3367447f2628c072294be7 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 7 Nov 2025 15:36:24 +0100 Subject: [PATCH 51/76] [cozystack-api][dashboard] Fix filtering for application services/ingresses/secrets (#1612) ## What this PR does - **[dashboard-controller] Fix labelSelectors** - **[cozystack-api] Enhance TenantSecrets filtering** - **[cozystack-api] Fix sorting for TenantSecrets** ### Release note ```release-note [cozystack-api][dashboard] Fix filtering for application services/ingresses/secrets ``` ## Summary by CodeRabbit * **Refactor** * Standardized internal configuration naming conventions across dashboard components. * Enhanced tenant secret validation and filtering logic with improved label-based operations for consistency and correctness. --- internal/controller/dashboard/factory.go | 8 +-- .../controller/dashboard/static_refactored.go | 4 +- pkg/registry/core/tenantsecret/rest.go | 70 +++++++++++++++---- 3 files changed, 61 insertions(+), 21 deletions(-) diff --git a/internal/controller/dashboard/factory.go b/internal/controller/dashboard/factory.go index c23bac4a..4e18ff09 100644 --- a/internal/controller/dashboard/factory.go +++ b/internal/controller/dashboard/factory.go @@ -221,7 +221,7 @@ func workloadsTab(kind string) map[string]any { "baseprefix": "/openapi-ui", "customizationId": "factory-details-v1alpha1.cozystack.io.workloadmonitors", "pathToItems": []any{"items"}, - "labelsSelector": map[string]any{ + "labelSelector": map[string]any{ "apps.cozystack.io/application.group": "apps.cozystack.io", "apps.cozystack.io/application.kind": kind, "apps.cozystack.io/application.name": "{reqs[0]['metadata','name']}", @@ -246,7 +246,7 @@ func servicesTab(kind string) map[string]any { "baseprefix": "/openapi-ui", "customizationId": "factory-details-v1.services", "pathToItems": []any{"items"}, - "labelsSelector": map[string]any{ + "labelSelector": map[string]any{ "apps.cozystack.io/application.group": "apps.cozystack.io", "apps.cozystack.io/application.kind": kind, "apps.cozystack.io/application.name": "{reqs[0]['metadata','name']}", @@ -272,7 +272,7 @@ func ingressesTab(kind string) map[string]any { "baseprefix": "/openapi-ui", "customizationId": "factory-details-networking.k8s.io.v1.ingresses", "pathToItems": []any{"items"}, - "labelsSelector": map[string]any{ + "labelSelector": map[string]any{ "apps.cozystack.io/application.group": "apps.cozystack.io", "apps.cozystack.io/application.kind": kind, "apps.cozystack.io/application.name": "{reqs[0]['metadata','name']}", @@ -298,7 +298,7 @@ func secretsTab(kind string) map[string]any { "baseprefix": "/openapi-ui", "customizationId": "factory-details-v1alpha1.core.cozystack.io.tenantsecrets", "pathToItems": []any{"items"}, - "labelsSelector": map[string]any{ + "labelSelector": map[string]any{ "apps.cozystack.io/application.group": "apps.cozystack.io", "apps.cozystack.io/application.kind": kind, "apps.cozystack.io/application.name": "{reqs[0]['metadata','name']}", diff --git a/internal/controller/dashboard/static_refactored.go b/internal/controller/dashboard/static_refactored.go index 31db0377..b52ea3cc 100644 --- a/internal/controller/dashboard/static_refactored.go +++ b/internal/controller/dashboard/static_refactored.go @@ -1056,7 +1056,7 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory { "clusterNamePartOfUrl": "{2}", "customizationId": "factory-kube-service-details-endpointslice", "fetchUrl": "/api/clusters/{2}/k8s/apis/discovery.k8s.io/v1/namespaces/{3}/endpointslices", - "labelsSelector": map[string]any{ + "labelSelector": map[string]any{ "kubernetes.io/service-name": "{reqsJsonPath[0]['.metadata.name']['-']}", }, "pathToItems": ".items[*].endpoints", @@ -1397,7 +1397,7 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory { "clusterNamePartOfUrl": "{2}", "customizationId": "factory-details-v1alpha1.cozystack.io.workloads", "fetchUrl": "/api/clusters/{2}/k8s/apis/cozystack.io/v1alpha1/namespaces/{3}/workloads", - "labelsSelector": map[string]any{ + "labelSelector": map[string]any{ "workloads.cozystack.io/monitor": "{reqs[0]['metadata','name']}", }, "pathToItems": []any{"items"}, diff --git a/pkg/registry/core/tenantsecret/rest.go b/pkg/registry/core/tenantsecret/rest.go index a13426e6..b1667c45 100644 --- a/pkg/registry/core/tenantsecret/rest.go +++ b/pkg/registry/core/tenantsecret/rest.go @@ -9,7 +9,7 @@ import ( "encoding/base64" "fmt" "net/http" - "sort" + "slices" "time" corev1 "k8s.io/api/core/v1" @@ -226,6 +226,9 @@ func (r *REST) Get( if err != nil { return nil, err } + if sec.Labels == nil || sec.Labels[tsLabelKey] != tsLabelValue { + return nil, apierrors.NewNotFound(r.gvr.GroupResource(), name) + } return secretToTenant(sec), nil } @@ -253,11 +256,13 @@ func (r *REST) List(ctx context.Context, opts *metainternal.ListOptions) (runtim list := &corev1.SecretList{} err = r.c.List(ctx, list, &client.ListOptions{ - Namespace: ns, + Namespace: ns, + LabelSelector: ls, Raw: &metav1.ListOptions{ LabelSelector: ls.String(), FieldSelector: fieldSel, - }}) + }, + }) if err != nil { return nil, err } @@ -273,7 +278,17 @@ func (r *REST) List(ctx context.Context, opts *metainternal.ListOptions) (runtim for i := range list.Items { out.Items = append(out.Items, *secretToTenant(&list.Items[i])) } - sort.Slice(out.Items, func(i, j int) bool { return out.Items[i].Name < out.Items[j].Name }) + slices.SortFunc(out.Items, func(a, b corev1alpha1.TenantSecret) int { + aKey := fmt.Sprintf("%s/%s", a.Namespace, a.Name) + bKey := fmt.Sprintf("%s/%s", b.Namespace, b.Name) + switch { + case aKey < bKey: + return -1 + case aKey > bKey: + return 1 + } + return 0 + }) return out, nil } @@ -291,10 +306,17 @@ func (r *REST) Update( return nil, false, err } - cur := &corev1.Secret{} - err = r.c.Get(ctx, types.NamespacedName{Namespace: ns, Name: name}, cur, &client.GetOptions{Raw: &metav1.GetOptions{}}) - if err != nil && !apierrors.IsNotFound(err) { - return nil, false, err + var cur *corev1.Secret + previous := &corev1.Secret{} + if err := r.c.Get(ctx, types.NamespacedName{Namespace: ns, Name: name}, previous, &client.GetOptions{Raw: &metav1.GetOptions{}}); err != nil { + if !apierrors.IsNotFound(err) { + return nil, false, err + } + } else { + if previous.Labels == nil || previous.Labels[tsLabelKey] != tsLabelValue { + return nil, false, apierrors.NewNotFound(r.gvr.GroupResource(), name) + } + cur = previous } newObj, err := objInfo.UpdatedObject(ctx, nil) @@ -306,7 +328,7 @@ func (r *REST) Update( newSec := tenantToSecret(in, cur) newSec.Namespace = ns if cur == nil { - if !forceCreate && err == nil { + if !forceCreate { return nil, false, apierrors.NewNotFound(r.gvr.GroupResource(), name) } err := r.c.Create(ctx, newSec, &client.CreateOptions{Raw: &metav1.CreateOptions{}}) @@ -328,6 +350,13 @@ func (r *REST) Delete( if err != nil { return nil, false, err } + current := &corev1.Secret{} + if err := r.c.Get(ctx, types.NamespacedName{Namespace: ns, Name: name}, current, &client.GetOptions{Raw: &metav1.GetOptions{}}); err != nil { + return nil, false, err + } + if current.Labels == nil || current.Labels[tsLabelKey] != tsLabelValue { + return nil, false, apierrors.NewNotFound(r.gvr.GroupResource(), name) + } err = r.c.Delete(ctx, &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Namespace: ns, Name: name}}, &client.DeleteOptions{Raw: opts}) return nil, err == nil, err } @@ -347,6 +376,13 @@ func (r *REST) Patch( if err != nil { return nil, err } + current := &corev1.Secret{} + if err := r.c.Get(ctx, types.NamespacedName{Namespace: ns, Name: name}, current, &client.GetOptions{Raw: &metav1.GetOptions{}}); err != nil { + return nil, err + } + if current.Labels == nil || current.Labels[tsLabelKey] != tsLabelValue { + return nil, apierrors.NewNotFound(r.gvr.GroupResource(), name) + } out := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Namespace: ns, @@ -383,12 +419,16 @@ func (r *REST) Watch(ctx context.Context, opts *metainternal.ListOptions) (watch } secList := &corev1.SecretList{} - ls := labels.Set{tsLabelKey: tsLabelValue}.AsSelector().String() - base, err := r.w.Watch(ctx, secList, &client.ListOptions{Namespace: ns, Raw: &metav1.ListOptions{ - Watch: true, - LabelSelector: ls, - ResourceVersion: opts.ResourceVersion, - }}) + ls := labels.Set{tsLabelKey: tsLabelValue}.AsSelector() + base, err := r.w.Watch(ctx, secList, &client.ListOptions{ + Namespace: ns, + LabelSelector: ls, + Raw: &metav1.ListOptions{ + Watch: true, + LabelSelector: ls.String(), + ResourceVersion: opts.ResourceVersion, + }, + }) if err != nil { return nil, err } From 4cbf562ae63efd836998a5b3d7e62cebf7a58737 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 7 Nov 2025 15:48:02 +0100 Subject: [PATCH 52/76] [virtual-machine] Revert per-vm network policies (#1611) Signed-off-by: Andrei Kvapil ## What this PR does Revert per-vm network policies functionality introduced by https://github.com/cozystack/cozystack/pull/1611 As it is not working as expected any way. This is temporary solution before implementing full-fledged security groups in Cozystack fixes https://github.com/cozystack/cozystack/issues/1601 alternative solution: https://github.com/cozystack/cozystack/pull/1602 ### Release note ```release-note [virtual-machine] Revert per-vm network policies ``` --- .../apps/tenant/templates/networkpolicy.yaml | 6 +---- .../virtual-machine/templates/service.yaml | 24 ------------------- .../apps/virtual-machine/templates/vm.yaml | 1 - .../apps/vm-instance/templates/service.yaml | 24 ------------------- packages/apps/vm-instance/templates/vm.yaml | 1 - 5 files changed, 1 insertion(+), 55 deletions(-) diff --git a/packages/apps/tenant/templates/networkpolicy.yaml b/packages/apps/tenant/templates/networkpolicy.yaml index 84df6d11..b66e85ff 100644 --- a/packages/apps/tenant/templates/networkpolicy.yaml +++ b/packages/apps/tenant/templates/networkpolicy.yaml @@ -20,11 +20,7 @@ metadata: name: allow-external-communication namespace: {{ include "tenant.name" . }} spec: - endpointSelector: - matchExpressions: - - key: policy.cozystack.io/allow-external-communication - operator: NotIn - values: ["false"] + endpointSelector: {} ingress: - fromEntities: - world diff --git a/packages/apps/virtual-machine/templates/service.yaml b/packages/apps/virtual-machine/templates/service.yaml index d9d77825..f212db62 100644 --- a/packages/apps/virtual-machine/templates/service.yaml +++ b/packages/apps/virtual-machine/templates/service.yaml @@ -28,27 +28,3 @@ spec: {{- end }} {{- end }} {{- end }} ---- -apiVersion: cilium.io/v2 -kind: CiliumNetworkPolicy -metadata: - name: {{ include "virtual-machine.fullname" . }} -spec: - endpointSelector: - matchLabels: - {{- include "virtual-machine.selectorLabels" . | nindent 6 }} - ingress: - - fromEntities: - - cluster - - fromEntities: - - world - {{- if eq .Values.externalMethod "PortList" }} - toPorts: - - ports: - {{- range .Values.externalPorts }} - - port: {{ quote . }} - {{- end }} - {{- end }} - egress: - - toEntities: - - world diff --git a/packages/apps/virtual-machine/templates/vm.yaml b/packages/apps/virtual-machine/templates/vm.yaml index 684e48c4..744ec220 100644 --- a/packages/apps/virtual-machine/templates/vm.yaml +++ b/packages/apps/virtual-machine/templates/vm.yaml @@ -62,7 +62,6 @@ spec: template: metadata: annotations: - policy.cozystack.io/allow-external-communication: "false" kubevirt.io/allow-pod-bridge-network-live-migration: "true" labels: {{- include "virtual-machine.labels" . | nindent 8 }} diff --git a/packages/apps/vm-instance/templates/service.yaml b/packages/apps/vm-instance/templates/service.yaml index d1ef4df9..f212db62 100644 --- a/packages/apps/vm-instance/templates/service.yaml +++ b/packages/apps/vm-instance/templates/service.yaml @@ -28,27 +28,3 @@ spec: {{- end }} {{- end }} {{- end }} ---- -apiVersion: cilium.io/v2 -kind: CiliumNetworkPolicy -metadata: - name: {{ include "virtual-machine.fullname" . }} -spec: - endpointSelector: - matchLabels: - {{- include "virtual-machine.selectorLabels" . | nindent 6 }} - ingress: - - fromEntities: - - cluster - - fromEntities: - - world - {{- if eq .Values.externalMethod "PortList" }} - toPorts: - - ports: - {{- range .Values.externalPorts }} - - port: {{ quote . }} - {{- end }} - {{- end }} - egress: - - toEntities: - - world diff --git a/packages/apps/vm-instance/templates/vm.yaml b/packages/apps/vm-instance/templates/vm.yaml index c6082a93..1674337f 100644 --- a/packages/apps/vm-instance/templates/vm.yaml +++ b/packages/apps/vm-instance/templates/vm.yaml @@ -26,7 +26,6 @@ spec: template: metadata: annotations: - policy.cozystack.io/allow-external-communication: "false" kubevirt.io/allow-pod-bridge-network-live-migration: "true" labels: {{- include "virtual-machine.labels" . | nindent 8 }} From 7ad74f04c60b1564ce7d84c203c0567e2dfa182c Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 7 Nov 2025 17:23:56 +0100 Subject: [PATCH 53/76] [dashboard-controller] Fix static resources reconciliation and showing secrets Signed-off-by: Andrei Kvapil --- internal/controller/dashboard/manager.go | 14 ++++++++++++-- internal/controller/dashboard/static_refactored.go | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/internal/controller/dashboard/manager.go b/internal/controller/dashboard/manager.go index 9c5d7e9d..12e50fbc 100644 --- a/internal/controller/dashboard/manager.go +++ b/internal/controller/dashboard/manager.go @@ -15,6 +15,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" + managerpkg "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/reconcile" ) @@ -53,10 +54,19 @@ func NewManager(c client.Client, scheme *runtime.Scheme) *Manager { } func (m *Manager) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). + if err := ctrl.NewControllerManagedBy(mgr). Named("dashboard-reconciler"). For(&cozyv1alpha1.CozystackResourceDefinition{}). - Complete(m) + Complete(m); err != nil { + return err + } + + return mgr.Add(managerpkg.RunnableFunc(func(ctx context.Context) error { + if !mgr.GetCache().WaitForCacheSync(ctx) { + return fmt.Errorf("dashboard static resources cache sync failed") + } + return m.ensureStaticResources(ctx) + })) } func (m *Manager) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { diff --git a/internal/controller/dashboard/static_refactored.go b/internal/controller/dashboard/static_refactored.go index b52ea3cc..266cb6d5 100644 --- a/internal/controller/dashboard/static_refactored.go +++ b/internal/controller/dashboard/static_refactored.go @@ -178,7 +178,7 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid createCustomColumnWithJsonPath("Name", ".metadata.name", "Secret", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-secret-details/{reqsJsonPath[0]['.metadata.name']['-']}"), createFlatMapColumn("Data", ".data"), createStringColumn("Key", "_flatMapData_Key"), - createSecretBase64Column("Value", "_flatMapData_Value"), + createSecretBase64Column("Value", "._flatMapData_Value"), createTimestampColumn("Created", ".metadata.creationTimestamp"), }), From cd3ea570daa8bb78895b69cfe25c235e4ee7bf41 Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Tue, 28 Oct 2025 18:28:03 +0300 Subject: [PATCH 54/76] [api,lineage] Ensure node-local traffic Since 0.37, many requests to the k8s API now go through a mutating webhook (lineage-controller-webhook). Since the lineage webhook makes multiple requests to the k8s API and, indirectly, to the Cozystack API server, each request for, e.g., creating a secret now causes a lot of chatter between the webhook, the k8s API, and the Cozystack API. When this happens cross-node or, worse yet, cross-zone, this can blow up the latency for simple requests. This patch changes the Cozystack API to a DaemonSet targetting controlplane nodes, configures its service for an `Local` internal traffic policy and adds environment variables indicating that the k8s API server is to be found at :6443, **not only for the Cozystack API, but also for the lineage-controller-webhook.** This is a valid configuration in most scenarios, including the default installation method on top of Talos Linux in Cozystack, however, if this is not valid in your environment, you must now set the values `.lineageControllerWebhook.localK8sAPIEndpoint.enabled` and `.cozystackAPI.localK8sAPIEndpoint.enabled` to `false` in the respective system Helm releases. ```release-note [api,lineage] Configure all chatter between the Lineage webhook, the Cozystack API server and the Kubernetes API server to be confined to a single controlplane node, improving k8s API latency. ``` Signed-off-by: Timofei Larkin --- .../cozystack-api/templates/apiservice.yaml | 6 ++- .../cozystack-api/templates/certmanager.yaml | 45 +++++++++++++++++++ .../cozystack-api/templates/deployment.yaml | 37 ++++++++++++++- .../cozystack-api/templates/service.yaml | 5 ++- packages/system/cozystack-api/values.yaml | 3 ++ .../templates/daemonset.yaml | 10 +++++ .../lineage-controller-webhook/values.yaml | 2 + 7 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 packages/system/cozystack-api/templates/certmanager.yaml diff --git a/packages/system/cozystack-api/templates/apiservice.yaml b/packages/system/cozystack-api/templates/apiservice.yaml index d0ab1185..3cd3665b 100644 --- a/packages/system/cozystack-api/templates/apiservice.yaml +++ b/packages/system/cozystack-api/templates/apiservice.yaml @@ -1,9 +1,10 @@ apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: + annotations: + cert-manager.io/inject-ca-from: "{{ .Release.Namespace }}/cozystack-api" name: v1alpha1.apps.cozystack.io spec: - insecureSkipTLSVerify: true group: apps.cozystack.io groupPriorityMinimum: 1000 versionPriority: 15 @@ -15,9 +16,10 @@ spec: apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: + annotations: + cert-manager.io/inject-ca-from: "{{ .Release.Namespace }}/cozystack-api" name: v1alpha1.core.cozystack.io spec: - insecureSkipTLSVerify: true group: core.cozystack.io groupPriorityMinimum: 1000 versionPriority: 15 diff --git a/packages/system/cozystack-api/templates/certmanager.yaml b/packages/system/cozystack-api/templates/certmanager.yaml new file mode 100644 index 00000000..def27bd1 --- /dev/null +++ b/packages/system/cozystack-api/templates/certmanager.yaml @@ -0,0 +1,45 @@ +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: cozystack-api-selfsigned + namespace: {{ .Release.Namespace }} +spec: + selfSigned: {} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: cozystack-api-ca + namespace: {{ .Release.Namespace }} +spec: + secretName: cozystack-api-ca + duration: 43800h # 5 years + commonName: cozystack-api-ca + issuerRef: + name: cozystack-api-selfsigned + isCA: true +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: cozystack-api-ca + namespace: {{ .Release.Namespace }} +spec: + ca: + secretName: cozystack-api-ca +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: cozystack-api + namespace: {{ .Release.Namespace }} +spec: + secretName: cozystack-api-cert + duration: 8760h + renewBefore: 720h + issuerRef: + name: cozystack-api-ca + commonName: cozystack-api + dnsNames: + - cozystack-api + - cozystack-api.{{ .Release.Namespace }}.svc diff --git a/packages/system/cozystack-api/templates/deployment.yaml b/packages/system/cozystack-api/templates/deployment.yaml index 46779d2b..1a63a0e0 100644 --- a/packages/system/cozystack-api/templates/deployment.yaml +++ b/packages/system/cozystack-api/templates/deployment.yaml @@ -1,12 +1,18 @@ apiVersion: apps/v1 +{{- if .Values.cozystackAPI.localK8sAPIEndpoint.enabled }} +kind: DaemonSet +{{- else }} kind: Deployment +{{- end }} metadata: name: cozystack-api namespace: cozy-system labels: app: cozystack-api spec: - replicas: 2 + {{- if not .Values.cozystackAPI.localK8sAPIEndpoint.enabled }} + replicas: {{ .Values.cozystackAPI.replicas }} + {{- end }} selector: matchLabels: app: cozystack-api @@ -16,6 +22,35 @@ spec: app: cozystack-api spec: serviceAccountName: cozystack-api + {{- if .Values.cozystackAPI.localK8sAPIEndpoint.enabled }} + nodeSelector: + node-role.kubernetes.io/control-plane: "" + {{- end }} containers: - name: cozystack-api + args: + - --tls-cert-file=/tmp/cozystack-api-certs/tls.crt + - --tls-private-key-file=/tmp/cozystack-api-certs/tls.key + {{- if .Values.cozystackAPI.localK8sAPIEndpoint.enabled }} + env: + - name: KUBERNETES_SERVICE_HOST + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: KUBERNETES_SERVICE_PORT + value: "6443" + {{- end }} image: "{{ .Values.cozystackAPI.image }}" + ports: + - containerPort: 443 + name: https + volumeMounts: + - name: cozystack-api-certs + mountPath: /tmp/cozystack-api-certs + readOnly: true + volumes: + - name: cozystack-api-certs + secret: + secretName: cozystack-api-cert + defaultMode: 0400 diff --git a/packages/system/cozystack-api/templates/service.yaml b/packages/system/cozystack-api/templates/service.yaml index 2dcd618b..abe67abc 100644 --- a/packages/system/cozystack-api/templates/service.yaml +++ b/packages/system/cozystack-api/templates/service.yaml @@ -4,9 +4,12 @@ metadata: name: cozystack-api namespace: cozy-system spec: + {{- if .Values.cozystackAPI.localK8sAPIEndpoint.enabled }} + internalTrafficPolicy: Local + {{- end }} ports: - port: 443 protocol: TCP - targetPort: 443 + targetPort: https selector: app: cozystack-api diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index 2928457d..59cf0f98 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,2 +1,5 @@ cozystackAPI: image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.5@sha256:1166252a96f14f4bcf4369577151aa3c372dabf171da9a8dbd28bab81889ac87 + localK8sAPIEndpoint: + enabled: true + replicas: 2 diff --git a/packages/system/lineage-controller-webhook/templates/daemonset.yaml b/packages/system/lineage-controller-webhook/templates/daemonset.yaml index 177bcd8b..22074e1d 100644 --- a/packages/system/lineage-controller-webhook/templates/daemonset.yaml +++ b/packages/system/lineage-controller-webhook/templates/daemonset.yaml @@ -26,6 +26,16 @@ spec: containers: - name: lineage-controller-webhook image: "{{ .Values.lineageControllerWebhook.image }}" + {{- if .Values.lineageControllerWebhook.localK8sAPIEndpoint.enabled }} + env: + - name: KUBERNETES_SERVICE_HOST + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: KUBERNETES_SERVICE_PORT + value: "6443" + {{- end }} args: {{- if .Values.lineageControllerWebhook.debug }} - --zap-log-level=debug diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index 53570a7c..d04d71c6 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,3 +1,5 @@ lineageControllerWebhook: image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.5@sha256:df3bd847e9a733a9e9e4b4ebb6a48a95405c68c663837a72f613ace2904242bd debug: false + localK8sAPIEndpoint: + enabled: true From ad117ecf5ac2fa8fa2bc34ad1309d56197b1b768 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 7 Nov 2025 22:47:30 +0100 Subject: [PATCH 55/76] [cozystack-controller] improve API tests Signed-off-by: Andrei Kvapil --- hack/e2e-install-cozystack.bats | 2 +- hack/e2e-test-openapi.bats | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hack/e2e-install-cozystack.bats b/hack/e2e-install-cozystack.bats index 50b6a071..da132132 100644 --- a/hack/e2e-install-cozystack.bats +++ b/hack/e2e-install-cozystack.bats @@ -118,7 +118,7 @@ EOF } @test "Check Cozystack API service" { - kubectl wait --for=condition=Available apiservices/v1alpha1.apps.cozystack.io --timeout=2m + kubectl wait --for=condition=Available apiservices/v1alpha1.apps.cozystack.io apiservices/v1alpha1.core.cozystack.io --timeout=2m } @test "Configure Tenant and wait for applications" { diff --git a/hack/e2e-test-openapi.bats b/hack/e2e-test-openapi.bats index 7e3cc992..aaddbe84 100644 --- a/hack/e2e-test-openapi.bats +++ b/hack/e2e-test-openapi.bats @@ -9,6 +9,7 @@ @test "Test OpenAPI v3 endpoint" { kubectl get -v7 --raw '/openapi/v3/apis/apps.cozystack.io/v1alpha1' > /dev/null + kubectl get -v7 --raw '/openapi/v3/apis/core.cozystack.io/v1alpha1' > /dev/null } @test "Test OpenAPI v2 endpoint (protobuf)" { From b5984e764bc8f23f158a69867778fdbe70547265 Mon Sep 17 00:00:00 2001 From: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> Date: Fri, 7 Nov 2025 22:00:21 +0000 Subject: [PATCH 56/76] Prepare release v0.37.6 Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> --- packages/core/installer/values.yaml | 2 +- packages/core/testing/values.yaml | 2 +- packages/extra/bootbox/images/matchbox.tag | 2 +- packages/extra/seaweedfs/images/objectstorage-sidecar.tag | 2 +- packages/system/bucket/images/s3manager.tag | 2 +- packages/system/cozystack-api/values.yaml | 2 +- packages/system/cozystack-controller/values.yaml | 4 ++-- packages/system/dashboard/templates/configmap.yaml | 2 +- packages/system/dashboard/values.yaml | 6 +++--- packages/system/kamaji/values.yaml | 4 ++-- packages/system/kubeovn-plunger/values.yaml | 2 +- packages/system/kubeovn-webhook/values.yaml | 2 +- packages/system/kubeovn/values.yaml | 2 +- packages/system/lineage-controller-webhook/values.yaml | 2 +- packages/system/objectstorage-controller/values.yaml | 2 +- packages/system/seaweedfs/values.yaml | 2 +- 16 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index 5d9da6d8..ad0ffe74 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:v0.37.5@sha256:b821a5375271a4192af8d63da5281f8f994831085bd99155665742a13da0c35e + image: ghcr.io/cozystack/cozystack/installer:v0.37.6@sha256:713030f2dfd27162b9e04b9c7b80c956142421a698f4ceef4a47ca7d42112341 diff --git a/packages/core/testing/values.yaml b/packages/core/testing/values.yaml index 33f32e35..7e2f947e 100755 --- a/packages/core/testing/values.yaml +++ b/packages/core/testing/values.yaml @@ -1,2 +1,2 @@ e2e: - image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.5@sha256:16c3c05956cb5a69bcff4f18fff9ba0d19b41b88c1cb01c013877ba90f613dc6 + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.6@sha256:474f5d58ec971a09eb6e89aad141313fb9bd319e1d49eacb1962b55a1a6870df diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index d2a8945d..b41aefb9 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v0.37.5@sha256:6a53b95bc53ed79d7f5bb4fe1c4f3f4f789238e7e91ec2ce8df66ce3b4970891 +ghcr.io/cozystack/cozystack/matchbox:v0.37.6@sha256:c01357aa1d7234c05775cc7f33009b03f7dc46e635d950233608841ede96cc77 diff --git a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag index e3303ab7..98483588 100644 --- a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag +++ b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.5@sha256:ac6380462d791bae88a1dc842ec5b2e6d7e1054c2255614e573c3997df64b463 +ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.6@sha256:0a6e11b8ef513e32fc73d2e413613103bd782ed1141b250c6c8641014eab845b diff --git a/packages/system/bucket/images/s3manager.tag b/packages/system/bucket/images/s3manager.tag index 3f1d8278..ca5d5b36 100644 --- a/packages/system/bucket/images/s3manager.tag +++ b/packages/system/bucket/images/s3manager.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:a5bb5014842d3deb551c707552721c2cfe8f6211f9fc8bc060f1bbf79a36e47e +ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:b9353e9d59e4c8e74134d63544dfdccea6d9dc9cdba8d8fc6570660b17ec1b59 diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index 59cf0f98..90b80630 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,5 +1,5 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.5@sha256:1166252a96f14f4bcf4369577151aa3c372dabf171da9a8dbd28bab81889ac87 + image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.6@sha256:d4f461af111e1b68d67d80fc598b75171b72239ac195dc8ea522bddd0ed76561 localK8sAPIEndpoint: enabled: true replicas: 2 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index 999cbb18..48b6da36 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,6 +1,6 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.5@sha256:0d339b30ce2d07634dd19176e6966c5bd722872b12e47176b4243abb5704a11f + image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.6@sha256:5b8d29e210c476a9d59dc2c17440678cde8bf8870bc44fd5ad419e134ee20e48 debug: false disableTelemetry: false - cozystackVersion: "v0.37.5" + cozystackVersion: "v0.37.6" cozystackAPIKind: "DaemonSet" diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml index 96550a35..1d9e3a72 100644 --- a/packages/system/dashboard/templates/configmap.yaml +++ b/packages/system/dashboard/templates/configmap.yaml @@ -1,6 +1,6 @@ {{- $brandingConfig:= lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} -{{- $tenantText := "latest" }} +{{- $tenantText := "v0.37.6" }} {{- $footerText := "Cozystack" }} {{- $titleText := "Cozystack Dashboard" }} {{- $logoText := "" }} diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index 71501fe0..f5b825c4 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,6 +1,6 @@ openapiUI: - image: ghcr.io/cozystack/cozystack/openapi-ui:latest@sha256:77991f2482c0026d082582b22a8ffb191f3ba6fc948b2f125ef9b1081538f865 + image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.6@sha256:e38725a9dfb0908c9360ff866b7ade03be75f6fc16517f0a825dc6a38bb7b182 openapiUIK8sBff: - image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:latest@sha256:8386f0747266726afb2b30db662092d66b0af0370e3becd8bee9684125fa9cc9 + image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.6@sha256:f1ae05b525e2d1a0098261638be52fa3c186935b4ef9207a2a74bd131c6cb1e8 tokenProxy: - image: ghcr.io/cozystack/cozystack/token-proxy:latest@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b + image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.6@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b diff --git a/packages/system/kamaji/values.yaml b/packages/system/kamaji/values.yaml index 23305230..77fce917 100644 --- a/packages/system/kamaji/values.yaml +++ b/packages/system/kamaji/values.yaml @@ -3,7 +3,7 @@ kamaji: deploy: false image: pullPolicy: IfNotPresent - tag: v0.37.5@sha256:9d076f9a6cfcf25a22a1d366ff7129439688ae8cb07f5a81eab77df3968155ef + tag: v0.37.6@sha256:912674a7ca09b745cd7921661bfe3ae8c66b6d0d5a0d842a3219e0997349a905 repository: ghcr.io/cozystack/cozystack/kamaji resources: limits: @@ -13,4 +13,4 @@ kamaji: cpu: 100m memory: 100Mi extraArgs: - - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.5@sha256:9d076f9a6cfcf25a22a1d366ff7129439688ae8cb07f5a81eab77df3968155ef + - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.6@sha256:912674a7ca09b745cd7921661bfe3ae8c66b6d0d5a0d842a3219e0997349a905 diff --git a/packages/system/kubeovn-plunger/values.yaml b/packages/system/kubeovn-plunger/values.yaml index 0bbeb83d..2ea0e52d 100644 --- a/packages/system/kubeovn-plunger/values.yaml +++ b/packages/system/kubeovn-plunger/values.yaml @@ -1,4 +1,4 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.5@sha256:3443a6ddc9a1e087b27f21937385f40699cdf1763ae7e2350f13610fecb1195c +image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.6@sha256:d66c3b2f5a39d7b72a05138fdf238fa814f9ddeb0011956ab693cdffd13a39b7 ovnCentralName: ovn-central diff --git a/packages/system/kubeovn-webhook/values.yaml b/packages/system/kubeovn-webhook/values.yaml index db117fc1..ba42e710 100644 --- a/packages/system/kubeovn-webhook/values.yaml +++ b/packages/system/kubeovn-webhook/values.yaml @@ -1,3 +1,3 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.5@sha256:7e63205708e607ce2cedfe2a2cafd323ca51e3ebc71244a21ff6f9016c6c87bc +image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.6@sha256:d5023bbfe524ec97bc499d853a3fe67affa9b37dd849eac521f38c651d50382c diff --git a/packages/system/kubeovn/values.yaml b/packages/system/kubeovn/values.yaml index 70e1f4eb..923f1c2b 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.5@sha256:0bbd4688ea73c6e9e08b1b3fecec39a051395fa50bf7afedbc93254cb1216df1 + tag: v1.14.5@sha256:0f9a6212c19f9f4d5ae12cd650870ba9717b9e42c71d54d2900cc411036bb053 diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index d04d71c6..2a54b988 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,5 +1,5 @@ lineageControllerWebhook: - image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.5@sha256:df3bd847e9a733a9e9e4b4ebb6a48a95405c68c663837a72f613ace2904242bd + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.6@sha256:3257848553c707171dfc10ebf9c543ef8ef730ed67f595389f8c686ca3c1c84a debug: false localK8sAPIEndpoint: enabled: true diff --git a/packages/system/objectstorage-controller/values.yaml b/packages/system/objectstorage-controller/values.yaml index 98e7e62b..a7591bdc 100644 --- a/packages/system/objectstorage-controller/values.yaml +++ b/packages/system/objectstorage-controller/values.yaml @@ -1,3 +1,3 @@ objectstorage: controller: - image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.5@sha256:7ee2109d9279c33507505f6b1a12173018749ead39229b642043b25621e63455" + image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.6@sha256:23ea3776d6359d55617bba023506581646cb1134b7e72869adbbd90d08c21d81" diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index c7c6bb94..ed00141c 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -124,7 +124,7 @@ seaweedfs: bucketClassName: "seaweedfs" region: "" sidecar: - image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.5@sha256:ac6380462d791bae88a1dc842ec5b2e6d7e1054c2255614e573c3997df64b463" + image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.6@sha256:0a6e11b8ef513e32fc73d2e413613103bd782ed1141b250c6c8641014eab845b" certificates: commonName: "SeaweedFS CA" ipAddresses: [] From ff89f4c390b02b96552ac0693294a33de5b8b7c2 Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Wed, 12 Nov 2025 14:09:37 +0300 Subject: [PATCH 57/76] [rbac] Fix permissions for high-privilege users ## What this PR does This patch grants "admin" permissions to super-admins, "use" permissions to admins and super-admins, "view" permissions to "use"-privileged users, admins, and super-admins. Previously lower-privileged roles were not assigned to higher-privileged users, so a viewer could excercise their basic read-only permissions which were not available to high-privilege users. This patch corrects the template function used to generate subjects in rolebindings, fixing the issue. ### Release note ```release-note [rbac] Fix issue of privileged users not having low-privilege read-only permissions. ``` Signed-off-by: Timofei Larkin (cherry picked from commit 7ddd9cf4a86d10dc32e4a45ea1db89109475d375) --- packages/apps/tenant/templates/tenant.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/apps/tenant/templates/tenant.yaml b/packages/apps/tenant/templates/tenant.yaml index 571a989d..54864baa 100644 --- a/packages/apps/tenant/templates/tenant.yaml +++ b/packages/apps/tenant/templates/tenant.yaml @@ -122,7 +122,7 @@ metadata: name: {{ include "tenant.name" . }}-view namespace: {{ include "tenant.name" . }} subjects: -{{ include "cozy-lib.rbac.subjectsForTenant" (list "view" (include "tenant.name" .)) | nindent 2 }} +{{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "view" (include "tenant.name" .)) | nindent 2 }} roleRef: kind: Role name: {{ include "tenant.name" . }}-view @@ -200,7 +200,7 @@ metadata: name: {{ include "tenant.name" . }}-use namespace: {{ include "tenant.name" . }} subjects: -{{ include "cozy-lib.rbac.subjectsForTenant" (list "use" (include "tenant.name" .)) | nindent 2 }} +{{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "use" (include "tenant.name" .)) | nindent 2 }} roleRef: kind: Role name: {{ include "tenant.name" . }}-use @@ -298,7 +298,7 @@ metadata: name: {{ include "tenant.name" . }}-admin namespace: {{ include "tenant.name" . }} subjects: -{{ include "cozy-lib.rbac.subjectsForTenant" (list "admin" (include "tenant.name" .)) | nindent 2 }} +{{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "admin" (include "tenant.name" .)) | nindent 2 }} roleRef: kind: Role name: {{ include "tenant.name" . }}-admin @@ -372,7 +372,7 @@ metadata: name: {{ include "tenant.name" . }}-super-admin namespace: {{ include "tenant.name" . }} subjects: -{{ include "cozy-lib.rbac.subjectsForTenant" (list "super-admin" (include "tenant.name" .) ) | nindent 2 }} +{{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "super-admin" (include "tenant.name" .) ) | nindent 2 }} roleRef: kind: Role name: {{ include "tenant.name" . }}-super-admin From 5d6195f146d5ba0e5dd88dcedebc2849dd0715bf Mon Sep 17 00:00:00 2001 From: Nikita <166552198+nbykov0@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:13:23 +0300 Subject: [PATCH 58/76] [system] kubeovn: increase limits (#1629) ## What this PR does Increases kube-ovn-cni limits ### Release note ```release-note Increased kube-ovn-cni limits so that it is not oomkilled during startup on busy nodes. ``` (cherry picked from commit a5c9bfabeec0819311e07e7ea751e706e615a165) Signed-off-by: Timofei Larkin --- packages/system/kubeovn/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/system/kubeovn/values.yaml b/packages/system/kubeovn/values.yaml index 923f1c2b..30b3abf4 100644 --- a/packages/system/kubeovn/values.yaml +++ b/packages/system/kubeovn/values.yaml @@ -44,7 +44,7 @@ kube-ovn: memory: "50Mi" limits: cpu: "1000m" - memory: "1Gi" + memory: "2Gi" kube-ovn-pinger: requests: cpu: "10m" From 309a49d34995d9b472443a164e0182a80ebae81d Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Thu, 13 Nov 2025 16:27:30 +0300 Subject: [PATCH 59/76] [kubernetes] Cleanup loadbalancer services ## What this PR does Similar to an earlier issue with DataVolumes remaining after deleting the tenant k8s cluster using them, a similar problem is observed with LoadBalancer services consuming external IPs. This patch adds another step to the cleanup Helm hook to delete any such services. ### Release note ```release-note [kubernetes] Add a cleanup hook to delete LoadBalancer services after deleting the tenant Kubernetes cluster that they were servicing. ``` Signed-off-by: Timofei Larkin (cherry picked from commit 1651d942911aa512c166bf902350323ae957d764) --- .../templates/{csi => }/delete.yaml | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) rename packages/apps/kubernetes/templates/{csi => }/delete.yaml (73%) diff --git a/packages/apps/kubernetes/templates/csi/delete.yaml b/packages/apps/kubernetes/templates/delete.yaml similarity index 73% rename from packages/apps/kubernetes/templates/csi/delete.yaml rename to packages/apps/kubernetes/templates/delete.yaml index 53a11af7..cd16cc99 100644 --- a/packages/apps/kubernetes/templates/csi/delete.yaml +++ b/packages/apps/kubernetes/templates/delete.yaml @@ -6,11 +6,11 @@ metadata: "helm.sh/hook": post-delete "helm.sh/hook-weight": "10" "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed - name: {{ .Release.Name }}-datavolume-cleanup + name: {{ .Release.Name }}-cleanup spec: template: spec: - serviceAccountName: {{ .Release.Name }}-datavolume-cleanup + serviceAccountName: {{ .Release.Name }}-cleanup restartPolicy: Never tolerations: - key: CriticalAddonsOnly @@ -28,12 +28,17 @@ spec: -l "cluster.x-k8s.io/cluster-name={{ .Release.Name }}" --ignore-not-found=true + kubectl -n {{ .Release.Namespace }} delete services + -l "cluster.x-k8s.io/cluster-name={{ .Release.Name }}" + --field-selector spec.type=LoadBalancer + --ignore-not-found=true + --- apiVersion: v1 kind: ServiceAccount metadata: - name: {{ .Release.Name }}-datavolume-cleanup + name: {{ .Release.Name }}-cleanup annotations: helm.sh/hook: post-delete helm.sh/hook-delete-policy: before-hook-creation,hook-failed,hook-succeeded @@ -46,7 +51,7 @@ metadata: "helm.sh/hook": post-delete "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed "helm.sh/hook-weight": "5" - name: {{ .Release.Name }}-datavolume-cleanup + name: {{ .Release.Name }}-cleanup rules: - apiGroups: - "cdi.kubevirt.io" @@ -56,6 +61,14 @@ rules: - get - list - delete + - apiGroups: + - "" + resources: + - services + verbs: + - get + - list + - delete --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding @@ -64,13 +77,13 @@ metadata: "helm.sh/hook": post-delete "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed "helm.sh/hook-weight": "5" - name: {{ .Release.Name }}-datavolume-cleanup + name: {{ .Release.Name }}-cleanup roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: {{ .Release.Name }}-datavolume-cleanup + name: {{ .Release.Name }}-cleanup subjects: - kind: ServiceAccount - name: {{ .Release.Name }}-datavolume-cleanup + name: {{ .Release.Name }}-cleanup namespace: {{ .Release.Namespace }} From b69b628a692d3b4a69fe2c3cba4a75847fab8198 Mon Sep 17 00:00:00 2001 From: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:30:01 +0000 Subject: [PATCH 60/76] Prepare release v0.37.7 Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> --- packages/apps/kubernetes/images/kubevirt-csi-driver.tag | 2 +- packages/core/installer/values.yaml | 2 +- packages/core/testing/values.yaml | 2 +- packages/extra/bootbox/images/matchbox.tag | 2 +- packages/extra/seaweedfs/images/objectstorage-sidecar.tag | 2 +- packages/system/bucket/images/s3manager.tag | 2 +- packages/system/cozystack-api/values.yaml | 2 +- packages/system/cozystack-controller/values.yaml | 4 ++-- packages/system/dashboard/templates/configmap.yaml | 2 +- packages/system/dashboard/values.yaml | 6 +++--- packages/system/kamaji/values.yaml | 4 ++-- packages/system/kubeovn-plunger/values.yaml | 2 +- packages/system/kubeovn-webhook/values.yaml | 2 +- packages/system/kubeovn/values.yaml | 2 +- packages/system/kubevirt-csi-node/values.yaml | 2 +- packages/system/lineage-controller-webhook/values.yaml | 2 +- packages/system/objectstorage-controller/values.yaml | 2 +- packages/system/seaweedfs/values.yaml | 2 +- 18 files changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag index d6e3eb37..5a5f8686 100644 --- a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag +++ b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:e7c575b0068cf78fae8730fe8d1919799e93356b14f0b645789645bd975878b9 +ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:f94f034f29aecf81d34ce87efb5ef0e82afc218b809494c4b477343965594289 diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index ad0ffe74..c7e417ba 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:v0.37.6@sha256:713030f2dfd27162b9e04b9c7b80c956142421a698f4ceef4a47ca7d42112341 + image: ghcr.io/cozystack/cozystack/installer:v0.37.7@sha256:0171d184faf7ba9e5266526824465859ab21816a4cc828d7c49a7d683f372221 diff --git a/packages/core/testing/values.yaml b/packages/core/testing/values.yaml index 7e2f947e..e5360d59 100755 --- a/packages/core/testing/values.yaml +++ b/packages/core/testing/values.yaml @@ -1,2 +1,2 @@ e2e: - image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.6@sha256:474f5d58ec971a09eb6e89aad141313fb9bd319e1d49eacb1962b55a1a6870df + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.7@sha256:16ccde6e631befd4acfcb1a54a02da159b295623768c8ad4e1251f16444c5ac6 diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index b41aefb9..17ddf36a 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v0.37.6@sha256:c01357aa1d7234c05775cc7f33009b03f7dc46e635d950233608841ede96cc77 +ghcr.io/cozystack/cozystack/matchbox:v0.37.7@sha256:b4abcc0fc373429630b04d333a1775fcec2052380834e85ef0f9a8c8f696478a diff --git a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag index 98483588..6d7048b0 100644 --- a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag +++ b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.6@sha256:0a6e11b8ef513e32fc73d2e413613103bd782ed1141b250c6c8641014eab845b +ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.7@sha256:e6bc53974c2710f45f71e8796bcf348ba18eebf4358dd0a51841611724364030 diff --git a/packages/system/bucket/images/s3manager.tag b/packages/system/bucket/images/s3manager.tag index ca5d5b36..bb3c6c11 100644 --- a/packages/system/bucket/images/s3manager.tag +++ b/packages/system/bucket/images/s3manager.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:b9353e9d59e4c8e74134d63544dfdccea6d9dc9cdba8d8fc6570660b17ec1b59 +ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:c72f5d8eadc0d31fee999836e16c44890dcd88a7cf04ff5f0d4abaccc642629e diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index 90b80630..d52a51e5 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,5 +1,5 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.6@sha256:d4f461af111e1b68d67d80fc598b75171b72239ac195dc8ea522bddd0ed76561 + image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.7@sha256:d7945e20fe26ecdaa1ebd9729a095cac64391ac2a0224b459f07c5819d56ff37 localK8sAPIEndpoint: enabled: true replicas: 2 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index 48b6da36..0aa36d9d 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,6 +1,6 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.6@sha256:5b8d29e210c476a9d59dc2c17440678cde8bf8870bc44fd5ad419e134ee20e48 + image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.7@sha256:fbfaba268cddd6e66949cd56154ff408f3da83f05567f1645e0299369d51f67d debug: false disableTelemetry: false - cozystackVersion: "v0.37.6" + cozystackVersion: "v0.37.7" cozystackAPIKind: "DaemonSet" diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml index 1d9e3a72..5dc90f1a 100644 --- a/packages/system/dashboard/templates/configmap.yaml +++ b/packages/system/dashboard/templates/configmap.yaml @@ -1,6 +1,6 @@ {{- $brandingConfig:= lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} -{{- $tenantText := "v0.37.6" }} +{{- $tenantText := "v0.37.7" }} {{- $footerText := "Cozystack" }} {{- $titleText := "Cozystack Dashboard" }} {{- $logoText := "" }} diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index f5b825c4..640df87d 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,6 +1,6 @@ openapiUI: - image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.6@sha256:e38725a9dfb0908c9360ff866b7ade03be75f6fc16517f0a825dc6a38bb7b182 + image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.7@sha256:f862b100c860fba72ff9d9f2c8f53fdedf3c54be309095cd67b57d7d53335752 openapiUIK8sBff: - image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.6@sha256:f1ae05b525e2d1a0098261638be52fa3c186935b4ef9207a2a74bd131c6cb1e8 + image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.7@sha256:c5a7d369b0199b1a02ff3a9c5233835eb274b4a6253677cd5c459d4b1e88db4d tokenProxy: - image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.6@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b + image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.7@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b diff --git a/packages/system/kamaji/values.yaml b/packages/system/kamaji/values.yaml index 77fce917..d6052354 100644 --- a/packages/system/kamaji/values.yaml +++ b/packages/system/kamaji/values.yaml @@ -3,7 +3,7 @@ kamaji: deploy: false image: pullPolicy: IfNotPresent - tag: v0.37.6@sha256:912674a7ca09b745cd7921661bfe3ae8c66b6d0d5a0d842a3219e0997349a905 + tag: v0.37.7@sha256:912674a7ca09b745cd7921661bfe3ae8c66b6d0d5a0d842a3219e0997349a905 repository: ghcr.io/cozystack/cozystack/kamaji resources: limits: @@ -13,4 +13,4 @@ kamaji: cpu: 100m memory: 100Mi extraArgs: - - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.6@sha256:912674a7ca09b745cd7921661bfe3ae8c66b6d0d5a0d842a3219e0997349a905 + - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.7@sha256:912674a7ca09b745cd7921661bfe3ae8c66b6d0d5a0d842a3219e0997349a905 diff --git a/packages/system/kubeovn-plunger/values.yaml b/packages/system/kubeovn-plunger/values.yaml index 2ea0e52d..d1929605 100644 --- a/packages/system/kubeovn-plunger/values.yaml +++ b/packages/system/kubeovn-plunger/values.yaml @@ -1,4 +1,4 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.6@sha256:d66c3b2f5a39d7b72a05138fdf238fa814f9ddeb0011956ab693cdffd13a39b7 +image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.7@sha256:54dd20f8c2f027d65cb98d07ea613673e18dbd7fe49926b21988f8149f394fd9 ovnCentralName: ovn-central diff --git a/packages/system/kubeovn-webhook/values.yaml b/packages/system/kubeovn-webhook/values.yaml index ba42e710..785b53dd 100644 --- a/packages/system/kubeovn-webhook/values.yaml +++ b/packages/system/kubeovn-webhook/values.yaml @@ -1,3 +1,3 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.6@sha256:d5023bbfe524ec97bc499d853a3fe67affa9b37dd849eac521f38c651d50382c +image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.7@sha256:9ec682497e12c0109ed0a90c34c4112090da08462a09f68616933c98bb4690f2 diff --git a/packages/system/kubeovn/values.yaml b/packages/system/kubeovn/values.yaml index 30b3abf4..d03e0650 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.5@sha256:0f9a6212c19f9f4d5ae12cd650870ba9717b9e42c71d54d2900cc411036bb053 + tag: v1.14.5@sha256:fe0d5ef7e431093bb60e705105478345f08118fafbde6caa13a0f566113b3ddb diff --git a/packages/system/kubevirt-csi-node/values.yaml b/packages/system/kubevirt-csi-node/values.yaml index a626a0ed..2e593b58 100644 --- a/packages/system/kubevirt-csi-node/values.yaml +++ b/packages/system/kubevirt-csi-node/values.yaml @@ -1,3 +1,3 @@ storageClass: replicated csiDriver: - image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:e7c575b0068cf78fae8730fe8d1919799e93356b14f0b645789645bd975878b9 + image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:f94f034f29aecf81d34ce87efb5ef0e82afc218b809494c4b477343965594289 diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index 2a54b988..3d03f4fa 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,5 +1,5 @@ lineageControllerWebhook: - image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.6@sha256:3257848553c707171dfc10ebf9c543ef8ef730ed67f595389f8c686ca3c1c84a + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.7@sha256:981f76e37dd3552e895b4c477f024e8e567017b6d0eb09dadcb2958be7e42554 debug: false localK8sAPIEndpoint: enabled: true diff --git a/packages/system/objectstorage-controller/values.yaml b/packages/system/objectstorage-controller/values.yaml index a7591bdc..4e6cd13b 100644 --- a/packages/system/objectstorage-controller/values.yaml +++ b/packages/system/objectstorage-controller/values.yaml @@ -1,3 +1,3 @@ objectstorage: controller: - image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.6@sha256:23ea3776d6359d55617bba023506581646cb1134b7e72869adbbd90d08c21d81" + image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.7@sha256:eb55bf7d90d1be91dc037bfa3781a9bebf2462d4d10bce3e45b941fe3258e8bf" diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index ed00141c..0bb15f43 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -124,7 +124,7 @@ seaweedfs: bucketClassName: "seaweedfs" region: "" sidecar: - image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.6@sha256:0a6e11b8ef513e32fc73d2e413613103bd782ed1141b250c6c8641014eab845b" + image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.7@sha256:e6bc53974c2710f45f71e8796bcf348ba18eebf4358dd0a51841611724364030" certificates: commonName: "SeaweedFS CA" ipAddresses: [] From b7a809701ec94dd631c8bd9f225800f930faab62 Mon Sep 17 00:00:00 2001 From: nbykov0 <166552198+nbykov0@users.noreply.github.com> Date: Tue, 25 Nov 2025 17:18:03 +0300 Subject: [PATCH 61/76] scripts: fix 20 migration Signed-off-by: nbykov0 <166552198+nbykov0@users.noreply.github.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> (cherry picked from commit ec1a150d2cb7bfea418cea8fd3de0b8eaf3c238e) --- scripts/migrations/20 | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/scripts/migrations/20 b/scripts/migrations/20 index 1a262ea7..2b2e1530 100755 --- a/scripts/migrations/20 +++ b/scripts/migrations/20 @@ -25,10 +25,24 @@ sleep 5 cozypkg -n cozy-system -C packages/system/cozystack-resource-definition-crd apply cozystack-resource-definition-crd --plain cozypkg -n cozy-system -C packages/system/cozystack-resource-definitions apply cozystack-resource-definitions --plain cozypkg -n cozy-system -C packages/system/cozystack-api apply cozystack-api --plain +if kubectl get ds cozystack-api -n cozy-system >/dev/null 2>&1; then + echo "Waiting for cozystack-api daemonset" + kubectl rollout status ds/cozystack-api -n cozy-system --timeout=5m || exit 1 +else + echo "Waiting for cozystack-api deployment" + kubectl rollout status deploy/cozystack-api -n cozy-system --timeout=5m || exit 1 +fi + helm upgrade --install -n cozy-system cozystack-controller ./packages/system/cozystack-controller/ --take-ownership +echo "Waiting for cozystack-controller" +kubectl rollout status deploy/cozystack-controller -n cozy-system --timeout=5m || exit 1 + helm upgrade --install -n cozy-system lineage-controller-webhook ./packages/system/lineage-controller-webhook/ --take-ownership +echo "Waiting for lineage-webhook" +kubectl rollout status ds/lineage-controller-webhook -n cozy-system --timeout=5m || exit 1 sleep 5 +echo "Running lineage-webhook test" kubectl delete ns cozy-lineage-webhook-test --ignore-not-found && kubectl create ns cozy-lineage-webhook-test cleanup_test_ns() { kubectl delete ns cozy-lineage-webhook-test --ignore-not-found @@ -37,9 +51,6 @@ trap cleanup_test_ns ERR timeout 60 sh -c 'until kubectl -n cozy-lineage-webhook-test create service clusterip lineage-webhook-test --clusterip="None" --dry-run=server; do sleep 1; done' cleanup_test_ns -kubectl wait deployment/cozystack-api -n cozy-system --timeout=4m --for=condition=available || exit 1 -kubectl wait deployment/cozystack-controller -n cozy-system --timeout=4m --for=condition=available || exit 1 - timestamp=$(date --rfc-3339=ns || date) kubectl get namespace -o custom-columns=NAME:.metadata.name --no-headers | grep '^tenant-' | @@ -50,6 +61,7 @@ kubectl get namespace -o custom-columns=NAME:.metadata.name --no-headers | -n "$namespace" --all \ migration.cozystack.io="$timestamp" --overwrite || true) done + # Stamp version kubectl create configmap -n cozy-system cozystack-version \ --from-literal=version=21 --dry-run=client -o yaml | kubectl apply -f- From 5271a5c9661a120ce5055ebce610323be6fc7c9d Mon Sep 17 00:00:00 2001 From: Nikita <166552198+nbykov0@users.noreply.github.com> Date: Tue, 25 Nov 2025 16:48:26 +0300 Subject: [PATCH 62/76] [extra] ingress: rm spaces from external ip list (#1652) ## What this PR does Remove spaces while processing exposed-external-ips list in cozystack configmap as they 1) are user-specified and 2) lead to an incorrect resource being created from it. ### Release note ```release-note Remove spaces while processing exposed-external-ips list in cozystack configmap ``` --- packages/extra/ingress/templates/nginx-ingress.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/extra/ingress/templates/nginx-ingress.yaml b/packages/extra/ingress/templates/nginx-ingress.yaml index faa0b061..e28918e4 100644 --- a/packages/extra/ingress/templates/nginx-ingress.yaml +++ b/packages/extra/ingress/templates/nginx-ingress.yaml @@ -1,6 +1,6 @@ {{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} {{- $exposeIngress := index $cozyConfig.data "expose-ingress" | default "tenant-root" }} -{{- $exposeExternalIPs := (index $cozyConfig.data "expose-external-ips") | default "" }} +{{- $exposeExternalIPs := (index $cozyConfig.data "expose-external-ips") | default "" | nospace }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: From c85e3cfc51850755739309addf037b368a2ffba1 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 25 Nov 2025 14:45:50 +0100 Subject: [PATCH 63/76] [cozy-lib] Fix malformed ResourceQuota rendering for LoadBalancer services (#1642) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds special handling for raw Kubernetes ResourceQuota fields, such as `services.loadbalancers`, preventing them from being wrapped as `limits.*` or `requests.*` keys by the flatten helper. This ensures that LoadBalancer quotas render correctly in tenant specifications. ```release-note [cozy-lib] Correctly render services.loadbalancers in ResourceQuota without limits.* or requests.* prefixes. ``` ## What this PR does ### Release note ## Summary by CodeRabbit * **Refactor** * Resource flattening now handles compute and quota keys separately: compute values are sanitized/flattened, quota-like inputs are emitted directly as plain YAML. * **Documentation** * Added in-template comments and clarified examples for resource processing behavior. * **New Features** * CI now runs unit tests; new test targets and test harnesses added along with a test chart and test cases for quota handling. ✏️ Tip: You can customize this high-level summary in your review settings. --- .../library/cozy-lib/templates/_resources.tpl | 67 +++++++++++++++++-- 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/packages/library/cozy-lib/templates/_resources.tpl b/packages/library/cozy-lib/templates/_resources.tpl index f402ee02..3976f442 100644 --- a/packages/library/cozy-lib/templates/_resources.tpl +++ b/packages/library/cozy-lib/templates/_resources.tpl @@ -174,15 +174,68 @@ {{- end }} {{- define "cozy-lib.resources.flatten" -}} +{{- /* +This helper either outputs raw ResourceQuota fields (e.g., services.loadbalancers) +as-is, or flattens sanitized resource maps into limits.* / requests.* keys. + +If ALL keys in the input are recognized quota keys (pods, services.*, etc.), +the input is output directly as YAML. Otherwise, the input is treated as a +resource map and processed through sanitize + flatten. + +Do not mix quota keys and resource keys in a single call. +*/ -}} +{{- $input := index . 0 -}} +{{- $ctx := index . 1 -}} + +{{- $rawQuotaKeys := list +"pods" +"services" +"services.loadbalancers" +"services.nodeports" +"services.clusterip" +"configmaps" +"secrets" +"persistentvolumeclaims" +"replicationcontrollers" +"resourcequotas" +-}} + +{{- $computeKeys := list +"cpu" +"memory" +"ephemeral-storage" +-}} + {{- $out := dict -}} -{{- $res := include "cozy-lib.resources.sanitize" . | fromYaml -}} +{{- $computeResources := dict -}} +{{- $quotaResources := dict -}} + +{{- range $k, $v := $input }} +{{- if or (has $k $computeKeys) (hasPrefix "limits." $k) (hasPrefix "requests." $k) }} +{{- $_ := set $computeResources $k $v }} +{{- else if has $k $rawQuotaKeys }} +{{- $_ := set $quotaResources $k $v }} +{{- else }} +{{- $_ := set $computeResources $k $v }} +{{- end }} +{{- end }} + +{{- if $computeResources }} +{{- $res := include "cozy-lib.resources.sanitize" (list $computeResources (index . 1)) | fromYaml -}} {{- range $section, $values := $res }} - {{- range $k, $v := $values }} - {{- $key := printf "%s.%s" $section $k }} - {{- if ne $key "limits.storage" }} - {{- $_ := set $out $key $v }} - {{- end }} - {{- end }} +{{- range $k, $v := $values }} +{{- $key := printf "%s.%s" $section $k }} +{{- if ne $key "limits.storage" }} +{{- $_ := set $out $key $v }} {{- end }} +{{- end }} +{{- end }} +{{- end }} + +{{- range $k, $v := $quotaResources }} +{{- $_ := set $out $k $v }} +{{- end }} + {{- $out | toYaml }} + {{- end }} From 1676d34e98474177e00a7297b7669d17618aa3d1 Mon Sep 17 00:00:00 2001 From: Nikita <166552198+nbykov0@users.noreply.github.com> Date: Tue, 25 Nov 2025 16:46:07 +0300 Subject: [PATCH 64/76] Increase strimzi memory limit (#1651) ## What this PR does Increase strimzi memory limit ### Release note ```release-note Increased strimzi memory limit ``` --- packages/system/kafka-operator/values.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/system/kafka-operator/values.yaml b/packages/system/kafka-operator/values.yaml index 3e85e449..ddfa2c9b 100644 --- a/packages/system/kafka-operator/values.yaml +++ b/packages/system/kafka-operator/values.yaml @@ -1,4 +1,7 @@ strimzi-kafka-operator: watchAnyNamespace: true generateNetworkPolicy: false - kubernetesServiceDnsDomain: cozy.local \ No newline at end of file + kubernetesServiceDnsDomain: cozy.local + resources: + limits: + memory: 512Mi From ac3358593671135e991e1b781e1f5db22b2a14de Mon Sep 17 00:00:00 2001 From: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> Date: Tue, 25 Nov 2025 15:58:09 +0000 Subject: [PATCH 65/76] Prepare release v0.37.8 Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> --- packages/apps/http-cache/images/nginx-cache.tag | 2 +- packages/apps/kubernetes/images/kubevirt-csi-driver.tag | 2 +- packages/core/installer/values.yaml | 2 +- packages/core/testing/values.yaml | 2 +- packages/extra/bootbox/images/matchbox.tag | 2 +- packages/extra/seaweedfs/images/objectstorage-sidecar.tag | 2 +- packages/system/bucket/images/s3manager.tag | 2 +- packages/system/cozystack-api/values.yaml | 2 +- packages/system/cozystack-controller/values.yaml | 4 ++-- packages/system/dashboard/templates/configmap.yaml | 2 +- packages/system/dashboard/values.yaml | 6 +++--- packages/system/kamaji/values.yaml | 4 ++-- packages/system/kubeovn-plunger/values.yaml | 2 +- packages/system/kubeovn-webhook/values.yaml | 2 +- packages/system/kubeovn/values.yaml | 2 +- packages/system/kubevirt-csi-node/values.yaml | 2 +- packages/system/lineage-controller-webhook/values.yaml | 2 +- packages/system/objectstorage-controller/values.yaml | 2 +- packages/system/seaweedfs/values.yaml | 2 +- 19 files changed, 23 insertions(+), 23 deletions(-) diff --git a/packages/apps/http-cache/images/nginx-cache.tag b/packages/apps/http-cache/images/nginx-cache.tag index a5e4ca7b..185dcc66 100644 --- a/packages/apps/http-cache/images/nginx-cache.tag +++ b/packages/apps/http-cache/images/nginx-cache.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:b7633717cd7449c0042ae92d8ca9b36e4d69566561f5c7d44e21058e7d05c6d5 +ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:e0a07082bb6fc6aeaae2315f335386f1705a646c72f9e0af512aebbca5cb2b15 diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag index 5a5f8686..80d3d2e6 100644 --- a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag +++ b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:f94f034f29aecf81d34ce87efb5ef0e82afc218b809494c4b477343965594289 +ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:d5c836ba33cf5dbed7e6f866784f668f80ffe69179e7c75847b680111984eefb diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index c7e417ba..ce5418af 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:v0.37.7@sha256:0171d184faf7ba9e5266526824465859ab21816a4cc828d7c49a7d683f372221 + image: ghcr.io/cozystack/cozystack/installer:v0.37.8@sha256:5168eb06fba358c4f70b8513eb84f37d261094085b48bfbb5e862d3085d9cae8 diff --git a/packages/core/testing/values.yaml b/packages/core/testing/values.yaml index e5360d59..50ad7ed6 100755 --- a/packages/core/testing/values.yaml +++ b/packages/core/testing/values.yaml @@ -1,2 +1,2 @@ e2e: - image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.7@sha256:16ccde6e631befd4acfcb1a54a02da159b295623768c8ad4e1251f16444c5ac6 + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.8@sha256:9c2574f06ce34951a11fa0b5baacf1d94c7ca31746faf7f8e4bb48cf234804b1 diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index 17ddf36a..f9201b2e 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v0.37.7@sha256:b4abcc0fc373429630b04d333a1775fcec2052380834e85ef0f9a8c8f696478a +ghcr.io/cozystack/cozystack/matchbox:v0.37.8@sha256:2477d8a0dd96d8bda0a391a21e5d9be60bb30942b42262e8f62d4ac5bc6fb2ca diff --git a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag index 6d7048b0..92f13804 100644 --- a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag +++ b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.7@sha256:e6bc53974c2710f45f71e8796bcf348ba18eebf4358dd0a51841611724364030 +ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.8@sha256:f83ded9a7ad1f59d225e26843d063b87a488f9bae353eeb51687643354125446 diff --git a/packages/system/bucket/images/s3manager.tag b/packages/system/bucket/images/s3manager.tag index bb3c6c11..3572ee82 100644 --- a/packages/system/bucket/images/s3manager.tag +++ b/packages/system/bucket/images/s3manager.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:c72f5d8eadc0d31fee999836e16c44890dcd88a7cf04ff5f0d4abaccc642629e +ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:d427ec741da4a648478aa424b323bf6af98f5d271d532cba1e3151b94a687eae diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index d52a51e5..5402b159 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,5 +1,5 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.7@sha256:d7945e20fe26ecdaa1ebd9729a095cac64391ac2a0224b459f07c5819d56ff37 + image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.8@sha256:ea13563f31ea1ccd59825537e18eb506137e1c74521b2c7c82626d29f6a1e22c localK8sAPIEndpoint: enabled: true replicas: 2 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index 0aa36d9d..47577e65 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,6 +1,6 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.7@sha256:fbfaba268cddd6e66949cd56154ff408f3da83f05567f1645e0299369d51f67d + image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.8@sha256:784ef9b8ffb7f2b3e2cd2857b5272123263e7c2a1d614487586c53d1cc771ab2 debug: false disableTelemetry: false - cozystackVersion: "v0.37.7" + cozystackVersion: "v0.37.8" cozystackAPIKind: "DaemonSet" diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml index 5dc90f1a..ddedee7b 100644 --- a/packages/system/dashboard/templates/configmap.yaml +++ b/packages/system/dashboard/templates/configmap.yaml @@ -1,6 +1,6 @@ {{- $brandingConfig:= lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} -{{- $tenantText := "v0.37.7" }} +{{- $tenantText := "v0.37.8" }} {{- $footerText := "Cozystack" }} {{- $titleText := "Cozystack Dashboard" }} {{- $logoText := "" }} diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index 640df87d..0238be60 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,6 +1,6 @@ openapiUI: - image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.7@sha256:f862b100c860fba72ff9d9f2c8f53fdedf3c54be309095cd67b57d7d53335752 + image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.8@sha256:189dcaa749729eb42f251327e064a00dada3921887d8a3fba0116d3b63b6bd8e openapiUIK8sBff: - image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.7@sha256:c5a7d369b0199b1a02ff3a9c5233835eb274b4a6253677cd5c459d4b1e88db4d + image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.8@sha256:b90344fbe81c25d6a24bf63ae4af713c2427f4a8b9fdfd9e7a8c51675cbb1c17 tokenProxy: - image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.7@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b + image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.8@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b diff --git a/packages/system/kamaji/values.yaml b/packages/system/kamaji/values.yaml index d6052354..e262a390 100644 --- a/packages/system/kamaji/values.yaml +++ b/packages/system/kamaji/values.yaml @@ -3,7 +3,7 @@ kamaji: deploy: false image: pullPolicy: IfNotPresent - tag: v0.37.7@sha256:912674a7ca09b745cd7921661bfe3ae8c66b6d0d5a0d842a3219e0997349a905 + tag: v0.37.8@sha256:2b4b600a93acffe364997e511d77719ddc0e84687151036852cf107ef110206a repository: ghcr.io/cozystack/cozystack/kamaji resources: limits: @@ -13,4 +13,4 @@ kamaji: cpu: 100m memory: 100Mi extraArgs: - - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.7@sha256:912674a7ca09b745cd7921661bfe3ae8c66b6d0d5a0d842a3219e0997349a905 + - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.8@sha256:2b4b600a93acffe364997e511d77719ddc0e84687151036852cf107ef110206a diff --git a/packages/system/kubeovn-plunger/values.yaml b/packages/system/kubeovn-plunger/values.yaml index d1929605..93cbbbd1 100644 --- a/packages/system/kubeovn-plunger/values.yaml +++ b/packages/system/kubeovn-plunger/values.yaml @@ -1,4 +1,4 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.7@sha256:54dd20f8c2f027d65cb98d07ea613673e18dbd7fe49926b21988f8149f394fd9 +image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.8@sha256:2b4ef215c2035297cab4242df11d85b75849c68d09bdbd644f28b96b30170982 ovnCentralName: ovn-central diff --git a/packages/system/kubeovn-webhook/values.yaml b/packages/system/kubeovn-webhook/values.yaml index 785b53dd..5bde2108 100644 --- a/packages/system/kubeovn-webhook/values.yaml +++ b/packages/system/kubeovn-webhook/values.yaml @@ -1,3 +1,3 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.7@sha256:9ec682497e12c0109ed0a90c34c4112090da08462a09f68616933c98bb4690f2 +image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.8@sha256:7bfd458299a507f2cf82cddb65941ded6991fd4ba92fd46010cbc8c363126085 diff --git a/packages/system/kubeovn/values.yaml b/packages/system/kubeovn/values.yaml index d03e0650..a880aa64 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.5@sha256:fe0d5ef7e431093bb60e705105478345f08118fafbde6caa13a0f566113b3ddb + tag: v1.14.5@sha256:8ad5e8de1911f413430cf0cfd5a1667779c8586499cfd5978ffcfe56658dcbd7 diff --git a/packages/system/kubevirt-csi-node/values.yaml b/packages/system/kubevirt-csi-node/values.yaml index 2e593b58..8d2a7d45 100644 --- a/packages/system/kubevirt-csi-node/values.yaml +++ b/packages/system/kubevirt-csi-node/values.yaml @@ -1,3 +1,3 @@ storageClass: replicated csiDriver: - image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:f94f034f29aecf81d34ce87efb5ef0e82afc218b809494c4b477343965594289 + image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:d5c836ba33cf5dbed7e6f866784f668f80ffe69179e7c75847b680111984eefb diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index 3d03f4fa..ea14efdd 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,5 +1,5 @@ lineageControllerWebhook: - image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.7@sha256:981f76e37dd3552e895b4c477f024e8e567017b6d0eb09dadcb2958be7e42554 + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.8@sha256:ccea58bdcbcf2362f0ef134c8567f15dd0cad4529f5cee082f0a1b3db60dd64b debug: false localK8sAPIEndpoint: enabled: true diff --git a/packages/system/objectstorage-controller/values.yaml b/packages/system/objectstorage-controller/values.yaml index 4e6cd13b..a2d40552 100644 --- a/packages/system/objectstorage-controller/values.yaml +++ b/packages/system/objectstorage-controller/values.yaml @@ -1,3 +1,3 @@ objectstorage: controller: - image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.7@sha256:eb55bf7d90d1be91dc037bfa3781a9bebf2462d4d10bce3e45b941fe3258e8bf" + image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.8@sha256:7d37495cce46d30d4613ecfacaa7b7f140e7ea8f3dbcc3e8c976e271de6cc71b" diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index 0bb15f43..fc31789b 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -124,7 +124,7 @@ seaweedfs: bucketClassName: "seaweedfs" region: "" sidecar: - image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.7@sha256:e6bc53974c2710f45f71e8796bcf348ba18eebf4358dd0a51841611724364030" + image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.8@sha256:f83ded9a7ad1f59d225e26843d063b87a488f9bae353eeb51687643354125446" certificates: commonName: "SeaweedFS CA" ipAddresses: [] From d209a2e17d036d92e1a1e153f1584ced546e5ada Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 27 Nov 2025 12:30:46 +0100 Subject: [PATCH 66/76] [Backport release-0.37] [dashboard] Add config hash annotations to restart pods on config changes (#1665) Backport of #1662 to `release-0.38`. Signed-off-by: Andrei Kvapil --- packages/system/dashboard/templates/nginx.yaml | 2 +- packages/system/dashboard/templates/web.yaml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/system/dashboard/templates/nginx.yaml b/packages/system/dashboard/templates/nginx.yaml index a5cbebed..caa75fa7 100644 --- a/packages/system/dashboard/templates/nginx.yaml +++ b/packages/system/dashboard/templates/nginx.yaml @@ -16,7 +16,7 @@ spec: template: metadata: annotations: - checksum/configmap-configurationnginxfile: 258c66b019c8c7f4a5d0a78dfd7bf297ce486b213346fbd2879c466abfc377e0 + checksum/config: {{ include (print $.Template.BasePath "/nginx-config.yaml") . | sha256sum }} labels: app.kubernetes.io/instance: incloud-web app.kubernetes.io/name: nginx diff --git a/packages/system/dashboard/templates/web.yaml b/packages/system/dashboard/templates/web.yaml index b647c743..17bc9c78 100644 --- a/packages/system/dashboard/templates/web.yaml +++ b/packages/system/dashboard/templates/web.yaml @@ -15,7 +15,8 @@ spec: type: RollingUpdate template: metadata: - annotations: null + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} labels: app.kubernetes.io/instance: incloud-web app.kubernetes.io/name: web From 94e6d9383d263c312aa5df94e77c30d24601f0a5 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 27 Nov 2025 14:31:05 +0100 Subject: [PATCH 67/76] [dashboard] Fix loading arrays in forms when editing existing objects Signed-off-by: Andrei Kvapil --- packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile b/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile index 51444ad0..ef698698 100644 --- a/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile +++ b/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile @@ -3,7 +3,7 @@ ARG NODE_VERSION=20.18.1 FROM node:${NODE_VERSION}-alpine AS builder WORKDIR /src -ARG COMMIT_REF=ba56271739505284aee569f914fc90e6a9c670da +ARG COMMIT_REF=183dc9dcbb0f8a1833dad642c35faa385c71e58d RUN wget -O- https://github.com/PRO-Robotech/openapi-ui-k8s-bff/archive/${COMMIT_REF}.tar.gz | tar xzf - --strip-components=1 ENV PATH=/src/node_modules/.bin:$PATH From 470cb1cbe54ad52eec89220000805b1887051ac9 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 27 Nov 2025 14:32:54 +0100 Subject: [PATCH 68/76] [tenant][kubernetes] Introduce better cleanup logic (#1661) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andrei Kvapil ## What this PR does ### Release note ```release-note [tenant][kubernetes] Introduce better cleanup logic ``` ## Summary by CodeRabbit * **New Features** * Added an automated pre-delete cleanup job for tenant namespaces to remove tenant-related releases during uninstall. * **Improvements** * Cleanup now runs early in the uninstall sequence with a clearer, stepwise orchestration for resource removal. * Expanded permissions and execution allowances to enable the cleanup workflow. * Deployment annotations now use a content checksum to better detect config changes. * **Removals** * Previous teardown sequence for certain release types was removed and replaced by the new workflow. ✏️ Tip: You can customize this high-level summary in your review settings. --- .../apps/kubernetes/templates/delete.yaml | 85 ++++++++++++-- .../templates/helmreleases/delete.yaml | 104 ------------------ .../apps/tenant/templates/cleanup-job.yaml | 85 ++++++++++++++ 3 files changed, 158 insertions(+), 116 deletions(-) delete mode 100644 packages/apps/kubernetes/templates/helmreleases/delete.yaml create mode 100644 packages/apps/tenant/templates/cleanup-job.yaml diff --git a/packages/apps/kubernetes/templates/delete.yaml b/packages/apps/kubernetes/templates/delete.yaml index cd16cc99..ae581226 100644 --- a/packages/apps/kubernetes/templates/delete.yaml +++ b/packages/apps/kubernetes/templates/delete.yaml @@ -3,12 +3,15 @@ apiVersion: batch/v1 kind: Job metadata: annotations: - "helm.sh/hook": post-delete + "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 spec: template: + metadata: + labels: + policy.cozystack.io/allow-to-apiserver: "true" spec: serviceAccountName: {{ .Release.Name }}-cleanup restartPolicy: Never @@ -24,14 +27,43 @@ spec: command: - /bin/sh - -c - - kubectl -n {{ .Release.Namespace }} delete datavolumes - -l "cluster.x-k8s.io/cluster-name={{ .Release.Name }}" - --ignore-not-found=true + - | + set -e + echo "Step 1: Suspending all HelmReleases with label cozystack.io/target-cluster-name={{ .Release.Name }}" + for hr in $(kubectl -n {{ .Release.Namespace }} get helmreleases.helm.toolkit.fluxcd.io -l "cozystack.io/target-cluster-name={{ .Release.Name }}" -o name 2>/dev/null || true); do + if [ -n "$hr" ]; then + echo " Suspending $hr" + kubectl -n {{ .Release.Namespace }} patch "$hr" \ + -p '{"spec": {"suspend": true}}' \ + --type=merge --field-manager=flux-client-side-apply + fi + done - kubectl -n {{ .Release.Namespace }} delete services - -l "cluster.x-k8s.io/cluster-name={{ .Release.Name }}" - --field-selector spec.type=LoadBalancer - --ignore-not-found=true + echo "Step 2: Deleting HelmReleases with label cozystack.io/target-cluster-name={{ .Release.Name }}" + kubectl -n {{ .Release.Namespace }} delete helmreleases.helm.toolkit.fluxcd.io \ + -l "cozystack.io/target-cluster-name={{ .Release.Name }}" \ + --ignore-not-found=true --wait=true + + echo "Step 3: Deleting KamajiControlPlane {{ .Release.Name }}" + kubectl -n {{ .Release.Namespace }} delete kamajicontrolplanes.controlplane.cluster.x-k8s.io {{ .Release.Name }} \ + --ignore-not-found=true + + echo "Step 4: Deleting TenantControlPlane {{ .Release.Name }}" + kubectl -n {{ .Release.Namespace }} delete tenantcontrolplanes.kamaji.clastix.io {{ .Release.Name }} \ + --ignore-not-found=true + + echo "Step 5: Cleaning up DataVolumes" + kubectl -n {{ .Release.Namespace }} delete datavolumes \ + -l "cluster.x-k8s.io/cluster-name={{ .Release.Name }}" \ + --ignore-not-found=true + + echo "Step 6: Cleaning up LoadBalancer Services" + kubectl -n {{ .Release.Namespace }} delete services \ + -l "cluster.x-k8s.io/cluster-name={{ .Release.Name }}" \ + --field-selector spec.type=LoadBalancer \ + --ignore-not-found=true + + echo "Cleanup completed successfully" --- @@ -40,7 +72,7 @@ kind: ServiceAccount metadata: name: {{ .Release.Name }}-cleanup annotations: - helm.sh/hook: post-delete + helm.sh/hook: pre-delete helm.sh/hook-delete-policy: before-hook-creation,hook-failed,hook-succeeded helm.sh/hook-weight: "0" --- @@ -48,11 +80,39 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: annotations: - "helm.sh/hook": post-delete + "helm.sh/hook": pre-delete "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed "helm.sh/hook-weight": "5" name: {{ .Release.Name }}-cleanup rules: + - apiGroups: + - "helm.toolkit.fluxcd.io" + resources: + - helmreleases + verbs: + - get + - list + - watch + - patch + - delete + - apiGroups: + - "controlplane.cluster.x-k8s.io" + resources: + - kamajicontrolplanes + verbs: + - get + - list + - watch + - delete + - apiGroups: + - "kamaji.clastix.io" + resources: + - tenantcontrolplanes + verbs: + - get + - list + - watch + - delete - apiGroups: - "cdi.kubevirt.io" resources: @@ -60,6 +120,7 @@ rules: verbs: - get - list + - watch - delete - apiGroups: - "" @@ -68,13 +129,14 @@ rules: verbs: - get - list + - watch - delete --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: annotations: - "helm.sh/hook": post-delete + "helm.sh/hook": pre-delete "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed "helm.sh/hook-weight": "5" name: {{ .Release.Name }}-cleanup @@ -86,4 +148,3 @@ subjects: - kind: ServiceAccount name: {{ .Release.Name }}-cleanup namespace: {{ .Release.Namespace }} - diff --git a/packages/apps/kubernetes/templates/helmreleases/delete.yaml b/packages/apps/kubernetes/templates/helmreleases/delete.yaml deleted file mode 100644 index ac15be9b..00000000 --- a/packages/apps/kubernetes/templates/helmreleases/delete.yaml +++ /dev/null @@ -1,104 +0,0 @@ ---- -apiVersion: batch/v1 -kind: Job -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 }}-flux-teardown -spec: - template: - spec: - serviceAccountName: {{ .Release.Name }}-flux-teardown - restartPolicy: Never - tolerations: - - key: CriticalAddonsOnly - operator: Exists - - key: node-role.kubernetes.io/control-plane - operator: Exists - effect: "NoSchedule" - containers: - - name: kubectl - image: docker.io/clastix/kubectl:v1.32 - command: - - /bin/sh - - -c - - >- - kubectl - --namespace={{ .Release.Namespace }} - patch - helmrelease - {{ .Release.Name }}-cilium - {{ .Release.Name }}-gateway-api-crds - {{ .Release.Name }}-csi - {{ .Release.Name }}-cert-manager - {{ .Release.Name }}-cert-manager-crds - {{ .Release.Name }}-vertical-pod-autoscaler - {{ .Release.Name }}-vertical-pod-autoscaler-crds - {{ .Release.Name }}-ingress-nginx - {{ .Release.Name }}-fluxcd-operator - {{ .Release.Name }}-fluxcd - {{ .Release.Name }}-gpu-operator - {{ .Release.Name }}-velero - {{ .Release.Name }}-coredns - -p '{"spec": {"suspend": true}}' - --type=merge --field-manager=flux-client-side-apply || true ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ .Release.Name }}-flux-teardown - annotations: - helm.sh/hook: pre-delete - helm.sh/hook-delete-policy: before-hook-creation,hook-failed,hook-succeeded - helm.sh/hook-weight: "0" ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - annotations: - "helm.sh/hook": pre-install,post-install,pre-delete - "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed - "helm.sh/hook-weight": "5" - name: {{ .Release.Name }}-flux-teardown -rules: - - apiGroups: - - "helm.toolkit.fluxcd.io" - resources: - - helmreleases - verbs: - - get - - patch - resourceNames: - - {{ .Release.Name }}-cilium - - {{ .Release.Name }}-csi - - {{ .Release.Name }}-cert-manager - - {{ .Release.Name }}-cert-manager-crds - - {{ .Release.Name }}-gateway-api-crds - - {{ .Release.Name }}-vertical-pod-autoscaler - - {{ .Release.Name }}-vertical-pod-autoscaler-crds - - {{ .Release.Name }}-ingress-nginx - - {{ .Release.Name }}-fluxcd-operator - - {{ .Release.Name }}-fluxcd - - {{ .Release.Name }}-gpu-operator - - {{ .Release.Name }}-velero - - {{ .Release.Name }}-coredns - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - annotations: - helm.sh/hook: pre-delete - helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation,hook-failed - helm.sh/hook-weight: "5" - name: {{ .Release.Name }}-flux-teardown -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: {{ .Release.Name }}-flux-teardown -subjects: - - kind: ServiceAccount - name: {{ .Release.Name }}-flux-teardown - namespace: {{ .Release.Namespace }} diff --git a/packages/apps/tenant/templates/cleanup-job.yaml b/packages/apps/tenant/templates/cleanup-job.yaml new file mode 100644 index 00000000..9a1bcdd5 --- /dev/null +++ b/packages/apps/tenant/templates/cleanup-job.yaml @@ -0,0 +1,85 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "tenant.name" . }}-cleanup + namespace: {{ include "tenant.name" . }} + annotations: + helm.sh/hook: pre-delete + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + helm.sh/hook-weight: "-5" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "tenant.name" . }}-cleanup + namespace: {{ include "tenant.name" . }} + annotations: + helm.sh/hook: pre-delete + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + helm.sh/hook-weight: "-5" +rules: +- apiGroups: ["helm.toolkit.fluxcd.io"] + resources: ["helmreleases"] + verbs: ["get", "list", "delete"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "tenant.name" . }}-cleanup + namespace: {{ include "tenant.name" . }} + annotations: + helm.sh/hook: pre-delete + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + helm.sh/hook-weight: "-5" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "tenant.name" . }}-cleanup +subjects: +- kind: ServiceAccount + name: {{ include "tenant.name" . }}-cleanup + namespace: {{ include "tenant.name" . }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "tenant.name" . }}-cleanup + namespace: {{ include "tenant.name" . }} + annotations: + helm.sh/hook: pre-delete + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + helm.sh/hook-weight: "0" +spec: + ttlSecondsAfterFinished: 300 + template: + metadata: + name: {{ include "tenant.name" . }}-cleanup + labels: + policy.cozystack.io/allow-to-apiserver: "true" + spec: + serviceAccountName: {{ include "tenant.name" . }}-cleanup + restartPolicy: OnFailure + containers: + - name: cleanup + image: bitnami/kubectl:latest + command: + - /bin/bash + - -c + - | + set -e + NAMESPACE="{{ include "tenant.name" . }}" + + echo "Cleaning up HelmReleases in namespace: $NAMESPACE" + + echo "Deleting Applications" + kubectl delete helmreleases.helm.toolkit.fluxcd.io -n "$NAMESPACE" \ + -l 'cozystack.io/ui=true,internal.cozystack.io/tenantmodule!=true' \ + --ignore-not-found=true --wait=true + + echo "Deleting Tenant Modules" + kubectl delete helmreleases.helm.toolkit.fluxcd.io -n "$NAMESPACE" \ + -l 'cozystack.io/ui=true,internal.cozystack.io/tenantmodule=true' \ + --ignore-not-found=true --wait=true + + echo "Cleanup completed successfully" From 8f15a3e06ca206324a7d3db22f0cda5d6d489395 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 27 Nov 2025 14:35:07 +0100 Subject: [PATCH 69/76] [Backport release-0.37] [seaweedfs] Extended CA certificate duration to reduce disruptive CA rotations. (#1666) Backport of #1657 to `release-0.37`. Signed-off-by: Andrei Kvapil --- packages/system/seaweedfs/Makefile | 1 + .../charts/seaweedfs/templates/cert/ca-cert.yaml | 2 ++ packages/system/seaweedfs/patches/long-term-ca.diff | 13 +++++++++++++ 3 files changed, 16 insertions(+) create mode 100644 packages/system/seaweedfs/patches/long-term-ca.diff diff --git a/packages/system/seaweedfs/Makefile b/packages/system/seaweedfs/Makefile index 9d1f47cd..2344f6b5 100644 --- a/packages/system/seaweedfs/Makefile +++ b/packages/system/seaweedfs/Makefile @@ -12,6 +12,7 @@ update: sed -i.bak "/ARG VERSION/ s|=.*|=$${version}|g" images/seaweedfs/Dockerfile && \ rm -f images/seaweedfs/Dockerfile.bak patch --no-backup-if-mismatch -p4 < patches/resize-api-server-annotation.diff + patch --no-backup-if-mismatch -p4 < patches/long-term-ca.diff #patch --no-backup-if-mismatch -p4 < patches/retention-policy-delete.yaml image: diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml index 0fd6615e..f2572558 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml @@ -13,6 +13,8 @@ spec: secretName: {{ template "seaweedfs.name" . }}-ca-cert commonName: "{{ template "seaweedfs.name" . }}-root-ca" isCA: true + duration: 87600h + renewBefore: 720h issuerRef: name: {{ template "seaweedfs.name" . }}-issuer kind: Issuer diff --git a/packages/system/seaweedfs/patches/long-term-ca.diff b/packages/system/seaweedfs/patches/long-term-ca.diff new file mode 100644 index 00000000..a53d697d --- /dev/null +++ b/packages/system/seaweedfs/patches/long-term-ca.diff @@ -0,0 +1,13 @@ +diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml +index 0fd6615e..f2572558 100644 +--- a/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml ++++ b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml +@@ -13,6 +13,8 @@ spec: + secretName: {{ template "seaweedfs.name" . }}-ca-cert + commonName: "{{ template "seaweedfs.name" . }}-root-ca" + isCA: true ++ duration: 87600h ++ renewBefore: 720h + issuerRef: + name: {{ template "seaweedfs.name" . }}-issuer + kind: Issuer From c82f440ff0a88130462d8610b187c026ab030ea5 Mon Sep 17 00:00:00 2001 From: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> Date: Thu, 27 Nov 2025 13:47:48 +0000 Subject: [PATCH 70/76] Prepare release v0.37.9 Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> --- packages/apps/http-cache/images/nginx-cache.tag | 2 +- packages/core/installer/values.yaml | 2 +- packages/core/testing/values.yaml | 2 +- packages/extra/bootbox/images/matchbox.tag | 2 +- packages/extra/seaweedfs/images/objectstorage-sidecar.tag | 2 +- packages/system/bucket/images/s3manager.tag | 2 +- packages/system/cozystack-api/values.yaml | 2 +- packages/system/cozystack-controller/values.yaml | 4 ++-- packages/system/dashboard/templates/configmap.yaml | 2 +- packages/system/dashboard/values.yaml | 6 +++--- packages/system/kamaji/values.yaml | 4 ++-- packages/system/kubeovn-plunger/values.yaml | 2 +- packages/system/kubeovn-webhook/values.yaml | 2 +- packages/system/kubeovn/values.yaml | 2 +- packages/system/lineage-controller-webhook/values.yaml | 2 +- packages/system/objectstorage-controller/values.yaml | 2 +- packages/system/seaweedfs/values.yaml | 2 +- 17 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/apps/http-cache/images/nginx-cache.tag b/packages/apps/http-cache/images/nginx-cache.tag index 185dcc66..a5e4ca7b 100644 --- a/packages/apps/http-cache/images/nginx-cache.tag +++ b/packages/apps/http-cache/images/nginx-cache.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:e0a07082bb6fc6aeaae2315f335386f1705a646c72f9e0af512aebbca5cb2b15 +ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:b7633717cd7449c0042ae92d8ca9b36e4d69566561f5c7d44e21058e7d05c6d5 diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index ce5418af..b4eea1ed 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:v0.37.8@sha256:5168eb06fba358c4f70b8513eb84f37d261094085b48bfbb5e862d3085d9cae8 + image: ghcr.io/cozystack/cozystack/installer:v0.37.9@sha256:bb0e2d456e9cd21416d3989672f572e2fe7faf9aca12921368d4359c054a7044 diff --git a/packages/core/testing/values.yaml b/packages/core/testing/values.yaml index 50ad7ed6..7e765590 100755 --- a/packages/core/testing/values.yaml +++ b/packages/core/testing/values.yaml @@ -1,2 +1,2 @@ e2e: - image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.8@sha256:9c2574f06ce34951a11fa0b5baacf1d94c7ca31746faf7f8e4bb48cf234804b1 + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.9@sha256:2d7ec813f60d44db710518fa599ed45444e79943bd6f3899bf8823ce2e22b588 diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index f9201b2e..c906d12b 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v0.37.8@sha256:2477d8a0dd96d8bda0a391a21e5d9be60bb30942b42262e8f62d4ac5bc6fb2ca +ghcr.io/cozystack/cozystack/matchbox:v0.37.9@sha256:d582f3836b7e18d7ac9d5a5be865f580081cebf7904c9385be4341753236ca9e diff --git a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag index 92f13804..8c10ee89 100644 --- a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag +++ b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.8@sha256:f83ded9a7ad1f59d225e26843d063b87a488f9bae353eeb51687643354125446 +ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.9@sha256:52894e32a084c30256b0e30359c9ef66083081594486f4c8e07a614ce5236d12 diff --git a/packages/system/bucket/images/s3manager.tag b/packages/system/bucket/images/s3manager.tag index 3572ee82..820822bf 100644 --- a/packages/system/bucket/images/s3manager.tag +++ b/packages/system/bucket/images/s3manager.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:d427ec741da4a648478aa424b323bf6af98f5d271d532cba1e3151b94a687eae +ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:bb2403e2ef69eedab12f69f302ccba4cda2e430292b01d2f68280b0483e9d6d1 diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index 5402b159..929f125c 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,5 +1,5 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.8@sha256:ea13563f31ea1ccd59825537e18eb506137e1c74521b2c7c82626d29f6a1e22c + image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.9@sha256:3b29e4a1226fa73e88d67b5349369a970b01667071b4d734da6d96426ea5b154 localK8sAPIEndpoint: enabled: true replicas: 2 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index 47577e65..afc3f79e 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,6 +1,6 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.8@sha256:784ef9b8ffb7f2b3e2cd2857b5272123263e7c2a1d614487586c53d1cc771ab2 + image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.9@sha256:68cc087920f41768447bffac4d77e7b38025eee96a499fa092d1d9461bcac23a debug: false disableTelemetry: false - cozystackVersion: "v0.37.8" + cozystackVersion: "v0.37.9" cozystackAPIKind: "DaemonSet" diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml index ddedee7b..df8b0392 100644 --- a/packages/system/dashboard/templates/configmap.yaml +++ b/packages/system/dashboard/templates/configmap.yaml @@ -1,6 +1,6 @@ {{- $brandingConfig:= lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} -{{- $tenantText := "v0.37.8" }} +{{- $tenantText := "v0.37.9" }} {{- $footerText := "Cozystack" }} {{- $titleText := "Cozystack Dashboard" }} {{- $logoText := "" }} diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index 0238be60..259d1eea 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,6 +1,6 @@ openapiUI: - image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.8@sha256:189dcaa749729eb42f251327e064a00dada3921887d8a3fba0116d3b63b6bd8e + image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.9@sha256:b30be2dc65398d9f3e5caa61ac73a3da96d15324c13f5c745bf8ae9e31ce4451 openapiUIK8sBff: - image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.8@sha256:b90344fbe81c25d6a24bf63ae4af713c2427f4a8b9fdfd9e7a8c51675cbb1c17 + image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.9@sha256:a7323c618f9d85d11d6e83e6b7e6ae3cc3856676e93681fa3384bfe47fad1499 tokenProxy: - image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.8@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b + image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.9@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b diff --git a/packages/system/kamaji/values.yaml b/packages/system/kamaji/values.yaml index e262a390..882615f3 100644 --- a/packages/system/kamaji/values.yaml +++ b/packages/system/kamaji/values.yaml @@ -3,7 +3,7 @@ kamaji: deploy: false image: pullPolicy: IfNotPresent - tag: v0.37.8@sha256:2b4b600a93acffe364997e511d77719ddc0e84687151036852cf107ef110206a + tag: v0.37.9@sha256:125e4e6a8b86418e891416d29353053ab8b65182b7e443f221b557c11a385280 repository: ghcr.io/cozystack/cozystack/kamaji resources: limits: @@ -13,4 +13,4 @@ kamaji: cpu: 100m memory: 100Mi extraArgs: - - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.8@sha256:2b4b600a93acffe364997e511d77719ddc0e84687151036852cf107ef110206a + - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.9@sha256:125e4e6a8b86418e891416d29353053ab8b65182b7e443f221b557c11a385280 diff --git a/packages/system/kubeovn-plunger/values.yaml b/packages/system/kubeovn-plunger/values.yaml index 93cbbbd1..4942e1be 100644 --- a/packages/system/kubeovn-plunger/values.yaml +++ b/packages/system/kubeovn-plunger/values.yaml @@ -1,4 +1,4 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.8@sha256:2b4ef215c2035297cab4242df11d85b75849c68d09bdbd644f28b96b30170982 +image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.9@sha256:e55fe31291a4d3cab2b8b51cce36378c04f15a37b687d4f1209187d27feb4caa ovnCentralName: ovn-central diff --git a/packages/system/kubeovn-webhook/values.yaml b/packages/system/kubeovn-webhook/values.yaml index 5bde2108..bee28f7f 100644 --- a/packages/system/kubeovn-webhook/values.yaml +++ b/packages/system/kubeovn-webhook/values.yaml @@ -1,3 +1,3 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.8@sha256:7bfd458299a507f2cf82cddb65941ded6991fd4ba92fd46010cbc8c363126085 +image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.9@sha256:a2e6c6619270769d56beb1166d09fdc541a7754757d567ede558e8ebdeae397a diff --git a/packages/system/kubeovn/values.yaml b/packages/system/kubeovn/values.yaml index a880aa64..ba73c10e 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.5@sha256:8ad5e8de1911f413430cf0cfd5a1667779c8586499cfd5978ffcfe56658dcbd7 + tag: v1.14.5@sha256:f49501b3a7f74de858645ddc9484d5b65224dac51bfa0143f7979de1ff2e5073 diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index ea14efdd..e7cca5c3 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,5 +1,5 @@ lineageControllerWebhook: - image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.8@sha256:ccea58bdcbcf2362f0ef134c8567f15dd0cad4529f5cee082f0a1b3db60dd64b + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.9@sha256:5c6e7b2b7e062b88bbf946e1fb3beb1e162526077ba8635515b5b4291d1a78e2 debug: false localK8sAPIEndpoint: enabled: true diff --git a/packages/system/objectstorage-controller/values.yaml b/packages/system/objectstorage-controller/values.yaml index a2d40552..c40afa8b 100644 --- a/packages/system/objectstorage-controller/values.yaml +++ b/packages/system/objectstorage-controller/values.yaml @@ -1,3 +1,3 @@ objectstorage: controller: - image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.8@sha256:7d37495cce46d30d4613ecfacaa7b7f140e7ea8f3dbcc3e8c976e271de6cc71b" + image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.9@sha256:7d37495cce46d30d4613ecfacaa7b7f140e7ea8f3dbcc3e8c976e271de6cc71b" diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index fc31789b..e479b75c 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -124,7 +124,7 @@ seaweedfs: bucketClassName: "seaweedfs" region: "" sidecar: - image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.8@sha256:f83ded9a7ad1f59d225e26843d063b87a488f9bae353eeb51687643354125446" + image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.9@sha256:52894e32a084c30256b0e30359c9ef66083081594486f4c8e07a614ce5236d12" certificates: commonName: "SeaweedFS CA" ipAddresses: [] From eb5f5d45761f9965bd35216ab383a0db8f6a25df Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 8 Dec 2025 23:27:24 +0100 Subject: [PATCH 71/76] [dashboard] Fix CustomFormsOverride schema to nest properties under spec.properties Signed-off-by: Andrei Kvapil (cherry picked from commit 578a810413c1521ff3f0e0b70c3da80ed31d851b) --- .../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 53d4a5e72c96db70241122b23c1158d381790ef2 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 5 Dec 2025 17:18:01 +0100 Subject: [PATCH 72/76] [virtual-machine] Improve check for resizing job Signed-off-by: Andrei Kvapil (cherry picked from commit 0bab8950266b30476824feb1ef72b91007f5e8ff) --- .../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 From 1111cac7e9c8a8787bd07dffc11bd5d565ec7946 Mon Sep 17 00:00:00 2001 From: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> Date: Tue, 9 Dec 2025 16:22:46 +0000 Subject: [PATCH 73/76] Prepare release v0.37.10 Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> --- packages/apps/http-cache/images/nginx-cache.tag | 2 +- packages/apps/kubernetes/images/cluster-autoscaler.tag | 2 +- packages/apps/kubernetes/images/kubevirt-csi-driver.tag | 2 +- packages/core/installer/values.yaml | 2 +- packages/core/testing/values.yaml | 2 +- packages/extra/bootbox/images/matchbox.tag | 2 +- packages/extra/seaweedfs/images/objectstorage-sidecar.tag | 2 +- packages/system/bucket/images/s3manager.tag | 2 +- packages/system/cozystack-api/values.yaml | 2 +- packages/system/cozystack-controller/values.yaml | 4 ++-- packages/system/dashboard/templates/configmap.yaml | 2 +- packages/system/dashboard/values.yaml | 6 +++--- packages/system/kamaji/values.yaml | 4 ++-- packages/system/kubeovn-plunger/values.yaml | 2 +- packages/system/kubeovn-webhook/values.yaml | 2 +- packages/system/kubeovn/values.yaml | 2 +- packages/system/kubevirt-csi-node/values.yaml | 2 +- packages/system/lineage-controller-webhook/values.yaml | 2 +- packages/system/objectstorage-controller/values.yaml | 2 +- packages/system/seaweedfs/values.yaml | 2 +- 20 files changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/apps/http-cache/images/nginx-cache.tag b/packages/apps/http-cache/images/nginx-cache.tag index a5e4ca7b..0970e11c 100644 --- a/packages/apps/http-cache/images/nginx-cache.tag +++ b/packages/apps/http-cache/images/nginx-cache.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:b7633717cd7449c0042ae92d8ca9b36e4d69566561f5c7d44e21058e7d05c6d5 +ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:50ac1581e3100bd6c477a71161cb455a341ffaf9e5e2f6086802e4e25271e8af diff --git a/packages/apps/kubernetes/images/cluster-autoscaler.tag b/packages/apps/kubernetes/images/cluster-autoscaler.tag index d5ab33d1..56fcb024 100644 --- a/packages/apps/kubernetes/images/cluster-autoscaler.tag +++ b/packages/apps/kubernetes/images/cluster-autoscaler.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/cluster-autoscaler:0.0.0@sha256:2d39989846c3579dd020b9f6c77e6e314cc81aa344eaac0f6d633e723c17196d +ghcr.io/cozystack/cozystack/cluster-autoscaler:0.0.0@sha256:e1c0eb54d0ddadc8c7d72cee4f4282d56c957bf4ff0f62ef37db6b38dd0e8a01 diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag index 80d3d2e6..61e9f2ba 100644 --- a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag +++ b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:d5c836ba33cf5dbed7e6f866784f668f80ffe69179e7c75847b680111984eefb +ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:47396dac04a24f824f82892c90efa160539e1e0f8ac697f5dc8ecf397e1ac413 diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index b4eea1ed..5d1caa27 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:v0.37.9@sha256:bb0e2d456e9cd21416d3989672f572e2fe7faf9aca12921368d4359c054a7044 + image: ghcr.io/cozystack/cozystack/installer:v0.37.10@sha256:df2e6d4cf91636f8b6e8553fe61fdfd48945fe97f22086f5d9c9fc5bac89fd71 diff --git a/packages/core/testing/values.yaml b/packages/core/testing/values.yaml index 7e765590..2d93ec5c 100755 --- a/packages/core/testing/values.yaml +++ b/packages/core/testing/values.yaml @@ -1,2 +1,2 @@ e2e: - image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.9@sha256:2d7ec813f60d44db710518fa599ed45444e79943bd6f3899bf8823ce2e22b588 + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.37.10@sha256:0a452cc4795500b094068330c23bb3e579f0fc3fe230b9371a394c023c415249 diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index c906d12b..b02335a2 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v0.37.9@sha256:d582f3836b7e18d7ac9d5a5be865f580081cebf7904c9385be4341753236ca9e +ghcr.io/cozystack/cozystack/matchbox:v0.37.10@sha256:5ebd5dca8c4adac48362f0c11de9696ce675a7edf184029e0118351dd701c730 diff --git a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag index 8c10ee89..6fa6e9d3 100644 --- a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag +++ b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.9@sha256:52894e32a084c30256b0e30359c9ef66083081594486f4c8e07a614ce5236d12 +ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.10@sha256:233a1177f309aa159a8c4a08212dab3f992f5a2b626f86a15c8ffd44f10bf2ad diff --git a/packages/system/bucket/images/s3manager.tag b/packages/system/bucket/images/s3manager.tag index 820822bf..ec7741c2 100644 --- a/packages/system/bucket/images/s3manager.tag +++ b/packages/system/bucket/images/s3manager.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:bb2403e2ef69eedab12f69f302ccba4cda2e430292b01d2f68280b0483e9d6d1 +ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:b58f5b192d1f47026c19ad51a857e31c256a9ff46c24a5fbbfcfe4f61981b8eb diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index 929f125c..a6e2d052 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,5 +1,5 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.9@sha256:3b29e4a1226fa73e88d67b5349369a970b01667071b4d734da6d96426ea5b154 + image: ghcr.io/cozystack/cozystack/cozystack-api:v0.37.10@sha256:04772e898edbab0613ff2beb0b7d62196b47d986488ef0c67b86946b69b30f24 localK8sAPIEndpoint: enabled: true replicas: 2 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index afc3f79e..1b222742 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,6 +1,6 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.9@sha256:68cc087920f41768447bffac4d77e7b38025eee96a499fa092d1d9461bcac23a + image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.37.10@sha256:224871a6e8f7a80d2b6476b57b6176c472afe112b503a5c5bf151b945d78a407 debug: false disableTelemetry: false - cozystackVersion: "v0.37.9" + cozystackVersion: "v0.37.10" cozystackAPIKind: "DaemonSet" diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml index df8b0392..4bf69678 100644 --- a/packages/system/dashboard/templates/configmap.yaml +++ b/packages/system/dashboard/templates/configmap.yaml @@ -1,6 +1,6 @@ {{- $brandingConfig:= lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} -{{- $tenantText := "v0.37.9" }} +{{- $tenantText := "v0.37.10" }} {{- $footerText := "Cozystack" }} {{- $titleText := "Cozystack Dashboard" }} {{- $logoText := "" }} diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index 259d1eea..e1352550 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,6 +1,6 @@ openapiUI: - image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.9@sha256:b30be2dc65398d9f3e5caa61ac73a3da96d15324c13f5c745bf8ae9e31ce4451 + image: ghcr.io/cozystack/cozystack/openapi-ui:v0.37.10@sha256:73e9a77e15c9e4e8bd72a292ee6093354048ac5d06df6db8e91ec0f3de6a37f0 openapiUIK8sBff: - image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.9@sha256:a7323c618f9d85d11d6e83e6b7e6ae3cc3856676e93681fa3384bfe47fad1499 + image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.37.10@sha256:2845688891e0cf9513768aa468ff4de5b6b40e58cc763bacbfe2b417ebad1bdf tokenProxy: - image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.9@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b + image: ghcr.io/cozystack/cozystack/token-proxy:v0.37.10@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b diff --git a/packages/system/kamaji/values.yaml b/packages/system/kamaji/values.yaml index 882615f3..002fdfca 100644 --- a/packages/system/kamaji/values.yaml +++ b/packages/system/kamaji/values.yaml @@ -3,7 +3,7 @@ kamaji: deploy: false image: pullPolicy: IfNotPresent - tag: v0.37.9@sha256:125e4e6a8b86418e891416d29353053ab8b65182b7e443f221b557c11a385280 + tag: v0.37.10@sha256:98ff5a995f77465d2d97566a342fc6204eacd0b51c845a1c895276145cdf4819 repository: ghcr.io/cozystack/cozystack/kamaji resources: limits: @@ -13,4 +13,4 @@ kamaji: cpu: 100m memory: 100Mi extraArgs: - - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.9@sha256:125e4e6a8b86418e891416d29353053ab8b65182b7e443f221b557c11a385280 + - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.37.10@sha256:98ff5a995f77465d2d97566a342fc6204eacd0b51c845a1c895276145cdf4819 diff --git a/packages/system/kubeovn-plunger/values.yaml b/packages/system/kubeovn-plunger/values.yaml index 4942e1be..89d853b8 100644 --- a/packages/system/kubeovn-plunger/values.yaml +++ b/packages/system/kubeovn-plunger/values.yaml @@ -1,4 +1,4 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.9@sha256:e55fe31291a4d3cab2b8b51cce36378c04f15a37b687d4f1209187d27feb4caa +image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.37.10@sha256:d7a6835ef256de2ea241512f23eca376d425c89a8942d9285f6a060004c48f46 ovnCentralName: ovn-central diff --git a/packages/system/kubeovn-webhook/values.yaml b/packages/system/kubeovn-webhook/values.yaml index bee28f7f..4934c288 100644 --- a/packages/system/kubeovn-webhook/values.yaml +++ b/packages/system/kubeovn-webhook/values.yaml @@ -1,3 +1,3 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.9@sha256:a2e6c6619270769d56beb1166d09fdc541a7754757d567ede558e8ebdeae397a +image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.37.10@sha256:1144245e22a546f0603aed3df046feccb0fea88c1218dee40c8acbd91ddc661a diff --git a/packages/system/kubeovn/values.yaml b/packages/system/kubeovn/values.yaml index ba73c10e..bffd03fc 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.5@sha256:f49501b3a7f74de858645ddc9484d5b65224dac51bfa0143f7979de1ff2e5073 + tag: v1.14.5@sha256:665ad3f64332dc8b70337953ddb3ac72559137b4110c2ec36ba609ceded6b972 diff --git a/packages/system/kubevirt-csi-node/values.yaml b/packages/system/kubevirt-csi-node/values.yaml index 8d2a7d45..6ff9991a 100644 --- a/packages/system/kubevirt-csi-node/values.yaml +++ b/packages/system/kubevirt-csi-node/values.yaml @@ -1,3 +1,3 @@ storageClass: replicated csiDriver: - image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:d5c836ba33cf5dbed7e6f866784f668f80ffe69179e7c75847b680111984eefb + image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:47396dac04a24f824f82892c90efa160539e1e0f8ac697f5dc8ecf397e1ac413 diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index e7cca5c3..c367a33f 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,5 +1,5 @@ lineageControllerWebhook: - image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.9@sha256:5c6e7b2b7e062b88bbf946e1fb3beb1e162526077ba8635515b5b4291d1a78e2 + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.37.10@sha256:bcb95c433ce24793ce1350c4f094d9d53a7c56f5415506c88f261949da42711a debug: false localK8sAPIEndpoint: enabled: true diff --git a/packages/system/objectstorage-controller/values.yaml b/packages/system/objectstorage-controller/values.yaml index c40afa8b..13856a2f 100644 --- a/packages/system/objectstorage-controller/values.yaml +++ b/packages/system/objectstorage-controller/values.yaml @@ -1,3 +1,3 @@ objectstorage: controller: - image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.9@sha256:7d37495cce46d30d4613ecfacaa7b7f140e7ea8f3dbcc3e8c976e271de6cc71b" + image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.37.10@sha256:91ed0ba4de7958708f77427d2c752dece969236c13927c17033d792700e9c6f4" diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index e479b75c..bfe82028 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -124,7 +124,7 @@ seaweedfs: bucketClassName: "seaweedfs" region: "" sidecar: - image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.9@sha256:52894e32a084c30256b0e30359c9ef66083081594486f4c8e07a614ce5236d12" + image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.37.10@sha256:233a1177f309aa159a8c4a08212dab3f992f5a2b626f86a15c8ffd44f10bf2ad" certificates: commonName: "SeaweedFS CA" ipAddresses: [] From d60b37702a565836acfcd5226672cbebf668321a Mon Sep 17 00:00:00 2001 From: IvanHunters Date: Fri, 2 Jan 2026 17:41:42 +0300 Subject: [PATCH 74/76] add lb tests for tenant k8s Signed-off-by: IvanHunters (cherry picked from commit 5638a7eae91940f27334938e55602032ce7fc3e4) --- hack/e2e-apps/run-kubernetes.sh | 101 +++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 2 deletions(-) diff --git a/hack/e2e-apps/run-kubernetes.sh b/hack/e2e-apps/run-kubernetes.sh index 1446b093..7c7ce7b9 100644 --- a/hack/e2e-apps/run-kubernetes.sh +++ b/hack/e2e-apps/run-kubernetes.sh @@ -72,7 +72,7 @@ EOF kubectl wait --for=condition=TenantControlPlaneCreated kamajicontrolplane -n tenant-test kubernetes-${test_name} --timeout=4m # Wait for Kubernetes resources to be ready (timeout after 2 minutes) - kubectl wait tcp -n tenant-test kubernetes-${test_name} --timeout=2m --for=jsonpath='{.status.kubernetesResources.version.status}'=Ready + kubectl wait tcp -n tenant-test kubernetes-${test_name} --timeout=5m --for=jsonpath='{.status.kubernetesResources.version.status}'=Ready # Wait for all required deployments to be available (timeout after 4 minutes) kubectl wait deploy --timeout=4m --for=condition=available -n tenant-test kubernetes-${test_name} kubernetes-${test_name}-cluster-autoscaler kubernetes-${test_name}-kccm kubernetes-${test_name}-kcsi-controller @@ -87,7 +87,7 @@ EOF # Set up port forwarding to the Kubernetes API server for a 200 second timeout - bash -c 'timeout 300s kubectl port-forward service/kubernetes-'"${test_name}"' -n tenant-test '"${port}"':6443 > /dev/null 2>&1 &' + bash -c 'timeout 500s kubectl port-forward service/kubernetes-'"${test_name}"' -n tenant-test '"${port}"':6443 > /dev/null 2>&1 &' # Verify the Kubernetes version matches what we expect (retry for up to 20 seconds) timeout 20 sh -ec 'until kubectl --kubeconfig tenantkubeconfig version 2>/dev/null | grep -Fq "Server Version: ${k8s_version}"; do sleep 5; done' @@ -141,6 +141,103 @@ EOF exit 1 fi + + kubectl --kubeconfig tenantkubeconfig-${test_name} apply -f - <&2 + exit 1 +fi + + kubectl run -n tenant-test lb-check-${test_name} \ + --rm -i --restart=Never \ + --image=curlimages/curl \ + --timeout=60s \ + --command -- \ + sh -c " + for i in \$(seq 1 20); do + echo \"Attempt \$i\"; + curl -sf http://${LB_ADDR} && exit 0; + sleep 3; + done; + echo 'LoadBalancer not reachable'; + exit 1 + " + + # Cleanup + kubectl delete deployment --kubeconfig tenantkubeconfig-${test_name} "${test_name}-backend" -n tenant-test + kubectl delete service --kubeconfig tenantkubeconfig-${test_name} "${test_name}-backend" -n tenant-test + # Wait for all machine deployment replicas to be ready (timeout after 10 minutes) kubectl wait machinedeployment kubernetes-${test_name}-md0 -n tenant-test --timeout=10m --for=jsonpath='{.status.v1beta2.readyReplicas}'=2 From 4a4529ea0bb7210411b063d656665e40aeaca866 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 2 Jan 2026 21:02:06 +0100 Subject: [PATCH 75/76] fix(e2e): run LB check curl from testing environment Run curl directly from the testing container instead of creating a separate pod with kubectl run. This avoids PodSecurity policy violations and simplifies the test execution. Co-Authored-By: Claude Signed-off-by: Andrei Kvapil (cherry picked from commit dd0bbd375f3d6c801f8d3f00fdbe99972e89eb5f) --- hack/e2e-apps/run-kubernetes.sh | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/hack/e2e-apps/run-kubernetes.sh b/hack/e2e-apps/run-kubernetes.sh index 7c7ce7b9..600749b8 100644 --- a/hack/e2e-apps/run-kubernetes.sh +++ b/hack/e2e-apps/run-kubernetes.sh @@ -219,20 +219,16 @@ if [ -z "$LB_ADDR" ]; then exit 1 fi - kubectl run -n tenant-test lb-check-${test_name} \ - --rm -i --restart=Never \ - --image=curlimages/curl \ - --timeout=60s \ - --command -- \ - sh -c " - for i in \$(seq 1 20); do - echo \"Attempt \$i\"; - curl -sf http://${LB_ADDR} && exit 0; - sleep 3; - done; - echo 'LoadBalancer not reachable'; + for i in $(seq 1 20); do + echo "Attempt $i" + curl --silent --fail "http://${LB_ADDR}" && break + sleep 3 + done + + if [ "$i" -eq 20 ]; then + echo "LoadBalancer not reachable" >&2 exit 1 - " + fi # Cleanup kubectl delete deployment --kubeconfig tenantkubeconfig-${test_name} "${test_name}-backend" -n tenant-test From 063d6cc7f6aef391b492ca4f372331a243867b79 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 2 Jan 2026 21:28:18 +0100 Subject: [PATCH 76/76] fix(e2e): correct Service selector to match Deployment labels The Service selector was using app: "${test_name}-backend" but the Deployment pod template has app: backend. Fixed selector to match the actual pod labels so endpoints are created correctly. Co-Authored-By: Claude Signed-off-by: Andrei Kvapil (cherry picked from commit 3a5977ff60c2b87efab0c356b6e723a55dac9d20) --- hack/e2e-apps/run-kubernetes.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hack/e2e-apps/run-kubernetes.sh b/hack/e2e-apps/run-kubernetes.sh index 600749b8..c9a54232 100644 --- a/hack/e2e-apps/run-kubernetes.sh +++ b/hack/e2e-apps/run-kubernetes.sh @@ -191,7 +191,8 @@ metadata: spec: type: LoadBalancer selector: - app: "${test_name}-backend" + app: backend + backend: "${test_name}-backend" ports: - port: 80 targetPort: 80