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.
我正在尝试构建 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.