Merge "veyron/lib/modules: adding an option to pass Config to a child process"
diff --git a/lib/modules/exec.go b/lib/modules/exec.go
index 26c8b61..ab893d8 100644
--- a/lib/modules/exec.go
+++ b/lib/modules/exec.go
@@ -134,7 +134,7 @@
 		return nil, err
 	}
 
-	handle := vexec.NewParentHandle(cmd)
+	handle := vexec.NewParentHandle(cmd, vexec.ConfigOpt{Config: sh.Config})
 	eh.stdout = stdout
 	eh.stderr = stderr
 	eh.stdin = stdin
diff --git a/lib/modules/shell.go b/lib/modules/shell.go
index 1f2a016..7f3c194 100644
--- a/lib/modules/shell.go
+++ b/lib/modules/shell.go
@@ -49,6 +49,7 @@
 	"sync"
 	"time"
 
+	"veyron.io/veyron/veyron/lib/exec"
 	"veyron.io/veyron/veyron/lib/flags/consts"
 	"veyron.io/veyron/veyron2/vlog"
 )
@@ -61,6 +62,7 @@
 	handles      map[Handle]struct{}
 	credDir      string
 	startTimeout time.Duration
+	Config       exec.Config
 }
 
 type commandDesc struct {
@@ -96,6 +98,7 @@
 		cmds:         make(map[string]*commandDesc),
 		handles:      make(map[Handle]struct{}),
 		startTimeout: time.Minute,
+		Config:       exec.NewConfig(),
 	}
 	if flag.Lookup("test.run") != nil && os.Getenv(consts.VeyronCredentials) == "" {
 		if err := sh.CreateAndUseNewCredentials(); err != nil {
diff --git a/lib/signals/signals_test.go b/lib/signals/signals_test.go
index 628daaf..cfe3f16 100644
--- a/lib/signals/signals_test.go
+++ b/lib/signals/signals_test.go
@@ -340,7 +340,9 @@
 	configServer, configServiceName, ch := createConfigServer(t)
 	defer configServer.Stop()
 	sh.SetVar(consts.VeyronCredentials, childcreds)
-	sh.SetVar(mgmt.ParentNodeManagerConfigKey, configServiceName)
+	sh.Config.Set(mgmt.ParentNameConfigKey, configServiceName)
+	sh.Config.Set(mgmt.ProtocolConfigKey, "tcp")
+	sh.Config.Set(mgmt.AddressConfigKey, "127.0.0.1:0")
 	h, err := sh.Start("handleDefaults", nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
diff --git a/runtimes/google/rt/mgmt.go b/runtimes/google/rt/mgmt.go
index 8fcee9a..a6cac2a 100644
--- a/runtimes/google/rt/mgmt.go
+++ b/runtimes/google/rt/mgmt.go
@@ -25,35 +25,48 @@
 	server       ipc.Server // Serves AppCycle service.
 }
 
-// parentName returns the object name for the Config service on which we should
-// communicate the object name of the app cycle service.  Currently, this can
-// be configured either via env vars or via the exec config passed from parent.
-func parentName() (name string) {
-	name = os.Getenv(mgmt.ParentNodeManagerConfigKey)
-	if len(name) > 0 {
-		return
+func getListenSpec(handle *exec.ChildHandle) (*ipc.ListenSpec, error) {
+	protocol, err := handle.Config.Get(mgmt.ProtocolConfigKey)
+	if err != nil {
+		return nil, err
 	}
-	handle, _ := exec.GetChildHandle()
-	if handle == nil {
-		return
+	if protocol == "" {
+		return nil, fmt.Errorf("%v is not set", mgmt.ProtocolConfigKey)
 	}
-	name, _ = handle.Config.Get(mgmt.ParentNodeManagerConfigKey)
-	return
+
+	address, err := handle.Config.Get(mgmt.AddressConfigKey)
+	if err != nil {
+		return nil, err
+	}
+	if address == "" {
+		return nil, fmt.Errorf("%v is not set", mgmt.AddressConfigKey)
+	}
+	return &ipc.ListenSpec{Protocol: protocol, Address: address}, nil
 }
 
-func (m *mgmtImpl) initMgmt(rt *vrt, listenSpec ipc.ListenSpec) error {
-	m.rt = rt
-	parentName := parentName()
-	if len(parentName) == 0 {
+func (m *mgmtImpl) initMgmt(rt *vrt) error {
+	// Do not initialize the mgmt runtime if the process has not
+	// been started through the veyron exec library by a node
+	// manager.
+	handle, err := exec.GetChildHandle()
+	if err != nil {
 		return nil
 	}
-	var err error
-	if m.server, err = rt.NewServer(); err != nil {
+	parentName, err := handle.Config.Get(mgmt.ParentNameConfigKey)
+	if err != nil {
+		return nil
+	}
+	listenSpec, err := getListenSpec(handle)
+	if err != nil {
 		return err
 	}
-	// TODO(caprita): We should pick the address to listen on from config.
-	var ep naming.Endpoint
-	if ep, err = m.server.Listen(listenSpec); err != nil {
+	m.rt = rt
+	m.server, err = rt.NewServer()
+	if err != nil {
+		return err
+	}
+	ep, err := m.server.Listen(*listenSpec)
+	if err != nil {
 		return err
 	}
 	if err := m.server.Serve("", appcycle.NewServerAppCycle(m), nil); err != nil {
diff --git a/runtimes/google/rt/mgmt_test.go b/runtimes/google/rt/mgmt_test.go
index 88ba312..002cc2e 100644
--- a/runtimes/google/rt/mgmt_test.go
+++ b/runtimes/google/rt/mgmt_test.go
@@ -291,7 +291,9 @@
 	configServer, configServiceName, ch := createConfigServer(t, r)
 	sh := modules.NewShell(appCmd)
 	sh.SetVar(consts.VeyronCredentials, childcreds)
-	sh.SetVar(mgmt.ParentNodeManagerConfigKey, configServiceName)
+	sh.Config.Set(mgmt.ParentNameConfigKey, configServiceName)
+	sh.Config.Set(mgmt.ProtocolConfigKey, "tcp")
+	sh.Config.Set(mgmt.AddressConfigKey, "127.0.0.1:0")
 	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 1c81f13..8e199b5 100644
--- a/runtimes/google/rt/rt.go
+++ b/runtimes/google/rt/rt.go
@@ -124,10 +124,7 @@
 		return nil, err
 	}
 
-	// TODO(caprita, cnicolaou): how is this to be configured?
-	// Can it ever be anything other than a localhost/loopback address?
-	listenSpec := ipc.ListenSpec{Protocol: "tcp", Address: "127.0.0.1:0"}
-	if err := rt.mgmt.initMgmt(rt, listenSpec); err != nil {
+	if err := rt.mgmt.initMgmt(rt); err != nil {
 		return nil, err
 	}
 
diff --git a/services/mgmt/node/impl/app_invoker.go b/services/mgmt/node/impl/app_invoker.go
index 4de936a..5832b36 100644
--- a/services/mgmt/node/impl/app_invoker.go
+++ b/services/mgmt/node/impl/app_invoker.go
@@ -503,7 +503,9 @@
 	listener := callbackState.listenFor(mgmt.AppCycleManagerConfigKey)
 	defer listener.cleanup()
 	cfg := vexec.NewConfig()
-	cfg.Set(mgmt.ParentNodeManagerConfigKey, listener.name())
+	cfg.Set(mgmt.ParentNameConfigKey, listener.name())
+	cfg.Set(mgmt.ProtocolConfigKey, "tcp")
+	cfg.Set(mgmt.AddressConfigKey, "127.0.0.1:0")
 	handle := vexec.NewParentHandle(cmd, vexec.ConfigOpt{cfg})
 	defer func() {
 		if handle != nil {
diff --git a/services/mgmt/node/impl/callback.go b/services/mgmt/node/impl/callback.go
index 514e183..7865bc6 100644
--- a/services/mgmt/node/impl/callback.go
+++ b/services/mgmt/node/impl/callback.go
@@ -18,7 +18,7 @@
 	switch err {
 	case nil:
 		// Node manager was started by self-update, notify the parent.
-		callbackName, err := handle.Config.Get(mgmt.ParentNodeManagerConfigKey)
+		callbackName, err := handle.Config.Get(mgmt.ParentNameConfigKey)
 		if err != nil {
 			// Node manager was not started by self-update, return silently.
 			return
@@ -29,8 +29,8 @@
 		}
 		ctx, cancel := rt.R().NewContext().WithTimeout(time.Minute)
 		defer cancel()
-		if err := nmClient.Set(ctx, mgmt.ChildNodeManagerConfigKey, name); err != nil {
-			vlog.Fatalf("Set(%v, %v) failed: %v", mgmt.ChildNodeManagerConfigKey, name, err)
+		if err := nmClient.Set(ctx, mgmt.ChildNameConfigKey, name); err != nil {
+			vlog.Fatalf("Set(%v, %v) failed: %v", mgmt.ChildNameConfigKey, name, err)
 		}
 	case exec.ErrNoVersion:
 	default:
diff --git a/services/mgmt/node/impl/node_invoker.go b/services/mgmt/node/impl/node_invoker.go
index 8b07f0d..309d867 100644
--- a/services/mgmt/node/impl/node_invoker.go
+++ b/services/mgmt/node/impl/node_invoker.go
@@ -216,11 +216,13 @@
 
 	// Setup up the child process callback.
 	callbackState := i.callback
-	listener := callbackState.listenFor(mgmt.ChildNodeManagerConfigKey)
+	listener := callbackState.listenFor(mgmt.ChildNameConfigKey)
 	defer listener.cleanup()
 	cfg := vexec.NewConfig()
 
-	cfg.Set(mgmt.ParentNodeManagerConfigKey, listener.name())
+	cfg.Set(mgmt.ParentNameConfigKey, listener.name())
+	cfg.Set(mgmt.ProtocolConfigKey, "tcp")
+	cfg.Set(mgmt.AddressConfigKey, "127.0.0.1:0")
 	handle := vexec.NewParentHandle(cmd, vexec.ConfigOpt{cfg})
 	// Start the child process.
 	if err := handle.Start(); err != nil {