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/network"
14 "github.com/docker/go-connections/nat"
17 // ContainerInspect returns low-level information about a
18 // container. Returns an error if the container cannot be found, or if
19 // there is an error getting the data.
20 func (daemon *Daemon) ContainerInspect(name string, size bool, version string) (interface{}, error) {
22 case versions.LessThan(version, "1.20"):
23 return daemon.containerInspectPre120(name)
24 case versions.Equal(version, "1.20"):
25 return daemon.containerInspect120(name)
27 return daemon.ContainerInspectCurrent(name, size)
30 // ContainerInspectCurrent returns low-level information about a
31 // container in a most recent api version.
32 func (daemon *Daemon) ContainerInspectCurrent(name string, size bool) (*types.ContainerJSON, error) {
33 container, err := daemon.GetContainer(name)
40 base, err := daemon.getInspectData(container)
46 apiNetworks := make(map[string]*networktypes.EndpointSettings)
47 for name, epConf := range container.NetworkSettings.Networks {
48 if epConf.EndpointSettings != nil {
49 // We must make a copy of this pointer object otherwise it can race with other operations
50 apiNetworks[name] = epConf.EndpointSettings.Copy()
54 mountPoints := container.GetMountPoints()
55 networkSettings := &types.NetworkSettings{
56 NetworkSettingsBase: types.NetworkSettingsBase{
57 Bridge: container.NetworkSettings.Bridge,
58 SandboxID: container.NetworkSettings.SandboxID,
59 HairpinMode: container.NetworkSettings.HairpinMode,
60 LinkLocalIPv6Address: container.NetworkSettings.LinkLocalIPv6Address,
61 LinkLocalIPv6PrefixLen: container.NetworkSettings.LinkLocalIPv6PrefixLen,
62 SandboxKey: container.NetworkSettings.SandboxKey,
63 SecondaryIPAddresses: container.NetworkSettings.SecondaryIPAddresses,
64 SecondaryIPv6Addresses: container.NetworkSettings.SecondaryIPv6Addresses,
66 DefaultNetworkSettings: daemon.getDefaultNetworkSettings(container.NetworkSettings.Networks),
67 Networks: apiNetworks,
70 ports := make(nat.PortMap, len(container.NetworkSettings.Ports))
71 for k, pm := range container.NetworkSettings.Ports {
74 networkSettings.NetworkSettingsBase.Ports = ports
79 sizeRw, sizeRootFs := daemon.getSize(base.ID)
81 base.SizeRootFs = &sizeRootFs
84 return &types.ContainerJSON{
85 ContainerJSONBase: base,
87 Config: container.Config,
88 NetworkSettings: networkSettings,
92 // containerInspect120 serializes the master version of a container into a json type.
93 func (daemon *Daemon) containerInspect120(name string) (*v1p20.ContainerJSON, error) {
94 container, err := daemon.GetContainer(name)
100 defer container.Unlock()
102 base, err := daemon.getInspectData(container)
107 mountPoints := container.GetMountPoints()
108 config := &v1p20.ContainerConfig{
109 Config: container.Config,
110 MacAddress: container.Config.MacAddress,
111 NetworkDisabled: container.Config.NetworkDisabled,
112 ExposedPorts: container.Config.ExposedPorts,
113 VolumeDriver: container.HostConfig.VolumeDriver,
115 networkSettings := daemon.getBackwardsCompatibleNetworkSettings(container.NetworkSettings)
117 return &v1p20.ContainerJSON{
118 ContainerJSONBase: base,
121 NetworkSettings: networkSettings,
125 func (daemon *Daemon) getInspectData(container *container.Container) (*types.ContainerJSONBase, error) {
126 // make a copy to play with
127 hostConfig := *container.HostConfig
129 children := daemon.children(container)
130 hostConfig.Links = nil // do not expose the internal structure
131 for linkAlias, child := range children {
132 hostConfig.Links = append(hostConfig.Links, fmt.Sprintf("%s:%s", child.Name, linkAlias))
135 // We merge the Ulimits from hostConfig with daemon default
136 daemon.mergeUlimits(&hostConfig)
138 var containerHealth *types.Health
139 if container.State.Health != nil {
140 containerHealth = &types.Health{
141 Status: container.State.Health.Status,
142 FailingStreak: container.State.Health.FailingStreak,
143 Log: append([]*types.HealthcheckResult{}, container.State.Health.Log...),
147 containerState := &types.ContainerState{
148 Status: container.State.StateString(),
149 Running: container.State.Running,
150 Paused: container.State.Paused,
151 Restarting: container.State.Restarting,
152 OOMKilled: container.State.OOMKilled,
153 Dead: container.State.Dead,
154 Pid: container.State.Pid,
155 ExitCode: container.State.ExitCode(),
156 Error: container.State.ErrorMsg,
157 StartedAt: container.State.StartedAt.Format(time.RFC3339Nano),
158 FinishedAt: container.State.FinishedAt.Format(time.RFC3339Nano),
159 Health: containerHealth,
162 contJSONBase := &types.ContainerJSONBase{
164 Created: container.Created.Format(time.RFC3339Nano),
165 Path: container.Path,
166 Args: container.Args,
167 State: containerState,
168 Image: container.ImageID.String(),
169 LogPath: container.LogPath,
170 Name: container.Name,
171 RestartCount: container.RestartCount,
172 Driver: container.Driver,
173 Platform: container.Platform,
174 MountLabel: container.MountLabel,
175 ProcessLabel: container.ProcessLabel,
176 ExecIDs: container.GetExecIDs(),
177 HostConfig: &hostConfig,
180 // Now set any platform-specific fields
181 contJSONBase = setPlatformSpecificContainerFields(container, contJSONBase)
183 contJSONBase.GraphDriver.Name = container.Driver
185 graphDriverData, err := container.RWLayer.Metadata()
186 // If container is marked as Dead, the container's graphdriver metadata
187 // could have been removed, it will cause error if we try to get the metadata,
188 // we can ignore the error if the container is dead.
189 if err != nil && !container.Dead {
192 contJSONBase.GraphDriver.Data = graphDriverData
194 return contJSONBase, nil
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, err := daemon.getExecConfig(id)
205 pc := inspectExecProcessConfig(e)
207 return &backend.ExecInspect{
210 ExitCode: e.ExitCode,
212 OpenStdin: e.OpenStdin,
213 OpenStdout: e.OpenStdout,
214 OpenStderr: e.OpenStderr,
215 CanRemove: e.CanRemove,
216 ContainerID: e.ContainerID,
217 DetachKeys: e.DetachKeys,
222 // VolumeInspect looks up a volume by name. An error is returned if
223 // the volume cannot be found.
224 func (daemon *Daemon) VolumeInspect(name string) (*types.Volume, error) {
225 v, err := daemon.volumes.Get(name)
229 apiV := volumeToAPIType(v)
230 apiV.Mountpoint = v.Path()
231 apiV.Status = v.Status()
235 func (daemon *Daemon) getBackwardsCompatibleNetworkSettings(settings *network.Settings) *v1p20.NetworkSettings {
236 result := &v1p20.NetworkSettings{
237 NetworkSettingsBase: types.NetworkSettingsBase{
238 Bridge: settings.Bridge,
239 SandboxID: settings.SandboxID,
240 HairpinMode: settings.HairpinMode,
241 LinkLocalIPv6Address: settings.LinkLocalIPv6Address,
242 LinkLocalIPv6PrefixLen: settings.LinkLocalIPv6PrefixLen,
243 Ports: settings.Ports,
244 SandboxKey: settings.SandboxKey,
245 SecondaryIPAddresses: settings.SecondaryIPAddresses,
246 SecondaryIPv6Addresses: settings.SecondaryIPv6Addresses,
248 DefaultNetworkSettings: daemon.getDefaultNetworkSettings(settings.Networks),
254 // getDefaultNetworkSettings creates the deprecated structure that holds the information
255 // about the bridge network for a container.
256 func (daemon *Daemon) getDefaultNetworkSettings(networks map[string]*network.EndpointSettings) types.DefaultNetworkSettings {
257 var settings types.DefaultNetworkSettings
259 if defaultNetwork, ok := networks["bridge"]; ok && defaultNetwork.EndpointSettings != nil {
260 settings.EndpointID = defaultNetwork.EndpointID
261 settings.Gateway = defaultNetwork.Gateway
262 settings.GlobalIPv6Address = defaultNetwork.GlobalIPv6Address
263 settings.GlobalIPv6PrefixLen = defaultNetwork.GlobalIPv6PrefixLen
264 settings.IPAddress = defaultNetwork.IPAddress
265 settings.IPPrefixLen = defaultNetwork.IPPrefixLen
266 settings.IPv6Gateway = defaultNetwork.IPv6Gateway
267 settings.MacAddress = defaultNetwork.MacAddress