command/kv: Add prefix option to kv import command

Currently when data is imported via `consul kv import` it overwrites
keys under the root key. Since `consul kv export` can retrieve data for
the given prefix, i.e. part of the KV tree, importing it under root may
be not what users want.

To mirror prefix behavior from export this PR adds prefix feature to the
import command that adds prefix to all keys that are imported.
This commit is contained in:
Alex Dzyoba 2021-02-19 14:04:28 +03:00
parent e3a4d843da
commit b99693b807
3 changed files with 72 additions and 5 deletions

View File

@ -10,6 +10,7 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath"
"github.com/hashicorp/consul/api" "github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/command/flags" "github.com/hashicorp/consul/command/flags"
@ -24,10 +25,11 @@ func New(ui cli.Ui) *cmd {
} }
type cmd struct { type cmd struct {
UI cli.Ui UI cli.Ui
flags *flag.FlagSet flags *flag.FlagSet
http *flags.HTTPFlags http *flags.HTTPFlags
help string help string
prefix string
// testStdin is the input for testing. // testStdin is the input for testing.
testStdin io.Reader testStdin io.Reader
@ -35,6 +37,7 @@ type cmd struct {
func (c *cmd) init() { func (c *cmd) init() {
c.flags = flag.NewFlagSet("", flag.ContinueOnError) c.flags = flag.NewFlagSet("", flag.ContinueOnError)
c.flags.StringVar(&c.prefix, "prefix", "", "Key prefix for imported data")
c.http = &flags.HTTPFlags{} c.http = &flags.HTTPFlags{}
flags.Merge(c.flags, c.http.ClientFlags()) flags.Merge(c.flags, c.http.ClientFlags())
flags.Merge(c.flags, c.http.ServerFlags()) flags.Merge(c.flags, c.http.ServerFlags())
@ -76,7 +79,7 @@ func (c *cmd) Run(args []string) int {
} }
pair := &api.KVPair{ pair := &api.KVPair{
Key: entry.Key, Key: filepath.Join(c.prefix, entry.Key),
Flags: entry.Flags, Flags: entry.Flags,
Value: value, Value: value,
} }

View File

@ -70,3 +70,55 @@ func TestKVImportCommand(t *testing.T) {
t.Fatalf("bad: expected: baz, got %s", pair.Value) t.Fatalf("bad: expected: baz, got %s", pair.Value)
} }
} }
func TestKVImportPrefixCommand(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()
const json = `[
{
"key": "foo",
"flags": 0,
"value": "YmFyCg=="
}
]`
ui := cli.NewMockUi()
c := New(ui)
c.testStdin = strings.NewReader(json)
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-prefix=" + "sub/",
"-",
}
code := c.Run(args)
if code != 0 {
t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String())
}
pair, _, err := client.KV().Get("foo", nil)
if err != nil {
t.Fatal(err)
}
if pair != nil {
t.Fatalf("bad: expected: nil, got %+v", pair)
}
pair, _, err = client.KV().Get("sub/foo", nil)
if err != nil {
t.Fatal(err)
}
if strings.TrimSpace(string(pair.Value)) != "bar" {
t.Fatalf("bad: expected: bar, got %s", pair.Value)
}
}

View File

@ -21,6 +21,11 @@ Usage: `consul kv import [options] [DATA]`
@include 'http_api_options_server.mdx' @include 'http_api_options_server.mdx'
#### KV Import Options
- `-prefix` - Key prefix for imported data. The default value is empty meaning
root.
#### Enterprise Options #### Enterprise Options
@include 'http_api_namespace_options.mdx' @include 'http_api_namespace_options.mdx'
@ -48,3 +53,10 @@ escaping:
$ consul kv import "$(cat values.json)" $ consul kv import "$(cat values.json)"
# Output # Output
``` ```
To import under prefix, use `-prefix` option:
```shell-session
$ cat values.json | consul kv import -prefix=sub/dir/ -
# Output
```