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  }