소스 검색

Merge pull request #20419 from aboch/cr

Allow passing global datastore to libnetwork and v0.7.0-dev1 vendoring
Arnaud Porterie 9 년 전
부모
커밋
117a982d2e
36개의 변경된 파일1281개의 추가작업 그리고 427개의 파일을 삭제
  1. 16 3
      daemon/daemon.go
  2. 2 2
      daemon/daemon_test.go
  3. 5 0
      daemon/daemon_windows.go
  4. 9 0
      docs/reference/commandline/daemon.md
  5. 1 1
      hack/vendor.sh
  6. 41 0
      integration-cli/docker_cli_daemon_test.go
  7. 8 0
      integration-cli/docker_cli_network_unix_test.go
  8. 8 0
      vendor/src/github.com/docker/libnetwork/CHANGELOG.md
  9. 0 1
      vendor/src/github.com/docker/libnetwork/Dockerfile.build
  10. 1 1
      vendor/src/github.com/docker/libnetwork/Makefile
  11. 16 0
      vendor/src/github.com/docker/libnetwork/config/config.go
  12. 103 17
      vendor/src/github.com/docker/libnetwork/controller.go
  13. 29 0
      vendor/src/github.com/docker/libnetwork/datastore/datastore.go
  14. 5 4
      vendor/src/github.com/docker/libnetwork/discoverapi/discoverapi.go
  15. 9 5
      vendor/src/github.com/docker/libnetwork/drivers.go
  16. 5 0
      vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go
  17. 8 20
      vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge_store.go
  18. 52 32
      vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go
  19. 12 0
      vendor/src/github.com/docker/libnetwork/drivers/windows/labels.go
  20. 372 10
      vendor/src/github.com/docker/libnetwork/drivers/windows/windows.go
  21. 9 2
      vendor/src/github.com/docker/libnetwork/drivers_windows.go
  22. 62 13
      vendor/src/github.com/docker/libnetwork/ipam/allocator.go
  23. 3 0
      vendor/src/github.com/docker/libnetwork/ipamapi/contract.go
  24. 2 0
      vendor/src/github.com/docker/libnetwork/ipams/builtin/builtin_unix.go
  25. 16 0
      vendor/src/github.com/docker/libnetwork/ipams/builtin/builtin_windows.go
  26. 11 0
      vendor/src/github.com/docker/libnetwork/ipams/remote/remote.go
  27. 93 0
      vendor/src/github.com/docker/libnetwork/ipams/windowsipam/windowsipam.go
  28. 11 0
      vendor/src/github.com/docker/libnetwork/netlabel/labels.go
  29. 1 1
      vendor/src/github.com/docker/libnetwork/network.go
  30. 1 1
      vendor/src/github.com/docker/libnetwork/portmapper/proxy.go
  31. 10 1
      vendor/src/github.com/docker/libnetwork/resolver.go
  32. 0 312
      vendor/src/github.com/docker/libnetwork/sandbox.go
  33. 323 0
      vendor/src/github.com/docker/libnetwork/sandbox_dns_unix.go
  34. 32 0
      vendor/src/github.com/docker/libnetwork/sandbox_dns_windows.go
  35. 1 1
      vendor/src/github.com/docker/libnetwork/sandbox_externalkey_unix.go
  36. 4 0
      vendor/src/github.com/docker/libnetwork/store.go

+ 16 - 3
daemon/daemon.go

