github.com/afbjorklund/moby@v20.10.5+incompatible/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 var ds [][2]string 147 drivers := "" 148 statuses := daemon.imageService.LayerStoreStatus() 149 for os, gd := range daemon.graphDrivers { 150 ds = append(ds, statuses[os]...) 151 drivers += gd 152 if len(daemon.graphDrivers) > 1 { 153 drivers += fmt.Sprintf(" (%s) ", os) 154 } 155 switch gd { 156 case "aufs", "devicemapper", "overlay": 157 v.Warnings = append(v.Warnings, fmt.Sprintf("WARNING: the %s storage-driver is deprecated, and will be removed in a future release.", gd)) 158 } 159 } 160 drivers = strings.TrimSpace(drivers) 161 162 v.Driver = drivers 163 v.DriverStatus = ds 164 165 fillDriverWarnings(v) 166 } 167 168 func (daemon *Daemon) fillPluginsInfo(v *types.Info) { 169 v.Plugins = types.PluginsInfo{ 170 Volume: daemon.volumes.GetDriverList(), 171 Network: daemon.GetNetworkDriverList(), 172 173 // The authorization plugins are returned in the order they are 174 // used as they constitute a request/response modification chain. 175 Authorization: daemon.configStore.AuthorizationPlugins, 176 Log: logger.ListDrivers(), 177 } 178 } 179 180 func (daemon *Daemon) fillSecurityOptions(v *types.Info, sysInfo *sysinfo.SysInfo) { 181 var securityOptions []string 182 if sysInfo.AppArmor { 183 securityOptions = append(securityOptions, "name=apparmor") 184 } 185 if sysInfo.Seccomp && supportsSeccomp { 186 profile := daemon.seccompProfilePath 187 if profile == "" { 188 profile = "default" 189 } 190 securityOptions = append(securityOptions, fmt.Sprintf("name=seccomp,profile=%s", profile)) 191 } 192 if selinux.GetEnabled() { 193 securityOptions = append(securityOptions, "name=selinux") 194 } 195 if rootIDs := daemon.idMapping.RootPair(); rootIDs.UID != 0 || rootIDs.GID != 0 { 196 securityOptions = append(securityOptions, "name=userns") 197 } 198 if daemon.Rootless() { 199 securityOptions = append(securityOptions, "name=rootless") 200 } 201 if daemon.cgroupNamespacesEnabled(sysInfo) { 202 securityOptions = append(securityOptions, "name=cgroupns") 203 } 204 205 v.SecurityOptions = securityOptions 206 } 207 208 func (daemon *Daemon) fillAPIInfo(v *types.Info) { 209 const warn string = ` 210 Access to the remote API is equivalent to root access on the host. Refer 211 to the 'Docker daemon attack surface' section in the documentation for 212 more information: https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface` 213 214 cfg := daemon.configStore 215 for _, host := range cfg.Hosts { 216 // cnf.Hosts is normalized during startup, so should always have a scheme/proto 217 h := strings.SplitN(host, "://", 2) 218 proto := h[0] 219 addr := h[1] 220 if proto != "tcp" { 221 continue 222 } 223 if cfg.TLS == nil || !*cfg.TLS { 224 v.Warnings = append(v.Warnings, fmt.Sprintf("WARNING: API is accessible on http://%s without encryption.%s", addr, warn)) 225 continue 226 } 227 if cfg.TLSVerify == nil || !*cfg.TLSVerify { 228 v.Warnings = append(v.Warnings, fmt.Sprintf("WARNING: API is accessible on https://%s without TLS client verification.%s", addr, warn)) 229 continue 230 } 231 } 232 } 233 234 func (daemon *Daemon) fillDefaultAddressPools(v *types.Info) { 235 for _, pool := range daemon.configStore.DefaultAddressPools.Value() { 236 v.DefaultAddressPools = append(v.DefaultAddressPools, types.NetworkAddressPool{ 237 Base: pool.Base, 238 Size: pool.Size, 239 }) 240 } 241 } 242 243 func hostName() string { 244 hostname := "" 245 if hn, err := os.Hostname(); err != nil { 246 logrus.Warnf("Could not get hostname: %v", err) 247 } else { 248 hostname = hn 249 } 250 return hostname 251 } 252 253 func kernelVersion() string { 254 var kernelVersion string 255 if kv, err := kernel.GetKernelVersion(); err != nil { 256 logrus.Warnf("Could not get kernel version: %v", err) 257 } else { 258 kernelVersion = kv.String() 259 } 260 return kernelVersion 261 } 262 263 func memInfo() *system.MemInfo { 264 memInfo, err := system.ReadMemInfo() 265 if err != nil { 266 logrus.Errorf("Could not read system memory info: %v", err) 267 memInfo = &system.MemInfo{} 268 } 269 return memInfo 270 } 271 272 func operatingSystem() (operatingSystem string) { 273 defer metrics.StartTimer(hostInfoFunctions.WithValues("operating_system"))() 274 275 if s, err := operatingsystem.GetOperatingSystem(); err != nil { 276 logrus.Warnf("Could not get operating system name: %v", err) 277 } else { 278 operatingSystem = s 279 } 280 // Don't do containerized check on Windows 281 if runtime.GOOS != "windows" { 282 if inContainer, err := operatingsystem.IsContainerized(); err != nil { 283 logrus.Errorf("Could not determine if daemon is containerized: %v", err) 284 operatingSystem += " (error determining if containerized)" 285 } else if inContainer { 286 operatingSystem += " (containerized)" 287 } 288 } 289 290 return operatingSystem 291 } 292 293 func osVersion() (version string) { 294 defer metrics.StartTimer(hostInfoFunctions.WithValues("os_version"))() 295 296 version, err := operatingsystem.GetOperatingSystemVersion() 297 if err != nil { 298 logrus.Warnf("Could not get operating system version: %v", err) 299 } 300 301 return version 302 } 303 304 func maskCredentials(rawURL string) string { 305 parsedURL, err := url.Parse(rawURL) 306 if err != nil || parsedURL.User == nil { 307 return rawURL 308 } 309 parsedURL.User = url.UserPassword("xxxxx", "xxxxx") 310 maskedURL := parsedURL.String() 311 return maskedURL 312 } 313 314 func getEnvAny(names ...string) string { 315 for _, n := range names { 316 if val := os.Getenv(n); val != "" { 317 return val 318 } 319 } 320 return "" 321 }