volume delete: allow prefix for ID (#24997)

The `volume delete` command doesn't allow using a prefix for the volume ID for
either CSI or dynamic host volumes. Use a prefix search and wildcard namespace
as we do for other CLI commands.

Ref: https://hashicorp.atlassian.net/browse/NET-12057
This commit is contained in:
Tim Gross
2025-02-03 11:29:43 -05:00
committed by GitHub
parent d9bb241b43
commit 7929939116
3 changed files with 58 additions and 4 deletions

3
.changelog/24997.txt Normal file
View File

@@ -0,0 +1,3 @@
```release-note:improvement
csi: Accept ID prefixes and wildcard namespace for the volume delete command
```

View File

@@ -9,6 +9,7 @@ import (
"github.com/hashicorp/nomad/api" "github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/api/contexts" "github.com/hashicorp/nomad/api/contexts"
"github.com/hashicorp/nomad/helper"
flaghelper "github.com/hashicorp/nomad/helper/flags" flaghelper "github.com/hashicorp/nomad/helper/flags"
"github.com/posener/complete" "github.com/posener/complete"
) )
@@ -136,7 +137,31 @@ func (c *VolumeDeleteCommand) deleteCSIVolume(client *api.Client, volID string,
} }
} }
err := client.CSIVolumes().DeleteOpts(&api.CSIVolumeDeleteRequest{ // get a CSI volume that matches the given prefix or a list of all matches
// if an exact match is not found.
stub, possible, err := getByPrefix[api.CSIVolumeListStub]("volumes", client.CSIVolumes().List,
func(vol *api.CSIVolumeListStub, prefix string) bool { return vol.ID == prefix },
&api.QueryOptions{
Prefix: volID,
Namespace: c.namespace,
})
if err != nil {
c.Ui.Error(fmt.Sprintf("Could not find existing volume to delete: %s", err))
return 1
}
if len(possible) > 0 {
out, err := csiFormatVolumes(possible, false, "")
if err != nil {
c.Ui.Error(fmt.Sprintf("Error formatting: %s", err))
return 1
}
c.Ui.Error(fmt.Sprintf("Prefix matched multiple volumes\n\n%s", out))
return 1
}
volID = stub.ID
c.namespace = stub.Namespace
err = client.CSIVolumes().DeleteOpts(&api.CSIVolumeDeleteRequest{
ExternalVolumeID: volID, ExternalVolumeID: volID,
Secrets: secrets, Secrets: secrets,
}, nil) }, nil)
@@ -150,6 +175,26 @@ func (c *VolumeDeleteCommand) deleteCSIVolume(client *api.Client, volID string,
} }
func (c *VolumeDeleteCommand) deleteHostVolume(client *api.Client, volID string) int { func (c *VolumeDeleteCommand) deleteHostVolume(client *api.Client, volID string) int {
if !helper.IsUUID(volID) {
stub, possible, err := getHostVolumeByPrefix(client, volID, c.namespace)
if err != nil {
c.Ui.Error(fmt.Sprintf("Could not find existing volume to delete: %s", err))
return 1
}
if len(possible) > 0 {
out, err := formatHostVolumes(possible, formatOpts{short: true})
if err != nil {
c.Ui.Error(fmt.Sprintf("Error formatting: %s", err))
return 1
}
c.Ui.Error(fmt.Sprintf("Prefix matched multiple volumes\n\n%s", out))
return 1
}
volID = stub.ID
c.namespace = stub.Namespace
}
_, err := client.HostVolumes().Delete(&api.HostVolumeDeleteRequest{ID: volID}, nil) _, err := client.HostVolumes().Delete(&api.HostVolumeDeleteRequest{ID: volID}, nil)
if err != nil { if err != nil {
c.Ui.Error(fmt.Sprintf("Error deleting volume: %s", err)) c.Ui.Error(fmt.Sprintf("Error deleting volume: %s", err))

View File

@@ -83,11 +83,17 @@ capability {
must.StrContains(t, ui.ErrorWriter.String(), "no such volume") must.StrContains(t, ui.ErrorWriter.String(), "no such volume")
ui.ErrorWriter.Reset() ui.ErrorWriter.Reset()
// fix the namespace // missing the namespace, but use a prefix
args = []string{"-address", url, "-type", "host", "-namespace", "prod", id} args = []string{"-address", url, "-type", "host", id[:12]}
code = cmd.Run(args)
must.Eq(t, 1, code)
must.StrContains(t, ui.ErrorWriter.String(), "no volumes with prefix")
ui.ErrorWriter.Reset()
// fix the namespace, and use a prefix
args = []string{"-address", url, "-type", "host", "-namespace", "prod", id[:12]}
code = cmd.Run(args) code = cmd.Run(args)
must.Eq(t, 0, code, must.Sprintf("got error: %s", ui.ErrorWriter.String())) must.Eq(t, 0, code, must.Sprintf("got error: %s", ui.ErrorWriter.String()))
out = ui.OutputWriter.String() out = ui.OutputWriter.String()
must.StrContains(t, out, fmt.Sprintf("Successfully deleted volume %q!", id)) must.StrContains(t, out, fmt.Sprintf("Successfully deleted volume %q!", id))
} }