mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #17393 from tiborvass/carry-17360
Carry Fix docker inspect container only reports last assigned information
This commit is contained in:
commit
9ab71b68af
15 changed files with 199 additions and 106 deletions
|
@ -5,6 +5,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/daemon/network"
|
"github.com/docker/docker/daemon/network"
|
||||||
|
"github.com/docker/docker/pkg/nat"
|
||||||
"github.com/docker/docker/pkg/version"
|
"github.com/docker/docker/pkg/version"
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
"github.com/docker/docker/runconfig"
|
"github.com/docker/docker/runconfig"
|
||||||
|
@ -256,7 +257,6 @@ type ContainerJSONBase struct {
|
||||||
Args []string
|
Args []string
|
||||||
State *ContainerState
|
State *ContainerState
|
||||||
Image string
|
Image string
|
||||||
NetworkSettings *network.Settings
|
|
||||||
ResolvConfPath string
|
ResolvConfPath string
|
||||||
HostnamePath string
|
HostnamePath string
|
||||||
HostsPath string
|
HostsPath string
|
||||||
|
@ -278,8 +278,28 @@ type ContainerJSONBase struct {
|
||||||
// ContainerJSON is newly used struct along with MountPoint
|
// ContainerJSON is newly used struct along with MountPoint
|
||||||
type ContainerJSON struct {
|
type ContainerJSON struct {
|
||||||
*ContainerJSONBase
|
*ContainerJSONBase
|
||||||
Mounts []MountPoint
|
Mounts []MountPoint
|
||||||
Config *runconfig.Config
|
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.
|
// MountPoint represents a mount point configuration inside the container.
|
||||||
|
|
|
@ -3,6 +3,7 @@ package v1p19
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/api/types/versions/v1p20"
|
||||||
"github.com/docker/docker/pkg/nat"
|
"github.com/docker/docker/pkg/nat"
|
||||||
"github.com/docker/docker/runconfig"
|
"github.com/docker/docker/runconfig"
|
||||||
)
|
)
|
||||||
|
@ -11,9 +12,10 @@ import (
|
||||||
// Note this is not used by the Windows daemon.
|
// Note this is not used by the Windows daemon.
|
||||||
type ContainerJSON struct {
|
type ContainerJSON struct {
|
||||||
*types.ContainerJSONBase
|
*types.ContainerJSONBase
|
||||||
Volumes map[string]string
|
Volumes map[string]string
|
||||||
VolumesRW map[string]bool
|
VolumesRW map[string]bool
|
||||||
Config *ContainerConfig
|
Config *ContainerConfig
|
||||||
|
NetworkSettings *v1p20.NetworkSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainerConfig is a backcompatibility struct for APIs prior to 1.20.
|
// ContainerConfig is a backcompatibility struct for APIs prior to 1.20.
|
||||||
|
|
|
@ -10,8 +10,9 @@ import (
|
||||||
// ContainerJSON is a backcompatibility struct for the API 1.20
|
// ContainerJSON is a backcompatibility struct for the API 1.20
|
||||||
type ContainerJSON struct {
|
type ContainerJSON struct {
|
||||||
*types.ContainerJSONBase
|
*types.ContainerJSONBase
|
||||||
Mounts []types.MountPoint
|
Mounts []types.MountPoint
|
||||||
Config *ContainerConfig
|
Config *ContainerConfig
|
||||||
|
NetworkSettings *NetworkSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainerConfig is a backcompatibility struct used in ContainerJSON for the API 1.20
|
// ContainerConfig is a backcompatibility struct used in ContainerJSON for the API 1.20
|
||||||
|
@ -31,3 +32,16 @@ type StatsJSON struct {
|
||||||
types.Stats
|
types.Stats
|
||||||
Network types.NetworkStats `json:"network,omitempty"`
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -332,10 +332,6 @@ func (streamConfig *streamConfig) StderrPipe() io.ReadCloser {
|
||||||
return ioutils.NewBufReader(reader)
|
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
|
// 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.
|
// around how containers are linked together. It also unmounts the container's root filesystem.
|
||||||
func (container *Container) cleanup() {
|
func (container *Container) cleanup() {
|
||||||
|
|
|
@ -88,15 +88,25 @@ func (container *Container) setupLinkedContainers() ([]string, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bridgeSettings := container.NetworkSettings.Networks["bridge"]
|
||||||
|
if bridgeSettings == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
if len(children) > 0 {
|
if len(children) > 0 {
|
||||||
for linkAlias, child := range children {
|
for linkAlias, child := range children {
|
||||||
if !child.IsRunning() {
|
if !child.IsRunning() {
|
||||||
return nil, derr.ErrorCodeLinkNotRunning.WithArgs(child.Name, linkAlias)
|
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(
|
link := links.NewLink(
|
||||||
container.NetworkSettings.IPAddress,
|
bridgeSettings.IPAddress,
|
||||||
child.NetworkSettings.IPAddress,
|
childBridgeSettings.IPAddress,
|
||||||
linkAlias,
|
linkAlias,
|
||||||
child.Config.Env,
|
child.Config.Env,
|
||||||
child.Config.ExposedPorts,
|
child.Config.ExposedPorts,
|
||||||
|
@ -542,13 +552,14 @@ func (container *Container) buildSandboxOptions(n libnetwork.Network) ([]libnetw
|
||||||
if alias != child.Name[1:] {
|
if alias != child.Name[1:] {
|
||||||
aliasList = aliasList + " " + 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)
|
cEndpoint, _ := child.getEndpointInNetwork(n)
|
||||||
if cEndpoint != nil && cEndpoint.ID() != "" {
|
if cEndpoint != nil && cEndpoint.ID() != "" {
|
||||||
childEndpoints = append(childEndpoints, cEndpoint.ID())
|
childEndpoints = append(childEndpoints, cEndpoint.ID())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bridgeSettings := container.NetworkSettings.Networks["bridge"]
|
||||||
refs := container.daemon.containerGraph().RefPaths(container.ID)
|
refs := container.daemon.containerGraph().RefPaths(container.ID)
|
||||||
for _, ref := range refs {
|
for _, ref := range refs {
|
||||||
if ref.ParentID == "0" {
|
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() {
|
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)
|
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, container.NetworkSettings.IPAddress))
|
sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(c.ID, ref.Name, bridgeSettings.IPAddress))
|
||||||
if ep.ID() != "" {
|
if ep.ID() != "" {
|
||||||
parentEndpoints = append(parentEndpoints, ep.ID())
|
parentEndpoints = append(parentEndpoints, ep.ID())
|
||||||
}
|
}
|
||||||
|
@ -583,12 +594,8 @@ func (container *Container) buildSandboxOptions(n libnetwork.Network) ([]libnetw
|
||||||
|
|
||||||
func isLinkable(child *Container) bool {
|
func isLinkable(child *Container) bool {
|
||||||
// A container is linkable only if it belongs to the default network
|
// A container is linkable only if it belongs to the default network
|
||||||
for _, nw := range child.NetworkSettings.Networks {
|
_, ok := child.NetworkSettings.Networks["bridge"]
|
||||||
if nw == "bridge" {
|
return ok
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) getEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) {
|
func (container *Container) getEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) {
|
||||||
|
@ -615,10 +622,6 @@ func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint, networkSett
|
||||||
return networkSettings, nil
|
return networkSettings, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if mac, ok := driverInfo[netlabel.MacAddress]; ok {
|
|
||||||
networkSettings.MacAddress = mac.(net.HardwareAddr).String()
|
|
||||||
}
|
|
||||||
|
|
||||||
networkSettings.Ports = nat.PortMap{}
|
networkSettings.Ports = nat.PortMap{}
|
||||||
|
|
||||||
if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
|
if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
|
||||||
|
@ -652,7 +655,7 @@ func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint, networkSett
|
||||||
return networkSettings, nil
|
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 {
|
if ep == nil {
|
||||||
return nil, derr.ErrorCodeEmptyEndpoint
|
return nil, derr.ErrorCodeEmptyEndpoint
|
||||||
}
|
}
|
||||||
|
@ -667,6 +670,11 @@ func (container *Container) buildEndpointInfo(ep libnetwork.Endpoint, networkSet
|
||||||
return networkSettings, nil
|
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()
|
iface := epInfo.Iface()
|
||||||
if iface == nil {
|
if iface == nil {
|
||||||
return networkSettings, nil
|
return networkSettings, nil
|
||||||
|
@ -674,29 +682,41 @@ func (container *Container) buildEndpointInfo(ep libnetwork.Endpoint, networkSet
|
||||||
|
|
||||||
if iface.Address() != nil {
|
if iface.Address() != nil {
|
||||||
ones, _ := iface.Address().Mask.Size()
|
ones, _ := iface.Address().Mask.Size()
|
||||||
networkSettings.IPAddress = iface.Address().IP.String()
|
networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String()
|
||||||
networkSettings.IPPrefixLen = ones
|
networkSettings.Networks[n.Name()].IPPrefixLen = ones
|
||||||
}
|
}
|
||||||
|
|
||||||
if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil {
|
if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil {
|
||||||
onesv6, _ := iface.AddressIPv6().Mask.Size()
|
onesv6, _ := iface.AddressIPv6().Mask.Size()
|
||||||
networkSettings.GlobalIPv6Address = iface.AddressIPv6().IP.String()
|
networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String()
|
||||||
networkSettings.GlobalIPv6PrefixLen = onesv6
|
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 {
|
||||||
|
networkSettings.Networks[n.Name()].MacAddress = mac.(net.HardwareAddr).String()
|
||||||
}
|
}
|
||||||
|
|
||||||
return networkSettings, nil
|
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()
|
epInfo := ep.Info()
|
||||||
if epInfo == nil {
|
if epInfo == nil {
|
||||||
// It is not an error to get an empty endpoint info
|
// It is not an error to get an empty endpoint info
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
container.NetworkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String()
|
||||||
container.NetworkSettings.Gateway = epInfo.Gateway().String()
|
|
||||||
if epInfo.GatewayIPv6().To16() != nil {
|
if epInfo.GatewayIPv6().To16() != nil {
|
||||||
container.NetworkSettings.IPv6Gateway = epInfo.GatewayIPv6().String()
|
container.NetworkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -704,11 +724,10 @@ func (container *Container) updateJoinInfo(ep libnetwork.Endpoint) error {
|
||||||
|
|
||||||
func (container *Container) updateNetworkSettings(n libnetwork.Network) error {
|
func (container *Container) updateNetworkSettings(n libnetwork.Network) error {
|
||||||
if container.NetworkSettings == nil {
|
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)
|
sn, err := container.daemon.FindNetwork(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
|
@ -727,7 +746,7 @@ func (container *Container) updateNetworkSettings(n libnetwork.Network) error {
|
||||||
return runconfig.ErrConflictNoNetwork
|
return runconfig.ErrConflictNoNetwork
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
settings.Networks = append(settings.Networks, n.Name())
|
container.NetworkSettings.Networks[n.Name()] = new(network.EndpointSettings)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -738,7 +757,7 @@ func (container *Container) updateEndpointNetworkSettings(n libnetwork.Network,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
networkSettings, err = container.buildEndpointInfo(ep, networkSettings)
|
networkSettings, err = container.buildEndpointInfo(n, ep, networkSettings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -769,7 +788,7 @@ func (container *Container) updateNetwork() error {
|
||||||
|
|
||||||
// Find if container is connected to the default bridge network
|
// Find if container is connected to the default bridge network
|
||||||
var n libnetwork.Network
|
var n libnetwork.Network
|
||||||
for _, name := range container.NetworkSettings.Networks {
|
for name := range container.NetworkSettings.Networks {
|
||||||
sn, err := container.daemon.FindNetwork(name)
|
sn, err := container.daemon.FindNetwork(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
|
@ -899,9 +918,8 @@ func createNetwork(controller libnetwork.NetworkController, dnet string, driver
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) allocateNetwork() error {
|
func (container *Container) allocateNetwork() error {
|
||||||
settings := container.NetworkSettings.Networks
|
|
||||||
updateSettings := false
|
updateSettings := false
|
||||||
if settings == nil {
|
if len(container.NetworkSettings.Networks) == 0 {
|
||||||
mode := container.hostConfig.NetworkMode
|
mode := container.hostConfig.NetworkMode
|
||||||
controller := container.daemon.netController
|
controller := container.daemon.netController
|
||||||
if container.Config.NetworkDisabled || mode.IsContainer() {
|
if container.Config.NetworkDisabled || mode.IsContainer() {
|
||||||
|
@ -912,11 +930,12 @@ func (container *Container) allocateNetwork() error {
|
||||||
if mode.IsDefault() {
|
if mode.IsDefault() {
|
||||||
networkName = controller.Config().Daemon.DefaultNetwork
|
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
|
updateSettings = true
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, n := range settings {
|
for n := range container.NetworkSettings.Networks {
|
||||||
if err := container.connectToNetwork(n, updateSettings); err != nil {
|
if err := container.connectToNetwork(n, updateSettings); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1015,7 +1034,7 @@ func (container *Container) connectToNetwork(idOrName string, updateSettings boo
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := container.updateJoinInfo(ep); err != nil {
|
if err := container.updateJoinInfo(n, ep); err != nil {
|
||||||
return derr.ErrorCodeJoinInfo.WithArgs(err)
|
return derr.ErrorCodeJoinInfo.WithArgs(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1142,6 +1161,9 @@ func (container *Container) releaseNetwork() {
|
||||||
|
|
||||||
sid := container.NetworkSettings.SandboxID
|
sid := container.NetworkSettings.SandboxID
|
||||||
networks := container.NetworkSettings.Networks
|
networks := container.NetworkSettings.Networks
|
||||||
|
for n := range networks {
|
||||||
|
networks[n] = &network.EndpointSettings{}
|
||||||
|
}
|
||||||
|
|
||||||
container.NetworkSettings = &network.Settings{Networks: networks}
|
container.NetworkSettings = &network.Settings{Networks: networks}
|
||||||
|
|
||||||
|
@ -1199,19 +1221,7 @@ 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)
|
return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
networks := container.NetworkSettings.Networks
|
delete(container.NetworkSettings.Networks, n.Name())
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/versions/v1p20"
|
"github.com/docker/docker/api/types/versions/v1p20"
|
||||||
|
"github.com/docker/docker/daemon/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerInspect returns low-level information about a
|
// ContainerInspect returns low-level information about a
|
||||||
|
@ -26,8 +27,22 @@ func (daemon *Daemon) ContainerInspect(name string, size bool) (*types.Container
|
||||||
}
|
}
|
||||||
|
|
||||||
mountPoints := addMountPoints(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.
|
// 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.Config.ExposedPorts,
|
||||||
container.hostConfig.VolumeDriver,
|
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) {
|
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{
|
contJSONBase := &types.ContainerJSONBase{
|
||||||
ID: container.ID,
|
ID: container.ID,
|
||||||
Created: container.Created.Format(time.RFC3339Nano),
|
Created: container.Created.Format(time.RFC3339Nano),
|
||||||
Path: container.Path,
|
Path: container.Path,
|
||||||
Args: container.Args,
|
Args: container.Args,
|
||||||
State: containerState,
|
State: containerState,
|
||||||
Image: container.ImageID,
|
Image: container.ImageID,
|
||||||
NetworkSettings: container.NetworkSettings,
|
LogPath: container.LogPath,
|
||||||
LogPath: container.LogPath,
|
Name: container.Name,
|
||||||
Name: container.Name,
|
RestartCount: container.RestartCount,
|
||||||
RestartCount: container.RestartCount,
|
Driver: container.Driver,
|
||||||
Driver: container.Driver,
|
ExecDriver: container.ExecDriver,
|
||||||
ExecDriver: container.ExecDriver,
|
MountLabel: container.MountLabel,
|
||||||
MountLabel: container.MountLabel,
|
ProcessLabel: container.ProcessLabel,
|
||||||
ProcessLabel: container.ProcessLabel,
|
ExecIDs: container.getExecIDs(),
|
||||||
ExecIDs: container.getExecIDs(),
|
HostConfig: &hostConfig,
|
||||||
HostConfig: &hostConfig,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -151,3 +166,30 @@ func (daemon *Daemon) VolumeInspect(name string) (*types.Volume, error) {
|
||||||
}
|
}
|
||||||
return volumeToAPIType(v), nil
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -50,8 +50,9 @@ func (daemon *Daemon) ContainerInspectPre120(name string) (*v1p19.ContainerJSON,
|
||||||
container.hostConfig.CPUShares,
|
container.hostConfig.CPUShares,
|
||||||
container.hostConfig.CpusetCpus,
|
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 {
|
func addMountPoints(container *Container) []types.MountPoint {
|
||||||
|
|
|
@ -26,22 +26,26 @@ type IPAMConfig struct {
|
||||||
// TODO Windows. Many of these fields can be factored out.,
|
// TODO Windows. Many of these fields can be factored out.,
|
||||||
type Settings struct {
|
type Settings struct {
|
||||||
Bridge string
|
Bridge string
|
||||||
EndpointID string
|
|
||||||
SandboxID string
|
SandboxID string
|
||||||
Gateway string
|
|
||||||
GlobalIPv6Address string
|
|
||||||
GlobalIPv6PrefixLen int
|
|
||||||
HairpinMode bool
|
HairpinMode bool
|
||||||
IPAddress string
|
|
||||||
IPPrefixLen int
|
|
||||||
IPv6Gateway string
|
|
||||||
LinkLocalIPv6Address string
|
LinkLocalIPv6Address string
|
||||||
LinkLocalIPv6PrefixLen int
|
LinkLocalIPv6PrefixLen int
|
||||||
MacAddress string
|
Networks map[string]*EndpointSettings
|
||||||
Networks []string
|
|
||||||
Ports nat.PortMap
|
Ports nat.PortMap
|
||||||
SandboxKey string
|
SandboxKey string
|
||||||
SecondaryIPAddresses []Address
|
SecondaryIPAddresses []Address
|
||||||
SecondaryIPv6Addresses []Address
|
SecondaryIPv6Addresses []Address
|
||||||
IsAnonymousEndpoint bool
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ func (s *DockerSuite) TestApiNetworkInspect(c *check.C) {
|
||||||
// run a container and attach it to the default bridge network
|
// run a container and attach it to the default bridge network
|
||||||
out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
|
out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
|
||||||
containerID := strings.TrimSpace(out)
|
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
|
// inspect default bridge network again and make sure the container is connected
|
||||||
nr = getNetworkResource(c, nr.ID)
|
nr = getNetworkResource(c, nr.ID)
|
||||||
|
@ -122,7 +122,7 @@ func (s *DockerSuite) TestApiNetworkConnectDisconnect(c *check.C) {
|
||||||
// check if container IP matches network inspect
|
// check if container IP matches network inspect
|
||||||
ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
|
ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
containerIP := findContainerIP(c, "test")
|
containerIP := findContainerIP(c, "test", "testnetwork")
|
||||||
c.Assert(ip.String(), checker.Equals, containerIP)
|
c.Assert(ip.String(), checker.Equals, containerIP)
|
||||||
|
|
||||||
// disconnect container from the network
|
// disconnect container from the network
|
||||||
|
|
|
@ -85,7 +85,7 @@ func (s *DockerSuite) TestApiStatsNetworkStats(c *check.C) {
|
||||||
c.Assert(waitRun(id), checker.IsNil)
|
c.Assert(waitRun(id), checker.IsNil)
|
||||||
|
|
||||||
// Retrieve the container address
|
// Retrieve the container address
|
||||||
contIP := findContainerIP(c, id)
|
contIP := findContainerIP(c, id, "bridge")
|
||||||
numPings := 10
|
numPings := 10
|
||||||
|
|
||||||
var preRxPackets uint64
|
var preRxPackets uint64
|
||||||
|
|
|
@ -303,7 +303,7 @@ func (s *DockerSuite) TestDaemonIPv6Enabled(c *check.C) {
|
||||||
c.Fatalf("Could not run container: %s, %v", out, err)
|
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'")
|
out = strings.Trim(out, " \r\n'")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -314,7 +314,7 @@ func (s *DockerSuite) TestDaemonIPv6Enabled(c *check.C) {
|
||||||
c.Fatalf("Container should have a link-local IPv6 address")
|
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'")
|
out = strings.Trim(out, " \r\n'")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -351,7 +351,7 @@ func (s *DockerSuite) TestDaemonIPv6FixedCIDR(c *check.C) {
|
||||||
c.Fatalf("Could not run container: %s, %v", out, err)
|
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'")
|
out = strings.Trim(out, " \r\n'")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -362,7 +362,7 @@ func (s *DockerSuite) TestDaemonIPv6FixedCIDR(c *check.C) {
|
||||||
c.Fatalf("Container should have a link-local IPv6 address")
|
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'")
|
out = strings.Trim(out, " \r\n'")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -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")
|
out, _ := dockerCmd(c, "run", "-d", "--name", "two", "--link", "one:onetwo", "--link", "one:one", "busybox", "top")
|
||||||
id := strings.TrimSpace(string(out))
|
id := strings.TrimSpace(string(out))
|
||||||
|
|
||||||
realIP, err := inspectField("one", "NetworkSettings.IPAddress")
|
realIP, err := inspectField("one", "NetworkSettings.Networks.bridge.IPAddress")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Fatal(err)
|
c.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,7 @@ func (s *DockerSuite) TestLinksUpdateOnRestart(c *check.C) {
|
||||||
c.Assert(ip, checker.Equals, realIP)
|
c.Assert(ip, checker.Equals, realIP)
|
||||||
|
|
||||||
dockerCmd(c, "restart", "one")
|
dockerCmd(c, "restart", "one")
|
||||||
realIP, err = inspectField("one", "NetworkSettings.IPAddress")
|
realIP, err = inspectField("one", "NetworkSettings.Networks.bridge.IPAddress")
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
content, err = readContainerFileWithExec(id, "/etc/hosts")
|
content, err = readContainerFileWithExec(id, "/etc/hosts")
|
||||||
|
|
|
@ -284,7 +284,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnect(c *check.C) {
|
||||||
// check if container IP matches network inspect
|
// check if container IP matches network inspect
|
||||||
ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
|
ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
containerIP := findContainerIP(c, "test")
|
containerIP := findContainerIP(c, "test", "test")
|
||||||
c.Assert(ip.String(), checker.Equals, containerIP)
|
c.Assert(ip.String(), checker.Equals, containerIP)
|
||||||
|
|
||||||
// disconnect container from the network
|
// disconnect container from the network
|
||||||
|
|
|
@ -184,7 +184,7 @@ func (s *DockerSuite) TestRunLinksContainerWithContainerName(c *check.C) {
|
||||||
testRequires(c, DaemonIsLinux)
|
testRequires(c, DaemonIsLinux)
|
||||||
dockerCmd(c, "run", "-i", "-t", "-d", "--name", "parent", "busybox")
|
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)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
out, _ := dockerCmd(c, "run", "--link", "parent:test", "busybox", "/bin/cat", "/etc/hosts")
|
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, _ := dockerCmd(c, "run", "-i", "-t", "-d", "busybox")
|
||||||
|
|
||||||
cID = strings.TrimSpace(cID)
|
cID = strings.TrimSpace(cID)
|
||||||
ip, err := inspectField(cID, "NetworkSettings.IPAddress")
|
ip, err := inspectField(cID, "NetworkSettings.Networks.bridge.IPAddress")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
out, _ := dockerCmd(c, "run", "--link", cID+":test", "busybox", "/bin/cat", "/etc/hosts")
|
out, _ := dockerCmd(c, "run", "--link", cID+":test", "busybox", "/bin/cat", "/etc/hosts")
|
||||||
|
@ -1945,7 +1945,7 @@ func (s *DockerSuite) TestRunInspectMacAddress(c *check.C) {
|
||||||
out, _ := dockerCmd(c, "run", "-d", "--mac-address="+mac, "busybox", "top")
|
out, _ := dockerCmd(c, "run", "-d", "--mac-address="+mac, "busybox", "top")
|
||||||
|
|
||||||
id := strings.TrimSpace(out)
|
id := strings.TrimSpace(out)
|
||||||
inspectedMac, err := inspectField(id, "NetworkSettings.MacAddress")
|
inspectedMac, err := inspectField(id, "NetworkSettings.Networks.bridge.MacAddress")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
if inspectedMac != mac {
|
if inspectedMac != mac {
|
||||||
c.Fatalf("docker inspect outputs wrong MAC address: %q, should be: %q", inspectedMac, mac)
|
c.Fatalf("docker inspect outputs wrong MAC address: %q, should be: %q", inspectedMac, mac)
|
||||||
|
@ -1968,7 +1968,7 @@ func (s *DockerSuite) TestRunDeallocatePortOnMissingIptablesRule(c *check.C) {
|
||||||
out, _ := dockerCmd(c, "run", "-d", "-p", "23:23", "busybox", "top")
|
out, _ := dockerCmd(c, "run", "-d", "-p", "23:23", "busybox", "top")
|
||||||
|
|
||||||
id := strings.TrimSpace(out)
|
id := strings.TrimSpace(out)
|
||||||
ip, err := inspectField(id, "NetworkSettings.IPAddress")
|
ip, err := inspectField(id, "NetworkSettings.Networks.bridge.IPAddress")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
iptCmd := exec.Command("iptables", "-D", "DOCKER", "-d", fmt.Sprintf("%s/32", ip),
|
iptCmd := exec.Command("iptables", "-D", "DOCKER", "-d", fmt.Sprintf("%s/32", ip),
|
||||||
"!", "-i", "docker0", "-o", "docker0", "-p", "tcp", "-m", "tcp", "--dport", "23", "-j", "ACCEPT")
|
"!", "-i", "docker0", "-o", "docker0", "-p", "tcp", "-m", "tcp", "--dport", "23", "-j", "ACCEPT")
|
||||||
|
@ -3548,7 +3548,7 @@ func (s *DockerSuite) TestRunNetworkNotInitializedNoneMode(c *check.C) {
|
||||||
testRequires(c, DaemonIsLinux)
|
testRequires(c, DaemonIsLinux)
|
||||||
out, _ := dockerCmd(c, "run", "-d", "--net=none", "busybox", "top")
|
out, _ := dockerCmd(c, "run", "-d", "--net=none", "busybox", "top")
|
||||||
id := strings.TrimSpace(out)
|
id := strings.TrimSpace(out)
|
||||||
res, err := inspectField(id, "NetworkSettings.IPAddress")
|
res, err := inspectField(id, "NetworkSettings.Networks.none.IPAddress")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
if res != "" {
|
if res != "" {
|
||||||
c.Fatalf("For 'none' mode network must not be initialized, but container got IP: %s", res)
|
c.Fatalf("For 'none' mode network must not be initialized, but container got IP: %s", res)
|
||||||
|
|
|
@ -805,13 +805,17 @@ func dockerCmdInDirWithTimeout(timeout time.Duration, path string, args ...strin
|
||||||
return integration.DockerCmdInDirWithTimeout(dockerBinary, timeout, path, args...)
|
return integration.DockerCmdInDirWithTimeout(dockerBinary, timeout, path, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func findContainerIP(c *check.C, id string, vargs ...string) string {
|
func findContainerIP(c *check.C, id string, network string) string {
|
||||||
out, _ := dockerCmd(c, "inspect", "--format='{{ .NetworkSettings.IPAddress }}'", id)
|
out, _ := dockerCmd(c, "inspect", fmt.Sprintf("--format='{{ .NetworkSettings.Networks.%s.IPAddress }}'", network), id)
|
||||||
return strings.Trim(out, " \r\n'")
|
return strings.Trim(out, " \r\n'")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Daemon) findContainerIP(id string) string {
|
func (d *Daemon) findContainerIP(id string) string {
|
||||||
return findContainerIP(d.c, id, "--host", d.sock())
|
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) {
|
func getContainerCount() (int, error) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue