Merge "veyron/tools/mgmt/nodex: create a unified node manager tool"
diff --git a/runtimes/google/ipc/client.go b/runtimes/google/ipc/client.go
index 8451c3e..c4903d2 100644
--- a/runtimes/google/ipc/client.go
+++ b/runtimes/google/ipc/client.go
@@ -590,13 +590,15 @@
// validation for a server's blessings are eanbled.
// Returning zero values affects more than third-party caveats, so yeah, have
// to remove them soon!
-func (c serverAuthContext) Timestamp() time.Time { return c.timestamp }
-func (serverAuthContext) Method() string { return "" }
-func (serverAuthContext) MethodTags() []interface{} { return nil }
-func (serverAuthContext) Name() string { return "" }
-func (serverAuthContext) Suffix() string { return "" }
-func (serverAuthContext) Label() (l security.Label) { return l }
-func (serverAuthContext) Discharges() map[string]security.Discharge { return nil }
+func (c serverAuthContext) Timestamp() time.Time { return c.timestamp }
+func (serverAuthContext) Method() string { return "" }
+func (serverAuthContext) MethodTags() []interface{} { return nil }
+func (serverAuthContext) Name() string { return "" }
+func (serverAuthContext) Suffix() string { return "" }
+func (serverAuthContext) Label() (l security.Label) { return l }
+
+// TODO(ataly): Remove this once the method is added to the flow type?
+func (serverAuthContext) RemoteDischarges() map[string]security.Discharge { return nil }
func splitObjectName(name string) (mtPattern, serverPattern security.BlessingPattern, objectName string) {
objectName = name
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index c30c097..649e8b4 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -495,11 +495,14 @@
s.Lock()
defer s.Unlock()
ivtrace.FromContext(s.ctx).Annotate("Serving under name: " + name)
+ if len(name) == 0 {
+ return fmt.Errorf("empty name")
+ }
if s.stopped {
return errServerStopped
}
- if len(name) == 0 {
- return fmt.Errorf("empty name")
+ if s.disp == nil {
+ return fmt.Errorf("Adding name before calling Serve or ServeDispatcher is not allowed")
}
s.publisher.AddName(name)
// TODO(cnicolaou): remove this map when the publisher's RemoveName
@@ -515,6 +518,9 @@
if s.stopped {
return errServerStopped
}
+ if s.disp == nil {
+ return fmt.Errorf("Removing name before calling Serve or ServeDispatcher is not allowed")
+ }
if _, present := s.names[name]; !present {
return fmt.Errorf("%q has not been previously used for this server", name)
}
@@ -921,7 +927,7 @@
// Implementations of ipc.ServerContext methods.
-func (fs *flowServer) Discharges() map[string]security.Discharge {
+func (fs *flowServer) RemoteDischarges() map[string]security.Discharge {
//nologcall
return fs.discharges
}
diff --git a/runtimes/google/ipc/stream/vc/auth.go b/runtimes/google/ipc/stream/vc/auth.go
index 439ead8..5fe37cf 100644
--- a/runtimes/google/ipc/stream/vc/auth.go
+++ b/runtimes/google/ipc/stream/vc/auth.go
@@ -5,13 +5,11 @@
"errors"
"fmt"
"io"
- "time"
"veyron.io/veyron/veyron/runtimes/google/ipc/stream/crypto"
"veyron.io/veyron/veyron/runtimes/google/lib/iobuf"
"veyron.io/veyron/veyron2/ipc/version"
- "veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/security"
"veyron.io/veyron/veyron2/vom"
)
@@ -58,10 +56,9 @@
if server, err = readBlessings(conn, authServerContextTag, crypter, v); err != nil {
return nil, nil, err
}
- serverB := server.ForContext(&serverAuthContext{
- self: principal,
- remote: server,
- timestamp: time.Now(),
+ serverB := server.ForContext(security.NewContext(&security.ContextParams{
+ LocalPrincipal: principal,
+ RemoteBlessings: server,
// TODO(ashankar): Get the local and remote endpoint here?
// There is also a bootstrapping problem here. For example, let's say
// (1) server has the blessing "provider/server" with a PeerIdentity caveat of "provider/client"
@@ -69,7 +66,7 @@
// How do we get that working?
// One option is to have a UnionOfBlessings of all blessings of the client in the BlessingStore
// made available to serverAuthContext.LocalBlessings for this call.
- })
+ }))
client = principal.BlessingStore().ForPeer(serverB...)
if client == nil {
return nil, nil, fmt.Errorf("no blessing tagged for peer %v in the BlessingStore", serverB)
@@ -132,24 +129,3 @@
}
return b, nil
}
-
-// security.Context implementation used when extracting blessings from what the
-// server presents during authentication.
-type serverAuthContext struct {
- self security.Principal
- remote security.Blessings
- timestamp time.Time
-}
-
-func (c *serverAuthContext) Timestamp() time.Time { return c.timestamp }
-func (*serverAuthContext) Method() string { return "" }
-func (*serverAuthContext) MethodTags() []interface{} { return nil }
-func (*serverAuthContext) Name() string { return "" }
-func (*serverAuthContext) Suffix() string { return "" }
-func (*serverAuthContext) Label() (l security.Label) { return l }
-func (c *serverAuthContext) Discharges() map[string]security.Discharge { return nil }
-func (c *serverAuthContext) LocalPrincipal() security.Principal { return c.self }
-func (c *serverAuthContext) LocalBlessings() security.Blessings { return nil }
-func (c *serverAuthContext) RemoteBlessings() security.Blessings { return c.remote }
-func (c *serverAuthContext) LocalEndpoint() naming.Endpoint { return nil }
-func (c *serverAuthContext) RemoteEndpoint() naming.Endpoint { return nil }
diff --git a/runtimes/google/rt/rt_test.go b/runtimes/google/rt/rt_test.go
index e391f1f..84085db 100644
--- a/runtimes/google/rt/rt_test.go
+++ b/runtimes/google/rt/rt_test.go
@@ -10,7 +10,6 @@
"testing"
"time"
- "veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/options"
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron2/security"
@@ -23,23 +22,6 @@
vsecurity "veyron.io/veyron/veyron/security"
)
-type context struct {
- local security.Principal
-}
-
-func (*context) Timestamp() (t time.Time) { return t }
-func (*context) Method() string { return "" }
-func (*context) MethodTags() []interface{} { return nil }
-func (*context) Name() string { return "" }
-func (*context) Suffix() string { return "" }
-func (*context) Label() (l security.Label) { return }
-func (*context) Discharges() map[string]security.Discharge { return nil }
-func (c *context) LocalPrincipal() security.Principal { return c.local }
-func (*context) LocalBlessings() security.Blessings { return nil }
-func (*context) RemoteBlessings() security.Blessings { return nil }
-func (*context) LocalEndpoint() naming.Endpoint { return nil }
-func (*context) RemoteEndpoint() naming.Endpoint { return nil }
-
func init() {
testutil.Init()
modules.RegisterChild("child", "", child)
@@ -120,7 +102,8 @@
return fmt.Errorf("rt.Principal().BlessingStore().Default() returned nil")
}
- if n := len(blessings.ForContext(&context{local: p})); n != 1 {
+ ctx := security.NewContext(&security.ContextParams{LocalPrincipal: p})
+ if n := len(blessings.ForContext(ctx)); n != 1 {
fmt.Errorf("rt.Principal().BlessingStore().Default() returned Blessing %v with %d recognized blessings, want exactly one recognized blessing", blessings, n)
}
return nil
diff --git a/security/acl_authorizer_test.go b/security/acl_authorizer_test.go
index f8785fa..98b0e2a 100644
--- a/security/acl_authorizer_test.go
+++ b/security/acl_authorizer_test.go
@@ -5,33 +5,10 @@
"os"
"runtime"
"testing"
- "time"
- "veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/security"
)
-// context implements security.Context.
-type context struct {
- localPrincipal security.Principal
- localBlessings, remoteBlessings security.Blessings
- method string
- label security.Label
-}
-
-func (c *context) Timestamp() (t time.Time) { return t }
-func (c *context) Method() string { return c.method }
-func (c *context) MethodTags() []interface{} { return nil }
-func (c *context) Name() string { return "" }
-func (c *context) Suffix() string { return "" }
-func (c *context) Label() security.Label { return c.label }
-func (c *context) Discharges() map[string]security.Discharge { return nil }
-func (c *context) LocalPrincipal() security.Principal { return c.localPrincipal }
-func (c *context) LocalBlessings() security.Blessings { return c.localBlessings }
-func (c *context) RemoteBlessings() security.Blessings { return c.remoteBlessings }
-func (c *context) LocalEndpoint() naming.Endpoint { return nil }
-func (c *context) RemoteEndpoint() naming.Endpoint { return nil }
-
func saveACLToTempFile(acl security.ACL) string {
f, err := ioutil.TempFile("", "saved_acl")
if err != nil {
@@ -62,31 +39,25 @@
pserver, server = newPrincipal("server")
_, imposter = newPrincipal("server")
palice, alice = newPrincipal("alice")
+ aliceServer = bless(palice, pserver, alice, "server")
- serverAlice = bless(pserver, palice, server, "alice")
- aliceServer = bless(palice, pserver, alice, "server")
-
- ctx = &context{
- localPrincipal: pserver,
- localBlessings: server,
- }
-
+ ctxp = &security.ContextParams{LocalPrincipal: pserver, LocalBlessings: server}
tests = []struct {
remote security.Blessings
isAuthorized bool
}{
{server, true},
{imposter, false},
- {serverAlice, false},
// A principal talking to itself (even if with a different blessing) is authorized.
// TODO(ashankar,ataly): Is this a desired property?
{aliceServer, true},
}
)
for _, test := range tests {
- ctx.remoteBlessings = test.remote
+ ctxp.RemoteBlessings = test.remote
+ ctx := security.NewContext(ctxp)
if got, want := authorizer.Authorize(ctx), test.isAuthorized; (got == nil) != want {
- t.Errorf("%s:%d: %+v.Authorize(&context{local: %v, remote: %v}) returned error: %v, want error: %v", file, line, authorizer, ctx.localBlessings, ctx.remoteBlessings, got, !want)
+ t.Errorf("%s:%d: %+v.Authorize(%v) returned error: %v, want error: %v", file, line, authorizer, ctx, got, !want)
}
}
}
@@ -119,13 +90,23 @@
// valid or invalid label.
for _, u := range users {
for _, l := range security.ValidLabels {
- ctx := &context{localPrincipal: pserver, localBlessings: server, remoteBlessings: u, label: l}
+ ctx := security.NewContext(&security.ContextParams{
+ LocalPrincipal: pserver,
+ LocalBlessings: server,
+ RemoteBlessings: u,
+ MethodTags: []interface{}{l},
+ })
if got := authorizer.Authorize(ctx); got == nil {
t.Errorf("%s:%d: %+v.Authorize(%v) returns nil, want error", file, line, authorizer, ctx)
}
}
- ctx := &context{localPrincipal: pserver, localBlessings: server, remoteBlessings: u, label: invalidLabel}
+ ctx := security.NewContext(&security.ContextParams{
+ LocalPrincipal: pserver,
+ LocalBlessings: server,
+ RemoteBlessings: u,
+ MethodTags: []interface{}{invalidLabel},
+ })
if got := authorizer.Authorize(ctx); got == nil {
t.Errorf("%s:%d: %+v.Authorize(%v) returns nil, want error", file, line, authorizer, ctx)
}
@@ -164,9 +145,14 @@
_, file, line, _ := runtime.Caller(1)
for user, labels := range expectations {
for _, l := range security.ValidLabels {
- ctx := &context{remoteBlessings: user, localBlessings: server, localPrincipal: pserver, label: l}
+ ctx := security.NewContext(&security.ContextParams{
+ LocalPrincipal: pserver,
+ LocalBlessings: server,
+ RemoteBlessings: user,
+ MethodTags: []interface{}{l},
+ })
if got, want := authorizer.Authorize(ctx), labels.HasLabel(l); (got == nil) != want {
- t.Errorf("%s:%d: %+v.Authorize(&context{remoteBlessings: %v, label: %v}) returned error: %v, want error: %v", file, line, authorizer, user, l, got, !want)
+ t.Errorf("%s:%d: %+v.Authorize(%v) returned error: %v, want error: %v", file, line, authorizer, ctx, got, !want)
}
}
}
diff --git a/services/GO.PACKAGE b/services/GO.PACKAGE
index e93556b..7a09896 100644
--- a/services/GO.PACKAGE
+++ b/services/GO.PACKAGE
@@ -6,6 +6,7 @@
{"allow": "veyron.io/veyron/veyron/profiles/...", "comment":"temporarily allowing dependency from profiles"},
{"allow": "veyron.io/veyron/veyron/tools/...", "comment":"temporarily allowing dependency from veyron/tools"},
{"allow": "veyron.io/veyron/veyron/runtimes/google/...", "comment":"temporarily allowing dependency from veyron/runtimes/google"},
+ {"allow": "veyron.io/jni/veyron/runtimes/google/...", "comment":"temporarily allowing dependency from veyron/runtimes/google"},
{"deny": "..."}
]
}
diff --git a/services/mgmt/binary/binaryd/test.sh b/services/mgmt/binary/binaryd/test.sh
index 2fd1661..51b7201 100755
--- a/services/mgmt/binary/binaryd/test.sh
+++ b/services/mgmt/binary/binaryd/test.sh
@@ -23,7 +23,7 @@
# Start the binary repository daemon.
local -r REPO="binaryd-test-repo"
- shell_test::start_server "${BINARYD_BIN}" --name="${REPO}" --veyron.tcp.address=127.0.0.1:0 \
+ shell_test::start_server "${BINARYD_BIN}" --name="${REPO}" --veyron.tcp.address=127.0.0.1:0 --http=127.0.0.1:0 \
|| shell_test::fail "line ${LINENO} failed to start binaryd"
local -r HTTP_ADDR=$(grep 'HTTP server at: "' "${START_SERVER_LOG_FILE}" | sed -e 's/^.*HTTP server at: "//' | sed -e 's/"$//')
diff --git a/services/mgmt/debug/dispatcher.go b/services/mgmt/debug/dispatcher.go
index 89154c5..0c855eb 100644
--- a/services/mgmt/debug/dispatcher.go
+++ b/services/mgmt/debug/dispatcher.go
@@ -54,9 +54,6 @@
}
switch parts[0] {
case "logs":
- if method == ipc.GlobMethod {
- return logreaderimpl.NewLogDirectoryInvoker(d.logsDir, suffix), d.auth, nil
- }
return logreaderimpl.NewLogFileInvoker(d.logsDir, suffix), d.auth, nil
case "pprof":
return pprofimpl.NewInvoker(), d.auth, nil
diff --git a/services/mgmt/debug/dispatcher_test.go b/services/mgmt/debug/dispatcher_test.go
index 2a19ee3..2d9236b 100644
--- a/services/mgmt/debug/dispatcher_test.go
+++ b/services/mgmt/debug/dispatcher_test.go
@@ -83,8 +83,8 @@
if len(results) != 0 {
t.Errorf("unexpected result. Got %v, want ''", results)
}
- if expected := verror.NoExist; !verror.Is(err, expected) {
- t.Errorf("unexpected error value, got %v, want: %v", err, expected)
+ if err != nil {
+ t.Errorf("unexpected error value: %v", err)
}
}
diff --git a/services/mgmt/logreader/impl/common_test.go b/services/mgmt/logreader/impl/common_test.go
deleted file mode 100644
index 91194ad..0000000
--- a/services/mgmt/logreader/impl/common_test.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package impl_test
-
-import (
- "testing"
-
- "veyron.io/veyron/veyron2/ipc"
- "veyron.io/veyron/veyron2/rt"
-
- "veyron.io/veyron/veyron/profiles"
-)
-
-func startServer(t *testing.T, disp ipc.Dispatcher) (ipc.Server, string, error) {
- server, err := rt.R().NewServer()
- if err != nil {
- t.Fatalf("NewServer failed: %v", err)
- return nil, "", err
- }
- endpoint, err := server.Listen(profiles.LocalListenSpec)
- if err != nil {
- t.Fatalf("Listen failed: %v", err)
- return nil, "", err
- }
- if err := server.ServeDispatcher("", disp); err != nil {
- t.Fatalf("Serve failed: %v", err)
- return nil, "", err
- }
- return server, endpoint.String(), nil
-}
-
-func stopServer(t *testing.T, server ipc.Server) {
- if err := server.Stop(); err != nil {
- t.Errorf("server.Stop failed: %v", err)
- }
-}
diff --git a/services/mgmt/logreader/impl/logdir_invoker.go b/services/mgmt/logreader/impl/logdir_invoker.go
deleted file mode 100644
index ef7a60b..0000000
--- a/services/mgmt/logreader/impl/logdir_invoker.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package impl
-
-import (
- "os"
- "path"
- "path/filepath"
-
- "veyron.io/veyron/veyron/lib/glob"
-
- "veyron.io/veyron/veyron2/ipc"
- "veyron.io/veyron/veyron2/services/mounttable/types"
- "veyron.io/veyron/veyron2/vlog"
-)
-
-// logDirectoryInvoker holds the state of an invocation.
-type logDirectoryInvoker struct {
- // root is the root directory from which the object names are based.
- root string
- // suffix is the suffix of the current invocation that is assumed to
- // be used as a relative object name to identify a log directory.
- suffix string
-}
-
-// NewLogDirectoryInvoker is the invoker factory.
-func NewLogDirectoryInvoker(root, suffix string) ipc.Invoker {
- return ipc.ReflectInvoker(&logDirectoryInvoker{filepath.Clean(root), suffix})
-}
-
-// Glob streams the name of all the objects that match pattern.
-func (i *logDirectoryInvoker) Glob(call ipc.ServerCall, pattern string) error {
- vlog.VI(1).Infof("%v.Glob(%v)", i.suffix, pattern)
- g, err := glob.Parse(pattern)
- if err != nil {
- return err
- }
- i.root, err = translateNameToFilename(i.root, i.suffix)
- if err != nil {
- return err
- }
- fi, err := os.Stat(i.root)
- if err != nil {
- if os.IsNotExist(err) {
- return errNotFound
- }
- return errOperationFailed
- }
- return i.globStep("", g, fi.IsDir(), call)
-}
-
-// globStep applies a glob recursively.
-func (i *logDirectoryInvoker) globStep(name string, g *glob.Glob, isDir bool, call ipc.ServerCall) error {
- if g.Len() == 0 {
- if err := call.Send(types.MountEntry{Name: name}); err != nil {
- return err
- }
- }
- if g.Finished() || !isDir {
- return nil
- }
- dirName, err := translateNameToFilename(i.root, name)
- if err != nil {
- return err
- }
- f, err := os.Open(dirName)
- if err != nil {
- if os.IsNotExist(err) {
- return errNotFound
- }
- return errOperationFailed
- }
- fi, err := f.Readdir(0)
- if err != nil {
- return errOperationFailed
- }
- f.Close()
- for _, file := range fi {
- fileName := file.Name()
- if fileName == "." || fileName == ".." {
- continue
- }
- if ok, _, left := g.MatchInitialSegment(fileName); ok {
- if err := i.globStep(path.Join(name, fileName), left, file.IsDir(), call); err != nil {
- return err
- }
- }
-
- }
- return nil
-}
diff --git a/services/mgmt/logreader/impl/logdir_invoker_test.go b/services/mgmt/logreader/impl/logdir_invoker_test.go
deleted file mode 100644
index f2bdf87..0000000
--- a/services/mgmt/logreader/impl/logdir_invoker_test.go
+++ /dev/null
@@ -1,226 +0,0 @@
-package impl_test
-
-import (
- "io/ioutil"
- "os"
- "path"
- "reflect"
- "sort"
- "testing"
-
- "veyron.io/veyron/veyron/services/mgmt/logreader/impl"
-
- "veyron.io/veyron/veyron2/naming"
- "veyron.io/veyron/veyron2/rt"
- "veyron.io/veyron/veyron2/security"
- "veyron.io/veyron/veyron2/services/mounttable"
- "veyron.io/veyron/veyron2/verror"
-)
-
-type logDirectoryDispatcher struct {
- root string
-}
-
-func (d *logDirectoryDispatcher) Lookup(suffix, _ string) (interface{}, security.Authorizer, error) {
- return impl.NewLogDirectoryInvoker(d.root, suffix), nil, nil
-}
-
-func TestLogDirectory(t *testing.T) {
- runtime := rt.Init()
-
- workdir, err := ioutil.TempDir("", "logreadertest")
- if err != nil {
- t.Fatalf("ioutil.TempDir: %v", err)
- }
- defer os.RemoveAll(workdir)
- server, endpoint, err := startServer(t, &logDirectoryDispatcher{workdir})
- if err != nil {
- t.Fatalf("startServer failed: %v", err)
- }
- defer stopServer(t, server)
-
- if err := os.Mkdir(path.Join(workdir, "subdir"), os.FileMode(0755)); err != nil {
- t.Fatalf("os.Mkdir failed: %v", err)
- }
- tests := []string{
- "foo.txt",
- "bar.txt",
- "subdir/foo2.txt",
- "subdir/bar2.txt",
- }
- for _, s := range tests {
- if err := ioutil.WriteFile(path.Join(workdir, s), []byte(s), os.FileMode(0644)); err != nil {
- t.Fatalf("ioutil.WriteFile failed: %v", err)
- }
- }
-
- // Try to access a directory that doesn't exist.
- {
- ld := mounttable.GlobbableClient(naming.JoinAddressName(endpoint, "//doesntexist"))
- stream, err := ld.Glob(runtime.NewContext(), "*")
- if err != nil {
- t.Errorf("unexpected error, got %v, want: nil", err)
- }
- if err := stream.Finish(); err != nil {
- if expected := verror.NoExist; !verror.Is(err, expected) {
- t.Errorf("unexpected error value, got %v, want: %v", err, expected)
- }
- }
- }
-
- // Try to access a directory that does exist.
- {
- ld := mounttable.GlobbableClient(naming.JoinAddressName(endpoint, "//"))
- stream, err := ld.Glob(runtime.NewContext(), "...")
- if err != nil {
- t.Errorf("Glob failed: %v", err)
- }
- results := []string{}
- expected := []string{"", "subdir"}
- expected = append(expected, tests...)
- iterator := stream.RecvStream()
- for count := 0; iterator.Advance(); count++ {
- results = append(results, iterator.Value().Name)
- }
- sort.Strings(expected)
- sort.Strings(results)
- if !reflect.DeepEqual(expected, results) {
- t.Errorf("unexpected result. Got %v, want %v", results, expected)
- }
-
- if err := iterator.Err(); err != nil {
- t.Errorf("unexpected stream error: %v", iterator.Err())
- }
- if err := stream.Finish(); err != nil {
- t.Errorf("Finish failed: %v", err)
- }
-
- stream, err = ld.Glob(runtime.NewContext(), "*")
- if err != nil {
- t.Errorf("Glob failed: %v", err)
- }
- results = []string{}
- iterator = stream.RecvStream()
- for count := 0; iterator.Advance(); count++ {
- results = append(results, iterator.Value().Name)
- }
- sort.Strings(results)
- expected = []string{
- "bar.txt",
- "foo.txt",
- "subdir",
- }
- if !reflect.DeepEqual(expected, results) {
- t.Errorf("unexpected result. Got %v, want %v", results, expected)
- }
-
- if err := iterator.Err(); err != nil {
- t.Errorf("unexpected stream error: %v", iterator.Err())
- }
- if err := stream.Finish(); err != nil {
- t.Errorf("Finish failed: %v", err)
- }
-
- stream, err = ld.Glob(runtime.NewContext(), "subdir/*")
- if err != nil {
- t.Errorf("Glob failed: %v", err)
- }
- results = []string{}
- iterator = stream.RecvStream()
- for count := 0; iterator.Advance(); count++ {
- results = append(results, iterator.Value().Name)
- }
- sort.Strings(results)
- expected = []string{
- "subdir/bar2.txt",
- "subdir/foo2.txt",
- }
- if !reflect.DeepEqual(expected, results) {
- t.Errorf("unexpected result. Got %v, want %v", results, expected)
- }
-
- if err := iterator.Err(); err != nil {
- t.Errorf("unexpected stream error: %v", iterator.Err())
- }
- if err := stream.Finish(); err != nil {
- t.Errorf("Finish failed: %v", err)
- }
- }
-
- // Try to access a sub-directory.
- {
- ld := mounttable.GlobbableClient(naming.JoinAddressName(endpoint, "//subdir"))
- stream, err := ld.Glob(runtime.NewContext(), "*")
- if err != nil {
- t.Errorf("Glob failed: %v", err)
- }
- results := []string{}
- iterator := stream.RecvStream()
- for count := 0; iterator.Advance(); count++ {
- results = append(results, iterator.Value().Name)
- }
- sort.Strings(results)
- expected := []string{
- "bar2.txt",
- "foo2.txt",
- }
- if !reflect.DeepEqual(expected, results) {
- t.Errorf("unexpected result. Got %v, want %v", results, expected)
- }
-
- if err := iterator.Err(); err != nil {
- t.Errorf("unexpected stream error: %v", iterator.Err())
- }
- if err := stream.Finish(); err != nil {
- t.Errorf("Finish failed: %v", err)
- }
- }
-
- // Try to access a file.
- {
- ld := mounttable.GlobbableClient(naming.JoinAddressName(endpoint, "//foo.txt"))
- stream, err := ld.Glob(runtime.NewContext(), "*")
- if err != nil {
- t.Errorf("Glob failed: %v", err)
- }
- results := []string{}
- iterator := stream.RecvStream()
- for count := 0; iterator.Advance(); count++ {
- results = append(results, iterator.Value().Name)
- }
- sort.Strings(results)
- expected := []string{}
- if !reflect.DeepEqual(expected, results) {
- t.Errorf("unexpected result. Got %v, want %v", results, expected)
- }
-
- if err := iterator.Err(); err != nil {
- t.Errorf("unexpected stream error: %v", iterator.Err())
- }
- if err := stream.Finish(); err != nil {
- t.Errorf("Finish failed: %v", err)
- }
-
- stream, err = ld.Glob(runtime.NewContext(), "")
- if err != nil {
- t.Errorf("Glob failed: %v", err)
- }
- results = []string{}
- iterator = stream.RecvStream()
- for count := 0; iterator.Advance(); count++ {
- results = append(results, iterator.Value().Name)
- }
- sort.Strings(results)
- expected = []string{""}
- if !reflect.DeepEqual(expected, results) {
- t.Errorf("unexpected result. Got %#v, want %#v", results, expected)
- }
-
- if err := iterator.Err(); err != nil {
- t.Errorf("unexpected stream error: %v", iterator.Err())
- }
- if err := stream.Finish(); err != nil {
- t.Errorf("Finish failed: %v", err)
- }
- }
-}
diff --git a/services/mgmt/logreader/impl/logfile_invoker.go b/services/mgmt/logreader/impl/logfile_invoker.go
index 00a1b3e..8f4f88c 100644
--- a/services/mgmt/logreader/impl/logfile_invoker.go
+++ b/services/mgmt/logreader/impl/logfile_invoker.go
@@ -81,3 +81,42 @@
}
return reader.tell(), nil
}
+
+// VGlobChildren returns the list of files in a directory, or an empty list if
+// the object is a file.
+func (i *logFileInvoker) VGlobChildren() ([]string, error) {
+ vlog.VI(1).Infof("%v.VGlobChildren()", i.suffix)
+ dirName, err := translateNameToFilename(i.root, i.suffix)
+ if err != nil {
+ return nil, err
+ }
+ stat, err := os.Stat(dirName)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return nil, errNotFound
+ }
+ return nil, errOperationFailed
+ }
+ if !stat.IsDir() {
+ return nil, nil
+ }
+
+ f, err := os.Open(dirName)
+ if err != nil {
+ return nil, errOperationFailed
+ }
+ fi, err := f.Readdir(0)
+ if err != nil {
+ return nil, errOperationFailed
+ }
+ f.Close()
+ children := []string{}
+ for _, file := range fi {
+ fileName := file.Name()
+ if fileName == "." || fileName == ".." {
+ continue
+ }
+ children = append(children, file.Name())
+ }
+ return children, nil
+}
diff --git a/services/mgmt/logreader/impl/logfile_invoker_test.go b/services/mgmt/logreader/impl/logfile_invoker_test.go
index 3f6a478..3defb7e 100644
--- a/services/mgmt/logreader/impl/logfile_invoker_test.go
+++ b/services/mgmt/logreader/impl/logfile_invoker_test.go
@@ -6,8 +6,10 @@
"path"
"testing"
+ "veyron.io/veyron/veyron/profiles"
"veyron.io/veyron/veyron/services/mgmt/logreader/impl"
+ "veyron.io/veyron/veyron2/ipc"
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron2/security"
@@ -16,6 +18,30 @@
"veyron.io/veyron/veyron2/verror"
)
+func startServer(t *testing.T, disp ipc.Dispatcher) (ipc.Server, string, error) {
+ server, err := rt.R().NewServer()
+ if err != nil {
+ t.Fatalf("NewServer failed: %v", err)
+ return nil, "", err
+ }
+ endpoint, err := server.Listen(profiles.LocalListenSpec)
+ if err != nil {
+ t.Fatalf("Listen failed: %v", err)
+ return nil, "", err
+ }
+ if err := server.ServeDispatcher("", disp); err != nil {
+ t.Fatalf("Serve failed: %v", err)
+ return nil, "", err
+ }
+ return server, endpoint.String(), nil
+}
+
+func stopServer(t *testing.T, server ipc.Server) {
+ if err := server.Stop(); err != nil {
+ t.Errorf("server.Stop failed: %v", err)
+ }
+}
+
type logFileDispatcher struct {
root string
}
diff --git a/services/mgmt/node/impl/app_invoker.go b/services/mgmt/node/impl/app_invoker.go
index f048999..7a00025 100644
--- a/services/mgmt/node/impl/app_invoker.go
+++ b/services/mgmt/node/impl/app_invoker.go
@@ -123,14 +123,11 @@
"veyron.io/veyron/veyron2/security"
"veyron.io/veyron/veyron2/services/mgmt/appcycle"
"veyron.io/veyron/veyron2/services/mgmt/application"
- "veyron.io/veyron/veyron2/services/mounttable"
- "veyron.io/veyron/veyron2/services/mounttable/types"
"veyron.io/veyron/veyron2/verror"
"veyron.io/veyron/veyron2/vlog"
vexec "veyron.io/veyron/veyron/lib/exec"
"veyron.io/veyron/veyron/lib/flags/consts"
- "veyron.io/veyron/veyron/lib/glob"
vsecurity "veyron.io/veyron/veyron/security"
iconfig "veyron.io/veyron/veyron/services/mgmt/node/config"
)
@@ -979,7 +976,6 @@
type treeNode struct {
children map[string]*treeNode
- remote string // Used to implement Glob for remote objects.
}
func newTreeNode() *treeNode {
@@ -1007,20 +1003,13 @@
}
}
-// scanConfigDir scans the config directory to build tree representation of all
-// the valid object names.
-func (i *appInvoker) scanConfigDir() *treeNode {
- tree := newTreeNode()
-
- // appIDMap[appID]title
- appIDMap := make(map[string]string)
-
- // Find all envelopes, extract appID and installID.
- envGlob := []string{i.config.Root, "app-*", "installation-*", "*", "envelope"}
+func (i *appInvoker) scanEnvelopes(tree *treeNode, appDir string) {
+ // Find all envelopes, extract installID.
+ envGlob := []string{i.config.Root, appDir, "installation-*", "*", "envelope"}
envelopes, err := filepath.Glob(filepath.Join(envGlob...))
if err != nil {
vlog.Errorf("unexpected error: %v", err)
- return nil
+ return
}
for _, path := range envelopes {
env, err := loadEnvelope(filepath.Dir(path))
@@ -1033,114 +1022,85 @@
vlog.Errorf("unexpected number of path components: %q (%q)", elems, path)
continue
}
- appID := strings.TrimPrefix(elems[0], "app-")
installID := strings.TrimPrefix(elems[1], "installation-")
- appIDMap[appID] = env.Title
tree.find([]string{env.Title, installID}, true)
}
+ return
+}
+func (i *appInvoker) scanInstances(tree *treeNode) {
+ if len(i.suffix) < 2 {
+ return
+ }
+ title := i.suffix[0]
+ installDir, err := installationDirCore(i.suffix[:2], i.config.Root)
+ if err != nil {
+ return
+ }
// Find all instances.
- infoGlob := []string{i.config.Root, "app-*", "installation-*", "instances", "instance-*", "info"}
+ infoGlob := []string{installDir, "instances", "instance-*", "info"}
instances, err := filepath.Glob(filepath.Join(infoGlob...))
if err != nil {
vlog.Errorf("unexpected error: %v", err)
- return nil
+ return
}
for _, path := range instances {
instanceDir := filepath.Dir(path)
- info, err := loadInstanceInfo(instanceDir)
+ i.scanInstance(tree, title, instanceDir)
+ }
+ return
+}
+
+func (i *appInvoker) scanInstance(tree *treeNode, title, instanceDir string) {
+ if _, err := loadInstanceInfo(instanceDir); err != nil {
+ return
+ }
+ relpath, _ := filepath.Rel(i.config.Root, instanceDir)
+ elems := strings.Split(relpath, string(filepath.Separator))
+ if len(elems) < 4 {
+ vlog.Errorf("unexpected number of path components: %q (%q)", elems, instanceDir)
+ return
+ }
+ installID := strings.TrimPrefix(elems[1], "installation-")
+ instanceID := strings.TrimPrefix(elems[3], "instance-")
+ tree.find([]string{title, installID, instanceID, "logs"}, true)
+ if instanceStateIs(instanceDir, started) {
+ for _, obj := range []string{"pprof", "stats"} {
+ tree.find([]string{title, installID, instanceID, obj}, true)
+ }
+ }
+}
+
+func (i *appInvoker) VGlobChildren() ([]string, error) {
+ tree := newTreeNode()
+ switch len(i.suffix) {
+ case 0:
+ i.scanEnvelopes(tree, "app-*")
+ case 1:
+ appDir := applicationDirName(i.suffix[0])
+ i.scanEnvelopes(tree, appDir)
+ case 2:
+ i.scanInstances(tree)
+ case 3:
+ dir, err := i.instanceDir()
if err != nil {
- continue
+ break
}
- relpath, _ := filepath.Rel(i.config.Root, path)
- elems := strings.Split(relpath, string(filepath.Separator))
- if len(elems) != len(infoGlob)-1 {
- vlog.Errorf("unexpected number of path components: %q (%q)", elems, path)
- continue
- }
- appID := strings.TrimPrefix(elems[0], "app-")
- installID := strings.TrimPrefix(elems[1], "installation-")
- instanceID := strings.TrimPrefix(elems[3], "instance-")
- if title, ok := appIDMap[appID]; ok {
- n := tree.find([]string{title, installID, instanceID, "logs"}, true)
- i.addLogFiles(n, filepath.Join(instanceDir, "logs"))
-
- if instanceStateIs(instanceDir, started) {
- // Set the name of the remote objects that should handle Glob.
- for _, obj := range []string{"pprof", "stats"} {
- n = tree.find([]string{title, installID, instanceID, obj}, true)
- n.remote = naming.JoinAddressName(info.AppCycleMgrName, naming.Join("__debug", obj))
- }
- }
- }
+ i.scanInstance(tree, i.suffix[0], dir)
+ default:
+ return nil, errNotExist
}
- return tree
-}
-
-func (i *appInvoker) addLogFiles(n *treeNode, dir string) {
- filepath.Walk(dir, func(path string, _ os.FileInfo, _ error) error {
- if path == dir {
- // Skip the logs directory itself.
- return nil
- }
- relpath, _ := filepath.Rel(dir, path)
- n.find(strings.Split(relpath, string(filepath.Separator)), true)
- return nil
- })
-}
-
-func (i *appInvoker) Glob(ctx mounttable.GlobbableGlobContext, pattern string) error {
- g, err := glob.Parse(pattern)
- if err != nil {
- return err
- }
- n := i.scanConfigDir().find(i.suffix, false)
+ n := tree.find(i.suffix, false)
if n == nil {
- return errInvalidSuffix
+ return nil, errInvalidSuffix
}
- i.globStep(ctx, "", g, n)
- return nil
-}
-
-func (i *appInvoker) globStep(ctx mounttable.GlobbableGlobContext, prefix string, g *glob.Glob, n *treeNode) {
- if n.remote != "" {
- remoteGlob(ctx, n.remote, prefix, g.String())
- return
+ children := make([]string, len(n.children))
+ index := 0
+ for child, _ := range n.children {
+ children[index] = child
+ index++
}
- if g.Len() == 0 {
- ctx.SendStream().Send(types.MountEntry{Name: prefix})
- }
- if g.Finished() {
- return
- }
- for name, child := range n.children {
- if ok, _, left := g.MatchInitialSegment(name); ok {
- i.globStep(ctx, naming.Join(prefix, name), left, child)
- }
- }
-}
-
-func remoteGlob(ctx mounttable.GlobbableGlobContext, remote, prefix, pattern string) {
- call, err := mounttable.GlobbableClient(remote).Glob(ctx, pattern)
- if err != nil {
- vlog.VI(1).Infof("%q.Glob(%q): %v", remote, pattern, err)
- return
- }
- it := call.RecvStream()
- sender := ctx.SendStream()
- for it.Advance() {
- me := it.Value()
- me.Name = naming.Join(prefix, me.Name)
- sender.Send(me)
- }
- if err := it.Err(); err != nil {
- vlog.VI(1).Infof("%q.Glob(%q): %v", remote, pattern, err)
- return
- }
- if err := call.Finish(); err != nil {
- vlog.VI(1).Infof("%q.Glob(%q): %v", remote, pattern, err)
- return
- }
+ return children, nil
}
// TODO(rjkroege): Refactor to eliminate redundancy with newAppSpecificAuthorizer.
diff --git a/services/mgmt/node/impl/dispatcher.go b/services/mgmt/node/impl/dispatcher.go
index b29347f..679a459 100644
--- a/services/mgmt/node/impl/dispatcher.go
+++ b/services/mgmt/node/impl/dispatcher.go
@@ -352,13 +352,11 @@
})
return ipc.ReflectInvoker(receiver), d.auth, nil
case appsSuffix:
- // Glob requests are handled by appInvoker, except for pprof and
- // stats objects which handle Glob themselves.
// Requests to apps/*/*/*/logs are handled locally by LogFileInvoker.
// Requests to apps/*/*/*/pprof are proxied to the apps' __debug/pprof object.
// Requests to apps/*/*/*/stats are proxied to the apps' __debug/stats object.
// Everything else is handled by appInvoker.
- if len(components) >= 5 && (method != ipc.GlobMethod || components[4] != "logs") {
+ if len(components) >= 5 {
appInstanceDir, err := instanceDir(d.config.Root, components[1:4])
if err != nil {
return nil, nil, err
diff --git a/services/mgmt/node/impl/node_invoker.go b/services/mgmt/node/impl/node_invoker.go
index 0e50fdd..51a35cc 100644
--- a/services/mgmt/node/impl/node_invoker.go
+++ b/services/mgmt/node/impl/node_invoker.go
@@ -47,12 +47,9 @@
"veyron.io/veyron/veyron2/services/mgmt/application"
"veyron.io/veyron/veyron2/services/mgmt/binary"
"veyron.io/veyron/veyron2/services/mgmt/node"
- "veyron.io/veyron/veyron2/services/mounttable"
- "veyron.io/veyron/veyron2/services/mounttable/types"
"veyron.io/veyron/veyron2/vlog"
vexec "veyron.io/veyron/veyron/lib/exec"
- "veyron.io/veyron/veyron/lib/glob"
"veyron.io/veyron/veyron/lib/netstate"
"veyron.io/veyron/veyron/services/mgmt/node/config"
"veyron.io/veyron/veyron/services/mgmt/profile"
@@ -463,17 +460,6 @@
return i.disp.getACL()
}
-func (i *nodeInvoker) Glob(ctx mounttable.GlobbableGlobContext, pattern string) error {
- g, err := glob.Parse(pattern)
- if err != nil {
- return err
- }
- if g.Len() == 0 {
- return ctx.SendStream().Send(types.MountEntry{Name: ""})
- }
- return nil
-}
-
func sameMachineCheck(call ipc.ServerContext) error {
switch local, err := netstate.SameMachine(call.RemoteEndpoint().Addr()); {
case err != nil:
diff --git a/services/mgmt/pprof/impl/server.go b/services/mgmt/pprof/impl/server.go
index 54da509..e7f13ff 100644
--- a/services/mgmt/pprof/impl/server.go
+++ b/services/mgmt/pprof/impl/server.go
@@ -7,10 +7,7 @@
"runtime/pprof"
"time"
- "veyron.io/veyron/veyron/lib/glob"
-
"veyron.io/veyron/veyron2/ipc"
- "veyron.io/veyron/veyron2/services/mounttable/types"
"veyron.io/veyron/veyron2/verror"
)
@@ -80,19 +77,6 @@
return results, nil
}
-// Glob streams the name of all the objects that match pattern. In this case,
-// there is only the root object.
-func (pprofInvoker) Glob(call ipc.ServerCall, pattern string) error {
- g, err := glob.Parse(pattern)
- if err != nil {
- return err
- }
- if g.Len() == 0 {
- return call.Send(types.MountEntry{Name: ""})
- }
- return nil
-}
-
type streamWriter struct {
call ipc.ServerCall
}
diff --git a/services/mgmt/suidhelper/impl/args.go b/services/mgmt/suidhelper/impl/args.go
index 7ab9574..4e3f4fb 100644
--- a/services/mgmt/suidhelper/impl/args.go
+++ b/services/mgmt/suidhelper/impl/args.go
@@ -35,8 +35,8 @@
var (
flagUsername, flagWorkspace, flagLogDir, flagRun *string
- flagMinimumUid *int64
- flagRemove *bool
+ flagMinimumUid *int64
+ flagRemove *bool
)
func init() {
diff --git a/services/mgmt/suidhelper/impl/flag/flag.go b/services/mgmt/suidhelper/impl/flag/flag.go
index 6a4cdb3..25782ab 100644
--- a/services/mgmt/suidhelper/impl/flag/flag.go
+++ b/services/mgmt/suidhelper/impl/flag/flag.go
@@ -14,8 +14,8 @@
var (
Username, Workspace, LogDir, Run *string
- MinimumUid *int64
- Remove *bool
+ MinimumUid *int64
+ Remove *bool
)
func init() {