Merge "veyron/tools/naming/simulator: add support for running proxies, sundry fixes."
diff --git a/lib/exec/exec_test.go b/lib/exec/exec_test.go
index cc1b292..f34b280 100644
--- a/lib/exec/exec_test.go
+++ b/lib/exec/exec_test.go
@@ -394,6 +394,22 @@
clean(t, ph)
}
+func TestExitEarly(t *testing.T) {
+ name := "exitEarly"
+ cmd := helperCommand(name)
+ tk := timekeeper.NewManualTime()
+ ph := vexec.NewParentHandle(cmd, vexec.TimeKeeperOpt{tk})
+ err := ph.Start()
+ if err != nil {
+ t.Fatalf("%s: start: %v", name, err)
+ }
+ e := ph.Wait(time.Second)
+ if e == nil || e.Error() != "exit status 1" {
+ t.Errorf("Unexpected value for error: %v\n", e)
+ }
+ clean(t, ph)
+}
+
func verifyNoExecVariable() {
version := os.Getenv(vexec.VersionVariable)
if len(version) != 0 {
@@ -434,6 +450,12 @@
cmd, args := args[0], args[1:]
switch cmd {
+ case "exitEarly":
+ _, err := vexec.GetChildHandle()
+ if err != nil {
+ log.Fatal(os.Stderr, "%s\n", err)
+ }
+ os.Exit(1)
case "testNeverReady":
_, err := vexec.GetChildHandle()
if err != nil {
diff --git a/lib/flags/doc.go b/lib/flags/doc.go
index ff98c9d..ef8c2c5 100644
--- a/lib/flags/doc.go
+++ b/lib/flags/doc.go
@@ -1,36 +1,13 @@
// Package flags provides flag definitions for commonly used flags and
// and, where appropriate, implementations of the flag.Value interface
-// for those flags to ensure that only valid values of those flags
-// are supplied.
-// In general, this package will be used by veyron profiles and the
-// runtime implementations, but can also be used by any application
+// for those flags to ensure that only valid values of those flags are
+// supplied. 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.
//
// TODO(cnicolaou): move reading of environment variables to here also,
// flags will override the environment variable settings.
+//
+// TODO(cnicolaou): implement simply subsetting of the flags to be defined
+// and parsed - e.g. for server configs, basic runtime configs/security etc.
package flags
-
-import "flag"
-
-type Flags struct {
- ListenProtocolFlag TCPProtocolFlag
- ListenAddressFlag IPHostPortFlag
- ListenProxyFlag string
- NamespaceRootsFlag string // TODO(cnicolaou): provide flag.Value impl
- CredentialsFlag string // TODO(cnicolaou): provide flag.Value impl
-}
-
-// New returns a new instance of flags.Flags. Calling Parse on the supplied
-// flagSet will populate the fields of the return flags.Flags with the appropriate
-// values.
-func New(fs *flag.FlagSet) *Flags {
- t := &Flags{}
- t.ListenProtocolFlag = TCPProtocolFlag{"tcp"}
- t.ListenAddressFlag = IPHostPortFlag{Port: "0"}
- fs.Var(&t.ListenProtocolFlag, "veyron.tcp.protocol", "protocol to listen with")
- fs.Var(&t.ListenAddressFlag, "veyron.tcp.address", "address to listen on")
- fs.StringVar(&t.ListenProxyFlag, "veyron.proxy", "", "object name of proxy service to use to export services across network boundaries")
- fs.StringVar(&t.NamespaceRootsFlag, "veyron.namespace.roots", "", ": separated list of roots for the local namespace")
- fs.StringVar(&t.CredentialsFlag, "veyron.credentials", "", "directory to use for storing security credentials")
- return t
-}
diff --git a/lib/flags/flags.go b/lib/flags/flags.go
new file mode 100644
index 0000000..270b72f
--- /dev/null
+++ b/lib/flags/flags.go
@@ -0,0 +1,44 @@
+package flags
+
+import "flag"
+
+type Flags struct {
+ // The FlagSet passed in as a parameter to New
+ FlagSet *flag.FlagSet
+
+ // As needed to initialize ipc.ListenSpec.
+ ListenProtocolFlag TCPProtocolFlag
+ ListenAddressFlag IPHostPortFlag
+ ListenProxyFlag string
+
+ // TODO(cnicolaou): implement these.
+ NamespaceRootsFlag string // TODO(cnicolaou): provide flag.Value impl
+ CredentialsFlag string // TODO(cnicolaou): provide flag.Value impl
+}
+
+// New returns a new instance of flags.Flags. Calling Parse on the supplied
+// flagSet will populate the fields of the returned flags.Flags with the
+// appropriate values. The currently supported set of flags only allows
+// for configuring one service at a time, but in the future this will
+// be expanded to support multiple services.
+func New(fs *flag.FlagSet) *Flags {
+ t := &Flags{FlagSet: fs}
+ t.ListenProtocolFlag = TCPProtocolFlag{"tcp"}
+ t.ListenAddressFlag = IPHostPortFlag{Port: "0"}
+ fs.Var(&t.ListenProtocolFlag, "veyron.tcp.protocol", "protocol to listen with")
+ fs.Var(&t.ListenAddressFlag, "veyron.tcp.address", "address to listen on")
+ fs.StringVar(&t.ListenProxyFlag, "veyron.proxy", "", "object name of proxy service to use to export services across network boundaries")
+ fs.StringVar(&t.NamespaceRootsFlag, "veyron.namespace.roots", "", "colon separated list of roots for the local namespace")
+ fs.StringVar(&t.CredentialsFlag, "veyron.credentials", "", "directory to use for storing security credentials")
+ return t
+}
+
+// Args returns the unparsed args, as per flag.Args
+func (fs *Flags) Args() []string {
+ return fs.FlagSet.Args()
+}
+
+// Parse parses the supplied args, as per flag.Parse
+func (fs *Flags) Parse(args []string) error {
+ return fs.FlagSet.Parse(args)
+}
diff --git a/lib/flags/flags_test.go b/lib/flags/flags_test.go
index 4030af6..7b17e99 100644
--- a/lib/flags/flags_test.go
+++ b/lib/flags/flags_test.go
@@ -2,6 +2,7 @@
import (
"flag"
+ "io/ioutil"
"testing"
"veyron.io/veyron/veyron/lib/flags"
@@ -21,4 +22,23 @@
if got, want := fl.ListenAddressFlag.String(), addr; got != want {
t.Errorf("got %q, want %q", got, want)
}
+ if got, want := len(fl.Args()), 0; got != want {
+ t.Errorf("got %d, want %d", got, want)
+ }
+}
+
+func TestFlagError(t *testing.T) {
+ fs := flag.NewFlagSet("test", flag.ContinueOnError)
+ fs.SetOutput(ioutil.Discard)
+ fl := flags.New(fs)
+ addr := "192.168.10.1:0"
+ args := []string{"--xxxveyron.tcp.address=" + addr, "not an arg"}
+ err := fl.Parse(args)
+ if err == nil {
+ t.Fatalf("expected this to fail!")
+ }
+ if got, want := len(fl.Args()), 1; got != want {
+ t.Errorf("got %d, want %d [args: %v]", got, want, fl.Args())
+ }
+
}
diff --git a/lib/modules/core/core.go b/lib/modules/core/core.go
index 9aa5767..bf4e6d4 100644
--- a/lib/modules/core/core.go
+++ b/lib/modules/core/core.go
@@ -37,37 +37,64 @@
//
// setRoots <name>...
// sets the local namespace's roots to the supplied names.
-// echoClient
-// echoServer
+//
+// echoServer <message> <name>
+// runs on echoServer at <name>, it will echo back <message>: <text>
+// where <text> is supplied by the client
+// echoClient <name> <text>
+// invoke <name>.Echo(<text>)
+//
+// proxyd <names>...
+// runs a proxy server
package core
import "veyron.io/veyron/veyron/lib/modules"
const (
- RootMTCommand = "root"
- MTCommand = "mt"
+ // Functions
LSCommand = "ls"
- LSExternalCommand = "lse"
SetNamespaceRootsCommand = "setRoots"
ResolveCommand = "resolve"
ResolveMTCommand = "resolveMT"
- EchoServerCommand = "echoServer"
- EchoClientCommand = "echoClient"
SleepCommand = "sleep"
TimeCommand = "time"
MountCommand = "mount"
NamespaceCacheCommand = "cache"
+ // Subprocesses
+ EchoServerCommand = "echoServer"
+ EchoClientCommand = "echoClient"
+ RootMTCommand = "root"
+ MTCommand = "mt"
+ LSExternalCommand = "lse"
+ ProxyServerCommand = "proxyd"
+ ShellCommand = "sh"
)
// NewShell returns a new Shell instance with the core commands installed.
func NewShell() *modules.Shell {
- shell := modules.NewShell(".*")
+ shell := modules.NewShell("")
Install(shell)
return shell
}
// Install installs the core commands into the supplied Shell.
func Install(shell *modules.Shell) {
+ // Explicitly add the subprocesses so that we can provide a help string
+ shell.AddSubprocess(EchoServerCommand, `<message> <name>
+ mount an echo server at <name>, it will prepend <message> to its responses`)
+ shell.AddSubprocess(EchoClientCommand, `
+ <name> <text>
+ invoke name.Echo(<text>)`)
+ shell.AddSubprocess(RootMTCommand, `run a root mount table
+ it will output MT_NAME, MT_ADDR and PID`)
+ shell.AddSubprocess(MTCommand, `<name>
+ run a mount table mounted at <name>`)
+ shell.AddSubprocess(LSExternalCommand, `<glob>
+ 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, "")
+
shell.AddFunction(LSCommand, ls, `<glob>...
issues glob requests using the current processes namespace library`)
shell.AddFunction(ResolveCommand, resolveObject, `<name>
diff --git a/lib/modules/core/core_internal_test.go b/lib/modules/core/core_internal_test.go
new file mode 100644
index 0000000..3679f2b
--- /dev/null
+++ b/lib/modules/core/core_internal_test.go
@@ -0,0 +1,21 @@
+package core
+
+import "testing"
+
+func TestCheckArgs(t *testing.T) {
+ if got, want := checkArgs([]string{}, 1, "<a>"), `wrong # args (got 0, expected 1) expected: "<a>" got: []`; got == nil || got.Error() != want {
+ t.Errorf("got %v, want %v", got, want)
+ }
+ if got, want := checkArgs([]string{}, -1, "<a>"), `wrong # args (got 0, expected >=1) expected: "<a>" got: []`; got == nil || got.Error() != want {
+ t.Errorf("got %v, want %v", got, want)
+ }
+ if got := checkArgs([]string{"a"}, 1, ""); got != nil {
+ t.Errorf("unexpected error: %s", got)
+ }
+ if got := checkArgs([]string{"a"}, -1, ""); got != nil {
+ t.Errorf("unexpected error: %s", got)
+ }
+ if got := checkArgs([]string{"a", "b"}, -1, ""); got != nil {
+ t.Errorf("unexpected error: %s", got)
+ }
+}
diff --git a/lib/modules/core/core_test.go b/lib/modules/core/core_test.go
index 843221c..c108b72 100644
--- a/lib/modules/core/core_test.go
+++ b/lib/modules/core/core_test.go
@@ -11,12 +11,13 @@
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/rt"
+ "veyron.io/veyron/veyron2/vlog"
"veyron.io/veyron/veyron/lib/expect"
"veyron.io/veyron/veyron/lib/modules"
"veyron.io/veyron/veyron/lib/modules/core"
-
"veyron.io/veyron/veyron/lib/testutil"
+ _ "veyron.io/veyron/veyron/profiles"
)
func TestCommands(t *testing.T) {
@@ -38,6 +39,7 @@
sh := core.NewShell()
return sh, func() {
if testing.Verbose() {
+ vlog.Infof("------ cleanup ------")
sh.Cleanup(os.Stderr, os.Stderr)
} else {
sh.Cleanup(nil, nil)
@@ -45,10 +47,15 @@
}
}
+func testArgs(args ...string) []string {
+ var targs = []string{"--", "--veyron.tcp.address=127.0.0.1:0"}
+ return append(targs, args...)
+}
+
func TestRoot(t *testing.T) {
shell, fn := newShell()
defer fn()
- root, err := shell.Start(core.RootMTCommand)
+ root, err := shell.Start(core.RootMTCommand, testArgs()...)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -59,16 +66,17 @@
root.CloseStdin()
}
-func startMountTables(t *testing.T, sh *modules.Shell, mountPoints ...string) (map[string]string, error) {
+func startMountTables(t *testing.T, sh *modules.Shell, mountPoints ...string) (map[string]string, func(), error) {
// Start root mount table
- root, err := sh.Start(core.RootMTCommand)
+ root, err := sh.Start(core.RootMTCommand, testArgs()...)
if err != nil {
t.Fatalf("unexpected error for root mt: %s", err)
}
+ sh.Forget(root)
rootSession := expect.NewSession(t, root.Stdout(), time.Minute)
rootName := rootSession.ExpectVar("MT_NAME")
if t.Failed() {
- return nil, rootSession.Error()
+ return nil, nil, rootSession.Error()
}
sh.SetVar("NAMESPACE_ROOT", rootName)
mountAddrs := make(map[string]string)
@@ -76,20 +84,27 @@
// Start the mount tables
for _, mp := range mountPoints {
- h, err := sh.Start(core.MTCommand, mp)
+ h, err := sh.Start(core.MTCommand, testArgs(mp)...)
if err != nil {
- return nil, fmt.Errorf("unexpected error for mt %q: %s", mp, err)
+ return nil, nil, fmt.Errorf("unexpected error for mt %q: %s", mp, err)
}
s := expect.NewSession(t, h.Stdout(), time.Minute)
// Wait until each mount table has at least called Serve to
// mount itself.
mountAddrs[mp] = s.ExpectVar("MT_NAME")
if s.Failed() {
- return nil, s.Error()
+ return nil, nil, s.Error()
}
}
- return mountAddrs, nil
-
+ deferFn := func() {
+ if testing.Verbose() {
+ vlog.Infof("------ root shutdown ------")
+ root.Shutdown(os.Stderr, os.Stderr)
+ } else {
+ root.Shutdown(nil, nil)
+ }
+ }
+ return mountAddrs, deferFn, nil
}
func getMatchingMountpoint(r [][]string) string {
@@ -115,10 +130,12 @@
defer fn()
mountPoints := []string{"a", "b", "c", "d", "e"}
- mountAddrs, err := startMountTables(t, shell, mountPoints...)
+ mountAddrs, fn, err := startMountTables(t, shell, mountPoints...)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
+ defer fn()
+
rootName := mountAddrs["root"]
ls, err := shell.Start(core.LSCommand, rootName+"/...")
if err != nil {
@@ -184,7 +201,7 @@
shell, fn := newShell()
defer fn()
- srv, err := shell.Start(core.EchoServerCommand, "test", "")
+ srv, err := shell.Start(core.EchoServerCommand, testArgs("test", "")...)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -193,13 +210,13 @@
if len(name) == 0 {
t.Fatalf("failed to get name")
}
-
clt, err := shell.Start(core.EchoClientCommand, name, "a message")
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
cltSession := expect.NewSession(t, clt.Stdout(), time.Minute)
cltSession.Expect("test: a message")
+ srv.Shutdown(nil, nil)
}
func TestResolve(t *testing.T) {
@@ -207,14 +224,15 @@
defer fn()
mountPoints := []string{"a", "b"}
- mountAddrs, err := startMountTables(t, shell, mountPoints...)
+ mountAddrs, fn, err := startMountTables(t, shell, mountPoints...)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
+ defer fn()
rootName := mountAddrs["root"]
mtName := "b"
echoName := naming.Join(mtName, "echo")
- srv, err := shell.Start(core.EchoServerCommand, "test", echoName)
+ srv, err := shell.Start(core.EchoServerCommand, testArgs("test", echoName)...)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -279,6 +297,8 @@
if err := resolver.Shutdown(nil, os.Stderr); err != nil {
t.Fatalf("unexpected error: %s", err)
}
+ srv.Shutdown(nil, nil)
+ nsroots.Shutdown(nil, nil)
}
func TestHelperProcess(t *testing.T) {
diff --git a/lib/modules/core/echo.go b/lib/modules/core/echo.go
index 9cac914..5fd3307 100644
--- a/lib/modules/core/echo.go
+++ b/lib/modules/core/echo.go
@@ -11,7 +11,6 @@
"veyron.io/veyron/veyron2/security"
"veyron.io/veyron/veyron/lib/modules"
- "veyron.io/veyron/veyron/profiles"
)
func init() {
@@ -39,17 +38,22 @@
}
func echoServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- if len(args) != 3 {
- return fmt.Errorf("wrong # args")
+ fl, err := ParseCommonFlags(args)
+ if err != nil {
+ return fmt.Errorf("failed parsing args: %s", err)
}
- id, mp := args[1], args[2]
+ args = fl.Args()
+ if err := checkArgs(args, 2, "<message> <name>"); err != nil {
+ return err
+ }
+ id, mp := args[0], args[1]
disp := &treeDispatcher{id: id}
server, err := rt.R().NewServer()
if err != nil {
return err
}
defer server.Stop()
- ep, err := server.Listen(profiles.LocalListenSpec)
+ ep, err := server.Listen(initListenSpec(fl))
if err != nil {
return err
}
@@ -64,11 +68,16 @@
}
func echoClient(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- if len(args) < 3 {
- return fmt.Errorf("wrong # args")
+ fl, err := ParseCommonFlags(args)
+ if err != nil {
+ return fmt.Errorf("failed parsing args: %s", err)
}
- name := args[1]
- args = args[2:]
+ args = fl.Args()
+ if err := checkArgs(args, 2, "<name> <message>"); err != nil {
+ return err
+ }
+ name := args[0]
+ args = args[1:]
client := rt.R().Client()
for _, a := range args {
ctxt := rt.R().NewContext()
diff --git a/lib/modules/core/flags.go b/lib/modules/core/flags.go
new file mode 100644
index 0000000..9a8bc95
--- /dev/null
+++ b/lib/modules/core/flags.go
@@ -0,0 +1 @@
+package core
diff --git a/lib/modules/core/misc.go b/lib/modules/core/misc.go
index e70aa02..577f3b2 100644
--- a/lib/modules/core/misc.go
+++ b/lib/modules/core/misc.go
@@ -42,8 +42,8 @@
}
func mountServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- if len(args) < 4 {
- return fmt.Errorf("wrong # args")
+ if err := checkArgs(args[1:], -3, "<mount point> <server> <ttl> [M][R]"); err != nil {
+ return err
}
var opts []naming.MountOpt
for _, arg := range args[4:] {
@@ -70,8 +70,8 @@
}
func namespaceCache(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- if len(args) != 2 {
- return fmt.Errorf("wrong # args")
+ if err := checkArgs(args[1:], 1, "on|off"); err != nil {
+ return err
}
disable := true
switch args[1] {
diff --git a/lib/modules/core/mounttable.go b/lib/modules/core/mounttable.go
index 79d9844..307dde3 100644
--- a/lib/modules/core/mounttable.go
+++ b/lib/modules/core/mounttable.go
@@ -12,7 +12,6 @@
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron/lib/modules"
- "veyron.io/veyron/veyron/profiles"
mounttable "veyron.io/veyron/veyron/services/mounttable/lib"
)
@@ -26,34 +25,37 @@
}
func mountTable(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- if len(args) != 2 {
- return fmt.Errorf("expected exactly one argument: <mount point>")
- }
return runMT(false, stdin, stdout, stderr, env, args...)
}
func rootMountTable(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- if len(args) != 1 {
- return fmt.Errorf("expected no arguments")
- }
return runMT(true, stdin, stdout, stderr, env, args...)
}
func runMT(root bool, stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- r := rt.Init()
+ r := rt.R()
+ fl, err := ParseCommonFlags(args)
+ if err != nil {
+ return fmt.Errorf("failed parsing args: %s", err)
+ }
+ args = fl.Args()
+ lspec := initListenSpec(fl)
server, err := r.NewServer(options.ServesMountTable(true))
if err != nil {
return fmt.Errorf("root failed: %v", err)
}
mp := ""
if !root {
- mp = args[1]
+ if err := checkArgs(args, 1, "<mount point>"); err != nil {
+ return err
+ }
+ mp = args[0]
}
mt, err := mounttable.NewMountTable("")
if err != nil {
return fmt.Errorf("mounttable.NewMountTable failed: %s", err)
}
- ep, err := server.Listen(profiles.LocalListenSpec)
+ ep, err := server.Listen(lspec)
if err != nil {
return fmt.Errorf("server.Listen failed: %s", err)
}
@@ -110,8 +112,8 @@
type resolver func(ctx context.T, name string) (names []string, err error)
func resolve(fn resolver, stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- if len(args) != 2 {
- return fmt.Errorf("wrong # args")
+ if err := checkArgs(args[1:], 1, "<name>"); err != nil {
+ return err
}
name := args[1]
servers, err := fn(rt.R().NewContext(), name)
@@ -136,8 +138,8 @@
func setNamespaceRoots(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
ns := rt.R().Namespace()
- if len(args) < 2 {
- return fmt.Errorf("wrong # args")
+ if err := checkArgs(args, -1, "<name>..."); err != nil {
+ return err
}
return ns.SetRoots(args[1:]...)
}
diff --git a/lib/modules/core/proxy.go b/lib/modules/core/proxy.go
new file mode 100644
index 0000000..0e24fe1
--- /dev/null
+++ b/lib/modules/core/proxy.go
@@ -0,0 +1,70 @@
+package core
+
+import (
+ "fmt"
+ "io"
+ "time"
+
+ "veyron.io/veyron/veyron2/naming"
+ "veyron.io/veyron/veyron2/rt"
+
+ "veyron.io/veyron/veyron/lib/modules"
+ "veyron.io/veyron/veyron/runtimes/google/ipc/stream/proxy"
+ "veyron.io/veyron/veyron/runtimes/google/lib/publisher"
+)
+
+func init() {
+ modules.RegisterChild(ProxyServerCommand, `<name>`, proxyServer)
+}
+
+func proxyServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+ fl, err := ParseCommonFlags(args)
+ if err != nil {
+ return fmt.Errorf("failed parsing args: %s", err)
+ }
+ args = fl.Args()
+ if err := checkArgs(args, -1, ""); err != nil {
+ return err
+ }
+ expected := len(args)
+ rid, err := naming.NewRoutingID()
+ if err != nil {
+ return err
+ }
+
+ // TODO(ashankar): Set the second argument to r.Principal() once the
+ // old security model is no longer operational.
+ proxy, err := proxy.New(rid, nil, fl.ListenProtocolFlag.String(), fl.ListenAddressFlag.String(), "")
+ if err != nil {
+ return err
+ }
+ defer proxy.Shutdown()
+ pname := naming.JoinAddressName(proxy.Endpoint().String(), "//")
+ fmt.Fprintf(stdout, "PROXY_ADDR=%s\n", proxy.Endpoint().String())
+ fmt.Fprintf(stdout, "PROXY_NAME=%s\n", pname)
+ r := rt.R()
+ pub := publisher.New(r.NewContext(), r.Namespace(), time.Minute)
+ defer pub.WaitForStop()
+ defer pub.Stop()
+ pub.AddServer(pname, false)
+ for _, name := range args {
+ pub.AddName(name)
+ }
+ // Wait for all the entries to be published.
+ for {
+ got := len(pub.Published())
+ if expected == got {
+ break
+ }
+ fmt.Fprintf(stderr, "%s\n", pub.DebugString())
+ delay := time.Second
+ fmt.Fprintf(stderr, "Sleeping: %s\n", delay)
+ time.Sleep(delay)
+ }
+ 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
new file mode 100644
index 0000000..507b7e3
--- /dev/null
+++ b/lib/modules/core/util.go
@@ -0,0 +1,47 @@
+package core
+
+import (
+ "flag"
+ "fmt"
+
+ "veyron.io/veyron/veyron2/ipc"
+
+ "veyron.io/veyron/veyron/lib/flags"
+)
+
+// ParseCommonFlags parses the supplied args for the common set of flags
+// and environment variables defined in in the veyron/lib/flags package.
+func ParseCommonFlags(args []string) (*flags.Flags, error) {
+ fs := flag.NewFlagSet("modules/core", flag.ContinueOnError)
+ fl := flags.New(fs)
+ if len(args) == 0 {
+ return fl, fmt.Errorf("no args supplied")
+ }
+ err := fl.Parse(args[1:])
+ return fl, err
+}
+
+func initListenSpec(fl *flags.Flags) ipc.ListenSpec {
+ return ipc.ListenSpec{
+ Protocol: fl.ListenProtocolFlag.String(),
+ Address: fl.ListenAddressFlag.String(),
+ Proxy: fl.ListenProxyFlag,
+ }
+}
+
+// checkArgs checks for the expected number of args in args. A -ve
+// value means at least that number of args are expected.
+func checkArgs(args []string, expected int, usage string) error {
+ got := len(args)
+ if expected < 0 {
+ expected = -expected
+ if got < expected {
+ return fmt.Errorf("wrong # args (got %d, expected >=%d) expected: %q got: %v", got, expected, usage, args)
+ }
+ } else {
+ if got != expected {
+ return fmt.Errorf("wrong # args (got %d, expected %d) expected: %q got: %v", got, expected, usage, args)
+ }
+ }
+ return nil
+}
diff --git a/tools/naming/simulator/ambiguity.scr b/tools/naming/simulator/ambiguity.scr
index f20b97b..df47997 100644
--- a/tools/naming/simulator/ambiguity.scr
+++ b/tools/naming/simulator/ambiguity.scr
@@ -19,15 +19,17 @@
# "s1/a", ["/s3/c"(mountpoint)]
# "s1/a", ["/s4//"(mountpoint)]
-root
+set localaddr="--veyron.tcp.address=127.0.0.1:0"
+
+root -- $localaddr
eval $_
set s1=$MT_NAME
-root
+root -- $localaddr
eval $_
set s2=$MT_NAME
-root
+root -- $localaddr
eval $_
set s3=$MT_NAME
@@ -37,7 +39,7 @@
mount $s2/b $s3/c 1h
wait $_
-echoServer "Echo" $s3/c
+echoServer -- $localaddr "Echo" $s3/c
set es_h=$_
# Returns the root and three mounts at s1/a.
diff --git a/tools/naming/simulator/commands.go b/tools/naming/simulator/commands.go
index b11a3da..3efbd5b 100644
--- a/tools/naming/simulator/commands.go
+++ b/tools/naming/simulator/commands.go
@@ -13,24 +13,26 @@
type builtinCmd func(sh *modules.Shell, state *cmdState, args ...string) (string, error)
-var varRE = regexp.MustCompile("(.*)=(.*)")
+var varRE = regexp.MustCompile("(.*?)=(.*)")
var builtins = map[string]*struct {
- nargs int
+ nargs int // -1 means a variable # of args.
usage string
needsHandle bool
fn builtinCmd
}{
- "print": {-1, "print <args>...", false, print},
- "help": {-1, "help", false, nil},
- "set": {-1, "set <var>=<val>...", false, set},
- "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},
- "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},
+ "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() {
@@ -42,6 +44,19 @@
return r, nil
}
+func splitEP(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
+ ep := strings.TrimLeft(args[0], "/")
+ ep = strings.TrimRight(ep, "/")
+ ep = strings.TrimLeft(ep, "@")
+ ep = strings.TrimRight(ep, "@")
+ parts := strings.Split(ep, "@")
+ sh.SetVar("PN", fmt.Sprintf("%d", len(parts)))
+ for i, p := range parts {
+ sh.SetVar(fmt.Sprintf("P%d", i), p)
+ }
+ return "", nil
+}
+
func help(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
r := ""
if len(args) == 0 {
@@ -103,6 +118,12 @@
return "", nil
}
+func stderr(sh *modules.Shell, state *cmdState, args ...string) (string, error) {
+ state.Session.Finish(nil)
+ delete(handles, args[0])
+ return readStderr(state)
+}
+
func readStderr(state *cmdState) (string, error) {
var b bytes.Buffer
if err := state.Handle.Shutdown(nil, &b); err != nil && err != io.EOF {
@@ -164,7 +185,7 @@
if err != nil {
return r, err
}
- // Now read and return the contents of stderr as e
+ // Now read and return the contents of stderr as a string
if str, err := readStderr(state); err != nil && err != io.EOF {
return str, err
}
@@ -188,7 +209,7 @@
r += fmt.Sprintf("%s: ok\n", k)
}
}
- fmt.Fprintf(os.Stdout, r)
+ fmt.Fprintf(os.Stdout, "%s\n", r)
os.Exit(0)
panic("unreachable")
}
diff --git a/tools/naming/simulator/driver.go b/tools/naming/simulator/driver.go
index db4748e..31e6038 100644
--- a/tools/naming/simulator/driver.go
+++ b/tools/naming/simulator/driver.go
@@ -21,6 +21,7 @@
"veyron.io/veyron/veyron/lib/expect"
"veyron.io/veyron/veyron/lib/modules"
"veyron.io/veyron/veyron/lib/modules/core"
+ _ "veyron.io/veyron/veyron/profiles"
)
type cmdState struct {
@@ -101,7 +102,7 @@
// Subprocess, run the requested command.
if err := modules.Dispatch(); err != nil {
fmt.Fprintf(os.Stderr, "failed: %v\n", err)
- return
+ os.Exit(1)
}
return
}
@@ -165,6 +166,9 @@
args = []string{}
}
sub, err := subVariables(sh, args)
+ if err != nil {
+ return err
+ }
if cmd := builtins[name]; cmd != nil {
if cmd.nargs >= 0 && len(sub) != cmd.nargs {
return fmt.Errorf("wrong (%d) # args for %q: usage %s", len(sub), name, cmd.usage)
@@ -177,7 +181,7 @@
l, err = cmd.fn(sh, nil, sub...)
}
if err != nil {
- return err
+ return fmt.Errorf("%s : %s", err, l)
}
output(lineno, l)
} else {
diff --git a/tools/naming/simulator/echo.scr b/tools/naming/simulator/echo.scr
index 788d1b0..c957371 100644
--- a/tools/naming/simulator/echo.scr
+++ b/tools/naming/simulator/echo.scr
@@ -1,8 +1,10 @@
# Simple example to show how names work both without and with a mount table
# and the difference between resolve and resolveMT.
+set localaddr=--veyron.tcp.address=127.0.0.1:0
+
# A 'stand-alone' server
-echoServer "text" ""
+echoServer -- $localaddr "text" ""
set es=$_
eval $es
eval $es
@@ -19,17 +21,17 @@
wait $ec
# now use a nameserver.
-root
+root -- $localaddr
eval $_
set root=$MT_NAME
set NAMESPACE_ROOT=$root
-echoServer "text2" "a/b"
+echoServer -- $localaddr "text2" "a/b"
set es=$_
eval $es
set es_name=$NAME
-set es_addr=$ADDR
read $es
+set es_addr=$ADDR
echoClient "a/b" "test 2"
set ec=$_
diff --git a/tools/naming/simulator/mt_complex.scr b/tools/naming/simulator/mt_complex.scr
index 6fb3532..a5c85e2 100644
--- a/tools/naming/simulator/mt_complex.scr
+++ b/tools/naming/simulator/mt_complex.scr
@@ -2,15 +2,17 @@
#
# TODO - list the examples and any issues.
+set localaddr="--veyron.tcp.address=127.0.0.1:0"
+
cache off
-root
+root -- $localaddr
set root_h=$_
eval $root_h
set root=$MT_NAME
set NAMESPACE_ROOT=$root
-mt tl/a
+mt -- $localaddr tl/a
set m=$_
set mt_a_h=$m
eval $m
@@ -18,7 +20,7 @@
set mt_a_name=$MT_NAME
set mt_a_addr=$MT_ADDR
-mt tl/b
+mt -- $localaddr tl/b
set m=$_
set mt_b_h=$m
eval $m
@@ -69,7 +71,7 @@
#
# run an echo server on tl.
-echoServer "E1" tl
+echoServer -- $localaddr "E1" tl
set es_E1=$_
read $es_E1
eval $es_E1
@@ -118,7 +120,7 @@
assert $R0 $mt_a_name
# run an echo server on tl/a
-echoServer "E2" tl/a
+echoServer -- $localaddr "E2" tl/a
set es_E2=$_
read $es_E2
eval $es_E2
@@ -198,7 +200,7 @@
# Create a mount table with a 'long' name
set long_name=tl/b/some/deep/name/that/is/a/mount/table
-mt $long_name
+mt -- $localaddr $long_name
set m=$_
eval $m
eval $m
@@ -208,7 +210,7 @@
# Create a second mount table with a 'long' name
set second_long_name=tl/a/some/deep/name/that/is/a/mount/table
-mt $second_long_name
+mt -- $localaddr $second_long_name
set m=$_
eval $m
eval $m
@@ -216,7 +218,7 @@
set mt_l2_addr=$MT_ADDR
# Run an echo server that uses that mount table
-echoServer "E3" $long_name/echo
+echoServer -- $localaddr "E3" $long_name/echo
set es_E3=$_
read $es_E3
eval $es_E3
diff --git a/tools/naming/simulator/mt_simple.scr b/tools/naming/simulator/mt_simple.scr
index 1dfb805..db78ef1 100644
--- a/tools/naming/simulator/mt_simple.scr
+++ b/tools/naming/simulator/mt_simple.scr
@@ -1,14 +1,16 @@
# Simple example showing multiple mount tables, servers and globing
-root
+set localaddr="--veyron.tcp.address=127.0.0.1:0"
+
+root -- $localaddr
eval $_
set root=$MT_NAME
set NAMESPACE_ROOT=$root
-mt usa
+mt -- $localaddr usa
eval $_
set usa_mt=$MT_NAME
-mt uk
+mt -- $localaddr uk
eval $_
set uk_mt=$MT_NAME
@@ -19,12 +21,12 @@
wait $l
set NAMESPACE_ROOT=$usa_mt
-mt "palo alto"
+mt -- $localaddr "palo alto"
eval $_
set pa_mt=$MT_NAME
set NAMESPACE_ROOT=$uk_mt
-mt "cambridge"
+mt -- $localaddr "cambridge"
eval $_
set cam_mt=$MT_NAME
@@ -32,6 +34,7 @@
set l=$_
eval $l
assert $RN 7
+wait $l
ls -l $root/...
wait $_
@@ -69,4 +72,4 @@
eval $r
# this behaves differently to the usa/palo alto case?
assert $R0 $cam_mt
-wait $r
\ No newline at end of file
+wait $r
diff --git a/tools/naming/simulator/proxy.scr b/tools/naming/simulator/proxy.scr
new file mode 100644
index 0000000..56bb960
--- /dev/null
+++ b/tools/naming/simulator/proxy.scr
@@ -0,0 +1,88 @@
+
+cache off
+
+set localaddr=--veyron.tcp.address=127.0.0.1:0
+
+root -- $localaddr
+eval $_
+set root=$MT_NAME
+set NAMESPACE_ROOT=$root
+setRoots $NAMESPACE_ROOT
+
+# run a non-proxied echo server
+echoServer -- $localaddr noproxy echo/noproxy
+set esnp=$_
+eval $esnp
+set NP_ECHOS_NAME=$NAME
+eval $esnp
+set NP_ECHOS_ADDR=$ADDR
+
+
+# run a proxy server
+proxyd -- $localaddr p1
+set proxy=$_
+# PROXY_ADDR=<address of proxy>
+eval $proxy
+# PROXY_NAME=<name of proxy>
+eval $proxy
+read $proxy
+splitEP $PROXY_ADDR
+assert $PN 6
+set PROXY_ADDRESS=$P2
+set PROXY_RID=$P3
+
+
+# TODO(cnicolaou): figure out why ls appears to run slowly when a proxy is
+# running, maybe a problem with the mount table.
+#ls ...
+#set l=$_
+#eval $l
+#assert $RN 3
+#wait $l
+
+echoServer -- $localaddr --veyron.proxy=p1 withproxy echo/withproxy
+set eswp=$_
+eval $eswp
+set ECHOS_NAME=$NAME
+eval $eswp
+set ECHOS_ADDR=$ADDR
+splitEP $ADDR
+set ECHOS_RID=$P3
+
+#ls ...
+#set l=$_
+#eval $l
+#assert $RN 4
+#wait $l
+
+print "root mt:" $NAMESPACE_ROOT
+print "no proxy: " $NP_ECHOS_ADDR
+print "with proxy: " $ECHOS_ADDR
+# The ipc.Server implementation publishes the proxy supplied address
+# in the mount table
+# TODO(cnicolaou): we also need a way of publishing the local address, right
+# only the proxy's address appears.
+resolve echo/withproxy
+set rs=$_
+eval $rs
+assert $RN 1
+eval $rs
+splitEP $R0
+assert $PN 6
+assert $P2 $PROXY_ADDRESS
+assert $P3 $ECHOS_RID
+
+ls -l echo/withproxy
+wait $_
+ls -l echo/noproxy
+wait $_
+
+echoClient echo/withproxy "ohh"
+set ec=$_
+read $ec l
+assert $l "withproxy: ohh"
+
+stop $eswp
+stop $esnp
+stop $proxy
+