inspect.go 10 KB

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