15759: Move crunch-run into arvados-server cmd.
authorTom Clegg <tom@tomclegg.ca>
Wed, 18 Dec 2019 16:55:32 +0000 (11:55 -0500)
committerTom Clegg <tom@tomclegg.ca>
Wed, 18 Dec 2019 16:55:32 +0000 (11:55 -0500)
Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom@tomclegg.ca>

15 files changed:
build/run-build-packages.sh
build/run-tests.sh
cmd/arvados-server/cmd.go
lib/cmd/cmd.go
lib/crunchrun/background.go [moved from services/crunch-run/background.go with 82% similarity]
lib/crunchrun/cgroup.go [moved from services/crunch-run/cgroup.go with 97% similarity]
lib/crunchrun/cgroup_test.go [moved from services/crunch-run/cgroup_test.go with 95% similarity]
lib/crunchrun/copier.go [moved from services/crunch-run/copier.go with 99% similarity]
lib/crunchrun/copier_test.go [moved from services/crunch-run/copier_test.go with 99% similarity]
lib/crunchrun/crunchrun.go [moved from services/crunch-run/crunchrun.go with 95% similarity]
lib/crunchrun/crunchrun_test.go [moved from services/crunch-run/crunchrun_test.go with 99% similarity]
lib/crunchrun/git_mount.go [moved from services/crunch-run/git_mount.go with 99% similarity]
lib/crunchrun/git_mount_test.go [moved from services/crunch-run/git_mount_test.go with 99% similarity]
lib/crunchrun/logging.go [moved from services/crunch-run/logging.go with 99% similarity]
lib/crunchrun/logging_test.go [moved from services/crunch-run/logging_test.go with 99% similarity]

index d6c8f5ac64ca13431560c56fe5f3d95962d90fb9..3173aa7057eed439e7827aec3f70cc384226f869 100755 (executable)
@@ -294,7 +294,7 @@ package_go_binary services/crunch-dispatch-local crunch-dispatch-local \
     "Dispatch Crunch containers on the local system"
 package_go_binary services/crunch-dispatch-slurm crunch-dispatch-slurm \
     "Dispatch Crunch containers to a SLURM cluster"
-package_go_binary services/crunch-run crunch-run \
+package_go_binary cmd/arvados-server crunch-run \
     "Supervise a single Crunch container"
 package_go_binary services/crunchstat crunchstat \
     "Gather cpu/memory/network statistics of running Crunch jobs"
index 02a6a4044ed9ffb42e163151a576c07c3ac58287..f21861762db80b40535c6d0522a379b12dadca1b 100755 (executable)
@@ -81,6 +81,7 @@ lib/controller/railsproxy
 lib/controller/router
 lib/controller/rpc
 lib/crunchstat
+lib/crunch-run
 lib/cloud
 lib/cloud/azure
 lib/cloud/cloudtest
@@ -104,7 +105,6 @@ services/keep-balance
 services/login-sync
 services/nodemanager
 services/nodemanager_integration
-services/crunch-run
 services/crunch-dispatch-local
 services/crunch-dispatch-slurm
 services/ws
index fe6689862971b22873f013c989c2c9924492370b..d93a8e78fd3f216788584872a7d1bd3f3fd675d2 100644 (file)
@@ -11,6 +11,7 @@ import (
        "git.arvados.org/arvados.git/lib/cmd"
        "git.arvados.org/arvados.git/lib/config"
        "git.arvados.org/arvados.git/lib/controller"
+       "git.arvados.org/arvados.git/lib/crunchrun"
        "git.arvados.org/arvados.git/lib/dispatchcloud"
 )
 
@@ -25,6 +26,7 @@ var (
                "config-dump":     config.DumpCommand,
                "config-defaults": config.DumpDefaultsCommand,
                "controller":      controller.Command,
+               "crunch-run":      crunchrun.Command,
                "dispatch-cloud":  dispatchcloud.Command,
        })
 )
index 24b69f0cc5c529fe45b5be6f4ae6698cff607ff9..51bcf55c76040e1f8c3a1320fcf7ab50db2090c6 100644 (file)
@@ -37,6 +37,10 @@ var version = "dev"
 
 type versionCommand struct{}
 
