X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/9c1f240500cca97fe986b529fcfc9c7f9fe1a283..4058b87cfdc07fe25da31f59577f835656e97816:/lib/controller/federation_test.go diff --git a/lib/controller/federation_test.go b/lib/controller/federation_test.go index 1b9bd11221..3b11625f66 100644 --- a/lib/controller/federation_test.go +++ b/lib/controller/federation_test.go @@ -10,12 +10,14 @@ import ( "net/http" "net/http/httptest" "net/url" + "os" "strings" "time" "git.curoverse.com/arvados.git/sdk/go/arvados" "git.curoverse.com/arvados.git/sdk/go/arvadostest" "git.curoverse.com/arvados.git/sdk/go/httpserver" + "git.curoverse.com/arvados.git/sdk/go/keepclient" "github.com/Sirupsen/logrus" check "gopkg.in/check.v1" ) @@ -300,7 +302,52 @@ func (s *FederationSuite) checkJSONErrorMatches(c *check.C, resp *http.Response, c.Check(jresp.Errors[0], check.Matches, re) } +func (s *FederationSuite) localServiceReturns404(c *check.C) *httpserver.Server { + srv := &httpserver.Server{ + Server: http.Server{ + Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + w.WriteHeader(404) + }), + }, + } + + c.Assert(srv.Start(), check.IsNil) + + np := arvados.NodeProfile{ + Controller: arvados.SystemServiceInstance{Listen: ":"}, + RailsAPI: arvados.SystemServiceInstance{Listen: srv.Addr, + TLS: false, Insecure: true}} + s.testHandler.Cluster.NodeProfiles["*"] = np + s.testHandler.NodeProfile = &np + + return srv +} + +func (s *FederationSuite) TestGetLocalCollection(c *check.C) { + np := arvados.NodeProfile{ + Controller: arvados.SystemServiceInstance{Listen: ":"}, + RailsAPI: arvados.SystemServiceInstance{Listen: os.Getenv("ARVADOS_TEST_API_HOST"), + TLS: true, Insecure: true}} + s.testHandler.Cluster.ClusterID = "zzzzz" + s.testHandler.Cluster.NodeProfiles["*"] = np + s.testHandler.NodeProfile = &np + + req := httptest.NewRequest("GET", "/arvados/v1/collections/"+arvadostest.UserAgreementCollection, nil) + req.Header.Set("Authorization", "Bearer "+arvadostest.ActiveToken) + resp := s.testRequest(req) + + c.Check(resp.StatusCode, check.Equals, http.StatusOK) + var col arvados.Collection + c.Check(json.NewDecoder(resp.Body).Decode(&col), check.IsNil) + c.Check(col.UUID, check.Equals, arvadostest.UserAgreementCollection) + c.Check(col.ManifestText, check.Matches, + `\. 6a4ff0499484c6c79c95cd8c566bd25f\+249025\+A[0-9a-f]{40}@[0-9a-f]{8} 0:249025:GNU_General_Public_License,_version_3.pdf +`) +} + func (s *FederationSuite) TestGetRemoteCollection(c *check.C) { + defer s.localServiceReturns404(c).Close() + req := httptest.NewRequest("GET", "/arvados/v1/collections/"+arvadostest.UserAgreementCollection, nil) req.Header.Set("Authorization", "Bearer "+arvadostest.ActiveToken) resp := s.testRequest(req) @@ -311,13 +358,258 @@ func (s *FederationSuite) TestGetRemoteCollection(c *check.C) { c.Check(col.ManifestText, check.Matches, `\. 6a4ff0499484c6c79c95cd8c566bd25f\+249025\+Rzzzzz-[0-9a-f]{40}@[0-9a-f]{8} 0:249025:GNU_General_Public_License,_version_3.pdf `) +} +func (s *FederationSuite) TestGetRemoteCollectionError(c *check.C) { + defer s.localServiceReturns404(c).Close() + + req := httptest.NewRequest("GET", "/arvados/v1/collections/zzzzz-4zz18-fakefakefakefak", nil) + req.Header.Set("Authorization", "Bearer "+arvadostest.ActiveToken) + resp := s.testRequest(req) + c.Check(resp.StatusCode, check.Equals, http.StatusNotFound) +} + +func (s *FederationSuite) TestSignedLocatorPattern(c *check.C) { // Confirm the regular expression identifies other groups of hints correctly - c.Check(SignedLocatorPattern.FindStringSubmatch(`6a4ff0499484c6c79c95cd8c566bd25f+249025+B1+C2+A05227438989d04712ea9ca1c91b556cef01d5cc7@5ba5405b+D3+E4`), + c.Check(keepclient.SignedLocatorRe.FindStringSubmatch(`6a4ff0499484c6c79c95cd8c566bd25f+249025+B1+C2+A05227438989d04712ea9ca1c91b556cef01d5cc7@5ba5405b+D3+E4`), check.DeepEquals, []string{"6a4ff0499484c6c79c95cd8c566bd25f+249025+B1+C2+A05227438989d04712ea9ca1c91b556cef01d5cc7@5ba5405b+D3+E4", - "6a4ff0499484c6c79c95cd8c566bd25f+249025", + "6a4ff0499484c6c79c95cd8c566bd25f", + "+249025", "+B1+C2", "+C2", "+A05227438989d04712ea9ca1c91b556cef01d5cc7@5ba5405b", + "05227438989d04712ea9ca1c91b556cef01d5cc7", "5ba5405b", "+D3+E4", "+E4"}) } + +func (s *FederationSuite) TestGetLocalCollectionByPDH(c *check.C) { + np := arvados.NodeProfile{ + Controller: arvados.SystemServiceInstance{Listen: ":"}, + RailsAPI: arvados.SystemServiceInstance{Listen: os.Getenv("ARVADOS_TEST_API_HOST"), + TLS: true, Insecure: true}} + s.testHandler.Cluster.NodeProfiles["*"] = np + s.testHandler.NodeProfile = &np + + req := httptest.NewRequest("GET", "/arvados/v1/collections/"+arvadostest.UserAgreementPDH, nil) + req.Header.Set("Authorization", "Bearer "+arvadostest.ActiveToken) + resp := s.testRequest(req) + + c.Check(resp.StatusCode, check.Equals, http.StatusOK) + var col arvados.Collection + c.Check(json.NewDecoder(resp.Body).Decode(&col), check.IsNil) + c.Check(col.PortableDataHash, check.Equals, arvadostest.UserAgreementPDH) + c.Check(col.ManifestText, check.Matches, + `\. 6a4ff0499484c6c79c95cd8c566bd25f\+249025\+A[0-9a-f]{40}@[0-9a-f]{8} 0:249025:GNU_General_Public_License,_version_3.pdf +`) +} + +func (s *FederationSuite) TestGetRemoteCollectionByPDH(c *check.C) { + defer s.localServiceReturns404(c).Close() + + req := httptest.NewRequest("GET", "/arvados/v1/collections/"+arvadostest.UserAgreementPDH, nil) + req.Header.Set("Authorization", "Bearer "+arvadostest.ActiveToken) + resp := s.testRequest(req) + + c.Check(resp.StatusCode, check.Equals, http.StatusOK) + + var col arvados.Collection + c.Check(json.NewDecoder(resp.Body).Decode(&col), check.IsNil) + c.Check(col.PortableDataHash, check.Equals, arvadostest.UserAgreementPDH) + c.Check(col.ManifestText, check.Matches, + `\. 6a4ff0499484c6c79c95cd8c566bd25f\+249025\+Rzzzzz-[0-9a-f]{40}@[0-9a-f]{8} 0:249025:GNU_General_Public_License,_version_3.pdf +`) +} + +func (s *FederationSuite) TestGetCollectionByPDHError(c *check.C) { + defer s.localServiceReturns404(c).Close() + + req := httptest.NewRequest("GET", "/arvados/v1/collections/99999999999999999999999999999999+99", nil) + req.Header.Set("Authorization", "Bearer "+arvadostest.ActiveToken) + + resp := s.testRequest(req) + defer resp.Body.Close() + + c.Check(resp.StatusCode, check.Equals, http.StatusNotFound) +} + +func (s *FederationSuite) TestGetCollectionByPDHErrorBadHash(c *check.C) { + defer s.localServiceReturns404(c).Close() + + srv2 := &httpserver.Server{ + Server: http.Server{ + Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + w.WriteHeader(200) + // Return a collection where the hash + // of the manifest text doesn't match + // PDH that was requested. + var col arvados.Collection + col.PortableDataHash = "99999999999999999999999999999999+99" + col.ManifestText = `. 6a4ff0499484c6c79c95cd8c566bd25f\+249025 0:249025:GNU_General_Public_License,_version_3.pdf +` + enc := json.NewEncoder(w) + enc.Encode(col) + }), + }, + } + + c.Assert(srv2.Start(), check.IsNil) + defer srv2.Close() + + // Direct zzzzz to service that returns a 200 result with a bogus manifest_text + s.testHandler.Cluster.RemoteClusters["zzzzz"] = arvados.RemoteCluster{ + Host: srv2.Addr, + Proxy: true, + Scheme: "http", + } + + req := httptest.NewRequest("GET", "/arvados/v1/collections/99999999999999999999999999999999+99", nil) + req.Header.Set("Authorization", "Bearer "+arvadostest.ActiveToken) + + resp := s.testRequest(req) + defer resp.Body.Close() + + c.Check(resp.StatusCode, check.Equals, http.StatusNotFound) +} + +func (s *FederationSuite) TestSaltedTokenGetCollectionByPDH(c *check.C) { + np := arvados.NodeProfile{ + Controller: arvados.SystemServiceInstance{Listen: ":"}, + RailsAPI: arvados.SystemServiceInstance{Listen: os.Getenv("ARVADOS_TEST_API_HOST"), + TLS: true, Insecure: true}} + s.testHandler.Cluster.NodeProfiles["*"] = np + s.testHandler.NodeProfile = &np + + req := httptest.NewRequest("GET", "/arvados/v1/collections/"+arvadostest.UserAgreementPDH, nil) + req.Header.Set("Authorization", "Bearer v2/zzzzz-gj3su-077z32aux8dg2s1/282d7d172b6cfdce364c5ed12ddf7417b2d00065") + resp := s.testRequest(req) + + c.Check(resp.StatusCode, check.Equals, http.StatusOK) + var col arvados.Collection + c.Check(json.NewDecoder(resp.Body).Decode(&col), check.IsNil) + c.Check(col.PortableDataHash, check.Equals, arvadostest.UserAgreementPDH) + c.Check(col.ManifestText, check.Matches, + `\. 6a4ff0499484c6c79c95cd8c566bd25f\+249025\+A[0-9a-f]{40}@[0-9a-f]{8} 0:249025:GNU_General_Public_License,_version_3.pdf +`) +} + +func (s *FederationSuite) TestSaltedTokenGetCollectionByPDHError(c *check.C) { + np := arvados.NodeProfile{ + Controller: arvados.SystemServiceInstance{Listen: ":"}, + RailsAPI: arvados.SystemServiceInstance{Listen: os.Getenv("ARVADOS_TEST_API_HOST"), + TLS: true, Insecure: true}} + s.testHandler.Cluster.NodeProfiles["*"] = np + s.testHandler.NodeProfile = &np + + req := httptest.NewRequest("GET", "/arvados/v1/collections/99999999999999999999999999999999+99", nil) + req.Header.Set("Authorization", "Bearer v2/zzzzz-gj3su-077z32aux8dg2s1/282d7d172b6cfdce364c5ed12ddf7417b2d00065") + resp := s.testRequest(req) + + c.Check(resp.StatusCode, check.Equals, http.StatusNotFound) +} + +func (s *FederationSuite) TestGetRemoteContainerRequest(c *check.C) { + defer s.localServiceReturns404(c).Close() + req := httptest.NewRequest("GET", "/arvados/v1/container_requests/"+arvadostest.QueuedContainerRequestUUID, nil) + req.Header.Set("Authorization", "Bearer "+arvadostest.ActiveToken) + resp := s.testRequest(req) + c.Check(resp.StatusCode, check.Equals, http.StatusOK) + var cr arvados.ContainerRequest + c.Check(json.NewDecoder(resp.Body).Decode(&cr), check.IsNil) + c.Check(cr.UUID, check.Equals, arvadostest.QueuedContainerRequestUUID) + c.Check(cr.Priority, check.Equals, 1) +} + +func (s *FederationSuite) TestUpdateRemoteContainerRequest(c *check.C) { + defer s.localServiceReturns404(c).Close() + req := httptest.NewRequest("PATCH", "/arvados/v1/container_requests/"+arvadostest.QueuedContainerRequestUUID, + strings.NewReader(`{"container_request": {"priority": 696}}`)) + req.Header.Set("Authorization", "Bearer "+arvadostest.ActiveToken) + req.Header.Set("Content-type", "application/json") + resp := s.testRequest(req) + c.Check(resp.StatusCode, check.Equals, http.StatusOK) + var cr arvados.ContainerRequest + c.Check(json.NewDecoder(resp.Body).Decode(&cr), check.IsNil) + c.Check(cr.UUID, check.Equals, arvadostest.QueuedContainerRequestUUID) + c.Check(cr.Priority, check.Equals, 696) +} + +func (s *FederationSuite) TestCreateRemoteContainerRequest1(c *check.C) { + defer s.localServiceReturns404(c).Close() + req := httptest.NewRequest("POST", "/arvados/v1/container_requests", + strings.NewReader(`{ + "cluster_id": "zzzzz", + "container_request": { + "name": "hello world", + "state": "Uncommitted", + "output_path": "/", + "container_image": "123", + "command": ["abc"] + } +} +`)) + req.Header.Set("Authorization", "Bearer "+arvadostest.ActiveToken) + req.Header.Set("Content-type", "application/json") + resp := s.testRequest(req) + c.Check(resp.StatusCode, check.Equals, http.StatusOK) + var cr arvados.ContainerRequest + c.Check(json.NewDecoder(resp.Body).Decode(&cr), check.IsNil) + c.Check(cr.Name, check.Equals, "hello world") + c.Check(strings.HasPrefix(cr.UUID, "zzzzz-"), check.Equals, true) +} + +func (s *FederationSuite) TestCreateRemoteContainerRequest2(c *check.C) { + defer s.localServiceReturns404(c).Close() + // pass cluster_id via query parameter, this allows arvados-controller + // to avoid parsing the body + req := httptest.NewRequest("POST", "/arvados/v1/container_requests?cluster_id=zzzzz", + strings.NewReader(`{ + "container_request": { + "name": "hello world", + "state": "Uncommitted", + "output_path": "/", + "container_image": "123", + "command": ["abc"] + } +} +`)) + req.Header.Set("Authorization", "Bearer "+arvadostest.ActiveToken) + req.Header.Set("Content-type", "application/json") + resp := s.testRequest(req) + c.Check(resp.StatusCode, check.Equals, http.StatusOK) + var cr arvados.ContainerRequest + c.Check(json.NewDecoder(resp.Body).Decode(&cr), check.IsNil) + c.Check(cr.Name, check.Equals, "hello world") + c.Check(strings.HasPrefix(cr.UUID, "zzzzz-"), check.Equals, true) +} + +func (s *FederationSuite) TestCreateRemoteContainerRequestError(c *check.C) { + defer s.localServiceReturns404(c).Close() + // pass cluster_id via query parameter, this allows arvados-controller + // to avoid parsing the body + req := httptest.NewRequest("POST", "/arvados/v1/container_requests?cluster_id=zz404", + strings.NewReader(`{ + "container_request": { + "name": "hello world", + "state": "Uncommitted", + "output_path": "/", + "container_image": "123", + "command": ["abc"] + } +} +`)) + req.Header.Set("Authorization", "Bearer "+arvadostest.ActiveToken) + req.Header.Set("Content-type", "application/json") + resp := s.testRequest(req) + c.Check(resp.StatusCode, check.Equals, http.StatusNotFound) +} + +func (s *FederationSuite) TestGetRemoteContainer(c *check.C) { + defer s.localServiceReturns404(c).Close() + req := httptest.NewRequest("GET", "/arvados/v1/containers/"+arvadostest.QueuedContainerUUID, nil) + req.Header.Set("Authorization", "Bearer "+arvadostest.ActiveToken) + resp := s.testRequest(req) + c.Check(resp.StatusCode, check.Equals, http.StatusOK) + var cn arvados.Container + c.Check(json.NewDecoder(resp.Body).Decode(&cn), check.IsNil) + c.Check(cn.UUID, check.Equals, arvadostest.QueuedContainerUUID) +}