- Updated Dockerfile to satisfy libnetwork GOPATH requirements.
- Reworked daemon to allocate network resources using libnetwork.
- Reworked remove link code to also update network resources in libnetwork.
- Adjusted the exec driver command population to reflect libnetwork design.
- Adjusted the exec driver create command steps.
- Updated a few test cases to reflect the change in design.
- Removed the dns setup code from docker as resolv.conf is entirely managed
in libnetwork.
- Integrated with lxc exec driver.
Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
| ... | ... |
@@ -23,7 +23,6 @@ import ( |
| 23 | 23 |
"github.com/docker/docker/builder" |
| 24 | 24 |
"github.com/docker/docker/cliconfig" |
| 25 | 25 |
"github.com/docker/docker/daemon" |
| 26 |
- "github.com/docker/docker/daemon/networkdriver/bridge" |
|
| 27 | 26 |
"github.com/docker/docker/graph" |
| 28 | 27 |
"github.com/docker/docker/pkg/ioutils" |
| 29 | 28 |
"github.com/docker/docker/pkg/jsonmessage" |
| ... | ... |
@@ -36,6 +35,7 @@ import ( |
| 36 | 36 |
"github.com/docker/docker/pkg/version" |
| 37 | 37 |
"github.com/docker/docker/runconfig" |
| 38 | 38 |
"github.com/docker/docker/utils" |
| 39 |
+ "github.com/docker/libnetwork/portallocator" |
|
| 39 | 40 |
) |
| 40 | 41 |
|
| 41 | 42 |
type ServerConfig struct {
|
| ... | ... |
@@ -1548,8 +1548,9 @@ func allocateDaemonPort(addr string) error {
|
| 1548 | 1548 |
return fmt.Errorf("failed to lookup %s address in host specification", host)
|
| 1549 | 1549 |
} |
| 1550 | 1550 |
|
| 1551 |
+ pa := portallocator.Get() |
|
| 1551 | 1552 |
for _, hostIP := range hostIPs {
|
| 1552 |
- if _, err := bridge.RequestPort(hostIP, "tcp", intPort); err != nil {
|
|
| 1553 |
+ if _, err := pa.RequestPort(hostIP, "tcp", intPort); err != nil {
|
|
| 1553 | 1554 |
return fmt.Errorf("failed to allocate daemon listening port %d (err: %v)", intPort, err)
|
| 1554 | 1555 |
} |
| 1555 | 1556 |
} |
| ... | ... |
@@ -1,8 +1,8 @@ |
| 1 | 1 |
package daemon |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "github.com/docker/docker/daemon/networkdriver" |
|
| 5 |
- "github.com/docker/docker/daemon/networkdriver/bridge" |
|
| 4 |
+ "net" |
|
| 5 |
+ |
|
| 6 | 6 |
"github.com/docker/docker/opts" |
| 7 | 7 |
flag "github.com/docker/docker/pkg/mflag" |
| 8 | 8 |
"github.com/docker/docker/runconfig" |
| ... | ... |
@@ -16,8 +16,9 @@ const ( |
| 16 | 16 |
// CommonConfig defines the configuration of a docker daemon which are |
| 17 | 17 |
// common across platforms. |
| 18 | 18 |
type CommonConfig struct {
|
| 19 |
- AutoRestart bool |
|
| 20 |
- Bridge bridge.Config |
|
| 19 |
+ AutoRestart bool |
|
| 20 |
+ // Bridge holds bridge network specific configuration. |
|
| 21 |
+ Bridge bridgeConfig |
|
| 21 | 22 |
Context map[string][]string |
| 22 | 23 |
CorsHeaders string |
| 23 | 24 |
DisableNetwork bool |
| ... | ... |
@@ -35,6 +36,24 @@ type CommonConfig struct {
|
| 35 | 35 |
TrustKeyPath string |
| 36 | 36 |
} |
| 37 | 37 |
|
| 38 |
+// bridgeConfig stores all the bridge driver specific |
|
| 39 |
+// configuration. |
|
| 40 |
+type bridgeConfig struct {
|
|
| 41 |
+ EnableIPv6 bool |
|
| 42 |
+ EnableIPTables bool |
|
| 43 |
+ EnableIPForward bool |
|
| 44 |
+ EnableIPMasq bool |
|
| 45 |
+ EnableUserlandProxy bool |
|
| 46 |
+ DefaultIP net.IP |
|
| 47 |
+ Iface string |
|
| 48 |
+ IP string |
|
| 49 |
+ FixedCIDR string |
|
| 50 |
+ FixedCIDRv6 string |
|
| 51 |
+ DefaultGatewayIPv4 string |
|
| 52 |
+ DefaultGatewayIPv6 string |
|
| 53 |
+ InterContainerCommunication bool |
|
| 54 |
+} |
|
| 55 |
+ |
|
| 38 | 56 |
// InstallCommonFlags adds command-line options to the top-level flag parser for |
| 39 | 57 |
// the current process. |
| 40 | 58 |
// Subsequent calls to `flag.Parse` will populate config with values parsed |
| ... | ... |
@@ -45,9 +64,9 @@ func (config *Config) InstallCommonFlags() {
|
| 45 | 45 |
flag.StringVar(&config.Root, []string{"g", "-graph"}, defaultGraph, "Root of the Docker runtime")
|
| 46 | 46 |
flag.StringVar(&config.ExecRoot, []string{"-exec-root"}, "/var/run/docker", "Root of the Docker execdriver")
|
| 47 | 47 |
flag.BoolVar(&config.AutoRestart, []string{"#r", "#-restart"}, true, "--restart on the daemon has been deprecated in favor of --restart policies on docker run")
|
| 48 |
- flag.BoolVar(&config.Bridge.EnableIptables, []string{"#iptables", "-iptables"}, true, "Enable addition of iptables rules")
|
|
| 49 |
- flag.BoolVar(&config.Bridge.EnableIpForward, []string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward")
|
|
| 50 |
- flag.BoolVar(&config.Bridge.EnableIpMasq, []string{"-ip-masq"}, true, "Enable IP masquerading")
|
|
| 48 |
+ flag.BoolVar(&config.Bridge.EnableIPTables, []string{"#iptables", "-iptables"}, true, "Enable addition of iptables rules")
|
|
| 49 |
+ flag.BoolVar(&config.Bridge.EnableIPForward, []string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward")
|
|
| 50 |
+ flag.BoolVar(&config.Bridge.EnableIPMasq, []string{"-ip-masq"}, true, "Enable IP masquerading")
|
|
| 51 | 51 |
flag.BoolVar(&config.Bridge.EnableIPv6, []string{"-ipv6"}, false, "Enable IPv6 networking")
|
| 52 | 52 |
flag.StringVar(&config.Bridge.IP, []string{"#bip", "-bip"}, "", "Specify network bridge IP")
|
| 53 | 53 |
flag.StringVar(&config.Bridge.Iface, []string{"b", "-bridge"}, "", "Attach containers to a network bridge")
|
| ... | ... |
@@ -61,7 +80,7 @@ func (config *Config) InstallCommonFlags() {
|
| 61 | 61 |
flag.IntVar(&config.Mtu, []string{"#mtu", "-mtu"}, 0, "Set the containers network MTU")
|
| 62 | 62 |
flag.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "#-api-enable-cors"}, false, "Enable CORS headers in the remote API, this is deprecated by --api-cors-header")
|
| 63 | 63 |
flag.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", "Set CORS headers in the remote API")
|
| 64 |
- opts.IPVar(&config.Bridge.DefaultIp, []string{"#ip", "-ip"}, "0.0.0.0", "Default IP when binding container ports")
|
|
| 64 |
+ opts.IPVar(&config.Bridge.DefaultIP, []string{"#ip", "-ip"}, "0.0.0.0", "Default IP when binding container ports")
|
|
| 65 | 65 |
// FIXME: why the inconsistency between "hosts" and "sockets"? |
| 66 | 66 |
opts.IPListVar(&config.Dns, []string{"#dns", "-dns"}, "DNS server to use")
|
| 67 | 67 |
opts.DnsSearchListVar(&config.DnsSearch, []string{"-dns-search"}, "DNS search domains to use")
|
| ... | ... |
@@ -71,10 +90,3 @@ func (config *Config) InstallCommonFlags() {
|
| 71 | 71 |
flag.BoolVar(&config.Bridge.EnableUserlandProxy, []string{"-userland-proxy"}, true, "Use userland proxy for loopback traffic")
|
| 72 | 72 |
|
| 73 | 73 |
} |
| 74 |
- |
|
| 75 |
-func getDefaultNetworkMtu() int {
|
|
| 76 |
- if iface, err := networkdriver.GetDefaultRouteIface(); err == nil {
|
|
| 77 |
- return iface.MTU |
|
| 78 |
- } |
|
| 79 |
- return defaultNetworkMtu |
|
| 80 |
-} |
| ... | ... |
@@ -252,18 +252,12 @@ func (container *Container) Start() (err error) {
|
| 252 | 252 |
} |
| 253 | 253 |
}() |
| 254 | 254 |
|
| 255 |
- if err := container.setupContainerDns(); err != nil {
|
|
| 256 |
- return err |
|
| 257 |
- } |
|
| 258 | 255 |
if err := container.Mount(); err != nil {
|
| 259 | 256 |
return err |
| 260 | 257 |
} |
| 261 | 258 |
if err := container.initializeNetworking(); err != nil {
|
| 262 | 259 |
return err |
| 263 | 260 |
} |
| 264 |
- if err := container.updateParentsHosts(); err != nil {
|
|
| 265 |
- return err |
|
| 266 |
- } |
|
| 267 | 261 |
container.verifyDaemonSettings() |
| 268 | 262 |
if err := container.prepareVolumes(); err != nil {
|
| 269 | 263 |
return err |
| ... | ... |
@@ -3,11 +3,13 @@ |
| 3 | 3 |
package daemon |
| 4 | 4 |
|
| 5 | 5 |
import ( |
| 6 |
- "bytes" |
|
| 7 | 6 |
"fmt" |
| 8 | 7 |
"io/ioutil" |
| 8 |
+ "net" |
|
| 9 | 9 |
"os" |
| 10 |
+ "path" |
|
| 10 | 11 |
"path/filepath" |
| 12 |
+ "strconv" |
|
| 11 | 13 |
"strings" |
| 12 | 14 |
"syscall" |
| 13 | 15 |
"time" |
| ... | ... |
@@ -15,20 +17,21 @@ import ( |
| 15 | 15 |
"github.com/Sirupsen/logrus" |
| 16 | 16 |
"github.com/docker/docker/daemon/execdriver" |
| 17 | 17 |
"github.com/docker/docker/daemon/network" |
| 18 |
- "github.com/docker/docker/daemon/networkdriver/bridge" |
|
| 19 | 18 |
"github.com/docker/docker/links" |
| 20 | 19 |
"github.com/docker/docker/nat" |
| 21 | 20 |
"github.com/docker/docker/pkg/archive" |
| 22 | 21 |
"github.com/docker/docker/pkg/directory" |
| 23 |
- "github.com/docker/docker/pkg/etchosts" |
|
| 24 | 22 |
"github.com/docker/docker/pkg/ioutils" |
| 25 |
- "github.com/docker/docker/pkg/resolvconf" |
|
| 26 | 23 |
"github.com/docker/docker/pkg/stringid" |
| 27 | 24 |
"github.com/docker/docker/pkg/ulimit" |
| 28 | 25 |
"github.com/docker/docker/runconfig" |
| 29 | 26 |
"github.com/docker/docker/utils" |
| 30 | 27 |
"github.com/docker/libcontainer/configs" |
| 31 | 28 |
"github.com/docker/libcontainer/devices" |
| 29 |
+ "github.com/docker/libnetwork" |
|
| 30 |
+ "github.com/docker/libnetwork/netlabel" |
|
| 31 |
+ "github.com/docker/libnetwork/netutils" |
|
| 32 |
+ "github.com/docker/libnetwork/options" |
|
| 32 | 33 |
) |
| 33 | 34 |
|
| 34 | 35 |
const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" |
| ... | ... |
@@ -65,179 +68,6 @@ func killProcessDirectly(container *Container) error {
|
| 65 | 65 |
return nil |
| 66 | 66 |
} |
| 67 | 67 |
|
| 68 |
-func (container *Container) setupContainerDns() error {
|
|
| 69 |
- if container.ResolvConfPath != "" {
|
|
| 70 |
- // check if this is an existing container that needs DNS update: |
|
| 71 |
- if container.UpdateDns {
|
|
| 72 |
- // read the host's resolv.conf, get the hash and call updateResolvConf |
|
| 73 |
- logrus.Debugf("Check container (%s) for update to resolv.conf - UpdateDns flag was set", container.ID)
|
|
| 74 |
- latestResolvConf, latestHash := resolvconf.GetLastModified() |
|
| 75 |
- |
|
| 76 |
- // clean container resolv.conf re: localhost nameservers and IPv6 NS (if IPv6 disabled) |
|
| 77 |
- updatedResolvConf, modified := resolvconf.FilterResolvDns(latestResolvConf, container.daemon.config.Bridge.EnableIPv6) |
|
| 78 |
- if modified {
|
|
| 79 |
- // changes have occurred during resolv.conf localhost cleanup: generate an updated hash |
|
| 80 |
- newHash, err := ioutils.HashData(bytes.NewReader(updatedResolvConf)) |
|
| 81 |
- if err != nil {
|
|
| 82 |
- return err |
|
| 83 |
- } |
|
| 84 |
- latestHash = newHash |
|
| 85 |
- } |
|
| 86 |
- |
|
| 87 |
- if err := container.updateResolvConf(updatedResolvConf, latestHash); err != nil {
|
|
| 88 |
- return err |
|
| 89 |
- } |
|
| 90 |
- // successful update of the restarting container; set the flag off |
|
| 91 |
- container.UpdateDns = false |
|
| 92 |
- } |
|
| 93 |
- return nil |
|
| 94 |
- } |
|
| 95 |
- |
|
| 96 |
- var ( |
|
| 97 |
- config = container.hostConfig |
|
| 98 |
- daemon = container.daemon |
|
| 99 |
- ) |
|
| 100 |
- |
|
| 101 |
- resolvConf, err := resolvconf.Get() |
|
| 102 |
- if err != nil {
|
|
| 103 |
- return err |
|
| 104 |
- } |
|
| 105 |
- container.ResolvConfPath, err = container.GetRootResourcePath("resolv.conf")
|
|
| 106 |
- if err != nil {
|
|
| 107 |
- return err |
|
| 108 |
- } |
|
| 109 |
- |
|
| 110 |
- if config.NetworkMode.IsBridge() || config.NetworkMode.IsNone() {
|
|
| 111 |
- // check configurations for any container/daemon dns settings |
|
| 112 |
- if len(config.Dns) > 0 || len(daemon.config.Dns) > 0 || len(config.DnsSearch) > 0 || len(daemon.config.DnsSearch) > 0 {
|
|
| 113 |
- var ( |
|
| 114 |
- dns = resolvconf.GetNameservers(resolvConf) |
|
| 115 |
- dnsSearch = resolvconf.GetSearchDomains(resolvConf) |
|
| 116 |
- ) |
|
| 117 |
- if len(config.Dns) > 0 {
|
|
| 118 |
- dns = config.Dns |
|
| 119 |
- } else if len(daemon.config.Dns) > 0 {
|
|
| 120 |
- dns = daemon.config.Dns |
|
| 121 |
- } |
|
| 122 |
- if len(config.DnsSearch) > 0 {
|
|
| 123 |
- dnsSearch = config.DnsSearch |
|
| 124 |
- } else if len(daemon.config.DnsSearch) > 0 {
|
|
| 125 |
- dnsSearch = daemon.config.DnsSearch |
|
| 126 |
- } |
|
| 127 |
- return resolvconf.Build(container.ResolvConfPath, dns, dnsSearch) |
|
| 128 |
- } |
|
| 129 |
- |
|
| 130 |
- // replace any localhost/127.*, and remove IPv6 nameservers if IPv6 disabled in daemon |
|
| 131 |
- resolvConf, _ = resolvconf.FilterResolvDns(resolvConf, daemon.config.Bridge.EnableIPv6) |
|
| 132 |
- } |
|
| 133 |
- //get a sha256 hash of the resolv conf at this point so we can check |
|
| 134 |
- //for changes when the host resolv.conf changes (e.g. network update) |
|
| 135 |
- resolvHash, err := ioutils.HashData(bytes.NewReader(resolvConf)) |
|
| 136 |
- if err != nil {
|
|
| 137 |
- return err |
|
| 138 |
- } |
|
| 139 |
- resolvHashFile := container.ResolvConfPath + ".hash" |
|
| 140 |
- if err = ioutil.WriteFile(resolvHashFile, []byte(resolvHash), 0644); err != nil {
|
|
| 141 |
- return err |
|
| 142 |
- } |
|
| 143 |
- return ioutil.WriteFile(container.ResolvConfPath, resolvConf, 0644) |
|
| 144 |
-} |
|
| 145 |
- |
|
| 146 |
-// called when the host's resolv.conf changes to check whether container's resolv.conf |
|
| 147 |
-// is unchanged by the container "user" since container start: if unchanged, the |
|
| 148 |
-// container's resolv.conf will be updated to match the host's new resolv.conf |
|
| 149 |
-func (container *Container) updateResolvConf(updatedResolvConf []byte, newResolvHash string) error {
|
|
| 150 |
- |
|
| 151 |
- if container.ResolvConfPath == "" {
|
|
| 152 |
- return nil |
|
| 153 |
- } |
|
| 154 |
- if container.Running {
|
|
| 155 |
- //set a marker in the hostConfig to update on next start/restart |
|
| 156 |
- container.UpdateDns = true |
|
| 157 |
- return nil |
|
| 158 |
- } |
|
| 159 |
- |
|
| 160 |
- resolvHashFile := container.ResolvConfPath + ".hash" |
|
| 161 |
- |
|
| 162 |
- //read the container's current resolv.conf and compute the hash |
|
| 163 |
- resolvBytes, err := ioutil.ReadFile(container.ResolvConfPath) |
|
| 164 |
- if err != nil {
|
|
| 165 |
- return err |
|
| 166 |
- } |
|
| 167 |
- curHash, err := ioutils.HashData(bytes.NewReader(resolvBytes)) |
|
| 168 |
- if err != nil {
|
|
| 169 |
- return err |
|
| 170 |
- } |
|
| 171 |
- |
|
| 172 |
- //read the hash from the last time we wrote resolv.conf in the container |
|
| 173 |
- hashBytes, err := ioutil.ReadFile(resolvHashFile) |
|
| 174 |
- if err != nil {
|
|
| 175 |
- if !os.IsNotExist(err) {
|
|
| 176 |
- return err |
|
| 177 |
- } |
|
| 178 |
- // backwards compat: if no hash file exists, this container pre-existed from |
|
| 179 |
- // a Docker daemon that didn't contain this update feature. Given we can't know |
|
| 180 |
- // if the user has modified the resolv.conf since container start time, safer |
|
| 181 |
- // to just never update the container's resolv.conf during it's lifetime which |
|
| 182 |
- // we can control by setting hashBytes to an empty string |
|
| 183 |
- hashBytes = []byte("")
|
|
| 184 |
- } |
|
| 185 |
- |
|
| 186 |
- //if the user has not modified the resolv.conf of the container since we wrote it last |
|
| 187 |
- //we will replace it with the updated resolv.conf from the host |
|
| 188 |
- if string(hashBytes) == curHash {
|
|
| 189 |
- logrus.Debugf("replacing %q with updated host resolv.conf", container.ResolvConfPath)
|
|
| 190 |
- |
|
| 191 |
- // for atomic updates to these files, use temporary files with os.Rename: |
|
| 192 |
- dir := filepath.Dir(container.ResolvConfPath) |
|
| 193 |
- tmpHashFile, err := ioutil.TempFile(dir, "hash") |
|
| 194 |
- if err != nil {
|
|
| 195 |
- return err |
|
| 196 |
- } |
|
| 197 |
- tmpResolvFile, err := ioutil.TempFile(dir, "resolv") |
|
| 198 |
- if err != nil {
|
|
| 199 |
- return err |
|
| 200 |
- } |
|
| 201 |
- |
|
| 202 |
- // write the updates to the temp files |
|
| 203 |
- if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newResolvHash), 0644); err != nil {
|
|
| 204 |
- return err |
|
| 205 |
- } |
|
| 206 |
- if err = ioutil.WriteFile(tmpResolvFile.Name(), updatedResolvConf, 0644); err != nil {
|
|
| 207 |
- return err |
|
| 208 |
- } |
|
| 209 |
- |
|
| 210 |
- // rename the temp files for atomic replace |
|
| 211 |
- if err = os.Rename(tmpHashFile.Name(), resolvHashFile); err != nil {
|
|
| 212 |
- return err |
|
| 213 |
- } |
|
| 214 |
- return os.Rename(tmpResolvFile.Name(), container.ResolvConfPath) |
|
| 215 |
- } |
|
| 216 |
- return nil |
|
| 217 |
-} |
|
| 218 |
- |
|
| 219 |
-func (container *Container) updateParentsHosts() error {
|
|
| 220 |
- refs := container.daemon.ContainerGraph().RefPaths(container.ID) |
|
| 221 |
- for _, ref := range refs {
|
|
| 222 |
- if ref.ParentID == "0" {
|
|
| 223 |
- continue |
|
| 224 |
- } |
|
| 225 |
- |
|
| 226 |
- c, err := container.daemon.Get(ref.ParentID) |
|
| 227 |
- if err != nil {
|
|
| 228 |
- logrus.Error(err) |
|
| 229 |
- } |
|
| 230 |
- |
|
| 231 |
- if c != nil && !container.daemon.config.DisableNetwork && container.hostConfig.NetworkMode.IsPrivate() {
|
|
| 232 |
- logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, container.NetworkSettings.IPAddress)
|
|
| 233 |
- if err := etchosts.Update(c.HostsPath, container.NetworkSettings.IPAddress, ref.Name); err != nil {
|
|
| 234 |
- logrus.Errorf("Failed to update /etc/hosts in parent container %s for alias %s: %v", c.ID, ref.Name, err)
|
|
| 235 |
- } |
|
| 236 |
- } |
|
| 237 |
- } |
|
| 238 |
- return nil |
|
| 239 |
-} |
|
| 240 |
- |
|
| 241 | 68 |
func (container *Container) setupLinkedContainers() ([]string, error) {
|
| 242 | 69 |
var ( |
| 243 | 70 |
env []string |
| ... | ... |
@@ -360,39 +190,16 @@ func getDevicesFromPath(deviceMapping runconfig.DeviceMapping) (devs []*configs. |
| 360 | 360 |
|
| 361 | 361 |
func populateCommand(c *Container, env []string) error {
|
| 362 | 362 |
en := &execdriver.Network{
|
| 363 |
- Mtu: c.daemon.config.Mtu, |
|
| 364 |
- Interface: nil, |
|
| 363 |
+ NamespacePath: c.NetworkSettings.SandboxKey, |
|
| 365 | 364 |
} |
| 366 | 365 |
|
| 367 | 366 |
parts := strings.SplitN(string(c.hostConfig.NetworkMode), ":", 2) |
| 368 |
- switch parts[0] {
|
|
| 369 |
- case "none": |
|
| 370 |
- case "host": |
|
| 371 |
- en.HostNetworking = true |
|
| 372 |
- case "bridge", "": // empty string to support existing containers |
|
| 373 |
- if !c.Config.NetworkDisabled {
|
|
| 374 |
- network := c.NetworkSettings |
|
| 375 |
- en.Interface = &execdriver.NetworkInterface{
|
|
| 376 |
- Gateway: network.Gateway, |
|
| 377 |
- Bridge: network.Bridge, |
|
| 378 |
- IPAddress: network.IPAddress, |
|
| 379 |
- IPPrefixLen: network.IPPrefixLen, |
|
| 380 |
- MacAddress: network.MacAddress, |
|
| 381 |
- LinkLocalIPv6Address: network.LinkLocalIPv6Address, |
|
| 382 |
- GlobalIPv6Address: network.GlobalIPv6Address, |
|
| 383 |
- GlobalIPv6PrefixLen: network.GlobalIPv6PrefixLen, |
|
| 384 |
- IPv6Gateway: network.IPv6Gateway, |
|
| 385 |
- HairpinMode: network.HairpinMode, |
|
| 386 |
- } |
|
| 387 |
- } |
|
| 388 |
- case "container": |
|
| 367 |
+ if parts[0] == "container" {
|
|
| 389 | 368 |
nc, err := c.getNetworkedContainer() |
| 390 | 369 |
if err != nil {
|
| 391 | 370 |
return err |
| 392 | 371 |
} |
| 393 | 372 |
en.ContainerID = nc.ID |
| 394 |
- default: |
|
| 395 |
- return fmt.Errorf("invalid network mode: %s", c.hostConfig.NetworkMode)
|
|
| 396 | 373 |
} |
| 397 | 374 |
|
| 398 | 375 |
ipc := &execdriver.Ipc{}
|
| ... | ... |
@@ -537,40 +344,318 @@ func (container *Container) GetSize() (int64, int64) {
|
| 537 | 537 |
return sizeRw, sizeRootfs |
| 538 | 538 |
} |
| 539 | 539 |
|
| 540 |
-func (container *Container) AllocateNetwork() error {
|
|
| 541 |
- mode := container.hostConfig.NetworkMode |
|
| 542 |
- if container.Config.NetworkDisabled || !mode.IsPrivate() {
|
|
| 540 |
+func (container *Container) buildHostnameFile() error {
|
|
| 541 |
+ hostnamePath, err := container.GetRootResourcePath("hostname")
|
|
| 542 |
+ if err != nil {
|
|
| 543 |
+ return err |
|
| 544 |
+ } |
|
| 545 |
+ container.HostnamePath = hostnamePath |
|
| 546 |
+ |
|
| 547 |
+ if container.Config.Domainname != "" {
|
|
| 548 |
+ return ioutil.WriteFile(container.HostnamePath, []byte(fmt.Sprintf("%s.%s\n", container.Config.Hostname, container.Config.Domainname)), 0644)
|
|
| 549 |
+ } |
|
| 550 |
+ return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644) |
|
| 551 |
+} |
|
| 552 |
+ |
|
| 553 |
+func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, error) {
|
|
| 554 |
+ var ( |
|
| 555 |
+ joinOptions []libnetwork.EndpointOption |
|
| 556 |
+ err error |
|
| 557 |
+ dns []string |
|
| 558 |
+ dnsSearch []string |
|
| 559 |
+ ) |
|
| 560 |
+ |
|
| 561 |
+ joinOptions = append(joinOptions, libnetwork.JoinOptionHostname(container.Config.Hostname), |
|
| 562 |
+ libnetwork.JoinOptionDomainname(container.Config.Domainname)) |
|
| 563 |
+ |
|
| 564 |
+ if container.hostConfig.NetworkMode.IsHost() {
|
|
| 565 |
+ joinOptions = append(joinOptions, libnetwork.JoinOptionUseDefaultSandbox()) |
|
| 566 |
+ } |
|
| 567 |
+ |
|
| 568 |
+ container.HostsPath, err = container.GetRootResourcePath("hosts")
|
|
| 569 |
+ if err != nil {
|
|
| 570 |
+ return nil, err |
|
| 571 |
+ } |
|
| 572 |
+ joinOptions = append(joinOptions, libnetwork.JoinOptionHostsPath(container.HostsPath)) |
|
| 573 |
+ |
|
| 574 |
+ container.ResolvConfPath, err = container.GetRootResourcePath("resolv.conf")
|
|
| 575 |
+ if err != nil {
|
|
| 576 |
+ return nil, err |
|
| 577 |
+ } |
|
| 578 |
+ joinOptions = append(joinOptions, libnetwork.JoinOptionResolvConfPath(container.ResolvConfPath)) |
|
| 579 |
+ |
|
| 580 |
+ if len(container.hostConfig.Dns) > 0 {
|
|
| 581 |
+ dns = container.hostConfig.Dns |
|
| 582 |
+ } else if len(container.daemon.config.Dns) > 0 {
|
|
| 583 |
+ dns = container.daemon.config.Dns |
|
| 584 |
+ } |
|
| 585 |
+ |
|
| 586 |
+ for _, d := range dns {
|
|
| 587 |
+ joinOptions = append(joinOptions, libnetwork.JoinOptionDNS(d)) |
|
| 588 |
+ } |
|
| 589 |
+ |
|
| 590 |
+ if len(container.hostConfig.DnsSearch) > 0 {
|
|
| 591 |
+ dnsSearch = container.hostConfig.DnsSearch |
|
| 592 |
+ } else if len(container.daemon.config.DnsSearch) > 0 {
|
|
| 593 |
+ dnsSearch = container.daemon.config.DnsSearch |
|
| 594 |
+ } |
|
| 595 |
+ |
|
| 596 |
+ for _, ds := range dnsSearch {
|
|
| 597 |
+ joinOptions = append(joinOptions, libnetwork.JoinOptionDNSSearch(ds)) |
|
| 598 |
+ } |
|
| 599 |
+ |
|
| 600 |
+ if container.NetworkSettings.SecondaryIPAddresses != nil {
|
|
| 601 |
+ name := container.Config.Hostname |
|
| 602 |
+ if container.Config.Domainname != "" {
|
|
| 603 |
+ name = name + "." + container.Config.Domainname |
|
| 604 |
+ } |
|
| 605 |
+ |
|
| 606 |
+ for _, a := range container.NetworkSettings.SecondaryIPAddresses {
|
|
| 607 |
+ joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(name, a.Addr)) |
|
| 608 |
+ } |
|
| 609 |
+ } |
|
| 610 |
+ |
|
| 611 |
+ var childEndpoints, parentEndpoints []string |
|
| 612 |
+ |
|
| 613 |
+ children, err := container.daemon.Children(container.Name) |
|
| 614 |
+ if err != nil {
|
|
| 615 |
+ return nil, err |
|
| 616 |
+ } |
|
| 617 |
+ |
|
| 618 |
+ for linkAlias, child := range children {
|
|
| 619 |
+ _, alias := path.Split(linkAlias) |
|
| 620 |
+ // allow access to the linked container via the alias, real name, and container hostname |
|
| 621 |
+ aliasList := alias + " " + child.Config.Hostname |
|
| 622 |
+ // only add the name if alias isn't equal to the name |
|
| 623 |
+ if alias != child.Name[1:] {
|
|
| 624 |
+ aliasList = aliasList + " " + child.Name[1:] |
|
| 625 |
+ } |
|
| 626 |
+ joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(aliasList, child.NetworkSettings.IPAddress)) |
|
| 627 |
+ if child.NetworkSettings.EndpointID != "" {
|
|
| 628 |
+ childEndpoints = append(childEndpoints, child.NetworkSettings.EndpointID) |
|
| 629 |
+ } |
|
| 630 |
+ } |
|
| 631 |
+ |
|
| 632 |
+ for _, extraHost := range container.hostConfig.ExtraHosts {
|
|
| 633 |
+ // allow IPv6 addresses in extra hosts; only split on first ":" |
|
| 634 |
+ parts := strings.SplitN(extraHost, ":", 2) |
|
| 635 |
+ joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(parts[0], parts[1])) |
|
| 636 |
+ } |
|
| 637 |
+ |
|
| 638 |
+ refs := container.daemon.ContainerGraph().RefPaths(container.ID) |
|
| 639 |
+ for _, ref := range refs {
|
|
| 640 |
+ if ref.ParentID == "0" {
|
|
| 641 |
+ continue |
|
| 642 |
+ } |
|
| 643 |
+ |
|
| 644 |
+ c, err := container.daemon.Get(ref.ParentID) |
|
| 645 |
+ if err != nil {
|
|
| 646 |
+ logrus.Error(err) |
|
| 647 |
+ } |
|
| 648 |
+ |
|
| 649 |
+ if c != nil && !container.daemon.config.DisableNetwork && container.hostConfig.NetworkMode.IsPrivate() {
|
|
| 650 |
+ logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, container.NetworkSettings.IPAddress)
|
|
| 651 |
+ joinOptions = append(joinOptions, libnetwork.JoinOptionParentUpdate(c.NetworkSettings.EndpointID, ref.Name, container.NetworkSettings.IPAddress)) |
|
| 652 |
+ if c.NetworkSettings.EndpointID != "" {
|
|
| 653 |
+ parentEndpoints = append(parentEndpoints, c.NetworkSettings.EndpointID) |
|
| 654 |
+ } |
|
| 655 |
+ } |
|
| 656 |
+ } |
|
| 657 |
+ |
|
| 658 |
+ linkOptions := options.Generic{
|
|
| 659 |
+ netlabel.GenericData: options.Generic{
|
|
| 660 |
+ "ParentEndpoints": parentEndpoints, |
|
| 661 |
+ "ChildEndpoints": childEndpoints, |
|
| 662 |
+ }, |
|
| 663 |
+ } |
|
| 664 |
+ |
|
| 665 |
+ joinOptions = append(joinOptions, libnetwork.JoinOptionGeneric(linkOptions)) |
|
| 666 |
+ |
|
| 667 |
+ return joinOptions, nil |
|
| 668 |
+} |
|
| 669 |
+ |
|
| 670 |
+func (container *Container) buildPortMapInfo(n libnetwork.Network, ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) {
|
|
| 671 |
+ if ep == nil {
|
|
| 672 |
+ return nil, fmt.Errorf("invalid endpoint while building port map info")
|
|
| 673 |
+ } |
|
| 674 |
+ |
|
| 675 |
+ if networkSettings == nil {
|
|
| 676 |
+ return nil, fmt.Errorf("invalid networksettings while building port map info")
|
|
| 677 |
+ } |
|
| 678 |
+ |
|
| 679 |
+ driverInfo, err := ep.DriverInfo() |
|
| 680 |
+ if err != nil {
|
|
| 681 |
+ return nil, err |
|
| 682 |
+ } |
|
| 683 |
+ |
|
| 684 |
+ if driverInfo == nil {
|
|
| 685 |
+ // It is not an error for epInfo to be nil |
|
| 686 |
+ return networkSettings, nil |
|
| 687 |
+ } |
|
| 688 |
+ |
|
| 689 |
+ if mac, ok := driverInfo[netlabel.MacAddress]; ok {
|
|
| 690 |
+ networkSettings.MacAddress = mac.(net.HardwareAddr).String() |
|
| 691 |
+ } |
|
| 692 |
+ |
|
| 693 |
+ mapData, ok := driverInfo[netlabel.PortMap] |
|
| 694 |
+ if !ok {
|
|
| 695 |
+ return networkSettings, nil |
|
| 696 |
+ } |
|
| 697 |
+ |
|
| 698 |
+ if portMapping, ok := mapData.([]netutils.PortBinding); ok {
|
|
| 699 |
+ networkSettings.Ports = nat.PortMap{}
|
|
| 700 |
+ for _, pp := range portMapping {
|
|
| 701 |
+ natPort := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port))) |
|
| 702 |
+ natBndg := nat.PortBinding{HostIp: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
|
|
| 703 |
+ networkSettings.Ports[natPort] = append(networkSettings.Ports[natPort], natBndg) |
|
| 704 |
+ } |
|
| 705 |
+ } |
|
| 706 |
+ |
|
| 707 |
+ return networkSettings, nil |
|
| 708 |
+} |
|
| 709 |
+ |
|
| 710 |
+func (container *Container) buildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) {
|
|
| 711 |
+ if ep == nil {
|
|
| 712 |
+ return nil, fmt.Errorf("invalid endpoint while building port map info")
|
|
| 713 |
+ } |
|
| 714 |
+ |
|
| 715 |
+ if networkSettings == nil {
|
|
| 716 |
+ return nil, fmt.Errorf("invalid networksettings while building port map info")
|
|
| 717 |
+ } |
|
| 718 |
+ |
|
| 719 |
+ epInfo := ep.Info() |
|
| 720 |
+ if epInfo == nil {
|
|
| 721 |
+ // It is not an error to get an empty endpoint info |
|
| 722 |
+ return networkSettings, nil |
|
| 723 |
+ } |
|
| 724 |
+ |
|
| 725 |
+ ifaceList := epInfo.InterfaceList() |
|
| 726 |
+ if len(ifaceList) == 0 {
|
|
| 727 |
+ return networkSettings, nil |
|
| 728 |
+ } |
|
| 729 |
+ |
|
| 730 |
+ iface := ifaceList[0] |
|
| 731 |
+ |
|
| 732 |
+ ones, _ := iface.Address().Mask.Size() |
|
| 733 |
+ networkSettings.IPAddress = iface.Address().IP.String() |
|
| 734 |
+ networkSettings.IPPrefixLen = ones |
|
| 735 |
+ |
|
| 736 |
+ if iface.AddressIPv6().IP.To16() != nil {
|
|
| 737 |
+ onesv6, _ := iface.AddressIPv6().Mask.Size() |
|
| 738 |
+ networkSettings.GlobalIPv6Address = iface.AddressIPv6().IP.String() |
|
| 739 |
+ networkSettings.GlobalIPv6PrefixLen = onesv6 |
|
| 740 |
+ } |
|
| 741 |
+ |
|
| 742 |
+ if len(ifaceList) == 1 {
|
|
| 743 |
+ return networkSettings, nil |
|
| 744 |
+ } |
|
| 745 |
+ |
|
| 746 |
+ networkSettings.SecondaryIPAddresses = make([]network.Address, 0, len(ifaceList)-1) |
|
| 747 |
+ networkSettings.SecondaryIPv6Addresses = make([]network.Address, 0, len(ifaceList)-1) |
|
| 748 |
+ for _, iface := range ifaceList[1:] {
|
|
| 749 |
+ ones, _ := iface.Address().Mask.Size() |
|
| 750 |
+ addr := network.Address{Addr: iface.Address().IP.String(), PrefixLen: ones}
|
|
| 751 |
+ networkSettings.SecondaryIPAddresses = append(networkSettings.SecondaryIPAddresses, addr) |
|
| 752 |
+ |
|
| 753 |
+ if iface.AddressIPv6().IP.To16() != nil {
|
|
| 754 |
+ onesv6, _ := iface.AddressIPv6().Mask.Size() |
|
| 755 |
+ addrv6 := network.Address{Addr: iface.AddressIPv6().IP.String(), PrefixLen: onesv6}
|
|
| 756 |
+ networkSettings.SecondaryIPv6Addresses = append(networkSettings.SecondaryIPv6Addresses, addrv6) |
|
| 757 |
+ } |
|
| 758 |
+ } |
|
| 759 |
+ |
|
| 760 |
+ return networkSettings, nil |
|
| 761 |
+} |
|
| 762 |
+ |
|
| 763 |
+func (container *Container) updateJoinInfo(ep libnetwork.Endpoint) error {
|
|
| 764 |
+ epInfo := ep.Info() |
|
| 765 |
+ if epInfo == nil {
|
|
| 766 |
+ // It is not an error to get an empty endpoint info |
|
| 543 | 767 |
return nil |
| 544 | 768 |
} |
| 545 | 769 |
|
| 546 |
- var err error |
|
| 770 |
+ container.NetworkSettings.Gateway = epInfo.Gateway().String() |
|
| 771 |
+ if epInfo.GatewayIPv6().To16() != nil {
|
|
| 772 |
+ container.NetworkSettings.IPv6Gateway = epInfo.GatewayIPv6().String() |
|
| 773 |
+ } |
|
| 774 |
+ |
|
| 775 |
+ container.NetworkSettings.SandboxKey = epInfo.SandboxKey() |
|
| 547 | 776 |
|
| 548 |
- networkSettings, err := bridge.Allocate(container.ID, container.Config.MacAddress, "", "") |
|
| 777 |
+ return nil |
|
| 778 |
+} |
|
| 779 |
+ |
|
| 780 |
+func (container *Container) updateNetworkSettings(n libnetwork.Network, ep libnetwork.Endpoint) error {
|
|
| 781 |
+ networkSettings := &network.Settings{NetworkID: n.ID(), EndpointID: ep.ID()}
|
|
| 782 |
+ |
|
| 783 |
+ networkSettings, err := container.buildPortMapInfo(n, ep, networkSettings) |
|
| 549 | 784 |
if err != nil {
|
| 550 | 785 |
return err |
| 551 | 786 |
} |
| 552 | 787 |
|
| 553 |
- // Error handling: At this point, the interface is allocated so we have to |
|
| 554 |
- // make sure that it is always released in case of error, otherwise we |
|
| 555 |
- // might leak resources. |
|
| 788 |
+ networkSettings, err = container.buildEndpointInfo(n, ep, networkSettings) |
|
| 789 |
+ if err != nil {
|
|
| 790 |
+ return err |
|
| 791 |
+ } |
|
| 792 |
+ |
|
| 793 |
+ if container.hostConfig.NetworkMode == runconfig.NetworkMode("bridge") {
|
|
| 794 |
+ networkSettings.Bridge = container.daemon.config.Bridge.Iface |
|
| 795 |
+ } |
|
| 796 |
+ |
|
| 797 |
+ container.NetworkSettings = networkSettings |
|
| 798 |
+ return nil |
|
| 799 |
+} |
|
| 800 |
+ |
|
| 801 |
+func (container *Container) UpdateNetwork() error {
|
|
| 802 |
+ n, err := container.daemon.netController.NetworkByID(container.NetworkSettings.NetworkID) |
|
| 803 |
+ if err != nil {
|
|
| 804 |
+ return fmt.Errorf("error locating network id %s: %v", container.NetworkSettings.NetworkID, err)
|
|
| 805 |
+ } |
|
| 806 |
+ |
|
| 807 |
+ ep, err := n.EndpointByID(container.NetworkSettings.EndpointID) |
|
| 808 |
+ if err != nil {
|
|
| 809 |
+ return fmt.Errorf("error locating endpoint id %s: %v", container.NetworkSettings.EndpointID, err)
|
|
| 810 |
+ } |
|
| 811 |
+ |
|
| 812 |
+ if err := ep.Leave(container.ID); err != nil {
|
|
| 813 |
+ return fmt.Errorf("endpoint leave failed: %v", err)
|
|
| 814 |
+ |
|
| 815 |
+ } |
|
| 816 |
+ |
|
| 817 |
+ joinOptions, err := container.buildJoinOptions() |
|
| 818 |
+ if err != nil {
|
|
| 819 |
+ return fmt.Errorf("Update network failed: %v", err)
|
|
| 820 |
+ } |
|
| 821 |
+ |
|
| 822 |
+ if _, err := ep.Join(container.ID, joinOptions...); err != nil {
|
|
| 823 |
+ return fmt.Errorf("endpoint join failed: %v", err)
|
|
| 824 |
+ } |
|
| 825 |
+ |
|
| 826 |
+ if err := container.updateJoinInfo(ep); err != nil {
|
|
| 827 |
+ return fmt.Errorf("Updating join info failed: %v", err)
|
|
| 828 |
+ } |
|
| 829 |
+ |
|
| 830 |
+ return nil |
|
| 831 |
+} |
|
| 832 |
+ |
|
| 833 |
+func (container *Container) buildCreateEndpointOptions() ([]libnetwork.EndpointOption, error) {
|
|
| 834 |
+ var ( |
|
| 835 |
+ portSpecs = make(nat.PortSet) |
|
| 836 |
+ bindings = make(nat.PortMap) |
|
| 837 |
+ pbList []netutils.PortBinding |
|
| 838 |
+ exposeList []netutils.TransportPort |
|
| 839 |
+ createOptions []libnetwork.EndpointOption |
|
| 840 |
+ ) |
|
| 556 | 841 |
|
| 557 | 842 |
if container.Config.PortSpecs != nil {
|
| 558 |
- if err = migratePortMappings(container.Config, container.hostConfig); err != nil {
|
|
| 559 |
- bridge.Release(container.ID) |
|
| 560 |
- return err |
|
| 843 |
+ if err := migratePortMappings(container.Config, container.hostConfig); err != nil {
|
|
| 844 |
+ return nil, err |
|
| 561 | 845 |
} |
| 562 | 846 |
container.Config.PortSpecs = nil |
| 563 |
- if err = container.WriteHostConfig(); err != nil {
|
|
| 564 |
- bridge.Release(container.ID) |
|
| 565 |
- return err |
|
| 847 |
+ if err := container.WriteHostConfig(); err != nil {
|
|
| 848 |
+ return nil, err |
|
| 566 | 849 |
} |
| 567 | 850 |
} |
| 568 | 851 |
|
| 569 |
- var ( |
|
| 570 |
- portSpecs = make(nat.PortSet) |
|
| 571 |
- bindings = make(nat.PortMap) |
|
| 572 |
- ) |
|
| 573 |
- |
|
| 574 | 852 |
if container.Config.ExposedPorts != nil {
|
| 575 | 853 |
portSpecs = container.Config.ExposedPorts |
| 576 | 854 |
} |
| ... | ... |
@@ -597,52 +682,99 @@ func (container *Container) AllocateNetwork() error {
|
| 597 | 597 |
} |
| 598 | 598 |
nat.SortPortMap(ports, bindings) |
| 599 | 599 |
for _, port := range ports {
|
| 600 |
- if err = container.allocatePort(port, bindings); err != nil {
|
|
| 601 |
- bridge.Release(container.ID) |
|
| 602 |
- return err |
|
| 600 |
+ expose := netutils.TransportPort{}
|
|
| 601 |
+ expose.Proto = netutils.ParseProtocol(port.Proto()) |
|
| 602 |
+ expose.Port = uint16(port.Int()) |
|
| 603 |
+ exposeList = append(exposeList, expose) |
|
| 604 |
+ |
|
| 605 |
+ pb := netutils.PortBinding{Port: expose.Port, Proto: expose.Proto}
|
|
| 606 |
+ binding := bindings[port] |
|
| 607 |
+ for i := 0; i < len(binding); i++ {
|
|
| 608 |
+ pbCopy := pb.GetCopy() |
|
| 609 |
+ pbCopy.HostPort = uint16(nat.Port(binding[i].HostPort).Int()) |
|
| 610 |
+ pbCopy.HostIP = net.ParseIP(binding[i].HostIp) |
|
| 611 |
+ pbList = append(pbList, pbCopy) |
|
| 603 | 612 |
} |
| 604 |
- } |
|
| 605 |
- container.WriteHostConfig() |
|
| 606 | 613 |
|
| 607 |
- networkSettings.Ports = bindings |
|
| 608 |
- container.NetworkSettings = networkSettings |
|
| 614 |
+ if container.hostConfig.PublishAllPorts && len(binding) == 0 {
|
|
| 615 |
+ pbList = append(pbList, pb) |
|
| 616 |
+ } |
|
| 617 |
+ } |
|
| 609 | 618 |
|
| 610 |
- return nil |
|
| 611 |
-} |
|
| 619 |
+ createOptions = append(createOptions, |
|
| 620 |
+ libnetwork.CreateOptionPortMapping(pbList), |
|
| 621 |
+ libnetwork.CreateOptionExposedPorts(exposeList)) |
|
| 612 | 622 |
|
| 613 |
-func (container *Container) initializeNetworking() error {
|
|
| 614 |
- var err error |
|
| 615 |
- if container.hostConfig.NetworkMode.IsHost() {
|
|
| 616 |
- container.Config.Hostname, err = os.Hostname() |
|
| 623 |
+ if container.Config.MacAddress != "" {
|
|
| 624 |
+ mac, err := net.ParseMAC(container.Config.MacAddress) |
|
| 617 | 625 |
if err != nil {
|
| 618 |
- return err |
|
| 626 |
+ return nil, err |
|
| 619 | 627 |
} |
| 620 | 628 |
|
| 621 |
- parts := strings.SplitN(container.Config.Hostname, ".", 2) |
|
| 622 |
- if len(parts) > 1 {
|
|
| 623 |
- container.Config.Hostname = parts[0] |
|
| 624 |
- container.Config.Domainname = parts[1] |
|
| 629 |
+ genericOption := options.Generic{
|
|
| 630 |
+ netlabel.MacAddress: mac, |
|
| 625 | 631 |
} |
| 626 | 632 |
|
| 627 |
- content, err := ioutil.ReadFile("/etc/hosts")
|
|
| 628 |
- if os.IsNotExist(err) {
|
|
| 629 |
- return container.buildHostnameAndHostsFiles("")
|
|
| 630 |
- } else if err != nil {
|
|
| 631 |
- return err |
|
| 632 |
- } |
|
| 633 |
+ createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption)) |
|
| 634 |
+ } |
|
| 633 | 635 |
|
| 634 |
- if err := container.buildHostnameFile(); err != nil {
|
|
| 635 |
- return err |
|
| 636 |
- } |
|
| 636 |
+ return createOptions, nil |
|
| 637 |
+} |
|
| 637 | 638 |
|
| 638 |
- hostsPath, err := container.GetRootResourcePath("hosts")
|
|
| 639 |
- if err != nil {
|
|
| 640 |
- return err |
|
| 641 |
- } |
|
| 642 |
- container.HostsPath = hostsPath |
|
| 639 |
+func (container *Container) AllocateNetwork() error {
|
|
| 640 |
+ mode := container.hostConfig.NetworkMode |
|
| 641 |
+ if container.Config.NetworkDisabled || mode.IsContainer() {
|
|
| 642 |
+ return nil |
|
| 643 |
+ } |
|
| 644 |
+ |
|
| 645 |
+ var err error |
|
| 646 |
+ |
|
| 647 |
+ n, err := container.daemon.netController.NetworkByName(string(mode)) |
|
| 648 |
+ if err != nil {
|
|
| 649 |
+ return fmt.Errorf("error locating network with name %s: %v", string(mode), err)
|
|
| 650 |
+ } |
|
| 643 | 651 |
|
| 644 |
- return ioutil.WriteFile(container.HostsPath, content, 0644) |
|
| 652 |
+ createOptions, err := container.buildCreateEndpointOptions() |
|
| 653 |
+ if err != nil {
|
|
| 654 |
+ return err |
|
| 655 |
+ } |
|
| 656 |
+ |
|
| 657 |
+ ep, err := n.CreateEndpoint(container.Name, createOptions...) |
|
| 658 |
+ if err != nil {
|
|
| 659 |
+ return err |
|
| 660 |
+ } |
|
| 661 |
+ |
|
| 662 |
+ if err := container.updateNetworkSettings(n, ep); err != nil {
|
|
| 663 |
+ return err |
|
| 664 |
+ } |
|
| 665 |
+ |
|
| 666 |
+ joinOptions, err := container.buildJoinOptions() |
|
| 667 |
+ if err != nil {
|
|
| 668 |
+ return err |
|
| 645 | 669 |
} |
| 670 |
+ |
|
| 671 |
+ if _, err := ep.Join(container.ID, joinOptions...); err != nil {
|
|
| 672 |
+ return err |
|
| 673 |
+ } |
|
| 674 |
+ |
|
| 675 |
+ if err := container.updateJoinInfo(ep); err != nil {
|
|
| 676 |
+ return fmt.Errorf("Updating join info failed: %v", err)
|
|
| 677 |
+ } |
|
| 678 |
+ |
|
| 679 |
+ container.WriteHostConfig() |
|
| 680 |
+ |
|
| 681 |
+ return nil |
|
| 682 |
+} |
|
| 683 |
+ |
|
| 684 |
+func (container *Container) initializeNetworking() error {
|
|
| 685 |
+ var err error |
|
| 686 |
+ |
|
| 687 |
+ // Make sure NetworkMode has an acceptable value before |
|
| 688 |
+ // initializing networking. |
|
| 689 |
+ if container.hostConfig.NetworkMode == runconfig.NetworkMode("") {
|
|
| 690 |
+ container.hostConfig.NetworkMode = runconfig.NetworkMode("bridge")
|
|
| 691 |
+ } |
|
| 692 |
+ |
|
| 646 | 693 |
if container.hostConfig.NetworkMode.IsContainer() {
|
| 647 | 694 |
// we need to get the hosts files from the container to join |
| 648 | 695 |
nc, err := container.getNetworkedContainer() |
| ... | ... |
@@ -656,14 +788,30 @@ func (container *Container) initializeNetworking() error {
|
| 656 | 656 |
container.Config.Domainname = nc.Config.Domainname |
| 657 | 657 |
return nil |
| 658 | 658 |
} |
| 659 |
+ |
|
| 659 | 660 |
if container.daemon.config.DisableNetwork {
|
| 660 | 661 |
container.Config.NetworkDisabled = true |
| 661 |
- return container.buildHostnameAndHostsFiles("127.0.1.1")
|
|
| 662 | 662 |
} |
| 663 |
+ |
|
| 664 |
+ if container.hostConfig.NetworkMode.IsHost() {
|
|
| 665 |
+ container.Config.Hostname, err = os.Hostname() |
|
| 666 |
+ if err != nil {
|
|
| 667 |
+ return err |
|
| 668 |
+ } |
|
| 669 |
+ |
|
| 670 |
+ parts := strings.SplitN(container.Config.Hostname, ".", 2) |
|
| 671 |
+ if len(parts) > 1 {
|
|
| 672 |
+ container.Config.Hostname = parts[0] |
|
| 673 |
+ container.Config.Domainname = parts[1] |
|
| 674 |
+ } |
|
| 675 |
+ |
|
| 676 |
+ } |
|
| 677 |
+ |
|
| 663 | 678 |
if err := container.AllocateNetwork(); err != nil {
|
| 664 | 679 |
return err |
| 665 | 680 |
} |
| 666 |
- return container.buildHostnameAndHostsFiles(container.NetworkSettings.IPAddress) |
|
| 681 |
+ |
|
| 682 |
+ return container.buildHostnameFile() |
|
| 667 | 683 |
} |
| 668 | 684 |
|
| 669 | 685 |
// Make sure the config is compatible with the current kernel |
| ... | ... |
@@ -701,62 +849,6 @@ func (container *Container) ExportRw() (archive.Archive, error) {
|
| 701 | 701 |
nil |
| 702 | 702 |
} |
| 703 | 703 |
|
| 704 |
-func (container *Container) buildHostnameFile() error {
|
|
| 705 |
- hostnamePath, err := container.GetRootResourcePath("hostname")
|
|
| 706 |
- if err != nil {
|
|
| 707 |
- return err |
|
| 708 |
- } |
|
| 709 |
- container.HostnamePath = hostnamePath |
|
| 710 |
- |
|
| 711 |
- if container.Config.Domainname != "" {
|
|
| 712 |
- return ioutil.WriteFile(container.HostnamePath, []byte(fmt.Sprintf("%s.%s\n", container.Config.Hostname, container.Config.Domainname)), 0644)
|
|
| 713 |
- } |
|
| 714 |
- return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644) |
|
| 715 |
-} |
|
| 716 |
- |
|
| 717 |
-func (container *Container) buildHostsFiles(IP string) error {
|
|
| 718 |
- |
|
| 719 |
- hostsPath, err := container.GetRootResourcePath("hosts")
|
|
| 720 |
- if err != nil {
|
|
| 721 |
- return err |
|
| 722 |
- } |
|
| 723 |
- container.HostsPath = hostsPath |
|
| 724 |
- |
|
| 725 |
- var extraContent []etchosts.Record |
|
| 726 |
- |
|
| 727 |
- children, err := container.daemon.Children(container.Name) |
|
| 728 |
- if err != nil {
|
|
| 729 |
- return err |
|
| 730 |
- } |
|
| 731 |
- |
|
| 732 |
- for linkAlias, child := range children {
|
|
| 733 |
- _, alias := filepath.Split(linkAlias) |
|
| 734 |
- // allow access to the linked container via the alias, real name, and container hostname |
|
| 735 |
- aliasList := alias + " " + child.Config.Hostname |
|
| 736 |
- // only add the name if alias isn't equal to the name |
|
| 737 |
- if alias != child.Name[1:] {
|
|
| 738 |
- aliasList = aliasList + " " + child.Name[1:] |
|
| 739 |
- } |
|
| 740 |
- extraContent = append(extraContent, etchosts.Record{Hosts: aliasList, IP: child.NetworkSettings.IPAddress})
|
|
| 741 |
- } |
|
| 742 |
- |
|
| 743 |
- for _, extraHost := range container.hostConfig.ExtraHosts {
|
|
| 744 |
- // allow IPv6 addresses in extra hosts; only split on first ":" |
|
| 745 |
- parts := strings.SplitN(extraHost, ":", 2) |
|
| 746 |
- extraContent = append(extraContent, etchosts.Record{Hosts: parts[0], IP: parts[1]})
|
|
| 747 |
- } |
|
| 748 |
- |
|
| 749 |
- return etchosts.Build(container.HostsPath, IP, container.Config.Hostname, container.Config.Domainname, extraContent) |
|
| 750 |
-} |
|
| 751 |
- |
|
| 752 |
-func (container *Container) buildHostnameAndHostsFiles(IP string) error {
|
|
| 753 |
- if err := container.buildHostnameFile(); err != nil {
|
|
| 754 |
- return err |
|
| 755 |
- } |
|
| 756 |
- |
|
| 757 |
- return container.buildHostsFiles(IP) |
|
| 758 |
-} |
|
| 759 |
- |
|
| 760 | 704 |
func (container *Container) getIpcContainer() (*Container, error) {
|
| 761 | 705 |
containerID := container.hostConfig.IpcMode.Container() |
| 762 | 706 |
c, err := container.daemon.Get(containerID) |
| ... | ... |
@@ -795,23 +887,6 @@ func (container *Container) setupWorkingDirectory() error {
|
| 795 | 795 |
return nil |
| 796 | 796 |
} |
| 797 | 797 |
|
| 798 |
-func (container *Container) allocatePort(port nat.Port, bindings nat.PortMap) error {
|
|
| 799 |
- binding := bindings[port] |
|
| 800 |
- if container.hostConfig.PublishAllPorts && len(binding) == 0 {
|
|
| 801 |
- binding = append(binding, nat.PortBinding{})
|
|
| 802 |
- } |
|
| 803 |
- |
|
| 804 |
- for i := 0; i < len(binding); i++ {
|
|
| 805 |
- b, err := bridge.AllocatePort(container.ID, port, binding[i]) |
|
| 806 |
- if err != nil {
|
|
| 807 |
- return err |
|
| 808 |
- } |
|
| 809 |
- binding[i] = b |
|
| 810 |
- } |
|
| 811 |
- bindings[port] = binding |
|
| 812 |
- return nil |
|
| 813 |
-} |
|
| 814 |
- |
|
| 815 | 798 |
func (container *Container) getNetworkedContainer() (*Container, error) {
|
| 816 | 799 |
parts := strings.SplitN(string(container.hostConfig.NetworkMode), ":", 2) |
| 817 | 800 |
switch parts[0] {
|
| ... | ... |
@@ -836,34 +911,31 @@ func (container *Container) getNetworkedContainer() (*Container, error) {
|
| 836 | 836 |
} |
| 837 | 837 |
|
| 838 | 838 |
func (container *Container) ReleaseNetwork() {
|
| 839 |
- if container.Config.NetworkDisabled || !container.hostConfig.NetworkMode.IsPrivate() {
|
|
| 839 |
+ if container.hostConfig.NetworkMode.IsContainer() {
|
|
| 840 | 840 |
return |
| 841 | 841 |
} |
| 842 |
- bridge.Release(container.ID) |
|
| 843 |
- container.NetworkSettings = &network.Settings{}
|
|
| 844 |
-} |
|
| 845 | 842 |
|
| 846 |
-func (container *Container) RestoreNetwork() error {
|
|
| 847 |
- mode := container.hostConfig.NetworkMode |
|
| 848 |
- // Don't attempt a restore if we previously didn't allocate networking. |
|
| 849 |
- // This might be a legacy container with no network allocated, in which case the |
|
| 850 |
- // allocation will happen once and for all at start. |
|
| 851 |
- if !container.isNetworkAllocated() || container.Config.NetworkDisabled || !mode.IsPrivate() {
|
|
| 852 |
- return nil |
|
| 843 |
+ n, err := container.daemon.netController.NetworkByID(container.NetworkSettings.NetworkID) |
|
| 844 |
+ if err != nil {
|
|
| 845 |
+ logrus.Errorf("error locating network id %s: %v", container.NetworkSettings.NetworkID, err)
|
|
| 846 |
+ return |
|
| 853 | 847 |
} |
| 854 | 848 |
|
| 855 |
- // Re-allocate the interface with the same IP and MAC address. |
|
| 856 |
- if _, err := bridge.Allocate(container.ID, container.NetworkSettings.MacAddress, container.NetworkSettings.IPAddress, ""); err != nil {
|
|
| 857 |
- return err |
|
| 849 |
+ ep, err := n.EndpointByID(container.NetworkSettings.EndpointID) |
|
| 850 |
+ if err != nil {
|
|
| 851 |
+ logrus.Errorf("error locating endpoint id %s: %v", container.NetworkSettings.EndpointID, err)
|
|
| 852 |
+ return |
|
| 858 | 853 |
} |
| 859 | 854 |
|
| 860 |
- // Re-allocate any previously allocated ports. |
|
| 861 |
- for port := range container.NetworkSettings.Ports {
|
|
| 862 |
- if err := container.allocatePort(port, container.NetworkSettings.Ports); err != nil {
|
|
| 863 |
- return err |
|
| 864 |
- } |
|
| 855 |
+ if err := ep.Leave(container.ID); err != nil {
|
|
| 856 |
+ logrus.Errorf("leaving endpoint failed: %v", err)
|
|
| 865 | 857 |
} |
| 866 |
- return nil |
|
| 858 |
+ |
|
| 859 |
+ if err := ep.Delete(); err != nil {
|
|
| 860 |
+ logrus.Errorf("deleting endpoint failed: %v", err)
|
|
| 861 |
+ } |
|
| 862 |
+ |
|
| 863 |
+ container.NetworkSettings = &network.Settings{}
|
|
| 867 | 864 |
} |
| 868 | 865 |
|
| 869 | 866 |
func disableAllActiveLinks(container *Container) {
|
| ... | ... |
@@ -878,6 +950,10 @@ func (container *Container) DisableLink(name string) {
|
| 878 | 878 |
if container.activeLinks != nil {
|
| 879 | 879 |
if link, exists := container.activeLinks[name]; exists {
|
| 880 | 880 |
link.Disable() |
| 881 |
+ delete(container.activeLinks, name) |
|
| 882 |
+ if err := container.UpdateNetwork(); err != nil {
|
|
| 883 |
+ logrus.Debugf("Could not update network to remove link: %v", err)
|
|
| 884 |
+ } |
|
| 881 | 885 |
} else {
|
| 882 | 886 |
logrus.Debugf("Could not find active link for %s", name)
|
| 883 | 887 |
} |
| ... | ... |
@@ -1,10 +1,10 @@ |
| 1 | 1 |
package daemon |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "bytes" |
|
| 5 | 4 |
"fmt" |
| 6 | 5 |
"io" |
| 7 | 6 |
"io/ioutil" |
| 7 |
+ "net" |
|
| 8 | 8 |
"os" |
| 9 | 9 |
"path" |
| 10 | 10 |
"path/filepath" |
| ... | ... |
@@ -15,6 +15,9 @@ import ( |
| 15 | 15 |
"time" |
| 16 | 16 |
|
| 17 | 17 |
"github.com/docker/libcontainer/label" |
| 18 |
+ "github.com/docker/libnetwork" |
|
| 19 |
+ "github.com/docker/libnetwork/netlabel" |
|
| 20 |
+ "github.com/docker/libnetwork/options" |
|
| 18 | 21 |
|
| 19 | 22 |
"github.com/Sirupsen/logrus" |
| 20 | 23 |
"github.com/docker/docker/api" |
| ... | ... |
@@ -26,7 +29,6 @@ import ( |
| 26 | 26 |
_ "github.com/docker/docker/daemon/graphdriver/vfs" |
| 27 | 27 |
"github.com/docker/docker/daemon/logger" |
| 28 | 28 |
"github.com/docker/docker/daemon/network" |
| 29 |
- "github.com/docker/docker/daemon/networkdriver/bridge" |
|
| 30 | 29 |
"github.com/docker/docker/graph" |
| 31 | 30 |
"github.com/docker/docker/image" |
| 32 | 31 |
"github.com/docker/docker/pkg/archive" |
| ... | ... |
@@ -37,7 +39,6 @@ import ( |
| 37 | 37 |
"github.com/docker/docker/pkg/namesgenerator" |
| 38 | 38 |
"github.com/docker/docker/pkg/parsers" |
| 39 | 39 |
"github.com/docker/docker/pkg/parsers/kernel" |
| 40 |
- "github.com/docker/docker/pkg/resolvconf" |
|
| 41 | 40 |
"github.com/docker/docker/pkg/stringid" |
| 42 | 41 |
"github.com/docker/docker/pkg/sysinfo" |
| 43 | 42 |
"github.com/docker/docker/pkg/truncindex" |
| ... | ... |
@@ -46,8 +47,6 @@ import ( |
| 46 | 46 |
"github.com/docker/docker/trust" |
| 47 | 47 |
"github.com/docker/docker/utils" |
| 48 | 48 |
"github.com/docker/docker/volumes" |
| 49 |
- |
|
| 50 |
- "github.com/go-fsnotify/fsnotify" |
|
| 51 | 49 |
) |
| 52 | 50 |
|
| 53 | 51 |
var ( |
| ... | ... |
@@ -109,6 +108,7 @@ type Daemon struct {
|
| 109 | 109 |
defaultLogConfig runconfig.LogConfig |
| 110 | 110 |
RegistryService *registry.Service |
| 111 | 111 |
EventsService *events.Events |
| 112 |
+ netController libnetwork.NetworkController |
|
| 112 | 113 |
} |
| 113 | 114 |
|
| 114 | 115 |
// Get looks for a container using the provided information, which could be |
| ... | ... |
@@ -349,61 +349,6 @@ func (daemon *Daemon) restore() error {
|
| 349 | 349 |
return nil |
| 350 | 350 |
} |
| 351 | 351 |
|
| 352 |
-// set up the watch on the host's /etc/resolv.conf so that we can update container's |
|
| 353 |
-// live resolv.conf when the network changes on the host |
|
| 354 |
-func (daemon *Daemon) setupResolvconfWatcher() error {
|
|
| 355 |
- |
|
| 356 |
- watcher, err := fsnotify.NewWatcher() |
|
| 357 |
- if err != nil {
|
|
| 358 |
- return err |
|
| 359 |
- } |
|
| 360 |
- |
|
| 361 |
- //this goroutine listens for the events on the watch we add |
|
| 362 |
- //on the resolv.conf file on the host |
|
| 363 |
- go func() {
|
|
| 364 |
- for {
|
|
| 365 |
- select {
|
|
| 366 |
- case event := <-watcher.Events: |
|
| 367 |
- if event.Name == "/etc/resolv.conf" && |
|
| 368 |
- (event.Op&(fsnotify.Write|fsnotify.Create) != 0) {
|
|
| 369 |
- // verify a real change happened before we go further--a file write may have happened |
|
| 370 |
- // without an actual change to the file |
|
| 371 |
- updatedResolvConf, newResolvConfHash, err := resolvconf.GetIfChanged() |
|
| 372 |
- if err != nil {
|
|
| 373 |
- logrus.Debugf("Error retrieving updated host resolv.conf: %v", err)
|
|
| 374 |
- } else if updatedResolvConf != nil {
|
|
| 375 |
- // because the new host resolv.conf might have localhost nameservers.. |
|
| 376 |
- updatedResolvConf, modified := resolvconf.FilterResolvDns(updatedResolvConf, daemon.config.Bridge.EnableIPv6) |
|
| 377 |
- if modified {
|
|
| 378 |
- // changes have occurred during localhost cleanup: generate an updated hash |
|
| 379 |
- newHash, err := ioutils.HashData(bytes.NewReader(updatedResolvConf)) |
|
| 380 |
- if err != nil {
|
|
| 381 |
- logrus.Debugf("Error generating hash of new resolv.conf: %v", err)
|
|
| 382 |
- } else {
|
|
| 383 |
- newResolvConfHash = newHash |
|
| 384 |
- } |
|
| 385 |
- } |
|
| 386 |
- logrus.Debug("host network resolv.conf changed--walking container list for updates")
|
|
| 387 |
- contList := daemon.containers.List() |
|
| 388 |
- for _, container := range contList {
|
|
| 389 |
- if err := container.updateResolvConf(updatedResolvConf, newResolvConfHash); err != nil {
|
|
| 390 |
- logrus.Debugf("Error on resolv.conf update check for container ID: %s: %v", container.ID, err)
|
|
| 391 |
- } |
|
| 392 |
- } |
|
| 393 |
- } |
|
| 394 |
- } |
|
| 395 |
- case err := <-watcher.Errors: |
|
| 396 |
- logrus.Debugf("host resolv.conf notify error: %v", err)
|
|
| 397 |
- } |
|
| 398 |
- } |
|
| 399 |
- }() |
|
| 400 |
- |
|
| 401 |
- if err := watcher.Add("/etc"); err != nil {
|
|
| 402 |
- return err |
|
| 403 |
- } |
|
| 404 |
- return nil |
|
| 405 |
-} |
|
| 406 |
- |
|
| 407 | 352 |
func (daemon *Daemon) checkDeprecatedExpose(config *runconfig.Config) bool {
|
| 408 | 353 |
if config != nil {
|
| 409 | 354 |
if config.PortSpecs != nil {
|
| ... | ... |
@@ -727,18 +672,15 @@ func (daemon *Daemon) RegisterLinks(container *Container, hostConfig *runconfig. |
| 727 | 727 |
} |
| 728 | 728 |
|
| 729 | 729 |
func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemon, err error) {
|
| 730 |
- if config.Mtu == 0 {
|
|
| 731 |
- config.Mtu = getDefaultNetworkMtu() |
|
| 732 |
- } |
|
| 733 | 730 |
// Check for mutually incompatible config options |
| 734 | 731 |
if config.Bridge.Iface != "" && config.Bridge.IP != "" {
|
| 735 | 732 |
return nil, fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one.")
|
| 736 | 733 |
} |
| 737 |
- if !config.Bridge.EnableIptables && !config.Bridge.InterContainerCommunication {
|
|
| 734 |
+ if !config.Bridge.EnableIPTables && !config.Bridge.InterContainerCommunication {
|
|
| 738 | 735 |
return nil, fmt.Errorf("You specified --iptables=false with --icc=false. ICC uses iptables to function. Please set --icc or --iptables to true.")
|
| 739 | 736 |
} |
| 740 |
- if !config.Bridge.EnableIptables && config.Bridge.EnableIpMasq {
|
|
| 741 |
- config.Bridge.EnableIpMasq = false |
|
| 737 |
+ if !config.Bridge.EnableIPTables && config.Bridge.EnableIPMasq {
|
|
| 738 |
+ config.Bridge.EnableIPMasq = false |
|
| 742 | 739 |
} |
| 743 | 740 |
config.DisableNetwork = config.Bridge.Iface == disableNetworkBridge |
| 744 | 741 |
|
| ... | ... |
@@ -882,8 +824,9 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo |
| 882 | 882 |
} |
| 883 | 883 |
|
| 884 | 884 |
if !config.DisableNetwork {
|
| 885 |
- if err := bridge.InitDriver(&config.Bridge); err != nil {
|
|
| 886 |
- return nil, fmt.Errorf("Error initializing Bridge: %v", err)
|
|
| 885 |
+ d.netController, err = initNetworkController(config) |
|
| 886 |
+ if err != nil {
|
|
| 887 |
+ return nil, fmt.Errorf("Error initializing network controller: %v", err)
|
|
| 887 | 888 |
} |
| 888 | 889 |
} |
| 889 | 890 |
|
| ... | ... |
@@ -942,12 +885,97 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo |
| 942 | 942 |
return nil, err |
| 943 | 943 |
} |
| 944 | 944 |
|
| 945 |
- // set up filesystem watch on resolv.conf for network changes |
|
| 946 |
- if err := d.setupResolvconfWatcher(); err != nil {
|
|
| 947 |
- return nil, err |
|
| 945 |
+ return d, nil |
|
| 946 |
+} |
|
| 947 |
+ |
|
| 948 |
+func initNetworkController(config *Config) (libnetwork.NetworkController, error) {
|
|
| 949 |
+ controller, err := libnetwork.New() |
|
| 950 |
+ if err != nil {
|
|
| 951 |
+ return nil, fmt.Errorf("error obtaining controller instance: %v", err)
|
|
| 948 | 952 |
} |
| 949 | 953 |
|
| 950 |
- return d, nil |
|
| 954 |
+ // Initialize default driver "null" |
|
| 955 |
+ |
|
| 956 |
+ if err := controller.ConfigureNetworkDriver("null", options.Generic{}); err != nil {
|
|
| 957 |
+ return nil, fmt.Errorf("Error initializing null driver: %v", err)
|
|
| 958 |
+ } |
|
| 959 |
+ |
|
| 960 |
+ // Initialize default network on "null" |
|
| 961 |
+ if _, err := controller.NewNetwork("null", "none"); err != nil {
|
|
| 962 |
+ return nil, fmt.Errorf("Error creating default \"null\" network: %v", err)
|
|
| 963 |
+ } |
|
| 964 |
+ |
|
| 965 |
+ // Initialize default driver "host" |
|
| 966 |
+ if err := controller.ConfigureNetworkDriver("host", options.Generic{}); err != nil {
|
|
| 967 |
+ return nil, fmt.Errorf("Error initializing host driver: %v", err)
|
|
| 968 |
+ } |
|
| 969 |
+ |
|
| 970 |
+ // Initialize default network on "host" |
|
| 971 |
+ if _, err := controller.NewNetwork("host", "host"); err != nil {
|
|
| 972 |
+ return nil, fmt.Errorf("Error creating default \"host\" network: %v", err)
|
|
| 973 |
+ } |
|
| 974 |
+ |
|
| 975 |
+ // Initialize default driver "bridge" |
|
| 976 |
+ option := options.Generic{
|
|
| 977 |
+ "EnableIPForwarding": config.Bridge.EnableIPForward} |
|
| 978 |
+ |
|
| 979 |
+ if err := controller.ConfigureNetworkDriver("bridge", options.Generic{netlabel.GenericData: option}); err != nil {
|
|
| 980 |
+ return nil, fmt.Errorf("Error initializing bridge driver: %v", err)
|
|
| 981 |
+ } |
|
| 982 |
+ |
|
| 983 |
+ netOption := options.Generic{
|
|
| 984 |
+ "BridgeName": config.Bridge.Iface, |
|
| 985 |
+ "Mtu": config.Mtu, |
|
| 986 |
+ "EnableIPTables": config.Bridge.EnableIPTables, |
|
| 987 |
+ "EnableIPMasquerade": config.Bridge.EnableIPMasq, |
|
| 988 |
+ "EnableICC": config.Bridge.InterContainerCommunication, |
|
| 989 |
+ "EnableUserlandProxy": config.Bridge.EnableUserlandProxy, |
|
| 990 |
+ } |
|
| 991 |
+ |
|
| 992 |
+ if config.Bridge.IP != "" {
|
|
| 993 |
+ ip, bipNet, err := net.ParseCIDR(config.Bridge.IP) |
|
| 994 |
+ if err != nil {
|
|
| 995 |
+ return nil, err |
|
| 996 |
+ } |
|
| 997 |
+ |
|
| 998 |
+ bipNet.IP = ip |
|
| 999 |
+ netOption["AddressIPv4"] = bipNet |
|
| 1000 |
+ } |
|
| 1001 |
+ |
|
| 1002 |
+ if config.Bridge.FixedCIDR != "" {
|
|
| 1003 |
+ _, fCIDR, err := net.ParseCIDR(config.Bridge.FixedCIDR) |
|
| 1004 |
+ if err != nil {
|
|
| 1005 |
+ return nil, err |
|
| 1006 |
+ } |
|
| 1007 |
+ |
|
| 1008 |
+ netOption["FixedCIDR"] = fCIDR |
|
| 1009 |
+ } |
|
| 1010 |
+ |
|
| 1011 |
+ if config.Bridge.FixedCIDRv6 != "" {
|
|
| 1012 |
+ _, fCIDRv6, err := net.ParseCIDR(config.Bridge.FixedCIDRv6) |
|
| 1013 |
+ if err != nil {
|
|
| 1014 |
+ return nil, err |
|
| 1015 |
+ } |
|
| 1016 |
+ |
|
| 1017 |
+ netOption["FixedCIDRv6"] = fCIDRv6 |
|
| 1018 |
+ } |
|
| 1019 |
+ |
|
| 1020 |
+ // --ip processing |
|
| 1021 |
+ if config.Bridge.DefaultIP != nil {
|
|
| 1022 |
+ netOption["DefaultBindingIP"] = config.Bridge.DefaultIP |
|
| 1023 |
+ } |
|
| 1024 |
+ |
|
| 1025 |
+ // Initialize default network on "bridge" with the same name |
|
| 1026 |
+ _, err = controller.NewNetwork("bridge", "bridge",
|
|
| 1027 |
+ libnetwork.NetworkOptionGeneric(options.Generic{
|
|
| 1028 |
+ netlabel.GenericData: netOption, |
|
| 1029 |
+ netlabel.EnableIPv6: config.Bridge.EnableIPv6, |
|
| 1030 |
+ })) |
|
| 1031 |
+ if err != nil {
|
|
| 1032 |
+ return nil, fmt.Errorf("Error creating default \"bridge\" network: %v", err)
|
|
| 1033 |
+ } |
|
| 1034 |
+ |
|
| 1035 |
+ return controller, nil |
|
| 951 | 1036 |
} |
| 952 | 1037 |
|
| 953 | 1038 |
func (daemon *Daemon) Shutdown() error {
|
| ... | ... |
@@ -35,13 +35,14 @@ func (daemon *Daemon) ContainerRm(name string, config *ContainerRmConfig) error |
| 35 | 35 |
} |
| 36 | 36 |
parentContainer, _ := daemon.Get(pe.ID()) |
| 37 | 37 |
|
| 38 |
+ if err := daemon.ContainerGraph().Delete(name); err != nil {
|
|
| 39 |
+ return err |
|
| 40 |
+ } |
|
| 41 |
+ |
|
| 38 | 42 |
if parentContainer != nil {
|
| 39 | 43 |
parentContainer.DisableLink(n) |
| 40 | 44 |
} |
| 41 | 45 |
|
| 42 |
- if err := daemon.ContainerGraph().Delete(name); err != nil {
|
|
| 43 |
- return err |
|
| 44 |
- } |
|
| 45 | 46 |
return nil |
| 46 | 47 |
} |
| 47 | 48 |
|
| ... | ... |
@@ -72,6 +72,7 @@ type Network struct {
|
| 72 | 72 |
Interface *NetworkInterface `json:"interface"` // if interface is nil then networking is disabled |
| 73 | 73 |
Mtu int `json:"mtu"` |
| 74 | 74 |
ContainerID string `json:"container_id"` // id of the container to join network. |
| 75 |
+ NamespacePath string `json:"namespace_path"` |
|
| 75 | 76 |
HostNetworking bool `json:"host_networking"` |
| 76 | 77 |
} |
| 77 | 78 |
|
| ... | ... |
@@ -12,6 +12,7 @@ import ( |
| 12 | 12 |
"os/exec" |
| 13 | 13 |
"path" |
| 14 | 14 |
"path/filepath" |
| 15 |
+ "runtime" |
|
| 15 | 16 |
"strconv" |
| 16 | 17 |
"strings" |
| 17 | 18 |
"sync" |
| ... | ... |
@@ -30,6 +31,7 @@ import ( |
| 30 | 30 |
"github.com/docker/libcontainer/system" |
| 31 | 31 |
"github.com/docker/libcontainer/user" |
| 32 | 32 |
"github.com/kr/pty" |
| 33 |
+ "github.com/vishvananda/netns" |
|
| 33 | 34 |
) |
| 34 | 35 |
|
| 35 | 36 |
const DriverName = "lxc" |
| ... | ... |
@@ -80,6 +82,41 @@ func (d *driver) Name() string {
|
| 80 | 80 |
return fmt.Sprintf("%s-%s", DriverName, version)
|
| 81 | 81 |
} |
| 82 | 82 |
|
| 83 |
+func setupNetNs(nsPath string) (*os.Process, error) {
|
|
| 84 |
+ runtime.LockOSThread() |
|
| 85 |
+ defer runtime.UnlockOSThread() |
|
| 86 |
+ |
|
| 87 |
+ origns, err := netns.Get() |
|
| 88 |
+ if err != nil {
|
|
| 89 |
+ return nil, err |
|
| 90 |
+ } |
|
| 91 |
+ defer origns.Close() |
|
| 92 |
+ |
|
| 93 |
+ f, err := os.OpenFile(nsPath, os.O_RDONLY, 0) |
|
| 94 |
+ if err != nil {
|
|
| 95 |
+ return nil, fmt.Errorf("failed to get network namespace %q: %v", nsPath, err)
|
|
| 96 |
+ } |
|
| 97 |
+ defer f.Close() |
|
| 98 |
+ |
|
| 99 |
+ nsFD := f.Fd() |
|
| 100 |
+ if err := netns.Set(netns.NsHandle(nsFD)); err != nil {
|
|
| 101 |
+ return nil, fmt.Errorf("failed to set network namespace %q: %v", nsPath, err)
|
|
| 102 |
+ } |
|
| 103 |
+ defer netns.Set(origns) |
|
| 104 |
+ |
|
| 105 |
+ cmd := exec.Command("/bin/sh", "-c", "while true; do sleep 1; done")
|
|
| 106 |
+ if err := cmd.Start(); err != nil {
|
|
| 107 |
+ return nil, fmt.Errorf("failed to start netns process: %v", err)
|
|
| 108 |
+ } |
|
| 109 |
+ |
|
| 110 |
+ return cmd.Process, nil |
|
| 111 |
+} |
|
| 112 |
+ |
|
| 113 |
+func killNetNsProc(proc *os.Process) {
|
|
| 114 |
+ proc.Kill() |
|
| 115 |
+ proc.Wait() |
|
| 116 |
+} |
|
| 117 |
+ |
|
| 83 | 118 |
func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (execdriver.ExitStatus, error) {
|
| 84 | 119 |
var ( |
| 85 | 120 |
term execdriver.Terminal |
| ... | ... |
@@ -87,6 +124,10 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba |
| 87 | 87 |
dataPath = d.containerDir(c.ID) |
| 88 | 88 |
) |
| 89 | 89 |
|
| 90 |
+ if c.Network.NamespacePath == "" && c.Network.ContainerID == "" {
|
|
| 91 |
+ return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("empty namespace path for non-container network")
|
|
| 92 |
+ } |
|
| 93 |
+ |
|
| 90 | 94 |
container, err := d.createContainer(c) |
| 91 | 95 |
if err != nil {
|
| 92 | 96 |
return execdriver.ExitStatus{ExitCode: -1}, err
|
| ... | ... |
@@ -136,10 +177,20 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba |
| 136 | 136 |
params = append(params, "-F") |
| 137 | 137 |
} |
| 138 | 138 |
|
| 139 |
+ proc := &os.Process{}
|
|
| 139 | 140 |
if c.Network.ContainerID != "" {
|
| 140 | 141 |
params = append(params, |
| 141 | 142 |
"--share-net", c.Network.ContainerID, |
| 142 | 143 |
) |
| 144 |
+ } else {
|
|
| 145 |
+ proc, err = setupNetNs(c.Network.NamespacePath) |
|
| 146 |
+ if err != nil {
|
|
| 147 |
+ return execdriver.ExitStatus{ExitCode: -1}, err
|
|
| 148 |
+ } |
|
| 149 |
+ |
|
| 150 |
+ pidStr := fmt.Sprintf("%d", proc.Pid)
|
|
| 151 |
+ params = append(params, |
|
| 152 |
+ "--share-net", pidStr) |
|
| 143 | 153 |
} |
| 144 | 154 |
if c.Ipc != nil {
|
| 145 | 155 |
if c.Ipc.ContainerID != "" {
|
| ... | ... |
@@ -157,15 +208,6 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba |
| 157 | 157 |
"--", |
| 158 | 158 |
c.InitPath, |
| 159 | 159 |
) |
| 160 |
- if c.Network.Interface != nil {
|
|
| 161 |
- params = append(params, |
|
| 162 |
- "-g", c.Network.Interface.Gateway, |
|
| 163 |
- "-i", fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen),
|
|
| 164 |
- ) |
|
| 165 |
- } |
|
| 166 |
- params = append(params, |
|
| 167 |
- "-mtu", strconv.Itoa(c.Network.Mtu), |
|
| 168 |
- ) |
|
| 169 | 160 |
|
| 170 | 161 |
if c.ProcessConfig.User != "" {
|
| 171 | 162 |
params = append(params, "-u", c.ProcessConfig.User) |
| ... | ... |
@@ -214,10 +256,12 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba |
| 214 | 214 |
c.ProcessConfig.Args = append([]string{name}, arg...)
|
| 215 | 215 |
|
| 216 | 216 |
if err := createDeviceNodes(c.Rootfs, c.AutoCreatedDevices); err != nil {
|
| 217 |
+ killNetNsProc(proc) |
|
| 217 | 218 |
return execdriver.ExitStatus{ExitCode: -1}, err
|
| 218 | 219 |
} |
| 219 | 220 |
|
| 220 | 221 |
if err := c.ProcessConfig.Start(); err != nil {
|
| 222 |
+ killNetNsProc(proc) |
|
| 221 | 223 |
return execdriver.ExitStatus{ExitCode: -1}, err
|
| 222 | 224 |
} |
| 223 | 225 |
|
| ... | ... |
@@ -245,8 +289,10 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba |
| 245 | 245 |
// Poll lxc for RUNNING status |
| 246 | 246 |
pid, err := d.waitForStart(c, waitLock) |
| 247 | 247 |
if err != nil {
|
| 248 |
+ killNetNsProc(proc) |
|
| 248 | 249 |
return terminate(err) |
| 249 | 250 |
} |
| 251 |
+ killNetNsProc(proc) |
|
| 250 | 252 |
|
| 251 | 253 |
cgroupPaths, err := cgroupPaths(c.ID) |
| 252 | 254 |
if err != nil {
|
| ... | ... |
@@ -15,8 +15,7 @@ import ( |
| 15 | 15 |
"github.com/docker/libcontainer/label" |
| 16 | 16 |
) |
| 17 | 17 |
|
| 18 |
-const LxcTemplate = ` |
|
| 19 |
-{{if .Network.Interface}}
|
|
| 18 |
+/* {{if .Network.Interface}}
|
|
| 20 | 19 |
# network configuration |
| 21 | 20 |
lxc.network.type = veth |
| 22 | 21 |
lxc.network.link = {{.Network.Interface.Bridge}}
|
| ... | ... |
@@ -30,8 +29,10 @@ lxc.network.type = none |
| 30 | 30 |
lxc.network.type = empty |
| 31 | 31 |
lxc.network.flags = up |
| 32 | 32 |
lxc.network.mtu = {{.Network.Mtu}}
|
| 33 |
-{{end}}
|
|
| 33 |
+{{end}} */
|
|
| 34 | 34 |
|
| 35 |
+const LxcTemplate = ` |
|
| 36 |
+lxc.network.type = none |
|
| 35 | 37 |
# root filesystem |
| 36 | 38 |
{{$ROOTFS := .Rootfs}}
|
| 37 | 39 |
lxc.rootfs = {{$ROOTFS}}
|
| ... | ... |
@@ -145,6 +146,7 @@ lxc.network.ipv4.gateway = {{.Network.Interface.Gateway}}
|
| 145 | 145 |
{{if .Network.Interface.MacAddress}}
|
| 146 | 146 |
lxc.network.hwaddr = {{.Network.Interface.MacAddress}}
|
| 147 | 147 |
{{end}}
|
| 148 |
+{{end}}
|
|
| 148 | 149 |
{{if .ProcessConfig.Env}}
|
| 149 | 150 |
lxc.utsname = {{getHostname .ProcessConfig.Env}}
|
| 150 | 151 |
{{end}}
|
| ... | ... |
@@ -164,7 +166,6 @@ lxc.cap.drop = {{.}}
|
| 164 | 164 |
{{end}}
|
| 165 | 165 |
{{end}}
|
| 166 | 166 |
{{end}}
|
| 167 |
-{{end}}
|
|
| 168 | 167 |
` |
| 169 | 168 |
|
| 170 | 169 |
var LxcTemplateCompiled *template.Template |
| ... | ... |
@@ -264,13 +264,8 @@ func TestCustomLxcConfigMisc(t *testing.T) {
|
| 264 | 264 |
"lxc.cgroup.cpuset.cpus = 0,1", |
| 265 | 265 |
}, |
| 266 | 266 |
Network: &execdriver.Network{
|
| 267 |
- Mtu: 1500, |
|
| 268 |
- Interface: &execdriver.NetworkInterface{
|
|
| 269 |
- Gateway: "10.10.10.1", |
|
| 270 |
- IPAddress: "10.10.10.10", |
|
| 271 |
- IPPrefixLen: 24, |
|
| 272 |
- Bridge: "docker0", |
|
| 273 |
- }, |
|
| 267 |
+ Mtu: 1500, |
|
| 268 |
+ Interface: nil, |
|
| 274 | 269 |
}, |
| 275 | 270 |
ProcessConfig: processConfig, |
| 276 | 271 |
CapAdd: []string{"net_admin", "syslog"},
|
| ... | ... |
@@ -282,13 +277,6 @@ func TestCustomLxcConfigMisc(t *testing.T) {
|
| 282 | 282 |
if err != nil {
|
| 283 | 283 |
t.Fatal(err) |
| 284 | 284 |
} |
| 285 |
- // network |
|
| 286 |
- grepFile(t, p, "lxc.network.type = veth") |
|
| 287 |
- grepFile(t, p, "lxc.network.link = docker0") |
|
| 288 |
- grepFile(t, p, "lxc.network.name = eth0") |
|
| 289 |
- grepFile(t, p, "lxc.network.ipv4 = 10.10.10.10/24") |
|
| 290 |
- grepFile(t, p, "lxc.network.ipv4.gateway = 10.10.10.1") |
|
| 291 |
- grepFile(t, p, "lxc.network.flags = up") |
|
| 292 | 285 |
grepFile(t, p, "lxc.aa_profile = lxc-container-default-with-nesting") |
| 293 | 286 |
// hostname |
| 294 | 287 |
grepFile(t, p, "lxc.utsname = testhost") |
| ... | ... |
@@ -329,13 +317,8 @@ func TestCustomLxcConfigMiscOverride(t *testing.T) {
|
| 329 | 329 |
"lxc.network.ipv4 = 172.0.0.1", |
| 330 | 330 |
}, |
| 331 | 331 |
Network: &execdriver.Network{
|
| 332 |
- Mtu: 1500, |
|
| 333 |
- Interface: &execdriver.NetworkInterface{
|
|
| 334 |
- Gateway: "10.10.10.1", |
|
| 335 |
- IPAddress: "10.10.10.10", |
|
| 336 |
- IPPrefixLen: 24, |
|
| 337 |
- Bridge: "docker0", |
|
| 338 |
- }, |
|
| 332 |
+ Mtu: 1500, |
|
| 333 |
+ Interface: nil, |
|
| 339 | 334 |
}, |
| 340 | 335 |
ProcessConfig: processConfig, |
| 341 | 336 |
CapAdd: []string{"NET_ADMIN", "SYSLOG"},
|
| ... | ... |
@@ -346,13 +329,6 @@ func TestCustomLxcConfigMiscOverride(t *testing.T) {
|
| 346 | 346 |
if err != nil {
|
| 347 | 347 |
t.Fatal(err) |
| 348 | 348 |
} |
| 349 |
- // network |
|
| 350 |
- grepFile(t, p, "lxc.network.type = veth") |
|
| 351 |
- grepFile(t, p, "lxc.network.link = docker0") |
|
| 352 |
- grepFile(t, p, "lxc.network.name = eth0") |
|
| 353 |
- grepFile(t, p, "lxc.network.ipv4 = 172.0.0.1") |
|
| 354 |
- grepFile(t, p, "lxc.network.ipv4.gateway = 10.10.10.1") |
|
| 355 |
- grepFile(t, p, "lxc.network.flags = up") |
|
| 356 | 349 |
|
| 357 | 350 |
// hostname |
| 358 | 351 |
grepFile(t, p, "lxc.utsname = testhost") |
| ... | ... |
@@ -89,40 +89,6 @@ func generateIfaceName() (string, error) {
|
| 89 | 89 |
} |
| 90 | 90 |
|
| 91 | 91 |
func (d *driver) createNetwork(container *configs.Config, c *execdriver.Command) error {
|
| 92 |
- if c.Network.HostNetworking {
|
|
| 93 |
- container.Namespaces.Remove(configs.NEWNET) |
|
| 94 |
- return nil |
|
| 95 |
- } |
|
| 96 |
- |
|
| 97 |
- container.Networks = []*configs.Network{
|
|
| 98 |
- {
|
|
| 99 |
- Type: "loopback", |
|
| 100 |
- }, |
|
| 101 |
- } |
|
| 102 |
- |
|
| 103 |
- iName, err := generateIfaceName() |
|
| 104 |
- if err != nil {
|
|
| 105 |
- return err |
|
| 106 |
- } |
|
| 107 |
- if c.Network.Interface != nil {
|
|
| 108 |
- vethNetwork := configs.Network{
|
|
| 109 |
- Name: "eth0", |
|
| 110 |
- HostInterfaceName: iName, |
|
| 111 |
- Mtu: c.Network.Mtu, |
|
| 112 |
- Address: fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen),
|
|
| 113 |
- MacAddress: c.Network.Interface.MacAddress, |
|
| 114 |
- Gateway: c.Network.Interface.Gateway, |
|
| 115 |
- Type: "veth", |
|
| 116 |
- Bridge: c.Network.Interface.Bridge, |
|
| 117 |
- HairpinMode: c.Network.Interface.HairpinMode, |
|
| 118 |
- } |
|
| 119 |
- if c.Network.Interface.GlobalIPv6Address != "" {
|
|
| 120 |
- vethNetwork.IPv6Address = fmt.Sprintf("%s/%d", c.Network.Interface.GlobalIPv6Address, c.Network.Interface.GlobalIPv6PrefixLen)
|
|
| 121 |
- vethNetwork.IPv6Gateway = c.Network.Interface.IPv6Gateway |
|
| 122 |
- } |
|
| 123 |
- container.Networks = append(container.Networks, &vethNetwork) |
|
| 124 |
- } |
|
| 125 |
- |
|
| 126 | 92 |
if c.Network.ContainerID != "" {
|
| 127 | 93 |
d.Lock() |
| 128 | 94 |
active := d.activeContainers[c.Network.ContainerID] |
| ... | ... |
@@ -138,8 +104,14 @@ func (d *driver) createNetwork(container *configs.Config, c *execdriver.Command) |
| 138 | 138 |
} |
| 139 | 139 |
|
| 140 | 140 |
container.Namespaces.Add(configs.NEWNET, state.NamespacePaths[configs.NEWNET]) |
| 141 |
+ return nil |
|
| 142 |
+ } |
|
| 143 |
+ |
|
| 144 |
+ if c.Network.NamespacePath == "" {
|
|
| 145 |
+ return fmt.Errorf("network namespace path is empty")
|
|
| 141 | 146 |
} |
| 142 | 147 |
|
| 148 |
+ container.Namespaces.Add(configs.NEWNET, c.Network.NamespacePath) |
|
| 143 | 149 |
return nil |
| 144 | 150 |
} |
| 145 | 151 |
|
| ... | ... |
@@ -2,18 +2,28 @@ package network |
| 2 | 2 |
|
| 3 | 3 |
import "github.com/docker/docker/nat" |
| 4 | 4 |
|
| 5 |
+type Address struct {
|
|
| 6 |
+ Addr string |
|
| 7 |
+ PrefixLen int |
|
| 8 |
+} |
|
| 9 |
+ |
|
| 5 | 10 |
type Settings struct {
|
| 11 |
+ Bridge string |
|
| 12 |
+ EndpointID string |
|
| 13 |
+ Gateway string |
|
| 14 |
+ GlobalIPv6Address string |
|
| 15 |
+ GlobalIPv6PrefixLen int |
|
| 16 |
+ HairpinMode bool |
|
| 6 | 17 |
IPAddress string |
| 7 | 18 |
IPPrefixLen int |
| 8 |
- MacAddress string |
|
| 19 |
+ IPv6Gateway string |
|
| 9 | 20 |
LinkLocalIPv6Address string |
| 10 | 21 |
LinkLocalIPv6PrefixLen int |
| 11 |
- GlobalIPv6Address string |
|
| 12 |
- GlobalIPv6PrefixLen int |
|
| 13 |
- Gateway string |
|
| 14 |
- IPv6Gateway string |
|
| 15 |
- Bridge string |
|
| 22 |
+ MacAddress string |
|
| 23 |
+ NetworkID string |
|
| 16 | 24 |
PortMapping map[string]map[string]string // Deprecated |
| 17 | 25 |
Ports nat.PortMap |
| 18 |
- HairpinMode bool |
|
| 26 |
+ SandboxKey string |
|
| 27 |
+ SecondaryIPAddresses []Address |
|
| 28 |
+ SecondaryIPv6Addresses []Address |
|
| 19 | 29 |
} |
| ... | ... |
@@ -15,6 +15,7 @@ import ( |
| 15 | 15 |
"strings" |
| 16 | 16 |
"time" |
| 17 | 17 |
|
| 18 |
+ "github.com/docker/libnetwork/iptables" |
|
| 18 | 19 |
"github.com/docker/libtrust" |
| 19 | 20 |
"github.com/go-check/check" |
| 20 | 21 |
) |
| ... | ... |
@@ -721,13 +722,49 @@ func (s *DockerDaemonSuite) TestDaemonICCLinkExpose(c *check.C) {
|
| 721 | 721 |
c.Assert(matched, check.Equals, true, |
| 722 | 722 |
check.Commentf("iptables output should have contained %q, but was %q", regex, out))
|
| 723 | 723 |
|
| 724 |
- _, err = d.Cmd("run", "-d", "--expose", "4567", "--name", "icc1", "busybox", "nc", "-l", "-p", "4567")
|
|
| 725 |
- c.Assert(err, check.IsNil) |
|
| 724 |
+ out, err = d.Cmd("run", "-d", "--expose", "4567", "--name", "icc1", "busybox", "nc", "-l", "-p", "4567")
|
|
| 725 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
| 726 | 726 |
|
| 727 | 727 |
out, err = d.Cmd("run", "--link", "icc1:icc1", "busybox", "nc", "icc1", "4567")
|
| 728 | 728 |
c.Assert(err, check.IsNil, check.Commentf(out)) |
| 729 | 729 |
} |
| 730 | 730 |
|
| 731 |
+func (s *DockerDaemonSuite) TestDaemonLinksIpTablesRulesWhenLinkAndUnlink(c *check.C) {
|
|
| 732 |
+ bridgeName := "external-bridge" |
|
| 733 |
+ bridgeIp := "192.169.1.1/24" |
|
| 734 |
+ |
|
| 735 |
+ out, err := createInterface(c, "bridge", bridgeName, bridgeIp) |
|
| 736 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
| 737 |
+ defer deleteInterface(c, bridgeName) |
|
| 738 |
+ |
|
| 739 |
+ args := []string{"--bridge", bridgeName, "--icc=false"}
|
|
| 740 |
+ err = s.d.StartWithBusybox(args...) |
|
| 741 |
+ c.Assert(err, check.IsNil) |
|
| 742 |
+ defer s.d.Restart() |
|
| 743 |
+ |
|
| 744 |
+ _, err = s.d.Cmd("run", "-d", "--name", "child", "--publish", "8080:80", "busybox", "top")
|
|
| 745 |
+ c.Assert(err, check.IsNil) |
|
| 746 |
+ _, err = s.d.Cmd("run", "-d", "--name", "parent", "--link", "child:http", "busybox", "top")
|
|
| 747 |
+ c.Assert(err, check.IsNil) |
|
| 748 |
+ |
|
| 749 |
+ childIP := s.d.findContainerIP("child")
|
|
| 750 |
+ parentIP := s.d.findContainerIP("parent")
|
|
| 751 |
+ |
|
| 752 |
+ sourceRule := []string{"-i", bridgeName, "-o", bridgeName, "-p", "tcp", "-s", childIP, "--sport", "80", "-d", parentIP, "-j", "ACCEPT"}
|
|
| 753 |
+ destinationRule := []string{"-i", bridgeName, "-o", bridgeName, "-p", "tcp", "-s", parentIP, "--dport", "80", "-d", childIP, "-j", "ACCEPT"}
|
|
| 754 |
+ if !iptables.Exists("filter", "DOCKER", sourceRule...) || !iptables.Exists("filter", "DOCKER", destinationRule...) {
|
|
| 755 |
+ c.Fatal("Iptables rules not found")
|
|
| 756 |
+ } |
|
| 757 |
+ |
|
| 758 |
+ s.d.Cmd("rm", "--link", "parent/http")
|
|
| 759 |
+ if iptables.Exists("filter", "DOCKER", sourceRule...) || iptables.Exists("filter", "DOCKER", destinationRule...) {
|
|
| 760 |
+ c.Fatal("Iptables rules should be removed when unlink")
|
|
| 761 |
+ } |
|
| 762 |
+ |
|
| 763 |
+ s.d.Cmd("kill", "child")
|
|
| 764 |
+ s.d.Cmd("kill", "parent")
|
|
| 765 |
+} |
|
| 766 |
+ |
|
| 731 | 767 |
func (s *DockerDaemonSuite) TestDaemonUlimitDefaults(c *check.C) {
|
| 732 | 768 |
testRequires(c, NativeExecDriver) |
| 733 | 769 |
|
| ... | ... |
@@ -10,7 +10,6 @@ import ( |
| 10 | 10 |
"strings" |
| 11 | 11 |
"time" |
| 12 | 12 |
|
| 13 |
- "github.com/docker/docker/pkg/iptables" |
|
| 14 | 13 |
"github.com/go-check/check" |
| 15 | 14 |
) |
| 16 | 15 |
|
| ... | ... |
@@ -110,31 +109,6 @@ func (s *DockerSuite) TestLinksPingLinkedContainersAfterRename(c *check.C) {
|
| 110 | 110 |
|
| 111 | 111 |
} |
| 112 | 112 |
|
| 113 |
-func (s *DockerSuite) TestLinksIpTablesRulesWhenLinkAndUnlink(c *check.C) {
|
|
| 114 |
- testRequires(c, SameHostDaemon) |
|
| 115 |
- |
|
| 116 |
- dockerCmd(c, "run", "-d", "--name", "child", "--publish", "8080:80", "busybox", "top") |
|
| 117 |
- dockerCmd(c, "run", "-d", "--name", "parent", "--link", "child:http", "busybox", "top") |
|
| 118 |
- |
|
| 119 |
- childIP := findContainerIP(c, "child") |
|
| 120 |
- parentIP := findContainerIP(c, "parent") |
|
| 121 |
- |
|
| 122 |
- sourceRule := []string{"-i", "docker0", "-o", "docker0", "-p", "tcp", "-s", childIP, "--sport", "80", "-d", parentIP, "-j", "ACCEPT"}
|
|
| 123 |
- destinationRule := []string{"-i", "docker0", "-o", "docker0", "-p", "tcp", "-s", parentIP, "--dport", "80", "-d", childIP, "-j", "ACCEPT"}
|
|
| 124 |
- if !iptables.Exists("filter", "DOCKER", sourceRule...) || !iptables.Exists("filter", "DOCKER", destinationRule...) {
|
|
| 125 |
- c.Fatal("Iptables rules not found")
|
|
| 126 |
- } |
|
| 127 |
- |
|
| 128 |
- dockerCmd(c, "rm", "--link", "parent/http") |
|
| 129 |
- if iptables.Exists("filter", "DOCKER", sourceRule...) || iptables.Exists("filter", "DOCKER", destinationRule...) {
|
|
| 130 |
- c.Fatal("Iptables rules should be removed when unlink")
|
|
| 131 |
- } |
|
| 132 |
- |
|
| 133 |
- dockerCmd(c, "kill", "child") |
|
| 134 |
- dockerCmd(c, "kill", "parent") |
|
| 135 |
- |
|
| 136 |
-} |
|
| 137 |
- |
|
| 138 | 113 |
func (s *DockerSuite) TestLinksInspectLinksStarted(c *check.C) {
|
| 139 | 114 |
var ( |
| 140 | 115 |
expected = map[string]struct{}{"/container1:/testinspectlink/alias1": {}, "/container2:/testinspectlink/alias2": {}}
|
| ... | ... |
@@ -19,7 +19,7 @@ import ( |
| 19 | 19 |
"time" |
| 20 | 20 |
|
| 21 | 21 |
"github.com/docker/docker/nat" |
| 22 |
- "github.com/docker/docker/pkg/resolvconf" |
|
| 22 |
+ "github.com/docker/libnetwork/resolvconf" |
|
| 23 | 23 |
"github.com/go-check/check" |
| 24 | 24 |
) |
| 25 | 25 |
|
| ... | ... |
@@ -1459,14 +1459,11 @@ func (s *DockerSuite) TestRunDnsOptionsBasedOnHostResolvConf(c *check.C) {
|
| 1459 | 1459 |
} |
| 1460 | 1460 |
} |
| 1461 | 1461 |
|
| 1462 |
-// Test the file watch notifier on docker host's /etc/resolv.conf |
|
| 1463 |
-// A go-routine is responsible for auto-updating containers which are |
|
| 1464 |
-// stopped and have an unmodified copy of resolv.conf, as well as |
|
| 1465 |
-// marking running containers as requiring an update on next restart |
|
| 1466 |
-func (s *DockerSuite) TestRunResolvconfUpdater(c *check.C) {
|
|
| 1467 |
- // Because overlay doesn't support inotify properly, we need to skip |
|
| 1468 |
- // this test if the docker daemon has Storage Driver == overlay |
|
| 1469 |
- testRequires(c, SameHostDaemon, NotOverlay) |
|
| 1462 |
+// Test if container resolv.conf gets updated the next time it restarts |
|
| 1463 |
+// if host /etc/resolv.conf has changed. This only applies if the container |
|
| 1464 |
+// uses the host's /etc/resolv.conf and does not have any dns options provided. |
|
| 1465 |
+func (s *DockerSuite) TestRunResolvconfUpdate(c *check.C) {
|
|
| 1466 |
+ testRequires(c, SameHostDaemon) |
|
| 1470 | 1467 |
|
| 1471 | 1468 |
tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78")
|
| 1472 | 1469 |
tmpLocalhostResolvConf := []byte("nameserver 127.0.0.1")
|
| ... | ... |
@@ -1492,7 +1489,7 @@ func (s *DockerSuite) TestRunResolvconfUpdater(c *check.C) {
|
| 1492 | 1492 |
} |
| 1493 | 1493 |
}() |
| 1494 | 1494 |
|
| 1495 |
- //1. test that a non-running container gets an updated resolv.conf |
|
| 1495 |
+ //1. test that a restarting container gets an updated resolv.conf |
|
| 1496 | 1496 |
cmd = exec.Command(dockerBinary, "run", "--name='first'", "busybox", "true") |
| 1497 | 1497 |
if _, err := runCommand(cmd); err != nil {
|
| 1498 | 1498 |
c.Fatal(err) |
| ... | ... |
@@ -1508,17 +1505,26 @@ func (s *DockerSuite) TestRunResolvconfUpdater(c *check.C) {
|
| 1508 | 1508 |
c.Fatal(err) |
| 1509 | 1509 |
} |
| 1510 | 1510 |
|
| 1511 |
- time.Sleep(time.Second / 2) |
|
| 1511 |
+ // start the container again to pickup changes |
|
| 1512 |
+ cmd = exec.Command(dockerBinary, "start", "first") |
|
| 1513 |
+ if out, err := runCommand(cmd); err != nil {
|
|
| 1514 |
+ c.Fatalf("Errored out %s, \nerror: %v", string(out), err)
|
|
| 1515 |
+ } |
|
| 1516 |
+ |
|
| 1512 | 1517 |
// check for update in container |
| 1513 | 1518 |
containerResolv, err := readContainerFile(containerID1, "resolv.conf") |
| 1514 | 1519 |
if err != nil {
|
| 1515 | 1520 |
c.Fatal(err) |
| 1516 | 1521 |
} |
| 1517 | 1522 |
if !bytes.Equal(containerResolv, bytesResolvConf) {
|
| 1518 |
- c.Fatalf("Stopped container does not have updated resolv.conf; expected %q, got %q", tmpResolvConf, string(containerResolv))
|
|
| 1523 |
+ c.Fatalf("Restarted container does not have updated resolv.conf; expected %q, got %q", tmpResolvConf, string(containerResolv))
|
|
| 1519 | 1524 |
} |
| 1520 | 1525 |
|
| 1521 |
- //2. test that a non-running container does not receive resolv.conf updates |
|
| 1526 |
+ /* //make a change to resolv.conf (in this case replacing our tmp copy with orig copy) |
|
| 1527 |
+ if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
|
|
| 1528 |
+ c.Fatal(err) |
|
| 1529 |
+ } */ |
|
| 1530 |
+ //2. test that a restarting container does not receive resolv.conf updates |
|
| 1522 | 1531 |
// if it modified the container copy of the starting point resolv.conf |
| 1523 | 1532 |
cmd = exec.Command(dockerBinary, "run", "--name='second'", "busybox", "sh", "-c", "echo 'search mylittlepony.com' >>/etc/resolv.conf") |
| 1524 | 1533 |
if _, err = runCommand(cmd); err != nil {
|
| ... | ... |
@@ -1528,24 +1534,26 @@ func (s *DockerSuite) TestRunResolvconfUpdater(c *check.C) {
|
| 1528 | 1528 |
if err != nil {
|
| 1529 | 1529 |
c.Fatal(err) |
| 1530 | 1530 |
} |
| 1531 |
- containerResolvHashBefore, err := readContainerFile(containerID2, "resolv.conf.hash") |
|
| 1532 |
- if err != nil {
|
|
| 1533 |
- c.Fatal(err) |
|
| 1534 |
- } |
|
| 1535 | 1531 |
|
| 1536 | 1532 |
//make a change to resolv.conf (in this case replacing our tmp copy with orig copy) |
| 1537 | 1533 |
if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
|
| 1538 | 1534 |
c.Fatal(err) |
| 1539 | 1535 |
} |
| 1540 | 1536 |
|
| 1541 |
- time.Sleep(time.Second / 2) |
|
| 1542 |
- containerResolvHashAfter, err := readContainerFile(containerID2, "resolv.conf.hash") |
|
| 1537 |
+ // start the container again |
|
| 1538 |
+ cmd = exec.Command(dockerBinary, "start", "second") |
|
| 1539 |
+ if out, err := runCommand(cmd); err != nil {
|
|
| 1540 |
+ c.Fatalf("Errored out %s, \nerror: %v", string(out), err)
|
|
| 1541 |
+ } |
|
| 1542 |
+ |
|
| 1543 |
+ // check for update in container |
|
| 1544 |
+ containerResolv, err = readContainerFile(containerID2, "resolv.conf") |
|
| 1543 | 1545 |
if err != nil {
|
| 1544 | 1546 |
c.Fatal(err) |
| 1545 | 1547 |
} |
| 1546 | 1548 |
|
| 1547 |
- if !bytes.Equal(containerResolvHashBefore, containerResolvHashAfter) {
|
|
| 1548 |
- c.Fatalf("Stopped container with modified resolv.conf should not have been updated; expected hash: %v, new hash: %v", containerResolvHashBefore, containerResolvHashAfter)
|
|
| 1549 |
+ if bytes.Equal(containerResolv, resolvConfSystem) {
|
|
| 1550 |
+ c.Fatalf("Restarting a container after container updated resolv.conf should not pick up host changes; expected %q, got %q", string(containerResolv), string(resolvConfSystem))
|
|
| 1549 | 1551 |
} |
| 1550 | 1552 |
|
| 1551 | 1553 |
//3. test that a running container's resolv.conf is not modified while running |
| ... | ... |
@@ -1556,26 +1564,19 @@ func (s *DockerSuite) TestRunResolvconfUpdater(c *check.C) {
|
| 1556 | 1556 |
} |
| 1557 | 1557 |
runningContainerID := strings.TrimSpace(out) |
| 1558 | 1558 |
|
| 1559 |
- containerResolvHashBefore, err = readContainerFile(runningContainerID, "resolv.conf.hash") |
|
| 1560 |
- if err != nil {
|
|
| 1561 |
- c.Fatal(err) |
|
| 1562 |
- } |
|
| 1563 |
- |
|
| 1564 | 1559 |
// replace resolv.conf |
| 1565 | 1560 |
if err := ioutil.WriteFile("/etc/resolv.conf", bytesResolvConf, 0644); err != nil {
|
| 1566 | 1561 |
c.Fatal(err) |
| 1567 | 1562 |
} |
| 1568 | 1563 |
|
| 1569 |
- // make sure the updater has time to run to validate we really aren't |
|
| 1570 |
- // getting updated |
|
| 1571 |
- time.Sleep(time.Second / 2) |
|
| 1572 |
- containerResolvHashAfter, err = readContainerFile(runningContainerID, "resolv.conf.hash") |
|
| 1564 |
+ // check for update in container |
|
| 1565 |
+ containerResolv, err = readContainerFile(runningContainerID, "resolv.conf") |
|
| 1573 | 1566 |
if err != nil {
|
| 1574 | 1567 |
c.Fatal(err) |
| 1575 | 1568 |
} |
| 1576 | 1569 |
|
| 1577 |
- if !bytes.Equal(containerResolvHashBefore, containerResolvHashAfter) {
|
|
| 1578 |
- c.Fatalf("Running container's resolv.conf should not be updated; expected hash: %v, new hash: %v", containerResolvHashBefore, containerResolvHashAfter)
|
|
| 1570 |
+ if bytes.Equal(containerResolv, bytesResolvConf) {
|
|
| 1571 |
+ c.Fatalf("Running container should not have updated resolv.conf; expected %q, got %q", string(resolvConfSystem), string(containerResolv))
|
|
| 1579 | 1572 |
} |
| 1580 | 1573 |
|
| 1581 | 1574 |
//4. test that a running container's resolv.conf is updated upon restart |
| ... | ... |
@@ -1591,7 +1592,7 @@ func (s *DockerSuite) TestRunResolvconfUpdater(c *check.C) {
|
| 1591 | 1591 |
c.Fatal(err) |
| 1592 | 1592 |
} |
| 1593 | 1593 |
if !bytes.Equal(containerResolv, bytesResolvConf) {
|
| 1594 |
- c.Fatalf("Restarted container should have updated resolv.conf; expected %q, got %q", tmpResolvConf, string(containerResolv))
|
|
| 1594 |
+ c.Fatalf("Restarted container should have updated resolv.conf; expected %q, got %q", string(bytesResolvConf), string(containerResolv))
|
|
| 1595 | 1595 |
} |
| 1596 | 1596 |
|
| 1597 | 1597 |
//5. test that additions of a localhost resolver are cleaned from |
| ... | ... |
@@ -1603,7 +1604,12 @@ func (s *DockerSuite) TestRunResolvconfUpdater(c *check.C) {
|
| 1603 | 1603 |
c.Fatal(err) |
| 1604 | 1604 |
} |
| 1605 | 1605 |
|
| 1606 |
- time.Sleep(time.Second / 2) |
|
| 1606 |
+ // start the container again to pickup changes |
|
| 1607 |
+ cmd = exec.Command(dockerBinary, "start", "first") |
|
| 1608 |
+ if out, err := runCommand(cmd); err != nil {
|
|
| 1609 |
+ c.Fatalf("Errored out %s, \nerror: %v", string(out), err)
|
|
| 1610 |
+ } |
|
| 1611 |
+ |
|
| 1607 | 1612 |
// our first exited container ID should have been updated, but with default DNS |
| 1608 | 1613 |
// after the cleanup of resolv.conf found only a localhost nameserver: |
| 1609 | 1614 |
containerResolv, err = readContainerFile(containerID1, "resolv.conf") |
| ... | ... |
@@ -1645,7 +1651,12 @@ func (s *DockerSuite) TestRunResolvconfUpdater(c *check.C) {
|
| 1645 | 1645 |
c.Fatal(err) |
| 1646 | 1646 |
} |
| 1647 | 1647 |
|
| 1648 |
- time.Sleep(time.Second / 2) |
|
| 1648 |
+ // start the container again to pickup changes |
|
| 1649 |
+ cmd = exec.Command(dockerBinary, "start", "third") |
|
| 1650 |
+ if out, err := runCommand(cmd); err != nil {
|
|
| 1651 |
+ c.Fatalf("Errored out %s, \nerror: %v", string(out), err)
|
|
| 1652 |
+ } |
|
| 1653 |
+ |
|
| 1649 | 1654 |
// check for update in container |
| 1650 | 1655 |
containerResolv, err = readContainerFile(containerID3, "resolv.conf") |
| 1651 | 1656 |
if err != nil {
|
| ... | ... |
@@ -5,9 +5,7 @@ import ( |
| 5 | 5 |
"path" |
| 6 | 6 |
"strings" |
| 7 | 7 |
|
| 8 |
- "github.com/docker/docker/daemon/networkdriver/bridge" |
|
| 9 | 8 |
"github.com/docker/docker/nat" |
| 10 |
- "github.com/docker/docker/pkg/iptables" |
|
| 11 | 9 |
) |
| 12 | 10 |
|
| 13 | 11 |
type Link struct {
|
| ... | ... |
@@ -140,26 +138,10 @@ func (l *Link) getDefaultPort() *nat.Port {
|
| 140 | 140 |
} |
| 141 | 141 |
|
| 142 | 142 |
func (l *Link) Enable() error {
|
| 143 |
- // -A == iptables append flag |
|
| 144 |
- if err := l.toggle("-A", false); err != nil {
|
|
| 145 |
- return err |
|
| 146 |
- } |
|
| 147 |
- // call this on Firewalld reload |
|
| 148 |
- iptables.OnReloaded(func() { l.toggle("-A", false) })
|
|
| 149 | 143 |
l.IsEnabled = true |
| 150 | 144 |
return nil |
| 151 | 145 |
} |
| 152 | 146 |
|
| 153 | 147 |
func (l *Link) Disable() {
|
| 154 |
- // We do not care about errors here because the link may not |
|
| 155 |
- // exist in iptables |
|
| 156 |
- // -D == iptables delete flag |
|
| 157 |
- l.toggle("-D", true)
|
|
| 158 |
- // call this on Firewalld reload |
|
| 159 |
- iptables.OnReloaded(func() { l.toggle("-D", true) })
|
|
| 160 | 148 |
l.IsEnabled = false |
| 161 | 149 |
} |
| 162 |
- |
|
| 163 |
-func (l *Link) toggle(action string, ignoreErrors bool) error {
|
|
| 164 |
- return bridge.LinkContainers(action, l.ParentIP, l.ChildIP, l.Ports, ignoreErrors) |
|
| 165 |
-} |
| ... | ... |
@@ -18,7 +18,7 @@ type NetworkMode string |
| 18 | 18 |
|
| 19 | 19 |
// IsPrivate indicates whether container use it's private network stack |
| 20 | 20 |
func (n NetworkMode) IsPrivate() bool {
|
| 21 |
- return !(n.IsHost() || n.IsContainer() || n.IsNone()) |
|
| 21 |
+ return !(n.IsHost() || n.IsContainer()) |
|
| 22 | 22 |
} |
| 23 | 23 |
|
| 24 | 24 |
func (n NetworkMode) IsBridge() bool {
|