github.com/jfrazelle/docker@v1.1.2-0.20210712172922-bf78e25fe508/daemon/info.go (about) 1 package daemon // import "github.com/docker/docker/daemon" 2 3 import ( 4 "fmt" 5 "net/url" 6 "os" 7 "runtime" 8 "strings" 9 "time" 10 11 "github.com/docker/docker/api" 12 "github.com/docker/docker/api/types" 13 "github.com/docker/docker/cli/debug" 14 "github.com/docker/docker/daemon/config" 15 "github.com/docker/docker/daemon/logger" 16 "github.com/docker/docker/dockerversion" 17 "github.com/docker/docker/pkg/fileutils" 18 "github.com/docker/docker/pkg/parsers/kernel" 19 "github.com/docker/docker/pkg/parsers/operatingsystem" 20 "github.com/docker/docker/pkg/platform" 21 "github.com/docker/docker/pkg/sysinfo" 22 "github.com/docker/docker/pkg/system" 23 "github.com/docker/docker/registry" 24 metrics "github.com/docker/go-metrics" 25 "github.com/opencontainers/selinux/go-selinux" 26 "github.com/sirupsen/logrus" 27 ) 28 29 // SystemInfo returns information about the host server the daemon is running on. 30 func (daemon *Daemon) SystemInfo() *types.Info { 31 defer metrics.StartTimer(hostInfoFunctions.WithValues("system_info"))() 32 33 sysInfo := daemon.RawSysInfo(true) 34 cRunning, cPaused, cStopped := stateCtr.get() 35 36 v := &types.Info{ 37 ID: daemon.ID, 38 Containers: cRunning + cPaused + cStopped, 39 ContainersRunning: cRunning, 40 ContainersPaused: cPaused, 41 ContainersStopped: cStopped, 42 Images: daemon.imageService.CountImages(), 43 IPv4Forwarding: !sysInfo.IPv4ForwardingDisabled, 44 BridgeNfIptables: !sysInfo.BridgeNFCallIPTablesDisabled, 45 BridgeNfIP6tables: !sysInfo.BridgeNFCallIP6TablesDisabled, 46 Debug: debug.IsEnabled(), 47 Name: hostName(), 48 NFd: fileutils.GetTotalUsedFds(), 49 NGoroutines: runtime.NumGoroutine(), 50 SystemTime: time.Now().Format(time.RFC3339Nano), 51 LoggingDriver: daemon.defaultLogConfig.Type, 52 NEventsListener: daemon.EventsService.SubscribersCount(), 53 KernelVersion: kernelVersion(), 54 OperatingSystem: operatingSystem(), 55 OSVersion: osVersion(), 56 IndexServerAddress: registry.IndexServer, 57 OSType: platform.OSType, 58 Architecture: platform.Architecture, 59 RegistryConfig: daemon.RegistryService.ServiceConfig(), 60 NCPU: sysinfo.NumCPU(), 61 MemTotal: memInfo().MemTotal, 62 GenericResources: daemon.genericResources, 63 DockerRootDir: daemon.configStore.Root, 64 Labels: daemon.configStore.Labels, 65 ExperimentalBuild: daemon.configStore.Experimental, 66 ServerVersion: dockerversion.Version, 67 HTTPProxy: maskCredentials(getEnvAny("HTTP_PROXY", "http_proxy")), 68 HTTPSProxy: maskCredentials(getEnvAny("HTTPS_PROXY", "https_proxy")), 69 NoProxy: getEnvAny("NO_PROXY", "no_proxy"), 70 LiveRestoreEnabled: daemon.configStore.LiveRestoreEnabled, 71 Isolation: daemon.defaultIsolation, 72 } 73 74 daemon.fillClusterInfo(v) 75 daemon.fillAPIInfo(v) 76 // Retrieve platform specific info 77 daemon.fillPlatformInfo(v, sysInfo) 78 daemon.fillDriverInfo(v) 79 daemon.fillPluginsInfo(v) 80 daemon.fillSecurityOptions(v, sysInfo) 81 daemon.fillLicense(v) 82 daemon.fillDefaultAddressPools(v) 83 84 if v.DefaultRuntime == config.LinuxV1RuntimeName { 85 v.Warnings = append(v.Warnings, fmt.Sprintf("Configured default runtime %q is deprecated and will be removed in the next release.", config.LinuxV1RuntimeName)) 86 } 87 88 return v 89 } 90 91 // SystemVersion returns version information about the daemon. 92 func (daemon *Daemon) SystemVersion() types.Version { 93 defer metrics.StartTimer(hostInfoFunctions.WithValues("system_version"))() 94 95 kernelVersion := kernelVersion() 96 97 v := types.Version{ 98 Components: []types.ComponentVersion{ 99 { 100 Name: "Engine", 101 Version: dockerversion.Version, 102 Details: map[string]string{ 103 "GitCommit": dockerversion.GitCommit, 104 "ApiVersion": api.DefaultVersion, 105 "MinAPIVersion": api.MinVersion, 106 "GoVersion": runtime.Version(), 107 "Os": runtime.GOOS, 108 "Arch": runtime.GOARCH, 109 "BuildTime": dockerversion.BuildTime, 110 "KernelVersion": kernelVersion, 111 "Experimental": fmt.Sprintf("%t", daemon.configStore.Experimental), 112 }, 113 }, 114 }, 115 116 // Populate deprecated fields for older clients 117 Version: dockerversion.Version, 118 GitCommit: dockerversion.GitCommit, 119 APIVersion: api.DefaultVersion, 120 MinAPIVersion: api.MinVersion, 121 GoVersion: runtime.Version(), 122 Os: runtime.GOOS, 123 Arch: runtime.GOARCH, 124 BuildTime: dockerversion.BuildTime, 125 KernelVersion: kernelVersion, 126 Experimental: daemon.configStore.Experimental, 127 } 128 129 v.Platform.Name = dockerversion.PlatformName 130 131 daemon.fillPlatformVersion(&v) 132 return v 133 } 134 135 func (daemon *Daemon) fillClusterInfo(v *types.Info) { 136 v.ClusterAdvertise = daemon.configStore.ClusterAdvertise 137 v.ClusterStore = daemon.configStore.ClusterStore 138 139 if v.ClusterAdvertise != "" || v.ClusterStore != "" { 140 v.Warnings = append(v.Warnings, `WARNING: node discovery and overlay networks with an external k/v store (cluster-advertise, 141 cluster-store, cluster-store-opt) are deprecated and will be removed in a future release.`) 142 } 143 } 144 145 func (daemon *Daemon) fillDriverInfo(v *types.Info) { 146 switch daemon.graphDriver { 147 case "aufs", "devicemapper", "overlay": 148 v.Warnings = append(v.Warnings, fmt.Sprintf("WARNING: the %s storage-driver is deprecated, and will be removed in a future release.", daemon.graphDriver)) 149 } 150 151 v.Driver = daemon.graphDriver 152 v.DriverStatus = daemon.imageService.LayerStoreStatus() 153 154 fillDriverWarnings(v) 155 } 156 157 func (daemon *Daemon) fillPluginsInfo(v *types.Info) { 158 v.Plugins = types.PluginsInfo{ 159 Volume: daemon.volumes.GetDriverList(), 160 Network: daemon.GetNetworkDriverList(), 161 162 // The authorization plugins are returned in the order they are 163 // used as they constitute a request/response modification chain. 164 Authorization: daemon.configStore.AuthorizationPlugins, 165 Log: logger.ListDrivers(), 166 } 167 } 168 169 func (daemon *Daemon) fillSecurityOptions(v *types.Info, sysInfo *sysinfo.SysInfo) { 170 var securityOptions []string 171 if sysInfo.AppArmor { 172 securityOptions = append(securityOptions, "name=apparmor") 173 } 174 if sysInfo.Seccomp && supportsSeccomp { 175 profile := daemon.seccompProfilePath 176 if profile == "" { 177 profile = "default" 178 } 179 securityOptions = append(securityOptions, fmt.Sprintf("name=seccomp,profile=%s", profile)) 180 } 181 if selinux.GetEnabled() { 182 securityOptions = append(securityOptions, "name=selinux") 183 } 184 if rootIDs := daemon.idMapping.RootPair(); rootIDs.UID != 0 || rootIDs.GID != 0 { 185 securityOptions = append(securityOptions, "name=userns") 186 } 187 if daemon.Rootless() { 188 securityOptions = append(securityOptions, "name=rootless") 189 } 190 if daemon.cgroupNamespacesEnabled(sysInfo) { 191 securityOptions = append(securityOptions, "name=cgroupns") 192 } 193 194 v.SecurityOptions = securityOptions 195 } 196 197 func (daemon *Daemon) fillAPIInfo(v *types.Info) { 198 const warn string = ` 199 Access to the remote API is equivalent to root access on the host. Refer 200 to the 'Docker daemon attack surface' section in the documentation for 201 more information: https://docs.docker.com/go/attack-surface/` 202 203 cfg := daemon.configStore 204 for _, host := range cfg.Hosts { 205 // cnf.Hosts is normalized during startup, so should always have a scheme/proto 206 h := strings.SplitN(host, "://", 2) 207 proto := h[0] 208 addr := h[1] 209 if proto != "tcp" { 210 continue 211 } 212 if cfg.TLS == nil || !*cfg.TLS { 213 v.Warnings = append(v.Warnings, fmt.Sprintf("WARNING: API is accessible on http://%s without encryption.%s", addr, warn)) 214 continue 215 } 216 if cfg.TLSVerify == nil || !*cfg.TLSVerify { 217 v.Warnings = append(v.Warnings, fmt.Sprintf("WARNING: API is accessible on https://%s without TLS client verification.%s", addr, warn)) 218 continue 219 } 220 } 221 } 222 223 func (daemon *Daemon) fillDefaultAddressPools(v *types.Info) { 224 for _, pool := range daemon.configStore.DefaultAddressPools.Value() { 225 v.DefaultAddressPools = append(v.DefaultAddressPools, types.NetworkAddressPool{ 226 Base: pool.Base, 227 Size: pool.Size, 228 }) 229 } 230 } 231 232 func hostName() string { 233 hostname := "" 234 if hn, err := os.Hostname(); err != nil { 235 logrus.Warnf("Could not get hostname: %v", err) 236 } else { 237 hostname = hn 238 } 239 return hostname 240 } 241 242 func kernelVersion() string { 243 var kernelVersion string 244 if kv, err := kernel.GetKernelVersion(); err != nil { 245 logrus.Warnf("Could not get kernel version: %v", err) 246 } else { 247 kernelVersion = kv.String() 248 } 249 return kernelVersion 250 } 251 252 func memInfo() *system.MemInfo { 253 memInfo, err := system.ReadMemInfo() 254 if err != nil { 255 logrus.Errorf("Could not read system memory info: %v", err) 256 memInfo = &system.MemInfo{} 257 } 258 return memInfo 259 } 260 261 func operatingSystem() (operatingSystem string) { 262 defer metrics.StartTimer(hostInfoFunctions.WithValues("operating_system"))() 263 264 if s, err := operatingsystem.GetOperatingSystem(); err != nil { 265 logrus.Warnf("Could not get operating system name: %v", err) 266 } else { 267 operatingSystem = s 268 } 269 // Don't do containerized check on Windows 270 if runtime.GOOS != "windows" { 271 if inContainer, err := operatingsystem.IsContainerized(); err != nil { 272 logrus.Errorf("Could not determine if daemon is containerized: %v", err) 273 operatingSystem += " (error determining if containerized)" 274 } else if inContainer { 275 operatingSystem += " (containerized)" 276 } 277 } 278 279 return operatingSystem 280 } 281 282 func osVersion() (version string) { 283 defer metrics.StartTimer(hostInfoFunctions.WithValues("os_version"))() 284 285 version, err := operatingsystem.GetOperatingSystemVersion() 286 if err != nil { 287 logrus.Warnf("Could not get operating system version: %v", err) 288 } 289 290 return version 291 } 292 293 func maskCredentials(rawURL string) string { 294 parsedURL, err := url.Parse(rawURL) 295 if err != nil || parsedURL.User == nil { 296 return rawURL 297 } 298 parsedURL.User = url.UserPassword("xxxxx", "xxxxx") 299 maskedURL := parsedURL.String() 300 return maskedURL 301 } 302 303 func getEnvAny(names ...string) string { 304 for _, n := range names { 305 if val := os.Getenv(n); val != "" { 306 return val 307 } 308 } 309 return "" 310 }