Skip to content

Commit

Permalink
refactor: rename package remote to package etcd (#175)
Browse files Browse the repository at this point in the history
* refactor: etcd != remote.

* test: fix unbounded context

* feat: add WithKey helper

* fix: eliminate pointers

BREAKING CHANGE: package remote no longer exists.
  • Loading branch information
Reasno authored Aug 6, 2021
1 parent 7d7f997 commit 2a18092
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 47 deletions.
9 changes: 0 additions & 9 deletions c.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (

"github.com/DoNewsCode/core/codec/yaml"
"github.com/DoNewsCode/core/config"
"github.com/DoNewsCode/core/config/remote"
"github.com/DoNewsCode/core/config/watcher"
"github.com/DoNewsCode/core/container"
"github.com/DoNewsCode/core/contract"
Expand All @@ -24,7 +23,6 @@ import (
"github.com/go-kit/kit/log"
"github.com/knadh/koanf/providers/confmap"
"github.com/knadh/koanf/providers/file"
clientv3 "go.etcd.io/etcd/client/v3"
)

// C stands for the core of the application. It contains service definitions and
Expand Down Expand Up @@ -93,13 +91,6 @@ func WithYamlFile(path string) (CoreOption, CoreOption) {
WithConfigWatcher(watcher.File{Path: path})
}

// WithRemoteYamlFile is a two-in-one coreOption. It uses the remote key on etcd as the
// source of configuration, and watches the change of that key for hot reloading.
func WithRemoteYamlFile(key string, cfg clientv3.Config) (CoreOption, CoreOption) {
r := remote.Provider(key, &cfg)
return WithConfigStack(r, config.CodecParser{Codec: yaml.Codec{}}), WithConfigWatcher(r)
}

// WithInline is a CoreOption that creates a inline config in the configuration stack.
func WithInline(key string, entry interface{}) CoreOption {
return WithConfigStack(confmap.Provider(map[string]interface{}{
Expand Down
41 changes: 25 additions & 16 deletions config/remote/remote.go → config/remote/etcd/etcd.go
Original file line number Diff line number Diff line change
@@ -1,31 +1,41 @@
package remote
// Package etcd allows the core package to bootstrap its configuration from an etcd server.
package etcd

import (
"context"
"errors"
"fmt"

"github.com/DoNewsCode/core"
"github.com/DoNewsCode/core/config"
"github.com/DoNewsCode/core/contract"
"go.etcd.io/etcd/client/v3"
)

// Remote is a core.ConfProvider and contract.ConfigWatcher implementation to read and watch remote config key.
// ETCD is a core.ConfProvider and contract.ConfigWatcher implementation to read and watch remote config key.
// The remote client uses etcd.
type Remote struct {
key string
clientConfig *clientv3.Config
type ETCD struct {
key string
clientConfig clientv3.Config
}

// Provider create a *Remote
func Provider(key string, clientConfig *clientv3.Config) *Remote {
return &Remote{
key: key,
// Provider create a *ETCD
func Provider(clientConfig clientv3.Config, key string) *ETCD {
return &ETCD{
key: key,
clientConfig: clientConfig,
}
}

// WithKey is a two-in-one coreOption. It uses the remote key on etcd as the
// source of configuration, and watches the change of that key for hot reloading.
func WithKey(cfg clientv3.Config, key string, codec contract.Codec) (core.CoreOption, core.CoreOption) {
r := Provider(cfg, key)
return core.WithConfigStack(r, config.CodecParser{Codec: codec}), core.WithConfigWatcher(r)
}

// ReadBytes reads the contents of a key from etcd and returns the bytes.
func (r *Remote) ReadBytes() ([]byte, error) {
client, err := clientv3.New(*r.clientConfig)
func (r *ETCD) ReadBytes() ([]byte, error) {
client, err := clientv3.New(r.clientConfig)
if err != nil {
return nil, err
}
Expand All @@ -43,16 +53,16 @@ func (r *Remote) ReadBytes() ([]byte, error) {
}

// Read is not supported by the remote provider.
func (r *Remote) Read() (map[string]interface{}, error) {
func (r *ETCD) Read() (map[string]interface{}, error) {
return nil, errors.New("remote provider does not support this method")
}

// Watch watches the change to the remote key from etcd. If the key is edited or created, the reload function
// will be called. note the reload function should not just load the changes made within this key, but rather
// it should reload the whole config stack. For example, if the flag or env takes precedence over the config
// key, they should remain to be so after the key changes.
func (r *Remote) Watch(ctx context.Context, reload func() error) error {
client, err := clientv3.New(*r.clientConfig)
func (r *ETCD) Watch(ctx context.Context, reload func() error) error {
client, err := clientv3.New(r.clientConfig)
if err != nil {
return err
}
Expand All @@ -74,4 +84,3 @@ func (r *Remote) Watch(ctx context.Context, reload func() error) error {
}
}
}

27 changes: 15 additions & 12 deletions config/remote/remote_test.go → config/remote/etcd/etcd_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package remote
package etcd

import (
"context"
Expand All @@ -19,12 +19,12 @@ func TestRemote(t *testing.T) {
return
}
addrs := strings.Split(os.Getenv("ETCD_ADDR"), ",")
cfg := &clientv3.Config{
cfg := clientv3.Config{
Endpoints: addrs,
DialTimeout: 2 * time.Second,
}

r := Provider("config.yaml", cfg)
r := Provider(cfg, "config.yaml")

var testVal = "name: app"
// PREPARE TEST DATA
Expand Down Expand Up @@ -67,16 +67,16 @@ func TestError(t *testing.T) {
}
addrs := strings.Split(os.Getenv("ETCD_ADDR"), ",")
var (
r *Remote
r *ETCD
err error
)

cfg := &clientv3.Config{
cfg := clientv3.Config{
Endpoints: []string{},
DialTimeout: 2 * time.Second,
}

r = Provider("config.yaml", cfg)
r = Provider(cfg, "config.yaml")
err = put(r, "test")
assert.Error(t, err)

Expand All @@ -88,15 +88,15 @@ func TestError(t *testing.T) {
})
assert.Error(t, err)

cfg = &clientv3.Config{
cfg = clientv3.Config{
Endpoints: addrs,
DialTimeout: 2 * time.Second,
}
r = Provider("config-test1", cfg)
r = Provider(cfg, "config-test1")
_, err = r.ReadBytes()
assert.Error(t, err)

r = Provider("config-test2", cfg)
r = Provider(cfg, "config-test2")

// Confirm that the two coroutines are finished
g := sync.WaitGroup{}
Expand Down Expand Up @@ -126,14 +126,17 @@ func TestError(t *testing.T) {
g.Wait()
}

func put(r *Remote, val string) error {
client, err := clientv3.New(*r.clientConfig)
func put(r *ETCD, val string) error {
client, err := clientv3.New(r.clientConfig)
if err != nil {
return err
}
defer client.Close()

_, err = client.Put(context.Background(), r.key, val)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()

_, err = client.Put(ctx, r.key, val)
if err != nil {
return err
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
package remote_test
package etcd_test

import (
"context"
"fmt"
"github.com/DoNewsCode/core"
"github.com/stretchr/testify/assert"
"github.com/DoNewsCode/core/codec/yaml"
"github.com/DoNewsCode/core/config/remote/etcd"
clientv3 "go.etcd.io/etcd/client/v3"
"os"
"strings"
"testing"
"time"
)

func Test_integration(t *testing.T) {
func Example() {
addr := os.Getenv("ETCD_ADDR")
if addr == "" {
t.Skip("set ETCD_ADDR for run remote test")
fmt.Println("set ETCD_ADDR for run example")
return
}
key := "core.yaml"
Expand All @@ -23,13 +24,14 @@ func Test_integration(t *testing.T) {
Endpoints: envEtcdAddrs,
DialTimeout: time.Second,
}
if err := put(cfg, key, "name: remote"); err != nil {
t.Fatal(err)
}
_ = put(cfg, key, "name: etcd")

c := core.New(core.WithRemoteYamlFile(key, cfg))
c := core.New(etcd.WithKey(cfg, key, yaml.Codec{}))
c.ProvideEssentials()
assert.Equal(t, "remote", c.String("name"))
fmt.Println(c.String("name"))

// Output:
// etcd
}

func put(cfg clientv3.Config, key, val string) error {
Expand Down

0 comments on commit 2a18092

Please sign in to comment.