Merge "veyron/tools/mgmt: Extend test.sh to support suid testing"
diff --git a/lib/modules/core/core.go b/lib/modules/core/core.go
index c2919fa..c937287 100644
--- a/lib/modules/core/core.go
+++ b/lib/modules/core/core.go
@@ -47,9 +47,6 @@
// echoClient <name> <text>
// invoke <name>.Echo(<text>)
//
-// exec <command> [args...]
-// executes the given command with the given arguments
-//
// proxyd <names>...
// runs a proxy server
package core
@@ -67,5 +64,4 @@
ProxyServerCommand = "proxyd"
WSPRCommand = "wsprd"
TestIdentitydCommand = "test_identityd"
- ExecCommand = "exec"
)
diff --git a/lib/modules/core/core_test.go b/lib/modules/core/core_test.go
index e5071c2..15a7c6a 100644
--- a/lib/modules/core/core_test.go
+++ b/lib/modules/core/core_test.go
@@ -202,7 +202,7 @@
func TestExec(t *testing.T) {
sh, cleanup := newShell(t)
defer cleanup()
- h, err := sh.Start(core.ExecCommand, nil, []string{"/bin/sh", "-c", "echo hello world"}...)
+ h, err := sh.StartExternalCommand(nil, []string{"/bin/sh", "-c", "echo hello world"}...)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -218,7 +218,7 @@
func TestExecWithEnv(t *testing.T) {
sh, cleanup := newShell(t)
defer cleanup()
- h, err := sh.Start(core.ExecCommand, []string{"BLAH=hello world"}, "/bin/sh", "-c", "printenv BLAH")
+ h, err := sh.StartExternalCommand([]string{"BLAH=hello world"}, "/bin/sh", "-c", "printenv BLAH")
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
diff --git a/lib/modules/core/exec.go b/lib/modules/core/exec.go
deleted file mode 100644
index be41d0d..0000000
--- a/lib/modules/core/exec.go
+++ /dev/null
@@ -1,20 +0,0 @@
-package core
-
-import (
- "io"
- "syscall"
-
- "v.io/core/veyron/lib/modules"
-)
-
-func init() {
- modules.RegisterChild(ExecCommand, "", execCommand)
-}
-
-func execCommand(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- envSlice := []string{}
- for key, value := range env {
- envSlice = append(envSlice, key+"="+value)
- }
- return syscall.Exec(args[1], args[1:], envSlice)
-}
diff --git a/lib/modules/exec.go b/lib/modules/exec.go
index b7e77c0..547ac0d 100644
--- a/lib/modules/exec.go
+++ b/lib/modules/exec.go
@@ -70,6 +70,10 @@
return &execHandle{name: name, entryPoint: shellEntryPoint + "=" + name, procErrCh: make(chan error, 1)}
}
+func newExecHandleForExternalCommand(name string) command {
+ return &execHandle{name: name, procErrCh: make(chan error, 1)}
+}
+
func (eh *execHandle) Stdout() io.Reader {
eh.mu.Lock()
defer eh.mu.Unlock()
@@ -114,8 +118,16 @@
eh.mu.Lock()
defer eh.mu.Unlock()
eh.sh = sh
- newargs, newenv := eh.envelope(sh, env, args[1:]...)
- cmd := exec.Command(os.Args[0], newargs[1:]...)
+ cmdPath := args[0]
+ newargs, newenv := args, env
+
+ // If an entry point is specified, use the envelope execution environment.
+ if eh.entryPoint != "" {
+ cmdPath = os.Args[0]
+ newargs, newenv = eh.envelope(sh, env, args[1:]...)
+ }
+
+ cmd := exec.Command(cmdPath, newargs[1:]...)
cmd.Env = newenv
stderr, err := newLogfile("stderr", eh.name)
if err != nil {
@@ -160,7 +172,6 @@
return nil, err
}
vlog.VI(1).Infof("Started: %q, pid %d", eh.name, cmd.Process.Pid)
- err = handle.WaitForReady(sh.startTimeout)
go func() {
eh.procErrCh <- eh.handle.Wait(0)
// It's now safe to close eh.stdout, since Wait only returns
@@ -170,7 +181,7 @@
eh.stdout.Close()
}()
- return eh, err
+ return eh, nil
}
func (eh *execHandle) Pid() int {
@@ -215,3 +226,7 @@
return procErr
}
+
+func (eh *execHandle) WaitForReady(timeout time.Duration) error {
+ return eh.handle.WaitForReady(timeout)
+}
diff --git a/lib/modules/func.go b/lib/modules/func.go
index e7372e6..5c5bc4c 100644
--- a/lib/modules/func.go
+++ b/lib/modules/func.go
@@ -5,6 +5,7 @@
"io"
"os"
"sync"
+ "time"
"v.io/core/veyron2/vlog"
)
@@ -143,3 +144,7 @@
fh.mu.Unlock()
return funcErr
}
+
+func (fh *functionHandle) WaitForReady(time.Duration) error {
+ return nil
+}
diff --git a/lib/modules/registry.go b/lib/modules/registry.go
index 7b01a1e..8331f9c 100644
--- a/lib/modules/registry.go
+++ b/lib/modules/registry.go
@@ -39,7 +39,7 @@
return r.cmds[name]
}
-// RegisterChild adds a new command to the registery that will be run
+// RegisterChild adds a new command to the registry that will be run
// as a subprocess. It must be called before Dispatch or DispatchInTest is
// called, typically from an init function.
func RegisterChild(name, help string, main Main) {
diff --git a/lib/modules/shell.go b/lib/modules/shell.go
index c80aae7..c6cd898 100644
--- a/lib/modules/shell.go
+++ b/lib/modules/shell.go
@@ -37,6 +37,7 @@
package modules
import (
+ "errors"
"fmt"
"io"
"io/ioutil"
@@ -213,6 +214,14 @@
return registry.help(command)
}
+func (sh *Shell) StartExternalCommand(env []string, args ...string) (Handle, error) {
+ if len(args) == 0 {
+ return nil, errors.New("no arguments specified to StartExternalCommand")
+ }
+ c := newExecHandleForExternalCommand(args[0])
+ return sh.startCommand(c, env, args...)
+}
+
// Start starts the specified command, it returns a Handle which can be
// used for interacting with that command.
//
@@ -236,6 +245,26 @@
// Commands must have already been registered using RegisterFunction
// or RegisterChild.
func (sh *Shell) Start(name string, env []string, args ...string) (Handle, error) {
+ cmd := registry.getCommand(name)
+ if cmd == nil {
+ return nil, fmt.Errorf("%s: not registered", name)
+ }
+ expanded := append([]string{name}, sh.expand(args...)...)
+ c := cmd.factory()
+ h, err := sh.startCommand(c, env, expanded...)
+ if err != nil {
+ // If the error is a timeout, then h can be used to recover
+ // any output from the process.
+ return h, err
+ }
+
+ if err := h.WaitForReady(sh.waitTimeout); err != nil {
+ return h, err
+ }
+ return h, nil
+}
+
+func (sh *Shell) startCommand(c command, env []string, args ...string) (Handle, error) {
cenv, err := sh.setupCommandEnv(env)
if err != nil {
return nil, err
@@ -244,16 +273,10 @@
if err != nil {
return nil, err
}
- cmd := registry.getCommand(name)
- if cmd == nil {
- return nil, fmt.Errorf("%s: not registered", name)
- }
- expanded := append([]string{name}, sh.expand(args...)...)
- h, err := cmd.factory().start(sh, p, cenv, expanded...)
+
+ h, err := c.start(sh, p, cenv, args...)
if err != nil {
- // If the error is a timeout, then h can be used to recover
- // any output from the process.
- return h, err
+ return nil, err
}
sh.mu.Lock()
sh.handles[h] = struct{}{}
@@ -459,6 +482,11 @@
// Pid returns the pid of the process running the command
Pid() int
+
+ // WaitForReady waits until the child process signals to us that it is
+ // ready. If this does not occur within the given timeout duration, a
+ // timeout error is returned.
+ WaitForReady(timeout time.Duration) error
}
// command is used to abstract the implementations of inprocess and subprocess
diff --git a/lib/testutil/integration/util.go b/lib/testutil/integration/util.go
index 46a2a6b..208fad1 100644
--- a/lib/testutil/integration/util.go
+++ b/lib/testutil/integration/util.go
@@ -262,9 +262,9 @@
locationString = fmt.Sprintf("(requested at %s:%d) ", filepath.Base(file), line)
}
b.env.t.Logf("%sstarting %s %s", locationString, b.Path(), strings.Join(args, " "))
- handle, err := b.env.shell.Start("exec", b.envVars, append([]string{b.Path()}, args...)...)
+ handle, err := b.env.shell.StartExternalCommand(b.envVars, append([]string{b.Path()}, args...)...)
if err != nil {
- b.env.t.Fatalf("Start(%v, %v) failed: %v", b.Path(), strings.Join(args, ", "), err)
+ b.env.t.Fatalf("StartExternalCommand(%v, %v) failed: %v", b.Path(), strings.Join(args, ", "), err)
}
b.env.t.Logf("started PID %d\n", handle.Pid())
return &integrationTestBinaryInvocation{
diff --git a/profiles/chrome/chromeinit.go b/profiles/chrome/chromeinit.go
index 9f4ace2..1019de9 100644
--- a/profiles/chrome/chromeinit.go
+++ b/profiles/chrome/chromeinit.go
@@ -7,6 +7,7 @@
"v.io/core/veyron2"
"v.io/core/veyron2/context"
+ "v.io/core/veyron2/ipc"
"v.io/core/veyron2/ipc/stream"
"v.io/core/veyron2/vlog"
@@ -31,7 +32,9 @@
return nil, nil, nil, err
}
- runtime, ctx, shutdown, err := grt.Init(ctx, nil, nil, nil, commonFlags.RuntimeFlags(), nil)
+ protocols := []string{"wsh", "ws"}
+ listenSpec := ipc.ListenSpec{Addrs: ipc.ListenAddrs{{Protocol: "ws", Address: ""}}}
+ runtime, ctx, shutdown, err := grt.Init(ctx, nil, protocols, &listenSpec, commonFlags.RuntimeFlags(), nil)
if err != nil {
return nil, nil, shutdown, err
}
diff --git a/profiles/roaming/roaming_server.go b/profiles/roaming/roaming_server.go
index e85f22e..30874be 100644
--- a/profiles/roaming/roaming_server.go
+++ b/profiles/roaming/roaming_server.go
@@ -7,6 +7,7 @@
"v.io/core/veyron2"
"v.io/core/veyron2/ipc"
+ "v.io/core/veyron2/vlog"
"v.io/core/veyron/profiles/roaming"
)
@@ -14,11 +15,10 @@
func main() {
ctx, shutdown := veyron2.Init()
defer shutdown()
- log := veyron2.GetLogger(ctx)
server, err := veyron2.NewServer(ctx)
if err != nil {
- log.Fatalf("unexpected error: %q", err)
+ vlog.Fatalf("unexpected error: %q", err)
}
listenSpec := veyron2.GetListenSpec(ctx)
@@ -26,13 +26,13 @@
fmt.Printf("listen spec: %v\n", listenSpec)
ep, err := server.Listen(listenSpec)
if err != nil {
- log.Fatalf("unexpected error: %q", err)
+ vlog.Fatalf("unexpected error: %q", err)
}
if ep != nil {
fmt.Println(ep)
}
if err := server.Serve("roamer", &receiver{}, nil); err != nil {
- log.Fatalf("unexpected error: %q", err)
+ vlog.Fatalf("unexpected error: %q", err)
}
done := make(chan struct{})
diff --git a/profiles/roaming/roaminginit.go b/profiles/roaming/roaminginit.go
index 48350e4..45a5f56 100644
--- a/profiles/roaming/roaminginit.go
+++ b/profiles/roaming/roaminginit.go
@@ -139,7 +139,6 @@
ch chan<- config.Setting) {
defer close(ch)
- log := runtime.GetLogger(ctx)
listenSpec := runtime.GetListenSpec(ctx)
// TODO(cnicolaou): add support for listening on multiple network addresses.
@@ -150,21 +149,21 @@
case <-watcher.Channel():
cur, err := netstate.GetAccessibleIPs()
if err != nil {
- log.Errorf("failed to read network state: %s", err)
+ vlog.Errorf("failed to read network state: %s", err)
continue
}
removed := netstate.FindRemoved(prev, cur)
added := netstate.FindAdded(prev, cur)
- log.VI(2).Infof("Previous: %d: %s", len(prev), prev)
- log.VI(2).Infof("Current : %d: %s", len(cur), cur)
- log.VI(2).Infof("Added : %d: %s", len(added), added)
- log.VI(2).Infof("Removed : %d: %s", len(removed), removed)
+ vlog.VI(2).Infof("Previous: %d: %s", len(prev), prev)
+ vlog.VI(2).Infof("Current : %d: %s", len(cur), cur)
+ vlog.VI(2).Infof("Added : %d: %s", len(added), added)
+ vlog.VI(2).Infof("Removed : %d: %s", len(removed), removed)
if len(removed) == 0 && len(added) == 0 {
- log.VI(2).Infof("Network event that lead to no address changes since our last 'baseline'")
+ vlog.VI(2).Infof("Network event that lead to no address changes since our last 'baseline'")
continue
}
if len(removed) > 0 {
- log.VI(2).Infof("Sending removed: %s", removed)
+ vlog.VI(2).Infof("Sending removed: %s", removed)
ch <- ipc.NewRmAddrsSetting(removed)
}
// We will always send the best currently available address
diff --git a/runtimes/fake/runtime.go b/runtimes/fake/runtime.go
index baa6386..4f5bd29 100644
--- a/runtimes/fake/runtime.go
+++ b/runtimes/fake/runtime.go
@@ -7,7 +7,6 @@
"v.io/core/veyron2"
"v.io/core/veyron2/context"
"v.io/core/veyron2/security"
- "v.io/core/veyron2/vlog"
tsecurity "v.io/core/veyron/lib/testutil/security"
)
@@ -28,6 +27,10 @@
return &Runtime{}, ctx, func() {}, nil
}
+func (r *Runtime) Init(ctx *context.T) error {
+ return nil
+}
+
func (r *Runtime) SetPrincipal(ctx *context.T, principal security.Principal) (*context.T, error) {
return context.WithValue(ctx, principalKey, principal), nil
}
@@ -37,19 +40,6 @@
return p
}
-func (r *Runtime) SetNewLogger(ctx *context.T, name string, opts ...vlog.LoggingOpts) (*context.T, vlog.Logger, error) {
- logger, err := vlog.NewLogger(name, opts...)
- if err != nil {
- return context.WithValue(ctx, loggerKey, logger), logger, nil
- }
- return ctx, nil, err
-}
-
-func (r *Runtime) GetLogger(ctx *context.T) vlog.Logger {
- l, _ := ctx.Value(loggerKey).(vlog.Logger)
- return l
-}
-
func (r *Runtime) GetAppCycle(ctx *context.T) veyron2.AppCycle {
panic("unimplemented")
}
diff --git a/runtimes/google/rt/mgmt.go b/runtimes/google/rt/mgmt.go
index ca0f7e3..ccaad62 100644
--- a/runtimes/google/rt/mgmt.go
+++ b/runtimes/google/rt/mgmt.go
@@ -14,13 +14,17 @@
"v.io/core/veyron/lib/exec"
)
-func (rt *Runtime) initMgmt(ctx *context.T, appCycle veyron2.AppCycle, handle *exec.ChildHandle) error {
- // Do not initialize the mgmt runtime if the process has not
- // been started through the veyron exec library by a device
- // manager.
- if handle == nil {
+func (rt *Runtime) initMgmt(ctx *context.T) error {
+ handle, err := exec.GetChildHandle()
+ if err == exec.ErrNoVersion {
+ // Do not initialize the mgmt runtime if the process has not
+ // been started through the veyron exec library by a device
+ // manager.
return nil
+ } else if err != nil {
+ return err
}
+
parentName, err := handle.Config.Get(mgmt.ParentNameConfigKey)
if err != nil {
return nil
@@ -45,7 +49,7 @@
if err != nil {
return err
}
- if err := server.Serve("", appCycle.Remote(), nil); err != nil {
+ if err := server.Serve("", veyron2.GetAppCycle(ctx).Remote(), nil); err != nil {
server.Stop()
return err
}
@@ -55,6 +59,13 @@
return err
}
+ // Note(mattr): that we ignore the error here.
+ // As far as I can tell this is because the modules framework actually calls
+ // SetReady(), so we would then call it here a second time and get
+ // an error.
+ // TODO(mattr): We should change the modules framework so we can properly check
+ // errors here.
+ handle.SetReady()
return nil
}
@@ -79,7 +90,7 @@
func (rt *Runtime) callbackToParent(ctx *context.T, parentName, myName string) error {
ctx, _ = context.WithTimeout(ctx, time.Minute)
- call, err := rt.GetClient(ctx).StartCall(ctx, parentName, "Set", []interface{}{mgmt.AppCycleManagerConfigKey, myName}, options.NoResolve{})
+ call, err := rt.GetClient(ctx).StartCall(ctx, parentName, "Set", []interface{}{mgmt.AppCycleManagerConfigKey, myName})
if err != nil {
return err
diff --git a/runtimes/google/rt/rt_test.go b/runtimes/google/rt/rt_test.go
index ce3a6a4..a4e473d 100644
--- a/runtimes/google/rt/rt_test.go
+++ b/runtimes/google/rt/rt_test.go
@@ -36,7 +36,7 @@
ctx, shutdown := veyron2.Init()
defer shutdown()
- l := veyron2.GetLogger(ctx)
+ l := vlog.Log
fmt.Println(l)
args := fmt.Sprintf("%s", l)
expected := regexp.MustCompile("name=veyron logdirs=\\[/tmp\\] logtostderr=true|false alsologtostderr=false|true max_stack_buf_size=4292608 v=[0-9] stderrthreshold=2 vmodule= log_backtrace_at=:0")
@@ -59,10 +59,10 @@
}
func child(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- ctx, shutdown := veyron2.Init()
+ _, shutdown := veyron2.Init()
defer shutdown()
- logger := veyron2.GetLogger(ctx)
+ logger := vlog.Log
vlog.Infof("%s\n", logger)
fmt.Fprintf(stdout, "%s\n", logger)
modules.WaitForEOF(stdin)
diff --git a/runtimes/google/rt/runtime.go b/runtimes/google/rt/runtime.go
index b74bc10..f52b2d9 100644
--- a/runtimes/google/rt/runtime.go
+++ b/runtimes/google/rt/runtime.go
@@ -21,7 +21,6 @@
"v.io/core/veyron2/vlog"
"v.io/core/veyron2/vtrace"
- "v.io/core/veyron/lib/exec"
"v.io/core/veyron/lib/flags"
_ "v.io/core/veyron/lib/stats/sysstats"
iipc "v.io/core/veyron/runtimes/google/ipc"
@@ -39,7 +38,6 @@
streamManagerKey = contextKey(iota)
clientKey
namespaceKey
- loggerKey
principalKey
reservedNameKey
profileKey
@@ -63,26 +61,16 @@
opts []ipc.ServerOpt
}
-// TODO(mattr,suharshs): Decide if ROpts would be better than this.
+// TODO(mattr,suharshs): Decide if Options would be better than this.
func Init(ctx *context.T, appCycle veyron2.AppCycle, protocols []string, listenSpec *ipc.ListenSpec, flags flags.RuntimeFlags,
reservedDispatcher ipc.Dispatcher, dispatcherOpts ...ipc.ServerOpt) (*Runtime, *context.T, veyron2.Shutdown, error) {
r := &Runtime{deps: dependency.NewGraph()}
- handle, err := exec.GetChildHandle()
- switch err {
- case exec.ErrNoVersion:
- // The process has not been started through the veyron exec
- // library. No further action is needed.
- case nil:
- // The process has been started through the veyron exec
- // library.
- default:
+ err := vlog.ConfigureLibraryLoggerFromFlags()
+ if err != nil {
return nil, nil, nil, err
}
- r.initLogging(ctx)
- ctx = context.WithValue(ctx, loggerKey, vlog.Log)
-
// Setup the initial trace.
ctx, err = ivtrace.Init(ctx, flags.Vtrace)
if err != nil {
@@ -148,7 +136,7 @@
}
// Initialize security.
- principal, err := initSecurity(ctx, handle, flags.Credentials, client)
+ principal, err := initSecurity(ctx, flags.Credentials, client)
if err != nil {
return nil, nil, nil, err
}
@@ -160,20 +148,11 @@
return nil, nil, nil, err
}
- // Initialize management.
- if err := r.initMgmt(ctx, r.GetAppCycle(ctx), handle); err != nil {
- return nil, nil, nil, err
- }
-
ctx = r.SetBackgroundContext(ctx)
// TODO(suharshs,mattr): Go through the rt.Cleanup function and make sure everything
// gets cleaned up.
- if handle != nil {
- handle.SetReady()
- }
-
return r, ctx, r.shutdown, nil
}
@@ -192,17 +171,15 @@
return nil
}
+func (r *Runtime) Init(ctx *context.T) error {
+ return r.initMgmt(ctx)
+}
+
func (r *Runtime) shutdown() {
r.deps.CloseAndWaitForAll()
vlog.FlushLog()
}
-// initLogging configures logging for the runtime. It needs to be called after
-// flag.Parse and after signal handling has been initialized.
-func (r *Runtime) initLogging(ctx *context.T) error {
- return vlog.ConfigureLibraryLoggerFromFlags()
-}
-
func (r *Runtime) initSignalHandling(ctx *context.T) {
// TODO(caprita): Given that our device manager implementation is to
// kill all child apps when the device manager dies, we should
@@ -394,19 +371,6 @@
return ns
}
-func (*Runtime) SetNewLogger(ctx *context.T, name string, opts ...vlog.LoggingOpts) (*context.T, vlog.Logger, error) {
- logger, err := vlog.NewLogger(name, opts...)
- if err == nil {
- ctx = context.WithValue(ctx, loggerKey, logger)
- }
- return ctx, logger, err
-}
-
-func (*Runtime) GetLogger(ctx *context.T) vlog.Logger {
- logger, _ := ctx.Value(loggerKey).(vlog.Logger)
- return logger
-}
-
func (*Runtime) GetAppCycle(ctx *context.T) veyron2.AppCycle {
appCycle, _ := ctx.Value(appCycleKey).(veyron2.AppCycle)
return appCycle
diff --git a/runtimes/google/rt/security.go b/runtimes/google/rt/security.go
index ab640df..b4a3aef 100644
--- a/runtimes/google/rt/security.go
+++ b/runtimes/google/rt/security.go
@@ -18,8 +18,8 @@
"v.io/core/veyron/security/agent"
)
-func initSecurity(ctx *context.T, handle *exec.ChildHandle, credentials string, client ipc.Client) (security.Principal, error) {
- principal, err := setupPrincipal(ctx, handle, credentials, client)
+func initSecurity(ctx *context.T, credentials string, client ipc.Client) (security.Principal, error) {
+ principal, err := setupPrincipal(ctx, credentials, client)
if err != nil {
return nil, err
}
@@ -31,13 +31,13 @@
return principal, nil
}
-func setupPrincipal(ctx *context.T, handle *exec.ChildHandle, credentials string, client ipc.Client) (security.Principal, error) {
+func setupPrincipal(ctx *context.T, credentials string, client ipc.Client) (security.Principal, error) {
var err error
var principal security.Principal
if principal, _ = ctx.Value(principalKey).(security.Principal); principal != nil {
return principal, nil
}
- if fd, err := agentFD(handle); err != nil {
+ if fd, err := agentFD(); err != nil {
return nil, err
} else if fd >= 0 {
return connectToAgent(ctx, fd, client)
@@ -66,7 +66,11 @@
// agentFD returns a non-negative file descriptor to be used to communicate with
// the security agent if the current process has been configured to use the
// agent.
-func agentFD(handle *exec.ChildHandle) (int, error) {
+func agentFD() (int, error) {
+ handle, err := exec.GetChildHandle()
+ if err != nil && err != exec.ErrNoVersion {
+ return -1, err
+ }
var fd string
if handle != nil {
// We were started by a parent (presumably, device manager).
diff --git a/security/agent/agentd/main.go b/security/agent/agentd/main.go
index c011d8a..ec7babd 100644
--- a/security/agent/agentd/main.go
+++ b/security/agent/agentd/main.go
@@ -81,13 +81,11 @@
vlog.Panic("failed to set principal for ctx: %v", err)
}
- log := veyron2.GetLogger(ctx)
-
if err = os.Setenv(agent.FdVarName, "3"); err != nil {
- log.Fatalf("setenv: %v", err)
+ vlog.Fatalf("setenv: %v", err)
}
if err = os.Setenv(consts.VeyronCredentials, ""); err != nil {
- log.Fatalf("setenv: %v", err)
+ vlog.Fatalf("setenv: %v", err)
}
if *keypath == "" && passphrase != nil {
@@ -101,11 +99,11 @@
// Start running our server.
var sock, mgrSock *os.File
if sock, err = server.RunAnonymousAgent(ctx, p); err != nil {
- log.Fatalf("RunAnonymousAgent: %v", err)
+ vlog.Fatalf("RunAnonymousAgent: %v", err)
}
if *keypath != "" {
if mgrSock, err = server.RunKeyManager(ctx, *keypath, passphrase); err != nil {
- log.Fatalf("RunKeyManager: %v", err)
+ vlog.Fatalf("RunKeyManager: %v", err)
}
}
@@ -123,7 +121,7 @@
err = cmd.Start()
if err != nil {
- log.Fatalf("Error starting child: %v", err)
+ vlog.Fatalf("Error starting child: %v", err)
}
shutdown := make(chan struct{})
go func() {
diff --git a/security/agent/pingpong/main.go b/security/agent/pingpong/main.go
index 532edd9..4b8c428 100644
--- a/security/agent/pingpong/main.go
+++ b/security/agent/pingpong/main.go
@@ -8,6 +8,7 @@
"v.io/core/veyron2/context"
"v.io/core/veyron2/ipc"
"v.io/core/veyron2/security"
+ "v.io/core/veyron2/vlog"
"v.io/core/veyron/lib/signals"
_ "v.io/core/veyron/profiles"
@@ -22,24 +23,22 @@
}
func clientMain(ctx *context.T) {
- log := veyron2.GetLogger(ctx)
- log.Info("Pinging...")
+ vlog.Info("Pinging...")
s := PingPongClient("pingpong")
pong, err := s.Ping(ctx, "ping")
if err != nil {
- log.Fatal("error pinging: ", err)
+ vlog.Fatal("error pinging: ", err)
}
fmt.Println(pong)
}
func serverMain(ctx *context.T) {
- log := veyron2.GetLogger(ctx)
s, err := veyron2.NewServer(ctx)
if err != nil {
- log.Fatal("failure creating server: ", err)
+ vlog.Fatal("failure creating server: ", err)
}
- log.Info("Waiting for ping")
+ vlog.Info("Waiting for ping")
serverPong := PingPongServer(&pongd{})
@@ -47,11 +46,11 @@
if endpoint, err := s.Listen(spec); err == nil {
fmt.Printf("Listening at: %v\n", endpoint)
} else {
- log.Fatal("error listening to service: ", err)
+ vlog.Fatal("error listening to service: ", err)
}
if err := s.Serve("pingpong", serverPong, allowEveryone{}); err != nil {
- log.Fatal("error serving service: ", err)
+ vlog.Fatal("error serving service: ", err)
}
// Wait forever.
@@ -63,8 +62,6 @@
func (allowEveryone) Authorize(security.Context) error { return nil }
func main() {
- flag.Parse()
-
ctx, shutdown := veyron2.Init()
defer shutdown()
diff --git a/services/mgmt/device/impl/app_service.go b/services/mgmt/device/impl/app_service.go
index 940df40..1538c98 100644
--- a/services/mgmt/device/impl/app_service.go
+++ b/services/mgmt/device/impl/app_service.go
@@ -119,7 +119,6 @@
"io/ioutil"
"os"
"os/exec"
- "os/user"
"path"
"path/filepath"
"reflect"
@@ -677,56 +676,6 @@
return instanceDir, instanceID, nil
}
-// isSetuid is defined like this so we can override its
-// implementation for tests.
-var isSetuid = func(fileStat os.FileInfo) bool {
- vlog.VI(2).Infof("running the original isSetuid")
- return fileStat.Mode()&os.ModeSetuid == os.ModeSetuid
-}
-
-// systemAccountForHelper returns the uname that the helper uses to invoke the
-// application. If the helper exists and is setuid, the device manager
-// requires that there is a uname associated with the Veyron
-// identity that requested starting an application.
-// TODO(rjkroege): This function assumes a desktop installation target
-// and is probably not a good fit in other contexts. Revisit the design
-// as appropriate. This function also internalizes a decision as to when
-// it is possible to start an application that needs to be made explicit.
-func systemAccountForHelper(ctx ipc.ServerContext, helperPath string, uat BlessingSystemAssociationStore) (systemName string, err error) {
- identityNames := ctx.RemoteBlessings().ForContext(ctx)
- helperStat, err := os.Stat(helperPath)
- if err != nil {
- vlog.Errorf("Stat(%v) failed: %v. helper is required.", helperPath, err)
- return "", verror2.Make(ErrOperationFailed, ctx.Context())
- }
- haveHelper := isSetuid(helperStat)
- systemName, present := uat.SystemAccountForBlessings(identityNames)
-
- switch {
- case haveHelper && present:
- return systemName, nil
- case haveHelper && !present:
- // The helper is owned by the device manager and installed as
- // setuid root. Therefore, the device manager must never run an
- // app as itself to prevent an app trivially granting itself
- // root permissions. There must be an associated uname for the
- // account in this case.
- return "", verror2.Make(verror2.NoAccess, ctx.Context(), "use of setuid helper requires an associated uname.")
- case !haveHelper:
- // When the helper is not setuid, the helper can't change the
- // app's uid so just run the app as the device manager's uname
- // whether or not there is an association.
- vlog.VI(1).Infof("helper not setuid. Device manager will invoke app with its own userid")
- user, err := user.Current()
- if err != nil {
- vlog.Errorf("user.Current() failed: %v", err)
- return "", verror2.Make(ErrOperationFailed, ctx.Context())
- }
- return user.Username, nil
- }
- return "", verror2.Make(ErrOperationFailed, ctx.Context())
-}
-
func genCmd(instanceDir, helperPath, systemName string, nsRoots []string) (*exec.Cmd, error) {
versionLink := filepath.Join(instanceDir, "version")
versionDir, err := filepath.EvalSymlinks(versionLink)
@@ -745,7 +694,15 @@
}
cmd := exec.Command(helperPath)
- cmd.Args = append(cmd.Args, "--username", systemName)
+
+ switch yes, err := suidHelper.suidhelperEnabled(systemName, helperPath); {
+ case err != nil:
+ return nil, err
+ case yes:
+ cmd.Args = append(cmd.Args, "--username", systemName)
+ case !yes:
+ cmd.Args = append(cmd.Args, "--username", systemName, "--dryrun")
+ }
var nsRootEnvs []string
for i, r := range nsRoots {
@@ -908,12 +865,7 @@
return nil, err
}
- systemName, err := systemAccountForHelper(call, helper, i.uat)
- if err != nil {
- cleanupDir(instanceDir, helper)
- return nil, err
- }
-
+ systemName := suidHelper.usernameForPrincipal(call, i.uat)
if err := saveSystemNameForInstance(instanceDir, systemName); err != nil {
cleanupDir(instanceDir, helper)
return nil, err
@@ -956,11 +908,7 @@
return err
}
- systemName, err := systemAccountForHelper(call, i.config.Helper, i.uat)
- if err != nil {
- return err
- }
-
+ systemName := suidHelper.usernameForPrincipal(call, i.uat)
startSystemName, err := readSystemNameForInstance(instanceDir)
if err != nil {
return err
diff --git a/services/mgmt/device/impl/helper_manager.go b/services/mgmt/device/impl/helper_manager.go
new file mode 100644
index 0000000..9e935d2
--- /dev/null
+++ b/services/mgmt/device/impl/helper_manager.go
@@ -0,0 +1,69 @@
+package impl
+
+import (
+ "os"
+ "os/user"
+
+ "v.io/core/veyron2/ipc"
+ "v.io/core/veyron2/verror2"
+ "v.io/core/veyron2/vlog"
+)
+
+type suidHelperState string
+
+var suidHelper suidHelperState
+
+func init() {
+ u, err := user.Current()
+ if err != nil {
+ vlog.Panicf("devicemanager has no current user: %v", err)
+ }
+ suidHelper = suidHelperState(u.Username)
+}
+
+// isSetuid is defined like this so we can override its
+// implementation for tests.
+var isSetuid = func(fileStat os.FileInfo) bool {
+ vlog.VI(2).Infof("running the original isSetuid")
+ return fileStat.Mode()&os.ModeSetuid == os.ModeSetuid
+}
+
+// unameRequiresSuidhelper determines if the the suidhelper must exist
+// and be setuid to run an application as system user un. If false, the
+// setuidhelper must be invoked with the --dryrun flag to skip making
+// system calls that will fail or provide apps with a trivial
+// priviledge escalation.
+func (dn suidHelperState) suidhelperEnabled(un, helperPath string) (bool, error) {
+ helperStat, err := os.Stat(helperPath)
+ if err != nil {
+ vlog.Errorf("Stat(%v) failed: %v. helper is required.", helperPath, err)
+ return false, verror2.Make(ErrOperationFailed, nil)
+ }
+ haveHelper := isSetuid(helperStat)
+
+ switch {
+ case haveHelper && string(dn) != un:
+ return true, nil
+ case haveHelper && string(dn) == un:
+ return false, verror2.Make(verror2.NoAccess, nil)
+ default:
+ return false, nil
+ }
+ // Keep the compiler happy.
+ return false, nil
+}
+
+// usernameForVanadiumPrincipal returns the system name that the
+// devicemanager will use to invoke apps.
+// TODO(rjkroege): This code assumes a desktop target and will need
+// to be reconsidered for embedded contexts.
+func (i suidHelperState) usernameForPrincipal(ctx ipc.ServerContext, uat BlessingSystemAssociationStore) string {
+ identityNames := ctx.RemoteBlessings().ForContext(ctx)
+ systemName, present := uat.SystemAccountForBlessings(identityNames)
+
+ if present {
+ return systemName
+ } else {
+ return string(i)
+ }
+}
diff --git a/services/mgmt/suidhelper/impl/args.go b/services/mgmt/suidhelper/impl/args.go
index 67003a3..185bae8 100644
--- a/services/mgmt/suidhelper/impl/args.go
+++ b/services/mgmt/suidhelper/impl/args.go
@@ -36,7 +36,7 @@
var (
flagUsername, flagWorkspace, flagLogDir, flagRun *string
flagMinimumUid *int64
- flagRemove *bool
+ flagRemove, flagDryrun *bool
)
func init() {
@@ -53,6 +53,7 @@
flagRun = sflag.Run
flagMinimumUid = sflag.MinimumUid
flagRemove = sflag.Remove
+ flagDryrun = sflag.Dryrun
}
// ParseArguments populates the WorkParameter object from the provided args
@@ -88,6 +89,8 @@
return fmt.Errorf("suidhelper does not permit uids less than %d", *flagMinimumUid)
}
+ wp.dryrun = *flagDryrun
+
// Preserve the arguments for examination by the test harness if executed
// in the course of a test.
if os.Getenv("VEYRON_SUIDHELPER_TEST") != "" {
diff --git a/services/mgmt/suidhelper/impl/args_test.go b/services/mgmt/suidhelper/impl/args_test.go
index 9358e9f..9341fc7 100644
--- a/services/mgmt/suidhelper/impl/args_test.go
+++ b/services/mgmt/suidhelper/impl/args_test.go
@@ -85,6 +85,24 @@
fmt.Errorf("suidhelper does not permit uids less than 501"),
WorkParameters{},
},
+
+ {
+ []string{"setuidhelper", "--minuid", "1", "--username", testUserName, "--workspace", "/hello",
+ "--logdir", "/logging", "--run", "/bin/veyron", "--dryrun", "--", "one", "two"},
+ []string{"A=B"},
+ nil,
+ WorkParameters{
+ uid: testUid,
+ gid: testGid,
+ workspace: "/hello",
+ logDir: "/logging",
+ argv0: "/bin/veyron",
+ argv: []string{"/bin/veyron", "one", "two"},
+ envv: []string{"A=B"},
+ dryrun: true,
+ remove: false,
+ },
+ },
}
for _, c := range cases {
diff --git a/services/mgmt/suidhelper/impl/flag/flag.go b/services/mgmt/suidhelper/impl/flag/flag.go
index f8b53e1..273f56b 100644
--- a/services/mgmt/suidhelper/impl/flag/flag.go
+++ b/services/mgmt/suidhelper/impl/flag/flag.go
@@ -15,7 +15,7 @@
var (
Username, Workspace, LogDir, Run *string
MinimumUid *int64
- Remove *bool
+ Remove, Dryrun *bool
)
func init() {
@@ -29,6 +29,7 @@
Run = fs.String("run", "", "Path to the application to exec.")
MinimumUid = fs.Int64("minuid", uidThreshold, "UIDs cannot be less than this number.")
Remove = fs.Bool("rm", false, "Remove the file trees given as command-line arguments.")
+ Dryrun = fs.Bool("dryrun", false, "Elides root-requiring systemcalls.")
}
const uidThreshold = 501
diff --git a/services/mgmt/suidhelper/impl/system.go b/services/mgmt/suidhelper/impl/system.go
index 60a7b92..8a93d91 100644
--- a/services/mgmt/suidhelper/impl/system.go
+++ b/services/mgmt/suidhelper/impl/system.go
@@ -34,22 +34,37 @@
}
func (hw *WorkParameters) Exec() error {
+ attr := new(syscall.ProcAttr)
+
+ if dir, err := os.Getwd(); err != nil {
+ log.Printf("error Getwd(): %v\n", err)
+ return fmt.Errorf("os.Getwd failed: %v", err)
+ attr.Dir = dir
+ }
+ attr.Env = hw.envv
+
if hw.dryrun {
log.Printf("[dryrun] syscall.Setgid(%d)", hw.gid)
log.Printf("[dryrun] syscall.Setuid(%d)", hw.uid)
} else {
- // NOTE(caprita): Commenting this out since it's broken with go
- // 1.4, to make the integration test pass. go/vcl/8240 will fix
- // it properly.
-
- // if err := syscall.Setgid(hw.gid); err != nil {
- // return fmt.Errorf("syscall.Setgid(%d) failed: %v", hw.gid, err)
- // }
- // if err := syscall.Setuid(hw.uid); err != nil {
- // return fmt.Errorf("syscall.Setuid(%d) failed: %v", hw.uid, err)
- // }
+ attr.Sys = new(syscall.SysProcAttr)
+ attr.Sys.Credential = new(syscall.Credential)
+ attr.Sys.Credential.Gid = uint32(hw.gid)
+ attr.Sys.Credential.Uid = uint32(hw.uid)
}
- return syscall.Exec(hw.argv0, hw.argv, hw.envv)
+
+ _, _, err := syscall.StartProcess(hw.argv0, hw.argv, attr)
+ if err != nil {
+ if !hw.dryrun {
+ log.Printf("StartProcess failed: attr: %#v, attr.Sys: %#v, attr.Sys.Cred: %#v error: %v\n", attr, attr.Sys, attr.Sys.Credential, err)
+ } else {
+ log.Printf("StartProcess failed: %v", err)
+ }
+ return fmt.Errorf("syscall.StartProcess(%s) failed: %v", hw.argv0, err)
+ }
+ // TODO(rjkroege): Return the pid to the node manager.
+ os.Exit(0)
+ return nil // Not reached.
}
func (hw *WorkParameters) Remove() error {
diff --git a/tools/application/impl.go b/tools/application/impl.go
index 026f2c3..ef0bf9e 100644
--- a/tools/application/impl.go
+++ b/tools/application/impl.go
@@ -17,7 +17,9 @@
"v.io/lib/cmdline"
)
-func getEnvelopeJSON(ctx *context.T, app repository.ApplicationClientMethods, profiles string) ([]byte, error) {
+func getEnvelopeJSON(app repository.ApplicationClientMethods, profiles string) ([]byte, error) {
+ ctx, cancel := context.WithTimeout(gctx, time.Minute)
+ defer cancel()
env, err := app.Match(ctx, strings.Split(profiles, ","))
if err != nil {
return nil, err
@@ -29,11 +31,13 @@
return j, nil
}
-func putEnvelopeJSON(ctx *context.T, app repository.ApplicationClientMethods, profiles string, j []byte) error {
+func putEnvelopeJSON(app repository.ApplicationClientMethods, profiles string, j []byte) error {
var env application.Envelope
if err := json.Unmarshal(j, &env); err != nil {
return fmt.Errorf("Unmarshal(%v) failed: %v", string(j), err)
}
+ ctx, cancel := context.WithTimeout(gctx, time.Minute)
+ defer cancel()
if err := app.Put(ctx, strings.Split(profiles, ","), env); err != nil {
return err
}
@@ -66,9 +70,7 @@
}
name, profiles := args[0], args[1]
app := repository.ApplicationClient(name)
- ctx, cancel := context.WithTimeout(gctx, time.Minute)
- defer cancel()
- j, err := getEnvelopeJSON(ctx, app, profiles)
+ j, err := getEnvelopeJSON(app, profiles)
if err != nil {
return err
}
@@ -81,29 +83,40 @@
Name: "put",
Short: "Add the given envelope to the application for the given profiles.",
Long: "Add the given envelope to the application for the given profiles.",
- ArgsName: "<application> <profiles> <envelope>",
+ ArgsName: "<application> <profiles> [<envelope>]",
ArgsLong: `
<application> is the full name of the application.
<profiles> is a comma-separated list of profiles.
-<envelope> is the file that contains a JSON-encoded envelope.`,
+<envelope> is the file that contains a JSON-encoded envelope. If this file is
+not provided, the user will be prompted to enter the data manually.`,
}
func runPut(cmd *cmdline.Command, args []string) error {
- if expected, got := 3, len(args); expected != got {
- return cmd.UsageErrorf("put: incorrect number of arguments, expected %d, got %d", expected, got)
+ if got := len(args); got != 2 && got != 3 {
+ return cmd.UsageErrorf("put: incorrect number of arguments, expected 2 or 3, got %d", got)
}
- name, profiles, envelope := args[0], args[1], args[2]
+ name, profiles := args[0], args[1]
app := repository.ApplicationClient(name)
- j, err := ioutil.ReadFile(envelope)
- if err != nil {
- return fmt.Errorf("ReadFile(%v): %v", envelope, err)
+ if len(args) == 3 {
+ envelope := args[2]
+ j, err := ioutil.ReadFile(envelope)
+ if err != nil {
+ return fmt.Errorf("ReadFile(%v): %v", envelope, err)
+ }
+ if err = putEnvelopeJSON(app, profiles, j); err != nil {
+ return err
+ }
+ fmt.Fprintln(cmd.Stdout(), "Application envelope added successfully.")
+ return nil
}
- ctx, cancel := context.WithTimeout(gctx, time.Minute)
- defer cancel()
- if err = putEnvelopeJSON(ctx, app, profiles, j); err != nil {
+ env := application.Envelope{Args: []string{}, Env: []string{}, Packages: map[string]string{}}
+ j, err := json.MarshalIndent(env, "", " ")
+ if err != nil {
+ return fmt.Errorf("MarshalIndent() failed: %v", err)
+ }
+ if err := editAndPutEnvelopeJSON(cmd, app, profiles, j); err != nil {
return err
}
- fmt.Fprintln(cmd.Stdout(), "Application envelope added successfully.")
return nil
}
@@ -150,6 +163,18 @@
}
name, profile := args[0], args[1]
app := repository.ApplicationClient(name)
+
+ envData, err := getEnvelopeJSON(app, profile)
+ if err != nil {
+ return err
+ }
+ if err := editAndPutEnvelopeJSON(cmd, app, profile, envData); err != nil {
+ return err
+ }
+ return nil
+}
+
+func editAndPutEnvelopeJSON(cmd *cmdline.Command, app repository.ApplicationClientMethods, profile string, envData []byte) error {
f, err := ioutil.TempFile("", "application-edit-")
if err != nil {
return fmt.Errorf("TempFile() failed: %v", err)
@@ -157,13 +182,6 @@
fileName := f.Name()
f.Close()
defer os.Remove(fileName)
-
- ctx, cancel := context.WithTimeout(gctx, time.Minute)
- defer cancel()
- envData, err := getEnvelopeJSON(ctx, app, profile)
- if err != nil {
- return err
- }
if err = ioutil.WriteFile(fileName, envData, os.FileMode(0644)); err != nil {
return err
}
@@ -191,7 +209,7 @@
fmt.Fprintln(cmd.Stdout(), "Nothing changed")
return nil
}
- if err = putEnvelopeJSON(ctx, app, profile, newData); err != nil {
+ if err = putEnvelopeJSON(app, profile, newData); err != nil {
fmt.Fprintf(cmd.Stdout(), "Error: %v\n", err)
if ans := promptUser(cmd, "Try again? [y/N] "); strings.ToUpper(ans) == "Y" {
continue
diff --git a/tools/mgmt/device/acl_fmt.go b/tools/mgmt/device/impl/acl_fmt.go
similarity index 99%
rename from tools/mgmt/device/acl_fmt.go
rename to tools/mgmt/device/impl/acl_fmt.go
index 24091bc..05a6b05 100644
--- a/tools/mgmt/device/acl_fmt.go
+++ b/tools/mgmt/device/impl/acl_fmt.go
@@ -1,4 +1,4 @@
-package main
+package impl
import (
"fmt"
diff --git a/tools/mgmt/device/acl_impl.go b/tools/mgmt/device/impl/acl_impl.go
similarity index 99%
rename from tools/mgmt/device/acl_impl.go
rename to tools/mgmt/device/impl/acl_impl.go
index e39f68e..dfa0cab 100644
--- a/tools/mgmt/device/acl_impl.go
+++ b/tools/mgmt/device/impl/acl_impl.go
@@ -1,4 +1,4 @@
-package main
+package impl
// Commands to get/set ACLs.
diff --git a/tools/mgmt/device/acl_test.go b/tools/mgmt/device/impl/acl_test.go
similarity index 98%
rename from tools/mgmt/device/acl_test.go
rename to tools/mgmt/device/impl/acl_test.go
index a146e82..d195afa 100644
--- a/tools/mgmt/device/acl_test.go
+++ b/tools/mgmt/device/impl/acl_test.go
@@ -1,4 +1,4 @@
-package main
+package impl_test
import (
"bytes"
@@ -10,6 +10,8 @@
"v.io/core/veyron2/security"
"v.io/core/veyron2/services/security/access"
verror "v.io/core/veyron2/verror2"
+
+ "v.io/core/veyron/tools/mgmt/device/impl"
)
const pkgPath = "v.io/core/veyron/tools/mgmt/device/main"
@@ -31,7 +33,7 @@
defer stopServer(t, server)
// Setup the command-line.
- cmd := root()
+ cmd := impl.Root()
var stdout, stderr bytes.Buffer
cmd.Init(nil, &stdout, &stderr)
deviceName := endpoint.Name()
@@ -80,7 +82,7 @@
defer stopServer(t, server)
// Setup the command-line.
- cmd := root()
+ cmd := impl.Root()
var stdout, stderr bytes.Buffer
cmd.Init(nil, &stdout, &stderr)
deviceName := endpoint.Name()
diff --git a/tools/mgmt/device/associate_impl.go b/tools/mgmt/device/impl/associate_impl.go
similarity index 99%
rename from tools/mgmt/device/associate_impl.go
rename to tools/mgmt/device/impl/associate_impl.go
index 1f21191..08d68f8 100644
--- a/tools/mgmt/device/associate_impl.go
+++ b/tools/mgmt/device/impl/associate_impl.go
@@ -1,4 +1,4 @@
-package main
+package impl
import (
"fmt"
diff --git a/tools/mgmt/device/devicemanager_mock_test.go b/tools/mgmt/device/impl/devicemanager_mock_test.go
similarity index 99%
rename from tools/mgmt/device/devicemanager_mock_test.go
rename to tools/mgmt/device/impl/devicemanager_mock_test.go
index 7501383..3777043 100644
--- a/tools/mgmt/device/devicemanager_mock_test.go
+++ b/tools/mgmt/device/impl/devicemanager_mock_test.go
@@ -1,4 +1,4 @@
-package main
+package impl_test
import (
"log"
diff --git a/tools/mgmt/device/impl.go b/tools/mgmt/device/impl/impl.go
similarity index 92%
rename from tools/mgmt/device/impl.go
rename to tools/mgmt/device/impl/impl.go
index b62fb96..3a60782 100644
--- a/tools/mgmt/device/impl.go
+++ b/tools/mgmt/device/impl/impl.go
@@ -1,4 +1,4 @@
-package main
+package impl
import (
"encoding/json"
@@ -135,14 +135,3 @@
}
return nil
}
-
-func root() *cmdline.Command {
- return &cmdline.Command{
- Name: "device",
- Short: "Tool for interacting with the veyron device manager",
- Long: `
-The device tool facilitates interaction with the veyron device manager.
-`,
- Children: []*cmdline.Command{cmdInstall, cmdStart, associateRoot(), cmdDescribe, cmdClaim, cmdStop, cmdSuspend, cmdResume, aclRoot()},
- }
-}
diff --git a/tools/mgmt/device/impl_test.go b/tools/mgmt/device/impl/impl_test.go
similarity index 96%
rename from tools/mgmt/device/impl_test.go
rename to tools/mgmt/device/impl/impl_test.go
index 065574c..dc53e15 100644
--- a/tools/mgmt/device/impl_test.go
+++ b/tools/mgmt/device/impl/impl_test.go
@@ -1,4 +1,4 @@
-package main
+package impl_test
import (
"bytes"
@@ -8,22 +8,12 @@
"strings"
"testing"
- tsecurity "v.io/core/veyron/lib/testutil/security"
-
- "v.io/core/veyron2"
"v.io/core/veyron2/naming"
"v.io/core/veyron2/services/mgmt/device"
verror "v.io/core/veyron2/verror2"
-)
-func initTest() (shutdown veyron2.Shutdown) {
- var err error
- gctx, shutdown = veyron2.Init()
- if gctx, err = veyron2.SetPrincipal(gctx, tsecurity.NewPrincipal("test-blessing")); err != nil {
- panic(err)
- }
- return shutdown
-}
+ "v.io/core/veyron/tools/mgmt/device/impl"
+)
func TestListCommand(t *testing.T) {
shutdown := initTest()
@@ -37,7 +27,7 @@
defer stopServer(t, server)
// Setup the command-line.
- cmd := root()
+ cmd := impl.Root()
var stdout, stderr bytes.Buffer
cmd.Init(nil, &stdout, &stderr)
deviceName := naming.JoinAddressName(endpoint.String(), "")
@@ -92,7 +82,7 @@
defer stopServer(t, server)
// Setup the command-line.
- cmd := root()
+ cmd := impl.Root()
var stdout, stderr bytes.Buffer
cmd.Init(nil, &stdout, &stderr)
deviceName := naming.JoinAddressName(endpoint.String(), "/myapp/1")
@@ -145,7 +135,7 @@
defer stopServer(t, server)
// Setup the command-line.
- cmd := root()
+ cmd := impl.Root()
var stdout, stderr bytes.Buffer
cmd.Init(nil, &stdout, &stderr)
deviceName := naming.JoinAddressName(endpoint.String(), "")
@@ -185,7 +175,7 @@
defer stopServer(t, server)
// Setup the command-line.
- cmd := root()
+ cmd := impl.Root()
var stdout, stderr bytes.Buffer
cmd.Init(nil, &stdout, &stderr)
deviceName := naming.JoinAddressName(endpoint.String(), "")
@@ -278,7 +268,7 @@
defer stopServer(t, server)
// Setup the command-line.
- cmd := root()
+ cmd := impl.Root()
var stdout, stderr bytes.Buffer
cmd.Init(nil, &stdout, &stderr)
deviceName := naming.JoinAddressName(endpoint.String(), "")
@@ -358,7 +348,7 @@
defer stopServer(t, server)
// Setup the command-line.
- cmd := root()
+ cmd := impl.Root()
var stdout, stderr bytes.Buffer
cmd.Init(nil, &stdout, &stderr)
appName := naming.JoinAddressName(endpoint.String(), "")
diff --git a/tools/mgmt/device/instance_impl.go b/tools/mgmt/device/impl/instance_impl.go
similarity index 99%
rename from tools/mgmt/device/instance_impl.go
rename to tools/mgmt/device/impl/instance_impl.go
index b7a1fc4..3210ad4 100644
--- a/tools/mgmt/device/instance_impl.go
+++ b/tools/mgmt/device/impl/instance_impl.go
@@ -1,4 +1,4 @@
-package main
+package impl
// Commands to modify instance.
diff --git a/tools/mgmt/device/instance_impl_test.go b/tools/mgmt/device/impl/instance_impl_test.go
similarity index 97%
rename from tools/mgmt/device/instance_impl_test.go
rename to tools/mgmt/device/impl/instance_impl_test.go
index 10f6702..08daed4 100644
--- a/tools/mgmt/device/instance_impl_test.go
+++ b/tools/mgmt/device/impl/instance_impl_test.go
@@ -1,4 +1,4 @@
-package main
+package impl_test
import (
"bytes"
@@ -8,6 +8,8 @@
"v.io/core/veyron2/naming"
verror "v.io/core/veyron2/verror2"
+
+ "v.io/core/veyron/tools/mgmt/device/impl"
)
func TestStopCommand(t *testing.T) {
@@ -22,7 +24,7 @@
defer stopServer(t, server)
// Setup the command-line.
- cmd := root()
+ cmd := impl.Root()
var stdout, stderr bytes.Buffer
cmd.Init(nil, &stdout, &stderr)
appName := naming.JoinAddressName(endpoint.String(), "")
@@ -97,7 +99,7 @@
defer stopServer(t, server)
// Setup the command-line.
- cmd := root()
+ cmd := impl.Root()
var stdout, stderr bytes.Buffer
cmd.Init(nil, &stdout, &stderr)
appName := naming.JoinAddressName(endpoint.String(), "")
diff --git a/tools/mgmt/device/mock_test.go b/tools/mgmt/device/impl/mock_test.go
similarity index 97%
rename from tools/mgmt/device/mock_test.go
rename to tools/mgmt/device/impl/mock_test.go
index 936fc45..f08b44c 100644
--- a/tools/mgmt/device/mock_test.go
+++ b/tools/mgmt/device/impl/mock_test.go
@@ -1,4 +1,4 @@
-package main
+package impl_test
import (
"fmt"
diff --git a/tools/mgmt/device/impl/root.go b/tools/mgmt/device/impl/root.go
new file mode 100644
index 0000000..9228247
--- /dev/null
+++ b/tools/mgmt/device/impl/root.go
@@ -0,0 +1,24 @@
+package impl
+
+import (
+ "v.io/core/veyron2/context"
+
+ "v.io/lib/cmdline"
+)
+
+var gctx *context.T
+
+func SetGlobalContext(ctx *context.T) {
+ gctx = ctx
+}
+
+func Root() *cmdline.Command {
+ return &cmdline.Command{
+ Name: "device",
+ Short: "Tool for interacting with the veyron device manager",
+ Long: `
+The device tool facilitates interaction with the veyron device manager.
+`,
+ Children: []*cmdline.Command{cmdInstall, cmdStart, associateRoot(), cmdDescribe, cmdClaim, cmdStop, cmdSuspend, cmdResume, aclRoot()},
+ }
+}
diff --git a/tools/mgmt/device/impl/util_test.go b/tools/mgmt/device/impl/util_test.go
new file mode 100644
index 0000000..e108e49
--- /dev/null
+++ b/tools/mgmt/device/impl/util_test.go
@@ -0,0 +1,27 @@
+package impl_test
+
+import (
+ "v.io/core/veyron2"
+ "v.io/core/veyron2/context"
+
+ "v.io/core/veyron/lib/testutil/security"
+ _ "v.io/core/veyron/profiles"
+ "v.io/core/veyron/tools/mgmt/device/impl"
+)
+
+var gctx *context.T
+
+func initTest() veyron2.Shutdown {
+ ctx, shutdown := veyron2.Init()
+ var err error
+ if ctx, err = veyron2.SetPrincipal(ctx, security.NewPrincipal("test-blessing")); err != nil {
+ panic(err)
+ }
+ gctx = ctx
+ impl.SetGlobalContext(gctx)
+ return func() {
+ shutdown()
+ impl.SetGlobalContext(nil)
+ gctx = nil
+ }
+}
diff --git a/tools/mgmt/device/main.go b/tools/mgmt/device/main.go
index 65f7187..fc24f06 100644
--- a/tools/mgmt/device/main.go
+++ b/tools/mgmt/device/main.go
@@ -7,17 +7,15 @@
"os"
"v.io/core/veyron2"
- "v.io/core/veyron2/context"
_ "v.io/core/veyron/profiles"
+ "v.io/core/veyron/tools/mgmt/device/impl"
)
-var gctx *context.T
-
func main() {
- var shutdown veyron2.Shutdown
- gctx, shutdown = veyron2.Init()
- exitCode := root().Main()
+ gctx, shutdown := veyron2.Init()
+ impl.SetGlobalContext(gctx)
+ exitCode := impl.Root().Main()
shutdown()
os.Exit(exitCode)
}