Allow cache mounts to be stages or additional build contexts

Allow cache mounts (RUN --mount=type=cache) to refer to other stages or
additional build contexts.

Update the build-check-cve-2024-9675 integration test to use different
directories for its main build context and the additional build context
that it uses for its final run.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
This commit is contained in:
Nalin Dahyabhai 2025-01-06 13:47:31 -05:00
parent 2973d7ba54
commit 286ece65ba
4 changed files with 31 additions and 15 deletions

View File

@ -597,7 +597,12 @@ func (s *StageExecutor) runStageMountPoints(mountList []string) (map[string]inte
// to `mountPoint` replaced from additional
// build-context. Reason: Parser will use this
// `from` to refer from stageMountPoints map later.
stageMountPoints[from] = internal.StageMountDetails{IsStage: false, DidExecute: true, MountPoint: mountPoint}
stageMountPoints[from] = internal.StageMountDetails{
IsAdditionalBuildContext: true,
IsImage: true,
DidExecute: true,
MountPoint: mountPoint,
}
break
} else {
// Most likely this points to path on filesystem
@ -629,7 +634,11 @@ func (s *StageExecutor) runStageMountPoints(mountList []string) (map[string]inte
mountPoint = additionalBuildContext.DownloadedCache
}
}
stageMountPoints[from] = internal.StageMountDetails{IsStage: true, DidExecute: true, MountPoint: mountPoint}
stageMountPoints[from] = internal.StageMountDetails{
IsAdditionalBuildContext: true,
DidExecute: true,
MountPoint: mountPoint,
}
break
}
}
@ -640,14 +649,22 @@ func (s *StageExecutor) runStageMountPoints(mountList []string) (map[string]inte
return nil, err
}
if otherStage, ok := s.executor.stages[from]; ok && otherStage.index < s.index {
stageMountPoints[from] = internal.StageMountDetails{IsStage: true, DidExecute: otherStage.didExecute, MountPoint: otherStage.mountPoint}
stageMountPoints[from] = internal.StageMountDetails{
IsStage: true,
DidExecute: otherStage.didExecute,
MountPoint: otherStage.mountPoint,
}
break
} else {
mountPoint, err := s.getImageRootfs(s.ctx, from)
if err != nil {
return nil, fmt.Errorf("%s from=%s: no stage or image found with that name", flag, from)
}
stageMountPoints[from] = internal.StageMountDetails{IsStage: false, DidExecute: true, MountPoint: mountPoint}
stageMountPoints[from] = internal.StageMountDetails{
IsImage: true,
DidExecute: true,
MountPoint: mountPoint,
}
break
}
default:

View File

@ -12,7 +12,9 @@ const (
// StageExecutor has ability to mount stages/images in current context and
// automatically clean them up.
type StageMountDetails struct {
DidExecute bool // tells if the stage which is being mounted was freshly executed or was part of older cache
IsStage bool // tells if mountpoint returned from stage executor is stage or image
MountPoint string // mountpoint of stage/image
DidExecute bool // true if this is a freshly-executed stage, or an image, possibly from a non-local cache
IsStage bool // true if the mountpoint is a stage's rootfs
IsImage bool // true if the mountpoint is an image's rootfs
IsAdditionalBuildContext bool // true if the mountpoint is an additional build context
MountPoint string // mountpoint of the stage or image's root directory or path of the additional build context
}

View File

@ -196,7 +196,7 @@ func GetBindMount(ctx *types.SystemContext, args []string, contextDir string, st
// buildkit parity: support absolute path for sources from current build context
if contextDir != "" {
// path should be /contextDir/specified path
evaluated, err := copier.Eval(contextDir, newMount.Source, copier.EvalOptions{})
evaluated, err := copier.Eval(contextDir, string(filepath.Separator)+newMount.Source, copier.EvalOptions{})
if err != nil {
return newMount, "", err
}
@ -358,12 +358,10 @@ func GetCacheMount(args []string, store storage.Store, imageMountLabel string, a
}
if fromStage != "" {
// do not create cache on host
// instead use read-only mounted stage as cache
mountPoint := ""
if additionalMountPoints != nil {
if val, ok := additionalMountPoints[fromStage]; ok {
if val.IsStage {
if !val.IsImage {
mountPoint = val.MountPoint
}
}
@ -371,7 +369,7 @@ func GetCacheMount(args []string, store storage.Store, imageMountLabel string, a
// Cache does not supports using image so if not stage found
// return with error
if mountPoint == "" {
return newMount, nil, fmt.Errorf("no stage found with name %s", fromStage)
return newMount, nil, fmt.Errorf("no stage or additional build context found with name %s", fromStage)
}
// path should be /contextDir/specified path
evaluated, err := copier.Eval(mountPoint, string(filepath.Separator)+newMount.Source, copier.EvalOptions{})

View File

@ -6282,9 +6282,8 @@ _EOF
run_buildah build -t buildkitbase $WITH_POLICY_JSON -f $contextdir/Dockerfilebuildkitbase $contextdir/
# try reading something from persistent cache in a different build
run_buildah 125 build -t testbud $WITH_POLICY_JSON -f $contextdir/Dockerfilecachefromimage
expect_output --substring "no stage found with name buildkitbase"
run_buildah rmi -f buildkitbase
TMPDIR=${TEST_SCRATCH_DIR} run_buildah 125 build -t testbud $WITH_POLICY_JSON -f $contextdir/Dockerfilecachefromimage
expect_output --substring "no stage or additional build context found with name buildkitbase"
}
@test "bud-with-mount-cache-multiple-from-like-buildkit" {