Merge "veyron/tools/mgmt,veyron/security/agent/agentd: node mgr integration test."
diff --git a/security/agent/agentd/main.go b/security/agent/agentd/main.go
index ed9fe2e..faa8c0d 100644
--- a/security/agent/agentd/main.go
+++ b/security/agent/agentd/main.go
@@ -23,7 +23,10 @@
 	"veyron.io/veyron/veyron2/vlog"
 )
 
-var keypath = flag.String("additional_principals", "", "If non-empty, allow for the creation of new principals and save them in this directory.")
+var (
+	keypath      = flag.String("additional_principals", "", "If non-empty, allow for the creation of new principals and save them in this directory.")
+	noPassphrase = flag.Bool("no_passphrase", false, "If true, user will not be prompted for principal encryption passphrase.")
+)
 
 func main() {
 	flag.Usage = func() {
@@ -116,9 +119,13 @@
 }
 
 func handleDoesNotExist(dir string) (security.Principal, []byte, error) {
-	pass, err := getPassword("Private key file does not exist. Creating new private key...\nEnter passphrase (entering nothing will store unencrypted): ")
-	if err != nil {
-		return nil, nil, fmt.Errorf("failed to read passphrase: %v", err)
+	fmt.Println("Private key file does not exist. Creating new private key...")
+	var pass []byte
+	if !*noPassphrase {
+		var err error
+		if pass, err = getPassword("Enter passphrase (entering nothing will store unencrypted): "); err != nil {
+			return nil, nil, fmt.Errorf("failed to read passphrase: %v", err)
+		}
 	}
 	p, err := vsecurity.CreatePersistentPrincipal(dir, pass)
 	if err != nil {
@@ -129,6 +136,9 @@
 }
 
 func handlePassphrase(dir string) (security.Principal, []byte, error) {
+	if *noPassphrase {
+		return nil, nil, fmt.Errorf("Passphrase required for decrypting principal.")
+	}
 	pass, err := getPassword("Private key file is encrypted. Please enter passphrase.\nEnter passphrase: ")
 	if err != nil {
 		return nil, nil, fmt.Errorf("failed to read passphrase: %v", err)
diff --git a/tools/mgmt/nminstall b/tools/mgmt/nminstall
index e6d71fd..02e59a6 100755
--- a/tools/mgmt/nminstall
+++ b/tools/mgmt/nminstall
@@ -28,7 +28,7 @@
 
 usage() {
   echo "usage:"
-  echo "./nminstall <install parent dir> [<binary source>]"
+  echo "./nminstall [--single_user] <install parent dir> [<binary source>]"
 }
 
 readonly BIN_NAMES=(noded suidhelper agentd)
@@ -118,6 +118,14 @@
 }
 
 main() {
+  if [[ "$1" == "--single_user" ]]; then
+    local -r SINGLE_USER=true
+    shift
+    local -r AGENT_FLAG="--no_passphrase"
+  else
+    local -r SINGLE_USER=false
+    local -r AGENT_FLAG=""
+  fi
   local -r INSTALL_PARENT_DIR="$1"
   if [[ -z "${INSTALL_PARENT_DIR}" ]]; then
     echo 'No local install destination specified!'
@@ -135,7 +143,11 @@
   # TODO(caprita): Check that the node manager is not already installed before
   # proceeding.  We should require an explicit uninstall to avoid wiping away
   # the node manager accidentally.
-  sudo rm -rf "${INSTALL_DIR}"
+  if [[ ! ${SINGLE_USER} ]]; then
+    sudo rm -rf "${INSTALL_DIR}"
+  else
+    rm -rf "${INSTALL_DIR}"
+  fi
   mkdir -m 700 "${INSTALL_DIR}"
 
   local -r BIN_INSTALL="${INSTALL_DIR}/bin"
@@ -156,7 +168,9 @@
   # Set up the suidhelper.
   echo "Configuring suidhelper ..."
   local -r SETUID_SCRIPT="${BIN_INSTALL}/suidhelper"
-  sudo bash -c "chown root:root \"${SETUID_SCRIPT}\"; chmod 4551 \"${SETUID_SCRIPT}\""
+  if [[ ! ${SINGLE_USER} ]]; then
+    sudo bash -c "chown root:root \"${SETUID_SCRIPT}\"; chmod 4551 \"${SETUID_SCRIPT}\""
+  fi
   echo "Suidhelper configured."
 
   # Tell the node manager to install itself.
@@ -176,11 +190,11 @@
   # Run node manager under the security agent.
   echo
   echo "Running:"
-  echo "VEYRON_CREDENTIALS=\"${PRINCIPAL_DIR}\" \"${BIN_INSTALL}/agentd\" --additional_principals=\"${AGENT_KEY_DIR}\" \"${INSTALL_DIR}/noded.curr\""
+  echo "VEYRON_CREDENTIALS=\"${PRINCIPAL_DIR}\" \"${BIN_INSTALL}/agentd\" ${AGENT_FLAG} --additional_principals=\"${AGENT_KEY_DIR}\" \"${INSTALL_DIR}/noded.curr\""
   echo
   # NOTE: If you update the command below, please also update the command echoed
   # above to keep the two in sync.
-  VEYRON_CREDENTIALS="${PRINCIPAL_DIR}" "${BIN_INSTALL}/agentd" --additional_principals="${AGENT_KEY_DIR}" "${INSTALL_DIR}/noded.curr"
+  VEYRON_CREDENTIALS="${PRINCIPAL_DIR}" "${BIN_INSTALL}/agentd" "${AGENT_FLAG}" --additional_principals="${AGENT_KEY_DIR}" "${INSTALL_DIR}/noded.curr"
 }
 
 main "$@"
diff --git a/tools/mgmt/test.sh b/tools/mgmt/test.sh
new file mode 100755
index 0000000..b3c4275
--- /dev/null
+++ b/tools/mgmt/test.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+# Test the node manager and related services and tools.
+
+source "${VEYRON_ROOT}/scripts/lib/shell_test.sh"
+
+readonly WORKDIR="${shell_test_WORK_DIR}"
+
+build() {
+  BINARYD_BIN="$(shell_test::build_go_binary 'veyron.io/veyron/veyron/services/mgmt/binary/binaryd')"
+  BINARY_BIN="$(shell_test::build_go_binary 'veyron.io/veyron/veyron/tools/binary')"
+  AGENTD_BIN="$(shell_test::build_go_binary 'veyron.io/veyron/veyron/security/agent/agentd')"
+  SUIDHELPER_BIN="$(shell_test::build_go_binary 'veyron.io/veyron/veyron/services/mgmt/suidhelper')"
+  NODEMANAGER_BIN="$(shell_test::build_go_binary 'veyron.io/veyron/veyron/services/mgmt/node/noded')"
+  NMINSTALL_SCRIPT="$(shell::go_package_dir 'veyron.io/veyron/veyron/tools/mgmt')/nminstall"
+}
+
+main() {
+  cd "${WORKDIR}"
+  build
+
+  BIN_STAGING_DIR=$(shell::tmp_dir)
+  cp "${AGENTD_BIN}" "${SUIDHELPER_BIN}" "${NODEMANAGER_BIN}" "${BIN_STAGING_DIR}"
+  shell_test::setup_server_test
+  # Unset VEYRON_CREDENTIALS set in setup_server_test.
+  export VEYRON_CREDENTIALS=
+
+  # TODO(caprita): Expose an option to turn --single_user off, so we can run
+  # test.sh by hand and exercise the code that requires root privileges.
+
+  # TODO(caprita): Uncomment when we're ready to use node manager.
+  # "${NMINSTALL_SCRIPT}" --single_user $(shell::tmp_dir) "${BIN_STAGING_DIR}" &
+
+  # TODO(caprita): Fill in the rest.
+  shell_test::pass
+}
+
+main "$@"