Merge "veyron/runtimes/google/rt: Use the new security model by default."
diff --git a/lib/flags/doc.go b/lib/flags/doc.go
index 49a7360..b752f0a 100644
--- a/lib/flags/doc.go
+++ b/lib/flags/doc.go
@@ -1,17 +1,18 @@
-// Package flags provides definitions for commonly used flags and where
-// appropriate, implementations of the flag.Value interface for those flags
-// to ensure that only valid values of those flags are supplied. Some of these
-// flags may also be specified using environment variables directly for
-// are documented accordingly; in these cases the command line value takes
+// Package flags provides definitions for commonly used flags and, where
+// appropriate, implementations of the flag.Value interface for those flags to
+// ensure that only valid values of those flags are supplied. Some of these
+// flags may also be specified using environment variables directly and are
+// documented accordingly; in these cases the command line value takes
// precedence over the environment variable.
-// Flags are defined as 'groups' of related flags so that caller may choose
-// which ones to use without having to be burdened with the full set. The
-// groups may be used directly or via the Flags type that aggregates multiple
-// groups. In all cases, the flags are registered with a supplied
-// flag.FlagSet and hence are not forced onto the command line
-// unless the caller passes in flag.CommandLine as the flag.FlagSet to use.
//
-// In general, this package will be used by veyron profiles and the
-// runtime implementations, but can also be used by any application
-// that wants access to the flags and environment variables it supports.
+// Flags are defined as 'groups' of related flags so that the caller may choose
+// which ones to use without having to be burdened with the full set. The groups
+// may be used directly or via the Flags type that aggregates multiple
+// groups. In all cases, the flags are registered with a supplied flag.FlagSet
+// and hence are not forced onto the command line unless the caller passes in
+// flag.CommandLine as the flag.FlagSet to use.
+//
+// In general, this package will be used by veyron profiles and the runtime
+// implementations, but can also be used by any application that wants access to
+// the flags and environment variables it supports.
package flags
diff --git a/lib/modules/core/core.go b/lib/modules/core/core.go
index bf4e6d4..add670f 100644
--- a/lib/modules/core/core.go
+++ b/lib/modules/core/core.go
@@ -67,6 +67,7 @@
MTCommand = "mt"
LSExternalCommand = "lse"
ProxyServerCommand = "proxyd"
+ WSPRCommand = "wsprd"
ShellCommand = "sh"
)
@@ -93,7 +94,11 @@
run a glob command as an external subprocess`)
shell.AddSubprocess(ProxyServerCommand, `<name>...
run a proxy server mounted at the specified names`)
- // shell.AddSubprocess(ShellCommand, subshell, "")
+ // TODO(sadovsky): It's unfortunate that we must duplicate help strings
+ // between RegisterChild and AddSubprocess. Will be fixed by my proposed
+ // refactoring.
+ shell.AddSubprocess(WSPRCommand, usageWSPR())
+ //shell.AddSubprocess(ShellCommand, subshell, "")
shell.AddFunction(LSCommand, ls, `<glob>...
issues glob requests using the current processes namespace library`)
diff --git a/lib/modules/core/echo.go b/lib/modules/core/echo.go
index 3f6ff42..f3adb9f 100644
--- a/lib/modules/core/echo.go
+++ b/lib/modules/core/echo.go
@@ -40,7 +40,7 @@
func echoServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
fl, args, err := parseListenFlags(args)
if err != nil {
- return fmt.Errorf("failed parsing args: %s", err)
+ return fmt.Errorf("failed to parse args: %s", err)
}
if err := checkArgs(args, 2, "<message> <name>"); err != nil {
return err
diff --git a/lib/modules/core/mounttable.go b/lib/modules/core/mounttable.go
index 9c4fec0..9326030 100644
--- a/lib/modules/core/mounttable.go
+++ b/lib/modules/core/mounttable.go
@@ -36,9 +36,8 @@
r := rt.R()
fl, args, err := parseListenFlags(args)
if err != nil {
- return fmt.Errorf("failed parsing args: %s", err)
+ return fmt.Errorf("failed to parse args: %s", err)
}
- // args = fl.Args()
lspec := initListenSpec(fl)
server, err := r.NewServer(options.ServesMountTable(true))
if err != nil {
@@ -72,7 +71,7 @@
func ls(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
details := false
- args = args[1:] // skip over comamnd name
+ args = args[1:] // skip over command name
if len(args) > 0 && args[0] == "-l" {
details = true
args = args[1:]
diff --git a/lib/modules/core/proxy.go b/lib/modules/core/proxy.go
index 7290543..3cc63ea 100644
--- a/lib/modules/core/proxy.go
+++ b/lib/modules/core/proxy.go
@@ -20,8 +20,10 @@
func proxyServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
fl, args, err := parseListenFlags(args)
if err != nil {
- return fmt.Errorf("failed parsing args: %s", err)
- } // args = fl.Args()
+ return fmt.Errorf("failed to parse args: %s", err)
+ }
+ // TODO(sadovsky): Why does this require >=1 arg? Seems 0 should be fine.
+ // Also note, we have no way to specify ">=0".
if err := checkArgs(args, -1, ""); err != nil {
return err
}
@@ -63,7 +65,6 @@
for _, p := range pub.Published() {
fmt.Fprintf(stdout, "PUBLISHED_PROXY_NAME=%s\n", p)
}
- fmt.Fprintf(stdout, "READY")
modules.WaitForEOF(stdin)
return nil
}
diff --git a/lib/modules/core/util.go b/lib/modules/core/util.go
index 81b6101..a429651 100644
--- a/lib/modules/core/util.go
+++ b/lib/modules/core/util.go
@@ -9,13 +9,19 @@
"veyron.io/veyron/veyron/lib/flags"
)
+func parseFlags(fl *flags.Flags, args []string) error {
+ if len(args) == 0 {
+ return nil
+ }
+ return fl.Parse(args[1:])
+}
+
+// parseListenFlags parses the given args using just the flags and env vars
+// defined in the veyron/lib/flags package.
func parseListenFlags(args []string) (*flags.Flags, []string, error) {
fs := flag.NewFlagSet("modules/core", flag.ContinueOnError)
fl := flags.CreateAndRegister(fs, flags.Listen)
- if len(args) == 0 {
- return fl, []string{}, nil
- }
- err := fl.Parse(args[1:])
+ err := parseFlags(fl, args)
return fl, fl.Args(), err
}
@@ -28,7 +34,7 @@
}
}
-// checkArgs checks for the expected number of args in args. A -ve
+// checkArgs checks for the expected number of args in args. A negative
// value means at least that number of args are expected.
func checkArgs(args []string, expected int, usage string) error {
got := len(args)
diff --git a/lib/modules/core/wspr.go b/lib/modules/core/wspr.go
new file mode 100644
index 0000000..2c242e8
--- /dev/null
+++ b/lib/modules/core/wspr.go
@@ -0,0 +1,72 @@
+package core
+
+import (
+ "flag"
+ "fmt"
+ "io"
+ "strings"
+
+ "veyron.io/veyron/veyron2"
+ "veyron.io/veyron/veyron2/options"
+
+ "veyron.io/veyron/veyron/lib/flags"
+ "veyron.io/veyron/veyron/lib/modules"
+ "veyron.io/wspr/veyron/services/wsprd/wspr"
+)
+
+var (
+ // TODO(sadovsky): We should restructure things so that we can avoid
+ // duplicating code between subprocess command impls and actual main()'s.
+ fs *flag.FlagSet = flag.NewFlagSet("wspr", flag.ContinueOnError)
+
+ port *int = fs.Int("port", 0, "Port to listen on.")
+ identd *string = fs.String("identd", "", "identd server name. Must be set.")
+ // TODO(ataly, ashankar, bjornick): Remove this flag once the old security
+ // model is killed.
+ newSecurityModel *bool = fs.Bool("new_security_model", false, "Use the new security model.")
+
+ fl *flags.Flags = flags.CreateAndRegister(fs, flags.Listen)
+)
+
+func usageWSPR() string {
+ res := []string{}
+ fs.VisitAll(func(f *flag.Flag) {
+ format := " -%s=%s: %s"
+ if getter, ok := f.Value.(flag.Getter); ok {
+ if _, ok := getter.Get().(string); ok {
+ // put quotes on the value
+ format = " -%s=%q: %s"
+ }
+ }
+ res = append(res, fmt.Sprintf(format, f.Name, f.DefValue, f.Usage))
+ })
+ return strings.Join(res, "\n") + "\n"
+}
+
+func init() {
+ modules.RegisterChild(WSPRCommand, usageWSPR(), startWSPR)
+}
+
+func startWSPR(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+ if err := parseFlags(fl, args); err != nil {
+ return fmt.Errorf("failed to parse args: %s", err)
+ }
+ args = fl.Args()
+
+ var opts []veyron2.ROpt
+ if *newSecurityModel {
+ opts = append(opts, options.ForceNewSecurityModel{})
+ }
+
+ proxy := wspr.NewWSPR(*port, initListenSpec(fl), *identd)
+ defer proxy.Shutdown()
+
+ addr := proxy.Listen()
+ go func() {
+ proxy.Serve()
+ }()
+
+ fmt.Fprintf(stdout, "WSPR_ADDR=%s\n", addr.String())
+ modules.WaitForEOF(stdin)
+ return nil
+}
diff --git a/runtimes/google/ipc/client.go b/runtimes/google/ipc/client.go
index 135100c..b2bd087 100644
--- a/runtimes/google/ipc/client.go
+++ b/runtimes/google/ipc/client.go
@@ -511,7 +511,7 @@
func (fc *flowClient) Finish(resultptrs ...interface{}) error {
defer vlog.LogCall()()
err := fc.finish(resultptrs...)
- vtrace.FromContext(fc.ctx).Annotate("Finished")
+ vtrace.FromContext(fc.ctx).Finish()
return err
}
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index fd213bc..dba781d 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -709,6 +709,8 @@
results, err := fs.processRequest()
+ ivtrace.FromContext(fs).Finish()
+
var traceResponse vtrace.Response
if fs.allowDebug {
traceResponse = ivtrace.Response(fs)
@@ -769,6 +771,9 @@
req, verr := fs.readIPCRequest()
if verr != nil {
+ // We don't know what the ipc call was supposed to be, but we'll create
+ // a placeholder span so we can capture annotations.
+ fs.T, _ = ivtrace.WithNewSpan(fs, "Failed IPC Call")
return nil, verr
}
fs.method = req.Method
diff --git a/runtimes/google/vtrace/collector.go b/runtimes/google/vtrace/collector.go
index 956b2d2..3313384 100644
--- a/runtimes/google/vtrace/collector.go
+++ b/runtimes/google/vtrace/collector.go
@@ -9,6 +9,17 @@
"veyron.io/veyron/veyron2/vtrace"
)
+func copySpanRecord(in *vtrace.SpanRecord) *vtrace.SpanRecord {
+ return &vtrace.SpanRecord{
+ ID: in.ID,
+ Parent: in.Parent,
+ Name: in.Name,
+ Start: in.Start,
+ End: in.End,
+ Annotations: append([]vtrace.Annotation{}, in.Annotations...),
+ }
+}
+
// collectors collect spans and annotations for output or analysis.
// collectors are safe to use from multiple goroutines simultaneously.
// TODO(mattr): collector should support log-based collection
@@ -44,18 +55,53 @@
}
}
-// annotate adds a span annotation to the collection.
-func (c *collector) annotate(s vtrace.Span, msg string) {
+func (c *collector) spanRecordLocked(s *span) *vtrace.SpanRecord {
+ sid := s.ID()
+ record, ok := c.spans[sid]
+ if !ok {
+ record = &vtrace.SpanRecord{
+ ID: sid,
+ Parent: s.parent,
+ Name: s.name,
+ Start: s.start.UnixNano(),
+ }
+ c.spans[sid] = record
+ }
+ return record
+}
+
+// start records the fact that a given span has begun.
+func (c *collector) start(s *span) {
c.mu.Lock()
defer c.mu.Unlock()
if c.method == vtrace.InMemory {
- sid := s.ID()
- record, ok := c.spans[sid]
- if !ok {
- record = &vtrace.SpanRecord{ID: sid, Parent: s.Parent(), Name: s.Name()}
- c.spans[sid] = record
- }
+ // Note that simply fetching the record is enough since
+ // if the record does not exist we will created it according
+ // to the start time in s.
+ c.spanRecordLocked(s)
+ }
+}
+
+// finish records the time that a span finished.
+func (c *collector) finish(s *span) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if c.method == vtrace.InMemory {
+ record := c.spanRecordLocked(s)
+ // TODO(mattr): Perhaps we should log an error if we have already been finished?
+ record.End = time.Now().UnixNano()
+ }
+}
+
+// annotate adds a span annotation to the collection.
+func (c *collector) annotate(s *span, msg string) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if c.method == vtrace.InMemory {
+ record := c.spanRecordLocked(s)
record.Annotations = append(record.Annotations, vtrace.Annotation{
When: time.Now().UnixNano(),
Message: msg,
@@ -69,7 +115,7 @@
defer c.mu.Unlock()
return vtrace.Response{
Method: c.method,
- Trace: c.recordLocked(),
+ Trace: c.traceRecordLocked(),
}
}
@@ -78,18 +124,13 @@
func (c *collector) Record() vtrace.TraceRecord {
c.mu.Lock()
defer c.mu.Unlock()
- return c.recordLocked()
+ return c.traceRecordLocked()
}
-func (c *collector) recordLocked() vtrace.TraceRecord {
+func (c *collector) traceRecordLocked() vtrace.TraceRecord {
spans := make([]vtrace.SpanRecord, 0, len(c.spans))
for _, span := range c.spans {
- spans = append(spans, vtrace.SpanRecord{
- ID: span.ID,
- Parent: span.Parent,
- Name: span.Name,
- Annotations: append([]vtrace.Annotation{}, span.Annotations...),
- })
+ spans = append(spans, *copySpanRecord(span))
}
return vtrace.TraceRecord{
ID: c.traceID,
@@ -110,12 +151,7 @@
// by assuming that children of parent need to start after parent
// and end before now.
for _, span := range t.Trace.Spans {
- c.spans[span.ID] = &vtrace.SpanRecord{
- ID: span.ID,
- Parent: span.Parent,
- Name: span.Name,
- Annotations: append([]vtrace.Annotation{}, span.Annotations...),
- }
+ c.spans[span.ID] = copySpanRecord(&span)
}
}
diff --git a/runtimes/google/vtrace/vtrace.go b/runtimes/google/vtrace/vtrace.go
index 0600677..3a41e41 100644
--- a/runtimes/google/vtrace/vtrace.go
+++ b/runtimes/google/vtrace/vtrace.go
@@ -4,6 +4,8 @@
package vtrace
import (
+ "time"
+
"veyron.io/veyron/veyron2/context"
"veyron.io/veyron/veyron2/uniqueid"
"veyron.io/veyron/veyron2/vlog"
@@ -16,6 +18,7 @@
parent uniqueid.ID
name string
collector *collector
+ start time.Time
}
func newSpan(parent uniqueid.ID, name string, collector *collector) *span {
@@ -28,8 +31,9 @@
parent: parent,
name: name,
collector: collector,
+ start: time.Now(),
}
- s.Annotate("Started")
+ collector.start(s)
return s
}
@@ -38,6 +42,7 @@
func (c *span) Name() string { return c.name }
func (c *span) Trace() vtrace.Trace { return c.collector }
func (c *span) Annotate(msg string) { c.collector.annotate(c, msg) }
+func (c *span) Finish() { c.collector.finish(c) }
// Request generates a vtrace.Request from the active Span.
func Request(ctx context.T) vtrace.Request {
diff --git a/runtimes/google/vtrace/vtrace_test.go b/runtimes/google/vtrace/vtrace_test.go
index 44b7d53..66c8bd7 100644
--- a/runtimes/google/vtrace/vtrace_test.go
+++ b/runtimes/google/vtrace/vtrace_test.go
@@ -122,11 +122,15 @@
}
func summary(span *vtrace.SpanRecord) string {
- msgs := []string{}
- for _, annotation := range span.Annotations {
- msgs = append(msgs, annotation.Message)
+ summary := span.Name
+ if len(span.Annotations) > 0 {
+ msgs := []string{}
+ for _, annotation := range span.Annotations {
+ msgs = append(msgs, annotation.Message)
+ }
+ summary += ": " + strings.Join(msgs, ", ")
}
- return span.Name + ": " + strings.Join(msgs, ",")
+ return summary
}
func expectSequence(t *testing.T, trace vtrace.TraceRecord, expectedSpans []string) {
@@ -135,16 +139,31 @@
}
spans := map[string]*vtrace.SpanRecord{}
+ summaries := []string{}
for i := range trace.Spans {
span := &trace.Spans[i]
+
+ // All spans should have a start.
+ if span.Start == 0 {
+ t.Errorf("span missing start: %#v", span)
+ }
+ // All spans except the root should have an end.
+ if span.Name != "" && span.End == 0 {
+ t.Errorf("span missing end: %#v", span)
+ if span.Start >= span.End {
+ t.Errorf("span end should be after start: %#v", span)
+ }
+ }
+
summary := summary(span)
+ summaries = append(summaries, summary)
spans[summary] = span
}
for i := range expectedSpans {
child, ok := spans[expectedSpans[i]]
if !ok {
- t.Errorf("expected span not found: %s", expectedSpans[i])
+ t.Errorf("expected span %s not found in %#v", expectedSpans[i], summaries)
continue
}
if i == 0 {
@@ -152,7 +171,7 @@
}
parent, ok := spans[expectedSpans[i-1]]
if !ok {
- t.Errorf("expected span not found: %s", expectedSpans[i-1])
+ t.Errorf("expected span %s not found in %#v", expectedSpans[i-1], summaries)
continue
}
if child.Parent != parent.ID {
@@ -207,11 +226,11 @@
span.Annotate("c0-end")
expectedSpans := []string{
- ": c0-begin,c0-end",
- "Client Call: c1.Run: Started,Finished",
- "Server Call: .Run: c1-begin,c1-end",
- "Client Call: c2.Run: Started,Finished",
- "Server Call: .Run: c2-begin,c2-end",
+ ": c0-begin, c0-end",
+ "Client Call: c1.Run",
+ "Server Call: .Run: c1-begin, c1-end",
+ "Client Call: c2.Run",
+ "Server Call: .Run: c2-begin, c2-end",
}
expectSequence(t, span.Trace().Record(), expectedSpans)
}
@@ -228,10 +247,10 @@
expectedSpans := []string{
": c0-end",
- "Client Call: c1.Run: Finished",
+ "Client Call: c1.Run",
"Server Call: .Run: c1-end",
- "Client Call: c2.Run: Finished",
- "Server Call: .Run: c2-begin,c2-end",
+ "Client Call: c2.Run",
+ "Server Call: .Run: c2-begin, c2-end",
}
expectSequence(t, span.Trace().Record(), expectedSpans)
}
diff --git a/tools/naming/simulator/commands.go b/tools/naming/simulator/commands.go
index 3efbd5b..cf82ed2 100644
--- a/tools/naming/simulator/commands.go
+++ b/tools/naming/simulator/commands.go
@@ -2,6 +2,7 @@
import (
"bytes"
+ "encoding/json"
"fmt"
"io"
"os"
@@ -21,18 +22,20 @@
needsHandle bool
fn builtinCmd
}{
- "print": {-1, "print <args>...", false, print},
- "help": {-1, "help", false, nil},
- "set": {-1, "set <var>=<val>...", false, set},
- "splitEP": {-1, "splitEP", false, splitEP},
- "assert": {2, "val1 val2", false, assert},
- "read": {-1, "read <handle> [var]", true, read},
- "eval": {1, "eval <handle>", true, eval},
- "wait": {1, "wait <handle>", true, wait},
- "stop": {1, "stop <handle>", true, stop},
- "stderr": {1, "stderr <handle>", true, stderr},
- "list": {0, "list", false, list},
- "quit": {0, "quit", false, quit},
+ "print": {-1, "print <args>...", false, print},
+ "help": {-1, "help", false, nil},
+ "set": {-1, "set <var>=<val>...", false, set},
+ "json_set": {-1, "<var>...", false, json_set},
+ "json_print": {0, "", false, json_print},
+ "splitEP": {-1, "splitEP", false, splitEP},
+ "assert": {2, "val1 val2", false, assert},
+ "read": {-1, "read <handle> [var]", true, read},
+ "eval": {1, "eval <handle>", true, eval},
+ "wait": {1, "wait <handle>", true, wait},
+ "stop": {1, "stop <handle>", true, stop},
+ "stderr": {1, "stderr <handle>", true, stderr},
+ "list": {0, "list", false, list},
+ "quit": {0, "quit", false, quit},
}
func init() {
@@ -222,3 +225,22 @@
l := handle.Session.ReadLine()
return l, handle.Session.Error()
}
+
+func json_set(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
+ for _, k := range args {
+ if v, present := sh.GetVar(k); present {
+ jsonDict[k] = v
+ } else {
+ return "", fmt.Errorf("unrecognised variable: %q", k)
+ }
+ }
+ return "", nil
+}
+
+func json_print(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
+ bytes, err := json.Marshal(jsonDict)
+ if err != nil {
+ return "", err
+ }
+ return string(bytes), nil
+}
diff --git a/tools/naming/simulator/driver.go b/tools/naming/simulator/driver.go
index 31e6038..c6abba2 100644
--- a/tools/naming/simulator/driver.go
+++ b/tools/naming/simulator/driver.go
@@ -33,11 +33,13 @@
var (
interactive bool
handles map[string]*cmdState
+ jsonDict map[string]string
)
func init() {
flag.BoolVar(&interactive, "interactive", true, "set interactive/batch mode")
handles = make(map[string]*cmdState)
+ jsonDict = make(map[string]string)
flag.Usage = usage
}
@@ -126,7 +128,9 @@
}
if err := process(shell, line, lineno); err != nil {
fmt.Printf("ERROR: %d> %q: %v\n", lineno, line, err)
- os.Exit(1)
+ if !interactive {
+ os.Exit(1)
+ }
}
}
shell.SetVar("_", strconv.Itoa(lineno))
@@ -194,11 +198,8 @@
expect.NewSession(nil, handle.Stdout(), time.Minute),
line,
}
- if !interactive {
- fmt.Printf("%d> %s\n", lineno, line)
- }
+ output(lineno, line)
}
-
return nil
}
diff --git a/tools/naming/simulator/json_example.scr b/tools/naming/simulator/json_example.scr
new file mode 100644
index 0000000..1fe1e3e
--- /dev/null
+++ b/tools/naming/simulator/json_example.scr
@@ -0,0 +1,29 @@
+
+cache off
+
+set localaddr=--veyron.tcp.address=127.0.0.1:0
+
+root -- $localaddr
+set root=$_
+eval $root
+set ROOT_NAME=$MT_NAME
+read $root
+eval $root
+set ROOT_PID=$PID
+json_set ROOT_NAME ROOT_PID
+
+set PROXY_MOUNTPOINT=$ROOT_NAME/proxy/mp
+proxyd -- $localaddr $PROXY_MOUNTPOINT
+set proxyd=$_
+read $proxyd
+eval $proxyd
+set PROXYD_NAME=$PROXY_NAME
+splitEP $PROXY_NAME
+set PROXY_HOST_ADDR=$P2
+json_set PROXY_MOUNTPOINT PROXY_NAME PROXY_HOST_ADDR
+
+
+json_print
+
+# uncomment wait $root to have the script leave all of the processes running
+#wait $root
diff --git a/tools/servicerunner/main.go b/tools/servicerunner/main.go
new file mode 100644
index 0000000..366e8f4
--- /dev/null
+++ b/tools/servicerunner/main.go
@@ -0,0 +1,105 @@
+// This binary starts several services (mount table, proxy, wspr), then prints a
+// JSON map with their vars to stdout (as a single line), then waits forever.
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "os"
+ "strings"
+ "time"
+
+ "veyron.io/veyron/veyron2/rt"
+
+ "veyron.io/veyron/veyron/lib/expect"
+ "veyron.io/veyron/veyron/lib/modules"
+ "veyron.io/veyron/veyron/lib/modules/core"
+ _ "veyron.io/veyron/veyron/profiles"
+)
+
+func panicOnError(err error) {
+ if err != nil {
+ panic(err)
+ }
+}
+
+// updateVars captures the vars from the given Handle's stdout and adds them to
+// the given vars map, overwriting existing entries.
+func updateVars(h modules.Handle, vars map[string]string, varNames ...string) error {
+ varsToAdd := map[string]bool{}
+ for _, v := range varNames {
+ varsToAdd[v] = true
+ }
+ numLeft := len(varsToAdd)
+
+ s := expect.NewSession(nil, h.Stdout(), 10*time.Second)
+ for {
+ l := s.ReadLine()
+ if err := s.OriginalError(); err != nil {
+ return err // EOF or otherwise
+ }
+ parts := strings.Split(l, "=")
+ if len(parts) != 2 {
+ return fmt.Errorf("Unexpected line: %s", l)
+ }
+ if _, ok := varsToAdd[parts[0]]; ok {
+ numLeft--
+ vars[parts[0]] = parts[1]
+ if numLeft == 0 {
+ break
+ }
+ }
+ }
+ return nil
+}
+
+func main() {
+ rt.Init()
+
+ // TODO(sadovsky): It would be better if Dispatch() itself performed the env
+ // check.
+ if os.Getenv(modules.ShellEntryPoint) != "" {
+ panicOnError(modules.Dispatch())
+ return
+ }
+
+ sh := modules.NewShell()
+ defer sh.Cleanup(os.Stderr, os.Stderr)
+ // TODO(sadovsky): Shell only does this for tests. It would be better if it
+ // either always did it or never did it.
+ if os.Getenv("VEYRON_CREDENTIALS") == "" {
+ panicOnError(sh.CreateAndUseNewCredentials())
+ }
+ // TODO(sadovsky): The following line will not be needed if the modules
+ // library is restructured per my proposal.
+ core.Install(sh)
+
+ vars := map[string]string{}
+
+ h, err := sh.Start("root", "--", "--veyron.tcp.address=127.0.0.1:0")
+ panicOnError(err)
+ updateVars(h, vars, "MT_NAME")
+
+ // Set NAMESPACE_ROOT env var, consumed downstream by proxyd among others.
+ // NOTE(sadovsky): If this is not set, proxyd takes several seconds to start;
+ // if it is set, proxyd starts instantly. Fun!
+ sh.SetVar("NAMESPACE_ROOT", vars["MT_NAME"])
+
+ // NOTE(sadovsky): The proxyd binary requires --protocol and --address flags
+ // while the proxyd command instead uses ListenSpec flags.
+ h, err = sh.Start("proxyd", "--", "--veyron.tcp.address=127.0.0.1:0", "p")
+ panicOnError(err)
+ updateVars(h, vars, "PROXY_ADDR")
+
+ // TODO(sadovsky): Which identd should we be using?
+ h, err = sh.Start("wsprd", "--", "--veyron.proxy="+vars["PROXY_ADDR"], "--identd=/proxy.envyor.com:8101/identity/veyron-test/google")
+ panicOnError(err)
+ updateVars(h, vars, "WSPR_ADDR")
+
+ bytes, err := json.Marshal(vars)
+ panicOnError(err)
+ fmt.Println(string(bytes))
+
+ // Wait to be killed.
+ select {}
+}