commit
484d6f8765
|
@ -0,0 +1,78 @@
|
|||
package remote
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
||||
etcdapi "github.com/coreos/etcd/client"
|
||||
)
|
||||
|
||||
func etcdFactory(conf map[string]string) (Client, error) {
|
||||
path, ok := conf["path"]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing 'path' configuration")
|
||||
}
|
||||
|
||||
endpoints, ok := conf["endpoints"]
|
||||
if !ok || endpoints == "" {
|
||||
return nil, fmt.Errorf("missing 'endpoints' configuration")
|
||||
}
|
||||
|
||||
config := etcdapi.Config{
|
||||
Endpoints: strings.Split(endpoints, " "),
|
||||
}
|
||||
if username, ok := conf["username"]; ok && username != "" {
|
||||
config.Username = username
|
||||
}
|
||||
if password, ok := conf["password"]; ok && password != "" {
|
||||
config.Password = password
|
||||
}
|
||||
|
||||
client, err := etcdapi.New(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &EtcdClient{
|
||||
Client: client,
|
||||
Path: path,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// EtcdClient is a remote client that stores data in etcd.
|
||||
type EtcdClient struct {
|
||||
Client etcdapi.Client
|
||||
Path string
|
||||
}
|
||||
|
||||
func (c *EtcdClient) Get() (*Payload, error) {
|
||||
resp, err := etcdapi.NewKeysAPI(c.Client).Get(context.Background(), c.Path, &etcdapi.GetOptions{Quorum: true})
|
||||
if err != nil {
|
||||
if err, ok := err.(etcdapi.Error); ok && err.Code == etcdapi.ErrorCodeKeyNotFound {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if resp.Node.Dir {
|
||||
return nil, fmt.Errorf("path is a directory")
|
||||
}
|
||||
|
||||
data := []byte(resp.Node.Value)
|
||||
md5 := md5.Sum(data)
|
||||
return &Payload{
|
||||
Data: data,
|
||||
MD5: md5[:],
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *EtcdClient) Put(data []byte) error {
|
||||
_, err := etcdapi.NewKeysAPI(c.Client).Set(context.Background(), c.Path, string(data), nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *EtcdClient) Delete() error {
|
||||
_, err := etcdapi.NewKeysAPI(c.Client).Delete(context.Background(), c.Path, nil)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package remote
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestEtcdClient_impl(t *testing.T) {
|
||||
var _ Client = new(EtcdClient)
|
||||
}
|
||||
|
||||
func TestEtcdClient(t *testing.T) {
|
||||
endpoint := os.Getenv("ETCD_ENDPOINT")
|
||||
if endpoint == "" {
|
||||
t.Skipf("skipping; ETCD_ENDPOINT must be set")
|
||||
}
|
||||
|
||||
config := map[string]string{
|
||||
"endpoints": endpoint,
|
||||
"path": fmt.Sprintf("tf-unit/%s", time.Now().String()),
|
||||
}
|
||||
|
||||
if username := os.Getenv("ETCD_USERNAME"); username != "" {
|
||||
config["username"] = username
|
||||
}
|
||||
if password := os.Getenv("ETCD_PASSWORD"); password != "" {
|
||||
config["password"] = password
|
||||
}
|
||||
|
||||
client, err := etcdFactory(config)
|
||||
if err != nil {
|
||||
t.Fatalf("Error for valid config: %s", err)
|
||||
}
|
||||
|
||||
testClient(t, client)
|
||||
}
|
|
@ -38,6 +38,7 @@ func NewClient(t string, conf map[string]string) (Client, error) {
|
|||
var BuiltinClients = map[string]Factory{
|
||||
"atlas": atlasFactory,
|
||||
"consul": consulFactory,
|
||||
"etcd": etcdFactory,
|
||||
"http": httpFactory,
|
||||
"s3": s3Factory,
|
||||
"swift": swiftFactory,
|
||||
|
|
|
@ -58,6 +58,11 @@ The following backends are supported:
|
|||
`address`, either `http` or `https`. SSL support can also be triggered
|
||||
by setting then environment variable `CONSUL_HTTP_SSL` to `true`.
|
||||
|
||||
* Etcd - Stores the state in etcd at a given path.
|
||||
Requires the `path` and `endpoints` variables. The `username` and `password`
|
||||
variables can optionally be provided. `endpoints` is assumed to be a
|
||||
space-separated list of etcd endpoints.
|
||||
|
||||
* S3 - Stores the state as a given key in a given bucket on Amazon S3.
|
||||
Requires the `bucket` and `key` variables. Supports and honors the standard
|
||||
AWS environment variables `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`
|
||||
|
|
Loading…
Reference in New Issue