Allow passing global datastore to libnetwork and v0.7.0-dev1 vendoring
| ... | ... |
@@ -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 |
|
| ... | ... |
@@ -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)) |
| ... | ... |
@@ -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 |
+} |
| ... | ... |
@@ -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) |