Esempio n. 1
0
def _upload_file(path, data, content_type, readers):
    """Overwrites a file in GCS, makes it readable to all authorized readers.

  Doesn't use streaming uploads currently. Data is limited by URL Fetch request
  size (10 MB).

  Args:
    path: "<bucket>/<object>" string.
    data: buffer with data to upload.
    content_type: MIME content type of 'data', to put into GCS metadata.
    readers: list of emails that should have read access to the file.

  Raises:
    Error if Google Storage writes fail.
  """
    # We upload both metadata and body in a single request, see:
    # https://cloud.google.com/storage/docs/json_api/v1/how-tos/multipart-upload.
    bucket, name = path.split('/', 1)
    payload, boundary = _multipart_payload(data, content_type, {
        'name': name,
        'acl': _gcs_acls(readers)
    })
    try:
        net.request(
            url='https://www.googleapis.com/upload/storage/v1/b/%s/o' % bucket,
            method='POST',
            payload=payload,
            params={'uploadType': 'multipart'},
            headers={
                'Content-Type': 'multipart/related; boundary=%s' % boundary
            },
            scopes=['https://www.googleapis.com/auth/cloud-platform'],
            deadline=30)
    except net.Error as exc:
        raise Error(str(exc))
Esempio n. 2
0
 def test_gives_up_retrying(self):
   self.mock_urlfetch([
     ({'url': 'http://localhost/123'}, Response(500, 'server error', {})),
     ({'url': 'http://localhost/123'}, Response(500, 'server error', {})),
     ({'url': 'http://localhost/123'}, Response(200, 'response body', {})),
   ])
   with self.assertRaises(net.Error):
     net.request('http://localhost/123', max_attempts=2)
Esempio n. 3
0
 def test_405(self):
     self.mock_urlfetch([
         ({
             'url': 'http://localhost/123'
         }, Response(405, 'method not allowed', {})),
     ])
     with self.assertRaises(net.MethodNotAllowed):
         net.request('http://localhost/123')
Esempio n. 4
0
 def test_404(self):
     self.mock_urlfetch([
         ({
             'url': 'http://localhost/123'
         }, Response(404, 'Not found', {})),
     ])
     with self.assertRaises(net.NotFoundError):
         net.request('http://localhost/123')
Esempio n. 5
0
 def test_legitimate_cloud_endpoints_404_is_not_retried(self):
     self.mock_urlfetch([
         ({
             'url': 'http://localhost/_ah/api/blah'
         }, Response(404, '{}', {'Content-Type': 'application/json'})),
     ])
     with self.assertRaises(net.NotFoundError):
         net.request('http://localhost/_ah/api/blah')
Esempio n. 6
0
 def test_403(self):
     self.mock_urlfetch([
         ({
             'url': 'http://localhost/123'
         }, Response(403, 'Auth error', {})),
     ])
     with self.assertRaises(net.AuthError):
         net.request('http://localhost/123')
Esempio n. 7
0
 def test_gives_up_retrying(self):
   self.mock_urlfetch([
     ({'url': 'http://localhost/123'}, Response(500, 'server error')),
     ({'url': 'http://localhost/123'}, Response(500, 'server error')),
     ({'url': 'http://localhost/123'}, Response(200, 'response body')),
   ])
   with self.assertRaises(net.Error):
     net.request('http://localhost/123', max_attempts=2)
Esempio n. 8
0
 def test_legitimate_cloud_endpoints_404_is_not_retried(self):
   self.mock_urlfetch([
     (
       {'url': 'http://localhost/_ah/api/blah'},
       Response(404, '{}', {'Content-Type': 'application/json'})
     ),
   ])
   with self.assertRaises(net.NotFoundError):
     net.request('http://localhost/_ah/api/blah')
Esempio n. 9
0
def forward_data(data, ip):
  """Forwards the raw data to the backend.

  The request contains all the required headers, incliding a special
  Endpoint-Url header with the endpoint URL, and the correct
  Authorization: header for that endpoint.

  Args:
    data (str): raw binary data to forward.
    ip (str):   the IP address of the data source (used for traffic split).

  Raises:
    AdminError when endpoint data is not entered in the admin console.
  """
  lb = LoadBalancer()
  module_name = lb.choose_module()
  logging.info('Forwarding request (%d bytes) to module: %s',
               len(data), module_name)
  hostname = app_identity.get_default_version_hostname()
  if utils.is_local_dev_server():
    protocol = 'http'
    hostname = 'localhost:808%s' % module_name[-1]
  else:
    protocol = 'https'

  config_data = _get_config_data()
  if not config_data:
    raise AdminError('Endpoints are not defined')

  # Make the traffic split deterministic in the source IP.

  # TODO(sergeyberezin): make it truly random. Most of our sources
  # are behind NAT boxes, and appear as the same IP.
  random_state = random.getstate()
  random.seed(ip)
  if random.uniform(0, 100) < config_data.secondary_endpoint_load:
    endpoint = config_data.secondary_endpoint
  else:
    endpoint = config_data.primary_endpoint
  random.setstate(random_state)

  url = '%s://%s/%s' % (protocol, hostname, module_name)
  service_account_key = _get_credentials(endpoint.credentials)
  headers = {
      common.ENDPOINT_URL_HEADER: endpoint.url,
      'Content-Type': 'application/x-protobuf',
  }
  headers.update(endpoint.headers)
  net.request(
      url=url,
      method='POST',
      payload=data,
      headers=headers,
      scopes=endpoint.scopes,
      service_account_key=service_account_key)
