Browse code

Fixes for libcontainer changes

Libcontainer no longer provides placeholders for
unsupported platforms, which cause the Windows
builds to fail.

This patch moves features that are not supported
to platform-specific files.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2018/01/13 10:57:50
Showing 6 changed files
... ...
@@ -12,7 +12,6 @@ import (
12 12
 	"path"
13 13
 	"path/filepath"
14 14
 	"runtime"
15
-	"strconv"
16 15
 	"strings"
17 16
 
18 17
 	"github.com/docker/docker/api/types"
... ...
@@ -24,10 +23,8 @@ import (
24 24
 	"github.com/docker/docker/pkg/containerfs"
25 25
 	"github.com/docker/docker/pkg/idtools"
26 26
 	"github.com/docker/docker/pkg/stringid"
27
-	"github.com/docker/docker/pkg/symlink"
28 27
 	"github.com/docker/docker/pkg/system"
29 28
 	"github.com/docker/go-connections/nat"
30
-	lcUser "github.com/opencontainers/runc/libcontainer/user"
31 29
 	"github.com/pkg/errors"
32 30
 )
33 31
 
... ...
@@ -217,82 +214,6 @@ func (b *Builder) performCopy(state *dispatchState, inst copyInstruction) error
217 217
 	return b.exportImage(state, imageMount, runConfigWithCommentCmd)
218 218
 }
219 219
 
220
-func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) {
221
-	var userStr, grpStr string
222
-	parts := strings.Split(chown, ":")
223
-	if len(parts) > 2 {
224
-		return idtools.IDPair{}, errors.New("invalid chown string format: " + chown)
225
-	}
226
-	if len(parts) == 1 {
227
-		// if no group specified, use the user spec as group as well
228
-		userStr, grpStr = parts[0], parts[0]
229
-	} else {
230
-		userStr, grpStr = parts[0], parts[1]
231
-	}
232
-
233
-	passwdPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "passwd"), ctrRootPath)
234
-	if err != nil {
235
-		return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/passwd path in container rootfs")
236
-	}
237
-	groupPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "group"), ctrRootPath)
238
-	if err != nil {
239
-		return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/group path in container rootfs")
240
-	}
241
-	uid, err := lookupUser(userStr, passwdPath)
242
-	if err != nil {
243
-		return idtools.IDPair{}, errors.Wrapf(err, "can't find uid for user "+userStr)
244
-	}
245
-	gid, err := lookupGroup(grpStr, groupPath)
246
-	if err != nil {
247
-		return idtools.IDPair{}, errors.Wrapf(err, "can't find gid for group "+grpStr)
248
-	}
249
-
250
-	// convert as necessary because of user namespaces
251
-	chownPair, err := idMappings.ToHost(idtools.IDPair{UID: uid, GID: gid})
252
-	if err != nil {
253
-		return idtools.IDPair{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
254
-	}
255
-	return chownPair, nil
256
-}
257
-
258
-func lookupUser(userStr, filepath string) (int, error) {
259
-	// if the string is actually a uid integer, parse to int and return
260
-	// as we don't need to translate with the help of files
261
-	uid, err := strconv.Atoi(userStr)
262
-	if err == nil {
263
-		return uid, nil
264
-	}
265
-	users, err := lcUser.ParsePasswdFileFilter(filepath, func(u lcUser.User) bool {
266
-		return u.Name == userStr
267
-	})
268
-	if err != nil {
269
-		return 0, err
270
-	}
271
-	if len(users) == 0 {
272
-		return 0, errors.New("no such user: " + userStr)
273
-	}
274
-	return users[0].Uid, nil
275
-}
276
-
277
-func lookupGroup(groupStr, filepath string) (int, error) {
278
-	// if the string is actually a gid integer, parse to int and return
279
-	// as we don't need to translate with the help of files
280
-	gid, err := strconv.Atoi(groupStr)
281
-	if err == nil {
282
-		return gid, nil
283
-	}
284
-	groups, err := lcUser.ParseGroupFileFilter(filepath, func(g lcUser.Group) bool {
285
-		return g.Name == groupStr
286
-	})
287
-	if err != nil {
288
-		return 0, err
289
-	}
290
-	if len(groups) == 0 {
291
-		return 0, errors.New("no such group: " + groupStr)
292
-	}
293
-	return groups[0].Gid, nil
294
-}
295
-
296 220
 func createDestInfo(workingDir string, inst copyInstruction, imageMount *imageMount, platform string) (copyInfo, error) {
297 221
 	// Twiddle the destination when it's a relative path - meaning, make it
298 222
 	// relative to the WORKINGDIR
299 223
new file mode 100644
... ...
@@ -0,0 +1,88 @@
0
+package dockerfile
1
+
2
+import (
3
+	"path/filepath"
4
+	"strconv"
5
+	"strings"
6
+
7
+	"github.com/docker/docker/pkg/idtools"
8
+	"github.com/docker/docker/pkg/symlink"
9
+	lcUser "github.com/opencontainers/runc/libcontainer/user"
10
+	"github.com/pkg/errors"
11
+)
12
+
13
+func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) {
14
+	var userStr, grpStr string
15
+	parts := strings.Split(chown, ":")
16
+	if len(parts) > 2 {
17
+		return idtools.IDPair{}, errors.New("invalid chown string format: " + chown)
18
+	}
19
+	if len(parts) == 1 {
20
+		// if no group specified, use the user spec as group as well
21
+		userStr, grpStr = parts[0], parts[0]
22
+	} else {
23
+		userStr, grpStr = parts[0], parts[1]
24
+	}
25
+
26
+	passwdPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "passwd"), ctrRootPath)
27
+	if err != nil {
28
+		return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/passwd path in container rootfs")
29
+	}
30
+	groupPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "group"), ctrRootPath)
31
+	if err != nil {
32
+		return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/group path in container rootfs")
33
+	}
34
+	uid, err := lookupUser(userStr, passwdPath)
35
+	if err != nil {
36
+		return idtools.IDPair{}, errors.Wrapf(err, "can't find uid for user "+userStr)
37
+	}
38
+	gid, err := lookupGroup(grpStr, groupPath)
39
+	if err != nil {
40
+		return idtools.IDPair{}, errors.Wrapf(err, "can't find gid for group "+grpStr)
41
+	}
42
+
43
+	// convert as necessary because of user namespaces
44
+	chownPair, err := idMappings.ToHost(idtools.IDPair{UID: uid, GID: gid})
45
+	if err != nil {
46
+		return idtools.IDPair{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
47
+	}
48
+	return chownPair, nil
49
+}
50
+
51
+func lookupUser(userStr, filepath string) (int, error) {
52
+	// if the string is actually a uid integer, parse to int and return
53
+	// as we don't need to translate with the help of files
54
+	uid, err := strconv.Atoi(userStr)
55
+	if err == nil {
56
+		return uid, nil
57
+	}
58
+	users, err := lcUser.ParsePasswdFileFilter(filepath, func(u lcUser.User) bool {
59
+		return u.Name == userStr
60
+	})
61
+	if err != nil {
62
+		return 0, err
63
+	}
64
+	if len(users) == 0 {
65
+		return 0, errors.New("no such user: " + userStr)
66
+	}
67
+	return users[0].Uid, nil
68
+}
69
+
70
+func lookupGroup(groupStr, filepath string) (int, error) {
71
+	// if the string is actually a gid integer, parse to int and return
72
+	// as we don't need to translate with the help of files
73
+	gid, err := strconv.Atoi(groupStr)
74
+	if err == nil {
75
+		return gid, nil
76
+	}
77
+	groups, err := lcUser.ParseGroupFileFilter(filepath, func(g lcUser.Group) bool {
78
+		return g.Name == groupStr
79
+	})
80
+	if err != nil {
81
+		return 0, err
82
+	}
83
+	if len(groups) == 0 {
84
+		return 0, errors.New("no such group: " + groupStr)
85
+	}
86
+	return groups[0].Gid, nil
87
+}
0 88
new file mode 100644
... ...
@@ -0,0 +1,138 @@
0
+package dockerfile
1
+
2
+import (
3
+	"os"
4
+	"path/filepath"
5
+	"testing"
6
+
7
+	"github.com/docker/docker/pkg/idtools"
8
+	"github.com/stretchr/testify/assert"
9
+	"github.com/stretchr/testify/require"
10
+)
11
+
12
+func TestChownFlagParsing(t *testing.T) {
13
+	testFiles := map[string]string{
14
+		"passwd": `root:x:0:0::/bin:/bin/false
15
+bin:x:1:1::/bin:/bin/false
16
+wwwwww:x:21:33::/bin:/bin/false
17
+unicorn:x:1001:1002::/bin:/bin/false
18
+		`,
19
+		"group": `root:x:0:
20
+bin:x:1:
21
+wwwwww:x:33:
22
+unicorn:x:1002:
23
+somegrp:x:5555:
24
+othergrp:x:6666:
25
+		`,
26
+	}
27
+	// test mappings for validating use of maps
28
+	idMaps := []idtools.IDMap{
29
+		{
30
+			ContainerID: 0,
31
+			HostID:      100000,
32
+			Size:        65536,
33
+		},
34
+	}
35
+	remapped := idtools.NewIDMappingsFromMaps(idMaps, idMaps)
36
+	unmapped := &idtools.IDMappings{}
37
+
38
+	contextDir, cleanup := createTestTempDir(t, "", "builder-chown-parse-test")
39
+	defer cleanup()
40
+
41
+	if err := os.Mkdir(filepath.Join(contextDir, "etc"), 0755); err != nil {
42
+		t.Fatalf("error creating test directory: %v", err)
43
+	}
44
+
45
+	for filename, content := range testFiles {
46
+		createTestTempFile(t, filepath.Join(contextDir, "etc"), filename, content, 0644)
47
+	}
48
+
49
+	// positive tests
50
+	for _, testcase := range []struct {
51
+		name      string
52
+		chownStr  string
53
+		idMapping *idtools.IDMappings
54
+		expected  idtools.IDPair
55
+	}{
56
+		{
57
+			name:      "UIDNoMap",
58
+			chownStr:  "1",
59
+			idMapping: unmapped,
60
+			expected:  idtools.IDPair{UID: 1, GID: 1},
61
+		},
62
+		{
63
+			name:      "UIDGIDNoMap",
64
+			chownStr:  "0:1",
65
+			idMapping: unmapped,
66
+			expected:  idtools.IDPair{UID: 0, GID: 1},
67
+		},
68
+		{
69
+			name:      "UIDWithMap",
70
+			chownStr:  "0",
71
+			idMapping: remapped,
72
+			expected:  idtools.IDPair{UID: 100000, GID: 100000},
73
+		},
74
+		{
75
+			name:      "UIDGIDWithMap",
76
+			chownStr:  "1:33",
77
+			idMapping: remapped,
78
+			expected:  idtools.IDPair{UID: 100001, GID: 100033},
79
+		},
80
+		{
81
+			name:      "UserNoMap",
82
+			chownStr:  "bin:5555",
83
+			idMapping: unmapped,
84
+			expected:  idtools.IDPair{UID: 1, GID: 5555},
85
+		},
86
+		{
87
+			name:      "GroupWithMap",
88
+			chownStr:  "0:unicorn",
89
+			idMapping: remapped,
90
+			expected:  idtools.IDPair{UID: 100000, GID: 101002},
91
+		},
92
+		{
93
+			name:      "UserOnlyWithMap",
94
+			chownStr:  "unicorn",
95
+			idMapping: remapped,
96
+			expected:  idtools.IDPair{UID: 101001, GID: 101002},
97
+		},
98
+	} {
99
+		t.Run(testcase.name, func(t *testing.T) {
100
+			idPair, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping)
101
+			require.NoError(t, err, "Failed to parse chown flag: %q", testcase.chownStr)
102
+			assert.Equal(t, testcase.expected, idPair, "chown flag mapping failure")
103
+		})
104
+	}
105
+
106
+	// error tests
107
+	for _, testcase := range []struct {
108
+		name      string
109
+		chownStr  string
110
+		idMapping *idtools.IDMappings
111
+		descr     string
112
+	}{
113
+		{
114
+			name:      "BadChownFlagFormat",
115
+			chownStr:  "bob:1:555",
116
+			idMapping: unmapped,
117
+			descr:     "invalid chown string format: bob:1:555",
118
+		},
119
+		{
120
+			name:      "UserNoExist",
121
+			chownStr:  "bob",
122
+			idMapping: unmapped,
123
+			descr:     "can't find uid for user bob: no such user: bob",
124
+		},
125
+		{
126
+			name:      "GroupNoExist",
127
+			chownStr:  "root:bob",
128
+			idMapping: unmapped,
129
+			descr:     "can't find gid for group bob: no such group: bob",
130
+		},
131
+	} {
132
+		t.Run(testcase.name, func(t *testing.T) {
133
+			_, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping)
134
+			assert.EqualError(t, err, testcase.descr, "Expected error string doesn't match")
135
+		})
136
+	}
137
+}
... ...
@@ -2,8 +2,6 @@ package dockerfile
2 2
 
