Merge "veyron/services/identity: Remove unused sql_config file."
diff --git a/lib/exec/child.go b/lib/exec/child.go
index 80ebfd2..7158ef7 100644
--- a/lib/exec/child.go
+++ b/lib/exec/child.go
@@ -5,6 +5,7 @@
"errors"
"io"
"os"
+ "strconv"
"sync"
)
@@ -62,7 +63,7 @@
// SetReady writes a 'ready' status to its parent.
func (c *ChildHandle) SetReady() error {
- _, err := c.statusPipe.Write([]byte(readyStatus))
+ _, err := c.statusPipe.Write([]byte(readyStatus + strconv.Itoa(os.Getpid())))
c.statusPipe.Close()
return err
}
diff --git a/lib/exec/parent.go b/lib/exec/parent.go
index 612020f..e4d40db 100644
--- a/lib/exec/parent.go
+++ b/lib/exec/parent.go
@@ -7,6 +7,7 @@
"io"
"os"
"os/exec"
+ "strconv"
"strings"
"sync"
"syscall"
@@ -34,6 +35,7 @@
waitDone bool
waitErr error
waitLock sync.Mutex
+ callbackPid int
}
// ParentHandleOpt is an option for NewParentHandle.
@@ -187,7 +189,12 @@
// waitForStatus has closed the channel, but we may not
// have read the message from it yet.
case st := <-c:
- if st == readyStatus {
+ if strings.HasPrefix(st, readyStatus) {
+ pid, err := strconv.Atoi(st[len(readyStatus):])
+ if err != nil {
+ return err
+ }
+ p.callbackPid = pid
return nil
}
if strings.HasPrefix(st, failedStatus) {
@@ -253,6 +260,12 @@
return 0
}
+// ChildPid returns the pid of a child process as reported by its status
+// callback.
+func (p *ParentHandle) ChildPid() int {
+ return p.callbackPid
+}
+
// Exists returns true if the child process exists and can be signal'ed
func (p *ParentHandle) Exists() bool {
if p.c.Process != nil {
diff --git a/services/mgmt/device/impl/app_service.go b/services/mgmt/device/impl/app_service.go
index 2d40769..383ab09 100644
--- a/services/mgmt/device/impl/app_service.go
+++ b/services/mgmt/device/impl/app_service.go
@@ -411,6 +411,10 @@
if _, err := newVersion(call.Context(), installationDir, envelope, ""); err != nil {
return "", err
}
+ if newOrigin, ok := config[mgmt.AppOriginConfigKey]; ok {
+ delete(config, mgmt.AppOriginConfigKey)
+ applicationVON = newOrigin
+ }
if err := saveOrigin(installationDir, applicationVON); err != nil {
return "", err
}
@@ -838,11 +842,16 @@
vlog.Errorf("WaitForReady(%v) failed: %v", childReadyTimeout, err)
return verror2.Make(ErrOperationFailed, nil)
}
+ pid := handle.ChildPid()
childName, err := listener.waitForValue(childReadyTimeout)
if err != nil {
return verror2.Make(ErrOperationFailed, nil)
}
- info.AppCycleMgrName, info.Pid = childName, handle.Pid()
+
+ // Because suidhelper uses Go's in-built support for setuid forking,
+ // handle.Pid() is the pid of suidhelper, not the pid of the app
+ // so use the pid returned in the app's ready status.
+ info.AppCycleMgrName, info.Pid = childName, pid
if err := saveInstanceInfo(instanceDir, info); err != nil {
return err
}
diff --git a/services/mgmt/device/impl/impl_test.go b/services/mgmt/device/impl/impl_test.go
index d146f15..ac9ec54 100644
--- a/services/mgmt/device/impl/impl_test.go
+++ b/services/mgmt/device/impl/impl_test.go
@@ -30,6 +30,7 @@
"v.io/core/veyron2"
"v.io/core/veyron2/context"
"v.io/core/veyron2/ipc"
+ "v.io/core/veyron2/mgmt"
"v.io/core/veyron2/naming"
"v.io/core/veyron2/security"
"v.io/core/veyron2/services/mgmt/application"
@@ -42,6 +43,7 @@
"v.io/core/veyron2/vlog"
"v.io/core/veyron/lib/expect"
+ "v.io/core/veyron/lib/flags/consts"
"v.io/core/veyron/lib/modules"
"v.io/core/veyron/lib/signals"
"v.io/core/veyron/lib/testutil"
@@ -584,8 +586,17 @@
*envelope = envelopeFromShell(sh, []string{testEnvVarName + "=env-val-envelope"}, appCmd, "google naps", fmt.Sprintf("--%s=flag-val-envelope", testFlagName), "appV1")
// Install the app. The config-specified flag value for testFlagName
- // should override the value specified in the envelope above.
- appID := installApp(t, ctx, device.Config{testFlagName: "flag-val-install"})
+ // should override the value specified in the envelope above, and the
+ // config-specified value for origin should override the value in the
+ // Install rpc argument.
+ mtName, ok := sh.GetVar(consts.NamespaceRootPrefix)
+ if !ok {
+ t.Fatalf("failed to get namespace root var from shell")
+ }
+ // This rooted name should be equivalent to the relative name "ar", but
+ // we want to test that the config override for origin works.
+ rootedAppRepoName := naming.Join(mtName, "ar")
+ appID := installApp(t, ctx, device.Config{testFlagName: "flag-val-install", mgmt.AppOriginConfigKey: rootedAppRepoName})
installationDebug := debug(t, ctx, appID)
// We spot-check a couple pieces of information we expect in the debug
// output.
@@ -593,7 +604,7 @@
// logic that assumes too much about the format? This may be one
// argument in favor of making the output of Debug a struct instead of
// free-form string.
- if !strings.Contains(installationDebug, "Origin: ar") {
+ if !strings.Contains(installationDebug, fmt.Sprintf("Origin: %v", rootedAppRepoName)) {
t.Fatalf("debug response doesn't contain expected info: %v", installationDebug)
}
if !strings.Contains(installationDebug, "Config: map[random_test_flag:flag-val-install]") {
diff --git a/tools/mgmt/device/doc.go b/tools/mgmt/device/doc.go
index b760e71..c8f4780 100644
--- a/tools/mgmt/device/doc.go
+++ b/tools/mgmt/device/doc.go
@@ -75,21 +75,23 @@
Install the given application.
Usage:
- device install <device> <application> [<config override>]
+ device install [flags] <device> <application>
<device> is the veyron object name of the device manager's app service.
<application> is the veyron object name of the application.
-<config override> is an optional JSON-encoded device.Config object, of the form:
- '{"flag1":"value1","flag2":"value2"}'.
+The device install flags are:
+ -config={}
+ JSON-encoded device.Config object, of the form:
+ '{"flag1":"value1","flag2":"value2"}'
Device Install-Local
Install the given application, specified using a local path.
Usage:
- device install-local <device> <title> [ENV=VAL ...] binary [--flag=val ...]
+ device install-local [flags] <device> <title> [ENV=VAL ...] binary [--flag=val ...]
<device> is the veyron object name of the device manager's app service.
@@ -98,6 +100,11 @@
This is followed by an arbitrary number of environment variable settings, the
local path for the binary to install, and arbitrary flag settings.
+The device install-local flags are:
+ -config={}
+ JSON-encoded device.Config object, of the form:
+ '{"flag1":"value1","flag2":"value2"}'
+
Device Start
Start an instance of the given application.
diff --git a/tools/mgmt/device/impl/impl.go b/tools/mgmt/device/impl/impl.go
index 8762b8a..2600b4e 100644
--- a/tools/mgmt/device/impl/impl.go
+++ b/tools/mgmt/device/impl/impl.go
@@ -17,29 +17,43 @@
Name: "install",
Short: "Install the given application.",
Long: "Install the given application.",
- ArgsName: "<device> <application> [<config override>]",
+ ArgsName: "<device> <application>",
ArgsLong: `
<device> is the veyron object name of the device manager's app service.
<application> is the veyron object name of the application.
+`,
+}
-<config override> is an optional JSON-encoded device.Config object, of the form:
- '{"flag1":"value1","flag2":"value2"}'.`,
+type configFlag device.Config
+
+func (c *configFlag) String() string {
+ jsonConfig, _ := json.Marshal(c)
+ return string(jsonConfig)
+}
+func (c *configFlag) Set(s string) error {
+ if err := json.Unmarshal([]byte(s), c); err != nil {
+ return fmt.Errorf("Unmarshal(%v) failed: %v", s, err)
+ }
+ return nil
+}
+
+var configOverride configFlag = configFlag{}
+
+func init() {
+ cmdInstall.Flags.Var(&configOverride, "config", "JSON-encoded device.Config object, of the form: '{\"flag1\":\"value1\",\"flag2\":\"value2\"}'")
}
func runInstall(cmd *cmdline.Command, args []string) error {
- if expectedMin, expectedMax, got := 2, 3, len(args); expectedMin > got || expectedMax < got {
- return cmd.UsageErrorf("install: incorrect number of arguments, expected between %d and %d, got %d", expectedMin, expectedMax, got)
+ if expected, got := 2, len(args); expected != got {
+ return cmd.UsageErrorf("install: incorrect number of arguments, expected %d, got %d", expected, got)
}
deviceName, appName := args[0], args[1]
- var cfg device.Config
- if len(args) > 2 {
- jsonConfig := args[2]
- if err := json.Unmarshal([]byte(jsonConfig), &cfg); err != nil {
- return fmt.Errorf("Unmarshal(%v) failed: %v", jsonConfig, err)
- }
- }
- appID, err := device.ApplicationClient(deviceName).Install(gctx, appName, cfg)
+ appID, err := device.ApplicationClient(deviceName).Install(gctx, appName, device.Config(configOverride))
+ // Reset the value for any future invocations of "install" or
+ // "install-local" (we run more than one command per process in unit
+ // tests).
+ configOverride = configFlag{}
if err != nil {
return fmt.Errorf("Install failed: %v", err)
}
diff --git a/tools/mgmt/device/impl/impl_test.go b/tools/mgmt/device/impl/impl_test.go
index 435d185..09e0a83 100644
--- a/tools/mgmt/device/impl/impl_test.go
+++ b/tools/mgmt/device/impl/impl_test.go
@@ -190,35 +190,35 @@
expectedTape interface{}
}{
{
- []string{"install", "blech"},
+ []string{"blech"},
nil,
true,
nil,
nil,
},
{
- []string{"install", "blech1", "blech2", "blech3", "blech4"},
+ []string{"blech1", "blech2", "blech3", "blech4"},
nil,
true,
nil,
nil,
},
{
- []string{"install", deviceName, appNameNoFetch, "not-valid-json"},
+ []string{deviceName, appNameNoFetch, "not-valid-json"},
nil,
true,
nil,
nil,
},
{
- []string{"install", deviceName, appNameNoFetch},
+ []string{deviceName, appNameNoFetch},
nil,
false,
InstallResponse{appId, nil},
InstallStimulus{"Install", appNameNoFetch, nil, application.Envelope{}, 0},
},
{
- []string{"install", deviceName, appNameNoFetch},
+ []string{deviceName, appNameNoFetch},
cfg,
false,
InstallResponse{appId, nil},
@@ -231,8 +231,9 @@
if err != nil {
t.Fatalf("test case %d: Marshal(%v) failed: %v", i, c.config, err)
}
- c.args = append(c.args, string(jsonConfig))
+ c.args = append([]string{fmt.Sprintf("--config=%s", string(jsonConfig))}, c.args...)
}
+ c.args = append([]string{"install"}, c.args...)
err := cmd.Execute(c.args)
if c.shouldErr {
if err == nil {
diff --git a/tools/mgmt/device/impl/local_install.go b/tools/mgmt/device/impl/local_install.go
index a8b8fb9..1598559 100644
--- a/tools/mgmt/device/impl/local_install.go
+++ b/tools/mgmt/device/impl/local_install.go
@@ -23,9 +23,6 @@
"v.io/lib/cmdline"
)
-// TODO(caprita): Add a way to provide an origin for the app, so we can do
-// updates after it's been installed.
-
var cmdInstallLocal = &cmdline.Command{
Run: runInstallLocal,
Name: "install-local",
@@ -41,6 +38,10 @@
local path for the binary to install, and arbitrary flag settings.`,
}
+func init() {
+ cmdInstallLocal.Flags.Var(&configOverride, "config", "JSON-encoded device.Config object, of the form: '{\"flag1\":\"value1\",\"flag2\":\"value2\"}'")
+}
+
type openAuthorizer struct{}
func (openAuthorizer) Authorize(security.Context) error { return nil }
@@ -226,7 +227,11 @@
objects["application"] = repository.ApplicationServer(envelopeInvoker(envelope))
appName := naming.Join(name, "application")
- appID, err := device.ApplicationClient(deviceName).Install(gctx, appName, nil)
+ appID, err := device.ApplicationClient(deviceName).Install(gctx, appName, device.Config(configOverride))
+ // Reset the value for any future invocations of "install" or
+ // "install-local" (we run more than one command per process in unit
+ // tests).
+ configOverride = configFlag{}
if err != nil {
return fmt.Errorf("Install failed: %v", err)
}
diff --git a/tools/mgmt/device/impl/local_install_test.go b/tools/mgmt/device/impl/local_install_test.go
index 7abb65f..9a65931 100644
--- a/tools/mgmt/device/impl/local_install_test.go
+++ b/tools/mgmt/device/impl/local_install_test.go
@@ -2,6 +2,7 @@
import (
"bytes"
+ "encoding/json"
"fmt"
"os"
"reflect"
@@ -10,6 +11,7 @@
"v.io/core/veyron2/naming"
"v.io/core/veyron2/services/mgmt/application"
+ "v.io/core/veyron2/services/mgmt/device"
"v.io/core/veyron/tools/mgmt/device/impl"
)
@@ -35,18 +37,19 @@
stderrSubstr string
}{
{
- []string{"install-local", deviceName}, "incorrect number of arguments",
+ []string{deviceName}, "incorrect number of arguments",
},
{
- []string{"install-local", deviceName, appTitle}, "missing binary",
+ []string{deviceName, appTitle}, "missing binary",
},
{
- []string{"install-local", deviceName, appTitle, "a=b"}, "missing binary",
+ []string{deviceName, appTitle, "a=b"}, "missing binary",
},
{
- []string{"install-local", deviceName, appTitle, "foo"}, "binary foo not found",
+ []string{deviceName, appTitle, "foo"}, "binary foo not found",
},
} {
+ c.args = append([]string{"install-local"}, c.args...)
if err := cmd.Execute(c.args); err == nil {
t.Fatalf("test case %d: wrongly failed to receive a non-nil error.", i)
} else {
@@ -69,20 +72,37 @@
t.Fatalf("Failed to stat %v: %v", binary, err)
}
binarySize := fi.Size()
+ cfg := device.Config{"someflag": "somevalue"}
for i, c := range []struct {
args []string
+ config device.Config
expectedTape interface{}
}{
{
- []string{"install-local", deviceName, appTitle, binary},
+ []string{deviceName, appTitle, binary},
+ nil,
InstallStimulus{"Install", appNameAfterFetch, nil, application.Envelope{Title: appTitle, Binary: binaryNameAfterFetch}, binarySize},
},
{
- []string{"install-local", deviceName, appTitle, "ENV1=V1", "ENV2=V2", binary, "FLAG1=V1", "FLAG2=V2"},
+ []string{deviceName, appTitle, binary},
+ cfg,
+ InstallStimulus{"Install", appNameAfterFetch, cfg, application.Envelope{Title: appTitle, Binary: binaryNameAfterFetch}, binarySize},
+ },
+ {
+ []string{deviceName, appTitle, "ENV1=V1", "ENV2=V2", binary, "FLAG1=V1", "FLAG2=V2"},
+ nil,
InstallStimulus{"Install", appNameAfterFetch, nil, application.Envelope{Title: appTitle, Binary: binaryNameAfterFetch, Env: []string{"ENV1=V1", "ENV2=V2"}, Args: []string{"FLAG1=V1", "FLAG2=V2"}}, binarySize},
},
} {
tape.SetResponses([]interface{}{InstallResponse{appId, nil}})
+ if c.config != nil {
+ jsonConfig, err := json.Marshal(c.config)
+ if err != nil {
+ t.Fatalf("test case %d: Marshal(%v) failed: %v", i, c.config, err)
+ }
+ c.args = append([]string{fmt.Sprintf("--config=%s", string(jsonConfig))}, c.args...)
+ }
+ c.args = append([]string{"install-local"}, c.args...)
if err := cmd.Execute(c.args); err != nil {
t.Fatalf("test case %d: %v", i, err)
}