Skip to content

pkg/overlay: cleanups #5927

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

Merged
merged 1 commit into from
Jan 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 30 additions & 23 deletions pkg/overlay/overlay.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ import (
"github.com/sirupsen/logrus"
)

// Options type holds various configuration options for overlay
// MountWithOptions accepts following type so it is easier to specify
// more verbose configuration for overlay mount.
// Options for MountWithOptions().
type Options struct {
// The Upper directory is normally writable layer in an overlay mount.
// Note!! : Following API does not handles escaping or validates correctness of the values
Expand All @@ -41,13 +39,13 @@ type Options struct {
// TODO: Should we address above comment and handle escaping of metacharacters like
// `comma`, `backslash` ,`colon` and any other special characters
WorkDirOptionFragment string
// Graph options relayed from podman, will be responsible for choosing mount program
// Graph options being used by the caller, will be searched when choosing mount program
GraphOpts []string
// Mark if following overlay is read only
ReadOnly bool
// RootUID is not used yet but keeping it here for legacy reasons.
// Deprecated: RootUID is not used
RootUID int
// RootGID is not used yet but keeping it here for legacy reasons.
// Deprecated: RootGID is not used
RootGID int
// Force overlay mounting and return a bind mount, rather than
// attempting to optimize by having the runtime actually mount and
Expand All @@ -57,7 +55,10 @@ type Options struct {
MountLabel string
}

// TempDir generates an overlay Temp directory in the container content
// TempDir generates a uniquely-named directory under ${containerDir}/overlay
// which can be used as a parent directory for the upper and working
// directories for an overlay mount, creates "upper" and "work" directories
// beneath it, and then returns the path of the new directory.
func TempDir(containerDir string, rootUID, rootGID int) (string, error) {
contentDir := filepath.Join(containerDir, "overlay")
if err := idtools.MkdirAllAs(contentDir, 0o700, rootUID, rootGID); err != nil {
Expand All @@ -69,7 +70,7 @@ func TempDir(containerDir string, rootUID, rootGID int) (string, error) {
return "", fmt.Errorf("failed to create the overlay tmpdir in %s directory: %w", contentDir, err)
}

return generateOverlayStructure(contentDir, rootUID, rootGID)
return contentDir, generateOverlayStructure(contentDir, rootUID, rootGID)
}

// GenerateStructure generates an overlay directory structure for container content
Expand All @@ -79,25 +80,24 @@ func GenerateStructure(containerDir, containerID, name string, rootUID, rootGID
return "", fmt.Errorf("failed to create the overlay %s directory: %w", contentDir, err)
}

return generateOverlayStructure(contentDir, rootUID, rootGID)
return contentDir, generateOverlayStructure(contentDir, rootUID, rootGID)
}

// generateOverlayStructure generates upper, work and merge directory structure for overlay directory
func generateOverlayStructure(containerDir string, rootUID, rootGID int) (string, error) {
// generateOverlayStructure generates upper, work and merge directories under the specified directory
func generateOverlayStructure(containerDir string, rootUID, rootGID int) error {
upperDir := filepath.Join(containerDir, "upper")
workDir := filepath.Join(containerDir, "work")
if err := idtools.MkdirAllAs(upperDir, 0o700, rootUID, rootGID); err != nil {
return "", fmt.Errorf("failed to create the overlay %s directory: %w", upperDir, err)
return fmt.Errorf("creating overlay upper directory %s: %w", upperDir, err)
}
if err := idtools.MkdirAllAs(workDir, 0o700, rootUID, rootGID); err != nil {
return "", fmt.Errorf("failed to create the overlay %s directory: %w", workDir, err)
return fmt.Errorf("creating overlay work directory %s: %w", workDir, err)
}
mergeDir := filepath.Join(containerDir, "merge")
if err := idtools.MkdirAllAs(mergeDir, 0o700, rootUID, rootGID); err != nil {
return "", fmt.Errorf("failed to create the overlay %s directory: %w", mergeDir, err)
return fmt.Errorf("creating overlay merge directory %s: %w", mergeDir, err)
}

return containerDir, nil
return nil
}

// Mount creates a subdir of the contentDir based on the source directory
Expand Down Expand Up @@ -140,8 +140,8 @@ func findMountProgram(graphOptions []string) string {
return ""
}

// mountWithMountProgram mount an overlay at mergeDir using the specified mount program
// and overlay options.
// mountWithMountProgram mounts an overlay at mergeDir using the specified
// mount program and overlay options.
func mountWithMountProgram(mountProgram, overlayOptions, mergeDir string) error {
cmd := exec.Command(mountProgram, "-o", overlayOptions, mergeDir)

Expand All @@ -162,8 +162,9 @@ func escapeColon(source string) string {
return strings.ReplaceAll(source, ":", "\\:")
}

// RemoveTemp removes temporary mountpoint and all content from its parent
// directory
// RemoveTemp unmounts a filesystem mounted at ${contentDir}/merge, and then
// removes ${contentDir}, which is typically a path returned by TempDir(),
// along with any contents it might still have.
func RemoveTemp(contentDir string) error {
if err := Unmount(contentDir); err != nil {
return err
Expand All @@ -172,7 +173,9 @@ func RemoveTemp(contentDir string) error {
return os.RemoveAll(contentDir)
}

// Unmount the overlay mountpoint
// Unmount the overlay mountpoint at ${contentDir}/merge, where ${contentDir}
// is typically a path returned by TempDir(). The mountpoint itself is left
// unmodified.
func Unmount(contentDir string) error {
mergeDir := filepath.Join(contentDir, "merge")

Expand All @@ -198,6 +201,8 @@ func Unmount(contentDir string) error {
return nil
}

// recreate removes a directory tree and then recreates the top of that tree
// with the same mode and ownership.
func recreate(contentDir string) error {
st, err := system.Stat(contentDir)
if err != nil {
Expand Down Expand Up @@ -228,8 +233,10 @@ func CleanupMount(contentDir string) (Err error) {
return nil
}

// CleanupContent removes all temporary mountpoint and all content from
// directory
// CleanupContent removes every temporary mountpoint created under
// ${containerDir}/overlay as a result of however many calls to TempDir(),
// roughly equivalent to calling RemoveTemp() for each of the directories whose
// paths it returned, and then removes ${containerDir} itself.
func CleanupContent(containerDir string) (Err error) {
contentDir := filepath.Join(containerDir, "overlay")

Expand Down
10 changes: 5 additions & 5 deletions pkg/overlay/overlay_freebsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import (
"github.com/opencontainers/runtime-spec/specs-go"
)

// MountWithOptions creates a subdir of the contentDir based on the source directory
// from the source system. It then mounts up the source directory on to the
// generated mount point and returns the mount point to the caller.
// But allows api to set custom workdir, upperdir and other overlay options
// Following API is being used by podman at the moment
// MountWithOptions returns a specs.Mount which makes the contents of ${source}
// visible at ${dest} in the container.
// Options allows the caller to configure whether or not the mount should be
// read-only.
// This API is used by podman.
func MountWithOptions(contentDir, source, dest string, opts *Options) (mount specs.Mount, Err error) {
if opts == nil {
opts = &Options{}
Expand Down
24 changes: 17 additions & 7 deletions pkg/overlay/overlay_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ import (
"github.com/opencontainers/selinux/go-selinux/label"
)

// MountWithOptions creates a subdir of the contentDir based on the source directory
// from the source system. It then mounts up the source directory on to the
// generated mount point and returns the mount point to the caller.
// But allows api to set custom workdir, upperdir and other overlay options
// Following API is being used by podman at the moment
// MountWithOptions creates ${contentDir}/merge, where ${contentDir} was
// presumably created and returned by a call to TempDir(), and either mounts a
// filesystem there and returns a mounts.Spec which bind-mounts the mountpoint
// to ${dest}, or returns a mounts.Spec which mounts a filesystem at ${dest}.
// Options allows the caller to configure a custom workdir and upperdir,
// indicate whether or not the overlay should be read-only, and provide the
// graph driver options that we'll search to determine whether or not we should
// be using a mount helper (i.e., fuse-overlayfs).
// This API is used by podman.
func MountWithOptions(contentDir, source, dest string, opts *Options) (mount specs.Mount, Err error) {
if opts == nil {
opts = &Options{}
Expand All @@ -26,7 +30,7 @@ func MountWithOptions(contentDir, source, dest string, opts *Options) (mount spe
// Create overlay mount options for rw/ro.
var overlayOptions string
if opts.ReadOnly {
// Read-only overlay mounts require two lower layer.
// Read-only overlay mounts require two lower layers.
lowerTwo := filepath.Join(contentDir, "lower")
if err := os.Mkdir(lowerTwo, 0o755); err != nil {
return mount, err
Expand All @@ -39,7 +43,13 @@ func MountWithOptions(contentDir, source, dest string, opts *Options) (mount spe

if opts.WorkDirOptionFragment != "" && opts.UpperDirOptionFragment != "" {
workDir = opts.WorkDirOptionFragment
if !filepath.IsAbs(workDir) {
workDir = filepath.Join(contentDir, workDir)
}
upperDir = opts.UpperDirOptionFragment
if !filepath.IsAbs(upperDir) {
upperDir = filepath.Join(contentDir, upperDir)
}
}

st, err := os.Stat(source)
Expand Down Expand Up @@ -74,7 +84,7 @@ func MountWithOptions(contentDir, source, dest string, opts *Options) (mount spe
}

if unshare.IsRootless() {
/* If a mount_program is not specified, fallback to try mounting native overlay. */
// If a mount_program is not specified, fallback to try mounting native overlay.
overlayOptions = fmt.Sprintf("%s,userxattr", overlayOptions)
}

Expand Down