Browse code

cleanup sysinfo package

Signed-off-by: Brian Goff <cpuguy83@gmail.com>

Brian Goff authored on 2015/06/17 11:36:20
Showing 4 changed files
... ...
@@ -743,6 +743,11 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
743 743
 	}
744 744
 
745 745
 	sysInfo := sysinfo.New(false)
746
+	// Check if Devices cgroup is mounted, it is hard requirement for container security.
747
+	if !sysInfo.CgroupDevicesEnabled {
748
+		return nil, fmt.Errorf("Devices cgroup isn't mounted")
749
+	}
750
+
746 751
 	ed, err := execdrivers.NewDriver(config.ExecDriver, config.ExecOptions, config.ExecRoot, config.Root, sysInitPath, sysInfo)
747 752
 	if err != nil {
748 753
 		return nil, err
... ...
@@ -3,13 +3,22 @@ package sysinfo
3 3
 // SysInfo stores information about which features a kernel supports.
4 4
 // TODO Windows: Factor out platform specific capabilities.
5 5
 type SysInfo struct {
6
-	MemoryLimit                   bool
7
-	SwapLimit                     bool
8
-	CpuCfsPeriod                  bool
9
-	CpuCfsQuota                   bool
6
+	AppArmor bool
7
+	*cgroupMemInfo
8
+	*cgroupCpuInfo
10 9
 	IPv4ForwardingDisabled        bool
11
-	AppArmor                      bool
12
-	OomKillDisable                bool
13 10
 	BridgeNfCallIptablesDisabled  bool
14 11
 	BridgeNfCallIp6tablesDisabled bool
12
+	CgroupDevicesEnabled          bool
13
+}
14
+
15
+type cgroupMemInfo struct {
16
+	MemoryLimit    bool
17
+	SwapLimit      bool
18
+	OomKillDisable bool
19
+}
20
+
21
+type cgroupCpuInfo struct {
22
+	CpuCfsPeriod bool
23
+	CpuCfsQuota  bool
15 24
 }
... ...
@@ -4,7 +4,6 @@ import (
4 4
 	"io/ioutil"
5 5
 	"os"
6 6
 	"path"
7
-	"strconv"
8 7
 	"strings"
9 8
 
10 9
 	"github.com/Sirupsen/logrus"
... ...
@@ -14,81 +13,78 @@ import (
14 14
 // New returns a new SysInfo, using the filesystem to detect which features the kernel supports.
15 15
 func New(quiet bool) *SysInfo {
16 16
 	sysInfo := &SysInfo{}
17
-	if cgroupMemoryMountpoint, err := cgroups.FindCgroupMountpoint("memory"); err != nil {
18
-		if !quiet {
19
-			logrus.Warnf("Your kernel does not support cgroup memory limit: %v", err)
20
-		}
21
-	} else {
22
-		// If memory cgroup is mounted, MemoryLimit is always enabled.
23
-		sysInfo.MemoryLimit = true
17
+	sysInfo.cgroupMemInfo = checkCgroupMem(quiet)
18
+	sysInfo.cgroupCpuInfo = checkCgroupCpu(quiet)
24 19
 
25
-		_, err1 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.memsw.limit_in_bytes"))
26
-		sysInfo.SwapLimit = err1 == nil
27
-		if !sysInfo.SwapLimit && !quiet {
28
-			logrus.Warn("Your kernel does not support swap memory limit.")
29
-		}
20
+	_, err := cgroups.FindCgroupMountpoint("devices")
21
+	sysInfo.CgroupDevicesEnabled = err == nil
30 22
 
31
-		_, err = ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.oom_control"))
32
-		sysInfo.OomKillDisable = err == nil
33
-		if !sysInfo.OomKillDisable && !quiet {
34
-			logrus.Warnf("Your kernel does not support oom control.")
35
-		}
23
+	sysInfo.IPv4ForwardingDisabled = !readProcBool("/proc/sys/net/ipv4/ip_forward")
24
+	sysInfo.BridgeNfCallIptablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-iptables")
25
+	sysInfo.BridgeNfCallIp6tablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-ip6tables")
26
+
27
+	// Check if AppArmor is supported.
28
+	if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) {
29
+		sysInfo.AppArmor = true
36 30
 	}
37 31
 
38
-	if cgroupCpuMountpoint, err := cgroups.FindCgroupMountpoint("cpu"); err != nil {
32
+	return sysInfo
33
+}
34
+
35
+func checkCgroupMem(quiet bool) *cgroupMemInfo {
36
+	info := &cgroupMemInfo{}
37
+	mountPoint, err := cgroups.FindCgroupMountpoint("memory")
38
+	if err != nil {
39 39
 		if !quiet {
40
-			logrus.Warnf("%v", err)
41
-		}
42
-	} else {
43
-		_, err := ioutil.ReadFile(path.Join(cgroupCpuMountpoint, "cpu.cfs_period_us"))
44
-		sysInfo.CpuCfsPeriod = err == nil
45
-		if !sysInfo.CpuCfsPeriod && !quiet {
46
-			logrus.Warn("Your kernel does not support cgroup cfs period")
47
-		}
48
-		_, err = ioutil.ReadFile(path.Join(cgroupCpuMountpoint, "cpu.cfs_quota_us"))
49
-		sysInfo.CpuCfsQuota = err == nil
50
-		if !sysInfo.CpuCfsQuota && !quiet {
51
-			logrus.Warn("Your kernel does not support cgroup cfs quotas")
40
+			logrus.Warnf("Your kernel does not support cgroup memory limit: %v", err)
52 41
 		}
42
+		return nil
53 43
 	}
44
+	info.MemoryLimit = true
54 45
 
55
-	// Checek if ipv4_forward is disabled.
56
-	if data, err := ioutil.ReadFile("/proc/sys/net/ipv4/ip_forward"); os.IsNotExist(err) {
57
-		sysInfo.IPv4ForwardingDisabled = true
58
-	} else {
59
-		if enabled, _ := strconv.Atoi(strings.TrimSpace(string(data))); enabled == 0 {
60
-			sysInfo.IPv4ForwardingDisabled = true
61
-		} else {
62
-			sysInfo.IPv4ForwardingDisabled = false
63
-		}
46
+	info.SwapLimit = cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes")
47
+	if !quiet && !info.SwapLimit {
48
+		logrus.Warn("Your kernel does not support swap memory limit.")
64 49
 	}
65
-
66
-	// Check if bridge-nf-call-iptables is disabled.
67
-	if data, err := ioutil.ReadFile("/proc/sys/net/bridge/bridge-nf-call-iptables"); os.IsNotExist(err) {
68
-		sysInfo.BridgeNfCallIptablesDisabled = true
69
-	} else {
70
-		enabled, _ := strconv.Atoi(strings.TrimSpace(string(data)))
71
-		sysInfo.BridgeNfCallIptablesDisabled = enabled == 0
50
+	info.OomKillDisable = cgroupEnabled(mountPoint, "memory.oom_control")
51
+	if !quiet && !info.OomKillDisable {
52
+		logrus.Warnf("Your kernel does not support oom control.")
72 53
 	}
73
-	// Check if bridge-nf-call-ip6tables is disabled.
74
-	if data, err := ioutil.ReadFile("/proc/sys/net/bridge/bridge-nf-call-ip6tables"); os.IsNotExist(err) {
75
-		sysInfo.BridgeNfCallIp6tablesDisabled = true
76
-	} else {
77
-		enabled, _ := strconv.Atoi(strings.TrimSpace(string(data)))
78
-		sysInfo.BridgeNfCallIp6tablesDisabled = enabled == 0
54
+
55
+	return info
56
+}
57
+
58
+func checkCgroupCpu(quiet bool) *cgroupCpuInfo {
59
+	info := &cgroupCpuInfo{}
60
+	mountPoint, err := cgroups.FindCgroupMountpoint("cpu")
61
+	if err != nil {
62
+		if !quiet {
63
+			logrus.Warn(err)
64
+		}
65
+		return nil
79 66
 	}
80 67
 
81
-	// Check if AppArmor is supported.
82
-	if _, err := os.Stat("/sys/kernel/security/apparmor"); os.IsNotExist(err) {
83
-		sysInfo.AppArmor = false
84
-	} else {
85
-		sysInfo.AppArmor = true
68
+	info.CpuCfsPeriod = cgroupEnabled(mountPoint, "cpu.cfs_period_us")
69
+	if !quiet && !info.CpuCfsPeriod {
70
+		logrus.Warn("Your kernel does not support cgroup cfs period")
86 71
 	}
87 72
 
88
-	// Check if Devices cgroup is mounted, it is hard requirement for container security.
89
-	if _, err := cgroups.FindCgroupMountpoint("devices"); err != nil {
90
-		logrus.Fatalf("Error mounting devices cgroup: %v", err)
73
+	info.CpuCfsQuota = cgroupEnabled(mountPoint, "cpu.cfs_quota_us")
74
+	if !quiet && !info.CpuCfsQuota {
75
+		logrus.Warn("Your kernel does not support cgroup cfs quotas")
91 76
 	}
77
+	return info
78
+}
92 79
 
93
-	return sysInfo
80
+func cgroupEnabled(mountPoint, name string) bool {
81
+	_, err := os.Stat(path.Join(mountPoint, name))
82
+	return err == nil
83
+}
84
+
85
+func readProcBool(path string) bool {
86
+	val, err := ioutil.ReadFile(path)
87
+	if err != nil {
88
+		return false
89
+	}
90
+	return strings.TrimSpace(string(val)) == "1"
94 91
 }
95 92
new file mode 100644
... ...
@@ -0,0 +1,58 @@
0
+package sysinfo
1
+
2
+import (
3
+	"io/ioutil"
4
+	"os"
5
+	"path"
6
+	"path/filepath"
7
+	"testing"
8
+)
9
+
10
+func TestReadProcBool(t *testing.T) {
11
+	tmpDir, err := ioutil.TempDir("", "test-sysinfo-proc")
12
+	if err != nil {
13
+		t.Fatal(err)
14
+	}
15
+	defer os.RemoveAll(tmpDir)
16
+
17
+	procFile := filepath.Join(tmpDir, "read-proc-bool")
18
+	if err := ioutil.WriteFile(procFile, []byte("1"), 644); err != nil {
19
+		t.Fatal(err)
20
+	}
21
+
22
+	if !readProcBool(procFile) {
23
+		t.Fatal("expected proc bool to be true, got false")
24
+	}
25
+
26
+	if err := ioutil.WriteFile(procFile, []byte("0"), 644); err != nil {
27
+		t.Fatal(err)
28
+	}
29
+	if readProcBool(procFile) {
30
+		t.Fatal("expected proc bool to be false, got false")
31
+	}
32
+
33
+	if readProcBool(path.Join(tmpDir, "no-exist")) {
34
+		t.Fatal("should be false for non-existent entry")
35
+	}
36
+
37
+}
38
+
39
+func TestCgroupEnabled(t *testing.T) {
40
+	cgroupDir, err := ioutil.TempDir("", "cgroup-test")
41
+	if err != nil {
42
+		t.Fatal(err)
43
+	}
44
+	defer os.RemoveAll(cgroupDir)
45
+
46
+	if cgroupEnabled(cgroupDir, "test") {
47
+		t.Fatal("cgroupEnabled should be false")
48
+	}
49
+
50
+	if err := ioutil.WriteFile(path.Join(cgroupDir, "test"), []byte{}, 644); err != nil {
51
+		t.Fatal(err)
52
+	}
53
+
54
+	if !cgroupEnabled(cgroupDir, "test") {
55
+		t.Fatal("cgroupEnabled should be true")
56
+	}
57
+}