+func (versionCommand) String() string {
+       return fmt.Sprintf("%s (%s)", version, runtime.Version())
+}
+
 func (versionCommand) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
        prog = regexp.MustCompile(` -*version$`).ReplaceAllLiteralString(prog, "")
        fmt.Fprintf(stdout, "%s %s (%s)\n", prog, version, runtime.Version())
@@ -61,9 +65,16 @@ type Multi map[string]Handler
 
 func (m Multi) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
        _, basename := filepath.Split(prog)
-       basename = strings.TrimPrefix(basename, "arvados-")
-       basename = strings.TrimPrefix(basename, "crunch-")
-       if cmd, ok := m[basename]; ok {
+       cmd, ok := m[basename]
+       if !ok {
+               // "controller" command exists, and binary is named "arvados-controller"
+               cmd, ok = m[strings.TrimPrefix(basename, "arvados-")]
+       }
+       if !ok {
+               // "dispatch-slurm" command exists, and binary is named "crunch-dispatch-slurm"
+               cmd, ok = m[strings.TrimPrefix(basename, "crunch-")]
+       }
+       if ok {
                return cmd.RunCommand(prog, args, stdin, stdout, stderr)
        } else if len(args) < 1 {
                fmt.Fprintf(stderr, "usage: %s command [args]\n", prog)
similarity index 82%
rename from services/crunch-run/background.go
rename to lib/crunchrun/background.go
index 852ccb6ece3979385423f3ceb55fb437f164c6aa..bf039afa0ad53799183607fe9795b5556f615bad 100644 (file)
@@ -2,7 +2,7 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-package main
+package crunchrun
 
 import (
        "encoding/json"
@@ -36,10 +36,10 @@ type procinfo struct {
 //
 // Stdout and stderr in the child process are sent to the systemd
 // journal using the systemd-cat program.
-func Detach(uuid string, args []string, stdout, stderr io.Writer) int {
-       return exitcode(stderr, detach(uuid, args, stdout, stderr))
+func Detach(uuid string, prog string, args []string, stdout, stderr io.Writer) int {
+       return exitcode(stderr, detach(uuid, prog, args, stdout, stderr))
 }
-func detach(uuid string, args []string, stdout, stderr io.Writer) error {
+func detach(uuid string, prog string, args []string, stdout, stderr io.Writer) error {
        lockfile, err := func() (*os.File, error) {
                // We must hold the dir-level lock between
                // opening/creating the lockfile and acquiring LOCK_EX
@@ -68,7 +68,31 @@ func detach(uuid string, args []string, stdout, stderr io.Writer) error {
        defer lockfile.Close()
        lockfile.Truncate(0)
 
-       cmd := exec.Command("systemd-cat", append([]string{"--identifier=crunch-run", args[0], "-no-detach"}, args[1:]...)...)
+       execargs := append([]string{"-no-detach"}, args...)
+       if strings.HasSuffix(prog, " crunch-run") {
+               // invoked as "/path/to/arvados-server crunch-run"
+               // (see arvados/lib/cmd.Multi)
+               execargs = append([]string{strings.TrimSuffix(prog, " crunch-run"), "crunch-run"}, execargs...)
+       } else {
+               // invoked as "/path/to/crunch-run"
+               execargs = append([]string{prog}, execargs...)
+       }
+       execargs = append([]string{
+               // Here, if the inner systemd-cat can't exec
+               // crunch-run, it writes an error message to stderr,
+               // and the outer systemd-cat writes it to the journal
+               // where the operator has a chance to discover it. (If
+               // we only used one systemd-cat command, it would be
+               // up to us to report the error -- but we are going to
+               // detach and exit, not wait for something to appear
+               // on stderr.)  Note these systemd-cat calls don't
+               // result in additional processes -- they just connect
+               // stderr/stdout to sockets and call exec().
+               "systemd-cat", "--identifier=crunch-run",
+               "systemd-cat", "--identifier=crunch-run",
+       }, execargs...)
+
+       cmd := exec.Command(execargs[0], execargs[1:]...)
        // Child inherits lockfile.
        cmd.ExtraFiles = []*os.File{lockfile}
        // Ensure child isn't interrupted even if we receive signals
similarity index 97%
rename from services/crunch-run/cgroup.go
rename to lib/crunchrun/cgroup.go
index 9e52de52aad2e8c94689685b341f8ca1210dbb3c..0b254f5bd7870dcaa188df80ad9552fa1eda83ed 100644 (file)
@@ -2,7 +2,7 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-package main
+package crunchrun
 
 import (
        "bytes"
similarity index 95%
rename from services/crunch-run/cgroup_test.go
rename to lib/crunchrun/cgroup_test.go
index 95adf7484d4558d4544a12ef8b2b98dfb2a1327a..b43479a3b4ae02379cff1f60d33c532a510a7f46 100644 (file)
@@ -2,7 +2,7 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-package main
+package crunchrun
 
 import (
        . "gopkg.in/check.v1"
similarity index 99%
rename from services/crunch-run/copier.go
rename to lib/crunchrun/copier.go
index e5711cc7362a5e11bd394f07afc5af2cd8924367..b1497277f2d52971d7a2bbe4c24e90e583500360 100644 (file)
@@ -2,7 +2,7 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-package main
+package crunchrun
 
 import (
        "encoding/json"
similarity index 99%
rename from services/crunch-run/copier_test.go
rename to lib/crunchrun/copier_test.go
index d767bc4639c912986f8ee923281e1d13e7bcb342..777b715d76dd8bb57e9d5b34309ee70b356df888 100644 (file)
@@ -2,7 +2,7 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-package main
+package crunchrun
 
 import (
        "io"
similarity index 95%
rename from services/crunch-run/crunchrun.go
rename to lib/crunchrun/crunchrun.go
index 0a19d17f4b275c7b8e4aed8854c0ddffffeb59d4..b0a4007f74f87fe12be18046583ba23cc29fa9ea 100644 (file)
@@ -2,7 +2,7 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-package main
+package crunchrun
 
 import (
        "bytes"
@@ -27,6 +27,7 @@ import (
        "syscall"
        "time"
 
+       "git.arvados.org/arvados.git/lib/cmd"
        "git.arvados.org/arvados.git/lib/crunchstat"
        "git.arvados.org/arvados.git/sdk/go/arvados"
        "git.arvados.org/arvados.git/sdk/go/arvadosclient"
@@ -40,7 +41,9 @@ import (
        dockerclient "github.com/docker/docker/client"
 )
 
-var version = "dev"
+type command struct{}
+
+var Command = command{}
 
 // IArvadosClient is the minimal Arvados API methods used by crunch-run.
 type IArvadosClient interface {
@@ -1527,7 +1530,7 @@ func (runner *ContainerRunner) NewArvLogWriter(name string) (io.WriteCloser, err
 
 // Run the full container lifecycle.
 func (runner *ContainerRunner) Run() (err error) {
-       runner.CrunchLog.Printf("crunch-run %s started", version)
+       runner.CrunchLog.Printf("crunch-run %s started", cmd.Version.String())
        runner.CrunchLog.Printf("Executing container '%s'", runner.Container.UUID)
 
        hostname, hosterr := os.Hostname()
@@ -1758,83 +1761,93 @@ func NewContainerRunner(dispatcherClient *arvados.Client,
        return cr, nil
 }
 
-func main() {
-       statInterval := flag.Duration("crunchstat-interval", 10*time.Second, "sampling period for periodic resource usage reporting")
-       cgroupRoot := flag.String("cgroup-root", "/sys/fs/cgroup", "path to sysfs cgroup tree")
-       cgroupParent := flag.String("cgroup-parent", "docker", "name of container's parent cgroup (ignored if -cgroup-parent-subsystem is used)")
-       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")
-       enableNetwork := flag.String("container-enable-networking", "default",
+func (command) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
+       flags := flag.NewFlagSet(prog, flag.ContinueOnError)
+       statInterval := flags.Duration("crunchstat-interval", 10*time.Second, "sampling period for periodic resource usage reporting")
+       cgroupRoot := flags.String("cgroup-root", "/sys/fs/cgroup", "path to sysfs cgroup tree")
+       cgroupParent := flags.String("cgroup-parent", "docker", "name of container's parent cgroup (ignored if -cgroup-parent-subsystem is used)")
+       cgroupParentSubsystem := flags.String("cgroup-parent-subsystem", "", "use current cgroup for given subsystem as parent cgroup for container")
+       caCertsPath := flags.String("ca-certs", "", "Path to TLS root certificates")
+       detach := flags.Bool("detach", false, "Detach from parent process and run in the background")
+       stdinEnv := flags.Bool("stdin-env", false, "Load environment variables from JSON message on stdin")
+       sleep := flags.Duration("sleep", 0, "Delay before starting (testing use only)")
+       kill := flags.Int("kill", -1, "Send signal to an existing crunch-run process for given UUID")
+       list := flags.Bool("list", false, "List UUIDs of existing crunch-run processes")
+       enableNetwork := flags.String("container-enable-networking", "default",
                `Specify if networking should be enabled for container.  One of 'default', 'always':
        default: only enable networking if container requests it.
        always:  containers always have networking enabled
        `)
-       networkMode := flag.String("container-network-mode", "default",
+       networkMode := flags.String("container-network-mode", "default",
                `Set networking mode for container.  Corresponds to Docker network mode (--net).
        `)
-       memprofile := flag.String("memprofile", "", "write memory profile to `file` after running container")
-       getVersion := flag.Bool("version", false, "Print version information and exit.")
-       flag.Duration("check-containerd", 0, "Ignored. Exists for compatibility with older versions.")
+       memprofile := flags.String("memprofile", "", "write memory profile to `file` after running container")
+       flags.Duration("check-containerd", 0, "Ignored. Exists for compatibility with older versions.")
 
        ignoreDetachFlag := false
-       if len(os.Args) > 1 && os.Args[1] == "-no-detach" {
+       if len(args) > 0 && args[0] == "-no-detach" {
                // This process was invoked by a parent process, which
                // has passed along its own arguments, including
                // -detach, after the leading -no-detach flag.  Strip
                // the leading -no-detach flag (it's not recognized by
-               // flag.Parse()) and ignore the -detach flag that
+               // flags.Parse()) and ignore the -detach flag that
                // comes later.
-               os.Args = append([]string{os.Args[0]}, os.Args[2:]...)
+               args = args[1:]
                ignoreDetachFlag = true
        }
 
-       flag.Parse()
+       if err := flags.Parse(args); err == flag.ErrHelp {
+               return 0
+       } else if err != nil {
+               log.Print(err)
+               return 1
+       }
 
        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)
+               err := loadEnv(os.Stdin)
+               if err != nil {
+                       log.Print(err)
+                       return 1
+               }
        }
 
+       containerId := flags.Arg(0)
+
        switch {
        case *detach && !ignoreDetachFlag:
-               os.Exit(Detach(flag.Arg(0), os.Args, os.Stdout, os.Stderr))
+               return Detach(containerId, prog, args, os.Stdout, os.Stderr)
        case *kill >= 0:
-               os.Exit(KillProcess(flag.Arg(0), syscall.Signal(*kill), os.Stdout, os.Stderr))
+               return KillProcess(containerId, syscall.Signal(*kill), os.Stdout, os.Stderr)
        case *list:
-               os.Exit(ListProcesses(os.Stdout, os.Stderr))
+               return ListProcesses(os.Stdout, os.Stderr)
        }
 
-       // Print version information if requested
-       if *getVersion {
-               fmt.Printf("crunch-run %s\n", version)
-               return
+       if containerId == "" {
+               log.Printf("usage: %s [options] UUID", prog)
+               return 1
        }
 
-       log.Printf("crunch-run %s started", version)
+       log.Printf("crunch-run %s started", cmd.Version.String())
        time.Sleep(*sleep)
 
-       containerId := flag.Arg(0)
-
        if *caCertsPath != "" {
                arvadosclient.CertFiles = []string{*caCertsPath}
        }
 
        api, err := arvadosclient.MakeArvadosClient()
        if err != nil {
-               log.Fatalf("%s: %v", containerId, err)
+               log.Printf("%s: %v", containerId, err)
+               return 1
        }
        api.Retries = 8
 
        kc, kcerr := keepclient.MakeKeepClient(api)
        if kcerr != nil {
-               log.Fatalf("%s: %v", containerId, kcerr)
+               log.Printf("%s: %v", containerId, kcerr)
+               return 1
        }
        kc.BlockCache = &keepclient.BlockCache{MaxBlocks: 2}
        kc.Retries = 4
@@ -1845,18 +1858,20 @@ func main() {
 
        cr, err := NewContainerRunner(arvados.NewClientFromEnv(), api, kc, docker, containerId)
        if err != nil {
-               log.Fatal(err)
+               log.Print(err)
+               return 1
        }
        if dockererr != nil {
                cr.CrunchLog.Printf("%s: %v", containerId, dockererr)
                cr.checkBrokenNode(dockererr)
                cr.CrunchLog.Close()
-               os.Exit(1)
+               return 1
        }
 
        parentTemp, tmperr := cr.MkTempDir("", "crunch-run."+containerId+".")
        if tmperr != nil {
-               log.Fatalf("%s: %v", containerId, tmperr)
+               log.Printf("%s: %v", containerId, tmperr)
+               return 1
        }
 
        cr.parentTemp = parentTemp
@@ -1889,24 +1904,27 @@ func main() {
        }
 
        if runerr != nil {
-               log.Fatalf("%s: %v", containerId, runerr)
+               log.Printf("%s: %v", containerId, runerr)
+               return 1
        }
+       return 0
 }
 
-func loadEnv(rdr io.Reader) {
+func loadEnv(rdr io.Reader) error {
        buf, err := ioutil.ReadAll(rdr)
        if err != nil {
-               log.Fatalf("read stdin: %s", err)
+               return fmt.Errorf("read stdin: %s", err)
        }
        var env map[string]string
        err = json.Unmarshal(buf, &env)
        if err != nil {
-               log.Fatalf("decode stdin: %s", err)
+               return fmt.Errorf("decode stdin: %s", err)
        }
        for k, v := range env {
                err = os.Setenv(k, v)
                if err != nil {
-                       log.Fatalf("setenv(%q): %s", k, err)
+                       return fmt.Errorf("setenv(%q): %s", k, err)
                }
        }
+       return nil
 }
similarity index 99%
rename from services/crunch-run/crunchrun_test.go
rename to lib/crunchrun/crunchrun_test.go
index 636926a8d0a06054c3cca22fe2ab72e2d4df67d4..e8c7660d1aee39424f88d2d6de0e2b3a213baa36 100644 (file)
@@ -2,7 +2,7 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-package main
+package crunchrun
 
 import (
        "bufio"
similarity index 99%
rename from services/crunch-run/git_mount.go
rename to lib/crunchrun/git_mount.go
index 4fcba1379446eb2378b36d5c7eb65ea5fbb673f5..92bb6d11d94a3f0ad49095db5d45692f0dc9f8b7 100644 (file)
@@ -2,7 +2,7 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-package main
+package crunchrun
 
 import (
        "fmt"
similarity index 99%
rename from services/crunch-run/git_mount_test.go
rename to lib/crunchrun/git_mount_test.go
index 608917808a6e57f0371d1deee66992c2d12a54ca..e39beaa943832487f23c4215b697becc6a47dc02 100644 (file)
@@ -2,7 +2,7 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-package main
+package crunchrun
 
 import (
        "io/ioutil"
similarity index 99%
rename from services/crunch-run/logging.go
rename to lib/crunchrun/logging.go
index 01cab69cd0558b62b01e45b68b934d86c5a4abc1..d5de184e5c41bf8e9dc434fe226d8d5ed17fa1f9 100644 (file)
@@ -2,7 +2,7 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-package main
+package crunchrun
 
 import (
        "bufio"
similarity index 99%
rename from services/crunch-run/logging_test.go
rename to lib/crunchrun/logging_test.go
index 4a2944f6463bc6231bc9de316e57dc3718aaace9..fab333b433c04d52663f203d888f745fd02346c3 100644 (file)
@@ -2,7 +2,7 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-package main
+package crunchrun
 
 import (
        "fmt"