5824: Merge branch 'master' into 5824-keep-web-workbench
authorTom Clegg <tom@curoverse.com>
Fri, 6 Nov 2015 21:53:01 +0000 (16:53 -0500)
committerTom Clegg <tom@curoverse.com>
Fri, 6 Nov 2015 21:53:01 +0000 (16:53 -0500)
1  2 
sdk/python/tests/run_test_server.py
services/api/test/fixtures/api_client_authorizations.yml
services/keepproxy/keepproxy_test.go

index cdfd93a0a5cce4bb933facf49eec3e915e7035e8,972b7f9d5172077b740e157cdb3f59b360ca824f..b58c6117dd56265b411340c9a700d3a660672817
@@@ -139,26 -139,6 +139,26 @@@ def _wait_until_port_listens(port, time
          format(port, timeout),
          file=sys.stderr)
  
 +def _fifo2stderr(label):
 +    """Create a fifo, and copy it to stderr, prepending label to each line.
 +
 +    Return value is the path to the new FIFO.
 +
 +    +label+ should contain only alphanumerics: it is also used as part
 +    of the FIFO filename.
 +    """
 +    fifo = os.path.join(TEST_TMPDIR, label+'.fifo')
 +    try:
 +        os.remove(fifo)
 +    except OSError as error:
 +        if error.errno != errno.ENOENT:
 +            raise
 +    os.mkfifo(fifo, 0700)
 +    subprocess.Popen(
 +        ['sed', '-e', 's/^/['+label+'] /', fifo],
 +        stdout=sys.stderr)
 +    return fifo
 +
  def run(leave_running_atexit=False):
      """Ensure an API server is running, and ARVADOS_API_* env vars have
      admin credentials for it.
@@@ -327,10 -307,9 +327,10 @@@ def _start_keep(n, keep_args)
      for arg, val in keep_args.iteritems():
          keep_cmd.append("{}={}".format(arg, val))
  
 -    logf = open(os.path.join(TEST_TMPDIR, 'keep{}.log'.format(n)), 'a+')
 +    logf = open(_fifo2stderr('keep{}'.format(n)), 'w')
      kp0 = subprocess.Popen(
          keep_cmd, stdin=open('/dev/null'), stdout=logf, stderr=logf, close_fds=True)
 +
      with open(_pidfile('keep{}'.format(n)), 'w') as f:
          f.write(str(kp0.pid))
  
@@@ -354,7 -333,7 +354,7 @@@ def run_keep(blob_signing_key=None, enf
          keep_args['-enforce-permissions'] = 'true'
      with open(os.path.join(TEST_TMPDIR, "keep.data-manager-token-file"), "w") as f:
          keep_args['-data-manager-token-file'] = f.name
-         f.write(os.environ['ARVADOS_API_TOKEN'])
+         f.write(auth_token('data_manager'))
      keep_args['-never-delete'] = 'false'
  
      api = arvados.api(
          token=os.environ['ARVADOS_API_TOKEN'],
          insecure=True)
  
 -    for d in api.keep_services().list().execute()['items']:
 +    for d in api.keep_services().list(filters=[['service_type','=','disk']]).execute()['items']:
          api.keep_services().delete(uuid=d['uuid']).execute()
      for d in api.keep_disks().list().execute()['items']:
          api.keep_disks().delete(uuid=d['uuid']).execute()
              'keep_disk': {'keep_service_uuid': svc['uuid'] }
          }).execute()
  
 +    # If keepproxy is running, send SIGHUP to make it discover the new
 +    # keepstore services.
 +    proxypidfile = _pidfile('keepproxy')
 +    if os.path.exists(proxypidfile):
 +        os.kill(int(open(proxypidfile).read()), signal.SIGHUP)
 +
  def _stop_keep(n):
      kill_server_pid(_pidfile('keep{}'.format(n)), 0)
      if os.path.exists("{}/keep{}.volume".format(TEST_TMPDIR, n)):
@@@ -405,20 -378,20 +405,20 @@@ def run_keep_proxy()
          return
      stop_keep_proxy()
  
 -    admin_token = auth_token('admin')
      port = find_available_port()
      env = os.environ.copy()
 -    env['ARVADOS_API_TOKEN'] = admin_token
 +    env['ARVADOS_API_TOKEN'] = auth_token('anonymous')
 +    logf = open(_fifo2stderr('keepproxy'), 'w')
      kp = subprocess.Popen(
          ['keepproxy',
           '-pid='+_pidfile('keepproxy'),
           '-listen=:{}'.format(port)],
 -        env=env, stdin=open('/dev/null'), stdout=sys.stderr)
 +        env=env, stdin=open('/dev/null'), stdout=logf, stderr=logf, close_fds=True)
  
      api = arvados.api(
          version='v1',
          host=os.environ['ARVADOS_API_HOST'],
 -        token=admin_token,
 +        token=auth_token('admin'),
          insecure=True)
      for d in api.keep_services().list(
              filters=[['service_type','=','proxy']]).execute()['items']:
@@@ -462,43 -435,17 +462,43 @@@ def stop_arv_git_httpd()
          return
      kill_server_pid(_pidfile('arv-git-httpd'), wait=0)
  
 +def run_keep_web():
 +    if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ:
 +        return
 +    stop_keep_web()
 +
 +    keepwebport = find_available_port()
 +    env = os.environ.copy()
 +    env.pop('ARVADOS_API_TOKEN', None)
 +    keepweb = subprocess.Popen(
 +        ['keep-web',
 +         '-anonymous-token='+fixture('api_client_authorizations')['anonymous']['api_token'],
 +         '-attachment-only-host=localhost:'+str(keepwebport),
 +         '-address=:'+str(keepwebport)],
 +        env=env, stdin=open('/dev/null'), stdout=sys.stderr)
 +    with open(_pidfile('keep-web'), 'w') as f:
 +        f.write(str(keepweb.pid))
 +    _setport('keep-web', keepwebport)
 +    _wait_until_port_listens(keepwebport)
 +
 +def stop_keep_web():
 +    if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ:
 +        return
 +    kill_server_pid(_pidfile('keep-web'), wait=0)
 +
  def run_nginx():
      if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ:
          return
      nginxconf = {}
 +    nginxconf['KEEPWEBPORT'] = _getport('keep-web')
 +    nginxconf['KEEPWEBSSLPORT'] = find_available_port()
      nginxconf['KEEPPROXYPORT'] = _getport('keepproxy')
      nginxconf['KEEPPROXYSSLPORT'] = find_available_port()
      nginxconf['GITPORT'] = _getport('arv-git-httpd')
      nginxconf['GITSSLPORT'] = find_available_port()
      nginxconf['SSLCERT'] = os.path.join(SERVICES_SRC_DIR, 'api', 'tmp', 'self-signed.pem')
      nginxconf['SSLKEY'] = os.path.join(SERVICES_SRC_DIR, 'api', 'tmp', 'self-signed.key')
 -    nginxconf['ACCESSLOG'] = os.path.join(TEST_TMPDIR, 'nginx_access_log.fifo')
 +    nginxconf['ACCESSLOG'] = _fifo2stderr('nginx_access_log')
  
      conftemplatefile = os.path.join(MY_DIRNAME, 'nginx.conf')
      conffile = os.path.join(TEST_TMPDIR, 'nginx.conf')
      env = os.environ.copy()
      env['PATH'] = env['PATH']+':/sbin:/usr/sbin:/usr/local/sbin'
  
 -    try:
 -        os.remove(nginxconf['ACCESSLOG'])
 -    except OSError as error:
 -        if error.errno != errno.ENOENT:
 -            raise
 -
 -    os.mkfifo(nginxconf['ACCESSLOG'], 0700)
      nginx = subprocess.Popen(
          ['nginx',
           '-g', 'error_log stderr info;',
           '-g', 'pid '+_pidfile('nginx')+';',
           '-c', conffile],
          env=env, stdin=open('/dev/null'), stdout=sys.stderr)
 -    cat_access = subprocess.Popen(
 -        ['cat', nginxconf['ACCESSLOG']],
 -        stdout=sys.stderr)
 +    _setport('keep-web-ssl', nginxconf['KEEPWEBSSLPORT'])
      _setport('keepproxy-ssl', nginxconf['KEEPPROXYSSLPORT'])
      _setport('arv-git-httpd-ssl', nginxconf['GITSSLPORT'])
  
@@@ -599,7 -555,6 +599,7 @@@ class TestCaseWithServers(unittest.Test
      MAIN_SERVER = None
      KEEP_SERVER = None
      KEEP_PROXY_SERVER = None
 +    KEEP_WEB_SERVER = None
  
      @staticmethod
      def _restore_dict(src, dest):
          for server_kwargs, start_func, stop_func in (
                  (cls.MAIN_SERVER, run, reset),
                  (cls.KEEP_SERVER, run_keep, stop_keep),
 -                (cls.KEEP_PROXY_SERVER, run_keep_proxy, stop_keep_proxy)):
 +                (cls.KEEP_PROXY_SERVER, run_keep_proxy, stop_keep_proxy),
 +                (cls.KEEP_WEB_SERVER, run_keep_web, stop_keep_web)):
              if server_kwargs is not None:
                  start_func(**server_kwargs)
                  cls._cleanup_funcs.append(stop_func)
@@@ -645,7 -599,6 +645,7 @@@ if __name__ == "__main__"
          'start', 'stop',
          'start_keep', 'stop_keep',
          'start_keep_proxy', 'stop_keep_proxy',
 +        'start_keep-web', 'stop_keep-web',
          'start_arv-git-httpd', 'stop_arv-git-httpd',
          'start_nginx', 'stop_nginx',
      ]
          run_arv_git_httpd()
      elif args.action == 'stop_arv-git-httpd':
          stop_arv_git_httpd()
 +    elif args.action == 'start_keep-web':
 +        run_keep_web()
 +    elif args.action == 'stop_keep-web':
 +        stop_keep_web()
      elif args.action == 'start_nginx':
          run_nginx()
      elif args.action == 'stop_nginx':
index cb96295064a244073bbe1865f436dd951db890bb,b9ea29c314792909d3fc48e3f2fdea32175bd70b..85c2c791a379552caabc10f6665e1dfca10a2190
@@@ -18,6 -18,18 +18,18 @@@ admin_trustedclient
    api_token: 1a9ffdcga2o7cw8q12dndskomgs1ygli3ns9k2o9hgzgmktc78
    expires_at: 2038-01-01 00:00:00
  
+ data_manager:
+   api_client: untrusted
+   user: system_user
+   api_token: 320mkve8qkswstz7ff61glpk3mhgghmg67wmic7elw4z41pke1
+   expires_at: 2038-01-01 00:00:00
+   scopes:
+     - GET /arvados/v1/collections
+     - GET /arvados/v1/keep_services
+     - GET /arvados/v1/keep_services/accessible
+     - GET /arvados/v1/users/current
+     - POST /arvados/v1/logs
  miniadmin:
    api_client: untrusted
    user: miniadmin
@@@ -87,7 -99,7 +99,7 @@@ active_all_collections
    user: active
    api_token: activecollectionsabcdefghijklmnopqrstuvwxyz1234567
    expires_at: 2038-01-01 00:00:00
 -  scopes: ["GET /arvados/v1/collections/", "GET /arvados/v1/keep_disks"]
 +  scopes: ["GET /arvados/v1/collections/", "GET /arvados/v1/keep_services/accessible"]
  
  active_userlist:
    api_client: untrusted
index e4f09b4e74a071b62797da22c3649ddd1f423938,88b86e063b11874092deec7595b7014fb84a8277..9c33948330262fe9912cd3ce6257ddbc5172060a
@@@ -2,19 -2,21 +2,19 @@@ package mai
  
  import (
        "crypto/md5"
 -      "crypto/tls"
        "fmt"
        "git.curoverse.com/arvados.git/sdk/go/arvadosclient"
        "git.curoverse.com/arvados.git/sdk/go/arvadostest"
        "git.curoverse.com/arvados.git/sdk/go/keepclient"
 -      . "gopkg.in/check.v1"
 -      "io"
        "io/ioutil"
        "log"
        "net/http"
 -      "net/url"
        "os"
        "strings"
        "testing"
        "time"
 +
 +      . "gopkg.in/check.v1"
  )
  
  // Gocheck boilerplate
@@@ -34,8 -36,6 +34,8 @@@ var _ = Suite(&NoKeepServerSuite{}
  // Test with no keepserver to simulate errors
  type NoKeepServerSuite struct{}
  
 +var TestProxyUUID = "zzzzz-bi6l4-lrixqc4fxofbmzz"
 +
  // Wait (up to 1 second) for keepproxy to listen on a port. This
  // avoids a race condition where we hit a "connection refused" error
  // because we start testing the proxy too soon.
@@@ -83,31 -83,106 +83,31 @@@ func (s *NoKeepServerSuite) TearDownSui
        arvadostest.StopAPI()
  }
  
 -func setupProxyService() {
 -
 -      client := &http.Client{Transport: &http.Transport{
 -              TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}}
 -
 -      var req *http.Request
 -      var err error
 -      if req, err = http.NewRequest("POST", fmt.Sprintf("https://%s/arvados/v1/keep_services", os.Getenv("ARVADOS_API_HOST")), nil); err != nil {
 -              panic(err.Error())
 -      }
 -      req.Header.Add("Authorization", fmt.Sprintf("OAuth2 %s", os.Getenv("ARVADOS_API_TOKEN")))
 -
 -      reader, writer := io.Pipe()
 -
 -      req.Body = reader
 -
 -      go func() {
 -              data := url.Values{}
 -              data.Set("keep_service", `{
 -  "service_host": "localhost",
 -  "service_port": 29950,
 -  "service_ssl_flag": false,
 -  "service_type": "proxy"
 -}`)
 -
 -              writer.Write([]byte(data.Encode()))
 -              writer.Close()
 -      }()
 -
 -      var resp *http.Response
 -      if resp, err = client.Do(req); err != nil {
 -              panic(err.Error())
 -      }
 -      if resp.StatusCode != 200 {
 -              panic(resp.Status)
 -      }
 -}
 +func runProxy(c *C, args []string, bogusClientToken bool) *keepclient.KeepClient {
 +      args = append([]string{"keepproxy"}, args...)
 +      os.Args = append(args, "-listen=:0")
 +      listener = nil
 +      go main()
 +      waitForListener()
  
 -func runProxy(c *C, args []string, port int, bogusClientToken bool) *keepclient.KeepClient {
 -      if bogusClientToken {
 -              os.Setenv("ARVADOS_API_TOKEN", "bogus-token")
 -      }
        arv, err := arvadosclient.MakeArvadosClient()
        c.Assert(err, Equals, nil)
 -      kc := keepclient.KeepClient{
 -              Arvados:       &arv,
 -              Want_replicas: 2,
 -              Using_proxy:   true,
 -              Client:        &http.Client{},
 -      }
 -      locals := map[string]string{
 -              "proxy": fmt.Sprintf("http://localhost:%v", port),
 -      }
 -      writableLocals := map[string]string{
 -              "proxy": fmt.Sprintf("http://localhost:%v", port),
 -      }
 -      kc.SetServiceRoots(locals, writableLocals, nil)
 -      c.Check(kc.Using_proxy, Equals, true)
 -      c.Check(len(kc.LocalRoots()), Equals, 1)
 -      for _, root := range kc.LocalRoots() {
 -              c.Check(root, Equals, fmt.Sprintf("http://localhost:%v", port))
 -      }
 -      log.Print("keepclient created")
        if bogusClientToken {
 -              arvadostest.ResetEnv()
 +              arv.ApiToken = "bogus-token"
        }
 -
 -      {
 -              os.Args = append(args, fmt.Sprintf("-listen=:%v", port))
 -              listener = nil
 -              go main()
 +      kc := keepclient.New(&arv)
 +      sr := map[string]string{
 +              TestProxyUUID: "http://" + listener.Addr().String(),
        }
 +      kc.SetServiceRoots(sr, sr, sr)
 +      kc.Arvados.External = true
 +      kc.Using_proxy = true
  
        return &kc
  }
  
  func (s *ServerRequiredSuite) TestPutAskGet(c *C) {
 -      log.Print("TestPutAndGet start")
 -
 -      os.Args = []string{"keepproxy", "-listen=:29950"}
 -      listener = nil
 -      go main()
 -      time.Sleep(100 * time.Millisecond)
 -
 -      setupProxyService()
 -
 -      os.Setenv("ARVADOS_EXTERNAL_CLIENT", "true")
 -      arv, err := arvadosclient.MakeArvadosClient()
 -      c.Assert(err, Equals, nil)
 -      kc, err := keepclient.MakeKeepClient(&arv)
 -      c.Assert(err, Equals, nil)
 -      c.Check(kc.Arvados.External, Equals, true)
 -      c.Check(kc.Using_proxy, Equals, true)
 -      c.Check(len(kc.LocalRoots()), Equals, 1)
 -      for _, root := range kc.LocalRoots() {
 -              c.Check(root, Equals, "http://localhost:29950")
 -      }
 -      os.Setenv("ARVADOS_EXTERNAL_CLIENT", "")
 -
 -      waitForListener()
 +      kc := runProxy(c, nil, false)
        defer closeListener()
  
        hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
                c.Check(blocklen, Equals, int64(0))
                log.Print("Finished Get zero block")
        }
 -
 -      log.Print("TestPutAndGet done")
  }
  
  func (s *ServerRequiredSuite) TestPutAskGetForbidden(c *C) {
 -      log.Print("TestPutAskGetForbidden start")
 -
 -      kc := runProxy(c, []string{"keepproxy"}, 29951, true)
 -      waitForListener()
 +      kc := runProxy(c, nil, true)
        defer closeListener()
  
        hash := fmt.Sprintf("%x", md5.Sum([]byte("bar")))
                c.Check(blocklen, Equals, int64(0))
                log.Print("Get")
        }
 -
 -      log.Print("TestPutAskGetForbidden done")
  }
  
  func (s *ServerRequiredSuite) TestGetDisabled(c *C) {
 -      log.Print("TestGetDisabled start")
 -
 -      kc := runProxy(c, []string{"keepproxy", "-no-get"}, 29952, false)
 -      waitForListener()
 +      kc := runProxy(c, []string{"-no-get"}, false)
        defer closeListener()
  
        hash := fmt.Sprintf("%x", md5.Sum([]byte("baz")))
                c.Check(blocklen, Equals, int64(0))
                log.Print("Get")
        }
 -
 -      log.Print("TestGetDisabled done")
  }
  
  func (s *ServerRequiredSuite) TestPutDisabled(c *C) {
 -      log.Print("TestPutDisabled start")
 -
 -      kc := runProxy(c, []string{"keepproxy", "-no-put"}, 29953, false)
 -      waitForListener()
 +      kc := runProxy(c, []string{"-no-put"}, false)
        defer closeListener()
  
 -      {
 -              hash2, rep, err := kc.PutB([]byte("quux"))
 -              c.Check(hash2, Equals, "")
 -              c.Check(rep, Equals, 0)
 -              c.Check(err, Equals, keepclient.InsufficientReplicasError)
 -              log.Print("PutB")
 -      }
 -
 -      log.Print("TestPutDisabled done")
 +      hash2, rep, err := kc.PutB([]byte("quux"))
 +      c.Check(hash2, Equals, "")
 +      c.Check(rep, Equals, 0)
 +      c.Check(err, Equals, keepclient.InsufficientReplicasError)
  }
  
  func (s *ServerRequiredSuite) TestCorsHeaders(c *C) {
 -      runProxy(c, []string{"keepproxy"}, 29954, false)
 -      waitForListener()
 +      runProxy(c, nil, false)
        defer closeListener()
  
        {
                client := http.Client{}
                req, err := http.NewRequest("OPTIONS",
 -                      fmt.Sprintf("http://localhost:29954/%x+3",
 -                              md5.Sum([]byte("foo"))),
 +                      fmt.Sprintf("http://%s/%x+3", listener.Addr().String(), md5.Sum([]byte("foo"))),
                        nil)
                req.Header.Add("Access-Control-Request-Method", "PUT")
                req.Header.Add("Access-Control-Request-Headers", "Authorization, X-Keep-Desired-Replicas")
  
        {
                resp, err := http.Get(
 -                      fmt.Sprintf("http://localhost:29954/%x+3",
 -                              md5.Sum([]byte("foo"))))
 +                      fmt.Sprintf("http://%s/%x+3", listener.Addr().String(), md5.Sum([]byte("foo"))))
                c.Check(err, Equals, nil)
                c.Check(resp.Header.Get("Access-Control-Allow-Headers"), Equals, "Authorization, Content-Length, Content-Type, X-Keep-Desired-Replicas")
                c.Check(resp.Header.Get("Access-Control-Allow-Origin"), Equals, "*")
  }
  
  func (s *ServerRequiredSuite) TestPostWithoutHash(c *C) {
 -      runProxy(c, []string{"keepproxy"}, 29955, false)
 -      waitForListener()
 +      runProxy(c, nil, false)
        defer closeListener()
  
        {
                client := http.Client{}
                req, err := http.NewRequest("POST",
 -                      "http://localhost:29955/",
 +                      "http://"+listener.Addr().String()+"/",
                        strings.NewReader("qux"))
                req.Header.Add("Authorization", "OAuth2 4axaw8zxe0qm22wa6urpp5nskcne8z88cvbupv653y1njyi05h")
                req.Header.Add("Content-Type", "application/octet-stream")
@@@ -345,7 -444,8 +345,7 @@@ func (s *ServerRequiredSuite) TestStrip
  //   With a valid but non-existing prefix (expect "\n")
  //   With an invalid prefix (expect error)
  func (s *ServerRequiredSuite) TestGetIndex(c *C) {
 -      kc := runProxy(c, []string{"keepproxy"}, 28852, false)
 -      waitForListener()
 +      kc := runProxy(c, nil, false)
        defer closeListener()
  
        // Put "index-data" blocks
        _, rep, err = kc.PutB([]byte("some-more-index-data"))
        c.Check(err, Equals, nil)
  
+       kc.Arvados.ApiToken = arvadostest.DataManagerToken
        // Invoke GetIndex
        for _, spec := range []struct {
                prefix         string
                {hash[:3], true, false},  // with matching prefix
                {"abcdef", false, false}, // with no such prefix
        } {
 -              indexReader, err := kc.GetIndex("proxy", spec.prefix)
 +              indexReader, err := kc.GetIndex(TestProxyUUID, spec.prefix)
                c.Assert(err, Equals, nil)
                indexResp, err := ioutil.ReadAll(indexReader)
                c.Assert(err, Equals, nil)
        }
  
        // GetIndex with invalid prefix
 -      _, err = kc.GetIndex("proxy", "xyz")
 +      _, err = kc.GetIndex(TestProxyUUID, "xyz")
        c.Assert((err != nil), Equals, true)
  }