X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/7ebe828a435dcaa1b5668b72adbaad495059f211..221d75b31b3fa5ab824eda6a2ca290665b35161f:/lib/crunchrun/executor_test.go diff --git a/lib/crunchrun/executor_test.go b/lib/crunchrun/executor_test.go index 1c963f9211..3a91c78641 100644 --- a/lib/crunchrun/executor_test.go +++ b/lib/crunchrun/executor_test.go @@ -6,6 +6,8 @@ package crunchrun import ( "bytes" + "context" + "fmt" "io" "io/ioutil" "net" @@ -14,37 +16,12 @@ import ( "strings" "time" + "git.arvados.org/arvados.git/lib/diagnostics" "git.arvados.org/arvados.git/sdk/go/arvados" - "golang.org/x/net/context" + "git.arvados.org/arvados.git/sdk/go/arvadostest" . "gopkg.in/check.v1" ) -func busyboxDockerImage(c *C) string { - fnm := "busybox_uclibc.tar" - cachedir := c.MkDir() - cachefile := cachedir + "/" + fnm - if _, err := os.Stat(cachefile); err == nil { - return cachefile - } - - f, err := ioutil.TempFile(cachedir, "") - c.Assert(err, IsNil) - defer f.Close() - defer os.Remove(f.Name()) - - resp, err := http.Get("https://cache.arvados.org/" + fnm) - c.Assert(err, IsNil) - defer resp.Body.Close() - _, err = io.Copy(f, resp.Body) - c.Assert(err, IsNil) - err = f.Close() - c.Assert(err, IsNil) - err = os.Rename(f.Name(), cachefile) - c.Assert(err, IsNil) - - return cachefile -} - type nopWriteCloser struct{ io.Writer } func (nopWriteCloser) Close() error { return nil } @@ -72,7 +49,7 @@ func (s *executorSuite) SetUpTest(c *C) { Stdout: nopWriteCloser{&s.stdout}, Stderr: nopWriteCloser{&s.stderr}, } - err := s.executor.LoadImage("", busyboxDockerImage(c), arvados.Container{}, "", nil) + err := s.executor.LoadImage("", arvadostest.BusyboxDockerImage(c), arvados.Container{}, "", nil) c.Assert(err, IsNil) } @@ -81,12 +58,28 @@ func (s *executorSuite) TearDownTest(c *C) { } func (s *executorSuite) TestExecTrivialContainer(c *C) { + c.Logf("Using container runtime: %s", s.executor.Runtime()) s.spec.Command = []string{"echo", "ok"} s.checkRun(c, 0) c.Check(s.stdout.String(), Equals, "ok\n") c.Check(s.stderr.String(), Equals, "") } +func (s *executorSuite) TestDiagnosticsImage(c *C) { + s.newExecutor(c) + imagefile := c.MkDir() + "/hello-world.tar" + err := ioutil.WriteFile(imagefile, diagnostics.HelloWorldDockerImage, 0777) + c.Assert(err, IsNil) + err = s.executor.LoadImage("", imagefile, arvados.Container{}, "", nil) + c.Assert(err, IsNil) + + c.Logf("Using container runtime: %s", s.executor.Runtime()) + s.spec.Image = "hello-world" + s.spec.Command = []string{"/hello"} + s.checkRun(c, 0) + c.Check(s.stdout.String(), Matches, `(?ms)\nHello from Docker!\n.*`) +} + func (s *executorSuite) TestExitStatus(c *C) { s.spec.Command = []string{"false"} s.checkRun(c, 1) @@ -141,6 +134,10 @@ func (s *executorSuite) TestExecCleanEnv(c *C) { // singularity also sets this by itself (v3.5.2, but not v3.7.4) case "PROMPT_COMMAND", "PS1", "SINGULARITY_BIND", "SINGULARITY_COMMAND", "SINGULARITY_ENVIRONMENT": // singularity also sets these by itself (v3.7.4) + case "SINGULARITY_NO_EVAL": + // our singularity driver sets this to control + // singularity behavior, and it gets passed + // through to the container default: got[kv[0]] = kv[1] } @@ -176,13 +173,22 @@ func (s *executorSuite) TestExecStdoutStderr(c *C) { } func (s *executorSuite) TestIPAddress(c *C) { - s.spec.Command = []string{"nc", "-l", "-p", "1951", "-e", "printf", `HTTP/1.1 418 I'm a teapot\r\n\r\n`} + // Listen on an available port on the host. + ln, err := net.Listen("tcp", net.JoinHostPort("0.0.0.0", "0")) + c.Assert(err, IsNil) + defer ln.Close() + _, port, err := net.SplitHostPort(ln.Addr().String()) + c.Assert(err, IsNil) + + // Start a container that listens on the same port number that + // is already in use on the host. + s.spec.Command = []string{"nc", "-l", "-p", port, "-e", "printf", `HTTP/1.1 418 I'm a teapot\r\n\r\n`} s.spec.EnableNetwork = true c.Assert(s.executor.Create(s.spec), IsNil) c.Assert(s.executor.Start(), IsNil) starttime := time.Now() - ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(2*time.Second)) + ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second)) defer cancel() for ctx.Err() == nil { @@ -192,9 +198,13 @@ func (s *executorSuite) TestIPAddress(c *C) { break } } + // When we connect to the port using s.executor.IPAddress(), + // we should reach the nc process running inside the + // container, not the net.Listen() running outside the + // container, even though both listen on the same port. ip, err := s.executor.IPAddress() if c.Check(err, IsNil) && c.Check(ip, Not(Equals), "") { - req, err := http.NewRequest("BREW", "http://"+net.JoinHostPort(ip, "1951"), nil) + req, err := http.NewRequest("BREW", "http://"+net.JoinHostPort(ip, port), nil) c.Assert(err, IsNil) resp, err := http.DefaultClient.Do(req) c.Assert(err, IsNil) @@ -205,10 +215,17 @@ func (s *executorSuite) TestIPAddress(c *C) { code, _ := s.executor.Wait(ctx) c.Logf("container ran for %v", time.Now().Sub(starttime)) c.Check(code, Equals, -1) + + c.Logf("stdout:\n%s\n\n", s.stdout.String()) + c.Logf("stderr:\n%s\n\n", s.stderr.String()) } func (s *executorSuite) TestInject(c *C) { + hostdir := c.MkDir() + c.Assert(os.WriteFile(hostdir+"/testfile", []byte("first tube"), 0777), IsNil) + mountdir := fmt.Sprintf("/injecttest-%d", os.Getpid()) s.spec.Command = []string{"sleep", "10"} + s.spec.BindMounts = map[string]bindmount{mountdir: {HostPath: hostdir, ReadOnly: true}} c.Assert(s.executor.Create(s.spec), IsNil) c.Assert(s.executor.Start(), IsNil) starttime := time.Now() @@ -216,13 +233,23 @@ func (s *executorSuite) TestInject(c *C) { ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(2*time.Second)) defer cancel() - injectcmd := []string{"cat", "/proc/1/cmdline"} + // Allow InjectCommand to fail a few times while the container + // is starting + for ctx.Err() == nil { + _, err := s.executor.InjectCommand(ctx, "", "root", false, []string{"true"}) + if err == nil { + break + } + time.Sleep(time.Second / 10) + } + + injectcmd := []string{"cat", mountdir + "/testfile"} cmd, err := s.executor.InjectCommand(ctx, "", "root", false, injectcmd) c.Assert(err, IsNil) out, err := cmd.CombinedOutput() c.Logf("inject %s => %q", injectcmd, out) c.Check(err, IsNil) - c.Check(string(out), Equals, "sleep\00010\000") + c.Check(string(out), Equals, "first tube") s.executor.Stop() code, _ := s.executor.Wait(ctx)