github.com/rish1988/moby@v25.0.2+incompatible/daemon/inspect.go (about)

     1  // FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
     2  //go:build go1.19
     3  
     4  package daemon // import "github.com/docker/docker/daemon"
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"fmt"
    10  	"time"
    11  
    12  	"github.com/docker/docker/api/types"
    13  	"github.com/docker/docker/api/types/backend"
    14  	containertypes "github.com/docker/docker/api/types/container"
    15  	networktypes "github.com/docker/docker/api/types/network"
    16  	"github.com/docker/docker/api/types/versions"
    17  	"github.com/docker/docker/api/types/versions/v1p20"
    18  	"github.com/docker/docker/container"
    19  	"github.com/docker/docker/daemon/config"
    20  	"github.com/docker/docker/daemon/network"
    21  	"github.com/docker/docker/errdefs"
    22  	"github.com/docker/docker/internal/sliceutil"
    23  	"github.com/docker/docker/pkg/stringid"
    24  	"github.com/docker/go-connections/nat"
    25  )
    26  
    27  // ContainerInspect returns low-level information about a
    28  // container. Returns an error if the container cannot be found, or if
    29  // there is an error getting the data.
    30  func (daemon *Daemon) ContainerInspect(ctx context.Context, name string, size bool, version string) (interface{}, error) {
    31  	switch {
    32  	case versions.LessThan(version, "1.20"):
    33  		return daemon.containerInspectPre120(ctx, name)
    34  	case versions.Equal(version, "1.20"):
    35  		return daemon.containerInspect120(name)
    36  	case versions.LessThan(version, "1.45"):
    37  		ctr, err := daemon.ContainerInspectCurrent(ctx, name, size)
    38  		if err != nil {
    39  			return nil, err
    40  		}
    41  
    42  		shortCID := stringid.TruncateID(ctr.ID)
    43  		for nwName, ep := range ctr.NetworkSettings.Networks {
    44  			if containertypes.NetworkMode(nwName).IsUserDefined() {
    45  				ep.Aliases = sliceutil.Dedup(append(ep.Aliases, shortCID, ctr.Config.Hostname))
    46  			}
    47  		}
    48  
    49  		return ctr, nil
    50  	default:
    51  		return daemon.ContainerInspectCurrent(ctx, name, size)
    52  	}
    53  }
    54  
    55  // ContainerInspectCurrent returns low-level information about a
    56  // container in a most recent api version.
    57  func (daemon *Daemon) ContainerInspectCurrent(ctx context.Context, name string, size bool) (*types.ContainerJSON, error) {
    58  	ctr, err := daemon.GetContainer(name)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  
    63  	ctr.Lock()
    64  
    65  	base, err := daemon.getInspectData(&daemon.config().Config, ctr)
    66  	if err != nil {
    67  		ctr.Unlock()
    68  		return nil, err
    69  	}
    70  
    71  	apiNetworks := make(map[string]*networktypes.EndpointSettings)
    72  	for nwName, epConf := range ctr.NetworkSettings.Networks {
    73  		if epConf.EndpointSettings != nil {
    74  			// We must make a copy of this pointer object otherwise it can race with other operations
    75  			apiNetworks[nwName] = epConf.EndpointSettings.Copy()
    76  		}
    77  	}
    78  
    79  	mountPoints := ctr.GetMountPoints()
    80  	networkSettings := &types.NetworkSettings{
    81  		NetworkSettingsBase: types.NetworkSettingsBase{
    82  			Bridge:                 ctr.NetworkSettings.Bridge,
    83  			SandboxID:              ctr.NetworkSettings.SandboxID,
    84  			SandboxKey:             ctr.NetworkSettings.SandboxKey,
    85  			HairpinMode:            ctr.NetworkSettings.HairpinMode,
    86  			LinkLocalIPv6Address:   ctr.NetworkSettings.LinkLocalIPv6Address,
    87  			LinkLocalIPv6PrefixLen: ctr.NetworkSettings.LinkLocalIPv6PrefixLen,
    88  			SecondaryIPAddresses:   ctr.NetworkSettings.SecondaryIPAddresses,
    89  			SecondaryIPv6Addresses: ctr.NetworkSettings.SecondaryIPv6Addresses,
    90  		},
    91  		DefaultNetworkSettings: daemon.getDefaultNetworkSettings(ctr.NetworkSettings.Networks),
    92  		Networks:               apiNetworks,
    93  	}
    94  
    95  	ports := make(nat.PortMap, len(ctr.NetworkSettings.Ports))
    96  	for k, pm := range ctr.NetworkSettings.Ports {
    97  		ports[k] = pm
    98  	}
    99  	networkSettings.NetworkSettingsBase.Ports = ports
   100  
   101  	ctr.Unlock()
   102  
   103  	if size {
   104  		sizeRw, sizeRootFs, err := daemon.imageService.GetContainerLayerSize(ctx, base.ID)
   105  		if err != nil {
   106  			return nil, err
   107  		}
   108  		base.SizeRw = &sizeRw
   109  		base.SizeRootFs = &sizeRootFs
   110  	}
   111  
   112  	return &types.ContainerJSON{
   113  		ContainerJSONBase: base,
   114  		Mounts:            mountPoints,
   115  		Config:            ctr.Config,
   116  		NetworkSettings:   networkSettings,
   117  	}, nil
   118  }
   119  
   120  // containerInspect120 serializes the master version of a container into a json type.
   121  func (daemon *Daemon) containerInspect120(name string) (*v1p20.ContainerJSON, error) {
   122  	ctr, err := daemon.GetContainer(name)
   123  	if err != nil {
   124  		return nil, err
   125  	}
   126  
   127  	ctr.Lock()
   128  	defer ctr.Unlock()
   129  
   130  	base, err := daemon.getInspectData(&daemon.config().Config, ctr)
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  
   135  	return &v1p20.ContainerJSON{
   136  		ContainerJSONBase: base,
   137  		Mounts:            ctr.GetMountPoints(),
   138  		Config: &v1p20.ContainerConfig{
   139  			Config:          ctr.Config,
   140  			MacAddress:      ctr.Config.MacAddress, //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
   141  			NetworkDisabled: ctr.Config.NetworkDisabled,
   142  			ExposedPorts:    ctr.Config.ExposedPorts,
   143  			VolumeDriver:    ctr.HostConfig.VolumeDriver,
   144  		},
   145  		NetworkSettings: daemon.getBackwardsCompatibleNetworkSettings(ctr.NetworkSettings),
   146  	}, nil
   147  }
   148  
   149  func (daemon *Daemon) getInspectData(daemonCfg *config.Config, container *container.Container) (*types.ContainerJSONBase, error) {
   150  	// make a copy to play with
   151  	hostConfig := *container.HostConfig
   152  
   153  	children := daemon.children(container)
   154  	hostConfig.Links = nil // do not expose the internal structure
   155  	for linkAlias, child := range children {
   156  		hostConfig.Links = append(hostConfig.Links, fmt.Sprintf("%s:%s", child.Name, linkAlias))
   157  	}
   158  
   159  	// We merge the Ulimits from hostConfig with daemon default
   160  	daemon.mergeUlimits(&hostConfig, daemonCfg)
   161  
   162  	// Migrate the container's default network's MacAddress to the top-level
   163  	// Config.MacAddress field for older API versions (< 1.44). We set it here
   164  	// unconditionally, to keep backward compatibility with clients that use
   165  	// unversioned API endpoints.
   166  	if container.Config != nil && container.Config.MacAddress == "" { //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
   167  		if nwm := hostConfig.NetworkMode; nwm.IsDefault() || nwm.IsBridge() || nwm.IsUserDefined() {
   168  			if epConf, ok := container.NetworkSettings.Networks[nwm.NetworkName()]; ok {
   169  				container.Config.MacAddress = epConf.MacAddress //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
   170  			}
   171  		}
   172  	}
   173  
   174  	var containerHealth *types.Health
   175  	if container.State.Health != nil {
   176  		containerHealth = &types.Health{
   177  			Status:        container.State.Health.Status(),
   178  			FailingStreak: container.State.Health.FailingStreak,
   179  			Log:           append([]*types.HealthcheckResult{}, container.State.Health.Log...),
   180  		}
   181  	}
   182  
   183  	containerState := &types.ContainerState{
   184  		Status:     container.State.StateString(),
   185  		Running:    container.State.Running,
   186  		Paused:     container.State.Paused,
   187  		Restarting: container.State.Restarting,
   188  		OOMKilled:  container.State.OOMKilled,
   189  		Dead:       container.State.Dead,
   190  		Pid:        container.State.Pid,
   191  		ExitCode:   container.State.ExitCode(),
   192  		Error:      container.State.ErrorMsg,
   193  		StartedAt:  container.State.StartedAt.Format(time.RFC3339Nano),
   194  		FinishedAt: container.State.FinishedAt.Format(time.RFC3339Nano),
   195  		Health:     containerHealth,
   196  	}
   197  
   198  	contJSONBase := &types.ContainerJSONBase{
   199  		ID:           container.ID,
   200  		Created:      container.Created.Format(time.RFC3339Nano),
   201  		Path:         container.Path,
   202  		Args:         container.Args,
   203  		State:        containerState,
   204  		Image:        container.ImageID.String(),
   205  		LogPath:      container.LogPath,
   206  		Name:         container.Name,
   207  		RestartCount: container.RestartCount,
   208  		Driver:       container.Driver,
   209  		Platform:     container.OS,
   210  		MountLabel:   container.MountLabel,
   211  		ProcessLabel: container.ProcessLabel,
   212  		ExecIDs:      container.GetExecIDs(),
   213  		HostConfig:   &hostConfig,
   214  	}
   215  
   216  	// Now set any platform-specific fields
   217  	contJSONBase = setPlatformSpecificContainerFields(container, contJSONBase)
   218  
   219  	contJSONBase.GraphDriver.Name = container.Driver
   220  
   221  	if daemon.UsesSnapshotter() {
   222  		// Additional information only applies to graphDrivers, so we're done.
   223  		return contJSONBase, nil
   224  	}
   225  
   226  	if container.RWLayer == nil {
   227  		if container.Dead {
   228  			return contJSONBase, nil
   229  		}
   230  		return nil, errdefs.System(errors.New("RWLayer of container " + container.ID + " is unexpectedly nil"))
   231  	}
   232  
   233  	graphDriverData, err := container.RWLayer.Metadata()
   234  	if err != nil {
   235  		if container.Dead {
   236  			// container is marked as Dead, and its graphDriver metadata may
   237  			// have been removed; we can ignore errors.
   238  			return contJSONBase, nil
   239  		}
   240  		return nil, errdefs.System(err)
   241  	}
   242  
   243  	contJSONBase.GraphDriver.Data = graphDriverData
   244  	return contJSONBase, nil
   245  }
   246  
   247  // ContainerExecInspect returns low-level information about the exec
   248  // command. An error is returned if the exec cannot be found.
   249  func (daemon *Daemon) ContainerExecInspect(id string) (*backend.ExecInspect, error) {
   250  	e := daemon.execCommands.Get(id)
   251  	if e == nil {
   252  		return nil, errExecNotFound(id)
   253  	}
   254  
   255  	if ctr := daemon.containers.Get(e.Container.ID); ctr == nil {
   256  		return nil, errExecNotFound(id)
   257  	}
   258  
   259  	e.Lock()
   260  	defer e.Unlock()
   261  	pc := inspectExecProcessConfig(e)
   262  	var pid int
   263  	if e.Process != nil {
   264  		pid = int(e.Process.Pid())
   265  	}
   266  
   267  	return &backend.ExecInspect{
   268  		ID:            e.ID,
   269  		Running:       e.Running,
   270  		ExitCode:      e.ExitCode,
   271  		ProcessConfig: pc,
   272  		OpenStdin:     e.OpenStdin,
   273  		OpenStdout:    e.OpenStdout,
   274  		OpenStderr:    e.OpenStderr,
   275  		CanRemove:     e.CanRemove,
   276  		ContainerID:   e.Container.ID,
   277  		DetachKeys:    e.DetachKeys,
   278  		Pid:           pid,
   279  	}, nil
   280  }
   281  
   282  func (daemon *Daemon) getBackwardsCompatibleNetworkSettings(settings *network.Settings) *v1p20.NetworkSettings {
   283  	result := &v1p20.NetworkSettings{
   284  		NetworkSettingsBase: types.NetworkSettingsBase{
   285  			Bridge:                 settings.Bridge,
   286  			SandboxID:              settings.SandboxID,
   287  			SandboxKey:             settings.SandboxKey,
   288  			HairpinMode:            settings.HairpinMode,
   289  			LinkLocalIPv6Address:   settings.LinkLocalIPv6Address,
   290  			LinkLocalIPv6PrefixLen: settings.LinkLocalIPv6PrefixLen,
   291  			Ports:                  settings.Ports,
   292  			SecondaryIPAddresses:   settings.SecondaryIPAddresses,
   293  			SecondaryIPv6Addresses: settings.SecondaryIPv6Addresses,
   294  		},
   295  		DefaultNetworkSettings: daemon.getDefaultNetworkSettings(settings.Networks),
   296  	}
   297  
   298  	return result
   299  }
   300  
   301  // getDefaultNetworkSettings creates the deprecated structure that holds the information
   302  // about the bridge network for a container.
   303  func (daemon *Daemon) getDefaultNetworkSettings(networks map[string]*network.EndpointSettings) types.DefaultNetworkSettings {
   304  	var settings types.DefaultNetworkSettings
   305  
   306  	if defaultNetwork, ok := networks[networktypes.NetworkBridge]; ok && defaultNetwork.EndpointSettings != nil {
   307  		settings.EndpointID = defaultNetwork.EndpointID
   308  		settings.Gateway = defaultNetwork.Gateway
   309  		settings.GlobalIPv6Address = defaultNetwork.GlobalIPv6Address
   310  		settings.GlobalIPv6PrefixLen = defaultNetwork.GlobalIPv6PrefixLen
   311  		settings.IPAddress = defaultNetwork.IPAddress
   312  		settings.IPPrefixLen = defaultNetwork.IPPrefixLen
   313  		settings.IPv6Gateway = defaultNetwork.IPv6Gateway
   314  		settings.MacAddress = defaultNetwork.MacAddress
   315  	}
   316  	return settings
   317  }