From 2aa5c4610a501a1635b5ff0b3b7728e203f997e9 Mon Sep 17 00:00:00 2001 From: Florian Thienel Date: Thu, 11 Jun 2026 11:34:46 +0200 Subject: [PATCH 01/17] define the CompatibilityMode field --- hack/api-reference/api.md | 11 +++++++++++ pkg/apis/stackit/v1alpha1/types_controlplane.go | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/hack/api-reference/api.md b/hack/api-reference/api.md index 8bbbc206..6169a6c6 100644 --- a/hack/api-reference/api.md +++ b/hack/api-reference/api.md @@ -215,6 +215,17 @@ string

+ + +compatibilityMode
+ +string + + + +

+ + diff --git a/pkg/apis/stackit/v1alpha1/types_controlplane.go b/pkg/apis/stackit/v1alpha1/types_controlplane.go index 5c10c28a..5b28637d 100644 --- a/pkg/apis/stackit/v1alpha1/types_controlplane.go +++ b/pkg/apis/stackit/v1alpha1/types_controlplane.go @@ -58,7 +58,8 @@ type Storage struct { } type CSI struct { - Name string `json:"name"` + Name string `json:"name"` + CompatibilityMode string `json:"compatibilityMode,omitempty"` } // CSIManila contains configuration for CSI Manila driver (support for NFS volumes) From 34b1e30b362558a49782286a96ae7d801d910bfc Mon Sep 17 00:00:00 2001 From: Florian Thienel Date: Thu, 11 Jun 2026 12:02:18 +0200 Subject: [PATCH 02/17] add the default value for CSI.CompatibilityMode --- pkg/apis/stackit/v1alpha1/constants.go | 2 ++ pkg/apis/stackit/v1alpha1/defaults.go | 3 +++ 2 files changed, 5 insertions(+) diff --git a/pkg/apis/stackit/v1alpha1/constants.go b/pkg/apis/stackit/v1alpha1/constants.go index 86bbdc81..c7270e7f 100644 --- a/pkg/apis/stackit/v1alpha1/constants.go +++ b/pkg/apis/stackit/v1alpha1/constants.go @@ -5,6 +5,8 @@ package v1alpha1 const ( // DefaultCSIName defines the default CSI (Container Storage Interface) name for STACKIT DefaultCSIName = "stackit" + // DefaultCSICompatibilityMode defines the default CSI driver's compatibility mode. + DefaultCSICompatibilityMode = "default" // DefaultCCMName defines the default CCM (Cloud Controller Manager) controller to use DefaultCCMName = "stackit" ) diff --git a/pkg/apis/stackit/v1alpha1/defaults.go b/pkg/apis/stackit/v1alpha1/defaults.go index d72cba93..e91caf34 100644 --- a/pkg/apis/stackit/v1alpha1/defaults.go +++ b/pkg/apis/stackit/v1alpha1/defaults.go @@ -43,4 +43,7 @@ func SetDefaults_ControlPlaneConfig(obj *ControlPlaneConfig) { if obj.Storage.CSI.Name == "" { obj.Storage.CSI.Name = DefaultCSIName } + if obj.Storage.CSI.CompatibilityMode == "" { + obj.Storage.CSI.CompatibilityMode = DefaultCSICompatibilityMode + } } From b26aa991eb3e55801d61269811c983b8e873e867 Mon Sep 17 00:00:00 2001 From: Florian Thienel Date: Fri, 12 Jun 2026 09:31:46 +0200 Subject: [PATCH 03/17] provide access to the new CompatibilityMode field --- pkg/apis/stackit/v1alpha1/constants.go | 8 ++++++++ pkg/controller/controlplane/valuesprovider.go | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/pkg/apis/stackit/v1alpha1/constants.go b/pkg/apis/stackit/v1alpha1/constants.go index c7270e7f..42400ae6 100644 --- a/pkg/apis/stackit/v1alpha1/constants.go +++ b/pkg/apis/stackit/v1alpha1/constants.go @@ -17,3 +17,11 @@ const ( STACKIT ControllerName = "stackit" OPENSTACK ControllerName = "openstack" ) + +type CSICompatibilityMode string + +const ( + DEFAULT CSICompatibilityMode = "default" + COMPAT CSICompatibilityMode = "compat" + COMPATBLOCK CSICompatibilityMode = "compatblock" +) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index 180ac234..c8490254 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -1216,6 +1216,10 @@ func getCSIDriver(cpConfig *stackitv1alpha1.ControlPlaneConfig) stackitv1alpha1. return stackitv1alpha1.ControllerName(cpConfig.Storage.CSI.Name) } +func getCSICompatibilityMode(cpConfig *stackitv1alpha1.ControlPlaneConfig) stackitv1alpha1.CSICompatibilityMode { + return stackitv1alpha1.CSICompatibilityMode(cpConfig.Storage.CSI.CompatibilityMode) +} + func getCCMController(cpConfig *stackitv1alpha1.ControlPlaneConfig) stackitv1alpha1.ControllerName { return stackitv1alpha1.ControllerName(cpConfig.CloudControllerManager.Name) } From 92697d7cfb0fee6738b281428ae64a2bfacc8b61 Mon Sep 17 00:00:00 2001 From: Florian Thienel Date: Fri, 12 Jun 2026 13:01:58 +0200 Subject: [PATCH 04/17] render the second DaemonSet in compatibility mode, if parameterized accordingly --- .../templates/daemonset.yaml | 150 ++++++++++++++++++ .../values.yaml | 4 + 2 files changed, 154 insertions(+) diff --git a/charts/internal/shoot-system-components/charts/stackit-blockstorage-csi-driver/templates/daemonset.yaml b/charts/internal/shoot-system-components/charts/stackit-blockstorage-csi-driver/templates/daemonset.yaml index cb04e3cf..e5e4e83d 100644 --- a/charts/internal/shoot-system-components/charts/stackit-blockstorage-csi-driver/templates/daemonset.yaml +++ b/charts/internal/shoot-system-components/charts/stackit-blockstorage-csi-driver/templates/daemonset.yaml @@ -144,3 +144,153 @@ spec: configMap: defaultMode: 420 name: {{ .Values.prefix }}-cloud-provider-config +--- +{{- if .Values.csiDriverCompatibility.enabled }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ .Values.prefix }}-csi-driver-compatibility-node + namespace: {{ .Release.Namespace }} + labels: + node.gardener.cloud/critical-component: "true" + app: {{ .Values.prefix }}-csi-compatibility + role: disk-driver +spec: + selector: + matchLabels: + app: {{ .Values.prefix }}-csi-compatibility + role: disk-driver + template: + metadata: + annotations: + checksum/configmap-cloud-provider-config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + node.gardener.cloud/wait-for-csi-node-stackit: block-storage.csi.stackit.cloud + labels: + node.gardener.cloud/critical-component: "true" + app: {{ .Values.prefix }}-csi-compatibility + role: disk-driver + spec: + hostNetwork: true + priorityClassName: system-node-critical + serviceAccountName: {{ .Values.prefix }}-csi-driver-node + tolerations: + - effect: NoSchedule + operator: Exists + - key: CriticalAddonsOnly + operator: Exists + - effect: NoExecute + operator: Exists + securityContext: + seccompProfile: + type: RuntimeDefault + containers: + - name: csi-driver-stackit + image: {{ index .Values.images "csi-driver-stackit" }} + args: + - /bin/stackit-csi-plugin + - --endpoint=$(CSI_ENDPOINT) + - --cloud-config=/etc/config/cloud.yaml + {{- range $userAgentHeader := .Values.userAgentHeaders }} + - --user-agent={{ $userAgentHeader }} + {{- end }} + - --v=2 + - --provide-controller-service=false + - --legacy-storage-mode=true + - --legacy-volume-creation={{ .Values.csiDriverCompatibility.legacyVolumeCreation }} + env: + - name: CSI_ENDPOINT + value: unix://{{ .Values.socketPath }} +{{- if .Values.resources.driver }} + resources: +{{ toYaml .Values.resources.driver | indent 10 }} +{{- end }} + securityContext: + privileged: true + capabilities: + add: ["SYS_ADMIN"] + allowPrivilegeEscalation: true + ports: + - name: healthz + containerPort: 9909 + protocol: TCP + livenessProbe: + httpGet: + path: /healthz + port: healthz + initialDelaySeconds: 10 + timeoutSeconds: 180 + periodSeconds: 30 + failureThreshold: 5 + volumeMounts: + - name: kubelet-dir + mountPath: /var/lib/kubelet + mountPropagation: "Bidirectional" + - name: plugin-dir + mountPath: /csi + - name: device-dir + mountPath: /dev + mountPropagation: "HostToContainer" + - name: cloud-provider-config + mountPath: /etc/config + + - name: csi-node-driver-registrar + image: {{ index .Values.images "csi-node-driver-registrar" }} + args: + - --csi-address=$(ADDRESS) + - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH) + - --v=5 + env: + - name: ADDRESS + value: {{ .Values.socketPath }} + - name: DRIVER_REG_SOCK_PATH + value: /var/lib/kubelet/plugins/block-storage.csi.stackit.cloud/csi.sock +{{- if .Values.resources.nodeDriverRegistrar }} + resources: +{{ toYaml .Values.resources.nodeDriverRegistrar | indent 10 }} +{{- end }} + volumeMounts: + - name: plugin-dir + mountPath: /csi + - name: registration-dir + mountPath: /registration + securityContext: + allowPrivilegeEscalation: false + + - name: csi-liveness-probe + image: {{ index .Values.images "csi-liveness-probe" }} + args: + - --probe-timeout=3m + - --csi-address={{ .Values.socketPath }} + - --health-port=9909 +{{- if .Values.resources.livenessProbe }} + resources: +{{ toYaml .Values.resources.livenessProbe | indent 10 }} +{{- end }} + volumeMounts: + - name: plugin-dir + mountPath: /csi + securityContext: + allowPrivilegeEscalation: false + + volumes: + - name: kubelet-dir + hostPath: + path: /var/lib/kubelet + type: Directory + - name: plugin-dir + hostPath: + path: /var/lib/kubelet/plugins/block-storage.csi.stackit.cloud/ + type: DirectoryOrCreate + - name: registration-dir + hostPath: + path: /var/lib/kubelet/plugins_registry/ + type: Directory + - name: device-dir + hostPath: + path: /dev + type: Directory + - name: cloud-provider-config + configMap: + defaultMode: 420 + name: {{ .Values.prefix }}-cloud-provider-config + {{- end }} diff --git a/charts/internal/shoot-system-components/charts/stackit-blockstorage-csi-driver/values.yaml b/charts/internal/shoot-system-components/charts/stackit-blockstorage-csi-driver/values.yaml index c5e073af..5eceba97 100644 --- a/charts/internal/shoot-system-components/charts/stackit-blockstorage-csi-driver/values.yaml +++ b/charts/internal/shoot-system-components/charts/stackit-blockstorage-csi-driver/values.yaml @@ -3,6 +3,10 @@ driverName: block-storage.csi.stackit.cloud rescanBlockStorageOnResize: "true" +csiDriverCompatibility: + enabled: false + legacyVolumeCreation: true + images: csi-driver-stackit: image-repository:image-tag csi-node-driver-registrar: image-repository:image-tag From 05cd918e1d94dd84d176ab585d08f6d9fa8a160d Mon Sep 17 00:00:00 2001 From: Niclas Schad Date: Mon, 15 Jun 2026 11:08:37 +0200 Subject: [PATCH 05/17] install control-plane stackit-blockstorage chart (compat) as ManagedResource Signed-off-by: Niclas Schad --- pkg/controller/controlplane/valuesprovider.go | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index c8490254..3f4e7d02 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -21,10 +21,12 @@ import ( "github.com/gardener/gardener/pkg/apis/core/v1beta1" v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" + "github.com/gardener/gardener/pkg/chartrenderer" gardenerutils "github.com/gardener/gardener/pkg/utils" "github.com/gardener/gardener/pkg/utils/chart" gutil "github.com/gardener/gardener/pkg/utils/gardener" kutil "github.com/gardener/gardener/pkg/utils/kubernetes" + "github.com/gardener/gardener/pkg/utils/managedresources" secretutils "github.com/gardener/gardener/pkg/utils/secrets" secretsmanager "github.com/gardener/gardener/pkg/utils/secrets/manager" monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" @@ -43,6 +45,7 @@ import ( "k8s.io/apimachinery/pkg/types" utilruntime "k8s.io/apimachinery/pkg/util/runtime" vpaautoscalingv1 "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1" + "k8s.io/client-go/rest" "k8s.io/utils/ptr" k8sclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" @@ -359,6 +362,7 @@ var ( func NewValuesProvider(mgr manager.Manager, deployALBIngressController bool, customLabelDomain string) genericactuator.ValuesProvider { return &valuesProvider{ client: mgr.GetClient(), + config: mgr.GetConfig(), decoder: serializer.NewCodecFactory(mgr.GetScheme(), serializer.EnableStrict).UniversalDecoder(), deployALBIngressController: deployALBIngressController, customLabelDomain: customLabelDomain, @@ -369,6 +373,7 @@ func NewValuesProvider(mgr manager.Manager, deployALBIngressController bool, cus type valuesProvider struct { genericactuator.NoopValuesProvider client k8sclient.Client + config *rest.Config decoder runtime.Decoder deployALBIngressController bool customLabelDomain string @@ -750,6 +755,12 @@ func (vp *valuesProvider) getControlPlaneChartValues(ctx context.Context, cpConf controlPlaneValues[openstack.CSIControllerName] = map[string]any{ "enabled": false, } + if getCSICompatibilityMode(cpConfig) == stackitv1alpha1.COMPAT { + err := vp.deploySeedCSICompatibilityMode(ctx, cluster.Shoot.GetNamespace(), csiSTACKIT) + if err != nil { + return nil, fmt.Errorf("failed to deploy CSI CSI compatibility mode: %w", err) + } + } default: return nil, fmt.Errorf("unsupported storage CSI Driver: %s", storageCSIDriver) } @@ -1176,6 +1187,31 @@ func (vp *valuesProvider) checkEmergencyLoadBalancerAccess(ctx context.Context, return apiURL, apiToken, nil } +func (vp *valuesProvider) deploySeedCSICompatibilityMode(ctx context.Context, namespace string, values map[string]any) error { + renderer, err := chartrenderer.NewForConfig(vp.config) + if err != nil { + return nil + } + + releaseName := "csi-compatibility-mode" + chartName := "stackit-blockstorage-csi-driver" + + values["prefix"] = "stackit-compat" + + renderedChart, err := renderer.RenderEmbeddedFS( + charts.InternalChart, "shoot-system-components/stackit-blockstorage-csi-driver", releaseName, v1beta1constants.GardenNamespace, values, + ) + if err != nil { + return err + } + + data := map[string][]byte{chartName: renderedChart.Manifest()} + return managedresources.Create( + ctx, vp.client, namespace, chartName, map[string]string{}, + false, "seed", data, new(false), nil, new(false), + ) +} + // decodeLoadBalancerAPIEmergencySecret decodes a [corev1.Secret] for emergency loadbalancer access and // returns the apiURL and apiToken to use or an error. // The apiURL and apiToken are only set if both values exist inside the secret and are not empty. From 3703159e5f8dd807e5899e140372ac3ab41d54bb Mon Sep 17 00:00:00 2001 From: Niclas Schad Date: Mon, 15 Jun 2026 11:10:55 +0200 Subject: [PATCH 06/17] fix chart path Signed-off-by: Niclas Schad --- pkg/controller/controlplane/valuesprovider.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index 3f4e7d02..cd8893e6 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -1199,7 +1199,7 @@ func (vp *valuesProvider) deploySeedCSICompatibilityMode(ctx context.Context, na values["prefix"] = "stackit-compat" renderedChart, err := renderer.RenderEmbeddedFS( - charts.InternalChart, "shoot-system-components/stackit-blockstorage-csi-driver", releaseName, v1beta1constants.GardenNamespace, values, + charts.InternalChart, "seed-controlplane/stackit-blockstorage-csi-driver", releaseName, v1beta1constants.GardenNamespace, values, ) if err != nil { return err From 3c1fef45ff9b25addedca94e251dc3e454397183 Mon Sep 17 00:00:00 2001 From: Niclas Schad Date: Mon, 15 Jun 2026 11:39:04 +0200 Subject: [PATCH 07/17] fix chart path and releaseName Signed-off-by: Niclas Schad --- pkg/controller/controlplane/valuesprovider.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index cd8893e6..e20a898e 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -1193,13 +1193,12 @@ func (vp *valuesProvider) deploySeedCSICompatibilityMode(ctx context.Context, na return nil } - releaseName := "csi-compatibility-mode" chartName := "stackit-blockstorage-csi-driver" values["prefix"] = "stackit-compat" renderedChart, err := renderer.RenderEmbeddedFS( - charts.InternalChart, "seed-controlplane/stackit-blockstorage-csi-driver", releaseName, v1beta1constants.GardenNamespace, values, + charts.InternalChart, "seed-controlplane/charts/stackit-blockstorage-csi-driver", chartName, namespace, values, ) if err != nil { return err From 2f32d470c96d1b4de8675229aabe23504bce3faf Mon Sep 17 00:00:00 2001 From: Niclas Schad Date: Mon, 15 Jun 2026 11:49:51 +0200 Subject: [PATCH 08/17] fix path? Signed-off-by: Niclas Schad --- pkg/controller/controlplane/valuesprovider.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index e20a898e..f6162512 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -1198,7 +1198,7 @@ func (vp *valuesProvider) deploySeedCSICompatibilityMode(ctx context.Context, na values["prefix"] = "stackit-compat" renderedChart, err := renderer.RenderEmbeddedFS( - charts.InternalChart, "seed-controlplane/charts/stackit-blockstorage-csi-driver", chartName, namespace, values, + charts.InternalChart, filepath.Join(charts.InternalChartsPath, "seed-controlplane/charts/stackit-blockstorage-csi-driver"), chartName, namespace, values, ) if err != nil { return err From 8dc17ef2c4b739717a25341a0fa493c68ca2f6b6 Mon Sep 17 00:00:00 2001 From: Niclas Schad Date: Mon, 15 Jun 2026 11:58:27 +0200 Subject: [PATCH 09/17] Move some things around Signed-off-by: Niclas Schad --- pkg/controller/controlplane/valuesprovider.go | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index f6162512..b3de76a8 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -741,6 +741,15 @@ func (vp *valuesProvider) getControlPlaneChartValues(ctx context.Context, cpConf return nil, err } + maps.Copy(controlPlaneValues, map[string]any{ + "global": map[string]any{ + "genericTokenKubeconfigSecretName": extensionscontroller.GenericTokenKubeconfigSecretNameFromCluster(cluster), + }, + openstack.CloudControllerManagerName: ccm, + openstack.STACKITCloudControllerManagerName: stackitccm, + stackit.PodIdentityWebhookName: podIdentityWebhook, + }) + storageCSIDriver := getCSIDriver(cpConfig) switch storageCSIDriver { case stackitv1alpha1.OPENSTACK: @@ -756,7 +765,7 @@ func (vp *valuesProvider) getControlPlaneChartValues(ctx context.Context, cpConf "enabled": false, } if getCSICompatibilityMode(cpConfig) == stackitv1alpha1.COMPAT { - err := vp.deploySeedCSICompatibilityMode(ctx, cluster.Shoot.GetNamespace(), csiSTACKIT) + err := vp.deploySeedCSICompatibilityMode(ctx, cluster.Shoot.GetNamespace(), controlPlaneValues) if err != nil { return nil, fmt.Errorf("failed to deploy CSI CSI compatibility mode: %w", err) } @@ -765,15 +774,6 @@ func (vp *valuesProvider) getControlPlaneChartValues(ctx context.Context, cpConf return nil, fmt.Errorf("unsupported storage CSI Driver: %s", storageCSIDriver) } - maps.Copy(controlPlaneValues, map[string]any{ - "global": map[string]any{ - "genericTokenKubeconfigSecretName": extensionscontroller.GenericTokenKubeconfigSecretNameFromCluster(cluster), - }, - openstack.CloudControllerManagerName: ccm, - openstack.STACKITCloudControllerManagerName: stackitccm, - stackit.PodIdentityWebhookName: podIdentityWebhook, - }) - if vp.deployALBIngressController { fmt.Println("deploying ALB Ingress Controller") albcm, err := getSTACKITALBCMChartValues(cpConfig, cluster, infra, stackitCredentialsConfig, apiEndpoints, scaledDown, stackitRegion) From a03c8df9979f84ad6c9e0f1ed40cf8695ff7ae19 Mon Sep 17 00:00:00 2001 From: Niclas Schad Date: Mon, 15 Jun 2026 12:00:36 +0200 Subject: [PATCH 10/17] fix values? Signed-off-by: Niclas Schad --- pkg/controller/controlplane/valuesprovider.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index b3de76a8..2a018f14 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -1195,7 +1195,8 @@ func (vp *valuesProvider) deploySeedCSICompatibilityMode(ctx context.Context, na chartName := "stackit-blockstorage-csi-driver" - values["prefix"] = "stackit-compat" + csiStackitValues := values[openstack.CSISTACKITControllerName].(map[string]string) + csiStackitValues["prefix"] = "stackit-compat" renderedChart, err := renderer.RenderEmbeddedFS( charts.InternalChart, filepath.Join(charts.InternalChartsPath, "seed-controlplane/charts/stackit-blockstorage-csi-driver"), chartName, namespace, values, From 4c59bcd1e48521fbc011ecab86ade9f89540d918 Mon Sep 17 00:00:00 2001 From: Niclas Schad Date: Mon, 15 Jun 2026 12:06:34 +0200 Subject: [PATCH 11/17] fix type assertion Signed-off-by: Niclas Schad --- pkg/controller/controlplane/valuesprovider.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index 2a018f14..68e71247 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -1195,7 +1195,7 @@ func (vp *valuesProvider) deploySeedCSICompatibilityMode(ctx context.Context, na chartName := "stackit-blockstorage-csi-driver" - csiStackitValues := values[openstack.CSISTACKITControllerName].(map[string]string) + csiStackitValues := values[openstack.CSISTACKITControllerName].(map[string]interface{}) csiStackitValues["prefix"] = "stackit-compat" renderedChart, err := renderer.RenderEmbeddedFS( From f46ef40346f800963456c3661e4bd59b1c2b421c Mon Sep 17 00:00:00 2001 From: Niclas Schad Date: Mon, 15 Jun 2026 12:11:30 +0200 Subject: [PATCH 12/17] fix namespace Signed-off-by: Niclas Schad --- pkg/controller/controlplane/valuesprovider.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index 68e71247..7f12b38e 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -765,7 +765,7 @@ func (vp *valuesProvider) getControlPlaneChartValues(ctx context.Context, cpConf "enabled": false, } if getCSICompatibilityMode(cpConfig) == stackitv1alpha1.COMPAT { - err := vp.deploySeedCSICompatibilityMode(ctx, cluster.Shoot.GetNamespace(), controlPlaneValues) + err := vp.deploySeedCSICompatibilityMode(ctx, cp.GetNamespace(), controlPlaneValues) if err != nil { return nil, fmt.Errorf("failed to deploy CSI CSI compatibility mode: %w", err) } From 5d15fee2d0298c65e941c0f36256144ab2745b08 Mon Sep 17 00:00:00 2001 From: Niclas Schad Date: Mon, 15 Jun 2026 12:29:42 +0200 Subject: [PATCH 13/17] use different name for MR release Signed-off-by: Niclas Schad --- pkg/controller/controlplane/valuesprovider.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index 7f12b38e..c852aaa2 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -1207,7 +1207,7 @@ func (vp *valuesProvider) deploySeedCSICompatibilityMode(ctx context.Context, na data := map[string][]byte{chartName: renderedChart.Manifest()} return managedresources.Create( - ctx, vp.client, namespace, chartName, map[string]string{}, + ctx, vp.client, namespace, "stackit-csi-compat-chart", map[string]string{}, false, "seed", data, new(false), nil, new(false), ) } From f6b0a546989767def78d83b8a04191260adf2c24 Mon Sep 17 00:00:00 2001 From: Niclas Schad Date: Mon, 15 Jun 2026 14:55:53 +0200 Subject: [PATCH 14/17] apply fixes and inject images manually Signed-off-by: Niclas Schad --- .../values.yaml | 1 - pkg/controller/controlplane/valuesprovider.go | 40 +++++++++++++++++-- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/charts/internal/seed-controlplane/charts/stackit-blockstorage-csi-driver/values.yaml b/charts/internal/seed-controlplane/charts/stackit-blockstorage-csi-driver/values.yaml index 60ff609a..02f0e30b 100644 --- a/charts/internal/seed-controlplane/charts/stackit-blockstorage-csi-driver/values.yaml +++ b/charts/internal/seed-controlplane/charts/stackit-blockstorage-csi-driver/values.yaml @@ -12,7 +12,6 @@ images: csi-resizer: image-repository:image-tag csi-liveness-probe: image-repository:image-tag csi-snapshot-controller: image-repository:image-tag - csi-snapshot-validation-webhook: image-repository:image-tag socketPath: /var/lib/csi/sockets/pluginproxy region: "" diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index c852aaa2..b242c926 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -764,6 +764,7 @@ func (vp *valuesProvider) getControlPlaneChartValues(ctx context.Context, cpConf controlPlaneValues[openstack.CSIControllerName] = map[string]any{ "enabled": false, } + // TODO: make it nice if getCSICompatibilityMode(cpConfig) == stackitv1alpha1.COMPAT { err := vp.deploySeedCSICompatibilityMode(ctx, cp.GetNamespace(), controlPlaneValues) if err != nil { @@ -1195,17 +1196,48 @@ func (vp *valuesProvider) deploySeedCSICompatibilityMode(ctx context.Context, na chartName := "stackit-blockstorage-csi-driver" - csiStackitValues := values[openstack.CSISTACKITControllerName].(map[string]interface{}) - csiStackitValues["prefix"] = "stackit-compat" + foo := map[string]interface{}{} + foo = maps.Clone(values) + // Get the chart Values + csiStackitValues := foo[openstack.CSISTACKITControllerName].(map[string]interface{}) + // Merge csiStackitValues to topLevel. Basically removes the openstack.CSISTACKITControllerName key + chartValues := gardenerutils.MergeMaps(foo, csiStackitValues) + // Override chart values + chartValues["prefix"] = "stackit-compat" + + //TODO: Use gardener tools for this? If possible + imagesToFind := []string{ + "csi-driver-stackit", + "csi-provisioner", + "csi-attacher", + "csi-snapshotter", + "csi-resizer", + "csi-liveness-probe", + "csi-snapshot-controller"} + images := imagevector.ImageVector() + imageMap := make(map[string]interface{}) + + for _, image := range imagesToFind { + foundImage, err := images.FindImage(image) + if err != nil { + return err + } + imageMap[image] = foundImage.String() + } + chartValues["images"] = imageMap renderedChart, err := renderer.RenderEmbeddedFS( - charts.InternalChart, filepath.Join(charts.InternalChartsPath, "seed-controlplane/charts/stackit-blockstorage-csi-driver"), chartName, namespace, values, + charts.InternalChart, + filepath.Join(charts.InternalChartsPath, "seed-controlplane/charts/stackit-blockstorage-csi-driver"), + chartName, + namespace, + chartValues, ) if err != nil { return err } - data := map[string][]byte{chartName: renderedChart.Manifest()} + data := renderedChart.AsSecretData() return managedresources.Create( ctx, vp.client, namespace, "stackit-csi-compat-chart", map[string]string{}, false, "seed", data, new(false), nil, new(false), From c923b5dd4bfcf45bc6d5b052a8bd0bd0db613a74 Mon Sep 17 00:00:00 2001 From: Florian Thienel Date: Tue, 16 Jun 2026 10:12:51 +0200 Subject: [PATCH 15/17] remove the duplicated DaemonSet as it is not needed --- .../templates/daemonset.yaml | 150 ------------------ .../values.yaml | 4 - 2 files changed, 154 deletions(-) diff --git a/charts/internal/shoot-system-components/charts/stackit-blockstorage-csi-driver/templates/daemonset.yaml b/charts/internal/shoot-system-components/charts/stackit-blockstorage-csi-driver/templates/daemonset.yaml index e5e4e83d..cb04e3cf 100644 --- a/charts/internal/shoot-system-components/charts/stackit-blockstorage-csi-driver/templates/daemonset.yaml +++ b/charts/internal/shoot-system-components/charts/stackit-blockstorage-csi-driver/templates/daemonset.yaml @@ -144,153 +144,3 @@ spec: configMap: defaultMode: 420 name: {{ .Values.prefix }}-cloud-provider-config ---- -{{- if .Values.csiDriverCompatibility.enabled }} -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: {{ .Values.prefix }}-csi-driver-compatibility-node - namespace: {{ .Release.Namespace }} - labels: - node.gardener.cloud/critical-component: "true" - app: {{ .Values.prefix }}-csi-compatibility - role: disk-driver -spec: - selector: - matchLabels: - app: {{ .Values.prefix }}-csi-compatibility - role: disk-driver - template: - metadata: - annotations: - checksum/configmap-cloud-provider-config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} - node.gardener.cloud/wait-for-csi-node-stackit: block-storage.csi.stackit.cloud - labels: - node.gardener.cloud/critical-component: "true" - app: {{ .Values.prefix }}-csi-compatibility - role: disk-driver - spec: - hostNetwork: true - priorityClassName: system-node-critical - serviceAccountName: {{ .Values.prefix }}-csi-driver-node - tolerations: - - effect: NoSchedule - operator: Exists - - key: CriticalAddonsOnly - operator: Exists - - effect: NoExecute - operator: Exists - securityContext: - seccompProfile: - type: RuntimeDefault - containers: - - name: csi-driver-stackit - image: {{ index .Values.images "csi-driver-stackit" }} - args: - - /bin/stackit-csi-plugin - - --endpoint=$(CSI_ENDPOINT) - - --cloud-config=/etc/config/cloud.yaml - {{- range $userAgentHeader := .Values.userAgentHeaders }} - - --user-agent={{ $userAgentHeader }} - {{- end }} - - --v=2 - - --provide-controller-service=false - - --legacy-storage-mode=true - - --legacy-volume-creation={{ .Values.csiDriverCompatibility.legacyVolumeCreation }} - env: - - name: CSI_ENDPOINT - value: unix://{{ .Values.socketPath }} -{{- if .Values.resources.driver }} - resources: -{{ toYaml .Values.resources.driver | indent 10 }} -{{- end }} - securityContext: - privileged: true - capabilities: - add: ["SYS_ADMIN"] - allowPrivilegeEscalation: true - ports: - - name: healthz - containerPort: 9909 - protocol: TCP - livenessProbe: - httpGet: - path: /healthz - port: healthz - initialDelaySeconds: 10 - timeoutSeconds: 180 - periodSeconds: 30 - failureThreshold: 5 - volumeMounts: - - name: kubelet-dir - mountPath: /var/lib/kubelet - mountPropagation: "Bidirectional" - - name: plugin-dir - mountPath: /csi - - name: device-dir - mountPath: /dev - mountPropagation: "HostToContainer" - - name: cloud-provider-config - mountPath: /etc/config - - - name: csi-node-driver-registrar - image: {{ index .Values.images "csi-node-driver-registrar" }} - args: - - --csi-address=$(ADDRESS) - - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH) - - --v=5 - env: - - name: ADDRESS - value: {{ .Values.socketPath }} - - name: DRIVER_REG_SOCK_PATH - value: /var/lib/kubelet/plugins/block-storage.csi.stackit.cloud/csi.sock -{{- if .Values.resources.nodeDriverRegistrar }} - resources: -{{ toYaml .Values.resources.nodeDriverRegistrar | indent 10 }} -{{- end }} - volumeMounts: - - name: plugin-dir - mountPath: /csi - - name: registration-dir - mountPath: /registration - securityContext: - allowPrivilegeEscalation: false - - - name: csi-liveness-probe - image: {{ index .Values.images "csi-liveness-probe" }} - args: - - --probe-timeout=3m - - --csi-address={{ .Values.socketPath }} - - --health-port=9909 -{{- if .Values.resources.livenessProbe }} - resources: -{{ toYaml .Values.resources.livenessProbe | indent 10 }} -{{- end }} - volumeMounts: - - name: plugin-dir - mountPath: /csi - securityContext: - allowPrivilegeEscalation: false - - volumes: - - name: kubelet-dir - hostPath: - path: /var/lib/kubelet - type: Directory - - name: plugin-dir - hostPath: - path: /var/lib/kubelet/plugins/block-storage.csi.stackit.cloud/ - type: DirectoryOrCreate - - name: registration-dir - hostPath: - path: /var/lib/kubelet/plugins_registry/ - type: Directory - - name: device-dir - hostPath: - path: /dev - type: Directory - - name: cloud-provider-config - configMap: - defaultMode: 420 - name: {{ .Values.prefix }}-cloud-provider-config - {{- end }} diff --git a/charts/internal/shoot-system-components/charts/stackit-blockstorage-csi-driver/values.yaml b/charts/internal/shoot-system-components/charts/stackit-blockstorage-csi-driver/values.yaml index 5eceba97..c5e073af 100644 --- a/charts/internal/shoot-system-components/charts/stackit-blockstorage-csi-driver/values.yaml +++ b/charts/internal/shoot-system-components/charts/stackit-blockstorage-csi-driver/values.yaml @@ -3,10 +3,6 @@ driverName: block-storage.csi.stackit.cloud rescanBlockStorageOnResize: "true" -csiDriverCompatibility: - enabled: false - legacyVolumeCreation: true - images: csi-driver-stackit: image-repository:image-tag csi-node-driver-registrar: image-repository:image-tag From 96a59fdc57415baa13c3f167f5c87b95701f8745 Mon Sep 17 00:00:00 2001 From: Florian Thienel Date: Wed, 17 Jun 2026 13:52:34 +0200 Subject: [PATCH 16/17] add a symmetric method for the Shoot controlplane in Compatibility Mode --- pkg/controller/controlplane/valuesprovider.go | 73 +++++++++++++++++-- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index b242c926..57f094a1 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -1088,6 +1088,11 @@ func (vp *valuesProvider) getControlPlaneShootChartValues(ctx context.Context, c case stackitv1alpha1.OPENSTACK: values[openstack.CSINodeName] = csiNodeDriverValues values[openstack.CSISTACKITNodeName] = map[string]any{"enabled": false} + if getCSICompatibilityMode(cpConfig) == stackitv1alpha1.COMPAT { + if err := vp.deployShootCSICompatibilityMode(ctx, cp.Namespace, values); err != nil { + return nil, fmt.Errorf("deploy shoot CSI compatibility mode: %w", err) + } + } default: return nil, fmt.Errorf("unsupported CSI driver type: %s", csiDriverInUse) } @@ -1194,14 +1199,13 @@ func (vp *valuesProvider) deploySeedCSICompatibilityMode(ctx context.Context, na return nil } + // TODO: constant chartName := "stackit-blockstorage-csi-driver" - foo := map[string]interface{}{} - foo = maps.Clone(values) // Get the chart Values - csiStackitValues := foo[openstack.CSISTACKITControllerName].(map[string]interface{}) + csiStackitValues := values[openstack.CSISTACKITControllerName].(map[string]any) // Merge csiStackitValues to topLevel. Basically removes the openstack.CSISTACKITControllerName key - chartValues := gardenerutils.MergeMaps(foo, csiStackitValues) + chartValues := gardenerutils.MergeMaps(values, csiStackitValues) // Override chart values chartValues["prefix"] = "stackit-compat" @@ -1213,9 +1217,10 @@ func (vp *valuesProvider) deploySeedCSICompatibilityMode(ctx context.Context, na "csi-snapshotter", "csi-resizer", "csi-liveness-probe", - "csi-snapshot-controller"} + "csi-snapshot-controller", + } images := imagevector.ImageVector() - imageMap := make(map[string]interface{}) + imageMap := make(map[string]any) for _, image := range imagesToFind { foundImage, err := images.FindImage(image) @@ -1244,6 +1249,62 @@ func (vp *valuesProvider) deploySeedCSICompatibilityMode(ctx context.Context, na ) } +func (vp *valuesProvider) deployShootCSICompatibilityMode(ctx context.Context, namespace string, values map[string]any) error { + renderer, err := chartrenderer.NewForConfig(vp.config) + if err != nil { + return err + } + + // TODO: constant + chartName := "stackit-blockstorage-csi-driver" + + // Get the chart Values + csiStackitValues := values[openstack.CSISTACKITControllerName].(map[string]any) + // Merge csiStackitValues to topLevel. Basically removes the openstack.CSISTACKITControllerName key + chartValues := gardenerutils.MergeMaps(values, csiStackitValues) + // Override chart values + chartValues["prefix"] = "stackit-compat" + + //TODO: Use gardener tools for this? If possible + imagesToFind := []string{ + "csi-driver-stackit", + "csi-provisioner", + "csi-attacher", + "csi-snapshotter", + "csi-resizer", + "csi-liveness-probe", + "csi-snapshot-controller", + } + images := imagevector.ImageVector() + imageMap := make(map[string]any) + + for _, image := range imagesToFind { + foundImage, err := images.FindImage(image) + if err != nil { + return err + } + imageMap[image] = foundImage.String() + } + chartValues["images"] = imageMap + + renderedChart, err := renderer.RenderEmbeddedFS( + charts.InternalChart, + filepath.Join(charts.InternalChartsPath, "shoot-system-components/charts/stackit-blockstorage-csi-driver"), + chartName, + namespace, + chartValues, + ) + if err != nil { + return err + } + + data := renderedChart.AsSecretData() + return managedresources.Create( + ctx, vp.client, namespace, "stackit-csi-compat-shoot-chart", map[string]string{}, + false, "shoot", data, new(false), nil, new(false), + ) +} + // decodeLoadBalancerAPIEmergencySecret decodes a [corev1.Secret] for emergency loadbalancer access and // returns the apiURL and apiToken to use or an error. // The apiURL and apiToken are only set if both values exist inside the secret and are not empty. From 00827ca07436b6ebf2fd82adb5993581bcb66659 Mon Sep 17 00:00:00 2001 From: Florian Thienel Date: Wed, 17 Jun 2026 14:13:51 +0200 Subject: [PATCH 17/17] use the correct image vector for the Shoot controlplane --- pkg/controller/controlplane/valuesprovider.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index 57f094a1..af0a341b 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -1268,12 +1268,8 @@ func (vp *valuesProvider) deployShootCSICompatibilityMode(ctx context.Context, n //TODO: Use gardener tools for this? If possible imagesToFind := []string{ "csi-driver-stackit", - "csi-provisioner", - "csi-attacher", - "csi-snapshotter", - "csi-resizer", + "csi-node-driver-registrar", "csi-liveness-probe", - "csi-snapshot-controller", } images := imagevector.ImageVector() imageMap := make(map[string]any)