//Fetch data from sync func (s *Sync) Fetch(key string) (*sync.Node, error) { node, err := s.etcdClient.Get(s.withTimeout(), key, etcd.WithSort(etcd.SortByKey, etcd.SortAscend)) if err != nil { return nil, err } dir, err := s.etcdClient.Get(s.withTimeout(), key+"/", etcd.WithPrefix(), etcd.WithSort(etcd.SortByKey, etcd.SortAscend)) if err != nil { return nil, err } return s.recursiveFetch(key, node.Kvs, dir.Kvs) }
/* Sync localdir to etcd server state. WARNING: ALL CONTENT OF localdir WILL BE LOST Return revision of synced state */ func firstSyncEtcDir_v3(prefix string, c *clientv3.Client, localdir string) int64 { cleanDir(localdir) key, option := prefixToKeyOption(prefix) // Get all values resp, err := c.Get(context.Background(), key, option, clientv3.WithSort(clientv3.SortByKey, clientv3.SortDescend)) if err != nil { panic(err) } for _, kv := range resp.Kvs { targetPath := keyToLocalPath(strings.TrimPrefix(string(kv.Key), prefix), localdir) if targetPath == "" { continue } targetDir := filepath.Dir(targetPath) os.MkdirAll(targetDir, DEFAULT_DIRMODE) err = ioutil.WriteFile(targetPath, kv.Value, DEFAULT_FILEMODE) if err != nil { log.Printf("firstSyncEtcDir_v3 error write file '%v': %v\n", targetPath, err) } } return resp.Header.Revision }
func ExampleKV_getSortedPrefix() { cli, err := clientv3.New(clientv3.Config{ Endpoints: endpoints, DialTimeout: dialTimeout, }) if err != nil { log.Fatal(err) } defer cli.Close() kvc := clientv3.NewKV(cli) for i := range make([]int, 3) { ctx, cancel := context.WithTimeout(context.Background(), requestTimeout) _, err = kvc.Put(ctx, fmt.Sprintf("key_%d", i), "value") cancel() if err != nil { log.Fatal(err) } } ctx, cancel := context.WithTimeout(context.Background(), requestTimeout) resp, err := kvc.Get(ctx, "key", clientv3.WithPrefix(), clientv3.WithSort(clientv3.SortByKey, clientv3.SortDescend)) cancel() if err != nil { log.Fatal(err) } for _, ev := range resp.Kvs { fmt.Printf("%s : %s\n", ev.Key, ev.Value) } // key_2 : value // key_1 : value // key_0 : value }
// waitDeletes efficiently waits until all keys matched by Get(key, opts...) are deleted func waitDeletes(ctx context.Context, client *v3.Client, key string, opts ...v3.OpOption) error { getOpts := []v3.OpOption{v3.WithSort(v3.SortByCreatedRev, v3.SortAscend)} getOpts = append(getOpts, opts...) resp, err := client.Get(ctx, key, getOpts...) maxRev := int64(math.MaxInt64) getOpts = append(getOpts, v3.WithRev(0)) for err == nil { for len(resp.Kvs) > 0 { i := len(resp.Kvs) - 1 if resp.Kvs[i].CreateRevision <= maxRev { break } resp.Kvs = resp.Kvs[:i] } if len(resp.Kvs) == 0 { break } lastKV := resp.Kvs[len(resp.Kvs)-1] maxRev = lastKV.CreateRevision err = waitDelete(ctx, client, string(lastKV.Key), maxRev) if err != nil || len(resp.Kvs) == 1 { break } getOpts = append(getOpts, v3.WithLimit(int64(len(resp.Kvs)-1))) resp, err = client.Get(ctx, key, getOpts...) } return err }
func (n *ng) GetSnapshot() (*engine.Snapshot, error) { response, err := n.client.Get(n.context, n.etcdKey, etcd.WithPrefix(), etcd.WithSort(etcd.SortByKey, etcd.SortAscend)) if err != nil { return nil, err } s := &engine.Snapshot{Index: uint64(response.Header.Revision)} s.FrontendSpecs, err = n.parseFrontends(filterByPrefix(response.Kvs, n.etcdKey+"/frontends")) if err != nil { return nil, err } s.BackendSpecs, err = n.parseBackends(filterByPrefix(response.Kvs, n.etcdKey+"/backends")) if err != nil { return nil, err } s.Hosts, err = n.parseHosts(filterByPrefix(response.Kvs, n.etcdKey+"/hosts")) if err != nil { return nil, err } s.Listeners, err = n.parseListeners(filterByPrefix(response.Kvs, n.etcdKey+"/listeners")) if err != nil { return nil, err } return s, nil }
func (e *etcdv3Registry) ListServices() ([]*registry.Service, error) { var services []*registry.Service nameSet := make(map[string]struct{}) ctx, cancel := context.WithTimeout(context.Background(), e.options.Timeout) defer cancel() rsp, err := e.client.Get(ctx, prefix, clientv3.WithPrefix(), clientv3.WithSort(clientv3.SortByKey, clientv3.SortDescend)) if err != nil { return nil, err } if len(rsp.Kvs) == 0 { return []*registry.Service{}, nil } for _, n := range rsp.Kvs { if sn := decode(n.Value); sn != nil { nameSet[sn.Name] = struct{}{} } } for k := range nameSet { service := ®istry.Service{} service.Name = k services = append(services, service) } return services, nil }
func (n *ng) GetFrontends() ([]engine.Frontend, error) { key := fmt.Sprintf("%s/frontends", n.etcdKey) response, err := n.client.Get(n.context, key, etcd.WithPrefix(), etcd.WithSort(etcd.SortByKey, etcd.SortAscend)) if err != nil { return nil, err } frontendSpecs, err := n.parseFrontends(response.Kvs, true) if err != nil { return nil, err } frontends := make([]engine.Frontend, len(frontendSpecs)) for i, frontendSpec := range frontendSpecs { frontends[i] = frontendSpec.Frontend } return frontends, nil }
func getGetOp(cmd *cobra.Command, args []string) (string, []clientv3.OpOption) { if len(args) == 0 { ExitWithError(ExitBadArgs, fmt.Errorf("range command needs arguments.")) } opts := []clientv3.OpOption{} key := args[0] if len(args) > 1 { opts = append(opts, clientv3.WithRange(args[1])) } opts = append(opts, clientv3.WithLimit(getLimit)) sortByOrder := clientv3.SortNone sortOrder := strings.ToUpper(getSortOrder) switch { case sortOrder == "ASCEND": sortByOrder = clientv3.SortAscend case sortOrder == "DESCEND": sortByOrder = clientv3.SortDescend case sortOrder == "": // nothing default: ExitWithError(ExitBadFeature, fmt.Errorf("bad sort order %v", getSortOrder)) } sortByTarget := clientv3.SortByKey sortTarget := strings.ToUpper(getSortTarget) switch { case sortTarget == "CREATE": sortByTarget = clientv3.SortByCreatedRev case sortTarget == "KEY": sortByTarget = clientv3.SortByKey case sortTarget == "MODIFY": sortByTarget = clientv3.SortByModifiedRev case sortTarget == "VALUE": sortByTarget = clientv3.SortByValue case sortTarget == "VERSION": sortByTarget = clientv3.SortByVersion case sortTarget == "": // nothing default: ExitWithError(ExitBadFeature, fmt.Errorf("bad sort target %v", getSortTarget)) } opts = append(opts, clientv3.WithSort(sortByTarget, sortByOrder)) return key, opts }
func RangeRequestToOp(r *pb.RangeRequest) clientv3.Op { opts := []clientv3.OpOption{} if len(r.RangeEnd) != 0 { opts = append(opts, clientv3.WithRange(string(r.RangeEnd))) } opts = append(opts, clientv3.WithRev(r.Revision)) opts = append(opts, clientv3.WithLimit(r.Limit)) opts = append(opts, clientv3.WithSort( clientv3.SortTarget(r.SortTarget), clientv3.SortOrder(r.SortOrder)), ) if r.Serializable { opts = append(opts, clientv3.WithSerializable()) } return clientv3.OpGet(string(r.Key), opts...) }
func (e *etcdv3Registry) GetService(name string) ([]*registry.Service, error) { ctx, cancel := context.WithTimeout(context.Background(), e.options.Timeout) defer cancel() rsp, err := e.client.Get(ctx, servicePath(name)+"/", clientv3.WithPrefix(), clientv3.WithSort(clientv3.SortByKey, clientv3.SortDescend)) if err != nil { return nil, err } if len(rsp.Kvs) == 0 { return nil, registry.ErrNotFound } serviceMap := map[string]*registry.Service{} for _, n := range rsp.Kvs { if sn := decode(n.Value); sn != nil { s, ok := serviceMap[sn.Version] if !ok { s = ®istry.Service{ Name: sn.Name, Version: sn.Version, Metadata: sn.Metadata, Endpoints: sn.Endpoints, } serviceMap[s.Version] = s } for _, node := range sn.Nodes { s.Nodes = append(s.Nodes, node) } } } var services []*registry.Service for _, service := range serviceMap { services = append(services, service) } return services, nil }
func (n *ng) getKeysBySecondPrefix(keys ...string) ([]string, error) { var out []string targetPrefix := strings.Join(keys, "/") response, err := n.client.Get(n.context, targetPrefix, etcd.WithPrefix(), etcd.WithSort(etcd.SortByKey, etcd.SortAscend)) if err != nil { if notFound(err) { return out, nil } return nil, err } //If /this/is/prefix then // allow /this/is/prefix/one/two // disallow /this/is/prefix/one/two/three // disallow /this/is/prefix/one for _, keyValue := range response.Kvs { if prefix(prefix(string(keyValue.Key))) == targetPrefix { out = append(out, string(keyValue.Key)) } } return out, nil }
func TestKVRange(t *testing.T) { defer testutil.AfterTest(t) clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3}) defer clus.Terminate(t) kv := clientv3.NewKV(clus.RandClient()) ctx := context.TODO() keySet := []string{"a", "b", "c", "c", "c", "foo", "foo/abc", "fop"} for i, key := range keySet { if _, err := kv.Put(ctx, key, ""); err != nil { t.Fatalf("#%d: couldn't put %q (%v)", i, key, err) } } resp, err := kv.Get(ctx, keySet[0]) if err != nil { t.Fatalf("couldn't get key (%v)", err) } wheader := resp.Header tests := []struct { begin, end string rev int64 sortOption *clientv3.SortOption serializable bool wantSet []*storagepb.KeyValue }{ // range first two { "a", "c", 0, nil, false, []*storagepb.KeyValue{ {Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1}, {Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1}, }, }, // range first two with serializable { "a", "c", 0, nil, true, []*storagepb.KeyValue{ {Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1}, {Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1}, }, }, // range all with rev { "a", "x", 2, nil, false, []*storagepb.KeyValue{ {Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1}, }, }, // range all with SortByKey, SortAscend { "a", "x", 0, &clientv3.SortOption{Target: clientv3.SortByKey, Order: clientv3.SortAscend}, false, []*storagepb.KeyValue{ {Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1}, {Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1}, {Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3}, {Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1}, {Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1}, {Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1}, }, }, // range all with SortByCreatedRev, SortDescend { "a", "x", 0, &clientv3.SortOption{Target: clientv3.SortByCreatedRev, Order: clientv3.SortDescend}, false, []*storagepb.KeyValue{ {Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1}, {Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1}, {Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1}, {Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3}, {Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1}, {Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1}, }, }, // range all with SortByModifiedRev, SortDescend { "a", "x", 0, &clientv3.SortOption{Target: clientv3.SortByModifiedRev, Order: clientv3.SortDescend}, false, []*storagepb.KeyValue{ {Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1}, {Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1}, {Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1}, {Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3}, {Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1}, {Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1}, }, }, } for i, tt := range tests { opts := []clientv3.OpOption{clientv3.WithRange(tt.end), clientv3.WithRev(tt.rev)} if tt.sortOption != nil { opts = append(opts, clientv3.WithSort(tt.sortOption.Target, tt.sortOption.Order)) } if tt.serializable == true { opts = append(opts, clientv3.WithSerializable()) } resp, err := kv.Get(ctx, tt.begin, opts...) if err != nil { t.Fatalf("#%d: couldn't range (%v)", i, err) } if !reflect.DeepEqual(wheader, resp.Header) { t.Fatalf("#%d: wheader expected %+v, got %+v", i, wheader, resp.Header) } if !reflect.DeepEqual(tt.wantSet, resp.Kvs) { t.Fatalf("#%d: resp.Kvs expected %+v, got %+v", i, tt.wantSet, resp.Kvs) } } }
func (n *ng) getVals(keys ...string) ([]Pair, error) { var out []Pair response, err := n.client.Get(n.context, strings.Join(keys, "/"), etcd.WithPrefix(), etcd.WithSort(etcd.SortByKey, etcd.SortAscend)) if err != nil { if notFound(err) { return out, nil } return nil, err } for _, keyValue := range response.Kvs { out = append(out, Pair{string(keyValue.Key), string(keyValue.Value)}) } return out, nil }
//Watch keep watch update under the path func (s *Sync) Watch(path string, responseChan chan *sync.Event, stopChan chan bool) error { node, err := s.etcdClient.Get(s.withTimeout(), path, etcd.WithSort(etcd.SortByKey, etcd.SortAscend)) if err != nil { return err } eventsFromNode("get", node.Kvs, responseChan) dir, err := s.etcdClient.Get(s.withTimeout(), path+"/", etcd.WithPrefix(), etcd.WithSort(etcd.SortByKey, etcd.SortAscend)) if err != nil { return err } eventsFromNode("get", dir.Kvs, responseChan) ctx, cancel := context.WithCancel(context.Background()) errors := make(chan error, 2) var wg syn.WaitGroup wg.Add(1) go func() { defer wg.Done() err := func() error { rch := s.etcdClient.Watch(ctx, path, etcd.WithRev(node.Header.Revision+1)) for wresp := range rch { err := wresp.Err() if err != nil { return err } for _, ev := range wresp.Events { action := "unknown" switch ev.Type { case etcd.EventTypePut: action = "set" case etcd.EventTypeDelete: action = "delete" } eventsFromNode(action, []*pb.KeyValue{ev.Kv}, responseChan) } } return nil }() errors <- err }() wg.Add(1) go func() { defer wg.Done() err := func() error { rch := s.etcdClient.Watch(ctx, path+"/", etcd.WithPrefix(), etcd.WithRev(node.Header.Revision+1)) for wresp := range rch { err := wresp.Err() if err != nil { return err } for _, ev := range wresp.Events { action := "unknown" switch ev.Type { case etcd.EventTypePut: action = "set" case etcd.EventTypeDelete: action = "delete" } eventsFromNode(action, []*pb.KeyValue{ev.Kv}, responseChan) } } return nil }() errors <- err }() select { case <-stopChan: cancel() wg.Wait() return nil case err := <-errors: cancel() wg.Wait() return err } }
func TestKVRange(t *testing.T) { defer testutil.AfterTest(t) clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3}) defer clus.Terminate(t) kv := clientv3.NewKV(clus.RandClient()) ctx := context.TODO() keySet := []string{"a", "b", "c", "c", "c", "foo", "foo/abc", "fop"} for i, key := range keySet { if _, err := kv.Put(ctx, key, ""); err != nil { t.Fatalf("#%d: couldn't put %q (%v)", i, key, err) } } resp, err := kv.Get(ctx, keySet[0]) if err != nil { t.Fatalf("couldn't get key (%v)", err) } wheader := resp.Header tests := []struct { begin, end string rev int64 opts []clientv3.OpOption wantSet []*mvccpb.KeyValue }{ // range first two { "a", "c", 0, nil, []*mvccpb.KeyValue{ {Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1}, {Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1}, }, }, // range first two with serializable { "a", "c", 0, []clientv3.OpOption{clientv3.WithSerializable()}, []*mvccpb.KeyValue{ {Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1}, {Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1}, }, }, // range all with rev { "a", "x", 2, nil, []*mvccpb.KeyValue{ {Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1}, }, }, // range all with countOnly { "a", "x", 2, []clientv3.OpOption{clientv3.WithCountOnly()}, nil, }, // range all with SortByKey, SortAscend { "a", "x", 0, []clientv3.OpOption{clientv3.WithSort(clientv3.SortByKey, clientv3.SortAscend)}, []*mvccpb.KeyValue{ {Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1}, {Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1}, {Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3}, {Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1}, {Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1}, {Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1}, }, }, // range all with SortByKey, missing sorting order (ASCEND by default) { "a", "x", 0, []clientv3.OpOption{clientv3.WithSort(clientv3.SortByKey, clientv3.SortNone)}, []*mvccpb.KeyValue{ {Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1}, {Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1}, {Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3}, {Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1}, {Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1}, {Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1}, }, }, // range all with SortByCreateRevision, SortDescend { "a", "x", 0, []clientv3.OpOption{clientv3.WithSort(clientv3.SortByCreateRevision, clientv3.SortDescend)}, []*mvccpb.KeyValue{ {Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1}, {Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1}, {Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1}, {Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3}, {Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1}, {Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1}, }, }, // range all with SortByCreateRevision, missing sorting order (ASCEND by default) { "a", "x", 0, []clientv3.OpOption{clientv3.WithSort(clientv3.SortByCreateRevision, clientv3.SortNone)}, []*mvccpb.KeyValue{ {Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1}, {Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1}, {Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3}, {Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1}, {Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1}, {Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1}, }, }, // range all with SortByModRevision, SortDescend { "a", "x", 0, []clientv3.OpOption{clientv3.WithSort(clientv3.SortByModRevision, clientv3.SortDescend)}, []*mvccpb.KeyValue{ {Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1}, {Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1}, {Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1}, {Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3}, {Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1}, {Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1}, }, }, // WithPrefix { "foo", "", 0, []clientv3.OpOption{clientv3.WithPrefix()}, []*mvccpb.KeyValue{ {Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1}, {Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1}, }, }, // WithFromKey { "fo", "", 0, []clientv3.OpOption{clientv3.WithFromKey()}, []*mvccpb.KeyValue{ {Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1}, {Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1}, {Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1}, }, }, } for i, tt := range tests { opts := []clientv3.OpOption{clientv3.WithRange(tt.end), clientv3.WithRev(tt.rev)} opts = append(opts, tt.opts...) resp, err := kv.Get(ctx, tt.begin, opts...) if err != nil { t.Fatalf("#%d: couldn't range (%v)", i, err) } if !reflect.DeepEqual(wheader, resp.Header) { t.Fatalf("#%d: wheader expected %+v, got %+v", i, wheader, resp.Header) } if !reflect.DeepEqual(tt.wantSet, resp.Kvs) { t.Fatalf("#%d: resp.Kvs expected %+v, got %+v", i, tt.wantSet, resp.Kvs) } } }
func (n *ng) GetBackends() ([]engine.Backend, error) { response, err := n.client.Get(n.context, fmt.Sprintf("%s/backends", n.etcdKey), etcd.WithPrefix(), etcd.WithSort(etcd.SortByKey, etcd.SortAscend)) if err != nil { return nil, err } backendSpecs, err := n.parseBackends(response.Kvs, true) if err != nil { return nil, err } backends := make([]engine.Backend, len(backendSpecs)) for i, backendSpec := range backendSpecs { backends[i] = backendSpec.Backend } return backends, nil }
func getGetOp(cmd *cobra.Command, args []string) (string, []clientv3.OpOption) { if len(args) == 0 { ExitWithError(ExitBadArgs, fmt.Errorf("range command needs arguments.")) } if getPrefix && getFromKey { ExitWithError(ExitBadArgs, fmt.Errorf("`--prefix` and `--from-key` cannot be set at the same time, choose one.")) } opts := []clientv3.OpOption{} switch getConsistency { case "s": opts = append(opts, clientv3.WithSerializable()) case "l": default: ExitWithError(ExitBadFeature, fmt.Errorf("unknown consistency flag %q", getConsistency)) } key := args[0] if len(args) > 1 { if getPrefix || getFromKey { ExitWithError(ExitBadArgs, fmt.Errorf("too many arguments, only accept one arguement when `--prefix` or `--from-key` is set.")) } opts = append(opts, clientv3.WithRange(args[1])) } opts = append(opts, clientv3.WithLimit(getLimit)) if getRev > 0 { opts = append(opts, clientv3.WithRev(getRev)) } sortByOrder := clientv3.SortNone sortOrder := strings.ToUpper(getSortOrder) switch { case sortOrder == "ASCEND": sortByOrder = clientv3.SortAscend case sortOrder == "DESCEND": sortByOrder = clientv3.SortDescend case sortOrder == "": // nothing default: ExitWithError(ExitBadFeature, fmt.Errorf("bad sort order %v", getSortOrder)) } sortByTarget := clientv3.SortByKey sortTarget := strings.ToUpper(getSortTarget) switch { case sortTarget == "CREATE": sortByTarget = clientv3.SortByCreateRevision case sortTarget == "KEY": sortByTarget = clientv3.SortByKey case sortTarget == "MODIFY": sortByTarget = clientv3.SortByModRevision case sortTarget == "VALUE": sortByTarget = clientv3.SortByValue case sortTarget == "VERSION": sortByTarget = clientv3.SortByVersion case sortTarget == "": // nothing default: ExitWithError(ExitBadFeature, fmt.Errorf("bad sort target %v", getSortTarget)) } opts = append(opts, clientv3.WithSort(sortByTarget, sortByOrder)) if getPrefix { opts = append(opts, clientv3.WithPrefix()) } if getFromKey { opts = append(opts, clientv3.WithFromKey()) } return key, opts }