etcd: add support for namespaces

This commit adds support for etcd namespaces. This is useful when
using a shared etcd database where separate users have access to
separate namespaces.
This commit is contained in:
Andras Banki-Horvath 2020-12-16 18:23:06 +01:00
parent f9641cdc64
commit 4a6af67241
No known key found for this signature in database
GPG Key ID: 80E5375C094198D8
5 changed files with 28 additions and 4 deletions

@ -44,6 +44,8 @@ type EtcdConfig struct {
Pass string `long:"pass" description:"Password for the database user."` Pass string `long:"pass" description:"Password for the database user."`
Namespace string `long:"namespace" description:"The etcd namespace to use."`
CertFile string `long:"cert_file" description:"Path to the TLS certificate for etcd RPC."` CertFile string `long:"cert_file" description:"Path to the TLS certificate for etcd RPC."`
KeyFile string `long:"key_file" description:"Path to the TLS private key for etcd RPC."` KeyFile string `long:"key_file" description:"Path to the TLS private key for etcd RPC."`

@ -12,6 +12,7 @@ import (
"github.com/btcsuite/btcwallet/walletdb" "github.com/btcsuite/btcwallet/walletdb"
"github.com/coreos/etcd/clientv3" "github.com/coreos/etcd/clientv3"
"github.com/coreos/etcd/clientv3/namespace"
"github.com/coreos/etcd/pkg/transport" "github.com/coreos/etcd/pkg/transport"
) )
@ -153,6 +154,9 @@ type BackendConfig struct {
// name spaces. // name spaces.
Prefix string Prefix string
// Namespace is the etcd namespace that we'll use for all keys.
Namespace string
// CollectCommitStats indicates wheter to commit commit stats. // CollectCommitStats indicates wheter to commit commit stats.
CollectCommitStats bool CollectCommitStats bool
} }
@ -184,11 +188,15 @@ func newEtcdBackend(config BackendConfig) (*db, error) {
TLS: tlsConfig, TLS: tlsConfig,
MaxCallSendMsgSize: 16384*1024 - 1, MaxCallSendMsgSize: 16384*1024 - 1,
}) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Apply the namespace.
cli.KV = namespace.NewKV(cli.KV, config.Namespace)
cli.Watcher = namespace.NewWatcher(cli.Watcher, config.Namespace)
cli.Lease = namespace.NewLease(cli.Lease, config.Namespace)
backend := &db{ backend := &db{
cli: cli, cli: cli,
config: config, config: config,

@ -21,6 +21,12 @@ const (
// embedded etcd servers. Ports are monotonically increasing starting // embedded etcd servers. Ports are monotonically increasing starting
// from this number and are determined by the results of getFreePort(). // from this number and are determined by the results of getFreePort().
defaultEtcdPort = 2379 defaultEtcdPort = 2379
// defaultNamespace is the namespace we'll use in our embedded etcd
// instance. Since it is only used for testing, we'll use the namespace
// name "test/" for this. Note that the namespace can be any string,
// the trailing / is not required.
defaultNamespace = "test/"
) )
var ( var (
@ -90,6 +96,7 @@ func NewEmbeddedEtcdInstance(path string) (*BackendConfig, func(), error) {
User: "user", User: "user",
Pass: "pass", Pass: "pass",
InsecureSkipVerify: true, InsecureSkipVerify: true,
Namespace: defaultNamespace,
} }
return connConfig, func() { return connConfig, func() {

@ -10,6 +10,7 @@ import (
"time" "time"
"github.com/coreos/etcd/clientv3" "github.com/coreos/etcd/clientv3"
"github.com/coreos/etcd/clientv3/namespace"
) )
const ( const (
@ -59,6 +60,11 @@ func NewEtcdTestFixture(t *testing.T) *EtcdTestFixture {
t.Fatalf("unable to create etcd test fixture: %v", err) t.Fatalf("unable to create etcd test fixture: %v", err)
} }
// Apply the default namespace (since that's what we use in tests).
cli.KV = namespace.NewKV(cli.KV, defaultNamespace)
cli.Watcher = namespace.NewWatcher(cli.Watcher, defaultNamespace)
cli.Lease = namespace.NewLease(cli.Lease, defaultNamespace)
return &EtcdTestFixture{ return &EtcdTestFixture{
t: t, t: t,
cli: cli, cli: cli,
@ -88,7 +94,7 @@ func (f *EtcdTestFixture) Get(key string) string {
resp, err := f.cli.Get(ctx, key) resp, err := f.cli.Get(ctx, key)
if err != nil { if err != nil {
f.t.Fatalf("etcd test fixture failed to put: %v", err) f.t.Fatalf("etcd test fixture failed to get: %v", err)
} }
if len(resp.Kvs) > 0 { if len(resp.Kvs) > 0 {
@ -103,9 +109,9 @@ func (f *EtcdTestFixture) Dump() map[string]string {
ctx, cancel := context.WithTimeout(context.TODO(), testEtcdTimeout) ctx, cancel := context.WithTimeout(context.TODO(), testEtcdTimeout)
defer cancel() defer cancel()
resp, err := f.cli.Get(ctx, "", clientv3.WithPrefix()) resp, err := f.cli.Get(ctx, "\x00", clientv3.WithFromKey())
if err != nil { if err != nil {
f.t.Fatalf("etcd test fixture failed to put: %v", err) f.t.Fatalf("etcd test fixture failed to get: %v", err)
} }
result := make(map[string]string) result := make(map[string]string)

@ -28,6 +28,7 @@ func GetEtcdBackend(ctx context.Context, prefix string,
KeyFile: etcdConfig.KeyFile, KeyFile: etcdConfig.KeyFile,
InsecureSkipVerify: etcdConfig.InsecureSkipVerify, InsecureSkipVerify: etcdConfig.InsecureSkipVerify,
Prefix: prefix, Prefix: prefix,
Namespace: etcdConfig.Namespace,
CollectCommitStats: etcdConfig.CollectStats, CollectCommitStats: etcdConfig.CollectStats,
} }