Merge "veyron/tools/mgmt/nodex: Code cleanup."
diff --git a/runtimes/google/ipc/benchmarks/bmclient/main.go b/runtimes/google/ipc/benchmarks/bmclient/main.go
index 874afb2..03bd219 100644
--- a/runtimes/google/ipc/benchmarks/bmclient/main.go
+++ b/runtimes/google/ipc/benchmarks/bmclient/main.go
@@ -18,13 +18,16 @@
)
func main() {
- r := rt.Init()
- defer r.Cleanup()
+ runtime, err := rt.New()
+ if err != nil {
+ panic(err)
+ }
+ defer runtime.Cleanup()
- ctx := r.NewContext()
+ ctx := runtime.NewContext()
if *chunkCount == 0 {
benchmarks.CallEcho(ctx, *server, *count, *payloadSize, os.Stdout)
} else {
- benchmarks.CallEchoStream(*server, *count, *chunkCount, *payloadSize, os.Stdout)
+ benchmarks.CallEchoStream(runtime, *server, *count, *chunkCount, *payloadSize, os.Stdout)
}
}
diff --git a/runtimes/google/ipc/benchmarks/client.go b/runtimes/google/ipc/benchmarks/client.go
index 1ed3a21..b9fe30c 100644
--- a/runtimes/google/ipc/benchmarks/client.go
+++ b/runtimes/google/ipc/benchmarks/client.go
@@ -6,8 +6,8 @@
"io"
"time"
+ "veyron.io/veyron/veyron2"
"veyron.io/veyron/veyron2/context"
- "veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron2/vlog"
)
@@ -39,7 +39,7 @@
// CallEchoStream calls the EchoStream method 'rpcCount' times. Each iteration
// sends 'messageCount' messages on the stream and receives the same number
// back. Each message has the given payload size. Optionally logs the result.
-func CallEchoStream(address string, rpcCount, messageCount, payloadSize int, log io.Writer) {
+func CallEchoStream(runtime veyron2.Runtime, address string, rpcCount, messageCount, payloadSize int, log io.Writer) {
payload := make([]byte, payloadSize)
for _, i := range payload {
payload[i] = byte(i & 0xff)
@@ -48,7 +48,7 @@
stub := BenchmarkClient(address)
for i := 0; i < rpcCount; i++ {
start := time.Now()
- ctx, _ := rt.R().NewContext().WithTimeout(time.Hour)
+ ctx, _ := runtime.NewContext().WithTimeout(time.Hour)
stream, err := stub.EchoStream(ctx)
if err != nil {
vlog.Fatalf("EchoStream failed: %v", err)
diff --git a/runtimes/google/ipc/benchmarks/ipc_test.go b/runtimes/google/ipc/benchmarks/ipc_test.go
index 9397219..bfd14ad 100644
--- a/runtimes/google/ipc/benchmarks/ipc_test.go
+++ b/runtimes/google/ipc/benchmarks/ipc_test.go
@@ -3,13 +3,22 @@
import (
"testing"
+ "veyron.io/veyron/veyron2"
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron/profiles"
"veyron.io/veyron/veyron/runtimes/google/ipc/benchmarks"
)
-var runtime = rt.Init()
+var runtime veyron2.Runtime
+
+func init() {
+ var err error
+ runtime, err = rt.New()
+ if err != nil {
+ panic(err)
+ }
+}
func RunBenchmark(b *testing.B, payloadSize int) {
address, stop := benchmarks.StartServer(runtime, profiles.LocalListenSpec)
@@ -23,9 +32,9 @@
func RunStreamBenchmark(b *testing.B, rpcCount, messageCount, payloadSize int) {
address, stop := benchmarks.StartServer(runtime, profiles.LocalListenSpec)
defer stop()
- benchmarks.CallEchoStream(address, 1, 1, 1, nil) // Create VC
+ benchmarks.CallEchoStream(runtime, address, 1, 1, 1, nil) // Create VC
b.ResetTimer()
- benchmarks.CallEchoStream(address, rpcCount, messageCount, payloadSize, nil)
+ benchmarks.CallEchoStream(runtime, address, rpcCount, messageCount, payloadSize, nil)
}
func Benchmark____1B(b *testing.B) {
diff --git a/runtimes/google/ipc/signature_test.go b/runtimes/google/ipc/signature_test.go
index 8f65a2e..4ffcb7e 100644
--- a/runtimes/google/ipc/signature_test.go
+++ b/runtimes/google/ipc/signature_test.go
@@ -17,8 +17,8 @@
func init() { testutil.Init() }
-func startSigServer(rt veyron2.Runtime, sig sigImpl) (string, func(), error) {
- server, err := rt.NewServer()
+func startSigServer(runtime veyron2.Runtime, sig sigImpl) (string, func(), error) {
+ server, err := runtime.NewServer()
if err != nil {
return "", nil, fmt.Errorf("failed to start sig server: %v", err)
}
@@ -41,7 +41,10 @@
// support for typeobject and encoding *vdl.Type. Re-enable this test when we
// have vom2 optionally enabled in our stack.
func disabledTestMethodSignature(t *testing.T) {
- runtime := rt.Init()
+ runtime, err := rt.New()
+ if err != nil {
+ t.Fatalf("Couldn't initialize runtime: %s", err)
+ }
defer runtime.Cleanup()
ep, stop, err := startSigServer(runtime, sigImpl{})
@@ -60,7 +63,7 @@
}
for _, test := range tests {
name := naming.JoinAddressName(ep, "")
- sig, err := reserved.MethodSignature(rt.R().NewContext(), name, test.Method)
+ sig, err := reserved.MethodSignature(runtime.NewContext(), name, test.Method)
if err != nil {
t.Errorf("call failed: %v", err)
}
diff --git a/services/identity/identityd/main.go b/services/identity/identityd/main.go
index 5e9f3dc..ccce46f 100644
--- a/services/identity/identityd/main.go
+++ b/services/identity/identityd/main.go
@@ -76,8 +76,11 @@
}
p, blessingLogReader := providerPrincipal(sqlDB)
- r := rt.Init(options.RuntimePrincipal{p})
- defer r.Cleanup()
+ runtime, err := rt.New(options.RuntimePrincipal{p})
+ if err != nil {
+ vlog.Fatal(err)
+ }
+ defer runtime.Cleanup()
var revocationManager *revocation.RevocationManager
// Only set revocationManager sqlConfig (and thus sqlDB) is set.
@@ -89,13 +92,13 @@
}
// Setup handlers
- http.Handle("/pubkey/", handlers.PublicKey{r.Principal().PublicKey()}) // public key of this server
+ http.Handle("/pubkey/", handlers.PublicKey{runtime.Principal().PublicKey()}) // public key of this server
macaroonKey := make([]byte, 32)
if _, err := rand.Read(macaroonKey); err != nil {
vlog.Fatalf("macaroonKey generation failed: %v", err)
}
// Google OAuth
- ipcServer, published, err := setupServices(r, revocationManager, macaroonKey)
+ ipcServer, published, err := setupServices(runtime, revocationManager, macaroonKey)
if err != nil {
vlog.Fatalf("Failed to setup veyron services for blessing: %v", err)
}
@@ -103,7 +106,7 @@
if clientID, clientSecret, ok := getOAuthClientIDAndSecret(*googleConfigWeb); ok {
n := "/google/"
h, err := googleoauth.NewHandler(googleoauth.HandlerArgs{
- R: r,
+ R: runtime,
MacaroonKey: macaroonKey,
Addr: fmt.Sprintf("%s%s", httpaddress(), n),
ClientID: clientID,
@@ -124,7 +127,7 @@
GoogleServers, DischargeServers []string
ListBlessingsRoute string
}{
- Self: rt.R().Principal().BlessingStore().Default(),
+ Self: runtime.Principal().BlessingStore().Default(),
RandomWeb: enableRandomHandler(),
}
if revocationManager != nil {
@@ -142,7 +145,7 @@
})
vlog.Infof("Running HTTP server at: %v", httpaddress())
go runHTTPSServer(*httpaddr)
- <-signals.ShutdownOnSignals(r)
+ <-signals.ShutdownOnSignals(runtime)
}
func appendSuffixTo(objectname []string, suffix string) []string {
diff --git a/services/identity/revocation/revocation_test.go b/services/identity/revocation/revocation_test.go
index 171d036..bb251fe 100644
--- a/services/identity/revocation/revocation_test.go
+++ b/services/identity/revocation/revocation_test.go
@@ -46,8 +46,7 @@
return &RevocationManager{}
}
-func revokerSetup(t *testing.T) (dischargerKey security.PublicKey, dischargerEndpoint string, revoker *RevocationManager, closeFunc func(), runtime veyron2.Runtime) {
- r := rt.Init()
+func revokerSetup(t *testing.T, r veyron2.Runtime) (dischargerKey security.PublicKey, dischargerEndpoint string, revoker *RevocationManager, closeFunc func(), runtime veyron2.Runtime) {
revokerService := newRevocationManager(t)
dischargerServer, err := r.NewServer()
if err != nil {
@@ -71,7 +70,13 @@
}
func TestDischargeRevokeDischargeRevokeDischarge(t *testing.T) {
- dcKey, dc, revoker, closeFunc, r := revokerSetup(t)
+ r, err := rt.New()
+ if err != nil {
+ t.Fatalf("Could not initialize runtime: %v", err)
+ }
+ defer r.Cleanup()
+
+ dcKey, dc, revoker, closeFunc, r := revokerSetup(t, r)
defer closeFunc()
discharger := services.DischargerClient(dc)
diff --git a/services/mgmt/binary/binaryd/main.go b/services/mgmt/binary/binaryd/main.go
index d65984f..677e9e7 100644
--- a/services/mgmt/binary/binaryd/main.go
+++ b/services/mgmt/binary/binaryd/main.go
@@ -2,11 +2,9 @@
import (
"flag"
- "io/ioutil"
"net"
"net/http"
"os"
- "path/filepath"
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/rt"
@@ -19,14 +17,11 @@
"veyron.io/veyron/veyron/services/mgmt/binary/impl"
)
-const (
- defaultDepth = 3
- defaultRootPrefix = "veyron_binary_repository"
-)
+const defaultDepth = 3
var (
name = flag.String("name", "", "name to mount the binary repository as")
- root = flag.String("root", "", "root directory for the binary repository")
+ rootFlag = flag.String("root", "", "root directory for the binary repository")
httpAddr = flag.String("http", ":0", "TCP address on which the HTTP server runs")
)
@@ -54,42 +49,16 @@
func main() {
runtime := rt.Init()
defer runtime.Cleanup()
- if *root == "" {
- var err error
- if *root, err = ioutil.TempDir("", defaultRootPrefix); err != nil {
- vlog.Errorf("TempDir() failed: %v\n", err)
- return
- }
- path, perm := filepath.Join(*root, impl.VersionFile), os.FileMode(0600)
- if err := ioutil.WriteFile(path, []byte(impl.Version), perm); err != nil {
- vlog.Errorf("WriteFile(%v, %v, %v) failed: %v", path, impl.Version, perm, err)
- return
- }
- } else {
- _, err := os.Stat(*root)
- switch {
- case err == nil:
- case os.IsNotExist(err):
- perm := os.FileMode(0700)
- if err := os.MkdirAll(*root, perm); err != nil {
- vlog.Errorf("MkdirAll(%v, %v) failed: %v", *root, perm, err)
- return
- }
- path, perm := filepath.Join(*root, impl.VersionFile), os.FileMode(0600)
- if err := ioutil.WriteFile(path, []byte(impl.Version), perm); err != nil {
- vlog.Errorf("WriteFile(%v, %v, %v) failed: %v", path, impl.Version, perm, err)
- return
- }
- default:
- vlog.Errorf("Stat(%v) failed: %v", *root, err)
- return
- }
- }
- vlog.Infof("Binary repository rooted at %v", *root)
-
- state, err := impl.NewState(*root, defaultDepth)
+ root, err := impl.SetupRoot(*rootFlag)
if err != nil {
- vlog.Errorf("NewState(%v, %v) failed: %v", *root, defaultDepth, err)
+ vlog.Errorf("SetupRoot(%q) failed: %v", *rootFlag, err)
+ return
+ }
+ vlog.Infof("Binary repository rooted at %v", root)
+
+ state, err := impl.NewState(root, defaultDepth)
+ if err != nil {
+ vlog.Errorf("NewState(%v, %v) failed: %v", root, defaultDepth, err)
return
}
diff --git a/services/mgmt/binary/impl/setup.go b/services/mgmt/binary/impl/setup.go
new file mode 100644
index 0000000..12e43fa
--- /dev/null
+++ b/services/mgmt/binary/impl/setup.go
@@ -0,0 +1,49 @@
+package impl
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
+ "veyron.io/veyron/veyron2/vlog"
+)
+
+const defaultRootPrefix = "veyron_binary_repository"
+
+// SetupRoot sets up the root directory if it doesn't already exist. If an
+// empty string is used as root, create a new temporary directory.
+func SetupRoot(root string) (string, error) {
+ if root == "" {
+ var err error
+ if root, err = ioutil.TempDir("", defaultRootPrefix); err != nil {
+ vlog.Errorf("TempDir() failed: %v\n", err)
+ return "", err
+ }
+ path, perm := filepath.Join(root, VersionFile), os.FileMode(0600)
+ if err := ioutil.WriteFile(path, []byte(Version), perm); err != nil {
+ vlog.Errorf("WriteFile(%v, %v, %v) failed: %v", path, Version, perm, err)
+ return "", err
+ }
+ return root, nil
+ }
+
+ _, err := os.Stat(root)
+ switch {
+ case err == nil:
+ case os.IsNotExist(err):
+ perm := os.FileMode(0700)
+ if err := os.MkdirAll(root, perm); err != nil {
+ vlog.Errorf("MkdirAll(%v, %v) failed: %v", root, perm, err)
+ return "", err
+ }
+ path, perm := filepath.Join(root, VersionFile), os.FileMode(0600)
+ if err := ioutil.WriteFile(path, []byte(Version), perm); err != nil {
+ vlog.Errorf("WriteFile(%v, %v, %v) failed: %v", path, Version, perm, err)
+ return "", err
+ }
+ default:
+ vlog.Errorf("Stat(%v) failed: %v", root, err)
+ return "", err
+ }
+ return root, nil
+}
diff --git a/services/mgmt/lib/binary/impl.go b/services/mgmt/lib/binary/impl.go
index 07bedd9..b68fe7f 100644
--- a/services/mgmt/lib/binary/impl.go
+++ b/services/mgmt/lib/binary/impl.go
@@ -11,6 +11,7 @@
"io"
"io/ioutil"
"os"
+ "path/filepath"
"time"
"veyron.io/veyron/veyron2/context"
@@ -285,3 +286,16 @@
mediaInfo := packages.MediaInfoForFileName(path)
return upload(ctx, file, mediaInfo, von)
}
+
+func UploadFromDir(ctx context.T, von, sourceDir string) error {
+ dir, err := ioutil.TempDir("", "create-package-")
+ if err != nil {
+ return err
+ }
+ defer os.RemoveAll(dir)
+ zipfile := filepath.Join(dir, "file.zip")
+ if err := packages.CreateZip(zipfile, sourceDir); err != nil {
+ return err
+ }
+ return UploadFromFile(ctx, von, zipfile)
+}
diff --git a/services/mgmt/lib/packages/packages.go b/services/mgmt/lib/packages/packages.go
index 57f9dde..e55374b 100644
--- a/services/mgmt/lib/packages/packages.go
+++ b/services/mgmt/lib/packages/packages.go
@@ -85,6 +85,53 @@
return nil
}
+// CreateZip creates a package from the files in the source directory. The
+// created package is a Zip file.
+func CreateZip(zipFile, sourceDir string) error {
+ z, err := os.OpenFile(zipFile, os.O_CREATE|os.O_WRONLY, os.FileMode(0644))
+ if err != nil {
+ return err
+ }
+ defer z.Close()
+ w := zip.NewWriter(z)
+ if err := filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if sourceDir == path {
+ return nil
+ }
+ fh, err := zip.FileInfoHeader(info)
+ if err != nil {
+ return err
+ }
+ fh.Name, _ = filepath.Rel(sourceDir, path)
+ hdr, err := w.CreateHeader(fh)
+ if err != nil {
+ return err
+ }
+ if !info.IsDir() {
+ content, err := ioutil.ReadFile(path)
+ if err != nil {
+ return err
+ }
+ if _, err = hdr.Write(content); err != nil {
+ return err
+ }
+ }
+ return nil
+ }); err != nil {
+ return err
+ }
+ if err := w.Close(); err != nil {
+ return err
+ }
+ if err := SaveMediaInfo(zipFile, repository.MediaInfo{Type: "application/zip"}); err != nil {
+ return err
+ }
+ return nil
+}
+
func extractZip(zipFile, installDir string) error {
zr, err := zip.OpenReader(zipFile)
if err != nil {
diff --git a/services/mgmt/lib/packages/packages_test.go b/services/mgmt/lib/packages/packages_test.go
index 8182b44..f18e9bc 100644
--- a/services/mgmt/lib/packages/packages_test.go
+++ b/services/mgmt/lib/packages/packages_test.go
@@ -2,7 +2,6 @@
import (
"archive/tar"
- "archive/zip"
"compress/gzip"
"fmt"
"io"
@@ -107,44 +106,8 @@
}
func makeZip(t *testing.T, zipfile, dir string) {
- z, err := os.OpenFile(zipfile, os.O_CREATE|os.O_WRONLY, os.FileMode(0644))
- if err != nil {
- t.Fatalf("os.OpenFile(%q) failed: %v", zipfile, err)
- }
- defer z.Close()
- w := zip.NewWriter(z)
- filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
- if err != nil {
- t.Fatalf("Walk(%q) error: %v", dir, err)
- }
- if dir == path {
- return nil
- }
- fh, err := zip.FileInfoHeader(info)
- if err != nil {
- t.Fatalf("FileInfoHeader failed: %v", err)
- }
- fh.Name, _ = filepath.Rel(dir, path)
- hdr, err := w.CreateHeader(fh)
- if err != nil {
- t.Fatalf("w.CreateHeader failed: %v", err)
- }
- if !info.IsDir() {
- content, err := ioutil.ReadFile(path)
- if err != nil {
- t.Fatalf("ioutil.ReadFile(%q) failed: %v", path, err)
- }
- if _, err = hdr.Write(content); err != nil {
- t.Fatalf("hdr.Write(%q) failed: %v", content, err)
- }
- }
- return nil
- })
- if err := w.Close(); err != nil {
- t.Fatalf("w.Close() failed: %v", err)
- }
- if err := ioutil.WriteFile(zipfile+".__info", []byte(`{"type":"application/zip"}`), os.FileMode(0644)); err != nil {
- t.Fatalf("ioutil.WriteFile() failed: %v", err)
+ if err := packages.CreateZip(zipfile, dir); err != nil {
+ t.Fatalf("packages.CreateZip failed: %v", err)
}
}
diff --git a/services/mgmt/node/impl/impl_test.go b/services/mgmt/node/impl/impl_test.go
index 103b2d4..334814b 100644
--- a/services/mgmt/node/impl/impl_test.go
+++ b/services/mgmt/node/impl/impl_test.go
@@ -47,6 +47,8 @@
"veyron.io/veyron/veyron/lib/signals"
"veyron.io/veyron/veyron/lib/testutil"
tsecurity "veyron.io/veyron/veyron/lib/testutil/security"
+ binaryimpl "veyron.io/veyron/veyron/services/mgmt/binary/impl"
+ libbinary "veyron.io/veyron/veyron/services/mgmt/lib/binary"
"veyron.io/veyron/veyron/services/mgmt/node/config"
"veyron.io/veyron/veyron/services/mgmt/node/impl"
suidhelper "veyron.io/veyron/veyron/services/mgmt/suidhelper/impl"
@@ -214,6 +216,17 @@
return message, nil
}
+func (appService) Cat(_ ipc.ServerContext, file string) (string, error) {
+ if file == "" || file[0] == filepath.Separator || file[0] == '.' {
+ return "", fmt.Errorf("illegal file name: %q", file)
+ }
+ bytes, err := ioutil.ReadFile(file)
+ if err != nil {
+ return "", err
+ }
+ return string(bytes), nil
+}
+
func ping() {
if call, err := rt.R().Client().StartCall(rt.R().NewContext(), "pingserver", "Ping", []interface{}{os.Getenv(suidhelper.SavedArgs)}); err != nil {
vlog.Fatalf("StartCall failed: %v", err)
@@ -222,6 +235,21 @@
}
}
+func cat(name, file string) (string, error) {
+ runtime := rt.R()
+ ctx, cancel := runtime.NewContext().WithTimeout(time.Minute)
+ defer cancel()
+ call, err := runtime.Client().StartCall(ctx, name, "Cat", []interface{}{file})
+ if err != nil {
+ return "", err
+ }
+ var content string
+ if ferr := call.Finish(&content, &err); ferr != nil {
+ err = ferr
+ }
+ return content, err
+}
+
func app(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
args = args[1:]
if expected, got := 1, len(args); expected != got {
@@ -711,6 +739,42 @@
return nil
}
+func startRealBinaryRepository(t *testing.T) func() {
+ root, err := binaryimpl.SetupRoot("")
+ if err != nil {
+ t.Fatalf("binaryimpl.SetupRoot failed: %v", err)
+ }
+ state, err := binaryimpl.NewState(root, 3)
+ if err != nil {
+ t.Fatalf("binaryimpl.NewState failed: %v", err)
+ }
+ server, _ := newServer()
+ name := "realbin"
+ if err := server.ServeDispatcher(name, binaryimpl.NewDispatcher(state, nil)); err != nil {
+ t.Fatalf("server.ServeDispatcher failed: %v", err)
+ }
+
+ tmpdir, err := ioutil.TempDir("", "test-package-")
+ if err != nil {
+ t.Fatalf("ioutil.TempDir failed: %v", err)
+ }
+ defer os.RemoveAll(tmpdir)
+ if err := ioutil.WriteFile(filepath.Join(tmpdir, "hello.txt"), []byte("Hello World!"), 0600); err != nil {
+ t.Fatalf("ioutil.WriteFile failed: %v", err)
+ }
+ if err := libbinary.UploadFromDir(rt.R().NewContext(), naming.Join(name, "testpkg"), tmpdir); err != nil {
+ t.Fatalf("libbinary.UploadFromDir failed: %v", err)
+ }
+ return func() {
+ if err := server.Stop(); err != nil {
+ t.Fatalf("server.Stop failed: %v", err)
+ }
+ if err := os.RemoveAll(root); err != nil {
+ t.Fatalf("os.RemoveAll(%q) failed: %v", root, err)
+ }
+ }
+}
+
// TestNodeManagerClaim claims a nodemanager and tests ACL permissions on its methods.
func TestNodeManagerClaim(t *testing.T) {
sh, deferFn := createShellAndMountTable(t)
@@ -1089,6 +1153,66 @@
}
}
+func TestNodeManagerPackages(t *testing.T) {
+ sh, deferFn := createShellAndMountTable(t)
+ defer deferFn()
+
+ // Set up mock application and binary repositories.
+ envelope, cleanup := startMockRepos(t)
+ defer cleanup()
+
+ defer startRealBinaryRepository(t)()
+
+ root, cleanup := setupRootDir(t)
+ defer cleanup()
+
+ crDir, crEnv := credentialsForChild("nodemanager")
+ defer os.RemoveAll(crDir)
+
+ // Create a script wrapping the test target that implements suidhelper.
+ helperPath := generateSuidHelperScript(t, root)
+
+ // Set up the node manager. Since we won't do node manager updates,
+ // don't worry about its application envelope and current link.
+ _, nms := runShellCommand(t, sh, crEnv, nodeManagerCmd, "nm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
+ pid := readPID(t, nms)
+ defer syscall.Kill(pid, syscall.SIGINT)
+
+ // Create the local server that the app uses to let us know it's ready.
+ pingCh, cleanup := setupPingServer(t)
+ defer cleanup()
+
+ // Create the envelope for the first version of the app.
+ *envelope = envelopeFromShell(sh, nil, appCmd, "google naps", "appV1")
+ (*envelope).Packages = map[string]string{
+ "test": "realbin/testpkg",
+ }
+
+ // Install the app.
+ appID := installApp(t)
+
+ // Start an instance of the app.
+ startApp(t, appID)
+
+ // Wait until the app pings us that it's ready.
+ select {
+ case <-pingCh:
+ case <-time.After(pingTimeout):
+ t.Fatalf("failed to get ping")
+ }
+
+ // Ask the app to cat a file from the package.
+ file := filepath.Join("packages", "test", "hello.txt")
+ name := "appV1"
+ content, err := cat(name, file)
+ if err != nil {
+ t.Errorf("cat(%q, %q) failed: %v", name, file, err)
+ }
+ if expected := "Hello World!"; content != expected {
+ t.Errorf("unexpected content: expected %q, got %q", expected, content)
+ }
+}
+
func listAndVerifyAssociations(t *testing.T, stub node.NodeClientMethods, run veyron2.Runtime, expected []node.Association) {
assocs, err := stub.ListAssociations(run.NewContext())
if err != nil {
diff --git a/tools/principal/main.go b/tools/principal/main.go
index ed12032..e90e3df 100644
--- a/tools/principal/main.go
+++ b/tools/principal/main.go
@@ -361,6 +361,49 @@
},
}
+ cmdStoreAddToRoots = &cmdline.Command{
+ Name: "addtoroots",
+ Short: "Add provided blessings to root set",
+ Long: `
+Adds the provided blessings to the set of trusted roots for this principal.
+
+'addtoroots b' adds blessings b to the trusted root set.
+
+For example, to make the principal in credentials directory A trust the
+root of the default blessing in credentials directory B:
+ principal -veyron.credentials=B bless A some_extension |
+ principal -veyron.credentials=A store addtoroots -
+
+The extension 'some_extension' has no effect in the command above.
+`,
+ ArgsName: "<file>",
+ ArgsLong: `
+<file> is the path to a file containing a blessing typically obtained
+from this tool. - is used for STDIN.
+`,
+ Run: func(cmd *cmdline.Command, args []string) error {
+ if len(args) != 1 {
+ return fmt.Errorf("requires exactly one argument <file>, provided %d", len(args))
+ }
+ blessings, err := decodeBlessings(args[0])
+ if err != nil {
+ return fmt.Errorf("failed to decode provided blessings: %v", err)
+ }
+
+ runtime, err := rt.New()
+ if err != nil {
+ panic(err)
+ }
+ defer runtime.Cleanup()
+
+ p := runtime.Principal()
+ if err := p.AddToRoots(blessings); err != nil {
+ return fmt.Errorf("AddToRoots failed: %v", err)
+ }
+ return nil
+ },
+ }
+
cmdStoreSetDefault = &cmdline.Command{
Name: "setdefault",
Short: "Set provided blessings as default",
@@ -632,7 +675,7 @@
All blessings are printed to stdout using base64-VOM-encoding
`,
- Children: []*cmdline.Command{cmdStoreDefault, cmdStoreSetDefault, cmdStoreForPeer, cmdStoreSet},
+ Children: []*cmdline.Command{cmdStoreDefault, cmdStoreSetDefault, cmdStoreForPeer, cmdStoreSet, cmdStoreAddToRoots},
}
(&cmdline.Command{