3 3
 import (
4 4
 	"fmt"
5
-	"os"
6
-	"path/filepath"
7 5
 	"runtime"
8 6
 	"testing"
9 7
 
... ...
@@ -13,7 +11,6 @@ import (
13 13
 	"github.com/docker/docker/builder"
14 14
 	"github.com/docker/docker/builder/remotecontext"
15 15
 	"github.com/docker/docker/pkg/archive"
16
-	"github.com/docker/docker/pkg/idtools"
17 16
 	"github.com/docker/go-connections/nat"
18 17
 	"github.com/stretchr/testify/assert"
19 18
 	"github.com/stretchr/testify/require"
... ...
@@ -171,130 +168,3 @@ func TestDeepCopyRunConfig(t *testing.T) {
171 171
 	copy.Shell[0] = "sh"
172 172
 	assert.Equal(t, fullMutableRunConfig(), runConfig)
173 173
 }
174
-
175
-func TestChownFlagParsing(t *testing.T) {
176
-	testFiles := map[string]string{
177
-		"passwd": `root:x:0:0::/bin:/bin/false
178
-bin:x:1:1::/bin:/bin/false
179
-wwwwww:x:21:33::/bin:/bin/false
180
-unicorn:x:1001:1002::/bin:/bin/false
181
-		`,
182
-		"group": `root:x:0:
183
-bin:x:1:
184
-wwwwww:x:33:
185
-unicorn:x:1002:
186
-somegrp:x:5555:
187
-othergrp:x:6666:
188
-		`,
189
-	}
190
-	// test mappings for validating use of maps
191
-	idMaps := []idtools.IDMap{
192
-		{
193
-			ContainerID: 0,
194
-			HostID:      100000,
195
-			Size:        65536,
196
-		},
197
-	}
198
-	remapped := idtools.NewIDMappingsFromMaps(idMaps, idMaps)
199
-	unmapped := &idtools.IDMappings{}
200
-
201
-	contextDir, cleanup := createTestTempDir(t, "", "builder-chown-parse-test")
202
-	defer cleanup()
203
-
204
-	if err := os.Mkdir(filepath.Join(contextDir, "etc"), 0755); err != nil {
205
-		t.Fatalf("error creating test directory: %v", err)
206
-	}
207
-
208
-	for filename, content := range testFiles {
209
-		createTestTempFile(t, filepath.Join(contextDir, "etc"), filename, content, 0644)
210
-	}
211
-
212
-	// positive tests
213
-	for _, testcase := range []struct {
214
-		name      string
215
-		chownStr  string
216
-		idMapping *idtools.IDMappings
217
-		expected  idtools.IDPair
218
-	}{
219
-		{
220
-			name:      "UIDNoMap",
221
-			chownStr:  "1",
222
-			idMapping: unmapped,
223
-			expected:  idtools.IDPair{UID: 1, GID: 1},
224
-		},
225
-		{
226
-			name:      "UIDGIDNoMap",
227
-			chownStr:  "0:1",
228
-			idMapping: unmapped,
229
-			expected:  idtools.IDPair{UID: 0, GID: 1},
230
-		},
231
-		{
232
-			name:      "UIDWithMap",
233
-			chownStr:  "0",
234
-			idMapping: remapped,
235
-			expected:  idtools.IDPair{UID: 100000, GID: 100000},
236
-		},
237
-		{
238
-			name:      "UIDGIDWithMap",
239
-			chownStr:  "1:33",
240
-			idMapping: remapped,
241
-			expected:  idtools.IDPair{UID: 100001, GID: 100033},
242
-		},
243
-		{
244
-			name:      "UserNoMap",
245
-			chownStr:  "bin:5555",
246
-			idMapping: unmapped,
247
-			expected:  idtools.IDPair{UID: 1, GID: 5555},
248
-		},
249
-		{
250
-			name:      "GroupWithMap",
251
-			chownStr:  "0:unicorn",
252
-			idMapping: remapped,
253
-			expected:  idtools.IDPair{UID: 100000, GID: 101002},
254
-		},
255
-		{
256
-			name:      "UserOnlyWithMap",
257
-			chownStr:  "unicorn",
258
-			idMapping: remapped,
259
-			expected:  idtools.IDPair{UID: 101001, GID: 101002},
260
-		},
261
-	} {
262
-		t.Run(testcase.name, func(t *testing.T) {
263
-			idPair, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping)
264
-			require.NoError(t, err, "Failed to parse chown flag: %q", testcase.chownStr)
265
-			assert.Equal(t, testcase.expected, idPair, "chown flag mapping failure")
266
-		})
267
-	}
268
-
269
-	// error tests
270
-	for _, testcase := range []struct {
271
-		name      string
272
-		chownStr  string
273
-		idMapping *idtools.IDMappings
274
-		descr     string
275
-	}{
276
-		{
277
-			name:      "BadChownFlagFormat",
278
-			chownStr:  "bob:1:555",
279
-			idMapping: unmapped,
280
-			descr:     "invalid chown string format: bob:1:555",
281
-		},
282
-		{
283
-			name:      "UserNoExist",
284
-			chownStr:  "bob",
285
-			idMapping: unmapped,
286
-			descr:     "can't find uid for user bob: no such user: bob",
287
-		},
288
-		{
289
-			name:      "GroupNoExist",
290
-			chownStr:  "root:bob",
291
-			idMapping: unmapped,
292
-			descr:     "can't find gid for group bob: no such group: bob",
293
-		},
294
-	} {
295
-		t.Run(testcase.name, func(t *testing.T) {
296
-			_, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping)
297
-			assert.EqualError(t, err, testcase.descr, "Expected error string doesn't match")
298
-		})
299
-	}
300
-}
301 174
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+package dockerfile
1
+
2
+import "github.com/docker/docker/pkg/idtools"
3
+
4
+func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) {
5
+	return idMappings.RootPair(), nil
6
+}
... ...
@@ -36,7 +36,6 @@ import (
36 36
 	"github.com/docker/libnetwork/types"
37 37
 	"github.com/go-check/check"
38 38
 	"github.com/gotestyourself/gotestyourself/icmd"
39
-	libcontainerUser "github.com/opencontainers/runc/libcontainer/user"
40 39
 	"golang.org/x/net/context"
41 40
 )
42 41
 
... ...
@@ -751,7 +750,7 @@ func (s *DockerSuite) TestRunUserByIDBig(c *check.C) {
751 751
 	if err == nil {
752 752
 		c.Fatal("No error, but must be.", out)
753 753
 	}
754
-	if !strings.Contains(strings.ToUpper(out), strings.ToUpper(libcontainerUser.ErrRange.Error())) {
754
+	if !strings.Contains(strings.ToLower(out), "uids and gids must be in range") {
755 755
 		c.Fatalf("expected error about uids range, got %s", out)
756 756
 	}
757 757
 }
... ...
@@ -764,7 +763,7 @@ func (s *DockerSuite) TestRunUserByIDNegative(c *check.C) {
764 764
 	if err == nil {
765 765
 		c.Fatal("No error, but must be.", out)
766 766
 	}
767
-	if !strings.Contains(strings.ToUpper(out), strings.ToUpper(libcontainerUser.ErrRange.Error())) {
767
+	if !strings.Contains(strings.ToLower(out), "uids and gids must be in range") {
768 768
 		c.Fatalf("expected error about uids range, got %s", out)
769 769
 	}
770 770
 }