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>
(cherry picked from commit d1c34831e930c1f6b3de28cab3f4a358845a79d5)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
diff --git a/builder/dockerfile/internals.go b/builder/dockerfile/internals.go
index c38f48a..117d4e7 100644
--- a/builder/dockerfile/internals.go
+++ b/builder/dockerfile/internals.go
@@ -11,7 +11,6 @@
"os"
"path"
"path/filepath"
- "strconv"
"strings"
"github.com/docker/docker/api/types"
@@ -23,10 +22,8 @@
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/stringid"
- "github.com/docker/docker/pkg/symlink"
"github.com/docker/docker/pkg/system"
"github.com/docker/go-connections/nat"
- lcUser "github.com/opencontainers/runc/libcontainer/user"
"github.com/pkg/errors"
)
@@ -216,82 +213,6 @@
return b.exportImage(state, imageMount, runConfigWithCommentCmd)
}
-func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) {
- var userStr, grpStr string
- parts := strings.Split(chown, ":")
- if len(parts) > 2 {
- return idtools.IDPair{}, errors.New("invalid chown string format: " + chown)
- }
- if len(parts) == 1 {
- // if no group specified, use the user spec as group as well
- userStr, grpStr = parts[0], parts[0]
- } else {
- userStr, grpStr = parts[0], parts[1]
- }
-
- passwdPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "passwd"), ctrRootPath)
- if err != nil {
- return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/passwd path in container rootfs")
- }
- groupPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "group"), ctrRootPath)
- if err != nil {
- return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/group path in container rootfs")
- }
- uid, err := lookupUser(userStr, passwdPath)
- if err != nil {
- return idtools.IDPair{}, errors.Wrapf(err, "can't find uid for user "+userStr)
- }
- gid, err := lookupGroup(grpStr, groupPath)
- if err != nil {
- return idtools.IDPair{}, errors.Wrapf(err, "can't find gid for group "+grpStr)
- }
-
- // convert as necessary because of user namespaces
- chownPair, err := idMappings.ToHost(idtools.IDPair{UID: uid, GID: gid})
- if err != nil {
- return idtools.IDPair{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
- }
- return chownPair, nil
-}
-
-func lookupUser(userStr, filepath string) (int, error) {
- // if the string is actually a uid integer, parse to int and return
- // as we don't need to translate with the help of files
- uid, err := strconv.Atoi(userStr)
- if err == nil {
- return uid, nil
- }
- users, err := lcUser.ParsePasswdFileFilter(filepath, func(u lcUser.User) bool {
- return u.Name == userStr
- })
- if err != nil {
- return 0, err
- }
- if len(users) == 0 {
- return 0, errors.New("no such user: " + userStr)
- }
- return users[0].Uid, nil
-}
-
-func lookupGroup(groupStr, filepath string) (int, error) {
- // if the string is actually a gid integer, parse to int and return
- // as we don't need to translate with the help of files
- gid, err := strconv.Atoi(groupStr)
- if err == nil {
- return gid, nil
- }
- groups, err := lcUser.ParseGroupFileFilter(filepath, func(g lcUser.Group) bool {
- return g.Name == groupStr
- })
- if err != nil {
- return 0, err
- }
- if len(groups) == 0 {
- return 0, errors.New("no such group: " + groupStr)
- }
- return groups[0].Gid, nil
-}
-
func createDestInfo(workingDir string, inst copyInstruction, imageMount *imageMount, platform string) (copyInfo, error) {
// Twiddle the destination when it's a relative path - meaning, make it
// relative to the WORKINGDIR
diff --git a/builder/dockerfile/internals_linux.go b/builder/dockerfile/internals_linux.go
new file mode 100644
index 0000000..1314779
--- /dev/null
+++ b/builder/dockerfile/internals_linux.go
@@ -0,0 +1,88 @@
+package dockerfile
+
+import (
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ "github.com/docker/docker/pkg/idtools"
+ "github.com/docker/docker/pkg/symlink"
+ lcUser "github.com/opencontainers/runc/libcontainer/user"
+ "github.com/pkg/errors"
+)
+
+func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) {
+ var userStr, grpStr string
+ parts := strings.Split(chown, ":")
+ if len(parts) > 2 {
+ return idtools.IDPair{}, errors.New("invalid chown string format: " + chown)
+ }
+ if len(parts) == 1 {
+ // if no group specified, use the user spec as group as well
+ userStr, grpStr = parts[0], parts[0]
+ } else {
+ userStr, grpStr = parts[0], parts[1]
+ }
+
+ passwdPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "passwd"), ctrRootPath)
+ if err != nil {
+ return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/passwd path in container rootfs")
+ }
+ groupPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "group"), ctrRootPath)
+ if err != nil {
+ return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/group path in container rootfs")
+ }
+ uid, err := lookupUser(userStr, passwdPath)
+ if err != nil {
+ return idtools.IDPair{}, errors.Wrapf(err, "can't find uid for user "+userStr)
+ }
+ gid, err := lookupGroup(grpStr, groupPath)
+ if err != nil {
+ return idtools.IDPair{}, errors.Wrapf(err, "can't find gid for group "+grpStr)
+ }
+
+ // convert as necessary because of user namespaces
+ chownPair, err := idMappings.ToHost(idtools.IDPair{UID: uid, GID: gid})
+ if err != nil {
+ return idtools.IDPair{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
+ }
+ return chownPair, nil
+}
+
+func lookupUser(userStr, filepath string) (int, error) {
+ // if the string is actually a uid integer, parse to int and return
+ // as we don't need to translate with the help of files
+ uid, err := strconv.Atoi(userStr)
+ if err == nil {
+ return uid, nil
+ }
+ users, err := lcUser.ParsePasswdFileFilter(filepath, func(u lcUser.User) bool {
+ return u.Name == userStr
+ })
+ if err != nil {
+ return 0, err
+ }
+ if len(users) == 0 {
+ return 0, errors.New("no such user: " + userStr)
+ }
+ return users[0].Uid, nil
+}
+
+func lookupGroup(groupStr, filepath string) (int, error) {
+ // if the string is actually a gid integer, parse to int and return
+ // as we don't need to translate with the help of files
+ gid, err := strconv.Atoi(groupStr)
+ if err == nil {
+ return gid, nil
+ }
+ groups, err := lcUser.ParseGroupFileFilter(filepath, func(g lcUser.Group) bool {
+ return g.Name == groupStr
+ })
+ if err != nil {
+ return 0, err
+ }
+ if len(groups) == 0 {
+ return 0, errors.New("no such group: " + groupStr)
+ }
+ return groups[0].Gid, nil
+}
diff --git a/builder/dockerfile/internals_linux_test.go b/builder/dockerfile/internals_linux_test.go
new file mode 100644
index 0000000..dd23a33
--- /dev/null
+++ b/builder/dockerfile/internals_linux_test.go
@@ -0,0 +1,138 @@
+package dockerfile
+
+import (
+ "os"
+ "path/filepath"
+ "testing"
+
+ "github.com/docker/docker/pkg/idtools"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestChownFlagParsing(t *testing.T) {
+ testFiles := map[string]string{
+ "passwd": `root:x:0:0::/bin:/bin/false
+bin:x:1:1::/bin:/bin/false
+wwwwww:x:21:33::/bin:/bin/false
+unicorn:x:1001:1002::/bin:/bin/false
+ `,
+ "group": `root:x:0:
+bin:x:1:
+wwwwww:x:33:
+unicorn:x:1002:
+somegrp:x:5555:
+othergrp:x:6666:
+ `,
+ }
+ // test mappings for validating use of maps
+ idMaps := []idtools.IDMap{
+ {
+ ContainerID: 0,
+ HostID: 100000,
+ Size: 65536,
+ },
+ }
+ remapped := idtools.NewIDMappingsFromMaps(idMaps, idMaps)
+ unmapped := &idtools.IDMappings{}
+
+ contextDir, cleanup := createTestTempDir(t, "", "builder-chown-parse-test")
+ defer cleanup()
+
+ if err := os.Mkdir(filepath.Join(contextDir, "etc"), 0755); err != nil {
+ t.Fatalf("error creating test directory: %v", err)
+ }
+
+ for filename, content := range testFiles {
+ createTestTempFile(t, filepath.Join(contextDir, "etc"), filename, content, 0644)
+ }
+
+ // positive tests
+ for _, testcase := range []struct {
+ name string
+ chownStr string
+ idMapping *idtools.IDMappings
+ expected idtools.IDPair
+ }{
+ {
+ name: "UIDNoMap",
+ chownStr: "1",
+ idMapping: unmapped,
+ expected: idtools.IDPair{UID: 1, GID: 1},
+ },
+ {
+ name: "UIDGIDNoMap",
+ chownStr: "0:1",
+ idMapping: unmapped,
+ expected: idtools.IDPair{UID: 0, GID: 1},
+ },
+ {
+ name: "UIDWithMap",
+ chownStr: "0",
+ idMapping: remapped,
+ expected: idtools.IDPair{UID: 100000, GID: 100000},
+ },
+ {
+ name: "UIDGIDWithMap",
+ chownStr: "1:33",
+ idMapping: remapped,
+ expected: idtools.IDPair{UID: 100001, GID: 100033},
+ },
+ {
+ name: "UserNoMap",
+ chownStr: "bin:5555",
+ idMapping: unmapped,
+ expected: idtools.IDPair{UID: 1, GID: 5555},
+ },
+ {
+ name: "GroupWithMap",
+ chownStr: "0:unicorn",
+ idMapping: remapped,
+ expected: idtools.IDPair{UID: 100000, GID: 101002},
+ },
+ {
+ name: "UserOnlyWithMap",
+ chownStr: "unicorn",
+ idMapping: remapped,
+ expected: idtools.IDPair{UID: 101001, GID: 101002},
+ },
+ } {
+ t.Run(testcase.name, func(t *testing.T) {
+ idPair, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping)
+ require.NoError(t, err, "Failed to parse chown flag: %q", testcase.chownStr)
+ assert.Equal(t, testcase.expected, idPair, "chown flag mapping failure")
+ })
+ }
+
+ // error tests
+ for _, testcase := range []struct {
+ name string
+ chownStr string
+ idMapping *idtools.IDMappings
+ descr string
+ }{
+ {
+ name: "BadChownFlagFormat",
+ chownStr: "bob:1:555",
+ idMapping: unmapped,
+ descr: "invalid chown string format: bob:1:555",
+ },
+ {
+ name: "UserNoExist",
+ chownStr: "bob",
+ idMapping: unmapped,
+ descr: "can't find uid for user bob: no such user: bob",
+ },
+ {
+ name: "GroupNoExist",
+ chownStr: "root:bob",
+ idMapping: unmapped,
+ descr: "can't find gid for group bob: no such group: bob",
+ },
+ } {
+ t.Run(testcase.name, func(t *testing.T) {
+ _, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping)
+ assert.EqualError(t, err, testcase.descr, "Expected error string doesn't match")
+ })
+ }
+}
diff --git a/builder/dockerfile/internals_test.go b/builder/dockerfile/internals_test.go
index 83a207c..04c8c4b 100644
--- a/builder/dockerfile/internals_test.go
+++ b/builder/dockerfile/internals_test.go
@@ -2,8 +2,6 @@
import (
"fmt"
- "os"
- "path/filepath"
"runtime"
"testing"
@@ -13,7 +11,6 @@
"github.com/docker/docker/builder"
"github.com/docker/docker/builder/remotecontext"
"github.com/docker/docker/pkg/archive"
- "github.com/docker/docker/pkg/idtools"
"github.com/docker/go-connections/nat"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -171,130 +168,3 @@
copy.Shell[0] = "sh"
assert.Equal(t, fullMutableRunConfig(), runConfig)
}
-
-func TestChownFlagParsing(t *testing.T) {
- testFiles := map[string]string{
- "passwd": `root:x:0:0::/bin:/bin/false
-bin:x:1:1::/bin:/bin/false
-wwwwww:x:21:33::/bin:/bin/false
-unicorn:x:1001:1002::/bin:/bin/false
- `,
- "group": `root:x:0:
-bin:x:1:
-wwwwww:x:33:
-unicorn:x:1002:
-somegrp:x:5555:
-othergrp:x:6666:
- `,
- }
- // test mappings for validating use of maps
- idMaps := []idtools.IDMap{
- {
- ContainerID: 0,
- HostID: 100000,
- Size: 65536,
- },
- }
- remapped := idtools.NewIDMappingsFromMaps(idMaps, idMaps)
- unmapped := &idtools.IDMappings{}
-
- contextDir, cleanup := createTestTempDir(t, "", "builder-chown-parse-test")
- defer cleanup()
-
- if err := os.Mkdir(filepath.Join(contextDir, "etc"), 0755); err != nil {
- t.Fatalf("error creating test directory: %v", err)
- }
-
- for filename, content := range testFiles {
- createTestTempFile(t, filepath.Join(contextDir, "etc"), filename, content, 0644)
- }
-
- // positive tests
- for _, testcase := range []struct {
- name string
- chownStr string
- idMapping *idtools.IDMappings
- expected idtools.IDPair
- }{
- {
- name: "UIDNoMap",
- chownStr: "1",
- idMapping: unmapped,
- expected: idtools.IDPair{UID: 1, GID: 1},
- },
- {
- name: "UIDGIDNoMap",
- chownStr: "0:1",
- idMapping: unmapped,
- expected: idtools.IDPair{UID: 0, GID: 1},
- },
- {
- name: "UIDWithMap",
- chownStr: "0",
- idMapping: remapped,
- expected: idtools.IDPair{UID: 100000, GID: 100000},
- },
- {
- name: "UIDGIDWithMap",
- chownStr: "1:33",
- idMapping: remapped,
- expected: idtools.IDPair{UID: 100001, GID: 100033},
- },
- {
- name: "UserNoMap",
- chownStr: "bin:5555",
- idMapping: unmapped,
- expected: idtools.IDPair{UID: 1, GID: 5555},
- },
- {
- name: "GroupWithMap",
- chownStr: "0:unicorn",
- idMapping: remapped,
- expected: idtools.IDPair{UID: 100000, GID: 101002},
- },
- {
- name: "UserOnlyWithMap",
- chownStr: "unicorn",
- idMapping: remapped,
- expected: idtools.IDPair{UID: 101001, GID: 101002},
- },
- } {
- t.Run(testcase.name, func(t *testing.T) {
- idPair, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping)
- require.NoError(t, err, "Failed to parse chown flag: %q", testcase.chownStr)
- assert.Equal(t, testcase.expected, idPair, "chown flag mapping failure")
- })
- }
-
- // error tests
- for _, testcase := range []struct {
- name string
- chownStr string
- idMapping *idtools.IDMappings
- descr string
- }{
- {
- name: "BadChownFlagFormat",
- chownStr: "bob:1:555",
- idMapping: unmapped,
- descr: "invalid chown string format: bob:1:555",
- },
- {
- name: "UserNoExist",
- chownStr: "bob",
- idMapping: unmapped,
- descr: "can't find uid for user bob: no such user: bob",
- },
- {
- name: "GroupNoExist",
- chownStr: "root:bob",
- idMapping: unmapped,
- descr: "can't find gid for group bob: no such group: bob",
- },
- } {
- t.Run(testcase.name, func(t *testing.T) {
- _, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping)
- assert.EqualError(t, err, testcase.descr, "Expected error string doesn't match")
- })
- }
-}
diff --git a/builder/dockerfile/internals_windows.go b/builder/dockerfile/internals_windows.go
new file mode 100644
index 0000000..931df2f
--- /dev/null
+++ b/builder/dockerfile/internals_windows.go
@@ -0,0 +1,7 @@
+package dockerfile
+
+import "github.com/docker/docker/pkg/idtools"
+
+func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) {
+ return idMappings.RootPair(), nil
+}
diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go
index e6c1d91..9231595 100644
--- a/integration-cli/docker_cli_run_test.go
+++ b/integration-cli/docker_cli_run_test.go
@@ -36,7 +36,6 @@
"github.com/docker/libnetwork/types"
"github.com/go-check/check"
"github.com/gotestyourself/gotestyourself/icmd"
- libcontainerUser "github.com/opencontainers/runc/libcontainer/user"
"golang.org/x/net/context"
)
@@ -751,7 +750,7 @@
if err == nil {
c.Fatal("No error, but must be.", out)
}
- if !strings.Contains(strings.ToUpper(out), strings.ToUpper(libcontainerUser.ErrRange.Error())) {
+ if !strings.Contains(strings.ToLower(out), "uids and gids must be in range") {
c.Fatalf("expected error about uids range, got %s", out)
}
}
@@ -764,7 +763,7 @@
if err == nil {
c.Fatal("No error, but must be.", out)
}
- if !strings.Contains(strings.ToUpper(out), strings.ToUpper(libcontainerUser.ErrRange.Error())) {
+ if !strings.Contains(strings.ToLower(out), "uids and gids must be in range") {
c.Fatalf("expected error about uids range, got %s", out)
}
}