inspect.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. package daemon
  2. import (
  3. "fmt"
  4. "time"
  5. "github.com/docker/docker/api/types"
  6. "github.com/docker/docker/api/types/backend"
  7. networktypes "github.com/docker/docker/api/types/network"
  8. "github.com/docker/docker/api/types/versions"
  9. "github.com/docker/docker/api/types/versions/v1p20"
  10. "github.com/docker/docker/container"
  11. "github.com/docker/docker/daemon/network"
  12. )
  13. // ContainerInspect returns low-level information about a
  14. // container. Returns an error if the container cannot be found, or if
  15. // there is an error getting the data.
  16. func (daemon *Daemon) ContainerInspect(name string, size bool, version string) (interface{}, error) {
  17. switch {
  18. case versions.LessThan(version, "1.20"):
  19. return daemon.containerInspectPre120(name)
  20. case versions.Equal(version, "1.20"):
  21. return daemon.containerInspect120(name)
  22. }
  23. return daemon.ContainerInspectCurrent(name, size)
  24. }
  25. // ContainerInspectCurrent returns low-level information about a
  26. // container in a most recent api version.
  27. func (daemon *Daemon) ContainerInspectCurrent(name string, size bool) (*types.ContainerJSON, error) {
  28. container, err := daemon.GetContainer(name)
  29. if err != nil {
  30. return nil, err
  31. }
  32. container.Lock()
  33. defer container.Unlock()
  34. base, err := daemon.getInspectData(container, size)
  35. if err != nil {
  36. return nil, err
  37. }
  38. apiNetworks := make(map[string]*networktypes.EndpointSettings)
  39. for name, epConf := range container.NetworkSettings.Networks {
  40. if epConf.EndpointSettings != nil {
  41. apiNetworks[name] = epConf.EndpointSettings
  42. }
  43. }
  44. mountPoints := addMountPoints(container)
  45. networkSettings := &types.NetworkSettings{
  46. NetworkSettingsBase: types.NetworkSettingsBase{
  47. Bridge: container.NetworkSettings.Bridge,
  48. SandboxID: container.NetworkSettings.SandboxID,
  49. HairpinMode: container.NetworkSettings.HairpinMode,
  50. LinkLocalIPv6Address: container.NetworkSettings.LinkLocalIPv6Address,
  51. LinkLocalIPv6PrefixLen: container.NetworkSettings.LinkLocalIPv6PrefixLen,
  52. Ports: container.NetworkSettings.Ports,
  53. SandboxKey: container.NetworkSettings.SandboxKey,
  54. SecondaryIPAddresses: container.NetworkSettings.SecondaryIPAddresses,
  55. SecondaryIPv6Addresses: container.NetworkSettings.SecondaryIPv6Addresses,
  56. },
  57. DefaultNetworkSettings: daemon.getDefaultNetworkSettings(container.NetworkSettings.Networks),
  58. Networks: apiNetworks,
  59. }
  60. return &types.ContainerJSON{
  61. ContainerJSONBase: base,
  62. Mounts: mountPoints,
  63. Config: container.Config,
  64. NetworkSettings: networkSettings,
  65. }, nil
  66. }
  67. // containerInspect120 serializes the master version of a container into a json type.
  68. func (daemon *Daemon) containerInspect120(name string) (*v1p20.ContainerJSON, error) {
  69. container, err := daemon.GetContainer(name)
  70. if err != nil {
  71. return nil, err
  72. }
  73. container.Lock()
  74. defer container.Unlock()
  75. base, err := daemon.getInspectData(container, false)
  76. if err != nil {
  77. return nil, err
  78. }
  79. mountPoints := addMountPoints(container)
  80. config := &v1p20.ContainerConfig{
  81. Config: container.Config,
  82. MacAddress: container.Config.MacAddress,
  83. NetworkDisabled: container.Config.NetworkDisabled,
  84. ExposedPorts: container.Config.ExposedPorts,
  85. VolumeDriver: container.HostConfig.VolumeDriver,
  86. }
  87. networkSettings := daemon.getBackwardsCompatibleNetworkSettings(container.NetworkSettings)
  88. return &v1p20.ContainerJSON{
  89. ContainerJSONBase: base,
  90. Mounts: mountPoints,
  91. Config: config,
  92. NetworkSettings: networkSettings,
  93. }, nil
  94. }
  95. func (daemon *Daemon) getInspectData(container *container.Container, size bool) (*types.ContainerJSONBase, error) {
  96. // make a copy to play with
  97. hostConfig := *container.HostConfig
  98. children := daemon.children(container)
  99. hostConfig.Links = nil // do not expose the internal structure
  100. for linkAlias, child := range children {
  101. hostConfig.Links = append(hostConfig.Links, fmt.Sprintf("%s:%s", child.Name, linkAlias))
  102. }
  103. // We merge the Ulimits from hostConfig with daemon default
  104. daemon.mergeUlimits(&hostConfig)
  105. var containerHealth *types.Health
  106. if container.State.Health != nil {
  107. containerHealth = &types.Health{
  108. Status: container.State.Health.Status,
  109. FailingStreak: container.State.Health.FailingStreak,
  110. Log: append([]*types.HealthcheckResult{}, container.State.Health.Log...),
  111. }
  112. }
  113. containerState := &types.ContainerState{
  114. Status: container.State.StateString(),
  115. Running: container.State.Running,
  116. Paused: container.State.Paused,
  117. Restarting: container.State.Restarting,
  118. OOMKilled: container.State.OOMKilled,
  119. Dead: container.State.Dead,
  120. Pid: container.State.Pid,
  121. ExitCode: container.State.ExitCode(),
  122. Error: container.State.Error(),
  123. StartedAt: container.State.StartedAt.Format(time.RFC3339Nano),
  124. FinishedAt: container.State.FinishedAt.Format(time.RFC3339Nano),
  125. Health: containerHealth,
  126. }
  127. contJSONBase := &types.ContainerJSONBase{
  128. ID: container.ID,
  129. Created: container.Created.Format(time.RFC3339Nano),
  130. Path: container.Path,
  131. Args: container.Args,
  132. State: containerState,
  133. Image: container.ImageID.String(),
  134. LogPath: container.LogPath,
  135. Name: container.Name,
  136. RestartCount: container.RestartCount,
  137. Driver: container.Driver,
  138. MountLabel: container.MountLabel,
  139. ProcessLabel: container.ProcessLabel,
  140. ExecIDs: container.GetExecIDs(),
  141. HostConfig: &hostConfig,
  142. }
  143. var (
  144. sizeRw int64
  145. sizeRootFs int64
  146. )
  147. if size {
  148. sizeRw, sizeRootFs = daemon.getSize(container)
  149. contJSONBase.SizeRw = &sizeRw
  150. contJSONBase.SizeRootFs = &sizeRootFs
  151. }
  152. // Now set any platform-specific fields
  153. contJSONBase = setPlatformSpecificContainerFields(container, contJSONBase)
  154. contJSONBase.GraphDriver.Name = container.Driver
  155. graphDriverData, err := container.RWLayer.Metadata()
  156. // If container is marked as Dead, the container's graphdriver metadata
  157. // could have been removed, it will cause error if we try to get the metadata,
  158. // we can ignore the error if the container is dead.
  159. if err != nil && !container.Dead {
  160. return nil, err
  161. }
  162. contJSONBase.GraphDriver.Data = graphDriverData
  163. return contJSONBase, nil
  164. }
  165. // ContainerExecInspect returns low-level information about the exec
  166. // command. An error is returned if the exec cannot be found.
  167. func (daemon *Daemon) ContainerExecInspect(id string) (*backend.ExecInspect, error) {
  168. e, err := daemon.getExecConfig(id)
  169. if err != nil {
  170. return nil, err
  171. }
  172. pc := inspectExecProcessConfig(e)
  173. return &backend.ExecInspect{
  174. ID: e.ID,
  175. Running: e.Running,
  176. ExitCode: e.ExitCode,
  177. ProcessConfig: pc,
  178. OpenStdin: e.OpenStdin,
  179. OpenStdout: e.OpenStdout,
  180. OpenStderr: e.OpenStderr,
  181. CanRemove: e.CanRemove,
  182. ContainerID: e.ContainerID,
  183. DetachKeys: e.DetachKeys,
  184. Pid: e.Pid,
  185. }, nil
  186. }
  187. // VolumeInspect looks up a volume by name. An error is returned if
  188. // the volume cannot be found.
  189. func (daemon *Daemon) VolumeInspect(name string) (*types.Volume, error) {
  190. v, err := daemon.volumes.Get(name)
  191. if err != nil {
  192. return nil, err
  193. }
  194. apiV := volumeToAPIType(v)
  195. apiV.Mountpoint = v.Path()
  196. apiV.Status = v.Status()
  197. return apiV, nil
  198. }
  199. func (daemon *Daemon) getBackwardsCompatibleNetworkSettings(settings *network.Settings) *v1p20.NetworkSettings {
  200. result := &v1p20.NetworkSettings{
  201. NetworkSettingsBase: types.NetworkSettingsBase{
  202. Bridge: settings.Bridge,
  203. SandboxID: settings.SandboxID,
  204. HairpinMode: settings.HairpinMode,
  205. LinkLocalIPv6Address: settings.LinkLocalIPv6Address,
  206. LinkLocalIPv6PrefixLen: settings.LinkLocalIPv6PrefixLen,
  207. Ports: settings.Ports,
  208. SandboxKey: settings.SandboxKey,
  209. SecondaryIPAddresses: settings.SecondaryIPAddresses,
  210. SecondaryIPv6Addresses: settings.SecondaryIPv6Addresses,
  211. },
  212. DefaultNetworkSettings: daemon.getDefaultNetworkSettings(settings.Networks),
  213. }
  214. return result
  215. }
  216. // getDefaultNetworkSettings creates the deprecated structure that holds the information
  217. // about the bridge network for a container.
  218. func (daemon *Daemon) getDefaultNetworkSettings(networks map[string]*network.EndpointSettings) types.DefaultNetworkSettings {
  219. var settings types.DefaultNetworkSettings
  220. if defaultNetwork, ok := networks["bridge"]; ok && defaultNetwork.EndpointSettings != nil {
  221. settings.EndpointID = defaultNetwork.EndpointID
  222. settings.Gateway = defaultNetwork.Gateway
  223. settings.GlobalIPv6Address = defaultNetwork.GlobalIPv6Address
  224. settings.GlobalIPv6PrefixLen = defaultNetwork.GlobalIPv6PrefixLen
  225. settings.IPAddress = defaultNetwork.IPAddress
  226. settings.IPPrefixLen = defaultNetwork.IPPrefixLen
  227. settings.IPv6Gateway = defaultNetwork.IPv6Gateway
  228. settings.MacAddress = defaultNetwork.MacAddress
  229. }
  230. return settings
  231. }