Add MountTempFromSource and RemoveTemp interfaces

These interfaces can be used to setup a graphdriver mountpoint
of the source directory for use within a container.
The RemoveTemp interface umounts the mountpoint and then removes
all of the modified data in the graphdriver for this source directory.

The primary use case of these interfaces is for container engines that
want to mount a directory from the host system into the container. The
source dirctory then can be modified without actually changing the
directory on the host.

Containers will use these interfaces for sharing packaing cache directories
like /var/cache/dnf, to help speed up container builds.

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
Daniel J Walsh 2019-04-29 14:46:40 -04:00
parent e90620ceae
commit e9695564db
No known key found for this signature in database
GPG Key ID: A2DF901DABE2C028
9 changed files with 172 additions and 0 deletions

View File

@ -165,6 +165,24 @@ func setContainerBigData(flags *mflag.FlagSet, action string, m storage.Store, a
return 0
}
func MountTempContainerSource(flags *mflag.FlagSet, action string, m storage.Store, args []string) int {
mountpoint, err := m.MountTempFromSource(args[0], args[1])
if err != nil {
fmt.Fprintf(os.Stderr, "%+v\n", err)
return 1
}
fmt.Fprintf(os.Stdout, "%s\n", mountpoint)
return 0
}
func RemoveTempContainerSource(flags *mflag.FlagSet, action string, m storage.Store, args []string) int {
if err := m.RemoveTemp(args[0]); err != nil {
fmt.Fprintf(os.Stderr, "%+v\n", err)
return 1
}
return 0
}
func getContainerDir(flags *mflag.FlagSet, action string, m storage.Store, args []string) int {
path, err := m.ContainerDirectory(args[0])
if err != nil {
@ -305,5 +323,19 @@ func init() {
addFlags: func(flags *mflag.FlagSet, cmd *command) {
flags.BoolVar(&jsonOutput, []string{"-json", "j"}, jsonOutput, "Prefer JSON output")
},
},
command{
names: []string{"mount-temp"},
optionsHelp: "[options [...]] containerNameOrID srcdir",
usage: "Mount srcdir for use by the container",
action: MountTempContainerSource,
minArgs: 2,
},
command{
names: []string{"remove-temp"},
optionsHelp: "[options [...]] mountdir",
usage: "Remove mount from use by the container",
action: RemoveTempContainerSource,
minArgs: 1,
})
}

View File

