csi: fix prefix queries for plugin list RPC (#12194)
The `CSIPlugin.List` RPC was intended to accept a prefix to filter the list of plugins being listed. This was being accidentally being done in the state store instead, which contributed to incorrect filtering behavior for plugins in the `volume plugin status` command. Move the prefix matching into the RPC so that it calls the prefix-matching method in the state store if we're looking for a prefix. Update the `plugin status command` to accept a prefix for the plugin ID argument so that it matches the expected behavior of other commands.
This commit is contained in:
parent
5c3d2315cc
commit
b776c1c196
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:bug
|
||||||
|
csi: Fixed a bug where `plugin status` commands could choose the incorrect plugin if a plugin with a name that matched the same prefix existed.
|
||||||
|
```
|
|
@ -37,6 +37,29 @@ func (c *PluginStatusCommand) csiStatus(client *api.Client, id string) int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// filter by plugin if a plugin ID was passed
|
||||||
|
plugs, _, err := client.CSIPlugins().List(&api.QueryOptions{Prefix: id})
|
||||||
|
if err != nil {
|
||||||
|
c.Ui.Error(fmt.Sprintf("Error querying CSI plugins: %s", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if len(plugs) == 0 {
|
||||||
|
c.Ui.Error(fmt.Sprintf("No plugins(s) with prefix or ID %q found", id))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if len(plugs) > 1 {
|
||||||
|
if id != plugs[0].ID {
|
||||||
|
out, err := c.csiFormatPlugins(plugs)
|
||||||
|
if err != nil {
|
||||||
|
c.Ui.Error(fmt.Sprintf("Error formatting: %s", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
c.Ui.Error(fmt.Sprintf("Prefix matched multiple plugins\n\n%s", out))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
id = plugs[0].ID
|
||||||
|
|
||||||
// Lookup matched a single plugin
|
// Lookup matched a single plugin
|
||||||
plug, _, err := client.CSIPlugins().Info(id, nil)
|
plug, _, err := client.CSIPlugins().Info(id, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1294,10 +1294,20 @@ func (v *CSIPlugin) List(args *structs.CSIPluginListRequest, reply *structs.CSIP
|
||||||
queryOpts: &args.QueryOptions,
|
queryOpts: &args.QueryOptions,
|
||||||
queryMeta: &reply.QueryMeta,
|
queryMeta: &reply.QueryMeta,
|
||||||
run: func(ws memdb.WatchSet, state *state.StateStore) error {
|
run: func(ws memdb.WatchSet, state *state.StateStore) error {
|
||||||
// Query all plugins
|
|
||||||
iter, err := state.CSIPlugins(ws)
|
var iter memdb.ResultIterator
|
||||||
if err != nil {
|
var err error
|
||||||
return err
|
if args.Prefix != "" {
|
||||||
|
iter, err = state.CSIPluginsByIDPrefix(ws, args.Prefix)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Query all plugins
|
||||||
|
iter, err = state.CSIPlugins(ws)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect results
|
// Collect results
|
||||||
|
|
|
@ -1100,6 +1100,7 @@ func TestCSIVolumeEndpoint_ListExternal(t *testing.T) {
|
||||||
// List external volumes; note that none of these exist in the state store
|
// List external volumes; note that none of these exist in the state store
|
||||||
|
|
||||||
req := &structs.CSIVolumeExternalListRequest{
|
req := &structs.CSIVolumeExternalListRequest{
|
||||||
|
PluginID: "minnie",
|
||||||
QueryOptions: structs.QueryOptions{
|
QueryOptions: structs.QueryOptions{
|
||||||
Region: "global",
|
Region: "global",
|
||||||
Namespace: structs.DefaultNamespace,
|
Namespace: structs.DefaultNamespace,
|
||||||
|
@ -1371,8 +1372,8 @@ func TestCSIVolumeEndpoint_ListSnapshots(t *testing.T) {
|
||||||
require.NoError(t, state.UpsertNode(structs.MsgTypeTestSetup, index, node))
|
require.NoError(t, state.UpsertNode(structs.MsgTypeTestSetup, index, node))
|
||||||
|
|
||||||
// List snapshots
|
// List snapshots
|
||||||
|
|
||||||
req := &structs.CSISnapshotListRequest{
|
req := &structs.CSISnapshotListRequest{
|
||||||
|
PluginID: "minnie",
|
||||||
Secrets: structs.CSISecrets{
|
Secrets: structs.CSISecrets{
|
||||||
"secret-key-1": "secret-val-1",
|
"secret-key-1": "secret-val-1",
|
||||||
},
|
},
|
||||||
|
|
|
@ -2696,7 +2696,7 @@ func (s *StateStore) CSIPluginByID(ws memdb.WatchSet, id string) (*structs.CSIPl
|
||||||
// CSIPluginByIDTxn returns a named CSIPlugin
|
// CSIPluginByIDTxn returns a named CSIPlugin
|
||||||
func (s *StateStore) CSIPluginByIDTxn(txn Txn, ws memdb.WatchSet, id string) (*structs.CSIPlugin, error) {
|
func (s *StateStore) CSIPluginByIDTxn(txn Txn, ws memdb.WatchSet, id string) (*structs.CSIPlugin, error) {
|
||||||
|
|
||||||
watchCh, obj, err := txn.FirstWatch("csi_plugins", "id_prefix", id)
|
watchCh, obj, err := txn.FirstWatch("csi_plugins", "id", id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("csi_plugin lookup failed: %s %v", id, err)
|
return nil, fmt.Errorf("csi_plugin lookup failed: %s %v", id, err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue