etcd: refactors to simplify etcd configuration

This refactor removes a redundancy where we had etcd configuration under
kvdb and kvdb/etcd packages.
This commit is contained in:
Andras Banki-Horvath 2021-02-09 20:19:31 +01:00
parent 44e312ace9
commit 6757e14998
No known key found for this signature in database
GPG Key ID: 80E5375C094198D8
16 changed files with 136 additions and 157 deletions

@ -33,30 +33,3 @@ type BoltConfig struct {
DBTimeout time.Duration `long:"dbtimeout" description:"Specify the timeout value used when opening the database."` DBTimeout time.Duration `long:"dbtimeout" description:"Specify the timeout value used when opening the database."`
} }
// EtcdConfig holds etcd configuration.
type EtcdConfig struct {
Embedded bool `long:"embedded" description:"Use embedded etcd instance instead of the external one. Note: use for testing only."`
EmbeddedClientPort uint16 `long:"embedded_client_port" description:"Client port to use for the embedded instance. Note: use for testing only."`
EmbeddedPeerPort uint16 `long:"embedded_peer_port" description:"Peer port to use for the embedded instance. Note: use for testing only."`
Host string `long:"host" description:"Etcd database host."`
User string `long:"user" description:"Etcd database user."`
Pass string `long:"pass" description:"Password for the database user."`
Namespace string `long:"namespace" description:"The etcd namespace to use."`
DisableTLS bool `long:"disabletls" description:"Disable TLS for etcd connection. Caution: use for development only."`
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."`
InsecureSkipVerify bool `long:"insecure_skip_verify" description:"Whether we intend to skip TLS verification"`
CollectStats bool `long:"collect_stats" description:"Whether to collect etcd commit stats."`
}

