Beispiel #1
0
class SheriffConfigClient(object):
    """Wrapping of sheriff-config HTTP API."""
    def __init__(self):
        """Make the Cloud Endpoints request from this handler."""
        credentials, _ = google.auth.default(
            scopes=['https://www.googleapis.com/auth/userinfo.email'])
        jwt_credentials = jwt.Credentials.from_signing_credentials(
            credentials, 'sheriff-config-dot-chromeperf.appspot.com')
        self._session = AuthorizedSession(jwt_credentials)

    @staticmethod
    def _ParseSubscription(revision, subscription):
        return Subscription(
            revision=revision,
            name=subscription.name,
            rotation_url=subscription.rotation_url,
            notification_email=subscription.notification_email,
            bug_labels=list(subscription.bug_labels),
            bug_components=list(subscription.bug_components),
            bug_cc_emails=list(subscription.bug_cc_emails),
            visibility=subscription.visibility,
        )

    def Match(self, path):
        response = self._session.post(
            'https://sheriff-config-dot-chromeperf.appspot.com/subscriptions/match',
            json={'path': path})
        if response.status_code == 404:  # If no subscription matched
            return [], None
        if not response.ok:
            return None, '%r\n%s' % (response, response.text)
        match_resp = json_format.Parse(response.text,
                                       sheriff_config_pb2.MatchResponse())
        return [
            self._ParseSubscription(s.revision, s.subscription)
            for s in match_resp.subscriptions
        ], None

    def List(self):
        response = self._session.post(
            'https://sheriff-config-dot-chromeperf.appspot.com/subscriptions/list',
            json={'identity_email': GetEmail()})
        if not response.ok:
            return None, '%r\n%s' % (response, response.text)
        list_resp = json_format.Parse(response.text,
                                      sheriff_config_pb2.ListResponse())
        return [
            self._ParseSubscription(s.revision, s.subscription)
            for s in list_resp.subscriptions
        ], None

    def Update(self):
        response = self._session.get(
            'https://sheriff-config-dot-chromeperf.appspot.com/configs/update')
        if response.ok:
            return True, None
        return False, '%r\n%s' % (response, response.text)
Beispiel #2
0
def token_info(
    *,
    profile: str,
    access_token: t.Optional[str] = None,
    id_token: t.Optional[str] = None,
) -> None:
    """token info"""
    import requests

    if access_token is None and id_token is None:
        from .config import Config
        from .authflow import Flow
        from google.auth.transport.requests import AuthorizedSession

        c = Config(profile=profile, skip_verify=True)
        flow = Flow(c)

        credentials = flow.get_credentials(scopes=None)
        session = AuthorizedSession(credentials)
    else:
        session = requests.Session()

    url = "https://www.googleapis.com/oauth2/v3/tokeninfo"
    data = {}
    if access_token:
        data["access_token"] = access_token
    if id_token:
        data["id_token"] = id_token
    response = session.post(url, data=data)
    assert response.status_code == 200, response.text
    print(response.text)
Beispiel #3
0
def revoke_token(
    *,
    profile: str,
    access_token: t.Optional[str] = None,
    refresh_token: t.Optional[str] = None,
) -> None:
    """revoke"""
    import requests

    if access_token is None:
        from .config import Config
        from .authflow import Flow
        from google.auth.transport.requests import AuthorizedSession

        c = Config(profile=profile, skip_verify=True)
        flow = Flow(c)

        credentials = flow.get_credentials(scopes=None)
        session = AuthorizedSession(credentials)
        token = credentials.refresh_token
    else:
        session = requests.Session()
        token = access_token or refresh_token

    url = "https://accounts.google.com/o/oauth2/revoke"

    response = session.post(url, data={"token": token})
    assert response.status_code == 200, response.text
    print(response.text)
    def refresh(self, request):

        iam_sign_endpoint = _IAM_IDTOKEN_ENDPOINT.format(
            self._target_credentials.signer_email
        )

        body = {
            "audience": self._target_audience,
            "delegates": self._target_credentials._delegates,
            "includeEmail": self._include_email,
        }

        headers = {"Content-Type": "application/json"}

        authed_session = AuthorizedSession(
            self._target_credentials._source_credentials, auth_request=request
        )

        response = authed_session.post(
            url=iam_sign_endpoint,
            headers=headers,
            data=json.dumps(body).encode("utf-8"),
        )

        id_token = response.json()["token"]
        self.token = id_token
        self.expiry = datetime.fromtimestamp(jwt.decode(id_token, verify=False)["exp"])
Beispiel #5
0
class AIPPClient(object):
    """
    A convenience wrapper around AI Platform Prediction REST API.
    """
    def __init__(self, service_endpoint):
        logging.info(
            "Setting the AI Platform Prediction service endpoint: {}".format(
                service_endpoint))
        credentials, _ = google.auth.default()
        self._authed_session = AuthorizedSession(credentials)
        self._service_endpoint = service_endpoint

    def predict(self, project_id, model, version, signature, instances):
        """
        Invokes the predict method on the specified signature.
        """

        url = '{}/v1/projects/{}/models/{}/versions/{}:predict'.format(
            self._service_endpoint, project_id, model, version)

        request_body = {'signature_name': signature, 'instances': instances}

        response = self._authed_session.post(url,
                                             data=json.dumps(request_body))
        return response
Beispiel #6
0
def insertOfferClass(payload):

    headers = {
        'Accept': 'application/json',
        'Content-Type': 'application/json; charset=UTF-8'
    }
    credentials = makeOauthCredential()
    response = None

    # Define insert() REST call of target vertical
    uri = 'https://www.googleapis.com/walletobjects/v1'
    path = '/%sClass' % (
        "offer"
    )  # Resource representation is for an Offer, so endpoint for offerClass

    # There is no Google API for Passes Client Library for Python.
    # Authorize a http client with credential generated from Google API client library.
    ## see https://google-auth.readthedocs.io/en/latest/user-guide.html#making-authenticated-requests
    authed_session = AuthorizedSession(credentials)

    # make the POST request to make an insert(); this returns a response object
    # other methods require different http methods; for example, get() requires authed_Session.get(...)
    # check the reference API to make the right REST call
    ## https://developers.google.com/pay/passes/reference/v1/offerclass/insert
    ## https://google-auth.readthedocs.io/en/latest/user-guide.html#making-authenticated-requests
    response = authed_session.post(
        uri + path  # REST API endpoint
        ,
        headers=headers  # Header; optional
        ,
        json=
        payload  # non-form-encoded Payload for POST. Check rest API for format based on method.
    )

    return response
Beispiel #7
0
def search(credentials: Credentials, search_id: str,
           query_params: dict) -> List[MediaItem]:
    a_session = AuthorizedSession(credentials)
    ub = Builder('photoslibrary.googleapis.com', 'v1')
    url = ub.build('/mediaItems:search')

    # dump all eg:
    params = {'pageSize': 100}
    for k in query_params:
        params[k] = query_params[k]
    wb = []
    context = RequestContext(search_id)
    while True:
        req = a_session.post(url, data=params)
        assert req.status_code == 200
        res = req.json()

        if 'mediaItems' not in res:
            break

        for _item in res['mediaItems']:
            wb.append(MediaItem.from_dict(_item))

        context.add(req.elapsed.total_seconds(), len(res['mediaItems']), 0)

        if 'nextPageToken' not in res:
            break

        params['pageToken'] = res['nextPageToken']

    context.stat()

    return wb
def register_device(project_id: str,
                    credentials: Credentials,
                    device_model_id: str,
                    device_id: str,
                    device_api_url: str = _DEVICE_API_URL) -> None:
    """Register a new assistant device instance.

    Args:
       project_id(str): The project ID used to register device instance.
       credentials(google.oauth2.credentials.Credentials): The Google
                OAuth2 credentials of the user to associate the device
                instance with.
       device_model_id(str): The registered device model ID.
       device_id(str): The device ID of the new instance.
       device_api_url(str): URL of the Device API.
    """
    base_url = '/'.join([device_api_url, 'projects', project_id, 'devices'])
    device_url = '/'.join([base_url, device_id])
    session = AuthorizedSession(credentials)
    r = session.get(device_url)
    # Check if the device already is registered and if not then we try to
    # register. If any HTTP connection fails raise a RegistrationError.
    if r.status_code == 404:
        print('Registering...', end='')
        r = session.post(base_url, data=json.dumps({
            'id': device_id,
            'model_id': device_model_id,
            'client_type': 'SDK_SERVICE',
            'nickname': 'Alexa Assistant'
        }))
        if r.status_code != 200:
            raise RegistrationError(r, device_model_id)
        print('Done.\n')
    elif r.status_code != 200:
        raise RegistrationError(r, device_model_id)
Beispiel #9
0
class GoogleUploader(DatabaseQueryWorker):
    def __init__(self, logger):
        super().__init__(
            'Google photo uploader',
            f'SELECT ROWID, * FROM {ARTIFACTS_TABLE} WHERE downloaded=1 AND uploaded is NULL',
            logger)
        self._session = AuthorizedSession(_loadGcloudCredentials())

    def process(self, result):
        index = result[0]
        id = result[1]
        name = result[2]
        filename = f'{STORAGE_DIR}/{index}.dat'
        with open(filename, 'rb') as f:
            self.logger.info('Uploading item', photo=id, file=filename)
            response = self._session.post(
                'https://photoslibrary.googleapis.com/v1/uploads',
                data=f,
                headers={
                    'Content-type': 'application/octet-stream',
                    'X-Goog-Upload-File-Name': name,
                    'X-Goog-Upload-Protocol': 'raw'
                })
            if response.status_code / 100 == 2:
                self.logger.info('Upload complete', photo=id, file=filename)
                c = self.db.cursor()
                c.execute(
                    f'UPDATE {ARTIFACTS_TABLE} SET uploaded=? WHERE id=?',
                    (response.content, id))
            else:
                raise Exception('Upload failed', response.status_code)
Beispiel #10
0
def import_csv():
    content = request.get_json()
    error_or_none = check_key_in_json(content,
                                      ['url_for_import', 'gcs_uri', 'key'])
    if error_or_none:
        return error_or_none
    (json_key_or_error, success) = validate_json_key(content['key'])
    if not success:
        return json_key_or_error
    url_for_import = content['url_for_import']
    try:
        credentials = service_account.Credentials.from_service_account_info(
            json_key_or_error)
        scoped_credentials = credentials.with_scopes(_DEFAULT_SCOPES)
        authed_session = AuthorizedSession(scoped_credentials)
        response = authed_session.post(url=url_for_import,
                                       data=json.dumps({
                                           'input_config': {
                                               'gcs_source': {
                                                   'csv_file_uri':
                                                   content['gcs_uri']
                                               }
                                           }
                                       })).json()
    except Exception as e:
        return _Error('Error post %r: %r' % (url_for_import, e))
    res = json.dumps({
        'success': True,
        'response': response,
    })
    return res
    async def _upload_photo_and_get_token(self, session: AuthorizedSession,
                                          photo_bytes: bytes):

        session.headers["Content-type"] = "application/octet-stream"
        session.headers["X-Goog-Upload-Protocol"] = "raw"

        upload_response = session.post(self.UPLOAD_URL, data=photo_bytes)
        return upload_response.text
Beispiel #12
0
def _send_pubsub_message(session: requests.AuthorizedSession, topic: str,
                         data: str) -> dict:
    url = f"https://pubsub.googleapis.com/v1/{topic}:publish"
    encoded_data = base64.b64encode(data.encode("utf-8"))

    publish_request = {"messages": [{"data": encoded_data.decode("utf-8")}]}

    resp = session.post(url, json=publish_request)
    resp.raise_for_status()

    return resp
Beispiel #13
0
def process_firebase_messages(lqueue, stop_event):
    firebaseSession = AuthorizedSession(credentials)
    baseUrl = FIREBASE_BASE_URL.format(args.firebaseAppName)
    print("hi, this is before debug -----0")
    while not stop_event.is_set():
        try:
            packet = lqueue.get(False)
            print("hi, this is try debug -----1")
        except Empty:
            print("hi, this is except debug -----1")
            time.sleep(NOTHING_TO_DO_DELAY)
            pass
        else:
            if packet is None:
                print("hi, this is none packet debug -----1")
                continue
            print("hi, this is debug -----0.01")
            print("data from queue: " + format(packet))  #debug
            firebasePath = packet['config']['firebasePath']
            if packet['config']['topicAsChild']:
                firebasePath = urllib.parse.urljoin(
                    packet['config']['firebasePath'] + '/', packet['topic'])
            firebasePath = baseUrl + '/' + firebasePath + '.json'
            print("Sending {0} to this URL {1}".format(packet['payload'],
                                                       firebasePath))  #debug
            retry = 0
            print("hi, this is debug -----1")
            while True:
                print("hi, this is debug -----2")
                try:
                    if not args.dryRun:  # https://obd-driving-data-default-rtdb.firebaseio.com/readings.json
                        r = firebaseSession.post(firebasePath,
                                                 json=packet['payload'],
                                                 timeout=FIREBASE_TIMEOUT
                                                 )  #replace with firebase path
                        print("payload inserted : " + r.text)  #debug
                #except firebase_admin.exceptions.
                except requests.exceptions.Timeout:
                    print("Firebase Timeout")
                    if retry < FIREBASE_MAX_RETRY:
                        retry += 1
                        debug("Retrying")
                        time.sleep(NOTHING_TO_DO_DELAY)
                        continue
                except requests.exceptions.RequestException as e:
                    print("Firebase Exception" + str(e))
                except Exception as e:
                    print(e)
                    print("Firebase Unknown Exception")
                break
            queue.task_done()
    firebaseSession.close()
    print("Stopping Firebase Thread ...")
Beispiel #14
0
def request_sync(key_file_name):
    credentials = service_account.Credentials.from_service_account_file(
        key_file_name)
    scoped_credentials = credentials.with_scopes(
        ['https://www.googleapis.com/auth/homegraph'])
    sess = AuthorizedSession(scoped_credentials)
    resp = sess.post('https://homegraph.googleapis.com/v1/devices:requestSync',
                     json={'agentUserId': '1'})

    resp.raise_for_status()

    return resp.json()
Beispiel #15
0
def start_resumable_upload_session(name, mime_type):
    """
    Mime type from the original file extension to upload file correctly. 

    """
    url = f"https://storage.googleapis.com/upload/storage/v1/b/{app.config['CLOUD_STORAGE_BUCKET']}/o?uploadType=resumable&name={name}"
    headers = {"X-Upload-Content-Type": mime_type}
    #prep an authenticated session to make requests
    authed_session = AuthorizedSession(credentials)

    resp = authed_session.post(url, headers=headers)
    if resp.status_code == 200:
        return resp.headers.get('Location', None)
    else:
        return None
class SheriffConfigClient(object):
    """Wrapping of sheriff-config HTTP API."""
    def __init__(self):
        """Make the Cloud Endpoints request from this handler."""
        credentials, _ = google.auth.default(
            scopes=['https://www.googleapis.com/auth/userinfo.email'])
        jwt_credentials = jwt.Credentials.from_signing_credentials(
            credentials, 'sheriff-config-dot-chromeperf.appspot.com')
        self._session = AuthorizedSession(jwt_credentials)

    @staticmethod
    def _SubscriptionToSheriff(subscription):
        sheriff = Sheriff(
            key=ndb.Key('Sheriff', subscription.name),
            internal_only=(subscription.visibility !=
                           sheriff_pb2.Subscription.PUBLIC),
            # Sheriff model only support glob patterns
            patterns=[p.glob for p in subscription.patterns if p.glob],
            labels=(list(subscription.bug_labels) + [
                'Component-' + c.replace('>', '-')
                for c in subscription.bug_components
            ]),
        )
        if subscription.rotation_url:
            sheriff.url = subscription.rotation_url
        if subscription.notification_email:
            sheriff.email = subscription.notification_email
        return sheriff

    def Match(self, path):
        response = self._session.post(
            'https://sheriff-config-dot-chromeperf.appspot.com/subscriptions/match',
            json={'path': path})
        if not response.ok:
            return None, '%r\n%s' % (response, response.text)
        match = json_format.Parse(response.text,
                                  sheriff_config_pb2.MatchResponse())
        return [
            self._SubscriptionToSheriff(s.subscription)
            for s in match.subscriptions
        ], None

    def Update(self):
        response = self._session.get(
            'https://sheriff-config-dot-chromeperf.appspot.com/configs/update')
        if response.ok:
            return True, None
        return False, '%r\n%s' % (response, response.text)
Beispiel #17
0
def _actually_list_media_items(session: AuthorizedSession):
    ret = []
    params = {
        "fields":
        "mediaItems(id,baseUrl,filename,mimeType,productUrl),nextPageToken",
    }
    search_json = {
        "pageSize": 100,
        "filters": {
            "includeArchivedMedia": False,
            "contentFilter": {
                "excludedContentCategories": [
                    "DOCUMENTS",
                    "RECEIPTS",
                    "SCREENSHOTS",
                    "UTILITY",
                    "WHITEBOARDS",
                ]
            },
            "mediaTypeFilter": {
                "mediaTypes": [
                    "PHOTO",
                ],
            },
        },
    }

    while True:
        rsp = session.post(
            "https://photoslibrary.googleapis.com/v1/mediaItems:search",
            params=params,
            json=search_json,
        ).json()
        if "error" in rsp:
            print(rsp)
            if rsp["error"].get("code", 429) == 503:
                continue
            return ret

        cur = [m for m in rsp.get("mediaItems", [])]
        ret += cur
        print(f"{len(cur)} new items, total {len(ret)}")

        pageToken = rsp.get("nextPageToken")
        if pageToken is None:
            break
        params["pageToken"] = pageToken
    return ret
    def _update_token(self, request):
        """Updates credentials with a new access_token representing
        the downscoped credentials.

        Args:
            request (google.auth.transport.requests.Request): Request object
                to use for refreshing credentials.
        """

        # Refresh our source credentials.
        self._source_credentials.refresh(request)

        request = google.auth.transport.requests.Request()

        ac = AnonymousCredentials()
        authed_session = AuthorizedSession(credentials=ac)

        body = {
            "grant_type": 'urn:ietf:params:oauth:grant-type:token-exchange',
            "subject_token_type":
            'urn:ietf:params:oauth:token-type:access_token',
            "requested_token_type":
            'urn:ietf:params:oauth:token-type:access_token',
            "subject_token": self._source_credentials.token,
            "options": json.dumps(self._downscoped_options)
        }

        resp = authed_session.post(_STS_ENDPOINT, data=body)
        if resp.status_code != http_client.OK:
            raise exceptions.RefreshError(_REFRESH_ERROR)

        data = resp.json()
        self.token = data['access_token']

        if 'expires_in' in data:
            self.expiry = datetime.now() + \
                timedelta(seconds=int(data['expires_in']))
        else:
            authed_session = AuthorizedSession(credentials=ac)
            payload = {'access_token': self._source_credentials.token}
            token_response = authed_session.get(_TOKEN_INFO_ENDPOINT,
                                                params=payload)
            if token_response.status_code != http_client.OK:
                raise exceptions.RefreshError(_TOKEN_INFO_ERROR)
            tokeninfo_data = token_response.json()
            self.expiry = datetime.now() + \
                timedelta(seconds=int(tokeninfo_data['expires_in']))