@ -742,3 +742,14 @@ func (a *Driver) UpdateLayerIDMap(id string, toContainer, toHost *idtools.IDMapp
func (a *Driver) SupportsShifting() bool {
return false
}
// MountTempFromSource mounts a source directory from the host using
// graphdriver and returns the mountpoint
func (a *Driver) MountTempFromSource(sourcedir, source, mountLabel string) (string, error) {
return "", fmt.Errorf("aufs driver does not support mount temp options")
}
// RemoveTemp removes temporary mountpoint from host using graphdriver
func (a *Driver) RemoveTemp(mountpoint string) error {
return fmt.Errorf("aufs driver does not support mount temp options")
}

View File

@ -685,3 +685,14 @@ func (d *Driver) Exists(id string) bool {
func (d *Driver) AdditionalImageStores() []string {
return nil
}
// MountTempFromSource mounts a source directory from the host using
// graphdriver and returns the mountpoint
func (d *Driver) MountTempFromSource(sourcedir, source, mountLabel string) (string, error) {
return "", fmt.Errorf("btrfs driver does not support mount temp options")
}
// RemoveTemp removes temporary mountpoint from host using graphdriver
func (d *Driver) RemoveTemp(source string) error {
return fmt.Errorf("btrfs driver does not support mount temp options")
}

View File

@ -242,3 +242,14 @@ func (d *Driver) Exists(id string) bool {
func (d *Driver) AdditionalImageStores() []string {
return nil
}
// MountTempFromSource mounts a source directory from the host using
// graphdriver and returns the mountpoint
func (d *Driver) MountTempFromSource(sourcedir, source, mountLabel string) (string, error) {
return "", fmt.Errorf("devmapper driver does not support mount temp options")
}
// RemoveTemp removes temporary mountpoint from host using graphdriver
func (d *Driver) RemoveTemp(mountpoint string) error {
return fmt.Errorf("devmapper driver does not support mount temp options")
}

View File

@ -100,6 +100,13 @@ type ProtoDriver interface {
Cleanup() error
// AdditionalImageStores returns additional image stores supported by the driver
AdditionalImageStores() []string
// MountTempFromSource mounts a source directory from the host using
// graphdriver and returns the mountpoint
MountTempFromSource(sourcedir, source, mountLabel string) (string, error)
// RemoveTemp removes temporary mountpoint from host using graphdriver
RemoveTemp(mountpoint string) error
}
// DiffDriver is the interface to use to implement graph diffs

View File

@ -1109,6 +1109,41 @@ func (d *Driver) SupportsShifting() bool {
return d.options.mountProgram != ""
}
// MountTempFromSource mounts a source directory from the host using
// graphdriver and returns the mountpoint
func (d *Driver) MountTempFromSource(sourceDir, source, mountLabel string) (string, error) {
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
if err != nil {
return "", err
}
upperDir := filepath.Join(sourceDir, "upper")
workDir := filepath.Join(sourceDir, "work")
mergeDir := filepath.Join(sourceDir, "merge")
if err := idtools.MkdirAllAs(upperDir, 0700, rootUID, rootGID); err != nil {
return "", errors.Wrapf(err, "failed to create the overlay %s directory", upperDir)
}
if err := idtools.MkdirAllAs(workDir, 0700, rootUID, rootGID); err != nil {
return "", errors.Wrapf(err, "failed to create the overlay %s directory", workDir)
}
if err := idtools.MkdirAllAs(mergeDir, 0700, rootUID, rootGID); err != nil {
return "", errors.Wrapf(err, "failed to create the overlay %s directory", mergeDir)
}
opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s,private", source, upperDir, workDir)
mountData := label.FormatMountLabel(opts, mountLabel)
if err := mount.Mount("none", mergeDir, "overlay", mountData); err != nil {
return "", errors.Wrapf(err, "failed to mount overlay %s directory", mergeDir)
}
return mergeDir, nil
}
// RemoveTemp removes temporary mountpoint from host using graphdriver
func (d *Driver) RemoveTemp(mountpoint string) error {
mount.Unmount(mountpoint) //Attempt to umount source
return os.RemoveAll(path.Dir(mountpoint))
}
// dumbJoin is more or less a dumber version of filepath.Join, but one which
// won't Clean() the path, allowing us to append ".." as a component and trust
// pathname resolution to do some non-obvious work.

View File

@ -219,3 +219,14 @@ func (d *Driver) AdditionalImageStores() []string {
}
return nil
}
// MountTempFromSource mounts a source directory from the host using
// graphdriver and returns the mountpoint
func (d *Driver) MountTempFromSource(id, source, mountLabel string) (string, error) {
return "", fmt.Errorf("vfs driver does not support mount temp options")
}
// RemoveTemp removes temporary mountpoint from host using graphdriver
func (d *Driver) RemoveTemp(mountpoint string) error {
return fmt.Errorf("vfs driver does not support mount temp options")
}

View File

@ -447,3 +447,14 @@ func (d *Driver) Exists(id string) bool {
func (d *Driver) AdditionalImageStores() []string {
return nil
}
// MountTempFromSource mounts a source directory from the host using
// graphdriver and returns the mountpoint
func (d *Driver) MountTempFromSource(sourcedir, source, mountLabel string) (string, error) {
return "", fmt.Errorf("zfs driver does not support mount temp options")
}
// RemoveTemp removes temporary mountpoint from host using graphdriver
func (d *Driver) RemoveTemp(mountpoint string) error {
return fmt.Errorf("zfs driver does not support mount temp options")
}

View File

@ -446,6 +446,13 @@ type Store interface {
// GID maps (if any are defined) don't contain corresponding IDs.
ContainerParentOwners(id string) ([]int, []int, error)
// MountTempFromSource mounts a source directory from the host using
// graphdriver and returns the mountpoint
MountTempFromSource(id, source string) (string, error)
// RemoveTemp removes temporary mountpoint from host using graphdriver
RemoveTemp(mountpoint string) error
// Lookup returns the ID of a layer, image, or container with the specified
// name or ID.
Lookup(name string) (string, error)
@ -1455,6 +1462,42 @@ func (s *store) ImageBigDataSize(id, key string) (int64, error) {
return -1, ErrSizeUnknown
}
func (s *store) MountTempFromSource(id, source string) (string, error) {
rcstore, err := s.ContainerStore()
if err != nil {
return "", err
}
rcstore.RLock()
defer rcstore.Unlock()
container, err := rcstore.Get(id)
if err != nil {
return "", err
}
driver, err := s.GraphDriver()
if err != nil {
return "", err
}
middleDir := s.graphDriverName + "-containers"
sourcedir := filepath.Join(s.GraphRoot(), middleDir, id, strings.Replace(source, "/", "_", -1))
return driver.MountTempFromSource(sourcedir, source, container.MountLabel())
}
func (s *store) RemoveTemp(source string) error {
rcstore, err := s.ContainerStore()
if err != nil {
return err
}
rcstore.RLock()
defer rcstore.Unlock()
driver, err := s.GraphDriver()
if err != nil {
return err
}
return driver.RemoveTemp(source)
}
func (s *store) ImageBigDataDigest(id, key string) (digest.Digest, error) {
ristore, err := s.ImageStore()
if err != nil {