X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/e1d9921132ec1f414aba996609bab2f46384e413..ad17f016de2feecc24a163af77c9c9c5add7dc3b:/lib/controller/localdb/container_gateway_test.go?ds=sidebyside diff --git a/lib/controller/localdb/container_gateway_test.go b/lib/controller/localdb/container_gateway_test.go index cc0011864e..dc8a8cea0d 100644 --- a/lib/controller/localdb/container_gateway_test.go +++ b/lib/controller/localdb/container_gateway_test.go @@ -29,6 +29,7 @@ import ( "git.arvados.org/arvados.git/sdk/go/arvadosclient" "git.arvados.org/arvados.git/sdk/go/arvadostest" "git.arvados.org/arvados.git/sdk/go/ctxlog" + "git.arvados.org/arvados.git/sdk/go/httpserver" "git.arvados.org/arvados.git/sdk/go/keepclient" "golang.org/x/crypto/ssh" check "gopkg.in/check.v1" @@ -38,6 +39,7 @@ var _ = check.Suite(&ContainerGatewaySuite{}) type ContainerGatewaySuite struct { localdbSuite + reqUUID string ctrUUID string srv *httptest.Server gw *crunchrun.Gateway @@ -46,14 +48,36 @@ type ContainerGatewaySuite struct { func (s *ContainerGatewaySuite) SetUpTest(c *check.C) { s.localdbSuite.SetUpTest(c) - s.ctrUUID = arvadostest.QueuedContainerUUID + cr, err := s.localdb.ContainerRequestCreate(s.userctx, arvados.CreateOptions{ + Attrs: map[string]interface{}{ + "command": []string{"echo", time.Now().Format(time.RFC3339Nano)}, + "container_count_max": 1, + "container_image": "arvados/apitestfixture:latest", + "cwd": "/tmp", + "environment": map[string]string{}, + "output_path": "/out", + "priority": 1, + "state": arvados.ContainerRequestStateCommitted, + "mounts": map[string]interface{}{ + "/out": map[string]interface{}{ + "kind": "tmp", + "capacity": 1000000, + }, + }, + "runtime_constraints": map[string]interface{}{ + "vcpus": 1, + "ram": 2, + }}}) + c.Assert(err, check.IsNil) + s.reqUUID = cr.UUID + s.ctrUUID = cr.ContainerUUID h := hmac.New(sha256.New, []byte(s.cluster.SystemRootToken)) fmt.Fprint(h, s.ctrUUID) authKey := fmt.Sprintf("%x", h.Sum(nil)) rtr := router.New(s.localdb, router.Config{}) - s.srv = httptest.NewUnstartedServer(rtr) + s.srv = httptest.NewUnstartedServer(httpserver.AddRequestIDs(httpserver.LogRequests(rtr))) s.srv.StartTLS() // the test setup doesn't use lib/service so // service.URLFromContext() returns nothing -- instead, this @@ -74,15 +98,14 @@ func (s *ContainerGatewaySuite) SetUpTest(c *check.C) { ArvadosClient: ac, } c.Assert(s.gw.Start(), check.IsNil) + rootctx := ctrlctx.NewWithToken(s.ctx, s.cluster, s.cluster.SystemRootToken) - // OK if this line fails (because state is already Running - // from a previous test case) as long as the following line - // succeeds: - s.localdb.ContainerUpdate(rootctx, arvados.UpdateOptions{ + _, err = s.localdb.ContainerUpdate(rootctx, arvados.UpdateOptions{ UUID: s.ctrUUID, Attrs: map[string]interface{}{ "state": arvados.ContainerStateLocked}}) - _, err := s.localdb.ContainerUpdate(rootctx, arvados.UpdateOptions{ + c.Assert(err, check.IsNil) + _, err = s.localdb.ContainerUpdate(rootctx, arvados.UpdateOptions{ UUID: s.ctrUUID, Attrs: map[string]interface{}{ "state": arvados.ContainerStateRunning, @@ -201,7 +224,11 @@ func (s *ContainerGatewaySuite) TestDirectTCP(c *check.C) { } } -func (s *ContainerGatewaySuite) setupLogCollection(c *check.C, files map[string]string) { +func (s *ContainerGatewaySuite) setupLogCollection(c *check.C) { + files := map[string]string{ + "stderr.txt": "hello world\n", + "a/b/c/d.html": "\n", + } client := arvados.NewClientFromEnv() ac, err := arvadosclient.New(client) c.Assert(err, check.IsNil) @@ -226,14 +253,40 @@ func (s *ContainerGatewaySuite) setupLogCollection(c *check.C, files map[string] s.gw.LogCollection = cfs } -func (s *ContainerGatewaySuite) TestContainerLogViaTunnel(c *check.C) { +func (s *ContainerGatewaySuite) saveLogAndCloseGateway(c *check.C) { + rootctx := ctrlctx.NewWithToken(s.ctx, s.cluster, s.cluster.SystemRootToken) + txt, err := s.gw.LogCollection.MarshalManifest(".") + c.Assert(err, check.IsNil) + coll, err := s.localdb.CollectionCreate(rootctx, arvados.CreateOptions{ + Attrs: map[string]interface{}{ + "manifest_text": txt, + }}) + c.Assert(err, check.IsNil) + _, err = s.localdb.ContainerUpdate(rootctx, arvados.UpdateOptions{ + UUID: s.ctrUUID, + Attrs: map[string]interface{}{ + "state": arvados.ContainerStateComplete, + "exit_code": 0, + "log": coll.PortableDataHash, + }}) + c.Assert(err, check.IsNil) + updatedReq, err := s.localdb.ContainerRequestGet(rootctx, arvados.GetOptions{UUID: s.reqUUID}) + c.Assert(err, check.IsNil) + c.Logf("container request log UUID is %s", updatedReq.LogUUID) + crLog, err := s.localdb.CollectionGet(rootctx, arvados.GetOptions{UUID: updatedReq.LogUUID, Select: []string{"manifest_text"}}) + c.Assert(err, check.IsNil) + c.Logf("collection log manifest:\n%s", crLog.ManifestText) + // Ensure localdb can't circumvent the keep-web proxy test by + // getting content from the container gateway. + s.gw.LogCollection = nil +} + +func (s *ContainerGatewaySuite) TestContainerRequestLogViaTunnel(c *check.C) { forceProxyForTest = true defer func() { forceProxyForTest = false }() s.gw = s.setupGatewayWithTunnel(c) - s.setupLogCollection(c, map[string]string{ - "stderr.txt": "hello world\n", - }) + s.setupLogCollection(c) for _, broken := range []bool{false, true} { c.Logf("broken=%v", broken) @@ -245,9 +298,9 @@ func (s *ContainerGatewaySuite) TestContainerLogViaTunnel(c *check.C) { defer delete(s.cluster.Services.Controller.InternalURLs, *forceInternalURLForTest) } - handler, err := s.localdb.ContainerLog(s.userctx, arvados.ContainerLogOptions{ - UUID: s.ctrUUID, - WebDAVOptions: arvados.WebDAVOptions{Path: "/stderr.txt"}, + handler, err := s.localdb.ContainerRequestLog(s.userctx, arvados.ContainerLogOptions{ + UUID: s.reqUUID, + WebDAVOptions: arvados.WebDAVOptions{Path: "/" + s.ctrUUID + "/stderr.txt"}, }) if broken { c.Check(err, check.ErrorMatches, `.*tunnel endpoint is invalid.*`) @@ -255,7 +308,7 @@ func (s *ContainerGatewaySuite) TestContainerLogViaTunnel(c *check.C) { } c.Check(err, check.IsNil) c.Assert(handler, check.NotNil) - r, err := http.NewRequestWithContext(s.userctx, "GET", "https://controller.example/arvados/v1/containers/"+s.ctrUUID+"/log/stderr.txt", nil) + r, err := http.NewRequestWithContext(s.userctx, "GET", "https://controller.example/arvados/v1/container_requests/"+s.reqUUID+"/log/"+s.ctrUUID+"/stderr.txt", nil) c.Assert(err, check.IsNil) r.Header.Set("Authorization", "Bearer "+arvadostest.ActiveTokenV2) rec := httptest.NewRecorder() @@ -268,41 +321,18 @@ func (s *ContainerGatewaySuite) TestContainerLogViaTunnel(c *check.C) { } } -func (s *ContainerGatewaySuite) TestContainerLogViaGateway(c *check.C) { - s.testContainerLog(c, true) +func (s *ContainerGatewaySuite) TestContainerRequestLogViaGateway(c *check.C) { + s.setupLogCollection(c) + s.testContainerRequestLog(c) } -func (s *ContainerGatewaySuite) TestContainerLogViaKeepWeb(c *check.C) { - s.testContainerLog(c, false) +func (s *ContainerGatewaySuite) TestContainerRequestLogViaKeepWeb(c *check.C) { + s.setupLogCollection(c) + s.saveLogAndCloseGateway(c) + s.testContainerRequestLog(c) } -func (s *ContainerGatewaySuite) testContainerLog(c *check.C, viaGateway bool) { - s.setupLogCollection(c, map[string]string{ - "stderr.txt": "hello world\n", - "a/b/c/d.html": "\n", - }) - if !viaGateway { - rootctx := ctrlctx.NewWithToken(s.ctx, s.cluster, s.cluster.SystemRootToken) - txt, err := s.gw.LogCollection.MarshalManifest(".") - c.Assert(err, check.IsNil) - coll, err := s.localdb.CollectionCreate(rootctx, arvados.CreateOptions{ - Attrs: map[string]interface{}{ - "manifest_text": txt, - }}) - c.Assert(err, check.IsNil) - _, err = s.localdb.ContainerUpdate(rootctx, arvados.UpdateOptions{ - UUID: s.ctrUUID, - Attrs: map[string]interface{}{ - "log": coll.PortableDataHash, - "gateway_address": "", - }}) - c.Assert(err, check.IsNil) - // gateway_address="" above already ensures localdb - // can't circumvent the keep-web proxy test by getting - // content from the container gateway; this is just - // extra insurance. - s.gw.LogCollection = nil - } +func (s *ContainerGatewaySuite) testContainerRequestLog(c *check.C) { for _, trial := range []struct { method string path string @@ -313,7 +343,7 @@ func (s *ContainerGatewaySuite) testContainerLog(c *check.C, viaGateway bool) { }{ { method: "GET", - path: "/stderr.txt", + path: s.ctrUUID + "/stderr.txt", expectStatus: http.StatusOK, expectBodyRe: "hello world\n", expectHeader: http.Header{ @@ -322,7 +352,7 @@ func (s *ContainerGatewaySuite) testContainerLog(c *check.C, viaGateway bool) { }, { method: "GET", - path: "/stderr.txt", + path: s.ctrUUID + "/stderr.txt", header: http.Header{ "Range": {"bytes=-6"}, }, @@ -335,7 +365,7 @@ func (s *ContainerGatewaySuite) testContainerLog(c *check.C, viaGateway bool) { }, { method: "OPTIONS", - path: "/stderr.txt", + path: s.ctrUUID + "/stderr.txt", expectStatus: http.StatusOK, expectBodyRe: "", expectHeader: http.Header{ @@ -345,25 +375,34 @@ func (s *ContainerGatewaySuite) testContainerLog(c *check.C, viaGateway bool) { }, { method: "PROPFIND", - path: "", + path: s.ctrUUID + "/", expectStatus: http.StatusMultiStatus, - expectBodyRe: `.*\Qstderr.txt\E.*`, + expectBodyRe: `.*\Qstderr.txt\E.*>\n?`, expectHeader: http.Header{ "Content-Type": {"text/xml; charset=utf-8"}, }, }, { method: "PROPFIND", - path: "/a/b/c/", + path: s.ctrUUID, expectStatus: http.StatusMultiStatus, - expectBodyRe: `.*\Qd.html\E.*`, + expectBodyRe: `.*\Qstderr.txt\E.*>\n?`, + expectHeader: http.Header{ + "Content-Type": {"text/xml; charset=utf-8"}, + }, + }, + { + method: "PROPFIND", + path: s.ctrUUID + "/a/b/c/", + expectStatus: http.StatusMultiStatus, + expectBodyRe: `.*\Qd.html\E.*>\n?`, expectHeader: http.Header{ "Content-Type": {"text/xml; charset=utf-8"}, }, }, { method: "GET", - path: "/a/b/c/d.html", + path: s.ctrUUID + "/a/b/c/d.html", expectStatus: http.StatusOK, expectBodyRe: "\n", expectHeader: http.Header{ @@ -372,13 +411,13 @@ func (s *ContainerGatewaySuite) testContainerLog(c *check.C, viaGateway bool) { }, } { c.Logf("trial %#v", trial) - handler, err := s.localdb.ContainerLog(s.userctx, arvados.ContainerLogOptions{ - UUID: s.ctrUUID, - WebDAVOptions: arvados.WebDAVOptions{Path: trial.path}, + handler, err := s.localdb.ContainerRequestLog(s.userctx, arvados.ContainerLogOptions{ + UUID: s.reqUUID, + WebDAVOptions: arvados.WebDAVOptions{Path: "/" + trial.path}, }) c.Assert(err, check.IsNil) c.Assert(handler, check.NotNil) - r, err := http.NewRequestWithContext(s.userctx, trial.method, "https://controller.example/arvados/v1/containers/"+s.ctrUUID+"/log"+trial.path, nil) + r, err := http.NewRequestWithContext(s.userctx, trial.method, "https://controller.example/arvados/v1/container_requests/"+s.reqUUID+"/log/"+trial.path, nil) c.Assert(err, check.IsNil) for k := range trial.header { r.Header.Set(k, trial.header.Get(k)) @@ -396,12 +435,19 @@ func (s *ContainerGatewaySuite) testContainerLog(c *check.C, viaGateway bool) { } } -func (s *ContainerGatewaySuite) TestContainerLogViaCadaver(c *check.C) { - out := s.runCadaver(c, arvadostest.ActiveToken, "/arvados/v1/containers/"+s.ctrUUID+"/log", "ls") +func (s *ContainerGatewaySuite) TestContainerRequestLogViaCadaver(c *check.C) { + s.setupLogCollection(c) + + out := s.runCadaver(c, arvadostest.ActiveToken, "/arvados/v1/container_requests/"+s.reqUUID+"/log/"+s.ctrUUID, "ls") c.Check(out, check.Matches, `(?ms).*stderr\.txt\s+12\s.*`) c.Check(out, check.Matches, `(?ms).*a\s+0\s.*`) - out = s.runCadaver(c, arvadostest.ActiveTokenV2, "/arvados/v1/containers/"+s.ctrUUID+"/log", "get stderr.txt") + out = s.runCadaver(c, arvadostest.ActiveTokenV2, "/arvados/v1/container_requests/"+s.reqUUID+"/log/"+s.ctrUUID, "get stderr.txt") + c.Check(out, check.Matches, `(?ms).*Downloading .* to stderr\.txt: .* succeeded\..*`) + + s.saveLogAndCloseGateway(c) + + out = s.runCadaver(c, arvadostest.ActiveTokenV2, "/arvados/v1/container_requests/"+s.reqUUID+"/log/"+s.ctrUUID, "get stderr.txt") c.Check(out, check.Matches, `(?ms).*Downloading .* to stderr\.txt: .* succeeded\..*`) } @@ -410,14 +456,9 @@ func (s *ContainerGatewaySuite) runCadaver(c *check.C, password, path, stdin str // just fail on TLS cert verification. s.srv.Close() rtr := router.New(s.localdb, router.Config{}) - s.srv = httptest.NewUnstartedServer(rtr) + s.srv = httptest.NewUnstartedServer(httpserver.AddRequestIDs(httpserver.LogRequests(rtr))) s.srv.Start() - s.setupLogCollection(c, map[string]string{ - "stderr.txt": "hello world\n", - "a/b/c/d.html": "\n", - }) - tempdir, err := ioutil.TempDir("", "localdb-test-") c.Assert(err, check.IsNil) defer os.RemoveAll(tempdir)