18491: Removes an unnecessary check that made the test fail on module upgrade.
[arvados.git] / lib / controller / localdb / container_gateway_test.go
index 336d5b63463e67ee521126340a03c6d014006ebe..70037cc501401375ee107d8e243f21e8f15c3cb5 100644 (file)
@@ -10,6 +10,8 @@ import (
        "crypto/sha256"
        "fmt"
        "io"
+       "io/ioutil"
+       "net"
        "time"
 
        "git.arvados.org/arvados.git/lib/config"
@@ -18,6 +20,7 @@ import (
        "git.arvados.org/arvados.git/sdk/go/arvadostest"
        "git.arvados.org/arvados.git/sdk/go/auth"
        "git.arvados.org/arvados.git/sdk/go/ctxlog"
+       "golang.org/x/crypto/ssh"
        check "gopkg.in/check.v1"
 )
 
@@ -53,11 +56,12 @@ func (s *ContainerGatewaySuite) SetUpSuite(c *check.C) {
        authKey := fmt.Sprintf("%x", h.Sum(nil))
 
        s.gw = &crunchrun.Gateway{
-               DockerContainerID: new(string),
-               ContainerUUID:     s.ctrUUID,
-               AuthSecret:        authKey,
-               Address:           "localhost:0",
-               Log:               ctxlog.TestLogger(c),
+               DockerContainerID:  new(string),
+               ContainerUUID:      s.ctrUUID,
+               AuthSecret:         authKey,
+               Address:            "localhost:0",
+               Log:                ctxlog.TestLogger(c),
+               ContainerIPAddress: func() (string, error) { return "localhost", nil },
        }
        c.Assert(s.gw.Start(), check.IsNil)
        rootctx := auth.NewContext(context.Background(), &auth.Credentials{Tokens: []string{s.cluster.SystemRootToken}})
@@ -74,6 +78,114 @@ func (s *ContainerGatewaySuite) SetUpSuite(c *check.C) {
        c.Assert(err, check.IsNil)
 }
 
+func (s *ContainerGatewaySuite) SetUpTest(c *check.C) {
+       s.cluster.Containers.ShellAccess.Admin = true
+       s.cluster.Containers.ShellAccess.User = true
+       _, err := arvadostest.DB(c, s.cluster).Exec(`update containers set interactive_session_started=$1 where uuid=$2`, false, s.ctrUUID)
+       c.Check(err, check.IsNil)
+}
+
+func (s *ContainerGatewaySuite) TestConfig(c *check.C) {
+       for _, trial := range []struct {
+               configAdmin bool
+               configUser  bool
+               sendToken   string
+               errorCode   int
+       }{
+               {true, true, arvadostest.ActiveTokenV2, 0},
+               {true, false, arvadostest.ActiveTokenV2, 503},
+               {false, true, arvadostest.ActiveTokenV2, 0},
+               {false, false, arvadostest.ActiveTokenV2, 503},
+               {true, true, arvadostest.AdminToken, 0},
+               {true, false, arvadostest.AdminToken, 0},
+               {false, true, arvadostest.AdminToken, 403},
+               {false, false, arvadostest.AdminToken, 503},
+       } {
+               c.Logf("trial %#v", trial)
+               s.cluster.Containers.ShellAccess.Admin = trial.configAdmin
+               s.cluster.Containers.ShellAccess.User = trial.configUser
+               ctx := auth.NewContext(s.ctx, &auth.Credentials{Tokens: []string{trial.sendToken}})
+               sshconn, err := s.localdb.ContainerSSH(ctx, arvados.ContainerSSHOptions{UUID: s.ctrUUID})
+               if trial.errorCode == 0 {
+                       if !c.Check(err, check.IsNil) {
+                               continue
+                       }
+                       if !c.Check(sshconn.Conn, check.NotNil) {
+                               continue
+                       }
+                       sshconn.Conn.Close()
+               } else {
+                       c.Check(err, check.NotNil)
+                       err, ok := err.(interface{ HTTPStatus() int })
+                       if c.Check(ok, check.Equals, true) {
+                               c.Check(err.HTTPStatus(), check.Equals, trial.errorCode)
+                       }
+               }
+       }
+}
+
+func (s *ContainerGatewaySuite) TestDirectTCP(c *check.C) {
+       // Set up servers on a few TCP ports
+       var addrs []string
+       for i := 0; i < 3; i++ {
+               ln, err := net.Listen("tcp", ":0")
+               c.Assert(err, check.IsNil)
+               defer ln.Close()
+               addrs = append(addrs, ln.Addr().String())
+               go func() {
+                       for {
+                               conn, err := ln.Accept()
+                               if err != nil {
+                                       return
+                               }
+                               var gotAddr string
+                               fmt.Fscanf(conn, "%s\n", &gotAddr)
+                               c.Logf("stub server listening at %s received string %q from remote %s", ln.Addr().String(), gotAddr, conn.RemoteAddr())
+                               if gotAddr == ln.Addr().String() {
+                                       fmt.Fprintf(conn, "%s\n", ln.Addr().String())
+                               }
+                               conn.Close()
+                       }
+               }()
+       }
+
+       c.Logf("connecting to %s", s.gw.Address)
+       sshconn, err := s.localdb.ContainerSSH(s.ctx, arvados.ContainerSSHOptions{UUID: s.ctrUUID})
+       c.Assert(err, check.IsNil)
+       c.Assert(sshconn.Conn, check.NotNil)
+       defer sshconn.Conn.Close()
+       conn, chans, reqs, err := ssh.NewClientConn(sshconn.Conn, "zzzz-dz642-abcdeabcdeabcde", &ssh.ClientConfig{
+               HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil },
+       })
+       c.Assert(err, check.IsNil)
+       client := ssh.NewClient(conn, chans, reqs)
+       for _, expectAddr := range addrs {
+               _, port, err := net.SplitHostPort(expectAddr)
+               c.Assert(err, check.IsNil)
+
+               c.Logf("trying foo:%s", port)
+               {
+                       conn, err := client.Dial("tcp", "foo:"+port)
+                       c.Assert(err, check.IsNil)
+                       conn.SetDeadline(time.Now().Add(time.Second))
+                       buf, err := ioutil.ReadAll(conn)
+                       c.Check(err, check.IsNil)
+                       c.Check(string(buf), check.Equals, "")
+               }
+
+               c.Logf("trying localhost:%s", port)
+               {
+                       conn, err := client.Dial("tcp", "localhost:"+port)
+                       c.Assert(err, check.IsNil)
+                       conn.SetDeadline(time.Now().Add(time.Second))
+                       conn.Write([]byte(expectAddr + "\n"))
+                       var gotAddr string
+                       fmt.Fscanf(conn, "%s\n", &gotAddr)
+                       c.Check(gotAddr, check.Equals, expectAddr)
+               }
+       }
+}
+
 func (s *ContainerGatewaySuite) TestConnect(c *check.C) {
        c.Logf("connecting to %s", s.gw.Address)
        sshconn, err := s.localdb.ContainerSSH(s.ctx, arvados.ContainerSSHOptions{UUID: s.ctrUUID})
@@ -98,16 +210,18 @@ func (s *ContainerGatewaySuite) TestConnect(c *check.C) {
                // Receive binary
                _, err = io.ReadFull(sshconn.Conn, buf[:4])
                c.Check(err, check.IsNil)
-               c.Check(buf[:4], check.DeepEquals, []byte{0, 0, 1, 0xfc})
 
                // If we can get this far into an SSH handshake...
-               c.Log("success, tunnel is working")
+               c.Logf("was able to read %x -- success, tunnel is working", buf[:4])
        }()
        select {
        case <-done:
        case <-time.After(time.Second):
                c.Fail()
        }
+       ctr, err := s.localdb.ContainerGet(s.ctx, arvados.GetOptions{UUID: s.ctrUUID})
+       c.Check(err, check.IsNil)
+       c.Check(ctr.InteractiveSessionStarted, check.Equals, true)
 }
 
 func (s *ContainerGatewaySuite) TestConnectFail(c *check.C) {