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