Python 从 Gcloud 获取账单信息

问题描述

我正在尝试构建一小部分 python 以获取有关谷歌云中组织的所有项目的帐单信息。

我按照官方的“操作方法https://cloud.google.com/billing/docs/reference/libraries

在完成所有步骤后(我检查了两次),我的小程序无法正常工作。 我无法获得任何信息或直接收到 403 错误

我认为这是“服务帐户”权限的问题,但此“服务帐户”具有所有者权限,如文档所示。

我目前非常迷茫,花了很多时间在互联网上阅读和寻找例子......所以我在这里发帖,寻找可以帮助我或找到正确方向的人。

让我与你分享我在 pyhon 中的小代码

from __future__ import print_function
import os.path
from googleapiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials
from urllib.error import HTTPError
import json

ScopES = [
    'https://www.googleapis.com/auth/cloud-billing.readonly','https://www.googleapis.com/auth/cloud-billing','https://www.googleapis.com/auth/cloud-platform'
]

JSON_KEY_FILE = '/Users/alek/lab/gcloud-billing/JSON_KEY.json'


def main():
    creds = None

    if os.path.exists(JSON_KEY_FILE):
        creds = ServiceAccountCredentials.from_json_keyfile_name(
            JSON_KEY_FILE,scopes=ScopES)

    with build('cloudbilling','v1',credentials=creds) as service:

        print(service.billingAccounts().list().execute())

        request = service.billingAccounts().list()

        try:
            response = request.execute()
        except HTTPError as e:
            print('Error response status code : {0},reason : {1}'.format(
                e.status_code,e.error_details))

        print(json.dumps(response,sort_keys=True,indent=4))

        #
        # Second test over a kNowing ID
        #

        request = service.billingAccounts().get(
            name="billingAccounts/XXXXXX-YYYYYY-ZZZZZZ")

        try:
            response = request.execute()

        except HTTPError as e:
            print('Error response status code : {0},e.error_details))




if __name__ == '__main__':
    main()

输出

{'billingAccounts': [],'nextPagetoken': ''}
{
    "billingAccounts": [],"nextPagetoken": ""
}
Traceback (most recent call last):
  File "/Users/alek/lab/gcloud-billing/test01.py",line 73,in <module>
    main()
  File "/Users/alek/lab/gcloud-billing/test01.py",line 47,in main
    response = request.execute()
  File "/Users/alek/.pyenv/versions/gcloud-billing/lib/python3.9/site-packages/googleapiclient/_helpers.py",line 134,in positional_wrapper
    return wrapped(*args,**kwargs)
  File "/Users/alek/.pyenv/versions/gcloud-billing/lib/python3.9/site-packages/googleapiclient/http.py",line 935,in execute
    raise HttpError(resp,content,uri=self.uri)
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://cloudbilling.googleapis.com/v1/billingAccounts/XXXXXX-YYYYYY-ZZZZZZ?alt=json returned "The caller does not have permission". Details: "The caller does not have permission">

解决方法

你的代码对我有用,但见下文...

如果您有一个组织(gcloud organizations list 返回一个组织),请参阅评论。

如果不这样做,您需要授予服务帐户权限结算帐户:

PROJECT=... # The Project that owns the Service Account
ACCOUNT=... # The Service Account 
EMAIL=${ACCOUNT}@${PROJECT}.iam.gserviceaccount.com

gcloud beta billing accounts add-iam-policy-binding ${BILLING} \
--role=roles/billing.viewer \
--member=serviceAccount:${EMAIL}

不要忘记启用cloudbilling

gcloud services enable cloudbilling.googleapis.com \
--project=${PROJECT}

那么它应该可以工作了!

{'billingAccounts': [{'name': 'billingAccounts/XXXXXX-XXXXXX-XXXXXX','open': True,'displayName': 'personal','masterBillingAccount': ''}],'nextPageToken': ''}
{
    "billingAccounts": [
        {
            "displayName": "billing-account","masterBillingAccount": "","name": "billingAccounts/XXXXXX-XXXXXX-XXXXXX","open": true
        }
    ],"nextPageToken": ""
}

建议:使用Application Default Credentials

export GOOGLE_APPLICATION_CREDENTIALS=./${ACCOUNT}.json

然后可以:

from googleapiclient.discovery import build

import google.auth


def main():
    creds,project_id = google.auth.default(scopes=SCOPES)
    ...

从头开始:

BILLING=...
PROJECT=...
ACCOUNT=...

EMAIL=${ACCOUNT}@${PROJECT}.iam.gserviceaccount.com

gcloud projects create ${PROJECT}
gcloud beta billing projects link ${PROJECT} \
--billing-account=${BILLING}

gcloud services enable cloudbilling.googleapis.com \
--project=${PROJECT}

gcloud iam service-accounts create ${ACCOUNT} \
--project=${PROJECT}

gcloud iam service-accounts keys create ./${ACCOUNT}.json \
--iam-account=${EMAIL} \
--project=${PROJECT}

gcloud beta billing accounts add-iam-policy-binding ${BILLING} \
--role=roles/billing.viewer \
--member=serviceAccount:${EMAIL}

python3 -m venv venv
source venv/bin/activate

python3 -m pip install google-api-python-client
python3 -m pip install google-auth

export PROJECT
export BILLING
export GOOGLE_APPLICATION_CREDENTIALS=./${ACCOUNT}.json

python3 main.py

完成后,删除权限:

gcloud beta billing accounts remove-iam-policy-binding ${BILLING} \
--role=roles/billing.viewer \
--member=serviceAccount:${EMAIL}

注意您使用的是 Google 的 Billing API 客户端库,但还有一个 Billing 的云客户端库。 Google Cloud 鼓励 Cloud Client over API Client,只需注意 differences