X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/ae44eb7e4d96e44ca3dc0481cef7cef354a23292..091ae55fc1df3ec50490becd437d512e38b0f972:/cmd/arvados-client/container_gateway_test.go diff --git a/cmd/arvados-client/container_gateway_test.go b/cmd/arvados-client/container_gateway_test.go index 97a615e4ba..743b91d69b 100644 --- a/cmd/arvados-client/container_gateway_test.go +++ b/cmd/arvados-client/container_gateway_test.go @@ -10,14 +10,23 @@ import ( "crypto/hmac" "crypto/sha256" "fmt" + "io/ioutil" + "net" + "net/http" "net/url" "os" "os/exec" + "strings" + "sync" + "syscall" + "time" "git.arvados.org/arvados.git/lib/controller/rpc" "git.arvados.org/arvados.git/lib/crunchrun" "git.arvados.org/arvados.git/sdk/go/arvados" "git.arvados.org/arvados.git/sdk/go/arvadostest" + "git.arvados.org/arvados.git/sdk/go/ctxlog" + "git.arvados.org/arvados.git/sdk/go/httpserver" check "gopkg.in/check.v1" ) @@ -41,12 +50,15 @@ func (s *ClientSuite) TestShellGateway(c *check.C) { h := hmac.New(sha256.New, []byte(arvadostest.SystemRootToken)) fmt.Fprint(h, uuid) authSecret := fmt.Sprintf("%x", h.Sum(nil)) - dcid := "theperthcountyconspiracy" gw := crunchrun.Gateway{ - DockerContainerID: &dcid, - ContainerUUID: uuid, - Address: "0.0.0.0:0", - AuthSecret: authSecret, + ContainerUUID: uuid, + Address: "0.0.0.0:0", + AuthSecret: authSecret, + Log: ctxlog.TestLogger(c), + // Just forward connections to localhost instead of a + // container, so we can test without running a + // container. + Target: crunchrun.GatewayTargetStub{}, } err := gw.Start() c.Assert(err, check.IsNil) @@ -76,7 +88,93 @@ func (s *ClientSuite) TestShellGateway(c *check.C) { cmd.Env = append(cmd.Env, "ARVADOS_API_TOKEN="+arvadostest.ActiveTokenV2) cmd.Stdout = &stdout cmd.Stderr = &stderr - c.Check(cmd.Run(), check.NotNil) - c.Log(stderr.String()) - c.Check(stderr.String(), check.Matches, `(?ms).*(No such container: theperthcountyconspiracy|exec: \"docker\": executable file not found in \$PATH).*`) + stdin, err := cmd.StdinPipe() + c.Assert(err, check.IsNil) + go fmt.Fprintln(stdin, "data appears on stdin, but stdin does not close; cmd should exit anyway, not hang") + time.AfterFunc(5*time.Second, func() { + c.Errorf("timed out -- remote end is probably hung waiting for us to close stdin") + stdin.Close() + }) + c.Check(cmd.Run(), check.IsNil) + c.Check(stdout.String(), check.Equals, "ok\n") + + // Set up an http server, and try using "arvados-client shell" + // to forward traffic to it. + httpTarget := &httpserver.Server{} + httpTarget.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + c.Logf("httpTarget.Handler: incoming request: %s %s", r.Method, r.URL) + if r.URL.Path == "/foo" { + fmt.Fprintln(w, "bar baz") + } else { + w.WriteHeader(http.StatusNotFound) + } + }) + err = httpTarget.Start() + c.Assert(err, check.IsNil) + + ln, err := net.Listen("tcp", ":0") + c.Assert(err, check.IsNil) + _, forwardedPort, _ := net.SplitHostPort(ln.Addr().String()) + ln.Close() + + stdout.Reset() + stderr.Reset() + ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second)) + defer cancel() + cmd = exec.CommandContext(ctx, + "go", "run", ".", "shell", uuid, + "-L", forwardedPort+":"+httpTarget.Addr, + "-o", "controlpath=none", + "-o", "userknownhostsfile="+c.MkDir()+"/known_hosts", + "-N", + ) + c.Logf("cmd.Args: %s", cmd.Args) + cmd.Env = append(cmd.Env, os.Environ()...) + cmd.Env = append(cmd.Env, "ARVADOS_API_TOKEN="+arvadostest.ActiveTokenV2) + cmd.Stdout = &stdout + cmd.Stderr = &stderr + cmd.Start() + + forwardedURL := fmt.Sprintf("http://localhost:%s/foo", forwardedPort) + + for range time.NewTicker(time.Second / 20).C { + resp, err := http.Get(forwardedURL) + if err != nil { + if !strings.Contains(err.Error(), "connect") { + c.Fatal(err) + } else if ctx.Err() != nil { + if cmd.Process.Signal(syscall.Signal(0)) != nil { + c.Error("OpenSSH exited") + } else { + c.Errorf("timed out trying to connect: %s", err) + } + c.Logf("OpenSSH stdout:\n%s", stdout.String()) + c.Logf("OpenSSH stderr:\n%s", stderr.String()) + c.FailNow() + } + // Retry until OpenSSH starts listening + continue + } + c.Check(resp.StatusCode, check.Equals, http.StatusOK) + body, err := ioutil.ReadAll(resp.Body) + c.Check(err, check.IsNil) + c.Check(string(body), check.Equals, "bar baz\n") + break + } + + var wg sync.WaitGroup + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + resp, err := http.Get(forwardedURL) + if !c.Check(err, check.IsNil) { + return + } + body, err := ioutil.ReadAll(resp.Body) + c.Check(err, check.IsNil) + c.Check(string(body), check.Equals, "bar baz\n") + }() + } + wg.Wait() }