diff --git a/client/pluginmanager/csimanager/fingerprint.go b/client/pluginmanager/csimanager/fingerprint.go index c35131a83..981bb63c6 100644 --- a/client/pluginmanager/csimanager/fingerprint.go +++ b/client/pluginmanager/csimanager/fingerprint.go @@ -168,6 +168,9 @@ func (p *pluginFingerprinter) buildNodeFingerprint(ctx context.Context, base *st return fp, err } fp.NodeInfo.RequiresNodeStageVolume = caps.HasStageUnstageVolume + fp.NodeInfo.SupportsStats = caps.HasGetVolumeStats + fp.NodeInfo.SupportsExpand = caps.HasExpandVolume + fp.NodeInfo.SupportsCondition = caps.HasVolumeCondition return fp, nil } diff --git a/nomad/structs/csi.go b/nomad/structs/csi.go index 8cdaa3403..a594071ad 100644 --- a/nomad/structs/csi.go +++ b/nomad/structs/csi.go @@ -952,6 +952,24 @@ const ( CSIControllerSupportsGet CSIControllerCapability = 11 ) +type CSINodeCapability byte + +const ( + + // CSINodeSupportsStageVolume indicates whether the client should + // Stage/Unstage volumes on this node. + CSINodeSupportsStageVolume CSINodeCapability = 0 + + // CSINodeSupportsStats indicates plugin support for GET_VOLUME_STATS + CSINodeSupportsStats CSINodeCapability = 1 + + // CSINodeSupportsExpand indicates plugin support for EXPAND_VOLUME + CSINodeSupportsExpand CSINodeCapability = 2 + + // CSINodeSupportsCondition indicates plugin support for VOLUME_CONDITION + CSINodeSupportsCondition CSINodeCapability = 3 +) + func (p *CSIPlugin) HasControllerCapability(cap CSIControllerCapability) bool { if len(p.Controllers) < 1 { return false @@ -991,6 +1009,29 @@ func (p *CSIPlugin) HasControllerCapability(cap CSIControllerCapability) bool { return false } +func (p *CSIPlugin) HasNodeCapability(cap CSINodeCapability) bool { + if len(p.Nodes) < 1 { + return false + } + // we're picking the first node because they should be uniform + // across the same version of the plugin + for _, c := range p.Nodes { + switch cap { + case CSINodeSupportsStageVolume: + return c.NodeInfo.RequiresNodeStageVolume + case CSINodeSupportsStats: + return c.NodeInfo.SupportsStats + case CSINodeSupportsExpand: + return c.NodeInfo.SupportsExpand + case CSINodeSupportsCondition: + return c.NodeInfo.SupportsCondition + default: + return false + } + } + return false +} + // AddPlugin adds a single plugin running on the node. Called from state.NodeUpdate in a // transaction func (p *CSIPlugin) AddPlugin(nodeID string, info *CSIInfo) error { diff --git a/nomad/structs/node.go b/nomad/structs/node.go index c8631ebff..98913a589 100644 --- a/nomad/structs/node.go +++ b/nomad/structs/node.go @@ -95,6 +95,15 @@ type CSINodeInfo struct { // RequiresNodeStageVolume indicates whether the client should Stage/Unstage // volumes on this node. RequiresNodeStageVolume bool + + // SupportsStats indicates plugin support for GET_VOLUME_STATS + SupportsStats bool + + // SupportsExpand indicates plugin support for EXPAND_VOLUME + SupportsExpand bool + + // SupportsCondition indicates plugin support for VOLUME_CONDITION + SupportsCondition bool } func (n *CSINodeInfo) Copy() *CSINodeInfo { diff --git a/plugins/csi/client_test.go b/plugins/csi/client_test.go index dbbd86b07..4233024b2 100644 --- a/plugins/csi/client_test.go +++ b/plugins/csi/client_test.go @@ -314,22 +314,7 @@ func TestClient_RPC_NodeGetCapabilities(t *testing.T) { ExpectedErr: fmt.Errorf("some grpc error"), }, { - Name: "ignores unknown capabilities", - Response: &csipbv1.NodeGetCapabilitiesResponse{ - Capabilities: []*csipbv1.NodeServiceCapability{ - { - Type: &csipbv1.NodeServiceCapability_Rpc{ - Rpc: &csipbv1.NodeServiceCapability_RPC{ - Type: csipbv1.NodeServiceCapability_RPC_EXPAND_VOLUME, - }, - }, - }, - }, - }, - ExpectedResponse: &NodeCapabilitySet{}, - }, - { - Name: "detects stage volumes capability", + Name: "detects multiple capabilities", Response: &csipbv1.NodeGetCapabilitiesResponse{ Capabilities: []*csipbv1.NodeServiceCapability{ { @@ -339,10 +324,18 @@ func TestClient_RPC_NodeGetCapabilities(t *testing.T) { }, }, }, + { + Type: &csipbv1.NodeServiceCapability_Rpc{ + Rpc: &csipbv1.NodeServiceCapability_RPC{ + Type: csipbv1.NodeServiceCapability_RPC_EXPAND_VOLUME, + }, + }, + }, }, }, ExpectedResponse: &NodeCapabilitySet{ HasStageUnstageVolume: true, + HasExpandVolume: true, }, }, } diff --git a/plugins/csi/plugin.go b/plugins/csi/plugin.go index 5b19d01d9..fdd112e0c 100644 --- a/plugins/csi/plugin.go +++ b/plugins/csi/plugin.go @@ -805,6 +805,9 @@ type ListSnapshotsResponse_Entry struct { type NodeCapabilitySet struct { HasStageUnstageVolume bool + HasGetVolumeStats bool + HasExpandVolume bool + HasVolumeCondition bool } func NewNodeCapabilitySet(resp *csipbv1.NodeGetCapabilitiesResponse) *NodeCapabilitySet { @@ -815,6 +818,12 @@ func NewNodeCapabilitySet(resp *csipbv1.NodeGetCapabilitiesResponse) *NodeCapabi switch c.Type { case csipbv1.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME: cs.HasStageUnstageVolume = true + case csipbv1.NodeServiceCapability_RPC_GET_VOLUME_STATS: + cs.HasGetVolumeStats = true + case csipbv1.NodeServiceCapability_RPC_EXPAND_VOLUME: + cs.HasExpandVolume = true + case csipbv1.NodeServiceCapability_RPC_VOLUME_CONDITION: + cs.HasVolumeCondition = true default: continue }