Tizen_4.0 base
[platform/upstream/docker-engine.git] / daemon / inspect.go
1 package daemon
2
3 import (
4         "fmt"
5         "time"
6
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"
15 )
16
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) {
21         switch {
22         case versions.LessThan(version, "1.20"):
23                 return daemon.containerInspectPre120(name)
24         case versions.Equal(version, "1.20"):
25                 return daemon.containerInspect120(name)
26         }
27         return daemon.ContainerInspectCurrent(name, size)
28 }
29
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)
34         if err != nil {
35                 return nil, err
36         }
37
38         container.Lock()
39
40         base, err := daemon.getInspectData(container)
41         if err != nil {
42                 container.Unlock()
43                 return nil, err
44         }
45
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()
51                 }
52         }
53
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,
65                 },
66                 DefaultNetworkSettings: daemon.getDefaultNetworkSettings(container.NetworkSettings.Networks),
67                 Networks:               apiNetworks,
68         }
69
70         ports := make(nat.PortMap, len(container.NetworkSettings.Ports))
71         for k, pm := range container.NetworkSettings.Ports {
72                 ports[k] = pm
73         }
74         networkSettings.NetworkSettingsBase.Ports = ports
75
76         container.Unlock()
77
78         if size {
79                 sizeRw, sizeRootFs := daemon.getSize(base.ID)
80                 base.SizeRw = &sizeRw
81                 base.SizeRootFs = &sizeRootFs
82         }
83
84         return &types.ContainerJSON{
85                 ContainerJSONBase: base,
86                 Mounts:            mountPoints,
87                 Config:            container.Config,
88                 NetworkSettings:   networkSettings,
89         }, nil
90 }
91
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)
95         if err != nil {
96                 return nil, err
97         }
98
99         container.Lock()
100         defer container.Unlock()
101
102         base, err := daemon.getInspectData(container)
103         if err != nil {
104                 return nil, err
105         }
106
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,
114         }
115         networkSettings := daemon.getBackwardsCompatibleNetworkSettings(container.NetworkSettings)
116
117         return &v1p20.ContainerJSON{
118                 ContainerJSONBase: base,
119                 Mounts:            mountPoints,
120                 Config:            config,
121                 NetworkSettings:   networkSettings,
122         }, nil
123 }
124
125 func (daemon *Daemon) getInspectData(container *container.Container) (*types.ContainerJSONBase, error) {
126         // make a copy to play with
127         hostConfig := *container.HostConfig
128
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))
133         }
134
135         // We merge the Ulimits from hostConfig with daemon default
136         daemon.mergeUlimits(&hostConfig)
137
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...),
144                 }
145         }
146
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,
160         }
161
162         contJSONBase := &types.ContainerJSONBase{
163                 ID:           container.ID,
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,
178         }
179
180         // Now set any platform-specific fields
181         contJSONBase = setPlatformSpecificContainerFields(container, contJSONBase)
182
183         contJSONBase.GraphDriver.Name = container.Driver
184
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 {
190                 return nil, err
191         }
192         contJSONBase.GraphDriver.Data = graphDriverData
193
194         return contJSONBase, nil
195 }
196
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)
201         if err != nil {
202                 return nil, err
203         }
204
205         pc := inspectExecProcessConfig(e)
206
207         return &backend.ExecInspect{
208                 ID:            e.ID,
209                 Running:       e.Running,
210                 ExitCode:      e.ExitCode,
211                 ProcessConfig: pc,
212                 OpenStdin:     e.OpenStdin,
213                 OpenStdout:    e.OpenStdout,
214                 OpenStderr:    e.OpenStderr,
215                 CanRemove:     e.CanRemove,
216                 ContainerID:   e.ContainerID,
217                 DetachKeys:    e.DetachKeys,
218                 Pid:           e.Pid,
219         }, nil
220 }
221
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)
226         if err != nil {
227                 return nil, err
228         }
229         apiV := volumeToAPIType(v)
230         apiV.Mountpoint = v.Path()
231         apiV.Status = v.Status()
232         return apiV, nil
233 }
234
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,
247                 },
248                 DefaultNetworkSettings: daemon.getDefaultNetworkSettings(settings.Networks),
249         }
250
251         return result
252 }
253
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
258
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
268         }
269         return settings
270 }