Merge "Update the playground to use vdl and new init scripts."
diff --git a/services/mounttable/lib/neighborhood.go b/services/mounttable/lib/neighborhood.go
index 5f3a110..7b49c1b 100644
--- a/services/mounttable/lib/neighborhood.go
+++ b/services/mounttable/lib/neighborhood.go
@@ -132,10 +132,11 @@
var reply []mounttable.MountedServer
si := nh.mdns.ResolveInstance(instance, "veyron")
+ // Use a map to dedup any addresses seen
+ addrMap := make(map[string]uint32)
+
// Look for any TXT records with addresses.
for _, rr := range si.TxtRRs {
- // Use a map to dedup any addresses seen
- addrMap := make(map[string]uint32)
for _, s := range rr.Txt {
if !strings.HasPrefix(s, addressPrefix) {
continue
@@ -143,9 +144,9 @@
addr := s[len(addressPrefix):]
addrMap[addr] = rr.Header().Ttl
}
- for addr, ttl := range addrMap {
- reply = append(reply, mounttable.MountedServer{addr, ttl})
- }
+ }
+ for addr, ttl := range addrMap {
+ reply = append(reply, mounttable.MountedServer{addr, ttl})
}
if reply != nil {
diff --git a/services/mounttable/mounttabled/mounttable.go b/services/mounttable/mounttabled/mounttable.go
index fadc4a8..23cf394 100644
--- a/services/mounttable/mounttabled/mounttable.go
+++ b/services/mounttable/mounttabled/mounttable.go
@@ -78,7 +78,7 @@
mtAddr := naming.JoinAddressName(mtEndpoint.String(), "")
r.Namespace().SetRoots(mtAddr)
- vlog.Infof("Mount table service at: %q (%s)",
+ vlog.Infof("Mount table service at: %q endpoint: %s",
name,
naming.JoinAddressName(mtEndpoint.String(), ""))
@@ -98,7 +98,7 @@
vlog.Errorf("nhServer.Listen failed: %v", err)
return
}
- nh, err := mounttable.NewNeighborhoodServer("", *nhName, mtAddr)
+ nh, err := mounttable.NewNeighborhoodServer(*nhName, mtAddr)
if err != nil {
vlog.Errorf("NewNeighborhoodServer failed: %v", err)
return
diff --git a/services/mounttable/mounttabled/test.sh b/services/mounttable/mounttabled/test.sh
new file mode 100755
index 0000000..1f15be1
--- /dev/null
+++ b/services/mounttable/mounttabled/test.sh
@@ -0,0 +1,87 @@
+#!/bin/sh
+
+# Test the mounttabled binary
+#
+# This test starts a mounttable server with the neighborhood option enabled,
+# and mounts 1) the mounttable on itself as 'myself', and 2) www.google.com:80
+# as 'google'.
+#
+# Then it verifies that <mounttable>.Glob(*) and <neighborhood>.Glob(nhname)
+# return the correct result.
+
+toplevel=$(git rev-parse --show-toplevel)
+go=${toplevel}/scripts/build/go
+thisscript=$0
+
+echo "Test directory: $(dirname $0)"
+
+builddir=$(mktemp -d --tmpdir=${toplevel}/go)
+tmplog=$(mktemp)
+trap onexit EXIT
+
+onexit() {
+ cd /
+ exec 2> /dev/null
+ kill -9 $(jobs -p)
+ rm -rf $builddir $tmplog
+}
+
+FAIL() {
+ [ $# -gt 0 ] && echo "$thisscript $*"
+ echo FAIL
+ exit 1
+}
+
+PASS() {
+ echo PASS
+ exit 0
+}
+
+# Build mounttabled and mounttable binaries.
+cd $builddir
+$go build veyron/services/mounttable/mounttabled || FAIL "line $LINENO: failed to build mounttabled"
+$go build veyron/tools/mounttable || FAIL "line $LINENO: failed to build mounttable"
+
+# Start mounttabled and find its endpoint.
+nhname=test$$
+./mounttabled --address=localhost:0 --neighborhood_name=$nhname > $tmplog 2>&1 &
+
+for i in 1 2 3 4; do
+ ep=$(grep "Mount table service at:" $tmplog | sed -re 's/^.*endpoint: ([^ ]*).*/\1/')
+ if [ -n "$ep" ]; then
+ break
+ fi
+ sleep 1
+done
+
+[ -z $ep ] && FAIL "line $LINENO: no server"
+
+# Get the neighborhood endpoint from the mounttable.
+nhep=$(./mounttable glob $ep nh | grep ^nh | cut -d' ' -f2)
+[ -z $nhep ] && FAIL "line $LINENO: no neighborhood server"
+
+# Mount objects and verify the result.
+./mounttable mount "${ep}/myself" "$ep" 5m > /dev/null || FAIL "line $LINENO: failed to mount the mounttable on itself"
+./mounttable mount "${ep}/google" /www.google.com:80 5m > /dev/null || FAIL "line $LINENO: failed to mount www.google.com"
+
+# <mounttable>.Glob('*')
+got=$(./mounttable glob $ep '*' | sed 's/TTL .m..s/TTL XmXXs/' | sort)
+want="[${ep}]
+google /www.google.com:80 (TTL XmXXs)
+myself ${ep} (TTL XmXXs)
+nh ${nhep} (TTL XmXXs)"
+
+if [ "$got" != "$want" ]; then
+ FAIL "line $LINENO: unexpected output. Got $got, want $want"
+fi
+
+# <neighborhood>.Glob('nhname')
+got=$(./mounttable glob $nhep $nhname | sed 's/TTL .m..s/TTL XmXXs/' | sort)
+want="[${nhep}]
+${nhname} ${ep} (TTL XmXXs)"
+
+if [ "$got" != "$want" ]; then
+ FAIL "line $LINENO: unexpected output. Got $got, want $want"
+fi
+
+PASS
diff --git a/tools/namespace/impl/impl.go b/tools/namespace/impl/impl.go
new file mode 100644
index 0000000..ad3cc43
--- /dev/null
+++ b/tools/namespace/impl/impl.go
@@ -0,0 +1,199 @@
+package impl
+
+import (
+ "fmt"
+ "time"
+
+ "veyron/lib/cmdline"
+
+ "veyron2/rt"
+ "veyron2/vlog"
+)
+
+var cmdGlob = &cmdline.Command{
+ Run: runGlob,
+ Name: "glob",
+ Short: "Returns all matching entries from the namespace",
+ Long: "Returns all matching entries from the namespace.",
+ ArgsName: "<pattern>",
+ ArgsLong: `
+<pattern> is a glob pattern that is matched against all the names below the
+specified mount name.
+`,
+}
+
+func runGlob(cmd *cmdline.Command, args []string) error {
+ if expected, got := 1, len(args); expected != got {
+ return cmd.Errorf("glob: incorrect number of arguments, expected %d, got %d", expected, got)
+ }
+ pattern := args[0]
+ ns := rt.R().Namespace()
+ c, err := ns.Glob(rt.R().NewContext(), pattern)
+ if err != nil {
+ vlog.Infof("ns.Glob(%q) failed: %v", pattern, err)
+ return err
+ }
+ for res := range c {
+ fmt.Fprint(cmd.Stdout(), res.Name)
+ for _, s := range res.Servers {
+ fmt.Fprintf(cmd.Stdout(), " %s (TTL %s)", s.Server, s.TTL)
+ }
+ fmt.Fprintln(cmd.Stdout())
+ }
+ return nil
+}
+
+var cmdMount = &cmdline.Command{
+ Run: runMount,
+ Name: "mount",
+ Short: "Adds a server to the namespace",
+ Long: "Adds server <server> to the namespace with name <name>.",
+ ArgsName: "<name> <server> <ttl>",
+ ArgsLong: `
+<name> is the name to add to the namespace.
+<server> is the object address of the server to add.
+<ttl> is the TTL of the new entry. It is a decimal number followed by a unit
+suffix (s, m, h). A value of 0s represents an infinite duration.
+`,
+}
+
+func runMount(cmd *cmdline.Command, args []string) error {
+ if expected, got := 3, len(args); expected != got {
+ return cmd.Errorf("mount: incorrect number of arguments, expected %d, got %d", expected, got)
+ }
+ name := args[0]
+ server := args[1]
+ ttlArg := args[2]
+
+ ttl, err := time.ParseDuration(ttlArg)
+ if err != nil {
+ return fmt.Errorf("TTL parse error: %v", err)
+ }
+ ns := rt.R().Namespace()
+ if err = ns.Mount(rt.R().NewContext(), name, server, ttl); err != nil {
+ vlog.Infof("ns.Mount(%q, %q, %s) failed: %v", name, server, ttl, err)
+ return err
+ }
+ fmt.Fprintln(cmd.Stdout(), "Server mounted successfully.")
+ return nil
+}
+
+var cmdUnmount = &cmdline.Command{
+ Run: runUnmount,
+ Name: "unmount",
+ Short: "Removes a server from the namespace",
+ Long: "Removes server <server> with name <name> from the namespace.",
+ ArgsName: "<name> <server>",
+ ArgsLong: `
+<name> is the name to remove from the namespace.
+<server> is the object address of the server to remove.
+`,
+}
+
+func runUnmount(cmd *cmdline.Command, args []string) error {
+ if expected, got := 2, len(args); expected != got {
+ return cmd.Errorf("unmount: incorrect number of arguments, expected %d, got %d", expected, got)
+ }
+ name := args[0]
+ server := args[1]
+ ns := rt.R().Namespace()
+ if err := ns.Unmount(rt.R().NewContext(), name, server); err != nil {
+ vlog.Infof("ns.Unmount(%q, %q) failed: %v", name, server, err)
+ return err
+ }
+ fmt.Fprintln(cmd.Stdout(), "Server unmounted successfully.")
+ return nil
+}
+
+var cmdResolve = &cmdline.Command{
+ Run: runResolve,
+ Name: "resolve",
+ Short: "Translates a object name to its object address(es)",
+ Long: "Translates a object name to its object address(es).",
+ ArgsName: "<name>",
+ ArgsLong: "<name> is the name to resolve.",
+}
+
+func runResolve(cmd *cmdline.Command, args []string) error {
+ if expected, got := 1, len(args); expected != got {
+ return cmd.Errorf("resolve: incorrect number of arguments, expected %d, got %d", expected, got)
+ }
+ name := args[0]
+ ns := rt.R().Namespace()
+ servers, err := ns.Resolve(rt.R().NewContext(), name)
+ if err != nil {
+ vlog.Infof("ns.Resolve(%q) failed: %v", name, err)
+ return err
+ }
+ for _, s := range servers {
+ fmt.Fprintln(cmd.Stdout(), s)
+ }
+ return nil
+}
+
+var cmdResolveToMT = &cmdline.Command{
+ Run: runResolveToMT,
+ Name: "resolvetomt",
+ Short: "Finds the address of the mounttable that holds an object name",
+ Long: "Finds the address of the mounttable that holds an object name.",
+ ArgsName: "<name>",
+ ArgsLong: "<name> is the name to resolve.",
+}
+
+func runResolveToMT(cmd *cmdline.Command, args []string) error {
+ if expected, got := 1, len(args); expected != got {
+ return cmd.Errorf("resolvetomt: incorrect number of arguments, expected %d, got %d", expected, got)
+ }
+ name := args[0]
+ ns := rt.R().Namespace()
+ servers, err := ns.ResolveToMountTable(rt.R().NewContext(), name)
+ if err != nil {
+ vlog.Infof("ns.ResolveToMountTable(%q) failed: %v", name, err)
+ return err
+ }
+ for _, s := range servers {
+ fmt.Fprintln(cmd.Stdout(), s)
+ }
+ return nil
+}
+
+var cmdUnresolve = &cmdline.Command{
+ Run: runUnresolve,
+ Name: "unresolve",
+ Short: "Returns the rooted object names for the given object name",
+ Long: "Returns the rooted object names for the given object name.",
+ ArgsName: "<name>",
+ ArgsLong: "<name> is the object name to unresolve.",
+}
+
+func runUnresolve(cmd *cmdline.Command, args []string) error {
+ if expected, got := 1, len(args); expected != got {
+ return cmd.Errorf("unresolve: incorrect number of arguments, expected %d, got %d", expected, got)
+ }
+ name := args[0]
+ ns := rt.R().Namespace()
+ servers, err := ns.Unresolve(rt.R().NewContext(), name)
+ if err != nil {
+ vlog.Infof("ns.Unresolve(%q) failed: %v", name, err)
+ return err
+ }
+ for _, s := range servers {
+ fmt.Fprintln(cmd.Stdout(), s)
+ }
+ return nil
+}
+
+func Root() *cmdline.Command {
+ return &cmdline.Command{
+ Name: "namespace",
+ Short: "Command-line tool for interacting with the Veyron namespace",
+ Long: `
+Command-line tool for interacting with the Veyron namespace.
+
+The namespace roots are set from environment variables that have a name
+starting with NAMESPACE_ROOT, e.g. NAMESPACE_ROOT, NAMESPACE_ROOT_2,
+NAMESPACE_ROOT_GOOGLE, etc.
+`,
+ Children: []*cmdline.Command{cmdGlob, cmdMount, cmdUnmount, cmdResolve, cmdResolveToMT, cmdUnresolve},
+ }
+}
diff --git a/tools/namespace/main.go b/tools/namespace/main.go
new file mode 100644
index 0000000..4a0ff2d
--- /dev/null
+++ b/tools/namespace/main.go
@@ -0,0 +1,12 @@
+// A command-line tool to interface with the veyron namespace.
+package main
+
+import (
+ "veyron/tools/namespace/impl"
+ "veyron2/rt"
+)
+
+func main() {
+ defer rt.Init().Shutdown()
+ impl.Root().Main()
+}