From c12c90262d36c1cbe9fe2cccc85bb28b43e4bf6c Mon Sep 17 00:00:00 2001 From: Tim Gross Date: Thu, 1 Apr 2021 15:39:38 -0400 Subject: [PATCH] CSI: fingerprint detailed node capabilities In order to support new node RPCs, we need to fingerprint plugin capabilities in more detail. This changeset mirrors recent work to fingerprint controller capabilities, but is not yet in use by any Nomad RPC. --- .../pluginmanager/csimanager/fingerprint.go | 3 ++ nomad/structs/csi.go | 41 +++++++++++++++++++ nomad/structs/node.go | 9 ++++ plugins/csi/client_test.go | 25 ++++------- plugins/csi/plugin.go | 9 ++++ 5 files changed, 71 insertions(+), 16 deletions(-) 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 }