예제 #1
0
 def _test_other_endpoints(self):
     service_paths = (
         '/',
         '/openapi',
         '/version',
         '/index/summary',
         '/index/files/order',
     )
     service_routes = ((config.service_endpoint(), path)
                       for path in service_paths)
     health_endpoints = (config.service_endpoint(),
                         config.indexer_endpoint())
     health_paths = (
         '',  # default keys for lambda
         '/',  # all keys
         '/basic',
         '/elasticsearch',
         '/queues',
         '/progress',
         '/api_endpoints',
         '/other_lambdas')
     health_routes = ((endpoint, '/health' + path)
                      for endpoint in health_endpoints
                      for path in health_paths)
     for endpoint, path in (*service_routes, *health_routes):
         with self.subTest('other_endpoints', endpoint=endpoint, path=path):
             self._check_endpoint(endpoint, path)
예제 #2
0
def main():
    catalogs = {
        'dcp2':
        config.Catalog(name='dcp2',
                       atlas='hca',
                       internal=False,
                       plugins=dict(
                           metadata=config.Catalog.Plugin(name='hca'),
                           repository=config.Catalog.Plugin(name='tdr')),
                       sources=set())
    }

    # To create a normalized OpenAPI document, we patch any
    # deployment-specific variables that affect the document.
    with patch.object(target=type(config),
                      attribute='catalogs',
                      new_callable=PropertyMock,
                      return_value=catalogs):
        assert config.catalogs == catalogs
        with patch.object(target=config,
                          attribute='service_function_name',
                          return_value='azul_service'):
            assert config.service_name == 'azul_service'
            with patch.object(target=config,
                              attribute='service_endpoint',
                              return_value='localhost'):
                assert config.service_endpoint() == 'localhost'
                app_module = load_app_module('service')
                app_spec = app_module.app.spec()
                doc_path = os.path.join(config.project_root,
                                        'lambdas/service/openapi.json')
                with write_file_atomically(doc_path) as file:
                    json.dump(app_spec, file, indent=4)
예제 #3
0
def request_manifest(filters):
    url = str(furl(url=config.service_endpoint(), path='fetch/manifest/files'))
    params = {
        'catalog': 'dcp2',
        'filters': json.dumps(filters),
        'format': 'terra.bdbag'
    }

    logger.debug(params)
    resp = requests.get(url=url, params=params)
    body = resp.json()
    assert body['Status'] == 301, body['Status']

    while True:
        url = body['Location']
        logger.debug(f'location is {url}')
        time.sleep(0.5)
        resp = requests.get(url=url)
        body = resp.json()
        if body['Status'] != 301:
            break

    assert body['Status'] == 302, body['Status']
    url = body['Location']
    logger.debug(f'location is {url}')
    return url
예제 #4
0
 def _mock_service_endpoints(self, helper: responses.RequestsMock,
                             endpoint_states: Mapping[str, bool]) -> None:
     for endpoint, endpoint_up in endpoint_states.items():
         helper.add(
             responses.Response(method='HEAD',
                                url=config.service_endpoint() + endpoint,
                                status=200 if endpoint_up else 503,
                                json={}))
예제 #5
0
 def _api_endpoint(self, path: str) -> Tuple[str, JSON]:
     url = config.service_endpoint() + path
     response = requests.head(url)
     try:
         response.raise_for_status()
     except requests.exceptions.HTTPError as e:
         return url, {'up': False, 'error': repr(e)}
     else:
         return url, {'up': True}
예제 #6
0
def filter_projects():
    # Tabula Muris causes 500 errors due to memory constraints
    # https://github.com/DataBiosphere/azul/issues/2442
    resp = requests.get(url=config.service_endpoint() + '/index/projects',
                        params=dict(size=1000))
    projects = resp.json()['termFacets']['project']['terms']
    return [
        one(project['projectId']) for project in projects
        if project['term'] != 'Tabula Muris'
    ]
예제 #7
0
 def test_openapi(self):
     service = config.service_endpoint()
     response = requests.get(service + '/')
     self.assertEqual(response.status_code, 200)
     self.assertEqual(response.headers['content-type'], 'text/html')
     self.assertGreater(len(response.content), 0)
     # validate OpenAPI spec
     response = requests.get(service + '/openapi')
     response.raise_for_status()
     spec = response.json()
     validate_spec(spec)
예제 #8
0
 def _get_one_file_uuid(self, catalog: CatalogName) -> str:
     filters = {'fileFormat': {'is': ['fastq.gz', 'fastq']}}
     response = self._check_endpoint(endpoint=config.service_endpoint(),
                                     path='/index/files',
                                     query=dict(catalog=catalog,
                                                filters=json.dumps(filters),
                                                size=1,
                                                order='asc',
                                                sort='fileSize'))
     hits = json.loads(response)
     return one(one(hits['hits'])['files'])['uuid']
예제 #9
0
 def write_to(self, output: IO[str]) -> Optional[str]:
     output.write('--create-dirs\n\n'
                  '--compressed\n\n'
                  '--location\n\n')
     for hit in self._create_request().scan():
         doc = self._hit_to_doc(hit)
         file = one(doc['contents']['files'])
         uuid, name, version = file['uuid'], file['name'], file['version']
         url = furl(config.service_endpoint(),
                    path=f'/repository/files/{uuid}',
                    args=dict(version=version, catalog=self.catalog))
         output.write(f'url={self._option(url.url)}\n'
                      f'output={self._option(name)}\n\n')
     return None