Beispiel #19
0
def backup_firestore(request: Request):
    """Backs up firestore DB

    :param request: flask Request
    """
    bucket_name = os.getenv('BACKUP_BUCKET')
    if not bucket_name:
        logging.error({
            "message": "Failed to perform backup",
            "reason": "Unspecified bucket"
        })

    prefix = "{timestamp}U{id}".format(
        timestamp=datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S"),
        id=str(uuid.uuid4())[:8])

    # create backup
    authorized_session = AuthorizedSession(credentials)
    response: requests.Response = authorized_session.post(
        'https://firestore.googleapis.com/v1beta1/projects/{project}/databases/(default):exportDocuments'
        .format(project=os.getenv('GCP_PROJECT')),
        json={
            "outputUriPrefix":
            "gs://{bucket}/{prefix}".format(prefix=prefix, bucket=bucket_name),
            # "collectionIds": ["breweries"]
        })
    logging.info({
        "message": "Firestore backup process finished",
        "result": "success" if response.status_code == 200 else "failure",
        "payload": response.text
    })

    if slack_client:
        if response.status_code == 200:
            slack_client.chat_postMessage(
                channel=slack_channel,
                text=
                "Firestore DB for *{project}* has been backed up. :partyparrot:"
                .format(project=os.getenv('GCP_PROJECT')))
        else:
            slack_client.chat_postMessage(
                channel=slack_channel,
                text=
                "Backup of Firestore DB for *{project}* has failed. :sadparrot:"
                .format(project=os.getenv('GCP_PROJECT')))
    def sign_bytes(self, message):

        iam_sign_endpoint = _IAM_SIGN_ENDPOINT.format(self._target_principal)

        body = {
            "payload": base64.b64encode(message).decode("utf-8"),
            "delegates": self._delegates,
        }

        headers = {"Content-Type": "application/json"}

        authed_session = AuthorizedSession(self._source_credentials)

        response = authed_session.post(
            url=iam_sign_endpoint, headers=headers, json=body
        )

        return base64.b64decode(response.json()["signedBlob"])
Beispiel #21
0
def post_request(session: AuthorizedSession, url: str, data: Any) -> None:
    """Posts a request to the given url.

  Args:
    session: The authorised session.
    url: The url.
    data: The data to be posted.

  Raises:
      Error: If the request was not processed successfully.
  """
    try:
        response = session.post(url, data)
        response.raise_for_status()
    except requests.exceptions.HTTPError as error:
        logging.exception('HTTPError "%s" "%s": post_request failed',
                          error.response.status_code, error.response.reason)
        raise Error('HTTPError {} {}: post_request failed.'.format(
            error.response.status_code, error.response.reason))
Beispiel #22
0
def product_search():
    result = parse_product_search_request(request)
    if type(result) == type(''):
        return _Error(result)
    try:
        (json_key, endpoint, product_search_request_json) = result
        credentials = service_account.Credentials.from_service_account_info(
            json_key)
        scoped_credentials = credentials.with_scopes(_DEFAULT_SCOPES)
        authed_session = AuthorizedSession(scoped_credentials)
        url = os.path.join(endpoint, 'images:annotate')
        response = authed_session.post(
            url=url, data=json.dumps(product_search_request_json)).json()
    except Exception as e:
        return _Error('Internal error: ' + str(e))
    return json.dumps({
        'success': True,
        'response': response,
    })
Beispiel #23
0
def onNewFile(event, context):

    print('Event ID: {}'.format(context.event_id))
    print('Event type: {}'.format(context.event_type))
    print('Bucket: {}'.format(event['bucket']))
    print('File: {}'.format(event['name']))

    scoped_credentials, project = google.auth.default(
        scopes=['https://www.googleapis.com/auth/cloud-platform'])
    authed_session = AuthorizedSession(scoped_credentials)

    URL = 'https://workflowexecutions.googleapis.com/v1/projects/YOUR_PROJECT/locations/YOUR_REGION/workflows/sample-workflow/executions'
    file_id_dict = {
        'bucket': '{}'.format(event['bucket']),
        'object': '{}'.format(event['name'])
    }
    PARAMS = {'argument': json.dumps(file_id_dict)}
    response = authed_session.post(url=URL, json=PARAMS)

    print(response)
def process_firebase_messages(lqueue, stop_event):
  firebaseSession = AuthorizedSession(credentials)
  baseUrl = FIREBASE_BASE_URL.format(args.firebaseAppName)

  while not stop_event.is_set():
    try:
      packet = lqueue.get(False)
    except Empty:
      time.sleep(NOTHING_TO_DO_DELAY)
      pass
    else:
      if packet is None:
        continue
      debug("data from queue: " + format(packet))
      firebasePath = packet['config']['firebasePath']
      if packet['config']['topicAsChild']:
        firebasePath = urllib.parse.urljoin(packet['config']['firebasePath'] + '/', packet['topic'])
      firebasePath = baseUrl + '/' + firebasePath + '.json'
      debug ("Sending {0} to this URL {1}".format(packet['payload'], firebasePath))
      retry = 0
      while True:
        try:
          if not args.dryRun:
            r = firebaseSession.post(firebasePath, json=packet['payload'], timeout=FIREBASE_TIMEOUT)
            debug ("payload inserted : " + r.text)
        except requests.exceptions.Timeout:
          print ("Firebase Timeout")
          if retry < FIREBASE_MAX_RETRY:
            retry += 1
            debug ("Retrying")
            time.sleep(NOTHING_TO_DO_DELAY)
            continue
        except requests.exceptions.RequestException as e:
          print ("Firebase Exception" + str(e))
        except:
          print ("Firebase Unknown Exception")
        break
      queue.task_done()
  firebaseSession.close()
  debug("Stopping Firebase Thread ...")
def down_scope_access_token(access_type, access_bucket, short_lived_token):
    request = google.auth.transport.requests.Request()
    ac = AnonymousCredentials()
    authed_session = AuthorizedSession(credentials=ac)
    body = {
        "grant_type":
        "urn:ietf:params:oauth:grant-type:token-exchange",
        "subject_token_type":
        "urn:ietf:params:oauth:token-type:access_token",
        "requested_token_type":
        "urn:ietf:params:oauth:token-type:access_token",
        "subject_token":
        short_lived_token,
        "options":
        json.dumps(create_downscoped_options(access_type, access_bucket))
    }

    resp = authed_session.post(_STS_ENDPOINT, data=body)
    if resp.status_code != http_client.OK:
        raise exceptions.RefreshError("Failed to acquire downscoped token")

    return resp.json()
Beispiel #26
0
    def sign_bytes(self, message):

        iam_sign_endpoint = _IAM_SIGN_ENDPOINT.format(self._target_principal)

        body = {
            "payload": base64.b64encode(message).decode("utf-8"),
            "delegates": self._delegates,
        }

        headers = {"Content-Type": "application/json"}

        authed_session = AuthorizedSession(self._source_credentials)

        response = authed_session.post(url=iam_sign_endpoint,
                                       headers=headers,
                                       json=body)

        if response.status_code != http_client.OK:
            raise exceptions.TransportError(
                "Error calling sign_bytes: {}".format(response.json()))

        return base64.b64decode(response.json()["signedBlob"])
