Skip to content

Commit 42d7b58

Browse files
author
Kent Rancourt
committed
chore(deisctl): refactor config/etcd code
In order to reuse the code for accessing a back-end config store (e.g. etcd) in the new upgrade feature, and in order to test that same code, the previous commit made some compromises that might have affected the long-term maintainability of deisctl. This is a follow-up commit to refactor some of that. It establishes cleaner boundaries between config back-end model, interface, and that interface's two implementations-- the existing one based on etcd and a new, in-memory "mock" used for testing.
1 parent bc4dd8e commit 42d7b58

13 files changed

Lines changed: 208 additions & 181 deletions

File tree

deisctl/client/client.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"github.com/deis/deis/deisctl/backend"
1010
"github.com/deis/deis/deisctl/backend/fleet"
1111
"github.com/deis/deis/deisctl/cmd"
12+
"github.com/deis/deis/deisctl/config"
13+
"github.com/deis/deis/deisctl/config/etcd"
1214
"github.com/deis/deis/deisctl/units"
1315

1416
docopt "github.com/docopt/docopt-go"
@@ -35,7 +37,8 @@ type DeisCtlClient interface {
3537

3638
// Client uses a backend to implement the DeisCtlClient interface.
3739
type Client struct {
38-
Backend backend.Backend
40+
Backend backend.Backend
41+
configBackend config.Backend
3942
}
4043

4144
// NewClient returns a Client using the requested backend.
@@ -57,7 +60,13 @@ func NewClient(requestedBackend string) (*Client, error) {
5760
default:
5861
return nil, errors.New("invalid backend")
5962
}
60-
return &Client{Backend: backend}, nil
63+
64+
cb, err := etcd.NewConfigBackend()
65+
if err != nil {
66+
return nil, err
67+
}
68+
69+
return &Client{Backend: backend, configBackend: cb}, nil
6170
}
6271

6372
// UpgradePrep prepares a running cluster to be upgraded
@@ -85,7 +94,7 @@ Usage:
8594
return err
8695
}
8796

88-
return cmd.UpgradeTakeover(c.Backend)
97+
return cmd.UpgradeTakeover(c.Backend, c.configBackend)
8998
}
9099

91100
// RollingRestart attempts a rolling restart of an instance unit
@@ -151,7 +160,7 @@ Examples:
151160
key = args["<key>"].([]string)
152161
}
153162

154-
return cmd.Config(args["<target>"].(string), action, key)
163+
return cmd.Config(args["<target>"].(string), action, key, c.configBackend)
155164
}
156165

157166
// Install loads the definitions of components from local unit files.
@@ -186,7 +195,7 @@ Options:
186195
}
187196
cmd.RouterMeshSize = uint8(parsedValue)
188197

189-
return cmd.Install(args["<target>"].([]string), c.Backend, cmd.CheckRequiredKeys)
198+
return cmd.Install(args["<target>"].([]string), c.Backend, c.configBackend, cmd.CheckRequiredKeys)
190199
}
191200

192201
// Journal prints log output for the specified components.

deisctl/cmd/cmd.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,14 @@ func RollingRestart(target string, b backend.Backend) error {
107107
return nil
108108
}
109109

