1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #42639 from thaJeztah/system_info_clean

pkg/sysinfo: assorted cleanup/refactoring for handling warnings and logging
This commit is contained in:
Justin Cormack 2021-07-19 15:17:07 +01:00 committed by GitHub
commit b337c70bdc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 185 additions and 237 deletions

View file

@ -212,6 +212,11 @@ type Info struct {
SecurityOptions []string SecurityOptions []string
ProductLicense string `json:",omitempty"` ProductLicense string `json:",omitempty"`
DefaultAddressPools []NetworkAddressPool `json:",omitempty"` DefaultAddressPools []NetworkAddressPool `json:",omitempty"`
// Warnings contains a slice of warnings that occurred while collecting
// system information. These warnings are intended to be informational
// messages for the user, and are not intended to be parsed / used for
// other purposes, as they do not have a fixed format.
Warnings []string Warnings []string
} }

View file

@ -478,14 +478,14 @@ func warnOnDeprecatedConfigOptions(config *config.Config) {
func initRouter(opts routerOptions) { func initRouter(opts routerOptions) {
decoder := runconfig.ContainerDecoder{ decoder := runconfig.ContainerDecoder{
GetSysInfo: func() *sysinfo.SysInfo { GetSysInfo: func() *sysinfo.SysInfo {
return opts.daemon.RawSysInfo(true) return opts.daemon.RawSysInfo()
}, },
} }
routers := []router.Router{ routers := []router.Router{
// we need to add the checkpoint router before the container router or the DELETE gets masked // we need to add the checkpoint router before the container router or the DELETE gets masked
checkpointrouter.NewRouter(opts.daemon, decoder), checkpointrouter.NewRouter(opts.daemon, decoder),
container.NewRouter(opts.daemon, decoder, opts.daemon.RawSysInfo(true).CgroupUnified), container.NewRouter(opts.daemon, decoder, opts.daemon.RawSysInfo().CgroupUnified),
image.NewRouter(opts.daemon.ImageService()), image.NewRouter(opts.daemon.ImageService()),
systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildkit, opts.features), systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildkit, opts.features),
volume.NewRouter(opts.daemon.VolumesService()), volume.NewRouter(opts.daemon.VolumesService()),

View file

@ -1050,7 +1050,10 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
return nil, err return nil, err
} }
sysInfo := d.RawSysInfo(false) sysInfo := d.RawSysInfo()
for _, w := range sysInfo.Warnings {
logrus.Warn(w)
}
// Check if Devices cgroup is mounted, it is hard requirement for container security, // Check if Devices cgroup is mounted, it is hard requirement for container security,
// on Linux. // on Linux.
if runtime.GOOS == "linux" && !sysInfo.CgroupDevicesEnabled && !userns.RunningInUserNS() { if runtime.GOOS == "linux" && !sysInfo.CgroupDevicesEnabled && !userns.RunningInUserNS() {

View file

@ -666,7 +666,7 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.
if hostConfig == nil { if hostConfig == nil {
return nil, nil return nil, nil
} }
sysInfo := daemon.RawSysInfo(true) sysInfo := daemon.RawSysInfo()
w, err := verifyPlatformContainerResources(&hostConfig.Resources, sysInfo, update) w, err := verifyPlatformContainerResources(&hostConfig.Resources, sysInfo, update)
@ -1718,14 +1718,14 @@ func (daemon *Daemon) setupSeccompProfile() error {
} }
// RawSysInfo returns *sysinfo.SysInfo . // RawSysInfo returns *sysinfo.SysInfo .
func (daemon *Daemon) RawSysInfo(quiet bool) *sysinfo.SysInfo { func (daemon *Daemon) RawSysInfo() *sysinfo.SysInfo {
var siOpts []sysinfo.Opt var siOpts []sysinfo.Opt
if daemon.getCgroupDriver() == cgroupSystemdDriver { if daemon.getCgroupDriver() == cgroupSystemdDriver {
if euid := os.Getenv("ROOTLESSKIT_PARENT_EUID"); euid != "" { if euid := os.Getenv("ROOTLESSKIT_PARENT_EUID"); euid != "" {
siOpts = append(siOpts, sysinfo.WithCgroup2GroupPath("/user.slice/user-"+euid+".slice")) siOpts = append(siOpts, sysinfo.WithCgroup2GroupPath("/user.slice/user-"+euid+".slice"))
} }
} }
return sysinfo.New(quiet, siOpts...) return sysinfo.New(siOpts...)
} }
func recursiveUnmount(target string) error { func recursiveUnmount(target string) error {

View file

@ -13,6 +13,6 @@ func setupResolvConf(config *config.Config) {
} }
// RawSysInfo returns *sysinfo.SysInfo . // RawSysInfo returns *sysinfo.SysInfo .
func (daemon *Daemon) RawSysInfo(quiet bool) *sysinfo.SysInfo { func (daemon *Daemon) RawSysInfo() *sysinfo.SysInfo {
return sysinfo.New(quiet) return sysinfo.New()
} }

View file

@ -652,6 +652,6 @@ func setupResolvConf(config *config.Config) {
} }
// RawSysInfo returns *sysinfo.SysInfo . // RawSysInfo returns *sysinfo.SysInfo .
func (daemon *Daemon) RawSysInfo(quiet bool) *sysinfo.SysInfo { func (daemon *Daemon) RawSysInfo() *sysinfo.SysInfo {
return sysinfo.New(quiet) return sysinfo.New()
} }

View file

@ -30,7 +30,7 @@ import (
func (daemon *Daemon) SystemInfo() *types.Info { func (daemon *Daemon) SystemInfo() *types.Info {
defer metrics.StartTimer(hostInfoFunctions.WithValues("system_info"))() defer metrics.StartTimer(hostInfoFunctions.WithValues("system_info"))()
sysInfo := daemon.RawSysInfo(true) sysInfo := daemon.RawSysInfo()
cRunning, cPaused, cStopped := stateCtr.get() cRunning, cPaused, cStopped := stateCtr.get()
v := &types.Info{ v := &types.Info{

View file

@ -824,7 +824,7 @@ func WithCgroups(daemon *Daemon, c *container.Container) coci.SpecOpts {
} }
// FIXME this is very expensive way to check if cpu rt is supported // FIXME this is very expensive way to check if cpu rt is supported
sysInfo := daemon.RawSysInfo(true) sysInfo := daemon.RawSysInfo()
if !sysInfo.CPURealtime { if !sysInfo.CPURealtime {
return errors.New("daemon-scoped cpu-rt-period and cpu-rt-runtime are not supported by the kernel") return errors.New("daemon-scoped cpu-rt-period and cpu-rt-runtime are not supported by the kernel")
} }

View file

@ -699,7 +699,7 @@ func (s *DockerSuite) TestRunSwapLessThanMemoryLimit(c *testing.T) {
func (s *DockerSuite) TestRunInvalidCpusetCpusFlagValue(c *testing.T) { func (s *DockerSuite) TestRunInvalidCpusetCpusFlagValue(c *testing.T) {
testRequires(c, cgroupCpuset, testEnv.IsLocalDaemon) testRequires(c, cgroupCpuset, testEnv.IsLocalDaemon)
sysInfo := sysinfo.New(true) sysInfo := sysinfo.New()
cpus, err := parsers.ParseUintList(sysInfo.Cpus) cpus, err := parsers.ParseUintList(sysInfo.Cpus)
assert.NilError(c, err) assert.NilError(c, err)
var invalid int var invalid int
@ -718,7 +718,7 @@ func (s *DockerSuite) TestRunInvalidCpusetCpusFlagValue(c *testing.T) {
func (s *DockerSuite) TestRunInvalidCpusetMemsFlagValue(c *testing.T) { func (s *DockerSuite) TestRunInvalidCpusetMemsFlagValue(c *testing.T) {
testRequires(c, cgroupCpuset) testRequires(c, cgroupCpuset)
sysInfo := sysinfo.New(true) sysInfo := sysinfo.New()
mems, err := parsers.ParseUintList(sysInfo.Mems) mems, err := parsers.ParseUintList(sysInfo.Mems)
assert.NilError(c, err) assert.NilError(c, err)
var invalid int var invalid int

View file

@ -84,6 +84,6 @@ func overlayFSSupported() bool {
func init() { func init() {
if testEnv.IsLocalDaemon() { if testEnv.IsLocalDaemon() {
SysInfo = sysinfo.New(true) SysInfo = sysinfo.New()
} }
} }

View file

@ -12,42 +12,13 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
type infoCollectorV2 func(info *SysInfo, controllers map[string]struct{}, dirPath string) (warnings []string) func newV2(options ...Opt) *SysInfo {
func newV2(quiet bool, opts *opts) *SysInfo {
var warnings []string
sysInfo := &SysInfo{ sysInfo := &SysInfo{
CgroupUnified: true, CgroupUnified: true,
cg2GroupPath: "/",
} }
g := opts.cg2GroupPath for _, o := range options {
if g == "" { o(sysInfo)
g = "/"
}
m, err := cgroupsV2.LoadManager("/sys/fs/cgroup", g)
if err != nil {
logrus.Warn(err)
} else {
controllersM := make(map[string]struct{})
controllers, err := m.Controllers()
if err != nil {
logrus.Warn(err)
}
for _, c := range controllers {
controllersM[c] = struct{}{}
}
opsV2 := []infoCollectorV2{
applyMemoryCgroupInfoV2,
applyCPUCgroupInfoV2,
applyIOCgroupInfoV2,
applyCPUSetCgroupInfoV2,
applyPIDSCgroupInfoV2,
applyDevicesCgroupInfoV2,
}
dirPath := path.Join("/sys/fs/cgroup", path.Clean(g))
for _, o := range opsV2 {
w := o(sysInfo, controllersM, dirPath)
warnings = append(warnings, w...)
}
} }
ops := []infoCollector{ ops := []infoCollector{
@ -56,14 +27,31 @@ func newV2(quiet bool, opts *opts) *SysInfo {
applySeccompInfo, applySeccompInfo,
applyCgroupNsInfo, applyCgroupNsInfo,
} }
m, err := cgroupsV2.LoadManager("/sys/fs/cgroup", sysInfo.cg2GroupPath)
if err != nil {
logrus.Warn(err)
} else {
sysInfo.cg2Controllers = make(map[string]struct{})
controllers, err := m.Controllers()
if err != nil {
logrus.Warn(err)
}
for _, c := range controllers {
sysInfo.cg2Controllers[c] = struct{}{}
}
ops = append(ops,
applyMemoryCgroupInfoV2,
applyCPUCgroupInfoV2,
applyIOCgroupInfoV2,
applyCPUSetCgroupInfoV2,
applyPIDSCgroupInfoV2,
applyDevicesCgroupInfoV2,
)
}
for _, o := range ops { for _, o := range ops {
w := o(sysInfo, nil) o(sysInfo)
warnings = append(warnings, w...)
}
if !quiet {
for _, w := range warnings {
logrus.Warn(w)
}
} }
return sysInfo return sysInfo
} }
@ -86,11 +74,10 @@ func getSwapLimitV2() bool {
return true return true
} }
func applyMemoryCgroupInfoV2(info *SysInfo, controllers map[string]struct{}, _ string) []string { func applyMemoryCgroupInfoV2(info *SysInfo) {
var warnings []string if _, ok := info.cg2Controllers["memory"]; !ok {
if _, ok := controllers["memory"]; !ok { info.Warnings = append(info.Warnings, "Unable to find memory controller")
warnings = append(warnings, "Unable to find memory controller") return
return warnings
} }
info.MemoryLimit = true info.MemoryLimit = true
@ -100,26 +87,22 @@ func applyMemoryCgroupInfoV2(info *SysInfo, controllers map[string]struct{}, _ s
info.MemorySwappiness = false info.MemorySwappiness = false
info.KernelMemory = false info.KernelMemory = false
info.KernelMemoryTCP = false info.KernelMemoryTCP = false
return warnings
} }
func applyCPUCgroupInfoV2(info *SysInfo, controllers map[string]struct{}, _ string) []string { func applyCPUCgroupInfoV2(info *SysInfo) {
var warnings []string if _, ok := info.cg2Controllers["cpu"]; !ok {
if _, ok := controllers["cpu"]; !ok { info.Warnings = append(info.Warnings, "Unable to find cpu controller")
warnings = append(warnings, "Unable to find cpu controller") return
return warnings
} }
info.CPUShares = true info.CPUShares = true
info.CPUCfs = true info.CPUCfs = true
info.CPURealtime = false info.CPURealtime = false
return warnings
} }
func applyIOCgroupInfoV2(info *SysInfo, controllers map[string]struct{}, _ string) []string { func applyIOCgroupInfoV2(info *SysInfo) {
var warnings []string if _, ok := info.cg2Controllers["io"]; !ok {
if _, ok := controllers["io"]; !ok { info.Warnings = append(info.Warnings, "Unable to find io controller")
warnings = append(warnings, "Unable to find io controller") return
return warnings
} }
info.BlkioWeight = true info.BlkioWeight = true
@ -128,42 +111,36 @@ func applyIOCgroupInfoV2(info *SysInfo, controllers map[string]struct{}, _ strin
info.BlkioWriteBpsDevice = true info.BlkioWriteBpsDevice = true
info.BlkioReadIOpsDevice = true info.BlkioReadIOpsDevice = true
info.BlkioWriteIOpsDevice = true info.BlkioWriteIOpsDevice = true
return warnings
} }
func applyCPUSetCgroupInfoV2(info *SysInfo, controllers map[string]struct{}, dirPath string) []string { func applyCPUSetCgroupInfoV2(info *SysInfo) {
var warnings []string if _, ok := info.cg2Controllers["cpuset"]; !ok {
if _, ok := controllers["cpuset"]; !ok { info.Warnings = append(info.Warnings, "Unable to find cpuset controller")
warnings = append(warnings, "Unable to find cpuset controller") return
return warnings
} }
info.Cpuset = true info.Cpuset = true
cpus, err := ioutil.ReadFile(path.Join(dirPath, "cpuset.cpus.effective")) cpus, err := ioutil.ReadFile(path.Join("/sys/fs/cgroup", info.cg2GroupPath, "cpuset.cpus.effective"))
if err != nil { if err != nil {
return warnings return
} }
info.Cpus = strings.TrimSpace(string(cpus)) info.Cpus = strings.TrimSpace(string(cpus))
mems, err := ioutil.ReadFile(path.Join(dirPath, "cpuset.mems.effective")) mems, err := ioutil.ReadFile(path.Join("/sys/fs/cgroup", info.cg2GroupPath, "cpuset.mems.effective"))
if err != nil { if err != nil {
return warnings return
} }
info.Mems = strings.TrimSpace(string(mems)) info.Mems = strings.TrimSpace(string(mems))
return warnings
} }
func applyPIDSCgroupInfoV2(info *SysInfo, controllers map[string]struct{}, _ string) []string { func applyPIDSCgroupInfoV2(info *SysInfo) {
var warnings []string if _, ok := info.cg2Controllers["pids"]; !ok {
if _, ok := controllers["pids"]; !ok { info.Warnings = append(info.Warnings, "Unable to find pids controller")
warnings = append(warnings, "Unable to find pids controller") return
return warnings
} }
info.PidsLimit = true info.PidsLimit = true
return warnings
} }
func applyDevicesCgroupInfoV2(info *SysInfo, controllers map[string]struct{}, _ string) []string { func applyDevicesCgroupInfoV2(info *SysInfo) {
info.CgroupDevicesEnabled = !userns.RunningInUserNS() info.CgroupDevicesEnabled = !userns.RunningInUserNS()
return nil
} }

View file

@ -2,6 +2,9 @@ package sysinfo // import "github.com/docker/docker/pkg/sysinfo"
import "github.com/docker/docker/pkg/parsers" import "github.com/docker/docker/pkg/parsers"
// Opt for New().
type Opt func(info *SysInfo)
// SysInfo stores information about which features a kernel supports. // SysInfo stores information about which features a kernel supports.
// TODO Windows: Factor out platform specific capabilities. // TODO Windows: Factor out platform specific capabilities.
type SysInfo struct { type SysInfo struct {
@ -33,6 +36,23 @@ type SysInfo struct {
// Whether the cgroup is in unified mode (v2). // Whether the cgroup is in unified mode (v2).
CgroupUnified bool CgroupUnified bool
// Warnings contains a slice of warnings that occurred while collecting
// system information. These warnings are intended to be informational
// messages for the user, and can either be logged or returned to the
// client; they are not intended to be parsed / used for other purposes,
// and do not have a fixed format.
Warnings []string
// cgMounts is the list of cgroup v1 mount paths, indexed by subsystem, to
// inspect availability of subsystems.
cgMounts map[string]string
// cg2GroupPath is the cgroup v2 group path to inspect availability of the controllers.
cg2GroupPath string
// cg2Controllers is an index of available cgroup v2 controllers.
cg2Controllers map[string]struct{}
} }
type cgroupMemInfo struct { type cgroupMemInfo struct {

View file

@ -28,14 +28,7 @@ func findCgroupMountpoints() (map[string]string, error) {
return mps, nil return mps, nil
} }
type infoCollector func(info *SysInfo, cgMounts map[string]string) (warnings []string) type infoCollector func(info *SysInfo)
type opts struct {
cg2GroupPath string
}
// Opt for New().
type Opt func(*opts)
// WithCgroup2GroupPath specifies the cgroup v2 group path to inspect availability // WithCgroup2GroupPath specifies the cgroup v2 group path to inspect availability
// of the controllers. // of the controllers.
@ -44,172 +37,158 @@ type Opt func(*opts)
// //
// e.g. g = "/user.slice/user-1000.slice/user@1000.service" // e.g. g = "/user.slice/user-1000.slice/user@1000.service"
func WithCgroup2GroupPath(g string) Opt { func WithCgroup2GroupPath(g string) Opt {
return func(o *opts) { return func(o *SysInfo) {
o.cg2GroupPath = path.Clean(g) if p := path.Clean(g); p != "" {
o.cg2GroupPath = p
}
} }
} }
// New returns a new SysInfo, using the filesystem to detect which features // New returns a new SysInfo, using the filesystem to detect which features
// the kernel supports. If `quiet` is `false` warnings are printed in logs // the kernel supports.
// whenever an error occurs or misconfigurations are present. func New(options ...Opt) *SysInfo {
func New(quiet bool, options ...Opt) *SysInfo {
var opts opts
for _, o := range options {
o(&opts)
}
if cdcgroups.Mode() == cdcgroups.Unified { if cdcgroups.Mode() == cdcgroups.Unified {
return newV2(quiet, &opts) return newV2(options...)
}
return newV1()
}
func newV1() *SysInfo {
var (
err error
sysInfo = &SysInfo{}
)
ops := []infoCollector{
applyNetworkingInfo,
applyAppArmorInfo,
applySeccompInfo,
applyCgroupNsInfo,
} }
var ops []infoCollector sysInfo.cgMounts, err = findCgroupMountpoints()
var warnings []string
sysInfo := &SysInfo{}
cgMounts, err := findCgroupMountpoints()
if err != nil { if err != nil {
logrus.Warn(err) logrus.Warn(err)
} else { } else {
ops = append(ops, []infoCollector{ ops = append(ops,
applyMemoryCgroupInfo, applyMemoryCgroupInfo,
applyCPUCgroupInfo, applyCPUCgroupInfo,
applyBlkioCgroupInfo, applyBlkioCgroupInfo,
applyCPUSetCgroupInfo, applyCPUSetCgroupInfo,
applyPIDSCgroupInfo, applyPIDSCgroupInfo,
applyDevicesCgroupInfo, applyDevicesCgroupInfo,
}...) )
} }
ops = append(ops, []infoCollector{
applyNetworkingInfo,
applyAppArmorInfo,
applySeccompInfo,
applyCgroupNsInfo,
}...)
for _, o := range ops { for _, o := range ops {
w := o(sysInfo, cgMounts) o(sysInfo)
warnings = append(warnings, w...)
}
if !quiet {
for _, w := range warnings {
logrus.Warn(w)
}
} }
return sysInfo return sysInfo
} }
// applyMemoryCgroupInfo adds the memory cgroup controller information to the info. // applyMemoryCgroupInfo adds the memory cgroup controller information to the info.
func applyMemoryCgroupInfo(info *SysInfo, cgMounts map[string]string) []string { func applyMemoryCgroupInfo(info *SysInfo) {
var warnings []string mountPoint, ok := info.cgMounts["memory"]
mountPoint, ok := cgMounts["memory"]
if !ok { if !ok {
warnings = append(warnings, "Your kernel does not support cgroup memory limit") info.Warnings = append(info.Warnings, "Your kernel does not support cgroup memory limit")
return warnings return
} }
info.MemoryLimit = ok info.MemoryLimit = ok
info.SwapLimit = cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes") info.SwapLimit = cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes")
if !info.SwapLimit { if !info.SwapLimit {
warnings = append(warnings, "Your kernel does not support swap memory limit") info.Warnings = append(info.Warnings, "Your kernel does not support swap memory limit")
} }
info.MemoryReservation = cgroupEnabled(mountPoint, "memory.soft_limit_in_bytes") info.MemoryReservation = cgroupEnabled(mountPoint, "memory.soft_limit_in_bytes")
if !info.MemoryReservation { if !info.MemoryReservation {
warnings = append(warnings, "Your kernel does not support memory reservation") info.Warnings = append(info.Warnings, "Your kernel does not support memory reservation")
} }
info.OomKillDisable = cgroupEnabled(mountPoint, "memory.oom_control") info.OomKillDisable = cgroupEnabled(mountPoint, "memory.oom_control")
if !info.OomKillDisable { if !info.OomKillDisable {
warnings = append(warnings, "Your kernel does not support oom control") info.Warnings = append(info.Warnings, "Your kernel does not support oom control")
} }
info.MemorySwappiness = cgroupEnabled(mountPoint, "memory.swappiness") info.MemorySwappiness = cgroupEnabled(mountPoint, "memory.swappiness")
if !info.MemorySwappiness { if !info.MemorySwappiness {
warnings = append(warnings, "Your kernel does not support memory swappiness") info.Warnings = append(info.Warnings, "Your kernel does not support memory swappiness")
} }
info.KernelMemory = cgroupEnabled(mountPoint, "memory.kmem.limit_in_bytes") info.KernelMemory = cgroupEnabled(mountPoint, "memory.kmem.limit_in_bytes")
if !info.KernelMemory { if !info.KernelMemory {
warnings = append(warnings, "Your kernel does not support kernel memory limit") info.Warnings = append(info.Warnings, "Your kernel does not support kernel memory limit")
} }
info.KernelMemoryTCP = cgroupEnabled(mountPoint, "memory.kmem.tcp.limit_in_bytes") info.KernelMemoryTCP = cgroupEnabled(mountPoint, "memory.kmem.tcp.limit_in_bytes")
if !info.KernelMemoryTCP { if !info.KernelMemoryTCP {
warnings = append(warnings, "Your kernel does not support kernel memory TCP limit") info.Warnings = append(info.Warnings, "Your kernel does not support kernel memory TCP limit")
} }
return warnings
} }
// applyCPUCgroupInfo adds the cpu cgroup controller information to the info. // applyCPUCgroupInfo adds the cpu cgroup controller information to the info.
func applyCPUCgroupInfo(info *SysInfo, cgMounts map[string]string) []string { func applyCPUCgroupInfo(info *SysInfo) {
var warnings []string mountPoint, ok := info.cgMounts["cpu"]
mountPoint, ok := cgMounts["cpu"]
if !ok { if !ok {
warnings = append(warnings, "Unable to find cpu cgroup in mounts") info.Warnings = append(info.Warnings, "Unable to find cpu cgroup in mounts")
return warnings return
} }
info.CPUShares = cgroupEnabled(mountPoint, "cpu.shares") info.CPUShares = cgroupEnabled(mountPoint, "cpu.shares")
if !info.CPUShares { if !info.CPUShares {
warnings = append(warnings, "Your kernel does not support CPU shares") info.Warnings = append(info.Warnings, "Your kernel does not support CPU shares")
} }
info.CPUCfs = cgroupEnabled(mountPoint, "cpu.cfs_quota_us") info.CPUCfs = cgroupEnabled(mountPoint, "cpu.cfs_quota_us")
if !info.CPUCfs { if !info.CPUCfs {
warnings = append(warnings, "Your kernel does not support CPU CFS scheduler") info.Warnings = append(info.Warnings, "Your kernel does not support CPU CFS scheduler")
} }
info.CPURealtime = cgroupEnabled(mountPoint, "cpu.rt_period_us") info.CPURealtime = cgroupEnabled(mountPoint, "cpu.rt_period_us")
if !info.CPURealtime { if !info.CPURealtime {
warnings = append(warnings, "Your kernel does not support CPU realtime scheduler") info.Warnings = append(info.Warnings, "Your kernel does not support CPU realtime scheduler")
} }
return warnings
} }
// applyBlkioCgroupInfo adds the blkio cgroup controller information to the info. // applyBlkioCgroupInfo adds the blkio cgroup controller information to the info.
func applyBlkioCgroupInfo(info *SysInfo, cgMounts map[string]string) []string { func applyBlkioCgroupInfo(info *SysInfo) {
var warnings []string mountPoint, ok := info.cgMounts["blkio"]
mountPoint, ok := cgMounts["blkio"]
if !ok { if !ok {
warnings = append(warnings, "Unable to find blkio cgroup in mounts") info.Warnings = append(info.Warnings, "Unable to find blkio cgroup in mounts")
return warnings return
} }
info.BlkioWeight = cgroupEnabled(mountPoint, "blkio.weight") info.BlkioWeight = cgroupEnabled(mountPoint, "blkio.weight")
if !info.BlkioWeight { if !info.BlkioWeight {
warnings = append(warnings, "Your kernel does not support cgroup blkio weight") info.Warnings = append(info.Warnings, "Your kernel does not support cgroup blkio weight")
} }
info.BlkioWeightDevice = cgroupEnabled(mountPoint, "blkio.weight_device") info.BlkioWeightDevice = cgroupEnabled(mountPoint, "blkio.weight_device")
if !info.BlkioWeightDevice { if !info.BlkioWeightDevice {
warnings = append(warnings, "Your kernel does not support cgroup blkio weight_device") info.Warnings = append(info.Warnings, "Your kernel does not support cgroup blkio weight_device")
} }
info.BlkioReadBpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.read_bps_device") info.BlkioReadBpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.read_bps_device")
if !info.BlkioReadBpsDevice { if !info.BlkioReadBpsDevice {
warnings = append(warnings, "Your kernel does not support cgroup blkio throttle.read_bps_device") info.Warnings = append(info.Warnings, "Your kernel does not support cgroup blkio throttle.read_bps_device")
} }
info.BlkioWriteBpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.write_bps_device") info.BlkioWriteBpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.write_bps_device")
if !info.BlkioWriteBpsDevice { if !info.BlkioWriteBpsDevice {
warnings = append(warnings, "Your kernel does not support cgroup blkio throttle.write_bps_device") info.Warnings = append(info.Warnings, "Your kernel does not support cgroup blkio throttle.write_bps_device")
} }
info.BlkioReadIOpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.read_iops_device") info.BlkioReadIOpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.read_iops_device")
if !info.BlkioReadIOpsDevice { if !info.BlkioReadIOpsDevice {
warnings = append(warnings, "Your kernel does not support cgroup blkio throttle.read_iops_device") info.Warnings = append(info.Warnings, "Your kernel does not support cgroup blkio throttle.read_iops_device")
} }
info.BlkioWriteIOpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.write_iops_device") info.BlkioWriteIOpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.write_iops_device")
if !info.BlkioWriteIOpsDevice { if !info.BlkioWriteIOpsDevice {
warnings = append(warnings, "Your kernel does not support cgroup blkio throttle.write_iops_device") info.Warnings = append(info.Warnings, "Your kernel does not support cgroup blkio throttle.write_iops_device")
} }
return warnings
} }
// applyCPUSetCgroupInfo adds the cpuset cgroup controller information to the info. // applyCPUSetCgroupInfo adds the cpuset cgroup controller information to the info.
func applyCPUSetCgroupInfo(info *SysInfo, cgMounts map[string]string) []string { func applyCPUSetCgroupInfo(info *SysInfo) {
var warnings []string mountPoint, ok := info.cgMounts["cpuset"]
mountPoint, ok := cgMounts["cpuset"]
if !ok { if !ok {
warnings = append(warnings, "Unable to find cpuset cgroup in mounts") info.Warnings = append(info.Warnings, "Unable to find cpuset cgroup in mounts")
return warnings return
} }
info.Cpuset = ok info.Cpuset = ok
@ -217,66 +196,54 @@ func applyCPUSetCgroupInfo(info *SysInfo, cgMounts map[string]string) []string {
cpus, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.cpus")) cpus, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.cpus"))
if err != nil { if err != nil {
return warnings return
} }
info.Cpus = strings.TrimSpace(string(cpus)) info.Cpus = strings.TrimSpace(string(cpus))
mems, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.mems")) mems, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.mems"))
if err != nil { if err != nil {
return warnings return
} }
info.Mems = strings.TrimSpace(string(mems)) info.Mems = strings.TrimSpace(string(mems))
return warnings
} }
// applyPIDSCgroupInfo adds whether the pids cgroup controller is available to the info. // applyPIDSCgroupInfo adds whether the pids cgroup controller is available to the info.
func applyPIDSCgroupInfo(info *SysInfo, cgMounts map[string]string) []string { func applyPIDSCgroupInfo(info *SysInfo) {
var warnings []string _, ok := info.cgMounts["pids"]
_, ok := cgMounts["pids"]
if !ok { if !ok {
warnings = append(warnings, "Unable to find pids cgroup in mounts") info.Warnings = append(info.Warnings, "Unable to find pids cgroup in mounts")
return warnings return
} }
info.PidsLimit = true info.PidsLimit = true
return warnings
} }
// applyDevicesCgroupInfo adds whether the devices cgroup controller is available to the info. // applyDevicesCgroupInfo adds whether the devices cgroup controller is available to the info.
func applyDevicesCgroupInfo(info *SysInfo, cgMounts map[string]string) []string { func applyDevicesCgroupInfo(info *SysInfo) {
var warnings []string _, ok := info.cgMounts["devices"]
_, ok := cgMounts["devices"]
info.CgroupDevicesEnabled = ok info.CgroupDevicesEnabled = ok
return warnings
} }
// applyNetworkingInfo adds networking information to the info. // applyNetworkingInfo adds networking information to the info.
func applyNetworkingInfo(info *SysInfo, _ map[string]string) []string { func applyNetworkingInfo(info *SysInfo) {
var warnings []string
info.IPv4ForwardingDisabled = !readProcBool("/proc/sys/net/ipv4/ip_forward") info.IPv4ForwardingDisabled = !readProcBool("/proc/sys/net/ipv4/ip_forward")
info.BridgeNFCallIPTablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-iptables") info.BridgeNFCallIPTablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-iptables")
info.BridgeNFCallIP6TablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-ip6tables") info.BridgeNFCallIP6TablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-ip6tables")
return warnings
} }
// applyAppArmorInfo adds whether AppArmor is enabled to the info. // applyAppArmorInfo adds whether AppArmor is enabled to the info.
func applyAppArmorInfo(info *SysInfo, _ map[string]string) []string { func applyAppArmorInfo(info *SysInfo) {
var warnings []string
if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) { if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) {
if _, err := ioutil.ReadFile("/sys/kernel/security/apparmor/profiles"); err == nil { if _, err := ioutil.ReadFile("/sys/kernel/security/apparmor/profiles"); err == nil {
info.AppArmor = true info.AppArmor = true
} }
} }
return warnings
} }
// applyCgroupNsInfo adds whether cgroupns is enabled to the info. // applyCgroupNsInfo adds whether cgroupns is enabled to the info.
func applyCgroupNsInfo(info *SysInfo, _ map[string]string) []string { func applyCgroupNsInfo(info *SysInfo) {
var warnings []string
if _, err := os.Stat("/proc/self/ns/cgroup"); !os.IsNotExist(err) { if _, err := os.Stat("/proc/self/ns/cgroup"); !os.IsNotExist(err) {
info.CgroupNamespaces = true info.CgroupNamespaces = true
} }
return warnings
} }
var ( var (
@ -285,8 +252,7 @@ var (
) )
// applySeccompInfo checks if Seccomp is supported, via CONFIG_SECCOMP. // applySeccompInfo checks if Seccomp is supported, via CONFIG_SECCOMP.
func applySeccompInfo(info *SysInfo, _ map[string]string) []string { func applySeccompInfo(info *SysInfo) {
var warnings []string
seccompOnce.Do(func() { seccompOnce.Do(func() {
// Check if Seccomp is supported, via CONFIG_SECCOMP. // Check if Seccomp is supported, via CONFIG_SECCOMP.
if err := unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0); err != unix.EINVAL { if err := unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0); err != unix.EINVAL {
@ -297,7 +263,6 @@ func applySeccompInfo(info *SysInfo, _ map[string]string) []string {
} }
}) })
info.Seccomp = seccompEnabled info.Seccomp = seccompEnabled
return warnings
} }
func cgroupEnabled(mountPoint, name string) bool { func cgroupEnabled(mountPoint, name string) bool {

View file

@ -55,11 +55,7 @@ func TestCgroupEnabled(t *testing.T) {
} }
func TestNew(t *testing.T) { func TestNew(t *testing.T) {
sysInfo := New(false) sysInfo := New()
assert.Assert(t, sysInfo != nil)
checkSysInfo(t, sysInfo)
sysInfo = New(true)
assert.Assert(t, sysInfo != nil) assert.Assert(t, sysInfo != nil)
checkSysInfo(t, sysInfo) checkSysInfo(t, sysInfo)
} }
@ -79,20 +75,20 @@ func checkSysInfo(t *testing.T, sysInfo *SysInfo) {
func TestNewAppArmorEnabled(t *testing.T) { func TestNewAppArmorEnabled(t *testing.T) {
// Check if AppArmor is supported. then it must be TRUE , else FALSE // Check if AppArmor is supported. then it must be TRUE , else FALSE
if _, err := os.Stat("/sys/kernel/security/apparmor"); err != nil { if _, err := os.Stat("/sys/kernel/security/apparmor"); err != nil {
t.Skip("App Armor Must be Enabled") t.Skip("AppArmor Must be Enabled")
} }
sysInfo := New(true) sysInfo := New()
assert.Assert(t, sysInfo.AppArmor) assert.Assert(t, sysInfo.AppArmor)
} }
func TestNewAppArmorDisabled(t *testing.T) { func TestNewAppArmorDisabled(t *testing.T) {
// Check if AppArmor is supported. then it must be TRUE , else FALSE // Check if AppArmor is supported. then it must be TRUE , else FALSE
if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) { if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) {
t.Skip("App Armor Must be Disabled") t.Skip("AppArmor Must be Disabled")
} }
sysInfo := New(true) sysInfo := New()
assert.Assert(t, !sysInfo.AppArmor) assert.Assert(t, !sysInfo.AppArmor)
} }
@ -102,7 +98,7 @@ func TestNewCgroupNamespacesEnabled(t *testing.T) {
t.Skip("cgroup namespaces must be enabled") t.Skip("cgroup namespaces must be enabled")
} }
sysInfo := New(true) sysInfo := New()
assert.Assert(t, sysInfo.CgroupNamespaces) assert.Assert(t, sysInfo.CgroupNamespaces)
} }
@ -112,7 +108,7 @@ func TestNewCgroupNamespacesDisabled(t *testing.T) {
t.Skip("cgroup namespaces must be disabled") t.Skip("cgroup namespaces must be disabled")
} }
sysInfo := New(true) sysInfo := New()
assert.Assert(t, !sysInfo.CgroupNamespaces) assert.Assert(t, !sysInfo.CgroupNamespaces)
} }