Beispiel #27
0
class RoutersRestTransport(RoutersTransport):
    """REST backend transport for Routers.

    The Routers API.

    This class defines the same methods as the primary client, so the
    primary client can load the underlying transport implementation
    and call it.

    It sends JSON representations of protocol buffers over HTTP/1.1
    """
    def __init__(
        self,
        *,
        host: str = "compute.googleapis.com",
        credentials: ga_credentials.Credentials = None,
        credentials_file: str = None,
        scopes: Sequence[str] = None,
        client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None,
        quota_project_id: Optional[str] = None,
        client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
    ) -> None:
        """Instantiate the transport.

        Args:
            host (Optional[str]):
                 The hostname to connect to.
            credentials (Optional[google.auth.credentials.Credentials]): The
                authorization credentials to attach to requests. These
                credentials identify the application to the service; if none
                are specified, the client will attempt to ascertain the
                credentials from the environment.

            credentials_file (Optional[str]): A file with credentials that can
                be loaded with :func:`google.auth.load_credentials_from_file`.
                This argument is ignored if ``channel`` is provided.
            scopes (Optional(Sequence[str])): A list of scopes. This argument is
                ignored if ``channel`` is provided.
            client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client
                certificate to configure mutual TLS HTTP channel. It is ignored
                if ``channel`` is provided.
            quota_project_id (Optional[str]): An optional project to use for billing
                and quota.
            client_info (google.api_core.gapic_v1.client_info.ClientInfo):
                The client info used to send a user-agent string along with
                API requests. If ``None``, then default info will be used.
                Generally, you only need to set this if you're developing
                your own client library.
        """
        # Run the base constructor
        # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc.
        # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the
        # credentials object
        super().__init__(
            host=host,
            credentials=credentials,
            client_info=client_info,
        )
        self._session = AuthorizedSession(self._credentials,
                                          default_host=self.DEFAULT_HOST)
        if client_cert_source_for_mtls:
            self._session.configure_mtls_channel(client_cert_source_for_mtls)
        self._prep_wrapped_messages(client_info)

    def aggregated_list(
        self,
        request: compute.AggregatedListRoutersRequest,
        *,
        metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.RouterAggregatedList:
        r"""Call the aggregated list method over HTTP.

        Args:
            request (~.compute.AggregatedListRoutersRequest):
                The request object. A request message for
                Routers.AggregatedList. See the method
                description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.RouterAggregatedList:
                Contains a list of routers.
        """

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/aggregated/routers".format(
            host=self._host,
            project=request.project,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}
        if compute.AggregatedListRoutersRequest.filter in request:
            query_params["filter"] = request.filter
        if compute.AggregatedListRoutersRequest.include_all_scopes in request:
            query_params["includeAllScopes"] = request.include_all_scopes
        if compute.AggregatedListRoutersRequest.max_results in request:
            query_params["maxResults"] = request.max_results
        if compute.AggregatedListRoutersRequest.order_by in request:
            query_params["orderBy"] = request.order_by
        if compute.AggregatedListRoutersRequest.page_token in request:
            query_params["pageToken"] = request.page_token
        if compute.AggregatedListRoutersRequest.return_partial_success in request:
            query_params[
                "returnPartialSuccess"] = request.return_partial_success

        # TODO(yon-mg): further discussion needed whether 'python truthiness' is appropriate here
        #               discards default values
        # TODO(yon-mg): add test for proper url encoded strings
        query_params = [
            "{k}={v}".format(k=k, v=v) for k, v in query_params.items()
        ]
        url += "?{}".format("&".join(query_params)).replace(" ", "+")

        # Send the request
        headers = dict(metadata)
        headers["Content-Type"] = "application/json"
        response = self._session.get(
            url,
            headers=headers,
        )

        # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception
        # subclass.
        if response.status_code >= 400:
            raise core_exceptions.from_http_response(response)

        # Return the response
        return compute.RouterAggregatedList.from_json(
            response.content, ignore_unknown_fields=True)

    def delete(
            self,
            request: compute.DeleteRouterRequest,
            *,
            metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.Operation:
        r"""Call the delete method over HTTP.

        Args:
            request (~.compute.DeleteRouterRequest):
                The request object. A request message for Routers.Delete.
                See the method description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.Operation:
                Represents an Operation resource.

                Google Compute Engine has three Operation resources:

                -  `Global </compute/docs/reference/rest/{$api_version}/globalOperations>`__
                   \*
                   `Regional </compute/docs/reference/rest/{$api_version}/regionOperations>`__
                   \*
                   `Zonal </compute/docs/reference/rest/{$api_version}/zoneOperations>`__

                You can use an operation resource to manage asynchronous
                API requests. For more information, read Handling API
                responses.

                Operations can be global, regional or zonal.

                -  For global operations, use the ``globalOperations``
                   resource.
                -  For regional operations, use the ``regionOperations``
                   resource.
                -  For zonal operations, use the ``zonalOperations``
                   resource.

                For more information, read Global, Regional, and Zonal
                Resources. (== resource_for
                {$api_version}.globalOperations ==) (== resource_for
                {$api_version}.regionOperations ==) (== resource_for
                {$api_version}.zoneOperations ==)

        """

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/regions/{region}/routers/{router}".format(
            host=self._host,
            project=request.project,
            region=request.region,
            router=request.router,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}
        if compute.DeleteRouterRequest.request_id in request:
            query_params["requestId"] = request.request_id

        # TODO(yon-mg): further discussion needed whether 'python truthiness' is appropriate here
        #               discards default values
        # TODO(yon-mg): add test for proper url encoded strings
        query_params = [
            "{k}={v}".format(k=k, v=v) for k, v in query_params.items()
        ]
        url += "?{}".format("&".join(query_params)).replace(" ", "+")

        # Send the request
        headers = dict(metadata)
        headers["Content-Type"] = "application/json"
        response = self._session.delete(
            url,
            headers=headers,
        )

        # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception
        # subclass.
        if response.status_code >= 400:
            raise core_exceptions.from_http_response(response)

        # Return the response
        return compute.Operation.from_json(response.content,
                                           ignore_unknown_fields=True)

    def get(
            self,
            request: compute.GetRouterRequest,
            *,
            metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.Router:
        r"""Call the get method over HTTP.

        Args:
            request (~.compute.GetRouterRequest):
                The request object. A request message for Routers.Get.
                See the method description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.Router:
                Represents a Cloud Router resource.
                For more information about Cloud Router,
                read the Cloud Router overview.

        """

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/regions/{region}/routers/{router}".format(
            host=self._host,
            project=request.project,
            region=request.region,
            router=request.router,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}

        # TODO(yon-mg): further discussion needed whether 'python truthiness' is appropriate here
        #               discards default values
        # TODO(yon-mg): add test for proper url encoded strings
        query_params = [
            "{k}={v}".format(k=k, v=v) for k, v in query_params.items()
        ]
        url += "?{}".format("&".join(query_params)).replace(" ", "+")

        # Send the request
        headers = dict(metadata)
        headers["Content-Type"] = "application/json"
        response = self._session.get(
            url,
            headers=headers,
        )

        # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception
        # subclass.
        if response.status_code >= 400:
            raise core_exceptions.from_http_response(response)

        # Return the response
        return compute.Router.from_json(response.content,
                                        ignore_unknown_fields=True)

    def get_nat_mapping_info(
        self,
        request: compute.GetNatMappingInfoRoutersRequest,
        *,
        metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.VmEndpointNatMappingsList:
        r"""Call the get nat mapping info method over HTTP.

        Args:
            request (~.compute.GetNatMappingInfoRoutersRequest):
                The request object. A request message for
                Routers.GetNatMappingInfo. See the
                method description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.VmEndpointNatMappingsList:
                Contains a list of
                VmEndpointNatMappings.

        """

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/regions/{region}/routers/{router}/getNatMappingInfo".format(
            host=self._host,
            project=request.project,
            region=request.region,
            router=request.router,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}
        if compute.GetNatMappingInfoRoutersRequest.filter in request:
            query_params["filter"] = request.filter
        if compute.GetNatMappingInfoRoutersRequest.max_results in request:
            query_params["maxResults"] = request.max_results
        if compute.GetNatMappingInfoRoutersRequest.order_by in request:
            query_params["orderBy"] = request.order_by
        if compute.GetNatMappingInfoRoutersRequest.page_token in request:
            query_params["pageToken"] = request.page_token
        if compute.GetNatMappingInfoRoutersRequest.return_partial_success in request:
            query_params[
                "returnPartialSuccess"] = request.return_partial_success

        # TODO(yon-mg): further discussion needed whether 'python truthiness' is appropriate here
        #               discards default values
        # TODO(yon-mg): add test for proper url encoded strings
        query_params = [
            "{k}={v}".format(k=k, v=v) for k, v in query_params.items()
        ]
        url += "?{}".format("&".join(query_params)).replace(" ", "+")

        # Send the request
        headers = dict(metadata)
        headers["Content-Type"] = "application/json"
        response = self._session.get(
            url,
            headers=headers,
        )

        # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception
        # subclass.
        if response.status_code >= 400:
            raise core_exceptions.from_http_response(response)

        # Return the response
        return compute.VmEndpointNatMappingsList.from_json(
            response.content, ignore_unknown_fields=True)

    def get_router_status(
        self,
        request: compute.GetRouterStatusRouterRequest,
        *,
        metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.RouterStatusResponse:
        r"""Call the get router status method over HTTP.

        Args:
            request (~.compute.GetRouterStatusRouterRequest):
                The request object. A request message for
                Routers.GetRouterStatus. See the method
                description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.RouterStatusResponse:

        """

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/regions/{region}/routers/{router}/getRouterStatus".format(
            host=self._host,
            project=request.project,
            region=request.region,
            router=request.router,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}

        # TODO(yon-mg): further discussion needed whether 'python truthiness' is appropriate here
        #               discards default values
        # TODO(yon-mg): add test for proper url encoded strings
        query_params = [
            "{k}={v}".format(k=k, v=v) for k, v in query_params.items()
        ]
        url += "?{}".format("&".join(query_params)).replace(" ", "+")

        # Send the request
        headers = dict(metadata)
        headers["Content-Type"] = "application/json"
        response = self._session.get(
            url,
            headers=headers,
        )

        # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception
        # subclass.
        if response.status_code >= 400:
            raise core_exceptions.from_http_response(response)

        # Return the response
        return compute.RouterStatusResponse.from_json(
            response.content, ignore_unknown_fields=True)

    def insert(
            self,
            request: compute.InsertRouterRequest,
            *,
            metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.Operation:
        r"""Call the insert method over HTTP.

        Args:
            request (~.compute.InsertRouterRequest):
                The request object. A request message for Routers.Insert.
                See the method description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.Operation:
                Represents an Operation resource.

                Google Compute Engine has three Operation resources:

                -  `Global </compute/docs/reference/rest/{$api_version}/globalOperations>`__
                   \*
                   `Regional </compute/docs/reference/rest/{$api_version}/regionOperations>`__
                   \*
                   `Zonal </compute/docs/reference/rest/{$api_version}/zoneOperations>`__

                You can use an operation resource to manage asynchronous
                API requests. For more information, read Handling API
                responses.

                Operations can be global, regional or zonal.

                -  For global operations, use the ``globalOperations``
                   resource.
                -  For regional operations, use the ``regionOperations``
                   resource.
                -  For zonal operations, use the ``zonalOperations``
                   resource.

                For more information, read Global, Regional, and Zonal
                Resources. (== resource_for
                {$api_version}.globalOperations ==) (== resource_for
                {$api_version}.regionOperations ==) (== resource_for
                {$api_version}.zoneOperations ==)

        """

        # Jsonify the request body
        body = compute.Router.to_json(
            request.router_resource,
            including_default_value_fields=False,
            use_integers_for_enums=False,
        )

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/regions/{region}/routers".format(
            host=self._host,
            project=request.project,
            region=request.region,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}
        if compute.InsertRouterRequest.request_id in request:
            query_params["requestId"] = request.request_id

        # TODO(yon-mg): further discussion needed whether 'python truthiness' is appropriate here
        #               discards default values
        # TODO(yon-mg): add test for proper url encoded strings
        query_params = [
            "{k}={v}".format(k=k, v=v) for k, v in query_params.items()
        ]
        url += "?{}".format("&".join(query_params)).replace(" ", "+")

        # Send the request
        headers = dict(metadata)
        headers["Content-Type"] = "application/json"
        response = self._session.post(
            url,
            headers=headers,
            data=body,
        )

        # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception
        # subclass.
        if response.status_code >= 400:
            raise core_exceptions.from_http_response(response)

        # Return the response
        return compute.Operation.from_json(response.content,
                                           ignore_unknown_fields=True)

    def list(
            self,
            request: compute.ListRoutersRequest,
            *,
            metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.RouterList:
        r"""Call the list method over HTTP.

        Args:
            request (~.compute.ListRoutersRequest):
                The request object. A request message for Routers.List.
                See the method description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.RouterList:
                Contains a list of Router resources.
        """

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/regions/{region}/routers".format(
            host=self._host,
            project=request.project,
            region=request.region,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}
        if compute.ListRoutersRequest.filter in request:
            query_params["filter"] = request.filter
        if compute.ListRoutersRequest.max_results in request:
            query_params["maxResults"] = request.max_results
        if compute.ListRoutersRequest.order_by in request:
            query_params["orderBy"] = request.order_by
        if compute.ListRoutersRequest.page_token in request:
            query_params["pageToken"] = request.page_token
        if compute.ListRoutersRequest.return_partial_success in request:
            query_params[
                "returnPartialSuccess"] = request.return_partial_success

        # TODO(yon-mg): further discussion needed whether 'python truthiness' is appropriate here
        #               discards default values
        # TODO(yon-mg): add test for proper url encoded strings
        query_params = [
            "{k}={v}".format(k=k, v=v) for k, v in query_params.items()
        ]
        url += "?{}".format("&".join(query_params)).replace(" ", "+")

        # Send the request
        headers = dict(metadata)
        headers["Content-Type"] = "application/json"
        response = self._session.get(
            url,
            headers=headers,
        )

        # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception
        # subclass.
        if response.status_code >= 400:
            raise core_exceptions.from_http_response(response)

        # Return the response
        return compute.RouterList.from_json(response.content,
                                            ignore_unknown_fields=True)

    def patch(
            self,
            request: compute.PatchRouterRequest,
            *,
            metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.Operation:
        r"""Call the patch method over HTTP.

        Args:
            request (~.compute.PatchRouterRequest):
                The request object. A request message for Routers.Patch.
                See the method description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.Operation:
                Represents an Operation resource.

                Google Compute Engine has three Operation resources:

                -  `Global </compute/docs/reference/rest/{$api_version}/globalOperations>`__
                   \*
                   `Regional </compute/docs/reference/rest/{$api_version}/regionOperations>`__
                   \*
                   `Zonal </compute/docs/reference/rest/{$api_version}/zoneOperations>`__

                You can use an operation resource to manage asynchronous
                API requests. For more information, read Handling API
                responses.

                Operations can be global, regional or zonal.

                -  For global operations, use the ``globalOperations``
                   resource.
                -  For regional operations, use the ``regionOperations``
                   resource.
                -  For zonal operations, use the ``zonalOperations``
                   resource.

                For more information, read Global, Regional, and Zonal
                Resources. (== resource_for
                {$api_version}.globalOperations ==) (== resource_for
                {$api_version}.regionOperations ==) (== resource_for
                {$api_version}.zoneOperations ==)

        """

        # Jsonify the request body
        body = compute.Router.to_json(
            request.router_resource,
            including_default_value_fields=False,
            use_integers_for_enums=False,
        )

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/regions/{region}/routers/{router}".format(
            host=self._host,
            project=request.project,
            region=request.region,
            router=request.router,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}
        if compute.PatchRouterRequest.request_id in request:
            query_params["requestId"] = request.request_id

        # TODO(yon-mg): further discussion needed whether 'python truthiness' is appropriate here
        #               discards default values
        # TODO(yon-mg): add test for proper url encoded strings
        query_params = [
            "{k}={v}".format(k=k, v=v) for k, v in query_params.items()
        ]
        url += "?{}".format("&".join(query_params)).replace(" ", "+")

        # Send the request
        headers = dict(metadata)
        headers["Content-Type"] = "application/json"
        response = self._session.patch(
            url,
            headers=headers,
            data=body,
        )

        # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception
        # subclass.
        if response.status_code >= 400:
            raise core_exceptions.from_http_response(response)

        # Return the response
        return compute.Operation.from_json(response.content,
                                           ignore_unknown_fields=True)

    def preview(
        self,
        request: compute.PreviewRouterRequest,
        *,
        metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.RoutersPreviewResponse:
        r"""Call the preview method over HTTP.

        Args:
            request (~.compute.PreviewRouterRequest):
                The request object. A request message for
                Routers.Preview. See the method
                description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.RoutersPreviewResponse:

        """

        # Jsonify the request body
        body = compute.Router.to_json(
            request.router_resource,
            including_default_value_fields=False,
            use_integers_for_enums=False,
        )

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/regions/{region}/routers/{router}/preview".format(
            host=self._host,
            project=request.project,
            region=request.region,
            router=request.router,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}

        # TODO(yon-mg): further discussion needed whether 'python truthiness' is appropriate here
        #               discards default values
        # TODO(yon-mg): add test for proper url encoded strings
        query_params = [
            "{k}={v}".format(k=k, v=v) for k, v in query_params.items()
        ]
        url += "?{}".format("&".join(query_params)).replace(" ", "+")

        # Send the request
        headers = dict(metadata)
        headers["Content-Type"] = "application/json"
        response = self._session.post(
            url,
            headers=headers,
            data=body,
        )

        # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception
        # subclass.
        if response.status_code >= 400:
            raise core_exceptions.from_http_response(response)

        # Return the response
        return compute.RoutersPreviewResponse.from_json(
            response.content, ignore_unknown_fields=True)

    def update(
            self,
            request: compute.UpdateRouterRequest,
            *,
            metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.Operation:
        r"""Call the update method over HTTP.

        Args:
            request (~.compute.UpdateRouterRequest):
                The request object. A request message for Routers.Update.
                See the method description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.Operation:
                Represents an Operation resource.

                Google Compute Engine has three Operation resources:

                -  `Global </compute/docs/reference/rest/{$api_version}/globalOperations>`__
                   \*
                   `Regional </compute/docs/reference/rest/{$api_version}/regionOperations>`__
                   \*
                   `Zonal </compute/docs/reference/rest/{$api_version}/zoneOperations>`__

                You can use an operation resource to manage asynchronous
                API requests. For more information, read Handling API
                responses.

                Operations can be global, regional or zonal.

                -  For global operations, use the ``globalOperations``
                   resource.
                -  For regional operations, use the ``regionOperations``
                   resource.
                -  For zonal operations, use the ``zonalOperations``
                   resource.

                For more information, read Global, Regional, and Zonal
                Resources. (== resource_for
                {$api_version}.globalOperations ==) (== resource_for
                {$api_version}.regionOperations ==) (== resource_for
                {$api_version}.zoneOperations ==)

        """

        # Jsonify the request body
        body = compute.Router.to_json(
            request.router_resource,
            including_default_value_fields=False,
            use_integers_for_enums=False,
        )

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/regions/{region}/routers/{router}".format(
            host=self._host,
            project=request.project,
            region=request.region,
            router=request.router,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}
        if compute.UpdateRouterRequest.request_id in request:
            query_params["requestId"] = request.request_id

        # TODO(yon-mg): further discussion needed whether 'python truthiness' is appropriate here
        #               discards default values
        # TODO(yon-mg): add test for proper url encoded strings
        query_params = [
            "{k}={v}".format(k=k, v=v) for k, v in query_params.items()
        ]
        url += "?{}".format("&".join(query_params)).replace(" ", "+")

        # Send the request
        headers = dict(metadata)
        headers["Content-Type"] = "application/json"
        response = self._session.put(
            url,
            headers=headers,
            data=body,
        )

        # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception
        # subclass.
        if response.status_code >= 400:
            raise core_exceptions.from_http_response(response)

        # Return the response
        return compute.Operation.from_json(response.content,
                                           ignore_unknown_fields=True)
