Merge "veyron/tools/associate: command line account association"
diff --git a/lib/exec/parent.go b/lib/exec/parent.go
index a3aebec..b0d995d 100644
--- a/lib/exec/parent.go
+++ b/lib/exec/parent.go
@@ -66,7 +66,6 @@
// NewParentHandle creates a ParentHandle for the child process represented by
// an instance of exec.Cmd.
func NewParentHandle(c *exec.Cmd, opts ...ParentHandleOpt) *ParentHandle {
-
cfg, secret := NewConfig(), ""
tk := timekeeper.RealTime()
for _, opt := range opts {
@@ -92,7 +91,18 @@
// Start starts the child process, sharing a secret with it and
// setting up a communication channel over which to read its status.
func (p *ParentHandle) Start() error {
- p.c.Env = append(p.c.Env, VersionVariable+"="+version1)
+ // Make sure that there are no instances of the VersionVariable
+ // already in the environment (which can happen when a subprocess
+ // creates a subprocess etc)
+ nenv := make([]string, 0, len(p.c.Env)+1)
+ for _, e := range p.c.Env {
+ if strings.HasPrefix(e, VersionVariable+"=") {
+ continue
+ }
+ nenv = append(nenv, e)
+ }
+ p.c.Env = append(nenv, VersionVariable+"="+version1)
+
// Create anonymous pipe for communicating data between the child
// and the parent.
dataRead, dataWrite, err := os.Pipe()
diff --git a/lib/flags/flags.go b/lib/flags/flags.go
index f6c2ef1..102ae14 100644
--- a/lib/flags/flags.go
+++ b/lib/flags/flags.go
@@ -11,11 +11,11 @@
type FlagGroup int
const (
- // Essential identifies the flags and associated environment variables
- // required by all Vanadium processes. Namely:
+ // Runtime identifies the flags and associated environment variables
+ // used by the Vanadium process runtime. Namely:
// --veyron.namespace.root (which may be repeated to supply multiple values)
// --veyron.credentials
- Essential FlagGroup = iota
+ Runtime FlagGroup = iota
// Listen identifies the flags typically required to configure
// ipc.ListenSpec. Namely:
// --veyron.tcp.protocol
@@ -44,8 +44,8 @@
return nil
}
-// EssentialFlags contains the values of the Essential flag group.
-type EssentialFlags struct {
+// RuntimeFlags contains the values of the Runtime flag group.
+type RuntimeFlags struct {
// NamespaceRoots may be initialized by NAMESPACE_ROOT* enivornment
// variables as well as --veyron.namespace.root. The command line
// will override the environment.
@@ -65,10 +65,10 @@
ListenProxy string
}
-// createAndRegisterEssentialFlags creates and registers the EssentialFlags
+// createAndRegisterRuntimeFlags creates and registers the RuntimeFlags
// group with the supplied flag.FlagSet.
-func createAndRegisterEssentialFlags(fs *flag.FlagSet) *EssentialFlags {
- f := &EssentialFlags{}
+func createAndRegisterRuntimeFlags(fs *flag.FlagSet) *RuntimeFlags {
+ f := &RuntimeFlags{}
fs.Var(&f.namespaceRootsFlag, "veyron.namespace.root", "local namespace root; can be repeated to provided multiple roots")
fs.StringVar(&f.Credentials, "veyron.credentials", "", "directory to use for storing security credentials")
return f
@@ -88,14 +88,16 @@
// CreateAndRegister creates a new set of flag groups as specified by the
// supplied flag group parameters and registers them with the supplied
-// flag.Flagset. The Essential flag group is always included.
+// flag.Flagset.
func CreateAndRegister(fs *flag.FlagSet, groups ...FlagGroup) *Flags {
+ if len(groups) == 0 {
+ return nil
+ }
f := &Flags{FlagSet: fs, groups: make(map[FlagGroup]interface{})}
- f.groups[Essential] = createAndRegisterEssentialFlags(fs)
- for _, s := range groups {
- switch s {
- case Essential:
- // do nothing, always included
+ for _, g := range groups {
+ switch g {
+ case Runtime:
+ f.groups[Runtime] = createAndRegisterRuntimeFlags(fs)
case Listen:
f.groups[Listen] = createAndRegisterListenFlags(fs)
}
@@ -103,10 +105,13 @@
return f
}
-// EssentialFlags returns the Essential flag subset stored in its Flags
+// RuntimeFlags returns the Runtime flag subset stored in its Flags
// instance.
-func (f *Flags) EssentialFlags() EssentialFlags {
- from := f.groups[Essential].(*EssentialFlags)
+func (f *Flags) RuntimeFlags() RuntimeFlags {
+ if p := f.groups[Runtime]; p == nil {
+ return RuntimeFlags{}
+ }
+ from := f.groups[Runtime].(*RuntimeFlags)
to := *from
to.NamespaceRoots = make([]string, len(from.NamespaceRoots))
copy(to.NamespaceRoots, from.NamespaceRoots)
@@ -138,7 +143,7 @@
// legacyEnvInit provides support for the legacy NAMESPACE_ROOT? and
// VEYRON_CREDENTIALS env vars.
-func (es *EssentialFlags) legacyEnvInit() {
+func (es *RuntimeFlags) legacyEnvInit() {
for _, ev := range os.Environ() {
p := strings.SplitN(ev, "=", 2)
if len(p) != 2 {
@@ -156,15 +161,22 @@
// Parse parses the supplied args, as per flag.Parse
func (f *Flags) Parse(args []string) error {
- f.groups[Essential].(*EssentialFlags).legacyEnvInit()
+ hasrt := f.groups[Runtime] != nil
+ if hasrt {
+ f.groups[Runtime].(*RuntimeFlags).legacyEnvInit()
+ }
+
// TODO(cnicolaou): implement a single env var 'VANADIUM_OPTS'
// that can be used to specify any command line.
if err := f.FlagSet.Parse(args); err != nil {
return err
}
- essential := f.groups[Essential].(*EssentialFlags)
- if len(essential.namespaceRootsFlag.roots) > 0 {
- essential.NamespaceRoots = essential.namespaceRootsFlag.roots
+
+ if hasrt {
+ runtime := f.groups[Runtime].(*RuntimeFlags)
+ if len(runtime.namespaceRootsFlag.roots) > 0 {
+ runtime.NamespaceRoots = runtime.namespaceRootsFlag.roots
+ }
}
return nil
}
diff --git a/lib/flags/flags_test.go b/lib/flags/flags_test.go
index e8ca273..8d10c8a 100644
--- a/lib/flags/flags_test.go
+++ b/lib/flags/flags_test.go
@@ -11,25 +11,32 @@
)
func TestFlags(t *testing.T) {
- fl := flags.CreateAndRegister(flag.NewFlagSet("test", flag.ContinueOnError))
+ fs := flag.NewFlagSet("test", flag.ContinueOnError)
+ if flags.CreateAndRegister(fs) != nil {
+ t.Errorf("should have failed")
+ }
+ fl := flags.CreateAndRegister(fs, flags.Runtime)
+ if fl == nil {
+ t.Fatalf("should have returned a non-nil value")
+ }
creds := "creddir"
roots := []string{"ab:cd:ef"}
args := []string{"--veyron.credentials=" + creds, "--veyron.namespace.root=" + roots[0]}
fl.Parse(args)
- es := fl.EssentialFlags()
- if got, want := es.NamespaceRoots, roots; !reflect.DeepEqual(got, want) {
+ rtf := fl.RuntimeFlags()
+ if got, want := rtf.NamespaceRoots, roots; !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
- if got, want := es.Credentials, creds; !reflect.DeepEqual(got, want) {
+ if got, want := rtf.Credentials, creds; !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
if got, want := fl.HasGroup(flags.Listen), false; got != want {
t.Errorf("got %t, want %t", got, want)
}
// Make sure we have a deep copy.
- es.NamespaceRoots[0] = "oooh"
- es = fl.EssentialFlags()
- if got, want := es.NamespaceRoots, roots; !reflect.DeepEqual(got, want) {
+ rtf.NamespaceRoots[0] = "oooh"
+ rtf = fl.RuntimeFlags()
+ if got, want := rtf.NamespaceRoots, roots; !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
}
@@ -37,7 +44,7 @@
func TestFlagError(t *testing.T) {
fs := flag.NewFlagSet("test", flag.ContinueOnError)
fs.SetOutput(ioutil.Discard)
- fl := flags.CreateAndRegister(fs)
+ fl := flags.CreateAndRegister(fs, flags.Runtime)
addr := "192.168.10.1:0"
args := []string{"--xxxveyron.tcp.address=" + addr, "not an arg"}
err := fl.Parse(args)
@@ -50,7 +57,7 @@
}
func TestFlagsGroups(t *testing.T) {
- fl := flags.CreateAndRegister(flag.NewFlagSet("test", flag.ContinueOnError), flags.Listen)
+ fl := flags.CreateAndRegister(flag.NewFlagSet("test", flag.ContinueOnError), flags.Runtime, flags.Listen)
if got, want := fl.HasGroup(flags.Listen), true; got != want {
t.Errorf("got %t, want %t", got, want)
}
@@ -59,7 +66,7 @@
args := []string{"--veyron.tcp.address=" + addr, "--veyron.namespace.root=" + roots[0]}
fl.Parse(args)
lf := fl.ListenFlags()
- if got, want := fl.EssentialFlags().NamespaceRoots, roots; !reflect.DeepEqual(got, want) {
+ if got, want := fl.RuntimeFlags().NamespaceRoots, roots; !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
if got, want := lf.ListenAddress.String(), addr; got != want {
@@ -81,39 +88,41 @@
defer os.Setenv(rootEnvVar0, oldroot0)
os.Setenv(credEnvVar, "bar")
- fl := flags.CreateAndRegister(flag.NewFlagSet("test", flag.ContinueOnError))
+ fl := flags.CreateAndRegister(flag.NewFlagSet("test", flag.ContinueOnError), flags.Runtime)
if err := fl.Parse([]string{}); err != nil {
t.Fatalf("unexpected error: %s", err)
}
- es := fl.EssentialFlags()
- if got, want := es.Credentials, "bar"; got != want {
+ rtf := fl.RuntimeFlags()
+ if got, want := rtf.Credentials, "bar"; got != want {
t.Errorf("got %q, want %q", got, want)
}
if err := fl.Parse([]string{"--veyron.credentials=baz"}); err != nil {
t.Fatalf("unexpected error: %s", err)
}
- es = fl.EssentialFlags()
- if got, want := es.Credentials, "baz"; got != want {
+ rtf = fl.RuntimeFlags()
+ if got, want := rtf.Credentials, "baz"; got != want {
t.Errorf("got %q, want %q", got, want)
}
os.Setenv(rootEnvVar, "a:1")
os.Setenv(rootEnvVar0, "a:2")
- fl = flags.CreateAndRegister(flag.NewFlagSet("test", flag.ContinueOnError))
+ fl = flags.CreateAndRegister(flag.NewFlagSet("test", flag.ContinueOnError), flags.Runtime)
if err := fl.Parse([]string{}); err != nil {
t.Fatalf("unexpected error: %s", err)
}
- es = fl.EssentialFlags()
- if got, want := es.NamespaceRoots, []string{"a:1", "a:2"}; !reflect.DeepEqual(got, want) {
+ rtf = fl.RuntimeFlags()
+ if got, want := rtf.NamespaceRoots, []string{"a:1", "a:2"}; !reflect.DeepEqual(got, want) {
t.Errorf("got %q, want %q", got, want)
}
- if err := fl.Parse([]string{"--veyron.namespace.root=b:1", "--veyron.namespace.root=b:2", "--veyron.namespace.root=b:3"}); err != nil {
+ if err := fl.Parse([]string{"--veyron.namespace.root=b:1", "--veyron.namespace.root=b:2", "--veyron.namespace.root=b:3", "--veyron.credentials=b:4"}); err != nil {
t.Fatalf("unexpected error: %s", err)
}
- es = fl.EssentialFlags()
- if got, want := es.NamespaceRoots, []string{"b:1", "b:2", "b:3"}; !reflect.DeepEqual(got, want) {
+ rtf = fl.RuntimeFlags()
+ if got, want := rtf.NamespaceRoots, []string{"b:1", "b:2", "b:3"}; !reflect.DeepEqual(got, want) {
t.Errorf("got %q, want %q", got, want)
}
-
+ if got, want := rtf.Credentials, "b:4"; got != want {
+ t.Errorf("got %q, want %q", got, want)
+ }
}
diff --git a/lib/modules/core/core_test.go b/lib/modules/core/core_test.go
index c108b72..19ee38b 100644
--- a/lib/modules/core/core_test.go
+++ b/lib/modules/core/core_test.go
@@ -21,10 +21,10 @@
)
func TestCommands(t *testing.T) {
- shell := core.NewShell()
- defer shell.Cleanup(nil, os.Stderr)
+ sh := core.NewShell()
+ defer sh.Cleanup(nil, os.Stderr)
for _, c := range []string{core.RootMTCommand, core.MTCommand} {
- if len(shell.Help(c)) == 0 {
+ if len(sh.Help(c)) == 0 {
t.Fatalf("missing command %q", c)
}
}
@@ -53,9 +53,9 @@
}
func TestRoot(t *testing.T) {
- shell, fn := newShell()
+ sh, fn := newShell()
defer fn()
- root, err := shell.Start(core.RootMTCommand, testArgs()...)
+ root, err := sh.Start(core.RootMTCommand, nil, testArgs()...)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -68,7 +68,7 @@
func startMountTables(t *testing.T, sh *modules.Shell, mountPoints ...string) (map[string]string, func(), error) {
// Start root mount table
- root, err := sh.Start(core.RootMTCommand, testArgs()...)
+ root, err := sh.Start(core.RootMTCommand, nil, testArgs()...)
if err != nil {
t.Fatalf("unexpected error for root mt: %s", err)
}
@@ -84,7 +84,7 @@
// Start the mount tables
for _, mp := range mountPoints {
- h, err := sh.Start(core.MTCommand, testArgs(mp)...)
+ h, err := sh.Start(core.MTCommand, nil, testArgs(mp)...)
if err != nil {
return nil, nil, fmt.Errorf("unexpected error for mt %q: %s", mp, err)
}
@@ -126,18 +126,18 @@
}
func TestMountTableAndGlob(t *testing.T) {
- shell, fn := newShell()
+ sh, fn := newShell()
defer fn()
mountPoints := []string{"a", "b", "c", "d", "e"}
- mountAddrs, fn, err := startMountTables(t, shell, mountPoints...)
+ mountAddrs, fn, err := startMountTables(t, sh, mountPoints...)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
defer fn()
rootName := mountAddrs["root"]
- ls, err := shell.Start(core.LSCommand, rootName+"/...")
+ ls, err := sh.Start(core.LSCommand, nil, rootName+"/...")
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -167,7 +167,7 @@
}
// Run the ls command in a subprocess, with NAMESPACE_ROOT as set above.
- lse, err := shell.Start(core.LSExternalCommand, "...")
+ lse, err := sh.Start(core.LSExternalCommand, nil, "...")
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -198,10 +198,10 @@
}
func TestEcho(t *testing.T) {
- shell, fn := newShell()
+ sh, fn := newShell()
defer fn()
- srv, err := shell.Start(core.EchoServerCommand, testArgs("test", "")...)
+ srv, err := sh.Start(core.EchoServerCommand, nil, testArgs("test", "")...)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -210,7 +210,7 @@
if len(name) == 0 {
t.Fatalf("failed to get name")
}
- clt, err := shell.Start(core.EchoClientCommand, name, "a message")
+ clt, err := sh.Start(core.EchoClientCommand, nil, name, "a message")
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -220,11 +220,11 @@
}
func TestResolve(t *testing.T) {
- shell, fn := newShell()
+ sh, fn := newShell()
defer fn()
mountPoints := []string{"a", "b"}
- mountAddrs, fn, err := startMountTables(t, shell, mountPoints...)
+ mountAddrs, fn, err := startMountTables(t, sh, mountPoints...)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -232,7 +232,7 @@
rootName := mountAddrs["root"]
mtName := "b"
echoName := naming.Join(mtName, "echo")
- srv, err := shell.Start(core.EchoServerCommand, testArgs("test", echoName)...)
+ srv, err := sh.Start(core.EchoServerCommand, nil, testArgs("test", echoName)...)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -242,7 +242,7 @@
addr = naming.JoinAddressName(addr, "//")
// Resolve an object
- resolver, err := shell.Start(core.ResolveCommand, rootName+"/"+echoName)
+ resolver, err := sh.Start(core.ResolveCommand, nil, rootName+"/"+echoName)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -259,7 +259,7 @@
// Resolve to a mount table using a rooted name.
addr = naming.JoinAddressName(mountAddrs[mtName], "//echo")
- resolver, err = shell.Start(core.ResolveMTCommand, rootName+"/"+echoName)
+ resolver, err = sh.Start(core.ResolveMTCommand, nil, rootName+"/"+echoName)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -275,7 +275,7 @@
}
// Resolve to a mount table, but using a relative name.
- nsroots, err := shell.Start(core.SetNamespaceRootsCommand, rootName)
+ nsroots, err := sh.Start(core.SetNamespaceRootsCommand, nil, rootName)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -283,7 +283,7 @@
t.Fatalf("unexpected error: %s", err)
}
- resolver, err = shell.Start(core.ResolveMTCommand, echoName)
+ resolver, err = sh.Start(core.ResolveMTCommand, nil, echoName)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
diff --git a/lib/modules/exec.go b/lib/modules/exec.go
index e81d38b..26c8b61 100644
--- a/lib/modules/exec.go
+++ b/lib/modules/exec.go
@@ -101,7 +101,16 @@
newargs := []string{os.Args[0]}
newargs = append(newargs, testFlags()...)
newargs = append(newargs, args...)
- return newargs, append(env, eh.entryPoint)
+ // Be careful to remove any existing ShellEntryPoint env vars. This
+ // can happen when subprocesses run other subprocesses etc.
+ cleaned := make([]string, 0, len(env)+1)
+ for _, e := range env {
+ if strings.HasPrefix(e, ShellEntryPoint+"=") {
+ continue
+ }
+ cleaned = append(cleaned, e)
+ }
+ return newargs, append(cleaned, eh.entryPoint)
}
func (eh *execHandle) start(sh *Shell, env []string, args ...string) (Handle, error) {
@@ -136,8 +145,8 @@
if err := handle.Start(); err != nil {
return nil, err
}
- // TODO(cnicolaou): make this timeout configurable
- err = handle.WaitForReady(time.Minute)
+ vlog.VI(1).Infof("Started: %q, pid %d", eh.name, cmd.Process.Pid)
+ err = handle.WaitForReady(sh.startTimeout)
return eh, err
}
@@ -223,11 +232,17 @@
}
func (child *childRegistrar) dispatch() error {
- ch, _ := vexec.GetChildHandle()
+ ch, err := vexec.GetChildHandle()
+ if err != nil {
+ // This is for debugging only. It's perfectly reasonable for this
+ // error to occur if the process is started by a means other
+ // than the exec library.
+ vlog.VI(1).Infof("failed to get child handle: %s", err)
+ }
+
// Only signal that the child is ready or failed if we successfully get
// a child handle. We most likely failed to get a child handle
// because the subprocess was run directly from the command line.
-
command := os.Getenv(ShellEntryPoint)
if len(command) == 0 {
err := fmt.Errorf("Failed to find entrypoint %q", ShellEntryPoint)
diff --git a/lib/modules/modules_internal_test.go b/lib/modules/modules_internal_test.go
index f60b2bb..07e76bc 100644
--- a/lib/modules/modules_internal_test.go
+++ b/lib/modules/modules_internal_test.go
@@ -35,9 +35,9 @@
sh.AddFunction("echof", Echo, "[args]*")
assertNumHandles(t, sh, 0)
- _, _ = sh.Start("echonotregistered") // won't start.
- hs, _ := sh.Start("echos", "a")
- hf, _ := sh.Start("echof", "b")
+ _, _ = sh.Start("echonotregistered", nil) // won't start.
+ hs, _ := sh.Start("echos", nil, "a")
+ hf, _ := sh.Start("echof", nil, "b")
assertNumHandles(t, sh, 2)
for i, h := range []Handle{hs, hf} {
@@ -47,8 +47,8 @@
}
assertNumHandles(t, sh, 0)
- hs, _ = sh.Start("echos", "a", "b")
- hf, _ = sh.Start("echof", "c")
+ hs, _ = sh.Start("echos", nil, "a", "b")
+ hf, _ = sh.Start("echof", nil, "c")
assertNumHandles(t, sh, 2)
sh.Cleanup(nil, nil)
diff --git a/lib/modules/modules_test.go b/lib/modules/modules_test.go
index 0c611d6..e155934 100644
--- a/lib/modules/modules_test.go
+++ b/lib/modules/modules_test.go
@@ -75,7 +75,7 @@
}
func testCommand(t *testing.T, sh *modules.Shell, name, key, val string) {
- h, err := sh.Start(name, key)
+ h, err := sh.Start(name, nil, key)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -124,7 +124,7 @@
key, val := "simpleVar", "foo & bar"
sh.SetVar(key, val)
testCommand(t, sh, "envtest", key, val)
- _, err := sh.Start("non-existent-command", "random", "args")
+ _, err := sh.Start("non-existent-command", nil, "random", "args")
if err == nil || err.Error() != `Shell command "non-existent-command" not registered` {
t.Fatalf("unexpected error %v", err)
}
@@ -142,7 +142,7 @@
func TestErrorChild(t *testing.T) {
sh := modules.NewShell("errortest")
defer sh.Cleanup(nil, nil)
- h, err := sh.Start("errortest")
+ h, err := sh.Start("errortest", nil)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -154,7 +154,7 @@
func testShutdown(t *testing.T, sh *modules.Shell, isfunc bool) {
result := ""
args := []string{"a", "b c", "ddd"}
- if _, err := sh.Start("echo", args...); err != nil {
+ if _, err := sh.Start("echo", nil, args...); err != nil {
t.Fatalf("unexpected error: %s", err)
}
var stdoutBuf bytes.Buffer
@@ -191,7 +191,7 @@
sh := modules.NewShell()
defer sh.Cleanup(nil, nil)
sh.AddFunction("errortest", ErrorMain, "")
- h, err := sh.Start("errortest")
+ h, err := sh.Start("errortest", nil)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -215,7 +215,7 @@
sh.SetVar("a", "1")
sh.SetVar("b", "2")
args := []string{"oh", "ah"}
- h, err := sh.Start("printenv", args...)
+ h, err := sh.Start("printenv", nil, args...)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -265,7 +265,7 @@
sh.SetVar("b", "2 also wrong")
os.Setenv("b", "wrong, should be 2")
- h, err := sh.StartWithEnv("printenv", []string{"b=2"})
+ h, err := sh.Start("printenv", []string{"b=2"})
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
diff --git a/lib/modules/shell.go b/lib/modules/shell.go
index cb68856..1bf3e61 100644
--- a/lib/modules/shell.go
+++ b/lib/modules/shell.go
@@ -47,17 +47,19 @@
"os"
"strings"
"sync"
+ "time"
"veyron.io/veyron/veyron2/vlog"
)
// Shell represents the context within which commands are run.
type Shell struct {
- mu sync.Mutex
- env map[string]string
- cmds map[string]*commandDesc
- handles map[Handle]struct{}
- credDir string
+ mu sync.Mutex
+ env map[string]string
+ cmds map[string]*commandDesc
+ handles map[Handle]struct{}
+ credDir string
+ startTimeout time.Duration
}
type commandDesc struct {
@@ -90,9 +92,10 @@
// TODO(cnicolaou): should create a new identity if one doesn't
// already exist
sh := &Shell{
- env: make(map[string]string),
- cmds: make(map[string]*commandDesc),
- handles: make(map[Handle]struct{}),
+ env: make(map[string]string),
+ cmds: make(map[string]*commandDesc),
+ handles: make(map[Handle]struct{}),
+ startTimeout: time.Minute,
}
if flag.Lookup("test.run") != nil && os.Getenv("VEYRON_CREDENTIALS") == "" {
if err := sh.CreateAndUseNewCredentials(); err != nil {
@@ -176,8 +179,15 @@
}
// Start starts the specified command, it returns a Handle which can be used
-// for interacting with that command. The Shell tracks all of the Handles
-// that it creates so that it can shut them down when asked to.
+// for interacting with that command. The OS and shell environment variables
+// are merged with the ones supplied as a parameter; the parameter specified
+// ones override the Shell and the Shell ones override the OS ones.
+//
+// The Shell tracks all of the Handles that it creates so that it can shut
+// them down when asked to. The returned Handle may be non-nil even when an
+// error is returned, in which case it may be used to retrieve any output
+// from the failed command.
+//
// Commands may have already been registered with the Shell using AddFunction
// or AddSubprocess, but if not, they will treated as subprocess commands
// and an attempt made to run them. Such 'dynamically' started subprocess
@@ -185,19 +195,15 @@
// message etc; their handles are remembered and will be acted on by
// the Cleanup method. If the non-registered subprocess command does not
// exist then the Start command will return an error.
-func (sh *Shell) Start(name string, args ...string) (Handle, error) {
- return sh.StartWithEnv(name, nil, args...)
-}
-
-// StartWithEnv is like Start except with a set of environment variables
-// that override those in the Shell and the OS' environment.
-func (sh *Shell) StartWithEnv(name string, env []string, args ...string) (Handle, error) {
+func (sh *Shell) Start(name string, env []string, args ...string) (Handle, error) {
cenv := sh.MergedEnv(env)
cmd := sh.getCommand(name)
expanded := append([]string{name}, sh.expand(args...)...)
h, err := cmd.factory().start(sh, cenv, expanded...)
if err != nil {
- return nil, err
+ // If the error is a timeout, then h can be used to recover
+ // any output from the process.
+ return h, err
}
sh.mu.Lock()
sh.handles[h] = struct{}{}
@@ -215,6 +221,11 @@
return cmd
}
+// SetStartTimeout sets the timeout for starting subcommands.
+func (sh *Shell) SetStartTimeout(d time.Duration) {
+ sh.startTimeout = d
+}
+
// CommandEnvelope returns the command line and environment that would be
// used for running the subprocess or function if it were started with the
// specifed arguments.
diff --git a/lib/signals/signals_test.go b/lib/signals/signals_test.go
index 636bbdb..b045ef9 100644
--- a/lib/signals/signals_test.go
+++ b/lib/signals/signals_test.go
@@ -113,7 +113,7 @@
func newShell(t *testing.T, command string) (*modules.Shell, modules.Handle, *expect.Session) {
sh := modules.NewShell()
sh.AddSubprocess(command, "")
- handle, err := sh.Start(command)
+ handle, err := sh.Start(command, nil)
if err != nil {
sh.Cleanup(os.Stderr, os.Stderr)
t.Fatalf("unexpected error: %s", err)
@@ -340,7 +340,7 @@
defer configServer.Stop()
sh.SetVar("VEYRON_CREDENTIALS", childcreds)
sh.SetVar(mgmt.ParentNodeManagerConfigKey, configServiceName)
- h, err := sh.Start("handleDefaults")
+ h, err := sh.Start("handleDefaults", nil)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
diff --git a/lib/textutil/line_writer.go b/lib/textutil/line_writer.go
index 0b70ae7..c7df3a5 100644
--- a/lib/textutil/line_writer.go
+++ b/lib/textutil/line_writer.go
@@ -155,7 +155,7 @@
//
// SetIndents() is equivalent to SetIndents(""), SetIndents("", ""), etc.
//
-// A new LineWriter instance has no idents by default.
+// A new LineWriter instance has no indents by default.
//
// Calls Flush internally, and returns any Flush error.
func (w *LineWriter) SetIndents(indents ...string) error {
diff --git a/runtimes/google/ipc/benchmarks/service.vdl.go b/runtimes/google/ipc/benchmarks/service.vdl.go
index 127b5d8..806dd55 100644
--- a/runtimes/google/ipc/benchmarks/service.vdl.go
+++ b/runtimes/google/ipc/benchmarks/service.vdl.go
@@ -16,8 +16,9 @@
_gen_wiretype "veyron.io/veyron/veyron2/wiretype"
)
-// TODO(bprosnitz) Remove this line once signatures are updated to use typevals.
-// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only bootstrap types are used on interfaces.
+// TODO(toddw): Remove this line once the new signature support is done.
+// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only
+// bootstrap types are used on interfaces.
const _ = _gen_wiretype.TypeIDInvalid
// Benchmark is the interface the client binds and uses.
diff --git a/runtimes/google/ipc/server_test.go b/runtimes/google/ipc/server_test.go
index 9718c2a..8a8020f 100644
--- a/runtimes/google/ipc/server_test.go
+++ b/runtimes/google/ipc/server_test.go
@@ -29,7 +29,7 @@
defer b.cleanup(t)
sh := modules.NewShell()
defer sh.Cleanup(os.Stderr, os.Stderr)
- server, err := sh.Start("runServer", "127.0.0.1:0")
+ server, err := sh.Start("runServer", nil, "127.0.0.1:0")
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -64,7 +64,7 @@
// Resurrect the server with the same address, verify client
// re-establishes the connection.
- server, err = sh.Start("runServer", addr)
+ server, err = sh.Start("runServer", nil, addr)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -85,7 +85,7 @@
func (h *proxyHandle) Start(t *testing.T) error {
sh := modules.NewShell()
- server, err := sh.Start("runProxy")
+ server, err := sh.Start("runProxy", nil)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
diff --git a/runtimes/google/ipc/stream/manager/manager_test.go b/runtimes/google/ipc/stream/manager/manager_test.go
index cd66579..873d882 100644
--- a/runtimes/google/ipc/stream/manager/manager_test.go
+++ b/runtimes/google/ipc/stream/manager/manager_test.go
@@ -438,7 +438,7 @@
client := InternalNew(naming.FixedRoutingID(0xcccccccc))
sh := modules.NewShell(".*")
defer sh.Cleanup(nil, nil)
- h, err := sh.Start("runServer", "127.0.0.1:0")
+ h, err := sh.Start("runServer", nil, "127.0.0.1:0")
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -459,7 +459,7 @@
t.Fatal("Expected client.Dial to fail since server is dead")
}
- h, err = sh.Start("runServer", addr)
+ h, err = sh.Start("runServer", nil, addr)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
diff --git a/runtimes/google/rt/mgmt_test.go b/runtimes/google/rt/mgmt_test.go
index 4b3b757..0737a1e 100644
--- a/runtimes/google/rt/mgmt_test.go
+++ b/runtimes/google/rt/mgmt_test.go
@@ -113,7 +113,7 @@
func TestNoWaiters(t *testing.T) {
sh := modules.NewShell(noWaitersCmd)
defer sh.Cleanup(os.Stderr, os.Stderr)
- h, err := sh.Start(noWaitersCmd)
+ h, err := sh.Start(noWaitersCmd, nil)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -139,7 +139,7 @@
func TestForceStop(t *testing.T) {
sh := modules.NewShell(forceStopCmd)
defer sh.Cleanup(os.Stderr, os.Stderr)
- h, err := sh.Start(forceStopCmd)
+ h, err := sh.Start(forceStopCmd, nil)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -291,7 +291,7 @@
sh := modules.NewShell(appCmd)
sh.SetVar("VEYRON_CREDENTIALS", childcreds)
sh.SetVar(mgmt.ParentNodeManagerConfigKey, configServiceName)
- h, err := sh.Start("app")
+ h, err := sh.Start("app", nil)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
diff --git a/runtimes/google/rt/rt.go b/runtimes/google/rt/rt.go
index d106b7f..6de8860 100644
--- a/runtimes/google/rt/rt.go
+++ b/runtimes/google/rt/rt.go
@@ -5,7 +5,6 @@
"fmt"
"os"
"path/filepath"
- "strings"
"sync"
"veyron.io/veyron/veyron2"
@@ -17,6 +16,7 @@
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron/lib/exec"
+ "veyron.io/veyron/veyron/lib/flags"
_ "veyron.io/veyron/veyron/lib/stats/sysstats"
"veyron.io/veyron/veyron/runtimes/google/naming/namespace"
"veyron.io/veyron/veyron2/options"
@@ -40,6 +40,7 @@
store security.PublicIDStore
client ipc.Client
mgmt *mgmtImpl
+ flags flags.RuntimeFlags
nServers int // GUARDED_BY(mu)
cleaningUp bool // GUARDED_BY(mu)
@@ -49,14 +50,21 @@
var _ veyron2.Runtime = (*vrt)(nil)
+var flagsOnce sync.Once
+var runtimeFlags *flags.Flags
+
func init() {
rt.RegisterRuntime(veyron2.GoogleRuntimeName, New)
+ runtimeFlags = flags.CreateAndRegister(flag.CommandLine, flags.Runtime)
}
// Implements veyron2/rt.New
func New(opts ...veyron2.ROpt) (veyron2.Runtime, error) {
rt := &vrt{mgmt: new(mgmtImpl), lang: i18n.LangIDFromEnv(), program: filepath.Base(os.Args[0])}
- flag.Parse()
+ flagsOnce.Do(func() {
+ runtimeFlags.Parse(os.Args[1:])
+ })
+ rt.flags = runtimeFlags.RuntimeFlags()
nsRoots := []string{}
for _, o := range opts {
switch v := o.(type) {
@@ -66,8 +74,6 @@
rt.id = v.PrivateID
case options.Profile:
rt.profile = v.Profile
- case options.NamespaceRoots:
- nsRoots = v
case options.RuntimeName:
if v != "google" && v != "" {
return nil, fmt.Errorf("%q is the wrong name for this runtime", v)
@@ -88,20 +94,7 @@
vlog.VI(1).Infof("Using profile %q", rt.profile.Name())
}
- if len(nsRoots) == 0 {
- for _, ev := range os.Environ() {
- p := strings.SplitN(ev, "=", 2)
- if len(p) != 2 {
- continue
- }
- k, v := p[0], p[1]
- if strings.HasPrefix(k, "NAMESPACE_ROOT") {
- nsRoots = append(nsRoots, v)
- }
- }
- }
-
- if ns, err := namespace.New(rt, nsRoots...); err != nil {
+ if ns, err := namespace.New(rt, rt.flags.NamespaceRoots...); err != nil {
return nil, fmt.Errorf("Couldn't create mount table: %v", err)
} else {
rt.ns = ns
@@ -113,7 +106,7 @@
return nil, fmt.Errorf("failed to create stream manager: %s", err)
}
- if err := rt.initSecurity(); err != nil {
+ if err := rt.initSecurity(rt.flags.Credentials); err != nil {
return nil, fmt.Errorf("failed to init sercurity: %s", err)
}
diff --git a/runtimes/google/rt/rt_test.go b/runtimes/google/rt/rt_test.go
index 8b23035..44b28fe 100644
--- a/runtimes/google/rt/rt_test.go
+++ b/runtimes/google/rt/rt_test.go
@@ -10,7 +10,6 @@
"testing"
"time"
- "veyron.io/veyron/veyron2"
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/options"
"veyron.io/veyron/veyron2/rt"
@@ -20,7 +19,6 @@
"veyron.io/veyron/veyron/lib/expect"
"veyron.io/veyron/veyron/lib/modules"
"veyron.io/veyron/veyron/lib/testutil"
- irt "veyron.io/veyron/veyron/runtimes/google/rt"
vsecurity "veyron.io/veyron/veyron/security"
)
@@ -28,6 +26,10 @@
local security.Principal
}
+// Environment variable pointing to a directory where information about a
+// principal (private key, blessing store, blessing roots etc.) is stored.
+const veyronCredentialsEnvVar = "VEYRON_CREDENTIALS"
+
func (*context) Method() string { return "" }
func (*context) Name() string { return "" }
func (*context) Suffix() string { return "" }
@@ -44,6 +46,9 @@
func init() {
testutil.Init()
modules.RegisterChild("child", "", child)
+ modules.RegisterChild("principal", "", principal)
+ modules.RegisterChild("mutate", "", mutatePrincipal)
+ modules.RegisterChild("runner", "", runner)
}
func TestHelperProcess(t *testing.T) {
@@ -71,14 +76,14 @@
vlog.Infof("%s\n", r.Logger())
fmt.Fprintf(stdout, "%s\n", r.Logger())
modules.WaitForEOF(stdin)
- fmt.Printf("done\n")
+ fmt.Fprintf(stdout, "done\n")
return nil
}
func TestInitArgs(t *testing.T) {
sh := modules.NewShell("child")
defer sh.Cleanup(os.Stderr, os.Stderr)
- h, err := sh.Start("child", "--logtostderr=true", "--vv=3", "--", "foobar")
+ h, err := sh.Start("child", nil, "--logtostderr=true", "--vv=3", "--", "foobar")
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -99,67 +104,221 @@
h.Shutdown(os.Stderr, os.Stderr)
}
-func TestInitPrincipal(t *testing.T) {
- newRT := func() veyron2.Runtime {
- r, err := rt.New(profileOpt)
- if err != nil {
- t.Fatalf("rt.New failed: %v", err)
- }
- return r
+func validatePrincipal(p security.Principal) error {
+ if p == nil {
+ return fmt.Errorf("nil principal")
}
- testPrincipal := func(r veyron2.Runtime) security.Principal {
- p := r.Principal()
- if p == nil {
- t.Fatalf("rt.Principal() returned nil")
- }
- blessings := p.BlessingStore().Default()
- if blessings == nil {
- t.Fatalf("rt.Principal().BlessingStore().Default() returned nil")
+ blessings := p.BlessingStore().Default()
+ if blessings == nil {
+ return fmt.Errorf("rt.Principal().BlessingStore().Default() returned nil")
- }
- if n := len(blessings.ForContext(&context{local: p})); n != 1 {
- t.Fatalf("rt.Principal().BlessingStore().Default() returned Blessing %v with %d recognized blessings, want exactly one recognized blessing", blessings, n)
- }
- return p
}
- origCredentialsDir := os.Getenv(irt.VeyronCredentialsEnvVar)
- defer os.Setenv(irt.VeyronCredentialsEnvVar, origCredentialsDir)
-
- // Test that even with VEYRON_CREDENTIALS unset the runtime's Principal
- // is correctly initialized.
- if err := os.Setenv(irt.VeyronCredentialsEnvVar, ""); err != nil {
- t.Fatal(err)
+ if n := len(blessings.ForContext(&context{local: p})); n != 1 {
+ fmt.Errorf("rt.Principal().BlessingStore().Default() returned Blessing %v with %d recognized blessings, want exactly one recognized blessing", blessings, n)
}
- testPrincipal(newRT())
+ return nil
+}
- // Test that with VEYRON_CREDENTIALS set the runtime's Principal is correctly
- // initialized.
- credentials, err := ioutil.TempDir("", "credentials")
+func tmpDir(t *testing.T) string {
+ dir, err := ioutil.TempDir("", "rt_test_dir")
if err != nil {
- t.Fatal(err)
+ t.Fatalf("unexpected error: %s", err)
}
- defer os.RemoveAll(credentials)
- if err := os.Setenv(irt.VeyronCredentialsEnvVar, credentials); err != nil {
- t.Fatal(err)
+ return dir
+}
+
+func principal(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+ r := rt.Init()
+ err := validatePrincipal(r.Principal())
+ fmt.Fprintf(stdout, "ERROR=%v\n", err)
+ fmt.Fprintf(stdout, "PUBKEY=%s\n", r.Principal().PublicKey())
+ modules.WaitForEOF(stdin)
+ return nil
+}
+
+// Runner runs a principal as a subprocess and reports back with its
+// own security info and it's childs.
+func runner(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+ r := rt.Init()
+ err := validatePrincipal(r.Principal())
+ fmt.Fprintf(stdout, "RUNNER_ERROR=%v\n", err)
+ fmt.Fprintf(stdout, "RUNNER_PUBKEY=%s\n", r.Principal().PublicKey())
+ if err != nil {
+ return err
}
- p := testPrincipal(newRT())
+ sh := modules.NewShell("principal")
+ defer sh.Cleanup(os.Stderr, os.Stderr)
+ h, err := sh.Start("principal", nil, args[1:]...)
+ if err != nil {
+ return err
+ }
+ s := expect.NewSession(nil, h.Stdout(), 1*time.Second) // time.Minute)
+ fmt.Fprintf(stdout, s.ReadLine()+"\n")
+ fmt.Fprintf(stdout, s.ReadLine()+"\n")
+ modules.WaitForEOF(stdin)
+ return nil
+}
+
+func mutatePrincipal(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+ r := rt.Init()
+
+ rtPrincipal := r.Principal()
+ err := validatePrincipal(rtPrincipal)
+ fmt.Fprintf(stdout, "ERROR=%v\n", err)
// Mutate the roots and store of this principal.
- blessing, err := p.BlessSelf("irrelevant")
+ blessing, err := rtPrincipal.BlessSelf("irrelevant")
if err != nil {
- t.Fatal(err)
+ return err
}
- if _, err := p.BlessingStore().Set(blessing, security.AllPrincipals); err != nil {
- t.Fatal(err)
+ if _, err := rtPrincipal.BlessingStore().Set(blessing, security.AllPrincipals); err != nil {
+ return err
}
- if err := p.AddToRoots(blessing); err != nil {
+ if err := rtPrincipal.AddToRoots(blessing); err != nil {
+ return err
+ }
+ newRT, err := rt.New(profileOpt)
+ if err != nil {
+ return fmt.Errorf("rt.New failed: %v", err)
+ }
+ // Test that the same principal gets initialized on creating a new runtime
+ // from the same credentials directory.
+ if got := newRT.Principal(); !reflect.DeepEqual(got, rtPrincipal) {
+ return fmt.Errorf("Initialized Principal: %v, expected: %v", got.PublicKey(), rtPrincipal.PublicKey())
+ }
+ fmt.Fprintf(stdout, "PUBKEY=%s\n", newRT.Principal().PublicKey())
+ modules.WaitForEOF(stdin)
+ return nil
+}
+
+func createCredentialsInDir(t *testing.T, dir string) security.Principal {
+ principal, err := vsecurity.CreatePersistentPrincipal(dir, nil)
+ if err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ vsecurity.InitDefaultBlessings(principal, "test")
+ return principal
+}
+
+func TestPrincipalInheritance(t *testing.T) {
+ sh := modules.NewShell("principal", "runner")
+ defer func() {
+ sh.Cleanup(os.Stdout, os.Stderr)
+ }()
+
+ // Test that the child inherits the parent's credentials correctly.
+ // The running test process may or may not have a credentials directory set
+ // up so we have to use a 'runner' process to ensure the correct setup.
+ cdir := tmpDir(t)
+ defer os.RemoveAll(cdir)
+
+ principal := createCredentialsInDir(t, cdir)
+
+ // directory supplied by the environment.
+ credEnv := []string{veyronCredentialsEnvVar + "=" + cdir}
+
+ h, err := sh.Start("runner", credEnv)
+ if err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ s := expect.NewSession(t, h.Stdout(), 2*time.Second) //time.Minute)
+ runnerErr := s.ExpectVar("RUNNER_ERROR")
+ runnerPubKey := s.ExpectVar("RUNNER_PUBKEY")
+ principalErr := s.ExpectVar("ERROR")
+ principalPubKey := s.ExpectVar("PUBKEY")
+ if err := s.Error(); err != nil {
+ t.Fatalf("failed to read input from children: %s", err)
+ }
+ h.Shutdown(os.Stdout, os.Stderr)
+ if runnerErr != "<nil>" || principalErr != "<nil>" {
+ t.Fatalf("unexpected error: runner %q, principal %q", runnerErr, principalErr)
+ }
+ pubKey := principal.PublicKey().String()
+ if runnerPubKey != pubKey || principalPubKey != pubKey {
+ t.Fatalf("unexpected pubkeys: expected %s: runner %s, principal %s",
+ pubKey, runnerPubKey, principalPubKey)
+ }
+
+}
+
+func TestPrincipalInit(t *testing.T) {
+ // Collet the process' public key and error status
+ collect := func(sh *modules.Shell, cmd string, env []string, args ...string) (string, error) {
+ h, err := sh.Start(cmd, env, args...)
+ if err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ s := expect.NewSession(t, h.Stdout(), time.Minute)
+ s.SetVerbosity(testing.Verbose())
+ errstr := s.ExpectVar("ERROR")
+ pubkey := s.ExpectVar("PUBKEY")
+ if errstr != "<nil>" {
+ return pubkey, fmt.Errorf("%s", errstr)
+ }
+ return pubkey, nil
+ }
+
+ // A credentials directory may, or may, not have been already specified.
+ // Either way, we want to use our own, so we set it aside and use our own.
+ origCredentialsDir := os.Getenv(veyronCredentialsEnvVar)
+ defer os.Setenv(veyronCredentialsEnvVar, origCredentialsDir)
+
+ // Test that with VEYRON_CREDENTIALS unset the runtime's Principal
+ // is correctly initialized.
+ if err := os.Setenv(veyronCredentialsEnvVar, ""); err != nil {
t.Fatal(err)
}
- // Test that the same principal gets initialized on creating a new runtime
- // from the same credentials directory.
- if got := newRT().Principal(); !reflect.DeepEqual(got, p) {
- t.Fatalf("Initialized Principal: %v, expected: %v", got.PublicKey(), p.PublicKey())
+ sh := modules.NewShell("principal")
+ defer sh.Cleanup(os.Stderr, os.Stderr)
+
+ pubkey, err := collect(sh, "principal", nil)
+ if err != nil {
+ t.Fatalf("child failed to create+validate principal: %v", err)
+ }
+ if len(pubkey) == 0 {
+ t.Fatalf("child failed to return a public key")
+ }
+
+ // Test specifying credentials via VEYRON_CREDENTIALS
+ cdir1 := tmpDir(t)
+ defer os.RemoveAll(cdir1)
+ principal := createCredentialsInDir(t, cdir1)
+ // directory supplied by the environment.
+ credEnv := []string{veyronCredentialsEnvVar + "=" + cdir1}
+
+ pubkey, err = collect(sh, "principal", credEnv)
+ if err != nil {
+ t.Errorf("unexpected error: %s", err)
+ }
+
+ if got, want := pubkey, principal.PublicKey().String(); got != want {
+ t.Errorf("got %q, want %q", got, want)
+ }
+
+ // Test specifying credentials via the command line and that the
+ // comand line overrides the environment
+ cdir2 := tmpDir(t)
+ defer os.RemoveAll(cdir2)
+ clPrincipal := createCredentialsInDir(t, cdir2)
+
+ pubkey, err = collect(sh, "principal", credEnv, "--veyron.credentials="+cdir2)
+ if err != nil {
+ t.Errorf("unexpected error: %s", err)
+ }
+
+ if got, want := pubkey, clPrincipal.PublicKey().String(); got != want {
+ t.Errorf("got %q, want %q", got, want)
+ }
+
+ // Mutate the roots and store of the principal in the child process.
+ pubkey, err = collect(sh, "mutate", credEnv, "--veyron.credentials="+cdir2)
+ if err != nil {
+ t.Errorf("unexpected error: %s", err)
+ }
+
+ if got, want := pubkey, clPrincipal.PublicKey().String(); got != want {
+ t.Errorf("got %q, want %q", got, want)
}
}
diff --git a/runtimes/google/rt/security.go b/runtimes/google/rt/security.go
index 0863c04a..aa673d4 100644
--- a/runtimes/google/rt/security.go
+++ b/runtimes/google/rt/security.go
@@ -15,10 +15,6 @@
"veyron.io/veyron/veyron2/vlog"
)
-// Environment variable pointing to a directory where information about a principal
-// (private key, blessing store, blessing roots etc.) is stored.
-const VeyronCredentialsEnvVar = "VEYRON_CREDENTIALS"
-
func (rt *vrt) Principal() security.Principal {
return rt.principal
}
@@ -35,31 +31,33 @@
return rt.store
}
-func (rt *vrt) initSecurity() error {
+func (rt *vrt) initSecurity(credentials string) error {
if err := rt.initOldSecurity(); err != nil {
return err
}
- if err := rt.initPrincipal(); err != nil {
+ if err := rt.initPrincipal(credentials); err != nil {
return fmt.Errorf("principal initialization failed: %v", err)
}
return nil
}
-func (rt *vrt) initPrincipal() error {
+func (rt *vrt) initPrincipal(credentials string) error {
if rt.principal != nil {
return nil
}
var err error
+ // TODO(cnicolaou,ashankar,ribrdb): this should be supplied via
+ // the exec.GetChildHandle call.
if len(os.Getenv(agent.FdVarName)) > 0 {
rt.principal, err = rt.connectToAgent()
return err
- } else if dir := os.Getenv(VeyronCredentialsEnvVar); len(dir) > 0 {
+ } else if len(credentials) > 0 {
// TODO(ataly, ashankar): If multiple runtimes are getting
// initialized at the same time from the same VEYRON_CREDENTIALS
// we will need some kind of locking for the credential files.
- if rt.principal, err = vsecurity.LoadPersistentPrincipal(dir, nil); err != nil {
+ if rt.principal, err = vsecurity.LoadPersistentPrincipal(credentials, nil); err != nil {
if os.IsNotExist(err) {
- if rt.principal, err = vsecurity.CreatePersistentPrincipal(dir, nil); err != nil {
+ if rt.principal, err = vsecurity.CreatePersistentPrincipal(credentials, nil); err != nil {
return err
}
return vsecurity.InitDefaultBlessings(rt.principal, defaultBlessingName())
diff --git a/runtimes/google/rt/signal_test.go b/runtimes/google/rt/signal_test.go
index 5aa1b3d..e37f883 100644
--- a/runtimes/google/rt/signal_test.go
+++ b/runtimes/google/rt/signal_test.go
@@ -47,7 +47,7 @@
func TestWithRuntime(t *testing.T) {
sh := modules.NewShell("withRuntime")
defer sh.Cleanup(os.Stderr, os.Stderr)
- h, err := sh.Start("withRuntime")
+ h, err := sh.Start("withRuntime", nil)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -64,7 +64,7 @@
func TestWithoutRuntime(t *testing.T) {
sh := modules.NewShell("withoutRuntime")
defer sh.Cleanup(os.Stderr, os.Stderr)
- h, err := sh.Start("withoutRuntime")
+ h, err := sh.Start("withoutRuntime", nil)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
diff --git a/runtimes/google/security/identity_test.go b/runtimes/google/security/identity_test.go
index 315e9cd..1dae49c 100644
--- a/runtimes/google/security/identity_test.go
+++ b/runtimes/google/security/identity_test.go
@@ -352,7 +352,7 @@
// registers all values encoded within the same process.
sh := modules.NewShell(".*")
defer sh.Cleanup(nil, nil)
- h, err := sh.Start("encodeUnregisteredCaveat")
+ h, err := sh.Start("encodeUnregisteredCaveat", nil)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
diff --git a/security/agent/agentd/main.go b/security/agent/agentd/main.go
index b3341cb..423e146 100644
--- a/security/agent/agentd/main.go
+++ b/security/agent/agentd/main.go
@@ -1,11 +1,12 @@
package main
import (
- "code.google.com/p/gopass"
+ "code.google.com/p/go.crypto/ssh/terminal"
"flag"
"fmt"
"os"
"os/exec"
+ "os/signal"
"syscall"
_ "veyron.io/veyron/veyron/profiles"
vsecurity "veyron.io/veyron/veyron/security"
@@ -89,11 +90,11 @@
func handleDoesNotExist(dir string) (security.Principal, error) {
fmt.Println("Private key file does not exist. Creating new private key...")
- pass, err := gopass.GetPass("Enter passphrase (entering nothing will store unecrypted): ")
+ pass, err := getPassword("Enter passphrase (entering nothing will store unecrypted): ")
if err != nil {
return nil, fmt.Errorf("failed to read passphrase: %v", err)
}
- p, err := vsecurity.CreatePersistentPrincipal(dir, []byte(pass))
+ p, err := vsecurity.CreatePersistentPrincipal(dir, pass)
if err != nil {
return nil, err
}
@@ -103,9 +104,40 @@
func handlePassphrase(dir string) (security.Principal, error) {
fmt.Println("Private key file is encrypted. Please enter passphrase.")
- pass, err := gopass.GetPass("Enter passphrase: ")
+ pass, err := getPassword("Enter passphrase: ")
if err != nil {
return nil, fmt.Errorf("failed to read passphrase: %v", err)
}
- return vsecurity.LoadPersistentPrincipal(dir, []byte(pass))
+ return vsecurity.LoadPersistentPrincipal(dir, pass)
+}
+
+func getPassword(prompt string) ([]byte, error) {
+ fmt.Printf(prompt)
+ stop := make(chan bool)
+ defer close(stop)
+ state, err := terminal.GetState(int(os.Stdin.Fd()))
+ if err != nil {
+ return nil, err
+ }
+ go catchTerminationSignals(stop, state)
+ return terminal.ReadPassword(int(os.Stdin.Fd()))
+}
+
+// catchTerminationSignals catches signals to allow us to turn terminal echo back on.
+func catchTerminationSignals(stop <-chan bool, state *terminal.State) {
+ var successErrno syscall.Errno
+ sig := make(chan os.Signal, 4)
+ // Catch the blockable termination signals.
+ signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGHUP)
+ select {
+ case <-sig:
+ // Start on new line in terminal.
+ fmt.Printf("\n")
+ if err := terminal.Restore(int(os.Stdin.Fd()), state); err != successErrno {
+ vlog.Errorf("Failed to restore terminal state (%v), you words may not show up when you type, enter 'stty echo' to fix this.", err)
+ }
+ os.Exit(-1)
+ case <-stop:
+ signal.Stop(sig)
+ }
}
diff --git a/security/agent/pingpong/wire.vdl.go b/security/agent/pingpong/wire.vdl.go
index 5a22289..9bf1574 100644
--- a/security/agent/pingpong/wire.vdl.go
+++ b/security/agent/pingpong/wire.vdl.go
@@ -13,8 +13,9 @@
_gen_wiretype "veyron.io/veyron/veyron2/wiretype"
)
-// TODO(bprosnitz) Remove this line once signatures are updated to use typevals.
-// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only bootstrap types are used on interfaces.
+// TODO(toddw): Remove this line once the new signature support is done.
+// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only
+// bootstrap types are used on interfaces.
const _ = _gen_wiretype.TypeIDInvalid
// Simple service used in the agent tests.
diff --git a/security/agent/server/wire.vdl.go b/security/agent/server/wire.vdl.go
index 445984a..d9fcc39 100644
--- a/security/agent/server/wire.vdl.go
+++ b/security/agent/server/wire.vdl.go
@@ -15,8 +15,9 @@
_gen_wiretype "veyron.io/veyron/veyron2/wiretype"
)
-// TODO(bprosnitz) Remove this line once signatures are updated to use typevals.
-// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only bootstrap types are used on interfaces.
+// TODO(toddw): Remove this line once the new signature support is done.
+// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only
+// bootstrap types are used on interfaces.
const _ = _gen_wiretype.TypeIDInvalid
// Agent is the interface the client binds and uses.
diff --git a/services/identity/identity.vdl.go b/services/identity/identity.vdl.go
index 068b53a..85027dc 100644
--- a/services/identity/identity.vdl.go
+++ b/services/identity/identity.vdl.go
@@ -16,8 +16,9 @@
_gen_wiretype "veyron.io/veyron/veyron2/wiretype"
)
-// TODO(bprosnitz) Remove this line once signatures are updated to use typevals.
-// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only bootstrap types are used on interfaces.
+// TODO(toddw): Remove this line once the new signature support is done.
+// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only
+// bootstrap types are used on interfaces.
const _ = _gen_wiretype.TypeIDInvalid
// OAuthBlesser exchanges OAuth access tokens for
diff --git a/services/mgmt/debug/debug.vdl.go b/services/mgmt/debug/debug.vdl.go
index 9a98789..96e09d0 100644
--- a/services/mgmt/debug/debug.vdl.go
+++ b/services/mgmt/debug/debug.vdl.go
@@ -19,8 +19,9 @@
_gen_wiretype "veyron.io/veyron/veyron2/wiretype"
)
-// TODO(bprosnitz) Remove this line once signatures are updated to use typevals.
-// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only bootstrap types are used on interfaces.
+// TODO(toddw): Remove this line once the new signature support is done.
+// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only
+// bootstrap types are used on interfaces.
const _ = _gen_wiretype.TypeIDInvalid
// This interface exists only for the purpose of generating a valid Signature
diff --git a/services/mgmt/node/config.vdl.go b/services/mgmt/node/config.vdl.go
index 32965b5..5ef274f 100644
--- a/services/mgmt/node/config.vdl.go
+++ b/services/mgmt/node/config.vdl.go
@@ -13,8 +13,9 @@
_gen_wiretype "veyron.io/veyron/veyron2/wiretype"
)
-// TODO(bprosnitz) Remove this line once signatures are updated to use typevals.
-// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only bootstrap types are used on interfaces.
+// TODO(toddw): Remove this line once the new signature support is done.
+// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only
+// bootstrap types are used on interfaces.
const _ = _gen_wiretype.TypeIDInvalid
// Config is an RPC API to the config service.
diff --git a/services/mgmt/node/impl/impl_test.go b/services/mgmt/node/impl/impl_test.go
index 8794636..69b1f2c 100644
--- a/services/mgmt/node/impl/impl_test.go
+++ b/services/mgmt/node/impl/impl_test.go
@@ -1081,6 +1081,8 @@
name = logFileTrimInfoRE.ReplaceAllString(name, "bin.<*>.INFO.<timestamp>")
filteredResults = append(filteredResults, name)
}
+ sort.Strings(filteredResults)
+ sort.Strings(tc.expected)
if !reflect.DeepEqual(filteredResults, tc.expected) {
t.Errorf("unexpected result for (%q, %q). Got %q, want %q", tc.name, tc.pattern, filteredResults, tc.expected)
}
@@ -1088,6 +1090,9 @@
// Call Size() on the log file objects.
files := doGlob(t, "nm", "apps/google naps/"+installID+"/"+instance1ID+"/logs/*")
+ if want, got := 4, len(files); got < want {
+ t.Errorf("Unexpected number of matches. Got %d, want at least %d", got, want)
+ }
for _, file := range files {
name := naming.Join("nm", file)
c, err := logreader.BindLogFile(name)
@@ -1155,7 +1160,6 @@
if err := stream.Finish(); err != nil {
t.Errorf("Finish failed: %v", err)
}
- sort.Strings(results)
return results
}
diff --git a/services/mgmt/node/impl/util_test.go b/services/mgmt/node/impl/util_test.go
index 8c098dc..c039bbd 100644
--- a/services/mgmt/node/impl/util_test.go
+++ b/services/mgmt/node/impl/util_test.go
@@ -39,7 +39,7 @@
}
func startRootMT(t *testing.T, sh *modules.Shell) (string, modules.Handle, *expect.Session) {
- h, err := sh.Start(core.RootMTCommand, "--", "--veyron.tcp.address=127.0.0.1:0")
+ h, err := sh.Start(core.RootMTCommand, nil, "--", "--veyron.tcp.address=127.0.0.1:0")
if err != nil {
t.Fatalf("failed to start root mount table: %s", err)
}
@@ -72,10 +72,10 @@
vlog.VI(1).Info("---------------------------------")
sh.Cleanup(nil, os.Stderr)
mtHandle.Shutdown(nil, os.Stderr)
- sh.Start(core.SetNamespaceRootsCommand, "")
+ sh.Start(core.SetNamespaceRootsCommand, nil, "")
}
- if _, err := sh.Start(core.SetNamespaceRootsCommand, mtName); err != nil {
+ if _, err := sh.Start(core.SetNamespaceRootsCommand, nil, mtName); err != nil {
t.Fatalf("%s: unexpected error: %s", loc(1), err)
}
sh.SetVar("NAMESPACE_ROOT", mtName)
@@ -83,7 +83,7 @@
}
func runShellCommand(t *testing.T, sh *modules.Shell, env []string, cmd string, args ...string) (modules.Handle, *expect.Session) {
- h, err := sh.StartWithEnv(cmd, env, args...)
+ h, err := sh.Start(cmd, env, args...)
if err != nil {
t.Fatalf("%s: failed to start %q: %s", loc(1), cmd, err)
return nil, nil
diff --git a/services/mgmt/repository/repository.vdl.go b/services/mgmt/repository/repository.vdl.go
index 2ec59c2..57ac530 100644
--- a/services/mgmt/repository/repository.vdl.go
+++ b/services/mgmt/repository/repository.vdl.go
@@ -23,8 +23,9 @@
_gen_wiretype "veyron.io/veyron/veyron2/wiretype"
)
-// TODO(bprosnitz) Remove this line once signatures are updated to use typevals.
-// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only bootstrap types are used on interfaces.
+// TODO(toddw): Remove this line once the new signature support is done.
+// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only
+// bootstrap types are used on interfaces.
const _ = _gen_wiretype.TypeIDInvalid
// Application describes an application repository internally. Besides
diff --git a/services/mgmt/root/root.vdl.go b/services/mgmt/root/root.vdl.go
index 09c1f3a..273f77b 100644
--- a/services/mgmt/root/root.vdl.go
+++ b/services/mgmt/root/root.vdl.go
@@ -15,8 +15,9 @@
_gen_wiretype "veyron.io/veyron/veyron2/wiretype"
)
-// TODO(bprosnitz) Remove this line once signatures are updated to use typevals.
-// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only bootstrap types are used on interfaces.
+// TODO(toddw): Remove this line once the new signature support is done.
+// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only
+// bootstrap types are used on interfaces.
const _ = _gen_wiretype.TypeIDInvalid
// Root is an interface to be implemented by a process with root level
diff --git a/services/mounttable/lib/collection_test.vdl.go b/services/mounttable/lib/collection_test.vdl.go
index 77b9710..e31a27d 100644
--- a/services/mounttable/lib/collection_test.vdl.go
+++ b/services/mounttable/lib/collection_test.vdl.go
@@ -13,8 +13,9 @@
_gen_wiretype "veyron.io/veyron/veyron2/wiretype"
)
-// TODO(bprosnitz) Remove this line once signatures are updated to use typevals.
-// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only bootstrap types are used on interfaces.
+// TODO(toddw): Remove this line once the new signature support is done.
+// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only
+// bootstrap types are used on interfaces.
const _ = _gen_wiretype.TypeIDInvalid
// Collection is the interface the client binds and uses.
diff --git a/services/security/discharger.vdl.go b/services/security/discharger.vdl.go
index 67dddaf..6793150 100644
--- a/services/security/discharger.vdl.go
+++ b/services/security/discharger.vdl.go
@@ -15,8 +15,9 @@
_gen_wiretype "veyron.io/veyron/veyron2/wiretype"
)
-// TODO(bprosnitz) Remove this line once signatures are updated to use typevals.
-// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only bootstrap types are used on interfaces.
+// TODO(toddw): Remove this line once the new signature support is done.
+// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only
+// bootstrap types are used on interfaces.
const _ = _gen_wiretype.TypeIDInvalid
// Discharger is the interface for obtaining discharges for ThirdPartyCaveats.
diff --git a/tools/mgmt/nminstall b/tools/mgmt/nminstall
new file mode 100755
index 0000000..c6358d2
--- /dev/null
+++ b/tools/mgmt/nminstall
@@ -0,0 +1,124 @@
+#!/bin/bash
+#
+# Installs node manager on the local machine.
+#
+# Specifically:
+#
+# 1. Fetches the binaries required for a node 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 node manager to run binaries
+# under different system accounts than itself.
+#
+# 3. Runs the self-install command on the node manager.
+#
+# Usage:
+#
+# # Gets binaries from local repository (TODO(caprita): implement)
+# ./nminstall <install parent dir>
+#
+# # Gets binaries from local filesystem
+# ./nminstall <install parent dir> /path/to/binaries
+#
+# # Gets binaries from HTTP server (TODO(caprita): implement)
+# ./nminstall <install parent dir> http://host/path
+
+set -e
+
+usage() {
+ echo "usage:"
+ echo "./nminstall <install parent dir> [<binary source>]"
+}
+
+# TODO(caprita): Also agent.
+readonly BIN_NAMES=(noded suidhelper)
+
+#######################################################
+# Fetches binaries needed by node manager installation.
+# Globals:
+# BIN_NAMES
+# VEYRON_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 "${VEYRON_ROOT}" ]]; then
+ echo 'ERROR: binary source not specified and no local repository available'
+ exit 1
+ fi
+ local -r REPO_BIN_DIR="${VEYRON_ROOT}/veyron/go/bin"
+ echo "Fetching binaries:${bin_names_str} from: ${REPO_BIN_DIR} ..."
+ for bin_name in ${BIN_NAMES[@]}; do
+ local repo_source="${REPO_BIN_DIR}/${bin_name}"
+ if [[ -x "${repo_source}" ]]; then
+ local file_destination="${BIN_INSTALL}/${bin_name}"
+ cp "${repo_source}" "${file_destination}"
+ chmod 700 "${file_destination}"
+ else
+ echo "couldn't find ${repo_source}"
+ exit 1
+ fi
+ done
+ echo "Binaries are in ${BIN_INSTALL}."
+ return
+ fi
+
+ echo 'ERROR: couldn'"'"'t fetch binaries.'
+ exit 1
+}
+
+main() {
+ local -r INSTALL_PARENT_DIR="$1"
+ if [[ -z "${INSTALL_PARENT_DIR}" ]]; then
+ echo 'No local install destination specified!'
+ usage
+ exit 1
+ fi
+
+ if [[ ! -d "${INSTALL_PARENT_DIR}" ]]; then
+ echo "${INSTALL_PARENT_DIR} is not a directory!"
+ exit 1
+ fi
+
+ local -r INSTALL_DIR="${INSTALL_PARENT_DIR}/node_manager"
+
+ # TODO(caprita): Check that the node manager is not already installed before
+ # proceeding. We should require an explicit uninstall to avoid wiping away
+ # the node manager accidentally.
+ sudo rm -rf "${INSTALL_DIR}"
+ mkdir -m 700 "${INSTALL_DIR}"
+
+ local -r BIN_INSTALL="${INSTALL_DIR}/bin"
+ mkdir -m 700 "${BIN_INSTALL}"
+
+ # Fetch the binaries.
+ local -r BIN_SOURCE="$2"
+ get_binaries "${BIN_INSTALL}" "${BIN_SOURCE}"
+
+ # Set up the suidhelper.
+ echo "Configuring suidhelper ..."
+ local -r SETUID_SCRIPT="${BIN_INSTALL}/suidhelper"
+ sudo bash -c "chown root:root \"${SETUID_SCRIPT}\"; chmod 4551 \"${SETUID_SCRIPT}\""
+ echo "Suidhelper configured."
+
+ # Tell the node manager to install itself.
+ local -r NM_ROOT="${INSTALL_DIR}/nmroot"
+ echo "Installing node manager under ${NM_ROOT} ..."
+ VEYRON_NM_CURRENT="${INSTALL_DIR}/curr" VEYRON_NM_ROOT="${NM_ROOT}" VEYRON_NM_HELPER="${SETUID_SCRIPT}" "${BIN_INSTALL}/noded" --install_self
+ echo "Node manager installed."
+}
+
+main "$@"
diff --git a/tools/naming/simulator/driver.go b/tools/naming/simulator/driver.go
index c6abba2..4f944ca 100644
--- a/tools/naming/simulator/driver.go
+++ b/tools/naming/simulator/driver.go
@@ -189,7 +189,7 @@
}
output(lineno, l)
} else {
- handle, err := sh.Start(name, sub...)
+ handle, err := sh.Start(name, nil, sub...)
if err != nil {
return err
}
diff --git a/tools/servicerunner/main.go b/tools/servicerunner/main.go
index 366e8f4..6b3f501 100644
--- a/tools/servicerunner/main.go
+++ b/tools/servicerunner/main.go
@@ -76,7 +76,7 @@
vars := map[string]string{}
- h, err := sh.Start("root", "--", "--veyron.tcp.address=127.0.0.1:0")
+ h, err := sh.Start("root", nil, "--", "--veyron.tcp.address=127.0.0.1:0")
panicOnError(err)
updateVars(h, vars, "MT_NAME")
@@ -87,12 +87,12 @@
// NOTE(sadovsky): The proxyd binary requires --protocol and --address flags
// while the proxyd command instead uses ListenSpec flags.
- h, err = sh.Start("proxyd", "--", "--veyron.tcp.address=127.0.0.1:0", "p")
+ h, err = sh.Start("proxyd", nil, "--", "--veyron.tcp.address=127.0.0.1:0", "p")
panicOnError(err)
updateVars(h, vars, "PROXY_ADDR")
// TODO(sadovsky): Which identd should we be using?
- h, err = sh.Start("wsprd", "--", "--veyron.proxy="+vars["PROXY_ADDR"], "--identd=/proxy.envyor.com:8101/identity/veyron-test/google")
+ h, err = sh.Start("wsprd", nil, "--", "--veyron.proxy="+vars["PROXY_ADDR"], "--identd=/proxy.envyor.com:8101/identity/veyron-test/google")
panicOnError(err)
updateVars(h, vars, "WSPR_ADDR")
diff --git a/tools/vrpc/test_base/test_base.vdl.go b/tools/vrpc/test_base/test_base.vdl.go
index bac146f..92bf836 100644
--- a/tools/vrpc/test_base/test_base.vdl.go
+++ b/tools/vrpc/test_base/test_base.vdl.go
@@ -19,8 +19,9 @@
Y int32
}
-// TODO(bprosnitz) Remove this line once signatures are updated to use typevals.
-// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only bootstrap types are used on interfaces.
+// TODO(toddw): Remove this line once the new signature support is done.
+// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only
+// bootstrap types are used on interfaces.
const _ = _gen_wiretype.TypeIDInvalid
// TypeTester is the interface the client binds and uses.