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  }