csi: accept list of caps during validation in volume register

When `nomad volume create` was introduced in Nomad 1.1.0, we changed the
volume spec to take a list of capabilities rather than a single capability, to
meet the requirements of the CSI spec. When a volume is registered via `nomad
volume register`, we should be using the same fields to validate the volume
with the controller plugin.
This commit is contained in:
Tim Gross 2021-06-03 15:47:55 -04:00 committed by Tim Gross
parent 4228bc7e9d
commit 8b2ecde5b4
6 changed files with 48 additions and 32 deletions

View File

@ -11,6 +11,7 @@ BUG FIXES:
* cli: Fixed a bug where `quota status` and `namespace status` commands may panic if the CLI targets a pre-1.1.0 cluster [[GH-10620](https://github.com/hashicorp/nomad/pull/10620)] * cli: Fixed a bug where `quota status` and `namespace status` commands may panic if the CLI targets a pre-1.1.0 cluster [[GH-10620](https://github.com/hashicorp/nomad/pull/10620)]
* cli: Fixed a bug where `alloc exec` may fail with "unexpected EOF" without returning the exit code after a command [[GH-10657](https://github.com/hashicorp/nomad/issues/10657)] * cli: Fixed a bug where `alloc exec` may fail with "unexpected EOF" without returning the exit code after a command [[GH-10657](https://github.com/hashicorp/nomad/issues/10657)]
* csi: Fixed a bug where `mount_options` were not passed to CSI controller plugins for validation during volume creation and mounting. [[GH-10643](https://github.com/hashicorp/nomad/issues/10643)] * csi: Fixed a bug where `mount_options` were not passed to CSI controller plugins for validation during volume creation and mounting. [[GH-10643](https://github.com/hashicorp/nomad/issues/10643)]
* csi: Fixed a bug where `capability` blocks were not passed to CSI controller plugins for validation for `nomad volume register` commands. [[GH-10703](https://github.com/hashicorp/nomad/issues/10703)]
* drivers/exec: Fixed a bug where `exec` and `java` tasks inherit the Nomad agent's `oom_score_adj` value [[GH-10698](https://github.com/hashicorp/nomad/issues/10698)] * drivers/exec: Fixed a bug where `exec` and `java` tasks inherit the Nomad agent's `oom_score_adj` value [[GH-10698](https://github.com/hashicorp/nomad/issues/10698)]
* quotas (Enterprise): Fixed a bug where stopped allocations for a failed deployment can be double-credited to quota limits, resulting in a quota limit bypass. [[GH-10694](https://github.com/hashicorp/nomad/issues/10694)] * quotas (Enterprise): Fixed a bug where stopped allocations for a failed deployment can be double-credited to quota limits, resulting in a quota limit bypass. [[GH-10694](https://github.com/hashicorp/nomad/issues/10694)]
* ui: Fixed a bug where exec would not work across regions. [[GH-10539](https://github.com/hashicorp/nomad/issues/10539)] * ui: Fixed a bug where exec would not work across regions. [[GH-10539](https://github.com/hashicorp/nomad/issues/10539)]

View File

@ -206,9 +206,11 @@ func TestCSIController_ValidateVolume(t *testing.T) {
CSIControllerQuery: structs.CSIControllerQuery{ CSIControllerQuery: structs.CSIControllerQuery{
PluginID: fakePlugin.Name, PluginID: fakePlugin.Name,
}, },
VolumeID: "1234-4321-1234-4321", VolumeID: "1234-4321-1234-4321",
AttachmentMode: nstructs.CSIVolumeAttachmentMode("bar"), VolumeCapabilities: []*nstructs.CSIVolumeCapability{{
AccessMode: nstructs.CSIVolumeAccessModeMultiNodeReader, AttachmentMode: nstructs.CSIVolumeAttachmentMode("bar"),
AccessMode: nstructs.CSIVolumeAccessModeMultiNodeReader,
}},
}, },
ExpectedErr: errors.New("CSI.ControllerValidateVolume: unknown volume attachment mode: bar"), ExpectedErr: errors.New("CSI.ControllerValidateVolume: unknown volume attachment mode: bar"),
}, },
@ -218,9 +220,11 @@ func TestCSIController_ValidateVolume(t *testing.T) {
CSIControllerQuery: structs.CSIControllerQuery{ CSIControllerQuery: structs.CSIControllerQuery{
PluginID: fakePlugin.Name, PluginID: fakePlugin.Name,
}, },
VolumeID: "1234-4321-1234-4321", VolumeID: "1234-4321-1234-4321",
AttachmentMode: nstructs.CSIVolumeAttachmentModeFilesystem, VolumeCapabilities: []*nstructs.CSIVolumeCapability{{
AccessMode: nstructs.CSIVolumeAccessMode("foo"), AttachmentMode: nstructs.CSIVolumeAttachmentModeFilesystem,
AccessMode: nstructs.CSIVolumeAccessMode("foo"),
}},
}, },
ExpectedErr: errors.New("CSI.ControllerValidateVolume: unknown volume access mode: foo"), ExpectedErr: errors.New("CSI.ControllerValidateVolume: unknown volume access mode: foo"),
}, },

View File

@ -54,10 +54,14 @@ func (c *CSIControllerQuery) SetControllerNodeID(nodeID string) {
type ClientCSIControllerValidateVolumeRequest struct { type ClientCSIControllerValidateVolumeRequest struct {
VolumeID string // note: this is the external ID VolumeID string // note: this is the external ID
VolumeCapabilities []*structs.CSIVolumeCapability
MountOptions *structs.CSIMountOptions
Secrets structs.CSISecrets
// COMPAT(1.1.1): the AttachmentMode and AccessMode fields are deprecated
// and replaced by the VolumeCapabilities field above
AttachmentMode structs.CSIVolumeAttachmentMode AttachmentMode structs.CSIVolumeAttachmentMode
AccessMode structs.CSIVolumeAccessMode AccessMode structs.CSIVolumeAccessMode
MountOptions *structs.CSIMountOptions
Secrets structs.CSISecrets
// Parameters as returned by storage provider in CreateVolumeResponse. // Parameters as returned by storage provider in CreateVolumeResponse.
// This field is optional. // This field is optional.
@ -75,18 +79,23 @@ func (c *ClientCSIControllerValidateVolumeRequest) ToCSIRequest() (*csi.Controll
return &csi.ControllerValidateVolumeRequest{}, nil return &csi.ControllerValidateVolumeRequest{}, nil
} }
caps, err := csi.VolumeCapabilityFromStructs(c.AttachmentMode, c.AccessMode, c.MountOptions) creq := &csi.ControllerValidateVolumeRequest{
if err != nil {
return nil, err
}
return &csi.ControllerValidateVolumeRequest{
ExternalID: c.VolumeID, ExternalID: c.VolumeID,
Secrets: c.Secrets, Secrets: c.Secrets,
Capabilities: caps, Capabilities: []*csi.VolumeCapability{},
Parameters: c.Parameters, Parameters: c.Parameters,
Context: c.Context, Context: c.Context,
}, nil }
for _, cap := range c.VolumeCapabilities {
ccap, err := csi.VolumeCapabilityFromStructs(
cap.AttachmentMode, cap.AccessMode, c.MountOptions)
if err != nil {
return nil, err
}
creq.Capabilities = append(creq.Capabilities, ccap)
}
return creq, nil
} }
type ClientCSIControllerValidateVolumeResponse struct { type ClientCSIControllerValidateVolumeResponse struct {

View File

@ -249,12 +249,11 @@ func (v *CSIVolume) controllerValidateVolume(req *structs.CSIVolumeRegisterReque
method := "ClientCSI.ControllerValidateVolume" method := "ClientCSI.ControllerValidateVolume"
cReq := &cstructs.ClientCSIControllerValidateVolumeRequest{ cReq := &cstructs.ClientCSIControllerValidateVolumeRequest{
VolumeID: vol.RemoteID(), VolumeID: vol.RemoteID(),
AttachmentMode: vol.AttachmentMode, VolumeCapabilities: vol.RequestedCapabilities,
AccessMode: vol.AccessMode, Secrets: vol.Secrets,
Secrets: vol.Secrets, Parameters: vol.Parameters,
Parameters: vol.Parameters, Context: vol.Context,
Context: vol.Context,
} }
cReq.PluginID = plugin.ID cReq.PluginID = plugin.ID
cResp := &cstructs.ClientCSIControllerValidateVolumeResponse{} cResp := &cstructs.ClientCSIControllerValidateVolumeResponse{}

View File

@ -664,14 +664,14 @@ func TestClient_RPC_ControllerValidateVolume(t *testing.T) {
_, cc, _, client := newTestClient() _, cc, _, client := newTestClient()
defer client.Close() defer client.Close()
requestedCaps := &VolumeCapability{ requestedCaps := []*VolumeCapability{{
AccessType: tc.AccessType, AccessType: tc.AccessType,
AccessMode: tc.AccessMode, AccessMode: tc.AccessMode,
MountVolume: &structs.CSIMountOptions{ // should be ignored MountVolume: &structs.CSIMountOptions{ // should be ignored
FSType: "ext4", FSType: "ext4",
MountFlags: []string{"noatime", "errors=remount-ro"}, MountFlags: []string{"noatime", "errors=remount-ro"},
}, },
} }}
req := &ControllerValidateVolumeRequest{ req := &ControllerValidateVolumeRequest{
ExternalID: "volumeID", ExternalID: "volumeID",
Secrets: structs.CSISecrets{}, Secrets: structs.CSISecrets{},

View File

@ -349,7 +349,7 @@ func NewControllerCapabilitySet(resp *csipbv1.ControllerGetCapabilitiesResponse)
type ControllerValidateVolumeRequest struct { type ControllerValidateVolumeRequest struct {
ExternalID string ExternalID string
Secrets structs.CSISecrets Secrets structs.CSISecrets
Capabilities *VolumeCapability Capabilities []*VolumeCapability
Parameters map[string]string Parameters map[string]string
Context map[string]string Context map[string]string
} }
@ -359,14 +359,17 @@ func (r *ControllerValidateVolumeRequest) ToCSIRepresentation() *csipbv1.Validat
return nil return nil
} }
caps := make([]*csipbv1.VolumeCapability, 0, len(r.Capabilities))
for _, cap := range r.Capabilities {
caps = append(caps, cap.ToCSIRepresentation())
}
return &csipbv1.ValidateVolumeCapabilitiesRequest{ return &csipbv1.ValidateVolumeCapabilitiesRequest{
VolumeId: r.ExternalID, VolumeId: r.ExternalID,
VolumeContext: r.Context, VolumeContext: r.Context,
VolumeCapabilities: []*csipbv1.VolumeCapability{ VolumeCapabilities: caps,
r.Capabilities.ToCSIRepresentation(), Parameters: r.Parameters,
}, Secrets: r.Secrets,
Parameters: r.Parameters,
Secrets: r.Secrets,
} }
} }