diff --git a/run_linux.go b/run_linux.go index 2ae374c31a..cea65caf2d 100644 --- a/run_linux.go +++ b/run_linux.go @@ -545,6 +545,11 @@ func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath st return nil, err } + // prepare list of mount destinations which can be cleaned up safely. + // we can clean bindFiles, subscriptionMounts and specMounts + // everything other than these might have users content + mountArtifacts.RunMountTargets = append(append(append(mountArtifacts.RunMountTargets, cleanableDestinationListFromMounts(bindFileMounts)...), cleanableDestinationListFromMounts(subscriptionMounts)...), cleanableDestinationListFromMounts(specMounts)...) + allMounts := util.SortMounts(append(append(append(append(append(append(volumes, builtins...), runMounts...), subscriptionMounts...), bindFileMounts...), specMounts...), sysfsMount...)) // Add them all, in the preferred order, except where they conflict with something that was previously added. for _, mount := range allMounts { @@ -561,6 +566,23 @@ func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath st return mountArtifacts, nil } +// Destinations which can be cleaned up after every RUN +func cleanableDestinationListFromMounts(mounts []spec.Mount) []string { + mountDest := []string{} + for _, mount := range mounts { + // Add all destination to mountArtifacts so that they can be cleaned up later + if mount.Destination != "" { + // we dont want to remove destinations with /etc, /dev, /sys, /proc as rootfs already contains these files + // and unionfs will create a `whiteout` i.e `.wh` files on removal of overlapping files from these directories. + // everything other than these will be cleanedup + if !strings.HasPrefix(mount.Destination, "/etc") && !strings.HasPrefix(mount.Destination, "/dev") && !strings.HasPrefix(mount.Destination, "/sys") && !strings.HasPrefix(mount.Destination, "/proc") { + mountDest = append(mountDest, mount.Destination) + } + } + } + return mountDest +} + // addResolvConf copies files from host and sets them up to bind mount into container func (b *Builder) addResolvConf(rdir string, chownOpts *idtools.IDPair, dnsServers, dnsSearch, dnsOptions []string, namespaceOptions define.NamespaceOptions) (string, error) { resolvConf := "/etc/resolv.conf" diff --git a/tests/bud.bats b/tests/bud.bats index 98c7eebb60..30b1704a28 100644 --- a/tests/bud.bats +++ b/tests/bud.bats @@ -3446,3 +3446,55 @@ _EOF run_buildah rmi -f ${target} } + +@test "bud with run should not leave mounts behind cleanup test" { + skip_if_in_container + run which podman + if [[ $status -ne 0 ]]; then + skip "podman is not installed" + fi + + # Create target dir where we will export tar + target=cleanable + mkdir ${TESTDIR}/${target} + + # Build and export container to tar + run_buildah build --no-cache --signature-policy ${TESTSDIR}/policy.json -t ${target} -f ${TESTSDIR}/bud/containerfile/Containerfile.in ${TESTSDIR}/bud/containerfile + podman export $(podman create --name ${target} ${target}) --output=${TESTDIR}/${target}.tar + + # We are done exporting so remove images and containers which are not needed + podman rm -f ${target} + run_buildah rmi ${target} + + # Explode tar + tar -xf ${TESTDIR}/${target}.tar -C ${TESTDIR}/${target} + count=$(ls -A ${TESTDIR}/${target}/run | wc -l) + ## exported /run should be empty + assert "$count" == "0" +} + +@test "bud with custom files in /run/ should persist cleanup test" { + skip_if_in_container + run which podman + if [[ $status -ne 0 ]]; then + skip "podman is not installed" + fi + + # Create target dir where we will export tar + target=cleanable + mkdir ${TESTDIR}/${target} + + # Build and export container to tar + run_buildah build --no-cache --signature-policy ${TESTSDIR}/policy.json -t ${target} -f ${TESTSDIR}/bud/add-run-dir + podman export $(podman create --name ${target} ${target}) --output=${TESTDIR}/${target}.tar + + # We are done exporting so remove images and containers which are not needed + podman rm -f ${target} + run_buildah rmi ${target} + + # Explode tar + tar -xf ${TESTDIR}/${target}.tar -C ${TESTDIR}/${target} + count=$(ls -A ${TESTDIR}/${target}/run | wc -l) + ## exported /run should not be empty + assert "$count" == "1" +} diff --git a/tests/bud/add-run-dir/Dockerfile b/tests/bud/add-run-dir/Dockerfile new file mode 100644 index 0000000000..d4b4ebe348 --- /dev/null +++ b/tests/bud/add-run-dir/Dockerfile @@ -0,0 +1,2 @@ +FROM alpine +RUN touch /run/hello