Esempio n. 10
0
def forward_data(data, ip):
    """Forwards the raw data to the backend.

  The request contains all the required headers, incliding a special
  Endpoint-Url header with the endpoint URL, and the correct
  Authorization: header for that endpoint.

  Args:
    data (str): raw binary data to forward.
    ip (str):   the IP address of the data source (used for traffic split).

  Raises:
    AdminError when endpoint data is not entered in the admin console.
  """
    lb = LoadBalancer()
    module_name = lb.choose_module()
    logging.info('Forwarding request (%d bytes) to module: %s', len(data),
                 module_name)
    hostname = app_identity.get_default_version_hostname()
    if utils.is_local_dev_server():
        protocol = 'http'
        hostname = 'localhost:808%s' % module_name[-1]
    else:
        protocol = 'https'

    config_data = _get_config_data()
    if not config_data:
        raise AdminError('Endpoints are not defined')

    # Make the traffic split deterministic in the source IP.

    # TODO(sergeyberezin): make it truly random. Most of our sources
    # are behind NAT boxes, and appear as the same IP.
    random_state = random.getstate()
    random.seed(ip)
    if random.uniform(0, 100) < config_data.secondary_endpoint_load:
        endpoint = config_data.secondary_endpoint
    else:
        endpoint = config_data.primary_endpoint
    random.setstate(random_state)

    url = '%s://%s/%s' % (protocol, hostname, module_name)
    service_account_key = _get_credentials(endpoint.credentials)
    headers = {
        common.ENDPOINT_URL_HEADER: endpoint.url,
        'Content-Type': 'application/x-protobuf',
    }
    headers.update(endpoint.headers)
    net.request(url=url,
                method='POST',
                payload=data,
                headers=headers,
                scopes=endpoint.scopes,
                service_account_key=service_account_key)
Esempio n. 11
0
 def test_project_tokens_external_service(self):
     self.mock_urlfetch([
         ({
             'deadline': 10,
             'headers': {
                 'Authorization': 'Bearer project-id-token'
             },
             'method': 'GET',
             'url': 'https://external.example.com/123',
         }, Response(200, '', {})),
     ])
     net.request(url='https://external.example.com/123',
                 project_id='project-id')
Esempio n. 12
0
 def test_request_works(self):
     self.mock_urlfetch([
         ({
             'deadline': 123,
             'headers': {
                 'Accept': 'text/plain',
                 'Authorization': 'Bearer token'
             },
             'method': 'POST',
             'payload': 'post body',
             'url': 'http://localhost/123?a=%3D&b=%26',
         }, Response(200, 'response body', {})),
     ])
     response = net.request(url='http://localhost/123',
                            method='POST',
                            payload='post body',
                            params={
                                'a': '=',
                                'b': '&'
                            },
                            headers={'Accept': 'text/plain'},
                            scopes=['scope'],
                            service_account_key=auth.ServiceAccountKey(
                                'a', 'b', 'c'),
                            deadline=123,
                            max_attempts=5)
     self.assertEqual('response body', response)
Esempio n. 13
0
 def test_retries_transient_errors(self):
   self.mock_urlfetch([
     ({'url': 'http://localhost/123'}, urlfetch.Error()),
     ({'url': 'http://localhost/123'}, Response(408, 'clien timeout', {})),
     ({'url': 'http://localhost/123'}, Response(500, 'server error', {})),
     ({'url': 'http://localhost/123'}, Response(200, 'response body', {})),
   ])
   response = net.request('http://localhost/123', max_attempts=4)
   self.assertEqual('response body', response)
Esempio n. 14
0
 def test_retries_transient_errors(self):
   self.mock_urlfetch([
     ({'url': 'http://localhost/123'}, urlfetch.Error()),
     ({'url': 'http://localhost/123'}, Response(408, 'clien timeout')),
     ({'url': 'http://localhost/123'}, Response(500, 'server error')),
     ({'url': 'http://localhost/123'}, Response(200, 'response body')),
   ])
   response = net.request('http://localhost/123', max_attempts=4)
   self.assertEqual('response body', response)
Esempio n. 15
0
 def test_crappy_cloud_endpoints_404_is_retried(self):
     self.mock_urlfetch([
         ({
             'url': 'http://localhost/_ah/api/blah'
         }, Response(404, 'Not found', {})),
         ({
             'url': 'http://localhost/_ah/api/blah'
         }, Response(200, 'response body', {})),
     ])
     response = net.request('http://localhost/_ah/api/blah')
     self.assertEqual('response body', response)
