diff --git a/client/client_test.go b/client/client_test.go index 20846bba..836e4cdb 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -124,6 +124,7 @@ func TestIntegration(t *testing.T) { testLazyImagePush, testStargzLazyPull, testFileOpInputSwap, + testRelativeMountpoint, }, mirrors) integration.Run(t, []integration.Test{ @@ -3458,6 +3459,44 @@ func testParallelLocalBuilds(t *testing.T, sb integration.Sandbox) { require.NoError(t, err) } +// testRelativeMountpoint is a test that relative paths for mountpoints don't +// fail when runc is upgraded to at least rc95, which introduces an error when +// mountpoints are not absolute. Relative paths should be transformed to +// absolute points based on the llb.State's current working directory. +func testRelativeMountpoint(t *testing.T, sb integration.Sandbox) { + requiresLinux(t) + c, err := New(context.TODO(), sb.Address()) + require.NoError(t, err) + defer c.Close() + + id := identity.NewID() + + st := llb.Image("busybox:latest").Dir("/root").Run( + llb.Shlexf("sh -c 'echo -n %s > /root/relpath/data'", id), + ).AddMount("relpath", llb.Scratch()) + + def, err := st.Marshal(context.TODO()) + require.NoError(t, err) + + destDir, err := ioutil.TempDir("", "buildkit") + require.NoError(t, err) + defer os.RemoveAll(destDir) + + _, err = c.Solve(context.TODO(), def, SolveOpt{ + Exports: []ExportEntry{ + { + Type: ExporterLocal, + OutputDir: destDir, + }, + }, + }, nil) + require.NoError(t, err) + + dt, err := ioutil.ReadFile(filepath.Join(destDir, "data")) + require.NoError(t, err) + require.Equal(t, dt, []byte(id)) +} + func tmpdir(appliers ...fstest.Applier) (string, error) { tmpdir, err := ioutil.TempDir("", "buildkit-client") if err != nil { diff --git a/frontend/gateway/container.go b/frontend/gateway/container.go index e124566d..f234401f 100644 --- a/frontend/gateway/container.go +++ b/frontend/gateway/container.go @@ -3,6 +3,7 @@ package gateway import ( "context" "fmt" + "path/filepath" "runtime" "sort" "strings" @@ -75,7 +76,7 @@ func NewContainer(ctx context.Context, w worker.Worker, sm *session.Manager, g s name := fmt.Sprintf("container %s", req.ContainerID) mm := mounts.NewMountManager(name, w.CacheManager(), sm, w.MetadataStore()) - p, err := PrepareMounts(ctx, mm, w.CacheManager(), g, mnts, refs, func(m *opspb.Mount, ref cache.ImmutableRef) (cache.MutableRef, error) { + p, err := PrepareMounts(ctx, mm, w.CacheManager(), g, "", mnts, refs, func(m *opspb.Mount, ref cache.ImmutableRef) (cache.MutableRef, error) { cm := w.CacheManager() if m.Input != opspb.Empty { cm = refs[m.Input].Worker.CacheManager() @@ -132,7 +133,7 @@ type MountMutableRef struct { type MakeMutable func(m *opspb.Mount, ref cache.ImmutableRef) (cache.MutableRef, error) -func PrepareMounts(ctx context.Context, mm *mounts.MountManager, cm cache.Manager, g session.Group, mnts []*opspb.Mount, refs []*worker.WorkerRef, makeMutable MakeMutable) (p PreparedMounts, err error) { +func PrepareMounts(ctx context.Context, mm *mounts.MountManager, cm cache.Manager, g session.Group, cwd string, mnts []*opspb.Mount, refs []*worker.WorkerRef, makeMutable MakeMutable) (p PreparedMounts, err error) { // loop over all mounts, fill in mounts, root and outputs for i, m := range mnts { var ( @@ -254,7 +255,11 @@ func PrepareMounts(ctx context.Context, mm *mounts.MountManager, cm cache.Manage p.Root = mountWithSession(root, g) } else { mws := mountWithSession(mountable, g) - mws.Dest = m.Dest + dest := m.Dest + if !filepath.IsAbs(filepath.Clean(dest)) { + dest = filepath.Join("/", cwd, dest) + } + mws.Dest = dest mws.Readonly = m.Readonly mws.Selector = m.Selector p.Mounts = append(p.Mounts, mws) diff --git a/solver/llbsolver/ops/exec.go b/solver/llbsolver/ops/exec.go index b5ef0f16..1e0b7ad9 100644 --- a/solver/llbsolver/ops/exec.go +++ b/solver/llbsolver/ops/exec.go @@ -243,7 +243,7 @@ func (e *execOp) Exec(ctx context.Context, g session.Group, inputs []solver.Resu } } - p, err := gateway.PrepareMounts(ctx, e.mm, e.cm, g, e.op.Mounts, refs, func(m *pb.Mount, ref cache.ImmutableRef) (cache.MutableRef, error) { + p, err := gateway.PrepareMounts(ctx, e.mm, e.cm, g, e.op.Meta.Cwd, e.op.Mounts, refs, func(m *pb.Mount, ref cache.ImmutableRef) (cache.MutableRef, error) { desc := fmt.Sprintf("mount %s from exec %s", m.Dest, strings.Join(e.op.Meta.Args, " ")) return e.cm.New(ctx, ref, g, cache.WithDescription(desc)) })