Refactor the multi-host salt install page.
[arvados.git] / services / keepstore / proxy_remote_test.go
index 4c505138089f3c88eec29a0551593a852e4a0781..534371cc0ece83ef3a0cead670d1612ec8f57172 100644 (file)
@@ -2,9 +2,10 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-package main
+package keepstore
 
 import (
+       "context"
        "crypto/md5"
        "encoding/json"
        "fmt"
@@ -16,10 +17,11 @@ import (
        "sync/atomic"
        "time"
 
-       "git.curoverse.com/arvados.git/sdk/go/arvados"
-       "git.curoverse.com/arvados.git/sdk/go/arvadostest"
-       "git.curoverse.com/arvados.git/sdk/go/auth"
-       "git.curoverse.com/arvados.git/sdk/go/keepclient"
+       "git.arvados.org/arvados.git/sdk/go/arvados"
+       "git.arvados.org/arvados.git/sdk/go/arvadostest"
+       "git.arvados.org/arvados.git/sdk/go/auth"
+       "git.arvados.org/arvados.git/sdk/go/keepclient"
+       "github.com/prometheus/client_golang/prometheus"
        check "gopkg.in/check.v1"
 )
 
@@ -27,8 +29,7 @@ var _ = check.Suite(&ProxyRemoteSuite{})
 
 type ProxyRemoteSuite struct {
        cluster *arvados.Cluster
-       vm      VolumeManager
-       rtr     http.Handler
+       handler *handler
 
        remoteClusterID      string
        remoteBlobSigningKey []byte
@@ -86,28 +87,23 @@ func (s *ProxyRemoteSuite) SetUpTest(c *check.C) {
        s.remoteKeepproxy = httptest.NewServer(http.HandlerFunc(s.remoteKeepproxyHandler))
        s.remoteAPI = httptest.NewUnstartedServer(http.HandlerFunc(s.remoteAPIHandler))
        s.remoteAPI.StartTLS()
-       s.cluster = arvados.IntegrationTestCluster()
+       s.cluster = testCluster(c)
+       s.cluster.Collections.BlobSigningKey = knownKey
+       s.cluster.SystemRootToken = arvadostest.SystemRootToken
        s.cluster.RemoteClusters = map[string]arvados.RemoteCluster{
-               s.remoteClusterID: arvados.RemoteCluster{
+               s.remoteClusterID: {
                        Host:     strings.Split(s.remoteAPI.URL, "//")[1],
                        Proxy:    true,
                        Scheme:   "http",
                        Insecure: true,
                },
        }
-       s.vm = MakeTestVolumeManager(2)
-       KeepVM = s.vm
-       theConfig = DefaultConfig()
-       theConfig.systemAuthToken = arvadostest.DataManagerToken
-       theConfig.Start()
-       s.rtr = MakeRESTRouter(s.cluster)
+       s.cluster.Volumes = map[string]arvados.Volume{"zzzzz-nyw5e-000000000000000": {Driver: "mock"}}
+       s.handler = &handler{}
+       c.Assert(s.handler.setup(context.Background(), s.cluster, "", prometheus.NewRegistry(), testServiceURL), check.IsNil)
 }
 
 func (s *ProxyRemoteSuite) TearDownTest(c *check.C) {
-       s.vm.Close()
-       KeepVM = nil
-       theConfig = DefaultConfig()
-       theConfig.Start()
        s.remoteAPI.Close()
        s.remoteKeepproxy.Close()
 }
@@ -120,30 +116,101 @@ func (s *ProxyRemoteSuite) TestProxyRemote(c *check.C) {
 
        path := "/" + strings.Replace(s.remoteKeepLocator, "+A", "+R"+s.remoteClusterID+"-", 1)
 
-       var req *http.Request
-       var resp *httptest.ResponseRecorder
-       tryWithToken := func(token string) {
-               req = httptest.NewRequest("GET", path, nil)
-               req.Header.Set("Authorization", "Bearer "+token)
+       for _, trial := range []struct {
+               label            string
+               method           string
+               token            string
+               xKeepSignature   string
+               expectRemoteReqs int64
+               expectCode       int
+               expectSignature  bool
+       }{
+               {
+                       label:            "GET only",
+                       method:           "GET",
+                       token:            arvadostest.ActiveTokenV2,
+                       expectRemoteReqs: 1,
+                       expectCode:       http.StatusOK,
+               },
+               {
+                       label:            "obsolete token",
+                       method:           "GET",
+                       token:            arvadostest.ActiveToken,
+                       expectRemoteReqs: 0,
+                       expectCode:       http.StatusBadRequest,
+               },
+               {
+                       label:            "bad token",
+                       method:           "GET",
+                       token:            arvadostest.ActiveTokenV2[:len(arvadostest.ActiveTokenV2)-3] + "xxx",
+                       expectRemoteReqs: 1,
+                       expectCode:       http.StatusNotFound,
+               },
+               {
+                       label:            "HEAD only",
+                       method:           "HEAD",
+                       token:            arvadostest.ActiveTokenV2,
+                       expectRemoteReqs: 1,
+                       expectCode:       http.StatusOK,
+               },
+               {
+                       label:            "HEAD with local signature",
+                       method:           "HEAD",
+                       xKeepSignature:   "local, time=" + time.Now().Format(time.RFC3339),
+                       token:            arvadostest.ActiveTokenV2,
+                       expectRemoteReqs: 1,
+                       expectCode:       http.StatusOK,
+                       expectSignature:  true,
+               },
+               {
+                       label:            "GET with local signature",
+                       method:           "GET",
+                       xKeepSignature:   "local, time=" + time.Now().Format(time.RFC3339),
+                       token:            arvadostest.ActiveTokenV2,
+                       expectRemoteReqs: 1,
+                       expectCode:       http.StatusOK,
+                       expectSignature:  true,
+               },
+       } {
+               c.Logf("trial: %s", trial.label)
+
+               s.remoteKeepRequests = 0
+
+               var req *http.Request
+               var resp *httptest.ResponseRecorder
+               req = httptest.NewRequest(trial.method, path, nil)
+               req.Header.Set("Authorization", "Bearer "+trial.token)
+               if trial.xKeepSignature != "" {
+                       req.Header.Set("X-Keep-Signature", trial.xKeepSignature)
+               }
                resp = httptest.NewRecorder()
-               s.rtr.ServeHTTP(resp, req)
+               s.handler.ServeHTTP(resp, req)
+               c.Check(s.remoteKeepRequests, check.Equals, trial.expectRemoteReqs)
+               c.Check(resp.Code, check.Equals, trial.expectCode)
+               if resp.Code == http.StatusOK {
+                       c.Check(resp.Body.String(), check.Equals, string(data))
+               } else {
+                       c.Check(resp.Body.String(), check.Not(check.Equals), string(data))
+               }
+
+               c.Check(resp.Header().Get("Vary"), check.Matches, `(.*, )?X-Keep-Signature(, .*)?`)
+
+               locHdr := resp.Header().Get("X-Keep-Locator")
+               if !trial.expectSignature {
+                       c.Check(locHdr, check.Equals, "")
+                       continue
+               }
+
+               c.Check(locHdr, check.Not(check.Equals), "")
+               c.Check(locHdr, check.Not(check.Matches), `.*\+R.*`)
+               c.Check(VerifySignature(s.cluster, locHdr, trial.token), check.IsNil)
+
+               // Ensure block can be requested using new signature
+               req = httptest.NewRequest("GET", "/"+locHdr, nil)
+               req.Header.Set("Authorization", "Bearer "+trial.token)
+               resp = httptest.NewRecorder()
+               s.handler.ServeHTTP(resp, req)
+               c.Check(resp.Code, check.Equals, http.StatusOK)
+               c.Check(s.remoteKeepRequests, check.Equals, trial.expectRemoteReqs)
        }
-
-       // Happy path
-       tryWithToken(arvadostest.ActiveTokenV2)
-       c.Check(s.remoteKeepRequests, check.Equals, int64(1))
-       c.Check(resp.Code, check.Equals, http.StatusOK)
-       c.Check(resp.Body.String(), check.Equals, string(data))
-
-       // Obsolete token
-       tryWithToken(arvadostest.ActiveToken)
-       c.Check(s.remoteKeepRequests, check.Equals, int64(1))
-       c.Check(resp.Code, check.Equals, http.StatusBadRequest)
-       c.Check(resp.Body.String(), check.Not(check.Equals), string(data))
-
-       // Bad token
-       tryWithToken(arvadostest.ActiveTokenV2[:len(arvadostest.ActiveTokenV2)-3] + "xxx")
-       c.Check(s.remoteKeepRequests, check.Equals, int64(2))
-       c.Check(resp.Code, check.Equals, http.StatusNotFound)
-       c.Check(resp.Body.String(), check.Not(check.Equals), string(data))
 }