consul/command/kv_get.go

224 lines
5.9 KiB
Go
Raw Normal View History

2016-09-26 15:12:14 +00:00
package command
import (
"bytes"
"encoding/base64"
2016-09-26 15:12:14 +00:00
"fmt"
"io"
"text/tabwriter"
"github.com/hashicorp/consul/api"
)
2016-09-26 15:22:50 +00:00
// KVGetCommand is a Command implementation that is used to fetch the value of
// a key from the key-value store.
2016-09-26 15:12:14 +00:00
type KVGetCommand struct {
pkg refactor command/agent/* -> agent/* command/consul/* -> agent/consul/* command/agent/command{,_test}.go -> command/agent{,_test}.go command/base/command.go -> command/base.go command/base/* -> command/* commands.go -> command/commands.go The script which did the refactor is: ( cd $GOPATH/src/github.com/hashicorp/consul git mv command/agent/command.go command/agent.go git mv command/agent/command_test.go command/agent_test.go git mv command/agent/flag_slice_value{,_test}.go command/ git mv command/agent . git mv command/base/command.go command/base.go git mv command/base/config_util{,_test}.go command/ git mv commands.go command/ git mv consul agent rmdir command/base/ gsed -i -e 's|package agent|package command|' command/agent{,_test}.go gsed -i -e 's|package agent|package command|' command/flag_slice_value{,_test}.go gsed -i -e 's|package base|package command|' command/base.go command/config_util{,_test}.go gsed -i -e 's|package main|package command|' command/commands.go gsed -i -e 's|base.Command|BaseCommand|' command/commands.go gsed -i -e 's|agent.Command|AgentCommand|' command/commands.go gsed -i -e 's|\tCommand:|\tBaseCommand:|' command/commands.go gsed -i -e 's|base\.||' command/commands.go gsed -i -e 's|command\.||' command/commands.go gsed -i -e 's|command|c|' main.go gsed -i -e 's|range Commands|range command.Commands|' main.go gsed -i -e 's|Commands: Commands|Commands: command.Commands|' main.go gsed -i -e 's|base\.BoolValue|BoolValue|' command/operator_autopilot_set.go gsed -i -e 's|base\.DurationValue|DurationValue|' command/operator_autopilot_set.go gsed -i -e 's|base\.StringValue|StringValue|' command/operator_autopilot_set.go gsed -i -e 's|base\.UintValue|UintValue|' command/operator_autopilot_set.go gsed -i -e 's|\bCommand\b|BaseCommand|' command/base.go gsed -i -e 's|BaseCommand Options|Command Options|' command/base.go gsed -i -e 's|base.Command|BaseCommand|' command/*.go gsed -i -e 's|c\.Command|c.BaseCommand|g' command/*.go gsed -i -e 's|\tCommand:|\tBaseCommand:|' command/*_test.go gsed -i -e 's|base\.||' command/*_test.go gsed -i -e 's|\bCommand\b|AgentCommand|' command/agent{,_test}.go gsed -i -e 's|cmd.AgentCommand|cmd.BaseCommand|' command/agent.go gsed -i -e 's|cli.AgentCommand = new(Command)|cli.Command = new(AgentCommand)|' command/agent_test.go gsed -i -e 's|exec.AgentCommand|exec.Command|' command/agent_test.go gsed -i -e 's|exec.BaseCommand|exec.Command|' command/agent_test.go gsed -i -e 's|NewTestAgent|agent.NewTestAgent|' command/agent_test.go gsed -i -e 's|= TestConfig|= agent.TestConfig|' command/agent_test.go gsed -i -e 's|: RetryJoin|: agent.RetryJoin|' command/agent_test.go gsed -i -e 's|\.\./\.\./|../|' command/config_util_test.go gsed -i -e 's|\bverifyUniqueListeners|VerifyUniqueListeners|' agent/config{,_test}.go command/agent.go gsed -i -e 's|\bserfLANKeyring\b|SerfLANKeyring|g' agent/{agent,keyring,testagent}.go command/agent.go gsed -i -e 's|\bserfWANKeyring\b|SerfWANKeyring|g' agent/{agent,keyring,testagent}.go command/agent.go gsed -i -e 's|\bNewAgent\b|agent.New|g' command/agent{,_test}.go gsed -i -e 's|\bNewAgent|New|' agent/{acl_test,agent,testagent}.go gsed -i -e 's|\bAgent\b|agent.&|g' command/agent{,_test}.go gsed -i -e 's|\bBool\b|agent.&|g' command/agent{,_test}.go gsed -i -e 's|\bConfig\b|agent.&|g' command/agent{,_test}.go gsed -i -e 's|\bDefaultConfig\b|agent.&|g' command/agent{,_test}.go gsed -i -e 's|\bDevConfig\b|agent.&|g' command/agent{,_test}.go gsed -i -e 's|\bMergeConfig\b|agent.&|g' command/agent{,_test}.go gsed -i -e 's|\bReadConfigPaths\b|agent.&|g' command/agent{,_test}.go gsed -i -e 's|\bParseMetaPair\b|agent.&|g' command/agent{,_test}.go gsed -i -e 's|\bSerfLANKeyring\b|agent.&|g' command/agent{,_test}.go gsed -i -e 's|\bSerfWANKeyring\b|agent.&|g' command/agent{,_test}.go gsed -i -e 's|circonus\.agent|circonus|g' command/agent{,_test}.go gsed -i -e 's|logger\.agent|logger|g' command/agent{,_test}.go gsed -i -e 's|metrics\.agent|metrics|g' command/agent{,_test}.go gsed -i -e 's|// agent.Agent|// agent|' command/agent{,_test}.go gsed -i -e 's|a\.agent\.Config|a.Config|' command/agent{,_test}.go gsed -i -e 's|agent\.AppendSliceValue|AppendSliceValue|' command/{configtest,validate}.go gsed -i -e 's|consul/consul|agent/consul|' GNUmakefile gsed -i -e 's|\.\./test|../../test|' agent/consul/server_test.go # fix imports f=$(grep -rl 'github.com/hashicorp/consul/command/agent' * | grep '\.go') gsed -i -e 's|github.com/hashicorp/consul/command/agent|github.com/hashicorp/consul/agent|' $f goimports -w $f f=$(grep -rl 'github.com/hashicorp/consul/consul' * | grep '\.go') gsed -i -e 's|github.com/hashicorp/consul/consul|github.com/hashicorp/consul/agent/consul|' $f goimports -w $f goimports -w command/*.go main.go )
2017-06-09 22:28:28 +00:00
BaseCommand
// flags
base64encode bool
detailed bool
keys bool
recurse bool
separator string
}
func (c *KVGetCommand) initFlags() {
c.InitFlagSet()
c.FlagSet.BoolVar(&c.base64encode, "base64", false,
"Base64 encode the value. The default value is false.")
c.FlagSet.BoolVar(&c.detailed, "detailed", false,
"Provide additional metadata about the key in addition to the value such "+
"as the ModifyIndex and any flags that may have been set on the key. "+
"The default value is false.")
c.FlagSet.BoolVar(&c.keys, "keys", false,
"List keys which start with the given prefix, but not their values. "+
"This is especially useful if you only need the key names themselves. "+
"This option is commonly combined with the -separator option. The default "+
"value is false.")
c.FlagSet.BoolVar(&c.recurse, "recurse", false,
"Recursively look at all keys prefixed with the given path. The default "+
"value is false.")
c.FlagSet.StringVar(&c.separator, "separator", "/",
"String to use as a separator between keys. The default value is \"/\", "+
"but this option is only taken into account when paired with the -keys flag.")
2016-09-26 15:12:14 +00:00
}
func (c *KVGetCommand) Help() string {
c.initFlags()
return c.HelpCommand(`
2016-09-26 15:12:14 +00:00
Usage: consul kv get [options] [KEY_OR_PREFIX]
Retrieves the value from Consul's key-value store at the given key name. If no
key exists with that name, an error is returned. If a key exists with that
name but has no data, nothing is returned. If the name or prefix is omitted,
it defaults to "" which is the root of the key-value store.
To retrieve the value for the key named "foo" in the key-value store:
$ consul kv get foo
This will return the original, raw value stored in Consul. To view detailed
information about the key, specify the "-detailed" flag. This will output all
known metadata about the key including ModifyIndex and any user-supplied
flags:
$ consul kv get -detailed foo
To treat the path as a prefix and list all keys which start with the given
prefix, specify the "-recurse" flag:
$ consul kv get -recurse foo
This will return all key-value pairs. To just list the keys which start with
2016-09-26 15:12:14 +00:00
the specified prefix, use the "-keys" option instead:
$ consul kv get -keys foo
For a full list of options and examples, please see the Consul documentation.
`)
2016-09-26 15:12:14 +00:00
}
func (c *KVGetCommand) Run(args []string) int {
c.initFlags()
if err := c.FlagSet.Parse(args); err != nil {
2016-09-26 15:12:14 +00:00
return 1
}
key := ""
// Check for arg validation
args = c.FlagSet.Args()
2016-09-26 15:12:14 +00:00
switch len(args) {
case 0:
key = ""
case 1:
key = args[0]
default:
2017-04-21 00:02:42 +00:00
c.UI.Error(fmt.Sprintf("Too many arguments (expected 1, got %d)", len(args)))
2016-09-26 15:12:14 +00:00
return 1
}
// This is just a "nice" thing to do. Since pairs cannot start with a /, but
// users will likely put "/" or "/foo", lets go ahead and strip that for them
// here.
if len(key) > 0 && key[0] == '/' {
key = key[1:]
}
// If the key is empty and we are not doing a recursive or key-based lookup,
// this is an error.
if key == "" && !(c.recurse || c.keys) {
2017-04-21 00:02:42 +00:00
c.UI.Error("Error! Missing KEY argument")
2016-09-26 15:12:14 +00:00
return 1
}
// Create and test the HTTP client
client, err := c.HTTPClient()
2016-09-26 15:12:14 +00:00
if err != nil {
2017-04-21 00:02:42 +00:00
c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err))
2016-09-26 15:12:14 +00:00
return 1
}
switch {
case c.keys:
keys, _, err := client.KV().Keys(key, c.separator, &api.QueryOptions{
AllowStale: c.HTTPStale(),
2016-09-26 15:12:14 +00:00
})
if err != nil {
2017-04-21 00:02:42 +00:00
c.UI.Error(fmt.Sprintf("Error querying Consul agent: %s", err))
2016-09-26 15:12:14 +00:00
return 1
}
for _, k := range keys {
2017-04-21 00:02:42 +00:00
c.UI.Info(string(k))
2016-09-26 15:12:14 +00:00
}
return 0
case c.recurse:
2016-09-26 15:12:14 +00:00
pairs, _, err := client.KV().List(key, &api.QueryOptions{
AllowStale: c.HTTPStale(),
2016-09-26 15:12:14 +00:00
})
if err != nil {
2017-04-21 00:02:42 +00:00
c.UI.Error(fmt.Sprintf("Error querying Consul agent: %s", err))
2016-09-26 15:12:14 +00:00
return 1
}
for i, pair := range pairs {
if c.detailed {
2016-09-26 15:12:14 +00:00
var b bytes.Buffer
if err := prettyKVPair(&b, pair, c.base64encode); err != nil {
2017-04-21 00:02:42 +00:00
c.UI.Error(fmt.Sprintf("Error rendering KV pair: %s", err))
2016-09-26 15:12:14 +00:00
return 1
}
2017-04-21 00:02:42 +00:00
c.UI.Info(b.String())
2016-09-26 15:12:14 +00:00
if i < len(pairs)-1 {
2017-04-21 00:02:42 +00:00
c.UI.Info("")
2016-09-26 15:12:14 +00:00
}
} else {
if c.base64encode {
2017-04-21 00:02:42 +00:00
c.UI.Info(fmt.Sprintf("%s:%s", pair.Key, base64.StdEncoding.EncodeToString(pair.Value)))
} else {
2017-04-21 00:02:42 +00:00
c.UI.Info(fmt.Sprintf("%s:%s", pair.Key, pair.Value))
}
2016-09-26 15:12:14 +00:00
}
}
return 0
default:
pair, _, err := client.KV().Get(key, &api.QueryOptions{
AllowStale: c.HTTPStale(),
2016-09-26 15:12:14 +00:00
})
if err != nil {
2017-04-21 00:02:42 +00:00
c.UI.Error(fmt.Sprintf("Error querying Consul agent: %s", err))
2016-09-26 15:12:14 +00:00
return 1
}
if pair == nil {
2017-04-21 00:02:42 +00:00
c.UI.Error(fmt.Sprintf("Error! No key exists at: %s", key))
2016-09-26 15:12:14 +00:00
return 1
}
if c.detailed {
2016-09-26 15:12:14 +00:00
var b bytes.Buffer
if err := prettyKVPair(&b, pair, c.base64encode); err != nil {
2017-04-21 00:02:42 +00:00
c.UI.Error(fmt.Sprintf("Error rendering KV pair: %s", err))
2016-09-26 15:12:14 +00:00
return 1
}
2017-04-21 00:02:42 +00:00
c.UI.Info(b.String())
2016-09-26 15:12:14 +00:00
return 0
}
c.UI.Info(string(pair.Value))
return 0
2016-09-26 15:12:14 +00:00
}
}
func (c *KVGetCommand) Synopsis() string {
return "Retrieves or lists data from the KV store"
}
func prettyKVPair(w io.Writer, pair *api.KVPair, base64EncodeValue bool) error {
2016-09-26 15:12:14 +00:00
tw := tabwriter.NewWriter(w, 0, 2, 6, ' ', 0)
fmt.Fprintf(tw, "CreateIndex\t%d\n", pair.CreateIndex)
fmt.Fprintf(tw, "Flags\t%d\n", pair.Flags)
fmt.Fprintf(tw, "Key\t%s\n", pair.Key)
fmt.Fprintf(tw, "LockIndex\t%d\n", pair.LockIndex)
fmt.Fprintf(tw, "ModifyIndex\t%d\n", pair.ModifyIndex)
if pair.Session == "" {
fmt.Fprint(tw, "Session\t-\n")
2016-09-26 15:12:14 +00:00
} else {
fmt.Fprintf(tw, "Session\t%s\n", pair.Session)
}
if base64EncodeValue {
fmt.Fprintf(tw, "Value\t%s", base64.StdEncoding.EncodeToString(pair.Value))
} else {
fmt.Fprintf(tw, "Value\t%s", pair.Value)
}
2016-09-26 15:12:14 +00:00
return tw.Flush()
}