Skip to content
This repository has been archived by the owner on May 12, 2021. It is now read-only.

Commit

Permalink
virtcontainers: copy files form host to guest
Browse files Browse the repository at this point in the history
Files are copied over gRPC and there is no limit in size of the files that
can be copied. Small files are copied using just one gRPC call while big files
are copied by parts.

Signed-off-by: Julio Montes <[email protected]>
  • Loading branch information
Julio Montes committed Dec 19, 2018
1 parent dcd48a9 commit 6291762
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 0 deletions.
3 changes: 3 additions & 0 deletions virtcontainers/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,4 +250,7 @@ type agent interface {

// setGuestDateTime asks the agent to set guest time to the provided one
setGuestDateTime(time.Time) error

// copyFile copies file from host to container's rootfs
copyFile(src, dst string) error
}
5 changes: 5 additions & 0 deletions virtcontainers/hyperstart_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -1005,3 +1005,8 @@ func (h *hyper) setGuestDateTime(time.Time) error {
// hyperstart-agent does not support setGuestDateTime
return nil
}

func (h *hyper) copyFile(src, dst string) error {
// hyperstart-agent does not support copyFile
return nil
}
8 changes: 8 additions & 0 deletions virtcontainers/hyperstart_agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,11 @@ func TestHyperGetAgentUrl(t *testing.T) {
assert.Nil(err)
assert.Empty(url)
}

func TestHyperCopyFile(t *testing.T) {
assert := assert.New(t)
h := &hyper{}

err := h.copyFile("", "")
assert.Nil(err)
}
59 changes: 59 additions & 0 deletions virtcontainers/kata_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"regexp"
Expand All @@ -34,6 +35,7 @@ import (
"github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
"golang.org/x/net/context"
"golang.org/x/sys/unix"
golangGrpc "google.golang.org/grpc"
"google.golang.org/grpc/codes"
grpcStatus "google.golang.org/grpc/status"
Expand Down Expand Up @@ -63,6 +65,7 @@ var (
shmDir = "shm"
kataEphemeralDevType = "ephemeral"
ephemeralPath = filepath.Join(kataGuestSandboxDir, kataEphemeralDevType)
grpcMaxDataSize = int64(1024 * 1024)
)

// KataAgentConfig is a structure storing information needed
Expand Down Expand Up @@ -1490,6 +1493,9 @@ func (k *kataAgent) installReqFunc(c *kataclient.AgentClient) {
k.reqHandlers["grpc.GuestDetailsRequest"] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
return k.client.GetGuestDetails(ctx, req.(*grpc.GuestDetailsRequest), opts...)
}
k.reqHandlers["grpc.CopyFileRequest"] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
return k.client.CopyFile(ctx, req.(*grpc.CopyFileRequest), opts...)
}
k.reqHandlers["grpc.SetGuestDateTimeRequest"] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
return k.client.SetGuestDateTime(ctx, req.(*grpc.SetGuestDateTimeRequest), opts...)
}
Expand Down Expand Up @@ -1708,3 +1714,56 @@ func (k *kataAgent) convertToRoutes(aRoutes []*aTypes.Route) (routes []*types.Ro

return routes
}

func (k *kataAgent) copyFile(src, dst string) error {
var st unix.Stat_t

err := unix.Stat(src, &st)
if err != nil {
return fmt.Errorf("Could not get file %s information: %v", src, err)
}

b, err := ioutil.ReadFile(src)
if err != nil {
return fmt.Errorf("Could not read file %s: %v", src, err)
}

fileSize := int64(len(b))

k.Logger().WithFields(logrus.Fields{
"source": src,
"dest": dst,
}).Debugf("Copying file from host to guest")

cpReq := &grpc.CopyFileRequest{
Path: dst,
DirMode: uint32(dirMode),
FileMode: st.Mode,
FileSize: fileSize,
Uid: int32(st.Uid),
Gid: int32(st.Gid),
}

// Copy file by parts if it's needed
remainingBytes := fileSize
offset := int64(0)
for remainingBytes > 0 {
bytesToCopy := int64(len(b))
if bytesToCopy > grpcMaxDataSize {
bytesToCopy = grpcMaxDataSize
}

cpReq.Data = b[:bytesToCopy]
cpReq.Offset = offset

if _, err = k.sendReq(cpReq); err != nil {
return fmt.Errorf("Could not send CopyFile request: %v", err)
}

b = b[bytesToCopy:]
remainingBytes -= bytesToCopy
offset += grpcMaxDataSize
}

return nil
}
56 changes: 56 additions & 0 deletions virtcontainers/kata_agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,10 @@ func (p *gRPCProxy) SetGuestDateTime(ctx context.Context, req *pb.SetGuestDateTi
return &gpb.Empty{}, nil
}

func (p *gRPCProxy) CopyFile(ctx context.Context, req *pb.CopyFileRequest) (*gpb.Empty, error) {
return &gpb.Empty{}, nil
}

func gRPCRegister(s *grpc.Server, srv interface{}) {
switch g := srv.(type) {
case *gRPCProxy:
Expand Down Expand Up @@ -844,3 +848,55 @@ func TestKataGetAgentUrl(t *testing.T) {
assert.NotEmpty(url)

}

func TestKataCopyFile(t *testing.T) {
assert := assert.New(t)

impl := &gRPCProxy{}

proxy := mock.ProxyGRPCMock{
GRPCImplementer: impl,
GRPCRegister: gRPCRegister,
}

sockDir, err := testGenerateKataProxySockDir()
assert.NoError(err)
defer os.RemoveAll(sockDir)

testKataProxyURL := fmt.Sprintf(testKataProxyURLTempl, sockDir)
err = proxy.Start(testKataProxyURL)
assert.NoError(err)
defer proxy.Stop()

k := &kataAgent{
state: KataAgentState{
URL: testKataProxyURL,
},
}

err = k.copyFile("/abc/xyz/123", "/tmp")
assert.Error(err)

src, err := ioutil.TempFile("", "src")
assert.NoError(err)
defer os.Remove(src.Name())

data := []byte("abcdefghi123456789")
_, err = src.Write(data)
assert.NoError(err)
assert.NoError(src.Close())

dst, err := ioutil.TempFile("", "dst")
assert.NoError(err)
assert.NoError(dst.Close())
defer os.Remove(dst.Name())

orgGrpcMaxDataSize := grpcMaxDataSize
grpcMaxDataSize = 1
defer func() {
grpcMaxDataSize = orgGrpcMaxDataSize
}()

err = k.copyFile(src.Name(), dst.Name())
assert.NoError(err)
}
5 changes: 5 additions & 0 deletions virtcontainers/noop_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,8 @@ func (n *noopAgent) getGuestDetails(*grpc.GuestDetailsRequest) (*grpc.GuestDetai
func (n *noopAgent) setGuestDateTime(time.Time) error {
return nil
}

// copyFile is the Noop agent copy file. It does nothing.
func (n *noopAgent) copyFile(src, dst string) error {
return nil
}
8 changes: 8 additions & 0 deletions virtcontainers/noop_agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,11 @@ func TestNoopGetAgentUrl(t *testing.T) {
assert.Nil(err)
assert.Empty(url)
}

func TestNoopCopyFile(t *testing.T) {
assert := assert.New(t)
n := &noopAgent{}

err := n.copyFile("", "")
assert.Nil(err)
}

0 comments on commit 6291762

Please sign in to comment.