github.imxd.top/hashicorp/consul@v1.4.5/command/kv/del/kv_delete.go (about)

     1  package del
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  
     7  	"github.com/hashicorp/consul/api"
     8  	"github.com/hashicorp/consul/command/flags"
     9  	"github.com/mitchellh/cli"
    10  )
    11  
    12  func New(ui cli.Ui) *cmd {
    13  	c := &cmd{UI: ui}
    14  	c.init()
    15  	return c
    16  }
    17  
    18  type cmd struct {
    19  	UI          cli.Ui
    20  	flags       *flag.FlagSet
    21  	http        *flags.HTTPFlags
    22  	help        string
    23  	cas         bool
    24  	modifyIndex uint64
    25  	recurse     bool
    26  }
    27  
    28  func (c *cmd) init() {
    29  	c.flags = flag.NewFlagSet("", flag.ContinueOnError)
    30  	c.flags.BoolVar(&c.cas, "cas", false,
    31  		"Perform a Check-And-Set operation. Specifying this value also requires "+
    32  			"the -modify-index flag to be set. The default value is false.")
    33  	c.flags.Uint64Var(&c.modifyIndex, "modify-index", 0,
    34  		"Unsigned integer representing the ModifyIndex of the key. This is "+
    35  			"used in combination with the -cas flag.")
    36  	c.flags.BoolVar(&c.recurse, "recurse", false,
    37  		"Recursively delete all keys with the path. The default value is false.")
    38  
    39  	c.http = &flags.HTTPFlags{}
    40  	flags.Merge(c.flags, c.http.ClientFlags())
    41  	flags.Merge(c.flags, c.http.ServerFlags())
    42  	c.help = flags.Usage(help, c.flags)
    43  }
    44  
    45  func (c *cmd) Run(args []string) int {
    46  	if err := c.flags.Parse(args); err != nil {
    47  		return 1
    48  	}
    49  
    50  	key := ""
    51  
    52  	// Check for arg validation
    53  	args = c.flags.Args()
    54  	switch len(args) {
    55  	case 0:
    56  		key = ""
    57  	case 1:
    58  		key = args[0]
    59  	default:
    60  		c.UI.Error(fmt.Sprintf("Too many arguments (expected 1, got %d)", len(args)))
    61  		return 1
    62  	}
    63  
    64  	// This is just a "nice" thing to do. Since pairs cannot start with a /, but
    65  	// users will likely put "/" or "/foo", lets go ahead and strip that for them
    66  	// here.
    67  	if len(key) > 0 && key[0] == '/' {
    68  		key = key[1:]
    69  	}
    70  
    71  	// If the key is empty and we are not doing a recursive delete, this is an
    72  	// error.
    73  	if key == "" && !c.recurse {
    74  		c.UI.Error("Error! Missing KEY argument")
    75  		return 1
    76  	}
    77  
    78  	// ModifyIndex is required for CAS
    79  	if c.cas && c.modifyIndex == 0 {
    80  		c.UI.Error("Must specify -modify-index with -cas!")
    81  		return 1
    82  	}
    83  
    84  	// Specifying a ModifyIndex for a non-CAS operation is not possible.
    85  	if c.modifyIndex != 0 && !c.cas {
    86  		c.UI.Error("Cannot specify -modify-index without -cas!")
    87  		return 1
    88  	}
    89  
    90  	// It is not valid to use a CAS and recurse in the same call
    91  	if c.recurse && c.cas {
    92  		c.UI.Error("Cannot specify both -cas and -recurse!")
    93  		return 1
    94  	}
    95  
    96  	// Create and test the HTTP client
    97  	client, err := c.http.APIClient()
    98  	if err != nil {
    99  		c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err))
   100  		return 1
   101  	}
   102  
   103  	switch {
   104  	case c.recurse:
   105  		if _, err := client.KV().DeleteTree(key, nil); err != nil {
   106  			c.UI.Error(fmt.Sprintf("Error! Did not delete prefix %s: %s", key, err))
   107  			return 1
   108  		}
   109  
   110  		c.UI.Info(fmt.Sprintf("Success! Deleted keys with prefix: %s", key))
   111  		return 0
   112  	case c.cas:
   113  		pair := &api.KVPair{
   114  			Key:         key,
   115  			ModifyIndex: c.modifyIndex,
   116  		}
   117  
   118  		success, _, err := client.KV().DeleteCAS(pair, nil)
   119  		if err != nil {
   120  			c.UI.Error(fmt.Sprintf("Error! Did not delete key %s: %s", key, err))
   121  			return 1
   122  		}
   123  		if !success {
   124  			c.UI.Error(fmt.Sprintf("Error! Did not delete key %s: CAS failed", key))
   125  			return 1
   126  		}
   127  
   128  		c.UI.Info(fmt.Sprintf("Success! Deleted key: %s", key))
   129  		return 0
   130  	default:
   131  		if _, err := client.KV().Delete(key, nil); err != nil {
   132  			c.UI.Error(fmt.Sprintf("Error deleting key %s: %s", key, err))
   133  			return 1
   134  		}
   135  
   136  		c.UI.Info(fmt.Sprintf("Success! Deleted key: %s", key))
   137  		return 0
   138  	}
   139  }
   140  
   141  func (c *cmd) Synopsis() string {
   142  	return synopsis
   143  }
   144  
   145  func (c *cmd) Help() string {
   146  	return c.help
   147  }
   148  
   149  const synopsis = "Removes data from the KV store"
   150  const help = `
   151  Usage: consul kv delete [options] KEY_OR_PREFIX
   152  
   153    Removes the value from Consul's key-value store at the given path. If no
   154    key exists at the path, no action is taken.
   155  
   156    To delete the value for the key named "foo" in the key-value store:
   157  
   158        $ consul kv delete foo
   159  
   160    To delete all keys which start with "foo", specify the -recurse option:
   161  
   162        $ consul kv delete -recurse foo
   163  
   164    This will delete the keys named "foo", "food", and "foo/bar/zip" if they
   165    existed.
   166  `