github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/daemon/inspect.go (about)

     1  package daemon
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/docker/docker/api/types"
     8  	"github.com/docker/docker/api/types/backend"
     9  	networktypes "github.com/docker/docker/api/types/network"
    10  	"github.com/docker/docker/api/types/versions"
    11  	"github.com/docker/docker/api/types/versions/v1p20"
    12  	"github.com/docker/docker/container"
    13  	"github.com/docker/docker/daemon/network"
    14  	"github.com/docker/go-connections/nat"
    15  )
    16  
    17  // ContainerInspect returns low-level information about a
    18  // container. Returns an error if the container cannot be found, or if
    19  // there is an error getting the data.
    20  func (daemon *Daemon) ContainerInspect(name string, size bool, version string) (interface{}, error) {
    21  	switch {
    22  	case versions.LessThan(version, "1.20"):
    23  		return daemon.containerInspectPre120(name)
    24  	case versions.Equal(version, "1.20"):
    25  		return daemon.containerInspect120(name)
    26  	}
    27  	return daemon.ContainerInspectCurrent(name, size)
    28  }
    29  
    30  // ContainerInspectCurrent returns low-level information about a
    31  // container in a most recent api version.
    32  func (daemon *Daemon) ContainerInspectCurrent(name string, size bool) (*types.ContainerJSON, error) {
    33  	container, err := daemon.GetContainer(name)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  
    38  	container.Lock()
    39  
    40  	base, err := daemon.getInspectData(container)
    41  	if err != nil {
    42  		container.Unlock()
    43  		return nil, err
    44  	}
    45  
    46  	apiNetworks := make(map[string]*networktypes.EndpointSettings)
    47  	for name, epConf := range container.NetworkSettings.Networks {
    48  		if epConf.EndpointSettings != nil {
    49  			// We must make a copy of this pointer object otherwise it can race with other operations
    50  			apiNetworks[name] = epConf.EndpointSettings.Copy()
    51  		}
    52  	}
    53  
    54  	mountPoints := addMountPoints(container)
    55  	networkSettings := &types.NetworkSettings{
    56  		NetworkSettingsBase: types.NetworkSettingsBase{
    57  			Bridge:                 container.NetworkSettings.Bridge,
    58  			SandboxID:              container.NetworkSettings.SandboxID,
    59  			HairpinMode:            container.NetworkSettings.HairpinMode,
    60  			LinkLocalIPv6Address:   container.NetworkSettings.LinkLocalIPv6Address,
    61  			LinkLocalIPv6PrefixLen: container.NetworkSettings.LinkLocalIPv6PrefixLen,
    62  			SandboxKey:             container.NetworkSettings.SandboxKey,
    63  			SecondaryIPAddresses:   container.NetworkSettings.SecondaryIPAddresses,
    64  			SecondaryIPv6Addresses: container.NetworkSettings.SecondaryIPv6Addresses,
    65  		},
    66  		DefaultNetworkSettings: daemon.getDefaultNetworkSettings(container.NetworkSettings.Networks),
    67  		Networks:               apiNetworks,
    68  	}
    69  
    70  	ports := make(nat.PortMap, len(container.NetworkSettings.Ports))
    71  	for k, pm := range container.NetworkSettings.Ports {
    72  		ports[k] = pm
    73  	}
    74  	networkSettings.NetworkSettingsBase.Ports = ports
    75  
    76  	container.Unlock()
    77  
    78  	if size {
    79  		sizeRw, sizeRootFs := daemon.getSize(base.ID)
    80  		base.SizeRw = &sizeRw
    81  		base.SizeRootFs = &sizeRootFs
    82  	}
    83  
    84  	return &types.ContainerJSON{
    85  		ContainerJSONBase: base,
    86  		Mounts:            mountPoints,
    87  		Config:            container.Config,
    88  		NetworkSettings:   networkSettings,
    89  	}, nil
    90  }
    91  
    92  // containerInspect120 serializes the master version of a container into a json type.
    93  func (daemon *Daemon) containerInspect120(name string) (*v1p20.ContainerJSON, error) {
    94  	container, err := daemon.GetContainer(name)
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  
    99  	container.Lock()
   100  	defer container.Unlock()
   101  
   102  	base, err := daemon.getInspectData(container)
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  
   107  	mountPoints := addMountPoints(container)
   108  	config := &v1p20.ContainerConfig{
   109  		Config:          container.Config,
   110  		MacAddress:      container.Config.MacAddress,
   111  		NetworkDisabled: container.Config.NetworkDisabled,
   112  		ExposedPorts:    container.Config.ExposedPorts,
   113  		VolumeDriver:    container.HostConfig.VolumeDriver,
   114  	}
   115  	networkSettings := daemon.getBackwardsCompatibleNetworkSettings(container.NetworkSettings)
   116  
   117  	return &v1p20.ContainerJSON{
   118  		ContainerJSONBase: base,
   119  		Mounts:            mountPoints,
   120  		Config:            config,
   121  		NetworkSettings:   networkSettings,
   122  	}, nil
   123  }
   124  
   125  func (daemon *Daemon) getInspectData(container *container.Container) (*types.ContainerJSONBase, error) {
   126  	// make a copy to play with
   127  	hostConfig := *container.HostConfig
   128  
   129  	children := daemon.children(container)
   130  	hostConfig.Links = nil // do not expose the internal structure
   131  	for linkAlias, child := range children {
   132  		hostConfig.Links = append(hostConfig.Links, fmt.Sprintf("%s:%s", child.Name, linkAlias))
   133  	}
   134  
   135  	// We merge the Ulimits from hostConfig with daemon default
   136  	daemon.mergeUlimits(&hostConfig)
   137  
   138  	var containerHealth *types.Health
   139  	if container.State.Health != nil {
   140  		containerHealth = &types.Health{
   141  			Status:        container.State.Health.Status,
   142  			FailingStreak: container.State.Health.FailingStreak,
   143  			Log:           append([]*types.HealthcheckResult{}, container.State.Health.Log...),
   144  		}
   145  	}
   146  
   147  	containerState := &types.ContainerState{
   148  		Status:     container.State.StateString(),
   149  		Running:    container.State.Running,
   150  		Paused:     container.State.Paused,
   151  		Restarting: container.State.Restarting,
   152  		OOMKilled:  container.State.OOMKilled,
   153  		Dead:       container.State.Dead,
   154  		Pid:        container.State.Pid,
   155  		ExitCode:   container.State.ExitCode(),
   156  		Error:      container.State.ErrorMsg,
   157  		StartedAt:  container.State.StartedAt.Format(time.RFC3339Nano),
   158  		FinishedAt: container.State.FinishedAt.Format(time.RFC3339Nano),
   159  		Health:     containerHealth,
   160  	}
   161  
   162  	contJSONBase := &types.ContainerJSONBase{
   163  		ID:           container.ID,
   164  		Created:      container.Created.Format(time.RFC3339Nano),
   165  		Path:         container.Path,
   166  		Args:         container.Args,
   167  		State:        containerState,
   168  		Image:        container.ImageID.String(),
   169  		LogPath:      container.LogPath,
   170  		Name:         container.Name,
   171  		RestartCount: container.RestartCount,
   172  		Driver:       container.Driver,
   173  		MountLabel:   container.MountLabel,
   174  		ProcessLabel: container.ProcessLabel,
   175  		ExecIDs:      container.GetExecIDs(),
   176  		HostConfig:   &hostConfig,
   177  	}
   178  
   179  	// Now set any platform-specific fields
   180  	contJSONBase = setPlatformSpecificContainerFields(container, contJSONBase)
   181  
   182  	contJSONBase.GraphDriver.Name = container.Driver
   183  
   184  	graphDriverData, err := container.RWLayer.Metadata()
   185  	// If container is marked as Dead, the container's graphdriver metadata
   186  	// could have been removed, it will cause error if we try to get the metadata,
   187  	// we can ignore the error if the container is dead.
   188  	if err != nil && !container.Dead {
   189  		return nil, err
   190  	}
   191  	contJSONBase.GraphDriver.Data = graphDriverData
   192  
   193  	return contJSONBase, nil
   194  }
   195  
   196  // ContainerExecInspect returns low-level information about the exec
   197  // command. An error is returned if the exec cannot be found.
   198  func (daemon *Daemon) ContainerExecInspect(id string) (*backend.ExecInspect, error) {
   199  	e, err := daemon.getExecConfig(id)
   200  	if err != nil {
   201  		return nil, err
   202  	}
   203  
   204  	pc := inspectExecProcessConfig(e)
   205  
   206  	return &backend.ExecInspect{
   207  		ID:            e.ID,
   208  		Running:       e.Running,
   209  		ExitCode:      e.ExitCode,
   210  		ProcessConfig: pc,
   211  		OpenStdin:     e.OpenStdin,
   212  		OpenStdout:    e.OpenStdout,
   213  		OpenStderr:    e.OpenStderr,
   214  		CanRemove:     e.CanRemove,
   215  		ContainerID:   e.ContainerID,
   216  		DetachKeys:    e.DetachKeys,
   217  		Pid:           e.Pid,
   218  	}, nil
   219  }
   220  
   221  // VolumeInspect looks up a volume by name. An error is returned if
   222  // the volume cannot be found.
   223  func (daemon *Daemon) VolumeInspect(name string) (*types.Volume, error) {
   224  	v, err := daemon.volumes.Get(name)
   225  	if err != nil {
   226  		return nil, err
   227  	}
   228  	apiV := volumeToAPIType(v)
   229  	apiV.Mountpoint = v.Path()
   230  	apiV.Status = v.Status()
   231  	return apiV, nil
   232  }
   233  
   234  func (daemon *Daemon) getBackwardsCompatibleNetworkSettings(settings *network.Settings) *v1p20.NetworkSettings {
   235  	result := &v1p20.NetworkSettings{
   236  		NetworkSettingsBase: types.NetworkSettingsBase{
   237  			Bridge:                 settings.Bridge,
   238  			SandboxID:              settings.SandboxID,
   239  			HairpinMode:            settings.HairpinMode,
   240  			LinkLocalIPv6Address:   settings.LinkLocalIPv6Address,
   241  			LinkLocalIPv6PrefixLen: settings.LinkLocalIPv6PrefixLen,
   242  			Ports:                  settings.Ports,
   243  			SandboxKey:             settings.SandboxKey,
   244  			SecondaryIPAddresses:   settings.SecondaryIPAddresses,
   245  			SecondaryIPv6Addresses: settings.SecondaryIPv6Addresses,
   246  		},
   247  		DefaultNetworkSettings: daemon.getDefaultNetworkSettings(settings.Networks),
   248  	}
   249  
   250  	return result
   251  }
   252  
   253  // getDefaultNetworkSettings creates the deprecated structure that holds the information
   254  // about the bridge network for a container.
   255  func (daemon *Daemon) getDefaultNetworkSettings(networks map[string]*network.EndpointSettings) types.DefaultNetworkSettings {
   256  	var settings types.DefaultNetworkSettings
   257  
   258  	if defaultNetwork, ok := networks["bridge"]; ok && defaultNetwork.EndpointSettings != nil {
   259  		settings.EndpointID = defaultNetwork.EndpointID
   260  		settings.Gateway = defaultNetwork.Gateway
   261  		settings.GlobalIPv6Address = defaultNetwork.GlobalIPv6Address
   262  		settings.GlobalIPv6PrefixLen = defaultNetwork.GlobalIPv6PrefixLen
   263  		settings.IPAddress = defaultNetwork.IPAddress
   264  		settings.IPPrefixLen = defaultNetwork.IPPrefixLen
   265  		settings.IPv6Gateway = defaultNetwork.IPv6Gateway
   266  		settings.MacAddress = defaultNetwork.MacAddress
   267  	}
   268  	return settings
   269  }