github.com/sl1pm4t/consul@v1.4.5-0.20190325224627-74c31c540f9c/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 `