-
Notifications
You must be signed in to change notification settings - Fork 814
RUN: only use an overlay for --mount=type=bind,rw on overlay #6126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
nalind
wants to merge
10
commits into
containers:main
Choose a base branch
from
nalind:overlay-copy
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
c510173
CI: expand the in-a-container-tests filesystem combinations
nalind 22d770e
RUN: only use an overlay for --mount=type=bind,rw on overlay
nalind c2f530c
pkg/overlay: fall back to trying fuse-overlayfs
nalind dad67d7
Builder.runSetupVolumeMounts(): force overlay mounts
nalind b12d92d
imagebuildah.StageExecutor.volumeCacheSaveOverlay(): force mount
nalind 7c5f9b9
run.bats(run overlay --volume with custom upper and workdir): drop ,z
nalind b2b6d04
run.bats(root fs only mounted once): also accept rw by itself
nalind 60e2359
run.bats(run --mount): skip if we're on overlay
nalind 7574fe2
overlay.bats(overlay path contains colon): skip if we're on overlay
nalind 2ed4845
chroot.bats(chroot with overlay root): ensure we can overlay
nalind File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,12 +4,14 @@ import ( | |
"context" | ||
"errors" | ||
"fmt" | ||
"io" | ||
"os" | ||
"path" | ||
"path/filepath" | ||
"slices" | ||
"strconv" | ||
"strings" | ||
"sync" | ||
|
||
"github.com/containers/buildah/copier" | ||
"github.com/containers/buildah/define" | ||
|
@@ -77,6 +79,11 @@ func mountIsReadWrite(m specs.Mount) bool { | |
return rw | ||
} | ||
|
||
// convertToOverlay accepts a specs.Mount that specifies a bind mount, and | ||
// returns a replacement for it that instead mounts an overlay at the desired | ||
// location, using the original source location as a "lower", so that writes to | ||
// it will be redirected to it to a temporary location which can later be | ||
// discarded, leaving the original location unmodified. | ||
func convertToOverlay(m specs.Mount, store storage.Store, mountLabel, tmpDir string, uid, gid int) (specs.Mount, string, error) { | ||
overlayDir, err := overlay.TempDir(tmpDir, uid, gid) | ||
if err != nil { | ||
|
@@ -93,7 +100,7 @@ func convertToOverlay(m specs.Mount, store storage.Store, mountLabel, tmpDir str | |
// do the normal thing of mounting this directory as a lower with a temporary upper | ||
mountThisInstead, err = overlay.MountWithOptions(overlayDir, m.Source, m.Destination, &options) | ||
if err != nil { | ||
return specs.Mount{}, "", fmt.Errorf("setting up overlay of %q: %w", m.Source, err) | ||
return specs.Mount{}, "", fmt.Errorf("setting up overlay of directory %q: %w", m.Source, err) | ||
} | ||
} else { | ||
// mount the parent directory as the lower with a temporary upper, and return a | ||
|
@@ -103,7 +110,7 @@ func convertToOverlay(m specs.Mount, store storage.Store, mountLabel, tmpDir str | |
destination := m.Destination | ||
mountedOverlay, err := overlay.MountWithOptions(overlayDir, sourceDir, destination, &options) | ||
if err != nil { | ||
return specs.Mount{}, "", fmt.Errorf("setting up overlay of %q: %w", sourceDir, err) | ||
return specs.Mount{}, "", fmt.Errorf("setting up overlay of directory %q containing %q: %w", sourceDir, sourceBase, err) | ||
} | ||
if mountedOverlay.Type != define.TypeBind { | ||
if err2 := overlay.RemoveTemp(overlayDir); err2 != nil { | ||
|
@@ -118,6 +125,91 @@ func convertToOverlay(m specs.Mount, store storage.Store, mountLabel, tmpDir str | |
return mountThisInstead, overlayDir, nil | ||
} | ||
|
||
// makeTempCopy accepts a specs.Mount that specifies a bind mount, and returns | ||
// a replacement for it that instead bind mounts a temporary copy of the | ||
// original source location, so that writes to it will succeed without actually | ||
// modifying the original copy. | ||
func makeTempCopy(m specs.Mount, tmpDir string, uid, gid int) (specs.Mount, string, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function seems like it could use a doc comment. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added one. |
||
succeeded := false | ||
overlayDir, err := overlay.TempDir(tmpDir, uid, gid) | ||
if err != nil { | ||
return specs.Mount{}, "", fmt.Errorf("setting up temporary copy of %q: %w", m.Destination, err) | ||
} | ||
defer func() { | ||
if !succeeded { | ||
if err := overlay.RemoveTemp(overlayDir); err != nil { | ||
logrus.Warnf("%v", err) | ||
} | ||
} | ||
}() | ||
mergedDir := filepath.Join(overlayDir, "merge") | ||
fileInfo, err := os.Stat(m.Source) | ||
if err != nil { | ||
return specs.Mount{}, "", fmt.Errorf("setting up temporary copy of %q: %w", m.Source, err) | ||
} | ||
copiedDir := filepath.Join(mergedDir, "copied") | ||
if fileInfo.IsDir() { | ||
if err = os.Mkdir(copiedDir, fileInfo.Mode()); err != nil { | ||
return specs.Mount{}, "", fmt.Errorf("creating top-level directory for copy of %q: %w", m.Source, err) | ||
} | ||
} else { | ||
if err = os.Mkdir(copiedDir, 0o755); err != nil { | ||
return specs.Mount{}, "", fmt.Errorf("creating parent directory for copy of %q: %w", m.Source, err) | ||
} | ||
} | ||
if err = os.Chown(copiedDir, uid, gid); err != nil { | ||
return specs.Mount{}, "", fmt.Errorf("setting ownership of %q: %w", m.Source, err) | ||
} | ||
forceOwner := idtools.IDPair{UID: uid, GID: gid} | ||
getOptions := copier.GetOptions{ | ||
ChownDirs: &forceOwner, | ||
ChownFiles: &forceOwner, | ||
} | ||
var wg sync.WaitGroup | ||
var putErr, getErr error | ||
copyReader, copyWriter := io.Pipe() | ||
wg.Add(1) | ||
go func() { | ||
defer wg.Done() | ||
putErr = copier.Put(copiedDir, copiedDir, copier.PutOptions{}, copyReader) | ||
copyReader.Close() | ||
}() | ||
mountThisInstead := m | ||
mountThisInstead.Options = append(slices.Clone(define.BindOptions), "z") | ||
wg.Add(1) | ||
if fileInfo.IsDir() { | ||
// copy the directory to the temporary directory | ||
go func() { | ||
defer wg.Done() | ||
getErr = copier.Get(m.Source, m.Source, getOptions, []string{"."}, copyWriter) | ||
copyWriter.Close() | ||
}() | ||
// point the if-everything-works mount at the temporary driectory | ||
mountThisInstead.Type = define.TypeBind | ||
mountThisInstead.Source = copiedDir | ||
mountThisInstead.Destination = m.Destination | ||
} else { | ||
// copy just the one thing to the temporary directory | ||
sourceDir := filepath.Dir(m.Source) | ||
sourceBase := filepath.Base(m.Source) | ||
go func() { | ||
defer wg.Done() | ||
getErr = copier.Get(sourceDir, sourceDir, getOptions, []string{sourceBase}, copyWriter) | ||
copyWriter.Close() | ||
}() | ||
// point the if-everything-works mount at the new copy of the item | ||
mountThisInstead.Type = define.TypeBind | ||
mountThisInstead.Source = filepath.Join(copiedDir, sourceBase) | ||
mountThisInstead.Destination = m.Destination | ||
} | ||
wg.Wait() | ||
if getErr != nil || putErr != nil { | ||
return specs.Mount{}, "", fmt.Errorf("creating a temporary copy: %w", errors.Join(getErr, putErr)) | ||
} | ||
succeeded = true | ||
return mountThisInstead, overlayDir, nil | ||
} | ||
|
||
// FIXME: this code needs to be merged with pkg/parse/parse.go ValidateVolumeOpts | ||
// | ||
// GetBindMount parses a single bind mount entry from the --mount flag. | ||
|
@@ -329,8 +421,15 @@ func GetBindMount(sys *types.SystemContext, args []string, contextDir string, st | |
|
||
overlayDir := "" | ||
if mountedImage != "" || mountIsReadWrite(newMount) { | ||
if newMount, overlayDir, err = convertToOverlay(newMount, store, mountLabel, tmpDir, 0, 0); err != nil { | ||
return newMount, "", "", "", err | ||
switch store.GraphDriverName() { | ||
case "overlay": | ||
if newMount, overlayDir, err = convertToOverlay(newMount, store, mountLabel, tmpDir, 0, 0); err != nil { | ||
return newMount, "", "", "", err | ||
} | ||
default: | ||
if newMount, overlayDir, err = makeTempCopy(newMount, tmpDir, 0, 0); err != nil { | ||
return newMount, "", "", "", err | ||
} | ||
} | ||
} | ||
|
||
|
@@ -662,8 +761,15 @@ func GetCacheMount(sys *types.SystemContext, args []string, store storage.Store, | |
|
||
overlayDir := "" | ||
if needToOverlay { | ||
if newMount, overlayDir, err = convertToOverlay(newMount, store, mountLabel, tmpDir, 0, 0); err != nil { | ||
return newMount, "", "", "", nil, err | ||
switch store.GraphDriverName() { | ||
case "overlay": | ||
if newMount, overlayDir, err = convertToOverlay(newMount, store, mountLabel, tmpDir, 0, 0); err != nil { | ||
return newMount, "", "", "", nil, err | ||
} | ||
default: | ||
if newMount, overlayDir, err = makeTempCopy(newMount, tmpDir, 0, 0); err != nil { | ||
return newMount, "", "", "", nil, err | ||
} | ||
} | ||
} | ||
|
||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe cirrus will happily accept this invalid YAML, but I believe
hack/get_ci_vm.sh
will puke on it because it uses python-yaml to parse the file. If this functionality is important, I believe something like the following would work: