Skip to content

Commit 37cbd6c

Browse files
authored
Merge pull request #18233 from jcferretti/etcdctl-minmaxcreatemod
etcdctl: add support for filtering by {min,max} x {create,mod} x {revision}
2 parents bf78a23 + 07b35dd commit 37cbd6c

File tree

3 files changed

+88
-14
lines changed

3 files changed

+88
-14
lines changed

etcdctl/README.md

+8
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,14 @@ RPC: Range
125125

126126
- keys-only -- Get only the keys
127127

128+
- max-create-revision -- restrict results to kvs with create revision lower or equal than the supplied revision
129+
130+
- min-create-revision -- restrict results to kvs with create revision greater or equal than the supplied revision
131+
132+
- max-mod-revision -- restrict results to kvs with modified revision lower or equal than the supplied revision
133+
134+
- min-mod-revision -- restrict results to kvs with modified revision greater or equal than the supplied revision
135+
128136
#### Output
129137
Prints the data in format below,
130138
```

etcdctl/ctlv3/command/get_command.go

+42-10
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,20 @@ import (
2525
)
2626

2727
var (
28-
getConsistency string
29-
getLimit int64
30-
getSortOrder string
31-
getSortTarget string
32-
getPrefix bool
33-
getFromKey bool
34-
getRev int64
35-
getKeysOnly bool
36-
getCountOnly bool
37-
printValueOnly bool
28+
getConsistency string
29+
getLimit int64
30+
getSortOrder string
31+
getSortTarget string
32+
getPrefix bool
33+
getFromKey bool
34+
getRev int64
35+
getKeysOnly bool
36+
getCountOnly bool
37+
printValueOnly bool
38+
getMinCreateRev int64
39+
getMaxCreateRev int64
40+
getMinModRev int64
41+
getMaxModRev int64
3842
)
3943

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

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

195+
if getMinCreateRev > 0 {
196+
opts = append(opts, clientv3.WithMinCreateRev(getMinCreateRev))
197+
}
198+
199+
if getMaxCreateRev > 0 {
200+
if getMinCreateRev > getMaxCreateRev {
201+
cobrautl.ExitWithError(cobrautl.ExitBadFeature,
202+
fmt.Errorf("getMinCreateRev(=%v) > getMaxCreateRev(=%v)", getMinCreateRev, getMaxCreateRev))
203+
}
204+
opts = append(opts, clientv3.WithMaxCreateRev(getMaxCreateRev))
205+
}
206+
207+
if getMinModRev > 0 {
208+
opts = append(opts, clientv3.WithMinModRev(getMinModRev))
209+
}
210+
211+
if getMaxModRev > 0 {
212+
if getMinModRev > getMaxModRev {
213+
cobrautl.ExitWithError(cobrautl.ExitBadFeature,
214+
fmt.Errorf("getMinModRev(=%v) > getMaxModRev(=%v)", getMinModRev, getMaxModRev))
215+
}
216+
opts = append(opts, clientv3.WithMaxModRev(getMaxModRev))
217+
}
218+
187219
return key, opts
188220
}

tests/e2e/ctl_v3_kv_test.go

+38-4
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ func TestCtlV3PutIgnoreLease(t *testing.T) { testCtl(t, putTestIgnoreLease) }
3737

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

40-
func TestCtlV3GetFormat(t *testing.T) { testCtl(t, getFormatTest) }
41-
func TestCtlV3GetRev(t *testing.T) { testCtl(t, getRevTest) }
42-
func TestCtlV3GetKeysOnly(t *testing.T) { testCtl(t, getKeysOnlyTest) }
43-
func TestCtlV3GetCountOnly(t *testing.T) { testCtl(t, getCountOnlyTest) }
40+
func TestCtlV3GetFormat(t *testing.T) { testCtl(t, getFormatTest) }
41+
func TestCtlV3GetRev(t *testing.T) { testCtl(t, getRevTest) }
42+
func TestCtlV3GetMinMaxCreateModRev(t *testing.T) { testCtl(t, getMinMaxCreateModRevTest) }
43+
func TestCtlV3GetKeysOnly(t *testing.T) { testCtl(t, getKeysOnlyTest) }
44+
func TestCtlV3GetCountOnly(t *testing.T) { testCtl(t, getCountOnlyTest) }
4445

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

@@ -216,6 +217,39 @@ func getRevTest(cx ctlCtx) {
216217
}
217218
}
218219

220+
func getMinMaxCreateModRevTest(cx ctlCtx) {
221+
var (
222+
kvs = []kv{ // revision: store | key create | key modify
223+
{"key1", "val1"}, // 2 2 2
224+
{"key2", "val2"}, // 3 3 3
225+
{"key1", "val3"}, // 4 2 4
226+
{"key4", "val4"}, // 5 5 5
227+
}
228+
)
229+
for i := range kvs {
230+
if err := ctlV3Put(cx, kvs[i].key, kvs[i].val, ""); err != nil {
231+
cx.t.Fatalf("getRevTest #%d: ctlV3Put error (%v)", i, err)
232+
}
233+
}
234+
235+
tests := []struct {
236+
args []string
237+
238+
wkv []kv
239+
}{
240+
{[]string{"key", "--prefix", "--max-create-rev", "3"}, []kv{kvs[1], kvs[2]}},
241+
{[]string{"key", "--prefix", "--min-create-rev", "3"}, []kv{kvs[1], kvs[3]}},
242+
{[]string{"key", "--prefix", "--max-mod-rev", "3"}, []kv{kvs[1]}},
243+
{[]string{"key", "--prefix", "--min-mod-rev", "4"}, kvs[2:]},
244+
}
245+
246+
for i, tt := range tests {
247+
if err := ctlV3Get(cx, tt.args, tt.wkv...); err != nil {
248+
cx.t.Errorf("getMinModRevTest #%d: ctlV3Get error (%v)", i, err)
249+
}
250+
}
251+
}
252+
219253
func getKeysOnlyTest(cx ctlCtx) {
220254
if err := ctlV3Put(cx, "key", "val", ""); err != nil {
221255
cx.t.Fatal(err)

0 commit comments

Comments
 (0)