Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

etcdctl: add support for filtering by {min,max} x {create,mod} x {revision} #18233

Merged
merged 1 commit into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions etcdctl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,14 @@ RPC: Range

- keys-only -- Get only the keys

- max-create-revision -- restrict results to kvs with create revision lower or equal than the supplied revision

- min-create-revision -- restrict results to kvs with create revision greater or equal than the supplied revision

- max-mod-revision -- restrict results to kvs with modified revision lower or equal than the supplied revision

- min-mod-revision -- restrict results to kvs with modified revision greater or equal than the supplied revision

#### Output
Prints the data in format below,
```
Expand Down
52 changes: 42 additions & 10 deletions etcdctl/ctlv3/command/get_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,20 @@ import (
)

var (
getConsistency string
getLimit int64
getSortOrder string
getSortTarget string
getPrefix bool
getFromKey bool
getRev int64
getKeysOnly bool
getCountOnly bool
printValueOnly bool
getConsistency string
getLimit int64
getSortOrder string
getSortTarget string
getPrefix bool
getFromKey bool
getRev int64
getKeysOnly bool
getCountOnly bool
printValueOnly bool
getMinCreateRev int64
getMaxCreateRev int64
getMinModRev int64
getMaxModRev int64
)

// NewGetCommand returns the cobra command for "get".
Expand All @@ -55,6 +59,10 @@ func NewGetCommand() *cobra.Command {
cmd.Flags().BoolVar(&getKeysOnly, "keys-only", false, "Get only the keys")
cmd.Flags().BoolVar(&getCountOnly, "count-only", false, "Get only the count")
cmd.Flags().BoolVar(&printValueOnly, "print-value-only", false, `Only write values when using the "simple" output format`)
cmd.Flags().Int64Var(&getMinCreateRev, "min-create-rev", 0, "Minimum create revision")
cmd.Flags().Int64Var(&getMaxCreateRev, "max-create-rev", 0, "Maximum create revision")
cmd.Flags().Int64Var(&getMinModRev, "min-mod-rev", 0, "Minimum modification revision")
cmd.Flags().Int64Var(&getMaxModRev, "max-mod-rev", 0, "Maximum modification revision")

cmd.RegisterFlagCompletionFunc("consistency", func(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
return []string{"l", "s"}, cobra.ShellCompDirectiveDefault
Expand Down Expand Up @@ -184,5 +192,29 @@ func getGetOp(args []string) (string, []clientv3.OpOption) {
opts = append(opts, clientv3.WithCountOnly())
}

if getMinCreateRev > 0 {
opts = append(opts, clientv3.WithMinCreateRev(getMinCreateRev))
}

if getMaxCreateRev > 0 {
if getMinCreateRev > getMaxCreateRev {
cobrautl.ExitWithError(cobrautl.ExitBadFeature,
fmt.Errorf("getMinCreateRev(=%v) > getMaxCreateRev(=%v)", getMinCreateRev, getMaxCreateRev))
}
opts = append(opts, clientv3.WithMaxCreateRev(getMaxCreateRev))
}

if getMinModRev > 0 {
opts = append(opts, clientv3.WithMinModRev(getMinModRev))
}

if getMaxModRev > 0 {
if getMinModRev > getMaxModRev {
cobrautl.ExitWithError(cobrautl.ExitBadFeature,
fmt.Errorf("getMinModRev(=%v) > getMaxModRev(=%v)", getMinModRev, getMaxModRev))
}
opts = append(opts, clientv3.WithMaxModRev(getMaxModRev))
}

return key, opts
}
42 changes: 38 additions & 4 deletions tests/e2e/ctl_v3_kv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ func TestCtlV3PutIgnoreLease(t *testing.T) { testCtl(t, putTestIgnoreLease) }

func TestCtlV3GetTimeout(t *testing.T) { testCtl(t, getTest, withDefaultDialTimeout()) }

func TestCtlV3GetFormat(t *testing.T) { testCtl(t, getFormatTest) }
func TestCtlV3GetRev(t *testing.T) { testCtl(t, getRevTest) }
func TestCtlV3GetKeysOnly(t *testing.T) { testCtl(t, getKeysOnlyTest) }
func TestCtlV3GetCountOnly(t *testing.T) { testCtl(t, getCountOnlyTest) }
func TestCtlV3GetFormat(t *testing.T) { testCtl(t, getFormatTest) }
func TestCtlV3GetRev(t *testing.T) { testCtl(t, getRevTest) }
func TestCtlV3GetMinMaxCreateModRev(t *testing.T) { testCtl(t, getMinMaxCreateModRevTest) }
func TestCtlV3GetKeysOnly(t *testing.T) { testCtl(t, getKeysOnlyTest) }
func TestCtlV3GetCountOnly(t *testing.T) { testCtl(t, getCountOnlyTest) }

func TestCtlV3DelTimeout(t *testing.T) { testCtl(t, delTest, withDefaultDialTimeout()) }

Expand Down Expand Up @@ -216,6 +217,39 @@ func getRevTest(cx ctlCtx) {
}
}

func getMinMaxCreateModRevTest(cx ctlCtx) {
var (
kvs = []kv{ // revision: store | key create | key modify
{"key1", "val1"}, // 2 2 2
{"key2", "val2"}, // 3 3 3
{"key1", "val3"}, // 4 2 4
{"key4", "val4"}, // 5 5 5
}
)
for i := range kvs {
if err := ctlV3Put(cx, kvs[i].key, kvs[i].val, ""); err != nil {
cx.t.Fatalf("getRevTest #%d: ctlV3Put error (%v)", i, err)
}
}

tests := []struct {
args []string

wkv []kv
}{
{[]string{"key", "--prefix", "--max-create-rev", "3"}, []kv{kvs[1], kvs[2]}},
{[]string{"key", "--prefix", "--min-create-rev", "3"}, []kv{kvs[1], kvs[3]}},
{[]string{"key", "--prefix", "--max-mod-rev", "3"}, []kv{kvs[1]}},
{[]string{"key", "--prefix", "--min-mod-rev", "4"}, kvs[2:]},
}

for i, tt := range tests {
if err := ctlV3Get(cx, tt.args, tt.wkv...); err != nil {
cx.t.Errorf("getMinModRevTest #%d: ctlV3Get error (%v)", i, err)
}
}
}

func getKeysOnlyTest(cx ctlCtx) {
if err := ctlV3Put(cx, "key", "val", ""); err != nil {
cx.t.Fatal(err)
Expand Down
Loading