Beispiel #28
0
class RegionUrlMapsRestTransport(RegionUrlMapsTransport):
    """REST backend transport for RegionUrlMaps.

    The RegionUrlMaps API.

    This class defines the same methods as the primary client, so the
    primary client can load the underlying transport implementation
    and call it.

    It sends JSON representations of protocol buffers over HTTP/1.1
    """

    def __init__(
        self,
        *,
        host: str = "compute.googleapis.com",
        credentials: ga_credentials.Credentials = None,
        credentials_file: str = None,
        scopes: Sequence[str] = None,
        client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None,
        quota_project_id: Optional[str] = None,
        client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
    ) -> None:
        """Instantiate the transport.

        Args:
            host (Optional[str]):
                 The hostname to connect to.
            credentials (Optional[google.auth.credentials.Credentials]): The
                authorization credentials to attach to requests. These
                credentials identify the application to the service; if none
                are specified, the client will attempt to ascertain the
                credentials from the environment.

            credentials_file (Optional[str]): A file with credentials that can
                be loaded with :func:`google.auth.load_credentials_from_file`.
                This argument is ignored if ``channel`` is provided.
            scopes (Optional(Sequence[str])): A list of scopes. This argument is
                ignored if ``channel`` is provided.
            client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client
                certificate to configure mutual TLS HTTP channel. It is ignored
                if ``channel`` is provided.
            quota_project_id (Optional[str]): An optional project to use for billing
                and quota.
            client_info (google.api_core.gapic_v1.client_info.ClientInfo):
                The client info used to send a user-agent string along with
                API requests. If ``None``, then default info will be used.
                Generally, you only need to set this if you're developing
                your own client library.
        """
        # Run the base constructor
        # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc.
        # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the
        # credentials object
        super().__init__(
            host=host, credentials=credentials, client_info=client_info,
        )
        self._session = AuthorizedSession(
            self._credentials, default_host=self.DEFAULT_HOST
        )
        if client_cert_source_for_mtls:
            self._session.configure_mtls_channel(client_cert_source_for_mtls)
        self._prep_wrapped_messages(client_info)

    def delete(
        self,
        request: compute.DeleteRegionUrlMapRequest,
        *,
        metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.Operation:
        r"""Call the delete method over HTTP.

        Args:
            request (~.compute.DeleteRegionUrlMapRequest):
                The request object. A request message for
                RegionUrlMaps.Delete. See the method
                description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.Operation:
                Represents an Operation resource.

                Google Compute Engine has three Operation resources:

                -  `Global </compute/docs/reference/rest/{$api_version}/globalOperations>`__
                   \*
                   `Regional </compute/docs/reference/rest/{$api_version}/regionOperations>`__
                   \*
                   `Zonal </compute/docs/reference/rest/{$api_version}/zoneOperations>`__

                You can use an operation resource to manage asynchronous
                API requests. For more information, read Handling API
                responses.

                Operations can be global, regional or zonal.

                -  For global operations, use the ``globalOperations``
                   resource.
                -  For regional operations, use the ``regionOperations``
                   resource.
                -  For zonal operations, use the ``zonalOperations``
                   resource.

                For more information, read Global, Regional, and Zonal
                Resources. (== resource_for
                {$api_version}.globalOperations ==) (== resource_for
                {$api_version}.regionOperations ==) (== resource_for
                {$api_version}.zoneOperations ==)

        """

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/regions/{region}/urlMaps/{url_map}".format(
            host=self._host,
            project=request.project,
            region=request.region,
            url_map=request.url_map,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}
        if compute.DeleteRegionUrlMapRequest.request_id in request:
            query_params["requestId"] = request.request_id

        # TODO(yon-mg): further discussion needed whether 'python truthiness' is appropriate here
        #               discards default values
        # TODO(yon-mg): add test for proper url encoded strings
        query_params = ["{k}={v}".format(k=k, v=v) for k, v in query_params.items()]
        url += "?{}".format("&".join(query_params)).replace(" ", "+")

        # Send the request
        response = self._session.delete(url,)

        # Raise requests.exceptions.HTTPError if the status code is >= 400
        response.raise_for_status()

        # Return the response
        return compute.Operation.from_json(response.content, ignore_unknown_fields=True)

    def get(
        self,
        request: compute.GetRegionUrlMapRequest,
        *,
        metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.UrlMap:
        r"""Call the get method over HTTP.

        Args:
            request (~.compute.GetRegionUrlMapRequest):
                The request object. A request message for
                RegionUrlMaps.Get. See the method
                description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.UrlMap:
                Represents a URL Map resource.

                Google Compute Engine has two URL Map resources:

                -  `Global </compute/docs/reference/rest/{$api_version}/urlMaps>`__
                   \*
                   `Regional </compute/docs/reference/rest/{$api_version}/regionUrlMaps>`__

                A URL map resource is a component of certain types of
                GCP load balancers and Traffic Director.

                -  urlMaps are used by external HTTP(S) load balancers
                   and Traffic Director. \* regionUrlMaps are used by
                   internal HTTP(S) load balancers.

                For a list of supported URL map features by load
                balancer type, see the Load balancing features: Routing
                and traffic management table.

                For a list of supported URL map features for Traffic
                Director, see the Traffic Director features: Routing and
                traffic management table.

                This resource defines mappings from host names and URL
                paths to either a backend service or a backend bucket.

                To use the global urlMaps resource, the backend service
                must have a loadBalancingScheme of either EXTERNAL or
                INTERNAL_SELF_MANAGED. To use the regionUrlMaps
                resource, the backend service must have a
                loadBalancingScheme of INTERNAL_MANAGED. For more
                information, read URL Map Concepts.

        """

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/regions/{region}/urlMaps/{url_map}".format(
            host=self._host,
            project=request.project,
            region=request.region,
            url_map=request.url_map,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}

        # TODO(yon-mg): further discussion needed whether 'python truthiness' is appropriate here
        #               discards default values
        # TODO(yon-mg): add test for proper url encoded strings
        query_params = ["{k}={v}".format(k=k, v=v) for k, v in query_params.items()]
        url += "?{}".format("&".join(query_params)).replace(" ", "+")

        # Send the request
        response = self._session.get(url,)

        # Raise requests.exceptions.HTTPError if the status code is >= 400
        response.raise_for_status()

        # Return the response
        return compute.UrlMap.from_json(response.content, ignore_unknown_fields=True)

    def insert(
        self,
        request: compute.InsertRegionUrlMapRequest,
        *,
        metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.Operation:
        r"""Call the insert method over HTTP.

        Args:
            request (~.compute.InsertRegionUrlMapRequest):
                The request object. A request message for
                RegionUrlMaps.Insert. See the method
                description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.Operation:
                Represents an Operation resource.

                Google Compute Engine has three Operation resources:

                -  `Global </compute/docs/reference/rest/{$api_version}/globalOperations>`__
                   \*
                   `Regional </compute/docs/reference/rest/{$api_version}/regionOperations>`__
                   \*
                   `Zonal </compute/docs/reference/rest/{$api_version}/zoneOperations>`__

                You can use an operation resource to manage asynchronous
                API requests. For more information, read Handling API
                responses.

                Operations can be global, regional or zonal.

                -  For global operations, use the ``globalOperations``
                   resource.
                -  For regional operations, use the ``regionOperations``
                   resource.
                -  For zonal operations, use the ``zonalOperations``
                   resource.

                For more information, read Global, Regional, and Zonal
                Resources. (== resource_for
                {$api_version}.globalOperations ==) (== resource_for
                {$api_version}.regionOperations ==) (== resource_for
                {$api_version}.zoneOperations ==)

        """

        # Jsonify the request body
        body = compute.UrlMap.to_json(
            request.url_map_resource,
            including_default_value_fields=False,
            use_integers_for_enums=False,
        )

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/regions/{region}/urlMaps".format(
            host=self._host, project=request.project, region=request.region,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}
        if compute.InsertRegionUrlMapRequest.request_id in request:
            query_params["requestId"] = request.request_id

        # TODO(yon-mg): further discussion needed whether 'python truthiness' is appropriate here
        #               discards default values
        # TODO(yon-mg): add test for proper url encoded strings
        query_params = ["{k}={v}".format(k=k, v=v) for k, v in query_params.items()]
        url += "?{}".format("&".join(query_params)).replace(" ", "+")

        # Send the request
        response = self._session.post(url, data=body,)

        # Raise requests.exceptions.HTTPError if the status code is >= 400
        response.raise_for_status()

        # Return the response
        return compute.Operation.from_json(response.content, ignore_unknown_fields=True)

    def list(
        self,
        request: compute.ListRegionUrlMapsRequest,
        *,
        metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.UrlMapList:
        r"""Call the list method over HTTP.

        Args:
            request (~.compute.ListRegionUrlMapsRequest):
                The request object. A request message for
                RegionUrlMaps.List. See the method
                description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.UrlMapList:
                Contains a list of UrlMap resources.
        """

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/regions/{region}/urlMaps".format(
            host=self._host, project=request.project, region=request.region,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}
        if compute.ListRegionUrlMapsRequest.filter in request:
            query_params["filter"] = request.filter
        if compute.ListRegionUrlMapsRequest.max_results in request:
            query_params["maxResults"] = request.max_results
        if compute.ListRegionUrlMapsRequest.order_by in request:
            query_params["orderBy"] = request.order_by
        if compute.ListRegionUrlMapsRequest.page_token in request:
            query_params["pageToken"] = request.page_token
        if compute.ListRegionUrlMapsRequest.return_partial_success in request:
            query_params["returnPartialSuccess"] = request.return_partial_success

        # TODO(yon-mg): further discussion needed whether 'python truthiness' is appropriate here
        #               discards default values
        # TODO(yon-mg): add test for proper url encoded strings
        query_params = ["{k}={v}".format(k=k, v=v) for k, v in query_params.items()]
        url += "?{}".format("&".join(query_params)).replace(" ", "+")

        # Send the request
        response = self._session.get(url,)

        # Raise requests.exceptions.HTTPError if the status code is >= 400
        response.raise_for_status()

        # Return the response
        return compute.UrlMapList.from_json(
            response.content, ignore_unknown_fields=True
        )

    def patch(
        self,
        request: compute.PatchRegionUrlMapRequest,
        *,
        metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.Operation:
        r"""Call the patch method over HTTP.

        Args:
            request (~.compute.PatchRegionUrlMapRequest):
                The request object. A request message for
                RegionUrlMaps.Patch. See the method
                description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.Operation:
                Represents an Operation resource.

                Google Compute Engine has three Operation resources:

                -  `Global </compute/docs/reference/rest/{$api_version}/globalOperations>`__
                   \*
                   `Regional </compute/docs/reference/rest/{$api_version}/regionOperations>`__
                   \*
                   `Zonal </compute/docs/reference/rest/{$api_version}/zoneOperations>`__

                You can use an operation resource to manage asynchronous
                API requests. For more information, read Handling API
                responses.

                Operations can be global, regional or zonal.

                -  For global operations, use the ``globalOperations``
                   resource.
                -  For regional operations, use the ``regionOperations``
                   resource.
                -  For zonal operations, use the ``zonalOperations``
                   resource.

                For more information, read Global, Regional, and Zonal
                Resources. (== resource_for
                {$api_version}.globalOperations ==) (== resource_for
                {$api_version}.regionOperations ==) (== resource_for
                {$api_version}.zoneOperations ==)

        """

        # Jsonify the request body
        body = compute.UrlMap.to_json(
            request.url_map_resource,
            including_default_value_fields=False,
            use_integers_for_enums=False,
        )

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/regions/{region}/urlMaps/{url_map}".format(
            host=self._host,
            project=request.project,
            region=request.region,
            url_map=request.url_map,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}
        if compute.PatchRegionUrlMapRequest.request_id in request:
            query_params["requestId"] = request.request_id

        # TODO(yon-mg): further discussion needed whether 'python truthiness' is appropriate here
        #               discards default values
        # TODO(yon-mg): add test for proper url encoded strings
        query_params = ["{k}={v}".format(k=k, v=v) for k, v in query_params.items()]
        url += "?{}".format("&".join(query_params)).replace(" ", "+")

        # Send the request
        response = self._session.patch(url, data=body,)

        # Raise requests.exceptions.HTTPError if the status code is >= 400
        response.raise_for_status()

        # Return the response
        return compute.Operation.from_json(response.content, ignore_unknown_fields=True)

    def update(
        self,
        request: compute.UpdateRegionUrlMapRequest,
        *,
        metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.Operation:
        r"""Call the update method over HTTP.

        Args:
            request (~.compute.UpdateRegionUrlMapRequest):
                The request object. A request message for
                RegionUrlMaps.Update. See the method
                description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.Operation:
                Represents an Operation resource.

                Google Compute Engine has three Operation resources:

                -  `Global </compute/docs/reference/rest/{$api_version}/globalOperations>`__
                   \*
                   `Regional </compute/docs/reference/rest/{$api_version}/regionOperations>`__
                   \*
                   `Zonal </compute/docs/reference/rest/{$api_version}/zoneOperations>`__

                You can use an operation resource to manage asynchronous
                API requests. For more information, read Handling API
                responses.

                Operations can be global, regional or zonal.

                -  For global operations, use the ``globalOperations``
                   resource.
                -  For regional operations, use the ``regionOperations``
                   resource.
                -  For zonal operations, use the ``zonalOperations``
                   resource.

                For more information, read Global, Regional, and Zonal
                Resources. (== resource_for
                {$api_version}.globalOperations ==) (== resource_for
                {$api_version}.regionOperations ==) (== resource_for
                {$api_version}.zoneOperations ==)

        """

        # Jsonify the request body
        body = compute.UrlMap.to_json(
            request.url_map_resource,
            including_default_value_fields=False,
            use_integers_for_enums=False,
        )

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/regions/{region}/urlMaps/{url_map}".format(
            host=self._host,
            project=request.project,
            region=request.region,
            url_map=request.url_map,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}
        if compute.UpdateRegionUrlMapRequest.request_id in request:
            query_params["requestId"] = request.request_id

        # TODO(yon-mg): further discussion needed whether 'python truthiness' is appropriate here
        #               discards default values
        # TODO(yon-mg): add test for proper url encoded strings
        query_params = ["{k}={v}".format(k=k, v=v) for k, v in query_params.items()]
        url += "?{}".format("&".join(query_params)).replace(" ", "+")

        # Send the request
        response = self._session.put(url, data=body,)

        # Raise requests.exceptions.HTTPError if the status code is >= 400
        response.raise_for_status()

        # Return the response
        return compute.Operation.from_json(response.content, ignore_unknown_fields=True)

    def validate(
        self,
        request: compute.ValidateRegionUrlMapRequest,
        *,
        metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.UrlMapsValidateResponse:
        r"""Call the validate method over HTTP.

        Args:
            request (~.compute.ValidateRegionUrlMapRequest):
                The request object. A request message for
                RegionUrlMaps.Validate. See the method
                description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.UrlMapsValidateResponse:

        """

        # Jsonify the request body
        body = compute.RegionUrlMapsValidateRequest.to_json(
            request.region_url_maps_validate_request_resource,
            including_default_value_fields=False,
            use_integers_for_enums=False,
        )

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/regions/{region}/urlMaps/{url_map}/validate".format(
            host=self._host,
            project=request.project,
            region=request.region,
            url_map=request.url_map,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}

        # TODO(yon-mg): further discussion needed whether 'python truthiness' is appropriate here
        #               discards default values
        # TODO(yon-mg): add test for proper url encoded strings
        query_params = ["{k}={v}".format(k=k, v=v) for k, v in query_params.items()]
        url += "?{}".format("&".join(query_params)).replace(" ", "+")

        # Send the request
        response = self._session.post(url, data=body,)

        # Raise requests.exceptions.HTTPError if the status code is >= 400
        response.raise_for_status()

        # Return the response
        return compute.UrlMapsValidateResponse.from_json(
            response.content, ignore_unknown_fields=True
        )
