Commit: don't depend on MountImage(), because .imagestore

Fall back to creating a new builder with it if MountImage() fails on the
base image, because when the store is configured with its "imagestore"
option, that can happen.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
This commit is contained in:
Nalin Dahyabhai 2025-08-13 20:40:16 -04:00
parent 0b0272eccf
commit 1f7f1d285d
2 changed files with 46 additions and 8 deletions

View File

@ -787,20 +787,37 @@ func (mb *ociManifestBuilder) manifestAndConfig() ([]byte, []byte, error) {
} }
// filterExclusionsByImage returns a slice of the members of "exclusions" which are present in the image with the specified ID // filterExclusionsByImage returns a slice of the members of "exclusions" which are present in the image with the specified ID
func (i containerImageRef) filterExclusionsByImage(exclusions []copier.EnsureParentPath, imageID string) ([]copier.EnsureParentPath, error) { func (i containerImageRef) filterExclusionsByImage(ctx context.Context, exclusions []copier.EnsureParentPath, imageID string) ([]copier.EnsureParentPath, error) {
if len(exclusions) == 0 || imageID == "" { if len(exclusions) == 0 || imageID == "" {
return nil, nil return nil, nil
} }
var paths []copier.EnsureParentPath var paths []copier.EnsureParentPath
mountPoint, err := i.store.MountImage(imageID, nil, i.mountLabel) mountPoint, err := i.store.MountImage(imageID, nil, i.mountLabel)
if err != nil { cleanup := func() {
return nil, err
}
defer func() {
if _, err := i.store.UnmountImage(imageID, false); err != nil { if _, err := i.store.UnmountImage(imageID, false); err != nil {
logrus.Debugf("unmounting image %q: %v", imageID, err) logrus.Debugf("unmounting image %q: %v", imageID, err)
} }
}() }
if err != nil && errors.Is(err, storage.ErrLayerUnknown) {
// if an imagestore is being used, this could be expected
if b, err2 := NewBuilder(ctx, i.store, BuilderOptions{
FromImage: imageID,
PullPolicy: define.PullNever,
ContainerSuffix: "tmp",
}); err2 == nil {
mountPoint, err = b.Mount(i.mountLabel)
cleanup = func() {
cid := b.ContainerID
if err := b.Delete(); err != nil {
logrus.Debugf("unmounting image %q as container %q: %v", imageID, cid, err)
}
}
}
}
if err != nil {
return nil, fmt.Errorf("mounting image %q to examine its contents: %w", imageID, err)
}
defer cleanup()
globs := make([]string, 0, len(exclusions)) globs := make([]string, 0, len(exclusions))
for _, exclusion := range exclusions { for _, exclusion := range exclusions {
globs = append(globs, exclusion.Path) globs = append(globs, exclusion.Path)
@ -835,7 +852,7 @@ func (i containerImageRef) filterExclusionsByImage(exclusions []copier.EnsurePar
return paths, nil return paths, nil
} }
func (i *containerImageRef) NewImageSource(_ context.Context, _ *types.SystemContext) (src types.ImageSource, err error) { func (i *containerImageRef) NewImageSource(ctx context.Context, _ *types.SystemContext) (src types.ImageSource, err error) {
// These maps will let us check if a layer ID is part of one group or another. // These maps will let us check if a layer ID is part of one group or another.
parentLayerIDs := make(map[string]bool) parentLayerIDs := make(map[string]bool)
apiLayerIDs := make(map[string]bool) apiLayerIDs := make(map[string]bool)
@ -1038,7 +1055,7 @@ func (i *containerImageRef) NewImageSource(_ context.Context, _ *types.SystemCon
// And we _might_ need to filter out directories that modified // And we _might_ need to filter out directories that modified
// by creating and removing mount targets, _if_ they were the // by creating and removing mount targets, _if_ they were the
// same in the base image for this stage. // same in the base image for this stage.
layerPullUps, err := i.filterExclusionsByImage(i.layerPullUps, i.fromImageID) layerPullUps, err := i.filterExclusionsByImage(ctx, i.layerPullUps, i.fromImageID)
if err != nil { if err != nil {
return nil, fmt.Errorf("checking which exclusions are in base image %q: %w", i.fromImageID, err) return nil, fmt.Errorf("checking which exclusions are in base image %q: %w", i.fromImageID, err)
} }

View File

@ -8728,3 +8728,24 @@ _EOF
diff -u ${TEST_SCRATCH_DIR}/squashed-layered-image-rootfs.txt ${TEST_SCRATCH_DIR}/squashed-image-rootfs.txt diff -u ${TEST_SCRATCH_DIR}/squashed-layered-image-rootfs.txt ${TEST_SCRATCH_DIR}/squashed-image-rootfs.txt
diff -u ${TEST_SCRATCH_DIR}/squashed-layered-image-rootfs.txt ${TEST_SCRATCH_DIR}/squashed-not-layered-image-rootfs.txt diff -u ${TEST_SCRATCH_DIR}/squashed-layered-image-rootfs.txt ${TEST_SCRATCH_DIR}/squashed-not-layered-image-rootfs.txt
} }
@test "bud with a previously-used graphroot with base image in it used as imagestore" {
# there are subtle differences between "this was always the imagestore" and
# "this was a graphroot, but i'm using it as an imagestore now"
case "${STORAGE_DRIVER}" in
overlay) ;;
*) skip "imagestore flag is compatible with overlay, but not ${STORAGE_DRIVER}" ;;
esac
_prefetch quay.io/libpod/alpine:latest
local contextdir=${TEST_SCRATCH_DIR}/context
mkdir -p ${contextdir}
cat > ${contextdir}/Dockerfile << _EOF
FROM quay.io/libpod/alpine:latest
RUN mkdir hello
_EOF
run_buildah --root=${TEST_SCRATCH_DIR}/newroot --storage-opt=imagestore=${TEST_SCRATCH_DIR}/root build --pull=never --no-cache --layers=true ${contextdir}
run_buildah --root=${TEST_SCRATCH_DIR}/newroot --storage-opt=imagestore=${TEST_SCRATCH_DIR}/root build --pull=never ${contextdir}
run_buildah --root=${TEST_SCRATCH_DIR}/newroot --storage-opt=imagestore=${TEST_SCRATCH_DIR}/root build --pull=never --squash ${contextdir}
}