github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/command/volume_deregister.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/hashicorp/nomad/api/contexts" 8 "github.com/posener/complete" 9 ) 10 11 type VolumeDeregisterCommand struct { 12 Meta 13 } 14 15 func (c *VolumeDeregisterCommand) Help() string { 16 helpText := ` 17 Usage: nomad volume deregister [options] <id> 18 19 Remove an unused volume from Nomad. 20 21 When ACLs are enabled, this command requires a token with the 22 'csi-write-volume' capability for the volume's namespace. 23 24 General Options: 25 26 ` + generalOptionsUsage(usageOptsDefault) + ` 27 28 Volume Deregister Options: 29 30 -force 31 Force deregistration of the volume and immediately drop claims for 32 terminal allocations. Returns an error if the volume has running 33 allocations. This does not detach the volume from client nodes. 34 ` 35 return strings.TrimSpace(helpText) 36 } 37 38 func (c *VolumeDeregisterCommand) AutocompleteFlags() complete.Flags { 39 return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient), 40 complete.Flags{ 41 "-force": complete.PredictNothing, 42 }) 43 } 44 45 func (c *VolumeDeregisterCommand) AutocompleteArgs() complete.Predictor { 46 return complete.PredictFunc(func(a complete.Args) []string { 47 client, err := c.Meta.Client() 48 if err != nil { 49 return nil 50 } 51 52 // When multiple volume types are implemented, this search should merge contexts 53 resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Volumes, nil) 54 if err != nil { 55 return []string{} 56 } 57 return resp.Matches[contexts.Volumes] 58 }) 59 } 60 61 func (c *VolumeDeregisterCommand) Synopsis() string { 62 return "Remove a volume" 63 } 64 65 func (c *VolumeDeregisterCommand) Name() string { return "volume deregister" } 66 67 func (c *VolumeDeregisterCommand) Run(args []string) int { 68 var force bool 69 flags := c.Meta.FlagSet(c.Name(), FlagSetClient) 70 flags.Usage = func() { c.Ui.Output(c.Help()) } 71 flags.BoolVar(&force, "force", false, "Force deregister and drop claims") 72 73 if err := flags.Parse(args); err != nil { 74 c.Ui.Error(fmt.Sprintf("Error parsing arguments %s", err)) 75 return 1 76 } 77 78 // Check that we get exactly one argument 79 args = flags.Args() 80 if l := len(args); l != 1 { 81 c.Ui.Error("This command takes one argument: <id>") 82 c.Ui.Error(commandErrorText(c)) 83 return 1 84 } 85 volID := args[0] 86 87 // Get the HTTP client 88 client, err := c.Meta.Client() 89 if err != nil { 90 c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) 91 return 1 92 } 93 94 // Confirm the -force flag 95 if force { 96 question := fmt.Sprintf("Are you sure you want to force deregister volume %q? [y/N]", volID) 97 answer, err := c.Ui.Ask(question) 98 if err != nil { 99 c.Ui.Error(fmt.Sprintf("Failed to parse answer: %v", err)) 100 return 1 101 } 102 103 if answer == "" || strings.ToLower(answer)[0] == 'n' { 104 // No case 105 c.Ui.Output("Cancelling volume deregister") 106 return 0 107 } else if strings.ToLower(answer)[0] == 'y' && len(answer) > 1 { 108 // Non exact match yes 109 c.Ui.Output("For confirmation, an exact ‘y’ is required.") 110 return 0 111 } else if answer != "y" { 112 c.Ui.Output("No confirmation detected. For confirmation, an exact 'y' is required.") 113 return 1 114 } 115 } 116 117 // Deregister only works on CSI volumes, but could be extended to support other 118 // network interfaces or host volumes 119 err = client.CSIVolumes().Deregister(volID, force, nil) 120 if err != nil { 121 c.Ui.Error(fmt.Sprintf("Error deregistering volume: %s", err)) 122 return 1 123 } 124 125 return 0 126 }