diff --git a/.gitignore b/.gitignore index 2b13b94..3dccb6f 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ /docker-cb216be.tar.gz /docker-selinux-d6560f8.tar.gz /docker-selinux-2ed73eb.tar.gz +/docker-selinux-44abd21.tar.gz diff --git a/dev-dont-modify.patch b/dev-dont-modify.patch deleted file mode 100644 index 1bb3213..0000000 --- a/dev-dont-modify.patch +++ /dev/null @@ -1,62 +0,0 @@ -From c9d58506297ed6c86c9d8a91d861e4de3772e699 Mon Sep 17 00:00:00 2001 -From: Mrunal Patel -Date: Tue, 7 Jul 2015 17:46:44 -0400 -Subject: [PATCH] Don't make modifications to /dev there are no devices in the - configuration - -Signed-off-by: Mrunal Patel ---- - libcontainer/rootfs_linux.go | 26 ++++++++++++++++---------- - 1 file changed, 16 insertions(+), 10 deletions(-) - -diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go -index 88aa77d..21f380d 100644 ---- a/libcontainer/rootfs_linux.go -+++ b/libcontainer/rootfs_linux.go -@@ -27,6 +27,8 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) { - if err := prepareRoot(config); err != nil { - return newSystemError(err) - } -+ -+ setupDev := len(config.Devices) == 0 - for _, m := range config.Mounts { - for _, precmd := range m.PremountCmds { - if err := mountCmd(precmd); err != nil { -@@ -43,14 +45,16 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) { - } - } - } -- if err := createDevices(config); err != nil { -- return newSystemError(err) -- } -- if err := setupPtmx(config, console); err != nil { -- return newSystemError(err) -- } -- if err := setupDevSymlinks(config.Rootfs); err != nil { -- return newSystemError(err) -+ if !setupDev { -+ if err := createDevices(config); err != nil { -+ return newSystemError(err) -+ } -+ if err := setupPtmx(config, console); err != nil { -+ return newSystemError(err) -+ } -+ if err := setupDevSymlinks(config.Rootfs); err != nil { -+ return newSystemError(err) -+ } - } - if err := syscall.Chdir(config.Rootfs); err != nil { - return newSystemError(err) -@@ -63,8 +67,10 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) { - if err != nil { - return newSystemError(err) - } -- if err := reOpenDevNull(config.Rootfs); err != nil { -- return newSystemError(err) -+ if !setupDev { -+ if err := reOpenDevNull(config.Rootfs); err != nil { -+ return newSystemError(err) -+ } - } - if config.Readonlyfs { - if err := setReadonly(); err != nil { diff --git a/dev-setup.patch b/dev-setup.patch deleted file mode 100644 index 3081065..0000000 --- a/dev-setup.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 4911b588627619b0e5c9cec5180b5aeea1e5fcd9 Mon Sep 17 00:00:00 2001 -From: Mrunal Patel -Date: Mon, 28 Sep 2015 18:28:16 -0400 -Subject: [PATCH] Skip /dev setup in container when it is bind mounted in - -We need to set the device array to nil to skip /dev setup in runc/libcontainer. -See https://github.com/opencontainers/runc/commit/c9d58506297ed6c86c9d8a91d861e4de3772e699 - -Signed-off-by: Mrunal Patel ---- - daemon/execdriver/native/create.go | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/daemon/execdriver/native/create.go b/daemon/execdriver/native/create.go -index d76dbd2..063fd28 100644 ---- a/daemon/execdriver/native/create.go -+++ b/daemon/execdriver/native/create.go -@@ -260,6 +260,7 @@ func (d *Driver) setupMounts(container *configs.Config, c *execdriver.Command) e - for _, m := range container.Mounts { - if _, ok := userMounts[m.Destination]; !ok { - if mountDev && strings.HasPrefix(m.Destination, "/dev/") { -+ container.Devices = nil - continue - } - defaultMounts = append(defaultMounts, m) diff --git a/dev.patch b/dev.patch new file mode 100644 index 0000000..b7c19d2 --- /dev/null +++ b/dev.patch @@ -0,0 +1,78 @@ +From 40b0f129f5a6e005a949dc0ba808fb9ee557ebe4 Mon Sep 17 00:00:00 2001 +From: Mrunal Patel +Date: Fri, 9 Oct 2015 17:57:44 -0400 +Subject: [PATCH] Cherry pick changes for allowing /dev mount from host + +docker #16639 + +runc commit id c9d58506297e + +Signed-off-by: Mrunal Patel +--- + daemon/execdriver/native/create.go | 1 + + .../runc/libcontainer/rootfs_linux.go | 26 +++++++++++++--------- + 2 files changed, 17 insertions(+), 10 deletions(-) + +diff --git a/daemon/execdriver/native/create.go b/daemon/execdriver/native/create.go +index bbc83fe..ca8d7fd 100644 +--- a/daemon/execdriver/native/create.go ++++ b/daemon/execdriver/native/create.go +@@ -234,6 +234,7 @@ func (d *driver) setupMounts(container *configs.Config, c *execdriver.Command) e + for _, m := range container.Mounts { + if _, ok := userMounts[m.Destination]; !ok { + if mountDev && strings.HasPrefix(m.Destination, "/dev/") { ++ container.Devices = nil + continue + } + defaultMounts = append(defaultMounts, m) +diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go +index a211d8d..9fd7058 100644 +--- a/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go ++++ b/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go +@@ -27,6 +27,8 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) { + if err := prepareRoot(config); err != nil { + return newSystemError(err) + } ++ ++ setupDev := len(config.Devices) == 0 + for _, m := range config.Mounts { + for _, precmd := range m.PremountCmds { + if err := mountCmd(precmd); err != nil { +@@ -43,14 +45,16 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) { + } + } + } +- if err := createDevices(config); err != nil { +- return newSystemError(err) +- } +- if err := setupPtmx(config, console); err != nil { +- return newSystemError(err) +- } +- if err := setupDevSymlinks(config.Rootfs); err != nil { +- return newSystemError(err) ++ if !setupDev { ++ if err := createDevices(config); err != nil { ++ return newSystemError(err) ++ } ++ if err := setupPtmx(config, console); err != nil { ++ return newSystemError(err) ++ } ++ if err := setupDevSymlinks(config.Rootfs); err != nil { ++ return newSystemError(err) ++ } + } + if err := syscall.Chdir(config.Rootfs); err != nil { + return newSystemError(err) +@@ -63,8 +67,10 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) { + if err != nil { + return newSystemError(err) + } +- if err := reOpenDevNull(config.Rootfs); err != nil { +- return newSystemError(err) ++ if !setupDev { ++ if err := reOpenDevNull(config.Rootfs); err != nil { ++ return newSystemError(err) ++ } + } + if config.Readonlyfs { + if err := setReadonly(); err != nil { diff --git a/docker.spec b/docker.spec index 04061e8..e02a1cf 100644 --- a/docker.spec +++ b/docker.spec @@ -34,7 +34,7 @@ %if 0%{?with_selinux} # docker-selinux stuff (prefix with ds_ for version/release etc.) # Some bits borrowed from the openstack-selinux package -%global ds_commit 2ed73eb5066f2a4e0e7fa84c260816d754433bc6 +%global ds_commit 44abd21628c8f4c054343f12d609d03de4644234 %global ds_shortcommit %(c=%{ds_commit}; echo ${c:0:7}) %global selinuxtype targeted %global moduletype services @@ -58,7 +58,7 @@ Name: %{repo} Version: 1.8.2 -Release: 6.git%{d_shortcommit}%{?dist} +Release: 7.git%{d_shortcommit}%{?dist} Summary: Automates deployment of containerized applications License: ASL 2.0 URL: http://www.%{repo}.com @@ -599,6 +599,12 @@ fi %{_bindir}/%{repo}tarsum %changelog +* Mon Oct 12 2015 Lokesh Mandvekar - 1.8.2-7.gitcb216be +- built docker @rhatdan/fedora-1.8 commit#cb216be +- built docker-selinux master commit#44abd21 +- built d-s-s master commit#6898d43 +- built docker-utils master commit#dab51ac + * Thu Oct 01 2015 Lokesh Mandvekar - 1.8.2-6.gitcb216be - built docker @rhatdan/fedora-1.8 commit#cb216be - built docker-selinux master commit#2ed73eb diff --git a/libcontainer.patch b/libcontainer.patch new file mode 100644 index 0000000..488507e --- /dev/null +++ b/libcontainer.patch @@ -0,0 +1,552 @@ +From 60cabaf0b8591b8e2bf6644114d8846adaf3239b Mon Sep 17 00:00:00 2001 +From: Mrunal Patel +Date: Fri, 9 Oct 2015 17:48:51 -0400 +Subject: [PATCH] Pick latest changes to libcontainer/user package + +Signed-off-by: Mrunal Patel +--- + .../opencontainers/runc/libcontainer/user/user.go | 39 +- + .../runc/libcontainer/user/user_test.go | 472 +++++++++++++++++++++ + 2 files changed, 494 insertions(+), 17 deletions(-) + create mode 100644 vendor/src/github.com/opencontainers/runc/libcontainer/user/user_test.go + +diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/user/user.go b/vendor/src/github.com/opencontainers/runc/libcontainer/user/user.go +index 964e31b..e6375ea 100644 +--- a/vendor/src/github.com/opencontainers/runc/libcontainer/user/user.go ++++ b/vendor/src/github.com/opencontainers/runc/libcontainer/user/user.go +@@ -349,21 +349,26 @@ func GetExecUser(userSpec string, defaults *ExecUser, passwd, group io.Reader) ( + return user, nil + } + +-// GetAdditionalGroups looks up a list of groups by name or group id against +-// against the given /etc/group formatted data. If a group name cannot be found, +-// an error will be returned. If a group id cannot be found, it will be returned +-// as-is. ++// GetAdditionalGroups looks up a list of groups by name or group id ++// against the given /etc/group formatted data. If a group name cannot ++// be found, an error will be returned. If a group id cannot be found, ++// or the given group data is nil, the id will be returned as-is ++// provided it is in the legal range. + func GetAdditionalGroups(additionalGroups []string, group io.Reader) ([]int, error) { +- groups, err := ParseGroupFilter(group, func(g Group) bool { +- for _, ag := range additionalGroups { +- if g.Name == ag || strconv.Itoa(g.Gid) == ag { +- return true ++ var groups = []Group{} ++ if group != nil { ++ var err error ++ groups, err = ParseGroupFilter(group, func(g Group) bool { ++ for _, ag := range additionalGroups { ++ if g.Name == ag || strconv.Itoa(g.Gid) == ag { ++ return true ++ } + } ++ return false ++ }) ++ if err != nil { ++ return nil, fmt.Errorf("Unable to find additional groups %v: %v", additionalGroups, err) + } +- return false +- }) +- if err != nil { +- return nil, fmt.Errorf("Unable to find additional groups %v: %v", additionalGroups, err) + } + + gidMap := make(map[int]struct{}) +@@ -401,13 +406,13 @@ func GetAdditionalGroups(additionalGroups []string, group io.Reader) ([]int, err + return gids, nil + } + +-// Wrapper around GetAdditionalGroups that opens the groupPath given and gives +-// it as an argument to GetAdditionalGroups. ++// GetAdditionalGroupsPath is a wrapper around GetAdditionalGroups ++// that opens the groupPath given and gives it as an argument to ++// GetAdditionalGroups. + func GetAdditionalGroupsPath(additionalGroups []string, groupPath string) ([]int, error) { + group, err := os.Open(groupPath) +- if err != nil { +- return nil, fmt.Errorf("Failed to open group file: %v", err) ++ if err == nil { ++ defer group.Close() + } +- defer group.Close() + return GetAdditionalGroups(additionalGroups, group) + } +diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/user/user_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/user/user_test.go +new file mode 100644 +index 0000000..53b2289 +--- /dev/null ++++ b/vendor/src/github.com/opencontainers/runc/libcontainer/user/user_test.go +@@ -0,0 +1,472 @@ ++package user ++ ++import ( ++ "io" ++ "reflect" ++ "sort" ++ "strconv" ++ "strings" ++ "testing" ++) ++ ++func TestUserParseLine(t *testing.T) { ++ var ( ++ a, b string ++ c []string ++ d int ++ ) ++ ++ parseLine("", &a, &b) ++ if a != "" || b != "" { ++ t.Fatalf("a and b should be empty ('%v', '%v')", a, b) ++ } ++ ++ parseLine("a", &a, &b) ++ if a != "a" || b != "" { ++ t.Fatalf("a should be 'a' and b should be empty ('%v', '%v')", a, b) ++ } ++ ++ parseLine("bad boys:corny cows", &a, &b) ++ if a != "bad boys" || b != "corny cows" { ++ t.Fatalf("a should be 'bad boys' and b should be 'corny cows' ('%v', '%v')", a, b) ++ } ++ ++ parseLine("", &c) ++ if len(c) != 0 { ++ t.Fatalf("c should be empty (%#v)", c) ++ } ++ ++ parseLine("d,e,f:g:h:i,j,k", &c, &a, &b, &c) ++ if a != "g" || b != "h" || len(c) != 3 || c[0] != "i" || c[1] != "j" || c[2] != "k" { ++ t.Fatalf("a should be 'g', b should be 'h', and c should be ['i','j','k'] ('%v', '%v', '%#v')", a, b, c) ++ } ++ ++ parseLine("::::::::::", &a, &b, &c) ++ if a != "" || b != "" || len(c) != 0 { ++ t.Fatalf("a, b, and c should all be empty ('%v', '%v', '%#v')", a, b, c) ++ } ++ ++ parseLine("not a number", &d) ++ if d != 0 { ++ t.Fatalf("d should be 0 (%v)", d) ++ } ++ ++ parseLine("b:12:c", &a, &d, &b) ++ if a != "b" || b != "c" || d != 12 { ++ t.Fatalf("a should be 'b' and b should be 'c', and d should be 12 ('%v', '%v', %v)", a, b, d) ++ } ++} ++ ++func TestUserParsePasswd(t *testing.T) { ++ users, err := ParsePasswdFilter(strings.NewReader(` ++root:x:0:0:root:/root:/bin/bash ++adm:x:3:4:adm:/var/adm:/bin/false ++this is just some garbage data ++`), nil) ++ if err != nil { ++ t.Fatalf("Unexpected error: %v", err) ++ } ++ if len(users) != 3 { ++ t.Fatalf("Expected 3 users, got %v", len(users)) ++ } ++ if users[0].Uid != 0 || users[0].Name != "root" { ++ t.Fatalf("Expected users[0] to be 0 - root, got %v - %v", users[0].Uid, users[0].Name) ++ } ++ if users[1].Uid != 3 || users[1].Name != "adm" { ++ t.Fatalf("Expected users[1] to be 3 - adm, got %v - %v", users[1].Uid, users[1].Name) ++ } ++} ++ ++func TestUserParseGroup(t *testing.T) { ++ groups, err := ParseGroupFilter(strings.NewReader(` ++root:x:0:root ++adm:x:4:root,adm,daemon ++this is just some garbage data ++`), nil) ++ if err != nil { ++ t.Fatalf("Unexpected error: %v", err) ++ } ++ if len(groups) != 3 { ++ t.Fatalf("Expected 3 groups, got %v", len(groups)) ++ } ++ if groups[0].Gid != 0 || groups[0].Name != "root" || len(groups[0].List) != 1 { ++ t.Fatalf("Expected groups[0] to be 0 - root - 1 member, got %v - %v - %v", groups[0].Gid, groups[0].Name, len(groups[0].List)) ++ } ++ if groups[1].Gid != 4 || groups[1].Name != "adm" || len(groups[1].List) != 3 { ++ t.Fatalf("Expected groups[1] to be 4 - adm - 3 members, got %v - %v - %v", groups[1].Gid, groups[1].Name, len(groups[1].List)) ++ } ++} ++ ++func TestValidGetExecUser(t *testing.T) { ++ const passwdContent = ` ++root:x:0:0:root user:/root:/bin/bash ++adm:x:42:43:adm:/var/adm:/bin/false ++this is just some garbage data ++` ++ const groupContent = ` ++root:x:0:root ++adm:x:43: ++grp:x:1234:root,adm ++this is just some garbage data ++` ++ defaultExecUser := ExecUser{ ++ Uid: 8888, ++ Gid: 8888, ++ Sgids: []int{8888}, ++ Home: "/8888", ++ } ++ ++ tests := []struct { ++ ref string ++ expected ExecUser ++ }{ ++ { ++ ref: "root", ++ expected: ExecUser{ ++ Uid: 0, ++ Gid: 0, ++ Sgids: []int{0, 1234}, ++ Home: "/root", ++ }, ++ }, ++ { ++ ref: "adm", ++ expected: ExecUser{ ++ Uid: 42, ++ Gid: 43, ++ Sgids: []int{1234}, ++ Home: "/var/adm", ++ }, ++ }, ++ { ++ ref: "root:adm", ++ expected: ExecUser{ ++ Uid: 0, ++ Gid: 43, ++ Sgids: defaultExecUser.Sgids, ++ Home: "/root", ++ }, ++ }, ++ { ++ ref: "adm:1234", ++ expected: ExecUser{ ++ Uid: 42, ++ Gid: 1234, ++ Sgids: defaultExecUser.Sgids, ++ Home: "/var/adm", ++ }, ++ }, ++ { ++ ref: "42:1234", ++ expected: ExecUser{ ++ Uid: 42, ++ Gid: 1234, ++ Sgids: defaultExecUser.Sgids, ++ Home: "/var/adm", ++ }, ++ }, ++ { ++ ref: "1337:1234", ++ expected: ExecUser{ ++ Uid: 1337, ++ Gid: 1234, ++ Sgids: defaultExecUser.Sgids, ++ Home: defaultExecUser.Home, ++ }, ++ }, ++ { ++ ref: "1337", ++ expected: ExecUser{ ++ Uid: 1337, ++ Gid: defaultExecUser.Gid, ++ Sgids: defaultExecUser.Sgids, ++ Home: defaultExecUser.Home, ++ }, ++ }, ++ { ++ ref: "", ++ expected: ExecUser{ ++ Uid: defaultExecUser.Uid, ++ Gid: defaultExecUser.Gid, ++ Sgids: defaultExecUser.Sgids, ++ Home: defaultExecUser.Home, ++ }, ++ }, ++ } ++ ++ for _, test := range tests { ++ passwd := strings.NewReader(passwdContent) ++ group := strings.NewReader(groupContent) ++ ++ execUser, err := GetExecUser(test.ref, &defaultExecUser, passwd, group) ++ if err != nil { ++ t.Logf("got unexpected error when parsing '%s': %s", test.ref, err.Error()) ++ t.Fail() ++ continue ++ } ++ ++ if !reflect.DeepEqual(test.expected, *execUser) { ++ t.Logf("got: %#v", execUser) ++ t.Logf("expected: %#v", test.expected) ++ t.Fail() ++ continue ++ } ++ } ++} ++ ++func TestInvalidGetExecUser(t *testing.T) { ++ const passwdContent = ` ++root:x:0:0:root user:/root:/bin/bash ++adm:x:42:43:adm:/var/adm:/bin/false ++this is just some garbage data ++` ++ const groupContent = ` ++root:x:0:root ++adm:x:43: ++grp:x:1234:root,adm ++this is just some garbage data ++` ++ ++ tests := []string{ ++ // No such user/group. ++ "notuser", ++ "notuser:notgroup", ++ "root:notgroup", ++ "notuser:adm", ++ "8888:notgroup", ++ "notuser:8888", ++ ++ // Invalid user/group values. ++ "-1:0", ++ "0:-3", ++ "-5:-2", ++ } ++ ++ for _, test := range tests { ++ passwd := strings.NewReader(passwdContent) ++ group := strings.NewReader(groupContent) ++ ++ execUser, err := GetExecUser(test, nil, passwd, group) ++ if err == nil { ++ t.Logf("got unexpected success when parsing '%s': %#v", test, execUser) ++ t.Fail() ++ continue ++ } ++ } ++} ++ ++func TestGetExecUserNilSources(t *testing.T) { ++ const passwdContent = ` ++root:x:0:0:root user:/root:/bin/bash ++adm:x:42:43:adm:/var/adm:/bin/false ++this is just some garbage data ++` ++ const groupContent = ` ++root:x:0:root ++adm:x:43: ++grp:x:1234:root,adm ++this is just some garbage data ++` ++ ++ defaultExecUser := ExecUser{ ++ Uid: 8888, ++ Gid: 8888, ++ Sgids: []int{8888}, ++ Home: "/8888", ++ } ++ ++ tests := []struct { ++ ref string ++ passwd, group bool ++ expected ExecUser ++ }{ ++ { ++ ref: "", ++ passwd: false, ++ group: false, ++ expected: ExecUser{ ++ Uid: 8888, ++ Gid: 8888, ++ Sgids: []int{8888}, ++ Home: "/8888", ++ }, ++ }, ++ { ++ ref: "root", ++ passwd: true, ++ group: false, ++ expected: ExecUser{ ++ Uid: 0, ++ Gid: 0, ++ Sgids: []int{8888}, ++ Home: "/root", ++ }, ++ }, ++ { ++ ref: "0", ++ passwd: false, ++ group: false, ++ expected: ExecUser{ ++ Uid: 0, ++ Gid: 8888, ++ Sgids: []int{8888}, ++ Home: "/8888", ++ }, ++ }, ++ { ++ ref: "0:0", ++ passwd: false, ++ group: false, ++ expected: ExecUser{ ++ Uid: 0, ++ Gid: 0, ++ Sgids: []int{8888}, ++ Home: "/8888", ++ }, ++ }, ++ } ++ ++ for _, test := range tests { ++ var passwd, group io.Reader ++ ++ if test.passwd { ++ passwd = strings.NewReader(passwdContent) ++ } ++ ++ if test.group { ++ group = strings.NewReader(groupContent) ++ } ++ ++ execUser, err := GetExecUser(test.ref, &defaultExecUser, passwd, group) ++ if err != nil { ++ t.Logf("got unexpected error when parsing '%s': %s", test.ref, err.Error()) ++ t.Fail() ++ continue ++ } ++ ++ if !reflect.DeepEqual(test.expected, *execUser) { ++ t.Logf("got: %#v", execUser) ++ t.Logf("expected: %#v", test.expected) ++ t.Fail() ++ continue ++ } ++ } ++} ++ ++func TestGetAdditionalGroups(t *testing.T) { ++ const groupContent = ` ++root:x:0:root ++adm:x:43: ++grp:x:1234:root,adm ++adm:x:4343:root,adm-duplicate ++this is just some garbage data ++` ++ tests := []struct { ++ groups []string ++ expected []int ++ hasError bool ++ }{ ++ { ++ // empty group ++ groups: []string{}, ++ expected: []int{}, ++ }, ++ { ++ // single group ++ groups: []string{"adm"}, ++ expected: []int{43}, ++ }, ++ { ++ // multiple groups ++ groups: []string{"adm", "grp"}, ++ expected: []int{43, 1234}, ++ }, ++ { ++ // invalid group ++ groups: []string{"adm", "grp", "not-exist"}, ++ expected: nil, ++ hasError: true, ++ }, ++ { ++ // group with numeric id ++ groups: []string{"43"}, ++ expected: []int{43}, ++ }, ++ { ++ // group with unknown numeric id ++ groups: []string{"adm", "10001"}, ++ expected: []int{43, 10001}, ++ }, ++ { ++ // groups specified twice with numeric and name ++ groups: []string{"adm", "43"}, ++ expected: []int{43}, ++ }, ++ { ++ // groups with too small id ++ groups: []string{"-1"}, ++ expected: nil, ++ hasError: true, ++ }, ++ { ++ // groups with too large id ++ groups: []string{strconv.Itoa(1 << 31)}, ++ expected: nil, ++ hasError: true, ++ }, ++ } ++ ++ for _, test := range tests { ++ group := strings.NewReader(groupContent) ++ ++ gids, err := GetAdditionalGroups(test.groups, group) ++ if test.hasError && err == nil { ++ t.Errorf("Parse(%#v) expects error but has none", test) ++ continue ++ } ++ if !test.hasError && err != nil { ++ t.Errorf("Parse(%#v) has error %v", test, err) ++ continue ++ } ++ sort.Sort(sort.IntSlice(gids)) ++ if !reflect.DeepEqual(gids, test.expected) { ++ t.Errorf("Gids(%v), expect %v from groups %v", gids, test.expected, test.groups) ++ } ++ } ++} ++ ++func TestGetAdditionalGroupsNumeric(t *testing.T) { ++ tests := []struct { ++ groups []string ++ expected []int ++ hasError bool ++ }{ ++ { ++ // numeric groups only ++ groups: []string{"1234", "5678"}, ++ expected: []int{1234, 5678}, ++ }, ++ { ++ // numeric and alphabetic ++ groups: []string{"1234", "fake"}, ++ expected: nil, ++ hasError: true, ++ }, ++ } ++ ++ for _, test := range tests { ++ gids, err := GetAdditionalGroups(test.groups, nil) ++ if test.hasError && err == nil { ++ t.Errorf("Parse(%#v) expects error but has none", test) ++ continue ++ } ++ if !test.hasError && err != nil { ++ t.Errorf("Parse(%#v) has error %v", test, err) ++ continue ++ } ++ sort.Sort(sort.IntSlice(gids)) ++ if !reflect.DeepEqual(gids, test.expected) { ++ t.Errorf("Gids(%v), expect %v from groups %v", gids, test.expected, test.groups) ++ } ++ } ++} diff --git a/sources b/sources index aca6bcb..2493007 100644 --- a/sources +++ b/sources @@ -1,4 +1,4 @@ 41de66f15f8151b1cb81b8d88c14d0e1 dab51acd1b1a77f7cb01a1b7e2129ec85c846b71.tar.gz b5b973bc59532bc041ddbcc797320520 docker-cb216be.tar.gz -c376da46c3ddee1dfa1c54f4b55f6c9a docker-selinux-2ed73eb.tar.gz +aa8093d35c0aac13d36558c9e81d2aaa docker-selinux-44abd21.tar.gz 7c4fa628f7ee14d88785f36c2163da64 docker-storage-setup-6898d43.tar.gz