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