daemon/inspect.go
603e00a3
 package daemon
 
 import (
55691e5f
 	"fmt"
c9207bc0
 	"time"
603e00a3
 
1af76ef5
 	"github.com/docker/docker/api/types/backend"
6bb0d181
 	"github.com/docker/docker/container"
25682577
 	"github.com/docker/docker/daemon/network"
38abba9e
 	"github.com/docker/docker/pkg/version"
907407d0
 	"github.com/docker/engine-api/types"
 	networktypes "github.com/docker/engine-api/types/network"
 	"github.com/docker/engine-api/types/versions/v1p20"
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.
38abba9e
 func (daemon *Daemon) ContainerInspect(name string, size bool, version version.Version) (interface{}, error) {
 	switch {
 	case version.LessThan("1.20"):
 		return daemon.containerInspectPre120(name)
 	case version.Equal("1.20"):
 		return daemon.containerInspect120(name)
 	}
 	return daemon.containerInspectCurrent(name, size)
 }
 
 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()
 	defer container.Unlock()
55691e5f
 
b4d6b238
 	base, err := daemon.getInspectData(container, size)
6deaa58b
 	if err != nil {
 		return nil, err
 	}
 
47c56e43
 	mountPoints := addMountPoints(container)
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,
 			Ports:                  container.NetworkSettings.Ports,
 			SandboxKey:             container.NetworkSettings.SandboxKey,
 			SecondaryIPAddresses:   container.NetworkSettings.SecondaryIPAddresses,
 			SecondaryIPv6Addresses: container.NetworkSettings.SecondaryIPv6Addresses,
 		},
f301c576
 		DefaultNetworkSettings: daemon.getDefaultNetworkSettings(container.NetworkSettings.Networks),
 		Networks:               container.NetworkSettings.Networks,
25682577
 	}
1c3cb2d3
 
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()
 
b4d6b238
 	base, err := daemon.getInspectData(container, false)
6549d651
 	if err != nil {
 		return nil, err
 	}
 
 	mountPoints := addMountPoints(container)
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
 }
 
6bb0d181
 func (daemon *Daemon) getInspectData(container *container.Container, size bool) (*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
 
47a6afb9
 	// we need this trick to preserve empty log driver, so
f1d34ac2
 	// container will use daemon defaults even if daemon changes them
4b9fe9c2
 	if hostConfig.LogConfig.Type == "" {
2f2779b6
 		hostConfig.LogConfig.Type = daemon.defaultLogConfig.Type
 	}
 
3f61002b
 	if len(hostConfig.LogConfig.Config) == 0 {
2f2779b6
 		hostConfig.LogConfig.Config = daemon.defaultLogConfig.Config
47a6afb9
 	}
55691e5f
 
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,
 		ExitCode:   container.State.ExitCode,
 		Error:      container.State.Error,
c9207bc0
 		StartedAt:  container.State.StartedAt.Format(time.RFC3339Nano),
 		FinishedAt: container.State.FinishedAt.Format(time.RFC3339Nano),
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,
 		MountLabel:   container.MountLabel,
 		ProcessLabel: container.ProcessLabel,
6bb0d181
 		ExecIDs:      container.GetExecIDs(),
25682577
 		HostConfig:   &hostConfig,
603e00a3
 	}
4b9fe9c2
 
b4d6b238
 	var (
 		sizeRw     int64
 		sizeRootFs int64
 	)
 	if size {
3a497650
 		sizeRw, sizeRootFs = daemon.getSize(container)
b4d6b238
 		contJSONBase.SizeRw = &sizeRw
 		contJSONBase.SizeRootFs = &sizeRootFs
 	}
 
47c56e43
 	// Now set any platform-specific fields
 	contJSONBase = setPlatformSpecificContainerFields(container, contJSONBase)
 
407a626b
 	contJSONBase.GraphDriver.Name = container.Driver
4352da78
 
d04fa49a
 	graphDriverData, err := container.RWLayer.Metadata()
407a626b
 	if err != nil {
 		return nil, err
 	}
 	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) {
 	e, err := daemon.getExecConfig(id)
90928eb1
 	if err != nil {
621ee1f6
 		return nil, err
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,
 	}, 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 {
 		return nil, err
 	}
 	return volumeToAPIType(v), nil
 }
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.
efda9618
 func (daemon *Daemon) getDefaultNetworkSettings(networks map[string]*networktypes.EndpointSettings) types.DefaultNetworkSettings {
f301c576
 	var settings types.DefaultNetworkSettings
 
 	if defaultNetwork, ok := networks["bridge"]; ok {
 		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
 }