Skip to content

Commit c4197ed

Browse files
author
Santhosh Manohar
committed
Merge pull request #908 from aboch/dds
Allow pass global datastore config after boot
2 parents 415dae5 + 71496ef commit c4197ed

13 files changed

Lines changed: 324 additions & 94 deletions

File tree

config/config.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,22 @@ func ParseConfig(tomlCfgFile string) (*Config, error) {
6161
return cfg, nil
6262
}
6363

64+
// ParseConfigOptions parses the configuration options and returns
65+
// a reference to the corresponding Config structure
66+
func ParseConfigOptions(cfgOptions ...Option) *Config {
67+
cfg := &Config{
68+
Daemon: DaemonCfg{
69+
DriverCfg: make(map[string]interface{}),
70+
},
71+
Scopes: make(map[string]*datastore.ScopeCfg),
72+
}
73+
74+
cfg.ProcessOptions(cfgOptions...)
75+
cfg.LoadDefaultScopes(cfg.Daemon.DataDir)
76+
77+
return cfg
78+
}
79+
6480
// Option is an option setter function type used to pass various configurations
6581
// to the controller
6682
type Option func(c *Config)

controller.go

Lines changed: 103 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ type NetworkController interface {
106106

107107
// Stop network controller
108108
Stop()
109+
110+
// ReloadCondfiguration updates the controller configuration
111+
ReloadConfiguration(cfgOptions ...config.Option) error
109112
}
110113

111114
// NetworkWalker is a client provided function which will be used to walk the Networks.
@@ -129,7 +132,6 @@ type ipamData struct {
129132
}
130133

131134
type driverTable map[string]*driverData
132-
133135
type ipamTable map[string]*ipamData
134136
type sandboxTable map[string]*sandbox
135137

