Skip to content

Commit 71496ef

Browse files
committed
Allow to pass global datastore config
- After boot via ReloadConfiguration() method Signed-off-by: Alessandro Boch <aboch@docker.com>
1 parent be2b696 commit 71496ef

4 files changed

Lines changed: 131 additions & 20 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: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -256,16 +256,21 @@ func NewDataStore(scope string, cfg *ScopeCfg) (DataStore, error) {
256256

257257
// NewDataStoreFromConfig creates a new instance of LibKV data store starting from the datastore config data
258258
func NewDataStoreFromConfig(dsc discoverapi.DatastoreConfigData) (DataStore, error) {
259-
sCfg, ok := dsc.Config.(*store.Config)
260-
if !ok {
259+
var (
260+
ok bool
261+
sCfgP *store.Config
262+
)
263+
264+
sCfgP, ok = dsc.Config.(*store.Config)
265+
if !ok && dsc.Config != nil {
261266
return nil, fmt.Errorf("cannot parse store configuration: %v", dsc.Config)
262267
}
263268

264269
scopeCfg := &ScopeCfg{
265270
Client: ScopeClientCfg{
266271
Address: dsc.Address,
267272
Provider: dsc.Provider,
268-
Config: sCfg,
273+
Config: sCfgP,
269274
},
270275
}
271276

store.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ func (c *controller) initStores() error {
1414
return nil
1515
}
1616
scopeConfigs := c.cfg.Scopes
17+
c.stores = nil
1718
c.Unlock()
1819

1920
for scope, scfg := range scopeConfigs {
@@ -417,6 +418,9 @@ func (c *controller) watchLoop() {
417418
}
418419

419420
func (c *controller) startWatch() {
421+
if c.watchCh != nil {
422+
return
423+
}
420424
c.watchCh = make(chan *endpoint)
421425
c.unWatchCh = make(chan *endpoint)
422426
c.nmap = make(map[string]*netWatch)

0 commit comments

Comments
 (0)