veyron/mgmt/lib/exec: move this into veyron/lib/exec and merge veyron/lib/config with it.

Change-Id: I8c5b2d1f1a4a9d3c48b6e76e1fe5e43c93416c0d
diff --git a/services/mgmt/lib/exec/child.go b/services/mgmt/lib/exec/child.go
deleted file mode 100644
index 909c6e9..0000000
--- a/services/mgmt/lib/exec/child.go
+++ /dev/null
@@ -1,119 +0,0 @@
-package exec
-
-import (
-	"encoding/binary"
-	"errors"
-	"io"
-	"os"
-	"sync"
-
-	"veyron.io/veyron/veyron/lib/config"
-)
-
-var (
-	ErrNoVersion          = errors.New(versionVariable + " environment variable missing")
-	ErrUnsupportedVersion = errors.New("Unsupported version of veyron/lib/exec request by " + versionVariable + " environment variable")
-)
-
-type ChildHandle struct {
-	// Config is passed down from the parent.
-	Config config.Config
-	// Secret is a secret passed to the child by its parent via a
-	// trusted channel.
-	Secret string
-	// statusPipe is a pipe that is used to notify the parent that the child
-	// process has started successfully. It is meant to be invoked by the
-	// veyron framework to notify the parent that the child process has
-	// successfully started.
-	statusPipe *os.File
-}
-
-var (
-	childHandle    *ChildHandle
-	childHandleErr error
-	once           sync.Once
-)
-
-// fileOffset accounts for the file descriptors that are always passed
-// to the child by the parent: stderr, stdin, stdout, data read, and
-// status write. Any extra files added by the client will follow
-// fileOffset.
-const fileOffset = 5
-
-// GetChildHandle returns a ChildHandle that can be used to signal
-// that the child is 'ready' (by calling SetReady) to its parent or to
-// retrieve data securely passed to this process by its parent. For
-// instance, a secret intended to create a secure communication
-// channels and or authentication.
-//
-// If the child is relying on exec.Cmd.ExtraFiles then its first file
-// descriptor will not be 3, but will be offset by extra files added
-// by the framework. The developer should use the NewExtraFile method
-// to robustly get their extra files with the correct offset applied.
-func GetChildHandle() (*ChildHandle, error) {
-	once.Do(func() {
-		childHandle, childHandleErr = createChildHandle()
-	})
-	return childHandle, childHandleErr
-}
-
-// SetReady writes a 'ready' status to its parent.
-func (c *ChildHandle) SetReady() error {
-	_, err := c.statusPipe.Write([]byte(readyStatus))
-	c.statusPipe.Close()
-	return err
-}
-
-// NewExtraFile creates a new file handle for the i-th file descriptor after
-// discounting stdout, stderr, stdin and the files reserved by the framework for
-// its own purposes.
-func (c *ChildHandle) NewExtraFile(i uintptr, name string) *os.File {
-	return os.NewFile(i+fileOffset, name)
-}
-
-func createChildHandle() (*ChildHandle, error) {
-	switch os.Getenv(versionVariable) {
-	case "":
-		return nil, ErrNoVersion
-	case version1:
-		// TODO(cnicolaou): need to use major.minor.build format for
-		// version #s.
-	default:
-		return nil, ErrUnsupportedVersion
-	}
-	dataPipe := os.NewFile(3, "data_rd")
-	serializedConfig, err := decodeString(dataPipe)
-	if err != nil {
-		return nil, err
-	}
-	cfg := config.New()
-	if err := cfg.MergeFrom(serializedConfig); err != nil {
-		return nil, err
-	}
-	secret, err := decodeString(dataPipe)
-	if err != nil {
-		return nil, err
-	}
-	childHandle = &ChildHandle{
-		Config:     cfg,
-		Secret:     secret,
-		statusPipe: os.NewFile(4, "status_wr"),
-	}
-	return childHandle, nil
-}
-
-func decodeString(r io.Reader) (string, error) {
-	var l int64 = 0
-	if err := binary.Read(r, binary.BigEndian, &l); err != nil {
-		return "", err
-	}
-	var data []byte = make([]byte, l)
-	if n, err := r.Read(data); err != nil || int64(n) != l {
-		if err != nil {
-			return "", err
-		} else {
-			return "", errors.New("partial read")
-		}
-	}
-	return string(data), nil
-}
diff --git a/services/mgmt/lib/exec/doc.go b/services/mgmt/lib/exec/doc.go
deleted file mode 100644
index 953965a..0000000
--- a/services/mgmt/lib/exec/doc.go
+++ /dev/null
@@ -1,13 +0,0 @@
-// Package exec implements simple process creation and rendezvous, including
-// sharing a secret with, and passing arbitrary configuration to, the newly
-// created process.
-//
-// Once a parent starts a child process it can use WaitForReady to wait
-// for the child to reach its 'Ready' state. Operations are provided to wait
-// for the child to terminate, and to terminate the child cleaning up any state
-// associated with it.
-//
-// A child process uses the GetChildHandle function to complete the initial
-// authentication handshake. The child must call SetReady to indicate that it is
-// fully initialized and ready for whatever purpose it is intended to fulfill.
-package exec
diff --git a/services/mgmt/lib/exec/example_test.go b/services/mgmt/lib/exec/example_test.go
deleted file mode 100644
index c66adcc..0000000
--- a/services/mgmt/lib/exec/example_test.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package exec
-
-import (
-	"log"
-	"os/exec"
-	"time"
-)
-
-func ExampleChildHandle() {
-	ch, _ := GetChildHandle()
-	// Initalize the app/service, access the secret shared with the
-	// child by its parent
-	_ = ch.Secret
-	ch.SetReady()
-	// Do work
-}
-
-func ExampleParentHandle() {
-	cmd := exec.Command("/bin/hostname")
-	ph := NewParentHandle(cmd, SecretOpt("secret"))
-
-	// Start the child process.
-	if err := ph.Start(); err != nil {
-		log.Printf("failed to start child: %s\n", err)
-		return
-	}
-
-	// Wait for the child to become ready.
-	if err := ph.WaitForReady(time.Second); err != nil {
-		log.Printf("failed to start child: %s\n", err)
-		return
-	}
-
-	// Wait for the child to exit giving it an hour to do it's work.
-	if err := ph.Wait(time.Hour); err != nil {
-		log.Printf("wait or child failed %s\n", err)
-	}
-}
diff --git a/services/mgmt/lib/exec/exec_test.go b/services/mgmt/lib/exec/exec_test.go
deleted file mode 100644
index 399f00a..0000000
--- a/services/mgmt/lib/exec/exec_test.go
+++ /dev/null
@@ -1,523 +0,0 @@
-package exec_test
-
-import (
-	"fmt"
-	"io"
-	"log"
-	"os"
-	"os/exec"
-	"sync"
-	"testing"
-	"time"
-
-	"veyron.io/veyron/veyron/lib/config"
-	// Use mock timekeeper to avoid actually sleeping during the test.
-	"veyron.io/veyron/veyron/runtimes/google/testing/timekeeper"
-	vexec "veyron.io/veyron/veyron/services/mgmt/lib/exec"
-)
-
-// We always expect there to be exactly three open file descriptors
-// when the test starts out: STDIN, STDOUT, and STDERR. This
-// assumption is tested in init below, and in the rare cases where it
-// is wrong, we bail out.
-const baselineOpenFiles = 3
-
-func init() {
-	if os.Getenv("GO_WANT_HELPER_PROCESS_EXEC") == "1" {
-		return
-	}
-	if want, got := baselineOpenFiles, openFiles(); want != got {
-		message := `Test expected to start with %d open files, found %d instead.
-This can happen if parent process has any open file descriptors,
-e.g. pipes, that are being inherited.`
-		panic(fmt.Errorf(message, want, got))
-	}
-}
-
-// These tests need to run a subprocess and we reuse this same test
-// binary to do so. A fake test 'TestHelperProcess' contains the code
-// we need to run in the child and we simply run this same binary with
-// a test.run= arg that runs just that test. This idea was taken from
-// the tests for os/exec.
-func helperCommand(s ...string) *exec.Cmd {
-	cs := []string{"-test.run=TestHelperProcess", "--"}
-	cs = append(cs, s...)
-	cmd := exec.Command(os.Args[0], cs...)
-	cmd.Env = append([]string{"GO_WANT_HELPER_PROCESS_EXEC=1"}, os.Environ()...)
-	return cmd
-}
-
-func openFiles() int {
-	f, err := os.Open("/dev/null")
-	if err != nil {
-		panic("Failed to open /dev/null\n")
-	}
-	n := f.Fd()
-	f.Close()
-	return int(n)
-}
-
-func clean(t *testing.T, ph ...*vexec.ParentHandle) {
-	for _, p := range ph {
-		alreadyClean := !p.Exists()
-		p.Clean()
-		if !alreadyClean && p.Exists() {
-			t.Errorf("child process left behind even after calling Clean")
-		}
-	}
-	if want, got := baselineOpenFiles, openFiles(); want != got {
-		t.Errorf("Leaking file descriptors: expect %d, got %d", want, got)
-	}
-}
-
-func read(ch chan bool, r io.Reader, m string) {
-	buf := make([]byte, 4096*4)
-	n, err := r.Read(buf)
-	if err != nil {
-		log.Printf("failed to read message: error %s, expecting '%s'\n",
-			err, m)
-		ch <- false
-		return
-	}
-	g := string(buf[:n])
-	b := g == m
-	if !b {
-		log.Printf("read '%s', not '%s'\n", g, m)
-	}
-	ch <- b
-}
-
-func expectMessage(r io.Reader, m string) bool {
-	ch := make(chan bool, 1)
-	go read(ch, r, m)
-	select {
-	case b := <-ch:
-		return b
-	case <-time.After(5 * time.Second):
-		log.Printf("expectMessage: timeout\n")
-		return false
-	}
-	panic("unreachable")
-}
-
-func TestConfigExchange(t *testing.T) {
-	cmd := helperCommand("testConfig")
-	stderr, _ := cmd.StderrPipe()
-	cfg := config.New()
-	cfg.Set("foo", "bar")
-	ph := vexec.NewParentHandle(cmd, vexec.ConfigOpt{cfg})
-	err := ph.Start()
-	if err != nil {
-		t.Fatalf("testConfig: start: %v", err)
-	}
-	serialized, err := cfg.Serialize()
-	if err != nil {
-		t.Fatalf("testConfig: failed to serialize config: %v", err)
-	}
-	if !expectMessage(stderr, serialized) {
-		t.Errorf("unexpected output from child")
-	} else {
-		if err = cmd.Wait(); err != nil {
-			t.Errorf("testConfig: wait: %v", err)
-		}
-	}
-	clean(t, ph)
-}
-
-func TestSecretExchange(t *testing.T) {
-	cmd := helperCommand("testSecret")
-	stderr, _ := cmd.StderrPipe()
-	ph := vexec.NewParentHandle(cmd, vexec.SecretOpt("dummy_secret"))
-	err := ph.Start()
-	if err != nil {
-		t.Fatalf("testSecretTest: start: %v", err)
-	}
-	if !expectMessage(stderr, "dummy_secret") {
-		t.Errorf("unexpected output from child")
-	} else {
-		if err = cmd.Wait(); err != nil {
-			t.Errorf("testSecretTest: wait: %v", err)
-		}
-	}
-	clean(t, ph)
-}
-
-func TestNoVersion(t *testing.T) {
-	// Make sure that Init correctly tests for the presence of VEXEC_VERSION
-	_, err := vexec.GetChildHandle()
-	if err != vexec.ErrNoVersion {
-		t.Errorf("Should be missing Version")
-	}
-}
-
-func waitForReady(t *testing.T, cmd *exec.Cmd, name string, delay int, ph *vexec.ParentHandle) error {
-	err := ph.Start()
-	if err != nil {
-		t.Fatalf("%s: start: %v", name, err)
-		return err
-	}
-	return ph.WaitForReady(time.Duration(delay) * time.Second)
-}
-
-func readyHelperCmd(t *testing.T, cmd *exec.Cmd, name, result string) *vexec.ParentHandle {
-	stderr, err := cmd.StderrPipe()
-	if err != nil {
-		t.Fatalf("%s: failed to get stderr pipe\n", name)
-	}
-	ph := vexec.NewParentHandle(cmd)
-	if err := waitForReady(t, cmd, name, 4, ph); err != nil {
-		t.Errorf("%s: WaitForReady: %v (%v)", name, err, ph)
-		return nil
-	}
-	if !expectMessage(stderr, result) {
-		t.Errorf("%s: failed to read '%s' from child\n", name, result)
-	}
-	return ph
-}
-
-func readyHelper(t *testing.T, name, test, result string) *vexec.ParentHandle {
-	cmd := helperCommand(test)
-	return readyHelperCmd(t, cmd, name, result)
-}
-
-func testMany(t *testing.T, name, test, result string) []*vexec.ParentHandle {
-	nprocs := 10
-	ph := make([]*vexec.ParentHandle, nprocs)
-	cmd := make([]*exec.Cmd, nprocs)
-	stderr := make([]io.ReadCloser, nprocs)
-	controlReaders := make([]io.ReadCloser, nprocs)
-	var done sync.WaitGroup
-	for i := 0; i < nprocs; i++ {
-		cmd[i] = helperCommand(test)
-		// The control pipe is used to signal the child when to wake up.
-		controlRead, controlWrite, err := os.Pipe()
-		if err != nil {
-			t.Errorf("Failed to create control pipe: %v", err)
-			return nil
-		}
-		controlReaders[i] = controlRead
-		cmd[i].ExtraFiles = append(cmd[i].ExtraFiles, controlRead)
-		stderr[i], _ = cmd[i].StderrPipe()
-		tk := timekeeper.NewManualTime()
-		ph[i] = vexec.NewParentHandle(cmd[i], vexec.TimeKeeperOpt{tk})
-		done.Add(1)
-		go func() {
-			// For simulated slow children, wait until the parent
-			// starts waiting, and then wake up the child.
-			if test == "testReadySlow" {
-				<-tk.Requests()
-				tk.AdvanceTime(3 * time.Second)
-				if _, err = controlWrite.Write([]byte("wake")); err != nil {
-					t.Errorf("Failed to write to control pipe: %v", err)
-				}
-			}
-			controlWrite.Close()
-			done.Done()
-		}()
-		if err := ph[i].Start(); err != nil {
-			t.Errorf("%s: Failed to start child %d: %s\n", name, i, err)
-		}
-	}
-	for i := 0; i < nprocs; i++ {
-		if err := ph[i].WaitForReady(5 * time.Second); err != nil {
-			t.Errorf("%s: Failed to wait for child %d: %s\n", name, i, err)
-		}
-		controlReaders[i].Close()
-	}
-	for i := 0; i < nprocs; i++ {
-		if !expectMessage(stderr[i], result) {
-			t.Errorf("%s: Failed to read message from child %d\n", name, i)
-		}
-	}
-	done.Wait()
-	return ph
-}
-
-func TestToReadyMany(t *testing.T) {
-	clean(t, testMany(t, "TestToReadyMany", "testReady", ".")...)
-}
-
-func TestToReadySlowMany(t *testing.T) {
-	clean(t, testMany(t, "TestToReadySlowMany", "testReadySlow", "..")...)
-}
-
-func TestToReady(t *testing.T) {
-	ph := readyHelper(t, "TestToReady", "testReady", ".")
-	clean(t, ph)
-}
-
-func TestNeverReady(t *testing.T) {
-	name := "testNeverReady"
-	result := "never ready"
-	cmd := helperCommand(name)
-	stderr, _ := cmd.StderrPipe()
-	ph := vexec.NewParentHandle(cmd)
-	err := waitForReady(t, cmd, name, 1, ph)
-	if err != vexec.ErrTimeout {
-		t.Errorf("Failed to get timeout: got %v\n", err)
-	} else {
-		// block waiting for error from child
-		if !expectMessage(stderr, result) {
-			t.Errorf("%s: failed to read '%s' from child\n", name, result)
-		}
-	}
-	clean(t, ph)
-}
-
-func TestTooSlowToReady(t *testing.T) {
-	name := "testTooSlowToReady"
-	result := "write status_wr: broken pipe"
-	cmd := helperCommand(name)
-	// The control pipe is used to signal the child when to wake up.
-	controlRead, controlWrite, err := os.Pipe()
-	if err != nil {
-		t.Errorf("Failed to create control pipe: %v", err)
-		return
-	}
-	cmd.ExtraFiles = append(cmd.ExtraFiles, controlRead)
-	stderr, _ := cmd.StderrPipe()
-	tk := timekeeper.NewManualTime()
-	ph := vexec.NewParentHandle(cmd, vexec.TimeKeeperOpt{tk})
-	defer clean(t, ph)
-	defer controlWrite.Close()
-	defer controlRead.Close()
-	// Wait for the parent to start waiting, then simulate a timeout.
-	go func() {
-		toWait := <-tk.Requests()
-		tk.AdvanceTime(toWait)
-	}()
-	err = waitForReady(t, cmd, name, 1, ph)
-	if err != vexec.ErrTimeout {
-		t.Errorf("Failed to get timeout: got %v\n", err)
-	} else {
-		// After the parent timed out, wake up the child and let it
-		// proceed.
-		if _, err = controlWrite.Write([]byte("wake")); err != nil {
-			t.Errorf("Failed to write to control pipe: %v", err)
-		} else {
-			// block waiting for error from child
-			if !expectMessage(stderr, result) {
-				t.Errorf("%s: failed to read '%s' from child\n", name, result)
-			}
-		}
-	}
-}
-
-func TestToReadySlow(t *testing.T) {
-	name := "TestToReadySlow"
-	cmd := helperCommand("testReadySlow")
-	// The control pipe is used to signal the child when to wake up.
-	controlRead, controlWrite, err := os.Pipe()
-	if err != nil {
-		t.Errorf("Failed to create control pipe: %v", err)
-		return
-	}
-	cmd.ExtraFiles = append(cmd.ExtraFiles, controlRead)
-	stderr, err := cmd.StderrPipe()
-	if err != nil {
-		t.Fatalf("%s: failed to get stderr pipe", name)
-	}
-	tk := timekeeper.NewManualTime()
-	ph := vexec.NewParentHandle(cmd, vexec.TimeKeeperOpt{tk})
-	defer clean(t, ph)
-	defer controlWrite.Close()
-	defer controlRead.Close()
-	// Wait for the parent to start waiting, simulate a short wait (but not
-	// enough to timeout the parent), then wake up the child.
-	go func() {
-		<-tk.Requests()
-		tk.AdvanceTime(2 * time.Second)
-		if _, err = controlWrite.Write([]byte("wake")); err != nil {
-			t.Errorf("Failed to write to control pipe: %v", err)
-		}
-	}()
-	if err := waitForReady(t, cmd, name, 4, ph); err != nil {
-		t.Errorf("%s: WaitForReady: %v (%v)", name, err, ph)
-		return
-	}
-	// After the child has replied, simulate a timeout on the server by
-	// advacing the time more; at this point, however, the timeout should no
-	// longer occur since the child already replied.
-	tk.AdvanceTime(2 * time.Second)
-	if result := ".."; !expectMessage(stderr, result) {
-		t.Errorf("%s: failed to read '%s' from child\n", name, result)
-	}
-}
-
-func TestToCompletion(t *testing.T) {
-	ph := readyHelper(t, "TestToCompletion", "testSuccess", "...ok")
-	e := ph.Wait(time.Second)
-	if e != nil {
-		t.Errorf("Wait failed: err %s\n", e)
-	}
-	clean(t, ph)
-}
-
-func TestToCompletionError(t *testing.T) {
-	ph := readyHelper(t, "TestToCompletionError", "testError", "...err")
-	e := ph.Wait(time.Second)
-	if e == nil {
-		t.Errorf("Wait failed: err %s\n", e)
-	}
-	clean(t, ph)
-}
-
-func TestExtraFiles(t *testing.T) {
-	cmd := helperCommand("testExtraFiles")
-	rd, wr, err := os.Pipe()
-	if err != nil {
-		t.Fatalf("Failed to create pipe: %s\n", err)
-	}
-	cmd.ExtraFiles = append(cmd.ExtraFiles, rd)
-	msg := "hello there..."
-	fmt.Fprintf(wr, msg)
-	ph := readyHelperCmd(t, cmd, "TestExtraFiles", "child: "+msg)
-	if ph == nil {
-		t.Fatalf("Failed to get vexec.ParentHandle\n")
-	}
-	e := ph.Wait(1 * time.Second)
-	if e != nil {
-		t.Errorf("Wait failed: err %s\n", e)
-	}
-	rd.Close()
-	wr.Close()
-	clean(t, ph)
-}
-
-// TestHelperProcess isn't a real test; it's used as a helper process
-// for the other tests.
-func TestHelperProcess(*testing.T) {
-	// Return immediately if this is not run as the child helper
-	// for the other tests.
-	if os.Getenv("GO_WANT_HELPER_PROCESS_EXEC") != "1" {
-		return
-	}
-	defer os.Exit(0)
-
-	// Write errors to stderr or using log. since the parent
-	// process is reading stderr.
-	args := os.Args
-	for len(args) > 0 {
-		if args[0] == "--" {
-			args = args[1:]
-			break
-		}
-		args = args[1:]
-	}
-
-	if len(args) == 0 {
-		log.Fatal(os.Stderr, "No command\n")
-	}
-
-	cmd, args := args[0], args[1:]
-
-	switch cmd {
-	case "testNeverReady":
-		_, err := vexec.GetChildHandle()
-		if err != nil {
-			log.Fatal(os.Stderr, "%s\n", err)
-		}
-		fmt.Fprintf(os.Stderr, "never ready")
-	case "testTooSlowToReady":
-		ch, err := vexec.GetChildHandle()
-		if err != nil {
-			log.Fatal(os.Stderr, "%s\n", err)
-		}
-		// Wait for the parent to tell us when it's ok to proceed.
-		controlPipe := ch.NewExtraFile(0, "control_rd")
-		for {
-			buf := make([]byte, 100)
-			n, err := controlPipe.Read(buf)
-			if err != nil {
-				log.Fatal(os.Stderr, "%s", err)
-			}
-			if n > 0 {
-				break
-			}
-		}
-		// SetReady should return an error since the parent has
-		// timed out on us and we'd be writing to a closed pipe.
-		if err := ch.SetReady(); err != nil {
-			fmt.Fprintf(os.Stderr, "%s", err)
-		} else {
-			fmt.Fprintf(os.Stderr, "didn't get the expected error")
-		}
-		os.Exit(0)
-	case "testReady":
-		ch, err := vexec.GetChildHandle()
-		if err != nil {
-			log.Fatal(os.Stderr, "%s", err)
-		}
-		ch.SetReady()
-		fmt.Fprintf(os.Stderr, ".")
-	case "testReadySlow":
-		ch, err := vexec.GetChildHandle()
-		if err != nil {
-			log.Fatal(os.Stderr, "%s", err)
-		}
-		// Wait for the parent to tell us when it's ok to proceed.
-		controlPipe := ch.NewExtraFile(0, "control_rd")
-		for {
-			buf := make([]byte, 100)
-			n, err := controlPipe.Read(buf)
-			if err != nil {
-				log.Fatal(os.Stderr, "%s", err)
-			}
-			if n > 0 {
-				break
-			}
-		}
-		ch.SetReady()
-		fmt.Fprintf(os.Stderr, "..")
-	case "testSuccess", "testError":
-		ch, err := vexec.GetChildHandle()
-		if err != nil {
-			log.Fatal(os.Stderr, "%s\n", err)
-		}
-		ch.SetReady()
-		rc := make(chan int)
-		go func() {
-			if cmd == "testError" {
-				fmt.Fprintf(os.Stderr, "...err")
-				rc <- 1
-			} else {
-				fmt.Fprintf(os.Stderr, "...ok")
-				rc <- 0
-			}
-		}()
-		r := <-rc
-		os.Exit(r)
-	case "testConfig":
-		ch, err := vexec.GetChildHandle()
-		if err != nil {
-			log.Fatalf("%v", err)
-		} else {
-			serialized, err := ch.Config.Serialize()
-			if err != nil {
-				log.Fatalf("%v", err)
-			}
-			fmt.Fprintf(os.Stderr, "%s", serialized)
-		}
-	case "testSecret":
-		ch, err := vexec.GetChildHandle()
-		if err != nil {
-			log.Fatalf("%s", err)
-		} else {
-			fmt.Fprintf(os.Stderr, "%s", ch.Secret)
-		}
-	case "testExtraFiles":
-		ch, err := vexec.GetChildHandle()
-		if err != nil {
-			log.Fatal("error.... %s\n", err)
-		}
-		err = ch.SetReady()
-		rd := ch.NewExtraFile(0, "read")
-		buf := make([]byte, 1024)
-		if n, err := rd.Read(buf); err != nil {
-			fmt.Fprintf(os.Stderr, "child: error %s\n", err)
-		} else {
-			fmt.Fprintf(os.Stderr, "child: %s", string(buf[:n]))
-		}
-		os.Exit(0)
-	}
-}
diff --git a/services/mgmt/lib/exec/parent.go b/services/mgmt/lib/exec/parent.go
deleted file mode 100644
index 91a6147..0000000
--- a/services/mgmt/lib/exec/parent.go
+++ /dev/null
@@ -1,250 +0,0 @@
-package exec
-
-import (
-	"encoding/binary"
-	"errors"
-	"io"
-	"os"
-	"os/exec"
-	"syscall"
-	"time"
-
-	"veyron.io/veyron/veyron/lib/config"
-	// TODO(cnicolaou): move timekeeper out of runtimes
-	"veyron.io/veyron/veyron/runtimes/google/lib/timekeeper"
-
-	"veyron.io/veyron/veyron2/vlog"
-)
-
-var (
-	ErrAuthTimeout    = errors.New("timout in auth handshake")
-	ErrTimeout        = errors.New("timeout waiting for child")
-	ErrSecretTooLarge = errors.New("secret is too large")
-)
-
-// A ParentHandle is the Parent process' means of managing a single child.
-type ParentHandle struct {
-	c           *exec.Cmd
-	config      config.Config
-	secret      string
-	statusRead  *os.File
-	statusWrite *os.File
-	tk          timekeeper.TimeKeeper
-}
-
-// ParentHandleOpt is an option for NewParentHandle.
-type ParentHandleOpt interface {
-	// ExecParentHandleOpt is a signature 'dummy' method for the
-	// interface.
-	ExecParentHandleOpt()
-}
-
-// ConfigOpt can be used to seed the parent handle with a
-// config to be passed to the child.
-type ConfigOpt struct {
-	config.Config
-}
-
-// ExecParentHandleOpt makes ConfigOpt an instance of
-// ParentHandleOpt.
-func (ConfigOpt) ExecParentHandleOpt() {}
-
-// SecretOpt can be used to seed the parent handle with a custom secret.
-type SecretOpt string
-
-// ExecParentHandleOpt makes SecretOpt an instance of ParentHandleOpt.
-func (SecretOpt) ExecParentHandleOpt() {}
-
-// TimeKeeperOpt can be used to seed the parent handle with a custom timekeeper.
-type TimeKeeperOpt struct {
-	timekeeper.TimeKeeper
-}
-
-// ExecParentHandleOpt makes TimeKeeperOpt an instance of ParentHandleOpt.
-func (TimeKeeperOpt) ExecParentHandleOpt() {}
-
-// NewParentHandle creates a ParentHandle for the child process represented by
-// an instance of exec.Cmd.
-func NewParentHandle(c *exec.Cmd, opts ...ParentHandleOpt) *ParentHandle {
-	c.Env = append(c.Env, versionVariable+"="+version1)
-	cfg, secret := config.New(), ""
-	tk := timekeeper.RealTime()
-	for _, opt := range opts {
-		switch v := opt.(type) {
-		case ConfigOpt:
-			cfg = v
-		case SecretOpt:
-			secret = string(v)
-		case TimeKeeperOpt:
-			tk = v
-		default:
-			vlog.Errorf("Unrecognized parent option: %v", v)
-		}
-	}
-	return &ParentHandle{
-		c:      c,
-		config: cfg,
-		secret: secret,
-		tk:     tk,
-	}
-}
-
-// 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 {
-	// Create anonymous pipe for communicating data between the child
-	// and the parent.
-	dataRead, dataWrite, err := os.Pipe()
-	if err != nil {
-		return err
-	}
-	defer dataRead.Close()
-	defer dataWrite.Close()
-	statusRead, statusWrite, err := os.Pipe()
-	if err != nil {
-		return err
-	}
-	p.statusRead = statusRead
-	p.statusWrite = statusWrite
-	// Add the parent-child pipes to cmd.ExtraFiles, offsetting all
-	// existing file descriptors accordingly.
-	extraFiles := make([]*os.File, len(p.c.ExtraFiles)+2)
-	extraFiles[0] = dataRead
-	extraFiles[1] = statusWrite
-	for i, _ := range p.c.ExtraFiles {
-		extraFiles[i+2] = p.c.ExtraFiles[i]
-	}
-	p.c.ExtraFiles = extraFiles
-	// Start the child process.
-	if err := p.c.Start(); err != nil {
-		p.statusWrite.Close()
-		p.statusRead.Close()
-		return err
-	}
-	// Pass data to the child using a pipe.
-	serializedConfig, err := p.config.Serialize()
-	if err != nil {
-		return err
-	}
-	if err := encodeString(dataWrite, serializedConfig); err != nil {
-		p.statusWrite.Close()
-		p.statusRead.Close()
-		return err
-	}
-	if err := encodeString(dataWrite, p.secret); err != nil {
-		p.statusWrite.Close()
-		p.statusRead.Close()
-		return err
-	}
-	return nil
-}
-
-func waitForStatus(c chan string, e chan error, r *os.File) {
-	buf := make([]byte, 100)
-	n, err := r.Read(buf)
-	if err != nil {
-		e <- err
-	} else {
-		c <- string(buf[:n])
-	}
-	r.Close()
-	close(c)
-	close(e)
-}
-
-// WaitForReady will wait for the child process to become ready.
-func (p *ParentHandle) WaitForReady(timeout time.Duration) error {
-	defer p.statusWrite.Close()
-	c := make(chan string, 1)
-	e := make(chan error, 1)
-	go waitForStatus(c, e, p.statusRead)
-	for {
-		select {
-		case err := <-e:
-			return err
-		case st := <-c:
-			if st == readyStatus {
-				return nil
-			}
-		case <-p.tk.After(timeout):
-			// Make sure that the read in waitForStatus
-			// returns now.
-			p.statusWrite.Write([]byte("quit"))
-			return ErrTimeout
-		}
-	}
-	panic("unreachable")
-}
-
-// Wait will wait for the child process to terminate of its own accord.
-// It returns nil if the process exited cleanly with an exit status of 0,
-// any other exit code or error will result in an appropriate error return
-func (p *ParentHandle) Wait(timeout time.Duration) error {
-	c := make(chan error, 1)
-	go func() {
-		c <- p.c.Wait()
-		close(c)
-	}()
-	// If timeout is zero time.After will panic; we handle zero specially
-	// to mean infinite timeout.
-	if timeout > 0 {
-		select {
-		case <-p.tk.After(timeout):
-			return ErrTimeout
-		case err := <-c:
-			return err
-		}
-	} else {
-		return <-c
-	}
-	panic("unreachable")
-}
-
-// Pid returns the pid of the child, 0 if the child process doesn't exist
-func (p *ParentHandle) Pid() int {
-	if p.c.Process != nil {
-		return p.c.Process.Pid
-	}
-	return 0
-}
-
-// Exists returns true if the child process exists and can be signal'ed
-func (p *ParentHandle) Exists() bool {
-	if p.c.Process != nil {
-		return syscall.Kill(p.c.Process.Pid, 0) == nil
-	}
-	return false
-}
-
-// Kill kills the child process.
-func (p *ParentHandle) Kill() error {
-	return p.c.Process.Kill()
-}
-
-// Signal sends the given signal to the child process.
-func (p *ParentHandle) Signal(sig syscall.Signal) error {
-	return syscall.Kill(p.c.Process.Pid, sig)
-}
-
-// Clean will clean up state, including killing the child process.
-func (p *ParentHandle) Clean() error {
-	if err := p.Kill(); err != nil {
-		return err
-	}
-	return p.c.Wait()
-}
-
-func encodeString(w io.Writer, data string) error {
-	l := len(data)
-	if err := binary.Write(w, binary.BigEndian, int64(l)); err != nil {
-		return err
-	}
-	if n, err := w.Write([]byte(data)); err != nil || n != l {
-		if err != nil {
-			return err
-		} else {
-			return errors.New("partial write")
-		}
-	}
-	return nil
-}
diff --git a/services/mgmt/lib/exec/shared.go b/services/mgmt/lib/exec/shared.go
deleted file mode 100644
index 936d2bf..0000000
--- a/services/mgmt/lib/exec/shared.go
+++ /dev/null
@@ -1,8 +0,0 @@
-package exec
-
-const (
-	version1        = "1.0.0"
-	readyStatus     = "ready"
-	initStatus      = "init"
-	versionVariable = "VEYRON_EXEC_VERSION"
-)
diff --git a/services/mgmt/lib/exec/util.go b/services/mgmt/lib/exec/util.go
deleted file mode 100644
index 8ecbeb2..0000000
--- a/services/mgmt/lib/exec/util.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package exec
-
-import (
-	"errors"
-	"strings"
-)
-
-// Getenv retrieves the value of the given variable from the given
-// slice of environment variable assignments.
-func Getenv(env []string, name string) (string, error) {
-	for _, v := range env {
-		if strings.HasPrefix(v, name+"=") {
-			return strings.TrimPrefix(v, name+"="), nil
-		}
-	}
-	return "", errors.New("not found")
-}
-
-// Setenv updates / adds the value assignment for the given variable
-// in the given slice of environment variable assigments.
-func Setenv(env []string, name, value string) []string {
-	newValue := name + "=" + value
-	for i, v := range env {
-		if strings.HasPrefix(v, name+"=") {
-			env[i] = newValue
-			return env
-		}
-	}
-	return append(env, newValue)
-}
diff --git a/services/mgmt/lib/exec/util_test.go b/services/mgmt/lib/exec/util_test.go
deleted file mode 100644
index a247524..0000000
--- a/services/mgmt/lib/exec/util_test.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package exec
-
-import (
-	"testing"
-)
-
-func TestEnv(t *testing.T) {
-	env := make([]string, 0)
-	env = Setenv(env, "NAME", "VALUE1")
-	if expected, got := 1, len(env); expected != got {
-		t.Fatalf("Unexpected length of environment variable slice: expected %d, got %d", expected, got)
-	}
-	if expected, got := "NAME=VALUE1", env[0]; expected != got {
-		t.Fatalf("Unexpected element in the environment variable slice: expected %d, got %d", expected, got)
-	}
-	env = Setenv(env, "NAME", "VALUE2")
-	if expected, got := 1, len(env); expected != got {
-		t.Fatalf("Unexpected length of environment variable slice: expected %d, got %d", expected, got)
-	}
-	if expected, got := "NAME=VALUE2", env[0]; expected != got {
-		t.Fatalf("Unexpected element in the environment variable slice: expected %d, got %d", expected, got)
-	}
-	value, err := Getenv(env, "NAME")
-	if err != nil {
-		t.Fatalf("Unexpected error when looking up environment variable value: %v", err)
-	}
-	if expected, got := "VALUE2", value; expected != got {
-		t.Fatalf("Unexpected value of an environment variable: expected %d, got %d", expected, got)
-	}
-	value, err = Getenv(env, "NONAME")
-	if err == nil {
-		t.Fatalf("Expected error when looking up environment variable value, got none", value)
-	}
-}
diff --git a/services/mgmt/node/impl/app_invoker.go b/services/mgmt/node/impl/app_invoker.go
index ddf2701..b7e3a9a 100644
--- a/services/mgmt/node/impl/app_invoker.go
+++ b/services/mgmt/node/impl/app_invoker.go
@@ -96,10 +96,6 @@
 	"strings"
 	"time"
 
