Переглянути джерело

clientv3: add more code examples

Gyu-Ho Lee 9 роки тому
батько
коміт
72a1e5618b

+ 1 - 1
clientv3/README.md

@@ -27,7 +27,7 @@ defer cli.Close()
 
 etcd v3 uses [`gRPC`](http://www.grpc.io) for remote procedure calls. And `clientv3` uses
 [`grpc-go`](https://github.com/grpc/grpc-go) to connect to etcd. Make sure to close the client after using it. 
-If the client is not closed, the connection will cause leaky goroutines. To specify client request timeout,
+If the client is not closed, the connection will have leaky goroutines. To specify client request timeout,
 pass `context.WithTimeout` to APIs:
 
 ```go

+ 43 - 0
clientv3/doc.go

@@ -0,0 +1,43 @@
+// Copyright 2016 CoreOS, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// clientv3 is the official Go etcd client for v3.
+//
+// Create client using `clientv3.New`:
+//
+//	cli, err := clientv3.New(clientv3.Config{
+//		Endpoints:   []string{"localhost:12378", "localhost:22378", "localhost:32378"},
+//		DialTimeout: 5 * time.Second,
+//	})
+//	if err != nil {
+//		// handle error!
+//	}
+//	defer cli.Close()
+//
+// Make sure to close the client after using it. If the client is not closed, the
+// connection will have leaky goroutines.
+//
+// To specify client request timeout, pass context.WithTimeout to APIs:
+//
+//	ctx, cancel := context.WithTimeout(context.Background(), timeout)
+//	resp, err := kvc.Put(ctx, "sample_key", "sample_value")
+//	cancel()
+//	if err != nil {
+//	    // handle error!
+//	}
+//	// use the response
+//
+//	TODO: document error handling
+//
+package clientv3

+ 131 - 0
clientv3/example_cluster_test.go

@@ -0,0 +1,131 @@
+// Copyright 2016 CoreOS, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package clientv3_test
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
+	"github.com/coreos/etcd/clientv3"
+)
+
+func ExampleCluster_memberList() {
+	cli, err := clientv3.New(clientv3.Config{
+		Endpoints:   endpoints,
+		DialTimeout: dialTimeout,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer cli.Close()
+
+	capi := clientv3.NewCluster(cli)
+
+	resp, err := capi.MemberList(context.Background())
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Println("members:", len(resp.Members))
+	// members: 3
+}
+
+func ExampleCluster_memberLeader() {
+	cli, err := clientv3.New(clientv3.Config{
+		Endpoints:   endpoints,
+		DialTimeout: dialTimeout,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer cli.Close()
+
+	capi := clientv3.NewCluster(cli)
+
+	resp, err := capi.MemberLeader(context.Background())
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Println("leader:", resp.Name)
+	// leader: infra1
+}
+
+func ExampleCluster_memberAdd() {
+	cli, err := clientv3.New(clientv3.Config{
+		Endpoints:   endpoints[:2],
+		DialTimeout: dialTimeout,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer cli.Close()
+
+	capi := clientv3.NewCluster(cli)
+
+	peerURLs := endpoints[2:]
+	mresp, err := capi.MemberAdd(context.Background(), peerURLs)
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Println("added member.PeerURLs:", mresp.Member.PeerURLs)
+	// added member.PeerURLs: [http://localhost:32380]
+}
+
+func ExampleCluster_memberRemove() {
+	cli, err := clientv3.New(clientv3.Config{
+		Endpoints:   endpoints[1:],
+		DialTimeout: dialTimeout,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer cli.Close()
+
+	capi := clientv3.NewCluster(cli)
+
+	resp, err := capi.MemberList(context.Background())
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	_, err = capi.MemberRemove(context.Background(), resp.Members[0].ID)
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+func ExampleCluster_memberUpdate() {
+	cli, err := clientv3.New(clientv3.Config{
+		Endpoints:   endpoints,
+		DialTimeout: dialTimeout,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer cli.Close()
+
+	capi := clientv3.NewCluster(cli)
+
+	resp, err := capi.MemberList(context.Background())
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	peerURLs := []string{"http://localhost:12378"}
+	_, err = capi.MemberUpdate(context.Background(), resp.Members[0].ID, peerURLs)
+	if err != nil {
+		log.Fatal(err)
+	}
+}

+ 130 - 15
clientv3/example_kv_test.go

@@ -17,19 +17,14 @@ package clientv3_test
 import (
 	"fmt"
 	"log"
-	"time"
 
 	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
 	"github.com/coreos/etcd/clientv3"
 )
 
 func ExampleKV_put() {
-	var (
-		dialTimeout    = 5 * time.Second
-		requestTimeout = 1 * time.Second
-	)
 	cli, err := clientv3.New(clientv3.Config{
-		Endpoints:   []string{"localhost:12378", "localhost:22378", "localhost:32378"},
+		Endpoints:   endpoints,
 		DialTimeout: dialTimeout,
 	})
 	if err != nil {
@@ -45,17 +40,13 @@ func ExampleKV_put() {
 	if err != nil {
 		log.Fatal(err)
 	}
-	fmt.Println("OK")
-	fmt.Println(resp.Header)
+	fmt.Println("current revision:", resp.Header.Revision) // revision start at 1
+	// current revision: 2
 }
 
 func ExampleKV_get() {
-	var (
-		dialTimeout    = 5 * time.Second
-		requestTimeout = 1 * time.Second
-	)
 	cli, err := clientv3.New(clientv3.Config{
-		Endpoints:   []string{"localhost:12378", "localhost:22378", "localhost:32378"},
+		Endpoints:   endpoints,
 		DialTimeout: dialTimeout,
 	})
 	if err != nil {
@@ -65,14 +56,138 @@ func ExampleKV_get() {
 
 	kvc := clientv3.NewKV(cli)
 
+	_, err = kvc.Put(context.TODO(), "foo", "bar")
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
+	resp, err := kvc.Get(ctx, "foo")
+	cancel()
+	if err != nil {
+		log.Fatal(err)
+	}
+	for _, ev := range resp.Kvs {
+		fmt.Printf("%s : %s\n", ev.Key, ev.Value)
+	}
+	// foo : bar
+}
+
+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, "sample_key")
+	resp, err := kvc.Get(ctx, "key", clientv3.WithPrefix(), clientv3.WithSort(clientv3.SortByKey, clientv3.SortDescend))
 	cancel()
 	if err != nil {
 		log.Fatal(err)
 	}
-	fmt.Println("OK")
 	for _, ev := range resp.Kvs {
 		fmt.Printf("%s : %s\n", ev.Key, ev.Value)
 	}
+	// key_2 : value
+	// key_1 : value
+	// key_0 : value
+}
+
+func ExampleKV_delete() {
+	cli, err := clientv3.New(clientv3.Config{
+		Endpoints:   endpoints,
+		DialTimeout: dialTimeout,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer cli.Close()
+
+	kvc := clientv3.NewKV(cli)
+
+	ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
+	resp, err := kvc.Delete(ctx, "key", clientv3.WithPrefix())
+	cancel()
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Println("Deleted", resp.Deleted, "keys")
+	// Deleted n keys
+}
+
+func ExampleKV_compact() {
+	cli, err := clientv3.New(clientv3.Config{
+		Endpoints:   endpoints,
+		DialTimeout: dialTimeout,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer cli.Close()
+
+	kvc := clientv3.NewKV(cli)
+
+	ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
+	resp, err := kvc.Get(ctx, "foo")
+	cancel()
+	if err != nil {
+		log.Fatal(err)
+	}
+	compRev := resp.Header.Revision // specify compact revision of your choice
+
+	ctx, cancel = context.WithTimeout(context.Background(), requestTimeout)
+	err = kvc.Compact(ctx, compRev)
+	cancel()
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+func ExampleKV_txn() {
+	cli, err := clientv3.New(clientv3.Config{
+		Endpoints:   endpoints,
+		DialTimeout: dialTimeout,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer cli.Close()
+
+	kvc := clientv3.NewKV(cli)
+
+	// TODO: 'if' not working. Add expected output once fixed.
+	ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
+	_, err = kvc.Txn(ctx).
+		If(clientv3.Compare(clientv3.Value("1"), ">", "1")).
+		Then(clientv3.OpPut("1", "100")).
+		Else(clientv3.OpPut("1", "-1")).
+		Commit()
+	cancel()
+	if err == nil {
+		log.Fatal(err)
+	}
+
+	gresp, err := kvc.Get(ctx, "1")
+	cancel()
+	if err != nil {
+		log.Fatal(err)
+	}
+	for _, ev := range gresp.Kvs {
+		fmt.Printf("%s : %s\n", ev.Key, ev.Value)
+	}
 }

+ 151 - 0
clientv3/example_lease_test.go

@@ -0,0 +1,151 @@
+// Copyright 2016 CoreOS, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package clientv3_test
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
+	"github.com/coreos/etcd/clientv3"
+	"github.com/coreos/etcd/lease"
+)
+
+func ExampleLease_create() {
+	cli, err := clientv3.New(clientv3.Config{
+		Endpoints:   endpoints,
+		DialTimeout: dialTimeout,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer cli.Close()
+
+	kvc := clientv3.NewKV(cli)
+	lapi := clientv3.NewLease(cli)
+	defer lapi.Close()
+
+	// minimum lease TTL is 5-second
+	resp, err := lapi.Create(context.TODO(), 5)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// after 5 seconds, the key 'foo' will be removed
+	_, err = kvc.Put(context.TODO(), "foo", "bar", clientv3.WithLease(lease.LeaseID(resp.ID)))
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+func ExampleLease_revoke() {
+	cli, err := clientv3.New(clientv3.Config{
+		Endpoints:   endpoints,
+		DialTimeout: dialTimeout,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer cli.Close()
+
+	kvc := clientv3.NewKV(cli)
+	lapi := clientv3.NewLease(cli)
+	defer lapi.Close()
+
+	resp, err := lapi.Create(context.TODO(), 5)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	_, err = kvc.Put(context.TODO(), "foo", "bar", clientv3.WithLease(lease.LeaseID(resp.ID)))
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// revoking lease expires the key attached to its lease ID
+	_, err = lapi.Revoke(context.TODO(), lease.LeaseID(resp.ID))
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	gresp, err := kvc.Get(context.TODO(), "foo")
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Println("number of keys:", len(gresp.Kvs))
+	// number of keys: 0
+}
+
+func ExampleLease_keepAlive() {
+	cli, err := clientv3.New(clientv3.Config{
+		Endpoints:   endpoints,
+		DialTimeout: dialTimeout,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer cli.Close()
+
+	kvc := clientv3.NewKV(cli)
+	lapi := clientv3.NewLease(cli)
+	defer lapi.Close()
+
+	resp, err := lapi.Create(context.TODO(), 5)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	_, err = kvc.Put(context.TODO(), "foo", "bar", clientv3.WithLease(lease.LeaseID(resp.ID)))
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// the key 'foo' will be kept forever
+	_, err = lapi.KeepAlive(context.TODO(), lease.LeaseID(resp.ID))
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+func ExampleLease_keepAliveOnce() {
+	cli, err := clientv3.New(clientv3.Config{
+		Endpoints:   endpoints,
+		DialTimeout: dialTimeout,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer cli.Close()
+
+	kvc := clientv3.NewKV(cli)
+	lapi := clientv3.NewLease(cli)
+	defer lapi.Close()
+
+	resp, err := lapi.Create(context.TODO(), 5)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	_, err = kvc.Put(context.TODO(), "foo", "bar", clientv3.WithLease(lease.LeaseID(resp.ID)))
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// to renew the lease only once
+	_, err = lapi.KeepAliveOnce(context.TODO(), lease.LeaseID(resp.ID))
+	if err != nil {
+		log.Fatal(err)
+	}
+}

+ 47 - 0
clientv3/example_test.go

@@ -0,0 +1,47 @@
+// Copyright 2016 CoreOS, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package clientv3_test
+
+import (
+	"log"
+	"time"
+
+	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
+	"github.com/coreos/etcd/clientv3"
+)
+
+var (
+	dialTimeout    = 5 * time.Second
+	requestTimeout = 1 * time.Second
+	endpoints      = []string{"localhost:12378", "localhost:22378", "http://localhost:32380"}
+)
+
+func Example() {
+	cli, err := clientv3.New(clientv3.Config{
+		Endpoints:   endpoints,
+		DialTimeout: dialTimeout,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer cli.Close() // make sure to close the client
+
+	kvc := clientv3.NewKV(cli)
+
+	_, err = kvc.Put(context.TODO(), "foo", "bar")
+	if err != nil {
+		log.Fatal(err)
+	}
+}

+ 67 - 0
clientv3/example_watch_test.go

@@ -0,0 +1,67 @@
+// Copyright 2016 CoreOS, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package clientv3_test
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
+	"github.com/coreos/etcd/clientv3"
+)
+
+func ExampleWatcher_watch() {
+	cli, err := clientv3.New(clientv3.Config{
+		Endpoints:   endpoints,
+		DialTimeout: dialTimeout,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer cli.Close()
+
+	wc := clientv3.NewWatcher(cli)
+	defer wc.Close()
+
+	rch := wc.Watch(context.Background(), "foo", 0)
+	for wresp := range rch {
+		for _, ev := range wresp.Events {
+			fmt.Printf("%s %q : %q\n", ev.Type, ev.Kv.Key, ev.Kv.Value)
+		}
+	}
+	// PUT "foo" : "bar"
+}
+
+func ExampleWatcher_watchPrefix() {
+	cli, err := clientv3.New(clientv3.Config{
+		Endpoints:   endpoints,
+		DialTimeout: dialTimeout,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer cli.Close()
+
+	wc := clientv3.NewWatcher(cli)
+	defer wc.Close()
+
+	rch := wc.WatchPrefix(context.Background(), "foo", 0)
+	for wresp := range rch {
+		for _, ev := range wresp.Events {
+			fmt.Printf("%s %q : %q\n", ev.Type, ev.Kv.Key, ev.Kv.Value)
+		}
+	}
+	// PUT "foo1" : "bar"
+}