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