Esempio n. 16
0
 def test_crappy_cloud_endpoints_404_is_retried(self):
   self.mock_urlfetch([
     (
       {'url': 'http://localhost/_ah/api/blah'},
       Response(404, 'Not found', {})
     ),
     (
       {'url': 'http://localhost/_ah/api/blah'},
       Response(200, 'response body', {})
     ),
   ])
   response = net.request('http://localhost/_ah/api/blah')
   self.assertEqual('response body', response)
Esempio n. 17
0
def _set_gcs_metadata(path, metadata):
    """Overwrites file metadata (including ACLs) in GCS.

  Args:
    path: "<bucket>/<object>" string.
    metadata: the metadata dict.

  Raises:
    Error if Google Storage update fails.
  """
    bucket, name = path.split('/', 1)
    try:
        net.request(
            url='https://www.googleapis.com/storage/v1/b/%s/o/%s' %
            (bucket, urllib.quote(name, safe='')),
            method='PUT',
            payload=utils.encode_to_json(metadata),
            headers={'Content-Type': 'application/json; charset=UTF-8'},
            scopes=['https://www.googleapis.com/auth/cloud-platform'],
            deadline=30)
    except net.Error as exc:
        raise Error(str(exc))
Esempio n. 18
0
    def test_project_tokens_fallback(self):
        @ndb.tasklet
        def get_project_access_token(_project_id, _scopes):
            raise auth.NotFoundError('not found')

        self.mock(auth, 'get_project_access_token_async',
                  get_project_access_token)

        self.mock_urlfetch([
            (
                {
                    'deadline': 10,
                    'headers': {
                        # Switches to own token.
                        'Authorization': 'Bearer own-token',
                    },
                    'method': 'GET',
                    'url': 'https://external.example.com/123',
                },
                Response(200, '', {})),
        ])
        net.request(url='https://external.example.com/123',
                    project_id='project-id')
Esempio n. 19
0
def fetch(hostname, path, **kwargs):
  """Sends request to Gerrit, returns raw response.

  See 'net.request' for list of accepted kwargs.

  Returns:
    Response body on success.
    None on 404 response.

  Raises:
    net.Error on communication errors.
  """
  assert not path.startswith('/'), path
  assert 'scopes' not in kwargs, kwargs['scopes']
  try:
    url = urlparse.urljoin('https://' + hostname, 'a/' + path)
    return net.request(url, scopes=[AUTH_SCOPE], **kwargs)
  except net.NotFoundError:
    return None
Esempio n. 20
0
 def test_request_works(self):
   self.mock_urlfetch([
     ({
       'deadline': 123,
       'headers': {'Accept': 'text/plain', 'Authorization': 'Bearer token'},
       'method': 'POST',
       'payload': 'post body',
       'url': 'http://localhost/123?a=%3D&b=%26',
     }, Response(200, 'response body', {})),
   ])
   response = net.request(
       url='http://localhost/123',
       method='POST',
       payload='post body',
       params={'a': '=', 'b': '&'},
       headers={'Accept': 'text/plain'},
       scopes=['scope'],
       service_account_key=auth.ServiceAccountKey('a', 'b', 'c'),
       deadline=123,
       max_attempts=5)
   self.assertEqual('response body', response)
Esempio n. 21
0
    def test_request_project_token_fallback_works(self):
        @ndb.tasklet
        def mocked_get_project_access_token_async(*args, **kwargs):
            mocked_get_project_access_token_async.params = (args, kwargs)
            mocked_get_project_access_token_async.called = True
            raise auth.NotFoundError('testing fallback 1')

        mocked_get_project_access_token_async.called = False

        @ndb.tasklet
        def mocked_get_access_token_async(*args, **kwargs):
            mocked_get_access_token_async.params = (args, kwargs)
            mocked_get_access_token_async.called = True
            raise Exception('testing fallback 2')

        mocked_get_access_token_async.called = False

        self.mock(auth, 'get_project_access_token_async',
                  mocked_get_project_access_token_async)
        self.mock(auth, 'get_access_token_async',
                  mocked_get_access_token_async)

        with self.assertRaises(Exception):
            _ = net.request(url='http://localhost/123',
                            method='POST',
                            payload='post body',
                            params={
                                'a': '=',
                                'b': '&'
                            },
                            headers={'Accept': 'text/plain'},
                            scopes=['scope'],
                            service_account_key=auth.ServiceAccountKey(
                                'a', 'b', 'c'),
                            deadline=123,
                            max_attempts=5,
                            project_id='project1')
        self.assertTrue(mocked_get_project_access_token_async.called)
        self.assertTrue(mocked_get_access_token_async.called)
Esempio n. 22
0
 def test_403(self):
   self.mock_urlfetch([
     ({'url': 'http://localhost/123'}, Response(403, 'Auth error', {})),
   ])
   with self.assertRaises(net.AuthError):
     net.request('http://localhost/123')
Esempio n. 23
0
 def test_404(self):
   self.mock_urlfetch([
     ({'url': 'http://localhost/123'}, Response(404, 'Not found', {})),
   ])
   with self.assertRaises(net.NotFoundError):
     net.request('http://localhost/123')