Skip to content

Commit

Permalink
build, mount: allow realtive mountpoints wrt to work dir
Browse files Browse the repository at this point in the history
When working with `--mount=type=bind` and `--mount=type=cache` allow
`target` to accept relative paths w.r.t to the configured work dir.

Closes: #4309

Signed-off-by: Aditya R <arajan@redhat.com>
  • Loading branch information
flouthoc committed Dec 8, 2022
1 parent 3f21c7d commit 96c737f
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 19 deletions.
2 changes: 1 addition & 1 deletion cmd/buildah/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ func runCmd(c *cobra.Command, args []string, iopts runInputOptions) error {
if err != nil {
return fmt.Errorf("building system context: %w", err)
}
mounts, mountedImages, targetLocks, err := internalParse.GetVolumes(systemContext, store, iopts.volumes, iopts.mounts, iopts.contextDir)
mounts, mountedImages, targetLocks, err := internalParse.GetVolumes(systemContext, store, iopts.volumes, iopts.mounts, iopts.contextDir, iopts.workingDir)
if err != nil {
return err
}
Expand Down
31 changes: 20 additions & 11 deletions internal/parse/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"os"
"path"
"path/filepath"
"strconv"
"strings"
Expand Down Expand Up @@ -49,7 +50,7 @@ var (
// GetBindMount parses a single bind mount entry from the --mount flag.
// Returns specifiedMount and a string which contains name of image that we mounted otherwise its empty.
// Caller is expected to perform unmount of any mounted images
func GetBindMount(ctx *types.SystemContext, args []string, contextDir string, store storage.Store, imageMountLabel string, additionalMountPoints map[string]internal.StageMountDetails) (specs.Mount, string, error) {
func GetBindMount(ctx *types.SystemContext, args []string, contextDir string, store storage.Store, imageMountLabel string, additionalMountPoints map[string]internal.StageMountDetails, workDir string) (specs.Mount, string, error) {
newMount := specs.Mount{
Type: define.TypeBind,
}
Expand Down Expand Up @@ -101,10 +102,14 @@ func GetBindMount(ctx *types.SystemContext, args []string, contextDir string, st
if len(kv) == 1 {
return newMount, "", fmt.Errorf("%v: %w", kv[0], errBadOptionArg)
}
if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil {
targetPath := kv[1]
if !path.IsAbs(targetPath) {
targetPath = filepath.Join(workDir, targetPath)
}
if err := parse.ValidateVolumeCtrDir(targetPath); err != nil {
return newMount, "", err
}
newMount.Destination = kv[1]
newMount.Destination = targetPath
setDest = true
case "consistency":
// Option for OS X only, has no meaning on other platforms
Expand Down Expand Up @@ -189,7 +194,7 @@ func GetBindMount(ctx *types.SystemContext, args []string, contextDir string, st
// GetCacheMount parses a single cache mount entry from the --mount flag.
//
// If this function succeeds and returns a non-nil *lockfile.LockFile, the caller must unlock it (when??).
func GetCacheMount(args []string, store storage.Store, imageMountLabel string, additionalMountPoints map[string]internal.StageMountDetails) (specs.Mount, *lockfile.LockFile, error) {
func GetCacheMount(args []string, store storage.Store, imageMountLabel string, additionalMountPoints map[string]internal.StageMountDetails, workDir string) (specs.Mount, *lockfile.LockFile, error) {
var err error
var mode uint64
var buildahLockFilesDir string
Expand Down Expand Up @@ -257,10 +262,14 @@ func GetCacheMount(args []string, store storage.Store, imageMountLabel string, a
if len(kv) == 1 {
return newMount, nil, fmt.Errorf("%v: %w", kv[0], errBadOptionArg)
}
if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil {
targetPath := kv[1]
if !path.IsAbs(targetPath) {
targetPath = filepath.Join(workDir, targetPath)
}
if err := parse.ValidateVolumeCtrDir(targetPath); err != nil {
return newMount, nil, err
}
newMount.Destination = kv[1]
newMount.Destination = targetPath
setDest = true
case "src", "source":
if len(kv) == 1 {
Expand Down Expand Up @@ -506,8 +515,8 @@ func UnlockLockArray(locks []*lockfile.LockFile) {
// GetVolumes gets the volumes from --volume and --mount
//
// If this function succeeds, the caller must unlock the returned *lockfile.LockFile s if any (when??).
func GetVolumes(ctx *types.SystemContext, store storage.Store, volumes []string, mounts []string, contextDir string) ([]specs.Mount, []string, []*lockfile.LockFile, error) {
unifiedMounts, mountedImages, targetLocks, err := getMounts(ctx, store, mounts, contextDir)
func GetVolumes(ctx *types.SystemContext, store storage.Store, volumes []string, mounts []string, contextDir string, workDir string) ([]specs.Mount, []string, []*lockfile.LockFile, error) {
unifiedMounts, mountedImages, targetLocks, err := getMounts(ctx, store, mounts, contextDir, workDir)
if err != nil {
return nil, mountedImages, nil, err
}
Expand Down Expand Up @@ -542,7 +551,7 @@ func GetVolumes(ctx *types.SystemContext, store storage.Store, volumes []string,
// buildah run --mount type=tmpfs,target=/dev/shm ...
//
// If this function succeeds, the caller must unlock the returned *lockfile.LockFile s if any (when??).
func getMounts(ctx *types.SystemContext, store storage.Store, mounts []string, contextDir string) (map[string]specs.Mount, []string, []*lockfile.LockFile, error) {
func getMounts(ctx *types.SystemContext, store storage.Store, mounts []string, contextDir string, workDir string) (map[string]specs.Mount, []string, []*lockfile.LockFile, error) {
// If `type` is not set default to "bind"
mountType := define.TypeBind
finalMounts := make(map[string]specs.Mount)
Expand Down Expand Up @@ -576,7 +585,7 @@ func getMounts(ctx *types.SystemContext, store storage.Store, mounts []string, c
}
switch mountType {
case define.TypeBind:
mount, image, err := GetBindMount(ctx, tokens, contextDir, store, "", nil)
mount, image, err := GetBindMount(ctx, tokens, contextDir, store, "", nil, workDir)
if err != nil {
return nil, mountedImages, nil, err
}
Expand All @@ -586,7 +595,7 @@ func getMounts(ctx *types.SystemContext, store storage.Store, mounts []string, c
finalMounts[mount.Destination] = mount
mountedImages = append(mountedImages, image)
case TypeCache:
mount, tl, err := GetCacheMount(tokens, store, "", nil)
mount, tl, err := GetCacheMount(tokens, store, "", nil, workDir)
if err != nil {
return nil, mountedImages, nil, err
}
Expand Down
2 changes: 2 additions & 0 deletions run.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ type runMountArtifacts struct {

// RunMountInfo are the available run mounts for this run
type runMountInfo struct {
// WorkDir is the current working directory inside the container.
WorkDir string
// ContextDir is the root directory for the source location for bind mounts.
ContextDir string
// Secrets are the available secrets to use in a RUN
Expand Down
8 changes: 4 additions & 4 deletions run_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -1511,7 +1511,7 @@ func (b *Builder) runSetupRunMounts(mounts []string, sources runMountInfo, idMap
sshCount++
}
case define.TypeBind:
mount, image, err := b.getBindMount(tokens, sources.SystemContext, sources.ContextDir, sources.StageMountPoints, idMaps)
mount, image, err := b.getBindMount(tokens, sources.SystemContext, sources.ContextDir, sources.StageMountPoints, idMaps, sources.WorkDir)
if err != nil {
return nil, nil, err
}
Expand All @@ -1529,7 +1529,7 @@ func (b *Builder) runSetupRunMounts(mounts []string, sources runMountInfo, idMap
finalMounts = append(finalMounts, *mount)
mountTargets = append(mountTargets, mount.Destination)
case "cache":
mount, tl, err := b.getCacheMount(tokens, sources.StageMountPoints, idMaps)
mount, tl, err := b.getCacheMount(tokens, sources.StageMountPoints, idMaps, sources.WorkDir)
if err != nil {
return nil, nil, err
}
Expand All @@ -1554,12 +1554,12 @@ func (b *Builder) runSetupRunMounts(mounts []string, sources runMountInfo, idMap
return finalMounts, artifacts, nil
}

func (b *Builder) getBindMount(tokens []string, context *imageTypes.SystemContext, contextDir string, stageMountPoints map[string]internal.StageMountDetails, idMaps IDMaps) (*spec.Mount, string, error) {
func (b *Builder) getBindMount(tokens []string, context *imageTypes.SystemContext, contextDir string, stageMountPoints map[string]internal.StageMountDetails, idMaps IDMaps, workDir string) (*spec.Mount, string, error) {
if contextDir == "" {
return nil, "", errors.New("Context Directory for current run invocation is not configured")
}
var optionMounts []specs.Mount
mount, image, err := internalParse.GetBindMount(context, tokens, contextDir, b.store, b.MountLabel, stageMountPoints)
mount, image, err := internalParse.GetBindMount(context, tokens, contextDir, b.store, b.MountLabel, stageMountPoints, workDir)
if err != nil {
return nil, image, err
}
Expand Down
2 changes: 1 addition & 1 deletion run_freebsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ func setupSpecialMountSpecChanges(spec *spec.Spec, shmSize string) ([]specs.Moun
}

// If this function succeeds and returns a non-nil *lockfile.LockFile, the caller must unlock it (when??).
func (b *Builder) getCacheMount(tokens []string, stageMountPoints map[string]internal.StageMountDetails, idMaps IDMaps) (*spec.Mount, *lockfile.LockFile, error) {
func (b *Builder) getCacheMount(tokens []string, stageMountPoints map[string]internal.StageMountDetails, idMaps IDMaps, workDir string) (*spec.Mount, *lockfile.LockFile, error) {
return nil, nil, errors.New("cache mounts not supported on freebsd")
}

Expand Down
7 changes: 5 additions & 2 deletions run_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,10 @@ func (b *Builder) Run(command []string, options RunOptions) error {
return err
}

workDir := b.WorkDir()
if options.WorkingDir != "" {
g.SetProcessCwd(options.WorkingDir)
workDir = options.WorkingDir
} else if b.WorkDir() != "" {
g.SetProcessCwd(b.WorkDir())
}
Expand Down Expand Up @@ -321,6 +323,7 @@ rootless=%d
}

runMountInfo := runMountInfo{
WorkDir: workDir,
ContextDir: options.ContextDir,
Secrets: options.Secrets,
SSHSources: options.SSHSources,
Expand Down Expand Up @@ -1200,9 +1203,9 @@ func checkIdsGreaterThan5(ids []spec.LinuxIDMapping) bool {
}

// If this function succeeds and returns a non-nil *lockfile.LockFile, the caller must unlock it (when??).
func (b *Builder) getCacheMount(tokens []string, stageMountPoints map[string]internal.StageMountDetails, idMaps IDMaps) (*spec.Mount, *lockfile.LockFile, error) {
func (b *Builder) getCacheMount(tokens []string, stageMountPoints map[string]internal.StageMountDetails, idMaps IDMaps, workDir string) (*spec.Mount, *lockfile.LockFile, error) {
var optionMounts []specs.Mount
mount, targetLock, err := internalParse.GetCacheMount(tokens, b.store, b.MountLabel, stageMountPoints)
mount, targetLock, err := internalParse.GetCacheMount(tokens, b.store, b.MountLabel, stageMountPoints, workDir)
if err != nil {
return nil, nil, err
}
Expand Down
24 changes: 24 additions & 0 deletions tests/bud.bats
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,30 @@ _EOF
expect_output --substring "Groups: 1000"
}

@test "build-test --mount=type=cache test relative to workdir mount" {
local contextdir=${TEST_SCRATCH_DIR}/bud/platform
mkdir -p $contextdir
## write-cache
cat > $contextdir/Dockerfile << _EOF
FROM alpine
RUN mkdir test
WORKDIR test
RUN --mount=type=cache,id=YfHI60aApFM-target,target=target echo world > /test/target/hello
_EOF

run_buildah build $WITH_POLICY_JSON -t source -f $contextdir/Dockerfile

cat > $contextdir/Dockerfile << _EOF
FROM alpine
RUN mkdir test
WORKDIR test
RUN --mount=type=cache,id=YfHI60aApFM-target,target=target cat /test/target/hello
_EOF

run_buildah build $WITH_POLICY_JSON -t source -f $contextdir/Dockerfile
expect_output --substring "world"
}

@test "build-test skipping unwanted stages with --skip-unused-stages=false and --skip-unused-stages=true" {
local contextdir=${TEST_SCRATCH_DIR}/bud/platform
mkdir -p $contextdir
Expand Down

0 comments on commit 96c737f

Please sign in to comment.