veyron/lib/binary: binary repository client-side library
Change-Id: I7306eefbfe73fa1fbb49160190b818cfc509565d
diff --git a/lib/testutil/blackbox/subprocess.go b/lib/testutil/blackbox/subprocess.go
index 8c7b655..0cb8092 100644
--- a/lib/testutil/blackbox/subprocess.go
+++ b/lib/testutil/blackbox/subprocess.go
@@ -81,11 +81,11 @@
stdout, _ := cmd.StdoutPipe()
stdin, _ := cmd.StdinPipe()
return &Child{
- Cmd: cmd,
- Name: command,
- Stdout: bufio.NewReader(stdout),
- Stdin: stdin,
- stderr: stderr,
+ Cmd: cmd,
+ Name: command,
+ Stdout: bufio.NewReader(stdout),
+ Stdin: stdin,
+ stderr: stderr,
t: t,
hasFailed: false,
}
diff --git a/runtimes/google/ipc/full_test.go b/runtimes/google/ipc/full_test.go
index 66e1cc7..dcf068e 100644
--- a/runtimes/google/ipc/full_test.go
+++ b/runtimes/google/ipc/full_test.go
@@ -38,10 +38,10 @@
var (
errAuthorizer = errors.New("ipc: application Authorizer denied access")
- errMethod = verror.Abortedf("server returned an error")
- clientID security.PrivateID
- serverID security.PrivateID
- clock = new(fakeClock)
+ errMethod = verror.Abortedf("server returned an error")
+ clientID security.PrivateID
+ serverID security.PrivateID
+ clock = new(fakeClock)
)
type fakeClock struct {
diff --git a/services/mgmt/binary/binaryd/main.go b/services/mgmt/binary/binaryd/main.go
index bb59019..1ea4203 100644
--- a/services/mgmt/binary/binaryd/main.go
+++ b/services/mgmt/binary/binaryd/main.go
@@ -84,7 +84,6 @@
return
}
vlog.Infof("Binary repository published at %v/%v", endpoint, name)
-
// Wait until shutdown.
<-signals.ShutdownOnSignals()
}
diff --git a/services/mgmt/lib/binary/impl.go b/services/mgmt/lib/binary/impl.go
new file mode 100644
index 0000000..357c5d0
--- /dev/null
+++ b/services/mgmt/lib/binary/impl.go
@@ -0,0 +1,276 @@
+// Package binary provides a client-side library for the binary
+// repository.
+//
+// TODO(jsimsa): Implement parallel download and upload.
+package binary
+
+import (
+ "bytes"
+ "crypto/md5"
+ "encoding/hex"
+ "io"
+ "io/ioutil"
+ "os"
+
+ "veyron2/rt"
+ "veyron2/services/mgmt/binary"
+ "veyron2/services/mgmt/repository"
+ "veyron2/verror"
+ "veyron2/vlog"
+)
+
+var (
+ errOperationFailed = verror.Internalf("operation failed")
+ errNotExist = verror.NotFoundf("binary does not exist")
+)
+
+const (
+ nAttempts = 2
+ partSize = 1 << 22
+ subpartSize = 1 << 12
+)
+
+func Delete(name string) error {
+ client, err := repository.BindBinary(name)
+ if err != nil {
+ vlog.Errorf("BindBinary(%v) failed: %v", name, err)
+ return err
+ }
+ if err := client.Delete(rt.R().NewContext()); err != nil {
+ vlog.Errorf("Delete() failed: %v", err)
+ return err
+ }
+ return nil
+}
+
+func download(w io.WriteSeeker, von string) error {
+ client, err := repository.BindBinary(von)
+ if err != nil {
+ vlog.Errorf("BindBinary(%v) failed: %v", von, err)
+ return err
+ }
+ parts, err := client.Stat(rt.R().NewContext())
+ if err != nil {
+ vlog.Errorf("Stat() failed: %v", err)
+ return err
+ }
+ for _, part := range parts {
+ if part.Checksum == binary.MissingChecksum {
+ return errNotExist
+ }
+ }
+ offset, whence := int64(0), 0
+ for i, part := range parts {
+ success := false
+ download:
+ for j := 0; !success && j < nAttempts; j++ {
+ if _, err := w.Seek(offset, whence); err != nil {
+ vlog.Errorf("Seek(%v, %v) failed: %v", offset, whence, err)
+ continue
+ }
+ stream, err := client.Download(rt.R().NewContext(), int32(i))
+ if err != nil {
+ vlog.Errorf("Download(%v) failed: %v", i, err)
+ continue
+ }
+ h, nreceived := md5.New(), 0
+ for {
+ bytes, err := stream.Recv()
+ if err != nil {
+ if err != io.EOF {
+ vlog.Errorf("Recv() failed: %v", err)
+ stream.Cancel()
+ continue download
+ }
+ break
+ }
+ if _, err := w.Write(bytes); err != nil {
+ vlog.Errorf("Write() failed: %v", err)
+ stream.Cancel()
+ continue download
+ }
+ h.Write(bytes)
+ nreceived += len(bytes)
+ }
+ if err := stream.Finish(); err != nil {
+ vlog.Errorf("Finish() failed: %v", err)
+ continue
+ }
+ if expected, got := part.Checksum, hex.EncodeToString(h.Sum(nil)); expected != got {
+ vlog.Errorf("Unexpected checksum: expected %v, got %v", expected, got)
+ continue
+ }
+ if expected, got := part.Size, int64(nreceived); expected != got {
+ vlog.Errorf("Unexpected size: expected %v, got %v", expected, got)
+ continue
+ }
+ success = true
+ }
+ if !success {
+ return errOperationFailed
+ }
+ offset += part.Size
+ }
+ return nil
+}
+
+func Download(von string) ([]byte, error) {
+ dir, prefix := "", ""
+ file, err := ioutil.TempFile(dir, prefix)
+ if err != nil {
+ vlog.Errorf("TempFile(%v, %v) failed: %v", dir, prefix, err)
+ return nil, errOperationFailed
+ }
+ defer os.Remove(file.Name())
+ defer file.Close()
+ if err := download(file, von); err != nil {
+ return nil, errOperationFailed
+ }
+ bytes, err := ioutil.ReadFile(file.Name())
+ if err != nil {
+ vlog.Errorf("ReadFile(%v) failed: %v", file.Name(), err)
+ return nil, errOperationFailed
+ }
+ return bytes, nil
+}
+
+func DownloadToFile(von, path string) error {
+ dir, prefix := "", ""
+ file, err := ioutil.TempFile(dir, prefix)
+ if err != nil {
+ vlog.Errorf("TempFile(%v, %v) failed: %v", dir, prefix, err)
+ return errOperationFailed
+ }
+ defer file.Close()
+ if err := download(file, von); err != nil {
+ if err := os.Remove(file.Name()); err != nil {
+ vlog.Errorf("Remove(%v) failed: %v", file.Name(), err)
+ }
+ return errOperationFailed
+ }
+ perm := os.FileMode(0700)
+ if err := file.Chmod(perm); err != nil {
+ vlog.Errorf("Chmod(%v) failed: %v", perm, err)
+ if err := os.Remove(file.Name()); err != nil {
+ vlog.Errorf("Remove(%v) failed: %v", file.Name(), err)
+ }
+ return errOperationFailed
+ }
+ if err := os.Rename(file.Name(), path); err != nil {
+ vlog.Errorf("Rename(%v, %v) failed: %v", file.Name(), path, err)
+ if err := os.Remove(file.Name()); err != nil {
+ vlog.Errorf("Remove(%v) failed: %v", file.Name(), err)
+ }
+ return errOperationFailed
+ }
+ return nil
+}
+
+func upload(r io.ReadSeeker, von string) error {
+ client, err := repository.BindBinary(von)
+ if err != nil {
+ vlog.Errorf("BindBinary(%v) failed: %v", von, err)
+ return err
+ }
+ offset, whence := int64(0), 2
+ size, err := r.Seek(offset, whence)
+ if err != nil {
+ vlog.Errorf("Seek(%v, %v) failed: %v", offset, whence, err)
+ return errOperationFailed
+ }
+ nparts := (size-1)/partSize + 1
+ if err := client.Create(rt.R().NewContext(), int32(nparts)); err != nil {
+ vlog.Errorf("Create() failed: %v", err)
+ return err
+ }
+ for i := 0; int64(i) < nparts; i++ {
+ success := false
+ upload:
+ for j := 0; !success && j < nAttempts; j++ {
+ offset, whence := int64(i*partSize), 0
+ if _, err := r.Seek(offset, whence); err != nil {
+ vlog.Errorf("Seek(%v, %v) failed: %v", offset, whence, err)
+ continue
+ }
+ stream, err := client.Upload(rt.R().NewContext(), int32(i))
+ if err != nil {
+ vlog.Errorf("Upload(%v) failed: %v", i, err)
+ continue
+ }
+ buffer := make([]byte, partSize)
+ if int64(i+1) == nparts {
+ buffer = buffer[:(size % partSize)]
+ }
+ nread := 0
+ for nread < len(buffer) {
+ n, err := r.Read(buffer[nread:])
+ nread += n
+ if err != nil && (err != io.EOF || nread < len(buffer)) {
+ vlog.Errorf("Read() failed: %v", err)
+ stream.Cancel()
+ continue upload
+ }
+ }
+ for from := 0; from < len(buffer); from += subpartSize {
+ to := from + subpartSize
+ if to > len(buffer) {
+ to = len(buffer)
+ }
+ if err := stream.Send(buffer[from:to]); err != nil {
+ vlog.Errorf("Send() failed: %v", err)
+ stream.Cancel()
+ continue upload
+ }
+ }
+ if err := stream.CloseSend(); err != nil {
+ vlog.Errorf("CloseSend() failed: %v", err)
+ parts, statErr := client.Stat(rt.R().NewContext())
+ if statErr != nil {
+ vlog.Errorf("Stat() failed: %v", statErr)
+ if deleteErr := client.Delete(rt.R().NewContext()); err != nil {
+ vlog.Errorf("Delete() failed: %v", deleteErr)
+ }
+ return err
+ }
+ if parts[i].Checksum == binary.MissingChecksum {
+ stream.Cancel()
+ continue
+ }
+ }
+ if err := stream.Finish(); err != nil {
+ vlog.Errorf("Finish() failed: %v", err)
+ parts, statErr := client.Stat(rt.R().NewContext())
+ if statErr != nil {
+ vlog.Errorf("Stat() failed: %v", statErr)
+ if deleteErr := client.Delete(rt.R().NewContext()); err != nil {
+ vlog.Errorf("Delete() failed: %v", deleteErr)
+ }
+ return err
+ }
+ if parts[i].Checksum == binary.MissingChecksum {
+ continue
+ }
+ }
+ success = true
+ }
+ if !success {
+ return errOperationFailed
+ }
+ }
+ return nil
+}
+
+func Upload(von string, data []byte) error {
+ buffer := bytes.NewReader(data)
+ return upload(buffer, von)
+}
+
+func UploadFromFile(von, path string) error {
+ file, err := os.Open(path)
+ defer file.Close()
+ if err != nil {
+ vlog.Errorf("Open(%v) failed: %v", err)
+ return errOperationFailed
+ }
+ return upload(file, von)
+}
diff --git a/services/mgmt/lib/binary/impl_test.go b/services/mgmt/lib/binary/impl_test.go
new file mode 100644
index 0000000..e99c693
--- /dev/null
+++ b/services/mgmt/lib/binary/impl_test.go
@@ -0,0 +1,135 @@
+package binary
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "testing"
+
+ "veyron/lib/testutil"
+ "veyron/services/mgmt/binary/impl"
+
+ "veyron2/naming"
+ "veyron2/rt"
+ "veyron2/vlog"
+)
+
+const (
+ veyronPrefix = "veyron_binary_repository"
+)
+
+func init() {
+ rt.Init()
+}
+
+func setupRepository(t *testing.T) (string, func()) {
+ // Setup the root of the binary repository.
+ root, err := ioutil.TempDir("", veyronPrefix)
+ if err != nil {
+ t.Fatalf("TempDir() failed: %v", err)
+ }
+ path, perm := filepath.Join(root, impl.VersionFile), os.FileMode(0600)
+ if err := ioutil.WriteFile(path, []byte(impl.Version), perm); err != nil {
+ vlog.Fatalf("WriteFile(%v, %v, %v) failed: %v", path, impl.Version, perm, err)
+ }
+ // Setup and start the binary repository server.
+ server, err := rt.R().NewServer()
+ if err != nil {
+ t.Fatalf("NewServer() failed: %v", err)
+ }
+ depth := 2
+ dispatcher, err := impl.NewDispatcher(root, depth, nil)
+ if err != nil {
+ t.Fatalf("NewDispatcher(%v, %v, %v) failed: %v", root, depth, nil, err)
+ }
+ protocol, hostname := "tcp", "localhost:0"
+ endpoint, err := server.Listen(protocol, hostname)
+ if err != nil {
+ t.Fatalf("Listen(%v, %v) failed: %v", protocol, hostname, err)
+ }
+ suffix := ""
+ if err := server.Serve(suffix, dispatcher); err != nil {
+ t.Fatalf("Serve(%v, %v) failed: %v", suffix, dispatcher, err)
+ }
+ von := naming.JoinAddressName(endpoint.String(), "//test")
+ return von, func() {
+ if err := os.Remove(path); err != nil {
+ t.Fatalf("Remove(%v) failed: %v", path, err)
+ }
+ // Check that any directories and files that were created to
+ // represent the binary objects have been garbage collected.
+ if err := os.Remove(root); err != nil {
+ t.Fatalf("Remove(%v) failed: %v", root, err)
+ }
+ // Shutdown the binary repository server.
+ if err := server.Stop(); err != nil {
+ t.Fatalf("Stop() failed: %v", err)
+ }
+ }
+}
+
+// TestBufferAPI tests the binary repository client-side library
+// interface using buffers.
+func TestBufferAPI(t *testing.T) {
+ von, cleanup := setupRepository(t)
+ defer cleanup()
+ data := testutil.RandomBytes(testutil.Rand.Intn(10 << 20))
+ if err := Upload(von, data); err != nil {
+ t.Fatalf("Upload(%v) failed: %v", von, err)
+ }
+ output, err := Download(von)
+ if err != nil {
+ t.Fatalf("Download(%v) failed: %v", von, err)
+ }
+ if bytes.Compare(data, output) != 0 {
+ t.Fatalf("Data mismatch:\nexpected %v %v\ngot %v %v", len(data), data[:100], len(output), output[:100])
+ }
+ if err := Delete(von); err != nil {
+ t.Fatalf("Delete(%v) failed: %v", von, err)
+ }
+ if _, err := Download(von); err == nil {
+ t.Fatalf("Download(%v) did not fail", von)
+ }
+}
+
+// TestFileAPI tests the binary repository client-side library
+// interface using files.
+func TestFileAPI(t *testing.T) {
+ von, cleanup := setupRepository(t)
+ defer cleanup()
+ // Create up to 10MB of random bytes.
+ data := testutil.RandomBytes(testutil.Rand.Intn(10 << 20))
+ dir, prefix := "", ""
+ src, err := ioutil.TempFile(dir, prefix)
+ if err != nil {
+ t.Fatalf("TempFile(%v, %v) failed: %v", dir, prefix, err)
+ }
+ defer os.Remove(src.Name())
+ defer src.Close()
+ dst, err := ioutil.TempFile(dir, prefix)
+ if err != nil {
+ t.Fatalf("TempFile(%v, %v) failed: %v", dir, prefix, err)
+ }
+ defer os.Remove(dst.Name())
+ defer dst.Close()
+ if _, err := src.Write(data); err != nil {
+ t.Fatalf("Write() failed: %v", err)
+ }
+ if err := UploadFromFile(von, src.Name()); err != nil {
+ t.Fatalf("UploadFromFile(%v, %v) failed: %v", von, src.Name(), err)
+ }
+ if err := DownloadToFile(von, dst.Name()); err != nil {
+ t.Fatalf("DownloadToFile(%v, %v) failed: %v", von, dst.Name(), err)
+ }
+ output, err := ioutil.ReadFile(dst.Name())
+ if err != nil {
+ t.Fatalf("ReadFile(%v) failed: %v", dst.Name(), err)
+ }
+ if bytes.Compare(data, output) != 0 {
+ t.Fatalf("Data mismatch:\nexpected %v %v\ngot %v %v", len(data), data[:100], len(output), output[:100])
+ }
+ if err := Delete(von); err != nil {
+ t.Fatalf("Delete(%v) failed: %v", von, err)
+ }
+}
diff --git a/services/mgmt/node/impl/impl_test.go b/services/mgmt/node/impl/impl_test.go
index f944877..a903c63 100644
--- a/services/mgmt/node/impl/impl_test.go
+++ b/services/mgmt/node/impl/impl_test.go
@@ -1,6 +1,8 @@
package impl_test
import (
+ "crypto/md5"
+ "encoding/hex"
"errors"
"fmt"
"io"
@@ -119,7 +121,14 @@
func (*crInvoker) Stat(ipc.ServerContext) ([]binary.PartInfo, error) {
vlog.VI(0).Infof("Stat()")
- return make([]binary.PartInfo, 1), nil
+ h := md5.New()
+ bytes, err := ioutil.ReadFile(os.Args[0])
+ if err != nil {
+ return []binary.PartInfo{}, errOperationFailed
+ }
+ h.Write(bytes)
+ part := binary.PartInfo{Checksum: hex.EncodeToString(h.Sum(nil)), Size: int64(len(bytes))}
+ return []binary.PartInfo{part}, nil
}
func (i *crInvoker) Upload(ipc.ServerContext, int32, repository.BinaryServiceUploadStream) error {
diff --git a/services/mgmt/node/impl/invoker.go b/services/mgmt/node/impl/invoker.go
index 72c3186..c6ca55d 100644
--- a/services/mgmt/node/impl/invoker.go
+++ b/services/mgmt/node/impl/invoker.go
@@ -28,7 +28,6 @@
"bytes"
"errors"
"fmt"
- "io"
"io/ioutil"
"math/rand"
"os"
@@ -44,6 +43,7 @@
"veyron/lib/config"
vexec "veyron/lib/exec"
ibuild "veyron/services/mgmt/build"
+ "veyron/services/mgmt/lib/binary"
"veyron/services/mgmt/profile"
"veyron2/ipc"
@@ -330,55 +330,15 @@
// APPLICATION INTERFACE IMPLEMENTATION
-func downloadBinary(workspace, binary string) error {
- stub, err := repository.BindBinary(binary)
+func downloadBinary(workspace, name string) error {
+ data, err := binary.Download(name)
if err != nil {
- vlog.Errorf("BindBinary(%q) failed: %v", binary, err)
+ vlog.Errorf("Download(%v) failed: %v", name, err)
return errOperationFailed
}
- path := filepath.Join(workspace, "noded")
- file, err := os.Create(path)
- if err != nil {
- vlog.Errorf("Create(%q) failed: %v", path, err)
- return errOperationFailed
- }
- defer file.Close()
- parts, err := stub.Stat(rt.R().NewContext())
- if err != nil {
- vlog.Errorf("Stat() failed: %v", err)
- return errOperationFailed
- }
- // TODO(jsimsa): Replace the code below with a call to a client-side
- // binary library once this library exists. In particular, we should
- // take care of resumption and consistency checking.
- for i := 0; i < len(parts); i++ {
- stream, err := stub.Download(rt.R().NewContext(), int32(i))
- if err != nil {
- vlog.Errorf("Download() failed: %v", err)
- return errOperationFailed
- }
- for {
- bytes, err := stream.Recv()
- if err == io.EOF {
- break
- }
- if err != nil {
- vlog.Errorf("Recv() failed: %v", err)
- return errOperationFailed
- }
- if _, err := file.Write(bytes); err != nil {
- vlog.Errorf("Write() failed: %v", err)
- return errOperationFailed
- }
- }
- if err := stream.Finish(); err != nil {
- vlog.Errorf("Finish() failed: %v", err)
- return errOperationFailed
- }
- }
- mode := os.FileMode(0755)
- if err := file.Chmod(mode); err != nil {
- vlog.Errorf("Chmod(%v) failed: %v", mode, err)
+ path, perm := filepath.Join(workspace, "noded"), os.FileMode(755)
+ if err := ioutil.WriteFile(path, data, perm); err != nil {
+ vlog.Errorf("WriteFile(%v, %v) failed: %v", path, perm, err)
return errOperationFailed
}
return nil
diff --git a/tools/binary/impl/impl.go b/tools/binary/impl/impl.go
index d4d205f..29b26b1 100644
--- a/tools/binary/impl/impl.go
+++ b/tools/binary/impl/impl.go
@@ -2,13 +2,9 @@
import (
"fmt"
- "io"
- "os"
"veyron/lib/cmdline"
-
- "veyron2/rt"
- "veyron2/services/mgmt/repository"
+ "veyron/services/mgmt/lib/binary"
)
var cmdDelete = &cmdline.Command{
@@ -16,21 +12,16 @@
Name: "delete",
Short: "Delete binary",
Long: "Delete connects to the binary repository and deletes the specified binary",
- ArgsName: "<binary>",
- ArgsLong: "<binary> is the object name of the binary to delete",
+ ArgsName: "<von>",
+ ArgsLong: "<von> is the veyron object name of the binary to delete",
}
func runDelete(cmd *cmdline.Command, args []string) error {
if expected, got := 1, len(args); expected != got {
return cmd.Errorf("delete: incorrect number of arguments, expected %d, got %d", expected, got)
}
- binary := args[0]
-
- c, err := repository.BindBinary(binary)
- if err != nil {
- return fmt.Errorf("bind error: %v", err)
- }
- if err = c.Delete(rt.R().NewContext()); err != nil {
+ von := args[0]
+ if err := binary.Delete(von); err != nil {
return err
}
fmt.Fprintf(cmd.Stdout(), "Binary deleted successfully\n")
@@ -45,9 +36,9 @@
Download connects to the binary repository, downloads the specified binary, and
writes it to a file.
`,
- ArgsName: "<binary> <filename>",
+ ArgsName: "<von> <filename>",
ArgsLong: `
-<binary> is the object name of the binary to download
+<von> is the veyron object name of the binary to download
<filename> is the name of the file where the binary will be written
`,
}
@@ -56,44 +47,10 @@
if expected, got := 2, len(args); expected != got {
return cmd.Errorf("download: incorrect number of arguments, expected %d, got %d", expected, got)
}
- binary, filename := args[0], args[1]
- f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0700)
- if err != nil {
- return fmt.Errorf("failed to open %q: %v", filename, err)
- }
- defer f.Close()
-
- c, err := repository.BindBinary(binary)
- if err != nil {
- return fmt.Errorf("bind error: %v", err)
- }
-
- // TODO(jsimsa): Replace the code below with a call to a client-side
- // binary library once this library exists. In particular, we should
- // take care of resumption and consistency checking.
- stream, err := c.Download(rt.R().NewContext(), 0)
- if err != nil {
+ von, filename := args[0], args[1]
+ if err := binary.DownloadToFile(von, filename); err != nil {
return err
}
-
- for {
- buf, err := stream.Recv()
- if err != nil {
- if err == io.EOF {
- break
- }
- return fmt.Errorf("recv error: %v", err)
- }
- if _, err = f.Write(buf); err != nil {
- return fmt.Errorf("write error: %v", err)
- }
- }
-
- err = stream.Finish()
- if err != nil {
- return fmt.Errorf("finish error: %v", err)
- }
-
fmt.Fprintf(cmd.Stdout(), "Binary downloaded to file %s\n", filename)
return nil
}
@@ -106,9 +63,9 @@
Upload connects to the binary repository and uploads the binary of the specified
file. When successful, it writes the name of the new binary to stdout.
`,
- ArgsName: "<binary> <filename>",
+ ArgsName: "<von> <filename>",
ArgsLong: `
-<binary> is the object name of the binary to upload
+<von> is the veyron object name of the binary to upload
<filename> is the name of the file to upload
`,
}
@@ -117,49 +74,11 @@
if expected, got := 2, len(args); expected != got {
return cmd.Errorf("upload: incorrect number of arguments, expected %d, got %d", expected, got)
}
- binary, filename := args[0], args[1]
- f, err := os.Open(filename)
- if err != nil {
- return fmt.Errorf("failed to open %q: %v", filename, err)
- }
- defer f.Close()
-
- c, err := repository.BindBinary(binary)
- if err != nil {
- return fmt.Errorf("bind error: %v", err)
- }
-
- // TODO(jsimsa): Add support for uploading multi-part binaries.
- if err := c.Create(rt.R().NewContext(), 1); err != nil {
+ von, filename := args[0], args[1]
+ if err := binary.UploadFromFile(von, filename); err != nil {
return err
}
-
- stream, err := c.Upload(rt.R().NewContext(), 0)
- if err != nil {
- return err
- }
-
- var buf [4096]byte
- for {
- n, err := f.Read(buf[:])
- if err != nil {
- if err == io.EOF {
- break
- }
- return fmt.Errorf("read error: %v", err)
- }
- if err := stream.Send(buf[:n]); err != nil {
- return fmt.Errorf("send error: %v", err)
- }
- }
- if err := stream.CloseSend(); err != nil {
- return fmt.Errorf("closesend error: %v", err)
- }
-
- if err := stream.Finish(); err != nil {
- return fmt.Errorf("finish error: %v", err)
- }
-
+ fmt.Fprintf(cmd.Stdout(), "Binary uploaded from file %s\n", filename)
return nil
}
diff --git a/tools/binary/impl/impl_test.go b/tools/binary/impl/impl_test.go
index 70c0122..5589c4a 100644
--- a/tools/binary/impl/impl_test.go
+++ b/tools/binary/impl/impl_test.go
@@ -2,6 +2,8 @@
import (
"bytes"
+ "crypto/md5"
+ "encoding/hex"
"fmt"
"io/ioutil"
"os"
@@ -26,12 +28,12 @@
}
func (s *server) Create(ipc.ServerContext, int32) error {
- vlog.VI(2).Infof("Create() was called. suffix=%v", s.suffix)
+ vlog.Infof("Create() was called. suffix=%v", s.suffix)
return nil
}
func (s *server) Delete(ipc.ServerContext) error {
- vlog.VI(2).Infof("Delete() was called. suffix=%v", s.suffix)
+ vlog.Infof("Delete() was called. suffix=%v", s.suffix)
if s.suffix != "exists" {
return fmt.Errorf("binary doesn't exist: %v", s.suffix)
}
@@ -39,24 +41,28 @@
}
func (s *server) Download(_ ipc.ServerContext, _ int32, stream repository.BinaryServiceDownloadStream) error {
- vlog.VI(2).Infof("Download() was called. suffix=%v", s.suffix)
+ vlog.Infof("Download() was called. suffix=%v", s.suffix)
stream.Send([]byte("Hello"))
stream.Send([]byte("World"))
return nil
}
func (s *server) DownloadURL(ipc.ServerContext) (string, int64, error) {
- vlog.VI(2).Infof("DownloadURL() was called. suffix=%v", s.suffix)
+ vlog.Infof("DownloadURL() was called. suffix=%v", s.suffix)
return "", 0, nil
}
func (s *server) Stat(ipc.ServerContext) ([]binary.PartInfo, error) {
- vlog.VI(2).Infof("Stat() was called. suffix=%v", s.suffix)
- return []binary.PartInfo{}, nil
+ vlog.Infof("Stat() was called. suffix=%v", s.suffix)
+ h := md5.New()
+ text := "HelloWorld"
+ h.Write([]byte(text))
+ part := binary.PartInfo{Checksum: hex.EncodeToString(h.Sum(nil)), Size: int64(len(text))}
+ return []binary.PartInfo{part}, nil
}
func (s *server) Upload(_ ipc.ServerContext, _ int32, stream repository.BinaryServiceUploadStream) error {
- vlog.VI(2).Infof("Upload() was called. suffix=%v", s.suffix)
+ vlog.Infof("Upload() was called. suffix=%v", s.suffix)
for {
if _, err := stream.Recv(); err != nil {
break
diff --git a/tools/playground/compilerd/main.go b/tools/playground/compilerd/main.go
index b565ae3..83f778e 100644
--- a/tools/playground/compilerd/main.go
+++ b/tools/playground/compilerd/main.go
@@ -29,7 +29,7 @@
func healthz(w http.ResponseWriter, r *http.Request) {
select {
- case <- lameduck:
+ case <-lameduck:
w.WriteHeader(http.StatusInternalServerError)
default:
w.Write([]byte("OK"))