603e00a3 |
package daemon
import ( |
55691e5f |
"fmt" |
c9207bc0 |
"time" |
603e00a3 |
|
91e197d6 |
"github.com/docker/docker/api/types" |
1af76ef5 |
"github.com/docker/docker/api/types/backend" |
91e197d6 |
networktypes "github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/api/types/versions/v1p20" |
6bb0d181 |
"github.com/docker/docker/container" |
25682577 |
"github.com/docker/docker/daemon/network" |
ebcb7d6b |
volumestore "github.com/docker/docker/volume/store" |
7917a36c |
"github.com/docker/go-connections/nat" |
603e00a3 |
)
|
abd72d40 |
// ContainerInspect returns low-level information about a
// container. Returns an error if the container cannot be found, or if
// there is an error getting the data. |
7534f172 |
func (daemon *Daemon) ContainerInspect(name string, size bool, version string) (interface{}, error) { |
38abba9e |
switch { |
7534f172 |
case versions.LessThan(version, "1.20"): |
38abba9e |
return daemon.containerInspectPre120(name) |
7534f172 |
case versions.Equal(version, "1.20"): |
38abba9e |
return daemon.containerInspect120(name)
} |
534a90a9 |
return daemon.ContainerInspectCurrent(name, size) |
38abba9e |
}
|
534a90a9 |
// ContainerInspectCurrent returns low-level information about a
// container in a most recent api version.
func (daemon *Daemon) ContainerInspectCurrent(name string, size bool) (*types.ContainerJSON, error) { |
d7d512bb |
container, err := daemon.GetContainer(name) |
4b9fe9c2 |
if err != nil {
return nil, err |
d25a6537 |
} |
68fb7f4b |
|
4b9fe9c2 |
container.Lock() |
55691e5f |
|
bd33a99a |
base, err := daemon.getInspectData(container) |
6deaa58b |
if err != nil { |
bd33a99a |
container.Unlock() |
6deaa58b |
return nil, err
}
|
99a98ccc |
apiNetworks := make(map[string]*networktypes.EndpointSettings)
for name, epConf := range container.NetworkSettings.Networks {
if epConf.EndpointSettings != nil { |
7917a36c |
// We must make a copy of this pointer object otherwise it can race with other operations
apiNetworks[name] = epConf.EndpointSettings.Copy() |
99a98ccc |
}
}
|
cfc404a3 |
mountPoints := container.GetMountPoints() |
25682577 |
networkSettings := &types.NetworkSettings{ |
f301c576 |
NetworkSettingsBase: types.NetworkSettingsBase{ |
25682577 |
Bridge: container.NetworkSettings.Bridge,
SandboxID: container.NetworkSettings.SandboxID,
HairpinMode: container.NetworkSettings.HairpinMode,
LinkLocalIPv6Address: container.NetworkSettings.LinkLocalIPv6Address,
LinkLocalIPv6PrefixLen: container.NetworkSettings.LinkLocalIPv6PrefixLen,
SandboxKey: container.NetworkSettings.SandboxKey,
SecondaryIPAddresses: container.NetworkSettings.SecondaryIPAddresses,
SecondaryIPv6Addresses: container.NetworkSettings.SecondaryIPv6Addresses,
}, |
f301c576 |
DefaultNetworkSettings: daemon.getDefaultNetworkSettings(container.NetworkSettings.Networks), |
99a98ccc |
Networks: apiNetworks, |
25682577 |
} |
1c3cb2d3 |
|
7917a36c |
ports := make(nat.PortMap, len(container.NetworkSettings.Ports))
for k, pm := range container.NetworkSettings.Ports {
ports[k] = pm
}
networkSettings.NetworkSettingsBase.Ports = ports
|
bd33a99a |
container.Unlock()
if size {
sizeRw, sizeRootFs := daemon.getSize(base.ID)
base.SizeRw = &sizeRw
base.SizeRootFs = &sizeRootFs
}
|
7aa28b6b |
return &types.ContainerJSON{
ContainerJSONBase: base,
Mounts: mountPoints,
Config: container.Config,
NetworkSettings: networkSettings,
}, nil |
6deaa58b |
}
|
38abba9e |
// containerInspect120 serializes the master version of a container into a json type.
func (daemon *Daemon) containerInspect120(name string) (*v1p20.ContainerJSON, error) { |
d7d512bb |
container, err := daemon.GetContainer(name) |
6549d651 |
if err != nil {
return nil, err
}
container.Lock()
defer container.Unlock()
|
bd33a99a |
base, err := daemon.getInspectData(container) |
6549d651 |
if err != nil {
return nil, err
}
|
cfc404a3 |
mountPoints := container.GetMountPoints() |
61634758 |
config := &v1p20.ContainerConfig{ |
7aa28b6b |
Config: container.Config,
MacAddress: container.Config.MacAddress,
NetworkDisabled: container.Config.NetworkDisabled,
ExposedPorts: container.Config.ExposedPorts, |
6bb0d181 |
VolumeDriver: container.HostConfig.VolumeDriver, |
6549d651 |
} |
f301c576 |
networkSettings := daemon.getBackwardsCompatibleNetworkSettings(container.NetworkSettings) |
6549d651 |
|
7aa28b6b |
return &v1p20.ContainerJSON{
ContainerJSONBase: base,
Mounts: mountPoints,
Config: config,
NetworkSettings: networkSettings,
}, nil |
6549d651 |
}
|
bd33a99a |
func (daemon *Daemon) getInspectData(container *container.Container) (*types.ContainerJSONBase, error) { |
4b9fe9c2 |
// make a copy to play with |
6bb0d181 |
hostConfig := *container.HostConfig |
4b43a6df |
|
0f9f9950 |
children := daemon.children(container)
hostConfig.Links = nil // do not expose the internal structure
for linkAlias, child := range children {
hostConfig.Links = append(hostConfig.Links, fmt.Sprintf("%s:%s", child.Name, linkAlias)) |
d25a6537 |
} |
0f9f9950 |
|
7d705a73 |
// We merge the Ulimits from hostConfig with daemon default
daemon.mergeUlimits(&hostConfig)
|
b6c7becb |
var containerHealth *types.Health
if container.State.Health != nil {
containerHealth = &types.Health{
Status: container.State.Health.Status,
FailingStreak: container.State.Health.FailingStreak,
Log: append([]*types.HealthcheckResult{}, container.State.Health.Log...),
}
}
|
4b9fe9c2 |
containerState := &types.ContainerState{ |
fed85c32 |
Status: container.State.StateString(), |
4b9fe9c2 |
Running: container.State.Running,
Paused: container.State.Paused,
Restarting: container.State.Restarting,
OOMKilled: container.State.OOMKilled,
Dead: container.State.Dead,
Pid: container.State.Pid, |
dcfe9927 |
ExitCode: container.State.ExitCode(), |
49211715 |
Error: container.State.ErrorMsg, |
c9207bc0 |
StartedAt: container.State.StartedAt.Format(time.RFC3339Nano),
FinishedAt: container.State.FinishedAt.Format(time.RFC3339Nano), |
b6c7becb |
Health: containerHealth, |
4b9fe9c2 |
} |
55691e5f |
|
6deaa58b |
contJSONBase := &types.ContainerJSONBase{ |
25682577 |
ID: container.ID,
Created: container.Created.Format(time.RFC3339Nano),
Path: container.Path,
Args: container.Args,
State: containerState, |
4352da78 |
Image: container.ImageID.String(), |
25682577 |
LogPath: container.LogPath,
Name: container.Name,
RestartCount: container.RestartCount,
Driver: container.Driver, |
0380fbff |
OS: container.OS, |
25682577 |
MountLabel: container.MountLabel,
ProcessLabel: container.ProcessLabel, |
6bb0d181 |
ExecIDs: container.GetExecIDs(), |
25682577 |
HostConfig: &hostConfig, |
603e00a3 |
} |
4b9fe9c2 |
|
47c56e43 |
// Now set any platform-specific fields
contJSONBase = setPlatformSpecificContainerFields(container, contJSONBase)
|
407a626b |
contJSONBase.GraphDriver.Name = container.Driver |
4352da78 |
|
d04fa49a |
graphDriverData, err := container.RWLayer.Metadata() |
c35186b0 |
// If container is marked as Dead, the container's graphdriver metadata
// could have been removed, it will cause error if we try to get the metadata,
// we can ignore the error if the container is dead.
if err != nil && !container.Dead { |
ebcb7d6b |
return nil, systemError{err} |
407a626b |
}
contJSONBase.GraphDriver.Data = graphDriverData
|
6deaa58b |
return contJSONBase, nil |
603e00a3 |
} |
90928eb1 |
|
abd72d40 |
// ContainerExecInspect returns low-level information about the exec
// command. An error is returned if the exec cannot be found. |
1af76ef5 |
func (daemon *Daemon) ContainerExecInspect(id string) (*backend.ExecInspect, error) { |
0e87588b |
e := daemon.execCommands.Get(id)
if e == nil {
return nil, errExecNotFound(id)
}
if container := daemon.containers.Get(e.ContainerID); container == nil {
return nil, errExecNotFound(id) |
90928eb1 |
} |
1af76ef5 |
pc := inspectExecProcessConfig(e)
return &backend.ExecInspect{
ID: e.ID,
Running: e.Running,
ExitCode: e.ExitCode,
ProcessConfig: pc,
OpenStdin: e.OpenStdin,
OpenStdout: e.OpenStdout,
OpenStderr: e.OpenStderr,
CanRemove: e.CanRemove,
ContainerID: e.ContainerID,
DetachKeys: e.DetachKeys, |
18083481 |
Pid: e.Pid, |
1af76ef5 |
}, nil |
90928eb1 |
} |
b3b7eb27 |
|
abd72d40 |
// VolumeInspect looks up a volume by name. An error is returned if
// the volume cannot be found. |
b08f071e |
func (daemon *Daemon) VolumeInspect(name string) (*types.Volume, error) { |
b3b7eb27 |
v, err := daemon.volumes.Get(name)
if err != nil { |
ebcb7d6b |
if volumestore.IsNotExist(err) {
return nil, volumeNotFound(name)
}
return nil, systemError{err} |
b3b7eb27 |
} |
9e6b1852 |
apiV := volumeToAPIType(v)
apiV.Mountpoint = v.Path() |
36a1c56c |
apiV.Status = v.Status() |
9e6b1852 |
return apiV, nil |
b3b7eb27 |
} |
25682577 |
|
f301c576 |
func (daemon *Daemon) getBackwardsCompatibleNetworkSettings(settings *network.Settings) *v1p20.NetworkSettings { |
25682577 |
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,
}, |
f301c576 |
DefaultNetworkSettings: daemon.getDefaultNetworkSettings(settings.Networks), |
25682577 |
} |
f301c576 |
|
25682577 |
return result
} |
f301c576 |
// getDefaultNetworkSettings creates the deprecated structure that holds the information
// about the bridge network for a container. |
99a98ccc |
func (daemon *Daemon) getDefaultNetworkSettings(networks map[string]*network.EndpointSettings) types.DefaultNetworkSettings { |
f301c576 |
var settings types.DefaultNetworkSettings
|
99a98ccc |
if defaultNetwork, ok := networks["bridge"]; ok && defaultNetwork.EndpointSettings != nil { |
f301c576 |
settings.EndpointID = defaultNetwork.EndpointID
settings.Gateway = defaultNetwork.Gateway
settings.GlobalIPv6Address = defaultNetwork.GlobalIPv6Address
settings.GlobalIPv6PrefixLen = defaultNetwork.GlobalIPv6PrefixLen
settings.IPAddress = defaultNetwork.IPAddress
settings.IPPrefixLen = defaultNetwork.IPPrefixLen
settings.IPv6Gateway = defaultNetwork.IPv6Gateway
settings.MacAddress = defaultNetwork.MacAddress
}
return settings
} |