Python 从 Gcloud 获取账单信息

Python to get billing info from Gcloud

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

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

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

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

我目前很迷茫,花了很多时间在互联网上阅读和寻找示例……这就是为什么我 post 在这里,寻找可以帮助我或指明正确方向的人。

让我与您分享我在 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}, reason : {1}'.format(
                e.status_code, 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 returns 组织),请查看评论。

如果不这样做,您需要向服务帐户授予计费帐户的权限:

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}

NOTE You're using Google's API Client Library for Billing but there's also a Cloud Client Library for Billing. Google Cloud encourages Cloud Client over API Client just be aware of the differences.