Browse code

Merge pull request #20419 from aboch/cr

Allow passing global datastore to libnetwork and v0.7.0-dev1 vendoring

Arnaud Porterie authored on 2016/02/19 10:39:46
Showing 37 changed files
... ...
@@ -1598,12 +1598,12 @@ func (daemon *Daemon) initDiscovery(config *Config) error {
1598 1598
 // daemon according to those changes.
1599 1599
 // This are the settings that Reload changes:
1600 1600
 // - Daemon labels.
1601
+// - Cluster discovery (reconfigure and restart).
1601 1602
 func (daemon *Daemon) Reload(config *Config) error {
1602 1603
 	daemon.configStore.reloadLock.Lock()
1604
+	defer daemon.configStore.reloadLock.Unlock()
1603 1605
 	daemon.configStore.Labels = config.Labels
1604
-	daemon.configStore.reloadLock.Unlock()
1605
-
1606
-	return nil
1606
+	return daemon.reloadClusterDiscovery(config)
1607 1607
 }
1608 1608
 
1609 1609
 func (daemon *Daemon) reloadClusterDiscovery(config *Config) error {
... ...
@@ -1640,6 +1640,19 @@ func (daemon *Daemon) reloadClusterDiscovery(config *Config) error {
1640 1640
 	daemon.configStore.ClusterOpts = config.ClusterOpts
1641 1641
 	daemon.configStore.ClusterAdvertise = newAdvertise
1642 1642
 
1643
+	if daemon.netController == nil {
1644
+		return nil
1645
+	}
1646
+	netOptions, err := daemon.networkOptions(daemon.configStore)
1647
+	if err != nil {
1648
+		logrus.Warnf("Failed to reload configuration with network controller: %v", err)
1649
+		return nil
1650
+	}
1651
+	err = daemon.netController.ReloadConfiguration(netOptions...)
1652
+	if err != nil {
1653
+		logrus.Warnf("Failed to reload configuration with network controller: %v", err)
1654
+	}
1655
+
1643 1656
 	return nil
1644 1657
 }
1645 1658
 
... ...
@@ -371,7 +371,7 @@ func TestDaemonDiscoveryReload(t *testing.T) {
371 371
 		&discovery.Entry{Host: "127.0.0.1", Port: "5555"},
372 372
 	}
373 373
 
374
-	if err := daemon.reloadClusterDiscovery(newConfig); err != nil {
374
+	if err := daemon.Reload(newConfig); err != nil {
375 375
 		t.Fatal(err)
376 376
 	}
377 377
 	ch, errCh = daemon.discoveryWatcher.Watch(stopCh)
... ...
@@ -403,7 +403,7 @@ func TestDaemonDiscoveryReloadFromEmptyDiscovery(t *testing.T) {
403 403
 		&discovery.Entry{Host: "127.0.0.1", Port: "5555"},
404 404
 	}
405 405
 
406
-	if err := daemon.reloadClusterDiscovery(newConfig); err != nil {
406
+	if err := daemon.Reload(newConfig); err != nil {
407 407
 		t.Fatal(err)
408 408
 	}
409 409
 	stopCh := make(chan struct{})
... ...
@@ -22,6 +22,7 @@ import (
22 22
 	"github.com/docker/docker/pkg/idtools"
23 23
 	"github.com/docker/docker/pkg/system"
24 24
 	"github.com/docker/libnetwork"
25
+	nwconfig "github.com/docker/libnetwork/config"
25 26
 	blkiodev "github.com/opencontainers/runc/libcontainer/configs"
26 27
 )
27 28
 
... ...
@@ -251,3 +252,7 @@ func restoreCustomImage(is image.Store, ls layer.Store, rs reference.Store) erro
251 251
 	}
252 252
 	return nil
253 253
 }
254
+
255
+func (daemon *Daemon) networkOptions(dconfig *Config) ([]nwconfig.Option, error) {
256
+	return nil, fmt.Errorf("Network controller config reload not aavailable on Windows yet")
257
+}
... ...
@@ -890,4 +890,13 @@ if there are conflicts, but it won't stop execution.
890 890
 The list of currently supported options that can be reconfigured is this:
891 891
 
892 892
 - `debug`: it changes the daemon to debug mode when set to true.
893
+- `cluster-store`: it reloads the discovery store with the new address.
894
+- `cluster-store-opts`: it uses the new options to reload the discovery store.
895
+- `cluster-advertise`: it modifies the address advertised after reloading.
893 896
 - `labels`: it replaces the daemon labels with a new set of labels.
897
+
898
+Updating and reloading the cluster configurations such as `--cluster-store`,
899
+`--cluster-advertise` and `--cluster-store-opts` will take effect only if
900
+these configurations were not previously configured. Configuration reload will
901
+log a warning message if it detects a change in previously configured cluster
902
+configurations.
894 903
\ No newline at end of file
... ...
@@ -29,7 +29,7 @@ clone git github.com/RackSec/srslog 6eb773f331e46fbba8eecb8e794e635e75fc04de
29 29
 clone git github.com/imdario/mergo 0.2.1
30 30
 
31 31
 #get libnetwork packages
32
-clone git github.com/docker/libnetwork v0.7.0-dev.2
32
+clone git github.com/docker/libnetwork v0.7.0-dev.3
33 33
 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
34 34
 clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
35 35
 clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
... ...
@@ -17,6 +17,7 @@ import (
17 17
 	"strconv"
18 18
 	"strings"
19 19
 	"sync"
20
+	"syscall"
20 21
 	"time"
21 22
 
22 23
 	"github.com/docker/docker/pkg/integration/checker"
... ...
@@ -2156,3 +2157,43 @@ func (s *DockerDaemonSuite) TestDaemonDebugLog(c *check.C) {
2156 2156
 	newD.Stop()
2157 2157
 	c.Assert(b.String(), checker.Contains, debugLog)
2158 2158
 }
2159
+
2160
+func (s *DockerSuite) TestDaemonDiscoveryBackendConfigReload(c *check.C) {
2161
+	testRequires(c, SameHostDaemon, DaemonIsLinux)
2162
+
2163
+	// daemon config file
2164
+	daemonConfig := `{ "debug" : false }`
2165
+	configFilePath := "test.json"
2166
+
2167
+	configFile, err := os.Create(configFilePath)
2168
+	c.Assert(err, checker.IsNil)
2169
+	fmt.Fprintf(configFile, "%s", daemonConfig)
2170
+
2171
+	d := NewDaemon(c)
2172
+	err = d.Start(fmt.Sprintf("--config-file=%s", configFilePath))
2173
+	c.Assert(err, checker.IsNil)
2174
+	defer d.Stop()
2175
+
2176
+	// daemon config file
2177
+	daemonConfig = `{
2178
+	      "cluster-store": "consul://consuladdr:consulport/some/path",
2179
+	      "cluster-advertise": "192.168.56.100:0",
2180
+	      "debug" : false
2181
+	}`
2182
+
2183
+	configFile.Close()
2184
+	os.Remove(configFilePath)
2185
+
2186
+	configFile, err = os.Create(configFilePath)
2187
+	c.Assert(err, checker.IsNil)
2188
+	fmt.Fprintf(configFile, "%s", daemonConfig)
2189
+
2190
+	syscall.Kill(d.cmd.Process.Pid, syscall.SIGHUP)
2191
+
2192
+	time.Sleep(3 * time.Second)
2193
+
2194
+	out, err := d.Cmd("info")
2195
+	c.Assert(err, checker.IsNil)
2196
+	c.Assert(out, checker.Contains, fmt.Sprintf("Cluster store: consul://consuladdr:consulport/some/path"))
2197
+	c.Assert(out, checker.Contains, fmt.Sprintf("Cluster advertise: 192.168.56.100:0"))
2198
+}
... ...
@@ -1389,6 +1389,14 @@ func (s *DockerSuite) TestUserDefinedNetworkConnectivity(c *check.C) {
1389 1389
 	c.Assert(err, check.NotNil)
1390 1390
 }
1391 1391
 
1392
+func (s *DockerSuite) TestEmbeddedDNSInvalidInput(c *check.C) {
1393
+	testRequires(c, DaemonIsLinux, NotUserNamespace)
1394
+	dockerCmd(c, "network", "create", "-d", "bridge", "nw1")
1395
+
1396
+	// Sending garbge to embedded DNS shouldn't crash the daemon
1397
+	dockerCmd(c, "run", "-i", "--net=nw1", "--name=c1", "debian:jessie", "bash", "-c", "echo InvalidQuery > /dev/udp/127.0.0.11/53")
1398
+}
1399
+
1392 1400
 func (s *DockerSuite) TestDockerNetworkConnectFailsNoInspectChange(c *check.C) {
1393 1401
 	dockerCmd(c, "run", "-d", "--name=bb", "busybox", "top")
1394 1402
 	c.Assert(waitRun("bb"), check.IsNil)
... ...
@@ -1,5 +1,13 @@
1 1
 # Changelog
2 2
 
3
+## 0.7.0-dev.3 (2016-02-17)
4
+- Fixes https://github.com/docker/docker/issues/20350
5
+- Fixes https://github.com/docker/docker/issues/20145
6
+- Initial Windows HNS integration
7
+- Allow passing global datastore config to libnetwork after boot
8
+- Set Recursion Available bit in DNS query responses
9
+- Make sure iptables chains are recreated on firewalld reload
10
+
3 11
 ## 0.7.0-dev.2 (2016-02-11)
4 12
 - Fixes https://github.com/docker/docker/issues/20140
5 13
 
... ...
@@ -8,6 +8,5 @@ RUN cd /go/src && mkdir -p golang.org/x && \
8 8
 RUN go get github.com/tools/godep \
9 9
 		github.com/golang/lint/golint \
10 10
 		golang.org/x/tools/cmd/vet \
11
-		golang.org/x/tools/cmd/goimports \
12 11
 		golang.org/x/tools/cmd/cover\
13 12
 		github.com/mattn/goveralls
... ...
@@ -53,7 +53,7 @@ check-code:
53 53
 
54 54
 check-format:
55 55
 	@echo "Checking format... "
56
-	test -z "$$(goimports -l . | grep -v Godeps/_workspace/src/ | tee /dev/stderr)"
56
+	test -z "$$(gofmt -s -l . | grep -v Godeps/_workspace/src/ | tee /dev/stderr)"
57 57
 	@echo "Done checking format"
58 58
 
59 59
 run-tests:
... ...
@@ -61,6 +61,22 @@ func ParseConfig(tomlCfgFile string) (*Config, error) {
61 61
 	return cfg, nil
62 62
 }
63 63
 
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
+
64 80
 // Option is an option setter function type used to pass various configurations
65 81
 // to the controller
66 82
 type Option func(c *Config)
... ...
@@ -106,6 +106,9 @@ type NetworkController interface {
106 106
 
107 107
 	// Stop network controller
108 108
 	Stop()
109
+
110
+	// ReloadCondfiguration updates the controller configuration
111
+	ReloadConfiguration(cfgOptions ...config.Option) error
109 112
 }
110 113
 
111 114
 // NetworkWalker is a client provided function which will be used to walk the Networks.
... ...
@@ -129,7 +132,6 @@ type ipamData struct {
129 129
 }
130 130
 
131 131
 type driverTable map[string]*driverData
132
-
133 132
 type ipamTable map[string]*ipamData
134 133
 type sandboxTable map[string]*sandbox
135 134
 
... ...
@@ -153,22 +155,9 @@ type controller struct {
153 153
 
154 154
 // New creates a new instance of network controller.
155 155
 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
-
169 156
 	c := &controller{
170 157
 		id:          stringid.GenerateRandomID(),
171
-		cfg:         cfg,
158
+		cfg:         config.ParseConfigOptions(cfgOptions...),
172 159
 		sandboxes:   sandboxTable{},
173 160
 		drivers:     driverTable{},
174 161
 		ipamDrivers: ipamTable{},
... ...
@@ -179,8 +168,8 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
179 179
 		return nil, err
180 180
 	}
181 181
 
182
-	if cfg != nil && cfg.Cluster.Watcher != nil {
183
-		if err := c.initDiscovery(cfg.Cluster.Watcher); err != nil {
182
+	if c.cfg != nil && c.cfg.Cluster.Watcher != nil {
183
+		if err := c.initDiscovery(c.cfg.Cluster.Watcher); err != nil {
184 184
 			// Failing to initalize discovery is a bad situation to be in.
185 185
 			// But it cannot fail creating the Controller
186 186
 			log.Errorf("Failed to Initialize Discovery : %v", err)
... ...
@@ -206,6 +195,83 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
206 206
 	return c, nil
207 207
 }
208 208
 
209
+var procReloadConfig = make(chan (bool), 1)
210
+
211
+func (c *controller) ReloadConfiguration(cfgOptions ...config.Option) error {
212
+	procReloadConfig <- true
213
+	defer func() { <-procReloadConfig }()
214
+
215
+	// For now we accept the configuration reload only as a mean to provide a global store config after boot.
216
+	// Refuse the configuration if it alters an existing datastore client configuration.
217
+	update := false
218
+	cfg := config.ParseConfigOptions(cfgOptions...)
219
+	for s := range c.cfg.Scopes {
220
+		if _, ok := cfg.Scopes[s]; !ok {
221
+			return types.ForbiddenErrorf("cannot accept new configuration because it removes an existing datastore client")
222
+		}
223
+	}
224
+	for s, nSCfg := range cfg.Scopes {
225
+		if eSCfg, ok := c.cfg.Scopes[s]; ok {
226
+			if eSCfg.Client.Provider != nSCfg.Client.Provider ||
227
+				eSCfg.Client.Address != nSCfg.Client.Address {
228
+				return types.ForbiddenErrorf("cannot accept new configuration because it modifies an existing datastore client")
229
+			}
230
+		} else {
231
+			update = true
232
+		}
233
+	}
234
+	if !update {
235
+		return nil
236
+	}
237
+
238
+	c.Lock()
239
+	c.cfg = cfg
240
+	c.Unlock()
241
+
242
+	if err := c.initStores(); err != nil {
243
+		return err
244
+	}
245
+
246
+	if c.discovery == nil && c.cfg.Cluster.Watcher != nil {
247
+		if err := c.initDiscovery(c.cfg.Cluster.Watcher); err != nil {
248
+			log.Errorf("Failed to Initialize Discovery after configuration update: %v", err)
249
+		}
250
+	}
251
+
252
+	var dsConfig *discoverapi.DatastoreConfigData
253
+	for scope, sCfg := range cfg.Scopes {
254
+		if scope == datastore.LocalScope || !sCfg.IsValid() {
255
+			continue
256
+		}
257
+		dsConfig = &discoverapi.DatastoreConfigData{
258
+			Scope:    scope,
259
+			Provider: sCfg.Client.Provider,
260
+			Address:  sCfg.Client.Address,
261
+			Config:   sCfg.Client.Config,
262
+		}
263
+		break
264
+	}
265
+	if dsConfig == nil {
266
+		return nil
267
+	}
268
+
269
+	for nm, id := range c.getIpamDrivers() {
270
+		err := id.driver.DiscoverNew(discoverapi.DatastoreConfig, *dsConfig)
271
+		if err != nil {
272
+			log.Errorf("Failed to set datastore in driver %s: %v", nm, err)
273
+		}
274
+	}
275
+
276
+	for nm, id := range c.getNetDrivers() {
277
+		err := id.driver.DiscoverNew(discoverapi.DatastoreConfig, *dsConfig)
278
+		if err != nil {
279
+			log.Errorf("Failed to set datastore in driver %s: %v", nm, err)
280
+		}
281
+	}
282
+
283
+	return nil
284
+}
285
+
209 286
 func (c *controller) ID() string {
210 287
 	return c.id
211 288
 }
... ...
@@ -726,6 +792,26 @@ func (c *controller) getIpamDriver(name string) (ipamapi.Ipam, error) {
726 726
 	return id.driver, nil
727 727
 }
728 728
 
729
+func (c *controller) getIpamDrivers() ipamTable {
730
+	c.Lock()
731
+	defer c.Unlock()
732
+	table := ipamTable{}
733
+	for i, d := range c.ipamDrivers {
734
+		table[i] = d
735
+	}
736
+	return table
737
+}
738
+
739
+func (c *controller) getNetDrivers() driverTable {
740
+	c.Lock()
741
+	defer c.Unlock()
742
+	table := driverTable{}
743
+	for i, d := range c.drivers {
744
+		table[i] = d
745
+	}
746
+	return table
747
+}
748
+
729 749
 func (c *controller) Stop() {
730 750
 	c.closeStores()
731 751
 	c.stopExternalKeyListener()
... ...
@@ -13,6 +13,7 @@ import (
13 13
 	"github.com/docker/libkv/store/consul"
14 14
 	"github.com/docker/libkv/store/etcd"
15 15
 	"github.com/docker/libkv/store/zookeeper"
16
+	"github.com/docker/libnetwork/discoverapi"
16 17
 	"github.com/docker/libnetwork/types"
17 18
 )
18 19
 
... ...
@@ -253,6 +254,34 @@ func NewDataStore(scope string, cfg *ScopeCfg) (DataStore, error) {
253 253
 	return newClient(scope, cfg.Client.Provider, cfg.Client.Address, cfg.Client.Config, cached)
254 254
 }
255 255
 
256
+// NewDataStoreFromConfig creates a new instance of LibKV data store starting from the datastore config data
257
+func NewDataStoreFromConfig(dsc discoverapi.DatastoreConfigData) (DataStore, error) {
258
+	var (
259
+		ok    bool
260
+		sCfgP *store.Config
261
+	)
262
+
263
+	sCfgP, ok = dsc.Config.(*store.Config)
264
+	if !ok && dsc.Config != nil {
265
+		return nil, fmt.Errorf("cannot parse store configuration: %v", dsc.Config)
266
+	}
267
+
268
+	scopeCfg := &ScopeCfg{
269
+		Client: ScopeClientCfg{
270
+			Address:  dsc.Address,
271
+			Provider: dsc.Provider,
272
+			Config:   sCfgP,
273
+		},
274
+	}
275
+
276
+	ds, err := NewDataStore(dsc.Scope, scopeCfg)
277
+	if err != nil {
278
+		return nil, fmt.Errorf("failed to construct datastore client from datastore configuration %v: %v", dsc, err)
279
+	}
280
+
281
+	return ds, err
282
+}
283
+
256 284
 func (ds *datastore) Close() {
257 285
 	ds.store.Close()
258 286
 }
... ...
@@ -16,8 +16,8 @@ type DiscoveryType int
16 16
 const (
17 17
 	// NodeDiscovery represents Node join/leave events provided by discovery
18 18
 	NodeDiscovery = iota + 1
19
-	// DatastoreUpdate represents a add/remove datastore event
20
-	DatastoreUpdate
19
+	// DatastoreConfig represents a add/remove datastore event
20
+	DatastoreConfig
21 21
 )
22 22
 
23 23
 // NodeDiscoveryData represents the structure backing the node discovery data json string
... ...
@@ -26,8 +26,9 @@ type NodeDiscoveryData struct {
26 26
 	Self    bool
27 27
 }
28 28
 
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
31 32
 	Provider string
32 33
 	Address  string
33 34
 	Config   interface{}
... ...
@@ -3,11 +3,13 @@ package libnetwork
3 3
 import (
4 4
 	"strings"
5 5
 
6
+	"github.com/docker/libnetwork/discoverapi"
6 7
 	"github.com/docker/libnetwork/driverapi"
7 8
 	"github.com/docker/libnetwork/ipamapi"
9
+	"github.com/docker/libnetwork/netlabel"
10
+
8 11
 	builtinIpam "github.com/docker/libnetwork/ipams/builtin"
9 12
 	remoteIpam "github.com/docker/libnetwork/ipams/remote"
10
-	"github.com/docker/libnetwork/netlabel"
11 13
 )
12 14
 
13 15
 type initializer struct {
... ...
@@ -56,10 +58,12 @@ func makeDriverConfig(c *controller, ntype string) map[string]interface{} {
56 56
 		if !v.IsValid() {
57 57
 			continue
58 58
 		}
59
-
60
-		config[netlabel.MakeKVProvider(k)] = v.Client.Provider
61
-		config[netlabel.MakeKVProviderURL(k)] = v.Client.Address
62
-		config[netlabel.MakeKVProviderConfig(k)] = v.Client.Config
59
+		config[netlabel.MakeKVClient(k)] = discoverapi.DatastoreConfigData{
60
+			Scope:    k,
61
+			Provider: v.Client.Provider,
62
+			Address:  v.Client.Address,
63
+			Config:   v.Client.Config,
64
+		}
63 65
 	}
64 66
 
65 67
 	return config
... ...
@@ -133,6 +133,9 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
133 133
 	if out, err := exec.Command("modprobe", "-va", "nf_nat").CombinedOutput(); err != nil {
134 134
 		logrus.Warnf("Running modprobe nf_nat failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
135 135
 	}
136
+	if out, err := exec.Command("modprobe", "-va", "xt_conntrack").CombinedOutput(); err != nil {
137
+		logrus.Warnf("Running modprobe xt_conntrack failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
138
+	}
136 139
 	if err := iptables.FirewalldInit(); err != nil {
137 140
 		logrus.Debugf("Fail to initialize firewalld: %v, using raw iptables instead", err)
138 141
 	}
... ...
@@ -384,6 +387,8 @@ func (d *driver) configure(option map[string]interface{}) error {
384 384
 		if err != nil {
385 385
 			return err
386 386
 		}
387
+		// Make sure on firewall reload, first thing being re-played is chains creation
388
+		iptables.OnReloaded(func() { logrus.Debugf("Recreating iptables chains on firewall reload"); setupIPChains(config) })
387 389
 	}
388 390
 
389 391
 	d.Lock()
... ...
@@ -6,9 +6,9 @@ import (
6 6
 	"net"
7 7
 
8 8
 	"github.com/Sirupsen/logrus"
9
-	"github.com/docker/libkv/store"
10 9
 	"github.com/docker/libkv/store/boltdb"
11 10
 	"github.com/docker/libnetwork/datastore"
11
+	"github.com/docker/libnetwork/discoverapi"
12 12
 	"github.com/docker/libnetwork/netlabel"
13 13
 	"github.com/docker/libnetwork/types"
14 14
 )
... ...
@@ -16,27 +16,15 @@ import (
16 16
 const bridgePrefix = "bridge"
17 17
 
18 18
 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)
30 24
 		}
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)
38 26
 		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)
40 28
 		}
41 29
 
42 30
 		return d.populateNetworks()
... ...
@@ -6,12 +6,12 @@ import (
6 6
 	"sync"
7 7
 
8 8
 	"github.com/Sirupsen/logrus"
9
-	"github.com/docker/libkv/store"
10 9
 	"github.com/docker/libnetwork/datastore"
11 10
 	"github.com/docker/libnetwork/discoverapi"
12 11
 	"github.com/docker/libnetwork/driverapi"
13 12
 	"github.com/docker/libnetwork/idm"
14 13
 	"github.com/docker/libnetwork/netlabel"
14
+	"github.com/docker/libnetwork/types"
15 15
 	"github.com/hashicorp/serf/serf"
16 16
 )
17 17
 
... ...
@@ -25,6 +25,8 @@ const (
25 25
 	vxlanVethMTU = 1450
26 26
 )
27 27
 
28
+var initVxlanIdm = make(chan (bool), 1)
29
+
28 30
 type driver struct {
29 31
 	eventCh      chan serf.Event
30 32
 	notifyCh     chan ovNotify
... ...
@@ -56,6 +58,18 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
56 56
 		config: config,
57 57
 	}
58 58
 
59
+	if data, ok := config[netlabel.GlobalKVClient]; ok {
60
+		var err error
61
+		dsc, ok := data.(discoverapi.DatastoreConfigData)
62
+		if !ok {
63
+			return types.InternalErrorf("incorrect data in datastore configuration: %v", data)
64
+		}
65
+		d.store, err = datastore.NewDataStoreFromConfig(dsc)
66
+		if err != nil {
67
+			return types.InternalErrorf("failed to initialize data store: %v", err)
68
+		}
69
+	}
70
+
59 71
 	return dc.RegisterDriver(networkType, d, c)
60 72
 }
61 73
 
... ...
@@ -73,42 +87,33 @@ func Fini(drv driverapi.Driver) {
73 73
 }
74 74
 
75 75
 func (d *driver) configure() error {
76
-	var err error
76
+	if d.store == nil {
77
+		return types.NoServiceErrorf("datastore is not available")
78
+	}
77 79
 
78
-	if len(d.config) == 0 {
79
-		return nil
80
+	if d.vxlanIdm == nil {
81
+		return d.initializeVxlanIdm()
80 82
 	}
81 83
 
82
-	d.once.Do(func() {
83
-		provider, provOk := d.config[netlabel.GlobalKVProvider]
84
-		provURL, urlOk := d.config[netlabel.GlobalKVProviderURL]
84
+	return nil
85
+}
85 86
 
86
-		if provOk && urlOk {
87
-			cfg := &datastore.ScopeCfg{
88
-				Client: datastore.ScopeClientCfg{
89
-					Provider: provider.(string),
90
-					Address:  provURL.(string),
91
-				},
92
-			}
93
-			provConfig, confOk := d.config[netlabel.GlobalKVProviderConfig]
94
-			if confOk {
95
-				cfg.Client.Config = provConfig.(*store.Config)
96
-			}
97
-			d.store, err = datastore.NewDataStore(datastore.GlobalScope, cfg)
98
-			if err != nil {
99
-				err = fmt.Errorf("failed to initialize data store: %v", err)
100
-				return
101
-			}
102
-		}
87
+func (d *driver) initializeVxlanIdm() error {
88
+	var err error
103 89
 
104
-		d.vxlanIdm, err = idm.New(d.store, "vxlan-id", vxlanIDStart, vxlanIDEnd)
105
-		if err != nil {
106
-			err = fmt.Errorf("failed to initialize vxlan id manager: %v", err)
107
-			return
108
-		}
109
-	})
90
+	initVxlanIdm <- true
91
+	defer func() { <-initVxlanIdm }()
92
+
93
+	if d.vxlanIdm != nil {
94
+		return nil
95
+	}
96
+
97
+	d.vxlanIdm, err = idm.New(d.store, "vxlan-id", vxlanIDStart, vxlanIDEnd)
98
+	if err != nil {
99
+		return fmt.Errorf("failed to initialize vxlan id manager: %v", err)
100
+	}
110 101
 
111
-	return err
102
+	return nil
112 103
 }
113 104
 
114 105
 func (d *driver) Type() string {
... ...
@@ -187,12 +192,27 @@ func (d *driver) pushLocalEndpointEvent(action, nid, eid string) {
187 187
 
188 188
 // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
189 189
 func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
190
-	if dType == discoverapi.NodeDiscovery {
190
+	switch dType {
191
+	case discoverapi.NodeDiscovery:
191 192
 		nodeData, ok := data.(discoverapi.NodeDiscoveryData)
192 193
 		if !ok || nodeData.Address == "" {
193 194
 			return fmt.Errorf("invalid discovery data")
194 195
 		}
195 196
 		d.nodeJoin(nodeData.Address, nodeData.Self)
197
+	case discoverapi.DatastoreConfig:
198
+		var err error
199
+		if d.store != nil {
200
+			return types.ForbiddenErrorf("cannot accept datastore configuration: Overlay driver has a datastore configured already")
201
+		}
202
+		dsc, ok := data.(discoverapi.DatastoreConfigData)
203
+		if !ok {
204
+			return types.InternalErrorf("incorrect data in datastore configuration: %v", data)
205
+		}
206
+		d.store, err = datastore.NewDataStoreFromConfig(dsc)
207
+		if err != nil {
208
+			return types.InternalErrorf("failed to initialize data store: %v", err)
209
+		}
210
+	default:
196 211
 	}
197 212
 	return nil
198 213
 }
199 214
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+package windows
1
+
2
+const (
3
+	// NetworkName label for bridge driver
4
+	NetworkName = "com.docker.network.windowsshim.networkname"
5
+
6
+	// HNSID of the discovered network
7
+	HNSID = "com.docker.network.windowsshim.hnsid"
8
+
9
+	// RoutingDomain of the network
10
+	RoutingDomain = "com.docker.network.windowsshim.routingdomain"
11
+)
... ...
@@ -1,57 +1,419 @@
1
+// +build windows
2
+
3
+// Shim for the Host Network Service (HNS) to manage networking for
4
+// Windows Server containers and Hyper-V containers. This module
5
+// is a basic libnetwork driver that passes all the calls to HNS
6
+// It implements the 4 networking modes supported by HNS L2Bridge,
7
+// L2Tunnel, NAT and Transparent(DHCP)
8
+//
9
+// The network are stored in memory and docker daemon ensures discovering
10
+// and loading these networks on startup
11
+
1 12
 package windows
2 13
 
3 14
 import (
15
+	"encoding/json"
16
+	"fmt"
17
+	"net"
18
+	"strings"
19
+	"sync"
20
+
21
+	"github.com/Microsoft/hcsshim"
22
+	log "github.com/Sirupsen/logrus"
4 23
 	"github.com/docker/libnetwork/datastore"
5 24
 	"github.com/docker/libnetwork/discoverapi"
6 25
 	"github.com/docker/libnetwork/driverapi"
26
+	"github.com/docker/libnetwork/netlabel"
27
+	"github.com/docker/libnetwork/types"
7 28
 )
8 29
 
9
-const networkType = "windows"
30
+// networkConfiguration for network specific configuration
31
+type networkConfiguration struct {
32
+	ID    string
33
+	Type  string
34
+	Name  string
35
+	HnsID string
36
+	RDID  string
37
+}
38
+
39
+type hnsEndpoint struct {
40
+	id         string
41
+	profileID  string
42
+	macAddress net.HardwareAddr
43
+	addr       *net.IPNet
44
+}
45
+
46
+type hnsNetwork struct {
47
+	id        string
48
+	config    *networkConfiguration
49
+	endpoints map[string]*hnsEndpoint // key: endpoint id
50
+	driver    *driver                 // The network's driver
51
+	sync.Mutex
52
+}
53
+
54
+type driver struct {
55
+	name     string
56
+	networks map[string]*hnsNetwork
57
+	sync.Mutex
58
+}
59
+
60
+func isValidNetworkType(networkType string) bool {
61
+	if "L2Bridge" == networkType || "L2Tunnel" == networkType || "NAT" == networkType || "Transparent" == networkType {
62
+		return true
63
+	}
64
+
65
+	return false
66
+}
67
+
68
+// New constructs a new bridge driver
69
+func newDriver(networkType string) *driver {
70
+	return &driver{name: networkType, networks: map[string]*hnsNetwork{}}
71
+}
72
+
73
+// GetInit returns an initializer for the given network type
74
+func GetInit(networkType string) func(dc driverapi.DriverCallback, config map[string]interface{}) error {
75
+	return func(dc driverapi.DriverCallback, config map[string]interface{}) error {
76
+		if !isValidNetworkType(networkType) {
77
+			return types.BadRequestErrorf("Network type not supported: %s", networkType)
78
+		}
79
+
80
+		return dc.RegisterDriver(networkType, newDriver(networkType), driverapi.Capability{
81
+			DataScope: datastore.LocalScope,
82
+		})
83
+	}
84
+}
85
+
86
+func (d *driver) getNetwork(id string) (*hnsNetwork, error) {
87
+	d.Lock()
88
+	defer d.Unlock()
89
+
90
+	if nw, ok := d.networks[id]; ok {
91
+		return nw, nil
92
+	}
93
+
94
+	return nil, types.NotFoundErrorf("network not found: %s", id)
95
+}
96
+
97
+func (n *hnsNetwork) getEndpoint(eid string) (*hnsEndpoint, error) {
98
+	n.Lock()
99
+	defer n.Unlock()
100
+
101
+	if ep, ok := n.endpoints[eid]; ok {
102
+		return ep, nil
103
+	}
104
+
105
+	return nil, types.NotFoundErrorf("Endpoint not found: %s", eid)
106
+}
107
+
108
+func (d *driver) parseNetworkOptions(id string, genericOptions map[string]string) (*networkConfiguration, error) {
109
+	config := &networkConfiguration{}
10 110
 
11
-// TODO Windows. This is a placeholder for now
111
+	for label, value := range genericOptions {
112
+		switch label {
113
+		case NetworkName:
114
+			config.Name = value
115
+		case HNSID:
116
+			config.HnsID = value
117
+		case RoutingDomain:
118
+			config.RDID = value
119
+		}
120
+	}
12 121
 
13
-type driver struct{}
122
+	config.ID = id
123
+	config.Type = d.name
124
+	return config, nil
125
+}
126
+
127
+func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error {
128
+	if len(ipamV6Data) > 0 {
129
+		return types.ForbiddenErrorf("windowsshim driver doesnt support v6 subnets")
130
+	}
14 131
 
15
-// Init registers a new instance of null driver
16
-func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
17
-	c := driverapi.Capability{
18
-		DataScope: datastore.LocalScope,
132
+	if len(ipamV4Data) == 0 {
133
+		return types.BadRequestErrorf("network %s requires ipv4 configuration", id)
19 134
 	}
20
-	return dc.RegisterDriver(networkType, &driver{}, c)
135
+
136
+	return nil
21 137
 }
22 138
 
139
+// Create a new network
23 140
 func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
141
+	if _, err := d.getNetwork(id); err == nil {
142
+		return types.ForbiddenErrorf("network %s exists", id)
143
+	}
144
+
145
+	genData, ok := option[netlabel.GenericData].(map[string]string)
146
+	if !ok {
147
+		return fmt.Errorf("Unknown generic data option")
148
+	}
149
+
150
+	// Parse and validate the config. It should not conflict with existing networks' config
151
+	config, err := d.parseNetworkOptions(id, genData)
152
+	if err != nil {
153
+		return err
154
+	}
155
+
156
+	err = config.processIPAM(id, ipV4Data, ipV6Data)
157
+	if err != nil {
158
+		return err
159
+	}
160
+
161
+	network := &hnsNetwork{
162
+		id:        config.ID,
163
+		endpoints: make(map[string]*hnsEndpoint),
164
+		config:    config,
165
+		driver:    d,
166
+	}
167
+
168
+	d.Lock()
169
+	d.networks[config.ID] = network
170
+	d.Unlock()
171
+
172
+	// A non blank hnsid indicates that the network was discovered
173
+	// from HNS. No need to call HNS if this network was discovered
174
+	// from HNS
175
+	if config.HnsID == "" {
176
+		subnets := []hcsshim.Subnet{}
177
+
178
+		for _, ipData := range ipV4Data {
179
+			subnet := hcsshim.Subnet{
180
+				AddressPrefix:  ipData.Pool.String(),
181
+				GatewayAddress: ipData.Gateway.IP.String(),
182
+			}
183
+
184
+			subnets = append(subnets, subnet)
185
+		}
186
+
187
+		network := &hcsshim.HNSNetwork{
188
+			Name:    config.Name,
189
+			Type:    d.name,
190
+			Subnets: subnets,
191
+		}
192
+
193
+		if network.Name == "" {
194
+			network.Name = id
195
+		}
196
+
197
+		configurationb, err := json.Marshal(network)
198
+		if err != nil {
199
+			return err
200
+		}
201
+
202
+		configuration := string(configurationb)
203
+		log.Debugf("HNSNetwork Request =%v Address Space=%v", configuration, subnets)
204
+
205
+		hnsresponse, err := hcsshim.HNSNetworkRequest("POST", "", configuration)
206
+		if err != nil {
207
+			return err
208
+		}
209
+
210
+		config.HnsID = hnsresponse.Id
211
+		genData[HNSID] = config.HnsID
212
+	}
213
+
24 214
 	return nil
25 215
 }
26 216
 
27 217
 func (d *driver) DeleteNetwork(nid string) error {
218
+	n, err := d.getNetwork(nid)
219
+	if err != nil {
220
+		return types.InternalMaskableErrorf("%s", err)
221
+	}
222
+
223
+	n.Lock()
224
+	config := n.config
225
+	n.Unlock()
226
+
227
+	// Cannot remove network if endpoints are still present
228
+	if len(n.endpoints) != 0 {
229
+		return fmt.Errorf("network %s has active endpoint", n.id)
230
+	}
231
+
232
+	_, err = hcsshim.HNSNetworkRequest("DELETE", config.HnsID, "")
233
+	if err != nil {
234
+		return err
235
+	}
236
+
237
+	d.Lock()
238
+	delete(d.networks, nid)
239
+	d.Unlock()
240
+
28 241
 	return nil
29 242
 }
30 243
 
244
+func convertPortBindings(portBindings []types.PortBinding) ([]json.RawMessage, error) {
245
+	var pbs []json.RawMessage
246
+
247
+	// Enumerate through the port bindings specified by the user and convert
248
+	// them into the internal structure matching the JSON blob that can be
249
+	// understood by the HCS.
250
+	for _, elem := range portBindings {
251
+		proto := strings.ToUpper(elem.Proto.String())
252
+		if proto != "TCP" && proto != "UDP" {
253
+			return nil, fmt.Errorf("invalid protocol %s", elem.Proto.String())
254
+		}
255
+
256
+		if elem.HostPort != elem.HostPortEnd {
257
+			return nil, fmt.Errorf("Windows does not support more than one host port in NAT settings")
258
+		}
259
+
260
+		if len(elem.HostIP) != 0 {
261
+			return nil, fmt.Errorf("Windows does not support host IP addresses in NAT settings")
262
+		}
263
+
264
+		encodedPolicy, err := json.Marshal(hcsshim.NatPolicy{
265
+			Type:         "NAT",
266
+			ExternalPort: elem.HostPort,
267
+			InternalPort: elem.Port,
268
+			Protocol:     elem.Proto.String(),
269
+		})
270
+
271
+		if err != nil {
272
+			return nil, err
273
+		}
274
+		pbs = append(pbs, encodedPolicy)
275
+	}
276
+	return pbs, nil
277
+}
278
+
31 279
 func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
280
+	n, err := d.getNetwork(nid)
281
+	if err != nil {
282
+		return err
283
+	}
284
+
285
+	// Check if endpoint id is good and retrieve corresponding endpoint
286
+	ep, err := n.getEndpoint(eid)
287
+	if err == nil && ep != nil {
288
+		return driverapi.ErrEndpointExists(eid)
289
+	}
290
+
291
+	endpointStruct := &hcsshim.HNSEndpoint{
292
+		VirtualNetwork: n.config.HnsID,
293
+	}
294
+
295
+	// Convert the port mapping for the network
296
+	if opt, ok := epOptions[netlabel.PortMap]; ok {
297
+		if bs, ok := opt.([]types.PortBinding); ok {
298
+			endpointStruct.Policies, err = convertPortBindings(bs)
299
+			if err != nil {
300
+				return err
301
+			}
302
+		} else {
303
+			return fmt.Errorf("Invalid endpoint configuration for endpoint id%s", eid)
304
+		}
305
+	}
306
+
307
+	configurationb, err := json.Marshal(endpointStruct)
308
+	if err != nil {
309
+		return err
310
+	}
311
+
312
+	hnsresponse, err := hcsshim.HNSEndpointRequest("POST", "", string(configurationb))
313
+	if err != nil {
314
+		return err
315
+	}
316
+
317
+	mac, err := net.ParseMAC(hnsresponse.MacAddress)
318
+	if err != nil {
319
+		return err
320
+	}
321
+
322
+	// TODO For now the ip mask is not in the info generated by HNS
323
+	endpoint := &hnsEndpoint{
324
+		id:         eid,
325
+		addr:       &net.IPNet{IP: hnsresponse.IPAddress, Mask: hnsresponse.IPAddress.DefaultMask()},
326
+		macAddress: mac,
327
+	}
328
+	endpoint.profileID = hnsresponse.Id
329
+	n.Lock()
330
+	n.endpoints[eid] = endpoint
331
+	n.Unlock()
332
+
333
+	ifInfo.SetIPAddress(endpoint.addr)
334
+	ifInfo.SetMacAddress(endpoint.macAddress)
335
+
32 336
 	return nil
33 337
 }
34 338
 
35 339
 func (d *driver) DeleteEndpoint(nid, eid string) error {
340
+	n, err := d.getNetwork(nid)
341
+	if err != nil {
342
+		return types.InternalMaskableErrorf("%s", err)
343
+	}
344
+
345
+	ep, err := n.getEndpoint(eid)
346
+	if err != nil {
347
+		return err
348
+	}
349
+
350
+	n.Lock()
351
+	delete(n.endpoints, eid)
352
+	n.Unlock()
353
+
354
+	_, err = hcsshim.HNSEndpointRequest("DELETE", ep.profileID, "")
355
+	if err != nil {
356
+		return err
357
+	}
358
+
36 359
 	return nil
37 360
 }
38 361
 
39 362
 func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
40
-	return make(map[string]interface{}, 0), nil
363
+	network, err := d.getNetwork(nid)
364
+	if err != nil {
365
+		return nil, err
366
+	}
367
+
368
+	endpoint, err := network.getEndpoint(eid)
369
+	if err != nil {
370
+		return nil, err
371
+	}
372
+
373
+	data := make(map[string]interface{}, 1)
374
+	data["hnsid"] = endpoint.profileID
375
+	return data, nil
41 376
 }
42 377
 
43 378
 // Join method is invoked when a Sandbox is attached to an endpoint.
44 379
 func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
380
+	network, err := d.getNetwork(nid)
381
+	if err != nil {
382
+		return err
383
+	}
384
+
385
+	// Ensure that the endpoint exists
386
+	_, err = network.getEndpoint(eid)
387
+	if err != nil {
388
+		return err
389
+	}
390
+
391
+	// This is just a stub for now
392
+
393
+	jinfo.DisableGatewayService()
45 394
 	return nil
46 395
 }
47 396
 
48 397
 // Leave method is invoked when a Sandbox detaches from an endpoint.
49 398
 func (d *driver) Leave(nid, eid string) error {
399
+	network, err := d.getNetwork(nid)
400
+	if err != nil {
401
+		return types.InternalMaskableErrorf("%s", err)
402
+	}
403
+
404
+	// Ensure that the endpoint exists
405
+	_, err = network.getEndpoint(eid)
406
+	if err != nil {
407
+		return err
408
+	}
409
+
410
+	// This is just a stub for now
411
+
50 412
 	return nil
51 413
 }
52 414
 
53 415
 func (d *driver) Type() string {
54
-	return networkType
416
+	return d.name
55 417
 }
56 418
 
57 419
 // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
... ...
@@ -1,9 +1,16 @@
1 1
 package libnetwork
2 2
 
3
-import "github.com/docker/libnetwork/drivers/windows"
3
+import (
4
+	"github.com/docker/libnetwork/drivers/null"
5
+	"github.com/docker/libnetwork/drivers/windows"
6
+)
4 7
 
5 8
 func getInitializers() []initializer {
6 9
 	return []initializer{
7
-		{windows.Init, "windows"},
10
+		{null.Init, "null"},
11
+		{windows.GetInit("Transparent"), "Transparent"},
12
+		{windows.GetInit("L2Bridge"), "L2Bridge"},
13
+		{windows.GetInit("L2Tunnel"), "L2Tunnel"},
14
+		{windows.GetInit("NAT"), "NAT"},
8 15
 	}
9 16
 }
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	log "github.com/Sirupsen/logrus"
9 9
 	"github.com/docker/libnetwork/bitseq"
10 10
 	"github.com/docker/libnetwork/datastore"
11
+	"github.com/docker/libnetwork/discoverapi"
11 12
 	"github.com/docker/libnetwork/ipamapi"
12 13
 	"github.com/docker/libnetwork/ipamutils"
13 14
 	"github.com/docker/libnetwork/types"
... ...
@@ -60,19 +61,9 @@ func NewAllocator(lcDs, glDs datastore.DataStore) (*Allocator, error) {
60 60
 		if aspc.ds == nil {
61 61
 			continue
62 62
 		}
63
-
64
-		a.addrSpaces[aspc.as] = &addrSpace{
65
-			subnets: map[SubnetKey]*PoolData{},
66
-			id:      dsConfigKey + "/" + aspc.as,
67
-			scope:   aspc.ds.Scope(),
68
-			ds:      aspc.ds,
69
-			alloc:   a,
70
-		}
63
+		a.initializeAddressSpace(aspc.as, aspc.ds)
71 64
 	}
72 65
 
73
-	a.checkConsistency(localAddressSpace)
74
-	a.checkConsistency(globalAddressSpace)
75
-
76 66
 	return a, nil
77 67
 }
78 68
 
... ...
@@ -118,25 +109,83 @@ func (a *Allocator) updateBitMasks(aSpace *addrSpace) error {
118 118
 	return nil
119 119
 }
120 120
 
121
-// Checks for and fixes damaged bitmask. Meant to be called in constructor only.
121
+// Checks for and fixes damaged bitmask.
122 122
 func (a *Allocator) checkConsistency(as string) {
123
+	var sKeyList []SubnetKey
124
+
123 125
 	// Retrieve this address space's configuration and bitmasks from the datastore
124 126
 	a.refresh(as)
127
+	a.Lock()
125 128
 	aSpace, ok := a.addrSpaces[as]
129
+	a.Unlock()
126 130
 	if !ok {
127 131
 		return
128 132
 	}
129 133
 	a.updateBitMasks(aSpace)
134
+
135
+	aSpace.Lock()
130 136
 	for sk, pd := range aSpace.subnets {
131 137
 		if pd.Range != nil {
132 138
 			continue
133 139
 		}
134
-		if err := a.addresses[sk].CheckConsistency(); err != nil {
140
+		sKeyList = append(sKeyList, sk)
141
+	}
142
+	aSpace.Unlock()
143
+
144
+	for _, sk := range sKeyList {
145
+		a.Lock()
146
+		bm := a.addresses[sk]
147
+		a.Unlock()
148
+		if err := bm.CheckConsistency(); err != nil {
135 149
 			log.Warnf("Error while running consistency check for %s: %v", sk, err)
136 150
 		}
137 151
 	}
138 152
 }
139 153
 
154
+func (a *Allocator) initializeAddressSpace(as string, ds datastore.DataStore) error {
155
+	a.Lock()
156
+	if _, ok := a.addrSpaces[as]; ok {
157
+		a.Unlock()
158
+		return types.ForbiddenErrorf("tried to add an axisting address space: %s", as)
159
+	}
160
+	a.addrSpaces[as] = &addrSpace{
161
+		subnets: map[SubnetKey]*PoolData{},
162
+		id:      dsConfigKey + "/" + as,
163
+		scope:   ds.Scope(),
164
+		ds:      ds,
165
+		alloc:   a,
166
+	}
167
+	a.Unlock()
168
+
169
+	a.checkConsistency(as)
170
+
171
+	return nil
172
+}
173
+
174
+// DiscoverNew informs the allocator about a new global scope datastore
175
+func (a *Allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
176
+	if dType != discoverapi.DatastoreConfig {
177
+		return nil
178
+	}
179
+
180
+	dsc, ok := data.(discoverapi.DatastoreConfigData)
181
+	if !ok {
182
+		return types.InternalErrorf("incorrect data in datastore update notification: %v", data)
183
+	}
184
+
185
+	ds, err := datastore.NewDataStoreFromConfig(dsc)
186
+	if err != nil {
187
+		return err
188
+	}
189
+
190
+	return a.initializeAddressSpace(globalAddressSpace, ds)
191
+}
192
+
193
+// DiscoverDelete is a notification of no interest for the allocator
194
+func (a *Allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
195
+	return nil
196
+}
197
+
140 198
 // GetDefaultAddressSpaces returns the local and global default address spaces
141 199
 func (a *Allocator) GetDefaultAddressSpaces() (string, string, error) {
142 200
 	return localAddressSpace, globalAddressSpace, nil
... ...
@@ -4,6 +4,7 @@ package ipamapi
4 4
 import (
5 5
 	"net"
6 6
 
7
+	"github.com/docker/libnetwork/discoverapi"
7 8
 	"github.com/docker/libnetwork/types"
8 9
 )
9 10
 
... ...
@@ -56,6 +57,8 @@ var (
56 56
 // Ipam represents the interface the IPAM service plugins must implement
57 57
 // in order to allow injection/modification of IPAM database.
58 58
 type Ipam interface {
59
+	discoverapi.Discover
60
+
59 61
 	// GetDefaultAddressSpaces returns the default local and global address spaces for this ipam
60 62
 	GetDefaultAddressSpaces() (string, string, error)
61 63
 	// RequestPool returns an address pool along with its unique id. Address space is a mandatory field
62 64
deleted file mode 100644
... ...
@@ -1,35 +0,0 @@
1
-package builtin
2
-
3
-import (
4
-	"fmt"
5
-
6
-	"github.com/docker/libnetwork/datastore"
7
-	"github.com/docker/libnetwork/ipam"
8
-	"github.com/docker/libnetwork/ipamapi"
9
-)
10
-
11
-// Init registers the built-in ipam service with libnetwork
12
-func Init(ic ipamapi.Callback, l, g interface{}) error {
13
-	var (
14
-		ok                bool
15
-		localDs, globalDs datastore.DataStore
16
-	)
17
-
18
-	if l != nil {
19
-		if localDs, ok = l.(datastore.DataStore); !ok {
20
-			return fmt.Errorf("incorrect local datastore passed to built-in ipam init")
21
-		}
22
-	}
23
-
24
-	if g != nil {
25
-		if globalDs, ok = g.(datastore.DataStore); !ok {
26
-			return fmt.Errorf("incorrect global datastore passed to built-in ipam init")
27
-		}
28
-	}
29
-	a, err := ipam.NewAllocator(localDs, globalDs)
30
-	if err != nil {
31
-		return err
32
-	}
33
-
34
-	return ic.RegisterIpamDriver(ipamapi.DefaultIPAM, a)
35
-}
36 1
new file mode 100644
... ...
@@ -0,0 +1,37 @@
0
+// +build linux freebsd
1
+
2
+package builtin
3
+
4
+import (
5
+	"fmt"
6
+
7
+	"github.com/docker/libnetwork/datastore"
8
+	"github.com/docker/libnetwork/ipam"
9
+	"github.com/docker/libnetwork/ipamapi"
10
+)
11
+
12
+// Init registers the built-in ipam service with libnetwork
13
+func Init(ic ipamapi.Callback, l, g interface{}) error {
14
+	var (
15
+		ok                bool
16
+		localDs, globalDs datastore.DataStore
17
+	)
18
+
19
+	if l != nil {
20
+		if localDs, ok = l.(datastore.DataStore); !ok {
21
+			return fmt.Errorf("incorrect local datastore passed to built-in ipam init")
22
+		}
23
+	}
24
+
25
+	if g != nil {
26
+		if globalDs, ok = g.(datastore.DataStore); !ok {
27
+			return fmt.Errorf("incorrect global datastore passed to built-in ipam init")
28
+		}
29
+	}
30
+	a, err := ipam.NewAllocator(localDs, globalDs)
31
+	if err != nil {
32
+		return err
33
+	}
34
+
35
+	return ic.RegisterIpamDriver(ipamapi.DefaultIPAM, a)
36
+}
0 37
new file mode 100644
... ...
@@ -0,0 +1,16 @@
0
+// +build windows
1
+
2
+package builtin
3
+
4
+import (
5
+	"github.com/docker/libnetwork/ipamapi"
6
+
7
+	windowsipam "github.com/docker/libnetwork/ipams/windowsipam"
8
+)
9
+
10
+// Init registers the built-in ipam service with libnetwork
11
+func Init(ic ipamapi.Callback, l, g interface{}) error {
12
+	initFunc := windowsipam.GetInit(ipamapi.DefaultIPAM)
13
+
14
+	return initFunc(ic, l, g)
15
+}
... ...
@@ -6,6 +6,7 @@ import (
6 6
 
7 7
 	log "github.com/Sirupsen/logrus"
8 8
 	"github.com/docker/docker/pkg/plugins"
9
+	"github.com/docker/libnetwork/discoverapi"
9 10
 	"github.com/docker/libnetwork/ipamapi"
10 11
 	"github.com/docker/libnetwork/ipams/remote/api"
11 12
 	"github.com/docker/libnetwork/types"
... ...
@@ -124,3 +125,13 @@ func (a *allocator) ReleaseAddress(poolID string, address net.IP) error {
124 124
 	res := &api.ReleaseAddressResponse{}
125 125
 	return a.call("ReleaseAddress", req, res)
126 126
 }
127
+
128
+// DiscoverNew is a notification for a new discovery event, such as a new global datastore
129
+func (a *allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
130
+	return nil
131
+}
132
+
133
+// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
134
+func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
135
+	return nil
136
+}
127 137
new file mode 100644
... ...
@@ -0,0 +1,93 @@
0
+package windowsipam
1
+
2
+import (
3
+	"net"
4
+
5
+	log "github.com/Sirupsen/logrus"
6
+	"github.com/docker/libnetwork/discoverapi"
7
+	"github.com/docker/libnetwork/ipamapi"
8
+	"github.com/docker/libnetwork/types"
9
+)
10
+
11
+const (
12
+	localAddressSpace  = "LocalDefault"
13
+	globalAddressSpace = "GlobalDefault"
14
+)
15
+
16
+var (
17
+	defaultPool, _ = types.ParseCIDR("0.0.0.0/0")
18
+)
19
+
20
+type allocator struct {
21
+}
22
+
23
+// GetInit registers the built-in ipam service with libnetwork
24
+func GetInit(ipamName string) func(ic ipamapi.Callback, l, g interface{}) error {
25
+	return func(ic ipamapi.Callback, l, g interface{}) error {
26
+		return ic.RegisterIpamDriver(ipamName, &allocator{})
27
+	}
28
+}
29
+
30
+func (a *allocator) GetDefaultAddressSpaces() (string, string, error) {
31
+	return localAddressSpace, globalAddressSpace, nil
32
+}
33
+
34
+// RequestPool returns an address pool along with its unique id. This is a null ipam driver. It allocates the
35
+// subnet user asked and does not validate anything. Doesnt support subpool allocation
36
+func (a *allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
37
+	log.Debugf("RequestPool(%s, %s, %s, %v, %t)", addressSpace, pool, subPool, options, v6)
38
+	if subPool != "" || v6 {
39
+		return "", nil, nil, types.InternalErrorf("This request is not supported by null ipam driver")
40
+	}
41
+
42
+	var ipNet *net.IPNet
43
+	var err error
44
+
45
+	if pool != "" {
46
+		_, ipNet, err = net.ParseCIDR(pool)
47
+		if err != nil {
48
+			return "", nil, nil, err
49
+		}
50
+	} else {
51
+		ipNet = defaultPool
52
+	}
53
+
54
+	return ipNet.String(), ipNet, nil, nil
55
+}
56
+
57
+// ReleasePool releases the address pool - always succeeds
58
+func (a *allocator) ReleasePool(poolID string) error {
59
+	log.Debugf("ReleasePool(%s)", poolID)
60
+	return nil
61
+}
62
+
63
+// RequestAddress returns an address from the specified pool ID.
64
+// Always allocate the 0.0.0.0/32 ip if no preferred address was specified
65
+func (a *allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[string]string) (*net.IPNet, map[string]string, error) {
66
+	log.Debugf("RequestAddress(%s, %v, %v) %s", poolID, prefAddress, opts, opts["RequestAddressType"])
67
+	_, ipNet, err := net.ParseCIDR(poolID)
68
+
69
+	if err != nil {
70
+		return nil, nil, err
71
+	}
72
+	if prefAddress == nil {
73
+		return ipNet, nil, nil
74
+	}
75
+	return &net.IPNet{IP: prefAddress, Mask: ipNet.Mask}, nil, nil
76
+}
77
+
78
+// ReleaseAddress releases the address - always succeeds
79
+func (a *allocator) ReleaseAddress(poolID string, address net.IP) error {
80
+	log.Debugf("ReleaseAddress(%s, %v)", poolID, address)
81
+	return nil
82
+}
83
+
84
+// DiscoverNew informs the allocator about a new global scope datastore
85
+func (a *allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
86
+	return nil
87
+}
88
+
89
+// DiscoverDelete is a notification of no interest for the allocator
90
+func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
91
+	return nil
92
+}
... ...
@@ -56,6 +56,9 @@ var (
56 56
 	// GlobalKVProviderConfig constant represents the KV provider Config
57 57
 	GlobalKVProviderConfig = MakeKVProviderConfig("global")
58 58
 
59
+	// GlobalKVClient constants represents the global kv store client
60
+	GlobalKVClient = MakeKVClient("global")
61
+
59 62
 	// LocalKVProvider constant represents the KV provider backend
60 63
 	LocalKVProvider = MakeKVProvider("local")
61 64
 
... ...
@@ -64,6 +67,9 @@ var (
64 64
 
65 65
 	// LocalKVProviderConfig constant represents the KV provider Config
66 66
 	LocalKVProviderConfig = MakeKVProviderConfig("local")
67
+
68
+	// LocalKVClient constants represents the local kv store client
69
+	LocalKVClient = MakeKVClient("local")
67 70
 )
68 71
 
69 72
 // MakeKVProvider returns the kvprovider label for the scope
... ...
@@ -81,6 +87,11 @@ func MakeKVProviderConfig(scope string) string {
81 81
 	return DriverPrivatePrefix + scope + "kv_provider_config"
82 82
 }
83 83
 
84
+// MakeKVClient returns the kv client label for the scope
85
+func MakeKVClient(scope string) string {
86
+	return DriverPrivatePrefix + scope + "kv_client"
87
+}
88
+
84 89
 // Key extracts the key portion of the label
85 90
 func Key(label string) (key string) {
86 91
 	if kv := strings.SplitN(label, "=", 2); len(kv) > 0 {
... ...
@@ -1004,7 +1004,7 @@ func (n *network) ipamAllocateVersion(ipVer int, ipam ipamapi.Ipam) error {
1004 1004
 		if ipVer == 6 {
1005 1005
 			return nil
1006 1006
 		}
1007
-		*cfgList = []*IpamConf{&IpamConf{}}
1007
+		*cfgList = []*IpamConf{{}}
1008 1008
 	}
1009 1009
 
1010 1010
 	*infoList = make([]*IpamInfo, len(*cfgList))
... ...
@@ -85,7 +85,7 @@ func handleStopSignals(p proxy.Proxy) {
85 85
 	s := make(chan os.Signal, 10)
86 86
 	signal.Notify(s, os.Interrupt, syscall.SIGTERM, syscall.SIGSTOP)
87 87
 
88
-	for _ = range s {
88
+	for range s {
89 89
 		p.Close()
90 90
 
91 91
 		os.Exit(0)
... ...
@@ -35,7 +35,7 @@ const (
35 35
 	dnsPort       = "53"
36 36
 	ptrIPv4domain = ".in-addr.arpa."
37 37
 	ptrIPv6domain = ".ip6.arpa."
38
-	respTTL       = 1800
38
+	respTTL       = 600
39 39
 	maxExtDNS     = 3 //max number of external servers to try
40 40
 )
41 41
 
... ...
@@ -147,6 +147,10 @@ func (r *resolver) ResolverOptions() []string {
147 147
 	return []string{"ndots:0"}
148 148
 }
149 149
 
150
+func setCommonFlags(msg *dns.Msg) {
151
+	msg.RecursionAvailable = true
152
+}
153
+
150 154
 func (r *resolver) handleIPv4Query(name string, query *dns.Msg) (*dns.Msg, error) {
151 155
 	addr := r.sb.ResolveName(name)
152 156
 	if addr == nil {
... ...
@@ -157,6 +161,7 @@ func (r *resolver) handleIPv4Query(name string, query *dns.Msg) (*dns.Msg, error
157 157
 
158 158
 	resp := new(dns.Msg)
159 159
 	resp.SetReply(query)
160
+	setCommonFlags(resp)
160 161
 
161 162
 	rr := new(dns.A)
162 163
 	rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL}
... ...
@@ -186,6 +191,7 @@ func (r *resolver) handlePTRQuery(ptr string, query *dns.Msg) (*dns.Msg, error)
186 186
 
187 187
 	resp := new(dns.Msg)
188 188
 	resp.SetReply(query)
189
+	setCommonFlags(resp)
189 190
 
190 191
 	rr := new(dns.PTR)
191 192
 	rr.Hdr = dns.RR_Header{Name: ptr, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: respTTL}
... ...
@@ -200,6 +206,9 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
200 200
 		err  error
201 201
 	)
202 202
 
203
+	if query == nil || len(query.Question) == 0 {
204
+		return
205
+	}
203 206
 	name := query.Question[0].Name
204 207
 	if query.Question[0].Qtype == dns.TypeA {
205 208
 		resp, err = r.handleIPv4Query(name, query)
... ...
@@ -4,19 +4,13 @@ import (
4 4
 	"container/heap"
5 5
 	"encoding/json"
6 6
 	"fmt"
7
-	"io/ioutil"
8 7
 	"net"
9
-	"os"
10
-	"path"
11
-	"path/filepath"
12 8
 	"strings"
13 9
 	"sync"
14 10
 
15 11
 	log "github.com/Sirupsen/logrus"
16 12
 	"github.com/docker/libnetwork/etchosts"
17
-	"github.com/docker/libnetwork/netutils"
18 13
 	"github.com/docker/libnetwork/osl"
19
-	"github.com/docker/libnetwork/resolvconf"
20 14
 	"github.com/docker/libnetwork/types"
21 15
 )
22 16
 
... ...
@@ -309,46 +303,6 @@ func (sb *sandbox) UnmarshalJSON(b []byte) (err error) {
309 309
 	return nil
310 310
 }
311 311
 
312
-func (sb *sandbox) startResolver() {
313
-	sb.resolverOnce.Do(func() {
314
-		var err error
315
-		sb.resolver = NewResolver(sb)
316
-		defer func() {
317
-			if err != nil {
318
-				sb.resolver = nil
319
-			}
320
-		}()
321
-
322
-		err = sb.rebuildDNS()
323
-		if err != nil {
324
-			log.Errorf("Updating resolv.conf failed for container %s, %q", sb.ContainerID(), err)
325
-			return
326
-		}
327
-		sb.resolver.SetExtServers(sb.extDNS)
328
-
329
-		sb.osSbox.InvokeFunc(sb.resolver.SetupFunc())
330
-		if err = sb.resolver.Start(); err != nil {
331
-			log.Errorf("Resolver Setup/Start failed for container %s, %q", sb.ContainerID(), err)
332
-		}
333
-	})
334
-}
335
-
336
-func (sb *sandbox) setupResolutionFiles() error {
337
-	if err := sb.buildHostsFile(); err != nil {
338
-		return err
339
-	}
340
-
341
-	if err := sb.updateParentHosts(); err != nil {
342
-		return err
343
-	}
344
-
345
-	if err := sb.setupDNS(); err != nil {
346
-		return err
347
-	}
348
-
349
-	return nil
350
-}
351
-
352 312
 func (sb *sandbox) Endpoints() []Endpoint {
353 313
 	sb.Lock()
354 314
 	defer sb.Unlock()
... ...
@@ -753,243 +707,6 @@ func (sb *sandbox) clearNetworkResources(origEp *endpoint) error {
753 753
 	return nil
754 754
 }
755 755
 
756
-const (
757
-	defaultPrefix = "/var/lib/docker/network/files"
758
-	dirPerm       = 0755
759
-	filePerm      = 0644
760
-)
761
-
762
-func (sb *sandbox) buildHostsFile() error {
763
-	if sb.config.hostsPath == "" {
764
-		sb.config.hostsPath = defaultPrefix + "/" + sb.id + "/hosts"
765
-	}
766
-
767
-	dir, _ := filepath.Split(sb.config.hostsPath)
768
-	if err := createBasePath(dir); err != nil {
769
-		return err
770
-	}
771
-
772
-	// This is for the host mode networking
773
-	if sb.config.originHostsPath != "" {
774
-		if err := copyFile(sb.config.originHostsPath, sb.config.hostsPath); err != nil && !os.IsNotExist(err) {
775
-			return types.InternalErrorf("could not copy source hosts file %s to %s: %v", sb.config.originHostsPath, sb.config.hostsPath, err)
776
-		}
777
-		return nil
778
-	}
779
-
780
-	extraContent := make([]etchosts.Record, 0, len(sb.config.extraHosts))
781
-	for _, extraHost := range sb.config.extraHosts {
782
-		extraContent = append(extraContent, etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
783
-	}
784
-
785
-	return etchosts.Build(sb.config.hostsPath, "", sb.config.hostName, sb.config.domainName, extraContent)
786
-}
787
-
788
-func (sb *sandbox) updateHostsFile(ifaceIP string) error {
789
-	var mhost string
790
-
791
-	if sb.config.originHostsPath != "" {
792
-		return nil
793
-	}
794
-
795
-	if sb.config.domainName != "" {
796
-		mhost = fmt.Sprintf("%s.%s %s", sb.config.hostName, sb.config.domainName,
797
-			sb.config.hostName)
798
-	} else {
799
-		mhost = sb.config.hostName
800
-	}
801
-
802
-	extraContent := []etchosts.Record{{Hosts: mhost, IP: ifaceIP}}
803
-
804
-	sb.addHostsEntries(extraContent)
805
-	return nil
806
-}
807
-
808
-func (sb *sandbox) addHostsEntries(recs []etchosts.Record) {
809
-	if err := etchosts.Add(sb.config.hostsPath, recs); err != nil {
810
-		log.Warnf("Failed adding service host entries to the running container: %v", err)
811
-	}
812
-}
813
-
814
-func (sb *sandbox) deleteHostsEntries(recs []etchosts.Record) {
815
-	if err := etchosts.Delete(sb.config.hostsPath, recs); err != nil {
816
-		log.Warnf("Failed deleting service host entries to the running container: %v", err)
817
-	}
818
-}
819
-
820
-func (sb *sandbox) updateParentHosts() error {
821
-	var pSb Sandbox
822
-
823
-	for _, update := range sb.config.parentUpdates {
824
-		sb.controller.WalkSandboxes(SandboxContainerWalker(&pSb, update.cid))
825
-		if pSb == nil {
826
-			continue
827
-		}
828
-		if err := etchosts.Update(pSb.(*sandbox).config.hostsPath, update.ip, update.name); err != nil {
829
-			return err
830
-		}
831
-	}
832
-
833
-	return nil
834
-}
835
-
836
-func (sb *sandbox) setupDNS() error {
837
-	var newRC *resolvconf.File
838
-
839
-	if sb.config.resolvConfPath == "" {
840
-		sb.config.resolvConfPath = defaultPrefix + "/" + sb.id + "/resolv.conf"
841
-	}
842
-
843
-	sb.config.resolvConfHashFile = sb.config.resolvConfPath + ".hash"
844
-
845
-	dir, _ := filepath.Split(sb.config.resolvConfPath)
846
-	if err := createBasePath(dir); err != nil {
847
-		return err
848
-	}
849
-
850
-	// This is for the host mode networking
851
-	if sb.config.originResolvConfPath != "" {
852
-		if err := copyFile(sb.config.originResolvConfPath, sb.config.resolvConfPath); err != nil {
853
-			return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", sb.config.originResolvConfPath, sb.config.resolvConfPath, err)
854
-		}
855
-		return nil
856
-	}
857
-
858
-	currRC, err := resolvconf.Get()
859
-	if err != nil {
860
-		return err
861
-	}
862
-
863
-	if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
864
-		var (
865
-			err            error
866
-			dnsList        = resolvconf.GetNameservers(currRC.Content, netutils.IP)
867
-			dnsSearchList  = resolvconf.GetSearchDomains(currRC.Content)
868
-			dnsOptionsList = resolvconf.GetOptions(currRC.Content)
869
-		)
870
-		if len(sb.config.dnsList) > 0 {
871
-			dnsList = sb.config.dnsList
872
-		}
873
-		if len(sb.config.dnsSearchList) > 0 {
874
-			dnsSearchList = sb.config.dnsSearchList
875
-		}
876
-		if len(sb.config.dnsOptionsList) > 0 {
877
-			dnsOptionsList = sb.config.dnsOptionsList
878
-		}
879
-		newRC, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
880
-		if err != nil {
881
-			return err
882
-		}
883
-	} else {
884
-		// Replace any localhost/127.* (at this point we have no info about ipv6, pass it as true)
885
-		if newRC, err = resolvconf.FilterResolvDNS(currRC.Content, true); err != nil {
886
-			return err
887
-		}
888
-		// No contention on container resolv.conf file at sandbox creation
889
-		if err := ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, filePerm); err != nil {
890
-			return types.InternalErrorf("failed to write unhaltered resolv.conf file content when setting up dns for sandbox %s: %v", sb.ID(), err)
891
-		}
892
-	}
893
-
894
-	// Write hash
895
-	if err := ioutil.WriteFile(sb.config.resolvConfHashFile, []byte(newRC.Hash), filePerm); err != nil {
896
-		return types.InternalErrorf("failed to write resolv.conf hash file when setting up dns for sandbox %s: %v", sb.ID(), err)
897
-	}
898
-
899
-	return nil
900
-}
901
-
902
-func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
903
-	var (
904
-		currHash string
905
-		hashFile = sb.config.resolvConfHashFile
906
-	)
907
-
908
-	// This is for the host mode networking
909
-	if sb.config.originResolvConfPath != "" {
910
-		return nil
911
-	}
912
-
913
-	if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
914
-		return nil
915
-	}
916
-
917
-	currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath)
918
-	if err != nil {
919
-		if !os.IsNotExist(err) {
920
-			return err
921
-		}
922
-	} else {
923
-		h, err := ioutil.ReadFile(hashFile)
924
-		if err != nil {
925
-			if !os.IsNotExist(err) {
926
-				return err
927
-			}
928
-		} else {
929
-			currHash = string(h)
930
-		}
931
-	}
932
-
933
-	if currHash != "" && currHash != currRC.Hash {
934
-		// Seems the user has changed the container resolv.conf since the last time
935
-		// we checked so return without doing anything.
936
-		log.Infof("Skipping update of resolv.conf file with ipv6Enabled: %t because file was touched by user", ipv6Enabled)
937
-		return nil
938
-	}
939
-
940
-	// replace any localhost/127.* and remove IPv6 nameservers if IPv6 disabled.
941
-	newRC, err := resolvconf.FilterResolvDNS(currRC.Content, ipv6Enabled)
942
-	if err != nil {
943
-		return err
944
-	}
945
-	err = ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, 0644)
946
-	if err != nil {
947
-		return err
948
-	}
949
-
950
-	// write the new hash in a temp file and rename it to make the update atomic
951
-	dir := path.Dir(sb.config.resolvConfPath)
952
-	tmpHashFile, err := ioutil.TempFile(dir, "hash")
953
-	if err != nil {
954
-		return err
955
-	}
956
-	if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newRC.Hash), filePerm); err != nil {
957
-		return err
958
-	}
959
-	return os.Rename(tmpHashFile.Name(), hashFile)
960
-}
961
-
962
-// Embedded DNS server has to be enabled for this sandbox. Rebuild the container's
963
-// resolv.conf by doing the follwing
964
-// - Save the external name servers in resolv.conf in the sandbox
965
-// - Add only the embedded server's IP to container's resolv.conf
966
-// - If the embedded server needs any resolv.conf options add it to the current list
967
-func (sb *sandbox) rebuildDNS() error {
968
-	currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath)
969
-	if err != nil {
970
-		return err
971
-	}
972
-
973
-	// localhost entries have already been filtered out from the list
974
-	// retain only the v4 servers in sb for forwarding the DNS queries
975
-	sb.extDNS = resolvconf.GetNameservers(currRC.Content, netutils.IPv4)
976
-
977
-	var (
978
-		dnsList        = []string{sb.resolver.NameServer()}
979
-		dnsOptionsList = resolvconf.GetOptions(currRC.Content)
980
-		dnsSearchList  = resolvconf.GetSearchDomains(currRC.Content)
981
-	)
982
-
983
-	// external v6 DNS servers has to be listed in resolv.conf
984
-	dnsList = append(dnsList, resolvconf.GetNameservers(currRC.Content, netutils.IPv6)...)
985
-
986
-	// Resolver returns the options in the format resolv.conf expects
987
-	dnsOptionsList = append(dnsOptionsList, sb.resolver.ResolverOptions()...)
988
-
989
-	_, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
990
-	return err
991
-}
992
-
993 756
 // joinLeaveStart waits to ensure there are no joins or leaves in progress and
994 757
 // marks this join/leave in progress without race
995 758
 func (sb *sandbox) joinLeaveStart() {
... ...
@@ -1191,32 +908,3 @@ func (eh *epHeap) Pop() interface{} {
1191 1191
 	*eh = old[0 : n-1]
1192 1192
 	return x
1193 1193
 }
1194
-
1195
-func createBasePath(dir string) error {
1196
-	return os.MkdirAll(dir, dirPerm)
1197
-}
1198
-
1199
-func createFile(path string) error {
1200
-	var f *os.File
1201
-
1202
-	dir, _ := filepath.Split(path)
1203
-	err := createBasePath(dir)
1204
-	if err != nil {
1205
-		return err
1206
-	}
1207
-
1208
-	f, err = os.Create(path)
1209
-	if err == nil {
1210
-		f.Close()
1211
-	}
1212
-
1213
-	return err
1214
-}
1215
-
1216
-func copyFile(src, dst string) error {
1217
-	sBytes, err := ioutil.ReadFile(src)
1218
-	if err != nil {
1219
-		return err
1220
-	}
1221
-	return ioutil.WriteFile(dst, sBytes, filePerm)
1222
-}
1223 1194
new file mode 100644
... ...
@@ -0,0 +1,323 @@
0
+// +build !windows
1
+
2
+package libnetwork
3
+
4
+import (
5
+	"fmt"
6
+	"io/ioutil"
7
+	"os"
8
+	"path"
9
+	"path/filepath"
10
+
11
+	log "github.com/Sirupsen/logrus"
12
+	"github.com/docker/libnetwork/etchosts"
13
+	"github.com/docker/libnetwork/netutils"
14
+	"github.com/docker/libnetwork/resolvconf"
15
+	"github.com/docker/libnetwork/types"
16
+)
17
+
18
+const (
19
+	defaultPrefix = "/var/lib/docker/network/files"
20
+	dirPerm       = 0755
21
+	filePerm      = 0644
22
+)
23
+
24
+func (sb *sandbox) startResolver() {
25
+	sb.resolverOnce.Do(func() {
26
+		var err error
27
+		sb.resolver = NewResolver(sb)
28
+		defer func() {
29
+			if err != nil {
30
+				sb.resolver = nil
31
+			}
32
+		}()
33
+
34
+		err = sb.rebuildDNS()
35
+		if err != nil {
36
+			log.Errorf("Updating resolv.conf failed for container %s, %q", sb.ContainerID(), err)
37
+			return
38
+		}
39
+		sb.resolver.SetExtServers(sb.extDNS)
40
+
41
+		sb.osSbox.InvokeFunc(sb.resolver.SetupFunc())
42
+		if err = sb.resolver.Start(); err != nil {
43
+			log.Errorf("Resolver Setup/Start failed for container %s, %q", sb.ContainerID(), err)
44
+		}
45
+	})
46
+}
47
+
48
+func (sb *sandbox) setupResolutionFiles() error {
49
+	if err := sb.buildHostsFile(); err != nil {
50
+		return err
51
+	}
52
+
53
+	if err := sb.updateParentHosts(); err != nil {
54
+		return err
55
+	}
56
+
57
+	if err := sb.setupDNS(); err != nil {
58
+		return err
59
+	}
60
+
61
+	return nil
62
+}
63
+
64
+func (sb *sandbox) buildHostsFile() error {
65
+	if sb.config.hostsPath == "" {
66
+		sb.config.hostsPath = defaultPrefix + "/" + sb.id + "/hosts"
67
+	}
68
+
69
+	dir, _ := filepath.Split(sb.config.hostsPath)
70
+	if err := createBasePath(dir); err != nil {
71
+		return err
72
+	}
73
+
74
+	// This is for the host mode networking
75
+	if sb.config.originHostsPath != "" {
76
+		if err := copyFile(sb.config.originHostsPath, sb.config.hostsPath); err != nil && !os.IsNotExist(err) {
77
+			return types.InternalErrorf("could not copy source hosts file %s to %s: %v", sb.config.originHostsPath, sb.config.hostsPath, err)
78
+		}
79
+		return nil
80
+	}
81
+
82
+	extraContent := make([]etchosts.Record, 0, len(sb.config.extraHosts))
83
+	for _, extraHost := range sb.config.extraHosts {
84
+		extraContent = append(extraContent, etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
85
+	}
86
+
87
+	return etchosts.Build(sb.config.hostsPath, "", sb.config.hostName, sb.config.domainName, extraContent)
88
+}
89
+
90
+func (sb *sandbox) updateHostsFile(ifaceIP string) error {
91
+	var mhost string
92
+
93
+	if sb.config.originHostsPath != "" {
94
+		return nil
95
+	}
96
+
97
+	if sb.config.domainName != "" {
98
+		mhost = fmt.Sprintf("%s.%s %s", sb.config.hostName, sb.config.domainName,
99
+			sb.config.hostName)
100
+	} else {
101
+		mhost = sb.config.hostName
102
+	}
103
+
104
+	extraContent := []etchosts.Record{{Hosts: mhost, IP: ifaceIP}}
105
+
106
+	sb.addHostsEntries(extraContent)
107
+	return nil
108
+}
109
+
110
+func (sb *sandbox) addHostsEntries(recs []etchosts.Record) {
111
+	if err := etchosts.Add(sb.config.hostsPath, recs); err != nil {
112
+		log.Warnf("Failed adding service host entries to the running container: %v", err)
113
+	}
114
+}
115
+
116
+func (sb *sandbox) deleteHostsEntries(recs []etchosts.Record) {
117
+	if err := etchosts.Delete(sb.config.hostsPath, recs); err != nil {
118
+		log.Warnf("Failed deleting service host entries to the running container: %v", err)
119
+	}
120
+}
121
+
122
+func (sb *sandbox) updateParentHosts() error {
123
+	var pSb Sandbox
124
+
125
+	for _, update := range sb.config.parentUpdates {
126
+		sb.controller.WalkSandboxes(SandboxContainerWalker(&pSb, update.cid))
127
+		if pSb == nil {
128
+			continue
129
+		}
130
+		if err := etchosts.Update(pSb.(*sandbox).config.hostsPath, update.ip, update.name); err != nil {
131
+			return err
132
+		}
133
+	}
134
+
135
+	return nil
136
+}
137
+
138
+func (sb *sandbox) setupDNS() error {
139
+	var newRC *resolvconf.File
140
+
141
+	if sb.config.resolvConfPath == "" {
142
+		sb.config.resolvConfPath = defaultPrefix + "/" + sb.id + "/resolv.conf"
143
+	}
144
+
145
+	sb.config.resolvConfHashFile = sb.config.resolvConfPath + ".hash"
146
+
147
+	dir, _ := filepath.Split(sb.config.resolvConfPath)
148
+	if err := createBasePath(dir); err != nil {
149
+		return err
150
+	}
151
+
152
+	// This is for the host mode networking
153
+	if sb.config.originResolvConfPath != "" {
154
+		if err := copyFile(sb.config.originResolvConfPath, sb.config.resolvConfPath); err != nil {
155
+			return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", sb.config.originResolvConfPath, sb.config.resolvConfPath, err)
156
+		}
157
+		return nil
158
+	}
159
+
160
+	currRC, err := resolvconf.Get()
161
+	if err != nil {
162
+		return err
163
+	}
164
+
165
+	if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
166
+		var (
167
+			err            error
168
+			dnsList        = resolvconf.GetNameservers(currRC.Content, netutils.IP)
169
+			dnsSearchList  = resolvconf.GetSearchDomains(currRC.Content)
170
+			dnsOptionsList = resolvconf.GetOptions(currRC.Content)
171
+		)
172
+		if len(sb.config.dnsList) > 0 {
173
+			dnsList = sb.config.dnsList
174
+		}
175
+		if len(sb.config.dnsSearchList) > 0 {
176
+			dnsSearchList = sb.config.dnsSearchList
177
+		}
178
+		if len(sb.config.dnsOptionsList) > 0 {
179
+			dnsOptionsList = sb.config.dnsOptionsList
180
+		}
181
+		newRC, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
182
+		if err != nil {
183
+			return err
184
+		}
185
+	} else {
186
+		// Replace any localhost/127.* (at this point we have no info about ipv6, pass it as true)
187
+		if newRC, err = resolvconf.FilterResolvDNS(currRC.Content, true); err != nil {
188
+			return err
189
+		}
190
+		// No contention on container resolv.conf file at sandbox creation
191
+		if err := ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, filePerm); err != nil {
192
+			return types.InternalErrorf("failed to write unhaltered resolv.conf file content when setting up dns for sandbox %s: %v", sb.ID(), err)
193
+		}
194
+	}
195
+
196
+	// Write hash
197
+	if err := ioutil.WriteFile(sb.config.resolvConfHashFile, []byte(newRC.Hash), filePerm); err != nil {
198
+		return types.InternalErrorf("failed to write resolv.conf hash file when setting up dns for sandbox %s: %v", sb.ID(), err)
199
+	}
200
+
201
+	return nil
202
+}
203
+
204
+func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
205
+	var (
206
+		currHash string
207
+		hashFile = sb.config.resolvConfHashFile
208
+	)
209
+
210
+	// This is for the host mode networking
211
+	if sb.config.originResolvConfPath != "" {
212
+		return nil
213
+	}
214
+
215
+	if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
216
+		return nil
217
+	}
218
+
219
+	currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath)
220
+	if err != nil {
221
+		if !os.IsNotExist(err) {
222
+			return err
223
+		}
224
+	} else {
225
+		h, err := ioutil.ReadFile(hashFile)
226
+		if err != nil {
227
+			if !os.IsNotExist(err) {
228
+				return err
229
+			}
230
+		} else {
231
+			currHash = string(h)
232
+		}
233
+	}
234
+
235
+	if currHash != "" && currHash != currRC.Hash {
236
+		// Seems the user has changed the container resolv.conf since the last time
237
+		// we checked so return without doing anything.
238
+		log.Infof("Skipping update of resolv.conf file with ipv6Enabled: %t because file was touched by user", ipv6Enabled)
239
+		return nil
240
+	}
241
+
242
+	// replace any localhost/127.* and remove IPv6 nameservers if IPv6 disabled.
243
+	newRC, err := resolvconf.FilterResolvDNS(currRC.Content, ipv6Enabled)
244
+	if err != nil {
245
+		return err
246
+	}
247
+	err = ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, 0644)
248
+	if err != nil {
249
+		return err
250
+	}
251
+
252
+	// write the new hash in a temp file and rename it to make the update atomic
253
+	dir := path.Dir(sb.config.resolvConfPath)
254
+	tmpHashFile, err := ioutil.TempFile(dir, "hash")
255
+	if err != nil {
256
+		return err
257
+	}
258
+	if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newRC.Hash), filePerm); err != nil {
259
+		return err
260
+	}
261
+	return os.Rename(tmpHashFile.Name(), hashFile)
262
+}
263
+
264
+// Embedded DNS server has to be enabled for this sandbox. Rebuild the container's
265
+// resolv.conf by doing the follwing
266
+// - Save the external name servers in resolv.conf in the sandbox
267
+// - Add only the embedded server's IP to container's resolv.conf
268
+// - If the embedded server needs any resolv.conf options add it to the current list
269
+func (sb *sandbox) rebuildDNS() error {
270
+	currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath)
271
+	if err != nil {
272
+		return err
273
+	}
274
+
275
+	// localhost entries have already been filtered out from the list
276
+	// retain only the v4 servers in sb for forwarding the DNS queries
277
+	sb.extDNS = resolvconf.GetNameservers(currRC.Content, netutils.IPv4)
278
+
279
+	var (
280
+		dnsList        = []string{sb.resolver.NameServer()}
281
+		dnsOptionsList = resolvconf.GetOptions(currRC.Content)
282
+		dnsSearchList  = resolvconf.GetSearchDomains(currRC.Content)
283
+	)
284
+
285
+	// external v6 DNS servers has to be listed in resolv.conf
286
+	dnsList = append(dnsList, resolvconf.GetNameservers(currRC.Content, netutils.IPv6)...)
287
+
288
+	// Resolver returns the options in the format resolv.conf expects
289
+	dnsOptionsList = append(dnsOptionsList, sb.resolver.ResolverOptions()...)
290
+
291
+	_, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
292
+	return err
293
+}
294
+
295
+func createBasePath(dir string) error {
296
+	return os.MkdirAll(dir, dirPerm)
297
+}
298
+
299
+func createFile(path string) error {
300
+	var f *os.File
301
+
302
+	dir, _ := filepath.Split(path)
303
+	err := createBasePath(dir)
304
+	if err != nil {
305
+		return err
306
+	}
307
+
308
+	f, err = os.Create(path)
309
+	if err == nil {
310
+		f.Close()
311
+	}
312
+
313
+	return err
314
+}
315
+
316
+func copyFile(src, dst string) error {
317
+	sBytes, err := ioutil.ReadFile(src)
318
+	if err != nil {
319
+		return err
320
+	}
321
+	return ioutil.WriteFile(dst, sBytes, filePerm)
322
+}
0 323
new file mode 100644
... ...
@@ -0,0 +1,32 @@
0
+// +build windows
1
+
2
+package libnetwork
3
+
4
+import (
5
+	"github.com/docker/libnetwork/etchosts"
6
+)
7
+
8
+// Stub implementations for DNS related functions
9
+
10
+func (sb *sandbox) startResolver() {
11
+}
12
+
13
+func (sb *sandbox) setupResolutionFiles() error {
14
+	return nil
15
+}
16
+
17
+func (sb *sandbox) updateHostsFile(ifaceIP string) error {
18
+	return nil
19
+}
20
+
21
+func (sb *sandbox) addHostsEntries(recs []etchosts.Record) {
22
+
23
+}
24
+
25
+func (sb *sandbox) deleteHostsEntries(recs []etchosts.Record) {
26
+
27
+}
28
+
29
+func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
30
+	return nil
31
+}
... ...
@@ -1,4 +1,4 @@
1
-// +build !windows
1
+// +build linux freebsd
2 2
 
3 3
 package libnetwork
4 4
 
... ...
@@ -14,6 +14,7 @@ func (c *controller) initStores() error {
14 14
 		return nil
15 15
 	}
16 16
 	scopeConfigs := c.cfg.Scopes
17
+	c.stores = nil
17 18
 	c.Unlock()
18 19
 
19 20
 	for scope, scfg := range scopeConfigs {
... ...
@@ -418,6 +419,9 @@ func (c *controller) watchLoop() {
418 418
 }
419 419
 
420 420
 func (c *controller) startWatch() {
421
+	if c.watchCh != nil {
422
+		return
423
+	}
421 424
 	c.watchCh = make(chan *endpoint)
422 425
 	c.unWatchCh = make(chan *endpoint)
423 426
 	c.nmap = make(map[string]*netWatch)