This leverages recent additions to libkv enabling client
authentication via TLS so the discovery back-end can be locked
down with mutual TLS. Example usage:
docker daemon [other args] \
--cluster-advertise 192.168.122.168:2376 \
--cluster-store etcd://192.168.122.168:2379 \
--cluster-store-opt kv.cacertfile=/path/to/ca.pem \
--cluster-store-opt kv.certfile=/path/to/cert.pem \
--cluster-store-opt kv.keyfile=/path/to/key.pem
Signed-off-by: Daniel Hiltgen <daniel.hiltgen@docker.com>
| ... | ... |
@@ -39,6 +39,10 @@ type CommonConfig struct {
|
| 39 | 39 |
// mechanism. |
| 40 | 40 |
ClusterStore string |
| 41 | 41 |
|
| 42 |
+ // ClusterOpts is used to pass options to the discovery package for tuning libkv settings, such |
|
| 43 |
+ // as TLS configuration settings. |
|
| 44 |
+ ClusterOpts map[string]string |
|
| 45 |
+ |
|
| 42 | 46 |
// ClusterAdvertise is the network endpoint that the Engine advertises for the purpose of node |
| 43 | 47 |
// discovery. This should be a 'host:port' combination on which that daemon instance is |
| 44 | 48 |
// reachable by other hosts. |
| ... | ... |
@@ -68,4 +72,5 @@ func (config *Config) InstallCommonFlags(cmd *flag.FlagSet, usageFn func(string) |
| 68 | 68 |
cmd.Var(opts.NewMapOpts(config.LogConfig.Config, nil), []string{"-log-opt"}, usageFn("Set log driver options"))
|
| 69 | 69 |
cmd.StringVar(&config.ClusterAdvertise, []string{"-cluster-advertise"}, "", usageFn("Address of the daemon instance to advertise"))
|
| 70 | 70 |
cmd.StringVar(&config.ClusterStore, []string{"-cluster-store"}, "", usageFn("Set the cluster store"))
|
| 71 |
+ cmd.Var(opts.NewMapOpts(config.ClusterOpts, nil), []string{"-cluster-store-opt"}, usageFn("Set cluster store options"))
|
|
| 71 | 72 |
} |
| ... | ... |
@@ -756,7 +756,7 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo |
| 756 | 756 |
// DiscoveryWatcher version. |
| 757 | 757 |
if config.ClusterStore != "" && config.ClusterAdvertise != "" {
|
| 758 | 758 |
var err error |
| 759 |
- if d.discoveryWatcher, err = initDiscovery(config.ClusterStore, config.ClusterAdvertise); err != nil {
|
|
| 759 |
+ if d.discoveryWatcher, err = initDiscovery(config.ClusterStore, config.ClusterAdvertise, config.ClusterOpts); err != nil {
|
|
| 760 | 760 |
return nil, fmt.Errorf("discovery initialization failed (%v)", err)
|
| 761 | 761 |
} |
| 762 | 762 |
} |
| ... | ... |
@@ -20,12 +20,12 @@ const ( |
| 20 | 20 |
|
| 21 | 21 |
// initDiscovery initialized the nodes discovery subsystem by connecting to the specified backend |
| 22 | 22 |
// and start a registration loop to advertise the current node under the specified address. |
| 23 |
-func initDiscovery(backend, address string) (discovery.Backend, error) {
|
|
| 23 |
+func initDiscovery(backend, address string, clusterOpts map[string]string) (discovery.Backend, error) {
|
|
| 24 | 24 |
var ( |
| 25 | 25 |
discoveryBackend discovery.Backend |
| 26 | 26 |
err error |
| 27 | 27 |
) |
| 28 |
- if discoveryBackend, err = discovery.New(backend, defaultDiscoveryHeartbeat, defaultDiscoveryTTL); err != nil {
|
|
| 28 |
+ if discoveryBackend, err = discovery.New(backend, defaultDiscoveryHeartbeat, defaultDiscoveryTTL, clusterOpts); err != nil {
|
|
| 29 | 29 |
return nil, err |
| 30 | 30 |
} |
| 31 | 31 |
|
| ... | ... |
@@ -71,6 +71,7 @@ func NewDaemonCli() *DaemonCli {
|
| 71 | 71 |
// TODO(tiborvass): remove InstallFlags? |
| 72 | 72 |
daemonConfig := new(daemon.Config) |
| 73 | 73 |
daemonConfig.LogConfig.Config = make(map[string]string) |
| 74 |
+ daemonConfig.ClusterOpts = make(map[string]string) |
|
| 74 | 75 |
daemonConfig.InstallFlags(daemonFlags, presentInHelp) |
| 75 | 76 |
daemonConfig.InstallFlags(flag.CommandLine, absentFromHelp) |
| 76 | 77 |
registryOptions := new(registry.Options) |
| ... | ... |
@@ -24,6 +24,7 @@ weight=1 |
| 24 | 24 |
--default-gateway-v6="" Container default gateway IPv6 address |
| 25 | 25 |
--cluster-store="" URL of the distributed storage backend |
| 26 | 26 |
--cluster-advertise="" Address of the daemon instance to advertise |
| 27 |
+ --cluster-store-opt=map[] Set cluster options |
|
| 27 | 28 |
--dns=[] DNS server to use |
| 28 | 29 |
--dns-opt=[] DNS options to use |
| 29 | 30 |
--dns-search=[] DNS search domains to use |
| ... | ... |
@@ -537,6 +538,20 @@ please check the [run](run.md) reference. |
| 537 | 537 |
daemon instance should use when advertising itself to the cluster. The daemon |
| 538 | 538 |
should be reachable by remote hosts on this 'host:port' combination. |
| 539 | 539 |
|
| 540 |
+The daemon uses [libkv](https://github.com/docker/libkv/) to advertise |
|
| 541 |
+the node within the cluster. Some Key/Value backends support mutual |
|
| 542 |
+TLS, and the client TLS settings used by the daemon can be configured |
|
| 543 |
+using the `--cluster-store-opt` flag, specifying the paths to PEM encoded |
|
| 544 |
+files. For example: |
|
| 545 |
+ |
|
| 546 |
+```bash |
|
| 547 |
+ --cluster-advertise 192.168.1.2:2376 \ |
|
| 548 |
+ --cluster-store etcd://192.168.1.2:2379 \ |
|
| 549 |
+ --cluster-store-opt kv.cacertfile=/path/to/ca.pem \ |
|
| 550 |
+ --cluster-store-opt kv.certfile=/path/to/cert.pem \ |
|
| 551 |
+ --cluster-store-opt kv.keyfile=/path/to/key.pem |
|
| 552 |
+``` |
|
| 553 |
+ |
|
| 540 | 554 |
## Miscellaneous options |
| 541 | 555 |
|
| 542 | 556 |
IP masquerading uses address translation to allow containers without a public |
| ... | ... |
@@ -41,11 +41,11 @@ func parse(rawurl string) (string, string) {
|
| 41 | 41 |
|
| 42 | 42 |
// New returns a new Discovery given a URL, heartbeat and ttl settings. |
| 43 | 43 |
// Returns an error if the URL scheme is not supported. |
| 44 |
-func New(rawurl string, heartbeat time.Duration, ttl time.Duration) (Backend, error) {
|
|
| 44 |
+func New(rawurl string, heartbeat time.Duration, ttl time.Duration, clusterOpts map[string]string) (Backend, error) {
|
|
| 45 | 45 |
scheme, uri := parse(rawurl) |
| 46 | 46 |
if backend, exists := backends[scheme]; exists {
|
| 47 | 47 |
log.WithFields(log.Fields{"name": scheme, "uri": uri}).Debug("Initializing discovery service")
|
| 48 |
- err := backend.Initialize(uri, heartbeat, ttl) |
|
| 48 |
+ err := backend.Initialize(uri, heartbeat, ttl, clusterOpts) |
|
| 49 | 49 |
return backend, err |
| 50 | 50 |
} |
| 51 | 51 |
|
| ... | ... |
@@ -27,8 +27,8 @@ type Backend interface {
|
| 27 | 27 |
// Watcher must be provided by every backend. |
| 28 | 28 |
Watcher |
| 29 | 29 |
|
| 30 |
- // Initialize the discovery with URIs, a heartbeat and a ttl. |
|
| 31 |
- Initialize(string, time.Duration, time.Duration) error |
|
| 30 |
+ // Initialize the discovery with URIs, a heartbeat, a ttl and optional settings. |
|
| 31 |
+ Initialize(string, time.Duration, time.Duration, map[string]string) error |
|
| 32 | 32 |
|
| 33 | 33 |
// Register to the discovery. |
| 34 | 34 |
Register(string) error |
| ... | ... |
@@ -25,7 +25,7 @@ func Init() {
|
| 25 | 25 |
} |
| 26 | 26 |
|
| 27 | 27 |
// Initialize is exported |
| 28 |
-func (s *Discovery) Initialize(path string, heartbeat time.Duration, ttl time.Duration) error {
|
|
| 28 |
+func (s *Discovery) Initialize(path string, heartbeat time.Duration, ttl time.Duration, _ map[string]string) error {
|
|
| 29 | 29 |
s.path = path |
| 30 | 30 |
s.heartbeat = heartbeat |
| 31 | 31 |
return nil |
| ... | ... |
@@ -19,12 +19,12 @@ var _ = check.Suite(&DiscoverySuite{})
|
| 19 | 19 |
|
| 20 | 20 |
func (s *DiscoverySuite) TestInitialize(c *check.C) {
|
| 21 | 21 |
d := &Discovery{}
|
| 22 |
- d.Initialize("/path/to/file", 1000, 0)
|
|
| 22 |
+ d.Initialize("/path/to/file", 1000, 0, nil)
|
|
| 23 | 23 |
c.Assert(d.path, check.Equals, "/path/to/file") |
| 24 | 24 |
} |
| 25 | 25 |
|
| 26 | 26 |
func (s *DiscoverySuite) TestNew(c *check.C) {
|
| 27 |
- d, err := discovery.New("file:///path/to/file", 0, 0)
|
|
| 27 |
+ d, err := discovery.New("file:///path/to/file", 0, 0, nil)
|
|
| 28 | 28 |
c.Assert(err, check.IsNil) |
| 29 | 29 |
c.Assert(d.(*Discovery).path, check.Equals, "/path/to/file") |
| 30 | 30 |
} |
| ... | ... |
@@ -81,7 +81,7 @@ func (s *DiscoverySuite) TestWatch(c *check.C) {
|
| 81 | 81 |
|
| 82 | 82 |
// Set up file discovery. |
| 83 | 83 |
d := &Discovery{}
|
| 84 |
- d.Initialize(tmp.Name(), 1000, 0) |
|
| 84 |
+ d.Initialize(tmp.Name(), 1000, 0, nil) |
|
| 85 | 85 |
stopCh := make(chan struct{})
|
| 86 | 86 |
ch, errCh := d.Watch(stopCh) |
| 87 | 87 |
|
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
|
| 9 | 9 |
log "github.com/Sirupsen/logrus" |
| 10 | 10 |
"github.com/docker/docker/pkg/discovery" |
| 11 |
+ "github.com/docker/docker/pkg/tlsconfig" |
|
| 11 | 12 |
"github.com/docker/libkv" |
| 12 | 13 |
"github.com/docker/libkv/store" |
| 13 | 14 |
"github.com/docker/libkv/store/consul" |
| ... | ... |
@@ -47,7 +48,7 @@ func Init() {
|
| 47 | 47 |
} |
| 48 | 48 |
|
| 49 | 49 |
// Initialize is exported |
| 50 |
-func (s *Discovery) Initialize(uris string, heartbeat time.Duration, ttl time.Duration) error {
|
|
| 50 |
+func (s *Discovery) Initialize(uris string, heartbeat time.Duration, ttl time.Duration, clusterOpts map[string]string) error {
|
|
| 51 | 51 |
var ( |
| 52 | 52 |
parts = strings.SplitN(uris, "/", 2) |
| 53 | 53 |
addrs = strings.Split(parts[0], ",") |
| ... | ... |
@@ -63,9 +64,34 @@ func (s *Discovery) Initialize(uris string, heartbeat time.Duration, ttl time.Du |
| 63 | 63 |
s.ttl = ttl |
| 64 | 64 |
s.path = path.Join(s.prefix, discoveryPath) |
| 65 | 65 |
|
| 66 |
+ var config *store.Config |
|
| 67 |
+ if clusterOpts["kv.cacertfile"] != "" && clusterOpts["kv.certfile"] != "" && clusterOpts["kv.keyfile"] != "" {
|
|
| 68 |
+ log.Info("Initializing discovery with TLS")
|
|
| 69 |
+ tlsConfig, err := tlsconfig.Client(tlsconfig.Options{
|
|
| 70 |
+ CAFile: clusterOpts["kv.cacertfile"], |
|
| 71 |
+ CertFile: clusterOpts["kv.certfile"], |
|
| 72 |
+ KeyFile: clusterOpts["kv.keyfile"], |
|
| 73 |
+ }) |
|
| 74 |
+ if err != nil {
|
|
| 75 |
+ return err |
|
| 76 |
+ } |
|
| 77 |
+ config = &store.Config{
|
|
| 78 |
+ // Set ClientTLS to trigger https (bug in libkv/etcd) |
|
| 79 |
+ ClientTLS: &store.ClientTLSConfig{
|
|
| 80 |
+ CACertFile: clusterOpts["kv.cacertfile"], |
|
| 81 |
+ CertFile: clusterOpts["kv.certfile"], |
|
| 82 |
+ KeyFile: clusterOpts["kv.keyfile"], |
|
| 83 |
+ }, |
|
| 84 |
+ // The actual TLS config that will be used |
|
| 85 |
+ TLS: tlsConfig, |
|
| 86 |
+ } |
|
| 87 |
+ } else {
|
|
| 88 |
+ log.Info("Initializing discovery without TLS")
|
|
| 89 |
+ } |
|
| 90 |
+ |
|
| 66 | 91 |
// Creates a new store, will ignore options given |
| 67 | 92 |
// if not supported by the chosen store |
| 68 |
- s.store, err = libkv.NewStore(s.backend, addrs, nil) |
|
| 93 |
+ s.store, err = libkv.NewStore(s.backend, addrs, config) |
|
| 69 | 94 |
return err |
| 70 | 95 |
} |
| 71 | 96 |
|
| ... | ... |
@@ -2,11 +2,14 @@ package kv |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"errors" |
| 5 |
+ "io/ioutil" |
|
| 6 |
+ "os" |
|
| 5 | 7 |
"path" |
| 6 | 8 |
"testing" |
| 7 | 9 |
"time" |
| 8 | 10 |
|
| 9 | 11 |
"github.com/docker/docker/pkg/discovery" |
| 12 |
+ "github.com/docker/libkv" |
|
| 10 | 13 |
"github.com/docker/libkv/store" |
| 11 | 14 |
|
| 12 | 15 |
"github.com/go-check/check" |
| ... | ... |
@@ -24,7 +27,7 @@ func (ds *DiscoverySuite) TestInitialize(c *check.C) {
|
| 24 | 24 |
Endpoints: []string{"127.0.0.1"},
|
| 25 | 25 |
} |
| 26 | 26 |
d := &Discovery{backend: store.CONSUL}
|
| 27 |
- d.Initialize("127.0.0.1", 0, 0)
|
|
| 27 |
+ d.Initialize("127.0.0.1", 0, 0, nil)
|
|
| 28 | 28 |
d.store = storeMock |
| 29 | 29 |
|
| 30 | 30 |
s := d.store.(*FakeStore) |
| ... | ... |
@@ -36,7 +39,7 @@ func (ds *DiscoverySuite) TestInitialize(c *check.C) {
|
| 36 | 36 |
Endpoints: []string{"127.0.0.1:1234"},
|
| 37 | 37 |
} |
| 38 | 38 |
d = &Discovery{backend: store.CONSUL}
|
| 39 |
- d.Initialize("127.0.0.1:1234/path", 0, 0)
|
|
| 39 |
+ d.Initialize("127.0.0.1:1234/path", 0, 0, nil)
|
|
| 40 | 40 |
d.store = storeMock |
| 41 | 41 |
|
| 42 | 42 |
s = d.store.(*FakeStore) |
| ... | ... |
@@ -48,7 +51,7 @@ func (ds *DiscoverySuite) TestInitialize(c *check.C) {
|
| 48 | 48 |
Endpoints: []string{"127.0.0.1:1234", "127.0.0.2:1234", "127.0.0.3:1234"},
|
| 49 | 49 |
} |
| 50 | 50 |
d = &Discovery{backend: store.CONSUL}
|
| 51 |
- d.Initialize("127.0.0.1:1234,127.0.0.2:1234,127.0.0.3:1234/path", 0, 0)
|
|
| 51 |
+ d.Initialize("127.0.0.1:1234,127.0.0.2:1234,127.0.0.3:1234/path", 0, 0, nil)
|
|
| 52 | 52 |
d.store = storeMock |
| 53 | 53 |
|
| 54 | 54 |
s = d.store.(*FakeStore) |
| ... | ... |
@@ -60,6 +63,150 @@ func (ds *DiscoverySuite) TestInitialize(c *check.C) {
|
| 60 | 60 |
c.Assert(d.path, check.Equals, "path/"+discoveryPath) |
| 61 | 61 |
} |
| 62 | 62 |
|
| 63 |
+// Extremely limited mock store so we can test initialization |
|
| 64 |
+type Mock struct {
|
|
| 65 |
+ // Endpoints passed to InitializeMock |
|
| 66 |
+ Endpoints []string |
|
| 67 |
+ |
|
| 68 |
+ // Options passed to InitializeMock |
|
| 69 |
+ Options *store.Config |
|
| 70 |
+} |
|
| 71 |
+ |
|
| 72 |
+func NewMock(endpoints []string, options *store.Config) (store.Store, error) {
|
|
| 73 |
+ s := &Mock{}
|
|
| 74 |
+ s.Endpoints = endpoints |
|
| 75 |
+ s.Options = options |
|
| 76 |
+ return s, nil |
|
| 77 |
+} |
|
| 78 |
+func (s *Mock) Put(key string, value []byte, opts *store.WriteOptions) error {
|
|
| 79 |
+ return errors.New("Put not supported")
|
|
| 80 |
+} |
|
| 81 |
+func (s *Mock) Get(key string) (*store.KVPair, error) {
|
|
| 82 |
+ return nil, errors.New("Get not supported")
|
|
| 83 |
+} |
|
| 84 |
+func (s *Mock) Delete(key string) error {
|
|
| 85 |
+ return errors.New("Delete not supported")
|
|
| 86 |
+} |
|
| 87 |
+ |
|
| 88 |
+// Exists mock |
|
| 89 |
+func (s *Mock) Exists(key string) (bool, error) {
|
|
| 90 |
+ return false, errors.New("Exists not supported")
|
|
| 91 |
+} |
|
| 92 |
+ |
|
| 93 |
+// Watch mock |
|
| 94 |
+func (s *Mock) Watch(key string, stopCh <-chan struct{}) (<-chan *store.KVPair, error) {
|
|
| 95 |
+ return nil, errors.New("Watch not supported")
|
|
| 96 |
+} |
|
| 97 |
+ |
|
| 98 |
+// WatchTree mock |
|
| 99 |
+func (s *Mock) WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*store.KVPair, error) {
|
|
| 100 |
+ return nil, errors.New("WatchTree not supported")
|
|
| 101 |
+} |
|
| 102 |
+ |
|
| 103 |
+// NewLock mock |
|
| 104 |
+func (s *Mock) NewLock(key string, options *store.LockOptions) (store.Locker, error) {
|
|
| 105 |
+ return nil, errors.New("NewLock not supported")
|
|
| 106 |
+} |
|
| 107 |
+ |
|
| 108 |
+// List mock |
|
| 109 |
+func (s *Mock) List(prefix string) ([]*store.KVPair, error) {
|
|
| 110 |
+ return nil, errors.New("List not supported")
|
|
| 111 |
+} |
|
| 112 |
+ |
|
| 113 |
+// DeleteTree mock |
|
| 114 |
+func (s *Mock) DeleteTree(prefix string) error {
|
|
| 115 |
+ return errors.New("DeleteTree not supported")
|
|
| 116 |
+} |
|
| 117 |
+ |
|
| 118 |
+// AtomicPut mock |
|
| 119 |
+func (s *Mock) AtomicPut(key string, value []byte, previous *store.KVPair, opts *store.WriteOptions) (bool, *store.KVPair, error) {
|
|
| 120 |
+ return false, nil, errors.New("AtomicPut not supported")
|
|
| 121 |
+} |
|
| 122 |
+ |
|
| 123 |
+// AtomicDelete mock |
|
| 124 |
+func (s *Mock) AtomicDelete(key string, previous *store.KVPair) (bool, error) {
|
|
| 125 |
+ return false, errors.New("AtomicDelete not supported")
|
|
| 126 |
+} |
|
| 127 |
+ |
|
| 128 |
+// Close mock |
|
| 129 |
+func (s *Mock) Close() {
|
|
| 130 |
+ return |
|
| 131 |
+} |
|
| 132 |
+ |
|
| 133 |
+func (ds *DiscoverySuite) TestInitializeWithCerts(c *check.C) {
|
|
| 134 |
+ cert := `-----BEGIN CERTIFICATE----- |
|
| 135 |
+MIIDCDCCAfKgAwIBAgIICifG7YeiQOEwCwYJKoZIhvcNAQELMBIxEDAOBgNVBAMT |
|
| 136 |
+B1Rlc3QgQ0EwHhcNMTUxMDAxMjMwMDAwWhcNMjAwOTI5MjMwMDAwWjASMRAwDgYD |
|
| 137 |
+VQQDEwdUZXN0IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1wRC |
|
| 138 |
+O+flnLTK5ImjTurNRHwSejuqGbc4CAvpB0hS+z0QlSs4+zE9h80aC4hz+6caRpds |
|
| 139 |
++J908Q+RvAittMHbpc7VjbZP72G6fiXk7yPPl6C10HhRSoSi3nY+B7F2E8cuz14q |
|
| 140 |
+V2e+ejhWhSrBb/keyXpcyjoW1BOAAJ2TIclRRkICSCZrpXUyXxAvzXfpFXo1RhSb |
|
| 141 |
+UywN11pfiCQzDUN7sPww9UzFHuAHZHoyfTr27XnJYVUerVYrCPq8vqfn//01qz55 |
|
| 142 |
+Xs0hvzGdlTFXhuabFtQnKFH5SNwo/fcznhB7rePOwHojxOpXTBepUCIJLbtNnWFT |
|
| 143 |
+V44t9gh5IqIWtoBReQIDAQABo2YwZDAOBgNVHQ8BAf8EBAMCAAYwEgYDVR0TAQH/ |
|
| 144 |
+BAgwBgEB/wIBAjAdBgNVHQ4EFgQUZKUI8IIjIww7X/6hvwggQK4bD24wHwYDVR0j |
|
| 145 |
+BBgwFoAUZKUI8IIjIww7X/6hvwggQK4bD24wCwYJKoZIhvcNAQELA4IBAQDES2cz |
|
| 146 |
+7sCQfDCxCIWH7X8kpi/JWExzUyQEJ0rBzN1m3/x8ySRxtXyGekimBqQwQdFqlwMI |
|
| 147 |
+xzAQKkh3ue8tNSzRbwqMSyH14N1KrSxYS9e9szJHfUasoTpQGPmDmGIoRJuq1h6M |
|
| 148 |
+ej5x1SCJ7GWCR6xEXKUIE9OftXm9TdFzWa7Ja3OHz/mXteii8VXDuZ5ACq6EE5bY |
|
| 149 |
+8sP4gcICfJ5fTrpTlk9FIqEWWQrCGa5wk95PGEj+GJpNogjXQ97wVoo/Y3p1brEn |
|
| 150 |
+t5zjN9PAq4H1fuCMdNNA+p1DHNwd+ELTxcMAnb2ajwHvV6lKPXutrTFc4umJToBX |
|
| 151 |
+FpTxDmJHEV4bzUzh |
|
| 152 |
+-----END CERTIFICATE----- |
|
| 153 |
+` |
|
| 154 |
+ key := `-----BEGIN RSA PRIVATE KEY----- |
|
| 155 |
+MIIEpQIBAAKCAQEA1wRCO+flnLTK5ImjTurNRHwSejuqGbc4CAvpB0hS+z0QlSs4 |
|
| 156 |
++zE9h80aC4hz+6caRpds+J908Q+RvAittMHbpc7VjbZP72G6fiXk7yPPl6C10HhR |
|
| 157 |
+SoSi3nY+B7F2E8cuz14qV2e+ejhWhSrBb/keyXpcyjoW1BOAAJ2TIclRRkICSCZr |
|
| 158 |
+pXUyXxAvzXfpFXo1RhSbUywN11pfiCQzDUN7sPww9UzFHuAHZHoyfTr27XnJYVUe |
|
| 159 |
+rVYrCPq8vqfn//01qz55Xs0hvzGdlTFXhuabFtQnKFH5SNwo/fcznhB7rePOwHoj |
|
| 160 |
+xOpXTBepUCIJLbtNnWFTV44t9gh5IqIWtoBReQIDAQABAoIBAHSWipORGp/uKFXj |
|
| 161 |
+i/mut776x8ofsAxhnLBARQr93ID+i49W8H7EJGkOfaDjTICYC1dbpGrri61qk8sx |
|
| 162 |
+qX7p3v/5NzKwOIfEpirgwVIqSNYe/ncbxnhxkx6tXtUtFKmEx40JskvSpSYAhmmO |
|
| 163 |
+1XSx0E/PWaEN/nLgX/f1eWJIlxlQkk3QeqL+FGbCXI48DEtlJ9+MzMu4pAwZTpj5 |
|
| 164 |
+5qtXo5JJ0jRGfJVPAOznRsYqv864AhMdMIWguzk6EGnbaCWwPcfcn+h9a5LMdony |
|
| 165 |
+MDHfBS7bb5tkF3+AfnVY3IBMVx7YlsD9eAyajlgiKu4zLbwTRHjXgShy+4Oussz0 |
|
| 166 |
+ugNGnkECgYEA/hi+McrZC8C4gg6XqK8+9joD8tnyDZDz88BQB7CZqABUSwvjDqlP |
|
| 167 |
+L8hcwo/lzvjBNYGkqaFPUICGWKjeCtd8pPS2DCVXxDQX4aHF1vUur0uYNncJiV3N |
|
| 168 |
+XQz4Iemsa6wnKf6M67b5vMXICw7dw0HZCdIHD1hnhdtDz0uVpeevLZ8CgYEA2KCT |
|
| 169 |
+Y43lorjrbCgMqtlefkr3GJA9dey+hTzCiWEOOqn9RqGoEGUday0sKhiLofOgmN2B |
|
| 170 |
+LEukpKIey8s+Q/cb6lReajDVPDsMweX8i7hz3Wa4Ugp4Xa5BpHqu8qIAE2JUZ7bU |
|
| 171 |
+t88aQAYE58pUF+/Lq1QzAQdrjjzQBx6SrBxieecCgYEAvukoPZEC8mmiN1VvbTX+ |
|
| 172 |
+QFHmlZha3QaDxChB+QUe7bMRojEUL/fVnzkTOLuVFqSfxevaI/km9n0ac5KtAchV |
|
| 173 |
+xjp2bTnBb5EUQFqjopYktWA+xO07JRJtMfSEmjZPbbay1kKC7rdTfBm961EIHaRj |
|
| 174 |
+xZUf6M+rOE8964oGrdgdLlECgYEA046GQmx6fh7/82FtdZDRQp9tj3SWQUtSiQZc |
|
| 175 |
+qhO59Lq8mjUXz+MgBuJXxkiwXRpzlbaFB0Bca1fUoYw8o915SrDYf/Zu2OKGQ/qa |
|
| 176 |
+V81sgiVmDuEgycR7YOlbX6OsVUHrUlpwhY3hgfMe6UtkMvhBvHF/WhroBEIJm1pV |
|
| 177 |
+PXZ/CbMCgYEApNWVktFBjOaYfY6SNn4iSts1jgsQbbpglg3kT7PLKjCAhI6lNsbk |
|
| 178 |
+dyT7ut01PL6RaW4SeQWtrJIVQaM6vF3pprMKqlc5XihOGAmVqH7rQx9rtQB5TicL |
|
| 179 |
+BFrwkQE4HQtQBV60hYQUzzlSk44VFDz+jxIEtacRHaomDRh2FtOTz+I= |
|
| 180 |
+-----END RSA PRIVATE KEY----- |
|
| 181 |
+` |
|
| 182 |
+ certFile, err := ioutil.TempFile("", "cert")
|
|
| 183 |
+ c.Assert(err, check.IsNil) |
|
| 184 |
+ defer os.Remove(certFile.Name()) |
|
| 185 |
+ certFile.Write([]byte(cert)) |
|
| 186 |
+ certFile.Close() |
|
| 187 |
+ keyFile, err := ioutil.TempFile("", "key")
|
|
| 188 |
+ c.Assert(err, check.IsNil) |
|
| 189 |
+ defer os.Remove(keyFile.Name()) |
|
| 190 |
+ keyFile.Write([]byte(key)) |
|
| 191 |
+ keyFile.Close() |
|
| 192 |
+ |
|
| 193 |
+ libkv.AddStore("mock", NewMock)
|
|
| 194 |
+ d := &Discovery{backend: "mock"}
|
|
| 195 |
+ err = d.Initialize("127.0.0.3:1234", 0, 0, map[string]string{
|
|
| 196 |
+ "kv.cacertfile": certFile.Name(), |
|
| 197 |
+ "kv.certfile": certFile.Name(), |
|
| 198 |
+ "kv.keyfile": keyFile.Name(), |
|
| 199 |
+ }) |
|
| 200 |
+ c.Assert(err, check.IsNil) |
|
| 201 |
+ s := d.store.(*Mock) |
|
| 202 |
+ c.Assert(s.Options.TLS, check.NotNil) |
|
| 203 |
+ c.Assert(s.Options.TLS.RootCAs, check.NotNil) |
|
| 204 |
+ c.Assert(s.Options.TLS.Certificates, check.HasLen, 1) |
|
| 205 |
+} |
|
| 206 |
+ |
|
| 63 | 207 |
func (ds *DiscoverySuite) TestWatch(c *check.C) {
|
| 64 | 208 |
mockCh := make(chan []*store.KVPair) |
| 65 | 209 |
|
| ... | ... |
@@ -69,7 +216,7 @@ func (ds *DiscoverySuite) TestWatch(c *check.C) {
|
| 69 | 69 |
} |
| 70 | 70 |
|
| 71 | 71 |
d := &Discovery{backend: store.CONSUL}
|
| 72 |
- d.Initialize("127.0.0.1:1234/path", 0, 0)
|
|
| 72 |
+ d.Initialize("127.0.0.1:1234/path", 0, 0, nil)
|
|
| 73 | 73 |
d.store = storeMock |
| 74 | 74 |
|
| 75 | 75 |
expected := discovery.Entries{
|
| ... | ... |
@@ -23,7 +23,7 @@ func Init() {
|
| 23 | 23 |
} |
| 24 | 24 |
|
| 25 | 25 |
// Initialize is exported |
| 26 |
-func (s *Discovery) Initialize(uris string, _ time.Duration, _ time.Duration) error {
|
|
| 26 |
+func (s *Discovery) Initialize(uris string, _ time.Duration, _ time.Duration, _ map[string]string) error {
|
|
| 27 | 27 |
for _, input := range strings.Split(uris, ",") {
|
| 28 | 28 |
for _, ip := range discovery.Generate(input) {
|
| 29 | 29 |
entry, err := discovery.NewEntry(ip) |
| ... | ... |
@@ -17,7 +17,7 @@ var _ = check.Suite(&DiscoverySuite{})
|
| 17 | 17 |
|
| 18 | 18 |
func (s *DiscoverySuite) TestInitialize(c *check.C) {
|
| 19 | 19 |
d := &Discovery{}
|
| 20 |
- d.Initialize("1.1.1.1:1111,2.2.2.2:2222", 0, 0)
|
|
| 20 |
+ d.Initialize("1.1.1.1:1111,2.2.2.2:2222", 0, 0, nil)
|
|
| 21 | 21 |
c.Assert(len(d.entries), check.Equals, 2) |
| 22 | 22 |
c.Assert(d.entries[0].String(), check.Equals, "1.1.1.1:1111") |
| 23 | 23 |
c.Assert(d.entries[1].String(), check.Equals, "2.2.2.2:2222") |
| ... | ... |
@@ -25,7 +25,7 @@ func (s *DiscoverySuite) TestInitialize(c *check.C) {
|
| 25 | 25 |
|
| 26 | 26 |
func (s *DiscoverySuite) TestInitializeWithPattern(c *check.C) {
|
| 27 | 27 |
d := &Discovery{}
|
| 28 |
- d.Initialize("1.1.1.[1:2]:1111,2.2.2.[2:4]:2222", 0, 0)
|
|
| 28 |
+ d.Initialize("1.1.1.[1:2]:1111,2.2.2.[2:4]:2222", 0, 0, nil)
|
|
| 29 | 29 |
c.Assert(len(d.entries), check.Equals, 5) |
| 30 | 30 |
c.Assert(d.entries[0].String(), check.Equals, "1.1.1.1:1111") |
| 31 | 31 |
c.Assert(d.entries[1].String(), check.Equals, "1.1.1.2:1111") |
| ... | ... |
@@ -36,7 +36,7 @@ func (s *DiscoverySuite) TestInitializeWithPattern(c *check.C) {
|
| 36 | 36 |
|
| 37 | 37 |
func (s *DiscoverySuite) TestWatch(c *check.C) {
|
| 38 | 38 |
d := &Discovery{}
|
| 39 |
- d.Initialize("1.1.1.1:1111,2.2.2.2:2222", 0, 0)
|
|
| 39 |
+ d.Initialize("1.1.1.1:1111,2.2.2.2:2222", 0, 0, nil)
|
|
| 40 | 40 |
expected := discovery.Entries{
|
| 41 | 41 |
&discovery.Entry{Host: "1.1.1.1", Port: "1111"},
|
| 42 | 42 |
&discovery.Entry{Host: "2.2.2.2", Port: "2222"},
|