inspect.go 8.9 KB

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