inspect.go 9.3 KB

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