veyron/services/mgmt/device,veyron/tools/mgmt: introduce devicex
Devicex is a new shell script to manage the device manager. It subsumes the old
dminstall and dminstall scripts (which go away), and also adds commands for
start and stop. Unlike dminstall and dmuninstall, devicex is a very thin
wrapper on top of the commands provided by deviced -- the only real value-add is
for downloading binaries and setting the permissions on the setuid helper. The
idea is that you only need the devicex script to administer a device manager
installation on a given device. The integration test (test.sh) shows how this
can work. Also, the unit test TestDeviceManagerInstallation uses exclusively the
install/uninstall/start/stop commands in a similar fashion.
To make the stop command work, we now track the device manager's object name, so
we can send it a Stop RPC and get it to exit cleanly (and with a return exit
code that convices the agent to not restart it anymore).
Some work still left to do, specifically around fleshing out the "non-session"
mode where we want to register the device manager with the system daemon
(e.g. init.d)
Change-Id: Idea144b45837cbf8c33a4bc64971ee5fd7143a65
diff --git a/lib/modules/registry.go b/lib/modules/registry.go
index 762d94f..7b01a1e 100644
--- a/lib/modules/registry.go
+++ b/lib/modules/registry.go
@@ -204,7 +204,7 @@
return m.main(os.Stdin, os.Stdout, os.Stderr, envSliceToMap(os.Environ()), args...)
}
-// WaitForEof returns when a read on its io.Reader parameter returns io.EOF
+// WaitForEOF returns when a read on its io.Reader parameter returns io.EOF
func WaitForEOF(stdin io.Reader) {
buf := [1024]byte{}
for {
diff --git a/services/mgmt/device/config/config.go b/services/mgmt/device/config/config.go
index dc89d92..8932f5d 100644
--- a/services/mgmt/device/config/config.go
+++ b/services/mgmt/device/config/config.go
@@ -99,13 +99,18 @@
// during an update, returning a slice of "key=value" strings, which are
// expected to be stuffed into environment variable settings by the caller.
func (c *State) Save(envelope *application.Envelope) ([]string, error) {
- jsonEnvelope, err := json.Marshal(envelope)
- if err != nil {
- return nil, fmt.Errorf("failed to encode envelope %v: %v", envelope, err)
+ var jsonEnvelope []byte
+ if envelope != nil {
+ var err error
+ if jsonEnvelope, err = json.Marshal(envelope); err != nil {
+ return nil, fmt.Errorf("failed to encode envelope %v: %v", envelope, err)
+ }
}
- currScript, err := filepath.EvalSymlinks(c.CurrentLink)
- if err != nil {
- return nil, fmt.Errorf("EvalSymlink failed: %v", err)
+ var currScript string
+ if _, err := os.Lstat(c.CurrentLink); !os.IsNotExist(err) {
+ if currScript, err = filepath.EvalSymlinks(c.CurrentLink); err != nil {
+ return nil, fmt.Errorf("EvalSymlinks failed: %v", err)
+ }
}
settings := map[string]string{
EnvelopeEnv: string(jsonEnvelope),
diff --git a/services/mgmt/device/deviced/commands.go b/services/mgmt/device/deviced/commands.go
index a597091..c151c8b 100644
--- a/services/mgmt/device/deviced/commands.go
+++ b/services/mgmt/device/deviced/commands.go
@@ -1,21 +1,43 @@
package main
import (
+ "fmt"
"os"
"v.io/lib/cmdline"
"v.io/core/veyron/services/mgmt/device/impl"
+ "v.io/core/veyron2/rt"
"v.io/core/veyron2/vlog"
)
-var installFrom string
+var (
+ installFrom string
+ suidHelper string
+ agent string
+ singleUser bool
+ sessionMode bool
+)
+
+const deviceDirEnv = "VANADIUM_DEVICE_DIR"
+
+func installationDir() string {
+ if d := os.Getenv(deviceDirEnv); d != "" {
+ return d
+ }
+ if d, err := os.Getwd(); err != nil {
+ vlog.Errorf("Failed to get current dir: %v", err)
+ return ""
+ } else {
+ return d
+ }
+}
var cmdInstall = &cmdline.Command{
Run: runInstall,
Name: "install",
Short: "Install the device manager.",
- Long: "Performs installation of device manager based on the config specified via the environment.",
+ Long: fmt.Sprintf("Performs installation of device manager into %s (if the env var set), or into the current dir otherwise", deviceDirEnv),
ArgsName: "[-- <arguments for device manager>]",
ArgsLong: `
Arguments to be passed to the installed device manager`,
@@ -23,9 +45,13 @@
func init() {
cmdInstall.Flags.StringVar(&installFrom, "from", "", "if specified, performs the installation from the provided application envelope object name")
+ cmdInstall.Flags.StringVar(&suidHelper, "suid_helper", "", "path to suid helper")
+ cmdInstall.Flags.StringVar(&agent, "agent", "", "path to security agent")
+ cmdInstall.Flags.BoolVar(&singleUser, "single_user", false, "if set, performs the installation assuming a single-user system")
+ cmdInstall.Flags.BoolVar(&sessionMode, "session_mode", false, "if set, installs the device manager to run a single session. Otherwise, the device manager is configured to get restarted upon exit")
}
-func runInstall(_ *cmdline.Command, args []string) error {
+func runInstall(cmd *cmdline.Command, args []string) error {
if installFrom != "" {
// TODO(caprita): Also pass args into InstallFrom.
if err := impl.InstallFrom(installFrom); err != nil {
@@ -34,7 +60,13 @@
}
return nil
}
- if err := impl.SelfInstall(args, os.Environ()); err != nil {
+ if suidHelper == "" {
+ return cmd.UsageErrorf("--suid_helper must be set")
+ }
+ if agent == "" {
+ return cmd.UsageErrorf("--agent must be set")
+ }
+ if err := impl.SelfInstall(installationDir(), suidHelper, agent, singleUser, sessionMode, args, os.Environ()); err != nil {
vlog.Errorf("SelfInstall failed: %v", err)
return err
}
@@ -45,13 +77,49 @@
Run: runUninstall,
Name: "uninstall",
Short: "Uninstall the device manager.",
- Long: "Removes the device manager installation based on the config specified via the environment.",
+ Long: fmt.Sprintf("Removes the device manager installation from %s (if the env var set), or the current dir otherwise", deviceDirEnv),
}
func runUninstall(*cmdline.Command, []string) error {
- if err := impl.Uninstall(); err != nil {
+ if err := impl.Uninstall(installationDir()); err != nil {
vlog.Errorf("Uninstall failed: %v", err)
return err
}
return nil
}
+
+var cmdStart = &cmdline.Command{
+ Run: runStart,
+ Name: "start",
+ Short: "Start the device manager.",
+ Long: fmt.Sprintf("Starts the device manager installed under from %s (if the env var set), or the current dir otherwise", deviceDirEnv),
+}
+
+func runStart(*cmdline.Command, []string) error {
+ if err := impl.Start(installationDir(), nil, nil); err != nil {
+ vlog.Errorf("Start failed: %v", err)
+ return err
+ }
+ return nil
+}
+
+var cmdStop = &cmdline.Command{
+ Run: runStop,
+ Name: "stop",
+ Short: "Stop the device manager.",
+ Long: fmt.Sprintf("Stops the device manager installed under from %s (if the env var set), or the current dir otherwise", deviceDirEnv),
+}
+
+func runStop(*cmdline.Command, []string) error {
+ runtime, err := rt.New()
+ if err != nil {
+ vlog.Errorf("Could not initialize runtime: %v", err)
+ return err
+ }
+ defer runtime.Cleanup()
+ if err := impl.Stop(installationDir(), runtime); err != nil {
+ vlog.Errorf("Stop failed: %v", err)
+ return err
+ }
+ return nil
+}
diff --git a/services/mgmt/device/deviced/main.go b/services/mgmt/device/deviced/main.go
index f0631db..9b21878 100644
--- a/services/mgmt/device/deviced/main.go
+++ b/services/mgmt/device/deviced/main.go
@@ -9,7 +9,7 @@
Long: `
deviced can be used to launch, configure, or manage the device manager.
`,
- Children: []*cmdline.Command{cmdInstall, cmdUninstall},
+ Children: []*cmdline.Command{cmdInstall, cmdUninstall, cmdStart, cmdStop},
Run: runServer,
}
rootCmd.Main()
diff --git a/services/mgmt/device/impl/device_installer.go b/services/mgmt/device/impl/device_installer.go
index da79289..77f6397 100644
--- a/services/mgmt/device/impl/device_installer.go
+++ b/services/mgmt/device/impl/device_installer.go
@@ -2,18 +2,30 @@
import (
"fmt"
+ "io"
+ "io/ioutil"
"os"
+ "os/exec"
"path/filepath"
"regexp"
"strings"
+ "v.io/core/veyron2"
"v.io/core/veyron2/services/mgmt/application"
- "v.io/core/veyron2/vlog"
+ "v.io/core/veyron2/services/mgmt/device"
- // For VeyronEnvironment, see TODO.
+ "v.io/core/veyron/lib/flags/consts"
"v.io/core/veyron/services/mgmt/device/config"
)
+// stopExitCode is the exit code that the device manager should return when it
+// gets a Stop RPC. This number is picked quasi-arbitrarily from the set of
+// exit codes without prior special meanings.
+const stopExitCode = 140
+
+// dmRoot is the directory name where the device manager installs itself.
+const dmRoot = "dmroot"
+
// InstallFrom takes a veyron object name denoting an application service where
// a device manager application envelope can be obtained. It downloads the
// latest version of the device manager and installs it.
@@ -44,37 +56,43 @@
return ret
}
-// VeyronEnvironment returns only this environment variables that are
-// specific to the Veyron system.
+// VeyronEnvironment returns only the environment variables that are specific
+// to the Veyron system.
func VeyronEnvironment(env []string) []string {
return filterEnvironment(env, allowedVarsRE, deniedVarsRE)
}
// SelfInstall installs the device manager and configures it using the
// environment and the supplied command-line flags.
-func SelfInstall(args, env []string) error {
- configState, err := config.Load()
- if err != nil {
- return fmt.Errorf("failed to load config: %v", err)
+func SelfInstall(installDir, suidHelper, agent string, singleUser, sessionMode bool, args, env []string) error {
+ root := filepath.Join(installDir, dmRoot)
+ if _, err := os.Stat(root); err == nil || !os.IsNotExist(err) {
+ return fmt.Errorf("%v already exists", root)
}
-
- vlog.VI(1).Infof("Config for device manager: %v", configState)
- configState.Name = "dummy" // Just so that Validate passes.
- if err := configState.Validate(); err != nil {
- return fmt.Errorf("invalid config %v: %v", configState, err)
- }
-
- // Create device manager directory tree.
- deviceDir := filepath.Join(configState.Root, "device-manager", "base")
- if err := os.RemoveAll(deviceDir); err != nil {
- return fmt.Errorf("RemoveAll(%v) failed: %v", deviceDir, err)
- }
+ deviceDir := filepath.Join(root, "device-manager", "base")
perm := os.FileMode(0700)
if err := os.MkdirAll(deviceDir, perm); err != nil {
return fmt.Errorf("MkdirAll(%v, %v) failed: %v", deviceDir, perm, err)
}
+ currLink := filepath.Join(root, "current")
+ configState := &config.State{
+ Name: "dummy", // So that Validate passes.
+ Root: root,
+ CurrentLink: currLink,
+ Helper: suidHelper,
+ }
+ if err := configState.Validate(); err != nil {
+ return fmt.Errorf("invalid config %v: %v", configState, err)
+ }
+ var extraArgs []string
+ if name, err := os.Hostname(); err == nil {
+ extraArgs = append(extraArgs, fmt.Sprintf("--name=%q", name))
+ }
+ if !sessionMode {
+ extraArgs = append(extraArgs, fmt.Sprintf("--stop_exit_code=%d", stopExitCode))
+ }
envelope := &application.Envelope{
- Args: args,
+ Args: append(extraArgs, args...),
// TODO(caprita): Cleaning up env vars to avoid picking up all
// the garbage from the user's env.
// Alternatively, pass the env vars meant specifically for the
@@ -84,33 +102,106 @@
if err := linkSelf(deviceDir, "deviced"); err != nil {
return err
}
- // We don't pass in the config state settings, since they're already
- // contained in the environment.
- if err := generateScript(deviceDir, nil, envelope); err != nil {
+ configSettings, err := configState.Save(nil)
+ if err != nil {
+ return fmt.Errorf("failed to serialize config %v: %v", configState, err)
+ }
+ if err := generateScript(deviceDir, configSettings, envelope); err != nil {
return err
}
// TODO(caprita): Test the device manager we just installed.
- return updateLink(filepath.Join(deviceDir, "deviced.sh"), configState.CurrentLink)
+ if err := updateLink(filepath.Join(deviceDir, "deviced.sh"), currLink); err != nil {
+ return err
+ }
+
+ return generateAgentScript(root, agent, currLink, singleUser, sessionMode)
// TODO(caprita): Update system management daemon.
}
-// Uninstall undoes SelfInstall, removing the device manager's installation
-// directory and soft link.
-func Uninstall() error {
- configState, err := config.Load()
- if err != nil {
- return fmt.Errorf("failed to load config: %v", err)
+func generateAgentScript(workspace, agent, currLink string, singleUser, sessionMode bool) error {
+ securityDir := filepath.Join(workspace, "security")
+ principalDir := filepath.Join(securityDir, "principal")
+ keyDir := filepath.Join(securityDir, "keys")
+ perm := os.FileMode(0700)
+ if err := os.MkdirAll(principalDir, perm); err != nil {
+ return fmt.Errorf("MkdirAll(%v, %v) failed: %v", principalDir, perm, err)
}
+ if err := os.MkdirAll(keyDir, perm); err != nil {
+ return fmt.Errorf("MkdirAll(%v, %v) failed: %v", keyDir, perm, err)
+ }
+ // TODO(caprita): Switch all our generated bash scripts to use templates.
+ output := "#!/bin/bash\n"
+ output += fmt.Sprintf("%s=%q ", consts.VeyronCredentials, principalDir)
+ // Escape the path to the binary; %q uses Go-syntax escaping, but it's
+ // close enough to Bash that we're using it as an approximation.
+ //
+ // TODO(caprita/rthellend): expose and use shellEscape (from
+ // veyron/tools/debug/impl.go) instead.
+ output += fmt.Sprintf("exec %q ", agent)
+ if singleUser {
+ output += "--no_passphrase "
+ }
+ if !sessionMode {
+ output += fmt.Sprintf("--restart_exit_code=!%d ", stopExitCode)
+ }
+ output += fmt.Sprintf("--additional_principals=%q ", keyDir)
+ output += fmt.Sprintf("%q\n", currLink)
+ path := filepath.Join(workspace, "agent_deviced.sh")
+ if err := ioutil.WriteFile(path, []byte(output), 0700); err != nil {
+ return fmt.Errorf("WriteFile(%v) failed: %v", path, err)
+ }
+ // TODO(caprita): Put logs under dmroot/device-manager/logs.
+ return nil
+}
- vlog.VI(1).Infof("Config for device manager: %v", configState)
- configState.Name = "dummy" // Just so that Validate passes.
- if err := configState.Validate(); err != nil {
- return fmt.Errorf("invalid config %v: %v", configState, err)
+// Uninstall undoes SelfInstall, removing the device manager's installation
+// directory.
+func Uninstall(installDir string) error {
+ // TODO(caprita): ensure device is stopped?
+
+ root := filepath.Join(installDir, dmRoot)
+ // TODO(caprita): Use suidhelper to delete dirs/files owned by other
+ // users under the app work dirs.
+ if err := os.RemoveAll(root); err != nil {
+ return fmt.Errorf("RemoveAll(%v) failed: %v", root, err)
}
- if err := os.RemoveAll(configState.Root); err != nil {
- return fmt.Errorf("RemoveAll(%v) failed: %v", configState.Root, err)
- }
- return os.Remove(configState.CurrentLink)
// TODO(caprita): Update system management daemon.
+ return nil
+}
+
+// Start starts the device manager.
+func Start(installDir string, stderr, stdout io.Writer) error {
+ // TODO(caprita): make sure it's not already running?
+
+ root := filepath.Join(installDir, dmRoot)
+ // TODO(caprita): In non-session mode, use system management daemon.
+ agentScript := filepath.Join(root, "agent_deviced.sh")
+ cmd := exec.Command(agentScript)
+ if stderr != nil {
+ cmd.Stderr = stderr
+ }
+ if stdout != nil {
+ cmd.Stdout = stdout
+ }
+ if err := cmd.Start(); err != nil {
+ return fmt.Errorf("Start failed: %v", err)
+ }
+ return nil
+}
+
+// Stop stops the device manager.
+func Stop(installDir string, runtime veyron2.Runtime) error {
+ root := filepath.Join(installDir, dmRoot)
+ info, err := loadManagerInfo(filepath.Join(root, "device-manager"))
+ if err != nil {
+ return fmt.Errorf("loadManagerInfo failed: %v", err)
+ }
+ if err := device.ApplicationClient(info.MgrName).Stop(runtime.NewContext(), 5); err != nil {
+ return fmt.Errorf("Stop failed: %v", err)
+ }
+ // TODO(caprita): Wait for the (device|agent) process to be gone.
+
+ // TODO(caprita): In non-session mode, use system management daemon.
+ return nil
}
diff --git a/services/mgmt/device/impl/device_service.go b/services/mgmt/device/impl/device_service.go
index 458456b..8c9f611 100644
--- a/services/mgmt/device/impl/device_service.go
+++ b/services/mgmt/device/impl/device_service.go
@@ -6,6 +6,8 @@
//
// <config.Root>/
// device-manager/
+// info - metadata for the device manager (such as object
+// name and process id)
// <version 1 timestamp>/ - timestamp of when the version was downloaded
// deviced - the device manager binary
// deviced.sh - a shell script to start the binary
@@ -27,6 +29,7 @@
import (
"bufio"
+ "encoding/json"
"fmt"
"io"
"io/ioutil"
@@ -95,6 +98,43 @@
uat BlessingSystemAssociationStore
}
+// managerInfo holds state about a running device manager.
+type managerInfo struct {
+ MgrName string
+ Pid int
+}
+
+func saveManagerInfo(dir string, info *managerInfo) error {
+ jsonInfo, err := json.Marshal(info)
+ if err != nil {
+ vlog.Errorf("Marshal(%v) failed: %v", info, err)
+ return verror2.Make(ErrOperationFailed, nil)
+ }
+ if err := os.MkdirAll(dir, os.FileMode(0700)); err != nil {
+ vlog.Errorf("MkdirAll(%v) failed: %v", dir, err)
+ return verror2.Make(ErrOperationFailed, nil)
+ }
+ infoPath := filepath.Join(dir, "info")
+ if err := ioutil.WriteFile(infoPath, jsonInfo, 0600); err != nil {
+ vlog.Errorf("WriteFile(%v) failed: %v", infoPath, err)
+ return verror2.Make(ErrOperationFailed, nil)
+ }
+ return nil
+}
+
+func loadManagerInfo(dir string) (*managerInfo, error) {
+ infoPath := filepath.Join(dir, "info")
+ info := new(managerInfo)
+ if infoBytes, err := ioutil.ReadFile(infoPath); err != nil {
+ vlog.Errorf("ReadFile(%v) failed: %v", infoPath, err)
+ return nil, verror2.Make(ErrOperationFailed, nil)
+ } else if err := json.Unmarshal(infoBytes, info); err != nil {
+ vlog.Errorf("Unmarshal(%v) failed: %v", infoBytes, err)
+ return nil, verror2.Make(ErrOperationFailed, nil)
+ }
+ return info, nil
+}
+
func (s *deviceService) Claim(ctx ipc.ServerContext) error {
return s.disp.claimDeviceManager(ctx)
}
diff --git a/services/mgmt/device/impl/dispatcher.go b/services/mgmt/device/impl/dispatcher.go
index cfedf73..dabfcbc 100644
--- a/services/mgmt/device/impl/dispatcher.go
+++ b/services/mgmt/device/impl/dispatcher.go
@@ -89,6 +89,16 @@
if err := config.Validate(); err != nil {
return nil, fmt.Errorf("invalid config %v: %v", config, err)
}
+ // TODO(caprita): use some mechansim (a file lock or presence of entry
+ // in mounttable) to ensure only one device manager is running in an
+ // installation?
+ mi := &managerInfo{
+ MgrName: naming.Join(config.Name, deviceSuffix),
+ Pid: os.Getpid(),
+ }
+ if err := saveManagerInfo(filepath.Join(config.Root, "device-manager"), mi); err != nil {
+ return nil, fmt.Errorf("failed to save info: %v", err)
+ }
uat, err := NewBlessingSystemAssociationStore(config.Root)
if err != nil {
return nil, fmt.Errorf("cannot create persistent store for identity to system account associations: %v", err)
diff --git a/services/mgmt/device/impl/impl_test.go b/services/mgmt/device/impl/impl_test.go
index adc7b64..f9e619d 100644
--- a/services/mgmt/device/impl/impl_test.go
+++ b/services/mgmt/device/impl/impl_test.go
@@ -10,6 +10,7 @@
"encoding/base64"
"encoding/hex"
"encoding/json"
+ "flag"
"fmt"
"io"
"io/ioutil"
@@ -43,6 +44,7 @@
verror "v.io/core/veyron2/verror2"
"v.io/core/veyron2/vlog"
+ "v.io/core/veyron/lib/expect"
"v.io/core/veyron/lib/modules"
"v.io/core/veyron/lib/signals"
"v.io/core/veyron/lib/testutil"
@@ -64,14 +66,16 @@
)
func init() {
+ // The installer sets this flag on the installed device manager, so we
+ // need to ensure it's defined.
+ flag.String("name", "", "")
+
// TODO(rthellend): Remove when vom2 is ready.
vdlutil.Register(&naming.VDLMountedServer{})
modules.RegisterChild(execScriptCmd, "", execScript)
modules.RegisterChild(deviceManagerCmd, "", deviceManager)
modules.RegisterChild(appCmd, "", app)
- modules.RegisterChild(installerCmd, "", install)
- modules.RegisterChild(uninstallerCmd, "", uninstall)
testutil.Init()
if modules.IsModulesProcess() {
@@ -194,35 +198,6 @@
return nil
}
-// install installs the device manager.
-func install(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- args = args[1:]
- // args[0] is the entrypoint for the binary to be run from the shell
- // script that SelfInstall will write out.
- entrypoint := args[0]
- // Overwrite the entrypoint in our environment (i.e. the one that got us
- // here), with the one we want written out in the shell script.
- osenv := modules.SetEntryPoint(env, entrypoint)
- if args[1] != "--" {
- vlog.Fatalf("expected '--' immediately following command name")
- }
- args = append([]string{""}, args[2:]...) // skip the cmd and '--'
- if err := impl.SelfInstall(args, osenv); err != nil {
- vlog.Fatalf("SelfInstall failed: %v", err)
- return err
- }
- return nil
-}
-
-// uninstall uninstalls the device manager.
-func uninstall(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- if err := impl.Uninstall(); err != nil {
- vlog.Fatalf("Uninstall failed: %v", err)
- return err
- }
- return nil
-}
-
// appService defines a test service that the test app should be running.
// TODO(caprita): Use this to make calls to the app and verify how Suspend/Stop
// interact with an active service.
@@ -947,73 +922,71 @@
}
}
-// TestDeviceManagerInstallUninstall verifies the 'self install' and 'uninstall'
+type simpleRW chan []byte
+
+func (s simpleRW) Write(p []byte) (n int, err error) {
+ s <- p
+ return len(p), nil
+}
+func (s simpleRW) Read(p []byte) (n int, err error) {
+ return copy(p, <-s), nil
+}
+
+// TestDeviceManagerInstallation verifies the 'self install' and 'uninstall'
// functionality of the device manager: it runs SelfInstall in a child process,
// then runs the executable from the soft link that the installation created.
// This should bring up a functioning device manager. In the end it runs
// Uninstall and verifies that the installation is gone.
-func TestDeviceManagerInstallUninstall(t *testing.T) {
+func TestDeviceManagerInstallation(t *testing.T) {
sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalRT)
defer deferFn()
-
testDir, cleanup := setupRootDir(t)
defer cleanup()
- root := filepath.Join(testDir, "root")
- currLink := filepath.Join(testDir, "current_link")
+ // Create a script wrapping the test target that implements suidhelper.
+ helperPath := generateSuidHelperScript(t, testDir)
+ // Create a dummy script mascarading as the security agent.
+ agentPath := generateAgentScript(t, testDir)
// Create an 'envelope' for the device manager that we can pass to the
// installer, to ensure that the device manager that the installer
- // configures can run. The installer uses a shell script, so we need
- // to get a set of arguments that will work from within the shell
- // script in order for it to start a device manager.
- // We don't need the environment here since that can only
- // be correctly setup in the actual 'installer' command implementation
- // (in this case the shell script) which will inherit its environment
- // when we run it.
- // TODO(caprita): figure out if this is really necessary, hopefully not.
- dmargs, _ := sh.CommandEnvelope(deviceManagerCmd, nil)
- argsForDeviceManager := append([]string{deviceManagerCmd, "--"}, dmargs[1:]...)
- argsForDeviceManager = append(argsForDeviceManager, "dm")
+ // configures can run.
+ dmargs, dmenv := sh.CommandEnvelope(deviceManagerCmd, nil, "dm")
+ dmDir := filepath.Join(testDir, "dm")
+ singleUser, sessionMode := true, true
+ if err := impl.SelfInstall(dmDir, helperPath, agentPath, singleUser, sessionMode, dmargs[1:], dmenv); err != nil {
+ t.Fatalf("SelfInstall failed: %v", err)
+ }
- // Add vars to instruct the installer how to configure the device
- // manager.
- installerEnv := []string{config.RootEnv + "=" + root, config.CurrentLinkEnv + "=" + currLink, config.HelperEnv + "=" + "unused"}
- installerh, installers := mgmttest.RunShellCommand(t, sh, installerEnv, installerCmd, argsForDeviceManager...)
- installers.ExpectEOF()
- installerh.Shutdown(os.Stderr, os.Stderr)
-
- // CurrLink should now be pointing to a device manager script that
- // can start up a device manager.
- dmh, dms := mgmttest.RunShellCommand(t, sh, nil, execScriptCmd, currLink)
-
- // We need the pid of the child process started by the device manager
- // script above to signal it, not the pid of the script itself.
- // TODO(caprita): the scripts that the device manager generates should
- // progagate signals so you don't have to obtain the pid of the child by
- // reading it from stdout as we do here. The device manager should be
- // able to retain a list of the processes it spawns and be confident
- // that sending a signal to them will also result in that signal being
- // sent to their children and so on.
- pid := mgmttest.ReadPID(t, dms)
+ resolveExpectNotFound(t, "dm")
+ // Start the device manager.
+ stdout := make(simpleRW, 100)
+ if err := impl.Start(dmDir, os.Stderr, stdout); err != nil {
+ t.Fatalf("Start failed: %v", err)
+ }
+ dms := expect.NewSession(t, stdout, mgmttest.ExpectTimeout)
+ mgmttest.ReadPID(t, dms)
resolve(t, "dm", 1)
revertDeviceExpectError(t, "dm", impl.ErrUpdateNoOp.ID) // No previous version available.
- syscall.Kill(pid, syscall.SIGINT)
+ // Stop the device manager.
+ if err := impl.Stop(dmDir, globalRT); err != nil {
+ t.Fatalf("Stop failed: %v", err)
+ }
+ dms.Expect("stop handler")
dms.Expect("dm terminating")
- dms.ExpectEOF()
- dmh.Shutdown(os.Stderr, os.Stderr)
// Uninstall.
- uninstallerEnv := []string{config.RootEnv + "=" + root, config.CurrentLinkEnv + "=" + currLink, config.HelperEnv + "=" + "unused"}
- uninstallerh, uninstallers := mgmttest.RunShellCommand(t, sh, uninstallerEnv, uninstallerCmd)
- uninstallers.ExpectEOF()
- uninstallerh.Shutdown(os.Stderr, os.Stderr)
- if _, err := os.Stat(currLink); err == nil || !os.IsNotExist(err) {
- t.Fatalf("Stat(%v) returned %v", currLink, err)
+ if err := impl.Uninstall(dmDir); err != nil {
+ t.Fatalf("Uninstall failed: %v", err)
}
- if _, err := os.Stat(root); err == nil || !os.IsNotExist(err) {
- t.Fatalf("Stat(%v) returned %v", root, err)
+ // Ensure that the installation is gone.
+ if files, err := ioutil.ReadDir(dmDir); err != nil || len(files) > 0 {
+ var finfo []string
+ for _, f := range files {
+ finfo = append(finfo, f.Name())
+ }
+ t.Fatalf("ReadDir returned (%v, %v)", err, finfo)
}
}
diff --git a/services/mgmt/device/impl/util_test.go b/services/mgmt/device/impl/util_test.go
index ee0a754..6cf2b0e 100644
--- a/services/mgmt/device/impl/util_test.go
+++ b/services/mgmt/device/impl/util_test.go
@@ -20,9 +20,9 @@
"v.io/core/veyron2/vlog"
"v.io/core/veyron/lib/modules"
+ "v.io/core/veyron/lib/testutil"
_ "v.io/core/veyron/profiles/static"
"v.io/core/veyron/services/mgmt/device/impl"
- "v.io/core/veyron/lib/testutil"
)
const (
@@ -291,11 +291,38 @@
if err := os.MkdirAll(root, 0755); err != nil {
t.Fatalf("MkdirAll failed: %v", err)
}
- // Helper does not need to live under the device manager's root dir, but
- // we put it there for convenience.
path := filepath.Join(root, "helper.sh")
if err := ioutil.WriteFile(path, []byte(output), 0755); err != nil {
t.Fatalf("WriteFile(%v) failed: %v", path, err)
}
return path
}
+
+// generateAgentScript creates a simple script that acts as the security agent
+// for tests. It blackholes arguments meant for the agent.
+func generateAgentScript(t *testing.T, root string) string {
+ output := `
+#!/bin/bash
+ARGS=$*
+for ARG in ${ARGS[@]}; do
+ if [[ ${ARG} = -- ]]; then
+ ARGS=(${ARGS[@]/$ARG})
+ break
+ elif [[ ${ARG} == --* ]]; then
+ ARGS=(${ARGS[@]/$ARG})
+ else
+ break
+ fi
+done
+
+exec ${ARGS[@]}
+`
+ if err := os.MkdirAll(root, 0755); err != nil {
+ t.Fatalf("MkdirAll failed: %v", err)
+ }
+ path := filepath.Join(root, "agenthelper.sh")
+ if err := ioutil.WriteFile(path, []byte(output), 0755); err != nil {
+ t.Fatalf("WriteFile(%v) failed: %v", path, err)
+ }
+ return path
+}
diff --git a/tools/mgmt/device/devicex b/tools/mgmt/device/devicex
new file mode 100755
index 0000000..813d842
--- /dev/null
+++ b/tools/mgmt/device/devicex
@@ -0,0 +1,280 @@
+#!/bin/bash
+#
+# Administers a device manager installation.
+#
+# This script is a thin wrapper on top of the deviced commands. Its main
+# purpose is to set up the installation by fetches the binaries required for a
+# device manager installation from a few possible sources and setting up the
+# setuid helper.
+
+set -e
+
+usage() {
+ echo "usage:"
+ echo
+ echo "Install device manager:"
+ echo "VANADIUM_DEVICE_DIR=<installation dir> ./devicex install [<binary source>] [ args for installer... ] [ -- args for device manager...]"
+ echo " Possible values for <binary source>:"
+ echo " unspecified: get binaries from local repository"
+ echo " /path/to/binaries: get binaries from local filesystem"
+ echo " http://host/path: get binaries from HTTP server"
+ echo
+ echo "Uninstall device manager:"
+ echo "VANADIUM_DEVICE_DIR=<installation dir> ./devicex uninstall"
+ echo
+ echo "Start device manager:"
+ echo "VANADIUM_DEVICE_DIR=<installation dir> ./devicex start"
+ echo
+ echo "Stop device manager:"
+ echo "VANADIUM_DEVICE_DIR=<installation dir> ./devicex stop"
+}
+
+readonly BIN_NAMES=(deviced suidhelper agentd)
+
+###############################################################################
+# Copies one binary from source to destination.
+# Arguments:
+# name of the binary
+# source dir of binary
+# destination dir of binary
+# Returns:
+# None
+###############################################################################
+copy_binary() {
+ local -r BIN_NAME="$1"
+ local -r BIN_SRC_DIR="$2"
+ local -r BIN_DEST_DIR="$3"
+ local -r SOURCE="${BIN_SRC_DIR}/${BIN_NAME}"
+ if [[ -x "${SOURCE}" ]]; then
+ local -r DESTINATION="${BIN_DEST_DIR}/${BIN_NAME}"
+ cp "${SOURCE}" "${DESTINATION}"
+ chmod 700 "${DESTINATION}"
+ else
+ echo "couldn't find ${SOURCE}"
+ exit 1
+ fi
+}
+
+###############################################################################
+# Fetches binaries needed by device manager installation.
+# Globals:
+# BIN_NAMES
+# VANADIUM_ROOT
+# Arguments:
+# destination for binaries
+# source of binaries
+# Returns:
+# None
+###############################################################################
+get_binaries() {
+ local -r BIN_INSTALL="$1"
+ local -r BIN_SOURCE="$2"
+
+ local bin_names_str=""
+ for bin_name in "${BIN_NAMES[@]}"; do
+ bin_names_str+=" ${bin_name}"
+ done
+
+ # If source is not specified, try to look for it in the repository.
+ if [[ -z "${BIN_SOURCE}" ]]; then
+ if [[ -z "${VANADIUM_ROOT}" ]]; then
+ echo 'ERROR: binary source not specified and no local repository available'
+ exit 1
+ fi
+ local -r REPO_BIN_DIR="${VANADIUM_ROOT}/release/go/bin"
+ echo "Fetching binaries:${bin_names_str} from build repository: ${REPO_BIN_DIR} ..."
+ for bin_name in "${BIN_NAMES[@]}"; do
+ copy_binary "${bin_name}" "${REPO_BIN_DIR}" "${BIN_INSTALL}"
+ done
+ return
+ fi
+
+ # If the source is specified as an existing local filesystem path,
+ # look for the binaries there.
+ if [[ -d "${BIN_SOURCE}" ]]; then
+ echo "Fetching binaries:${bin_names_str} locally from: ${BIN_SOURCE} ..."
+ for bin_name in "${BIN_NAMES[@]}"; do
+ copy_binary "${bin_name}" "${BIN_SOURCE}" "${BIN_INSTALL}"
+ done
+ return
+ fi
+
+ # If the source looks like a URL, use HTTP to fetch.
+ local -r URL_REGEXP='^(https?|ftp|file)://'
+ if [[ "${BIN_SOURCE}" =~ ${URL_REGEXP} ]]; then
+ echo "Fetching binaries:${bin_names_str} remotely from: ${BIN_SOURCE} ..."
+ for bin_name in "${BIN_NAMES[@]}"; do
+ local DEST="${BIN_INSTALL}/${bin_name}"
+ curl -f -o "${DEST}" "${BIN_SOURCE}/${bin_name}"
+ chmod 700 "${DEST}"
+ done
+ return
+ fi
+
+ echo 'ERROR: couldn'"'"'t fetch binaries.'
+ exit 1
+}
+
+###############################################################################
+# Installs device manager: fetches binaries, configures suidhelper, calls the
+# self-install command on deviced.
+# Globals:
+# VANADIUM_DEVICE_DIR
+# Arguments:
+# source of binaries (optional)
+# args for self-install command and for device manager (optional)
+# Returns:
+# None
+###############################################################################
+install() {
+ if [[ -e "${VANADIUM_DEVICE_DIR}" ]]; then
+ echo "${VANADIUM_DEVICE_DIR} already exists!"
+ exit 1
+ fi
+ mkdir -m 700 "${VANADIUM_DEVICE_DIR}"
+ local -r BIN_INSTALL="${VANADIUM_DEVICE_DIR}/bin"
+ mkdir -m 700 "${BIN_INSTALL}"
+
+ # Fetch the binaries.
+ if [[ $# = 0 || "$1" == --* ]]; then
+ local -r BIN_SOURCE=""
+ else
+ local -r BIN_SOURCE="$1"
+ shift
+ fi
+ get_binaries "${BIN_INSTALL}" "${BIN_SOURCE}"
+ for bin_name in "${BIN_NAMES[@]}"; do
+ local BINARY="${BIN_INSTALL}/${bin_name}"
+ if [[ ! -s "${BINARY}" ]]; then
+ echo "${BINARY} is empty."
+ exit 1
+ fi
+ done
+ echo "Binaries are in ${BIN_INSTALL}."
+
+ # Set up the suidhelper.
+ echo "Configuring suidhelper ..."
+ local -r SETUID_SCRIPT="${BIN_INSTALL}/suidhelper"
+ local SINGLE_USER=false
+ for ARG in $*; do
+ if [[ ${ARG} = "--" ]]; then
+ break
+ elif [[ ${ARG} = "--single_user" ]]; then
+ SINGLE_USER=true
+ break
+ fi
+ done
+ if [[ ${SINGLE_USER} == false ]]; then
+ sudo bash -c "chown root:root \"${SETUID_SCRIPT}\"; chmod 4551 \"${SETUID_SCRIPT}\""
+ fi
+ echo "Suidhelper configured."
+
+ # Install the device manager.
+ echo "Installing device manager under ${VANADIUM_DEVICE_DIR} ..."
+ "${BIN_INSTALL}/deviced" install --suid_helper="${SETUID_SCRIPT}" --agent="${BIN_INSTALL}/agentd" "$@"
+ echo "Device manager installed."
+}
+
+###############################################################################
+# Uninstalls device manager: calls the uninstall command of deviced and removes
+# the installation.
+# Globals:
+# VANADIUM_DEVICE_DIR
+# Arguments:
+# None
+# Returns:
+# None
+###############################################################################
+uninstall() {
+ if [[ ! -d "${VANADIUM_DEVICE_DIR}" ]]; then
+ echo "${VANADIUM_DEVICE_DIR} is not a directory!"
+ exit 1
+ fi
+ local -r BIN_INSTALL="${VANADIUM_DEVICE_DIR}/bin"
+ echo "Uninstalling device manager from ${VANADIUM_DEVICE_DIR} ..."
+ "${BIN_INSTALL}/deviced" uninstall
+ echo "Device manager uninstalled."
+ # Any data created underneath "${VANADIUM_DEVICE_DIR}" by the "deviced
+ # install" command would have been cleaned up already by "deviced uninstall".
+ # However, install() created "${VANADIUM_DEVICE_DIR}", so uninstall() needs
+ # to remove it (as well as data created by install(), like bin/*).
+ rm -rf "${VANADIUM_DEVICE_DIR}"
+ echo "Removed ${VANADIUM_DEVICE_DIR}"
+}
+
+###############################################################################
+# Starts device manager: calls the start command of deviced.
+# Globals:
+# VANADIUM_DEVICE_DIR
+# Arguments:
+# None
+# Returns:
+# None
+###############################################################################
+start() {
+ if [[ ! -d "${VANADIUM_DEVICE_DIR}" ]]; then
+ echo "${VANADIUM_DEVICE_DIR} is not a directory!"
+ exit 1
+ fi
+ local -r BIN_INSTALL="${VANADIUM_DEVICE_DIR}/bin"
+ "${BIN_INSTALL}/deviced" start
+}
+
+###############################################################################
+# Stops device manager: calls the stop command of deviced.
+# Globals:
+# VANADIUM_DEVICE_DIR
+# Arguments:
+# None
+# Returns:
+# None
+###############################################################################
+stop() {
+ if [[ ! -d "${VANADIUM_DEVICE_DIR}" ]]; then
+ echo "${VANADIUM_DEVICE_DIR} is not a directory!"
+ exit 1
+ fi
+ local -r BIN_INSTALL="${VANADIUM_DEVICE_DIR}/bin"
+ "${BIN_INSTALL}/deviced" stop
+}
+
+main() {
+ if [[ -z "${VANADIUM_DEVICE_DIR}" ]]; then
+ echo 'No local device installation dir specified!'
+ usage
+ exit 1
+ fi
+ if [[ -e "${VANADIUM_DEVICE_DIR}" && ! -d "${VANADIUM_DEVICE_DIR}" ]]; then
+ echo "${VANADIUM_DEVICE_DIR} is not a directory!"
+ usage
+ exit 1
+ fi
+
+ if [[ $# = 0 ]]; then
+ echo 'No command specified!'
+ usage
+ exit 1
+ fi
+ local -r COMMAND="$1"
+ shift
+ case "${COMMAND}" in
+ install)
+ install "$@"
+ ;;
+ uninstall)
+ uninstall
+ ;;
+ start)
+ start
+ ;;
+ stop)
+ stop
+ ;;
+ *)
+ echo "Unrecognized command: ${COMMAND}!"
+ usage
+ exit 1
+ esac
+}
+
+main "$@"
diff --git a/tools/mgmt/device/dminstall b/tools/mgmt/device/dminstall
deleted file mode 100755
index 3a15d5c..0000000
--- a/tools/mgmt/device/dminstall
+++ /dev/null
@@ -1,222 +0,0 @@
-#!/bin/bash
-#
-# Installs device manager on the local machine.
-#
-# Specifically:
-#
-# 1. Fetches the binaries required for a device manager installation from a few
-# possible sources.
-#
-# 2. Sets up the helper with setuid. The helper binary needs to be owned by
-# root and have the suid bit set, to enable the device manager to run binaries
-# under different system accounts than itself.
-#
-# 3. Runs the self-install command on the device manager.
-#
-# Usage:
-#
-# # Gets binaries from local repository
-# ./dminstall <install parent dir>
-#
-# # Gets binaries from local filesystem
-# ./dminstall <install parent dir> /path/to/binaries
-#
-# # Gets binaries from HTTP server
-# ./dminstall <install parent dir> http://host/path
-
-set -e
-
-usage() {
- echo "usage:"
- echo "./dminstall [--single_user] <install parent dir> [<binary source>] [-- args for device manager...]"
-}
-
-readonly BIN_NAMES=(deviced suidhelper agentd)
-readonly STOP_EXIT_CODE=140
-
-###############################################################################
-# Copies one binary from source to destination.
-# Arguments:
-# name of the binary
-# source dir of binary
-# destination dir of binary
-# Returns:
-# None
-###############################################################################
-copy_binary() {
- local -r BIN_NAME="$1"
- local -r BIN_SRC_DIR="$2"
- local -r BIN_DEST_DIR="$3"
- local -r SOURCE="${BIN_SRC_DIR}/${BIN_NAME}"
- if [[ -x "${SOURCE}" ]]; then
- local -r DESTINATION="${BIN_DEST_DIR}/${BIN_NAME}"
- cp "${SOURCE}" "${DESTINATION}"
- chmod 700 "${DESTINATION}"
- else
- echo "couldn't find ${SOURCE}"
- exit 1
- fi
-}
-
-###############################################################################
-# Fetches binaries needed by device manager installation.
-# Globals:
-# BIN_NAMES
-# VANADIUM_ROOT
-# Arguments:
-# destination for binaries
-# source of binaries
-# Returns:
-# None
-###############################################################################
-get_binaries() {
- local -r BIN_INSTALL="$1"
- local -r BIN_SOURCE="$2"
-
- local bin_names_str=""
- for bin_name in "${BIN_NAMES[@]}"; do
- bin_names_str+=" ${bin_name}"
- done
-
- # If source is not specified, try to look for it in the repository.
- if [[ -z "${BIN_SOURCE}" ]]; then
- if [[ -z "${VANADIUM_ROOT}" ]]; then
- echo 'ERROR: binary source not specified and no local repository available'
- exit 1
- fi
- local -r REPO_BIN_DIR="${VANADIUM_ROOT}/release/go/bin"
- echo "Fetching binaries:${bin_names_str} from build repository: ${REPO_BIN_DIR} ..."
- for bin_name in "${BIN_NAMES[@]}"; do
- copy_binary "${bin_name}" "${REPO_BIN_DIR}" "${BIN_INSTALL}"
- done
- return
- fi
-
- # If the source is specified as an existing local filesystem path,
- # look for the binaries there.
- if [[ -d "${BIN_SOURCE}" ]]; then
- echo "Fetching binaries:${bin_names_str} locally from: ${BIN_SOURCE} ..."
- for bin_name in "${BIN_NAMES[@]}"; do
- copy_binary "${bin_name}" "${BIN_SOURCE}" "${BIN_INSTALL}"
- done
- return
- fi
-
- # If the source looks like a URL, use HTTP to fetch.
- local -r URL_REGEXP='^(https?|ftp|file)://'
- if [[ "${BIN_SOURCE}" =~ ${URL_REGEXP} ]]; then
- echo "Fetching binaries:${bin_names_str} remotely from: ${BIN_SOURCE} ..."
- for bin_name in "${BIN_NAMES[@]}"; do
- local DEST="${BIN_INSTALL}/${bin_name}"
- curl -f -o "${DEST}" "${BIN_SOURCE}/${bin_name}"
- chmod 700 "${DEST}"
- done
- return
- fi
-
- echo 'ERROR: couldn'"'"'t fetch binaries.'
- exit 1
-}
-
-main() {
- if [[ "$1" == "--single_user" ]]; then
- local -r SINGLE_USER=true
- shift
- local AGENT_FLAG="--no_passphrase"
- else
- local -r SINGLE_USER=false
- local AGENT_FLAG=""
- fi
-
- local -r INSTALL_PARENT_DIR="$1"
- if [[ -z "${INSTALL_PARENT_DIR}" ]]; then
- echo 'No local install destination specified!'
- usage
- exit 1
- fi
- shift
-
- if [[ ! -d "${INSTALL_PARENT_DIR}" ]]; then
- echo "${INSTALL_PARENT_DIR} is not a directory!"
- exit 1
- fi
-
- local -r INSTALL_DIR="${INSTALL_PARENT_DIR}/device_manager"
-
- # TODO(caprita): Check that the device manager is not already installed before
- # proceeding. We should require an explicit uninstall to avoid wiping away
- # the device manager accidentally.
- if [[ ${SINGLE_USER} == false ]]; then
- sudo rm -rf "${INSTALL_DIR}"
- else
- rm -rf "${INSTALL_DIR}"
- fi
- mkdir -m 700 "${INSTALL_DIR}"
-
- local -r BIN_INSTALL="${INSTALL_DIR}/bin"
- mkdir -m 700 "${BIN_INSTALL}"
-
- # Fetch the binaries.
- if [[ $# = 0 || "$1" = "--" ]]; then
- local -r BIN_SOURCE=""
- else
- local -r BIN_SOURCE="$1"
- shift
- fi
- get_binaries "${BIN_INSTALL}" "${BIN_SOURCE}"
- for bin_name in "${BIN_NAMES[@]}"; do
- local BINARY="${BIN_INSTALL}/${bin_name}"
- if [[ ! -s "${BINARY}" ]]; then
- echo "${BINARY} is empty."
- exit 1
- fi
- done
- echo "Binaries are in ${BIN_INSTALL}."
-
- # Set up the suidhelper.
- echo "Configuring suidhelper ..."
- local -r SETUID_SCRIPT="${BIN_INSTALL}/suidhelper"
- if [[ ${SINGLE_USER} == false ]]; then
- sudo bash -c "chown root:root \"${SETUID_SCRIPT}\"; chmod 4551 \"${SETUID_SCRIPT}\""
- fi
- echo "Suidhelper configured."
-
- # Tell the device manager to install itself.
- local -r DM_ROOT="${INSTALL_DIR}/dmroot"
- echo "Installing device manager under ${DM_ROOT} ..."
- local -r PUBLISH=$(hostname)
- if [[ "$1" = "--" ]]; then
- shift
- elif [[ $# != 0 ]]; then
- echo "Unexpected arguments: $@"
- usage
- exit 1
- fi
-
- VEYRON_DM_CURRENT="${INSTALL_DIR}/deviced.curr" VEYRON_DM_ROOT="${DM_ROOT}" \
- VEYRON_DM_HELPER="${SETUID_SCRIPT}" "${BIN_INSTALL}/deviced" install -- \
- --name="${PUBLISH}" --stop_exit_code=${STOP_EXIT_CODE} "$@"
- echo "Device manager installed."
-
- local -r SECURITY_DIR="${INSTALL_DIR}/security"
- mkdir -m 700 "${SECURITY_DIR}"
- local -r PRINCIPAL_DIR="${SECURITY_DIR}/principal"
- mkdir -m 700 "${PRINCIPAL_DIR}"
- local -r AGENT_KEY_DIR="${SECURITY_DIR}/keys"
- mkdir -m 700 "${AGENT_KEY_DIR}"
-
- # Run device manager under the security agent.
- echo
- echo "Running:"
- echo "VEYRON_CREDENTIALS=\"${PRINCIPAL_DIR}\" \"${BIN_INSTALL}/agentd\" \
-${AGENT_FLAG} --restart_exit_code=!${STOP_EXIT_CODE} \
---additional_principals=\"${AGENT_KEY_DIR}\" \"${INSTALL_DIR}/deviced.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}" exec "${BIN_INSTALL}/agentd" \
- ${AGENT_FLAG} --restart_exit_code=!${STOP_EXIT_CODE} \
- --additional_principals="${AGENT_KEY_DIR}" "${INSTALL_DIR}/deviced.curr"
-}
-
-main "$@"
diff --git a/tools/mgmt/device/dmuninstall b/tools/mgmt/device/dmuninstall
deleted file mode 100755
index e9daa29..0000000
--- a/tools/mgmt/device/dmuninstall
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/bin/bash
-#
-# Uninstalls device manager from the local machine.
-#
-# Usage:
-#
-# ./dmuninstall <install parent dir>
-
-set -e
-
-usage() {
- echo "usage:"
- echo "./dmuninstall [--single_user] <install parent dir>"
-}
-
-main() {
- if [[ "$1" == "--single_user" ]]; then
- local -r SINGLE_USER=true
- shift
- else
- local -r SINGLE_USER=false
- fi
- local -r INSTALL_PARENT_DIR="$1"
- if [[ -z "${INSTALL_PARENT_DIR}" ]]; then
- echo 'No local install directory specified!'
- usage
- exit 1
- fi
- shift
- local -r INSTALL_DIR="${INSTALL_PARENT_DIR}/device_manager"
- if [[ ! -d "${INSTALL_DIR}" ]]; then
- echo "${INSTALL_DIR} does not exist or is not a directory!"
- exit 1
- fi
-
- # Tell the device manager to uninstall itself.
- local -r DM_ROOT="${INSTALL_DIR}/dmroot"
- echo "Uninstalling device manager from ${DM_ROOT} ..."
-
- local -r BIN_INSTALL="${INSTALL_DIR}/bin"
-
- VEYRON_DM_CURRENT="${INSTALL_DIR}/deviced.curr" VEYRON_DM_ROOT="${DM_ROOT}" \
- VEYRON_DM_HELPER="unused" "${BIN_INSTALL}/deviced" uninstall
- echo "Device manager uninstalled."
-
- if [[ ${SINGLE_USER} == false ]]; then
- sudo rm -rf "${INSTALL_DIR}"
- else
- rm -rf "${INSTALL_DIR}"
- fi
- echo "Removed ${INSTALL_DIR}"
-}
-
-main "$@"
diff --git a/tools/mgmt/test.sh b/tools/mgmt/test.sh
index 0198535..7c52a27 100755
--- a/tools/mgmt/test.sh
+++ b/tools/mgmt/test.sh
@@ -21,8 +21,7 @@
NAMESPACE_BIN="$(shell_test::build_go_binary 'v.io/core/veyron/tools/namespace')"
PRINCIPAL_BIN="$(shell_test::build_go_binary 'v.io/core/veyron/tools/principal')"
DEBUG_BIN="$(shell_test::build_go_binary 'v.io/core/veyron/tools/debug')"
- DMINSTALL_SCRIPT="$(go list -f {{.Dir}} v.io/core/veyron/tools/mgmt/device)/dminstall"
- DMUNINSTALL_SCRIPT="$(go list -f {{.Dir}} v.io/core/veyron/tools/mgmt/device)/dmuninstall"
+ DEVICE_SCRIPT="$(go list -f {{.Dir}} v.io/core/veyron/tools/mgmt/device)/devicex"
}
# TODO(caprita): Move to shell_tesh.sh
@@ -45,7 +44,7 @@
local -r NAME="$3"
local -r OLD_ENTRY="${4:+}"
for i in $(seq 1 "${TIMEOUT}"); do
- local ENTRY=$("${NAMESPACE_BIN}" resolve "${NAME}" 2>/dev/null || true)
+ local ENTRY=$("${NAMESPACE_BIN}" resolve "${NAME}" 2>/dev/null)
if [[ -n "${ENTRY}" && "${ENTRY}" != "${OLD_ENTRY}" ]]; then
echo ${ENTRY}
return 0
@@ -57,25 +56,28 @@
}
###############################################################################
-# Waits until the given process is gone, within a set timeout.
+# Waits until the given name disappears from the mounttable, within a set
+# timeout.
# Arguments:
-# pid of process
+# path to namespace command-line tool
# timeout in seconds
+# name to look up
# Returns:
-# 0 if the pid is gone, and 1 if the timeout expires before that happens.
+# 0 if the name was gone from the mounttable, and 1 if the timeout expires
+# while the name is still in the mounttable.
###############################################################################
-wait_for_process_exit() {
- local -r PID="$1"
+wait_for_no_mountentry() {
+ local -r NAMESPACE_BIN="$1"
local -r TIMEOUT="$2"
+ local -r NAME="$3"
for i in $(seq 1 "${TIMEOUT}"); do
- local RESULT=$(shell::check_result kill -0 "${PID}")
- if [[ "${RESULT}" != "0" ]]; then
- # Process is gone, can return early.
+ local ENTRY=$("${NAMESPACE_BIN}" resolve "${NAME}" 2>/dev/null)
+ if [[ -z "${ENTRY}" ]]; then
return 0
fi
sleep 1
done
- echo "Timed out waiting for PID ${PID} to disappear."
+ echo "Timed out waiting for ${NAME} to disappear from the mounttable."
return 1
}
@@ -92,13 +94,12 @@
# Install and start device manager.
DM_INSTALL_DIR=$(shell::tmp_dir)
- shell_test::start_server "${VRUN}" "${DMINSTALL_SCRIPT}" --single_user "${DM_INSTALL_DIR}" \
- "${BIN_STAGING_DIR}" -- --veyron.tcp.address=127.0.0.1:0 || shell_test::fail "line ${LINENO} failed to start device manager"
+
+ export VANADIUM_DEVICE_DIR="${DM_INSTALL_DIR}/dm"
+ "${DEVICE_SCRIPT}" install "${BIN_STAGING_DIR}" --single_user -- --veyron.tcp.address=127.0.0.1:0
+ "${VRUN}" "${DEVICE_SCRIPT}" start
local -r DM_NAME=$(hostname)
DM_EP=$(wait_for_mountentry "${NAMESPACE_BIN}" 5 "${DM_NAME}")
- # Dump dminstall's log, just to provide visibility into its steps.
- local -r DM_PID="${START_SERVER_PID}"
- cat "${START_SERVER_LOG_FILE}"
# Verify that device manager is published under the expected name (hostname).
shell_test::assert_ne "$("${NAMESPACE_BIN}" glob "${DM_NAME}")" "" "${LINENO}"
@@ -179,17 +180,17 @@
shell_test::assert_eq "$("${NAMESPACE_BIN}" glob "${INSTANCE_NAME}/stats/...")" "" "${LINENO}"
shell_test::assert_ne "$("${NAMESPACE_BIN}" glob "${INSTANCE_NAME}/logs/...")" "" "${LINENO}"
+ # Restart the device manager.
"${DEVICE_BIN}" suspend "${DM_NAME}/device"
- DM_EP=$(wait_for_mountentry "${NAMESPACE_BIN}" "5" "${DM_NAME}" "{DM_EP}")
+ wait_for_mountentry "${NAMESPACE_BIN}" "5" "${DM_NAME}" "{DM_EP}"
- "${DEVICE_BIN}" stop "${DM_NAME}/device"
- wait_for_process_exit "${DM_PID}" 5
+ # Stop the device manager.
+ "${DEVICE_SCRIPT}" stop
+ wait_for_no_mountentry "${NAMESPACE_BIN}" "5" "${DM_NAME}"
- "${DMUNINSTALL_SCRIPT}" --single_user "${DM_INSTALL_DIR}" \
- || shell_test::fail "line ${LINENO} failed to uninstall device manager"
-
- if [[ -n "$(ls -A "${DM_INSTALL_DIR}")" ]]; then
- shell_test::fail "${DM_INSTALL_DIR} is not empty"
+ "${DEVICE_SCRIPT}" uninstall
+ if [[ -n "$(ls -A "${VANADIUM_DEVICE_DIR}" 2>/dev/null)" ]]; then
+ shell_test::fail "${VANADIUM_DEVICE_DIR} is not empty"
fi
shell_test::pass
}