From 1b9a08e719776e53b7aea1a89c2c29fbf27b1ae4 Mon Sep 17 00:00:00 2001 From: Lei Jitang Date: Mon, 26 Oct 2015 08:00:49 -0400 Subject: [PATCH 1/2] Fix docker inspect container only reports last assigned information Signed-off-by: Lei Jitang --- daemon/container_unix.go | 103 ++++++++++++------ daemon/network/settings.go | 30 +++-- integration-cli/docker_api_network_test.go | 4 +- integration-cli/docker_api_stats_test.go | 2 +- .../docker_cli_network_unix_test.go | 2 +- integration-cli/docker_utils.go | 6 +- 6 files changed, 95 insertions(+), 52 deletions(-) diff --git a/daemon/container_unix.go b/daemon/container_unix.go index d5ea7afd97e0c..d6766f73e9947 100644 --- a/daemon/container_unix.go +++ b/daemon/container_unix.go @@ -615,10 +615,6 @@ func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint, networkSett return networkSettings, nil } - if mac, ok := driverInfo[netlabel.MacAddress]; ok { - networkSettings.MacAddress = mac.(net.HardwareAddr).String() - } - networkSettings.Ports = nat.PortMap{} if expData, ok := driverInfo[netlabel.ExposedPorts]; ok { @@ -652,7 +648,7 @@ func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint, networkSett return networkSettings, nil } -func (container *Container) buildEndpointInfo(ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) { +func (container *Container) buildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) { if ep == nil { return nil, derr.ErrorCodeEmptyEndpoint } @@ -667,36 +663,70 @@ func (container *Container) buildEndpointInfo(ep libnetwork.Endpoint, networkSet return networkSettings, nil } + networkSettings.Networks[n.Name()].EndpointID = ep.ID() + iface := epInfo.Iface() if iface == nil { return networkSettings, nil } + if networkSettings.EndpointID == "" { + networkSettings.EndpointID = ep.ID() + } if iface.Address() != nil { ones, _ := iface.Address().Mask.Size() - networkSettings.IPAddress = iface.Address().IP.String() - networkSettings.IPPrefixLen = ones + if networkSettings.IPAddress == "" || networkSettings.IPPrefixLen == 0 { + networkSettings.IPAddress = iface.Address().IP.String() + networkSettings.IPPrefixLen = ones + } + networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String() + networkSettings.Networks[n.Name()].IPPrefixLen = ones } if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil { onesv6, _ := iface.AddressIPv6().Mask.Size() - networkSettings.GlobalIPv6Address = iface.AddressIPv6().IP.String() - networkSettings.GlobalIPv6PrefixLen = onesv6 + if networkSettings.GlobalIPv6Address == "" || networkSettings.GlobalIPv6PrefixLen == 0 { + networkSettings.GlobalIPv6Address = iface.AddressIPv6().IP.String() + networkSettings.GlobalIPv6PrefixLen = onesv6 + } + networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String() + networkSettings.Networks[n.Name()].GlobalIPv6PrefixLen = onesv6 + } + + driverInfo, err := ep.DriverInfo() + if err != nil { + return nil, err + } + + if driverInfo == nil { + // It is not an error for epInfo to be nil + return networkSettings, nil + } + if mac, ok := driverInfo[netlabel.MacAddress]; ok { + if networkSettings.MacAddress == "" { + networkSettings.MacAddress = mac.(net.HardwareAddr).String() + } + networkSettings.Networks[n.Name()].MacAddress = mac.(net.HardwareAddr).String() } return networkSettings, nil } -func (container *Container) updateJoinInfo(ep libnetwork.Endpoint) error { +func (container *Container) updateJoinInfo(n libnetwork.Network, ep libnetwork.Endpoint) error { epInfo := ep.Info() if epInfo == nil { // It is not an error to get an empty endpoint info return nil } - - container.NetworkSettings.Gateway = epInfo.Gateway().String() + if container.NetworkSettings.Gateway == "" { + container.NetworkSettings.Gateway = epInfo.Gateway().String() + } + container.NetworkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String() if epInfo.GatewayIPv6().To16() != nil { - container.NetworkSettings.IPv6Gateway = epInfo.GatewayIPv6().String() + if container.NetworkSettings.IPv6Gateway == "" { + container.NetworkSettings.IPv6Gateway = epInfo.GatewayIPv6().String() + } + container.NetworkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String() } return nil @@ -704,11 +734,10 @@ func (container *Container) updateJoinInfo(ep libnetwork.Endpoint) error { func (container *Container) updateNetworkSettings(n libnetwork.Network) error { if container.NetworkSettings == nil { - container.NetworkSettings = &network.Settings{Networks: []string{}} + container.NetworkSettings = &network.Settings{Networks: make(map[string]*network.EndpointSettings)} } - settings := container.NetworkSettings - for _, s := range settings.Networks { + for s := range container.NetworkSettings.Networks { sn, err := container.daemon.FindNetwork(s) if err != nil { continue @@ -727,7 +756,7 @@ func (container *Container) updateNetworkSettings(n libnetwork.Network) error { return runconfig.ErrConflictNoNetwork } } - settings.Networks = append(settings.Networks, n.Name()) + container.NetworkSettings.Networks[n.Name()] = new(network.EndpointSettings) return nil } @@ -738,7 +767,7 @@ func (container *Container) updateEndpointNetworkSettings(n libnetwork.Network, return err } - networkSettings, err = container.buildEndpointInfo(ep, networkSettings) + networkSettings, err = container.buildEndpointInfo(n, ep, networkSettings) if err != nil { return err } @@ -769,7 +798,7 @@ func (container *Container) updateNetwork() error { // Find if container is connected to the default bridge network var n libnetwork.Network - for _, name := range container.NetworkSettings.Networks { + for name := range container.NetworkSettings.Networks { sn, err := container.daemon.FindNetwork(name) if err != nil { continue @@ -899,9 +928,8 @@ func createNetwork(controller libnetwork.NetworkController, dnet string, driver } func (container *Container) allocateNetwork() error { - settings := container.NetworkSettings.Networks updateSettings := false - if settings == nil { + if len(container.NetworkSettings.Networks) == 0 { mode := container.hostConfig.NetworkMode controller := container.daemon.netController if container.Config.NetworkDisabled || mode.IsContainer() { @@ -912,11 +940,12 @@ func (container *Container) allocateNetwork() error { if mode.IsDefault() { networkName = controller.Config().Daemon.DefaultNetwork } - settings = []string{networkName} + container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings) + container.NetworkSettings.Networks[networkName] = new(network.EndpointSettings) updateSettings = true } - for _, n := range settings { + for n := range container.NetworkSettings.Networks { if err := container.connectToNetwork(n, updateSettings); err != nil { return err } @@ -1015,7 +1044,7 @@ func (container *Container) connectToNetwork(idOrName string, updateSettings boo return err } - if err := container.updateJoinInfo(ep); err != nil { + if err := container.updateJoinInfo(n, ep); err != nil { return derr.ErrorCodeJoinInfo.WithArgs(err) } @@ -1142,6 +1171,9 @@ func (container *Container) releaseNetwork() { sid := container.NetworkSettings.SandboxID networks := container.NetworkSettings.Networks + for n := range networks { + networks[n] = &network.EndpointSettings{} + } container.NetworkSettings = &network.Settings{Networks: networks} @@ -1199,19 +1231,18 @@ func (container *Container) disconnectFromNetwork(n libnetwork.Network) error { return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err) } - networks := container.NetworkSettings.Networks - for i, s := range networks { - sn, err := container.daemon.FindNetwork(s) - if err != nil { - continue - } - if sn.Name() == n.Name() { - networks = append(networks[:i], networks[i+1:]...) - container.NetworkSettings.Networks = networks - break - } - } + if container.NetworkSettings.EndpointID == container.NetworkSettings.Networks[n.Name()].EndpointID { + container.NetworkSettings.EndpointID = "" + container.NetworkSettings.Gateway = "" + container.NetworkSettings.GlobalIPv6Address = "" + container.NetworkSettings.GlobalIPv6PrefixLen = 0 + container.NetworkSettings.IPAddress = "" + container.NetworkSettings.IPPrefixLen = 0 + container.NetworkSettings.IPv6Gateway = "" + container.NetworkSettings.MacAddress = "" + } + delete(container.NetworkSettings.Networks, n.Name()) return nil } diff --git a/daemon/network/settings.go b/daemon/network/settings.go index 4ade4354134ff..ecfecc60c69d0 100644 --- a/daemon/network/settings.go +++ b/daemon/network/settings.go @@ -26,22 +26,34 @@ type IPAMConfig struct { // TODO Windows. Many of these fields can be factored out., type Settings struct { Bridge string - EndpointID string + EndpointID string // this is for backward compatibility SandboxID string - Gateway string - GlobalIPv6Address string - GlobalIPv6PrefixLen int + Gateway string // this is for backward compatibility + GlobalIPv6Address string // this is for backward compatibility + GlobalIPv6PrefixLen int // this is for backward compatibility HairpinMode bool - IPAddress string - IPPrefixLen int - IPv6Gateway string + IPAddress string // this is for backward compatibility + IPPrefixLen int // this is for backward compatibility + IPv6Gateway string // this is for backward compatibility LinkLocalIPv6Address string LinkLocalIPv6PrefixLen int - MacAddress string - Networks []string + MacAddress string // this is for backward compatibility + Networks map[string]*EndpointSettings Ports nat.PortMap SandboxKey string SecondaryIPAddresses []Address SecondaryIPv6Addresses []Address IsAnonymousEndpoint bool } + +// EndpointSettings stores the network endpoint details +type EndpointSettings struct { + EndpointID string + Gateway string + IPAddress string + IPPrefixLen int + IPv6Gateway string + GlobalIPv6Address string + GlobalIPv6PrefixLen int + MacAddress string +} diff --git a/integration-cli/docker_api_network_test.go b/integration-cli/docker_api_network_test.go index f76796b77870a..2180cd10e4299 100644 --- a/integration-cli/docker_api_network_test.go +++ b/integration-cli/docker_api_network_test.go @@ -54,7 +54,7 @@ func (s *DockerSuite) TestApiNetworkInspect(c *check.C) { // run a container and attach it to the default bridge network out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top") containerID := strings.TrimSpace(out) - containerIP := findContainerIP(c, "test") + containerIP := findContainerIP(c, "test", "bridge") // inspect default bridge network again and make sure the container is connected nr = getNetworkResource(c, nr.ID) @@ -122,7 +122,7 @@ func (s *DockerSuite) TestApiNetworkConnectDisconnect(c *check.C) { // check if container IP matches network inspect ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address) c.Assert(err, checker.IsNil) - containerIP := findContainerIP(c, "test") + containerIP := findContainerIP(c, "test", "testnetwork") c.Assert(ip.String(), checker.Equals, containerIP) // disconnect container from the network diff --git a/integration-cli/docker_api_stats_test.go b/integration-cli/docker_api_stats_test.go index cf204b92f1642..4b302dacbcf01 100644 --- a/integration-cli/docker_api_stats_test.go +++ b/integration-cli/docker_api_stats_test.go @@ -85,7 +85,7 @@ func (s *DockerSuite) TestApiStatsNetworkStats(c *check.C) { c.Assert(waitRun(id), checker.IsNil) // Retrieve the container address - contIP := findContainerIP(c, id) + contIP := findContainerIP(c, id, "bridge") numPings := 10 var preRxPackets uint64 diff --git a/integration-cli/docker_cli_network_unix_test.go b/integration-cli/docker_cli_network_unix_test.go index fca94b219e1b0..d4a7eb337f9e7 100644 --- a/integration-cli/docker_cli_network_unix_test.go +++ b/integration-cli/docker_cli_network_unix_test.go @@ -284,7 +284,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnect(c *check.C) { // check if container IP matches network inspect ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address) c.Assert(err, check.IsNil) - containerIP := findContainerIP(c, "test") + containerIP := findContainerIP(c, "test", "test") c.Assert(ip.String(), checker.Equals, containerIP) // disconnect container from the network diff --git a/integration-cli/docker_utils.go b/integration-cli/docker_utils.go index 01c53efc09155..67627aff93bf1 100644 --- a/integration-cli/docker_utils.go +++ b/integration-cli/docker_utils.go @@ -782,13 +782,13 @@ func dockerCmdInDirWithTimeout(timeout time.Duration, path string, args ...strin return integration.DockerCmdInDirWithTimeout(dockerBinary, timeout, path, args...) } -func findContainerIP(c *check.C, id string, vargs ...string) string { - out, _ := dockerCmd(c, "inspect", "--format='{{ .NetworkSettings.IPAddress }}'", id) +func findContainerIP(c *check.C, id string, network string) string { + out, _ := dockerCmd(c, "inspect", fmt.Sprintf("--format='{{ .NetworkSettings.Networks.%s.IPAddress }}'", network), id) return strings.Trim(out, " \r\n'") } func (d *Daemon) findContainerIP(id string) string { - return findContainerIP(d.c, id, "--host", d.sock()) + return findContainerIP(d.c, id, "--host") } func getContainerCount() (int, error) { From 25682577c9d29b325b4b615c4b88c132a4640082 Mon Sep 17 00:00:00 2001 From: David Calavera Date: Mon, 26 Oct 2015 22:35:49 -0400 Subject: [PATCH 2/2] Extract network settings types for inspect. Keeping backwards compatibility. Signed-off-by: David Calavera Signed-off-by: Tibor Vass --- api/types/types.go | 26 +++++++- api/types/versions/v1p19/types.go | 8 ++- api/types/versions/v1p20/types.go | 18 +++++- daemon/container.go | 4 -- daemon/container_unix.go | 63 ++++++------------ daemon/inspect.go | 78 +++++++++++++++++------ daemon/inspect_unix.go | 3 +- daemon/network/settings.go | 8 --- integration-cli/docker_cli_daemon_test.go | 8 +-- integration-cli/docker_cli_links_test.go | 4 +- integration-cli/docker_cli_run_test.go | 10 +-- integration-cli/docker_utils.go | 6 +- 12 files changed, 143 insertions(+), 93 deletions(-) diff --git a/api/types/types.go b/api/types/types.go index efe5ea28beb1f..5a63faad37b3b 100644 --- a/api/types/types.go +++ b/api/types/types.go @@ -5,6 +5,7 @@ import ( "time" "github.com/docker/docker/daemon/network" + "github.com/docker/docker/pkg/nat" "github.com/docker/docker/pkg/version" "github.com/docker/docker/registry" "github.com/docker/docker/runconfig" @@ -255,7 +256,6 @@ type ContainerJSONBase struct { Args []string State *ContainerState Image string - NetworkSettings *network.Settings ResolvConfPath string HostnamePath string HostsPath string @@ -277,8 +277,28 @@ type ContainerJSONBase struct { // ContainerJSON is newly used struct along with MountPoint type ContainerJSON struct { *ContainerJSONBase - Mounts []MountPoint - Config *runconfig.Config + Mounts []MountPoint + Config *runconfig.Config + NetworkSettings *NetworkSettings +} + +// NetworkSettings exposes the network settings in the api +type NetworkSettings struct { + NetworkSettingsBase + Networks map[string]*network.EndpointSettings +} + +// NetworkSettingsBase holds basic information about networks +type NetworkSettingsBase struct { + Bridge string + SandboxID string + HairpinMode bool + LinkLocalIPv6Address string + LinkLocalIPv6PrefixLen int + Ports nat.PortMap + SandboxKey string + SecondaryIPAddresses []network.Address + SecondaryIPv6Addresses []network.Address } // MountPoint represents a mount point configuration inside the container. diff --git a/api/types/versions/v1p19/types.go b/api/types/versions/v1p19/types.go index da31b5ca202d4..a66aa9d5e5257 100644 --- a/api/types/versions/v1p19/types.go +++ b/api/types/versions/v1p19/types.go @@ -3,6 +3,7 @@ package v1p19 import ( "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/versions/v1p20" "github.com/docker/docker/pkg/nat" "github.com/docker/docker/runconfig" ) @@ -11,9 +12,10 @@ import ( // Note this is not used by the Windows daemon. type ContainerJSON struct { *types.ContainerJSONBase - Volumes map[string]string - VolumesRW map[string]bool - Config *ContainerConfig + Volumes map[string]string + VolumesRW map[string]bool + Config *ContainerConfig + NetworkSettings *v1p20.NetworkSettings } // ContainerConfig is a backcompatibility struct for APIs prior to 1.20. diff --git a/api/types/versions/v1p20/types.go b/api/types/versions/v1p20/types.go index 3255204dac474..7b2c25d08a04e 100644 --- a/api/types/versions/v1p20/types.go +++ b/api/types/versions/v1p20/types.go @@ -10,8 +10,9 @@ import ( // ContainerJSON is a backcompatibility struct for the API 1.20 type ContainerJSON struct { *types.ContainerJSONBase - Mounts []types.MountPoint - Config *ContainerConfig + Mounts []types.MountPoint + Config *ContainerConfig + NetworkSettings *NetworkSettings } // ContainerConfig is a backcompatibility struct used in ContainerJSON for the API 1.20 @@ -31,3 +32,16 @@ type StatsJSON struct { types.Stats Network types.NetworkStats `json:"network,omitempty"` } + +// NetworkSettings is a backward compatible struct for APIs prior to 1.21 +type NetworkSettings struct { + types.NetworkSettingsBase + EndpointID string + Gateway string + GlobalIPv6Address string + GlobalIPv6PrefixLen int + IPAddress string + IPPrefixLen int + IPv6Gateway string + MacAddress string +} diff --git a/daemon/container.go b/daemon/container.go index 2cc0ecb3bd3f8..480bd8eb96277 100644 --- a/daemon/container.go +++ b/daemon/container.go @@ -332,10 +332,6 @@ func (streamConfig *streamConfig) StderrPipe() io.ReadCloser { return ioutils.NewBufReader(reader) } -func (container *Container) isNetworkAllocated() bool { - return container.NetworkSettings.IPAddress != "" -} - // cleanup releases any network resources allocated to the container along with any rules // around how containers are linked together. It also unmounts the container's root filesystem. func (container *Container) cleanup() { diff --git a/daemon/container_unix.go b/daemon/container_unix.go index d6766f73e9947..5c48019ef51eb 100644 --- a/daemon/container_unix.go +++ b/daemon/container_unix.go @@ -88,15 +88,25 @@ func (container *Container) setupLinkedContainers() ([]string, error) { return nil, err } + bridgeSettings := container.NetworkSettings.Networks["bridge"] + if bridgeSettings == nil { + return nil, nil + } + if len(children) > 0 { for linkAlias, child := range children { if !child.IsRunning() { return nil, derr.ErrorCodeLinkNotRunning.WithArgs(child.Name, linkAlias) } + childBridgeSettings := child.NetworkSettings.Networks["bridge"] + if childBridgeSettings == nil { + return nil, fmt.Errorf("container %d not attached to default bridge network", child.ID) + } + link := links.NewLink( - container.NetworkSettings.IPAddress, - child.NetworkSettings.IPAddress, + bridgeSettings.IPAddress, + childBridgeSettings.IPAddress, linkAlias, child.Config.Env, child.Config.ExposedPorts, @@ -542,13 +552,14 @@ func (container *Container) buildSandboxOptions(n libnetwork.Network) ([]libnetw if alias != child.Name[1:] { aliasList = aliasList + " " + child.Name[1:] } - sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.IPAddress)) + sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.Networks["bridge"].IPAddress)) cEndpoint, _ := child.getEndpointInNetwork(n) if cEndpoint != nil && cEndpoint.ID() != "" { childEndpoints = append(childEndpoints, cEndpoint.ID()) } } + bridgeSettings := container.NetworkSettings.Networks["bridge"] refs := container.daemon.containerGraph().RefPaths(container.ID) for _, ref := range refs { if ref.ParentID == "0" { @@ -561,8 +572,8 @@ func (container *Container) buildSandboxOptions(n libnetwork.Network) ([]libnetw } if c != nil && !container.daemon.configStore.DisableBridge && container.hostConfig.NetworkMode.IsPrivate() { - logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, container.NetworkSettings.IPAddress) - sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(c.ID, ref.Name, container.NetworkSettings.IPAddress)) + logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, bridgeSettings.IPAddress) + sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(c.ID, ref.Name, bridgeSettings.IPAddress)) if ep.ID() != "" { parentEndpoints = append(parentEndpoints, ep.ID()) } @@ -583,12 +594,8 @@ func (container *Container) buildSandboxOptions(n libnetwork.Network) ([]libnetw func isLinkable(child *Container) bool { // A container is linkable only if it belongs to the default network - for _, nw := range child.NetworkSettings.Networks { - if nw == "bridge" { - return true - } - } - return false + _, ok := child.NetworkSettings.Networks["bridge"] + return ok } func (container *Container) getEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) { @@ -663,6 +670,9 @@ func (container *Container) buildEndpointInfo(n libnetwork.Network, ep libnetwor return networkSettings, nil } + if _, ok := networkSettings.Networks[n.Name()]; !ok { + networkSettings.Networks[n.Name()] = new(network.EndpointSettings) + } networkSettings.Networks[n.Name()].EndpointID = ep.ID() iface := epInfo.Iface() @@ -670,25 +680,14 @@ func (container *Container) buildEndpointInfo(n libnetwork.Network, ep libnetwor return networkSettings, nil } - if networkSettings.EndpointID == "" { - networkSettings.EndpointID = ep.ID() - } if iface.Address() != nil { ones, _ := iface.Address().Mask.Size() - if networkSettings.IPAddress == "" || networkSettings.IPPrefixLen == 0 { - networkSettings.IPAddress = iface.Address().IP.String() - networkSettings.IPPrefixLen = ones - } networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String() networkSettings.Networks[n.Name()].IPPrefixLen = ones } if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil { onesv6, _ := iface.AddressIPv6().Mask.Size() - if networkSettings.GlobalIPv6Address == "" || networkSettings.GlobalIPv6PrefixLen == 0 { - networkSettings.GlobalIPv6Address = iface.AddressIPv6().IP.String() - networkSettings.GlobalIPv6PrefixLen = onesv6 - } networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String() networkSettings.Networks[n.Name()].GlobalIPv6PrefixLen = onesv6 } @@ -703,9 +702,6 @@ func (container *Container) buildEndpointInfo(n libnetwork.Network, ep libnetwor return networkSettings, nil } if mac, ok := driverInfo[netlabel.MacAddress]; ok { - if networkSettings.MacAddress == "" { - networkSettings.MacAddress = mac.(net.HardwareAddr).String() - } networkSettings.Networks[n.Name()].MacAddress = mac.(net.HardwareAddr).String() } @@ -718,14 +714,8 @@ func (container *Container) updateJoinInfo(n libnetwork.Network, ep libnetwork.E // It is not an error to get an empty endpoint info return nil } - if container.NetworkSettings.Gateway == "" { - container.NetworkSettings.Gateway = epInfo.Gateway().String() - } container.NetworkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String() if epInfo.GatewayIPv6().To16() != nil { - if container.NetworkSettings.IPv6Gateway == "" { - container.NetworkSettings.IPv6Gateway = epInfo.GatewayIPv6().String() - } container.NetworkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String() } @@ -1231,17 +1221,6 @@ func (container *Container) disconnectFromNetwork(n libnetwork.Network) error { return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err) } - if container.NetworkSettings.EndpointID == container.NetworkSettings.Networks[n.Name()].EndpointID { - container.NetworkSettings.EndpointID = "" - container.NetworkSettings.Gateway = "" - container.NetworkSettings.GlobalIPv6Address = "" - container.NetworkSettings.GlobalIPv6PrefixLen = 0 - container.NetworkSettings.IPAddress = "" - container.NetworkSettings.IPPrefixLen = 0 - container.NetworkSettings.IPv6Gateway = "" - container.NetworkSettings.MacAddress = "" - - } delete(container.NetworkSettings.Networks, n.Name()) return nil } diff --git a/daemon/inspect.go b/daemon/inspect.go index 8bac0408fb610..bd1f07fdca98e 100644 --- a/daemon/inspect.go +++ b/daemon/inspect.go @@ -6,6 +6,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/versions/v1p20" + "github.com/docker/docker/daemon/network" ) // ContainerInspect returns low-level information about a @@ -26,8 +27,22 @@ func (daemon *Daemon) ContainerInspect(name string, size bool) (*types.Container } mountPoints := addMountPoints(container) + networkSettings := &types.NetworkSettings{ + types.NetworkSettingsBase{ + Bridge: container.NetworkSettings.Bridge, + SandboxID: container.NetworkSettings.SandboxID, + HairpinMode: container.NetworkSettings.HairpinMode, + LinkLocalIPv6Address: container.NetworkSettings.LinkLocalIPv6Address, + LinkLocalIPv6PrefixLen: container.NetworkSettings.LinkLocalIPv6PrefixLen, + Ports: container.NetworkSettings.Ports, + SandboxKey: container.NetworkSettings.SandboxKey, + SecondaryIPAddresses: container.NetworkSettings.SecondaryIPAddresses, + SecondaryIPv6Addresses: container.NetworkSettings.SecondaryIPv6Addresses, + }, + container.NetworkSettings.Networks, + } - return &types.ContainerJSON{base, mountPoints, container.Config}, nil + return &types.ContainerJSON{base, mountPoints, container.Config, networkSettings}, nil } // ContainerInspect120 serializes the master version of a container into a json type. @@ -53,8 +68,9 @@ func (daemon *Daemon) ContainerInspect120(name string) (*v1p20.ContainerJSON, er container.Config.ExposedPorts, container.hostConfig.VolumeDriver, } + networkSettings := getBackwardsCompatibleNetworkSettings(container.NetworkSettings) - return &v1p20.ContainerJSON{base, mountPoints, config}, nil + return &v1p20.ContainerJSON{base, mountPoints, config, networkSettings}, nil } func (daemon *Daemon) getInspectData(container *Container, size bool) (*types.ContainerJSONBase, error) { @@ -91,22 +107,21 @@ func (daemon *Daemon) getInspectData(container *Container, size bool) (*types.Co } contJSONBase := &types.ContainerJSONBase{ - ID: container.ID, - Created: container.Created.Format(time.RFC3339Nano), - Path: container.Path, - Args: container.Args, - State: containerState, - Image: container.ImageID, - NetworkSettings: container.NetworkSettings, - LogPath: container.LogPath, - Name: container.Name, - RestartCount: container.RestartCount, - Driver: container.Driver, - ExecDriver: container.ExecDriver, - MountLabel: container.MountLabel, - ProcessLabel: container.ProcessLabel, - ExecIDs: container.getExecIDs(), - HostConfig: &hostConfig, + ID: container.ID, + Created: container.Created.Format(time.RFC3339Nano), + Path: container.Path, + Args: container.Args, + State: containerState, + Image: container.ImageID, + LogPath: container.LogPath, + Name: container.Name, + RestartCount: container.RestartCount, + Driver: container.Driver, + ExecDriver: container.ExecDriver, + MountLabel: container.MountLabel, + ProcessLabel: container.ProcessLabel, + ExecIDs: container.getExecIDs(), + HostConfig: &hostConfig, } var ( @@ -151,3 +166,30 @@ func (daemon *Daemon) VolumeInspect(name string) (*types.Volume, error) { } return volumeToAPIType(v), nil } + +func getBackwardsCompatibleNetworkSettings(settings *network.Settings) *v1p20.NetworkSettings { + result := &v1p20.NetworkSettings{ + NetworkSettingsBase: types.NetworkSettingsBase{ + Bridge: settings.Bridge, + SandboxID: settings.SandboxID, + HairpinMode: settings.HairpinMode, + LinkLocalIPv6Address: settings.LinkLocalIPv6Address, + LinkLocalIPv6PrefixLen: settings.LinkLocalIPv6PrefixLen, + Ports: settings.Ports, + SandboxKey: settings.SandboxKey, + SecondaryIPAddresses: settings.SecondaryIPAddresses, + SecondaryIPv6Addresses: settings.SecondaryIPv6Addresses, + }, + } + if bridgeSettings := settings.Networks["bridge"]; bridgeSettings != nil { + result.EndpointID = bridgeSettings.EndpointID + result.Gateway = bridgeSettings.Gateway + result.GlobalIPv6Address = bridgeSettings.GlobalIPv6Address + result.GlobalIPv6PrefixLen = bridgeSettings.GlobalIPv6PrefixLen + result.IPAddress = bridgeSettings.IPAddress + result.IPPrefixLen = bridgeSettings.IPPrefixLen + result.IPv6Gateway = bridgeSettings.IPv6Gateway + result.MacAddress = bridgeSettings.MacAddress + } + return result +} diff --git a/daemon/inspect_unix.go b/daemon/inspect_unix.go index 1122259ff9fdf..d2d8794d04181 100644 --- a/daemon/inspect_unix.go +++ b/daemon/inspect_unix.go @@ -50,8 +50,9 @@ func (daemon *Daemon) ContainerInspectPre120(name string) (*v1p19.ContainerJSON, container.hostConfig.CPUShares, container.hostConfig.CpusetCpus, } + networkSettings := getBackwardsCompatibleNetworkSettings(container.NetworkSettings) - return &v1p19.ContainerJSON{base, volumes, volumesRW, config}, nil + return &v1p19.ContainerJSON{base, volumes, volumesRW, config, networkSettings}, nil } func addMountPoints(container *Container) []types.MountPoint { diff --git a/daemon/network/settings.go b/daemon/network/settings.go index ecfecc60c69d0..2fe23c7866127 100644 --- a/daemon/network/settings.go +++ b/daemon/network/settings.go @@ -26,18 +26,10 @@ type IPAMConfig struct { // TODO Windows. Many of these fields can be factored out., type Settings struct { Bridge string - EndpointID string // this is for backward compatibility SandboxID string - Gateway string // this is for backward compatibility - GlobalIPv6Address string // this is for backward compatibility - GlobalIPv6PrefixLen int // this is for backward compatibility HairpinMode bool - IPAddress string // this is for backward compatibility - IPPrefixLen int // this is for backward compatibility - IPv6Gateway string // this is for backward compatibility LinkLocalIPv6Address string LinkLocalIPv6PrefixLen int - MacAddress string // this is for backward compatibility Networks map[string]*EndpointSettings Ports nat.PortMap SandboxKey string diff --git a/integration-cli/docker_cli_daemon_test.go b/integration-cli/docker_cli_daemon_test.go index 1f5a2b9c8ca7c..d344ef68a4a26 100644 --- a/integration-cli/docker_cli_daemon_test.go +++ b/integration-cli/docker_cli_daemon_test.go @@ -303,7 +303,7 @@ func (s *DockerSuite) TestDaemonIPv6Enabled(c *check.C) { c.Fatalf("Could not run container: %s, %v", out, err) } - out, err := d.Cmd("inspect", "--format", "'{{.NetworkSettings.LinkLocalIPv6Address}}'", "ipv6test") + out, err := d.Cmd("inspect", "--format", "'{{.NetworkSettings.Networks.bridge.LinkLocalIPv6Address}}'", "ipv6test") out = strings.Trim(out, " \r\n'") if err != nil { @@ -314,7 +314,7 @@ func (s *DockerSuite) TestDaemonIPv6Enabled(c *check.C) { c.Fatalf("Container should have a link-local IPv6 address") } - out, err = d.Cmd("inspect", "--format", "'{{.NetworkSettings.GlobalIPv6Address}}'", "ipv6test") + out, err = d.Cmd("inspect", "--format", "'{{.NetworkSettings.Networks.bridge.GlobalIPv6Address}}'", "ipv6test") out = strings.Trim(out, " \r\n'") if err != nil { @@ -351,7 +351,7 @@ func (s *DockerSuite) TestDaemonIPv6FixedCIDR(c *check.C) { c.Fatalf("Could not run container: %s, %v", out, err) } - out, err := d.Cmd("inspect", "--format", "'{{.NetworkSettings.LinkLocalIPv6Address}}'", "ipv6test") + out, err := d.Cmd("inspect", "--format", "'{{.NetworkSettings.Networks.bridge.LinkLocalIPv6Address}}'", "ipv6test") out = strings.Trim(out, " \r\n'") if err != nil { @@ -362,7 +362,7 @@ func (s *DockerSuite) TestDaemonIPv6FixedCIDR(c *check.C) { c.Fatalf("Container should have a link-local IPv6 address") } - out, err = d.Cmd("inspect", "--format", "'{{.NetworkSettings.GlobalIPv6Address}}'", "ipv6test") + out, err = d.Cmd("inspect", "--format", "'{{.NetworkSettings.Networks.bridge.GlobalIPv6Address}}'", "ipv6test") out = strings.Trim(out, " \r\n'") if err != nil { diff --git a/integration-cli/docker_cli_links_test.go b/integration-cli/docker_cli_links_test.go index b49bf7d8826ca..4bf5562054de5 100644 --- a/integration-cli/docker_cli_links_test.go +++ b/integration-cli/docker_cli_links_test.go @@ -135,7 +135,7 @@ func (s *DockerSuite) TestLinksUpdateOnRestart(c *check.C) { out, _ := dockerCmd(c, "run", "-d", "--name", "two", "--link", "one:onetwo", "--link", "one:one", "busybox", "top") id := strings.TrimSpace(string(out)) - realIP, err := inspectField("one", "NetworkSettings.IPAddress") + realIP, err := inspectField("one", "NetworkSettings.Networks.bridge.IPAddress") if err != nil { c.Fatal(err) } @@ -156,7 +156,7 @@ func (s *DockerSuite) TestLinksUpdateOnRestart(c *check.C) { c.Assert(ip, checker.Equals, realIP) dockerCmd(c, "restart", "one") - realIP, err = inspectField("one", "NetworkSettings.IPAddress") + realIP, err = inspectField("one", "NetworkSettings.Networks.bridge.IPAddress") c.Assert(err, checker.IsNil) content, err = readContainerFileWithExec(id, "/etc/hosts") diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index 7b86eb20f0d6c..0d203afd99117 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -184,7 +184,7 @@ func (s *DockerSuite) TestRunLinksContainerWithContainerName(c *check.C) { testRequires(c, DaemonIsLinux) dockerCmd(c, "run", "-i", "-t", "-d", "--name", "parent", "busybox") - ip, err := inspectField("parent", "NetworkSettings.IPAddress") + ip, err := inspectField("parent", "NetworkSettings.Networks.bridge.IPAddress") c.Assert(err, check.IsNil) out, _ := dockerCmd(c, "run", "--link", "parent:test", "busybox", "/bin/cat", "/etc/hosts") @@ -201,7 +201,7 @@ func (s *DockerSuite) TestRunLinksContainerWithContainerId(c *check.C) { cID, _ := dockerCmd(c, "run", "-i", "-t", "-d", "busybox") cID = strings.TrimSpace(cID) - ip, err := inspectField(cID, "NetworkSettings.IPAddress") + ip, err := inspectField(cID, "NetworkSettings.Networks.bridge.IPAddress") c.Assert(err, check.IsNil) out, _ := dockerCmd(c, "run", "--link", cID+":test", "busybox", "/bin/cat", "/etc/hosts") @@ -1833,7 +1833,7 @@ func (s *DockerSuite) TestRunInspectMacAddress(c *check.C) { out, _ := dockerCmd(c, "run", "-d", "--mac-address="+mac, "busybox", "top") id := strings.TrimSpace(out) - inspectedMac, err := inspectField(id, "NetworkSettings.MacAddress") + inspectedMac, err := inspectField(id, "NetworkSettings.Networks.bridge.MacAddress") c.Assert(err, check.IsNil) if inspectedMac != mac { c.Fatalf("docker inspect outputs wrong MAC address: %q, should be: %q", inspectedMac, mac) @@ -1856,7 +1856,7 @@ func (s *DockerSuite) TestRunDeallocatePortOnMissingIptablesRule(c *check.C) { out, _ := dockerCmd(c, "run", "-d", "-p", "23:23", "busybox", "top") id := strings.TrimSpace(out) - ip, err := inspectField(id, "NetworkSettings.IPAddress") + ip, err := inspectField(id, "NetworkSettings.Networks.bridge.IPAddress") c.Assert(err, check.IsNil) iptCmd := exec.Command("iptables", "-D", "DOCKER", "-d", fmt.Sprintf("%s/32", ip), "!", "-i", "docker0", "-o", "docker0", "-p", "tcp", "-m", "tcp", "--dport", "23", "-j", "ACCEPT") @@ -3403,7 +3403,7 @@ func (s *DockerSuite) TestRunNetworkNotInitializedNoneMode(c *check.C) { testRequires(c, DaemonIsLinux) out, _ := dockerCmd(c, "run", "-d", "--net=none", "busybox", "top") id := strings.TrimSpace(out) - res, err := inspectField(id, "NetworkSettings.IPAddress") + res, err := inspectField(id, "NetworkSettings.Networks.none.IPAddress") c.Assert(err, check.IsNil) if res != "" { c.Fatalf("For 'none' mode network must not be initialized, but container got IP: %s", res) diff --git a/integration-cli/docker_utils.go b/integration-cli/docker_utils.go index 67627aff93bf1..98de35f6c6e90 100644 --- a/integration-cli/docker_utils.go +++ b/integration-cli/docker_utils.go @@ -788,7 +788,11 @@ func findContainerIP(c *check.C, id string, network string) string { } func (d *Daemon) findContainerIP(id string) string { - return findContainerIP(d.c, id, "--host") + out, err := d.Cmd("inspect", fmt.Sprintf("--format='{{ .NetworkSettings.Networks.bridge.IPAddress }}'"), id) + if err != nil { + d.c.Log(err) + } + return strings.Trim(out, " \r\n'") } func getContainerCount() (int, error) {