Add ADD/COPY --chown flag support to Windows
This implements chown support on Windows. Built-in accounts as well as accounts included in the SAM database of the container are supported. NOTE: IDPair is now named Identity and IDMappings is now named IdentityMapping. The following are valid examples: ADD --chown=Guest . <some directory> COPY --chown=Administrator . <some directory> COPY --chown=Guests . <some directory> COPY --chown=ContainerUser . <some directory> On Windows an owner is only granted the permission to read the security descriptor and read/write the discretionary access control list. This fix also grants read/write and execute permissions to the owner. Signed-off-by: Salahuddin Khan <salah@docker.com>
This commit is contained in:
parent
1fd7e4c28d
commit
763d839261
64 changed files with 610 additions and 301 deletions
|
@ -56,21 +56,21 @@ type SessionGetter interface {
|
|||
|
||||
// BuildManager is shared across all Builder objects
|
||||
type BuildManager struct {
|
||||
idMappings *idtools.IDMappings
|
||||
backend builder.Backend
|
||||
pathCache pathCache // TODO: make this persistent
|
||||
sg SessionGetter
|
||||
fsCache *fscache.FSCache
|
||||
idMapping *idtools.IdentityMapping
|
||||
backend builder.Backend
|
||||
pathCache pathCache // TODO: make this persistent
|
||||
sg SessionGetter
|
||||
fsCache *fscache.FSCache
|
||||
}
|
||||
|
||||
// NewBuildManager creates a BuildManager
|
||||
func NewBuildManager(b builder.Backend, sg SessionGetter, fsCache *fscache.FSCache, idMappings *idtools.IDMappings) (*BuildManager, error) {
|
||||
func NewBuildManager(b builder.Backend, sg SessionGetter, fsCache *fscache.FSCache, identityMapping *idtools.IdentityMapping) (*BuildManager, error) {
|
||||
bm := &BuildManager{
|
||||
backend: b,
|
||||
pathCache: &syncmap.Map{},
|
||||
sg: sg,
|
||||
idMappings: idMappings,
|
||||
fsCache: fsCache,
|
||||
backend: b,
|
||||
pathCache: &syncmap.Map{},
|
||||
sg: sg,
|
||||
idMapping: identityMapping,
|
||||
fsCache: fsCache,
|
||||
}
|
||||
if err := fsCache.RegisterTransport(remotecontext.ClientSessionRemote, NewClientSessionTransport()); err != nil {
|
||||
return nil, err
|
||||
|
@ -111,7 +111,7 @@ func (bm *BuildManager) Build(ctx context.Context, config backend.BuildConfig) (
|
|||
ProgressWriter: config.ProgressWriter,
|
||||
Backend: bm.backend,
|
||||
PathCache: bm.pathCache,
|
||||
IDMappings: bm.idMappings,
|
||||
IDMapping: bm.idMapping,
|
||||
}
|
||||
b, err := newBuilder(ctx, builderOptions)
|
||||
if err != nil {
|
||||
|
@ -159,7 +159,7 @@ type builderOptions struct {
|
|||
Backend builder.Backend
|
||||
ProgressWriter backend.ProgressWriter
|
||||
PathCache pathCache
|
||||
IDMappings *idtools.IDMappings
|
||||
IDMapping *idtools.IdentityMapping
|
||||
}
|
||||
|
||||
// Builder is a Dockerfile builder
|
||||
|
@ -175,7 +175,7 @@ type Builder struct {
|
|||
docker builder.Backend
|
||||
clientCtx context.Context
|
||||
|
||||
idMappings *idtools.IDMappings
|
||||
idMapping *idtools.IdentityMapping
|
||||
disableCommit bool
|
||||
imageSources *imageSources
|
||||
pathCache pathCache
|
||||
|
@ -199,7 +199,7 @@ func newBuilder(clientCtx context.Context, options builderOptions) (*Builder, er
|
|||
Aux: options.ProgressWriter.AuxFormatter,
|
||||
Output: options.ProgressWriter.Output,
|
||||
docker: options.Backend,
|
||||
idMappings: options.IDMappings,
|
||||
idMapping: options.IDMapping,
|
||||
imageSources: newImageSources(clientCtx, options),
|
||||
pathCache: options.PathCache,
|
||||
imageProber: newImageProber(options.Backend, config.CacheFrom, config.NoCache),
|
||||
|
|
|
@ -451,7 +451,7 @@ func downloadSource(output io.Writer, stdout io.Writer, srcURL string) (remote b
|
|||
|
||||
type copyFileOptions struct {
|
||||
decompress bool
|
||||
chownPair idtools.IDPair
|
||||
identity idtools.Identity
|
||||
archiver Archiver
|
||||
}
|
||||
|
||||
|
@ -481,7 +481,7 @@ func performCopyForInfo(dest copyInfo, source copyInfo, options copyFileOptions)
|
|||
return errors.Wrapf(err, "source path not found")
|
||||
}
|
||||
if src.IsDir() {
|
||||
return copyDirectory(archiver, srcEndpoint, destEndpoint, options.chownPair)
|
||||
return copyDirectory(archiver, srcEndpoint, destEndpoint, options.identity)
|
||||
}
|
||||
if options.decompress && isArchivePath(source.root, srcPath) && !source.noDecompress {
|
||||
return archiver.UntarPath(srcPath, destPath)
|
||||
|
@ -499,7 +499,7 @@ func performCopyForInfo(dest copyInfo, source copyInfo, options copyFileOptions)
|
|||
destPath = dest.root.Join(destPath, source.root.Base(source.path))
|
||||
destEndpoint = ©Endpoint{driver: dest.root, path: destPath}
|
||||
}
|
||||
return copyFile(archiver, srcEndpoint, destEndpoint, options.chownPair)
|
||||
return copyFile(archiver, srcEndpoint, destEndpoint, options.identity)
|
||||
}
|
||||
|
||||
func isArchivePath(driver containerfs.ContainerFS, path string) bool {
|
||||
|
@ -517,7 +517,7 @@ func isArchivePath(driver containerfs.ContainerFS, path string) bool {
|
|||
return err == nil
|
||||
}
|
||||
|
||||
func copyDirectory(archiver Archiver, source, dest *copyEndpoint, chownPair idtools.IDPair) error {
|
||||
func copyDirectory(archiver Archiver, source, dest *copyEndpoint, identity idtools.Identity) error {
|
||||
destExists, err := isExistingDirectory(dest)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to query destination path")
|
||||
|
@ -527,17 +527,17 @@ func copyDirectory(archiver Archiver, source, dest *copyEndpoint, chownPair idto
|
|||
return errors.Wrapf(err, "failed to copy directory")
|
||||
}
|
||||
// TODO: @gupta-ak. Investigate how LCOW permission mappings will work.
|
||||
return fixPermissions(source.path, dest.path, chownPair, !destExists)
|
||||
return fixPermissions(source.path, dest.path, identity, !destExists)
|
||||
}
|
||||
|
||||
func copyFile(archiver Archiver, source, dest *copyEndpoint, chownPair idtools.IDPair) error {
|
||||
func copyFile(archiver Archiver, source, dest *copyEndpoint, identity idtools.Identity) error {
|
||||
if runtime.GOOS == "windows" && dest.driver.OS() == "linux" {
|
||||
// LCOW
|
||||
if err := dest.driver.MkdirAll(dest.driver.Dir(dest.path), 0755); err != nil {
|
||||
return errors.Wrapf(err, "failed to create new directory")
|
||||
}
|
||||
} else {
|
||||
if err := idtools.MkdirAllAndChownNew(filepath.Dir(dest.path), 0755, chownPair); err != nil {
|
||||
if err := idtools.MkdirAllAndChownNew(filepath.Dir(dest.path), 0755, identity); err != nil {
|
||||
// Normal containers
|
||||
return errors.Wrapf(err, "failed to create new directory")
|
||||
}
|
||||
|
@ -547,7 +547,7 @@ func copyFile(archiver Archiver, source, dest *copyEndpoint, chownPair idtools.I
|
|||
return errors.Wrapf(err, "failed to copy file")
|
||||
}
|
||||
// TODO: @gupta-ak. Investigate how LCOW permission mappings will work.
|
||||
return fixPermissions(source.path, dest.path, chownPair, false)
|
||||
return fixPermissions(source.path, dest.path, identity, false)
|
||||
}
|
||||
|
||||
func endsInSlash(driver containerfs.Driver, path string) bool {
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"github.com/docker/docker/pkg/idtools"
|
||||
)
|
||||
|
||||
func fixPermissions(source, destination string, rootIDs idtools.IDPair, overrideSkip bool) error {
|
||||
func fixPermissions(source, destination string, identity idtools.Identity, overrideSkip bool) error {
|
||||
var (
|
||||
skipChownRoot bool
|
||||
err error
|
||||
|
@ -39,7 +39,7 @@ func fixPermissions(source, destination string, rootIDs idtools.IDPair, override
|
|||
}
|
||||
|
||||
fullpath = filepath.Join(destination, cleaned)
|
||||
return os.Lchown(fullpath, rootIDs.UID, rootIDs.GID)
|
||||
return os.Lchown(fullpath, identity.UID, identity.GID)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
package dockerfile // import "github.com/docker/docker/builder/dockerfile"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/Microsoft/go-winio"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var pathBlacklist = map[string]bool{
|
||||
|
@ -13,9 +19,69 @@ var pathBlacklist = map[string]bool{
|
|||
"c:\\windows": true,
|
||||
}
|
||||
|
||||
func fixPermissions(source, destination string, rootIDs idtools.IDPair, overrideSkip bool) error {
|
||||
// chown is not supported on Windows
|
||||
return nil
|
||||
func init() {
|
||||
reexec.Register("windows-fix-permissions", fixPermissionsReexec)
|
||||
}
|
||||
|
||||
func fixPermissions(source, destination string, identity idtools.Identity, _ bool) error {
|
||||
if identity.SID == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := reexec.Command("windows-fix-permissions", source, destination, identity.SID)
|
||||
output, err := cmd.CombinedOutput()
|
||||
|
||||
return errors.Wrapf(err, "failed to exec windows-fix-permissions: %s", output)
|
||||
}
|
||||
|
||||
func fixPermissionsReexec() {
|
||||
err := fixPermissionsWindows(os.Args[1], os.Args[2], os.Args[3])
|
||||
if err != nil {
|
||||
fmt.Fprint(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func fixPermissionsWindows(source, destination, SID string) error {
|
||||
|
||||
privileges := []string{winio.SeRestorePrivilege, system.SeTakeOwnershipPrivilege}
|
||||
|
||||
err := winio.EnableProcessPrivileges(privileges)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer winio.DisableProcessPrivileges(privileges)
|
||||
|
||||
sid, err := windows.StringToSid(SID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Owners on *nix have read/write/delete/read control and write DAC.
|
||||
// Add an ACE that grants this to the user/group specified with the
|
||||
// chown option. Currently Windows is not honoring the owner change,
|
||||
// however, they are aware of this and it should be fixed at some
|
||||
// point.
|
||||
|
||||
sddlString := system.SddlAdministratorsLocalSystem
|
||||
sddlString += "(A;OICI;GRGWGXRCWDSD;;;" + SID + ")"
|
||||
|
||||
securityDescriptor, err := winio.SddlToSecurityDescriptor(sddlString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var daclPresent uint32
|
||||
var daclDefaulted uint32
|
||||
var dacl *byte
|
||||
|
||||
err = system.GetSecurityDescriptorDacl(&securityDescriptor[0], &daclPresent, &dacl, &daclDefaulted)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return system.SetNamedSecurityInfo(windows.StringToUTF16Ptr(destination), system.SE_FILE_OBJECT, system.OWNER_SECURITY_INFORMATION|system.DACL_SECURITY_INFORMATION, sid, nil, dacl, nil)
|
||||
}
|
||||
|
||||
func validateCopySourcePath(imageSource *imageMount, origPath, platform string) error {
|
||||
|
|
|
@ -37,7 +37,7 @@ type Archiver interface {
|
|||
UntarPath(src, dst string) error
|
||||
CopyWithTar(src, dst string) error
|
||||
CopyFileWithTar(src, dst string) error
|
||||
IDMappings() *idtools.IDMappings
|
||||
IdentityMapping() *idtools.IdentityMapping
|
||||
}
|
||||
|
||||
// The builder will use the following interfaces if the container fs implements
|
||||
|
@ -68,11 +68,11 @@ func tarFunc(i interface{}) containerfs.TarFunc {
|
|||
func (b *Builder) getArchiver(src, dst containerfs.Driver) Archiver {
|
||||
t, u := tarFunc(src), untarFunc(dst)
|
||||
return &containerfs.Archiver{
|
||||
SrcDriver: src,
|
||||
DstDriver: dst,
|
||||
Tar: t,
|
||||
Untar: u,
|
||||
IDMappingsVar: b.idMappings,
|
||||
SrcDriver: src,
|
||||
DstDriver: dst,
|
||||
Tar: t,
|
||||
Untar: u,
|
||||
IDMapping: b.idMapping,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,14 +185,18 @@ func (b *Builder) performCopy(req dispatchRequest, inst copyInstruction) error {
|
|||
return err
|
||||
}
|
||||
|
||||
chownPair := b.idMappings.RootPair()
|
||||
identity := b.idMapping.RootPair()
|
||||
// if a chown was requested, perform the steps to get the uid, gid
|
||||
// translated (if necessary because of user namespaces), and replace
|
||||
// the root pair with the chown pair for copy operations
|
||||
if inst.chownStr != "" {
|
||||
chownPair, err = parseChownFlag(inst.chownStr, destInfo.root.Path(), b.idMappings)
|
||||
identity, err = parseChownFlag(b, state, inst.chownStr, destInfo.root.Path(), b.idMapping)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to convert uid/gid chown string to host mapping")
|
||||
if b.options.Platform != "windows" {
|
||||
return errors.Wrapf(err, "unable to convert uid/gid chown string to host mapping")
|
||||
}
|
||||
|
||||
return errors.Wrapf(err, "unable to map container user account name to SID")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -200,7 +204,7 @@ func (b *Builder) performCopy(req dispatchRequest, inst copyInstruction) error {
|
|||
opts := copyFileOptions{
|
||||
decompress: inst.allowLocalDecompression,
|
||||
archiver: b.getArchiver(info.root, destInfo.root),
|
||||
chownPair: chownPair,
|
||||
identity: identity,
|
||||
}
|
||||
if err := performCopyForInfo(destInfo, info, opts); err != nil {
|
||||
return errors.Wrapf(err, "failed to copy files")
|
||||
|
|
|
@ -11,11 +11,11 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) {
|
||||
func parseChownFlag(builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping *idtools.IdentityMapping) (idtools.Identity, error) {
|
||||
var userStr, grpStr string
|
||||
parts := strings.Split(chown, ":")
|
||||
if len(parts) > 2 {
|
||||
return idtools.IDPair{}, errors.New("invalid chown string format: " + chown)
|
||||
return idtools.Identity{}, errors.New("invalid chown string format: " + chown)
|
||||
}
|
||||
if len(parts) == 1 {
|
||||
// if no group specified, use the user spec as group as well
|
||||
|
@ -26,25 +26,25 @@ func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (
|
|||
|
||||
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")
|
||||
return idtools.Identity{}, 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")
|
||||
return idtools.Identity{}, 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)
|
||||
return idtools.Identity{}, 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)
|
||||
return idtools.Identity{}, 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})
|
||||
chownPair, err := identityMapping.ToHost(idtools.Identity{UID: uid, GID: gid})
|
||||
if err != nil {
|
||||
return idtools.IDPair{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
|
||||
return idtools.Identity{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
|
||||
}
|
||||
return chownPair, nil
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
|
@ -34,7 +35,7 @@ othergrp:x:6666:
|
|||
},
|
||||
}
|
||||
remapped := idtools.NewIDMappingsFromMaps(idMaps, idMaps)
|
||||
unmapped := &idtools.IDMappings{}
|
||||
unmapped := &idtools.IdentityMapping{}
|
||||
|
||||
contextDir, cleanup := createTestTempDir(t, "", "builder-chown-parse-test")
|
||||
defer cleanup()
|
||||
|
@ -49,56 +50,72 @@ othergrp:x:6666:
|
|||
|
||||
// positive tests
|
||||
for _, testcase := range []struct {
|
||||
builder *Builder
|
||||
name string
|
||||
chownStr string
|
||||
idMapping *idtools.IDMappings
|
||||
expected idtools.IDPair
|
||||
idMapping *idtools.IdentityMapping
|
||||
state *dispatchState
|
||||
expected idtools.Identity
|
||||
}{
|
||||
{
|
||||
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
||||
name: "UIDNoMap",
|
||||
chownStr: "1",
|
||||
idMapping: unmapped,
|
||||
expected: idtools.IDPair{UID: 1, GID: 1},
|
||||
state: &dispatchState{},
|
||||
expected: idtools.Identity{UID: 1, GID: 1},
|
||||
},
|
||||
{
|
||||
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
||||
name: "UIDGIDNoMap",
|
||||
chownStr: "0:1",
|
||||
idMapping: unmapped,
|
||||
expected: idtools.IDPair{UID: 0, GID: 1},
|
||||
state: &dispatchState{},
|
||||
expected: idtools.Identity{UID: 0, GID: 1},
|
||||
},
|
||||
{
|
||||
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
||||
name: "UIDWithMap",
|
||||
chownStr: "0",
|
||||
idMapping: remapped,
|
||||
expected: idtools.IDPair{UID: 100000, GID: 100000},
|
||||
state: &dispatchState{},
|
||||
expected: idtools.Identity{UID: 100000, GID: 100000},
|
||||
},
|
||||
{
|
||||
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
||||
name: "UIDGIDWithMap",
|
||||
chownStr: "1:33",
|
||||
idMapping: remapped,
|
||||
expected: idtools.IDPair{UID: 100001, GID: 100033},
|
||||
state: &dispatchState{},
|
||||
expected: idtools.Identity{UID: 100001, GID: 100033},
|
||||
},
|
||||
{
|
||||
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
||||
name: "UserNoMap",
|
||||
chownStr: "bin:5555",
|
||||
idMapping: unmapped,
|
||||
expected: idtools.IDPair{UID: 1, GID: 5555},
|
||||
state: &dispatchState{},
|
||||
expected: idtools.Identity{UID: 1, GID: 5555},
|
||||
},
|
||||
{
|
||||
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
||||
name: "GroupWithMap",
|
||||
chownStr: "0:unicorn",
|
||||
idMapping: remapped,
|
||||
expected: idtools.IDPair{UID: 100000, GID: 101002},
|
||||
state: &dispatchState{},
|
||||
expected: idtools.Identity{UID: 100000, GID: 101002},
|
||||
},
|
||||
{
|
||||
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
||||
name: "UserOnlyWithMap",
|
||||
chownStr: "unicorn",
|
||||
idMapping: remapped,
|
||||
expected: idtools.IDPair{UID: 101001, GID: 101002},
|
||||
state: &dispatchState{},
|
||||
expected: idtools.Identity{UID: 101001, GID: 101002},
|
||||
},
|
||||
} {
|
||||
t.Run(testcase.name, func(t *testing.T) {
|
||||
idPair, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping)
|
||||
idPair, err := parseChownFlag(testcase.builder, testcase.state, testcase.chownStr, contextDir, testcase.idMapping)
|
||||
assert.NilError(t, err, "Failed to parse chown flag: %q", testcase.chownStr)
|
||||
assert.Check(t, is.DeepEqual(testcase.expected, idPair), "chown flag mapping failure")
|
||||
})
|
||||
|
@ -106,32 +123,40 @@ othergrp:x:6666:
|
|||
|
||||
// error tests
|
||||
for _, testcase := range []struct {
|
||||
builder *Builder
|
||||
name string
|
||||
chownStr string
|
||||
idMapping *idtools.IDMappings
|
||||
idMapping *idtools.IdentityMapping
|
||||
state *dispatchState
|
||||
descr string
|
||||
}{
|
||||
{
|
||||
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
||||
name: "BadChownFlagFormat",
|
||||
chownStr: "bob:1:555",
|
||||
idMapping: unmapped,
|
||||
state: &dispatchState{},
|
||||
descr: "invalid chown string format: bob:1:555",
|
||||
},
|
||||
{
|
||||
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
||||
name: "UserNoExist",
|
||||
chownStr: "bob",
|
||||
idMapping: unmapped,
|
||||
state: &dispatchState{},
|
||||
descr: "can't find uid for user bob: no such user: bob",
|
||||
},
|
||||
{
|
||||
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
||||
name: "GroupNoExist",
|
||||
chownStr: "root:bob",
|
||||
idMapping: unmapped,
|
||||
state: &dispatchState{},
|
||||
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)
|
||||
_, err := parseChownFlag(testcase.builder, testcase.state, testcase.chownStr, contextDir, testcase.idMapping)
|
||||
assert.Check(t, is.Error(err, testcase.descr), "Expected error string doesn't match")
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,7 +1,120 @@
|
|||
package dockerfile // import "github.com/docker/docker/builder/dockerfile"
|
||||
|
||||
import "github.com/docker/docker/pkg/idtools"
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) {
|
||||
return idMappings.RootPair(), nil
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func parseChownFlag(builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping *idtools.IdentityMapping) (idtools.Identity, error) {
|
||||
if builder.options.Platform == "windows" {
|
||||
return getAccountIdentity(builder, chown, ctrRootPath, state)
|
||||
}
|
||||
|
||||
return identityMapping.RootPair(), nil
|
||||
}
|
||||
|
||||
func getAccountIdentity(builder *Builder, accountName string, ctrRootPath string, state *dispatchState) (idtools.Identity, error) {
|
||||
// If this is potentially a string SID then attempt to convert it to verify
|
||||
// this, otherwise continue looking for the account.
|
||||
if strings.HasPrefix(accountName, "S-") || strings.HasPrefix(accountName, "s-") {
|
||||
sid, err := windows.StringToSid(accountName)
|
||||
|
||||
if err == nil {
|
||||
accountSid, err := sid.String()
|
||||
|
||||
if err != nil {
|
||||
return idtools.Identity{SID: ""}, errors.Wrapf(err, "error converting SID to string")
|
||||
}
|
||||
|
||||
return idtools.Identity{SID: accountSid}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to obtain the SID using the name.
|
||||
sid, _, accType, err := windows.LookupSID("", accountName)
|
||||
|
||||
// If this is a SID that is built-in and hence the same across all systems then use that.
|
||||
if err == nil && (accType == windows.SidTypeAlias || accType == windows.SidTypeWellKnownGroup) {
|
||||
accountSid, err := sid.String()
|
||||
|
||||
if err != nil {
|
||||
return idtools.Identity{SID: ""}, errors.Wrapf(err, "error converting SID to string")
|
||||
}
|
||||
|
||||
return idtools.Identity{SID: accountSid}, nil
|
||||
}
|
||||
|
||||
// Check if the account name is one unique to containers.
|
||||
if strings.EqualFold(accountName, "ContainerAdministrator") {
|
||||
return idtools.Identity{SID: system.ContainerAdministratorSidString}, nil
|
||||
|
||||
} else if strings.EqualFold(accountName, "ContainerUser") {
|
||||
return idtools.Identity{SID: system.ContainerUserSidString}, nil
|
||||
}
|
||||
|
||||
// All other lookups failed, so therefore determine if the account in
|
||||
// question exists in the container and if so, obtain its SID.
|
||||
return lookupNTAccount(builder, accountName, state)
|
||||
}
|
||||
|
||||
func lookupNTAccount(builder *Builder, accountName string, state *dispatchState) (idtools.Identity, error) {
|
||||
|
||||
source, _ := filepath.Split(os.Args[0])
|
||||
|
||||
target := "C:\\Docker"
|
||||
targetExecutable := target + "\\containerutility.exe"
|
||||
|
||||
optionsPlatform, err := platforms.Parse(builder.options.Platform)
|
||||
if err != nil {
|
||||
return idtools.Identity{}, err
|
||||
}
|
||||
|
||||
runConfig := copyRunConfig(state.runConfig,
|
||||
withCmdCommentString("internal run to obtain NT account information.", optionsPlatform.OS))
|
||||
|
||||
runConfig.ArgsEscaped = true
|
||||
runConfig.Cmd = []string{targetExecutable, "getaccountsid", accountName}
|
||||
|
||||
hostConfig := &container.HostConfig{Mounts: []mount.Mount{
|
||||
{
|
||||
Type: mount.TypeBind,
|
||||
Source: source,
|
||||
Target: target,
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
container, err := builder.containerManager.Create(runConfig, hostConfig)
|
||||
if err != nil {
|
||||
return idtools.Identity{}, err
|
||||
}
|
||||
|
||||
stdout := new(bytes.Buffer)
|
||||
stderr := new(bytes.Buffer)
|
||||
|
||||
if err := builder.containerManager.Run(builder.clientCtx, container.ID, stdout, stderr); err != nil {
|
||||
if err, ok := err.(*statusCodeError); ok {
|
||||
return idtools.Identity{}, &jsonmessage.JSONError{
|
||||
Message: stderr.String(),
|
||||
Code: err.StatusCode(),
|
||||
}
|
||||
}
|
||||
return idtools.Identity{}, err
|
||||
}
|
||||
|
||||
accountSid := stdout.String()
|
||||
|
||||
return idtools.Identity{SID: accountSid}, nil
|
||||
}
|
||||
|
|
|
@ -267,7 +267,7 @@ func newRouterOptions(config *config.Config, daemon *daemon.Daemon) (routerOptio
|
|||
return opts, errors.Wrap(err, "failed to create fscache")
|
||||
}
|
||||
|
||||
manager, err := dockerfile.NewBuildManager(daemon.BuilderBackend(), sm, buildCache, daemon.IDMappings())
|
||||
manager, err := dockerfile.NewBuildManager(daemon.BuilderBackend(), sm, buildCache, daemon.IdentityMapping())
|
||||
if err != nil {
|
||||
return opts, err
|
||||
}
|
||||
|
|
|
@ -254,7 +254,7 @@ func (container *Container) WriteHostConfig() (*containertypes.HostConfig, error
|
|||
}
|
||||
|
||||
// SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir
|
||||
func (container *Container) SetupWorkingDirectory(rootIDs idtools.IDPair) error {
|
||||
func (container *Container) SetupWorkingDirectory(rootIdentity idtools.Identity) error {
|
||||
// TODO @jhowardmsft, @gupta-ak LCOW Support. This will need revisiting.
|
||||
// We will need to do remote filesystem operations here.
|
||||
if container.OS != runtime.GOOS {
|
||||
|
@ -271,7 +271,7 @@ func (container *Container) SetupWorkingDirectory(rootIDs idtools.IDPair) error
|
|||
return err
|
||||
}
|
||||
|
||||
if err := idtools.MkdirAllAndChownNew(pth, 0755, rootIDs); err != nil {
|
||||
if err := idtools.MkdirAllAndChownNew(pth, 0755, rootIdentity); err != nil {
|
||||
pthInfo, err2 := os.Stat(pth)
|
||||
if err2 == nil && pthInfo != nil && !pthInfo.IsDir() {
|
||||
return errors.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir)
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
func (daemon *Daemon) defaultTarCopyOptions(noOverwriteDirNonDir bool) *archive.TarOptions {
|
||||
return &archive.TarOptions{
|
||||
NoOverwriteDirNonDir: noOverwriteDirNonDir,
|
||||
UIDMaps: daemon.idMappings.UIDs(),
|
||||
GIDMaps: daemon.idMappings.GIDs(),
|
||||
UIDMaps: daemon.idMapping.UIDs(),
|
||||
GIDMaps: daemon.idMapping.GIDs(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,10 @@ func (daemon *Daemon) tarCopyOptions(container *container.Container, noOverwrite
|
|||
return nil, err
|
||||
}
|
||||
|
||||
identity := idtools.Identity{UID: user.Uid, GID: user.Gid}
|
||||
|
||||
return &archive.TarOptions{
|
||||
NoOverwriteDirNonDir: noOverwriteDirNonDir,
|
||||
ChownOpts: &idtools.IDPair{UID: user.Uid, GID: user.Gid},
|
||||
ChownOpts: &identity,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
|
|||
fallthrough
|
||||
|
||||
case ipcMode.IsShareable():
|
||||
rootIDs := daemon.idMappings.RootPair()
|
||||
rootIDs := daemon.idMapping.RootPair()
|
||||
if !c.HasMountFor("/dev/shm") {
|
||||
shmPath, err := c.ShmResourcePath()
|
||||
if err != nil {
|
||||
|
@ -179,7 +179,7 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
|
|||
}
|
||||
|
||||
// retrieve possible remapped range start for root UID, GID
|
||||
rootIDs := daemon.idMappings.RootPair()
|
||||
rootIDs := daemon.idMapping.RootPair()
|
||||
|
||||
for _, s := range c.SecretReferences {
|
||||
// TODO (ehazlett): use type switch when more are supported
|
||||
|
@ -278,7 +278,7 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
|
|||
// In practice this is using a tmpfs mount and is used for both "configs" and "secrets"
|
||||
func (daemon *Daemon) createSecretsDir(c *container.Container) error {
|
||||
// retrieve possible remapped range start for root UID, GID
|
||||
rootIDs := daemon.idMappings.RootPair()
|
||||
rootIDs := daemon.idMapping.RootPair()
|
||||
dir, err := c.SecretMountPath()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error getting container secrets dir")
|
||||
|
@ -304,7 +304,7 @@ func (daemon *Daemon) remountSecretDir(c *container.Container) error {
|
|||
if err := label.Relabel(dir, c.MountLabel, false); err != nil {
|
||||
logrus.WithError(err).WithField("dir", dir).Warn("Error while attempting to set selinux label")
|
||||
}
|
||||
rootIDs := daemon.idMappings.RootPair()
|
||||
rootIDs := daemon.idMapping.RootPair()
|
||||
tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
|
||||
|
||||
// remount secrets ro
|
||||
|
@ -407,5 +407,5 @@ func (daemon *Daemon) setupContainerMountsRoot(c *container.Container) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return idtools.MkdirAllAndChown(p, 0700, daemon.idMappings.RootPair())
|
||||
return idtools.MkdirAllAndChown(p, 0700, daemon.idMapping.RootPair())
|
||||
}
|
||||
|
|
|
@ -155,13 +155,14 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (
|
|||
}
|
||||
|
||||
// Set RWLayer for container after mount labels have been set
|
||||
rwLayer, err := daemon.imageService.CreateLayer(container, setupInitLayer(daemon.idMappings))
|
||||
rwLayer, err := daemon.imageService.CreateLayer(container, setupInitLayer(daemon.idMapping))
|
||||
if err != nil {
|
||||
return nil, errdefs.System(err)
|
||||
}
|
||||
container.RWLayer = rwLayer
|
||||
|
||||
rootIDs := daemon.idMappings.RootPair()
|
||||
rootIDs := daemon.idMapping.RootPair()
|
||||
|
||||
if err := idtools.MkdirAndChown(container.Root, 0700, rootIDs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ func (daemon *Daemon) createContainerOSSpecificSettings(container *container.Con
|
|||
}
|
||||
defer daemon.Unmount(container)
|
||||
|
||||
rootIDs := daemon.idMappings.RootPair()
|
||||
rootIDs := daemon.idMapping.RootPair()
|
||||
if err := container.SetupWorkingDirectory(rootIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ type Daemon struct {
|
|||
seccompEnabled bool
|
||||
apparmorEnabled bool
|
||||
shutdown bool
|
||||
idMappings *idtools.IDMappings
|
||||
idMapping *idtools.IdentityMapping
|
||||
// TODO: move graphDrivers field to an InfoService
|
||||
graphDrivers map[string]string // By operating system
|
||||
|
||||
|
@ -594,11 +594,11 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
|
|||
return nil, err
|
||||
}
|
||||
|
||||
idMappings, err := setupRemappedRoot(config)
|
||||
idMapping, err := setupRemappedRoot(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rootIDs := idMappings.RootPair()
|
||||
rootIDs := idMapping.RootPair()
|
||||
if err := setupDaemonProcess(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -749,7 +749,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
|
|||
MetadataStorePathTemplate: filepath.Join(config.Root, "image", "%s", "layerdb"),
|
||||
GraphDriver: gd,
|
||||
GraphDriverOptions: config.GraphOptions,
|
||||
IDMappings: idMappings,
|
||||
IDMapping: idMapping,
|
||||
PluginGetter: d.PluginStore,
|
||||
ExperimentalEnabled: config.Experimental,
|
||||
OS: operatingSystem,
|
||||
|
@ -856,7 +856,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
|
|||
|
||||
d.EventsService = events.New()
|
||||
d.root = config.Root
|
||||
d.idMappings = idMappings
|
||||
d.idMapping = idMapping
|
||||
d.seccompEnabled = sysInfo.Seccomp
|
||||
d.apparmorEnabled = sysInfo.AppArmor
|
||||
|
||||
|
@ -1106,7 +1106,7 @@ func (daemon *Daemon) Subnets() ([]net.IPNet, []net.IPNet) {
|
|||
// prepareTempDir prepares and returns the default directory to use
|
||||
// for temporary files.
|
||||
// If it doesn't exist, it is created. If it exists, its content is removed.
|
||||
func prepareTempDir(rootDir string, rootIDs idtools.IDPair) (string, error) {
|
||||
func prepareTempDir(rootDir string, rootIdentity idtools.Identity) (string, error) {
|
||||
var tmpDir string
|
||||
if tmpDir = os.Getenv("DOCKER_TMPDIR"); tmpDir == "" {
|
||||
tmpDir = filepath.Join(rootDir, "tmp")
|
||||
|
@ -1126,7 +1126,7 @@ func prepareTempDir(rootDir string, rootIDs idtools.IDPair) (string, error) {
|
|||
}
|
||||
// We don't remove the content of tmpdir if it's not the default,
|
||||
// it may hold things that do not belong to us.
|
||||
return tmpDir, idtools.MkdirAllAndChown(tmpDir, 0700, rootIDs)
|
||||
return tmpDir, idtools.MkdirAllAndChown(tmpDir, 0700, rootIdentity)
|
||||
}
|
||||
|
||||
func (daemon *Daemon) setGenericResources(conf *config.Config) error {
|
||||
|
@ -1274,11 +1274,11 @@ func CreateDaemonRoot(config *config.Config) error {
|
|||
}
|
||||
}
|
||||
|
||||
idMappings, err := setupRemappedRoot(config)
|
||||
idMapping, err := setupRemappedRoot(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return setupDaemonRoot(config, realRoot, idMappings.RootPair())
|
||||
return setupDaemonRoot(config, realRoot, idMapping.RootPair())
|
||||
}
|
||||
|
||||
// checkpointAndSave grabs a container lock to safely call container.CheckpointTo
|
||||
|
@ -1304,9 +1304,9 @@ func (daemon *Daemon) GetAttachmentStore() *network.AttachmentStore {
|
|||
return &daemon.attachmentStore
|
||||
}
|
||||
|
||||
// IDMappings returns uid/gid mappings for the builder
|
||||
func (daemon *Daemon) IDMappings() *idtools.IDMappings {
|
||||
return daemon.idMappings
|
||||
// IdentityMapping returns uid/gid mapping or a SID (in the case of Windows) for the builder
|
||||
func (daemon *Daemon) IdentityMapping() *idtools.IdentityMapping {
|
||||
return daemon.idMapping
|
||||
}
|
||||
|
||||
// ImageService returns the Daemon's ImageService
|
||||
|
|
|
@ -124,7 +124,7 @@ func TestTmpfsDevShmSizeOverride(t *testing.T) {
|
|||
mnt := "/dev/shm"
|
||||
|
||||
d := Daemon{
|
||||
idMappings: &idtools.IDMappings{},
|
||||
idMapping: &idtools.IdentityMapping{},
|
||||
}
|
||||
c := &container.Container{
|
||||
HostConfig: &containertypes.HostConfig{
|
||||
|
|
|
@ -118,7 +118,7 @@ func initDaemonWithVolumeStore(tmp string) (*Daemon, error) {
|
|||
repository: tmp,
|
||||
root: tmp,
|
||||
}
|
||||
daemon.volumes, err = volumesservice.NewVolumeService(tmp, nil, idtools.IDPair{UID: 0, GID: 0}, daemon)
|
||||
daemon.volumes, err = volumesservice.NewVolumeService(tmp, nil, idtools.Identity{UID: 0, GID: 0}, daemon)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -1003,9 +1003,9 @@ func removeDefaultBridgeInterface() {
|
|||
}
|
||||
}
|
||||
|
||||
func setupInitLayer(idMappings *idtools.IDMappings) func(containerfs.ContainerFS) error {
|
||||
func setupInitLayer(idMapping *idtools.IdentityMapping) func(containerfs.ContainerFS) error {
|
||||
return func(initPath containerfs.ContainerFS) error {
|
||||
return initlayer.Setup(initPath, idMappings.RootPair())
|
||||
return initlayer.Setup(initPath, idMapping.RootPair())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1102,7 +1102,7 @@ func parseRemappedRoot(usergrp string) (string, string, error) {
|
|||
return username, groupname, nil
|
||||
}
|
||||
|
||||
func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) {
|
||||
func setupRemappedRoot(config *config.Config) (*idtools.IdentityMapping, error) {
|
||||
if runtime.GOOS != "linux" && config.RemappedRoot != "" {
|
||||
return nil, fmt.Errorf("User namespaces are only supported on Linux")
|
||||
}
|
||||
|
@ -1118,22 +1118,22 @@ func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) {
|
|||
// Cannot setup user namespaces with a 1-to-1 mapping; "--root=0:0" is a no-op
|
||||
// effectively
|
||||
logrus.Warn("User namespaces: root cannot be remapped with itself; user namespaces are OFF")
|
||||
return &idtools.IDMappings{}, nil
|
||||
return &idtools.IdentityMapping{}, nil
|
||||
}
|
||||
logrus.Infof("User namespaces: ID ranges will be mapped to subuid/subgid ranges of: %s:%s", username, groupname)
|
||||
// update remapped root setting now that we have resolved them to actual names
|
||||
config.RemappedRoot = fmt.Sprintf("%s:%s", username, groupname)
|
||||
|
||||
mappings, err := idtools.NewIDMappings(username, groupname)
|
||||
mappings, err := idtools.NewIdentityMapping(username, groupname)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Can't create ID mappings")
|
||||
}
|
||||
return mappings, nil
|
||||
}
|
||||
return &idtools.IDMappings{}, nil
|
||||
return &idtools.IdentityMapping{}, nil
|
||||
}
|
||||
|
||||
func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPair) error {
|
||||
func setupDaemonRoot(config *config.Config, rootDir string, rootIdentity idtools.Identity) error {
|
||||
config.Root = rootDir
|
||||
// the docker root metadata directory needs to have execute permissions for all users (g+x,o+x)
|
||||
// so that syscalls executing as non-root, operating on subdirectories of the graph root
|
||||
|
@ -1158,10 +1158,10 @@ func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPa
|
|||
// a new subdirectory with ownership set to the remapped uid/gid (so as to allow
|
||||
// `chdir()` to work for containers namespaced to that uid/gid)
|
||||
if config.RemappedRoot != "" {
|
||||
config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootIDs.UID, rootIDs.GID))
|
||||
config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootIdentity.UID, rootIdentity.GID))
|
||||
logrus.Debugf("Creating user namespaced daemon root: %s", config.Root)
|
||||
// Create the root directory if it doesn't exist
|
||||
if err := idtools.MkdirAllAndChown(config.Root, 0700, rootIDs); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(config.Root, 0700, rootIdentity); err != nil {
|
||||
return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err)
|
||||
}
|
||||
// we also need to verify that any pre-existing directories in the path to
|
||||
|
@ -1174,7 +1174,7 @@ func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPa
|
|||
if dirPath == "/" {
|
||||
break
|
||||
}
|
||||
if !idtools.CanAccess(dirPath, rootIDs) {
|
||||
if !idtools.CanAccess(dirPath, rootIdentity) {
|
||||
return fmt.Errorf("a subdirectory in your graphroot path (%s) restricts access to the remapped root uid/gid; please fix by allowing 'o+x' permissions on existing directories", config.Root)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ func parseSecurityOpt(container *container.Container, config *containertypes.Hos
|
|||
return nil
|
||||
}
|
||||
|
||||
func setupInitLayer(idMappings *idtools.IDMappings) func(containerfs.ContainerFS) error {
|
||||
func setupInitLayer(idMapping *idtools.IdentityMapping) func(containerfs.ContainerFS) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -465,11 +465,11 @@ func (daemon *Daemon) cleanupMounts() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) {
|
||||
return &idtools.IDMappings{}, nil
|
||||
func setupRemappedRoot(config *config.Config) (*idtools.IdentityMapping, error) {
|
||||
return &idtools.IdentityMapping{}, nil
|
||||
}
|
||||
|
||||
func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPair) error {
|
||||
func setupDaemonRoot(config *config.Config, rootDir string, rootIdentity idtools.Identity) error {
|
||||
config.Root = rootDir
|
||||
// Create the root directory if it doesn't exists
|
||||
if err := system.MkdirAllWithACL(config.Root, 0, system.SddlAdministratorsLocalSystem); err != nil {
|
||||
|
|
|
@ -68,8 +68,8 @@ func (daemon *Daemon) containerExport(container *container.Container) (arch io.R
|
|||
|
||||
archive, err := archivePath(basefs, basefs.Path(), &archive.TarOptions{
|
||||
Compression: archive.Uncompressed,
|
||||
UIDMaps: daemon.idMappings.UIDs(),
|
||||
GIDMaps: daemon.idMappings.GIDs(),
|
||||
UIDMaps: daemon.idMapping.UIDs(),
|
||||
GIDMaps: daemon.idMapping.GIDs(),
|
||||
})
|
||||
if err != nil {
|
||||
rwlayer.Unmount()
|
||||
|
|
|
@ -135,13 +135,13 @@ func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
|
|||
return nil, err
|
||||
}
|
||||
// Create the root aufs driver dir
|
||||
if err := idtools.MkdirAllAndChown(root, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(root, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Populate the dir structure
|
||||
for _, p := range paths {
|
||||
if err := idtools.MkdirAllAndChown(path.Join(root, p), 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(path.Join(root, p), 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
@ -289,7 +289,7 @@ func (a *Driver) createDirsFor(id string) error {
|
|||
// The path of directories are <aufs_root_path>/mnt/<image_id>
|
||||
// and <aufs_root_path>/diff/<image_id>
|
||||
for _, p := range paths {
|
||||
if err := idtools.MkdirAllAndChown(path.Join(a.rootPath(), p, id), 0755, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(path.Join(a.rootPath(), p, id), 0755, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := idtools.MkdirAllAndChown(home, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(home, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -502,7 +502,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := idtools.MkdirAllAndChown(subvolumes, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(subvolumes, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
||||
return err
|
||||
}
|
||||
if parent == "" {
|
||||
|
@ -537,7 +537,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
|
|||
if err := d.setStorageSize(path.Join(subvolumes, id), driver); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := idtools.MkdirAllAndChown(quotas, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(quotas, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(path.Join(quotas, id), []byte(fmt.Sprint(driver.options.size)), 0644); err != nil {
|
||||
|
|
|
@ -268,7 +268,7 @@ func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) {
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := idtools.MkdirAllAndChown(dirname, 0700, idtools.IDPair{UID: uid, GID: gid}); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(dirname, 0700, idtools.Identity{UID: uid, GID: gid}); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
@ -1691,7 +1691,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) (retErr error) {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := idtools.MkdirAndChown(devices.root, 0700, idtools.IDPair{UID: uid, GID: gid}); err != nil {
|
||||
if err := idtools.MkdirAndChown(devices.root, 0700, idtools.Identity{UID: uid, GID: gid}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(devices.metadataDir(), 0700); err != nil {
|
||||
|
|
|
@ -200,11 +200,11 @@ func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
|
|||
}
|
||||
|
||||
// Create the target directories if they don't exist
|
||||
if err := idtools.MkdirAllAndChown(path.Join(d.home, "mnt"), 0755, idtools.IDPair{UID: uid, GID: gid}); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(path.Join(d.home, "mnt"), 0755, idtools.Identity{UID: uid, GID: gid}); err != nil {
|
||||
d.ctr.Decrement(mp)
|
||||
return nil, err
|
||||
}
|
||||
if err := idtools.MkdirAndChown(mp, 0755, idtools.IDPair{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
|
||||
if err := idtools.MkdirAndChown(mp, 0755, idtools.Identity{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
|
||||
d.ctr.Decrement(mp)
|
||||
return nil, err
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := idtools.MkdirAllAndChown(rootFs, 0755, idtools.IDPair{UID: uid, GID: gid}); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(rootFs, 0755, idtools.Identity{UID: uid, GID: gid}); err != nil {
|
||||
d.ctr.Decrement(mp)
|
||||
d.DeviceSet.UnmountDevice(id, mp)
|
||||
return nil, err
|
||||
|
|
|
@ -183,17 +183,17 @@ func InitDriver(dataRoot string, options []string, _, _ []idtools.IDMap) (graphd
|
|||
}
|
||||
|
||||
// Make sure the dataRoot directory is created
|
||||
if err := idtools.MkdirAllAndChown(dataRoot, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(dataRoot, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
|
||||
return nil, fmt.Errorf("%s failed to create '%s': %v", title, dataRoot, err)
|
||||
}
|
||||
|
||||
// Make sure the cache directory is created under dataRoot
|
||||
if err := idtools.MkdirAllAndChown(cd, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(cd, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
|
||||
return nil, fmt.Errorf("%s failed to create '%s': %v", title, cd, err)
|
||||
}
|
||||
|
||||
// Make sure the scratch directory is created under dataRoot
|
||||
if err := idtools.MkdirAllAndChown(sd, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(sd, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
|
||||
return nil, fmt.Errorf("%s failed to create '%s': %v", title, sd, err)
|
||||
}
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
|
|||
return nil, err
|
||||
}
|
||||
// Create the driver home dir
|
||||
if err := idtools.MkdirAllAndChown(home, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(home, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -291,7 +291,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
root := idtools.IDPair{UID: rootUID, GID: rootGID}
|
||||
root := idtools.Identity{UID: rootUID, GID: rootGID}
|
||||
|
||||
if err := idtools.MkdirAllAndChown(path.Dir(dir), 0700, root); err != nil {
|
||||
return err
|
||||
|
@ -413,7 +413,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, err erro
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
||||
if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var (
|
||||
|
|
|
@ -200,7 +200,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
|
|||
return nil, err
|
||||
}
|
||||
// Create the driver home dir
|
||||
if err := idtools.MkdirAllAndChown(path.Join(home, linkDir), 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(path.Join(home, linkDir), 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -378,7 +378,7 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
root := idtools.IDPair{UID: rootUID, GID: rootGID}
|
||||
root := idtools.Identity{UID: rootUID, GID: rootGID}
|
||||
|
||||
if err := idtools.MkdirAllAndChown(path.Dir(dir), 0700, root); err != nil {
|
||||
return err
|
||||
|
@ -586,7 +586,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
||||
if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
@ -27,10 +27,10 @@ func init() {
|
|||
// This sets the home directory for the driver and returns NaiveDiffDriver.
|
||||
func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
|
||||
d := &Driver{
|
||||
home: home,
|
||||
idMappings: idtools.NewIDMappingsFromMaps(uidMaps, gidMaps),
|
||||
home: home,
|
||||
idMapping: idtools.NewIDMappingsFromMaps(uidMaps, gidMaps),
|
||||
}
|
||||
rootIDs := d.idMappings.RootPair()
|
||||
rootIDs := d.idMapping.RootPair()
|
||||
if err := idtools.MkdirAllAndChown(home, 0700, rootIDs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -46,8 +46,8 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
|
|||
// Driver must be wrapped in NaiveDiffDriver to be used as a graphdriver.Driver
|
||||
type Driver struct {
|
||||
driverQuota
|
||||
home string
|
||||
idMappings *idtools.IDMappings
|
||||
home string
|
||||
idMapping *idtools.IdentityMapping
|
||||
}
|
||||
|
||||
func (d *Driver) String() string {
|
||||
|
@ -105,7 +105,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
|
|||
|
||||
func (d *Driver) create(id, parent string, size uint64) error {
|
||||
dir := d.dir(id)
|
||||
rootIDs := d.idMappings.RootPair()
|
||||
rootIDs := d.idMapping.RootPair()
|
||||
if err := idtools.MkdirAllAndChown(filepath.Dir(dir), 0700, rootIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ func InitFilter(home string, options []string, uidMaps, gidMaps []idtools.IDMap)
|
|||
return nil, fmt.Errorf("%s is on an ReFS volume - ReFS volumes are not supported", home)
|
||||
}
|
||||
|
||||
if err := idtools.MkdirAllAndChown(home, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(home, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
|
||||
return nil, fmt.Errorf("windowsfilter failed to create '%s': %v", home, err)
|
||||
}
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdri
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to get root uid/guid: %v", err)
|
||||
}
|
||||
if err := idtools.MkdirAllAndChown(base, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(base, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
||||
return nil, fmt.Errorf("Failed to create '%s': %v", base, err)
|
||||
}
|
||||
|
||||
|
@ -385,7 +385,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
|
|||
return nil, err
|
||||
}
|
||||
// Create the target directories if they don't exist
|
||||
if err := idtools.MkdirAllAndChown(mountpoint, 0755, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(mountpoint, 0755, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
@ -162,7 +162,7 @@ func (daemon *Daemon) fillSecurityOptions(v *types.Info, sysInfo *sysinfo.SysInf
|
|||
if selinuxEnabled() {
|
||||
securityOptions = append(securityOptions, "name=selinux")
|
||||
}
|
||||
if rootIDs := daemon.idMappings.RootPair(); rootIDs.UID != 0 || rootIDs.GID != 0 {
|
||||
if rootIDs := daemon.idMapping.RootPair(); rootIDs.UID != 0 || rootIDs.GID != 0 {
|
||||
securityOptions = append(securityOptions, "name=userns")
|
||||
}
|
||||
v.SecurityOptions = securityOptions
|
||||
|
|
|
@ -17,7 +17,7 @@ import (
|
|||
//
|
||||
// This extra layer is used by all containers as the top-most ro layer. It protects
|
||||
// the container from unwanted side-effects on the rw layer.
|
||||
func Setup(initLayerFs containerfs.ContainerFS, rootIDs idtools.IDPair) error {
|
||||
func Setup(initLayerFs containerfs.ContainerFS, rootIdentity idtools.Identity) error {
|
||||
// Since all paths are local to the container, we can just extract initLayerFs.Path()
|
||||
initLayer := initLayerFs.Path()
|
||||
|
||||
|
@ -42,12 +42,12 @@ func Setup(initLayerFs containerfs.ContainerFS, rootIDs idtools.IDPair) error {
|
|||
|
||||
if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootIDs); err != nil {
|
||||
if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootIdentity); err != nil {
|
||||
return err
|
||||
}
|
||||
switch typ {
|
||||
case "dir":
|
||||
if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, pth), 0755, rootIDs); err != nil {
|
||||
if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, pth), 0755, rootIdentity); err != nil {
|
||||
return err
|
||||
}
|
||||
case "file":
|
||||
|
@ -55,7 +55,7 @@ func Setup(initLayerFs containerfs.ContainerFS, rootIDs idtools.IDPair) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Chown(rootIDs.UID, rootIDs.GID)
|
||||
f.Chown(rootIdentity.UID, rootIdentity.GID)
|
||||
f.Close()
|
||||
default:
|
||||
if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil {
|
||||
|
|
|
@ -11,6 +11,6 @@ import (
|
|||
//
|
||||
// This extra layer is used by all containers as the top-most ro layer. It protects
|
||||
// the container from unwanted side-effects on the rw layer.
|
||||
func Setup(initLayer containerfs.ContainerFS, rootIDs idtools.IDPair) error {
|
||||
func Setup(initLayer containerfs.ContainerFS, rootIDs idtools.Identity) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -217,13 +217,13 @@ func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error
|
|||
userNS := false
|
||||
// user
|
||||
if c.HostConfig.UsernsMode.IsPrivate() {
|
||||
uidMap := daemon.idMappings.UIDs()
|
||||
uidMap := daemon.idMapping.UIDs()
|
||||
if uidMap != nil {
|
||||
userNS = true
|
||||
ns := specs.LinuxNamespace{Type: "user"}
|
||||
setNamespace(s, ns)
|
||||
s.Linux.UIDMappings = specMapping(uidMap)
|
||||
s.Linux.GIDMappings = specMapping(daemon.idMappings.GIDs())
|
||||
s.Linux.GIDMappings = specMapping(daemon.idMapping.GIDs())
|
||||
}
|
||||
}
|
||||
// network
|
||||
|
@ -619,7 +619,7 @@ func setMounts(daemon *Daemon, s *specs.Spec, c *container.Container, mounts []c
|
|||
|
||||
// TODO: until a kernel/mount solution exists for handling remount in a user namespace,
|
||||
// we must clear the readonly flag for the cgroups mount (@mrunalp concurs)
|
||||
if uidMap := daemon.idMappings.UIDs(); uidMap != nil || c.HostConfig.Privileged {
|
||||
if uidMap := daemon.idMapping.UIDs(); uidMap != nil || c.HostConfig.Privileged {
|
||||
for i, m := range s.Mounts {
|
||||
if m.Type == "cgroup" {
|
||||
clearReadOnly(&s.Mounts[i])
|
||||
|
@ -642,7 +642,7 @@ func (daemon *Daemon) populateCommonSpec(s *specs.Spec, c *container.Container)
|
|||
Path: c.BaseFS.Path(),
|
||||
Readonly: c.HostConfig.ReadonlyRootfs,
|
||||
}
|
||||
if err := c.SetupWorkingDirectory(daemon.idMappings.RootPair()); err != nil {
|
||||
if err := c.SetupWorkingDirectory(daemon.idMapping.RootPair()); err != nil {
|
||||
return err
|
||||
}
|
||||
cwd := c.Config.WorkingDir
|
||||
|
|
|
@ -21,7 +21,7 @@ func TestTmpfsDevShmNoDupMount(t *testing.T) {
|
|||
d := Daemon{
|
||||
// some empty structs to avoid getting a panic
|
||||
// caused by a null pointer dereference
|
||||
idMappings: &idtools.IDMappings{},
|
||||
idMapping: &idtools.IdentityMapping{},
|
||||
configStore: &config.Config{},
|
||||
}
|
||||
c := &container.Container{
|
||||
|
@ -58,7 +58,7 @@ func TestIpcPrivateVsReadonly(t *testing.T) {
|
|||
d := Daemon{
|
||||
// some empty structs to avoid getting a panic
|
||||
// caused by a null pointer dereference
|
||||
idMappings: &idtools.IDMappings{},
|
||||
idMapping: &idtools.IdentityMapping{},
|
||||
configStore: &config.Config{},
|
||||
}
|
||||
c := &container.Container{
|
||||
|
|
|
@ -47,7 +47,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er
|
|||
return nil
|
||||
}
|
||||
|
||||
path, err := m.Setup(c.MountLabel, daemon.idMappings.RootPair(), checkfunc)
|
||||
path, err := m.Setup(c.MountLabel, daemon.idMapping.RootPair(), checkfunc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er
|
|||
// if we are going to mount any of the network files from container
|
||||
// metadata, the ownership must be set properly for potential container
|
||||
// remapped root (user namespaces)
|
||||
rootIDs := daemon.idMappings.RootPair()
|
||||
rootIDs := daemon.idMapping.RootPair()
|
||||
for _, mount := range netMounts {
|
||||
// we should only modify ownership of network files within our own container
|
||||
// metadata repository. If the user specifies a mount path external, it is
|
||||
|
|
|
@ -24,7 +24,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er
|
|||
if err := daemon.lazyInitializeVolume(c.ID, mount); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s, err := mount.Setup(c.MountLabel, idtools.IDPair{UID: 0, GID: 0}, nil)
|
||||
s, err := mount.Setup(c.MountLabel, idtools.Identity{}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -16,5 +16,5 @@ func (daemon *Daemon) ContainerCreateWorkdir(cID string) error {
|
|||
return err
|
||||
}
|
||||
defer daemon.Unmount(container)
|
||||
return container.SetupWorkingDirectory(daemon.idMappings.RootPair())
|
||||
return container.SetupWorkingDirectory(daemon.idMapping.RootPair())
|
||||
}
|
||||
|
|
20
hack/make/containerutility
Normal file
20
hack/make/containerutility
Normal file
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
CONTAINER_UTILITY_COMMIT=e004a1415a433447369e315b9d7df357102be0d2 # v0.9.0
|
||||
|
||||
(
|
||||
git clone https://github.com/docker/windows-container-utility.git "$GOPATH/src/github.com/docker/windows-container-utility"
|
||||
cd "$GOPATH/src/github.com/docker/windows-container-utility"
|
||||
git checkout -q "$CONTAINER_UTILITY_COMMIT"
|
||||
|
||||
echo Building: ${DEST}/containerutility.exe
|
||||
|
||||
(
|
||||
make
|
||||
)
|
||||
|
||||
mkdir -p ${ABS_DEST}
|
||||
|
||||
cp containerutility.exe ${ABS_DEST}/containerutility.exe
|
||||
)
|
|
@ -25,5 +25,7 @@ for platform in $DOCKER_CROSSPLATFORMS; do
|
|||
mkdir -p "$DEST"
|
||||
ABS_DEST="$(cd "$DEST" && pwd -P)"
|
||||
source "${MAKEDIR}/binary-daemon"
|
||||
|
||||
source "${MAKEDIR}/cross-platform-dependent"
|
||||
)
|
||||
done
|
||||
|
|
6
hack/make/cross-platform-dependent
Normal file
6
hack/make/cross-platform-dependent
Normal file
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
if [ $platform == "windows/amd64" ]; then
|
||||
source "${MAKEDIR}/containerutility"
|
||||
fi
|
|
@ -45,7 +45,7 @@ type StoreOptions struct {
|
|||
MetadataStorePathTemplate string
|
||||
GraphDriver string
|
||||
GraphDriverOptions []string
|
||||
IDMappings *idtools.IDMappings
|
||||
IDMapping *idtools.IdentityMapping
|
||||
PluginGetter plugingetter.PluginGetter
|
||||
ExperimentalEnabled bool
|
||||
OS string
|
||||
|
@ -56,8 +56,8 @@ func NewStoreFromOptions(options StoreOptions) (Store, error) {
|
|||
driver, err := graphdriver.New(options.GraphDriver, options.PluginGetter, graphdriver.Options{
|
||||
Root: options.Root,
|
||||
DriverOptions: options.GraphDriverOptions,
|
||||
UIDMaps: options.IDMappings.UIDs(),
|
||||
GIDMaps: options.IDMappings.GIDs(),
|
||||
UIDMaps: options.IDMapping.UIDs(),
|
||||
GIDMaps: options.IDMapping.GIDs(),
|
||||
ExperimentalEnabled: options.ExperimentalEnabled,
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
@ -58,7 +58,7 @@ func getSpecUser(ociSpec *specs.Spec) (int, int) {
|
|||
func prepareBundleDir(bundleDir string, ociSpec *specs.Spec) (string, error) {
|
||||
uid, gid := getSpecUser(ociSpec)
|
||||
if uid == 0 && gid == 0 {
|
||||
return bundleDir, idtools.MkdirAllAndChownNew(bundleDir, 0755, idtools.IDPair{UID: 0, GID: 0})
|
||||
return bundleDir, idtools.MkdirAllAndChownNew(bundleDir, 0755, idtools.Identity{UID: 0, GID: 0})
|
||||
}
|
||||
|
||||
p := string(filepath.Separator)
|
||||
|
@ -71,7 +71,7 @@ func prepareBundleDir(bundleDir string, ociSpec *specs.Spec) (string, error) {
|
|||
}
|
||||
if os.IsNotExist(err) || fi.Mode()&1 == 0 {
|
||||
p = fmt.Sprintf("%s.%d.%d", p, uid, gid)
|
||||
if err := idtools.MkdirAndChown(p, 0700, idtools.IDPair{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
|
||||
if err := idtools.MkdirAndChown(p, 0700, idtools.Identity{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ type (
|
|||
NoLchown bool
|
||||
UIDMaps []idtools.IDMap
|
||||
GIDMaps []idtools.IDMap
|
||||
ChownOpts *idtools.IDPair
|
||||
ChownOpts *idtools.Identity
|
||||
IncludeSourceDir bool
|
||||
// WhiteoutFormat is the expected on disk format for whiteout files.
|
||||
// This format will be converted to the standard format on pack
|
||||
|
@ -72,13 +72,13 @@ type (
|
|||
// this package with a pluggable Untar function. Also, to facilitate the passing of specific id
|
||||
// mappings for untar, an Archiver can be created with maps which will then be passed to Untar operations.
|
||||
type Archiver struct {
|
||||
Untar func(io.Reader, string, *TarOptions) error
|
||||
IDMappingsVar *idtools.IDMappings
|
||||
Untar func(io.Reader, string, *TarOptions) error
|
||||
IDMapping *idtools.IdentityMapping
|
||||
}
|
||||
|
||||
// NewDefaultArchiver returns a new Archiver without any IDMappings
|
||||
// NewDefaultArchiver returns a new Archiver without any IdentityMapping
|
||||
func NewDefaultArchiver() *Archiver {
|
||||
return &Archiver{Untar: Untar, IDMappingsVar: &idtools.IDMappings{}}
|
||||
return &Archiver{Untar: Untar, IDMapping: &idtools.IdentityMapping{}}
|
||||
}
|
||||
|
||||
// breakoutError is used to differentiate errors related to breaking out
|
||||
|
@ -420,9 +420,9 @@ type tarAppender struct {
|
|||
Buffer *bufio.Writer
|
||||
|
||||
// for hardlink mapping
|
||||
SeenFiles map[uint64]string
|
||||
IDMappings *idtools.IDMappings
|
||||
ChownOpts *idtools.IDPair
|
||||
SeenFiles map[uint64]string
|
||||
IdentityMapping *idtools.IdentityMapping
|
||||
ChownOpts *idtools.Identity
|
||||
|
||||
// For packing and unpacking whiteout files in the
|
||||
// non standard format. The whiteout files defined
|
||||
|
@ -431,13 +431,13 @@ type tarAppender struct {
|
|||
WhiteoutConverter tarWhiteoutConverter
|
||||
}
|
||||
|
||||
func newTarAppender(idMapping *idtools.IDMappings, writer io.Writer, chownOpts *idtools.IDPair) *tarAppender {
|
||||
func newTarAppender(idMapping *idtools.IdentityMapping, writer io.Writer, chownOpts *idtools.Identity) *tarAppender {
|
||||
return &tarAppender{
|
||||
SeenFiles: make(map[uint64]string),
|
||||
TarWriter: tar.NewWriter(writer),
|
||||
Buffer: pools.BufioWriter32KPool.Get(nil),
|
||||
IDMappings: idMapping,
|
||||
ChownOpts: chownOpts,
|
||||
SeenFiles: make(map[uint64]string),
|
||||
TarWriter: tar.NewWriter(writer),
|
||||
Buffer: pools.BufioWriter32KPool.Get(nil),
|
||||
IdentityMapping: idMapping,
|
||||
ChownOpts: chownOpts,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -502,14 +502,12 @@ func (ta *tarAppender) addTarFile(path, name string) error {
|
|||
//handle re-mapping container ID mappings back to host ID mappings before
|
||||
//writing tar headers/files. We skip whiteout files because they were written
|
||||
//by the kernel and already have proper ownership relative to the host
|
||||
if !isOverlayWhiteout &&
|
||||
!strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) &&
|
||||
!ta.IDMappings.Empty() {
|
||||
if !isOverlayWhiteout && !strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) && !ta.IdentityMapping.Empty() {
|
||||
fileIDPair, err := getFileUIDGID(fi.Sys())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hdr.Uid, hdr.Gid, err = ta.IDMappings.ToContainer(fileIDPair)
|
||||
hdr.Uid, hdr.Gid, err = ta.IdentityMapping.ToContainer(fileIDPair)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -572,7 +570,7 @@ func (ta *tarAppender) addTarFile(path, name string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *idtools.IDPair, inUserns bool) error {
|
||||
func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *idtools.Identity, inUserns bool) error {
|
||||
// hdr.Mode is in linux format, which we can use for sycalls,
|
||||
// but for os.Foo() calls we need the mode converted to os.FileMode,
|
||||
// so use hdrInfo.Mode() (they differ for e.g. setuid bits)
|
||||
|
@ -652,7 +650,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
|
|||
// Lchown is not supported on Windows.
|
||||
if Lchown && runtime.GOOS != "windows" {
|
||||
if chownOpts == nil {
|
||||
chownOpts = &idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid}
|
||||
chownOpts = &idtools.Identity{UID: hdr.Uid, GID: hdr.Gid}
|
||||
}
|
||||
if err := os.Lchown(path, chownOpts.UID, chownOpts.GID); err != nil {
|
||||
return err
|
||||
|
@ -901,8 +899,8 @@ func Unpack(decompressedArchive io.Reader, dest string, options *TarOptions) err
|
|||
defer pools.BufioReader32KPool.Put(trBuf)
|
||||
|
||||
var dirs []*tar.Header
|
||||
idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
|
||||
rootIDs := idMappings.RootPair()
|
||||
idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
|
||||
rootIDs := idMapping.RootPair()
|
||||
whiteoutConverter := getWhiteoutConverter(options.WhiteoutFormat)
|
||||
|
||||
// Iterate through the files in the archive.
|
||||
|
@ -981,7 +979,7 @@ loop:
|
|||
}
|
||||
trBuf.Reset(tr)
|
||||
|
||||
if err := remapIDs(idMappings, hdr); err != nil {
|
||||
if err := remapIDs(idMapping, hdr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -1068,8 +1066,8 @@ func (archiver *Archiver) TarUntar(src, dst string) error {
|
|||
}
|
||||
defer archive.Close()
|
||||
options := &TarOptions{
|
||||
UIDMaps: archiver.IDMappingsVar.UIDs(),
|
||||
GIDMaps: archiver.IDMappingsVar.GIDs(),
|
||||
UIDMaps: archiver.IDMapping.UIDs(),
|
||||
GIDMaps: archiver.IDMapping.GIDs(),
|
||||
}
|
||||
return archiver.Untar(archive, dst, options)
|
||||
}
|
||||
|
@ -1082,8 +1080,8 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
|
|||
}
|
||||
defer archive.Close()
|
||||
options := &TarOptions{
|
||||
UIDMaps: archiver.IDMappingsVar.UIDs(),
|
||||
GIDMaps: archiver.IDMappingsVar.GIDs(),
|
||||
UIDMaps: archiver.IDMapping.UIDs(),
|
||||
GIDMaps: archiver.IDMapping.GIDs(),
|
||||
}
|
||||
return archiver.Untar(archive, dst, options)
|
||||
}
|
||||
|
@ -1104,7 +1102,7 @@ func (archiver *Archiver) CopyWithTar(src, dst string) error {
|
|||
// if this Archiver is set up with ID mapping we need to create
|
||||
// the new destination directory with the remapped root UID/GID pair
|
||||
// as owner
|
||||
rootIDs := archiver.IDMappingsVar.RootPair()
|
||||
rootIDs := archiver.IDMapping.RootPair()
|
||||
// Create dst, copy src's content into it
|
||||
logrus.Debugf("Creating dest directory: %s", dst)
|
||||
if err := idtools.MkdirAllAndChownNew(dst, 0755, rootIDs); err != nil {
|
||||
|
@ -1164,7 +1162,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
|
|||
hdr.Name = filepath.Base(dst)
|
||||
hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
|
||||
|
||||
if err := remapIDs(archiver.IDMappingsVar, hdr); err != nil {
|
||||
if err := remapIDs(archiver.IDMapping, hdr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -1192,13 +1190,13 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
// IDMappings returns the IDMappings of the archiver.
|
||||
func (archiver *Archiver) IDMappings() *idtools.IDMappings {
|
||||
return archiver.IDMappingsVar
|
||||
// IdentityMapping returns the IdentityMapping of the archiver.
|
||||
func (archiver *Archiver) IdentityMapping() *idtools.IdentityMapping {
|
||||
return archiver.IDMapping
|
||||
}
|
||||
|
||||
func remapIDs(idMappings *idtools.IDMappings, hdr *tar.Header) error {
|
||||
ids, err := idMappings.ToHost(idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid})
|
||||
func remapIDs(idMapping *idtools.IdentityMapping, hdr *tar.Header) error {
|
||||
ids, err := idMapping.ToHost(idtools.Identity{UID: hdr.Uid, GID: hdr.Gid})
|
||||
hdr.Uid, hdr.Gid = ids.UID, ids.GID
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -755,11 +755,11 @@ func TestTarWithOptionsChownOptsAlwaysOverridesIdPair(t *testing.T) {
|
|||
expectedUID int
|
||||
expectedGID int
|
||||
}{
|
||||
{&TarOptions{ChownOpts: &idtools.IDPair{UID: 1337, GID: 42}}, 1337, 42},
|
||||
{&TarOptions{ChownOpts: &idtools.IDPair{UID: 100001, GID: 100001}, UIDMaps: idMaps, GIDMaps: idMaps}, 100001, 100001},
|
||||
{&TarOptions{ChownOpts: &idtools.IDPair{UID: 0, GID: 0}, NoLchown: false}, 0, 0},
|
||||
{&TarOptions{ChownOpts: &idtools.IDPair{UID: 1, GID: 1}, NoLchown: true}, 1, 1},
|
||||
{&TarOptions{ChownOpts: &idtools.IDPair{UID: 1000, GID: 1000}, NoLchown: true}, 1000, 1000},
|
||||
{&TarOptions{ChownOpts: &idtools.Identity{UID: 1337, GID: 42}}, 1337, 42},
|
||||
{&TarOptions{ChownOpts: &idtools.Identity{UID: 100001, GID: 100001}, UIDMaps: idMaps, GIDMaps: idMaps}, 100001, 100001},
|
||||
{&TarOptions{ChownOpts: &idtools.Identity{UID: 0, GID: 0}, NoLchown: false}, 0, 0},
|
||||
{&TarOptions{ChownOpts: &idtools.Identity{UID: 1, GID: 1}, NoLchown: true}, 1, 1},
|
||||
{&TarOptions{ChownOpts: &idtools.Identity{UID: 1000, GID: 1000}, NoLchown: true}, 1000, 1000},
|
||||
}
|
||||
for _, testCase := range cases {
|
||||
reader, err := TarWithOptions(filePath, testCase.opts)
|
||||
|
|
|
@ -68,13 +68,13 @@ func getInodeFromStat(stat interface{}) (inode uint64, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func getFileUIDGID(stat interface{}) (idtools.IDPair, error) {
|
||||
func getFileUIDGID(stat interface{}) (idtools.Identity, error) {
|
||||
s, ok := stat.(*syscall.Stat_t)
|
||||
|
||||
if !ok {
|
||||
return idtools.IDPair{}, errors.New("cannot convert stat value to syscall.Stat_t")
|
||||
return idtools.Identity{}, errors.New("cannot convert stat value to syscall.Stat_t")
|
||||
}
|
||||
return idtools.IDPair{UID: int(s.Uid), GID: int(s.Gid)}, nil
|
||||
return idtools.Identity{UID: int(s.Uid), GID: int(s.Gid)}, nil
|
||||
}
|
||||
|
||||
// handleTarTypeBlockCharFifo is an OS-specific helper function used by
|
||||
|
|
|
@ -61,7 +61,7 @@ func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func getFileUIDGID(stat interface{}) (idtools.IDPair, error) {
|
||||
func getFileUIDGID(stat interface{}) (idtools.Identity, error) {
|
||||
// no notion of file ownership mapping yet on Windows
|
||||
return idtools.IDPair{UID: 0, GID: 0}, nil
|
||||
return idtools.Identity{UID: 0, GID: 0}, nil
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
|||
if options.ExcludePatterns == nil {
|
||||
options.ExcludePatterns = []string{}
|
||||
}
|
||||
idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
|
||||
idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
|
||||
|
||||
aufsTempdir := ""
|
||||
aufsHardlinks := make(map[string]*tar.Header)
|
||||
|
@ -192,7 +192,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
|||
srcData = tmpFile
|
||||
}
|
||||
|
||||
if err := remapIDs(idMappings, srcHdr); err != nil {
|
||||
if err := remapIDs(idMapping, srcHdr); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
|
|
|
@ -12,13 +12,13 @@ import (
|
|||
)
|
||||
|
||||
// NewArchiver returns a new Archiver which uses chrootarchive.Untar
|
||||
func NewArchiver(idMappings *idtools.IDMappings) *archive.Archiver {
|
||||
if idMappings == nil {
|
||||
idMappings = &idtools.IDMappings{}
|
||||
func NewArchiver(idMapping *idtools.IdentityMapping) *archive.Archiver {
|
||||
if idMapping == nil {
|
||||
idMapping = &idtools.IdentityMapping{}
|
||||
}
|
||||
return &archive.Archiver{
|
||||
Untar: Untar,
|
||||
IDMappingsVar: idMappings,
|
||||
Untar: Untar,
|
||||
IDMapping: idMapping,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,8 +49,8 @@ func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions
|
|||
options.ExcludePatterns = []string{}
|
||||
}
|
||||
|
||||
idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
|
||||
rootIDs := idMappings.RootPair()
|
||||
idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
|
||||
rootIDs := idMapping.RootPair()
|
||||
|
||||
dest = filepath.Clean(dest)
|
||||
if _, err := os.Stat(dest); os.IsNotExist(err) {
|
||||
|
|
|
@ -22,11 +22,11 @@ type UntarFunc func(io.Reader, string, *archive.TarOptions) error
|
|||
|
||||
// Archiver provides a similar implementation of the archive.Archiver package with the rootfs abstraction
|
||||
type Archiver struct {
|
||||
SrcDriver Driver
|
||||
DstDriver Driver
|
||||
Tar TarFunc
|
||||
Untar UntarFunc
|
||||
IDMappingsVar *idtools.IDMappings
|
||||
SrcDriver Driver
|
||||
DstDriver Driver
|
||||
Tar TarFunc
|
||||
Untar UntarFunc
|
||||
IDMapping *idtools.IdentityMapping
|
||||
}
|
||||
|
||||
// TarUntar is a convenience function which calls Tar and Untar, with the output of one piped into the other.
|
||||
|
@ -39,8 +39,8 @@ func (archiver *Archiver) TarUntar(src, dst string) error {
|
|||
}
|
||||
defer tarArchive.Close()
|
||||
options := &archive.TarOptions{
|
||||
UIDMaps: archiver.IDMappingsVar.UIDs(),
|
||||
GIDMaps: archiver.IDMappingsVar.GIDs(),
|
||||
UIDMaps: archiver.IDMapping.UIDs(),
|
||||
GIDMaps: archiver.IDMapping.GIDs(),
|
||||
}
|
||||
return archiver.Untar(tarArchive, dst, options)
|
||||
}
|
||||
|
@ -53,8 +53,8 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
|
|||
}
|
||||
defer tarArchive.Close()
|
||||
options := &archive.TarOptions{
|
||||
UIDMaps: archiver.IDMappingsVar.UIDs(),
|
||||
GIDMaps: archiver.IDMappingsVar.GIDs(),
|
||||
UIDMaps: archiver.IDMapping.UIDs(),
|
||||
GIDMaps: archiver.IDMapping.GIDs(),
|
||||
}
|
||||
return archiver.Untar(tarArchive, dst, options)
|
||||
}
|
||||
|
@ -75,9 +75,11 @@ func (archiver *Archiver) CopyWithTar(src, dst string) error {
|
|||
// if this archiver is set up with ID mapping we need to create
|
||||
// the new destination directory with the remapped root UID/GID pair
|
||||
// as owner
|
||||
rootIDs := archiver.IDMappingsVar.RootPair()
|
||||
|
||||
identity := idtools.Identity{UID: archiver.IDMapping.RootPair().UID, GID: archiver.IDMapping.RootPair().GID}
|
||||
|
||||
// Create dst, copy src's content into it
|
||||
if err := idtools.MkdirAllAndChownNew(dst, 0755, rootIDs); err != nil {
|
||||
if err := idtools.MkdirAllAndChownNew(dst, 0755, identity); err != nil {
|
||||
return err
|
||||
}
|
||||
logrus.Debugf("Calling TarUntar(%s, %s)", src, dst)
|
||||
|
@ -150,7 +152,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
|
|||
hdr.Mode = int64(os.FileMode(hdr.Mode))
|
||||
}
|
||||
|
||||
if err := remapIDs(archiver.IDMappingsVar, hdr); err != nil {
|
||||
if err := remapIDs(archiver.IDMapping, hdr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -178,13 +180,13 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
// IDMappings returns the IDMappings of the archiver.
|
||||
func (archiver *Archiver) IDMappings() *idtools.IDMappings {
|
||||
return archiver.IDMappingsVar
|
||||
// IdentityMapping returns the IdentityMapping of the archiver.
|
||||
func (archiver *Archiver) IdentityMapping() *idtools.IdentityMapping {
|
||||
return archiver.IDMapping
|
||||
}
|
||||
|
||||
func remapIDs(idMappings *idtools.IDMappings, hdr *tar.Header) error {
|
||||
ids, err := idMappings.ToHost(idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid})
|
||||
func remapIDs(idMapping *idtools.IdentityMapping, hdr *tar.Header) error {
|
||||
ids, err := idMapping.ToHost(idtools.Identity{UID: hdr.Uid, GID: hdr.Gid})
|
||||
hdr.Uid, hdr.Gid = ids.UID, ids.GID
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -37,23 +37,23 @@ const (
|
|||
// MkdirAllAndChown creates a directory (include any along the path) and then modifies
|
||||
// ownership to the requested uid/gid. If the directory already exists, this
|
||||
// function will still change ownership to the requested uid/gid pair.
|
||||
func MkdirAllAndChown(path string, mode os.FileMode, owner IDPair) error {
|
||||
return mkdirAs(path, mode, owner.UID, owner.GID, true, true)
|
||||
func MkdirAllAndChown(path string, mode os.FileMode, owner Identity) error {
|
||||
return mkdirAs(path, mode, owner, true, true)
|
||||
}
|
||||
|
||||
// MkdirAndChown creates a directory and then modifies ownership to the requested uid/gid.
|
||||
// If the directory already exists, this function still changes ownership.
|
||||
// Note that unlike os.Mkdir(), this function does not return IsExist error
|
||||
// in case path already exists.
|
||||
func MkdirAndChown(path string, mode os.FileMode, owner IDPair) error {
|
||||
return mkdirAs(path, mode, owner.UID, owner.GID, false, true)
|
||||
func MkdirAndChown(path string, mode os.FileMode, owner Identity) error {
|
||||
return mkdirAs(path, mode, owner, false, true)
|
||||
}
|
||||
|
||||
// MkdirAllAndChownNew creates a directory (include any along the path) and then modifies
|
||||
// ownership ONLY of newly created directories to the requested uid/gid. If the
|
||||
// directories along the path exist, no change of ownership will be performed
|
||||
func MkdirAllAndChownNew(path string, mode os.FileMode, owner IDPair) error {
|
||||
return mkdirAs(path, mode, owner.UID, owner.GID, true, false)
|
||||
func MkdirAllAndChownNew(path string, mode os.FileMode, owner Identity) error {
|
||||
return mkdirAs(path, mode, owner, true, false)
|
||||
}
|
||||
|
||||
// GetRootUIDGID retrieves the remapped root uid/gid pair from the set of maps.
|
||||
|
@ -102,22 +102,23 @@ func toHost(contID int, idMap []IDMap) (int, error) {
|
|||
return -1, fmt.Errorf("Container ID %d cannot be mapped to a host ID", contID)
|
||||
}
|
||||
|
||||
// IDPair is a UID and GID pair
|
||||
type IDPair struct {
|
||||
// Identity is either a UID and GID pair or a SID (but not both)
|
||||
type Identity struct {
|
||||
UID int
|
||||
GID int
|
||||
SID string
|
||||
}
|
||||
|
||||
// IDMappings contains a mappings of UIDs and GIDs
|
||||
type IDMappings struct {
|
||||
// IdentityMapping contains a mappings of UIDs and GIDs
|
||||
type IdentityMapping struct {
|
||||
uids []IDMap
|
||||
gids []IDMap
|
||||
}
|
||||
|
||||
// NewIDMappings takes a requested user and group name and
|
||||
// NewIdentityMapping takes a requested user and group name and
|
||||
// using the data from /etc/sub{uid,gid} ranges, creates the
|
||||
// proper uid and gid remapping ranges for that user/group pair
|
||||
func NewIDMappings(username, groupname string) (*IDMappings, error) {
|
||||
func NewIdentityMapping(username, groupname string) (*IdentityMapping, error) {
|
||||
subuidRanges, err := parseSubuid(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -133,7 +134,7 @@ func NewIDMappings(username, groupname string) (*IDMappings, error) {
|
|||
return nil, fmt.Errorf("No subgid ranges found for group %q", groupname)
|
||||
}
|
||||
|
||||
return &IDMappings{
|
||||
return &IdentityMapping{
|
||||
uids: createIDMap(subuidRanges),
|
||||
gids: createIDMap(subgidRanges),
|
||||
}, nil
|
||||
|
@ -141,21 +142,21 @@ func NewIDMappings(username, groupname string) (*IDMappings, error) {
|
|||
|
||||
// NewIDMappingsFromMaps creates a new mapping from two slices
|
||||
// Deprecated: this is a temporary shim while transitioning to IDMapping
|
||||
func NewIDMappingsFromMaps(uids []IDMap, gids []IDMap) *IDMappings {
|
||||
return &IDMappings{uids: uids, gids: gids}
|
||||
func NewIDMappingsFromMaps(uids []IDMap, gids []IDMap) *IdentityMapping {
|
||||
return &IdentityMapping{uids: uids, gids: gids}
|
||||
}
|
||||
|
||||
// RootPair returns a uid and gid pair for the root user. The error is ignored
|
||||
// because a root user always exists, and the defaults are correct when the uid
|
||||
// and gid maps are empty.
|
||||
func (i *IDMappings) RootPair() IDPair {
|
||||
func (i *IdentityMapping) RootPair() Identity {
|
||||
uid, gid, _ := GetRootUIDGID(i.uids, i.gids)
|
||||
return IDPair{UID: uid, GID: gid}
|
||||
return Identity{UID: uid, GID: gid}
|
||||
}
|
||||
|
||||
// ToHost returns the host UID and GID for the container uid, gid.
|
||||
// Remapping is only performed if the ids aren't already the remapped root ids
|
||||
func (i *IDMappings) ToHost(pair IDPair) (IDPair, error) {
|
||||
func (i *IdentityMapping) ToHost(pair Identity) (Identity, error) {
|
||||
var err error
|
||||
target := i.RootPair()
|
||||
|
||||
|
@ -173,7 +174,7 @@ func (i *IDMappings) ToHost(pair IDPair) (IDPair, error) {
|
|||
}
|
||||
|
||||
// ToContainer returns the container UID and GID for the host uid and gid
|
||||
func (i *IDMappings) ToContainer(pair IDPair) (int, int, error) {
|
||||
func (i *IdentityMapping) ToContainer(pair Identity) (int, int, error) {
|
||||
uid, err := toContainer(pair.UID, i.uids)
|
||||
if err != nil {
|
||||
return -1, -1, err
|
||||
|
@ -183,19 +184,19 @@ func (i *IDMappings) ToContainer(pair IDPair) (int, int, error) {
|
|||
}
|
||||
|
||||
// Empty returns true if there are no id mappings
|
||||
func (i *IDMappings) Empty() bool {
|
||||
func (i *IdentityMapping) Empty() bool {
|
||||
return len(i.uids) == 0 && len(i.gids) == 0
|
||||
}
|
||||
|
||||
// UIDs return the UID mapping
|
||||
// TODO: remove this once everything has been refactored to use pairs
|
||||
func (i *IDMappings) UIDs() []IDMap {
|
||||
func (i *IdentityMapping) UIDs() []IDMap {
|
||||
return i.uids
|
||||
}
|
||||
|
||||
// GIDs return the UID mapping
|
||||
// TODO: remove this once everything has been refactored to use pairs
|
||||
func (i *IDMappings) GIDs() []IDMap {
|
||||
func (i *IdentityMapping) GIDs() []IDMap {
|
||||
return i.gids
|
||||
}
|
||||
|
||||
|
|
|
@ -21,11 +21,12 @@ var (
|
|||
getentCmd string
|
||||
)
|
||||
|
||||
func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chownExisting bool) error {
|
||||
func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error {
|
||||
// make an array containing the original path asked for, plus (for mkAll == true)
|
||||
// all path components leading up to the complete path that don't exist before we MkdirAll
|
||||
// so that we can chown all of them properly at the end. If chownExisting is false, we won't
|
||||
// chown the full directory path if it exists
|
||||
|
||||
var paths []string
|
||||
|
||||
stat, err := system.Stat(path)
|
||||
|
@ -38,7 +39,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
|
|||
}
|
||||
|
||||
// short-circuit--we were called with an existing directory and chown was requested
|
||||
return lazyChown(path, ownerUID, ownerGID, stat)
|
||||
return lazyChown(path, owner.UID, owner.GID, stat)
|
||||
}
|
||||
|
||||
if os.IsNotExist(err) {
|
||||
|
@ -69,7 +70,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
|
|||
// even if it existed, we will chown the requested path + any subpaths that
|
||||
// didn't exist when we called MkdirAll
|
||||
for _, pathComponent := range paths {
|
||||
if err := lazyChown(pathComponent, ownerUID, ownerGID, nil); err != nil {
|
||||
if err := lazyChown(pathComponent, owner.UID, owner.GID, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +79,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
|
|||
|
||||
// CanAccess takes a valid (existing) directory and a uid, gid pair and determines
|
||||
// if that uid, gid pair has access (execute bit) to the directory
|
||||
func CanAccess(path string, pair IDPair) bool {
|
||||
func CanAccess(path string, pair Identity) bool {
|
||||
statInfo, err := system.Stat(path)
|
||||
if err != nil {
|
||||
return false
|
||||
|
|
|
@ -46,7 +46,7 @@ func TestMkdirAllAndChown(t *testing.T) {
|
|||
}
|
||||
|
||||
// test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid
|
||||
if err := MkdirAllAndChown(filepath.Join(dirName, "usr", "share"), 0755, IDPair{UID: 99, GID: 99}); err != nil {
|
||||
if err := MkdirAllAndChown(filepath.Join(dirName, "usr", "share"), 0755, Identity{UID: 99, GID: 99}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testTree["usr/share"] = node{99, 99}
|
||||
|
@ -59,7 +59,7 @@ func TestMkdirAllAndChown(t *testing.T) {
|
|||
}
|
||||
|
||||
// test 2-deep new directories--both should be owned by the uid/gid pair
|
||||
if err := MkdirAllAndChown(filepath.Join(dirName, "lib", "some", "other"), 0755, IDPair{UID: 101, GID: 101}); err != nil {
|
||||
if err := MkdirAllAndChown(filepath.Join(dirName, "lib", "some", "other"), 0755, Identity{UID: 101, GID: 101}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testTree["lib/some"] = node{101, 101}
|
||||
|
@ -73,7 +73,7 @@ func TestMkdirAllAndChown(t *testing.T) {
|
|||
}
|
||||
|
||||
// test a directory that already exists; should be chowned, but nothing else
|
||||
if err := MkdirAllAndChown(filepath.Join(dirName, "usr"), 0755, IDPair{UID: 102, GID: 102}); err != nil {
|
||||
if err := MkdirAllAndChown(filepath.Join(dirName, "usr"), 0755, Identity{UID: 102, GID: 102}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testTree["usr"] = node{102, 102}
|
||||
|
@ -102,7 +102,7 @@ func TestMkdirAllAndChownNew(t *testing.T) {
|
|||
assert.NilError(t, buildTree(dirName, testTree))
|
||||
|
||||
// test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid
|
||||
err = MkdirAllAndChownNew(filepath.Join(dirName, "usr", "share"), 0755, IDPair{UID: 99, GID: 99})
|
||||
err = MkdirAllAndChownNew(filepath.Join(dirName, "usr", "share"), 0755, Identity{UID: 99, GID: 99})
|
||||
assert.NilError(t, err)
|
||||
|
||||
testTree["usr/share"] = node{99, 99}
|
||||
|
@ -111,7 +111,7 @@ func TestMkdirAllAndChownNew(t *testing.T) {
|
|||
assert.NilError(t, compareTrees(testTree, verifyTree))
|
||||
|
||||
// test 2-deep new directories--both should be owned by the uid/gid pair
|
||||
err = MkdirAllAndChownNew(filepath.Join(dirName, "lib", "some", "other"), 0755, IDPair{UID: 101, GID: 101})
|
||||
err = MkdirAllAndChownNew(filepath.Join(dirName, "lib", "some", "other"), 0755, Identity{UID: 101, GID: 101})
|
||||
assert.NilError(t, err)
|
||||
testTree["lib/some"] = node{101, 101}
|
||||
testTree["lib/some/other"] = node{101, 101}
|
||||
|
@ -120,7 +120,7 @@ func TestMkdirAllAndChownNew(t *testing.T) {
|
|||
assert.NilError(t, compareTrees(testTree, verifyTree))
|
||||
|
||||
// test a directory that already exists; should NOT be chowned
|
||||
err = MkdirAllAndChownNew(filepath.Join(dirName, "usr"), 0755, IDPair{UID: 102, GID: 102})
|
||||
err = MkdirAllAndChownNew(filepath.Join(dirName, "usr"), 0755, Identity{UID: 102, GID: 102})
|
||||
assert.NilError(t, err)
|
||||
verifyTree, err = readTree(dirName, "")
|
||||
assert.NilError(t, err)
|
||||
|
@ -143,7 +143,7 @@ func TestMkdirAndChown(t *testing.T) {
|
|||
}
|
||||
|
||||
// test a directory that already exists; should just chown to the requested uid/gid
|
||||
if err := MkdirAndChown(filepath.Join(dirName, "usr"), 0755, IDPair{UID: 99, GID: 99}); err != nil {
|
||||
if err := MkdirAndChown(filepath.Join(dirName, "usr"), 0755, Identity{UID: 99, GID: 99}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testTree["usr"] = node{99, 99}
|
||||
|
@ -156,12 +156,12 @@ func TestMkdirAndChown(t *testing.T) {
|
|||
}
|
||||
|
||||
// create a subdir under a dir which doesn't exist--should fail
|
||||
if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin", "subdir"), 0755, IDPair{UID: 102, GID: 102}); err == nil {
|
||||
if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin", "subdir"), 0755, Identity{UID: 102, GID: 102}); err == nil {
|
||||
t.Fatalf("Trying to create a directory with Mkdir where the parent doesn't exist should have failed")
|
||||
}
|
||||
|
||||
// create a subdir under an existing dir; should only change the ownership of the new subdir
|
||||
if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin"), 0755, IDPair{UID: 102, GID: 102}); err != nil {
|
||||
if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin"), 0755, Identity{UID: 102, GID: 102}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testTree["usr/bin"] = node{102, 102}
|
||||
|
@ -326,19 +326,19 @@ func TestNewIDMappings(t *testing.T) {
|
|||
group, err := user.LookupGroupId(string(gids[0]))
|
||||
assert.Check(t, err)
|
||||
|
||||
idMappings, err := NewIDMappings(tempUser.Username, group.Name)
|
||||
idMapping, err := NewIdentityMapping(tempUser.Username, group.Name)
|
||||
assert.Check(t, err)
|
||||
|
||||
rootUID, rootGID, err := GetRootUIDGID(idMappings.UIDs(), idMappings.GIDs())
|
||||
rootUID, rootGID, err := GetRootUIDGID(idMapping.UIDs(), idMapping.GIDs())
|
||||
assert.Check(t, err)
|
||||
|
||||
dirName, err := ioutil.TempDir("", "mkdirall")
|
||||
assert.Check(t, err, "Couldn't create temp directory")
|
||||
defer os.RemoveAll(dirName)
|
||||
|
||||
err = MkdirAllAndChown(dirName, 0700, IDPair{UID: rootUID, GID: rootGID})
|
||||
err = MkdirAllAndChown(dirName, 0700, Identity{UID: rootUID, GID: rootGID})
|
||||
assert.Check(t, err, "Couldn't change ownership of file path. Got error")
|
||||
assert.Check(t, CanAccess(dirName, idMappings.RootPair()), fmt.Sprintf("Unable to access %s directory with user UID:%d and GID:%d", dirName, rootUID, rootGID))
|
||||
assert.Check(t, CanAccess(dirName, idMapping.RootPair()), fmt.Sprintf("Unable to access %s directory with user UID:%d and GID:%d", dirName, rootUID, rootGID))
|
||||
}
|
||||
|
||||
func TestLookupUserAndGroup(t *testing.T) {
|
||||
|
@ -388,7 +388,7 @@ func TestMkdirIsNotDir(t *testing.T) {
|
|||
}
|
||||
defer os.Remove(file.Name())
|
||||
|
||||
err = mkdirAs(file.Name(), 0755, 0, 0, false, false)
|
||||
err = mkdirAs(file.Name(), 0755, Identity{UID: 0, GID: 0}, false, false)
|
||||
assert.Check(t, is.Error(err, "mkdir "+file.Name()+": not a directory"))
|
||||
}
|
||||
|
||||
|
|
|
@ -6,9 +6,11 @@ import (
|
|||
"github.com/docker/docker/pkg/system"
|
||||
)
|
||||
|
||||
// Platforms such as Windows do not support the UID/GID concept. So make this
|
||||
// just a wrapper around system.MkdirAll.
|
||||
func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chownExisting bool) error {
|
||||
// This is currently a wrapper around MkdirAll, however, since currently
|
||||
// permissions aren't set through this path, the identity isn't utilized.
|
||||
// Ownership is handled elsewhere, but in the future could be support here
|
||||
// too.
|
||||
func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error {
|
||||
if err := system.MkdirAll(path, mode, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -18,6 +20,6 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
|
|||
// CanAccess takes a valid (existing) directory and a uid, gid pair and determines
|
||||
// if that uid, gid pair has access (execute bit) to the directory
|
||||
// Windows does not require/support this function, so always return true
|
||||
func CanAccess(path string, pair IDPair) bool {
|
||||
func CanAccess(path string, identity Identity) bool {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -2,16 +2,62 @@ package system // import "github.com/docker/docker/pkg/system"
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
const (
|
||||
OWNER_SECURITY_INFORMATION = 0x00000001
|
||||
GROUP_SECURITY_INFORMATION = 0x00000002
|
||||
DACL_SECURITY_INFORMATION = 0x00000004
|
||||
SACL_SECURITY_INFORMATION = 0x00000008
|
||||
LABEL_SECURITY_INFORMATION = 0x00000010
|
||||
ATTRIBUTE_SECURITY_INFORMATION = 0x00000020
|
||||
SCOPE_SECURITY_INFORMATION = 0x00000040
|
||||
PROCESS_TRUST_LABEL_SECURITY_INFORMATION = 0x00000080
|
||||
ACCESS_FILTER_SECURITY_INFORMATION = 0x00000100
|
||||
BACKUP_SECURITY_INFORMATION = 0x00010000
|
||||
PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000
|
||||
PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000
|
||||
UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000
|
||||
UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000
|
||||
)
|
||||
|
||||
const (
|
||||
SE_UNKNOWN_OBJECT_TYPE = iota
|
||||
SE_FILE_OBJECT
|
||||
SE_SERVICE
|
||||
SE_PRINTER
|
||||
SE_REGISTRY_KEY
|
||||
SE_LMSHARE
|
||||
SE_KERNEL_OBJECT
|
||||
SE_WINDOW_OBJECT
|
||||
SE_DS_OBJECT
|
||||
SE_DS_OBJECT_ALL
|
||||
SE_PROVIDER_DEFINED_OBJECT
|
||||
SE_WMIGUID_OBJECT
|
||||
SE_REGISTRY_WOW64_32KEY
|
||||
)
|
||||
|
||||
const (
|
||||
SeTakeOwnershipPrivilege = "SeTakeOwnershipPrivilege"
|
||||
)
|
||||
|
||||
const (
|
||||
ContainerAdministratorSidString = "S-1-5-93-2-1"
|
||||
ContainerUserSidString = "S-1-5-93-2-2"
|
||||
)
|
||||
|
||||
var (
|
||||
ntuserApiset = windows.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0")
|
||||
procGetVersionExW = modkernel32.NewProc("GetVersionExW")
|
||||
procGetProductInfo = modkernel32.NewProc("GetProductInfo")
|
||||
ntuserApiset = windows.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0")
|
||||
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
||||
procGetVersionExW = modkernel32.NewProc("GetVersionExW")
|
||||
procGetProductInfo = modkernel32.NewProc("GetProductInfo")
|
||||
procSetNamedSecurityInfo = modadvapi32.NewProc("SetNamedSecurityInfoW")
|
||||
procGetSecurityDescriptorDacl = modadvapi32.NewProc("GetSecurityDescriptorDacl")
|
||||
)
|
||||
|
||||
// OSVersion is a wrapper for Windows version information
|
||||
|
@ -125,3 +171,23 @@ func HasWin32KSupport() bool {
|
|||
// APIs.
|
||||
return ntuserApiset.Load() == nil
|
||||
}
|
||||
|
||||
func SetNamedSecurityInfo(objectName *uint16, objectType uint32, securityInformation uint32, sidOwner *windows.SID, sidGroup *windows.SID, dacl *byte, sacl *byte) (result error) {
|
||||
r0, _, _ := syscall.Syscall9(procSetNamedSecurityInfo.Addr(), 7, uintptr(unsafe.Pointer(objectName)), uintptr(objectType), uintptr(securityInformation), uintptr(unsafe.Pointer(sidOwner)), uintptr(unsafe.Pointer(sidGroup)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl)), 0, 0)
|
||||
if r0 != 0 {
|
||||
result = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetSecurityDescriptorDacl(securityDescriptor *byte, daclPresent *uint32, dacl **byte, daclDefaulted *uint32) (result error) {
|
||||
r1, _, e1 := syscall.Syscall6(procGetSecurityDescriptorDacl.Addr(), 4, uintptr(unsafe.Pointer(securityDescriptor)), uintptr(unsafe.Pointer(daclPresent)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(daclDefaulted)), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
result = syscall.Errno(e1)
|
||||
} else {
|
||||
result = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ func (pm *Manager) enable(p *v2.Plugin, c *controller, force bool) error {
|
|||
}
|
||||
|
||||
rootFS := containerfs.NewLocalContainerFS(filepath.Join(pm.config.Root, p.PluginObj.ID, rootFSFileName))
|
||||
if err := initlayer.Setup(rootFS, idtools.IDPair{UID: 0, GID: 0}); err != nil {
|
||||
if err := initlayer.Setup(rootFS, idtools.Identity{UID: 0, GID: 0}); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -46,18 +46,18 @@ type activeMount struct {
|
|||
// New instantiates a new Root instance with the provided scope. Scope
|
||||
// is the base path that the Root instance uses to store its
|
||||
// volumes. The base path is created here if it does not exist.
|
||||
func New(scope string, rootIDs idtools.IDPair) (*Root, error) {
|
||||
func New(scope string, rootIdentity idtools.Identity) (*Root, error) {
|
||||
rootDirectory := filepath.Join(scope, volumesPathName)
|
||||
|
||||
if err := idtools.MkdirAllAndChown(rootDirectory, 0700, rootIDs); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(rootDirectory, 0700, rootIdentity); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := &Root{
|
||||
scope: scope,
|
||||
path: rootDirectory,
|
||||
volumes: make(map[string]*localVolume),
|
||||
rootIDs: rootIDs,
|
||||
scope: scope,
|
||||
path: rootDirectory,
|
||||
volumes: make(map[string]*localVolume),
|
||||
rootIdentity: rootIdentity,
|
||||
}
|
||||
|
||||
dirs, err := ioutil.ReadDir(rootDirectory)
|
||||
|
@ -101,11 +101,11 @@ func New(scope string, rootIDs idtools.IDPair) (*Root, error) {
|
|||
// manages the creation/removal of volumes. It uses only standard vfs
|
||||
// commands to create/remove dirs within its provided scope.
|
||||
type Root struct {
|
||||
m sync.Mutex
|
||||
scope string
|
||||
path string
|
||||
volumes map[string]*localVolume
|
||||
rootIDs idtools.IDPair
|
||||
m sync.Mutex
|
||||
scope string
|
||||
path string
|
||||
volumes map[string]*localVolume
|
||||
rootIdentity idtools.Identity
|
||||
}
|
||||
|
||||
// List lists all the volumes
|
||||
|
@ -146,7 +146,7 @@ func (r *Root) Create(name string, opts map[string]string) (volume.Volume, error
|
|||
}
|
||||
|
||||
path := r.DataPath(name)
|
||||
if err := idtools.MkdirAllAndChown(path, 0755, r.rootIDs); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(path, 0755, r.rootIdentity); err != nil {
|
||||
return nil, errors.Wrapf(errdefs.System(err), "error while creating volume path '%s'", path)
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ func TestRemove(t *testing.T) {
|
|||
}
|
||||
defer os.RemoveAll(rootDir)
|
||||
|
||||
r, err := New(rootDir, idtools.IDPair{UID: os.Geteuid(), GID: os.Getegid()})
|
||||
r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ func TestInitializeWithVolumes(t *testing.T) {
|
|||
}
|
||||
defer os.RemoveAll(rootDir)
|
||||
|
||||
r, err := New(rootDir, idtools.IDPair{UID: os.Geteuid(), GID: os.Getegid()})
|
||||
r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ func TestInitializeWithVolumes(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r, err = New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
|
||||
r, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ func TestCreate(t *testing.T) {
|
|||
}
|
||||
defer os.RemoveAll(rootDir)
|
||||
|
||||
r, err := New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
|
||||
r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ func TestCreate(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
r, err = New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
|
||||
r, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ func TestCreateWithOpts(t *testing.T) {
|
|||
}
|
||||
defer os.RemoveAll(rootDir)
|
||||
|
||||
r, err := New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
|
||||
r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -261,7 +261,7 @@ func TestCreateWithOpts(t *testing.T) {
|
|||
t.Fatal("expected mount to still be active")
|
||||
}
|
||||
|
||||
r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0})
|
||||
r, err = New(rootDir, idtools.Identity{UID: 0, GID: 0})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -283,7 +283,7 @@ func TestRelaodNoOpts(t *testing.T) {
|
|||
}
|
||||
defer os.RemoveAll(rootDir)
|
||||
|
||||
r, err := New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
|
||||
r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -311,7 +311,7 @@ func TestRelaodNoOpts(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r, err = New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
|
||||
r, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ func (m *MountPoint) Cleanup() error {
|
|||
// configured, or creating the source directory if supplied.
|
||||
// The, optional, checkFun parameter allows doing additional checking
|
||||
// before creating the source directory on the host.
|
||||
func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.IDPair, checkFun func(m *MountPoint) error) (path string, err error) {
|
||||
func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.Identity, checkFun func(m *MountPoint) error) (path string, err error) {
|
||||
if m.SkipMountpointCreation {
|
||||
return m.Source, nil
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func setupDefaultDriver(store *drivers.Store, root string, rootIDs idtools.IDPair) error {
|
||||
func setupDefaultDriver(store *drivers.Store, root string, rootIDs idtools.Identity) error {
|
||||
d, err := local.New(root, rootIDs)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error setting up default driver")
|
||||
|
|
|
@ -7,4 +7,4 @@ import (
|
|||
"github.com/docker/docker/volume/drivers"
|
||||
)
|
||||
|
||||
func setupDefaultDriver(_ *drivers.Store, _ string, _ idtools.IDPair) error { return nil }
|
||||
func setupDefaultDriver(_ *drivers.Store, _ string, _ idtools.Identity) error { return nil }
|
||||
|
|
|
@ -35,7 +35,7 @@ type VolumesService struct {
|
|||
}
|
||||
|
||||
// NewVolumeService creates a new volume service
|
||||
func NewVolumeService(root string, pg plugingetter.PluginGetter, rootIDs idtools.IDPair, logger volumeEventLogger) (*VolumesService, error) {
|
||||
func NewVolumeService(root string, pg plugingetter.PluginGetter, rootIDs idtools.Identity, logger volumeEventLogger) (*VolumesService, error) {
|
||||
ds := drivers.NewStore(pg)
|
||||
if err := setupDefaultDriver(ds, root, rootIDs); err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -25,7 +25,7 @@ func TestLocalVolumeSize(t *testing.T) {
|
|||
assert.Assert(t, err)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
l, err := local.New(dir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
|
||||
l, err := local.New(dir, idtools.Identity{UID: os.Getuid(), GID: os.Getegid()})
|
||||
assert.Assert(t, err)
|
||||
assert.Assert(t, ds.Register(l, volume.DefaultDriverName))
|
||||
assert.Assert(t, ds.Register(testutils.NewFakeDriver("fake"), "fake"))
|
||||
|
|
Loading…
Reference in a new issue