github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/daemon/inspect.go (about) 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 := addMountPoints(container) 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 := addMountPoints(container) 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 MountLabel: container.MountLabel, 174 ProcessLabel: container.ProcessLabel, 175 ExecIDs: container.GetExecIDs(), 176 HostConfig: &hostConfig, 177 } 178 179 // Now set any platform-specific fields 180 contJSONBase = setPlatformSpecificContainerFields(container, contJSONBase) 181 182 contJSONBase.GraphDriver.Name = container.Driver 183 184 graphDriverData, err := container.RWLayer.Metadata() 185 // If container is marked as Dead, the container's graphdriver metadata 186 // could have been removed, it will cause error if we try to get the metadata, 187 // we can ignore the error if the container is dead. 188 if err != nil && !container.Dead { 189 return nil, err 190 } 191 contJSONBase.GraphDriver.Data = graphDriverData 192 193 return contJSONBase, nil 194 } 195 196 // ContainerExecInspect returns low-level information about the exec 197 // command. An error is returned if the exec cannot be found. 198 func (daemon *Daemon) ContainerExecInspect(id string) (*backend.ExecInspect, error) { 199 e, err := daemon.getExecConfig(id) 200 if err != nil { 201 return nil, err 202 } 203 204 pc := inspectExecProcessConfig(e) 205 206 return &backend.ExecInspect{ 207 ID: e.ID, 208 Running: e.Running, 209 ExitCode: e.ExitCode, 210 ProcessConfig: pc, 211 OpenStdin: e.OpenStdin, 212 OpenStdout: e.OpenStdout, 213 OpenStderr: e.OpenStderr, 214 CanRemove: e.CanRemove, 215 ContainerID: e.ContainerID, 216 DetachKeys: e.DetachKeys, 217 Pid: e.Pid, 218 }, nil 219 } 220 221 // VolumeInspect looks up a volume by name. An error is returned if 222 // the volume cannot be found. 223 func (daemon *Daemon) VolumeInspect(name string) (*types.Volume, error) { 224 v, err := daemon.volumes.Get(name) 225 if err != nil { 226 return nil, err 227 } 228 apiV := volumeToAPIType(v) 229 apiV.Mountpoint = v.Path() 230 apiV.Status = v.Status() 231 return apiV, nil 232 } 233 234 func (daemon *Daemon) getBackwardsCompatibleNetworkSettings(settings *network.Settings) *v1p20.NetworkSettings { 235 result := &v1p20.NetworkSettings{ 236 NetworkSettingsBase: types.NetworkSettingsBase{ 237 Bridge: settings.Bridge, 238 SandboxID: settings.SandboxID, 239 HairpinMode: settings.HairpinMode, 240 LinkLocalIPv6Address: settings.LinkLocalIPv6Address, 241 LinkLocalIPv6PrefixLen: settings.LinkLocalIPv6PrefixLen, 242 Ports: settings.Ports, 243 SandboxKey: settings.SandboxKey, 244 SecondaryIPAddresses: settings.SecondaryIPAddresses, 245 SecondaryIPv6Addresses: settings.SecondaryIPv6Addresses, 246 }, 247 DefaultNetworkSettings: daemon.getDefaultNetworkSettings(settings.Networks), 248 } 249 250 return result 251 } 252 253 // getDefaultNetworkSettings creates the deprecated structure that holds the information 254 // about the bridge network for a container. 255 func (daemon *Daemon) getDefaultNetworkSettings(networks map[string]*network.EndpointSettings) types.DefaultNetworkSettings { 256 var settings types.DefaultNetworkSettings 257 258 if defaultNetwork, ok := networks["bridge"]; ok && defaultNetwork.EndpointSettings != nil { 259 settings.EndpointID = defaultNetwork.EndpointID 260 settings.Gateway = defaultNetwork.Gateway 261 settings.GlobalIPv6Address = defaultNetwork.GlobalIPv6Address 262 settings.GlobalIPv6PrefixLen = defaultNetwork.GlobalIPv6PrefixLen 263 settings.IPAddress = defaultNetwork.IPAddress 264 settings.IPPrefixLen = defaultNetwork.IPPrefixLen 265 settings.IPv6Gateway = defaultNetwork.IPv6Gateway 266 settings.MacAddress = defaultNetwork.MacAddress 267 } 268 return settings 269 }