veyron2: make it possible to specify a 'reserved name' dispatcher.
This allows us to move the dependencies on the debug server out
of the core runtime. It is now configured via a profile and as
such is more flexible.
Change-Id: I3ee3e2663c2a02e9d4c4fd4162c1363aac7a9651
diff --git a/profiles/roaming/roaming.go b/profiles/roaming/roaming.go
index 816b4a1..a28feea 100644
--- a/profiles/roaming/roaming.go
+++ b/profiles/roaming/roaming.go
@@ -23,6 +23,9 @@
"veyron.io/veyron/veyron/lib/netstate"
"veyron.io/veyron/veyron/profiles"
"veyron.io/veyron/veyron/profiles/internal"
+ "veyron.io/veyron/veyron/services/mgmt/debug"
+ // TODO(cnicolaou,ashankar): move this into flags.
+ sflag "veyron.io/veyron/veyron/security/flag"
)
const (
@@ -69,6 +72,8 @@
func (p *profile) Init(rt veyron2.Runtime, publisher *config.Publisher) error {
log := rt.Logger()
+ rt.ConfigureReservedName("__debug", debug.NewDispatcher(log.LogDir(), sflag.NewAuthorizerOrDie()))
+
lf := commonFlags.ListenFlags()
ListenSpec = ipc.ListenSpec{
Protocol: lf.ListenProtocol.Protocol,
diff --git a/profiles/static/static.go b/profiles/static/static.go
index ba90318..18b7625 100644
--- a/profiles/static/static.go
+++ b/profiles/static/static.go
@@ -15,6 +15,9 @@
"veyron.io/veyron/veyron/lib/netstate"
"veyron.io/veyron/veyron/profiles"
"veyron.io/veyron/veyron/profiles/internal"
+ "veyron.io/veyron/veyron/services/mgmt/debug"
+ // TODO(cnicolaou,ashankar): move this into flags.
+ sflag "veyron.io/veyron/veyron/security/flag"
)
var (
@@ -55,6 +58,8 @@
func (p *static) Init(rt veyron2.Runtime, _ *config.Publisher) error {
log := rt.Logger()
+ rt.ConfigureReservedName("debug", debug.NewDispatcher(log.LogDir(), sflag.NewAuthorizerOrDie()))
+
lf := commonFlags.ListenFlags()
ListenSpec = ipc.ListenSpec{
Protocol: lf.ListenProtocol.Protocol,
diff --git a/runtimes/google/ipc/debug_test.go b/runtimes/google/ipc/debug_test.go
index 6292622..e05c185 100644
--- a/runtimes/google/ipc/debug_test.go
+++ b/runtimes/google/ipc/debug_test.go
@@ -9,12 +9,14 @@
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/options"
"veyron.io/veyron/veyron2/services/mounttable/types"
+ "veyron.io/veyron/veyron2/vlog"
"veyron.io/veyron/veyron/lib/stats"
"veyron.io/veyron/veyron/runtimes/google/ipc/stream/manager"
"veyron.io/veyron/veyron/runtimes/google/ipc/stream/sectest"
"veyron.io/veyron/veyron/runtimes/google/ipc/stream/vc"
tnaming "veyron.io/veyron/veyron/runtimes/google/testing/mocks/naming"
+ "veyron.io/veyron/veyron/services/mgmt/debug"
)
func TestDebugServer(t *testing.T) {
@@ -28,10 +30,13 @@
pclient.AddToRoots(bclient) // Client recognizes "server" as a root of blessings.
pclient.BlessingStore().Set(bclient, "server") // Client presents bclient to server
+ debugDisp := debug.NewDispatcher(vlog.Log.LogDir(), nil)
+
sm := manager.InternalNew(naming.FixedRoutingID(0x555555555))
defer sm.Shutdown()
ns := tnaming.NewSimpleNamespace()
- server, err := InternalNewServer(testContext(), sm, ns, vc.LocalPrincipal{pserver})
+
+ server, err := InternalNewServer(testContext(), sm, ns, options.ReservedNameDispatcher{"__debug", debugDisp}, vc.LocalPrincipal{pserver})
if err != nil {
t.Fatalf("InternalNewServer failed: %v", err)
}
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index 08fb74a..10d4263 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -28,7 +28,6 @@
"veyron.io/veyron/veyron/runtimes/google/lib/publisher"
inaming "veyron.io/veyron/veyron/runtimes/google/naming"
ivtrace "veyron.io/veyron/veyron/runtimes/google/vtrace"
- "veyron.io/veyron/veyron/services/mgmt/debug"
)
var (
@@ -48,8 +47,7 @@
stoppedChan chan struct{} // closed when the server has been stopped.
ns naming.Namespace
servesMountTable bool
- debugAuthorizer security.Authorizer
- debugDisp ipc.Dispatcher
+ reservedOpt options.ReservedNameDispatcher
// TODO(cnicolaou): add roaming stats to ipcStats
stats *ipcStats // stats for this server.
}
@@ -82,11 +80,10 @@
s.listenerOpts = append(s.listenerOpts, opt)
case options.ServesMountTable:
s.servesMountTable = bool(opt)
- case options.DebugAuthorizer:
- s.debugAuthorizer = opt.Authorizer
+ case options.ReservedNameDispatcher:
+ s.reservedOpt = opt
}
}
- s.debugDisp = debug.NewDispatcher(vlog.Log.LogDir(), s.debugAuthorizer)
return s, nil
}
@@ -622,12 +619,12 @@
// flow that's already connected to the client.
type flowServer struct {
context.T
- server *server // ipc.Server that this flow server belongs to
- disp ipc.Dispatcher // ipc.Dispatcher that will serve RPCs on this flow
- dec *vom.Decoder // to decode requests and args from the client
- enc *vom.Encoder // to encode responses and results to the client
- flow stream.Flow // underlying flow
- debugDisp ipc.Dispatcher // internal debug dispatcher
+ server *server // ipc.Server that this flow server belongs to
+ disp ipc.Dispatcher // ipc.Dispatcher that will serve RPCs on this flow
+ dec *vom.Decoder // to decode requests and args from the client
+ enc *vom.Encoder // to encode responses and results to the client
+ flow stream.Flow // underlying flow
+ reservedOpt options.ReservedNameDispatcher
// Fields filled in during the server invocation.
blessings security.Blessings
@@ -652,11 +649,11 @@
server: server,
disp: disp,
// TODO(toddw): Support different codecs
- dec: vom.NewDecoder(flow),
- enc: vom.NewEncoder(flow),
- flow: flow,
- debugDisp: server.debugDisp,
- discharges: make(map[string]security.Discharge),
+ dec: vom.NewDecoder(flow),
+ enc: vom.NewEncoder(flow),
+ flow: flow,
+ reservedOpt: server.reservedOpt,
+ discharges: make(map[string]security.Discharge),
}
}
@@ -857,14 +854,16 @@
func (fs *flowServer) lookup(name, method string) (ipc.Invoker, security.Authorizer, string, verror.E) {
name = strings.TrimLeft(name, "/")
if method == "Glob" && len(name) == 0 {
- return ipc.ReflectInvoker(&globInvoker{fs}), &acceptAllAuthorizer{}, name, nil
+ return ipc.ReflectInvoker(&globInvoker{fs.reservedOpt.Prefix, fs}), &acceptAllAuthorizer{}, name, nil
}
disp := fs.disp
- if name == ipc.DebugKeyword || strings.HasPrefix(name, ipc.DebugKeyword+"/") {
- name = strings.TrimPrefix(name, ipc.DebugKeyword)
+ prefix := fs.reservedOpt.Prefix
+ if len(prefix) > 0 && (name == prefix || strings.HasPrefix(name, prefix+"/")) {
+ name = strings.TrimPrefix(name, prefix)
name = strings.TrimLeft(name, "/")
- disp = fs.debugDisp
+ disp = fs.reservedOpt.Dispatcher
}
+
if disp != nil {
invoker, auth, err := disp.Lookup(name, method)
switch {
@@ -884,7 +883,8 @@
}
type globInvoker struct {
- fs *flowServer
+ prefix string
+ fs *flowServer
}
// Glob matches the pattern against internal object names if the double-
@@ -895,15 +895,12 @@
if err != nil {
return err
}
- if strings.HasPrefix(pattern, "__") {
+ if strings.HasPrefix(pattern, naming.ReservedNamePrefix) {
var err error
// Match against internal object names.
- internalLeaves := []string{ipc.DebugKeyword}
- for _, leaf := range internalLeaves {
- if ok, _, left := g.MatchInitialSegment(leaf); ok {
- if ierr := i.invokeGlob(call, i.fs.debugDisp, leaf, left.String()); ierr != nil {
- err = ierr
- }
+ if ok, _, left := g.MatchInitialSegment(i.prefix); ok {
+ if ierr := i.invokeGlob(call, i.fs.reservedOpt.Dispatcher, i.prefix, left.String()); ierr != nil {
+ err = ierr
}
}
return err
@@ -938,6 +935,7 @@
if err != nil {
return err
}
+
if len(results) != 1 {
return verror.BadArgf("unexpected number of results. Got %d, want 1", len(results))
}
diff --git a/runtimes/google/rt/ipc.go b/runtimes/google/rt/ipc.go
index 293657a..4923176 100644
--- a/runtimes/google/rt/ipc.go
+++ b/runtimes/google/rt/ipc.go
@@ -93,6 +93,11 @@
}
// Add the option that provides the principal to the server.
otherOpts = append(otherOpts, vc.LocalPrincipal{rt.principal})
+ if rt.reservedDisp != nil {
+ ropts := options.ReservedNameDispatcher{rt.reservedPrefix, rt.reservedDisp}
+ otherOpts = append(otherOpts, ropts)
+ otherOpts = append(otherOpts, rt.reservedOpts...)
+ }
ctx := rt.NewContext()
return iipc.InternalNewServer(ctx, sm, ns, otherOpts...)
}
diff --git a/runtimes/google/rt/rt.go b/runtimes/google/rt/rt.go
index 8383b6d..7bb5e3b 100644
--- a/runtimes/google/rt/rt.go
+++ b/runtimes/google/rt/rt.go
@@ -5,6 +5,7 @@
"fmt"
"os"
"path/filepath"
+ "strings"
"sync"
"veyron.io/veyron/veyron2"
@@ -30,17 +31,20 @@
type vrt struct {
mu sync.Mutex
- profile veyron2.Profile
- publisher *config.Publisher
- sm []stream.Manager // GUARDED_BY(mu)
- ns naming.Namespace
- signals chan os.Signal
- principal security.Principal
- client ipc.Client
- mgmt *mgmtImpl
- flags flags.RuntimeFlags
- nServers int // GUARDED_BY(mu)
- cleaningUp bool // GUARDED_BY(mu)
+ profile veyron2.Profile
+ publisher *config.Publisher
+ sm []stream.Manager // GUARDED_BY(mu)
+ ns naming.Namespace
+ signals chan os.Signal
+ principal security.Principal
+ client ipc.Client
+ mgmt *mgmtImpl
+ flags flags.RuntimeFlags
+ reservedDisp ipc.Dispatcher
+ reservedPrefix string
+ reservedOpts []ipc.ServerOpt
+ nServers int // GUARDED_BY(mu)
+ cleaningUp bool // GUARDED_BY(mu)
lang i18n.LangID // Language, from environment variables.
program string // Program name, from os.Args[0].
@@ -118,6 +122,11 @@
return nil, fmt.Errorf("failed to get child handle: %s", err)
}
+ rt.publisher = config.NewPublisher()
+ if err := rt.profile.Init(rt, rt.publisher); err != nil {
+ return nil, err
+ }
+
// TODO(caprita, cnicolaou): how is this to be configured?
// Can it ever be anything other than a localhost/loopback address?
listenSpec := ipc.ListenSpec{Protocol: "tcp", Address: "127.0.0.1:0"}
@@ -125,11 +134,6 @@
return nil, err
}
- rt.publisher = config.NewPublisher()
- if err := rt.profile.Init(rt, rt.publisher); err != nil {
- return nil, err
- }
-
vlog.VI(2).Infof("rt.Init done")
return rt, nil
}
@@ -138,8 +142,18 @@
return rt.publisher
}
-func (r *vrt) Profile() veyron2.Profile {
- return r.profile
+func (rt *vrt) Profile() veyron2.Profile {
+ return rt.profile
+}
+
+func (rt *vrt) ConfigureReservedName(prefix string, server ipc.Dispatcher, opts ...ipc.ServerOpt) {
+ rt.mu.Lock()
+ defer rt.mu.Unlock()
+ rt.reservedDisp = server
+ prefix = strings.TrimLeft(prefix, "_")
+ rt.reservedPrefix = naming.ReservedNamePrefix + prefix
+ rt.reservedOpts = make([]ipc.ServerOpt, 0, len(opts))
+ copy(rt.reservedOpts, opts)
}
func (rt *vrt) Cleanup() {
diff --git a/runtimes/google/testing/mocks/runtime/panic_runtime.go b/runtimes/google/testing/mocks/runtime/panic_runtime.go
index 215fb5c..cccc4d7 100644
--- a/runtimes/google/testing/mocks/runtime/panic_runtime.go
+++ b/runtimes/google/testing/mocks/runtime/panic_runtime.go
@@ -45,4 +45,7 @@
func (*PanicRuntime) AdvanceGoal(delta int) { panic(badRuntime) }
func (*PanicRuntime) AdvanceProgress(delta int) { panic(badRuntime) }
func (*PanicRuntime) TrackTask(chan<- veyron2.Task) { panic(badRuntime) }
-func (*PanicRuntime) Cleanup() { panic(badRuntime) }
+func (*PanicRuntime) ConfigureReservedName(string, ipc.Dispatcher, ...ipc.ServerOpt) {
+ panic(badRuntime)
+}
+func (*PanicRuntime) Cleanup() { panic(badRuntime) }
diff --git a/services/mgmt/lib/toplevelglob/invoker.go b/services/mgmt/lib/toplevelglob/invoker.go
index fd605a4..16d1676 100644
--- a/services/mgmt/lib/toplevelglob/invoker.go
+++ b/services/mgmt/lib/toplevelglob/invoker.go
@@ -46,6 +46,9 @@
if err != nil {
return err
}
+ if invoker == nil {
+ return verror.BadArgf("failed to find invoker for %q", leaf)
+ }
argptrs := []interface{}{&pattern}
leafCall := &localServerCall{call, leaf}
results, err := invoker.Invoke("Glob", leafCall, argptrs)
diff --git a/services/mgmt/node/impl/proxy_invoker_test.go b/services/mgmt/node/impl/proxy_invoker_test.go
index 7f84099..dd87323 100644
--- a/services/mgmt/node/impl/proxy_invoker_test.go
+++ b/services/mgmt/node/impl/proxy_invoker_test.go
@@ -11,8 +11,6 @@
"veyron.io/veyron/veyron2/security"
"veyron.io/veyron/veyron2/services/mgmt/stats"
"veyron.io/veyron/veyron2/services/mounttable"
-
- "veyron.io/veyron/veyron/profiles"
)
func TestProxyInvoker(t *testing.T) {
@@ -24,7 +22,8 @@
t.Fatalf("NewServer: %v", err)
}
defer server1.Stop()
- ep1, err := server1.Listen(profiles.LocalListenSpec)
+ localSpec := ipc.ListenSpec{Protocol: "tcp", Address: "127.0.0.1:0"}
+ ep1, err := server1.Listen(localSpec)
if err != nil {
t.Fatalf("Listen: %v", err)
}
@@ -38,7 +37,7 @@
t.Fatalf("NewServer: %v", err)
}
defer server2.Stop()
- ep2, err := server2.Listen(profiles.LocalListenSpec)
+ ep2, err := server2.Listen(localSpec)
if err != nil {
t.Fatalf("Listen: %v", err)
}
@@ -79,7 +78,7 @@
}
stream, err := c.Glob(rt.R().NewContext(), pattern)
if err != nil {
- t.Errorf("Glob failed: %v", err)
+ t.Fatalf("Glob failed: %v", err)
}
results := []string{}
iterator := stream.RecvStream()