Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions pkg/csi/cinder/controllerserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,12 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
// First check if volAvailability is already specified, if not get preferred from Topology
// Required, in case vol AZ is different from node AZ
var volAvailability string
volAvailabilityFromTopology := false
if volParams["availability"] != "" {
volAvailability = volParams["availability"]
} else if cs.Driver.withTopology && accessibleTopologyReq != nil {
volAvailability = sharedcsi.GetAZFromTopology(topologyKey, accessibleTopologyReq)
volAvailabilityFromTopology = true
}

// get the PVC annotation
Expand Down Expand Up @@ -157,6 +159,10 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
if err == nil && snap.Status != "available" {
return nil, status.Errorf(codes.Unavailable, "VolumeContentSource Snapshot %s is not yet available. status: %s", snapshotID, snap.Status)
}
if err == nil && volAvailabilityFromTopology {
klog.V(4).Infof("CreateVolume: clearing topology-derived availability zone %q for snapshot %s to let Cinder select the correct zone", volAvailability, snapshotID)
volAvailability = ""
}

// In case a snapshot is not found
// check if a Backup with the same ID exists
Expand Down
97 changes: 97 additions & 0 deletions pkg/csi/cinder/controllerserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,103 @@ func TestCreateVolumeFromSnapshot(t *testing.T) {
assert.Equal(FakeSnapshotID, actualRes.Volume.ContentSource.GetSnapshot().SnapshotId)
}

func TestCreateVolumeFromSnapshotWithTopology(t *testing.T) {
fakeCs, osmock := fakeControllerServer()

properties := map[string]string{cinderCSIClusterIDKey: FakeCluster}
// Expect empty AZ: the driver should clear the topology-derived AZ
// and let Cinder place the volume in the snapshot's AZ.
osmock.On("CreateVolume", FakeVolName, mock.AnythingOfType("int"), FakeVolType, "", FakeSnapshotID, "", "", properties).Return(&FakeVolFromSnapshot, nil)
osmock.On("GetVolumesByName", FakeVolName).Return(FakeVolListEmpty, nil)
osmock.On("GetBlockStorageOpts").Return(openstack.BlockStorageOpts{})

assert := assert.New(t)

src := &csi.VolumeContentSource{
Type: &csi.VolumeContentSource_Snapshot{
Snapshot: &csi.VolumeContentSource_SnapshotSource{
SnapshotId: FakeSnapshotID,
},
},
}

fakeReq := &csi.CreateVolumeRequest{
Name: FakeVolName,
VolumeCapabilities: []*csi.VolumeCapability{
{
AccessMode: &csi.VolumeCapability_AccessMode{
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
},
},
},
VolumeContentSource: src,
AccessibilityRequirements: &csi.TopologyRequirement{
Preferred: []*csi.Topology{
{
Segments: map[string]string{topologyKey: "az-2"},
},
},
},
}

actualRes, err := fakeCs.CreateVolume(FakeCtx, fakeReq)
if err != nil {
t.Errorf("failed to CreateVolume: %v", err)
}

assert.NotNil(actualRes.Volume)
assert.Equal(FakeSnapshotID, actualRes.Volume.ContentSource.GetSnapshot().SnapshotId)
}

func TestCreateVolumeFromSnapshotWithExplicitAvailability(t *testing.T) {
fakeCs, osmock := fakeControllerServer()

properties := map[string]string{cinderCSIClusterIDKey: FakeCluster}
osmock.On("CreateVolume", FakeVolName, mock.AnythingOfType("int"), FakeVolType, "explicit-az", FakeSnapshotID, "", "", properties).Return(&FakeVolFromSnapshot, nil)
osmock.On("GetVolumesByName", FakeVolName).Return(FakeVolListEmpty, nil)
osmock.On("GetBlockStorageOpts").Return(openstack.BlockStorageOpts{})

assert := assert.New(t)

src := &csi.VolumeContentSource{
Type: &csi.VolumeContentSource_Snapshot{
Snapshot: &csi.VolumeContentSource_SnapshotSource{
SnapshotId: FakeSnapshotID,
},
},
}

fakeReq := &csi.CreateVolumeRequest{
Name: FakeVolName,
Parameters: map[string]string{
"availability": "explicit-az",
},
VolumeCapabilities: []*csi.VolumeCapability{
{
AccessMode: &csi.VolumeCapability_AccessMode{
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
},
},
},
VolumeContentSource: src,
AccessibilityRequirements: &csi.TopologyRequirement{
Preferred: []*csi.Topology{
{
Segments: map[string]string{topologyKey: "az-2"},
},
},
},
}

actualRes, err := fakeCs.CreateVolume(FakeCtx, fakeReq)
if err != nil {
t.Errorf("failed to CreateVolume: %v", err)
}

assert.NotNil(actualRes.Volume)
assert.Equal(FakeSnapshotID, actualRes.Volume.ContentSource.GetSnapshot().SnapshotId)
}

func TestCreateVolumeFromSourceVolume(t *testing.T) {
fakeCs, osmock := fakeControllerServer()

Expand Down