毎回迷子になるのでまとめときます。
AWS
概要
の中に、高レベルの Resource と 低レベルの Client があります。
すべてのサービスで Resource が実装されているわけではないので、統一性を求めて個人的には Client を使っています。でも、Resource は Collection の all()
(ec2.instances.all()
)や filter()
を呼ぶとイテレータが返ってきて、それを for
で回せばよいのでいちいち paginator の処理を書かなくてよいのは便利ですね。
Resource
- リファレンス
- https://boto3.amazonaws.com/v1/documentation/api/latest/index.html#api-reference
- 使いたいサービスを探して、その中に
Resources
のリンクがあれば実装されています。そこになければ実装されてませんね、ということなのでClient
を使いましょう。 - インスタンスなどの一覧を得るときに使う Collection のドキュメントは、
Resources
のリンクの先のService Resource
のリンクの先にあります。
- 使いたいサービスを探して、その中に
- https://boto3.amazonaws.com/v1/documentation/api/latest/index.html#api-reference
- サンプルコード
- Resource や Action のページにコード片が掲載されているので、それを参考にするとよいです。
Client
- リファレンス
- https://boto3.amazonaws.com/v1/documentation/api/latest/index.html#api-reference
- 使いたいサービスを探して、その中の
Client
のリンクがリファレンスです。
- 使いたいサービスを探して、その中の
- https://boto3.amazonaws.com/v1/documentation/api/latest/index.html#api-reference
- サンプルコード
- Client やそのメソッドのページにコード片が掲載されているので、それを参考にするとよいです。
tips
たくさんのアカウントでなにかしたい
たくさんのアカウントでなにかしたいときに、それぞれのアカウントのクレデンシャルを用意するのはたいへんなので、Organizations を導入しているのが前提ですが、assume role を使うとよいです。
こんな感じのを用意して、
def assumed_session( *, management_session: boto3.session.Session, assumed_account_id: str, role_name='OrganizationAccountAccessRole', ) -> boto3.session.Session: res = management_session.client('sts').assume_role( RoleArn=f"arn:aws:iam::{assumed_account_id}:role/{role_name}", RoleSessionName=f"{assumed_account_id}@{role_name}"[:64], ) return boto3.session.Session( aws_access_key_id=res['Credentials']['AccessKeyId'], aws_secret_access_key=res['Credentials']['SecretAccessKey'], aws_session_token=res['Credentials']['SessionToken'], )
管理アカウントのセッションとメンバーアカウントの ID を渡すと、メンバーアカウントのセッションが返るので、それを使って Resource や Client を作って処理します。
さらに、任意の関数を受けて concurrent.futures.ThreadPoolExecutor
を使って並列実行する便利関数を用意しておくといろいろ捗ります。
- 複数のアカウントの IAM ユーザーの情報を得るスクリプト
GCP
概要
- https://github.com/googleapis/google-cloud-python (
google.cloud
) - https://github.com/googleapis/google-api-python-client (
googleapiclient
)
の 2 種類があります。
https://cloud.google.com/apis/docs/client-libraries-explained に依れば、
一部の Google Cloud APIs では、言語によっては Cloud クライアント ライブラリを利用できません。これらの API のいずれかを使用する際に希望する言語の Cloud クライアント ライブラリが存在しない場合は、以前のスタイルのクライアント ライブラリ(Google API クライアント ライブラリ)を引き続き使用できます。
とのことなので、使いたいサービスが高レベルの google-cloud-python で実装されていればそれを、そうでなければ低レベルの google-api-python-client を使うとよさそうです。
が、昔(今は改善されてるかも知れません)、google-cloud-python が意図した通りに動かなくてハマったことがあるので、自分は google-api-python-client を使うようにしています。
google-cloud-python
- レポジトリ
- リファレンス
- サンプルコード
- https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-SERVICENAME/samples/ にあります。
- google-cloud-python 各サービスの Overview の Code samples and snippets から辿れるものもあります。
google-api-python-client
- レポジトリ
- リファレンス
- https://github.com/googleapis/google-api-python-client/blob/main/docs/dyn/index.md
- 使いたいサービスを見つけてください。
- リンク先のページはたいそう殺風景なので、後述の API そのもののリファレンスもあわせて読んだほうがよいと思います。
- 使いたいサービスを見つけてください。
- https://github.com/googleapis/google-api-python-client/blob/main/docs/dyn/index.md
- サンプルコード
- https://github.com/googleapis/google-api-python-client/tree/main/samples
- Pagination
- https://github.com/googleapis/google-api-python-client/blob/main/docs/pagination.md
- インスタンスの一覧とか、結果がたくさんある場合にぐるぐるループを回してすべての結果を得るアレです。
- ときに、https://github.com/googleapis/google-api-python-client/tree/main/docs はめずらしく人のぬくもりが感じられるドキュメントですし、内容的にも一読しておいたほうがよいです。
API
- リファレンス
tips
update は丸ごと置き換えの場合が多いので注意しましょう
update メソッドはぜーんぶまるごと総入れ替えの場合が多いです。ドキュメントに注意書きがあるはずですが、見落として部分更新のつもりで一部のパラメータだけ添えて update すると、指定しなかったパラメータの値が消えちゃうことがあるので注意しましょう。
多くの API では部分更新の patch メソッドが提供されているのでそれを使うか、まず現在の値を得た後、一部の値を変更してすべて update メソッドに添えるかしましょう。
gcloud の credentials を拝借する
API アクセスに必要な credentials は色々な方法で用意できますが、予め gcloud auth login
して生成された credentials を拝借することもできます。
#!/usr/bin/env python3 import json import os import sqlite3 import sys import google.auth.transport.requests import google.oauth2.credentials def credentials_from_gcloud() -> google.oauth2.credentials.Credentials: """gcloud の credentials を拝借する""" con = sqlite3.connect(os.path.expanduser('~/.config/gcloud/credentials.db')) con.row_factory = sqlite3.Row rows = con.execute(''' SELECT * FROM credentials WHERE account_id LIKE "%@gmail.com" -- 適当に変えて使ってください。 ''').fetchall() assert len(rows) == 1 cred_data = json.loads(rows[0]['value']) cred = google.oauth2.credentials.Credentials( 'gcloud', client_id=cred_data['client_id'], client_secret=cred_data['client_secret'], token_uri=cred_data['token_uri'], refresh_token=cred_data['refresh_token'], ) try: cred.refresh(google.auth.transport.requests.Request()) except google.auth.exceptions.RefreshError as e: print('期限切れてるみたいだから gcloud auth login してねん。', file=sys.stderr) raise e return cred credentials = credentials_from_gcloud()
プロジェクトの一覧を得る方法
Resource Manager API の projects.list でプロジェクトの一覧を得ることができます。
が、Google Workspace(旧 GSuite)を利用していて組織リソースが存在する場合、何も考えずに projects.list
するとおびただしい数のプロジェクトが返ってくるかもしれません。
これは、Apps Script プロジェクトが作成されると同時に GCP のプロジェクトも作成され、それが 組織/system-gsuite/apps-script/
のフォルダの中に配置されるためです。
なので、リソースの管理 で apps-script
フォルダの ID(数字です)を調べて、そのフォルダ ID を親とするプロジェクトは除外するようにすればよいです。
import googleapiclient.discovery projects: list[dict] = [] # 除外する apps-script フォルダの ID apps_script_folder_id = '999999999999' crm_client = googleapiclient.discovery.build( 'cloudresourcemanager', 'v3', credentials=credentials, ) projects_r = crm_client.projects() request = projects_r.list( filter=f"NOT parent.id={apps_script_folder_id}" ) while request is not None: response = request.execute() projects.extend(response['projects']) request = projects_r.list_next(request, response) for project in projects: print(project['projectId'])
また、請求先アカウントにリンクされているプロジェクトの一覧(=非課金の野良プロジェクトは除外したい)なら、Cloud Billing API の billingAccounts.projects.list を使うのもよいと思います。
gcloud がアクセスしている API を知りたい
--verbosity=debug
を指定すると API のエンドポイントが表示されます。
例えば、gcloud alpha services quota list
がアクセスしている API を知りたい時は、このように実行すると、
$ gcloud --verbosity=debug alpha services quota list --service='bigquery.googleapis.com' --consumer='projects/oreno-project'` DEBUG: Running [gcloud.alpha.services.quota.list] with arguments: [--consumer: "projects/oreno-project", --service: "bigquery.googleapis.com", --verbosity: "debug"] DEBUG: Starting new HTTPS connection (1): serviceusage.googleapis.com:443 DEBUG: https://serviceusage.googleapis.com:443 "GET /v1beta1/projects/oreno-project/services/bigquery.googleapis.com/consumerQuotaMetrics?alt=json HTTP/1.1" 200 None ...
と出力され、Service Usage API の v1beta1
の services.consumerQuotaMetrics
にアクセスしていることがわかります。