From 32324fa647c8cddfbb91e427ecaa151a61342431 Mon Sep 17 00:00:00 2001 From: Niclas Schad Date: Wed, 12 Nov 2025 10:04:53 +0100 Subject: [PATCH 1/4] Add support for legacy storage operations Signed-off-by: Niclas Schad --- cmd/stackit-csi-plugin/main.go | 13 ++++++++++-- pkg/csi/blockstorage/controllerserver.go | 19 +++++++++++++----- pkg/csi/blockstorage/driver.go | 25 ++++++++++++++++-------- pkg/csi/blockstorage/nodeserver.go | 7 ++++++- 4 files changed, 48 insertions(+), 16 deletions(-) diff --git a/cmd/stackit-csi-plugin/main.go b/cmd/stackit-csi-plugin/main.go index d952bd60..3290b7de 100644 --- a/cmd/stackit-csi-plugin/main.go +++ b/cmd/stackit-csi-plugin/main.go @@ -24,6 +24,7 @@ var ( httpEndpoint string provideControllerService bool provideNodeService bool + legacyStorageMode bool ) func main() { @@ -72,6 +73,8 @@ func main() { "If set to true then the CSI driver does provide the controller service (default: true)") cmd.PersistentFlags().BoolVar(&provideNodeService, "provide-node-service", true, "If set to true then the CSI driver does provide the node service (default: true)") + cmd.PersistentFlags().BoolVar(&legacyStorageMode, "legacy-storage-mode", false, + "Configures the CSI to listen to the legacy storage driverName cinder.csi.openstack.org instead") stackit.AddExtraFlags(pflag.CommandLine) @@ -81,11 +84,17 @@ func main() { func handle() { // Initialize cloud - d := blockstorage.NewDriver(&blockstorage.DriverOpts{ + driverOpts := &blockstorage.DriverOpts{ Endpoint: endpoint, ClusterID: cluster, PVCLister: csi.GetPVCLister(), - }) + } + + if legacyStorageMode { + driverOpts.LegacyDriverName = true + } + + d := blockstorage.NewDriver(driverOpts) if provideControllerService { var err error diff --git a/pkg/csi/blockstorage/controllerserver.go b/pkg/csi/blockstorage/controllerserver.go index ef962edd..8f6cb127 100644 --- a/pkg/csi/blockstorage/controllerserver.go +++ b/pkg/csi/blockstorage/controllerserver.go @@ -112,7 +112,11 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol accessibleTopologyReq := req.GetAccessibilityRequirements() // Check from topology if accessibleTopologyReq != nil { - volAvailability = sharedcsi.GetAZFromTopology(topologyKey, accessibleTopologyReq) + if cs.Driver.legacyDriver { + volAvailability = sharedcsi.GetAZFromTopology(legacyTopologyKey, accessibleTopologyReq) + } else { + volAvailability = sharedcsi.GetAZFromTopology(topologyKey, accessibleTopologyReq) + } } } @@ -131,7 +135,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol return nil, status.Error(codes.Internal, fmt.Sprintf("Volume %s is not in available state", *vols[0].Id)) } klog.V(4).Infof("Volume %s already exists in Availability Zone: %s of size %d GiB", *vols[0].Id, vols[0].AvailabilityZone, *vols[0].Size) - return getCreateVolumeResponse(&vols[0]), nil + return cs.getCreateVolumeResponse(&vols[0]), nil } else if len(vols) > 1 { klog.V(3).Infof("found multiple existing volumes with selected name (%s) during create", volName) return nil, status.Error(codes.Internal, "Multiple volumes reported by Cinder with same name") @@ -274,7 +278,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol klog.V(4).Infof("CreateVolume: Successfully created volume %s in Availability Zone: %s of size %d GiB", *vol.Id, vol.AvailabilityZone, *vol.Size) - return getCreateVolumeResponse(vol), nil + return cs.getCreateVolumeResponse(vol), nil } func setVolumeEncryptionParameters(opts *iaas.CreateVolumePayload, volParams *stackitParameterConfig) error { @@ -965,7 +969,7 @@ func (cs *controllerServer) ControllerExpandVolume(ctx context.Context, req *csi }, nil } -func getCreateVolumeResponse(vol *iaas.Volume) *csi.CreateVolumeResponse { +func (cs *controllerServer) getCreateVolumeResponse(vol *iaas.Volume) *csi.CreateVolumeResponse { var volsrc *csi.VolumeContentSource var volumeSourceType stackit.VolumeSourceTypes volCnx := map[string]string{} @@ -1006,9 +1010,14 @@ func getCreateVolumeResponse(vol *iaas.Volume) *csi.CreateVolumeResponse { } } + topoKey := topologyKey + if cs.Driver.legacyDriver { + topoKey = legacyTopologyKey + } + accessibleTopology := []*csi.Topology{ { - Segments: map[string]string{topologyKey: vol.AvailabilityZone}, + Segments: map[string]string{topoKey: vol.AvailabilityZone}, }, } diff --git a/pkg/csi/blockstorage/driver.go b/pkg/csi/blockstorage/driver.go index 56fd1818..265ead93 100644 --- a/pkg/csi/blockstorage/driver.go +++ b/pkg/csi/blockstorage/driver.go @@ -15,8 +15,10 @@ import ( ) const ( - driverName = "block-storage.csi.stackit.cloud" - topologyKey = "topology." + driverName + "/zone" + driverName = "block-storage.csi.stackit.cloud" + legacyDriverName = "cinder.csi.openstack.org" + topologyKey = "topology." + driverName + "/zone" + legacyTopologyKey = "topology." + legacyDriverName + "/zone" // ResizeRequired parameter, if set to true, will trigger a resize on mount operation ResizeRequired = driverName + "/resizeRequired" @@ -29,10 +31,11 @@ var ( ) type Driver struct { - name string - fqVersion string // Fully qualified version in format {Version}@{CPO version} - endpoint string - clusterID string + name string + fqVersion string // Fully qualified version in format {Version}@{CPO version} + endpoint string + clusterID string + legacyDriver bool ids *identityServer cs *controllerServer @@ -47,8 +50,9 @@ type Driver struct { } type DriverOpts struct { - ClusterID string - Endpoint string + ClusterID string + Endpoint string + LegacyDriverName bool PVCLister corev1.PersistentVolumeClaimLister } @@ -62,6 +66,11 @@ func NewDriver(o *DriverOpts) *Driver { pvcLister: o.PVCLister, } + if o.LegacyDriverName { + d.name = legacyDriverName + d.legacyDriver = true + } + klog.Info("Driver: ", d.name) klog.Info("Driver version: ", d.fqVersion) klog.Info("CSI Spec version: ", specVersion) diff --git a/pkg/csi/blockstorage/nodeserver.go b/pkg/csi/blockstorage/nodeserver.go index 1e368ba2..2ce7dd87 100644 --- a/pkg/csi/blockstorage/nodeserver.go +++ b/pkg/csi/blockstorage/nodeserver.go @@ -312,9 +312,14 @@ func (ns *nodeServer) NodeGetInfo(ctx context.Context, _ *csi.NodeGetInfoRequest return nil, status.Errorf(codes.Internal, "[NodeGetInfo] Unable to retrieve availability zone of node %v", err) } + topoKey := topologyKey + if ns.Driver.legacyDriver { + topoKey = legacyTopologyKey + } + //TODO: support well-known topology key "topology.kubernetes.io/zone" segments := map[string]string{ - topologyKey: zone, + topoKey: zone, } nodeInfo.AccessibleTopology = &csi.Topology{Segments: segments} From 6bd098876f9de0fed19ab7f165bb53e3c1116f44 Mon Sep 17 00:00:00 2001 From: Niclas Schad Date: Tue, 28 Apr 2026 11:01:48 +0200 Subject: [PATCH 2/4] add flag to block volume creation Signed-off-by: Niclas Schad --- cmd/stackit-csi-plugin/main.go | 6 ++++++ pkg/csi/blockstorage/controllerserver.go | 8 ++++++++ pkg/csi/blockstorage/driver.go | 22 ++++++++++++++-------- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/cmd/stackit-csi-plugin/main.go b/cmd/stackit-csi-plugin/main.go index 3290b7de..06933db6 100644 --- a/cmd/stackit-csi-plugin/main.go +++ b/cmd/stackit-csi-plugin/main.go @@ -25,6 +25,7 @@ var ( provideControllerService bool provideNodeService bool legacyStorageMode bool + blockVolumeCreation bool ) func main() { @@ -75,6 +76,7 @@ func main() { "If set to true then the CSI driver does provide the node service (default: true)") cmd.PersistentFlags().BoolVar(&legacyStorageMode, "legacy-storage-mode", false, "Configures the CSI to listen to the legacy storage driverName cinder.csi.openstack.org instead") + cmd.PersistentFlags().BoolVar(&blockVolumeCreation, "block-volume-creation", false, "Block volume creation") stackit.AddExtraFlags(pflag.CommandLine) @@ -94,6 +96,10 @@ func handle() { driverOpts.LegacyDriverName = true } + if blockVolumeCreation { + driverOpts.BlockVolumeCreation = true + } + d := blockstorage.NewDriver(driverOpts) if provideControllerService { diff --git a/pkg/csi/blockstorage/controllerserver.go b/pkg/csi/blockstorage/controllerserver.go index 8f6cb127..eeb8394d 100644 --- a/pkg/csi/blockstorage/controllerserver.go +++ b/pkg/csi/blockstorage/controllerserver.go @@ -77,6 +77,10 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol cloud := cs.Instance + if cs.Driver.blockVolumeCreation { + return nil, status.Error(codes.FailedPrecondition, "CSI driver is in read/update-only mode") + } + // Volume Name volName := req.GetName() volCapabilities := req.GetVolumeCapabilities() @@ -480,6 +484,10 @@ func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS cloud := cs.Instance + if cs.Driver.blockVolumeCreation { + return nil, status.Error(codes.FailedPrecondition, "The old driver is update/read-only mode please migrate to the new driver") + } + name := req.Name volumeID := req.GetSourceVolumeId() snapshotType := req.Parameters[stackit.SnapshotType] diff --git a/pkg/csi/blockstorage/driver.go b/pkg/csi/blockstorage/driver.go index 265ead93..73d92bb1 100644 --- a/pkg/csi/blockstorage/driver.go +++ b/pkg/csi/blockstorage/driver.go @@ -31,11 +31,12 @@ var ( ) type Driver struct { - name string - fqVersion string // Fully qualified version in format {Version}@{CPO version} - endpoint string - clusterID string - legacyDriver bool + name string + fqVersion string // Fully qualified version in format {Version}@{CPO version} + endpoint string + clusterID string + legacyDriver bool + blockVolumeCreation bool ids *identityServer cs *controllerServer @@ -50,9 +51,10 @@ type Driver struct { } type DriverOpts struct { - ClusterID string - Endpoint string - LegacyDriverName bool + ClusterID string + Endpoint string + LegacyDriverName bool + BlockVolumeCreation bool PVCLister corev1.PersistentVolumeClaimLister } @@ -71,6 +73,10 @@ func NewDriver(o *DriverOpts) *Driver { d.legacyDriver = true } + if o.BlockVolumeCreation { + d.blockVolumeCreation = true + } + klog.Info("Driver: ", d.name) klog.Info("Driver version: ", d.fqVersion) klog.Info("CSI Spec version: ", specVersion) From 24300bf4ba2bdfbd194c7b3b33c12fd76e869157 Mon Sep 17 00:00:00 2001 From: Niclas Schad Date: Wed, 29 Apr 2026 09:34:16 +0200 Subject: [PATCH 3/4] update error text Signed-off-by: Niclas Schad --- pkg/csi/blockstorage/controllerserver.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/csi/blockstorage/controllerserver.go b/pkg/csi/blockstorage/controllerserver.go index eeb8394d..fa5c9430 100644 --- a/pkg/csi/blockstorage/controllerserver.go +++ b/pkg/csi/blockstorage/controllerserver.go @@ -78,7 +78,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol cloud := cs.Instance if cs.Driver.blockVolumeCreation { - return nil, status.Error(codes.FailedPrecondition, "CSI driver is in read/update-only mode") + return nil, status.Errorf(codes.FailedPrecondition, "The %s driver is update/read-only mode please migrate to the new driver", legacyDriverName) } // Volume Name @@ -485,7 +485,7 @@ func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS cloud := cs.Instance if cs.Driver.blockVolumeCreation { - return nil, status.Error(codes.FailedPrecondition, "The old driver is update/read-only mode please migrate to the new driver") + return nil, status.Errorf(codes.FailedPrecondition, "The %s driver is update/read-only mode please migrate to the new driver", legacyDriverName) } name := req.Name From 3f3eeb20d37a27816ac901e87d3d7074e5ab1f4b Mon Sep 17 00:00:00 2001 From: Niclas Schad Date: Wed, 17 Jun 2026 12:28:00 +0200 Subject: [PATCH 4/4] adjust calculateMaxVolumesPerNode() depending on which driverName is configured Signed-off-by: Niclas Schad --- pkg/csi/blockstorage/nodeserver.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pkg/csi/blockstorage/nodeserver.go b/pkg/csi/blockstorage/nodeserver.go index 2ce7dd87..17501b5a 100644 --- a/pkg/csi/blockstorage/nodeserver.go +++ b/pkg/csi/blockstorage/nodeserver.go @@ -304,7 +304,7 @@ func (ns *nodeServer) NodeGetInfo(ctx context.Context, _ *csi.NodeGetInfoRequest nodeInfo := &csi.NodeGetInfoResponse{ NodeId: nodeID, - MaxVolumesPerNode: calculateMaxVolumesPerNode(), + MaxVolumesPerNode: ns.calculateMaxVolumesPerNode(), } zone, err := ns.Metadata.GetAvailabilityZone(ctx) @@ -327,14 +327,20 @@ func (ns *nodeServer) NodeGetInfo(ctx context.Context, _ *csi.NodeGetInfoRequest return nodeInfo, nil } -func calculateMaxVolumesPerNode() int64 { +func (ns *nodeServer) calculateMaxVolumesPerNode() int64 { freePCIeRootPorts, err := mount.CountFreePCIeSlots() if err != nil { klog.Errorf("[NodeGetInfo] unable to retrieve PCIe root ports: %v", err) freePCIeRootPorts = 0 } - mountedCSIVolumes, err := mount.CountLocalCSIVolumes(driverName) + csiDriverName := driverName + if ns.Driver.legacyDriver { + // If driver launched in legacy-mode use "cinder.csi.openstack.org" + csiDriverName = legacyDriverName + } + + mountedCSIVolumes, err := mount.CountLocalCSIVolumes(csiDriverName) if err != nil { klog.Errorf("[NodeGetInfo] unable to retrieve volume count: %v", err) mountedCSIVolumes = 0