Skip to content
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
30 changes: 30 additions & 0 deletions client/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,36 @@ func (g *gatewayClientForBuild) ReleaseContainer(ctx context.Context, in *gatewa
return g.gateway.ReleaseContainer(ctx, in, opts...)
}

func (g *gatewayClientForBuild) ReadFileContainer(ctx context.Context, in *gatewayapi.ReadFileRequest, opts ...grpc.CallOption) (*gatewayapi.ReadFileResponse, error) {
if g.caps != nil {
if err := g.caps.Supports(gatewayapi.CapGatewayExecFilesystem); err != nil {
return nil, err
}
}
ctx = buildid.AppendToOutgoingContext(ctx, g.buildID)
return g.gateway.ReadFileContainer(ctx, in, opts...)
}

func (g *gatewayClientForBuild) ReadDirContainer(ctx context.Context, in *gatewayapi.ReadDirRequest, opts ...grpc.CallOption) (*gatewayapi.ReadDirResponse, error) {
if g.caps != nil {
if err := g.caps.Supports(gatewayapi.CapGatewayExecFilesystem); err != nil {
return nil, err
}
}
ctx = buildid.AppendToOutgoingContext(ctx, g.buildID)
return g.gateway.ReadDirContainer(ctx, in, opts...)
}

func (g *gatewayClientForBuild) StatFileContainer(ctx context.Context, in *gatewayapi.StatFileRequest, opts ...grpc.CallOption) (*gatewayapi.StatFileResponse, error) {
if g.caps != nil {
if err := g.caps.Supports(gatewayapi.CapGatewayExecFilesystem); err != nil {
return nil, err
}
}
ctx = buildid.AppendToOutgoingContext(ctx, g.buildID)
return g.gateway.StatFileContainer(ctx, in, opts...)
}