class GcloudRestLibBase:
    """
    Expected to house all common functionality for Rest Client
    """
    operation_polling_time_sleep_secs = 5

    def __init__(self, project_id, **kwargs):
        # Add authentication check here
        # Add common object instantiation
        # TODO: fetch the default project from the APPLICATION CREDENTIALS JSON
        self.project_id = project_id
        self.credentials, self.default_project_id = default(
            scopes=['https://www.googleapis.com/auth/cloud-platform'])
        self.session = AuthorizedSession(self.credentials)
        self.logger = get_logger(__name__)

    def wait_for_operation(self, operation, max_timeout_mins=15):
        """
        :param operation: the  operation object
        :param max_timeout_mins:
        :return: Bool(status), Dict(Last Operation Recieved)
        """
        # TODO: Implement max_timeout_mins
        operation_status = operation['status']
        self.logger.debug('Beginning to poll for operation')
        operation_self_link = operation['selfLink']
        start_time = time.time()
        while operation_status != 'DONE' and time.time(
        ) - start_time < max_timeout_mins * 60:
            self.logger.debug(
                f'Sleeping for {self.operation_polling_time_sleep_secs} secs before polling'
            )
            time.sleep(self.operation_polling_time_sleep_secs)
            self.logger.debug(
                "Making post call for operation status on wait endpoint ..")
            operation_response = self.session.post(operation_self_link +
                                                   "/wait")
            self.logger.error(
                f'Recieved operation response: {operation_response.text}')
            if not operation_response.status_code == codes.ok:
                if operation_response.status_code == codes.not_found:
                    self.logger.debug('Apprehending 404 not found  as ')
                    return True
                self.logger.error(f'Error while polling for operation')
                return False
            operation = operation_response.json()
            operation_status = operation['status']
            self.logger.debug(operation)

        error = operation.get('error')
        if error:
            self.logger.exception(
                'Error while polling for operation: {}'.format(error))
            return False
        self.logger.debug(f"Final operation status: {operation}")
        return operation_status == 'DONE'

    def delete_self_link(self, self_link, delete_dependencies=True):
        max_retries = 5
        count = 0
        self.logger.debug(f'Received request to delete: {self_link}')

        while count < max_retries:
            count += 1
            self.logger.debug(f"Attempt #{count}")

            if count > 1:
                self.logger.debug(
                    f"Sleeping  for {self.operation_polling_time_sleep_secs} secs before re-attempting"
                )
                time.sleep(self.operation_polling_time_sleep_secs)

            del_response = self.session.delete(self_link)
            self.logger.info(del_response.status_code)

            # Apprehending 404 not_found as resource already deleted
            if del_response.status_code == codes.not_found:
                self.logger.info(
                    "Apprehending 404 as resource already deleted")
                return True

            # If response == 400, trying to check if it a resourceInUseByAnotherResource and resolve it
            if del_response.status_code == codes.bad_request:
                self.logger.debug(
                    "Bad Request on delete request. Trying to debug it .. ")
                self.logger.debug(f"Response text : {del_response.text}")
                try:
                    self.logger.debug("Decoding Error JSON")
                    response_json = del_response.json()
                    for error in response_json['error'].get('errors', []):
                        if error.get('reason', "") == "resourceInUseByAnotherResource" \
                                and ("used" in error.get("message", "") or "depend" in error.get("message", "")):
                            error_message = error['message']
                            possible_dependency_search = re.search(
                                pattern=r"'[0-9a-zA-Z_/-]+'$",
                                string=error_message)
                            self.logger.debug(
                                'Using regex to figure out dependency')
                            if possible_dependency_search:
                                dependent_resource = possible_dependency_search.group(
                                )
                                old = self_link.split('/')
                                new = dependent_resource.strip("'").split('/')
                                for i in range(old.index(new[0])):
                                    new.insert(i, old[i])
                                dependent_resource_self_link = '/'.join(new)
                                self.logger.info(
                                    f"Dependent resource self_link : {dependent_resource_self_link}"
                                )
                                self.logger.info("Attempting to delete it .. ")
                                self.delete_self_link(
                                    dependent_resource_self_link)
                            else:
                                self.logger.debug(
                                    'Dependency could not be identified using regex'
                                )
                        else:
                            self.logger.debug(
                                'The error message is not known .. cant debug that'
                            )

                except ValueError:
                    self.logger.exception(
                        'ValueError while reading JSON from response body')
                    pass
                except KeyError:
                    pass

            # Checking if an operation object was returned
            try:
                response_json = del_response.json()
                if "operation" in response_json.get("kind", ""):
                    return self.wait_for_operation(operation=response_json)
            except ValueError:
                pass

        # Anything in 400 and 500 series
        try:
            del_response.raise_for_status()
        except exceptions.HTTPError as ex:
            self.logger.exception(del_response.text)
            raise ex

        return True
