github.com/portworx/docker@v1.12.1/daemon/inspect.go (about) 1 package daemon 2 3 import ( 4 "fmt" 5 "time" 6 7 "github.com/docker/docker/api/types/backend" 8 "github.com/docker/docker/container" 9 "github.com/docker/docker/daemon/network" 10 "github.com/docker/engine-api/types" 11 networktypes "github.com/docker/engine-api/types/network" 12 "github.com/docker/engine-api/types/versions" 13 "github.com/docker/engine-api/types/versions/v1p20" 14 ) 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 29 // ContainerInspectCurrent returns low-level information about a 30 // container in a most recent api version. 31 func (daemon *Daemon) ContainerInspectCurrent(name string, size bool) (*types.ContainerJSON, error) { 32 container, err := daemon.GetContainer(name) 33 if err != nil { 34 return nil, err 35 } 36 37 container.Lock() 38 defer container.Unlock() 39 40 base, err := daemon.getInspectData(container, size) 41 if err != nil { 42 return nil, err 43 } 44 45 mountPoints := addMountPoints(container) 46 networkSettings := &types.NetworkSettings{ 47 NetworkSettingsBase: types.NetworkSettingsBase{ 48 Bridge: container.NetworkSettings.Bridge, 49 SandboxID: container.NetworkSettings.SandboxID, 50 HairpinMode: container.NetworkSettings.HairpinMode, 51 LinkLocalIPv6Address: container.NetworkSettings.LinkLocalIPv6Address, 52 LinkLocalIPv6PrefixLen: container.NetworkSettings.LinkLocalIPv6PrefixLen, 53 Ports: container.NetworkSettings.Ports, 54 SandboxKey: container.NetworkSettings.SandboxKey, 55 SecondaryIPAddresses: container.NetworkSettings.SecondaryIPAddresses, 56 SecondaryIPv6Addresses: container.NetworkSettings.SecondaryIPv6Addresses, 57 }, 58 DefaultNetworkSettings: daemon.getDefaultNetworkSettings(container.NetworkSettings.Networks), 59 Networks: container.NetworkSettings.Networks, 60 } 61 62 return &types.ContainerJSON{ 63 ContainerJSONBase: base, 64 Mounts: mountPoints, 65 Config: container.Config, 66 NetworkSettings: networkSettings, 67 }, nil 68 } 69 70 // containerInspect120 serializes the master version of a container into a json type. 71 func (daemon *Daemon) containerInspect120(name string) (*v1p20.ContainerJSON, error) { 72 container, err := daemon.GetContainer(name) 73 if err != nil { 74 return nil, err 75 } 76 77 container.Lock() 78 defer container.Unlock() 79 80 base, err := daemon.getInspectData(container, false) 81 if err != nil { 82 return nil, err 83 } 84 85 mountPoints := addMountPoints(container) 86 config := &v1p20.ContainerConfig{ 87 Config: container.Config, 88 MacAddress: container.Config.MacAddress, 89 NetworkDisabled: container.Config.NetworkDisabled, 90 ExposedPorts: container.Config.ExposedPorts, 91 VolumeDriver: container.HostConfig.VolumeDriver, 92 } 93 networkSettings := daemon.getBackwardsCompatibleNetworkSettings(container.NetworkSettings) 94 95 return &v1p20.ContainerJSON{ 96 ContainerJSONBase: base, 97 Mounts: mountPoints, 98 Config: config, 99 NetworkSettings: networkSettings, 100 }, nil 101 } 102 103 func (daemon *Daemon) getInspectData(container *container.Container, size bool) (*types.ContainerJSONBase, error) { 104 // make a copy to play with 105 hostConfig := *container.HostConfig 106 107 children := daemon.children(container) 108 hostConfig.Links = nil // do not expose the internal structure 109 for linkAlias, child := range children { 110 hostConfig.Links = append(hostConfig.Links, fmt.Sprintf("%s:%s", child.Name, linkAlias)) 111 } 112 113 var containerHealth *types.Health 114 if container.State.Health != nil { 115 containerHealth = &types.Health{ 116 Status: container.State.Health.Status, 117 FailingStreak: container.State.Health.FailingStreak, 118 Log: append([]*types.HealthcheckResult{}, container.State.Health.Log...), 119 } 120 } 121 122 containerState := &types.ContainerState{ 123 Status: container.State.StateString(), 124 Running: container.State.Running, 125 Paused: container.State.Paused, 126 Restarting: container.State.Restarting, 127 OOMKilled: container.State.OOMKilled, 128 Dead: container.State.Dead, 129 Pid: container.State.Pid, 130 ExitCode: container.State.ExitCode(), 131 Error: container.State.Error(), 132 StartedAt: container.State.StartedAt.Format(time.RFC3339Nano), 133 FinishedAt: container.State.FinishedAt.Format(time.RFC3339Nano), 134 Health: containerHealth, 135 } 136 137 contJSONBase := &types.ContainerJSONBase{ 138 ID: container.ID, 139 Created: container.Created.Format(time.RFC3339Nano), 140 Path: container.Path, 141 Args: container.Args, 142 State: containerState, 143 Image: container.ImageID.String(), 144 LogPath: container.LogPath, 145 Name: container.Name, 146 RestartCount: container.RestartCount, 147 Driver: container.Driver, 148 MountLabel: container.MountLabel, 149 ProcessLabel: container.ProcessLabel, 150 ExecIDs: container.GetExecIDs(), 151 HostConfig: &hostConfig, 152 } 153 154 var ( 155 sizeRw int64 156 sizeRootFs int64 157 ) 158 if size { 159 sizeRw, sizeRootFs = daemon.getSize(container) 160 contJSONBase.SizeRw = &sizeRw 161 contJSONBase.SizeRootFs = &sizeRootFs 162 } 163 164 // Now set any platform-specific fields 165 contJSONBase = setPlatformSpecificContainerFields(container, contJSONBase) 166 167 contJSONBase.GraphDriver.Name = container.Driver 168 169 graphDriverData, err := container.RWLayer.Metadata() 170 if err != nil { 171 return nil, err 172 } 173 contJSONBase.GraphDriver.Data = graphDriverData 174 175 return contJSONBase, nil 176 } 177 178 // ContainerExecInspect returns low-level information about the exec 179 // command. An error is returned if the exec cannot be found. 180 func (daemon *Daemon) ContainerExecInspect(id string) (*backend.ExecInspect, error) { 181 e, err := daemon.getExecConfig(id) 182 if err != nil { 183 return nil, err 184 } 185 186 pc := inspectExecProcessConfig(e) 187 188 return &backend.ExecInspect{ 189 ID: e.ID, 190 Running: e.Running, 191 ExitCode: e.ExitCode, 192 ProcessConfig: pc, 193 OpenStdin: e.OpenStdin, 194 OpenStdout: e.OpenStdout, 195 OpenStderr: e.OpenStderr, 196 CanRemove: e.CanRemove, 197 ContainerID: e.ContainerID, 198 DetachKeys: e.DetachKeys, 199 }, nil 200 } 201 202 // VolumeInspect looks up a volume by name. An error is returned if 203 // the volume cannot be found. 204 func (daemon *Daemon) VolumeInspect(name string) (*types.Volume, error) { 205 v, err := daemon.volumes.Get(name) 206 if err != nil { 207 return nil, err 208 } 209 apiV := volumeToAPIType(v) 210 apiV.Mountpoint = v.Path() 211 apiV.Status = v.Status() 212 return apiV, nil 213 } 214 215 func (daemon *Daemon) getBackwardsCompatibleNetworkSettings(settings *network.Settings) *v1p20.NetworkSettings { 216 result := &v1p20.NetworkSettings{ 217 NetworkSettingsBase: types.NetworkSettingsBase{ 218 Bridge: settings.Bridge, 219 SandboxID: settings.SandboxID, 220 HairpinMode: settings.HairpinMode, 221 LinkLocalIPv6Address: settings.LinkLocalIPv6Address, 222 LinkLocalIPv6PrefixLen: settings.LinkLocalIPv6PrefixLen, 223 Ports: settings.Ports, 224 SandboxKey: settings.SandboxKey, 225 SecondaryIPAddresses: settings.SecondaryIPAddresses, 226 SecondaryIPv6Addresses: settings.SecondaryIPv6Addresses, 227 }, 228 DefaultNetworkSettings: daemon.getDefaultNetworkSettings(settings.Networks), 229 } 230 231 return result 232 } 233 234 // getDefaultNetworkSettings creates the deprecated structure that holds the information 235 // about the bridge network for a container. 236 func (daemon *Daemon) getDefaultNetworkSettings(networks map[string]*networktypes.EndpointSettings) types.DefaultNetworkSettings { 237 var settings types.DefaultNetworkSettings 238 239 if defaultNetwork, ok := networks["bridge"]; ok { 240 settings.EndpointID = defaultNetwork.EndpointID 241 settings.Gateway = defaultNetwork.Gateway 242 settings.GlobalIPv6Address = defaultNetwork.GlobalIPv6Address 243 settings.GlobalIPv6PrefixLen = defaultNetwork.GlobalIPv6PrefixLen 244 settings.IPAddress = defaultNetwork.IPAddress 245 settings.IPPrefixLen = defaultNetwork.IPPrefixLen 246 settings.IPv6Gateway = defaultNetwork.IPv6Gateway 247 settings.MacAddress = defaultNetwork.MacAddress 248 } 249 return settings 250 }