Browse code

refactor aaparser pkg, add unit tests

Signed-off-by: Jessica Frazelle <acidburn@docker.com>

Jessica Frazelle authored on 2016/01/13 03:01:04
Showing 3 changed files
... ...
@@ -4,7 +4,6 @@ package native
4 4
 
5 5
 import (
6 6
 	"bufio"
7
-	"fmt"
8 7
 	"io"
9 8
 	"os"
10 9
 	"os/exec"
... ...
@@ -137,15 +136,10 @@ func installAppArmorProfile() error {
137 137
 	}
138 138
 	f.Close()
139 139
 
140
-	cmd := exec.Command("/sbin/apparmor_parser", "-r", "-W", "docker")
141
-	// to use the parser directly we have to make sure we are in the correct
142
-	// dir with the profile
143
-	cmd.Dir = "/etc/apparmor.d"
144
-
145
-	output, err := cmd.CombinedOutput()
146
-	if err != nil {
147
-		return fmt.Errorf("Error loading docker apparmor profile: %s (%s)", err, output)
140
+	if err := aaparser.LoadProfile(apparmorProfilePath); err != nil {
141
+		return err
148 142
 	}
143
+
149 144
 	return nil
150 145
 }
151 146
 
... ...
@@ -1,35 +1,66 @@
1
+// Package aaparser is a convenience package interacting with `apparmor_parser`.
1 2
 package aaparser
2 3
 
3 4
 import (
4 5
 	"fmt"
5
-	"log"
6 6
 	"os/exec"
7
+	"path/filepath"
7 8
 	"strconv"
8 9
 	"strings"
9 10
 )
10 11
 
11
-// GetVersion returns the major and minor version of apparmor_parser
12
+const (
13
+	binary = "apparmor_parser"
14
+)
15
+
16
+// GetVersion returns the major and minor version of apparmor_parser.
12 17
 func GetVersion() (int, int, error) {
13
-	// get the apparmor_version version
14
-	cmd := exec.Command("apparmor_parser", "--version")
18
+	output, err := cmd("", "--version")
19
+	if err != nil {
20
+		return -1, -1, err
21
+	}
22
+
23
+	return parseVersion(string(output))
24
+}
15 25
 
16
-	output, err := cmd.CombinedOutput()
26
+// LoadProfile runs `apparmor_parser -r -W` on a specified apparmor profile to
27
+// replace and write it to disk.
28
+func LoadProfile(profilePath string) error {
29
+	_, err := cmd(filepath.Dir(profilePath), "-r", "-W", filepath.Base(profilePath))
17 30
 	if err != nil {
18
-		log.Fatalf("getting apparmor_parser version failed: %s (%s)", err, output)
31
+		return err
19 32
 	}
33
+	return nil
34
+}
20 35
 
21
-	// parse the version from the output
36
+// cmd runs `apparmor_parser` with the passed arguments.
37
+func cmd(dir string, arg ...string) (string, error) {
38
+	c := exec.Command(binary, arg...)
39
+	c.Dir = dir
40
+
41
+	output, err := c.CombinedOutput()
42
+	if err != nil {
43
+		return "", fmt.Errorf("running `%s %s` failed with output: %s\nerror: %v", c.Path, strings.Join(c.Args, " "), string(output), err)
44
+	}
45
+
46
+	return string(output), nil
47
+}
48
+
49
+// parseVersion takes the output from `apparmor_parser --version` and returns
50
+// the major and minor version for `apparor_parser`.
51
+func parseVersion(output string) (int, int, error) {
22 52
 	// output is in the form of the following:
23 53
 	// AppArmor parser version 2.9.1
24 54
 	// Copyright (C) 1999-2008 Novell Inc.
25 55
 	// Copyright 2009-2012 Canonical Ltd.
26
-	lines := strings.SplitN(string(output), "\n", 2)
56
+	lines := strings.SplitN(output, "\n", 2)
27 57
 	words := strings.Split(lines[0], " ")
28 58
 	version := words[len(words)-1]
59
+
29 60
 	// split by major minor version
30 61
 	v := strings.Split(version, ".")
31 62
 	if len(v) < 2 {
32
-		return -1, -1, fmt.Errorf("parsing major minor version failed for %q", version)
63
+		return -1, -1, fmt.Errorf("parsing major minor version failed for output: `%s`", output)
33 64
 	}
34 65
 
35 66
 	majorVersion, err := strconv.Atoi(v[0])
36 67
new file mode 100644
... ...
@@ -0,0 +1,65 @@
0
+package aaparser
1
+
2
+import (
3
+	"testing"
4
+)
5
+
6
+type versionExpected struct {
7
+	output string
8
+	major  int
9
+	minor  int
10
+}
11
+
12
+func TestParseVersion(t *testing.T) {
13
+	versions := []versionExpected{
14
+		{
15
+			output: `AppArmor parser version 2.10
16
+Copyright (C) 1999-2008 Novell Inc.
17
+Copyright 2009-2012 Canonical Ltd.
18
+
19
+`,
20
+			major: 2,
21
+			minor: 10,
22
+		},
23
+		{
24
+			output: `AppArmor parser version 2.8
25
+Copyright (C) 1999-2008 Novell Inc.
26
+Copyright 2009-2012 Canonical Ltd.
27
+
28
+`,
29
+			major: 2,
30
+			minor: 8,
31
+		},
32
+		{
33
+			output: `AppArmor parser version 2.20
34
+Copyright (C) 1999-2008 Novell Inc.
35
+Copyright 2009-2012 Canonical Ltd.
36
+
37
+`,
38
+			major: 2,
39
+			minor: 20,
40
+		},
41
+		{
42
+			output: `AppArmor parser version 2.05
43
+Copyright (C) 1999-2008 Novell Inc.
44
+Copyright 2009-2012 Canonical Ltd.
45
+
46
+`,
47
+			major: 2,
48
+			minor: 5,
49
+		},
50
+	}
51
+
52
+	for _, v := range versions {
53
+		major, minor, err := parseVersion(v.output)
54
+		if err != nil {
55
+			t.Fatalf("expected error to be nil for %#v, got: %v", v, err)
56
+		}
57
+		if major != v.major {
58
+			t.Fatalf("expected major version to be %d, was %d, for: %#v\n", v.major, major, v)
59
+		}
60
+		if minor != v.minor {
61
+			t.Fatalf("expected minor version to be %d, was %d, for: %#v\n", v.minor, minor, v)
62
+		}
63
+	}
64
+}