Finish refactor of UID/GID usage to a new struct

Finish the refactor which was partially completed with commit
34536c498d, passing around IdentityMapping structs instead of pairs of
[]IDMap slices.

Existing code which uses []IDMap relies on zero-valued fields to be
valid, empty mappings. So in order to successfully finish the
refactoring without introducing bugs, their replacement therefore also
needs to have a useful zero value which represents an empty mapping.
Change IdentityMapping to be a pass-by-value type so that there are no
nil pointers to worry about.

The functionality provided by the deprecated NewIDMappingsFromMaps
function is required by unit tests to to construct arbitrary
IdentityMapping values. And the daemon will always need to access the
mappings to pass them to the Linux kernel. Accommodate these use cases
by exporting the struct fields instead. BuildKit currently depends on
the UIDs and GIDs methods so we cannot get rid of them yet.

Signed-off-by: Cory Snider <csnider@mirantis.com>
This commit is contained in:
Cory Snider 2022-03-14 15:24:29 -04:00
parent 16009830c2
commit 098a44c07f
51 changed files with 301 additions and 340 deletions

View file

@ -31,7 +31,7 @@ type Opt struct {
GraphDriver graphdriver.Driver
LayerStore layer.Store
Root string
IdentityMapping *idtools.IdentityMapping
IdentityMapping idtools.IdentityMapping
}
type graphIDRegistrar interface {
@ -99,7 +99,12 @@ func (s *snapshotter) Name() string {
}
func (s *snapshotter) IdentityMapping() *idtools.IdentityMapping {
return s.opt.IdentityMapping
// Returning a non-nil but empty *IdentityMapping breaks BuildKit:
// https://github.com/moby/moby/pull/39444
if s.opt.IdentityMapping.Empty() {
return nil
}
return &s.opt.IdentityMapping
}
func (s *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshots.Opt) error {
@ -481,7 +486,7 @@ type mountable struct {
acquire func() ([]mount.Mount, func() error, error)
release func() error
refCount int
idmap *idtools.IdentityMapping
idmap idtools.IdentityMapping
}
func (m *mountable) Mount() ([]mount.Mount, func() error, error) {
@ -526,5 +531,10 @@ func (m *mountable) releaseMount() error {
}
func (m *mountable) IdentityMapping() *idtools.IdentityMapping {
return m.idmap
// Returning a non-nil but empty *IdentityMapping breaks BuildKit:
// https://github.com/moby/moby/pull/39444
if m.idmap.Empty() {
return nil
}
return &m.idmap
}

View file

@ -72,7 +72,7 @@ type Opt struct {
RegistryHosts docker.RegistryHosts
BuilderConfig config.BuilderConfig
Rootless bool
IdentityMapping *idtools.IdentityMapping
IdentityMapping idtools.IdentityMapping
DNSConfig config.DNSConfig
ApparmorProfile string
}
@ -90,10 +90,6 @@ type Builder struct {
func New(opt Opt) (*Builder, error) {
reqHandler := newReqBodyHandler(tracing.DefaultTransport)
if opt.IdentityMapping != nil && opt.IdentityMapping.Empty() {
opt.IdentityMapping = nil
}
c, err := newController(reqHandler, opt)
if err != nil {
return nil, err

View file

@ -25,7 +25,7 @@ import (
const networkName = "bridge"
func newExecutor(root, cgroupParent string, net libnetwork.NetworkController, dnsConfig *oci.DNSConfig, rootless bool, idmap *idtools.IdentityMapping, apparmorProfile string) (executor.Executor, error) {
func newExecutor(root, cgroupParent string, net libnetwork.NetworkController, dnsConfig *oci.DNSConfig, rootless bool, idmap idtools.IdentityMapping, apparmorProfile string) (executor.Executor, error) {
netRoot := filepath.Join(root, "net")
networkProviders := map[pb.NetMode]network.Provider{
pb.NetMode_UNSET: &bridgeProvider{NetworkController: net, Root: netRoot},
@ -44,13 +44,20 @@ func newExecutor(root, cgroupParent string, net libnetwork.NetworkController, dn
}
}
// Returning a non-nil but empty *IdentityMapping breaks BuildKit:
// https://github.com/moby/moby/pull/39444
pidmap := &idmap
if idmap.Empty() {
pidmap = nil
}
return runcexecutor.New(runcexecutor.Opt{
Root: filepath.Join(root, "executor"),
CommandCandidates: []string{"runc"},
DefaultCgroupParent: cgroupParent,
Rootless: rootless,
NoPivot: os.Getenv("DOCKER_RAMDISK") != "",
IdentityMapping: idmap,
IdentityMapping: pidmap,
DNS: dnsConfig,
ApparmorProfile: apparmorProfile,
}, networkProviders)

View file

@ -11,7 +11,7 @@ import (
"github.com/moby/buildkit/executor/oci"
)
func newExecutor(_, _ string, _ libnetwork.NetworkController, _ *oci.DNSConfig, _ bool, _ *idtools.IdentityMapping, _ string) (executor.Executor, error) {
func newExecutor(_, _ string, _ libnetwork.NetworkController, _ *oci.DNSConfig, _ bool, _ idtools.IdentityMapping, _ string) (executor.Executor, error) {
return &winExecutor{}, nil
}

View file

@ -46,13 +46,13 @@ const (
// BuildManager is shared across all Builder objects
type BuildManager struct {
idMapping *idtools.IdentityMapping
idMapping idtools.IdentityMapping
backend builder.Backend
pathCache pathCache // TODO: make this persistent
}
// NewBuildManager creates a BuildManager
func NewBuildManager(b builder.Backend, identityMapping *idtools.IdentityMapping) (*BuildManager, error) {
func NewBuildManager(b builder.Backend, identityMapping idtools.IdentityMapping) (*BuildManager, error) {
bm := &BuildManager{
backend: b,
pathCache: &syncmap.Map{},
@ -103,7 +103,7 @@ type builderOptions struct {
Backend builder.Backend
ProgressWriter backend.ProgressWriter
PathCache pathCache
IDMapping *idtools.IdentityMapping
IDMapping idtools.IdentityMapping
}
// Builder is a Dockerfile builder
@ -119,7 +119,7 @@ type Builder struct {
docker builder.Backend
clientCtx context.Context
idMapping *idtools.IdentityMapping
idMapping idtools.IdentityMapping
disableCommit bool
imageSources *imageSources
pathCache pathCache

View file

@ -33,7 +33,7 @@ type Archiver interface {
UntarPath(src, dst string) error
CopyWithTar(src, dst string) error
CopyFileWithTar(src, dst string) error
IdentityMapping() *idtools.IdentityMapping
IdentityMapping() idtools.IdentityMapping
}
// The builder will use the following interfaces if the container fs implements

View file

@ -11,7 +11,7 @@ import (
"github.com/pkg/errors"
)
func parseChownFlag(builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping *idtools.IdentityMapping) (idtools.Identity, 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 {

View file

@ -34,8 +34,8 @@ othergrp:x:6666:
Size: 65536,
},
}
remapped := idtools.NewIDMappingsFromMaps(idMaps, idMaps)
unmapped := &idtools.IdentityMapping{}
remapped := idtools.IdentityMapping{UIDMaps: idMaps, GIDMaps: idMaps}
unmapped := idtools.IdentityMapping{}
contextDir, cleanup := createTestTempDir(t, "", "builder-chown-parse-test")
defer cleanup()
@ -53,7 +53,7 @@ othergrp:x:6666:
builder *Builder
name string
chownStr string
idMapping *idtools.IdentityMapping
idMapping idtools.IdentityMapping
state *dispatchState
expected idtools.Identity
}{
@ -126,7 +126,7 @@ othergrp:x:6666:
builder *Builder
name string
chownStr string
idMapping *idtools.IdentityMapping
idMapping idtools.IdentityMapping
state *dispatchState
descr string
}{

View file

@ -14,7 +14,7 @@ import (
"golang.org/x/sys/windows"
)
func parseChownFlag(builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping *idtools.IdentityMapping) (idtools.Identity, error) {
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)
}

View file

@ -14,6 +14,7 @@ import (
"github.com/docker/docker/daemon/graphdriver/devmapper"
"github.com/docker/docker/pkg/devicemapper"
"github.com/docker/docker/pkg/idtools"
"github.com/sirupsen/logrus"
)
@ -76,7 +77,7 @@ func main() {
args := flag.Args()
home := path.Join(*root, "devicemapper")
devices, err := devmapper.NewDeviceSet(home, false, nil, nil, nil)
devices, err := devmapper.NewDeviceSet(home, false, nil, idtools.IdentityMapping{})
if err != nil {
fmt.Println("Can't initialize device mapper: ", err)
os.Exit(1)

View file

@ -9,7 +9,6 @@ import (
func (daemon *Daemon) defaultTarCopyOptions(noOverwriteDirNonDir bool) *archive.TarOptions {
return &archive.TarOptions{
NoOverwriteDirNonDir: noOverwriteDirNonDir,
UIDMaps: daemon.idMapping.UIDs(),
GIDMaps: daemon.idMapping.GIDs(),
IDMap: daemon.idMapping,
}
}

View file

@ -97,7 +97,7 @@ type Daemon struct {
sysInfoOnce sync.Once
sysInfo *sysinfo.SysInfo
shutdown bool
idMapping *idtools.IdentityMapping
idMapping idtools.IdentityMapping
graphDriver string // TODO: move graphDriver field to an InfoService
PluginStore *plugin.Store // TODO: remove
pluginManager *plugin.Manager
@ -1460,7 +1460,7 @@ func (daemon *Daemon) GetAttachmentStore() *network.AttachmentStore {
}
// IdentityMapping returns uid/gid mapping or a SID (in the case of Windows) for the builder
func (daemon *Daemon) IdentityMapping() *idtools.IdentityMapping {
func (daemon *Daemon) IdentityMapping() idtools.IdentityMapping {
return daemon.idMapping
}

View file

@ -1063,7 +1063,7 @@ func removeDefaultBridgeInterface() {
}
}
func setupInitLayer(idMapping *idtools.IdentityMapping) func(containerfs.ContainerFS) error {
func setupInitLayer(idMapping idtools.IdentityMapping) func(containerfs.ContainerFS) error {
return func(initPath containerfs.ContainerFS) error {
return initlayer.Setup(initPath, idMapping.RootPair())
}
@ -1162,9 +1162,9 @@ func parseRemappedRoot(usergrp string) (string, string, error) {
return username, groupname, nil
}
func setupRemappedRoot(config *config.Config) (*idtools.IdentityMapping, 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")
return idtools.IdentityMapping{}, fmt.Errorf("User namespaces are only supported on Linux")
}
// if the daemon was started with remapped root option, parse
@ -1172,25 +1172,25 @@ func setupRemappedRoot(config *config.Config) (*idtools.IdentityMapping, error)
if config.RemappedRoot != "" {
username, groupname, err := parseRemappedRoot(config.RemappedRoot)
if err != nil {
return nil, err
return idtools.IdentityMapping{}, err
}
if username == "root" {
// 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.IdentityMapping{}, nil
return idtools.IdentityMapping{}, nil
}
logrus.Infof("User namespaces: ID ranges will be mapped to subuid/subgid ranges of: %s", username)
// update remapped root setting now that we have resolved them to actual names
config.RemappedRoot = fmt.Sprintf("%s:%s", username, groupname)
mappings, err := idtools.NewIdentityMapping(username)
mappings, err := idtools.LoadIdentityMapping(username)
if err != nil {
return nil, errors.Wrap(err, "Can't create ID mappings")
return idtools.IdentityMapping{}, errors.Wrap(err, "Can't create ID mappings")
}
return mappings, nil
}
return &idtools.IdentityMapping{}, nil
return idtools.IdentityMapping{}, nil
}
func setupDaemonRoot(config *config.Config, rootDir string, remappedRoot idtools.Identity) error {

View file

@ -62,7 +62,7 @@ func (daemon *Daemon) parseSecurityOpt(container *container.Container, hostConfi
return nil
}
func setupInitLayer(idMapping *idtools.IdentityMapping) func(containerfs.ContainerFS) error {
func setupInitLayer(idMapping idtools.IdentityMapping) func(containerfs.ContainerFS) error {
return nil
}
@ -436,8 +436,8 @@ func recursiveUnmount(_ string) error {
return nil
}
func setupRemappedRoot(config *config.Config) (*idtools.IdentityMapping, error) {
return &idtools.IdentityMapping{}, nil
func setupRemappedRoot(config *config.Config) (idtools.IdentityMapping, error) {
return idtools.IdentityMapping{}, nil
}
func setupDaemonRoot(config *config.Config, rootDir string, rootIdentity idtools.Identity) error {

View file

@ -63,8 +63,7 @@ func (daemon *Daemon) containerExport(container *container.Container) (arch io.R
archv, err := archivePath(basefs, basefs.Path(), &archive.TarOptions{
Compression: archive.Uncompressed,
UIDMaps: daemon.idMapping.UIDs(),
GIDMaps: daemon.idMapping.GIDs(),
IDMap: daemon.idMapping,
}, basefs.Path())
if err != nil {
rwlayer.Unmount()

View file

@ -71,8 +71,7 @@ func init() {
// Driver contains information about the filesystem mounted.
type Driver struct {
root string
uidMaps []idtools.IDMap
gidMaps []idtools.IDMap
idMap idtools.IdentityMapping
ctr *graphdriver.RefCounter
pathCacheLock sync.Mutex
pathCache map[string]string
@ -83,7 +82,7 @@ type Driver struct {
// Init returns a new AUFS driver.
// An error is returned if AUFS is not supported.
func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
func Init(root string, options []string, idMap idtools.IdentityMapping) (graphdriver.Driver, error) {
// Try to load the aufs kernel module
if err := supportsAufs(); err != nil {
logger.Error(err)
@ -121,21 +120,16 @@ func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
a := &Driver{
root: root,
uidMaps: uidMaps,
gidMaps: gidMaps,
idMap: idMap,
pathCache: make(map[string]string),
ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicAufs)),
locker: locker.New(),
}
currentID := idtools.CurrentIdentity()
_, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
if err != nil {
return nil, err
}
dirID := idtools.Identity{
UID: currentID.UID,
GID: rootGID,
GID: a.idMap.RootPair().GID,
}
// Create the root aufs driver dir
@ -170,7 +164,7 @@ func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
}
}
a.naiveDiff = graphdriver.NewNaiveDiffDriver(a, uidMaps, gidMaps)
a.naiveDiff = graphdriver.NewNaiveDiffDriver(a, a.idMap)
return a, nil
}
@ -285,15 +279,11 @@ func (a *Driver) createDirsFor(id string) error {
"diff",
}
rootUID, rootGID, err := idtools.GetRootUIDGID(a.uidMaps, a.gidMaps)
if err != nil {
return err
}
// Directory permission is 0755.
// 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.Identity{UID: rootUID, GID: rootGID}); err != nil {
if err := idtools.MkdirAllAndChown(path.Join(a.rootPath(), p, id), 0755, a.idMap.RootPair()); err != nil {
return err
}
}
@ -439,8 +429,7 @@ func (a *Driver) Diff(id, parent string) (io.ReadCloser, error) {
return archive.TarWithOptions(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
Compression: archive.Uncompressed,
ExcludePatterns: []string{archive.WhiteoutMetaPrefix + "*", "!" + archive.WhiteoutOpaqueDir},
UIDMaps: a.uidMaps,
GIDMaps: a.gidMaps,
IDMap: a.idMap,
})
}
@ -461,8 +450,7 @@ func (a *Driver) DiffGetter(id string) (graphdriver.FileGetCloser, error) {
func (a *Driver) applyDiff(id string, diff io.Reader) error {
return chrootarchive.UntarUncompressed(diff, path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
UIDMaps: a.uidMaps,
GIDMaps: a.gidMaps,
IDMap: a.idMap,
})
}

View file

@ -15,6 +15,7 @@ import (
"github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/reexec"
"github.com/docker/docker/pkg/stringid"
"gotest.tools/v3/assert"
@ -31,7 +32,7 @@ func init() {
}
func testInit(dir string, t testing.TB) graphdriver.Driver {
d, err := Init(dir, nil, nil, nil)
d, err := Init(dir, nil, idtools.IdentityMapping{})
if err != nil {
if err == graphdriver.ErrNotSupported {
t.Skip(err)

View file

@ -50,7 +50,7 @@ type btrfsOptions struct {
// Init returns a new BTRFS driver.
// An error is returned if BTRFS is not supported.
func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
func Init(home string, options []string, idMap idtools.IdentityMapping) (graphdriver.Driver, error) {
// Perform feature detection on /var/lib/docker/btrfs if it's an existing directory.
// This covers situations where /var/lib/docker/btrfs is a mount, and on a different
@ -70,11 +70,10 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, graphdriver.ErrPrerequisites
}
remappedRoot := idtools.NewIDMappingsFromMaps(uidMaps, gidMaps)
currentID := idtools.CurrentIdentity()
dirID := idtools.Identity{
UID: currentID.UID,
GID: remappedRoot.RootPair().GID,
GID: idMap.RootPair().GID,
}
if err := idtools.MkdirAllAndChown(home, 0710, dirID); err != nil {
@ -97,8 +96,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
driver := &Driver{
home: home,
uidMaps: uidMaps,
gidMaps: gidMaps,
idMap: idMap,
options: opt,
}
@ -108,7 +106,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
}
}
return graphdriver.NewNaiveDiffDriver(driver, uidMaps, gidMaps), nil
return graphdriver.NewNaiveDiffDriver(driver, driver.idMap), nil
}
func parseOptions(opt []string) (btrfsOptions, bool, error) {
@ -139,8 +137,7 @@ func parseOptions(opt []string) (btrfsOptions, bool, error) {
type Driver struct {
// root of the file system
home string
uidMaps []idtools.IDMap
gidMaps []idtools.IDMap
idMap idtools.IdentityMapping
options btrfsOptions
quotaEnabled bool
once sync.Once
@ -490,15 +487,12 @@ func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts
func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
quotas := path.Join(d.home, "quotas")
subvolumes := path.Join(d.home, "subvolumes")
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
if err != nil {
return err
}
root := d.idMap.RootPair()
currentID := idtools.CurrentIdentity()
dirID := idtools.Identity{
UID: currentID.UID,
GID: rootGID,
GID: root.GID,
}
if err := idtools.MkdirAllAndChown(subvolumes, 0710, dirID); err != nil {
@ -546,8 +540,8 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
// if we have a remapped root (user namespaces enabled), change the created snapshot
// dir ownership to match
if rootUID != 0 || rootGID != 0 {
if err := os.Chown(path.Join(subvolumes, id), rootUID, rootGID); err != nil {
if root.UID != 0 || root.GID != 0 {
if err := root.Chown(path.Join(subvolumes, id)); err != nil {
return err
}
}

View file

@ -117,8 +117,7 @@ type DeviceSet struct {
BaseDeviceFilesystem string // save filesystem of base device
nrDeletedDevices uint // number of deleted devices
deletionWorkerTicker *time.Ticker
uidMaps []idtools.IDMap
gidMaps []idtools.IDMap
idMap idtools.IdentityMapping
minFreeSpacePercent uint32 // min free space percentage in thinpool
xfsNospaceRetries string // max retries when xfs receives ENOSPC
lvmSetupConfig directLVMConfig
@ -264,11 +263,7 @@ func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) {
dirname := devices.loopbackDir()
filename := path.Join(dirname, name)
uid, gid, err := idtools.GetRootUIDGID(devices.uidMaps, devices.gidMaps)
if err != nil {
return "", err
}
if err := idtools.MkdirAllAndChown(dirname, 0700, idtools.Identity{UID: uid, GID: gid}); err != nil {
if err := idtools.MkdirAllAndChown(dirname, 0700, devices.idMap.RootPair()); err != nil {
return "", err
}
@ -1694,11 +1689,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) (retErr error) {
// create the root dir of the devmapper driver ownership to match this
// daemon's remapped root uid/gid so containers can start properly
uid, gid, err := idtools.GetRootUIDGID(devices.uidMaps, devices.gidMaps)
if err != nil {
return err
}
if err := idtools.MkdirAndChown(devices.root, 0700, idtools.Identity{UID: uid, GID: gid}); err != nil {
if err := idtools.MkdirAndChown(devices.root, 0700, devices.idMap.RootPair()); err != nil {
return err
}
if err := os.MkdirAll(devices.metadataDir(), 0700); err != nil {
@ -2622,7 +2613,7 @@ func (devices *DeviceSet) exportDeviceMetadata(hash string) (*deviceMetadata, er
}
// NewDeviceSet creates the device set based on the options provided.
func NewDeviceSet(root string, doInit bool, options []string, uidMaps, gidMaps []idtools.IDMap) (*DeviceSet, error) {
func NewDeviceSet(root string, doInit bool, options []string, idMap idtools.IdentityMapping) (*DeviceSet, error) {
devicemapper.SetDevDir("/dev")
devices := &DeviceSet{
@ -2636,8 +2627,7 @@ func NewDeviceSet(root string, doInit bool, options []string, uidMaps, gidMaps [
thinpBlockSize: defaultThinpBlockSize,
deviceIDMap: make([]byte, deviceIDMapSz),
deletionWorkerTicker: time.NewTicker(time.Second * 30),
uidMaps: uidMaps,
gidMaps: gidMaps,
idMap: idMap,
minFreeSpacePercent: defaultMinFreeSpacePercent,
}

View file

@ -13,6 +13,7 @@ import (
"github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/daemon/graphdriver/graphtest"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/parsers/kernel"
"golang.org/x/sys/unix"
)
@ -115,7 +116,7 @@ func testChangeLoopBackSize(t *testing.T, delta, expectDataSize, expectMetaDataS
d, err := Init(driver.home, []string{
fmt.Sprintf("dm.loopdatasize=%d", defaultDataLoopbackSize+delta),
fmt.Sprintf("dm.loopmetadatasize=%d", defaultMetaDataLoopbackSize+delta),
}, nil, nil)
}, idtools.IdentityMapping{})
if err != nil {
t.Fatalf("error creating devicemapper driver: %v", err)
}

View file

@ -27,16 +27,14 @@ func init() {
// Driver contains the device set mounted and the home directory
type Driver struct {
*DeviceSet
home string
uidMaps []idtools.IDMap
gidMaps []idtools.IDMap
ctr *graphdriver.RefCounter
locker *locker.Locker
home string
ctr *graphdriver.RefCounter
locker *locker.Locker
}
// Init creates a driver with the given home and the set of options.
func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
deviceSet, err := NewDeviceSet(home, true, options, uidMaps, gidMaps)
func Init(home string, options []string, idMap idtools.IdentityMapping) (graphdriver.Driver, error) {
deviceSet, err := NewDeviceSet(home, true, options, idMap)
if err != nil {
return nil, err
}
@ -44,13 +42,11 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
d := &Driver{
DeviceSet: deviceSet,
home: home,
uidMaps: uidMaps,
gidMaps: gidMaps,
ctr: graphdriver.NewRefCounter(graphdriver.NewDefaultChecker()),
locker: locker.New(),
}
return graphdriver.NewNaiveDiffDriver(d, uidMaps, gidMaps), nil
return graphdriver.NewNaiveDiffDriver(d, d.idMap), nil
}
func (d *Driver) String() string {
@ -188,18 +184,14 @@ func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
return containerfs.NewLocalContainerFS(rootFs), nil
}
uid, gid, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
if err != nil {
d.ctr.Decrement(mp)
return nil, err
}
root := d.idMap.RootPair()
// Create the target directories if they don't exist
if err := idtools.MkdirAllAndChown(path.Join(d.home, "mnt"), 0755, idtools.Identity{UID: uid, GID: gid}); err != nil {
if err := idtools.MkdirAllAndChown(path.Join(d.home, "mnt"), 0755, root); err != nil {
d.ctr.Decrement(mp)
return nil, err
}
if err := idtools.MkdirAndChown(mp, 0755, idtools.Identity{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
if err := idtools.MkdirAndChown(mp, 0755, root); err != nil && !os.IsExist(err) {
d.ctr.Decrement(mp)
return nil, err
}
@ -210,7 +202,7 @@ func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
return nil, err
}
if err := idtools.MkdirAllAndChown(rootFs, 0755, idtools.Identity{UID: uid, GID: gid}); err != nil {
if err := idtools.MkdirAllAndChown(rootFs, 0755, root); err != nil {
d.ctr.Decrement(mp)
d.DeviceSet.UnmountDevice(id, mp)
return nil, err

View file

@ -37,7 +37,7 @@ type CreateOpts struct {
}
// InitFunc initializes the storage driver.
type InitFunc func(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (Driver, error)
type InitFunc func(root string, options []string, idMap idtools.IdentityMapping) (Driver, error)
// ProtoDriver defines the basic capabilities of a driver.
// This interface exists solely to be a minimum set of methods
@ -162,7 +162,7 @@ func Register(name string, initFunc InitFunc) error {
// GetDriver initializes and returns the registered driver
func GetDriver(name string, pg plugingetter.PluginGetter, config Options) (Driver, error) {
if initFunc, exists := drivers[name]; exists {
return initFunc(filepath.Join(config.Root, name), config.DriverOptions, config.UIDMaps, config.GIDMaps)
return initFunc(filepath.Join(config.Root, name), config.DriverOptions, config.IDMap)
}
pluginDriver, err := lookupPlugin(name, pg, config)
@ -174,9 +174,9 @@ func GetDriver(name string, pg plugingetter.PluginGetter, config Options) (Drive
}
// getBuiltinDriver initializes and returns the registered driver, but does not try to load from plugins
func getBuiltinDriver(name, home string, options []string, uidMaps, gidMaps []idtools.IDMap) (Driver, error) {
func getBuiltinDriver(name, home string, options []string, idMap idtools.IdentityMapping) (Driver, error) {
if initFunc, exists := drivers[name]; exists {
return initFunc(filepath.Join(home, name), options, uidMaps, gidMaps)
return initFunc(filepath.Join(home, name), options, idMap)
}
logrus.Errorf("Failed to built-in GetDriver graph %s %s", name, home)
return nil, ErrNotSupported
@ -186,8 +186,7 @@ func getBuiltinDriver(name, home string, options []string, uidMaps, gidMaps []id
type Options struct {
Root string
DriverOptions []string
UIDMaps []idtools.IDMap
GIDMaps []idtools.IDMap
IDMap idtools.IdentityMapping
ExperimentalEnabled bool
}
@ -211,7 +210,7 @@ func New(name string, pg plugingetter.PluginGetter, config Options) (Driver, err
if _, prior := driversMap[name]; prior {
// of the state found from prior drivers, check in order of our priority
// which we would prefer
driver, err := getBuiltinDriver(name, config.Root, config.DriverOptions, config.UIDMaps, config.GIDMaps)
driver, err := getBuiltinDriver(name, config.Root, config.DriverOptions, config.IDMap)
if err != nil {
// unlike below, we will return error here, because there is prior
// state, and now it is no longer supported/prereq/compatible, so
@ -240,7 +239,7 @@ func New(name string, pg plugingetter.PluginGetter, config Options) (Driver, err
// Check for priority drivers first
for _, name := range list {
driver, err := getBuiltinDriver(name, config.Root, config.DriverOptions, config.UIDMaps, config.GIDMaps)
driver, err := getBuiltinDriver(name, config.Root, config.DriverOptions, config.IDMap)
if err != nil {
if IsDriverNotSupported(err) {
continue
@ -258,7 +257,7 @@ func New(name string, pg plugingetter.PluginGetter, config Options) (Driver, err
// can be selected through configuration.
continue
}
driver, err := initFunc(filepath.Join(config.Root, name), config.DriverOptions, config.UIDMaps, config.GIDMaps)
driver, err := initFunc(filepath.Join(config.Root, name), config.DriverOptions, config.IDMap)
if err != nil {
if IsDriverNotSupported(err) {
continue

View file

@ -24,8 +24,7 @@ var (
// Notably, the AUFS driver doesn't need to be wrapped like this.
type NaiveDiffDriver struct {
ProtoDriver
uidMaps []idtools.IDMap
gidMaps []idtools.IDMap
idMap idtools.IdentityMapping
}
// NewNaiveDiffDriver returns a fully functional driver that wraps the
@ -35,10 +34,9 @@ type NaiveDiffDriver struct {
// Changes(id, parent string) ([]archive.Change, error)
// ApplyDiff(id, parent string, diff archive.Reader) (size int64, err error)
// DiffSize(id, parent string) (size int64, err error)
func NewNaiveDiffDriver(driver ProtoDriver, uidMaps, gidMaps []idtools.IDMap) Driver {
func NewNaiveDiffDriver(driver ProtoDriver, idMap idtools.IdentityMapping) Driver {
return &NaiveDiffDriver{ProtoDriver: driver,
uidMaps: uidMaps,
gidMaps: gidMaps}
idMap: idMap}
}
// Diff produces an archive of the changes between the specified
@ -84,7 +82,7 @@ func (gdw *NaiveDiffDriver) Diff(id, parent string) (arch io.ReadCloser, err err
return nil, err
}
archive, err := archive.ExportChanges(layerFs, changes, gdw.uidMaps, gdw.gidMaps)
archive, err := archive.ExportChanges(layerFs, changes, gdw.idMap)
if err != nil {
return nil, err
}
@ -142,8 +140,7 @@ func (gdw *NaiveDiffDriver) ApplyDiff(id, parent string, diff io.Reader) (size i
defer driver.Put(id)
layerFs := layerRootFs.Path()
options := &archive.TarOptions{UIDMaps: gdw.uidMaps,
GIDMaps: gdw.gidMaps}
options := &archive.TarOptions{IDMap: gdw.idMap}
start := time.Now().UTC()
logrus.WithField("id", id).Debug("Start untar layer")
if size, err = ApplyUncompressedLayer(layerFs, diff, options); err != nil {

View file

@ -60,8 +60,7 @@ const (
// mounts that are created using this driver.
type Driver struct {
home string
uidMaps []idtools.IDMap
gidMaps []idtools.IDMap
idMap idtools.IdentityMapping
ctr *graphdriver.RefCounter
naiveDiff graphdriver.DiffDriver
locker *locker.Locker
@ -78,7 +77,7 @@ func init() {
// Init returns the naive diff driver for fuse-overlayfs.
// If fuse-overlayfs is not supported on the host, the error
// graphdriver.ErrNotSupported is returned.
func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
func Init(home string, options []string, idMap idtools.IdentityMapping) (graphdriver.Driver, error) {
if _, err := exec.LookPath(binary); err != nil {
logger.Error(err)
return nil, graphdriver.ErrNotSupported
@ -87,11 +86,10 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, graphdriver.ErrNotSupported
}
remappedRoot := idtools.NewIDMappingsFromMaps(uidMaps, gidMaps)
currentID := idtools.CurrentIdentity()
dirID := idtools.Identity{
UID: currentID.UID,
GID: remappedRoot.RootPair().GID,
GID: idMap.RootPair().GID,
}
if err := idtools.MkdirAllAndChown(home, 0710, dirID); err != nil {
@ -102,14 +100,13 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
}
d := &Driver{
home: home,
uidMaps: uidMaps,
gidMaps: gidMaps,
ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicFUSE)),
locker: locker.New(),
home: home,
idMap: idMap,
ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicFUSE)),
locker: locker.New(),
}
d.naiveDiff = graphdriver.NewNaiveDiffDriver(d, uidMaps, gidMaps)
d.naiveDiff = graphdriver.NewNaiveDiffDriver(d, idMap)
return d, nil
}
@ -175,22 +172,12 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr
func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr error) {
dir := d.dir(id)
root := d.idMap.RootPair()
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
if err != nil {
if err := idtools.MkdirAllAndChown(path.Dir(dir), 0710, root); err != nil {
return err
}
root := idtools.Identity{UID: rootUID, GID: rootGID}
dirID := idtools.Identity{
UID: rootUID,
GID: rootGID,
}
if err := idtools.MkdirAllAndChown(path.Dir(dir), 0710, dirID); err != nil {
return err
}
if err := idtools.MkdirAndChown(dir, 0710, dirID); err != nil {
if err := idtools.MkdirAndChown(dir, 0710, root); err != nil {
return err
}
@ -224,7 +211,7 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr
return nil
}
if err := idtools.MkdirAndChown(path.Join(dir, workDirName), 0710, dirID); err != nil {
if err := idtools.MkdirAndChown(path.Join(dir, workDirName), 0710, root); err != nil {
return err
}
@ -377,11 +364,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
mountData := label.FormatMountLabel(opts, mountLabel)
mountTarget := mergedDir
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
if err != nil {
return nil, err
}
if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
if err := idtools.MkdirAndChown(mergedDir, 0700, d.idMap.RootPair()); err != nil {
return nil, err
}
@ -477,8 +460,7 @@ func (d *Driver) ApplyDiff(id string, parent string, diff io.Reader) (size int64
logger.Debugf("Applying tar in %s", applyDir)
// Overlay doesn't need the parent id to apply the diff
if err := untar(diff, applyDir, &archive.TarOptions{
UIDMaps: d.uidMaps,
GIDMaps: d.gidMaps,
IDMap: d.idMap,
// Use AUFS whiteout format: https://github.com/containers/storage/blob/39a8d5ed9843844eafb5d2ba6e6a7510e0126f40/drivers/overlay/overlay.go#L1084-L1089
WhiteoutFormat: archive.AUFSWhiteoutFormat,
InUserNS: userns.RunningInUserNS(),

View file

@ -50,9 +50,9 @@ type naiveDiffDriverWithApply struct {
}
// NaiveDiffDriverWithApply returns a NaiveDiff driver with custom ApplyDiff.
func NaiveDiffDriverWithApply(driver ApplyDiffProtoDriver, uidMaps, gidMaps []idtools.IDMap) graphdriver.Driver {
func NaiveDiffDriverWithApply(driver ApplyDiffProtoDriver, idMap idtools.IdentityMapping) graphdriver.Driver {
return &naiveDiffDriverWithApply{
Driver: graphdriver.NewNaiveDiffDriver(driver, uidMaps, gidMaps),
Driver: graphdriver.NewNaiveDiffDriver(driver, idMap),
applyDiff: driver,
}
}
@ -99,8 +99,7 @@ type overlayOptions struct{}
// Driver contains information about the home directory and the list of active mounts that are created using this driver.
type Driver struct {
home string
uidMaps []idtools.IDMap
gidMaps []idtools.IDMap
idMap idtools.IdentityMapping
ctr *graphdriver.RefCounter
supportsDType bool
locker *locker.Locker
@ -115,7 +114,7 @@ func init() {
// graphdriver.ErrNotSupported is returned.
// If an overlay filesystem is not supported over an existing filesystem then
// error graphdriver.ErrIncompatibleFS is returned.
func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
func Init(home string, options []string, idMap idtools.IdentityMapping) (graphdriver.Driver, error) {
_, err := parseOptions(options)
if err != nil {
return nil, err
@ -156,13 +155,9 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
}
currentID := idtools.CurrentIdentity()
_, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
if err != nil {
return nil, err
}
dirID := idtools.Identity{
UID: currentID.UID,
GID: rootGID,
GID: idMap.RootPair().GID,
}
// Create the driver home dir
@ -171,14 +166,13 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
}
d := &Driver{
home: home,
uidMaps: uidMaps,
gidMaps: gidMaps,
idMap: idMap,
ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicOverlay)),
supportsDType: supportsDType,
locker: locker.New(),
}
return NaiveDiffDriverWithApply(d, uidMaps, gidMaps), nil
return NaiveDiffDriverWithApply(d, d.idMap), nil
}
func parseOptions(options []string) (*overlayOptions, error) {
@ -262,17 +256,12 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr
}
dir := d.dir(id)
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
if err != nil {
return err
}
root := idtools.Identity{UID: rootUID, GID: rootGID}
root := d.idMap.RootPair()
currentID := idtools.CurrentIdentity()
dirID := idtools.Identity{
UID: currentID.UID,
GID: rootGID,
GID: root.GID,
}
if err := idtools.MkdirAndChown(dir, 0710, dirID); err != nil {
return err
@ -388,11 +377,8 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, err erro
if err != nil {
return nil, err
}
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
if err != nil {
return nil, err
}
if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
root := d.idMap.RootPair()
if err := idtools.MkdirAndChown(mergedDir, 0700, root); err != nil {
return nil, err
}
var (
@ -406,7 +392,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, err erro
}
// chown "workdir/work" to the remapped root UID/GID. Overlay fs inside a
// user namespace requires this to move a directory from lower to upper.
if err := os.Chown(path.Join(workDir, "work"), rootUID, rootGID); err != nil {
if err := root.Chown(path.Join(workDir, "work")); err != nil {
return nil, err
}
return containerfs.NewLocalContainerFS(mergedDir), nil
@ -483,7 +469,7 @@ func (d *Driver) ApplyDiff(id string, parent string, diff io.Reader) (size int64
return 0, err
}
options := &archive.TarOptions{UIDMaps: d.uidMaps, GIDMaps: d.gidMaps}
options := &archive.TarOptions{IDMap: d.idMap}
if size, err = graphdriver.ApplyUncompressedLayer(tmpRootDir, diff, options); err != nil {
return 0, err
}

View file

@ -93,8 +93,7 @@ type overlayOptions struct {
// mounts that are created using this driver.
type Driver struct {
home string
uidMaps []idtools.IDMap
gidMaps []idtools.IDMap
idMap idtools.IdentityMapping
ctr *graphdriver.RefCounter
quotaCtl *quota.Control
options overlayOptions
@ -124,7 +123,7 @@ func init() {
// graphdriver.ErrNotSupported is returned.
// If an overlay filesystem is not supported over an existing filesystem then
// the error graphdriver.ErrIncompatibleFS is returned.
func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
func Init(home string, options []string, idMap idtools.IdentityMapping) (graphdriver.Driver, error) {
opts, err := parseOptions(options)
if err != nil {
return nil, err
@ -164,15 +163,10 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
logger.Warn(overlayutils.ErrDTypeNotSupported("overlay2", backingFs))
}
_, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
if err != nil {
return nil, err
}
cur := idtools.CurrentIdentity()
dirID := idtools.Identity{
UID: cur.UID,
GID: rootGID,
GID: idMap.RootPair().GID,
}
if err := idtools.MkdirAllAndChown(home, 0710, dirID); err != nil {
return nil, err
@ -183,15 +177,14 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
d := &Driver{
home: home,
uidMaps: uidMaps,
gidMaps: gidMaps,
idMap: idMap,
ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicOverlay)),
supportsDType: supportsDType,
locker: locker.New(),
options: *opts,
}
d.naiveDiff = graphdriver.NewNaiveDiffDriver(d, uidMaps, gidMaps)
d.naiveDiff = graphdriver.NewNaiveDiffDriver(d, idMap)
if backingFs == "xfs" {
// Try to enable project quota support over xfs.
@ -351,14 +344,10 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr
func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr error) {
dir := d.dir(id)
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
if err != nil {
return err
}
root := idtools.Identity{UID: rootUID, GID: rootGID}
root := d.idMap.RootPair()
dirID := idtools.Identity{
UID: idtools.CurrentIdentity().UID,
GID: rootGID,
GID: root.GID,
}
if err := idtools.MkdirAllAndChown(path.Dir(dir), 0710, dirID); err != nil {
@ -580,11 +569,8 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
mount := unix.Mount
mountTarget := mergedDir
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
if err != nil {
return nil, err
}
if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
root := d.idMap.RootPair()
if err := idtools.MkdirAndChown(mergedDir, 0700, root); err != nil {
return nil, err
}
@ -618,7 +604,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
if !readonly {
// chown "workdir/work" to the remapped root UID/GID. Overlay fs inside a
// user namespace requires this to move a directory from lower to upper.
if err := os.Chown(path.Join(workDir, workDirName), rootUID, rootGID); err != nil {
if err := root.Chown(path.Join(workDir, workDirName)); err != nil {
return nil, err
}
}
@ -702,8 +688,7 @@ func (d *Driver) ApplyDiff(id string, parent string, diff io.Reader) (size int64
logger.Debugf("Applying tar in %s", applyDir)
// Overlay doesn't need the parent id to apply the diff
if err := untar(diff, applyDir, &archive.TarOptions{
UIDMaps: d.uidMaps,
GIDMaps: d.gidMaps,
IDMap: d.idMap,
WhiteoutFormat: archive.OverlayWhiteoutFormat,
}); err != nil {
return 0, err
@ -740,8 +725,7 @@ func (d *Driver) Diff(id, parent string) (io.ReadCloser, error) {
logger.Debugf("Tar with options on %s", diffPath)
return archive.TarWithOptions(diffPath, &archive.TarOptions{
Compression: archive.Uncompressed,
UIDMaps: d.uidMaps,
GIDMaps: d.gidMaps,
IDMap: d.idMap,
WhiteoutFormat: archive.OverlayWhiteoutFormat,
})
}

View file

@ -51,5 +51,5 @@ func newPluginDriver(name string, pl plugingetter.CompatPlugin, config Options)
return nil, errdefs.System(errors.Errorf("got unknown plugin type %T", pt))
}
return proxy, proxy.Init(filepath.Join(home, name), config.DriverOptions, config.UIDMaps, config.GIDMaps)
return proxy, proxy.Init(filepath.Join(home, name), config.DriverOptions, config.IDMap)
}

View file

@ -38,13 +38,12 @@ type graphDriverResponse struct {
}
type graphDriverInitRequest struct {
Home string
Opts []string `json:"Opts"`
UIDMaps []idtools.IDMap `json:"UIDMaps"`
GIDMaps []idtools.IDMap `json:"GIDMaps"`
Home string
Opts []string `json:"Opts"`
idtools.IdentityMapping
}
func (d *graphDriverProxy) Init(home string, opts []string, uidMaps, gidMaps []idtools.IDMap) error {
func (d *graphDriverProxy) Init(home string, opts []string, idMap idtools.IdentityMapping) error {
if !d.p.IsV1() {
if cp, ok := d.p.(plugingetter.CountedPlugin); ok {
// always acquire here, it will be cleaned up on daemon shutdown
@ -52,10 +51,9 @@ func (d *graphDriverProxy) Init(home string, opts []string, uidMaps, gidMaps []i
}
}
args := &graphDriverInitRequest{
Home: home,
Opts: opts,
UIDMaps: uidMaps,
GIDMaps: gidMaps,
Home: home,
Opts: opts,
IdentityMapping: idMap,
}
var ret graphDriverResponse
if err := d.client.Call("GraphDriver.Init", args, &ret); err != nil {

View file

@ -0,0 +1,43 @@
package graphdriver // import "github.com/docker/docker/daemon/graphdriver"
import (
"encoding/json"
"testing"
"github.com/docker/docker/pkg/idtools"
"gotest.tools/v3/assert"
)
func TestGraphDriverInitRequestIsCompatible(t *testing.T) {
// Graph driver plugins may unmarshal into this version of the init
// request struct. Verify that the serialization of
// graphDriverInitRequest is fully backwards compatible.
type graphDriverInitRequestV1 struct {
Home string
Opts []string `json:"Opts"`
UIDMaps []idtools.IDMap `json:"UIDMaps"`
GIDMaps []idtools.IDMap `json:"GIDMaps"`
}
args := graphDriverInitRequest{
Home: "homedir",
Opts: []string{"option1", "option2"},
IdentityMapping: idtools.IdentityMapping{
UIDMaps: []idtools.IDMap{{ContainerID: 123, HostID: 456, Size: 42}},
GIDMaps: []idtools.IDMap{{ContainerID: 789, HostID: 1011, Size: 16}},
},
}
v, err := json.Marshal(&args)
assert.NilError(t, err)
var got graphDriverInitRequestV1
assert.NilError(t, json.Unmarshal(v, &got))
want := graphDriverInitRequestV1{
Home: args.Home,
Opts: args.Opts,
UIDMaps: args.UIDMaps,
GIDMaps: args.GIDMaps,
}
assert.DeepEqual(t, got, want)
}

View file

@ -3,8 +3,11 @@
package vfs // import "github.com/docker/docker/daemon/graphdriver/vfs"
import "github.com/docker/docker/pkg/chrootarchive"
import (
"github.com/docker/docker/pkg/chrootarchive"
"github.com/docker/docker/pkg/idtools"
)
func dirCopy(srcDir, dstDir string) error {
return chrootarchive.NewArchiver(nil).CopyWithTar(srcDir, dstDir)
return chrootarchive.NewArchiver(idtools.IdentityMapping{}).CopyWithTar(srcDir, dstDir)
}

View file

@ -27,23 +27,19 @@ func init() {
// Init returns a new VFS driver.
// This sets the home directory for the driver and returns NaiveDiffDriver.
func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
func Init(home string, options []string, idMap idtools.IdentityMapping) (graphdriver.Driver, error) {
d := &Driver{
home: home,
idMapping: idtools.NewIDMappingsFromMaps(uidMaps, gidMaps),
idMapping: idMap,
}
if err := d.parseOptions(options); err != nil {
return nil, err
}
_, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
if err != nil {
return nil, err
}
dirID := idtools.Identity{
UID: idtools.CurrentIdentity().UID,
GID: rootGID,
GID: d.idMapping.RootPair().GID,
}
if err := idtools.MkdirAllAndChown(home, 0710, dirID); err != nil {
return nil, err
@ -55,7 +51,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, quota.ErrQuotaNotSupported
}
return graphdriver.NewNaiveDiffDriver(d, uidMaps, gidMaps), nil
return graphdriver.NewNaiveDiffDriver(d, d.idMapping), nil
}
// Driver holds information about the driver, home directory of the driver.
@ -65,7 +61,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
type Driver struct {
driverQuota
home string
idMapping *idtools.IdentityMapping
idMapping idtools.IdentityMapping
}
func (d *Driver) String() string {

View file

@ -97,7 +97,7 @@ type Driver struct {
}
// InitFilter returns a new Windows storage filter driver.
func InitFilter(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
func InitFilter(home string, options []string, _ idtools.IdentityMapping) (graphdriver.Driver, error) {
logrus.Debugf("WindowsGraphDriver InitFilter at %s", home)
fsType, err := getFileSystemType(string(home[0]))

View file

@ -47,7 +47,7 @@ func (*Logger) Log(cmd []string) {
// Init returns a new ZFS driver.
// It takes base mount path and an array of options which are represented as key value pairs.
// Each option is in the for key=value. 'zfs.fsname' is expected to be a valid key in the options.
func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
func Init(base string, opt []string, idMap idtools.IdentityMapping) (graphdriver.Driver, error) {
var err error
logger := logrus.WithField("storage-driver", "zfs")
@ -106,14 +106,9 @@ func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdri
return nil, fmt.Errorf("BUG: zfs get all -t filesystem -rHp '%s' should contain '%s'", options.fsName, options.fsName)
}
_, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
if err != nil {
return nil, err
}
dirID := idtools.Identity{
UID: idtools.CurrentIdentity().UID,
GID: rootGID,
GID: idMap.RootPair().GID,
}
if err := idtools.MkdirAllAndChown(base, 0710, dirID); err != nil {
return nil, fmt.Errorf("Failed to create '%s': %v", base, err)
@ -123,12 +118,11 @@ func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdri
dataset: rootDataset,
options: options,
filesystemsCache: filesystemsCache,
uidMaps: uidMaps,
gidMaps: gidMaps,
idMap: idMap,
ctr: graphdriver.NewRefCounter(graphdriver.NewDefaultChecker()),
locker: locker.New(),
}
return graphdriver.NewNaiveDiffDriver(d, uidMaps, gidMaps), nil
return graphdriver.NewNaiveDiffDriver(d, idMap), nil
}
func parseOptions(opt []string) (zfsOptions, error) {
@ -181,8 +175,7 @@ type Driver struct {
options zfsOptions
sync.Mutex // protects filesystem cache against concurrent access
filesystemsCache map[string]bool
uidMaps []idtools.IDMap
gidMaps []idtools.IDMap
idMap idtools.IdentityMapping
ctr *graphdriver.RefCounter
locker *locker.Locker
}
@ -395,12 +388,9 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
options := label.FormatMountLabel("", mountLabel)
logrus.WithField("storage-driver", "zfs").Debugf(`mount("%s", "%s", "%s")`, filesystem, mountpoint, options)
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
if err != nil {
return nil, err
}
root := d.idMap.RootPair()
// Create the target directories if they don't exist
if err := idtools.MkdirAllAndChown(mountpoint, 0755, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
if err := idtools.MkdirAllAndChown(mountpoint, 0755, root); err != nil {
return nil, err
}
@ -410,7 +400,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
// this could be our first mount after creation of the filesystem, and the root dir may still have root
// permissions instead of the remapped root uid:gid (if user namespaces are enabled):
if err := os.Chown(mountpoint, rootUID, rootGID); err != nil {
if err := root.Chown(mountpoint); err != nil {
return nil, fmt.Errorf("error modifying zfs mountpoint (%s) directory ownership: %v", mountpoint, err)
}

View file

@ -227,13 +227,13 @@ func WithNamespaces(daemon *Daemon, c *container.Container) coci.SpecOpts {
userNS := false
// user
if c.HostConfig.UsernsMode.IsPrivate() {
uidMap := daemon.idMapping.UIDs()
uidMap := daemon.idMapping.UIDMaps
if uidMap != nil {
userNS = true
ns := specs.LinuxNamespace{Type: "user"}
setNamespace(s, ns)
s.Linux.UIDMappings = specMapping(uidMap)
s.Linux.GIDMappings = specMapping(daemon.idMapping.GIDs())
s.Linux.GIDMappings = specMapping(daemon.idMapping.GIDMaps)
}
}
// network
@ -689,7 +689,7 @@ func WithMounts(daemon *Daemon, c *container.Container) coci.SpecOpts {
// 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.idMapping.UIDs(); uidMap != nil || c.HostConfig.Privileged {
if uidMap := daemon.idMapping.UIDMaps; uidMap != nil || c.HostConfig.Privileged {
for i, m := range s.Mounts {
if m.Type == "cgroup" {
clearReadOnly(&s.Mounts[i])

View file

@ -11,7 +11,6 @@ import (
"github.com/docker/docker/daemon/network"
"github.com/docker/docker/libnetwork"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/idtools"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/skip"
@ -31,7 +30,6 @@ func setupFakeDaemon(t *testing.T, c *container.Container) *Daemon {
d := &Daemon{
// some empty structs to avoid getting a panic
// caused by a null pointer dereference
idMapping: &idtools.IdentityMapping{},
configStore: &config.Config{},
linkIndex: newLinkIndex(),
netController: netController,

View file

@ -49,7 +49,7 @@ func TestRemoveImageGarbageCollector(t *testing.T) {
MetadataStorePathTemplate: filepath.Join(d.RootDir(), "image", "%s", "layerdb"),
GraphDriver: d.StorageDriver(),
GraphDriverOptions: nil,
IDMapping: &idtools.IdentityMapping{},
IDMapping: idtools.IdentityMapping{},
PluginGetter: nil,
ExperimentalEnabled: false,
})

View file

@ -19,6 +19,7 @@ import (
"github.com/docker/docker/integration/internal/container"
"github.com/docker/docker/integration/internal/requirement"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/plugins"
"github.com/docker/docker/testutil/daemon"
"gotest.tools/v3/assert"
@ -146,9 +147,9 @@ func setupPlugin(t *testing.T, ec map[string]*graphEventsCounter, ext string, mu
base, err := os.MkdirTemp("", name)
assert.NilError(t, err)
vfsProto, err := vfs.Init(base, []string{}, nil, nil)
vfsProto, err := vfs.Init(base, []string{}, idtools.IdentityMapping{})
assert.NilError(t, err, "error initializing graph driver")
driver := graphdriver.NewNaiveDiffDriver(vfsProto, nil, nil)
driver := graphdriver.NewNaiveDiffDriver(vfsProto, idtools.IdentityMapping{})
ec[ext] = &graphEventsCounter{}
mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {

View file

@ -49,7 +49,7 @@ type StoreOptions struct {
MetadataStorePathTemplate string
GraphDriver string
GraphDriverOptions []string
IDMapping *idtools.IdentityMapping
IDMapping idtools.IdentityMapping
PluginGetter plugingetter.PluginGetter
ExperimentalEnabled bool
}
@ -59,8 +59,7 @@ func NewStoreFromOptions(options StoreOptions) (Store, error) {
driver, err := graphdriver.New(options.GraphDriver, options.PluginGetter, graphdriver.Options{
Root: options.Root,
DriverOptions: options.GraphDriverOptions,
UIDMaps: options.IDMapping.UIDs(),
GIDMaps: options.IDMapping.GIDs(),
IDMap: options.IDMapping,
ExperimentalEnabled: options.ExperimentalEnabled,
})
if err != nil {

View file

@ -41,7 +41,7 @@ func newVFSGraphDriver(td string) (graphdriver.Driver, error) {
},
}
options := graphdriver.Options{Root: td, UIDMaps: uidMap, GIDMaps: gidMap}
options := graphdriver.Options{Root: td, IDMap: idtools.IdentityMapping{UIDMaps: uidMap, GIDMaps: gidMap}}
return graphdriver.GetDriver("vfs", nil, options)
}

View file

@ -40,8 +40,7 @@ type (
ExcludePatterns []string
Compression Compression
NoLchown bool
UIDMaps []idtools.IDMap
GIDMaps []idtools.IDMap
IDMap idtools.IdentityMapping
ChownOpts *idtools.Identity
IncludeSourceDir bool
// WhiteoutFormat is the expected on disk format for whiteout files.
@ -63,12 +62,12 @@ type (
// 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
IDMapping *idtools.IdentityMapping
IDMapping idtools.IdentityMapping
}
// NewDefaultArchiver returns a new Archiver without any IdentityMapping
func NewDefaultArchiver() *Archiver {
return &Archiver{Untar: Untar, IDMapping: &idtools.IdentityMapping{}}
return &Archiver{Untar: Untar}
}
// breakoutError is used to differentiate errors related to breaking out
@ -534,7 +533,7 @@ type tarAppender struct {
// for hardlink mapping
SeenFiles map[uint64]string
IdentityMapping *idtools.IdentityMapping
IdentityMapping idtools.IdentityMapping
ChownOpts *idtools.Identity
// For packing and unpacking whiteout files in the
@ -544,7 +543,7 @@ type tarAppender struct {
WhiteoutConverter tarWhiteoutConverter
}
func newTarAppender(idMapping *idtools.IdentityMapping, writer io.Writer, chownOpts *idtools.Identity) *tarAppender {
func newTarAppender(idMapping idtools.IdentityMapping, writer io.Writer, chownOpts *idtools.Identity) *tarAppender {
return &tarAppender{
SeenFiles: make(map[uint64]string),
TarWriter: tar.NewWriter(writer),
@ -860,7 +859,7 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
go func() {
ta := newTarAppender(
idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps),
options.IDMap,
compressWriter,
options.ChownOpts,
)
@ -1044,8 +1043,7 @@ func Unpack(decompressedArchive io.Reader, dest string, options *TarOptions) err
defer pools.BufioReader32KPool.Put(trBuf)
var dirs []*tar.Header
idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
rootIDs := idMapping.RootPair()
rootIDs := options.IDMap.RootPair()
whiteoutConverter, err := getWhiteoutConverter(options.WhiteoutFormat, options.InUserNS)
if err != nil {
return err
@ -1134,7 +1132,7 @@ loop:
}
trBuf.Reset(tr)
if err := remapIDs(idMapping, hdr); err != nil {
if err := remapIDs(options.IDMap, hdr); err != nil {
return err
}
@ -1221,8 +1219,7 @@ func (archiver *Archiver) TarUntar(src, dst string) error {
}
defer archive.Close()
options := &TarOptions{
UIDMaps: archiver.IDMapping.UIDs(),
GIDMaps: archiver.IDMapping.GIDs(),
IDMap: archiver.IDMapping,
}
return archiver.Untar(archive, dst, options)
}
@ -1235,8 +1232,7 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
}
defer archive.Close()
options := &TarOptions{
UIDMaps: archiver.IDMapping.UIDs(),
GIDMaps: archiver.IDMapping.GIDs(),
IDMap: archiver.IDMapping,
}
return archiver.Untar(archive, dst, options)
}
@ -1343,11 +1339,11 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
}
// IdentityMapping returns the IdentityMapping of the archiver.
func (archiver *Archiver) IdentityMapping() *idtools.IdentityMapping {
func (archiver *Archiver) IdentityMapping() idtools.IdentityMapping {
return archiver.IDMapping
}
func remapIDs(idMapping *idtools.IdentityMapping, hdr *tar.Header) error {
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

View file

@ -791,7 +791,7 @@ func TestTarWithOptionsChownOptsAlwaysOverridesIdPair(t *testing.T) {
expectedGID int
}{
{&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: 100001, GID: 100001}, IDMap: idtools.IdentityMapping{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},

View file

@ -394,10 +394,10 @@ func ChangesSize(newDir string, changes []Change) int64 {
}
// ExportChanges produces an Archive from the provided changes, relative to dir.
func ExportChanges(dir string, changes []Change, uidMaps, gidMaps []idtools.IDMap) (io.ReadCloser, error) {
func ExportChanges(dir string, changes []Change, idMap idtools.IdentityMapping) (io.ReadCloser, error) {
reader, writer := io.Pipe()
go func() {
ta := newTarAppender(idtools.NewIDMappingsFromMaps(uidMaps, gidMaps), writer, nil)
ta := newTarAppender(idMap, writer, nil)
// this buffer is needed for the duration of this piped stream
defer pools.BufioWriter32KPool.Put(ta.Buffer)

View file

@ -8,6 +8,8 @@ import (
"path"
"sort"
"testing"
"github.com/docker/docker/pkg/idtools"
)
func TestHardLinkOrder(t *testing.T) {
@ -60,7 +62,7 @@ func TestHardLinkOrder(t *testing.T) {
sort.Sort(changesByPath(changes))
// ExportChanges
ar, err := ExportChanges(dest, changes, nil, nil)
ar, err := ExportChanges(dest, changes, idtools.IdentityMapping{})
if err != nil {
t.Fatal(err)
}
@ -72,7 +74,7 @@ func TestHardLinkOrder(t *testing.T) {
// reverse sort
sort.Sort(sort.Reverse(changesByPath(changes)))
// ExportChanges
arRev, err := ExportChanges(dest, changes, nil, nil)
arRev, err := ExportChanges(dest, changes, idtools.IdentityMapping{})
if err != nil {
t.Fatal(err)
}

View file

@ -14,6 +14,7 @@ import (
"time"
"github.com/Microsoft/hcsshim/osversion"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/parsers/kernel"
"github.com/docker/docker/pkg/system"
"gotest.tools/v3/assert"
@ -444,7 +445,7 @@ func TestApplyLayer(t *testing.T) {
changes, err := ChangesDirs(dst, src)
assert.NilError(t, err)
layer, err := ExportChanges(dst, changes, nil, nil)
layer, err := ExportChanges(dst, changes, idtools.IdentityMapping{})
assert.NilError(t, err)
layerCopy, err := NewTempArchive(layer, "")

View file

@ -9,7 +9,6 @@ import (
"runtime"
"strings"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/pools"
"github.com/docker/docker/pkg/system"
"github.com/sirupsen/logrus"
@ -32,7 +31,6 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
if options.ExcludePatterns == nil {
options.ExcludePatterns = []string{}
}
idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
aufsTempdir := ""
aufsHardlinks := make(map[string]*tar.Header)
@ -192,7 +190,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
srcData = tmpFile
}
if err := remapIDs(idMapping, srcHdr); err != nil {
if err := remapIDs(options.IDMap, srcHdr); err != nil {
return 0, err
}

View file

@ -20,10 +20,7 @@ func init() {
}
// NewArchiver returns a new Archiver which uses chrootarchive.Untar
func NewArchiver(idMapping *idtools.IdentityMapping) *archive.Archiver {
if idMapping == nil {
idMapping = &idtools.IdentityMapping{}
}
func NewArchiver(idMapping idtools.IdentityMapping) *archive.Archiver {
return &archive.Archiver{
Untar: Untar,
IDMapping: idMapping,
@ -76,8 +73,7 @@ func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions
// If dest is inside a root then directory is created within chroot by extractor.
// This case is only currently used by cp.
if dest == root {
idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
rootIDs := idMapping.RootPair()
rootIDs := options.IDMap.RootPair()
dest = filepath.Clean(dest)
if _, err := os.Stat(dest); os.IsNotExist(err) {

View file

@ -13,6 +13,7 @@ import (
"time"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/reexec"
"github.com/docker/docker/pkg/system"
"gotest.tools/v3/skip"
@ -22,7 +23,7 @@ func init() {
reexec.Init()
}
var chrootArchiver = NewArchiver(nil)
var chrootArchiver = NewArchiver(idtools.IdentityMapping{})
func TarUntar(src, dst string) error {
return chrootArchiver.TarUntar(src, dst)

View file

@ -26,7 +26,7 @@ type Archiver struct {
DstDriver Driver
Tar TarFunc
Untar UntarFunc
IDMapping *idtools.IdentityMapping
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,7 @@ func (archiver *Archiver) TarUntar(src, dst string) error {
}
defer tarArchive.Close()
options := &archive.TarOptions{
UIDMaps: archiver.IDMapping.UIDs(),
GIDMaps: archiver.IDMapping.GIDs(),
IDMap: archiver.IDMapping,
}
return archiver.Untar(tarArchive, dst, options)
}
@ -53,8 +52,7 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
}
defer tarArchive.Close()
options := &archive.TarOptions{
UIDMaps: archiver.IDMapping.UIDs(),
GIDMaps: archiver.IDMapping.GIDs(),
IDMap: archiver.IDMapping,
}
return archiver.Untar(tarArchive, dst, options)
}
@ -181,11 +179,11 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (retErr error) {
}
// IdentityMapping returns the IdentityMapping of the archiver.
func (archiver *Archiver) IdentityMapping() *idtools.IdentityMapping {
func (archiver *Archiver) IdentityMapping() idtools.IdentityMapping {
return archiver.IDMapping
}
func remapIDs(idMapping *idtools.IdentityMapping, hdr *tar.Header) error {
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

View file

@ -108,70 +108,72 @@ type Identity struct {
SID string
}
// IdentityMapping contains a mappings of UIDs and GIDs
type IdentityMapping struct {
uids []IDMap
gids []IDMap
// Chown changes the numeric uid and gid of the named file to id.UID and id.GID.
func (id Identity) Chown(name string) error {
return os.Chown(name, id.UID, id.GID)
}
// NewIDMappingsFromMaps creates a new mapping from two slices
// Deprecated: this is a temporary shim while transitioning to IDMapping
func NewIDMappingsFromMaps(uids []IDMap, gids []IDMap) *IdentityMapping {
return &IdentityMapping{uids: uids, gids: gids}
// IdentityMapping contains a mappings of UIDs and GIDs.
// The zero value represents an empty mapping.
type IdentityMapping struct {
UIDMaps []IDMap `json:"UIDMaps"`
GIDMaps []IDMap `json:"GIDMaps"`
}
// 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 *IdentityMapping) RootPair() Identity {
uid, gid, _ := GetRootUIDGID(i.uids, i.gids)
func (i IdentityMapping) RootPair() Identity {
uid, gid, _ := GetRootUIDGID(i.UIDMaps, i.GIDMaps)
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 *IdentityMapping) ToHost(pair Identity) (Identity, error) {
func (i IdentityMapping) ToHost(pair Identity) (Identity, error) {
var err error
target := i.RootPair()
if pair.UID != target.UID {
target.UID, err = toHost(pair.UID, i.uids)
target.UID, err = toHost(pair.UID, i.UIDMaps)
if err != nil {
return target, err
}
}
if pair.GID != target.GID {
target.GID, err = toHost(pair.GID, i.gids)
target.GID, err = toHost(pair.GID, i.GIDMaps)
}
return target, err
}
// ToContainer returns the container UID and GID for the host uid and gid
func (i *IdentityMapping) ToContainer(pair Identity) (int, int, error) {
uid, err := toContainer(pair.UID, i.uids)
func (i IdentityMapping) ToContainer(pair Identity) (int, int, error) {
uid, err := toContainer(pair.UID, i.UIDMaps)
if err != nil {
return -1, -1, err
}
gid, err := toContainer(pair.GID, i.gids)
gid, err := toContainer(pair.GID, i.GIDMaps)
return uid, gid, err
}
// Empty returns true if there are no id mappings
func (i *IdentityMapping) Empty() bool {
return len(i.uids) == 0 && len(i.gids) == 0
func (i IdentityMapping) Empty() bool {
return len(i.UIDMaps) == 0 && len(i.GIDMaps) == 0
}
// UIDs return the UID mapping
// TODO: remove this once everything has been refactored to use pairs
func (i *IdentityMapping) UIDs() []IDMap {
return i.uids
// UIDs returns the mapping for UID.
//
// Deprecated: reference the UIDMaps field directly.
func (i IdentityMapping) UIDs() []IDMap {
return i.UIDMaps
}
// GIDs return the UID mapping
// TODO: remove this once everything has been refactored to use pairs
func (i *IdentityMapping) GIDs() []IDMap {
return i.gids
// GIDs returns the mapping for GID.
//
// Deprecated: reference the GIDMaps field directly.
func (i IdentityMapping) GIDs() []IDMap {
return i.GIDMaps
}
func createIDMap(subidRanges ranges) []IDMap {

View file

@ -240,24 +240,37 @@ func setPermissions(p string, mode os.FileMode, uid, gid int, stat *system.StatT
// NewIdentityMapping takes a requested username and
// using the data from /etc/sub{uid,gid} ranges, creates the
// proper uid and gid remapping ranges for that user/group pair
//
// Deprecated: Use LoadIdentityMapping.
func NewIdentityMapping(name string) (*IdentityMapping, error) {
m, err := LoadIdentityMapping(name)
if err != nil {
return nil, err
}
return &m, err
}
// LoadIdentityMapping takes a requested username and
// using the data from /etc/sub{uid,gid} ranges, creates the
// proper uid and gid remapping ranges for that user/group pair
func LoadIdentityMapping(name string) (IdentityMapping, error) {
usr, err := LookupUser(name)
if err != nil {
return nil, fmt.Errorf("Could not get user for username %s: %v", name, err)
return IdentityMapping{}, fmt.Errorf("Could not get user for username %s: %v", name, err)
}
subuidRanges, err := lookupSubUIDRanges(usr)
if err != nil {
return nil, err
return IdentityMapping{}, err
}
subgidRanges, err := lookupSubGIDRanges(usr)
if err != nil {
return nil, err
return IdentityMapping{}, err
}
return &IdentityMapping{
uids: subuidRanges,
gids: subgidRanges,
return IdentityMapping{
UIDMaps: subuidRanges,
GIDMaps: subgidRanges,
}, nil
}

View file

@ -321,10 +321,10 @@ func TestNewIDMappings(t *testing.T) {
tempUser, err := user.Lookup(tempUser)
assert.Check(t, err)
idMapping, err := NewIdentityMapping(tempUser.Username)
idMapping, err := LoadIdentityMapping(tempUser.Username)
assert.Check(t, err)
rootUID, rootGID, err := GetRootUIDGID(idMapping.UIDs(), idMapping.GIDs())
rootUID, rootGID, err := GetRootUIDGID(idMapping.UIDMaps, idMapping.GIDMaps)
assert.Check(t, err)
dirName, err := os.MkdirTemp("", "mkdirall")