This document contains useful example of usage for libkv
. It might not be complete but provides with general informations on how to use the client.
package main
import (
"fmt"
"time"
"log"
"github.com/docker/libkv"
"github.com/docker/libkv/store"
"github.com/docker/libkv/store/boltdb"
"github.com/docker/libkv/store/consul"
"github.com/docker/libkv/store/etcd/v3"
"github.com/docker/libkv/store/zookeeper"
"github.com/docker/libkv/store/redis"
)
func init() {
// Register consul store to libkv
consul.Register()
// We can register more backends that are supported by
// libkv if we plan to use these
etcdv3.Register()
zookeeper.Register()
boltdb.Register()
redis.Register()
}
func main() {
client := "localhost:8500"
// Initialize a new store with consul
kv, err := libkv.NewStore(
store.CONSUL, // or "consul"
[]string{client},
&store.Config{
ConnectionTimeout: 10*time.Second,
},
)
if err != nil {
log.Fatal("Cannot create store consul")
}
key := "foo"
err = kv.Put(key, []byte("bar"), nil)
if err != nil {
fmt.Errorf("Error trying to put value at key: %v", key)
}
pair, err := kv.Get(key, nil)
if err != nil {
fmt.Errorf("Error trying accessing value at key: %v", key)
}
err = kv.Delete(key)
if err != nil {
fmt.Errorf("Error trying to delete key %v", key)
}
log.Info("value: ", string(pair.Value))
}
// List will list all the keys under `key` if it contains a set of child keys/values
entries, err := kv.List(key, nil)
for _, pair := range entries {
fmt.Printf("key=%v - value=%v", pair.Key, string(pair.Value))
}
You can use watches to watch modifications on a key. First you need to check if the key exists. If this is not the case, we need to create it using the Put
function.
// Checking on the key before watching
if !kv.Exists(key, nil) {
err := kv.Put(key, []byte("bar"), nil)
if err != nil {
fmt.Errorf("Something went wrong when initializing key %v", key)
}
}
stopCh := make(<-chan struct{})
events, err := kv.Watch(key, stopCh, nil)
for {
select {
case pair := <-events:
// Do something with events
fmt.Printf("value changed on key %v: new value=%v", key, pair.Value)
}
}
You can use watches to watch modifications on a key. First you need to check if the key exists. If this is not the case, we need to create it using the Put
function. There is a special step here if you are using etcd APIv2 and if want your code to work across backends. etcd
with APIv2 makes the distinction between directories and keys, we need to make sure that the created key is considered as a directory by enforcing IsDir
at true
.
// Checking on the key before watching
if !kv.Exists(key, nil) {
// Do not forget `IsDir:true` if you are using etcd APIv2
err := kv.Put(key, []byte("bar"), &store.WriteOptions{IsDir:true})
if err != nil {
fmt.Errorf("Something went wrong when initializing key %v", key)
}
}
stopCh := make(<-chan struct{})
events, err := kv.WatchTree(key, stopCh, nil)
select {
case pairs := <-events:
// Do something with events
for _, pair := range pairs {
fmt.Printf("value changed on key %v: new value=%v", key, pair.Value)
}
}
key := "lockKey"
value := []byte("bar")
// Initialize a distributed lock. TTL is optional, it is here to make sure that
// the lock is released after the program that is holding the lock ends or crashes
lock, err := kv.NewLock(key, &store.LockOptions{Value: value, TTL: 2 * time.Second})
if err != nil {
fmt.Errorf("something went wrong when trying to initialize the Lock")
}
// Try to lock the key, the call to Lock() is blocking
_, err := lock.Lock(nil)
if err != nil {
fmt.Errorf("something went wrong when trying to lock key %v", key)
}
// Get should work because we are holding the key
pair, err := kv.Get(key, nil)
if err != nil {
fmt.Errorf("key %v has value %v", key, pair.Value)
}
// Unlock the key
err = lock.Unlock()
if err != nil {
fmt.Errorf("something went wrong when trying to unlock key %v", key)
}