Fix Consul KV CLI 'GET' flags 'keys' and 'recurse' to be set together (#13493)

allow flags -recurse and -keys to be run at the same time in consul kv get CLI
This commit is contained in:
Dao Thanh Tung 2022-08-26 06:21:49 +08:00 committed by GitHub
parent d71e9f1b39
commit ca508de2e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 133 additions and 5 deletions

3
.changelog/13493.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:bug
cli: Fix Consul kv CLI 'GET' flags 'keys' and 'recurse' to be set together
```

View File

@ -99,6 +99,32 @@ func (c *cmd) Run(args []string) int {
} }
switch { switch {
case c.keys && c.recurse:
pairs, _, err := client.KV().List(key, &api.QueryOptions{
AllowStale: c.http.Stale(),
})
if err != nil {
c.UI.Error(fmt.Sprintf("Error querying Consul agent: %s", err))
return 1
}
for i, pair := range pairs {
if c.detailed {
var b bytes.Buffer
if err := prettyKVPair(&b, pair, false, true); err != nil {
c.UI.Error(fmt.Sprintf("Error rendering KV key: %s", err))
return 1
}
c.UI.Info(b.String())
if i < len(pairs)-1 {
c.UI.Info("")
}
} else {
c.UI.Info(fmt.Sprintf("%s", pair.Key))
}
}
return 0
case c.keys: case c.keys:
keys, _, err := client.KV().Keys(key, c.separator, &api.QueryOptions{ keys, _, err := client.KV().Keys(key, c.separator, &api.QueryOptions{
AllowStale: c.http.Stale(), AllowStale: c.http.Stale(),
@ -125,7 +151,7 @@ func (c *cmd) Run(args []string) int {
for i, pair := range pairs { for i, pair := range pairs {
if c.detailed { if c.detailed {
var b bytes.Buffer var b bytes.Buffer
if err := prettyKVPair(&b, pair, c.base64encode); err != nil { if err := prettyKVPair(&b, pair, c.base64encode, false); err != nil {
c.UI.Error(fmt.Sprintf("Error rendering KV pair: %s", err)) c.UI.Error(fmt.Sprintf("Error rendering KV pair: %s", err))
return 1 return 1
} }
@ -161,7 +187,7 @@ func (c *cmd) Run(args []string) int {
if c.detailed { if c.detailed {
var b bytes.Buffer var b bytes.Buffer
if err := prettyKVPair(&b, pair, c.base64encode); err != nil { if err := prettyKVPair(&b, pair, c.base64encode, false); err != nil {
c.UI.Error(fmt.Sprintf("Error rendering KV pair: %s", err)) c.UI.Error(fmt.Sprintf("Error rendering KV pair: %s", err))
return 1 return 1
} }
@ -187,7 +213,7 @@ func (c *cmd) Help() string {
return c.help return c.help
} }
func prettyKVPair(w io.Writer, pair *api.KVPair, base64EncodeValue bool) error { func prettyKVPair(w io.Writer, pair *api.KVPair, base64EncodeValue bool, keysOnly bool) error {
tw := tabwriter.NewWriter(w, 0, 2, 6, ' ', 0) tw := tabwriter.NewWriter(w, 0, 2, 6, ' ', 0)
fmt.Fprintf(tw, "CreateIndex\t%d\n", pair.CreateIndex) fmt.Fprintf(tw, "CreateIndex\t%d\n", pair.CreateIndex)
fmt.Fprintf(tw, "Flags\t%d\n", pair.Flags) fmt.Fprintf(tw, "Flags\t%d\n", pair.Flags)
@ -205,9 +231,9 @@ func prettyKVPair(w io.Writer, pair *api.KVPair, base64EncodeValue bool) error {
if pair.Namespace != "" { if pair.Namespace != "" {
fmt.Fprintf(tw, "Namespace\t%s\n", pair.Namespace) fmt.Fprintf(tw, "Namespace\t%s\n", pair.Namespace)
} }
if base64EncodeValue { if !keysOnly && base64EncodeValue {
fmt.Fprintf(tw, "Value\t%s", base64.StdEncoding.EncodeToString(pair.Value)) fmt.Fprintf(tw, "Value\t%s", base64.StdEncoding.EncodeToString(pair.Value))
} else { } else if !keysOnly {
fmt.Fprintf(tw, "Value\t%s", pair.Value) fmt.Fprintf(tw, "Value\t%s", pair.Value)
} }
return tw.Flush() return tw.Flush()

View File

@ -418,3 +418,102 @@ func TestKVGetCommand_DetailedBase64(t *testing.T) {
t.Fatalf("bad %#v, value is not base64 encoded", output) t.Fatalf("bad %#v, value is not base64 encoded", output)
} }
} }
func TestKVGetCommand_KeysRecurse(t *testing.T) {
if testing.Short() {
t.Skip("too slow for testing.Short")
}
t.Parallel()
a := agent.NewTestAgent(t, ``)
defer a.Shutdown()
client := a.Client()
ui := cli.NewMockUi()
c := New(ui)
keys := map[string]string{
"foo/": "",
"foo/a": "Hello World 2",
"foo1/a": "Hello World 1",
}
for k, v := range keys {
var pair *api.KVPair
switch v {
case "":
pair = &api.KVPair{Key: k, Value: nil}
default:
pair = &api.KVPair{Key: k, Value: []byte(v)}
}
if _, err := client.KV().Put(pair, nil); err != nil {
t.Fatalf("err: %#v", err)
}
}
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-recurse",
"-keys",
"foo",
}
code := c.Run(args)
if code != 0 {
t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String())
}
output := ui.OutputWriter.String()
for key, value := range keys {
if !strings.Contains(output, key) {
t.Fatalf("bad %#v missing %q", output, key)
}
if strings.Contains(output, key+":"+value) {
t.Fatalf("bad %#v expected no values for keys %q but received %q", output, key, value)
}
}
}
func TestKVGetCommand_DetailedKeysRecurse(t *testing.T) {
if testing.Short() {
t.Skip("too slow for testing.Short")
}
t.Parallel()
a := agent.NewTestAgent(t, ``)
defer a.Shutdown()
client := a.Client()
ui := cli.NewMockUi()
c := New(ui)
keys := map[string]string{
"foo/": "",
"foo/a": "Hello World 2",
"foo1/a": "Hello World 1",
}
for k, v := range keys {
var pair *api.KVPair
switch v {
case "":
pair = &api.KVPair{Key: k, Value: nil}
default:
pair = &api.KVPair{Key: k, Value: []byte(v)}
}
if _, err := client.KV().Put(pair, nil); err != nil {
t.Fatalf("err: %#v", err)
}
}
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-recurse",
"-keys",
"-detailed",
"foo",
}
code := c.Run(args)
if code != 0 {
t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String())
}
output := ui.OutputWriter.String()
for key, value := range keys {
if value != "" && strings.Contains(output, value) {
t.Fatalf("bad %#v expected no values for keys %q but received %q", output, key, value)
}
}
}