2018-02-05 21:05:59 +00:00
|
|
|
package daemon // import "github.com/docker/docker/daemon"
|
2014-08-08 03:01:55 +00:00
|
|
|
|
|
|
|
import (
|
2016-11-16 21:30:29 +00:00
|
|
|
"fmt"
|
2018-09-27 02:43:26 +00:00
|
|
|
"net/url"
|
2014-08-08 03:01:55 +00:00
|
|
|
"os"
|
|
|
|
"runtime"
|
2017-05-16 23:56:56 +00:00
|
|
|
"strings"
|
2015-03-10 18:25:47 +00:00
|
|
|
"time"
|
2014-08-08 03:01:55 +00:00
|
|
|
|
2016-11-02 17:04:39 +00:00
|
|
|
"github.com/docker/docker/api"
|
2016-09-06 18:18:12 +00:00
|
|
|
"github.com/docker/docker/api/types"
|
2016-12-12 08:33:58 +00:00
|
|
|
"github.com/docker/docker/cli/debug"
|
2017-04-11 21:21:21 +00:00
|
|
|
"github.com/docker/docker/daemon/logger"
|
2015-11-09 18:32:46 +00:00
|
|
|
"github.com/docker/docker/dockerversion"
|
2015-03-29 21:17:23 +00:00
|
|
|
"github.com/docker/docker/pkg/fileutils"
|
2014-08-08 03:01:55 +00:00
|
|
|
"github.com/docker/docker/pkg/parsers/kernel"
|
|
|
|
"github.com/docker/docker/pkg/parsers/operatingsystem"
|
2015-11-14 22:03:02 +00:00
|
|
|
"github.com/docker/docker/pkg/platform"
|
2015-08-06 11:54:48 +00:00
|
|
|
"github.com/docker/docker/pkg/sysinfo"
|
2014-10-24 22:48:23 +00:00
|
|
|
"github.com/docker/docker/pkg/system"
|
2014-08-08 03:01:55 +00:00
|
|
|
"github.com/docker/docker/registry"
|
2019-08-05 14:37:47 +00:00
|
|
|
metrics "github.com/docker/go-metrics"
|
2017-07-26 21:42:13 +00:00
|
|
|
"github.com/sirupsen/logrus"
|
2014-08-08 03:01:55 +00:00
|
|
|
)
|
|
|
|
|
2015-07-30 21:01:53 +00:00
|
|
|
// SystemInfo returns information about the host server the daemon is running on.
|
2015-09-29 17:51:40 +00:00
|
|
|
func (daemon *Daemon) SystemInfo() (*types.Info, error) {
|
2019-05-30 16:51:41 +00:00
|
|
|
defer metrics.StartTimer(hostInfoFunctions.WithValues("system_info"))()
|
|
|
|
|
2015-10-09 06:57:47 +00:00
|
|
|
sysInfo := sysinfo.New(true)
|
2017-02-10 02:57:35 +00:00
|
|
|
cRunning, cPaused, cStopped := stateCtr.get()
|
2015-10-27 20:12:33 +00:00
|
|
|
|
2016-11-16 21:30:29 +00:00
|
|
|
v := &types.Info{
|
2015-04-10 17:26:30 +00:00
|
|
|
ID: daemon.ID,
|
2017-08-24 17:11:44 +00:00
|
|
|
Containers: cRunning + cPaused + cStopped,
|
|
|
|
ContainersRunning: cRunning,
|
|
|
|
ContainersPaused: cPaused,
|
|
|
|
ContainersStopped: cStopped,
|
2018-02-02 22:18:46 +00:00
|
|
|
Images: daemon.imageService.CountImages(),
|
2015-08-06 11:54:48 +00:00
|
|
|
IPv4Forwarding: !sysInfo.IPv4ForwardingDisabled,
|
2016-02-26 18:47:43 +00:00
|
|
|
BridgeNfIptables: !sysInfo.BridgeNFCallIPTablesDisabled,
|
|
|
|
BridgeNfIP6tables: !sysInfo.BridgeNFCallIP6TablesDisabled,
|
2016-12-12 08:33:58 +00:00
|
|
|
Debug: debug.IsEnabled(),
|
2018-07-13 10:55:59 +00:00
|
|
|
Name: hostName(),
|
2015-04-10 17:26:30 +00:00
|
|
|
NFd: fileutils.GetTotalUsedFds(),
|
|
|
|
NGoroutines: runtime.NumGoroutine(),
|
|
|
|
SystemTime: time.Now().Format(time.RFC3339Nano),
|
|
|
|
LoggingDriver: daemon.defaultLogConfig.Type,
|
2016-02-18 10:10:31 +00:00
|
|
|
CgroupDriver: daemon.getCgroupDriver(),
|
2015-04-10 17:26:30 +00:00
|
|
|
NEventsListener: daemon.EventsService.SubscribersCount(),
|
2018-07-13 10:55:59 +00:00
|
|
|
KernelVersion: kernelVersion(),
|
|
|
|
OperatingSystem: operatingSystem(),
|
2019-05-30 16:51:41 +00:00
|
|
|
OSVersion: osVersion(),
|
2015-07-21 19:40:36 +00:00
|
|
|
IndexServerAddress: registry.IndexServer,
|
2015-11-14 22:03:02 +00:00
|
|
|
OSType: platform.OSType,
|
|
|
|
Architecture: platform.Architecture,
|
2016-03-08 21:03:37 +00:00
|
|
|
RegistryConfig: daemon.RegistryService.ServiceConfig(),
|
2016-06-25 14:26:00 +00:00
|
|
|
NCPU: sysinfo.NumCPU(),
|
2018-07-13 10:55:59 +00:00
|
|
|
MemTotal: memInfo().MemTotal,
|
2017-05-31 00:02:11 +00:00
|
|
|
GenericResources: daemon.genericResources,
|
2015-12-03 10:46:53 +00:00
|
|
|
DockerRootDir: daemon.configStore.Root,
|
|
|
|
Labels: daemon.configStore.Labels,
|
2016-10-06 14:09:54 +00:00
|
|
|
ExperimentalBuild: daemon.configStore.Experimental,
|
2015-11-09 18:32:46 +00:00
|
|
|
ServerVersion: dockerversion.Version,
|
2015-12-03 10:46:53 +00:00
|
|
|
ClusterStore: daemon.configStore.ClusterStore,
|
|
|
|
ClusterAdvertise: daemon.configStore.ClusterAdvertise,
|
2019-09-25 08:56:41 +00:00
|
|
|
HTTPProxy: maskCredentials(getEnvAny("HTTP_PROXY", "http_proxy")),
|
|
|
|
HTTPSProxy: maskCredentials(getEnvAny("HTTPS_PROXY", "https_proxy")),
|
|
|
|
NoProxy: getEnvAny("NO_PROXY", "no_proxy"),
|
2016-07-24 20:00:15 +00:00
|
|
|
LiveRestoreEnabled: daemon.configStore.LiveRestoreEnabled,
|
2016-09-07 22:10:00 +00:00
|
|
|
Isolation: daemon.defaultIsolation,
|
2015-04-10 17:26:30 +00:00
|
|
|
}
|
|
|
|
|
2018-08-21 12:06:06 +00:00
|
|
|
daemon.fillAPIInfo(v)
|
2016-11-11 16:02:23 +00:00
|
|
|
// Retrieve platform specific info
|
2018-07-13 11:14:45 +00:00
|
|
|
daemon.fillPlatformInfo(v, sysInfo)
|
2018-07-13 10:55:59 +00:00
|
|
|
daemon.fillDriverInfo(v)
|
|
|
|
daemon.fillPluginsInfo(v)
|
|
|
|
daemon.fillSecurityOptions(v, sysInfo)
|
2018-08-18 00:05:21 +00:00
|
|
|
daemon.fillLicense(v)
|
2015-04-10 17:26:30 +00:00
|
|
|
|
2016-11-16 21:30:29 +00:00
|
|
|
return v, nil
|
2014-08-08 03:01:55 +00:00
|
|
|
}
|
2015-10-23 06:08:26 +00:00
|
|
|
|
2015-12-03 18:11:19 +00:00
|
|
|
// SystemVersion returns version information about the daemon.
|
|
|
|
func (daemon *Daemon) SystemVersion() types.Version {
|
2019-05-30 16:51:41 +00:00
|
|
|
defer metrics.StartTimer(hostInfoFunctions.WithValues("system_version"))()
|
|
|
|
|
2018-07-13 10:55:59 +00:00
|
|
|
kernelVersion := kernelVersion()
|
2017-12-05 14:29:37 +00:00
|
|
|
|
2015-12-03 18:11:19 +00:00
|
|
|
v := types.Version{
|
2017-12-05 14:29:37 +00:00
|
|
|
Components: []types.ComponentVersion{
|
|
|
|
{
|
|
|
|
Name: "Engine",
|
|
|
|
Version: dockerversion.Version,
|
|
|
|
Details: map[string]string{
|
|
|
|
"GitCommit": dockerversion.GitCommit,
|
|
|
|
"ApiVersion": api.DefaultVersion,
|
|
|
|
"MinAPIVersion": api.MinVersion,
|
|
|
|
"GoVersion": runtime.Version(),
|
|
|
|
"Os": runtime.GOOS,
|
|
|
|
"Arch": runtime.GOARCH,
|
|
|
|
"BuildTime": dockerversion.BuildTime,
|
|
|
|
"KernelVersion": kernelVersion,
|
|
|
|
"Experimental": fmt.Sprintf("%t", daemon.configStore.Experimental),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
// Populate deprecated fields for older clients
|
2016-11-02 17:04:39 +00:00
|
|
|
Version: dockerversion.Version,
|
|
|
|
GitCommit: dockerversion.GitCommit,
|
2017-12-05 14:29:37 +00:00
|
|
|
APIVersion: api.DefaultVersion,
|
2016-11-02 17:04:39 +00:00
|
|
|
MinAPIVersion: api.MinVersion,
|
|
|
|
GoVersion: runtime.Version(),
|
|
|
|
Os: runtime.GOOS,
|
|
|
|
Arch: runtime.GOARCH,
|
|
|
|
BuildTime: dockerversion.BuildTime,
|
2017-12-05 14:29:37 +00:00
|
|
|
KernelVersion: kernelVersion,
|
2016-11-02 17:04:39 +00:00
|
|
|
Experimental: daemon.configStore.Experimental,
|
2015-12-03 18:11:19 +00:00
|
|
|
}
|
|
|
|
|
2017-12-05 14:29:37 +00:00
|
|
|
v.Platform.Name = dockerversion.PlatformName
|
2015-12-03 18:11:19 +00:00
|
|
|
|
Add containerd, runc, and docker-init versions to /version
This patch adds version information about the containerd,
runc, and docker-init components to the /version endpoint.
With this patch applied, running:
```
curl --unix-socket /var/run/docker.sock http://localhost/version | jq .
```
Will produce this response:
```json
{
"Platform": {
"Name": ""
},
"Components": [
{
"Name": "Engine",
"Version": "dev",
"Details": {
"ApiVersion": "1.40",
"Arch": "amd64",
"BuildTime": "2018-11-08T10:23:42.000000000+00:00",
"Experimental": "false",
"GitCommit": "7d02782d2f",
"GoVersion": "go1.11.2",
"KernelVersion": "4.9.93-linuxkit-aufs",
"MinAPIVersion": "1.12",
"Os": "linux"
}
},
{
"Name": "containerd",
"Version": "v1.1.4",
"Details": {
"GitCommit": "9f2e07b1fc1342d1c48fe4d7bbb94cb6d1bf278b"
}
},
{
"Name": "runc",
"Version": "1.0.0-rc5+dev",
"Details": {
"GitCommit": "a00bf0190895aa465a5fbed0268888e2c8ddfe85"
}
},
{
"Name": "docker-init",
"Version": "0.18.0",
"Details": {
"GitCommit": "fec3683"
}
}
],
"Version": "dev",
"ApiVersion": "1.40",
"MinAPIVersion": "1.12",
"GitCommit": "7d02782d2f",
"GoVersion": "go1.11.2",
"Os": "linux",
"Arch": "amd64",
"KernelVersion": "4.9.93-linuxkit-aufs",
"BuildTime": "2018-11-08T10:23:42.000000000+00:00"
}
```
When using a recent version of the CLI, that information is included in the
output of `docker version`:
```
Client: Docker Engine - Community
Version: 18.09.0
API version: 1.39
Go version: go1.10.4
Git commit: 4d60db4
Built: Wed Nov 7 00:46:51 2018
OS/Arch: linux/amd64
Experimental: false
Server:
Engine:
Version: dev
API version: 1.40 (minimum version 1.12)
Go version: go1.11.2
Git commit: 7d02782d2f
Built: Thu Nov 8 10:23:42 2018
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: v1.1.4
GitCommit: 9f2e07b1fc1342d1c48fe4d7bbb94cb6d1bf278b
runc:
Version: 1.0.0-rc5+dev
GitCommit: a00bf0190895aa465a5fbed0268888e2c8ddfe85
docker-init:
Version: 0.18.0
GitCommit: fec3683
```
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-05 10:30:10 +00:00
|
|
|
daemon.fillPlatformVersion(&v)
|
2015-12-03 18:11:19 +00:00
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
2018-07-13 10:55:59 +00:00
|
|
|
func (daemon *Daemon) fillDriverInfo(v *types.Info) {
|
|
|
|
var ds [][2]string
|
|
|
|
drivers := ""
|
|
|
|
statuses := daemon.imageService.LayerStoreStatus()
|
|
|
|
for os, gd := range daemon.graphDrivers {
|
|
|
|
ds = append(ds, statuses[os]...)
|
|
|
|
drivers += gd
|
|
|
|
if len(daemon.graphDrivers) > 1 {
|
|
|
|
drivers += fmt.Sprintf(" (%s) ", os)
|
|
|
|
}
|
2018-10-11 10:44:43 +00:00
|
|
|
switch gd {
|
2018-10-26 16:41:46 +00:00
|
|
|
case "aufs", "devicemapper", "overlay":
|
2018-10-11 10:44:43 +00:00
|
|
|
v.Warnings = append(v.Warnings, fmt.Sprintf("WARNING: the %s storage-driver is deprecated, and will be removed in a future release.", gd))
|
|
|
|
}
|
2018-07-13 10:55:59 +00:00
|
|
|
}
|
|
|
|
drivers = strings.TrimSpace(drivers)
|
2015-10-23 06:08:26 +00:00
|
|
|
|
2018-07-13 10:55:59 +00:00
|
|
|
v.Driver = drivers
|
|
|
|
v.DriverStatus = ds
|
2018-07-19 11:45:32 +00:00
|
|
|
|
|
|
|
fillDriverWarnings(v)
|
2018-07-13 10:55:59 +00:00
|
|
|
}
|
2015-12-29 21:10:23 +00:00
|
|
|
|
2018-07-13 10:55:59 +00:00
|
|
|
func (daemon *Daemon) fillPluginsInfo(v *types.Info) {
|
|
|
|
v.Plugins = types.PluginsInfo{
|
|
|
|
Volume: daemon.volumes.GetDriverList(),
|
|
|
|
Network: daemon.GetNetworkDriverList(),
|
|
|
|
|
|
|
|
// The authorization plugins are returned in the order they are
|
|
|
|
// used as they constitute a request/response modification chain.
|
|
|
|
Authorization: daemon.configStore.AuthorizationPlugins,
|
|
|
|
Log: logger.ListDrivers(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (daemon *Daemon) fillSecurityOptions(v *types.Info, sysInfo *sysinfo.SysInfo) {
|
|
|
|
var securityOptions []string
|
|
|
|
if sysInfo.AppArmor {
|
|
|
|
securityOptions = append(securityOptions, "name=apparmor")
|
|
|
|
}
|
|
|
|
if sysInfo.Seccomp && supportsSeccomp {
|
|
|
|
profile := daemon.seccompProfilePath
|
|
|
|
if profile == "" {
|
|
|
|
profile = "default"
|
|
|
|
}
|
|
|
|
securityOptions = append(securityOptions, fmt.Sprintf("name=seccomp,profile=%s", profile))
|
|
|
|
}
|
|
|
|
if selinuxEnabled() {
|
|
|
|
securityOptions = append(securityOptions, "name=selinux")
|
|
|
|
}
|
2017-11-16 06:20:33 +00:00
|
|
|
if rootIDs := daemon.idMapping.RootPair(); rootIDs.UID != 0 || rootIDs.GID != 0 {
|
2018-07-13 10:55:59 +00:00
|
|
|
securityOptions = append(securityOptions, "name=userns")
|
|
|
|
}
|
2019-02-28 08:12:55 +00:00
|
|
|
if daemon.Rootless() {
|
2018-10-15 07:52:53 +00:00
|
|
|
securityOptions = append(securityOptions, "name=rootless")
|
|
|
|
}
|
2019-03-15 03:44:18 +00:00
|
|
|
if daemon.cgroupNamespacesEnabled(sysInfo) {
|
|
|
|
securityOptions = append(securityOptions, "name=cgroupns")
|
|
|
|
}
|
|
|
|
|
2018-07-13 10:55:59 +00:00
|
|
|
v.SecurityOptions = securityOptions
|
|
|
|
}
|
|
|
|
|
2018-08-21 12:06:06 +00:00
|
|
|
func (daemon *Daemon) fillAPIInfo(v *types.Info) {
|
|
|
|
const warn string = `
|
|
|
|
Access to the remote API is equivalent to root access on the host. Refer
|
|
|
|
to the 'Docker daemon attack surface' section in the documentation for
|
|
|
|
more information: https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface`
|
|
|
|
|
|
|
|
cfg := daemon.configStore
|
|
|
|
for _, host := range cfg.Hosts {
|
|
|
|
// cnf.Hosts is normalized during startup, so should always have a scheme/proto
|
|
|
|
h := strings.SplitN(host, "://", 2)
|
|
|
|
proto := h[0]
|
|
|
|
addr := h[1]
|
|
|
|
if proto != "tcp" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if !cfg.TLS {
|
|
|
|
v.Warnings = append(v.Warnings, fmt.Sprintf("WARNING: API is accessible on http://%s without encryption.%s", addr, warn))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if !cfg.TLSVerify {
|
|
|
|
v.Warnings = append(v.Warnings, fmt.Sprintf("WARNING: API is accessible on https://%s without TLS client verification.%s", addr, warn))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-13 10:55:59 +00:00
|
|
|
func hostName() string {
|
|
|
|
hostname := ""
|
|
|
|
if hn, err := os.Hostname(); err != nil {
|
|
|
|
logrus.Warnf("Could not get hostname: %v", err)
|
|
|
|
} else {
|
|
|
|
hostname = hn
|
|
|
|
}
|
|
|
|
return hostname
|
|
|
|
}
|
|
|
|
|
|
|
|
func kernelVersion() string {
|
2018-07-16 14:07:47 +00:00
|
|
|
var kernelVersion string
|
2018-07-13 10:55:59 +00:00
|
|
|
if kv, err := kernel.GetKernelVersion(); err != nil {
|
|
|
|
logrus.Warnf("Could not get kernel version: %v", err)
|
|
|
|
} else {
|
|
|
|
kernelVersion = kv.String()
|
|
|
|
}
|
|
|
|
return kernelVersion
|
|
|
|
}
|
|
|
|
|
|
|
|
func memInfo() *system.MemInfo {
|
|
|
|
memInfo, err := system.ReadMemInfo()
|
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("Could not read system memory info: %v", err)
|
|
|
|
memInfo = &system.MemInfo{}
|
|
|
|
}
|
|
|
|
return memInfo
|
|
|
|
}
|
|
|
|
|
2019-05-30 16:51:41 +00:00
|
|
|
func operatingSystem() (operatingSystem string) {
|
|
|
|
defer metrics.StartTimer(hostInfoFunctions.WithValues("operating_system"))()
|
|
|
|
|
2018-07-13 10:55:59 +00:00
|
|
|
if s, err := operatingsystem.GetOperatingSystem(); err != nil {
|
|
|
|
logrus.Warnf("Could not get operating system name: %v", err)
|
|
|
|
} else {
|
|
|
|
operatingSystem = s
|
|
|
|
}
|
|
|
|
// Don't do containerized check on Windows
|
|
|
|
if runtime.GOOS != "windows" {
|
|
|
|
if inContainer, err := operatingsystem.IsContainerized(); err != nil {
|
|
|
|
logrus.Errorf("Could not determine if daemon is containerized: %v", err)
|
|
|
|
operatingSystem += " (error determining if containerized)"
|
|
|
|
} else if inContainer {
|
|
|
|
operatingSystem += " (containerized)"
|
|
|
|
}
|
|
|
|
}
|
2019-05-30 16:51:41 +00:00
|
|
|
|
2018-07-13 10:55:59 +00:00
|
|
|
return operatingSystem
|
2015-10-23 06:08:26 +00:00
|
|
|
}
|
2018-09-27 02:43:26 +00:00
|
|
|
|
2019-05-30 16:51:41 +00:00
|
|
|
func osVersion() (version string) {
|
|
|
|
defer metrics.StartTimer(hostInfoFunctions.WithValues("os_version"))()
|
|
|
|
|
|
|
|
version, err := operatingsystem.GetOperatingSystemVersion()
|
|
|
|
if err != nil {
|
|
|
|
logrus.Warnf("Could not get operating system version: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return version
|
|
|
|
}
|
|
|
|
|
2018-09-27 02:43:26 +00:00
|
|
|
func maskCredentials(rawURL string) string {
|
|
|
|
parsedURL, err := url.Parse(rawURL)
|
|
|
|
if err != nil || parsedURL.User == nil {
|
|
|
|
return rawURL
|
|
|
|
}
|
|
|
|
parsedURL.User = url.UserPassword("xxxxx", "xxxxx")
|
|
|
|
maskedURL := parsedURL.String()
|
|
|
|
return maskedURL
|
|
|
|
}
|
2019-09-25 08:56:41 +00:00
|
|
|
|
|
|
|
func getEnvAny(names ...string) string {
|
|
|
|
for _, n := range names {
|
|
|
|
if val := os.Getenv(n); val != "" {
|
|
|
|
return val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|