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  }