Beispiel #30
0
class ZoneOperationsRestTransport(ZoneOperationsTransport):
    """REST backend transport for ZoneOperations.

    The ZoneOperations API.

    This class defines the same methods as the primary client, so the
    primary client can load the underlying transport implementation
    and call it.

    It sends JSON representations of protocol buffers over HTTP/1.1
    """

    def __init__(
        self,
        *,
        host: str = "compute.googleapis.com",
        credentials: ga_credentials.Credentials = None,
        credentials_file: str = None,
        scopes: Sequence[str] = None,
        client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None,
        quota_project_id: Optional[str] = None,
        client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
        always_use_jwt_access: Optional[bool] = False,
    ) -> None:
        """Instantiate the transport.

        Args:
            host (Optional[str]):
                 The hostname to connect to.
            credentials (Optional[google.auth.credentials.Credentials]): The
                authorization credentials to attach to requests. These
                credentials identify the application to the service; if none
                are specified, the client will attempt to ascertain the
                credentials from the environment.

            credentials_file (Optional[str]): A file with credentials that can
                be loaded with :func:`google.auth.load_credentials_from_file`.
                This argument is ignored if ``channel`` is provided.
            scopes (Optional(Sequence[str])): A list of scopes. This argument is
                ignored if ``channel`` is provided.
            client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client
                certificate to configure mutual TLS HTTP channel. It is ignored
                if ``channel`` is provided.
            quota_project_id (Optional[str]): An optional project to use for billing
                and quota.
            client_info (google.api_core.gapic_v1.client_info.ClientInfo):
                The client info used to send a user-agent string along with
                API requests. If ``None``, then default info will be used.
                Generally, you only need to set this if you're developing
                your own client library.
        """
        # Run the base constructor
        # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc.
        # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the
        # credentials object
        super().__init__(
            host=host,
            credentials=credentials,
            client_info=client_info,
            always_use_jwt_access=always_use_jwt_access,
        )
        self._session = AuthorizedSession(
            self._credentials, default_host=self.DEFAULT_HOST
        )
        if client_cert_source_for_mtls:
            self._session.configure_mtls_channel(client_cert_source_for_mtls)
        self._prep_wrapped_messages(client_info)

    def delete(
        self,
        request: compute.DeleteZoneOperationRequest,
        *,
        metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.DeleteZoneOperationResponse:
        r"""Call the delete method over HTTP.

        Args:
            request (~.compute.DeleteZoneOperationRequest):
                The request object. A request message for
                ZoneOperations.Delete. See the method
                description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.DeleteZoneOperationResponse:
                A response message for
                ZoneOperations.Delete. See the method
                description for details.

        """

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/zones/{zone}/operations/{operation}".format(
            host=self._host,
            project=request.project,
            zone=request.zone,
            operation=request.operation,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}

        # Send the request
        headers = dict(metadata)
        headers["Content-Type"] = "application/json"
        response = self._session.delete(url, headers=headers, params=query_params,)

        # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception
        # subclass.
        if response.status_code >= 400:
            raise core_exceptions.from_http_response(response)

        # Return the response
        return compute.DeleteZoneOperationResponse.from_json(
            response.content, ignore_unknown_fields=True
        )

    def get(
        self,
        request: compute.GetZoneOperationRequest,
        *,
        metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.Operation:
        r"""Call the get method over HTTP.

        Args:
            request (~.compute.GetZoneOperationRequest):
                The request object. A request message for
                ZoneOperations.Get. See the method
                description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.Operation:
                Represents an Operation resource.

                Google Compute Engine has three Operation resources:

                -  `Global </compute/docs/reference/rest/{$api_version}/globalOperations>`__
                   \*
                   `Regional </compute/docs/reference/rest/{$api_version}/regionOperations>`__
                   \*
                   `Zonal </compute/docs/reference/rest/{$api_version}/zoneOperations>`__

                You can use an operation resource to manage asynchronous
                API requests. For more information, read Handling API
                responses.

                Operations can be global, regional or zonal.

                -  For global operations, use the ``globalOperations``
                   resource.
                -  For regional operations, use the ``regionOperations``
                   resource.
                -  For zonal operations, use the ``zonalOperations``
                   resource.

                For more information, read Global, Regional, and Zonal
                Resources. (== resource_for
                {$api_version}.globalOperations ==) (== resource_for
                {$api_version}.regionOperations ==) (== resource_for
                {$api_version}.zoneOperations ==)

        """

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/zones/{zone}/operations/{operation}".format(
            host=self._host,
            project=request.project,
            zone=request.zone,
            operation=request.operation,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}

        # Send the request
        headers = dict(metadata)
        headers["Content-Type"] = "application/json"
        response = self._session.get(url, headers=headers, params=query_params,)

        # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception
        # subclass.
        if response.status_code >= 400:
            raise core_exceptions.from_http_response(response)

        # Return the response
        return compute.Operation.from_json(response.content, ignore_unknown_fields=True)

    def list(
        self,
        request: compute.ListZoneOperationsRequest,
        *,
        metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.OperationList:
        r"""Call the list method over HTTP.

        Args:
            request (~.compute.ListZoneOperationsRequest):
                The request object. A request message for
                ZoneOperations.List. See the method
                description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.OperationList:
                Contains a list of Operation
                resources.

        """

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/zones/{zone}/operations".format(
            host=self._host, project=request.project, zone=request.zone,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}
        if compute.ListZoneOperationsRequest.filter in request:
            query_params["filter"] = request.filter
        if compute.ListZoneOperationsRequest.max_results in request:
            query_params["maxResults"] = request.max_results
        if compute.ListZoneOperationsRequest.order_by in request:
            query_params["orderBy"] = request.order_by
        if compute.ListZoneOperationsRequest.page_token in request:
            query_params["pageToken"] = request.page_token
        if compute.ListZoneOperationsRequest.return_partial_success in request:
            query_params["returnPartialSuccess"] = request.return_partial_success

        # Send the request
        headers = dict(metadata)
        headers["Content-Type"] = "application/json"
        response = self._session.get(url, headers=headers, params=query_params,)

        # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception
        # subclass.
        if response.status_code >= 400:
            raise core_exceptions.from_http_response(response)

        # Return the response
        return compute.OperationList.from_json(
            response.content, ignore_unknown_fields=True
        )

    def wait(
        self,
        request: compute.WaitZoneOperationRequest,
        *,
        metadata: Sequence[Tuple[str, str]] = (),
    ) -> compute.Operation:
        r"""Call the wait method over HTTP.

        Args:
            request (~.compute.WaitZoneOperationRequest):
                The request object. A request message for
                ZoneOperations.Wait. See the method
                description for details.

            metadata (Sequence[Tuple[str, str]]): Strings which should be
                sent along with the request as metadata.

        Returns:
            ~.compute.Operation:
                Represents an Operation resource.

                Google Compute Engine has three Operation resources:

                -  `Global </compute/docs/reference/rest/{$api_version}/globalOperations>`__
                   \*
                   `Regional </compute/docs/reference/rest/{$api_version}/regionOperations>`__
                   \*
                   `Zonal </compute/docs/reference/rest/{$api_version}/zoneOperations>`__

                You can use an operation resource to manage asynchronous
                API requests. For more information, read Handling API
                responses.

                Operations can be global, regional or zonal.

                -  For global operations, use the ``globalOperations``
                   resource.
                -  For regional operations, use the ``regionOperations``
                   resource.
                -  For zonal operations, use the ``zonalOperations``
                   resource.

                For more information, read Global, Regional, and Zonal
                Resources. (== resource_for
                {$api_version}.globalOperations ==) (== resource_for
                {$api_version}.regionOperations ==) (== resource_for
                {$api_version}.zoneOperations ==)

        """

        # TODO(yon-mg): need to handle grpc transcoding and parse url correctly
        #               current impl assumes basic case of grpc transcoding
        url = "https://{host}/compute/v1/projects/{project}/zones/{zone}/operations/{operation}/wait".format(
            host=self._host,
            project=request.project,
            zone=request.zone,
            operation=request.operation,
        )

        # TODO(yon-mg): handle nested fields corerctly rather than using only top level fields
        #               not required for GCE
        query_params = {}

        # Send the request
        headers = dict(metadata)
        headers["Content-Type"] = "application/json"
        response = self._session.post(url, headers=headers, params=query_params,)

        # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception
        # subclass.
        if response.status_code >= 400:
            raise core_exceptions.from_http_response(response)

        # Return the response
        return compute.Operation.from_json(response.content, ignore_unknown_fields=True)