예제 #10
0
    def _test_repository_files(self, catalog: str):
        with self.subTest('repository_files', catalog=catalog):
            file_uuid = self._get_one_file_uuid(catalog)
            response = self._check_endpoint(
                endpoint=config.service_endpoint(),
                path=f'/fetch/repository/files/{file_uuid}',
                query=dict(catalog=catalog))
            response = json.loads(response)

            while response['Status'] != 302:
                self.assertEqual(301, response['Status'])
                response = self._get_url(response['Location']).json()

            content = self._get_url_content(response['Location'])
            self._validate_fastq_content(content)
예제 #11
0
    def _get_entities(self, catalog: CatalogName, entity_type):
        entities = []
        size = 100
        params = dict(catalog=catalog, size=str(size))
        url = furl(url=config.service_endpoint(),
                   path=('index', entity_type),
                   query_params=params).url
        while True:
            response = self._get_url(url)
            body = response.json()
            hits = body['hits']
            entities.extend(hits)
            url = body['pagination']['next']
            if url is None:
                break

        return entities
예제 #12
0
 def test_manifest_status_running(self, step_function_helper):
     """
     A running manifest job should return a 301 status and a url to retry checking the job status
     """
     execution_id = 'd4ee1bed-0bd7-4c11-9c86-372e07801536'
     execution_running_output = {
         'executionArn':
         StepFunctionHelper().execution_arn(
             config.manifest_state_machine_name, execution_id),
         'stateMachineArn':
         StepFunctionHelper().state_machine_arn(
             config.manifest_state_machine_name),
         'name':
         execution_id,
         'status':
         'RUNNING',
         'startDate':
         datetime.datetime(2018, 11, 15, 18, 30, 44, 896000),
         'input':
         '{"filters": {}}'
     }
     step_function_helper.describe_execution.return_value = execution_running_output
     manifest_service = AsyncManifestService()
     token = manifest_service.encode_token({'execution_id': execution_id})
     retry_url = config.service_endpoint() + '/manifest/files'
     format_ = ManifestFormat.compact
     filters = manifest_service.parse_filters('{}')
     wait_time, manifest = manifest_service.start_or_inspect_manifest_generation(
         self_url=retry_url,
         format_=format_,
         catalog=self.catalog,
         filters=filters,
         token=token)
     self.assertEqual(type(wait_time), int)
     self.assertEqual(wait_time, 1)
     expected_token = manifest_service.encode_token({
         'execution_id': execution_id,
         'request_index': 1
     })
     location = furl(retry_url, args={'token': expected_token})
     expected_obj = Manifest(location=location.url,
                             was_cached=False,
                             properties={})
     self.assertEqual(expected_obj, manifest)
예제 #13
0
 def _expected_api_endpoints(self, endpoint_states: Mapping[str,
                                                            bool]) -> JSON:
     return {
         'api_endpoints': {
             'up':
             all(up for endpoint, up in endpoint_states.items()),
             **({
                 config.service_endpoint() + endpoint: {
                     'up': up
                 } if up else {
                     'up':
                     up,
                     'error': ("HTTPError('503 Server Error: "
                               "Service Unavailable for url: "
                               f"{config.service_endpoint() + endpoint}')")
                 }
                 for endpoint, up in endpoint_states.items()
             })
         }
     }
예제 #14
0
    def get_fusillade_login_url(redirect_uri: str = None) -> str:
        """
        Get the login URL.

        :param redirect_uri: The URI that Fusillade will redirect back to

        According to the documentation, client_id is the service's domain name
        (azul.config.domain_name). However, specifying client_id will cause an
        Auth0 misconfiguration error. This method intentionally excludes
        ``client_id`` from the request to Fusillade.
        """
        if redirect_uri:
            if not Authenticator.valid_redirect_uri_pattern.search(redirect_uri):
                raise InvalidRedirectUriError(redirect_uri)
        else:
            redirect_uri = config.service_endpoint() + '/auth/callback'
        query = dict(response_type="code",
                     scope="openid email",
                     redirect_uri=redirect_uri,
                     state='')
        return '?'.join([Authenticator.get_fusillade_url('authorize'),
                         urlencode(query)])
예제 #15
0
 def _test_manifest(self, catalog: CatalogName):
     for format_, validator, attempts in [
         (None, self._check_manifest, 1),
         ('compact', self._check_manifest, 1),
         ('full', self._check_manifest, 3),
         ('terra.bdbag', self._check_terra_bdbag, 1)
     ]:
         with self.subTest('manifest',
                           catalog=catalog,
                           format=format_,
                           attempts=attempts):
             assert attempts > 0
             params = dict(catalog=catalog)
             if format_ is not None:
                 params['format'] = format_
             for attempt in range(attempts):
                 start = time.time()
                 response = self._check_endpoint(config.service_endpoint(),
                                                 '/manifest/files', params)
                 log.info('Request %i/%i took %.3fs to execute.',
                          attempt + 1, attempts,
                          time.time() - start)
                 validator(catalog, response)
예제 #16
0
 def _test_dos(self, catalog: CatalogName, file_uuid: str):
     with self.subTest('dos', catalog=catalog):
         log.info('Resolving file %s with DOS', file_uuid)
         response = self._check_endpoint(
             config.service_endpoint(),
             path=drs.dos_object_url_path(file_uuid),
             query=dict(catalog=catalog))
         json_data = json.loads(response)['data_object']
         file_url = first(json_data['urls'])['url']
         while True:
             response = self._get_url(file_url, allow_redirects=False)
             # We handle redirects ourselves so we can log each request
             if response.status_code in (301, 302):
                 file_url = response.headers['Location']
                 try:
                     retry_after = response.headers['Retry-After']
                 except KeyError:
                     pass
                 else:
                     time.sleep(int(retry_after))
             else:
                 break
         self._assertResponseStatus(response)
         self._validate_fastq_content(response.content)