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