@@ -153,22 +155,9 @@ type controller struct {
153155

154156
// New creates a new instance of network controller.
155157
func New(cfgOptions ...config.Option) (NetworkController, error) {
156-
var cfg *config.Config
157-
cfg = &config.Config{
158-
Daemon: config.DaemonCfg{
159-
DriverCfg: make(map[string]interface{}),
160-
},
161-
Scopes: make(map[string]*datastore.ScopeCfg),
162-
}
163-
164-
if len(cfgOptions) > 0 {
165-
cfg.ProcessOptions(cfgOptions...)
166-
}
167-
cfg.LoadDefaultScopes(cfg.Daemon.DataDir)
168-
169158
c := &controller{
170159
id: stringid.GenerateRandomID(),
171-
cfg: cfg,
160+
cfg: config.ParseConfigOptions(cfgOptions...),
172161
sandboxes: sandboxTable{},
173162
drivers: driverTable{},
174163
ipamDrivers: ipamTable{},
@@ -179,8 +168,8 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
179168
return nil, err
180169
}
181170

182-
if cfg != nil && cfg.Cluster.Watcher != nil {
183-
if err := c.initDiscovery(cfg.Cluster.Watcher); err != nil {
171+
if c.cfg != nil && c.cfg.Cluster.Watcher != nil {
172+
if err := c.initDiscovery(c.cfg.Cluster.Watcher); err != nil {
184173
// Failing to initalize discovery is a bad situation to be in.
185174
// But it cannot fail creating the Controller
186175
log.Errorf("Failed to Initialize Discovery : %v", err)
@@ -206,6 +195,83 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
206195
return c, nil
207196
}
208197

198+
var procReloadConfig = make(chan (bool), 1)
199+
200+
func (c *controller) ReloadConfiguration(cfgOptions ...config.Option) error {
201+
procReloadConfig <- true
202+
defer func() { <-procReloadConfig }()
203+
204+
// For now we accept the configuration reload only as a mean to provide a global store config after boot.
205+
// Refuse the configuration if it alters an existing datastore client configuration.
206+
update := false
207+
cfg := config.ParseConfigOptions(cfgOptions...)
208+
for s := range c.cfg.Scopes {
209+
if _, ok := cfg.Scopes[s]; !ok {
210+
return types.ForbiddenErrorf("cannot accept new configuration because it removes an existing datastore client")
211+
}
212+
}
213+
for s, nSCfg := range cfg.Scopes {
214+
if eSCfg, ok := c.cfg.Scopes[s]; ok {
215+
if eSCfg.Client.Provider != nSCfg.Client.Provider ||
216+
eSCfg.Client.Address != nSCfg.Client.Address {
217+
return types.ForbiddenErrorf("cannot accept new configuration because it modifies an existing datastore client")
218+
}
219+
} else {
220+
update = true
221+
}
222+
}
223+
if !update {
224+
return nil
225+
}
226+
227+
c.Lock()
228+
c.cfg = cfg
229+
c.Unlock()
230+
231+
if err := c.initStores(); err != nil {
232+
return err
233+
}
234+
235+
if c.discovery == nil && c.cfg.Cluster.Watcher != nil {
236+
if err := c.initDiscovery(c.cfg.Cluster.Watcher); err != nil {
237+
log.Errorf("Failed to Initialize Discovery after configuration update: %v", err)
238+
}
239+
}
240+
241+
var dsConfig *discoverapi.DatastoreConfigData
242+
for scope, sCfg := range cfg.Scopes {
243+
if scope == datastore.LocalScope || !sCfg.IsValid() {
244+
continue
245+
}
246+
dsConfig = &discoverapi.DatastoreConfigData{
247+
Scope: scope,
248+
Provider: sCfg.Client.Provider,
249+
Address: sCfg.Client.Address,
250+
Config: sCfg.Client.Config,
251+
}
252+
break
253+
}
254+
if dsConfig == nil {
255+
return nil
256+
}
257+
258+
for nm, id := range c.getIpamDrivers() {
259+
err := id.driver.DiscoverNew(discoverapi.DatastoreConfig, *dsConfig)
260+
if err != nil {
261+
log.Errorf("Failed to set datastore in driver %s: %v", nm, err)
262+
}
263+
}
264+
265+
for nm, id := range c.getNetDrivers() {
266+
err := id.driver.DiscoverNew(discoverapi.DatastoreConfig, *dsConfig)
267+
if err != nil {
268+
log.Errorf("Failed to set datastore in driver %s: %v", nm, err)
269+
}
270+
}
271+
272+
return nil
273+
}
274+
209275
func (c *controller) ID() string {
210276
return c.id
211277
}
@@ -726,6 +792,26 @@ func (c *controller) getIpamDriver(name string) (ipamapi.Ipam, error) {
726792
return id.driver, nil
727793
}
728794

795+
func (c *controller) getIpamDrivers() ipamTable {
796+
c.Lock()
797+
defer c.Unlock()
798+
table := ipamTable{}
799+
for i, d := range c.ipamDrivers {
800+
table[i] = d
801+
}
802+
return table
803+
}
804+
805+
func (c *controller) getNetDrivers() driverTable {
806+
c.Lock()
807+
defer c.Unlock()
808+
table := driverTable{}
809+
for i, d := range c.drivers {
810+
table[i] = d
811+
}
812+
return table
813+
}
814+
729815
func (c *controller) Stop() {
730816
c.closeStores()
731817
c.stopExternalKeyListener()

datastore/datastore.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/docker/libkv/store/consul"
1414
"github.com/docker/libkv/store/etcd"
1515
"github.com/docker/libkv/store/zookeeper"
16+
"github.com/docker/libnetwork/discoverapi"
1617
"github.com/docker/libnetwork/types"
1718
)
1819

@@ -253,6 +254,34 @@ func NewDataStore(scope string, cfg *ScopeCfg) (DataStore, error) {
253254
return newClient(scope, cfg.Client.Provider, cfg.Client.Address, cfg.Client.Config, cached)
254255
}
255256

257+
// NewDataStoreFromConfig creates a new instance of LibKV data store starting from the datastore config data
258+
func NewDataStoreFromConfig(dsc discoverapi.DatastoreConfigData) (DataStore, error) {
259+
var (
260+
ok bool
261+
sCfgP *store.Config
262+
)
263+
264+
sCfgP, ok = dsc.Config.(*store.Config)
265+
if !ok && dsc.Config != nil {
266+
return nil, fmt.Errorf("cannot parse store configuration: %v", dsc.Config)
267+
}
268+
269+
scopeCfg := &ScopeCfg{
270+
Client: ScopeClientCfg{
271+
Address: dsc.Address,
272+
Provider: dsc.Provider,
273+
Config: sCfgP,
274+
},
275+
}
276+
277+
ds, err := NewDataStore(dsc.Scope, scopeCfg)
278+
if err != nil {
279+
return nil, fmt.Errorf("failed to construct datastore client from datastore configuration %v: %v", dsc, err)
280+
}
281+
282+
return ds, err
283+
}
284+
256285
func (ds *datastore) Close() {
257286
ds.store.Close()
258287
}

discoverapi/discoverapi.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ type DiscoveryType int
1616
const (
1717
// NodeDiscovery represents Node join/leave events provided by discovery
1818
NodeDiscovery = iota + 1
19-
// DatastoreUpdate represents a add/remove datastore event
20-
DatastoreUpdate
19+
// DatastoreConfig represents a add/remove datastore event
20+
DatastoreConfig
2121
)
2222

2323
// NodeDiscoveryData represents the structure backing the node discovery data json string
@@ -26,8 +26,9 @@ type NodeDiscoveryData struct {
2626
Self bool
2727
}
2828

29-
// DatastoreUpdateData is the data for the datastore update event message
30-
type DatastoreUpdateData struct {
29+
// DatastoreConfigData is the data for the datastore update event message
30+
type DatastoreConfigData struct {
31+
Scope string
3132
Provider string
3233
Address string
3334
Config interface{}

drivers.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package libnetwork
33
import (
44
"strings"
55

6+
"github.com/docker/libnetwork/discoverapi"
67
"github.com/docker/libnetwork/driverapi"
78
"github.com/docker/libnetwork/ipamapi"
89
"github.com/docker/libnetwork/netlabel"
@@ -57,10 +58,12 @@ func makeDriverConfig(c *controller, ntype string) map[string]interface{} {
5758
if !v.IsValid() {
5859
continue
5960
}
60-
61-
config[netlabel.MakeKVProvider(k)] = v.Client.Provider
62-
config[netlabel.MakeKVProviderURL(k)] = v.Client.Address
63-
config[netlabel.MakeKVProviderConfig(k)] = v.Client.Config
61+
config[netlabel.MakeKVClient(k)] = discoverapi.DatastoreConfigData{
62+
Scope: k,
63+
Provider: v.Client.Provider,
64+
Address: v.Client.Address,
65+
Config: v.Client.Config,
66+
}
6467
}
6568

6669
return config

drivers/bridge/bridge_store.go

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,25 @@ import (
66
"net"
77

88
"github.com/Sirupsen/logrus"
9-
"github.com/docker/libkv/store"
109
"github.com/docker/libkv/store/boltdb"
1110
"github.com/docker/libnetwork/datastore"
11+
"github.com/docker/libnetwork/discoverapi"
1212
"github.com/docker/libnetwork/netlabel"
1313
"github.com/docker/libnetwork/types"
1414
)
1515

1616
const bridgePrefix = "bridge"
1717

1818
func (d *driver) initStore(option map[string]interface{}) error {
19-
var err error
20-
21-
provider, provOk := option[netlabel.LocalKVProvider]
22-
provURL, urlOk := option[netlabel.LocalKVProviderURL]
23-
24-
if provOk && urlOk {
25-
cfg := &datastore.ScopeCfg{
26-
Client: datastore.ScopeClientCfg{
27-
Provider: provider.(string),
28-
Address: provURL.(string),
29-
},
19+
if data, ok := option[netlabel.LocalKVClient]; ok {
20+
var err error
21+
dsc, ok := data.(discoverapi.DatastoreConfigData)
22+
if !ok {
23+
return types.InternalErrorf("incorrect data in datastore configuration: %v", data)
3024
}
31-
32-
provConfig, confOk := option[netlabel.LocalKVProviderConfig]
33-
if confOk {
34-
cfg.Client.Config = provConfig.(*store.Config)
35-
}
36-
37-
d.store, err = datastore.NewDataStore(datastore.LocalScope, cfg)
25+
d.store, err = datastore.NewDataStoreFromConfig(dsc)
3826
if err != nil {
39-
return fmt.Errorf("bridge driver failed to initialize data store: %v", err)
27+
return types.InternalErrorf("bridge driver failed to initialize data store: %v", err)
4028
}
4129

4230
return d.populateNetworks()

0 commit comments

Comments
 (0)