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 }