14807: Load API host/token directly from stdin without shell hack.
authorTom Clegg <tclegg@veritasgenetics.com>
Fri, 15 Feb 2019 20:26:10 +0000 (15:26 -0500)
committerTom Clegg <tclegg@veritasgenetics.com>
Fri, 15 Feb 2019 21:13:19 +0000 (16:13 -0500)
Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tclegg@veritasgenetics.com>

lib/dispatchcloud/test/stub_driver.go
lib/dispatchcloud/worker/worker.go
services/crunch-run/crunchrun.go

index 917853cf83f8b996a557a9ff1e7afc83f88c5234..d81382a301cf564ef4759eb69f1b0e297aa57006 100644 (file)
@@ -226,13 +226,12 @@ func (svm *StubVM) Exec(env map[string]string, command string, stdin io.Reader,
                fmt.Fprint(stderr, "crunch-run: command not found\n")
                return 1
        }
-       if strings.HasPrefix(command, "source /dev/stdin; crunch-run --detach ") {
-               stdinKV := map[string]string{}
-               for _, line := range strings.Split(string(stdinData), "\n") {
-                       kv := strings.SplitN(strings.TrimPrefix(line, "export "), "=", 2)
-                       if len(kv) == 2 && len(kv[1]) > 0 {
-                               stdinKV[kv[0]] = kv[1]
-                       }
+       if strings.HasPrefix(command, "crunch-run --detach --stdin-env ") {
+               var stdinKV map[string]string
+               err := json.Unmarshal(stdinData, &stdinKV)
+               if err != nil {
+                       fmt.Fprintf(stderr, "unmarshal stdin: %s (stdin was: %q)\n", err, stdinData)
+                       return 1
                }
                for _, name := range []string{"ARVADOS_API_HOST", "ARVADOS_API_TOKEN"} {
                        if stdinKV[name] == "" {
index ab0eac33c4e08e23a4f268da06accebb44361754..7cf4bd72f52bfa33b1bafcd0ae261e8fe0d49bf8 100644 (file)
@@ -6,6 +6,7 @@ package worker
 
 import (
        "bytes"
+       "encoding/json"
        "fmt"
        "strings"
        "sync"
@@ -101,14 +102,22 @@ func (wkr *worker) startContainer(ctr arvados.Container) {
        wkr.starting[ctr.UUID] = struct{}{}
        wkr.state = StateRunning
        go func() {
-               cmd := "crunch-run --detach '" + ctr.UUID + "'"
-               stdin := bytes.NewBufferString(fmt.Sprintf("export %s=%q\nexport %s=%q\n",
-                       "ARVADOS_API_HOST", wkr.wp.arvClient.APIHost,
-                       "ARVADOS_API_TOKEN", wkr.wp.arvClient.AuthToken))
+               env := map[string]string{
+                       "ARVADOS_API_HOST":  wkr.wp.arvClient.APIHost,
+                       "ARVADOS_API_TOKEN": wkr.wp.arvClient.AuthToken,
+               }
+               if wkr.wp.arvClient.Insecure {
+                       env["ARVADOS_API_HOST_INSECURE"] = "1"
+               }
+               envJSON, err := json.Marshal(env)
+               if err != nil {
+                       panic(err)
+               }
+               stdin := bytes.NewBuffer(envJSON)
+               cmd := "crunch-run --detach --stdin-env '" + ctr.UUID + "'"
                if u := wkr.instance.RemoteUser(); u != "root" {
-                       cmd = "sudo -E " + cmd
+                       cmd = "sudo " + cmd
                }
-               cmd = "source /dev/stdin; " + cmd
                stdout, stderr, err := wkr.executor.Execute(nil, cmd, stdin)
                wkr.mtx.Lock()
                defer wkr.mtx.Unlock()
index 2b9a119581dfd7c4f3245b1e57317ae95155f5b9..0576337aa13c280841187db3a7aea2dcf4af65c0 100644 (file)
@@ -1737,6 +1737,7 @@ func main() {
        cgroupParentSubsystem := flag.String("cgroup-parent-subsystem", "", "use current cgroup for given subsystem as parent cgroup for container")
        caCertsPath := flag.String("ca-certs", "", "Path to TLS root certificates")
        detach := flag.Bool("detach", false, "Detach from parent process and run in the background")
+       stdinEnv := flag.Bool("stdin-env", false, "Load environment variables from JSON message on stdin")
        sleep := flag.Duration("sleep", 0, "Delay before starting (testing use only)")
        kill := flag.Int("kill", -1, "Send signal to an existing crunch-run process for given UUID")
        list := flag.Bool("list", false, "List UUIDs of existing crunch-run processes")
@@ -1766,6 +1767,13 @@ func main() {
 
        flag.Parse()
 
+       if *stdinEnv && !ignoreDetachFlag {
+               // Load env vars on stdin if asked (but not in a
+               // detached child process, in which case stdin is
+               // /dev/null).
+               loadEnv(os.Stdin)
+       }
+
        switch {
        case *detach && !ignoreDetachFlag:
                os.Exit(Detach(flag.Arg(0), os.Args, os.Stdout, os.Stderr))
@@ -1856,3 +1864,21 @@ func main() {
                log.Fatalf("%s: %v", containerId, runerr)
        }
 }
+
+func loadEnv(rdr io.Reader) {
+       buf, err := ioutil.ReadAll(rdr)
+       if err != nil {
+               log.Fatalf("read stdin: %s", err)
+       }
+       var env map[string]string
+       err = json.Unmarshal(buf, &env)
+       if err != nil {
+               log.Fatalf("decode stdin: %s", err)
+       }
+       for k, v := range env {
+               err = os.Setenv(k, v)
+               if err != nil {
+                       log.Fatalf("setenv(%q): %s", k, err)
+               }
+       }
+}