View file

@ -0,0 +1,8 @@
// +build !linux
package sysinfo // import "github.com/docker/docker/pkg/sysinfo"
// New returns an empty SysInfo for non linux for now.
func New(options ...Opt) *SysInfo {
return &SysInfo{}
}

View file

@ -1,14 +0,0 @@
// +build !linux,!windows
package sysinfo // import "github.com/docker/docker/pkg/sysinfo"
type opts struct{}
// Opt for New().
type Opt func(*opts)
// New returns an empty SysInfo for non linux for now.
func New(quiet bool, options ...Opt) *SysInfo {
sysInfo := &SysInfo{}
return sysInfo
}

View file

@ -1,12 +0,0 @@
package sysinfo // import "github.com/docker/docker/pkg/sysinfo"
type opts struct{}
// Opt for New().
type Opt func(*opts)
// New returns an empty SysInfo for windows for now.
func New(quiet bool, options ...Opt) *SysInfo {
sysInfo := &SysInfo{}
return sysInfo
}

View file

@ -21,7 +21,7 @@ func (r ContainerDecoder) DecodeConfig(src io.Reader) (*container.Config, *conta
if r.GetSysInfo != nil { if r.GetSysInfo != nil {
si = r.GetSysInfo() si = r.GetSysInfo()
} else { } else {
si = sysinfo.New(true) si = sysinfo.New()
} }
return decodeContainerConfig(src, si) return decodeContainerConfig(src, si)

View file

@ -47,7 +47,7 @@ func TestDecodeContainerConfig(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
c, h, _, err := decodeContainerConfig(bytes.NewReader(b), sysinfo.New(true)) c, h, _, err := decodeContainerConfig(bytes.NewReader(b), sysinfo.New())
if err != nil { if err != nil {
t.Fatal(fmt.Errorf("Error parsing %s: %v", f, err)) t.Fatal(fmt.Errorf("Error parsing %s: %v", f, err))
} }
@ -131,5 +131,5 @@ func callDecodeContainerConfigIsolation(isolation string) (*container.Config, *c
if b, err = json.Marshal(w); err != nil { if b, err = json.Marshal(w); err != nil {
return nil, nil, nil, fmt.Errorf("Error on marshal %s", err.Error()) return nil, nil, nil, fmt.Errorf("Error on marshal %s", err.Error())
} }
return decodeContainerConfig(bytes.NewReader(b), sysinfo.New(true)) return decodeContainerConfig(bytes.NewReader(b), sysinfo.New())
} }