110-
// CheckRequiredKeys exist in etcd
111-
func CheckRequiredKeys() error {
112-
if err := config.CheckConfig("/deis/platform/", "domain"); err != nil {
110+
// CheckRequiredKeys exist in config backend
111+
func CheckRequiredKeys(cb config.Backend) error {
112+
if err := config.CheckConfig("/deis/platform/", "domain", cb); err != nil {
113113
return fmt.Errorf(`Missing platform domain, use:
114114
deisctl config platform set domain=<your-domain>`)
115115
}
116116

117-
if err := config.CheckConfig("/deis/platform/", "sshPrivateKey"); err != nil {
117+
if err := config.CheckConfig("/deis/platform/", "sshPrivateKey", cb); err != nil {
118118
fmt.Printf(`Warning: Missing sshPrivateKey, "deis run" will be unavailable. Use:
119119
deisctl config platform set sshPrivateKey=<path-to-key>
120120
`)
@@ -286,15 +286,15 @@ func Journal(targets []string, b backend.Backend) error {
286286

287287
// Install loads the definitions of components from local unit files.
288288
// After Install, the components will be available to Start.
289-
func Install(targets []string, b backend.Backend, checkKeys func() error) error {
289+
func Install(targets []string, b backend.Backend, cb config.Backend, checkKeys func(config.Backend) error) error {
290290

291291
// if target is platform, install all services
292292
if len(targets) == 1 {
293293
switch targets[0] {
294294
case PlatformCommand:
295-
return InstallPlatform(b, checkKeys, false)
295+
return InstallPlatform(b, cb, checkKeys, false)
296296
case StatelessPlatformCommand:
297-
return InstallPlatform(b, checkKeys, true)
297+
return InstallPlatform(b, cb, checkKeys, true)
298298
case mesos:
299299
return InstallMesos(b)
300300
case swarm:
@@ -439,11 +439,11 @@ func splitScaleTarget(target string) (c string, num int, err error) {
439439

440440
// Config gets or sets a configuration value from the cluster.
441441
//
442-
// A configuration value is stored and retrieved from a key/value store (in this case, etcd)
442+
// A configuration value is stored and retrieved from a key/value store
443443
// at /deis/<component>/<config>. Configuration values are typically used for component-level
444444
// configuration, such as enabling TLS for the routers.
445-
func Config(target string, action string, key []string) error {
446-
if err := config.Config(target, action, key); err != nil {
445+
func Config(target string, action string, key []string, cb config.Backend) error {
446+
if err := config.Config(target, action, key, cb); err != nil {
447447
return err
448448
}
449449
return nil

deisctl/cmd/cmd_test.go

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import (
1313
"testing"
1414

1515
"github.com/deis/deis/deisctl/backend"
16-
"github.com/deis/deis/deisctl/etcdclient"
16+
"github.com/deis/deis/deisctl/config"
17+
"github.com/deis/deis/deisctl/config/model"
1718
"github.com/deis/deis/deisctl/test/mock"
1819
"github.com/deis/deis/deisctl/units"
1920
)
@@ -86,7 +87,7 @@ func (backend *backendStub) SSHExec(target, command string) error {
8687

8788
var _ backend.Backend = &backendStub{}
8889

89-
func fakeCheckKeys() error {
90+
func fakeCheckKeys(cb config.Backend) error {
9091
return nil
9192
}
9293

@@ -306,7 +307,7 @@ func TestUpgradePrep(t *testing.T) {
306307

307308
func TestUpgradeTakeover(t *testing.T) {
308309
t.Parallel()
309-
testMock := mock.Client{Expected: []*etcdclient.ServiceKey{{Key: "/deis/services/app1", Value: "foo", TTL: 10},
310+
testMock := mock.ConfigBackend{Expected: []*model.ConfigNode{{Key: "/deis/services/app1", Value: "foo", TTL: 10},
310311
{Key: "/deis/services/app2", Value: "8000", TTL: 10}}}
311312

312313
b := backendStub{}
@@ -477,9 +478,11 @@ func TestInstall(t *testing.T) {
477478
t.Parallel()
478479

479480
b := backendStub{}
481+
cb := mock.ConfigBackend{}
482+
480483
expected := []string{"router@1", "router@2"}
481484

482-
Install(expected, &b, fakeCheckKeys)
485+
Install(expected, &b, &cb, fakeCheckKeys)
483486

484487
if !reflect.DeepEqual(b.installedUnits, expected) {
485488
t.Error(fmt.Errorf("Expected %v, Got %v", expected, b.installedUnits))
@@ -490,11 +493,13 @@ func TestInstallPlatform(t *testing.T) {
490493
t.Parallel()
491494

492495
b := backendStub{}
496+
cb := mock.ConfigBackend{}
497+
493498
expected := []string{"store-daemon", "store-monitor", "store-metadata", "store-volume",
494499
"store-gateway@1", "logger", "logspout", "database", "registry@1",
495500
"controller", "builder", "publisher", "router@1", "router@2", "router@3"}
496501

497-
Install([]string{"platform"}, &b, fakeCheckKeys)
502+
Install([]string{"platform"}, &b, &cb, fakeCheckKeys)
498503

499504
if !reflect.DeepEqual(b.installedUnits, expected) {
500505
t.Error(fmt.Errorf("Expected %v, Got %v", expected, b.installedUnits))
@@ -505,12 +510,14 @@ func TestInstallPlatformWithCustomRouterMeshSize(t *testing.T) {
505510
t.Parallel()
506511

507512
b := backendStub{}
513+
cb := mock.ConfigBackend{}
514+
508515
expected := []string{"store-daemon", "store-monitor", "store-metadata", "store-volume",
509516
"store-gateway@1", "logger", "logspout", "database", "registry@1",
510517
"controller", "builder", "publisher", "router@1", "router@2", "router@3", "router@4", "router@5"}
511518
RouterMeshSize = 5
512519

513-
Install([]string{"platform"}, &b, fakeCheckKeys)
520+
Install([]string{"platform"}, &b, &cb, fakeCheckKeys)
514521
RouterMeshSize = DefaultRouterMeshSize
515522

516523
if !reflect.DeepEqual(b.installedUnits, expected) {
@@ -522,10 +529,12 @@ func TestInstallStatelessPlatform(t *testing.T) {
522529
t.Parallel()
523530

524531
b := backendStub{}
532+
cb := mock.ConfigBackend{}
533+
525534
expected := []string{"logspout", "registry@1",
526535
"controller", "builder", "publisher", "router@1", "router@2", "router@3"}
527536

528-
Install([]string{"stateless-platform"}, &b, fakeCheckKeys)
537+
Install([]string{"stateless-platform"}, &b, &cb, fakeCheckKeys)
529538

530539
if !reflect.DeepEqual(b.installedUnits, expected) {
531540
t.Error(fmt.Errorf("Expected %v, Got %v", expected, b.installedUnits))
@@ -536,9 +545,11 @@ func TestInstallSwarm(t *testing.T) {
536545
t.Parallel()
537546

538547
b := backendStub{}
548+
cb := mock.ConfigBackend{}
549+
539550
expected := []string{"swarm-node", "swarm-manager"}
540551

541-
Install([]string{"swarm"}, &b, fakeCheckKeys)
552+
Install([]string{"swarm"}, &b, &cb, fakeCheckKeys)
542553

543554
if !reflect.DeepEqual(b.installedUnits, expected) {
544555
t.Error(fmt.Errorf("Expected %v, Got %v", expected, b.installedUnits))

deisctl/cmd/platform.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ import (
66
"sync"
77

88
"github.com/deis/deis/deisctl/backend"
9+
"github.com/deis/deis/deisctl/config"
910
"github.com/deis/deis/pkg/prettyprint"
1011
)
1112

1213
// InstallPlatform loads all components' definitions from local unit files.
1314
// After InstallPlatform, all components will be available for StartPlatform.
14-
func InstallPlatform(b backend.Backend, checkKeys func() error, stateless bool) error {
15+
func InstallPlatform(b backend.Backend, cb config.Backend, checkKeys func(config.Backend) error, stateless bool) error {
1516

16-
if err := checkKeys(); err != nil {
17+
if err := checkKeys(cb); err != nil {
1718
return err
1819
}
1920

deisctl/cmd/upgrade.go

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import (
55
"sync"
66

77
"github.com/deis/deis/deisctl/backend"
8-
"github.com/deis/deis/deisctl/etcdclient"
8+
"github.com/deis/deis/deisctl/config"
9+
"github.com/deis/deis/deisctl/config/model"
910
)
1011

1112
// UpgradePrep stops and uninstalls all components except router and publisher
@@ -43,18 +44,18 @@ func UpgradePrep(b backend.Backend) error {
4344
return nil
4445
}
4546

46-
func listPublishedServices(etcdClient etcdclient.Client) ([]*etcdclient.ServiceKey, error) {
47-
nodes, err := etcdClient.GetRecursive("deis/services")
47+
func listPublishedServices(cb config.Backend) ([]*model.ConfigNode, error) {
48+
nodes, err := cb.GetRecursive("deis/services")
4849
if err != nil {
4950
return nil, err
5051
}
5152

5253
return nodes, nil
5354
}
5455

55-
func republishServices(ttl uint64, nodes []*etcdclient.ServiceKey, etcdClient etcdclient.Client) error {
56+
func republishServices(ttl uint64, nodes []*model.ConfigNode, cb config.Backend) error {
5657
for _, node := range nodes {
57-
_, err := etcdClient.Update(node.Key, node.Value, ttl)
58+
_, err := cb.SetWithTTL(node.Key, node.Value, ttl)
5859
if err != nil {
5960
return err
6061
}
@@ -64,23 +65,19 @@ func republishServices(ttl uint64, nodes []*etcdclient.ServiceKey, etcdClient et
6465
}
6566

6667
// UpgradeTakeover gracefully starts a platform stopped with UpgradePrep
67-
func UpgradeTakeover(b backend.Backend) error {
68-
etcdClient, err := etcdclient.GetEtcdClient()
69-
if err != nil {
70-
return err
71-
}
68+
func UpgradeTakeover(b backend.Backend, cb config.Backend) error {
7269

73-
if err := doUpgradeTakeOver(b, etcdClient); err != nil {
70+
if err := doUpgradeTakeOver(b, cb); err != nil {
7471
return err
7572
}
7673

7774
return nil
7875
}
7976

80-
func doUpgradeTakeOver(b backend.Backend, etcdClient etcdclient.Client) error {
77+
func doUpgradeTakeOver(b backend.Backend, cb config.Backend) error {
8178
var wg sync.WaitGroup
8279

83-
nodes, err := listPublishedServices(etcdClient)
80+
nodes, err := listPublishedServices(cb)
8481
if err != nil {
8582
return err
8683
}
@@ -90,7 +87,7 @@ func doUpgradeTakeOver(b backend.Backend, etcdClient etcdclient.Client) error {
9087
b.Destroy([]string{"publisher"}, &wg, Stdout, Stderr)
9188
wg.Wait()
9289

93-
if err := republishServices(1800, nodes, etcdClient); err != nil {
90+
if err := republishServices(1800, nodes, cb); err != nil {
9491
return err
9592
}
9693

deisctl/config/backend.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package config
2+
3+
import "github.com/deis/deis/deisctl/config/model"
4+
5+
// Backend is an interface for any sort of underlying key/value config store
6+
type Backend interface {
7+
Get(string) (string, error)
8+
Set(string, string) (string, error)
9+
SetWithTTL(string, string, uint64) (string, error)
10+
Delete(string) error
11+
GetRecursive(string) ([]*model.ConfigNode, error)
12+
}

0 commit comments

Comments
 (0)