veyron/tools/namespace: add command-line tool.

This is a command-line tool to interact with the namespace. It is really just a
wrapper around all the exported functions in veyron/runtimes/google/naming/namespace.

Change-Id: I6a29ed7d8fb63966e054bd1db660754d858dc50d
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},
+	}
+}