info.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. package daemon // import "github.com/docker/docker/daemon"
  2. import (
  3. "fmt"
  4. "net/url"
  5. "os"
  6. "runtime"
  7. "strings"
  8. "time"
  9. "github.com/docker/docker/api"
  10. "github.com/docker/docker/api/types"
  11. "github.com/docker/docker/cli/debug"
  12. "github.com/docker/docker/daemon/logger"
  13. "github.com/docker/docker/dockerversion"
  14. "github.com/docker/docker/pkg/fileutils"
  15. "github.com/docker/docker/pkg/parsers/kernel"
  16. "github.com/docker/docker/pkg/parsers/operatingsystem"
  17. "github.com/docker/docker/pkg/platform"
  18. "github.com/docker/docker/pkg/sysinfo"
  19. "github.com/docker/docker/pkg/system"
  20. "github.com/docker/docker/registry"
  21. "github.com/docker/go-connections/sockets"
  22. "github.com/sirupsen/logrus"
  23. )
  24. // SystemInfo returns information about the host server the daemon is running on.
  25. func (daemon *Daemon) SystemInfo() (*types.Info, error) {
  26. sysInfo := sysinfo.New(true)
  27. cRunning, cPaused, cStopped := stateCtr.get()
  28. v := &types.Info{
  29. ID: daemon.ID,
  30. Containers: cRunning + cPaused + cStopped,
  31. ContainersRunning: cRunning,
  32. ContainersPaused: cPaused,
  33. ContainersStopped: cStopped,
  34. Images: daemon.imageService.CountImages(),
  35. IPv4Forwarding: !sysInfo.IPv4ForwardingDisabled,
  36. BridgeNfIptables: !sysInfo.BridgeNFCallIPTablesDisabled,
  37. BridgeNfIP6tables: !sysInfo.BridgeNFCallIP6TablesDisabled,
  38. Debug: debug.IsEnabled(),
  39. Name: hostName(),
  40. NFd: fileutils.GetTotalUsedFds(),
  41. NGoroutines: runtime.NumGoroutine(),
  42. SystemTime: time.Now().Format(time.RFC3339Nano),
  43. LoggingDriver: daemon.defaultLogConfig.Type,
  44. CgroupDriver: daemon.getCgroupDriver(),
  45. NEventsListener: daemon.EventsService.SubscribersCount(),
  46. KernelVersion: kernelVersion(),
  47. OperatingSystem: operatingSystem(),
  48. IndexServerAddress: registry.IndexServer,
  49. OSType: platform.OSType,
  50. Architecture: platform.Architecture,
  51. RegistryConfig: daemon.RegistryService.ServiceConfig(),
  52. NCPU: sysinfo.NumCPU(),
  53. MemTotal: memInfo().MemTotal,
  54. GenericResources: daemon.genericResources,
  55. DockerRootDir: daemon.configStore.Root,
  56. Labels: daemon.configStore.Labels,
  57. ExperimentalBuild: daemon.configStore.Experimental,
  58. ServerVersion: dockerversion.Version,
  59. ClusterStore: daemon.configStore.ClusterStore,
  60. ClusterAdvertise: daemon.configStore.ClusterAdvertise,
  61. HTTPProxy: maskCredentials(sockets.GetProxyEnv("http_proxy")),
  62. HTTPSProxy: maskCredentials(sockets.GetProxyEnv("https_proxy")),
  63. NoProxy: sockets.GetProxyEnv("no_proxy"),
  64. LiveRestoreEnabled: daemon.configStore.LiveRestoreEnabled,
  65. Isolation: daemon.defaultIsolation,
  66. }
  67. daemon.fillAPIInfo(v)
  68. // Retrieve platform specific info
  69. daemon.fillPlatformInfo(v, sysInfo)
  70. daemon.fillDriverInfo(v)
  71. daemon.fillPluginsInfo(v)
  72. daemon.fillSecurityOptions(v, sysInfo)
  73. daemon.fillLicense(v)
  74. return v, nil
  75. }
  76. // SystemVersion returns version information about the daemon.
  77. func (daemon *Daemon) SystemVersion() types.Version {
  78. kernelVersion := kernelVersion()
  79. v := types.Version{
  80. Components: []types.ComponentVersion{
  81. {
  82. Name: "Engine",
  83. Version: dockerversion.Version,
  84. Details: map[string]string{
  85. "GitCommit": dockerversion.GitCommit,
  86. "ApiVersion": api.DefaultVersion,
  87. "MinAPIVersion": api.MinVersion,
  88. "GoVersion": runtime.Version(),
  89. "Os": runtime.GOOS,
  90. "Arch": runtime.GOARCH,
  91. "BuildTime": dockerversion.BuildTime,
  92. "KernelVersion": kernelVersion,
  93. "Experimental": fmt.Sprintf("%t", daemon.configStore.Experimental),
  94. },
  95. },
  96. },
  97. // Populate deprecated fields for older clients
  98. Version: dockerversion.Version,
  99. GitCommit: dockerversion.GitCommit,
  100. APIVersion: api.DefaultVersion,
  101. MinAPIVersion: api.MinVersion,
  102. GoVersion: runtime.Version(),
  103. Os: runtime.GOOS,
  104. Arch: runtime.GOARCH,
  105. BuildTime: dockerversion.BuildTime,
  106. KernelVersion: kernelVersion,
  107. Experimental: daemon.configStore.Experimental,
  108. }
  109. v.Platform.Name = dockerversion.PlatformName
  110. return v
  111. }
  112. func (daemon *Daemon) fillDriverInfo(v *types.Info) {
  113. var ds [][2]string
  114. drivers := ""
  115. statuses := daemon.imageService.LayerStoreStatus()
  116. for os, gd := range daemon.graphDrivers {
  117. ds = append(ds, statuses[os]...)
  118. drivers += gd
  119. if len(daemon.graphDrivers) > 1 {
  120. drivers += fmt.Sprintf(" (%s) ", os)
  121. }
  122. switch gd {
  123. case "devicemapper", "overlay":
  124. v.Warnings = append(v.Warnings, fmt.Sprintf("WARNING: the %s storage-driver is deprecated, and will be removed in a future release.", gd))
  125. }
  126. }
  127. drivers = strings.TrimSpace(drivers)
  128. v.Driver = drivers
  129. v.DriverStatus = ds
  130. fillDriverWarnings(v)
  131. }
  132. func (daemon *Daemon) fillPluginsInfo(v *types.Info) {
  133. v.Plugins = types.PluginsInfo{
  134. Volume: daemon.volumes.GetDriverList(),
  135. Network: daemon.GetNetworkDriverList(),
  136. // The authorization plugins are returned in the order they are
  137. // used as they constitute a request/response modification chain.
  138. Authorization: daemon.configStore.AuthorizationPlugins,
  139. Log: logger.ListDrivers(),
  140. }
  141. }
  142. func (daemon *Daemon) fillSecurityOptions(v *types.Info, sysInfo *sysinfo.SysInfo) {
  143. var securityOptions []string
  144. if sysInfo.AppArmor {
  145. securityOptions = append(securityOptions, "name=apparmor")
  146. }
  147. if sysInfo.Seccomp && supportsSeccomp {
  148. profile := daemon.seccompProfilePath
  149. if profile == "" {
  150. profile = "default"
  151. }
  152. securityOptions = append(securityOptions, fmt.Sprintf("name=seccomp,profile=%s", profile))
  153. }
  154. if selinuxEnabled() {
  155. securityOptions = append(securityOptions, "name=selinux")
  156. }
  157. if rootIDs := daemon.idMapping.RootPair(); rootIDs.UID != 0 || rootIDs.GID != 0 {
  158. securityOptions = append(securityOptions, "name=userns")
  159. }
  160. v.SecurityOptions = securityOptions
  161. }
  162. func (daemon *Daemon) fillAPIInfo(v *types.Info) {
  163. const warn string = `
  164. Access to the remote API is equivalent to root access on the host. Refer
  165. to the 'Docker daemon attack surface' section in the documentation for
  166. more information: https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface`
  167. cfg := daemon.configStore
  168. for _, host := range cfg.Hosts {
  169. // cnf.Hosts is normalized during startup, so should always have a scheme/proto
  170. h := strings.SplitN(host, "://", 2)
  171. proto := h[0]
  172. addr := h[1]
  173. if proto != "tcp" {
  174. continue
  175. }
  176. if !cfg.TLS {
  177. v.Warnings = append(v.Warnings, fmt.Sprintf("WARNING: API is accessible on http://%s without encryption.%s", addr, warn))
  178. continue
  179. }
  180. if !cfg.TLSVerify {
  181. v.Warnings = append(v.Warnings, fmt.Sprintf("WARNING: API is accessible on https://%s without TLS client verification.%s", addr, warn))
  182. continue
  183. }
  184. }
  185. }
  186. func hostName() string {
  187. hostname := ""
  188. if hn, err := os.Hostname(); err != nil {
  189. logrus.Warnf("Could not get hostname: %v", err)
  190. } else {
  191. hostname = hn
  192. }
  193. return hostname
  194. }
  195. func kernelVersion() string {
  196. var kernelVersion string
  197. if kv, err := kernel.GetKernelVersion(); err != nil {
  198. logrus.Warnf("Could not get kernel version: %v", err)
  199. } else {
  200. kernelVersion = kv.String()
  201. }
  202. return kernelVersion
  203. }
  204. func memInfo() *system.MemInfo {
  205. memInfo, err := system.ReadMemInfo()
  206. if err != nil {
  207. logrus.Errorf("Could not read system memory info: %v", err)
  208. memInfo = &system.MemInfo{}
  209. }
  210. return memInfo
  211. }
  212. func operatingSystem() string {
  213. var operatingSystem string
  214. if s, err := operatingsystem.GetOperatingSystem(); err != nil {
  215. logrus.Warnf("Could not get operating system name: %v", err)
  216. } else {
  217. operatingSystem = s
  218. }
  219. // Don't do containerized check on Windows
  220. if runtime.GOOS != "windows" {
  221. if inContainer, err := operatingsystem.IsContainerized(); err != nil {
  222. logrus.Errorf("Could not determine if daemon is containerized: %v", err)
  223. operatingSystem += " (error determining if containerized)"
  224. } else if inContainer {
  225. operatingSystem += " (containerized)"
  226. }
  227. }
  228. return operatingSystem
  229. }
  230. func maskCredentials(rawURL string) string {
  231. parsedURL, err := url.Parse(rawURL)
  232. if err != nil || parsedURL.User == nil {
  233. return rawURL
  234. }
  235. parsedURL.User = url.UserPassword("xxxxx", "xxxxx")
  236. maskedURL := parsedURL.String()
  237. return maskedURL
  238. }