csi: get plugin ID for creating snapshot from volume, not args (#12195)

The `CreateSnapshot` RPC expects a plugin ID to be set by the API, but
in the common case of the `nomad volume snapshot create` command, we
don't ask the user for the plugin ID because it's available from the
volume we're snapshotting.

Change the order of the RPC so that we get the volume first and then
use the volume's plugin ID for the plugin if the API didn't set the
value.
This commit is contained in:
Tim Gross 2022-03-07 09:06:50 -05:00 committed by GitHub
parent b776c1c196
commit 3a692a4360
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 25 additions and 18 deletions

3
.changelog/12195.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:bug
csi: Fixed a bug where creating snapshots required a plugin ID instead of falling back to the volume's plugin ID
```

View File

@ -1095,22 +1095,6 @@ func (v *CSIVolume) CreateSnapshot(args *structs.CSISnapshotCreateRequest, reply
return fmt.Errorf("snapshot cannot be nil") return fmt.Errorf("snapshot cannot be nil")
} }
plugin, err := state.CSIPluginByID(nil, snap.PluginID)
if err != nil {
multierror.Append(&mErr,
fmt.Errorf("error querying plugin %q: %v", snap.PluginID, err))
continue
}
if plugin == nil {
multierror.Append(&mErr, fmt.Errorf("no such plugin %q", snap.PluginID))
continue
}
if !plugin.HasControllerCapability(structs.CSIControllerSupportsCreateDeleteSnapshot) {
multierror.Append(&mErr,
fmt.Errorf("plugin %q does not support snapshot", snap.PluginID))
continue
}
vol, err := state.CSIVolumeByID(nil, args.RequestNamespace(), snap.SourceVolumeID) vol, err := state.CSIVolumeByID(nil, args.RequestNamespace(), snap.SourceVolumeID)
if err != nil { if err != nil {
multierror.Append(&mErr, fmt.Errorf("error querying volume %q: %v", snap.SourceVolumeID, err)) multierror.Append(&mErr, fmt.Errorf("error querying volume %q: %v", snap.SourceVolumeID, err))
@ -1121,13 +1105,34 @@ func (v *CSIVolume) CreateSnapshot(args *structs.CSISnapshotCreateRequest, reply
continue continue
} }
pluginID := snap.PluginID
if pluginID == "" {
pluginID = vol.PluginID
}
plugin, err := state.CSIPluginByID(nil, pluginID)
if err != nil {
multierror.Append(&mErr,
fmt.Errorf("error querying plugin %q: %v", pluginID, err))
continue
}
if plugin == nil {
multierror.Append(&mErr, fmt.Errorf("no such plugin %q", pluginID))
continue
}
if !plugin.HasControllerCapability(structs.CSIControllerSupportsCreateDeleteSnapshot) {
multierror.Append(&mErr,
fmt.Errorf("plugin %q does not support snapshot", pluginID))
continue
}
cReq := &cstructs.ClientCSIControllerCreateSnapshotRequest{ cReq := &cstructs.ClientCSIControllerCreateSnapshotRequest{
ExternalSourceVolumeID: vol.ExternalID, ExternalSourceVolumeID: vol.ExternalID,
Name: snap.Name, Name: snap.Name,
Secrets: vol.Secrets, Secrets: vol.Secrets,
Parameters: snap.Parameters, Parameters: snap.Parameters,
} }
cReq.PluginID = plugin.ID cReq.PluginID = pluginID
cResp := &cstructs.ClientCSIControllerCreateSnapshotResponse{} cResp := &cstructs.ClientCSIControllerCreateSnapshotResponse{}
err = v.srv.RPC(method, cReq, cResp) err = v.srv.RPC(method, cReq, cResp)
if err != nil { if err != nil {

View File

@ -1200,7 +1200,6 @@ func TestCSIVolumeEndpoint_CreateSnapshot(t *testing.T) {
SourceVolumeID: "test-volume0", SourceVolumeID: "test-volume0",
Secrets: structs.CSISecrets{"mysecret": "secretvalue"}, Secrets: structs.CSISecrets{"mysecret": "secretvalue"},
Parameters: map[string]string{"myparam": "paramvalue"}, Parameters: map[string]string{"myparam": "paramvalue"},
PluginID: "minnie",
}}, }},
WriteRequest: structs.WriteRequest{ WriteRequest: structs.WriteRequest{
Region: "global", Region: "global",