func (g *gatewayClientForBuild) ExecProcess(ctx context.Context, opts ...grpc.CallOption) (gatewayapi.LLBBridge_ExecProcessClient, error) {
if g.caps != nil {
if err := g.caps.Supports(gatewayapi.CapGatewayExec); err != nil {
Expand Down
131 changes: 92 additions & 39 deletions client/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ func testWarnings(t *testing.T, sb integration.Sandbox) {
product := "buildkit_test"

b := func(ctx context.Context, c client.Client) (*client.Result, error) {
st := llb.Scratch().File(llb.Mkfile("/dummy", 0600, []byte("foo")))
st := llb.Scratch().File(llb.Mkfile("/dummy", 0o600, []byte("foo")))

def, err := st.Marshal(ctx)
if err != nil {
Expand Down Expand Up @@ -660,7 +660,7 @@ func testClientGatewayContainerMounts(t *testing.T, sb integration.Sandbox) {

tmpdir := integration.Tmpdir(t)

err = os.WriteFile(filepath.Join(tmpdir.Name, "local-file"), []byte("local"), 0644)
err = os.WriteFile(filepath.Join(tmpdir.Name, "local-file"), []byte("local"), 0o644)
require.NoError(t, err)

a := agent.NewKeyring()
Expand Down Expand Up @@ -690,31 +690,51 @@ func testClientGatewayContainerMounts(t *testing.T, sb integration.Sandbox) {
// TODO How do we get a results.Ref for a cache mount, tmpfs mount
}

containerMounts := []client.Mount{{
Dest: "/cached",
MountType: pb.MountType_CACHE,
CacheOpt: &pb.CacheOpt{
ID: t.Name(),
Sharing: pb.CacheSharingOpt_SHARED,
containerMounts := []client.Mount{
{
Dest: "/",
MountType: pb.MountType_BIND,
},
}, {
Dest: "/tmpfs",
MountType: pb.MountType_TMPFS,
}, {
Dest: "/run/secrets/mysecret",
MountType: pb.MountType_SECRET,
SecretOpt: &pb.SecretOpt{
ID: "/run/secrets/mysecret",
{
Dest: "/foo",
MountType: pb.MountType_BIND,
},
}, {
Dest: sockPath,
MountType: pb.MountType_SSH,
SSHOpt: &pb.SSHOpt{
ID: t.Name(),
{
Dest: "/local",
MountType: pb.MountType_BIND,
},
}}
{
Dest: "/cached",
MountType: pb.MountType_CACHE,
CacheOpt: &pb.CacheOpt{
ID: t.Name(),
Sharing: pb.CacheSharingOpt_SHARED,
},
},
{
Dest: "/tmpfs",
MountType: pb.MountType_TMPFS,
},
{
Dest: "/run/secrets/mysecret",
MountType: pb.MountType_SECRET,
SecretOpt: &pb.SecretOpt{
ID: "/run/secrets/mysecret",
},
},
{
Dest: sockPath,
MountType: pb.MountType_SSH,
SSHOpt: &pb.SSHOpt{
ID: t.Name(),
},
},
}

// Fill in mount references.
for i, m := range containerMounts {
st := mounts[m.Dest]

for mountpoint, st := range mounts {
def, err := st.Marshal(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to marshal state")
Expand All @@ -726,11 +746,7 @@ func testClientGatewayContainerMounts(t *testing.T, sb integration.Sandbox) {
if err != nil {
return nil, errors.Wrap(err, "failed to solve")
}
containerMounts = append(containerMounts, client.Mount{
Dest: mountpoint,
MountType: pb.MountType_BIND,
Ref: r.Ref,
})
containerMounts[i].Ref = r.Ref
}

ctr, err := c.NewContainer(ctx, client.NewContainerRequest{Mounts: containerMounts})
Expand All @@ -745,6 +761,43 @@ func testClientGatewayContainerMounts(t *testing.T, sb integration.Sandbox) {
require.NoError(t, err)
defer pid1.Wait()

files := []struct {
index int
path string
data []byte
}{
{0, "/root-file", []byte(nil)},
{1, "/foo-file", []byte(nil)},
{2, "/local-file", []byte(`local`)},
{3, "/cache-file", []byte(nil)},
}
for _, file := range files {
cpath := containerMounts[file.index].Dest + file.path
pid, err := ctr.Start(ctx, client.StartRequest{
Args: []string{"test", "-f", cpath},
})
require.NoError(t, err, "cannot start container to check for file: %s", cpath)
err = pid.Wait()
require.NoError(t, err, "process for checking file failed: %s", cpath)

_, err = ctr.StatFile(ctx, client.StatContainerRequest{
StatRequest: client.StatRequest{
Path: file.path,
},
MountIndex: file.index,
})
require.NoError(t, err, "stat file for %q on mount %d failed", file.path, file.index)

b, err := ctr.ReadFile(ctx, client.ReadContainerRequest{
ReadRequest: client.ReadRequest{
Filename: file.path,
},
MountIndex: file.index,
})
require.NoError(t, err, "read file for %q on mount %d failed", file.path, file.index)
require.Equal(t, file.data, b)
}

pid, err := ctr.Start(ctx, client.StartRequest{
Args: []string{"test", "-f", "/root-file"},
})
Expand Down Expand Up @@ -1280,8 +1333,8 @@ func testClientSlowCacheRootfsRef(t *testing.T, sb integration.Sandbox) {
b := func(ctx context.Context, c client.Client) (*client.Result, error) {
id := identity.NewID()
input := llb.Scratch().File(
llb.Mkdir("/found", 0700).
Mkfile("/found/data", 0600, []byte(id)),
llb.Mkdir("/found", 0o700).
Mkfile("/found/data", 0o600, []byte(id)),
)

st := llb.Image("busybox:latest").Run(
Expand Down Expand Up @@ -1442,7 +1495,7 @@ func testClientGatewayExecError(t *testing.T, sb integration.Sandbox) {
"rootfs and readwrite mount",
llb.Image("busybox:latest").Run(
llb.Shlexf(`sh -c "echo %s > /data && echo %s > /rw/data && fail"`, id, id),
llb.AddMount("/rw", llb.Scratch().File(llb.Mkfile("foo", 0700, []byte(id)))),
llb.AddMount("/rw", llb.Scratch().File(llb.Mkfile("foo", 0o700, []byte(id)))),
).Root(),
2,
[]string{"/data", "/rw/data", "/rw/foo"},
Expand All @@ -1460,7 +1513,7 @@ func testClientGatewayExecError(t *testing.T, sb integration.Sandbox) {
llb.Shlexf(`sh -c "echo %s > /data && echo %s > /rw/data && fail"`, id, id),
llb.AddMount(
"/rw",
llb.Scratch().File(llb.Mkfile("foo", 0700, []byte(id))),
llb.Scratch().File(llb.Mkfile("foo", 0o700, []byte(id))),
llb.ForceNoOutput,
),
).Root(),
Expand Down Expand Up @@ -1579,8 +1632,8 @@ func testClientGatewaySlowCacheExecError(t *testing.T, sb integration.Sandbox) {

id := identity.NewID()
input := llb.Scratch().File(
llb.Mkdir("/found", 0700).
Mkfile("/found/data", 0600, []byte(id)),
llb.Mkdir("/found", 0o700).
Mkfile("/found/data", 0o600, []byte(id)),
)

st := llb.Image("busybox:latest").Run(
Expand Down Expand Up @@ -1691,17 +1744,17 @@ func testClientGatewayExecFileActionError(t *testing.T, sb integration.Sandbox)
}{{
"mkfile",
llb.Scratch().File(
llb.Mkdir("/found", 0700).
Mkfile("/found/foo", 0600, []byte(id)).
Mkfile("/notfound/foo", 0600, []byte(id)),
llb.Mkdir("/found", 0o700).
Mkfile("/found/foo", 0o600, []byte(id)).
Mkfile("/notfound/foo", 0o600, []byte(id)),
),
0, 3, "/input/found/foo",
}, {
"copy from input",
llb.Image("busybox").File(
llb.Copy(
llb.Scratch().File(
llb.Mkdir("/foo", 0600).Mkfile("/foo/bar", 0700, []byte(id)),
llb.Mkdir("/foo", 0o600).Mkfile("/foo/bar", 0o700, []byte(id)),
),
"/foo/bar",
"/notfound/baz",
Expand All @@ -1712,7 +1765,7 @@ func testClientGatewayExecFileActionError(t *testing.T, sb integration.Sandbox)
"copy from action",
llb.Image("busybox").File(
llb.Copy(
llb.Mkdir("/foo", 0600).Mkfile("/foo/bar", 0700, []byte(id)).WithState(llb.Scratch()),
llb.Mkdir("/foo", 0o600).Mkfile("/foo/bar", 0o700, []byte(id)).WithState(llb.Scratch()),
"/foo/bar",
"/notfound/baz",
),
Expand Down
24 changes: 24 additions & 0 deletions control/gateway/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,30 @@ func (gwf *GatewayForwarder) ReleaseContainer(ctx context.Context, req *gwapi.Re
return fwd.ReleaseContainer(ctx, req)
}

func (gwf *GatewayForwarder) ReadFileContainer(ctx context.Context, req *gwapi.ReadFileRequest) (*gwapi.ReadFileResponse, error) {
fwd, err := gwf.lookupForwarder(ctx)
if err != nil {
return nil, errors.Wrap(err, "forwarding ReadFileContainer")
}
return fwd.ReadFileContainer(ctx, req)
}

func (gwf *GatewayForwarder) ReadDirContainer(ctx context.Context, req *gwapi.ReadDirRequest) (*gwapi.ReadDirResponse, error) {
fwd, err := gwf.lookupForwarder(ctx)
if err != nil {
return nil, errors.Wrap(err, "forwarding ReadDirContainer")
}
return fwd.ReadDirContainer(ctx, req)
}

func (gwf *GatewayForwarder) StatFileContainer(ctx context.Context, req *gwapi.StatFileRequest) (*gwapi.StatFileResponse, error) {
fwd, err := gwf.lookupForwarder(ctx)
if err != nil {
return nil, errors.Wrap(err, "forwarding StatFileContainer")
}
return fwd.StatFileContainer(ctx, req)
}

func (gwf *GatewayForwarder) ExecProcess(srv gwapi.LLBBridge_ExecProcessServer) error {
fwd, err := gwf.lookupForwarder(srv.Context())
if err != nil {
Expand Down
18 changes: 18 additions & 0 deletions frontend/gateway/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ type Mount struct {
type Container interface {
Start(context.Context, StartRequest) (ContainerProcess, error)
Release(context.Context) error
ReadFile(ctx context.Context, req ReadContainerRequest) ([]byte, error)
StatFile(ctx context.Context, req StatContainerRequest) (*fstypes.Stat, error)
ReadDir(ctx context.Context, req ReadDirContainerRequest) ([]*fstypes.Stat, error)
}

// StartRequest encapsulates the arguments to define a process within a
Expand Down Expand Up @@ -111,6 +114,11 @@ type ReadRequest struct {
Range *FileRange
}

type ReadContainerRequest struct {
ReadRequest
MountIndex int
}

type FileRange struct {
Offset int
Length int
Expand All @@ -121,10 +129,20 @@ type ReadDirRequest struct {
IncludePattern string
}

type ReadDirContainerRequest struct {
ReadDirRequest
MountIndex int
}

type StatRequest struct {
Path string
}

type StatContainerRequest struct {
StatRequest
MountIndex int
}

// SolveRequest is same as frontend.SolveRequest but avoiding dependency
type SolveRequest struct {
Evaluate bool
Expand Down
Loading