github.com/kjdelisle/consul@v1.4.5/command/kv/get/kv_get.go (about)

     1  package get
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/base64"
     6  	"flag"
     7  	"fmt"
     8  	"io"
     9  	"text/tabwriter"
    10  
    11  	"github.com/hashicorp/consul/api"
    12  	"github.com/hashicorp/consul/command/flags"
    13  	"github.com/mitchellh/cli"
    14  )
    15  
    16  func New(ui cli.Ui) *cmd {
    17  	c := &cmd{UI: ui}
    18  	c.init()
    19  	return c
    20  }
    21  
    22  type cmd struct {
    23  	UI           cli.Ui
    24  	flags        *flag.FlagSet
    25  	http         *flags.HTTPFlags
    26  	help         string
    27  	base64encode bool
    28  	detailed     bool
    29  	keys         bool
    30  	recurse      bool
    31  	separator    string
    32  }
    33  
    34  func (c *cmd) init() {
    35  	c.flags = flag.NewFlagSet("", flag.ContinueOnError)
    36  	c.flags.BoolVar(&c.base64encode, "base64", false,
    37  		"Base64 encode the value. The default value is false.")
    38  	c.flags.BoolVar(&c.detailed, "detailed", false,
    39  		"Provide additional metadata about the key in addition to the value such "+
    40  			"as the ModifyIndex and any flags that may have been set on the key. "+
    41  			"The default value is false.")
    42  	c.flags.BoolVar(&c.keys, "keys", false,
    43  		"List keys which start with the given prefix, but not their values. "+
    44  			"This is especially useful if you only need the key names themselves. "+
    45  			"This option is commonly combined with the -separator option. The default "+
    46  			"value is false.")
    47  	c.flags.BoolVar(&c.recurse, "recurse", false,
    48  		"Recursively look at all keys prefixed with the given path. The default "+
    49  			"value is false.")
    50  	c.flags.StringVar(&c.separator, "separator", "/",
    51  		"String to use as a separator between keys. The default value is \"/\", "+
    52  			"but this option is only taken into account when paired with the -keys flag.")
    53  
    54  	c.http = &flags.HTTPFlags{}
    55  	flags.Merge(c.flags, c.http.ClientFlags())
    56  	flags.Merge(c.flags, c.http.ServerFlags())
    57  	c.help = flags.Usage(help, c.flags)
    58  }
    59  
    60  func (c *cmd) Run(args []string) int {
    61  	if err := c.flags.Parse(args); err != nil {
    62  		return 1
    63  	}
    64  
    65  	key := ""
    66  
    67  	// Check for arg validation
    68  	args = c.flags.Args()
    69  	switch len(args) {
    70  	case 0:
    71  		key = ""
    72  	case 1:
    73  		key = args[0]
    74  	default:
    75  		c.UI.Error(fmt.Sprintf("Too many arguments (expected 1, got %d)", len(args)))
    76  		return 1
    77  	}
    78  
    79  	// This is just a "nice" thing to do. Since pairs cannot start with a /, but
    80  	// users will likely put "/" or "/foo", lets go ahead and strip that for them
    81  	// here.
    82  	if len(key) > 0 && key[0] == '/' {
    83  		key = key[1:]
    84  	}
    85  
    86  	// If the key is empty and we are not doing a recursive or key-based lookup,
    87  	// this is an error.
    88  	if key == "" && !(c.recurse || c.keys) {
    89  		c.UI.Error("Error! Missing KEY argument")
    90  		return 1
    91  	}
    92  
    93  	// Create and test the HTTP client
    94  	client, err := c.http.APIClient()
    95  	if err != nil {
    96  		c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err))
    97  		return 1
    98  	}
    99  
   100  	switch {
   101  	case c.keys:
   102  		keys, _, err := client.KV().Keys(key, c.separator, &api.QueryOptions{
   103  			AllowStale: c.http.Stale(),
   104  		})
   105  		if err != nil {
   106  			c.UI.Error(fmt.Sprintf("Error querying Consul agent: %s", err))
   107  			return 1
   108  		}
   109  
   110  		for _, k := range keys {
   111  			c.UI.Info(string(k))
   112  		}
   113  
   114  		return 0
   115  	case c.recurse:
   116  		pairs, _, err := client.KV().List(key, &api.QueryOptions{
   117  			AllowStale: c.http.Stale(),
   118  		})
   119  		if err != nil {
   120  			c.UI.Error(fmt.Sprintf("Error querying Consul agent: %s", err))
   121  			return 1
   122  		}
   123  
   124  		for i, pair := range pairs {
   125  			if c.detailed {
   126  				var b bytes.Buffer
   127  				if err := prettyKVPair(&b, pair, c.base64encode); err != nil {
   128  					c.UI.Error(fmt.Sprintf("Error rendering KV pair: %s", err))
   129  					return 1
   130  				}
   131  
   132  				c.UI.Info(b.String())
   133  
   134  				if i < len(pairs)-1 {
   135  					c.UI.Info("")
   136  				}
   137  			} else {
   138  				if c.base64encode {
   139  					c.UI.Info(fmt.Sprintf("%s:%s", pair.Key, base64.StdEncoding.EncodeToString(pair.Value)))
   140  				} else {
   141  					c.UI.Info(fmt.Sprintf("%s:%s", pair.Key, pair.Value))
   142  				}
   143  			}
   144  		}
   145  
   146  		return 0
   147  	default:
   148  		pair, _, err := client.KV().Get(key, &api.QueryOptions{
   149  			AllowStale: c.http.Stale(),
   150  		})
   151  		if err != nil {
   152  			c.UI.Error(fmt.Sprintf("Error querying Consul agent: %s", err))
   153  			return 1
   154  		}
   155  
   156  		if pair == nil {
   157  			c.UI.Error(fmt.Sprintf("Error! No key exists at: %s", key))
   158  			return 1
   159  		}
   160  
   161  		if c.detailed {
   162  			var b bytes.Buffer
   163  			if err := prettyKVPair(&b, pair, c.base64encode); err != nil {
   164  				c.UI.Error(fmt.Sprintf("Error rendering KV pair: %s", err))
   165  				return 1
   166  			}
   167  
   168  			c.UI.Info(b.String())
   169  			return 0
   170  		}
   171  
   172  		if c.base64encode {
   173  			c.UI.Info(base64.StdEncoding.EncodeToString(pair.Value))
   174  		} else {
   175  			c.UI.Info(string(pair.Value))
   176  		}
   177  		return 0
   178  	}
   179  }
   180  
   181  func (c *cmd) Synopsis() string {
   182  	return synopsis
   183  }
   184  
   185  func (c *cmd) Help() string {
   186  	return c.help
   187  }
   188  
   189  func prettyKVPair(w io.Writer, pair *api.KVPair, base64EncodeValue bool) error {
   190  	tw := tabwriter.NewWriter(w, 0, 2, 6, ' ', 0)
   191  	fmt.Fprintf(tw, "CreateIndex\t%d\n", pair.CreateIndex)
   192  	fmt.Fprintf(tw, "Flags\t%d\n", pair.Flags)
   193  	fmt.Fprintf(tw, "Key\t%s\n", pair.Key)
   194  	fmt.Fprintf(tw, "LockIndex\t%d\n", pair.LockIndex)
   195  	fmt.Fprintf(tw, "ModifyIndex\t%d\n", pair.ModifyIndex)
   196  	if pair.Session == "" {
   197  		fmt.Fprint(tw, "Session\t-\n")
   198  	} else {
   199  		fmt.Fprintf(tw, "Session\t%s\n", pair.Session)
   200  	}
   201  	if base64EncodeValue {
   202  		fmt.Fprintf(tw, "Value\t%s", base64.StdEncoding.EncodeToString(pair.Value))
   203  	} else {
   204  		fmt.Fprintf(tw, "Value\t%s", pair.Value)
   205  	}
   206  	return tw.Flush()
   207  }
   208  
   209  const synopsis = "Retrieves or lists data from the KV store"
   210  const help = `
   211  Usage: consul kv get [options] [KEY_OR_PREFIX]
   212  
   213    Retrieves the value from Consul's key-value store at the given key name. If no
   214    key exists with that name, an error is returned. If a key exists with that
   215    name but has no data, nothing is returned. If the name or prefix is omitted,
   216    it defaults to "" which is the root of the key-value store.
   217  
   218    To retrieve the value for the key named "foo" in the key-value store:
   219  
   220        $ consul kv get foo
   221  
   222    This will return the original, raw value stored in Consul. To view detailed
   223    information about the key, specify the "-detailed" flag. This will output all
   224    known metadata about the key including ModifyIndex and any user-supplied
   225    flags:
   226  
   227        $ consul kv get -detailed foo
   228  
   229    To treat the path as a prefix and list all keys which start with the given
   230    prefix, specify the "-recurse" flag:
   231  
   232        $ consul kv get -recurse foo
   233  
   234    This will return all key-value pairs. To just list the keys which start with
   235    the specified prefix, use the "-keys" option instead:
   236  
   237        $ consul kv get -keys foo
   238  
   239    For a full list of options and examples, please see the Consul documentation.
   240  `