github.com/adityamillind98/moby@v23.0.0-rc.4+incompatible/daemon/info.go (about)

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