AWS と GCP のクライアントライブラリ(Python)のドキュメントのありか
毎回迷子になるのでまとめときます。
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
にアクセスしていることがわかります。
ぼくのかんがえたさいきょうの /etc/apt/sources.list
これ
# /etc/apt/sources.list deb mirror+file:/etc/apt/mirrors.txt jammy main restricted universe multiverse deb-src mirror+file:/etc/apt/mirrors.txt jammy main restricted universe multiverse deb mirror+file:/etc/apt/mirrors.txt jammy-updates main restricted universe multiverse deb-src mirror+file:/etc/apt/mirrors.txt jammy-updates main restricted universe multiverse deb http://security.ubuntu.com/ubuntu jammy-security main restricted universe multiverse deb-src http://security.ubuntu.com/ubuntu jammy-security main restricted universe multiverse
# /etc/apt/mirrors.txt # http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu/ priority:1 # http://asia-northeast1.gce.archive.ubuntu.com/ubuntu/ priority:1 https://ftp.udx.icscoe.jp/Linux/ubuntu/ priority:2 https://linux.yz.yamagata-u.ac.jp/ubuntu/ priority:3 http://archive.ubuntu.com/ubuntu/
です。
これで、
ftp.udx.icscoe.jp
にアクセスして成功したらそれで OK- 失敗したら
linux.yz.yamagata-u.ac.jp
にアクセスして成功したらそれで OK - 更に失敗したら最後の砦の
http://archive.ubuntu.com/ubuntu/
にアクセスする
な動作になります。
EC2 や GCE な向きは、リージョンを適宜変更して(まれによくコケる)REGION.ec2.archive.ubuntu.com
や REGION.gce.archive.ubuntu.com/ubuntu/
のコメントを外して最初に試行するとよいでしょう。
/etc/apt/mirrors.txt
について詳しく説明すると、
priority
の値が小さい順に試行して、失敗したら次のを試行するpriority
の値がないのは最後に試行するpriority
の値が同じもの同士、もしくはpriority
の値がないもの同士はその中からランダムで選ばれ、失敗したらその中からまたランダムで選んで試行を繰り返す- URL と
priority
の間はタブで区切る! スペースではダメ!!- 今回の超絶おハマりポイントです!!
cat -T /etc/apt/mirrors.txt
で^I
となっているか確認しましょう
- この機能が使えるのは
apt
1.6 以上で、bionic のが 1.6.x なので bionic より古いと使えないかもです
詳細は apt-transport-mirror(1) を参照してください。
公式の apt repos のミラーの一覧はここにあるので、お好みのを選んでみてください。
ときに、爆速の ICSCoE が以前は掲載されていた記憶なんですが、公式ミラーから外れちゃったんすかね?
おハマりその 2
do-release-upgrade
するときは事前に元の source.list に戻しましょう。
do-release-upgrade
の過程で source.list の中のコードネームが書き換わるのですが、少なくとも bionic → focal のときはmirror+file:
の行が bionic のままでエラー終了しちゃいました。
Ruby の net-ssh で OpenSSH 8.8 以上のサーバーにアクセスできない件
Ubuntu 22.04 LTS (Jammy) の OpenSSH 8.9 な sshd
に対して、OpenSSH 7.2 以降の ssh
ではアクセスできるけど Ruby の net-ssh
ではアクセスできない件。
理由は以下の通り。
- OpenSSH 8.8 で
ssh-rsa
署名が無効化された rsa
鍵はssh-rsa
署名の他に、rsa-sha2-256
やrsa-sha2-512
でも署名可能- 実装によっては、ネゴシエーション時に利用可能とわかれば、
rsa-sha2-256
やrsa-sha2-512
署名を使う- OpenSSH は 7.2 以降で対応している
- Ruby の
net-ssh
は現時点の最新リリース版 6.1.0 では未対応
- 従って、
- OpenSSH 7.2 以降の
ssh
はrsa-sha2-512
署名を使って接続可能 - Ruby の
net-ssh
はssh-rsa
署名を使うので接続失敗
- OpenSSH 7.2 以降の
詳しい説明は、ヌーラボさんの「OpenSSHがSHA-1を使用したRSA署名を廃止、BacklogのGitで発生した問題と解決にいたるまでの道のり」とそこからリンクされているサイトを参照されたし。
Ruby の net-ssh
で接続するには、
- HEAD を使う、もしくは対応版がリリースされるのを待つ
rsa
以外の鍵を使う- 手元の環境では
ecdsa
鍵なら追加 gem なしで接続できたecdsa
鍵には 懸念点がある そうなので、要確認
ed25519
鍵は追加 gem が必要な模様 https://github.com/net-ssh/net-ssh
- 手元の環境では
これからSwitchをお迎えする人へ
年末に向け、新しく Switch をお迎えする人も多いかと思います。そんな人へ、スムーズに使い始められるようにお勧めの準備事項をまとめてみました。
(以前、某所に投稿したやつの 2021 年版です)
SDカード
ダウンロードソフトの保存先に必要なので買っときましょう。本体内蔵のは有機 EL モデルが 64GB、無印と Lite が 32GB なんであっという間にいっぱいになります。
microSDXC の 128GB 以上ならいいんでないかと。
粗悪品を掴まされないように、信頼できる販路で信頼できるメーカーのを購入しましょう。(個人的には SanDisk か Transcend)
ちなみにソフトの容量はこんな感じ:
- ブレワイ: 14.4GB
- Xenoblade DE: 13.6GB
- スプラ2: 6.1GB
- あつ森: 6.6GB
ニンテンドーアカウント
Switch内の「ユーザー」に「ニンテンドーアカウント」を連携させるとポイント溜まったりニンテンドーeショップでソフト買えたりできます。
ので、「ニンテンドーアカウント」は予め作っておいた方がスムーズに始められるかと。
Switch が無くても PC or スマホでここからアカウント作れます。
ちな、Nintendo Switch Online には「ニンテンドーアカウント」は必須です。
子どもアカウント
0 歳から 17 歳までのアカウントは「子どもアカウント」として登録できて、「みまもり設定」で各種制限を加えることができます。
一度「子どもアカウント」にすると 13 歳以上になるまで「一般アカウント」にすることができませんが、ボイチャ使うゲームを子どもがやらない限りはまぁ「子どもアカウント」でいいんじゃないかと思います。
Nintendo Switch Online
Nintendo Switch Online は入るのをお勧めします。
オンラインプレイだけじゃなくて、セーブデータお預かり(セーブデータのバックアップ)もできるので。
300時間のハイラルの思い出が吹っ飛んだら立ち直れませんよね?
ただ、セーブデータお預かりに対応してないゲームもあるので気をつけてください…
あとは、昔のファミコン、スーファミのゲームも遊べるようになります!
個人だと 2,400 円/年。ファミリープラン(最大 8 アカウント)だと 4,500 円/年です。
NINTENDO 64 好きなら、10 月下旬に追加予定の「追加パック」も要チェック。
Proコン
必要になったらでおk
ゲームはダウンロード版?パッケージ版?
ゲームカードを入れ替えるのが地味にめんどいのでダウンロード版をお勧めします。
が、パッケージ版のメリットもあるので状況次第で。
- 飽きたら売り飛ばしたい
- Switchを複数台もってて、両方でプレイしたい(連携してるニンテンドーアカウントが別の場合)
- 「いつもあそぶ本体」機能で条件付きで緩和可能
- 中古で安く買いたい
- ご賞味したい(ゲームカードは舐めると味がします。中古の場合は抵抗ありますが…)
液晶保護フィルム
持ち運び時にキズがついたらイヤなので自分は貼ってます。
キャリングケース
持ち運ぶときにはあった方がいいかもす。
カバンに放り込んで液晶に傷がついたりスティックがぐんにゃり逝ったりすると悲しいので、かさばらないソフトケース持ってます。
あと、ケースに入れても入れなくても、持ち運ぶときは電源オフにした方がいいす! カバンの中で、スティックに何かが触れるとスリープから覚めてしばらくしてまたスリープして〜を繰り返して、さてやるか!!ってときにバッテリーが尽きてると悲しいので。(経験者)
goのtviewを使う時は、
FAQ
にも書いてあるけど、 export LC_CTYPE="en_US.UTF-8"
しましょう。
じゃないと、枠線がガビガビになったり行頭の1文字が書けたりしちゃいます。
もしくは、こんな感じで環境変数をセットして再実行するのでもいいかと。
func init() { // https://github.com/rivo/tview/wiki/FAQ#why-do-my-borders-look-weird if os.Getenv("LC_CTYPE") != "en_US.UTF-8" { os.Setenv("LC_CTYPE", "en_US.UTF-8") env := os.Environ() if err := syscall.Exec(os.Args[0], os.Args, env); err != nil { panic(err) } } }
内部NLBによるパケットの書き換えのまとめ
そういえば、内部 NLB 構成ってどうやって同一セグメントのクライアントにパケットが返ってきてるんだろ? リアルサーバーからみたときに、パケットの送信元がクライアントのになる DSR だとすると返せるのはわかるんだけど、VIP (NLBのIPアドレス) 宛のパケットを受ける設定してなくても動いてるし、NAT (DNAT) 型だとすると(クライアントが同一セグメントにいるので)戻りのパケットが NAT した NLB を経由しないんでクライアントに破棄されるだろうし??? とふと疑問を持ったので調べてみた結果です。
調べたところ、リアルサーバーに届くパケットはこんな感じでした:
まとめると:
- 内部 NLB は NAT型 の L4LB
- dstはリアルサーバーのMACアドレス、IPアドレスに書き換えられる(DNAT)
- srcのMACアドレスはNLBのMACアドレスに書き換えられる
- リアルサーバーからの戻りのパケットが必ずNLBを経由するようにこうなってると思われ
- DNATのみだと、srcはクライアントのMAC、IPになるので、リアルサーバーはNLBを経由せずに直接クライアントに戻りのパケットを送信しちゃって、クライアントは送ったのと違うところからパケットが返って来ることになるので破棄しちゃう
- ターゲットタイプで違うのは、srcのIPアドレスのみ
- ターゲットをインスタンスIDで指定したときの注意点
- リアルサーバーが内部NLBにアクセスすると、タイムアウトになる
- ref: Network Load Balancer のトラブルシューティング の「ターゲットからそのロードバランサーへのリクエストが接続タイムアウトになる」
- NLBに送ったパケットが、自分自身からのパケットになって届くので破棄されちゃう、ヘアピン問題
な感じでした。なるほどー
良いお年を!