veyron/tools/mgmt/nodex: add per-instance commands

Extend the nodex command with the instance sub-command for manipulating
application instances.

Change-Id: I798a8b4c02a27722d40355b22324366c59e8d816
diff --git a/tools/mgmt/nodex/doc.go b/tools/mgmt/nodex/doc.go
index 3ab0e44..7f2fa78 100644
--- a/tools/mgmt/nodex/doc.go
+++ b/tools/mgmt/nodex/doc.go
@@ -13,6 +13,7 @@
    associate   Tool for creating associations between Vanadium blessings and a
                system account
    claim       Claim the node.
+   instance    Subtool for managing application instances
    help        Display help for commands or topics
 Run "nodex help [command]" for command usage.
 
@@ -123,6 +124,67 @@
 <grant extension> is used to extend the default blessing of the current
 principal when blessing the app instance.
 
+Nodex Instance
+
+The instance tool permits controlling application instances.
+
+Usage:
+   nodex instance <command>
+
+The nodex instance commands are:
+   stop        Stop the given application instance.
+   suspend     Suspend the given application instance.
+   resume      Resume the given application instance.
+   refresh     Refresh the given application instance.
+   suspend     Restart the given application instance.
+
+Nodex Instance Stop
+
+Stop the given application instance.
+
+Usage:
+   nodex instance stop <app instance> [<deadline>]
+
+<app instance> is the veyron object name of the application instance to stop.
+<deadline> is the optional deadline to shut down by. If not provided, defaults
+to 5 seconds.
+
+Nodex Instance Suspend
+
+Suspend the given application instance.
+
+Usage:
+   nodex instance suspend <app instance>
+
+<app instance> is the veyron object name of the application instance to stop.
+
+Nodex Instance Resume
+
+Resume the given application instance.
+
+Usage:
+   nodex instance resume <app instance>
+
+<app instance> is the veyron object name of the application instance to stop.
+
+Nodex Instance Refresh
+
+Refresh the given application instance.
+
+Usage:
+   nodex instance refresh <app instance>
+
+<app instance> is the veyron object name of the application instance to stop.
+
+Nodex Instance Suspend
+
+Restart the given application instance.
+
+Usage:
+   nodex instance suspend <app instance>
+
+<app instance> is the veyron object name of the application instance to stop.
+
 Nodex Help
 
 Help with no args displays the usage of the parent command.
diff --git a/tools/mgmt/nodex/impl.go b/tools/mgmt/nodex/impl.go
index e0de5f1..e4547fc 100644
--- a/tools/mgmt/nodex/impl.go
+++ b/tools/mgmt/nodex/impl.go
@@ -108,6 +108,7 @@
 The nodex tool facilitates interaction with the veyron node manager.
 `,
 
-		Children: []*cmdline.Command{cmdInstall, cmdStart, associateRoot(), cmdClaim},
+		// TODO(rjk): will have to fold these in...
+		Children: []*cmdline.Command{cmdInstall, cmdStart, associateRoot(), cmdClaim, cmdStop, cmdSuspend, cmdResume},
 	}
 }
diff --git a/tools/mgmt/nodex/instance_impl.go b/tools/mgmt/nodex/instance_impl.go
new file mode 100644
index 0000000..251db6f
--- /dev/null
+++ b/tools/mgmt/nodex/instance_impl.go
@@ -0,0 +1,81 @@
+package main
+
+// Commands to modify instance.
+
+import (
+	"fmt"
+
+	"veyron.io/veyron/veyron2/rt"
+	"veyron.io/veyron/veyron2/services/mgmt/node"
+
+	"veyron.io/veyron/veyron/lib/cmdline"
+)
+
+var cmdStop = &cmdline.Command{
+	Run:      runStop,
+	Name:     "stop",
+	Short:    "Stop the given application instance.",
+	Long:     "Stop the given application instance.",
+	ArgsName: "<app instance>",
+	ArgsLong: `
+<app instance> is the veyron object name of the application instance to stop.`,
+}
+
+func runStop(cmd *cmdline.Command, args []string) error {
+	if expected, got := 1, len(args); expected != got {
+		return cmd.UsageErrorf("stop: incorrect number of arguments, expected %d, got %d", expected, got)
+	}
+	appName := args[0]
+
+	if err := node.ApplicationClient(appName).Stop(rt.R().NewContext(), 5); err != nil {
+		return fmt.Errorf("Stop failed: %v", err)
+	}
+	fmt.Fprintf(cmd.Stdout(), "Stop succeeded\n")
+	return nil
+}
+
+var cmdSuspend = &cmdline.Command{
+	Run:      runSuspend,
+	Name:     "suspend",
+	Short:    "Suspend the given application instance.",
+	Long:     "Suspend the given application instance.",
+	ArgsName: "<app instance>",
+	ArgsLong: `
+<app instance> is the veyron object name of the application instance to suspend.`,
+}
+
+func runSuspend(cmd *cmdline.Command, args []string) error {
+	if expected, got := 1, len(args); expected != got {
+		return cmd.UsageErrorf("suspend: incorrect number of arguments, expected %d, got %d", expected, got)
+	}
+	appName := args[0]
+
+	if err := node.ApplicationClient(appName).Suspend(rt.R().NewContext()); err != nil {
+		return fmt.Errorf("Suspend failed: %v", err)
+	}
+	fmt.Fprintf(cmd.Stdout(), "Suspend succeeded\n")
+	return nil
+}
+
+var cmdResume = &cmdline.Command{
+	Run:      runResume,
+	Name:     "resume",
+	Short:    "Resume the given application instance.",
+	Long:     "Resume the given application instance.",
+	ArgsName: "<app instance>",
+	ArgsLong: `
+<app instance> is the veyron object name of the application instance to resume.`,
+}
+
+func runResume(cmd *cmdline.Command, args []string) error {
+	if expected, got := 1, len(args); expected != got {
+		return cmd.UsageErrorf("resume: incorrect number of arguments, expected %d, got %d", expected, got)
+	}
+	appName := args[0]
+
+	if err := node.ApplicationClient(appName).Resume(rt.R().NewContext()); err != nil {
+		return fmt.Errorf("Resume failed: %v", err)
+	}
+	fmt.Fprintf(cmd.Stdout(), "Resume succeeded\n")
+	return nil
+}