-	"veyron.io/veyron/veyron/lib/config"
-	vexec "veyron.io/veyron/veyron/services/mgmt/lib/exec"
-	iconfig "veyron.io/veyron/veyron/services/mgmt/node/config"
-
 	"veyron.io/veyron/veyron2/context"
 	"veyron.io/veyron/veyron2/ipc"
 	"veyron.io/veyron/veyron2/mgmt"
@@ -108,6 +104,9 @@
 	"veyron.io/veyron/veyron2/services/mgmt/appcycle"
 	"veyron.io/veyron/veyron2/services/mgmt/application"
 	"veyron.io/veyron/veyron2/vlog"
+
+	vexec "veyron.io/veyron/veyron/lib/exec"
+	iconfig "veyron.io/veyron/veyron/services/mgmt/node/config"
 )
 
 // instanceInfo holds state about a running instance.
@@ -470,7 +469,7 @@
 	callbackState := i.callback
 	listener := callbackState.listenFor(mgmt.AppCycleManagerConfigKey)
 	defer listener.cleanup()
-	cfg := config.New()
+	cfg := vexec.NewConfig()
 	cfg.Set(mgmt.ParentNodeManagerConfigKey, listener.name())
 	handle := vexec.NewParentHandle(cmd, vexec.ConfigOpt{cfg})
 	defer func() {
diff --git a/services/mgmt/node/impl/callback.go b/services/mgmt/node/impl/callback.go
index 92ddf6f..46dbc21 100644
--- a/services/mgmt/node/impl/callback.go
+++ b/services/mgmt/node/impl/callback.go
@@ -3,12 +3,12 @@
 import (
 	"time"
 
-	"veyron.io/veyron/veyron/services/mgmt/lib/exec"
-	"veyron.io/veyron/veyron/services/mgmt/node"
-
 	"veyron.io/veyron/veyron2/mgmt"
 	"veyron.io/veyron/veyron2/rt"
 	"veyron.io/veyron/veyron2/vlog"
+
+	"veyron.io/veyron/veyron/lib/exec"
+	"veyron.io/veyron/veyron/services/mgmt/node"
 )
 
 // InvokeCallback provides the parent node manager with the given name (which is
diff --git a/services/mgmt/node/impl/impl_test.go b/services/mgmt/node/impl/impl_test.go
index 139c5bd..879a34a 100644
--- a/services/mgmt/node/impl/impl_test.go
+++ b/services/mgmt/node/impl/impl_test.go
@@ -16,11 +16,11 @@
 	"testing"
 	"time"
 
+	"veyron.io/veyron/veyron/lib/exec"
 	"veyron.io/veyron/veyron/lib/signals"
 	"veyron.io/veyron/veyron/lib/testutil/blackbox"
 	tsecurity "veyron.io/veyron/veyron/lib/testutil/security"
 	vsecurity "veyron.io/veyron/veyron/security"
-	"veyron.io/veyron/veyron/services/mgmt/lib/exec"
 	"veyron.io/veyron/veyron/services/mgmt/node/config"
 	"veyron.io/veyron/veyron/services/mgmt/node/impl"
 	suidhelper "veyron.io/veyron/veyron/services/mgmt/suidhelper/impl"
diff --git a/services/mgmt/node/impl/node_invoker.go b/services/mgmt/node/impl/node_invoker.go
index 965c34c..9db7b75 100644
--- a/services/mgmt/node/impl/node_invoker.go
+++ b/services/mgmt/node/impl/node_invoker.go
@@ -34,11 +34,6 @@
 	"sync"
 	"time"
 
-	"veyron.io/veyron/veyron/lib/config"
-	vexec "veyron.io/veyron/veyron/services/mgmt/lib/exec"
-	iconfig "veyron.io/veyron/veyron/services/mgmt/node/config"
-	"veyron.io/veyron/veyron/services/mgmt/profile"
-
 	"veyron.io/veyron/veyron2/context"
 	"veyron.io/veyron/veyron2/ipc"
 	"veyron.io/veyron/veyron2/mgmt"
@@ -49,6 +44,10 @@
 	"veyron.io/veyron/veyron2/services/mgmt/binary"
 	"veyron.io/veyron/veyron2/services/mgmt/node"
 	"veyron.io/veyron/veyron2/vlog"
+
+	vexec "veyron.io/veyron/veyron/lib/exec"
+	iconfig "veyron.io/veyron/veyron/services/mgmt/node/config"
+	"veyron.io/veyron/veyron/services/mgmt/profile"
 )
 
 type updatingState struct {
@@ -167,7 +166,7 @@
 	callbackState := i.callback
 	listener := callbackState.listenFor(mgmt.ChildNodeManagerConfigKey)
 	defer listener.cleanup()
-	cfg := config.New()
+	cfg := vexec.NewConfig()
 	cfg.Set(mgmt.ParentNodeManagerConfigKey, listener.name())
 	handle := vexec.NewParentHandle(cmd, vexec.ConfigOpt{cfg})
 	// Start the child process.
diff --git a/services/mgmt/node/impl/util_test.go b/services/mgmt/node/impl/util_test.go
index 6d7e0f2..c107d42 100644
--- a/services/mgmt/node/impl/util_test.go
+++ b/services/mgmt/node/impl/util_test.go
@@ -13,10 +13,10 @@
 	"veyron.io/veyron/veyron2/verror"
 	"veyron.io/veyron/veyron2/vlog"
 
+	"veyron.io/veyron/veyron/lib/exec"
 	"veyron.io/veyron/veyron/lib/testutil/blackbox"
 	"veyron.io/veyron/veyron/lib/testutil/security"
 	"veyron.io/veyron/veyron/profiles"
-	"veyron.io/veyron/veyron/services/mgmt/lib/exec"
 	mtlib "veyron.io/veyron/veyron/services/mounttable/lib"
 )