@@ -1598,12 +1598,12 @@ func (daemon *Daemon) initDiscovery(config *Config) error {
 // daemon according to those changes.
 // This are the settings that Reload changes:
 // - Daemon labels.
+// - Cluster discovery (reconfigure and restart).
 func (daemon *Daemon) Reload(config *Config) error {
 	daemon.configStore.reloadLock.Lock()
+	defer daemon.configStore.reloadLock.Unlock()
 	daemon.configStore.Labels = config.Labels
-	daemon.configStore.reloadLock.Unlock()
-
-	return nil
+	return daemon.reloadClusterDiscovery(config)
 }
 
 func (daemon *Daemon) reloadClusterDiscovery(config *Config) error {
@@ -1640,6 +1640,19 @@ func (daemon *Daemon) reloadClusterDiscovery(config *Config) error {
 	daemon.configStore.ClusterOpts = config.ClusterOpts
 	daemon.configStore.ClusterAdvertise = newAdvertise
 
+	if daemon.netController == nil {
+		return nil
+	}
+	netOptions, err := daemon.networkOptions(daemon.configStore)
+	if err != nil {
+		logrus.Warnf("Failed to reload configuration with network controller: %v", err)
+		return nil
+	}
+	err = daemon.netController.ReloadConfiguration(netOptions...)
+	if err != nil {
+		logrus.Warnf("Failed to reload configuration with network controller: %v", err)
+	}
+
 	return nil
 }
 

+ 2 - 2
daemon/daemon_test.go

@@ -371,7 +371,7 @@ func TestDaemonDiscoveryReload(t *testing.T) {
 		&discovery.Entry{Host: "127.0.0.1", Port: "5555"},
 	}
 
-	if err := daemon.reloadClusterDiscovery(newConfig); err != nil {
+	if err := daemon.Reload(newConfig); err != nil {
 		t.Fatal(err)
 	}
 	ch, errCh = daemon.discoveryWatcher.Watch(stopCh)
@@ -403,7 +403,7 @@ func TestDaemonDiscoveryReloadFromEmptyDiscovery(t *testing.T) {
 		&discovery.Entry{Host: "127.0.0.1", Port: "5555"},
 	}
 
-	if err := daemon.reloadClusterDiscovery(newConfig); err != nil {
+	if err := daemon.Reload(newConfig); err != nil {
 		t.Fatal(err)
 	}
 	stopCh := make(chan struct{})

+ 5 - 0
daemon/daemon_windows.go

@@ -22,6 +22,7 @@ import (
 	"github.com/docker/docker/pkg/idtools"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/libnetwork"
+	nwconfig "github.com/docker/libnetwork/config"
 	blkiodev "github.com/opencontainers/runc/libcontainer/configs"
 )
 
@@ -251,3 +252,7 @@ func restoreCustomImage(is image.Store, ls layer.Store, rs reference.Store) erro
 	}
 	return nil
 }
+
+func (daemon *Daemon) networkOptions(dconfig *Config) ([]nwconfig.Option, error) {
+	return nil, fmt.Errorf("Network controller config reload not aavailable on Windows yet")
+}

+ 9 - 0
docs/reference/commandline/daemon.md

@@ -890,4 +890,13 @@ if there are conflicts, but it won't stop execution.
 The list of currently supported options that can be reconfigured is this:
 
 - `debug`: it changes the daemon to debug mode when set to true.
+- `cluster-store`: it reloads the discovery store with the new address.
+- `cluster-store-opts`: it uses the new options to reload the discovery store.
+- `cluster-advertise`: it modifies the address advertised after reloading.
 - `labels`: it replaces the daemon labels with a new set of labels.
+
+Updating and reloading the cluster configurations such as `--cluster-store`,
+`--cluster-advertise` and `--cluster-store-opts` will take effect only if
+these configurations were not previously configured. Configuration reload will
+log a warning message if it detects a change in previously configured cluster
+configurations.

+ 1 - 1
hack/vendor.sh

@@ -29,7 +29,7 @@ clone git github.com/RackSec/srslog 6eb773f331e46fbba8eecb8e794e635e75fc04de
 clone git github.com/imdario/mergo 0.2.1
 
 #get libnetwork packages
-clone git github.com/docker/libnetwork v0.7.0-dev.2
+clone git github.com/docker/libnetwork v0.7.0-dev.3
 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
 clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
 clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4

+ 41 - 0
integration-cli/docker_cli_daemon_test.go

@@ -17,6 +17,7 @@ import (
 	"strconv"
 	"strings"
 	"sync"
+	"syscall"
 	"time"
 
 	"github.com/docker/docker/pkg/integration/checker"
@@ -2156,3 +2157,43 @@ func (s *DockerDaemonSuite) TestDaemonDebugLog(c *check.C) {
 	newD.Stop()
 	c.Assert(b.String(), checker.Contains, debugLog)
 }
+
+func (s *DockerSuite) TestDaemonDiscoveryBackendConfigReload(c *check.C) {
+	testRequires(c, SameHostDaemon, DaemonIsLinux)
+
+	// daemon config file
+	daemonConfig := `{ "debug" : false }`
+	configFilePath := "test.json"
+
+	configFile, err := os.Create(configFilePath)
+	c.Assert(err, checker.IsNil)
+	fmt.Fprintf(configFile, "%s", daemonConfig)
+
+	d := NewDaemon(c)
+	err = d.Start(fmt.Sprintf("--config-file=%s", configFilePath))
+	c.Assert(err, checker.IsNil)
+	defer d.Stop()
+
+	// daemon config file
+	daemonConfig = `{
+	      "cluster-store": "consul://consuladdr:consulport/some/path",
+	      "cluster-advertise": "192.168.56.100:0",
+	      "debug" : false
+	}`
+
+	configFile.Close()
+	os.Remove(configFilePath)
+
+	configFile, err = os.Create(configFilePath)
+	c.Assert(err, checker.IsNil)
+	fmt.Fprintf(configFile, "%s", daemonConfig)
+
+	syscall.Kill(d.cmd.Process.Pid, syscall.SIGHUP)
+
+	time.Sleep(3 * time.Second)
+
+	out, err := d.Cmd("info")
+	c.Assert(err, checker.IsNil)
+	c.Assert(out, checker.Contains, fmt.Sprintf("Cluster store: consul://consuladdr:consulport/some/path"))
+	c.Assert(out, checker.Contains, fmt.Sprintf("Cluster advertise: 192.168.56.100:0"))
+}

+ 8 - 0
integration-cli/docker_cli_network_unix_test.go

@@ -1389,6 +1389,14 @@ func (s *DockerSuite) TestUserDefinedNetworkConnectivity(c *check.C) {
 	c.Assert(err, check.NotNil)
 }
 
+func (s *DockerSuite) TestEmbeddedDNSInvalidInput(c *check.C) {
+	testRequires(c, DaemonIsLinux, NotUserNamespace)
+	dockerCmd(c, "network", "create", "-d", "bridge", "nw1")
+
+	// Sending garbge to embedded DNS shouldn't crash the daemon
+	dockerCmd(c, "run", "-i", "--net=nw1", "--name=c1", "debian:jessie", "bash", "-c", "echo InvalidQuery > /dev/udp/127.0.0.11/53")
+}
+
 func (s *DockerSuite) TestDockerNetworkConnectFailsNoInspectChange(c *check.C) {
 	dockerCmd(c, "run", "-d", "--name=bb", "busybox", "top")
 	c.Assert(waitRun("bb"), check.IsNil)

+ 8 - 0
vendor/src/github.com/docker/libnetwork/CHANGELOG.md

@@ -1,5 +1,13 @@
 # Changelog
 
+## 0.7.0-dev.3 (2016-02-17)
+- Fixes https://github.com/docker/docker/issues/20350
+- Fixes https://github.com/docker/docker/issues/20145
+- Initial Windows HNS integration
+- Allow passing global datastore config to libnetwork after boot
+- Set Recursion Available bit in DNS query responses
+- Make sure iptables chains are recreated on firewalld reload
+
 ## 0.7.0-dev.2 (2016-02-11)
 - Fixes https://github.com/docker/docker/issues/20140
 

+ 0 - 1
vendor/src/github.com/docker/libnetwork/Dockerfile.build

@@ -8,6 +8,5 @@ RUN cd /go/src && mkdir -p golang.org/x && \
 RUN go get github.com/tools/godep \
 		github.com/golang/lint/golint \
 		golang.org/x/tools/cmd/vet \
-		golang.org/x/tools/cmd/goimports \
 		golang.org/x/tools/cmd/cover\
 		github.com/mattn/goveralls

+ 1 - 1
vendor/src/github.com/docker/libnetwork/Makefile

@@ -53,7 +53,7 @@ check-code:
 
 check-format:
 	@echo "Checking format... "
-	test -z "$$(goimports -l . | grep -v Godeps/_workspace/src/ | tee /dev/stderr)"
+	test -z "$$(gofmt -s -l . | grep -v Godeps/_workspace/src/ | tee /dev/stderr)"
 	@echo "Done checking format"
 
 run-tests:

+ 16 - 0
vendor/src/github.com/docker/libnetwork/config/config.go

@@ -61,6 +61,22 @@ func ParseConfig(tomlCfgFile string) (*Config, error) {
 	return cfg, nil
 }
 
+// ParseConfigOptions parses the configuration options and returns
+// a reference to the corresponding Config structure
+func ParseConfigOptions(cfgOptions ...Option) *Config {
+	cfg := &Config{
+		Daemon: DaemonCfg{
+			DriverCfg: make(map[string]interface{}),
+		},
+		Scopes: make(map[string]*datastore.ScopeCfg),
+	}
+
+	cfg.ProcessOptions(cfgOptions...)
+	cfg.LoadDefaultScopes(cfg.Daemon.DataDir)
+
+	return cfg
+}
+
 // Option is an option setter function type used to pass various configurations
 // to the controller
 type Option func(c *Config)

+ 103 - 17
vendor/src/github.com/docker/libnetwork/controller.go

@@ -106,6 +106,9 @@ type NetworkController interface {
 
 	// Stop network controller
 	Stop()
+
+	// ReloadCondfiguration updates the controller configuration
+	ReloadConfiguration(cfgOptions ...config.Option) error
 }
 
 // NetworkWalker is a client provided function which will be used to walk the Networks.
@@ -129,7 +132,6 @@ type ipamData struct {
 }
 
 type driverTable map[string]*driverData
-
 type ipamTable map[string]*ipamData
 type sandboxTable map[string]*sandbox
 
@@ -153,22 +155,9 @@ type controller struct {
 
 // New creates a new instance of network controller.
 func New(cfgOptions ...config.Option) (NetworkController, error) {
-	var cfg *config.Config
-	cfg = &config.Config{
-		Daemon: config.DaemonCfg{
-			DriverCfg: make(map[string]interface{}),
-		},
-		Scopes: make(map[string]*datastore.ScopeCfg),
-	}
-
-	if len(cfgOptions) > 0 {
-		cfg.ProcessOptions(cfgOptions...)
-	}
-	cfg.LoadDefaultScopes(cfg.Daemon.DataDir)
-
 	c := &controller{
 		id:          stringid.GenerateRandomID(),
-		cfg:         cfg,
+		cfg:         config.ParseConfigOptions(cfgOptions...),
 		sandboxes:   sandboxTable{},
 		drivers:     driverTable{},
 		ipamDrivers: ipamTable{},
@@ -179,8 +168,8 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
 		return nil, err
 	}
 
-	if cfg != nil && cfg.Cluster.Watcher != nil {
-		if err := c.initDiscovery(cfg.Cluster.Watcher); err != nil {
+	if c.cfg != nil && c.cfg.Cluster.Watcher != nil {
+		if err := c.initDiscovery(c.cfg.Cluster.Watcher); err != nil {
 			// Failing to initalize discovery is a bad situation to be in.
 			// But it cannot fail creating the Controller
 			log.Errorf("Failed to Initialize Discovery : %v", err)
@@ -206,6 +195,83 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
 	return c, nil
 }
 
+var procReloadConfig = make(chan (bool), 1)
+
+func (c *controller) ReloadConfiguration(cfgOptions ...config.Option) error {
+	procReloadConfig <- true
+	defer func() { <-procReloadConfig }()
+
+	// For now we accept the configuration reload only as a mean to provide a global store config after boot.
+	// Refuse the configuration if it alters an existing datastore client configuration.
+	update := false
+	cfg := config.ParseConfigOptions(cfgOptions...)
+	for s := range c.cfg.Scopes {
+		if _, ok := cfg.Scopes[s]; !ok {
+			return types.ForbiddenErrorf("cannot accept new configuration because it removes an existing datastore client")
+		}
+	}
+	for s, nSCfg := range cfg.Scopes {
+		if eSCfg, ok := c.cfg.Scopes[s]; ok {
+			if eSCfg.Client.Provider != nSCfg.Client.Provider ||
+				eSCfg.Client.Address != nSCfg.Client.Address {
+				return types.ForbiddenErrorf("cannot accept new configuration because it modifies an existing datastore client")
+			}
+		} else {
+			update = true
+		}
+	}
+	if !update {
+		return nil
+	}
+
+	c.Lock()
+	c.cfg = cfg
+	c.Unlock()
+
+	if err := c.initStores(); err != nil {
+		return err
+	}
+
+	if c.discovery == nil && c.cfg.Cluster.Watcher != nil {
+		if err := c.initDiscovery(c.cfg.Cluster.Watcher); err != nil {
+			log.Errorf("Failed to Initialize Discovery after configuration update: %v", err)
+		}
+	}
+
+	var dsConfig *discoverapi.DatastoreConfigData
+	for scope, sCfg := range cfg.Scopes {
+		if scope == datastore.LocalScope || !sCfg.IsValid() {
+			continue
+		}
+		dsConfig = &discoverapi.DatastoreConfigData{
+			Scope:    scope,
+			Provider: sCfg.Client.Provider,
+			Address:  sCfg.Client.Address,
+			Config:   sCfg.Client.Config,
+		}
+		break
+	}
+	if dsConfig == nil {
+		return nil
+	}
+
+	for nm, id := range c.getIpamDrivers() {
+		err := id.driver.DiscoverNew(discoverapi.DatastoreConfig, *dsConfig)
+		if err != nil {
+			log.Errorf("Failed to set datastore in driver %s: %v", nm, err)
+		}
+	}
+
+	for nm, id := range c.getNetDrivers() {
+		err := id.driver.DiscoverNew(discoverapi.DatastoreConfig, *dsConfig)
+		if err != nil {
+			log.Errorf("Failed to set datastore in driver %s: %v", nm, err)
+		}
+	}
+
+	return nil
+}
+
 func (c *controller) ID() string {
 	return c.id
 }
@@ -726,6 +792,26 @@ func (c *controller) getIpamDriver(name string) (ipamapi.Ipam, error) {
 	return id.driver, nil
 }
 
+func (c *controller) getIpamDrivers() ipamTable {
+	c.Lock()
+	defer c.Unlock()
+	table := ipamTable{}
+	for i, d := range c.ipamDrivers {
+		table[i] = d
+	}
+	return table
+}
+
+func (c *controller) getNetDrivers() driverTable {
+	c.Lock()
+	defer c.Unlock()
+	table := driverTable{}
+	for i, d := range c.drivers {
+		table[i] = d
+	}
+	return table
+}
+
 func (c *controller) Stop() {
 	c.closeStores()
 	c.stopExternalKeyListener()

+ 29 - 0
vendor/src/github.com/docker/libnetwork/datastore/datastore.go

@@ -13,6 +13,7 @@ import (
 	"github.com/docker/libkv/store/consul"
 	"github.com/docker/libkv/store/etcd"
 	"github.com/docker/libkv/store/zookeeper"
+	"github.com/docker/libnetwork/discoverapi"
 	"github.com/docker/libnetwork/types"
 )
 
@@ -253,6 +254,34 @@ func NewDataStore(scope string, cfg *ScopeCfg) (DataStore, error) {
 	return newClient(scope, cfg.Client.Provider, cfg.Client.Address, cfg.Client.Config, cached)
 }
 
+// NewDataStoreFromConfig creates a new instance of LibKV data store starting from the datastore config data
+func NewDataStoreFromConfig(dsc discoverapi.DatastoreConfigData) (DataStore, error) {
+	var (
+		ok    bool
+		sCfgP *store.Config
+	)
+
+	sCfgP, ok = dsc.Config.(*store.Config)
+	if !ok && dsc.Config != nil {
+		return nil, fmt.Errorf("cannot parse store configuration: %v", dsc.Config)
+	}
+
+	scopeCfg := &ScopeCfg{
+		Client: ScopeClientCfg{
+			Address:  dsc.Address,
+			Provider: dsc.Provider,
+			Config:   sCfgP,
+		},
+	}
+
+	ds, err := NewDataStore(dsc.Scope, scopeCfg)
+	if err != nil {
+		return nil, fmt.Errorf("failed to construct datastore client from datastore configuration %v: %v", dsc, err)
+	}
+
+	return ds, err
+}
+
 func (ds *datastore) Close() {
 	ds.store.Close()
 }

+ 5 - 4
vendor/src/github.com/docker/libnetwork/discoverapi/discoverapi.go

@@ -16,8 +16,8 @@ type DiscoveryType int
 const (
 	// NodeDiscovery represents Node join/leave events provided by discovery
 	NodeDiscovery = iota + 1
-	// DatastoreUpdate represents a add/remove datastore event
-	DatastoreUpdate
+	// DatastoreConfig represents a add/remove datastore event
+	DatastoreConfig
 )
 
 // NodeDiscoveryData represents the structure backing the node discovery data json string
@@ -26,8 +26,9 @@ type NodeDiscoveryData struct {
 	Self    bool
 }
 
-// DatastoreUpdateData is the data for the datastore update event message
-type DatastoreUpdateData struct {
+// DatastoreConfigData is the data for the datastore update event message
+type DatastoreConfigData struct {
+	Scope    string
 	Provider string
 	Address  string
 	Config   interface{}

+ 9 - 5
vendor/src/github.com/docker/libnetwork/drivers.go

@@ -3,11 +3,13 @@ package libnetwork
 import (
 	"strings"
 
+	"github.com/docker/libnetwork/discoverapi"
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/ipamapi"
+	"github.com/docker/libnetwork/netlabel"
+
 	builtinIpam "github.com/docker/libnetwork/ipams/builtin"
 	remoteIpam "github.com/docker/libnetwork/ipams/remote"
-	"github.com/docker/libnetwork/netlabel"
 )
 
 type initializer struct {
@@ -56,10 +58,12 @@ func makeDriverConfig(c *controller, ntype string) map[string]interface{} {
 		if !v.IsValid() {
 			continue
 		}
-
-		config[netlabel.MakeKVProvider(k)] = v.Client.Provider
-		config[netlabel.MakeKVProviderURL(k)] = v.Client.Address
-		config[netlabel.MakeKVProviderConfig(k)] = v.Client.Config
+		config[netlabel.MakeKVClient(k)] = discoverapi.DatastoreConfigData{
+			Scope:    k,
+			Provider: v.Client.Provider,
+			Address:  v.Client.Address,
+			Config:   v.Client.Config,
+		}
 	}
 
 	return config

+ 5 - 0
vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go

@@ -133,6 +133,9 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
 	if out, err := exec.Command("modprobe", "-va", "nf_nat").CombinedOutput(); err != nil {
 		logrus.Warnf("Running modprobe nf_nat failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
 	}
+	if out, err := exec.Command("modprobe", "-va", "xt_conntrack").CombinedOutput(); err != nil {
+		logrus.Warnf("Running modprobe xt_conntrack failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
+	}
 	if err := iptables.FirewalldInit(); err != nil {
 		logrus.Debugf("Fail to initialize firewalld: %v, using raw iptables instead", err)
 	}
@@ -384,6 +387,8 @@ func (d *driver) configure(option map[string]interface{}) error {
 		if err != nil {
 			return err
 		}
+		// Make sure on firewall reload, first thing being re-played is chains creation
+		iptables.OnReloaded(func() { logrus.Debugf("Recreating iptables chains on firewall reload"); setupIPChains(config) })
 	}
 
 	d.Lock()

+ 8 - 20
vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge_store.go

@@ -6,9 +6,9 @@ import (
 	"net"
 
 	"github.com/Sirupsen/logrus"
-	"github.com/docker/libkv/store"
 	"github.com/docker/libkv/store/boltdb"
 	"github.com/docker/libnetwork/datastore"
+	"github.com/docker/libnetwork/discoverapi"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/types"
 )
@@ -16,27 +16,15 @@ import (
 const bridgePrefix = "bridge"
 
 func (d *driver) initStore(option map[string]interface{}) error {
-	var err error
-
-	provider, provOk := option[netlabel.LocalKVProvider]
-	provURL, urlOk := option[netlabel.LocalKVProviderURL]
-
-	if provOk && urlOk {
-		cfg := &datastore.ScopeCfg{
-			Client: datastore.ScopeClientCfg{
-				Provider: provider.(string),
-				Address:  provURL.(string),
-			},
+	if data, ok := option[netlabel.LocalKVClient]; ok {
+		var err error
+		dsc, ok := data.(discoverapi.DatastoreConfigData)
+		if !ok {
+			return types.InternalErrorf("incorrect data in datastore configuration: %v", data)
 		}
-
-		provConfig, confOk := option[netlabel.LocalKVProviderConfig]
-		if confOk {
-			cfg.Client.Config = provConfig.(*store.Config)
-		}
-
-		d.store, err = datastore.NewDataStore(datastore.LocalScope, cfg)
+		d.store, err = datastore.NewDataStoreFromConfig(dsc)
 		if err != nil {
-			return fmt.Errorf("bridge driver failed to initialize data store: %v", err)
+			return types.InternalErrorf("bridge driver failed to initialize data store: %v", err)
 		}
 
 		return d.populateNetworks()

+ 52 - 32
vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go

@@ -6,12 +6,12 @@ import (
 	"sync"
 
 	"github.com/Sirupsen/logrus"
-	"github.com/docker/libkv/store"
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/discoverapi"
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/idm"
 	"github.com/docker/libnetwork/netlabel"
+	"github.com/docker/libnetwork/types"
 	"github.com/hashicorp/serf/serf"
 )
 
@@ -25,6 +25,8 @@ const (
 	vxlanVethMTU = 1450
 )
 
+var initVxlanIdm = make(chan (bool), 1)
+
 type driver struct {
 	eventCh      chan serf.Event
 	notifyCh     chan ovNotify
@@ -56,6 +58,18 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
 		config: config,
 	}
 
+	if data, ok := config[netlabel.GlobalKVClient]; ok {
+		var err error
+		dsc, ok := data.(discoverapi.DatastoreConfigData)
+		if !ok {
+			return types.InternalErrorf("incorrect data in datastore configuration: %v", data)
+		}
+		d.store, err = datastore.NewDataStoreFromConfig(dsc)
+		if err != nil {
+			return types.InternalErrorf("failed to initialize data store: %v", err)
+		}
+	}
+
 	return dc.RegisterDriver(networkType, d, c)
 }
 
@@ -73,42 +87,33 @@ func Fini(drv driverapi.Driver) {
 }
 
 func (d *driver) configure() error {
-	var err error
+	if d.store == nil {
+		return types.NoServiceErrorf("datastore is not available")
+	}
 
-	if len(d.config) == 0 {
-		return nil
+	if d.vxlanIdm == nil {
+		return d.initializeVxlanIdm()
 	}
 
-	d.once.Do(func() {
-		provider, provOk := d.config[netlabel.GlobalKVProvider]
-		provURL, urlOk := d.config[netlabel.GlobalKVProviderURL]
+	return nil
+}
 
-		if provOk && urlOk {
-			cfg := &datastore.ScopeCfg{
-				Client: datastore.ScopeClientCfg{
-					Provider: provider.(string),
-					Address:  provURL.(string),
-				},
-			}
-			provConfig, confOk := d.config[netlabel.GlobalKVProviderConfig]
-			if confOk {
-				cfg.Client.Config = provConfig.(*store.Config)
-			}
-			d.store, err = datastore.NewDataStore(datastore.GlobalScope, cfg)
-			if err != nil {
-				err = fmt.Errorf("failed to initialize data store: %v", err)
-				return
-			}
-		}
+func (d *driver) initializeVxlanIdm() error {
+	var err error
 
-		d.vxlanIdm, err = idm.New(d.store, "vxlan-id", vxlanIDStart, vxlanIDEnd)
-		if err != nil {
-			err = fmt.Errorf("failed to initialize vxlan id manager: %v", err)
-			return
-		}
-	})
+	initVxlanIdm <- true
+	defer func() { <-initVxlanIdm }()
+
+	if d.vxlanIdm != nil {
+		return nil
+	}
+
+	d.vxlanIdm, err = idm.New(d.store, "vxlan-id", vxlanIDStart, vxlanIDEnd)
+	if err != nil {
+		return fmt.Errorf("failed to initialize vxlan id manager: %v", err)
+	}
 
-	return err
+	return nil
 }
 
 func (d *driver) Type() string {
@@ -187,12 +192,27 @@ func (d *driver) pushLocalEndpointEvent(action, nid, eid string) {
 
 // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
 func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
-	if dType == discoverapi.NodeDiscovery {
+	switch dType {
+	case discoverapi.NodeDiscovery:
 		nodeData, ok := data.(discoverapi.NodeDiscoveryData)
 		if !ok || nodeData.Address == "" {
 			return fmt.Errorf("invalid discovery data")
 		}
 		d.nodeJoin(nodeData.Address, nodeData.Self)
+	case discoverapi.DatastoreConfig:
+		var err error
+		if d.store != nil {
+			return types.ForbiddenErrorf("cannot accept datastore configuration: Overlay driver has a datastore configured already")
+		}
+		dsc, ok := data.(discoverapi.DatastoreConfigData)
+		if !ok {
+			return types.InternalErrorf("incorrect data in datastore configuration: %v", data)
+		}
+		d.store, err = datastore.NewDataStoreFromConfig(dsc)
+		if err != nil {
+			return types.InternalErrorf("failed to initialize data store: %v", err)
+		}
+	default:
 	}
 	return nil
 }

+ 12 - 0
vendor/src/github.com/docker/libnetwork/drivers/windows/labels.go

@@ -0,0 +1,12 @@
+package windows
+
+const (
+	// NetworkName label for bridge driver
+	NetworkName = "com.docker.network.windowsshim.networkname"
+
+	// HNSID of the discovered network
+	HNSID = "com.docker.network.windowsshim.hnsid"
+
+	// RoutingDomain of the network
+	RoutingDomain = "com.docker.network.windowsshim.routingdomain"
+)

+ 372 - 10
vendor/src/github.com/docker/libnetwork/drivers/windows/windows.go

@@ -1,57 +1,419 @@
+// +build windows
+
+// Shim for the Host Network Service (HNS) to manage networking for
+// Windows Server containers and Hyper-V containers. This module
+// is a basic libnetwork driver that passes all the calls to HNS
+// It implements the 4 networking modes supported by HNS L2Bridge,
+// L2Tunnel, NAT and Transparent(DHCP)
+//
+// The network are stored in memory and docker daemon ensures discovering
+// and loading these networks on startup
+
 package windows
 
 import (
+	"encoding/json"
+	"fmt"
+	"net"
+	"strings"
+	"sync"
+
+	"github.com/Microsoft/hcsshim"
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/discoverapi"
 	"github.com/docker/libnetwork/driverapi"
+	"github.com/docker/libnetwork/netlabel"
+	"github.com/docker/libnetwork/types"
 )
 
-const networkType = "windows"
+// networkConfiguration for network specific configuration
+type networkConfiguration struct {
+	ID    string
+	Type  string
+	Name  string
+	HnsID string
+	RDID  string
+}
+
+type hnsEndpoint struct {
+	id         string
+	profileID  string
+	macAddress net.HardwareAddr
+	addr       *net.IPNet
+}
+
+type hnsNetwork struct {
+	id        string
+	config    *networkConfiguration
+	endpoints map[string]*hnsEndpoint // key: endpoint id
+	driver    *driver                 // The network's driver
+	sync.Mutex
+}
+
+type driver struct {
+	name     string
+	networks map[string]*hnsNetwork
+	sync.Mutex
+}
+
+func isValidNetworkType(networkType string) bool {
+	if "L2Bridge" == networkType || "L2Tunnel" == networkType || "NAT" == networkType || "Transparent" == networkType {
+		return true
+	}
+
+	return false
+}
+
+// New constructs a new bridge driver
+func newDriver(networkType string) *driver {
+	return &driver{name: networkType, networks: map[string]*hnsNetwork{}}
+}
+
+// GetInit returns an initializer for the given network type
+func GetInit(networkType string) func(dc driverapi.DriverCallback, config map[string]interface{}) error {
+	return func(dc driverapi.DriverCallback, config map[string]interface{}) error {
+		if !isValidNetworkType(networkType) {
+			return types.BadRequestErrorf("Network type not supported: %s", networkType)
+		}
+
+		return dc.RegisterDriver(networkType, newDriver(networkType), driverapi.Capability{
+			DataScope: datastore.LocalScope,
+		})
+	}
+}
+
+func (d *driver) getNetwork(id string) (*hnsNetwork, error) {
+	d.Lock()
+	defer d.Unlock()
+
+	if nw, ok := d.networks[id]; ok {
+		return nw, nil
+	}
+
+	return nil, types.NotFoundErrorf("network not found: %s", id)
+}
+
+func (n *hnsNetwork) getEndpoint(eid string) (*hnsEndpoint, error) {
+	n.Lock()
+	defer n.Unlock()
+
+	if ep, ok := n.endpoints[eid]; ok {
+		return ep, nil
+	}
+
+	return nil, types.NotFoundErrorf("Endpoint not found: %s", eid)
+}
+
+func (d *driver) parseNetworkOptions(id string, genericOptions map[string]string) (*networkConfiguration, error) {
+	config := &networkConfiguration{}
 
-// TODO Windows. This is a placeholder for now
+	for label, value := range genericOptions {
+		switch label {
+		case NetworkName:
+			config.Name = value
+		case HNSID:
+			config.HnsID = value
+		case RoutingDomain:
+			config.RDID = value
+		}
+	}
 
-type driver struct{}
+	config.ID = id
+	config.Type = d.name
+	return config, nil
+}
+
+func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error {
+	if len(ipamV6Data) > 0 {
+		return types.ForbiddenErrorf("windowsshim driver doesnt support v6 subnets")
+	}
 
-// Init registers a new instance of null driver
-func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
-	c := driverapi.Capability{
-		DataScope: datastore.LocalScope,
+	if len(ipamV4Data) == 0 {
+		return types.BadRequestErrorf("network %s requires ipv4 configuration", id)
 	}
-	return dc.RegisterDriver(networkType, &driver{}, c)
+
+	return nil
 }
 
+// Create a new network
 func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
+	if _, err := d.getNetwork(id); err == nil {
+		return types.ForbiddenErrorf("network %s exists", id)
+	}
+
+	genData, ok := option[netlabel.GenericData].(map[string]string)
+	if !ok {
+		return fmt.Errorf("Unknown generic data option")
+	}
+
+	// Parse and validate the config. It should not conflict with existing networks' config
+	config, err := d.parseNetworkOptions(id, genData)
+	if err != nil {
+		return err
+	}
+
+	err = config.processIPAM(id, ipV4Data, ipV6Data)
+	if err != nil {
+		return err
+	}
+
+	network := &hnsNetwork{
+		id:        config.ID,
+		endpoints: make(map[string]*hnsEndpoint),
+		config:    config,
+		driver:    d,
+	}
+
+	d.Lock()
+	d.networks[config.ID] = network
+	d.Unlock()
+
+	// A non blank hnsid indicates that the network was discovered
+	// from HNS. No need to call HNS if this network was discovered
+	// from HNS
+	if config.HnsID == "" {
+		subnets := []hcsshim.Subnet{}
+
+		for _, ipData := range ipV4Data {
+			subnet := hcsshim.Subnet{
+				AddressPrefix:  ipData.Pool.String(),
+				GatewayAddress: ipData.Gateway.IP.String(),
+			}
+
+			subnets = append(subnets, subnet)
+		}
+
+		network := &hcsshim.HNSNetwork{
+			Name:    config.Name,
+			Type:    d.name,
+			Subnets: subnets,
+		}
+
+		if network.Name == "" {
+			network.Name = id
+		}
+
+		configurationb, err := json.Marshal(network)
+		if err != nil {
+			return err
+		}
+
+		configuration := string(configurationb)
+		log.Debugf("HNSNetwork Request =%v Address Space=%v", configuration, subnets)
+
+		hnsresponse, err := hcsshim.HNSNetworkRequest("POST", "", configuration)
+		if err != nil {
+			return err
+		}
+
+		config.HnsID = hnsresponse.Id
+		genData[HNSID] = config.HnsID
+	}
+
 	return nil
 }
 
 func (d *driver) DeleteNetwork(nid string) error {
+	n, err := d.getNetwork(nid)
+	if err != nil {
+		return types.InternalMaskableErrorf("%s", err)
+	}
+
+	n.Lock()
+	config := n.config
+	n.Unlock()
+
+	// Cannot remove network if endpoints are still present
+	if len(n.endpoints) != 0 {
+		return fmt.Errorf("network %s has active endpoint", n.id)
+	}
+
+	_, err = hcsshim.HNSNetworkRequest("DELETE", config.HnsID, "")
+	if err != nil {
+		return err
+	}
+
+	d.Lock()
+	delete(d.networks, nid)
+	d.Unlock()
+
 	return nil
 }
 
+func convertPortBindings(portBindings []types.PortBinding) ([]json.RawMessage, error) {
+	var pbs []json.RawMessage
+
+	// Enumerate through the port bindings specified by the user and convert
+	// them into the internal structure matching the JSON blob that can be
+	// understood by the HCS.
+	for _, elem := range portBindings {
+		proto := strings.ToUpper(elem.Proto.String())
+		if proto != "TCP" && proto != "UDP" {
+			return nil, fmt.Errorf("invalid protocol %s", elem.Proto.String())
+		}
+
+		if elem.HostPort != elem.HostPortEnd {
+			return nil, fmt.Errorf("Windows does not support more than one host port in NAT settings")
+		}
+
+		if len(elem.HostIP) != 0 {
+			return nil, fmt.Errorf("Windows does not support host IP addresses in NAT settings")
+		}
+
+		encodedPolicy, err := json.Marshal(hcsshim.NatPolicy{
+			Type:         "NAT",
+			ExternalPort: elem.HostPort,
+			InternalPort: elem.Port,
+			Protocol:     elem.Proto.String(),
+		})
+
+		if err != nil {
+			return nil, err
+		}
+		pbs = append(pbs, encodedPolicy)
+	}
+	return pbs, nil
+}
+
 func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
+	n, err := d.getNetwork(nid)
+	if err != nil {
+		return err
+	}
+
+	// Check if endpoint id is good and retrieve corresponding endpoint
+	ep, err := n.getEndpoint(eid)
+	if err == nil && ep != nil {
+		return driverapi.ErrEndpointExists(eid)
+	}
+
+	endpointStruct := &hcsshim.HNSEndpoint{
+		VirtualNetwork: n.config.HnsID,
+	}
+
+	// Convert the port mapping for the network
+	if opt, ok := epOptions[netlabel.PortMap]; ok {
+		if bs, ok := opt.([]types.PortBinding); ok {
+			endpointStruct.Policies, err = convertPortBindings(bs)
+			if err != nil {
+				return err
+			}
+		} else {
+			return fmt.Errorf("Invalid endpoint configuration for endpoint id%s", eid)
+		}
+	}
+
+	configurationb, err := json.Marshal(endpointStruct)
+	if err != nil {
+		return err
+	}
+
+	hnsresponse, err := hcsshim.HNSEndpointRequest("POST", "", string(configurationb))
+	if err != nil {
+		return err
+	}
+
+	mac, err := net.ParseMAC(hnsresponse.MacAddress)
+	if err != nil {
+		return err
+	}
+
+	// TODO For now the ip mask is not in the info generated by HNS
+	endpoint := &hnsEndpoint{
+		id:         eid,
+		addr:       &net.IPNet{IP: hnsresponse.IPAddress, Mask: hnsresponse.IPAddress.DefaultMask()},
+		macAddress: mac,
+	}
+	endpoint.profileID = hnsresponse.Id
+	n.Lock()
+	n.endpoints[eid] = endpoint
+	n.Unlock()
+
+	ifInfo.SetIPAddress(endpoint.addr)
+	ifInfo.SetMacAddress(endpoint.macAddress)
+
 	return nil
 }
 
 func (d *driver) DeleteEndpoint(nid, eid string) error {
+	n, err := d.getNetwork(nid)
+	if err != nil {
+		return types.InternalMaskableErrorf("%s", err)
+	}
+
+	ep, err := n.getEndpoint(eid)
+	if err != nil {
+		return err
+	}
+
+	n.Lock()
+	delete(n.endpoints, eid)
+	n.Unlock()
+
+	_, err = hcsshim.HNSEndpointRequest("DELETE", ep.profileID, "")
+	if err != nil {
+		return err
+	}
+
 	return nil
 }
 
 func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
-	return make(map[string]interface{}, 0), nil
+	network, err := d.getNetwork(nid)
+	if err != nil {
+		return nil, err
+	}
+
+	endpoint, err := network.getEndpoint(eid)
+	if err != nil {
+		return nil, err
+	}
+
+	data := make(map[string]interface{}, 1)
+	data["hnsid"] = endpoint.profileID
+	return data, nil
 }
 
 // Join method is invoked when a Sandbox is attached to an endpoint.
 func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
+	network, err := d.getNetwork(nid)
+	if err != nil {
+		return err
+	}
+
+	// Ensure that the endpoint exists
+	_, err = network.getEndpoint(eid)
+	if err != nil {
+		return err
+	}
+
+	// This is just a stub for now
+
+	jinfo.DisableGatewayService()
 	return nil
 }
 
 // Leave method is invoked when a Sandbox detaches from an endpoint.
 func (d *driver) Leave(nid, eid string) error {
+	network, err := d.getNetwork(nid)
+	if err != nil {
+		return types.InternalMaskableErrorf("%s", err)
+	}
+
+	// Ensure that the endpoint exists
+	_, err = network.getEndpoint(eid)
+	if err != nil {
+		return err
+	}
+
+	// This is just a stub for now
+
 	return nil
 }
 
 func (d *driver) Type() string {
-	return networkType
+	return d.name
 }
 
 // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster

+ 9 - 2
vendor/src/github.com/docker/libnetwork/drivers_windows.go

@@ -1,9 +1,16 @@
 package libnetwork
 
-import "github.com/docker/libnetwork/drivers/windows"
+import (
+	"github.com/docker/libnetwork/drivers/null"
+	"github.com/docker/libnetwork/drivers/windows"
+)
 
 func getInitializers() []initializer {
 	return []initializer{
-		{windows.Init, "windows"},
+		{null.Init, "null"},
+		{windows.GetInit("Transparent"), "Transparent"},
+		{windows.GetInit("L2Bridge"), "L2Bridge"},
+		{windows.GetInit("L2Tunnel"), "L2Tunnel"},
+		{windows.GetInit("NAT"), "NAT"},
 	}
 }

+ 62 - 13
vendor/src/github.com/docker/libnetwork/ipam/allocator.go

@@ -8,6 +8,7 @@ import (
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/bitseq"
 	"github.com/docker/libnetwork/datastore"
+	"github.com/docker/libnetwork/discoverapi"
 	"github.com/docker/libnetwork/ipamapi"
 	"github.com/docker/libnetwork/ipamutils"
 	"github.com/docker/libnetwork/types"
@@ -60,19 +61,9 @@ func NewAllocator(lcDs, glDs datastore.DataStore) (*Allocator, error) {
 		if aspc.ds == nil {
 			continue
 		}
-
-		a.addrSpaces[aspc.as] = &addrSpace{
-			subnets: map[SubnetKey]*PoolData{},
-			id:      dsConfigKey + "/" + aspc.as,
-			scope:   aspc.ds.Scope(),
-			ds:      aspc.ds,
-			alloc:   a,
-		}
+		a.initializeAddressSpace(aspc.as, aspc.ds)
 	}
 
-	a.checkConsistency(localAddressSpace)
-	a.checkConsistency(globalAddressSpace)
-
 	return a, nil
 }
 
@@ -118,25 +109,83 @@ func (a *Allocator) updateBitMasks(aSpace *addrSpace) error {
 	return nil
 }
 
-// Checks for and fixes damaged bitmask. Meant to be called in constructor only.
+// Checks for and fixes damaged bitmask.
 func (a *Allocator) checkConsistency(as string) {
+	var sKeyList []SubnetKey
+
 	// Retrieve this address space's configuration and bitmasks from the datastore
 	a.refresh(as)
+	a.Lock()
 	aSpace, ok := a.addrSpaces[as]
+	a.Unlock()
 	if !ok {
 		return
 	}
 	a.updateBitMasks(aSpace)
+
+	aSpace.Lock()
 	for sk, pd := range aSpace.subnets {
 		if pd.Range != nil {
 			continue
 		}
-		if err := a.addresses[sk].CheckConsistency(); err != nil {
+		sKeyList = append(sKeyList, sk)
+	}
+	aSpace.Unlock()
+
+	for _, sk := range sKeyList {
+		a.Lock()
+		bm := a.addresses[sk]
+		a.Unlock()
+		if err := bm.CheckConsistency(); err != nil {
 			log.Warnf("Error while running consistency check for %s: %v", sk, err)
 		}
 	}
 }
 
+func (a *Allocator) initializeAddressSpace(as string, ds datastore.DataStore) error {
+	a.Lock()
+	if _, ok := a.addrSpaces[as]; ok {
+		a.Unlock()
+		return types.ForbiddenErrorf("tried to add an axisting address space: %s", as)
+	}
+	a.addrSpaces[as] = &addrSpace{
+		subnets: map[SubnetKey]*PoolData{},
+		id:      dsConfigKey + "/" + as,
+		scope:   ds.Scope(),
+		ds:      ds,
+		alloc:   a,
+	}
+	a.Unlock()
+
+	a.checkConsistency(as)
+
+	return nil
+}
+
+// DiscoverNew informs the allocator about a new global scope datastore
+func (a *Allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
+	if dType != discoverapi.DatastoreConfig {
+		return nil
+	}
+
+	dsc, ok := data.(discoverapi.DatastoreConfigData)
+	if !ok {
+		return types.InternalErrorf("incorrect data in datastore update notification: %v", data)
+	}
+
+	ds, err := datastore.NewDataStoreFromConfig(dsc)
+	if err != nil {
+		return err
+	}
+
+	return a.initializeAddressSpace(globalAddressSpace, ds)
+}
+
+// DiscoverDelete is a notification of no interest for the allocator
+func (a *Allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
+	return nil
+}
+
 // GetDefaultAddressSpaces returns the local and global default address spaces
 func (a *Allocator) GetDefaultAddressSpaces() (string, string, error) {
 	return localAddressSpace, globalAddressSpace, nil

+ 3 - 0
vendor/src/github.com/docker/libnetwork/ipamapi/contract.go

@@ -4,6 +4,7 @@ package ipamapi
 import (
 	"net"
 
+	"github.com/docker/libnetwork/discoverapi"
 	"github.com/docker/libnetwork/types"
 )
 
@@ -56,6 +57,8 @@ var (
 // Ipam represents the interface the IPAM service plugins must implement
 // in order to allow injection/modification of IPAM database.
 type Ipam interface {
+	discoverapi.Discover
+
 	// GetDefaultAddressSpaces returns the default local and global address spaces for this ipam
 	GetDefaultAddressSpaces() (string, string, error)
 	// RequestPool returns an address pool along with its unique id. Address space is a mandatory field

+ 2 - 0
vendor/src/github.com/docker/libnetwork/ipams/builtin/builtin.go → vendor/src/github.com/docker/libnetwork/ipams/builtin/builtin_unix.go

@@ -1,3 +1,5 @@
+// +build linux freebsd
+
 package builtin
 
 import (

+ 16 - 0
vendor/src/github.com/docker/libnetwork/ipams/builtin/builtin_windows.go

@@ -0,0 +1,16 @@
+// +build windows
+
+package builtin
+
+import (
+	"github.com/docker/libnetwork/ipamapi"
+
+	windowsipam "github.com/docker/libnetwork/ipams/windowsipam"
+)
+
+// Init registers the built-in ipam service with libnetwork
+func Init(ic ipamapi.Callback, l, g interface{}) error {
+	initFunc := windowsipam.GetInit(ipamapi.DefaultIPAM)
+
+	return initFunc(ic, l, g)
+}

+ 11 - 0
vendor/src/github.com/docker/libnetwork/ipams/remote/remote.go

@@ -6,6 +6,7 @@ import (
 
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/plugins"
+	"github.com/docker/libnetwork/discoverapi"
 	"github.com/docker/libnetwork/ipamapi"
 	"github.com/docker/libnetwork/ipams/remote/api"
 	"github.com/docker/libnetwork/types"
@@ -124,3 +125,13 @@ func (a *allocator) ReleaseAddress(poolID string, address net.IP) error {
 	res := &api.ReleaseAddressResponse{}
 	return a.call("ReleaseAddress", req, res)
 }
+
+// DiscoverNew is a notification for a new discovery event, such as a new global datastore
+func (a *allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
+	return nil
+}
+
+// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
+func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
+	return nil
+}

+ 93 - 0
vendor/src/github.com/docker/libnetwork/ipams/windowsipam/windowsipam.go

@@ -0,0 +1,93 @@
+package windowsipam
+
+import (
+	"net"
+
+	log "github.com/Sirupsen/logrus"
+	"github.com/docker/libnetwork/discoverapi"
+	"github.com/docker/libnetwork/ipamapi"
+	"github.com/docker/libnetwork/types"
+)
+
+const (
+	localAddressSpace  = "LocalDefault"
+	globalAddressSpace = "GlobalDefault"
+)
+
+var (
+	defaultPool, _ = types.ParseCIDR("0.0.0.0/0")
+)
+
+type allocator struct {
+}
+
+// GetInit registers the built-in ipam service with libnetwork
+func GetInit(ipamName string) func(ic ipamapi.Callback, l, g interface{}) error {
+	return func(ic ipamapi.Callback, l, g interface{}) error {
+		return ic.RegisterIpamDriver(ipamName, &allocator{})
+	}
+}
+
+func (a *allocator) GetDefaultAddressSpaces() (string, string, error) {
+	return localAddressSpace, globalAddressSpace, nil
+}
+
+// RequestPool returns an address pool along with its unique id. This is a null ipam driver. It allocates the
+// subnet user asked and does not validate anything. Doesnt support subpool allocation
+func (a *allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
+	log.Debugf("RequestPool(%s, %s, %s, %v, %t)", addressSpace, pool, subPool, options, v6)
+	if subPool != "" || v6 {
+		return "", nil, nil, types.InternalErrorf("This request is not supported by null ipam driver")
+	}
+
+	var ipNet *net.IPNet
+	var err error
+
+	if pool != "" {
+		_, ipNet, err = net.ParseCIDR(pool)
+		if err != nil {
+			return "", nil, nil, err
+		}
+	} else {
+		ipNet = defaultPool
+	}
+
+	return ipNet.String(), ipNet, nil, nil
+}
+
+// ReleasePool releases the address pool - always succeeds
+func (a *allocator) ReleasePool(poolID string) error {
+	log.Debugf("ReleasePool(%s)", poolID)
+	return nil
+}
+
+// RequestAddress returns an address from the specified pool ID.
+// Always allocate the 0.0.0.0/32 ip if no preferred address was specified
+func (a *allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[string]string) (*net.IPNet, map[string]string, error) {
+	log.Debugf("RequestAddress(%s, %v, %v) %s", poolID, prefAddress, opts, opts["RequestAddressType"])
+	_, ipNet, err := net.ParseCIDR(poolID)
+
+	if err != nil {
+		return nil, nil, err
+	}
+	if prefAddress == nil {
+		return ipNet, nil, nil
+	}
+	return &net.IPNet{IP: prefAddress, Mask: ipNet.Mask}, nil, nil
+}
+
+// ReleaseAddress releases the address - always succeeds
+func (a *allocator) ReleaseAddress(poolID string, address net.IP) error {
+	log.Debugf("ReleaseAddress(%s, %v)", poolID, address)
+	return nil
+}
+
+// DiscoverNew informs the allocator about a new global scope datastore
+func (a *allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
+	return nil
+}
+
+// DiscoverDelete is a notification of no interest for the allocator
+func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
+	return nil
+}

+ 11 - 0
vendor/src/github.com/docker/libnetwork/netlabel/labels.go

@@ -56,6 +56,9 @@ var (
 	// GlobalKVProviderConfig constant represents the KV provider Config
 	GlobalKVProviderConfig = MakeKVProviderConfig("global")
 
+	// GlobalKVClient constants represents the global kv store client
+	GlobalKVClient = MakeKVClient("global")
+
 	// LocalKVProvider constant represents the KV provider backend
 	LocalKVProvider = MakeKVProvider("local")
 
@@ -64,6 +67,9 @@ var (
 
 	// LocalKVProviderConfig constant represents the KV provider Config
 	LocalKVProviderConfig = MakeKVProviderConfig("local")
+
+	// LocalKVClient constants represents the local kv store client
+	LocalKVClient = MakeKVClient("local")
 )
 
 // MakeKVProvider returns the kvprovider label for the scope
@@ -81,6 +87,11 @@ func MakeKVProviderConfig(scope string) string {
 	return DriverPrivatePrefix + scope + "kv_provider_config"
 }
 
+// MakeKVClient returns the kv client label for the scope
+func MakeKVClient(scope string) string {
+	return DriverPrivatePrefix + scope + "kv_client"
+}
+
 // Key extracts the key portion of the label
 func Key(label string) (key string) {
 	if kv := strings.SplitN(label, "=", 2); len(kv) > 0 {

+ 1 - 1
vendor/src/github.com/docker/libnetwork/network.go

@@ -1004,7 +1004,7 @@ func (n *network) ipamAllocateVersion(ipVer int, ipam ipamapi.Ipam) error {
 		if ipVer == 6 {
 			return nil
 		}
-		*cfgList = []*IpamConf{&IpamConf{}}
+		*cfgList = []*IpamConf{{}}
 	}
 
 	*infoList = make([]*IpamInfo, len(*cfgList))

+ 1 - 1
vendor/src/github.com/docker/libnetwork/portmapper/proxy.go

@@ -85,7 +85,7 @@ func handleStopSignals(p proxy.Proxy) {
 	s := make(chan os.Signal, 10)
 	signal.Notify(s, os.Interrupt, syscall.SIGTERM, syscall.SIGSTOP)
 
-	for _ = range s {
+	for range s {
 		p.Close()
 
 		os.Exit(0)

+ 10 - 1
vendor/src/github.com/docker/libnetwork/resolver.go

@@ -35,7 +35,7 @@ const (
 	dnsPort       = "53"
 	ptrIPv4domain = ".in-addr.arpa."
 	ptrIPv6domain = ".ip6.arpa."
-	respTTL       = 1800
+	respTTL       = 600
 	maxExtDNS     = 3 //max number of external servers to try
 )
 
@@ -147,6 +147,10 @@ func (r *resolver) ResolverOptions() []string {
 	return []string{"ndots:0"}
 }
 
+func setCommonFlags(msg *dns.Msg) {
+	msg.RecursionAvailable = true
+}
+
 func (r *resolver) handleIPv4Query(name string, query *dns.Msg) (*dns.Msg, error) {
 	addr := r.sb.ResolveName(name)
 	if addr == nil {
@@ -157,6 +161,7 @@ func (r *resolver) handleIPv4Query(name string, query *dns.Msg) (*dns.Msg, error
 
 	resp := new(dns.Msg)
 	resp.SetReply(query)
+	setCommonFlags(resp)
 
 	rr := new(dns.A)
 	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)
 
 	resp := new(dns.Msg)
 	resp.SetReply(query)
+	setCommonFlags(resp)
 
 	rr := new(dns.PTR)
 	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) {
 		err  error
 	)
 
+	if query == nil || len(query.Question) == 0 {
+		return
+	}
 	name := query.Question[0].Name
 	if query.Question[0].Qtype == dns.TypeA {
 		resp, err = r.handleIPv4Query(name, query)

+ 0 - 312
vendor/src/github.com/docker/libnetwork/sandbox.go

@@ -4,19 +4,13 @@ import (
 	"container/heap"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"net"
-	"os"
-	"path"
-	"path/filepath"
 	"strings"
 	"sync"
 
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/etchosts"
-	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/osl"
-	"github.com/docker/libnetwork/resolvconf"
 	"github.com/docker/libnetwork/types"
 )
 
@@ -309,46 +303,6 @@ func (sb *sandbox) UnmarshalJSON(b []byte) (err error) {
 	return nil
 }
 
-func (sb *sandbox) startResolver() {
-	sb.resolverOnce.Do(func() {
-		var err error
-		sb.resolver = NewResolver(sb)
-		defer func() {
-			if err != nil {
-				sb.resolver = nil
-			}
-		}()
-
-		err = sb.rebuildDNS()
-		if err != nil {
-			log.Errorf("Updating resolv.conf failed for container %s, %q", sb.ContainerID(), err)
-			return
-		}
-		sb.resolver.SetExtServers(sb.extDNS)
-
-		sb.osSbox.InvokeFunc(sb.resolver.SetupFunc())
-		if err = sb.resolver.Start(); err != nil {
-			log.Errorf("Resolver Setup/Start failed for container %s, %q", sb.ContainerID(), err)
-		}
-	})
-}
-
-func (sb *sandbox) setupResolutionFiles() error {
-	if err := sb.buildHostsFile(); err != nil {
-		return err
-	}
-
-	if err := sb.updateParentHosts(); err != nil {
-		return err
-	}
-
-	if err := sb.setupDNS(); err != nil {
-		return err
-	}
-
-	return nil
-}
-
 func (sb *sandbox) Endpoints() []Endpoint {
 	sb.Lock()
 	defer sb.Unlock()
@@ -753,243 +707,6 @@ func (sb *sandbox) clearNetworkResources(origEp *endpoint) error {
 	return nil
 }
 
-const (
-	defaultPrefix = "/var/lib/docker/network/files"
-	dirPerm       = 0755
-	filePerm      = 0644
-)
-
-func (sb *sandbox) buildHostsFile() error {
-	if sb.config.hostsPath == "" {
-		sb.config.hostsPath = defaultPrefix + "/" + sb.id + "/hosts"
-	}
-
-	dir, _ := filepath.Split(sb.config.hostsPath)
-	if err := createBasePath(dir); err != nil {
-		return err
-	}
-
-	// This is for the host mode networking
-	if sb.config.originHostsPath != "" {
-		if err := copyFile(sb.config.originHostsPath, sb.config.hostsPath); err != nil && !os.IsNotExist(err) {
-			return types.InternalErrorf("could not copy source hosts file %s to %s: %v", sb.config.originHostsPath, sb.config.hostsPath, err)
-		}
-		return nil
-	}
-
-	extraContent := make([]etchosts.Record, 0, len(sb.config.extraHosts))
-	for _, extraHost := range sb.config.extraHosts {
-		extraContent = append(extraContent, etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
-	}
-
-	return etchosts.Build(sb.config.hostsPath, "", sb.config.hostName, sb.config.domainName, extraContent)
-}
-
-func (sb *sandbox) updateHostsFile(ifaceIP string) error {
-	var mhost string
-
-	if sb.config.originHostsPath != "" {
-		return nil
-	}
-
-	if sb.config.domainName != "" {
-		mhost = fmt.Sprintf("%s.%s %s", sb.config.hostName, sb.config.domainName,
-			sb.config.hostName)
-	} else {
-		mhost = sb.config.hostName
-	}
-
-	extraContent := []etchosts.Record{{Hosts: mhost, IP: ifaceIP}}
-
-	sb.addHostsEntries(extraContent)
-	return nil
-}
-
-func (sb *sandbox) addHostsEntries(recs []etchosts.Record) {
-	if err := etchosts.Add(sb.config.hostsPath, recs); err != nil {
-		log.Warnf("Failed adding service host entries to the running container: %v", err)
-	}
-}
-
-func (sb *sandbox) deleteHostsEntries(recs []etchosts.Record) {
-	if err := etchosts.Delete(sb.config.hostsPath, recs); err != nil {
-		log.Warnf("Failed deleting service host entries to the running container: %v", err)
-	}
-}
-
-func (sb *sandbox) updateParentHosts() error {
-	var pSb Sandbox
-
-	for _, update := range sb.config.parentUpdates {
-		sb.controller.WalkSandboxes(SandboxContainerWalker(&pSb, update.cid))
-		if pSb == nil {
-			continue
-		}
-		if err := etchosts.Update(pSb.(*sandbox).config.hostsPath, update.ip, update.name); err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
-
-func (sb *sandbox) setupDNS() error {
-	var newRC *resolvconf.File
-
-	if sb.config.resolvConfPath == "" {
-		sb.config.resolvConfPath = defaultPrefix + "/" + sb.id + "/resolv.conf"
-	}
-
-	sb.config.resolvConfHashFile = sb.config.resolvConfPath + ".hash"
-
-	dir, _ := filepath.Split(sb.config.resolvConfPath)
-	if err := createBasePath(dir); err != nil {
-		return err
-	}
-
-	// This is for the host mode networking
-	if sb.config.originResolvConfPath != "" {
-		if err := copyFile(sb.config.originResolvConfPath, sb.config.resolvConfPath); err != nil {
-			return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", sb.config.originResolvConfPath, sb.config.resolvConfPath, err)
-		}
-		return nil
-	}
-
-	currRC, err := resolvconf.Get()
-	if err != nil {
-		return err
-	}
-
-	if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
-		var (
-			err            error
-			dnsList        = resolvconf.GetNameservers(currRC.Content, netutils.IP)
-			dnsSearchList  = resolvconf.GetSearchDomains(currRC.Content)
-			dnsOptionsList = resolvconf.GetOptions(currRC.Content)
-		)
-		if len(sb.config.dnsList) > 0 {
-			dnsList = sb.config.dnsList
-		}
-		if len(sb.config.dnsSearchList) > 0 {
-			dnsSearchList = sb.config.dnsSearchList
-		}
-		if len(sb.config.dnsOptionsList) > 0 {
-			dnsOptionsList = sb.config.dnsOptionsList
-		}
-		newRC, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
-		if err != nil {
-			return err
-		}
-	} else {
-		// Replace any localhost/127.* (at this point we have no info about ipv6, pass it as true)
-		if newRC, err = resolvconf.FilterResolvDNS(currRC.Content, true); err != nil {
-			return err
-		}
-		// No contention on container resolv.conf file at sandbox creation
-		if err := ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, filePerm); err != nil {
-			return types.InternalErrorf("failed to write unhaltered resolv.conf file content when setting up dns for sandbox %s: %v", sb.ID(), err)
-		}
-	}
-
-	// Write hash
-	if err := ioutil.WriteFile(sb.config.resolvConfHashFile, []byte(newRC.Hash), filePerm); err != nil {
-		return types.InternalErrorf("failed to write resolv.conf hash file when setting up dns for sandbox %s: %v", sb.ID(), err)
-	}
-
-	return nil
-}
-
-func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
-	var (
-		currHash string
-		hashFile = sb.config.resolvConfHashFile
-	)
-
-	// This is for the host mode networking
-	if sb.config.originResolvConfPath != "" {
-		return nil
-	}
-
-	if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
-		return nil
-	}
-
-	currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath)
-	if err != nil {
-		if !os.IsNotExist(err) {
-			return err
-		}
-	} else {
-		h, err := ioutil.ReadFile(hashFile)
-		if err != nil {
-			if !os.IsNotExist(err) {
-				return err
-			}
-		} else {
-			currHash = string(h)
-		}
-	}
-
-	if currHash != "" && currHash != currRC.Hash {
-		// Seems the user has changed the container resolv.conf since the last time
-		// we checked so return without doing anything.
-		log.Infof("Skipping update of resolv.conf file with ipv6Enabled: %t because file was touched by user", ipv6Enabled)
-		return nil
-	}
-
-	// replace any localhost/127.* and remove IPv6 nameservers if IPv6 disabled.
-	newRC, err := resolvconf.FilterResolvDNS(currRC.Content, ipv6Enabled)
-	if err != nil {
-		return err
-	}
-	err = ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, 0644)
-	if err != nil {
-		return err
-	}
-
-	// write the new hash in a temp file and rename it to make the update atomic
-	dir := path.Dir(sb.config.resolvConfPath)
-	tmpHashFile, err := ioutil.TempFile(dir, "hash")
-	if err != nil {
-		return err
-	}
-	if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newRC.Hash), filePerm); err != nil {
-		return err
-	}
-	return os.Rename(tmpHashFile.Name(), hashFile)
-}
-
-// Embedded DNS server has to be enabled for this sandbox. Rebuild the container's
-// resolv.conf by doing the follwing
-// - Save the external name servers in resolv.conf in the sandbox
-// - Add only the embedded server's IP to container's resolv.conf
-// - If the embedded server needs any resolv.conf options add it to the current list
-func (sb *sandbox) rebuildDNS() error {
-	currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath)
-	if err != nil {
-		return err
-	}
-
-	// localhost entries have already been filtered out from the list
-	// retain only the v4 servers in sb for forwarding the DNS queries
-	sb.extDNS = resolvconf.GetNameservers(currRC.Content, netutils.IPv4)
-
-	var (
-		dnsList        = []string{sb.resolver.NameServer()}
-		dnsOptionsList = resolvconf.GetOptions(currRC.Content)
-		dnsSearchList  = resolvconf.GetSearchDomains(currRC.Content)
-	)
-
-	// external v6 DNS servers has to be listed in resolv.conf
-	dnsList = append(dnsList, resolvconf.GetNameservers(currRC.Content, netutils.IPv6)...)
-
-	// Resolver returns the options in the format resolv.conf expects
-	dnsOptionsList = append(dnsOptionsList, sb.resolver.ResolverOptions()...)
-
-	_, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
-	return err
-}
-
 // joinLeaveStart waits to ensure there are no joins or leaves in progress and
 // marks this join/leave in progress without race
 func (sb *sandbox) joinLeaveStart() {
@@ -1191,32 +908,3 @@ func (eh *epHeap) Pop() interface{} {
 	*eh = old[0 : n-1]
 	return x
 }
-
-func createBasePath(dir string) error {
-	return os.MkdirAll(dir, dirPerm)
-}
-
-func createFile(path string) error {
-	var f *os.File
-
-	dir, _ := filepath.Split(path)
-	err := createBasePath(dir)
-	if err != nil {
-		return err
-	}
-
-	f, err = os.Create(path)
-	if err == nil {
-		f.Close()
-	}
-
-	return err
-}
-
-func copyFile(src, dst string) error {
-	sBytes, err := ioutil.ReadFile(src)
-	if err != nil {
-		return err
-	}
-	return ioutil.WriteFile(dst, sBytes, filePerm)
-}

+ 323 - 0
vendor/src/github.com/docker/libnetwork/sandbox_dns_unix.go

@@ -0,0 +1,323 @@
+// +build !windows
+
+package libnetwork
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path"
+	"path/filepath"
+
+	log "github.com/Sirupsen/logrus"
+	"github.com/docker/libnetwork/etchosts"
+	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/resolvconf"
+	"github.com/docker/libnetwork/types"
+)
+
+const (
+	defaultPrefix = "/var/lib/docker/network/files"
+	dirPerm       = 0755
+	filePerm      = 0644
+)
+
+func (sb *sandbox) startResolver() {
+	sb.resolverOnce.Do(func() {
+		var err error
+		sb.resolver = NewResolver(sb)
+		defer func() {
+			if err != nil {
+				sb.resolver = nil
+			}
+		}()
+
+		err = sb.rebuildDNS()
+		if err != nil {
+			log.Errorf("Updating resolv.conf failed for container %s, %q", sb.ContainerID(), err)
+			return
+		}
+		sb.resolver.SetExtServers(sb.extDNS)
+
+		sb.osSbox.InvokeFunc(sb.resolver.SetupFunc())
+		if err = sb.resolver.Start(); err != nil {
+			log.Errorf("Resolver Setup/Start failed for container %s, %q", sb.ContainerID(), err)
+		}
+	})
+}
+
+func (sb *sandbox) setupResolutionFiles() error {
+	if err := sb.buildHostsFile(); err != nil {
+		return err
+	}
+
+	if err := sb.updateParentHosts(); err != nil {
+		return err
+	}
+
+	if err := sb.setupDNS(); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (sb *sandbox) buildHostsFile() error {
+	if sb.config.hostsPath == "" {
+		sb.config.hostsPath = defaultPrefix + "/" + sb.id + "/hosts"
+	}
+
+	dir, _ := filepath.Split(sb.config.hostsPath)
+	if err := createBasePath(dir); err != nil {
+		return err
+	}
+
+	// This is for the host mode networking
+	if sb.config.originHostsPath != "" {
+		if err := copyFile(sb.config.originHostsPath, sb.config.hostsPath); err != nil && !os.IsNotExist(err) {
+			return types.InternalErrorf("could not copy source hosts file %s to %s: %v", sb.config.originHostsPath, sb.config.hostsPath, err)
+		}
+		return nil
+	}
+
+	extraContent := make([]etchosts.Record, 0, len(sb.config.extraHosts))
+	for _, extraHost := range sb.config.extraHosts {
+		extraContent = append(extraContent, etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
+	}
+
+	return etchosts.Build(sb.config.hostsPath, "", sb.config.hostName, sb.config.domainName, extraContent)
+}
+
+func (sb *sandbox) updateHostsFile(ifaceIP string) error {
+	var mhost string
+
+	if sb.config.originHostsPath != "" {
+		return nil
+	}
+
+	if sb.config.domainName != "" {
+		mhost = fmt.Sprintf("%s.%s %s", sb.config.hostName, sb.config.domainName,
+			sb.config.hostName)
+	} else {
+		mhost = sb.config.hostName
+	}
+
+	extraContent := []etchosts.Record{{Hosts: mhost, IP: ifaceIP}}
+
+	sb.addHostsEntries(extraContent)
+	return nil
+}
+
+func (sb *sandbox) addHostsEntries(recs []etchosts.Record) {
+	if err := etchosts.Add(sb.config.hostsPath, recs); err != nil {
+		log.Warnf("Failed adding service host entries to the running container: %v", err)
+	}
+}
+
+func (sb *sandbox) deleteHostsEntries(recs []etchosts.Record) {
+	if err := etchosts.Delete(sb.config.hostsPath, recs); err != nil {
+		log.Warnf("Failed deleting service host entries to the running container: %v", err)
+	}
+}
+
+func (sb *sandbox) updateParentHosts() error {
+	var pSb Sandbox
+
+	for _, update := range sb.config.parentUpdates {
+		sb.controller.WalkSandboxes(SandboxContainerWalker(&pSb, update.cid))
+		if pSb == nil {
+			continue
+		}
+		if err := etchosts.Update(pSb.(*sandbox).config.hostsPath, update.ip, update.name); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (sb *sandbox) setupDNS() error {
+	var newRC *resolvconf.File
+
+	if sb.config.resolvConfPath == "" {
+		sb.config.resolvConfPath = defaultPrefix + "/" + sb.id + "/resolv.conf"
+	}
+
+	sb.config.resolvConfHashFile = sb.config.resolvConfPath + ".hash"
+
+	dir, _ := filepath.Split(sb.config.resolvConfPath)
+	if err := createBasePath(dir); err != nil {
+		return err
+	}
+
+	// This is for the host mode networking
+	if sb.config.originResolvConfPath != "" {
+		if err := copyFile(sb.config.originResolvConfPath, sb.config.resolvConfPath); err != nil {
+			return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", sb.config.originResolvConfPath, sb.config.resolvConfPath, err)
+		}
+		return nil
+	}
+
+	currRC, err := resolvconf.Get()
+	if err != nil {
+		return err
+	}
+
+	if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
+		var (
+			err            error
+			dnsList        = resolvconf.GetNameservers(currRC.Content, netutils.IP)
+			dnsSearchList  = resolvconf.GetSearchDomains(currRC.Content)
+			dnsOptionsList = resolvconf.GetOptions(currRC.Content)
+		)
+		if len(sb.config.dnsList) > 0 {
+			dnsList = sb.config.dnsList
+		}
+		if len(sb.config.dnsSearchList) > 0 {
+			dnsSearchList = sb.config.dnsSearchList
+		}
+		if len(sb.config.dnsOptionsList) > 0 {
+			dnsOptionsList = sb.config.dnsOptionsList
+		}
+		newRC, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
+		if err != nil {
+			return err
+		}
+	} else {
+		// Replace any localhost/127.* (at this point we have no info about ipv6, pass it as true)
+		if newRC, err = resolvconf.FilterResolvDNS(currRC.Content, true); err != nil {
+			return err
+		}
+		// No contention on container resolv.conf file at sandbox creation
+		if err := ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, filePerm); err != nil {
+			return types.InternalErrorf("failed to write unhaltered resolv.conf file content when setting up dns for sandbox %s: %v", sb.ID(), err)
+		}
+	}
+
+	// Write hash
+	if err := ioutil.WriteFile(sb.config.resolvConfHashFile, []byte(newRC.Hash), filePerm); err != nil {
+		return types.InternalErrorf("failed to write resolv.conf hash file when setting up dns for sandbox %s: %v", sb.ID(), err)
+	}
+
+	return nil
+}
+
+func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
+	var (
+		currHash string
+		hashFile = sb.config.resolvConfHashFile
+	)
+
+	// This is for the host mode networking
+	if sb.config.originResolvConfPath != "" {
+		return nil
+	}
+
+	if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
+		return nil
+	}
+
+	currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath)
+	if err != nil {
+		if !os.IsNotExist(err) {
+			return err
+		}
+	} else {
+		h, err := ioutil.ReadFile(hashFile)
+		if err != nil {
+			if !os.IsNotExist(err) {
+				return err
+			}
+		} else {
+			currHash = string(h)
+		}
+	}
+
+	if currHash != "" && currHash != currRC.Hash {
+		// Seems the user has changed the container resolv.conf since the last time
+		// we checked so return without doing anything.
+		log.Infof("Skipping update of resolv.conf file with ipv6Enabled: %t because file was touched by user", ipv6Enabled)
+		return nil
+	}
+
+	// replace any localhost/127.* and remove IPv6 nameservers if IPv6 disabled.
+	newRC, err := resolvconf.FilterResolvDNS(currRC.Content, ipv6Enabled)
+	if err != nil {
+		return err
+	}
+	err = ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, 0644)
+	if err != nil {
+		return err
+	}
+
+	// write the new hash in a temp file and rename it to make the update atomic
+	dir := path.Dir(sb.config.resolvConfPath)
+	tmpHashFile, err := ioutil.TempFile(dir, "hash")
+	if err != nil {
+		return err
+	}
+	if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newRC.Hash), filePerm); err != nil {
+		return err
+	}
+	return os.Rename(tmpHashFile.Name(), hashFile)
+}
+
+// Embedded DNS server has to be enabled for this sandbox. Rebuild the container's
+// resolv.conf by doing the follwing
+// - Save the external name servers in resolv.conf in the sandbox
+// - Add only the embedded server's IP to container's resolv.conf
+// - If the embedded server needs any resolv.conf options add it to the current list
+func (sb *sandbox) rebuildDNS() error {
+	currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath)
+	if err != nil {
+		return err
+	}
+
+	// localhost entries have already been filtered out from the list
+	// retain only the v4 servers in sb for forwarding the DNS queries
+	sb.extDNS = resolvconf.GetNameservers(currRC.Content, netutils.IPv4)
+
+	var (
+		dnsList        = []string{sb.resolver.NameServer()}
+		dnsOptionsList = resolvconf.GetOptions(currRC.Content)
+		dnsSearchList  = resolvconf.GetSearchDomains(currRC.Content)
+	)
+
+	// external v6 DNS servers has to be listed in resolv.conf
+	dnsList = append(dnsList, resolvconf.GetNameservers(currRC.Content, netutils.IPv6)...)
+
+	// Resolver returns the options in the format resolv.conf expects
+	dnsOptionsList = append(dnsOptionsList, sb.resolver.ResolverOptions()...)
+
+	_, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
+	return err
+}
+
+func createBasePath(dir string) error {
+	return os.MkdirAll(dir, dirPerm)
+}
+
+func createFile(path string) error {
+	var f *os.File
+
+	dir, _ := filepath.Split(path)
+	err := createBasePath(dir)
+	if err != nil {
+		return err
+	}
+
+	f, err = os.Create(path)
+	if err == nil {
+		f.Close()
+	}
+
+	return err
+}
+
+func copyFile(src, dst string) error {
+	sBytes, err := ioutil.ReadFile(src)
+	if err != nil {
+		return err
+	}
+	return ioutil.WriteFile(dst, sBytes, filePerm)
+}

+ 32 - 0
vendor/src/github.com/docker/libnetwork/sandbox_dns_windows.go

@@ -0,0 +1,32 @@
+// +build windows
+
+package libnetwork
+
+import (
+	"github.com/docker/libnetwork/etchosts"
+)
+
+// Stub implementations for DNS related functions
+
+func (sb *sandbox) startResolver() {
+}
+
+func (sb *sandbox) setupResolutionFiles() error {
+	return nil
+}
+
+func (sb *sandbox) updateHostsFile(ifaceIP string) error {
+	return nil
+}
+
+func (sb *sandbox) addHostsEntries(recs []etchosts.Record) {
+
+}
+
+func (sb *sandbox) deleteHostsEntries(recs []etchosts.Record) {
+
+}
+
+func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
+	return nil
+}

+ 1 - 1
vendor/src/github.com/docker/libnetwork/sandbox_externalkey_unix.go

@@ -1,4 +1,4 @@
-// +build !windows
+// +build linux freebsd
 
 package libnetwork
 

+ 4 - 0
vendor/src/github.com/docker/libnetwork/store.go

@@ -14,6 +14,7 @@ func (c *controller) initStores() error {
 		return nil
 	}
 	scopeConfigs := c.cfg.Scopes
+	c.stores = nil
 	c.Unlock()
 
 	for scope, scfg := range scopeConfigs {
@@ -418,6 +419,9 @@ func (c *controller) watchLoop() {
 }
 
 func (c *controller) startWatch() {
+	if c.watchCh != nil {
+		return
+	}
 	c.watchCh = make(chan *endpoint)
 	c.unWatchCh = make(chan *endpoint)
 	c.nmap = make(map[string]*netWatch)