@ -7,7 +7,7 @@ package etcd
func bkey(buckets ...string) string { func bkey(buckets ...string) string {
var bucketKey []byte var bucketKey []byte
rootID := makeBucketID([]byte("")) rootID := makeBucketID([]byte(etcdDefaultRootBucketId))
parent := rootID[:] parent := rootID[:]
for _, bucketName := range buckets { for _, bucketName := range buckets {
@ -29,7 +29,7 @@ func bval(buckets ...string) string {
// vkey is a helper function used in tests to create a value key from the // vkey is a helper function used in tests to create a value key from the
// passed key and bucket list. // passed key and bucket list.
func vkey(key string, buckets ...string) string { func vkey(key string, buckets ...string) string {
rootID := makeBucketID([]byte("")) rootID := makeBucketID([]byte(etcdDefaultRootBucketId))
bucket := rootID[:] bucket := rootID[:]
for _, bucketName := range buckets { for _, bucketName := range buckets {

@ -0,0 +1,28 @@
package etcd
// Config holds etcd configuration alongside with configuration related to our higher level interface.
type Config struct {
Embedded bool `long:"embedded" description:"Use embedded etcd instance instead of the external one. Note: use for testing only."`
EmbeddedClientPort uint16 `long:"embedded_client_port" description:"Client port to use for the embedded instance. Note: use for testing only."`
EmbeddedPeerPort uint16 `long:"embedded_peer_port" description:"Peer port to use for the embedded instance. Note: use for testing only."`
Host string `long:"host" description:"Etcd database host."`
User string `long:"user" description:"Etcd database user."`
Pass string `long:"pass" description:"Password for the database user."`
Namespace string `long:"namespace" description:"The etcd namespace to use."`
DisableTLS bool `long:"disabletls" description:"Disable TLS for etcd connection. Caution: use for development only."`
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."`
InsecureSkipVerify bool `long:"insecure_skip_verify" description:"Whether we intend to skip TLS verification"`
CollectStats bool `long:"collect_stats" description:"Whether to collect etcd commit stats."`
}

@ -120,7 +120,8 @@ func (c *commitStatsCollector) callback(succ bool, stats CommitStats) {
// db holds a reference to the etcd client connection. // db holds a reference to the etcd client connection.
type db struct { type db struct {
config BackendConfig cfg Config
ctx context.Context
cli *clientv3.Client cli *clientv3.Client
commitStatsCollector *commitStatsCollector commitStatsCollector *commitStatsCollector
txQueue *commitQueue txQueue *commitQueue
@ -129,61 +130,23 @@ type db struct {
// Enforce db implements the walletdb.DB interface. // Enforce db implements the walletdb.DB interface.
var _ walletdb.DB = (*db)(nil) var _ walletdb.DB = (*db)(nil)
// BackendConfig holds and etcd backend config and connection parameters.
type BackendConfig struct {
// Ctx is the context we use to cancel operations upon exit.
Ctx context.Context
// Host holds the peer url of the etcd instance.
Host string
// User is the username for the etcd peer.
User string
// Pass is the password for the etcd peer.
Pass string
// DisableTLS disables the use of TLS for etcd connections.
DisableTLS bool
// CertFile holds the path to the TLS certificate for etcd RPC.
CertFile string
// KeyFile holds the path to the TLS private key for etcd RPC.
KeyFile string
// InsecureSkipVerify should be set to true if we intend to
// skip TLS verification.
InsecureSkipVerify bool
// Namespace is the etcd namespace that we'll use for all keys.
Namespace string
// CollectCommitStats indicates wheter to commit commit stats.
CollectCommitStats bool
}
// newEtcdBackend returns a db object initialized with the passed backend // newEtcdBackend returns a db object initialized with the passed backend
// config. If etcd connection cannot be estabished, then returns error. // config. If etcd connection cannot be estabished, then returns error.
func newEtcdBackend(config BackendConfig) (*db, error) { func newEtcdBackend(ctx context.Context, cfg Config) (*db, error) {
if config.Ctx == nil {
config.Ctx = context.Background()
}
clientCfg := clientv3.Config{ clientCfg := clientv3.Config{
Context: config.Ctx, Context: ctx,
Endpoints: []string{config.Host}, Endpoints: []string{cfg.Host},
DialTimeout: etcdConnectionTimeout, DialTimeout: etcdConnectionTimeout,
Username: config.User, Username: cfg.User,
Password: config.Pass, Password: cfg.Pass,
MaxCallSendMsgSize: 16384*1024 - 1, MaxCallSendMsgSize: 16384*1024 - 1,
} }
if !config.DisableTLS { if !cfg.DisableTLS {
tlsInfo := transport.TLSInfo{ tlsInfo := transport.TLSInfo{
CertFile: config.CertFile, CertFile: cfg.CertFile,
KeyFile: config.KeyFile, KeyFile: cfg.KeyFile,
InsecureSkipVerify: config.InsecureSkipVerify, InsecureSkipVerify: cfg.InsecureSkipVerify,
} }
tlsConfig, err := tlsInfo.ClientConfig() tlsConfig, err := tlsInfo.ClientConfig()
@ -200,17 +163,18 @@ func newEtcdBackend(config BackendConfig) (*db, error) {
} }
// Apply the namespace. // Apply the namespace.
cli.KV = namespace.NewKV(cli.KV, config.Namespace) cli.KV = namespace.NewKV(cli.KV, cfg.Namespace)
cli.Watcher = namespace.NewWatcher(cli.Watcher, config.Namespace) cli.Watcher = namespace.NewWatcher(cli.Watcher, cfg.Namespace)
cli.Lease = namespace.NewLease(cli.Lease, config.Namespace) cli.Lease = namespace.NewLease(cli.Lease, cfg.Namespace)
backend := &db{ backend := &db{
cfg: cfg,
ctx: ctx,
cli: cli, cli: cli,
config: config, txQueue: NewCommitQueue(ctx),
txQueue: NewCommitQueue(config.Ctx),
} }
if config.CollectCommitStats { if cfg.CollectStats {
backend.commitStatsCollector = newCommitStatsColletor() backend.commitStatsCollector = newCommitStatsColletor()
} }
@ -220,10 +184,10 @@ func newEtcdBackend(config BackendConfig) (*db, error) {
// getSTMOptions creats all STM options based on the backend config. // getSTMOptions creats all STM options based on the backend config.
func (db *db) getSTMOptions() []STMOptionFunc { func (db *db) getSTMOptions() []STMOptionFunc {
opts := []STMOptionFunc{ opts := []STMOptionFunc{
WithAbortContext(db.config.Ctx), WithAbortContext(db.ctx),
} }
if db.config.CollectCommitStats { if db.cfg.CollectStats {
opts = append(opts, opts = append(opts,
WithCommitStatsCallback(db.commitStatsCollector.callback), WithCommitStatsCallback(db.commitStatsCollector.callback),
) )
@ -293,7 +257,7 @@ func (db *db) BeginReadTx() (walletdb.ReadTx, error) {
// start a read-only transaction to perform all operations. // start a read-only transaction to perform all operations.
// This function is part of the walletdb.Db interface implementation. // This function is part of the walletdb.Db interface implementation.
func (db *db) Copy(w io.Writer) error { func (db *db) Copy(w io.Writer) error {
ctx, cancel := context.WithTimeout(db.config.Ctx, etcdLongTimeout) ctx, cancel := context.WithTimeout(db.ctx, etcdLongTimeout)
defer cancel() defer cancel()
readCloser, err := db.cli.Snapshot(ctx) readCloser, err := db.cli.Snapshot(ctx)

@ -17,7 +17,7 @@ func TestCopy(t *testing.T) {
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
defer f.Cleanup() defer f.Cleanup()
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(context.TODO(), f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
err = db.Update(func(tx walletdb.ReadWriteTx) error { err = db.Update(func(tx walletdb.ReadWriteTx) error {
@ -53,10 +53,9 @@ func TestAbortContext(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
config := f.BackendConfig() config := f.BackendConfig()
config.Ctx = ctx
// Pass abort context and abort right away. // Pass abort context and abort right away.
db, err := newEtcdBackend(config) db, err := newEtcdBackend(ctx, config)
require.NoError(t, err) require.NoError(t, err)
cancel() cancel()

@ -3,6 +3,7 @@
package etcd package etcd
import ( import (
"context"
"fmt" "fmt"
"github.com/btcsuite/btcwallet/walletdb" "github.com/btcsuite/btcwallet/walletdb"
@ -13,45 +14,55 @@ const (
) )
// parseArgs parses the arguments from the walletdb Open/Create methods. // parseArgs parses the arguments from the walletdb Open/Create methods.
func parseArgs(funcName string, args ...interface{}) (*BackendConfig, error) { func parseArgs(funcName string, args ...interface{}) (context.Context,
if len(args) != 1 { *Config, error) {
return nil, fmt.Errorf("invalid number of arguments to %s.%s -- "+
"expected: etcd.BackendConfig", if len(args) != 2 {
return nil, nil, fmt.Errorf("invalid number of arguments to "+
"%s.%s -- expected: context.Context, etcd.Config",
dbType, funcName, dbType, funcName,
) )
} }
config, ok := args[0].(BackendConfig) ctx, ok := args[0].(context.Context)
if !ok { if !ok {
return nil, fmt.Errorf("argument to %s.%s is invalid -- "+ return nil, nil, fmt.Errorf("argument 0 to %s.%s is invalid "+
"expected: etcd.BackendConfig", "-- expected: context.Context",
dbType, funcName, dbType, funcName,
) )
} }
return &config, nil config, ok := args[1].(*Config)
if !ok {
return nil, nil, fmt.Errorf("argument 1 to %s.%s is invalid -- "+
"expected: etcd.Config",
dbType, funcName,
)
}
return ctx, config, nil
} }
// createDBDriver is the callback provided during driver registration that // createDBDriver is the callback provided during driver registration that
// creates, initializes, and opens a database for use. // creates, initializes, and opens a database for use.
func createDBDriver(args ...interface{}) (walletdb.DB, error) { func createDBDriver(args ...interface{}) (walletdb.DB, error) {
config, err := parseArgs("Create", args...) ctx, config, err := parseArgs("Create", args...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return newEtcdBackend(*config) return newEtcdBackend(ctx, *config)
} }
// openDBDriver is the callback provided during driver registration that opens // openDBDriver is the callback provided during driver registration that opens
// an existing database for use. // an existing database for use.
func openDBDriver(args ...interface{}) (walletdb.DB, error) { func openDBDriver(args ...interface{}) (walletdb.DB, error) {
config, err := parseArgs("Open", args...) ctx, config, err := parseArgs("Open", args...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return newEtcdBackend(*config) return newEtcdBackend(ctx, *config)
} }
func init() { func init() {

@ -3,7 +3,6 @@
package etcd package etcd
import ( import (
"context"
"fmt" "fmt"
"net" "net"
"net/url" "net/url"
@ -62,7 +61,7 @@ func getFreePort() int {
// listening on random open ports. Returns the backend config and a cleanup // listening on random open ports. Returns the backend config and a cleanup
// func that will stop the etcd instance. // func that will stop the etcd instance.
func NewEmbeddedEtcdInstance(path string, clientPort, peerPort uint16) ( func NewEmbeddedEtcdInstance(path string, clientPort, peerPort uint16) (
*BackendConfig, func(), error) { *Config, func(), error) {
cfg := embed.NewConfig() cfg := embed.NewConfig()
cfg.Dir = path cfg.Dir = path
@ -98,10 +97,7 @@ func NewEmbeddedEtcdInstance(path string, clientPort, peerPort uint16) (
fmt.Errorf("etcd failed to start after: %v", readyTimeout) fmt.Errorf("etcd failed to start after: %v", readyTimeout)
} }
ctx, cancel := context.WithCancel(context.Background()) connConfig := &Config{
connConfig := &BackendConfig{
Ctx: ctx,
Host: "http://" + peerURL, Host: "http://" + peerURL,
User: "user", User: "user",
Pass: "pass", Pass: "pass",
@ -110,7 +106,6 @@ func NewEmbeddedEtcdInstance(path string, clientPort, peerPort uint16) (
} }
return connConfig, func() { return connConfig, func() {
cancel()
etcd.Close() etcd.Close()
}, nil }, nil
} }

@ -22,14 +22,14 @@ const (
type EtcdTestFixture struct { type EtcdTestFixture struct {
t *testing.T t *testing.T
cli *clientv3.Client cli *clientv3.Client
config *BackendConfig config *Config
cleanup func() cleanup func()
} }
// NewTestEtcdInstance creates an embedded etcd instance for testing, listening // NewTestEtcdInstance creates an embedded etcd instance for testing, listening
// on random open ports. Returns the connection config and a cleanup func that // on random open ports. Returns the connection config and a cleanup func that
// will stop the etcd instance. // will stop the etcd instance.
func NewTestEtcdInstance(t *testing.T, path string) (*BackendConfig, func()) { func NewTestEtcdInstance(t *testing.T, path string) (*Config, func()) {
t.Helper() t.Helper()
config, cleanup, err := NewEmbeddedEtcdInstance(path, 0, 0) config, cleanup, err := NewEmbeddedEtcdInstance(path, 0, 0)
@ -124,7 +124,7 @@ func (f *EtcdTestFixture) Dump() map[string]string {
// BackendConfig returns the backend config for connecting to theembedded // BackendConfig returns the backend config for connecting to theembedded
// etcd instance. // etcd instance.
func (f *EtcdTestFixture) BackendConfig() BackendConfig { func (f *EtcdTestFixture) BackendConfig() Config {
return *f.config return *f.config
} }

@ -3,6 +3,7 @@
package etcd package etcd
import ( import (
"context"
"fmt" "fmt"
"math" "math"
"testing" "testing"
@ -17,7 +18,7 @@ func TestBucketCreation(t *testing.T) {
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
defer f.Cleanup() defer f.Cleanup()
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(context.TODO(), f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
err = db.Update(func(tx walletdb.ReadWriteTx) error { err = db.Update(func(tx walletdb.ReadWriteTx) error {
@ -98,7 +99,7 @@ func TestBucketDeletion(t *testing.T) {
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
defer f.Cleanup() defer f.Cleanup()
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(context.TODO(), f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
err = db.Update(func(tx walletdb.ReadWriteTx) error { err = db.Update(func(tx walletdb.ReadWriteTx) error {
@ -208,7 +209,7 @@ func TestBucketForEach(t *testing.T) {
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
defer f.Cleanup() defer f.Cleanup()
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(context.TODO(), f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
err = db.Update(func(tx walletdb.ReadWriteTx) error { err = db.Update(func(tx walletdb.ReadWriteTx) error {
@ -284,7 +285,7 @@ func TestBucketForEachWithError(t *testing.T) {
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
defer f.Cleanup() defer f.Cleanup()
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(context.TODO(), f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
err = db.Update(func(tx walletdb.ReadWriteTx) error { err = db.Update(func(tx walletdb.ReadWriteTx) error {
@ -374,7 +375,7 @@ func TestBucketSequence(t *testing.T) {
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
defer f.Cleanup() defer f.Cleanup()
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(context.TODO(), f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
err = db.Update(func(tx walletdb.ReadWriteTx) error { err = db.Update(func(tx walletdb.ReadWriteTx) error {
@ -413,7 +414,7 @@ func TestKeyClash(t *testing.T) {
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
defer f.Cleanup() defer f.Cleanup()
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(context.TODO(), f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
// First: // First:
@ -481,7 +482,7 @@ func TestBucketCreateDelete(t *testing.T) {
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
defer f.Cleanup() defer f.Cleanup()
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(context.TODO(), f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
err = db.Update(func(tx walletdb.ReadWriteTx) error { err = db.Update(func(tx walletdb.ReadWriteTx) error {

@ -3,6 +3,7 @@
package etcd package etcd
import ( import (
"context"
"testing" "testing"
"github.com/btcsuite/btcwallet/walletdb" "github.com/btcsuite/btcwallet/walletdb"
@ -15,7 +16,7 @@ func TestReadCursorEmptyInterval(t *testing.T) {
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
defer f.Cleanup() defer f.Cleanup()
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(context.TODO(), f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
err = db.Update(func(tx walletdb.ReadWriteTx) error { err = db.Update(func(tx walletdb.ReadWriteTx) error {
@ -59,7 +60,7 @@ func TestReadCursorNonEmptyInterval(t *testing.T) {
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
defer f.Cleanup() defer f.Cleanup()
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(context.TODO(), f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
testKeyValues := []KV{ testKeyValues := []KV{
@ -136,7 +137,7 @@ func TestReadWriteCursor(t *testing.T) {
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
defer f.Cleanup() defer f.Cleanup()
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(context.TODO(), f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
testKeyValues := []KV{ testKeyValues := []KV{
@ -300,7 +301,7 @@ func TestReadWriteCursorWithBucketAndValue(t *testing.T) {
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
defer f.Cleanup() defer f.Cleanup()
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(context.TODO(), f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
// Pre-store the first half of the interval. // Pre-store the first half of the interval.

@ -3,6 +3,7 @@
package etcd package etcd
import ( import (
"context"
"testing" "testing"
"github.com/btcsuite/btcwallet/walletdb" "github.com/btcsuite/btcwallet/walletdb"
@ -15,7 +16,7 @@ func TestTxManualCommit(t *testing.T) {
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
defer f.Cleanup() defer f.Cleanup()
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(context.TODO(), f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
tx, err := db.BeginReadWriteTx() tx, err := db.BeginReadWriteTx()
@ -55,7 +56,7 @@ func TestTxRollback(t *testing.T) {
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
defer f.Cleanup() defer f.Cleanup()
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(context.TODO(), f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
tx, err := db.BeginReadWriteTx() tx, err := db.BeginReadWriteTx()
@ -79,7 +80,7 @@ func TestChangeDuringManualTx(t *testing.T) {
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
defer f.Cleanup() defer f.Cleanup()
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(context.TODO(), f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
tx, err := db.BeginReadWriteTx() tx, err := db.BeginReadWriteTx()
@ -108,7 +109,7 @@ func TestChangeDuringUpdate(t *testing.T) {
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
defer f.Cleanup() defer f.Cleanup()
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(context.TODO(), f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
count := 0 count := 0

@ -3,6 +3,7 @@
package etcd package etcd
import ( import (
"context"
"errors" "errors"
"testing" "testing"
@ -21,13 +22,16 @@ func TestPutToEmpty(t *testing.T) {
t.Parallel() t.Parallel()
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
txQueue := NewCommitQueue(f.config.Ctx) ctx, cancel := context.WithCancel(context.Background())
txQueue := NewCommitQueue(ctx)
defer func() { defer func() {
cancel()
f.Cleanup() f.Cleanup()
txQueue.Wait() txQueue.Wait()
}() }()
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(ctx, f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
apply := func(stm STM) error { apply := func(stm STM) error {
@ -45,8 +49,11 @@ func TestGetPutDel(t *testing.T) {
t.Parallel() t.Parallel()
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
txQueue := NewCommitQueue(f.config.Ctx) ctx, cancel := context.WithCancel(context.Background())
txQueue := NewCommitQueue(ctx)
defer func() { defer func() {
cancel()
f.Cleanup() f.Cleanup()
txQueue.Wait() txQueue.Wait()
}() }()
@ -63,7 +70,7 @@ func TestGetPutDel(t *testing.T) {
f.Put(kv.key, kv.val) f.Put(kv.key, kv.val)
} }
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(ctx, f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
apply := func(stm STM) error { apply := func(stm STM) error {
@ -128,8 +135,11 @@ func TestFirstLastNextPrev(t *testing.T) {
t.Parallel() t.Parallel()
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
txQueue := NewCommitQueue(f.config.Ctx) ctx, cancel := context.WithCancel(context.Background())
txQueue := NewCommitQueue(ctx)
defer func() { defer func() {
cancel()
f.Cleanup() f.Cleanup()
txQueue.Wait() txQueue.Wait()
}() }()
@ -145,7 +155,7 @@ func TestFirstLastNextPrev(t *testing.T) {
f.Put(kv.key, kv.val) f.Put(kv.key, kv.val)
} }
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(ctx, f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
apply := func(stm STM) error { apply := func(stm STM) error {
@ -283,13 +293,16 @@ func TestCommitError(t *testing.T) {
t.Parallel() t.Parallel()
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
txQueue := NewCommitQueue(f.config.Ctx) ctx, cancel := context.WithCancel(context.Background())
txQueue := NewCommitQueue(ctx)
defer func() { defer func() {
cancel()
f.Cleanup() f.Cleanup()
txQueue.Wait() txQueue.Wait()
}() }()
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(ctx, f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
// Preset DB state. // Preset DB state.
@ -328,13 +341,16 @@ func TestManualTxError(t *testing.T) {
t.Parallel() t.Parallel()
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
txQueue := NewCommitQueue(f.config.Ctx) ctx, cancel := context.WithCancel(context.Background())
txQueue := NewCommitQueue(ctx)
defer func() { defer func() {
cancel()
f.Cleanup() f.Cleanup()
txQueue.Wait() txQueue.Wait()
}() }()
db, err := newEtcdBackend(f.BackendConfig()) db, err := newEtcdBackend(ctx, f.BackendConfig())
require.NoError(t, err) require.NoError(t, err)
// Preset DB state. // Preset DB state.

@ -3,6 +3,7 @@
package etcd package etcd
import ( import (
"context"
"testing" "testing"
"github.com/btcsuite/btcwallet/walletdb/walletdbtest" "github.com/btcsuite/btcwallet/walletdb/walletdbtest"
@ -13,5 +14,6 @@ import (
func TestWalletDBInterface(t *testing.T) { func TestWalletDBInterface(t *testing.T) {
f := NewEtcdTestFixture(t) f := NewEtcdTestFixture(t)
defer f.Cleanup() defer f.Cleanup()
walletdbtest.TestInterface(t, dbType, f.BackendConfig()) cfg := f.BackendConfig()
walletdbtest.TestInterface(t, dbType, context.TODO(), &cfg)
} }

@ -14,25 +14,10 @@ const TestBackend = EtcdBackendName
// GetEtcdBackend returns an etcd backend configured according to the // GetEtcdBackend returns an etcd backend configured according to the
// passed etcdConfig. // passed etcdConfig.
func GetEtcdBackend(ctx context.Context, etcdConfig *EtcdConfig) ( func GetEtcdBackend(ctx context.Context, etcdConfig *etcd.Config) (
Backend, error) { Backend, error) {
// Config translation is needed here in order to keep the return Open(EtcdBackendName, etcdConfig)
// etcd package fully independent from the rest of the source tree.
backendConfig := etcd.BackendConfig{
Ctx: ctx,
Host: etcdConfig.Host,
User: etcdConfig.User,
Pass: etcdConfig.Pass,
DisableTLS: etcdConfig.DisableTLS,
CertFile: etcdConfig.CertFile,
KeyFile: etcdConfig.KeyFile,
InsecureSkipVerify: etcdConfig.InsecureSkipVerify,
Namespace: etcdConfig.Namespace,
CollectCommitStats: etcdConfig.CollectStats,
}
return Open(EtcdBackendName, backendConfig)
} }
// GetEtcdTestBackend creates an embedded etcd backend for testing // GetEtcdTestBackend creates an embedded etcd backend for testing
@ -49,7 +34,7 @@ func GetEtcdTestBackend(path string, clientPort, peerPort uint16) (
return nil, empty, err return nil, empty, err
} }
backend, err := Open(EtcdBackendName, *config) backend, err := Open(EtcdBackendName, context.Background(), config)
if err != nil { if err != nil {
cleanup() cleanup()
return nil, empty, err return nil, empty, err

@ -5,6 +5,8 @@ package kvdb
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/lightningnetwork/lnd/channeldb/kvdb/etcd"
) )
// TestBackend is conditionally set to bdb when the kvdb_etcd build tag is // TestBackend is conditionally set to bdb when the kvdb_etcd build tag is
@ -14,7 +16,7 @@ const TestBackend = BoltBackendName
var errEtcdNotAvailable = fmt.Errorf("etcd backend not available") var errEtcdNotAvailable = fmt.Errorf("etcd backend not available")
// GetEtcdBackend is a stub returning nil and errEtcdNotAvailable error. // GetEtcdBackend is a stub returning nil and errEtcdNotAvailable error.
func GetEtcdBackend(ctx context.Context, etcdConfig *EtcdConfig) ( func GetEtcdBackend(ctx context.Context, etcdConfig *etcd.Config) (
Backend, error) { Backend, error) {
return nil, errEtcdNotAvailable return nil, errEtcdNotAvailable

@ -6,6 +6,7 @@ import (
"time" "time"
"github.com/lightningnetwork/lnd/channeldb/kvdb" "github.com/lightningnetwork/lnd/channeldb/kvdb"
"github.com/lightningnetwork/lnd/channeldb/kvdb/etcd"
) )
const ( const (
@ -21,7 +22,7 @@ type DB struct {
BatchCommitInterval time.Duration `long:"batch-commit-interval" description:"The maximum duration the channel graph batch schedulers will wait before attempting to commit a batch of pending updates. This can be tradeoff database contenion for commit latency."` BatchCommitInterval time.Duration `long:"batch-commit-interval" description:"The maximum duration the channel graph batch schedulers will wait before attempting to commit a batch of pending updates. This can be tradeoff database contenion for commit latency."`
Etcd *kvdb.EtcdConfig `group:"etcd" namespace:"etcd" description:"Etcd settings."` Etcd *etcd.Config `group:"etcd" namespace:"etcd" description:"Etcd settings."`
Bolt *kvdb.BoltConfig `group:"bolt" namespace:"bolt" description:"Bolt settings."` Bolt *kvdb.BoltConfig `group:"bolt" namespace:"bolt" description:"Bolt settings."`
} }