inspect.go 9.2 KB

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