CSI: display plugin capabilities in verbose status (#12116)

The behaviors of CSI plugins are governed by their capabilities as
defined by the CSI specification. When debugging plugin issues, it's
useful to know which behaviors are expected so they can be matched
against RPC calls made to the plugin allocations.

Expose the plugin capabilities as named in the CSI spec in the `nomad
plugin status -verbose` output.
This commit is contained in:
Tim Gross 2022-02-24 13:51:38 -05:00 committed by GitHub
parent 61d79e75b0
commit 13ea2c7fb3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 100 additions and 1 deletions

3
.changelog/12116.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:improvement
csi: Display plugin capabilities in `nomad plugin status -verbose` output
```

View File

@ -105,9 +105,105 @@ func (c *PluginStatusCommand) csiFormatPlugin(plug *api.CSIPlugin) (string, erro
return formatKV(output), nil return formatKV(output), nil
} }
full := []string{formatKV(output)}
if c.verbose {
controllerCaps := c.formatControllerCaps(plug.Controllers)
if controllerCaps != "" {
full = append(full, c.Colorize().Color("\n[bold]Controller Capabilities[reset]"))
full = append(full, controllerCaps)
}
nodeCaps := c.formatNodeCaps(plug.Nodes)
if nodeCaps != "" {
full = append(full, c.Colorize().Color("\n[bold]Node Capabilities[reset]"))
full = append(full, nodeCaps)
}
}
// Format the allocs // Format the allocs
banner := c.Colorize().Color("\n[bold]Allocations[reset]") banner := c.Colorize().Color("\n[bold]Allocations[reset]")
allocs := formatAllocListStubs(plug.Allocations, c.verbose, c.length) allocs := formatAllocListStubs(plug.Allocations, c.verbose, c.length)
full := []string{formatKV(output), banner, allocs} full = append(full, banner)
full = append(full, allocs)
return strings.Join(full, "\n"), nil return strings.Join(full, "\n"), nil
} }
func (c *PluginStatusCommand) formatControllerCaps(controllers map[string]*api.CSIInfo) string {
caps := []string{}
for _, controller := range controllers {
switch info := controller.ControllerInfo; {
case info.SupportsCreateDelete:
caps = append(caps, "CREATE_DELETE_VOLUME")
fallthrough
case info.SupportsAttachDetach:
caps = append(caps, "CONTROLLER_ATTACH_DETACH")
fallthrough
case info.SupportsListVolumes:
caps = append(caps, "LIST_VOLUMES")
fallthrough
case info.SupportsGetCapacity:
caps = append(caps, "GET_CAPACITY")
fallthrough
case info.SupportsCreateDeleteSnapshot:
caps = append(caps, "CREATE_DELETE_SNAPSHOT")
fallthrough
case info.SupportsListSnapshots:
caps = append(caps, "CREATE_LIST_SNAPSHOTS")
fallthrough
case info.SupportsClone:
caps = append(caps, "CLONE_VOLUME")
fallthrough
case info.SupportsReadOnlyAttach:
caps = append(caps, "ATTACH_READONLY")
fallthrough
case info.SupportsExpand:
caps = append(caps, "EXPAND_VOLUME")
fallthrough
case info.SupportsListVolumesAttachedNodes:
caps = append(caps, "LIST_VOLUMES_PUBLISHED_NODES")
fallthrough
case info.SupportsCondition:
caps = append(caps, "VOLUME_CONDITION")
fallthrough
case info.SupportsGet:
caps = append(caps, "GET_VOLUME")
fallthrough
default:
}
break
}
if len(caps) == 0 {
return ""
}
return strings.Join(caps, "\n\t")
}
func (c *PluginStatusCommand) formatNodeCaps(nodes map[string]*api.CSIInfo) string {
caps := []string{}
for _, node := range nodes {
switch info := node.NodeInfo; {
case info.RequiresNodeStageVolume:
caps = append(caps, "STAGE_UNSTAGE_VOLUME")
fallthrough
case info.SupportsStats:
caps = append(caps, "GET_VOLUME_STATS")
fallthrough
case info.SupportsExpand:
caps = append(caps, "EXPAND_VOLUME")
fallthrough
case info.SupportsCondition:
caps = append(caps, "VOLUME_CONDITION")
fallthrough
default:
}
break
}
if len(caps) == 0 {
return ""
}
return " " + strings.Join(caps, "\n ")
}