Skip to content

Commit

Permalink
feat: wcow: add support for bind and cache mounts
Browse files Browse the repository at this point in the history
Currently, mounts are not supported for WCOW builds,
see #5678. This commit introduces support for
bind and cache mounts. The remaining two require
a little more work and consultation with the platform
teams for enlightment.

WIP Checklist:

- [x] Support for bind mounts
- [x] Support for cache mounts
- [x] add frontend/dockerfile integration tests
- [ ] add client integration tests
- [ ] add documentatio
- [ ] add note and plan on the missing feature(s)
	i.e. secret mounts (that need tmpfs)
- [ ] spec out / second attempt for SSH mount

Fixes #5603
Addresses part of #5678

Signed-off-by: Anthony Nandaa <[email protected]>
  • Loading branch information
profnandaa committed Feb 11, 2025
1 parent 3f4bcd3 commit 00b9867
Show file tree
Hide file tree
Showing 8 changed files with 255 additions and 45 deletions.
21 changes: 16 additions & 5 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1561,15 +1561,22 @@ func testLocalSymlinkEscape(t *testing.T, sb integration.Sandbox) {
}

func testRelativeWorkDir(t *testing.T, sb integration.Sandbox) {
requiresLinux(t)
c, err := New(sb.Context(), sb.Address())
require.NoError(t, err)
defer c.Close()

pwd := llb.Image("docker.io/library/busybox:latest").
imgName := integration.UnixOrWindows(
"docker.io/library/busybox:latest",
"mcr.microsoft.com/windows/nanoserver:ltsc2022",
)
cmdStr := integration.UnixOrWindows(
`sh -c "pwd > /out/pwd"`,
`cmd /C "cd > /out/pwd"`,
)
pwd := llb.Image(imgName).
Dir("test1").
Dir("test2").
Run(llb.Shlex(`sh -c "pwd > /out/pwd"`)).
Run(llb.Shlex(cmdStr)).
AddMount("/out", llb.Scratch())

def, err := pwd.Marshal(sb.Context())
Expand All @@ -1589,7 +1596,11 @@ func testRelativeWorkDir(t *testing.T, sb integration.Sandbox) {

dt, err := os.ReadFile(filepath.Join(destDir, "pwd"))
require.NoError(t, err)
require.Equal(t, []byte("/test1/test2\n"), dt)
pathStr := integration.UnixOrWindows(
"/test1/test2\n",
"C:\\test1\\test2\r\n",
)
require.Equal(t, []byte(pathStr), dt)
}

// TODO: remove this test once `client.SolveOpt.LocalDirs`, now marked as deprecated, is removed.
Expand Down Expand Up @@ -7480,7 +7491,7 @@ func testMergeOp(t *testing.T, sb integration.Sandbox) {
File(llb.Mkfile("bar/D", 0644, []byte("D"))).
File(llb.Mkfile("bar/E", 0755, nil)).
File(llb.Mkfile("qaz", 0644, nil)),
// /foo from stateE is not here because it is deleted in stateB, which is part of a submerge of mergeD
// /foo from stateE is not here because it is deleted in stateB, which is part of a submerge of mergeD
)
}

Expand Down
9 changes: 7 additions & 2 deletions executor/oci/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package oci

import (
"context"
"github.com/moby/buildkit/util/system"
"os"
"path"
"path/filepath"
Expand Down Expand Up @@ -201,8 +202,8 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou
return nil, nil, err
}
s.Mounts = append(s.Mounts, specs.Mount{
Destination: m.Dest,
Type: mount.Type,
Destination: system.GetAbsolutePath(m.Dest),
Type: getMountType(mount.Type),
Source: mount.Source,
Options: mount.Options,
})
Expand Down Expand Up @@ -243,6 +244,10 @@ type submounts struct {

func (s *submounts) subMount(m mount.Mount, subPath string) (mount.Mount, error) {
if path.Join("/", subPath) == "/" {
// for Windows, the mounting by HCS doesn't go through
// WCIFS, hence we have to give the direct path of the
// mount, which is in the /Files subdirectory.
m.Source = getCompleteSourcePath(m.Source)
return m, nil
}
if s.m == nil {
Expand Down
13 changes: 13 additions & 0 deletions executor/oci/spec_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//go:build !windows

package oci

// no effect for non-Windows
func getMountType(mType string) string {
return mType
}

// no effect for non-Windows
func getCompleteSourcePath(p string) string {
return p
}
13 changes: 13 additions & 0 deletions executor/oci/spec_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,16 @@ func sub(m mount.Mount, subPath string) (mount.Mount, func() error, error) {
m.Source = src
return m, func() error { return nil }, nil
}

func getMountType(_ string) string {
// HCS shim doesn't expect a named type
// for the mount.
return ""
}

// For Windows, the mounting by HCS doesn't go through
// WCIFS, hence we have to give the direct path of the
// mount, which is in the /Files subdirectory.
func getCompleteSourcePath(p string) string {
return filepath.Join(p, "Files")
}
3 changes: 2 additions & 1 deletion frontend/dockerfile/dockerfile2llb/convert_runmount.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package dockerfile2llb

import (
"context"
"github.com/moby/buildkit/util/system"
"os"
"path"
"path/filepath"
Expand Down Expand Up @@ -118,7 +119,7 @@ func dispatchRunMounts(d *dispatchState, c *instructions.RunCommand, sources []*
mountOpts = append(mountOpts, llb.AsPersistentCacheDir(opt.cacheIDNamespace+"/"+mount.CacheID, sharing))
}
target := mount.Target
if !filepath.IsAbs(filepath.Clean(mount.Target)) {
if !system.IsAbsolutePath(filepath.Clean(mount.Target)) {
dir, err := d.state.GetDir(context.TODO())
if err != nil {
return nil, err
Expand Down
Loading

0 comments on commit 00b9867

Please sign in to comment.