dynamic host volumes: autocomplete for CLI (#24533)

Adds dynamic host volumes to argument autocomplete for the `volume status` and
`volume delete` commands. Adds flag autocompletion for those commands plus
`volume create`.

Ref: https://github.com/hashicorp/nomad/pull/24479
This commit is contained in:
Tim Gross
2024-12-02 09:11:18 -05:00
parent d1352b285d
commit e3864a5f4a
8 changed files with 60 additions and 31 deletions

View File

@@ -13,6 +13,7 @@ import (
"time"
humanize "github.com/dustin/go-humanize"
"github.com/hashicorp/go-set/v3"
"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/api/contexts"
"github.com/hashicorp/nomad/helper/pointer"
@@ -129,8 +130,12 @@ func (c *NodeStatusCommand) AutocompleteFlags() complete.Flags {
}
func (c *NodeStatusCommand) AutocompleteArgs() complete.Predictor {
return nodePredictor(c.Client, nil)
}
func nodePredictor(factory ApiClientFactory, filter *set.Set[string]) complete.Predictor {
return complete.PredictFunc(func(a complete.Args) []string {
client, err := c.Meta.Client()
client, err := factory()
if err != nil {
return nil
}

View File

@@ -58,21 +58,10 @@ func (c *PluginStatusCommand) Synopsis() string {
return "Display status information about a plugin"
}
// predictVolumeType is also used in volume_status
var predictVolumeType = complete.PredictFunc(func(a complete.Args) []string {
types := []string{"csi"}
for _, t := range types {
if strings.Contains(t, a.Last) {
return []string{t}
}
}
return nil
})
func (c *PluginStatusCommand) AutocompleteFlags() complete.Flags {
return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
complete.Flags{
"-type": predictVolumeType,
"-type": complete.PredictSet("csi"),
"-short": complete.PredictNothing,
"-verbose": complete.PredictNothing,
"-json": complete.PredictNothing,

View File

@@ -52,7 +52,11 @@ Create Options:
}
func (c *VolumeCreateCommand) AutocompleteFlags() complete.Flags {
return c.Meta.AutocompleteFlags(FlagSetClient)
return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
complete.Flags{
"-detach": complete.PredictNothing,
"-verbose": complete.PredictNothing,
})
}
func (c *VolumeCreateCommand) AutocompleteArgs() complete.Predictor {

View File

@@ -40,7 +40,7 @@ Delete Options:
-secret
Secrets to pass to the plugin to delete the snapshot. Accepts multiple
flags in the form -secret key=value
flags in the form -secret key=value. Only available for CSI volumes.
-type <type>
Type of volume to delete. Must be one of "csi" or "host". Defaults to "csi".
@@ -50,7 +50,10 @@ Delete Options:
func (c *VolumeDeleteCommand) AutocompleteFlags() complete.Flags {
return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
complete.Flags{})
complete.Flags{
"-type": complete.PredictSet("csi", "host"),
"-secret": complete.PredictNothing,
})
}
func (c *VolumeDeleteCommand) AutocompleteArgs() complete.Predictor {
@@ -66,11 +69,11 @@ func (c *VolumeDeleteCommand) AutocompleteArgs() complete.Predictor {
}
matches := resp.Matches[contexts.Volumes]
resp, _, err = client.Search().PrefixSearch(a.Last, contexts.Nodes, nil)
resp, _, err = client.Search().PrefixSearch(a.Last, contexts.HostVolumes, nil)
if err != nil {
return []string{}
}
matches = append(matches, resp.Matches[contexts.Nodes]...)
matches = append(matches, resp.Matches[contexts.HostVolumes]...)
return matches
})
}

View File

@@ -12,6 +12,7 @@ import (
"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/ci"
"github.com/mitchellh/cli"
"github.com/posener/complete"
"github.com/shoenig/test/must"
)
@@ -62,8 +63,18 @@ capability {
ui.OutputWriter.Reset()
// autocomplete
cmd := &VolumeDeleteCommand{Meta: Meta{Ui: ui, namespace: "*", flagAddress: url}}
prefix := id[:len(id)-5]
cargs := complete.Args{Last: prefix}
predictor := cmd.AutocompleteArgs()
res := predictor.Predict(cargs)
must.SliceLen(t, 1, res)
must.Eq(t, id, res[0])
// missing the namespace
cmd := &VolumeDeleteCommand{Meta: Meta{Ui: ui}}
cmd = &VolumeDeleteCommand{Meta: Meta{Ui: ui}}
args = []string{"-address", url, "-type", "host", id}
code = cmd.Run(args)
must.Eq(t, 1, code)
@@ -76,4 +87,5 @@ capability {
must.Eq(t, 0, code, must.Sprintf("got error: %s", ui.ErrorWriter.String()))
out = ui.OutputWriter.String()
must.StrContains(t, out, fmt.Sprintf("Successfully deleted volume %q!", id))
}

View File

@@ -53,7 +53,6 @@ func (c *VolumeDeregisterCommand) AutocompleteArgs() complete.Predictor {
return nil
}
// When multiple volume types are implemented, this search should merge contexts
resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Volumes, nil)
if err != nil {
return []string{}

View File

@@ -69,15 +69,13 @@ func (c *VolumeStatusCommand) Synopsis() string {
func (c *VolumeStatusCommand) AutocompleteFlags() complete.Flags {
return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
complete.Flags{
"-type": predictVolumeType,
"-type": complete.PredictSet("csi", "host"),
"-short": complete.PredictNothing,
"-verbose": complete.PredictNothing,
"-json": complete.PredictNothing,
"-t": complete.PredictAnything,
// TODO(1.10.0): wire-up predictions for nodes and node pools
"-node": complete.PredictNothing,
"-node-pool": complete.PredictNothing,
"-node": nodePredictor(c.Client, nil),
"-node-pool": nodePoolPredictor(c.Client, nil),
})
}
@@ -92,7 +90,14 @@ func (c *VolumeStatusCommand) AutocompleteArgs() complete.Predictor {
if err != nil {
return []string{}
}
return resp.Matches[contexts.Volumes]
matches := resp.Matches[contexts.Volumes]
resp, _, err = client.Search().PrefixSearch(a.Last, contexts.HostVolumes, nil)
if err != nil {
return []string{}
}
matches = append(matches, resp.Matches[contexts.HostVolumes]...)
return matches
})
}

View File

@@ -12,6 +12,7 @@ import (
"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/ci"
"github.com/mitchellh/cli"
"github.com/posener/complete"
"github.com/shoenig/test/must"
)
@@ -141,8 +142,19 @@ capability {
ui.OutputWriter.Reset()
// autocomplete
cmd := &VolumeStatusCommand{Meta: Meta{Ui: ui, namespace: "*", flagAddress: url}}
cmd.Meta.namespace = "*"
prefix := id[:len(id)-5]
cargs := complete.Args{Last: prefix}
predictor := cmd.AutocompleteArgs()
res := predictor.Predict(cargs)
must.SliceLen(t, 1, res)
must.Eq(t, id, res[0])
// missing the namespace
cmd := &VolumeStatusCommand{Meta: Meta{Ui: ui}}
cmd = &VolumeStatusCommand{Meta: Meta{Ui: ui}}
args = []string{"-address", url, "-type", "host", id}
code = cmd.Run(args)
must.Eq(t, 1, code)