AWS CLI と boto3 でできることの差分を確認してみる

# そもそものきっかけ

皆さん、AWS Bedrock には触っていますか？  

Bedrock では、用意されている CLI が [bedrock](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/bedrock/index.html) と [bedrock-runtime](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/bedrock-runtime/index.html) の2つに分かれています。  
後者 "-runtime" で用意されていたコマンドが、 [invoke-model](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/bedrock-runtime/invoke-model.html) 1つのみだった (2023年12月時点) のに気づいたことが、この記事を書くきっかけです。

# AWS CLI と boto3 でできることが違う！(当たり前！)

aws cli でのコマンドでできることは上記の通りですが、boto3 の API と比べてみると、 [bedrock-runtime](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-runtime.html) クライアントでは、AWS CLI 相当の [invoke_model](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-runtime/client/invoke_model.html) のメソッドと、

* can_paginate
* close
* get_paginator
* get_waiter

といった、どのクライアントにも共通で用意されているメソッド以外にも、以下のメソッドが用意されていました。***この boto3 メソッド (invoke_model_with_response_stream) に相当する AWS CLI は用意されていません。***

* [invoke_model_with_response_stream](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-runtime/client/invoke_model_with_response_stream.html)

ただし、これは名称からわかる通り、Bedrock からの応答を、Stream として 受け取るためのメソッドとなっており、基本的に逐次実行が想定されている AWS CLI では扱いづらい メソッドのため、CLI には用意されなかった操作なのだろう、ということが得心できました。

これまで私は、AWS CLI と boto3 でできることは、おおむねイコールなのではないか、という思い込みがありました。しかし、上記のような AWS CLI と boto3 でできることの差分が他にもあるのではないか？ と考えたのが、以下で確認してみた内容になります。

# Python スクリプトで確認してもらう

とは言え、(当たり前ですが)リファレンスなどから、差分をひとつひとつ確認するのは効率的ではありません。  
そこで、AI に、python のクライアントのメソッドから、CLI の有無を確認してもらう スクリプトを書いてもらいました。  
以下がその内容です。

:::note warn  
念の為の注意事項  
なお、下記スクリプトでは、内部から AWS CLI を呼び出します。  
APIをたたいて、不必要なリソースを作成することのないよう、有効なアクセスキーなどが使えない状態(APIが実際に実行されることのない状態)で実行しないと、意図しない料金の請求などにつながりかねないので、ご注意ください。  
(基本的には、オプションなしの実行では、基本的にコマンドは失敗することがほとんどのため、何かのリソースの作成、料金の請求につながる可能性は低いとは思いますが…)  
:::

``` python:check_boto3_method.py
import sys
import boto3
import subprocess

def generate_cli_commands(service_name, available_methods):
    # AWS CLIスタイルのコマンドを生成
    return [f"aws {service_name} {method.replace('_', '-')}" for method in available_methods]

def check_cli_command_exists(cli_command):
    # AWS CLIコマンドが存在するか確認
    try:
        result = subprocess.run(cli_command, shell=True, check=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8')
        if result.returncode == 252:
            return result.returncode == 0 or "aws: error: the following arguments are required:" in result.stderr
        elif result.returncode == 254:
            return True
        else:
            return result.returncode == 0  # 終了エラーコードが252以外の場合はTrueを返す
    except Exception as e:
        print(f"Error executing command: {e}")
        return False

def main():
    # 引数からサービス名を取得
    if len(sys.argv) != 2:
        print("Usage: python script_name.py <service_name>")
        sys.exit(1)

    service_name = sys.argv[1]

    # 引数で指定したリージョン
    region_name = 'ap-northeast-1'

    # Boto3クライアントの作成
    try:
        client = boto3.client(service_name, region_name=region_name)
    except Exception as e:
        print(f"Error creating boto3 client: {e}")
        sys.exit(1)

    # クライアントのメソッド一覧を取得
    available_methods = [method_name for method_name in dir(client) if callable(getattr(client, method_name)) and not method_name.startswith('_')]

    if not available_methods:
        print(f"No methods found for {service_name} client.")
        sys.exit(1)

    # AWS CLIスタイルのコマンドを生成
    cli_commands = generate_cli_commands(service_name, available_methods)

    # 生成したコマンドがAWS CLIに存在するか確認
    for cli_command in cli_commands:
        if check_cli_command_exists(cli_command):
            print(f"AWS CLI command exists: {cli_command}")
        else:
            print(f"AWS CLI command does not exist: {cli_command}")

if __name__ == "__main__":
    main()

```

さて、こちらのスクリプトを実行してみます。

```
$ python check_boto3_method.py bedrock-runtime
AWS CLI command does not exist: aws bedrock-runtime can-paginate
AWS CLI command does not exist: aws bedrock-runtime close
AWS CLI command does not exist: aws bedrock-runtime generate-presigned-url
AWS CLI command does not exist: aws bedrock-runtime get-paginator
AWS CLI command does not exist: aws bedrock-runtime get-waiter
AWS CLI command exists: aws bedrock-runtime invoke-model
AWS CLI command does not exist: aws bedrock-runtime invoke-model-with-response-stream
```

最終行にて、boto3 の bedrock-runtime クライアントにはあるメソッドなのに、"invoke-model-with-response-stream" コマンドはないよ、ということで、期待するチェックができているようですね。

# EC2 の場合

さて、前述のスクリプトを使って、

```
python check_boto3_method.py ec2
```

と、ec2 における AWS CLI と boto3 でできることの差分を確認してみます。

以下がその結果(boto3にのみ用意されているメソッド)になります(長いので全体は割愛)。

* [import_instance](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2/client/import_instance.html)
* [import_volume](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2/client/import_volume.html)

前者の "import_instance" のリファレンスには、まさに以下の記載もあります。

> This API action is not supported by the Command Line Interface (CLI). For information about using the Amazon EC2 CLI,

これらの API にはなぜ CLI  が用意されていないのでしょうか？ "import_instance" のリファレンスには、以下の記載もありました。

> この API アクションは、単一ボリューム VM のみをサポートします。 マルチボリューム VM をインポートするには、代わりに ImportImage を使用します。

こちらの記事を見ると、同じ CLI は用意されていないものの、マルチボリュームをサボートする、 [aws ec2 import-image](https://docs.aws.amazon.com/cli/latest/reference/ec2/import-image.html) で同等の操作ができる(ので用意されていない)ということが言えそうですね。

# RDS の場合

では、RDS の場合はどうでしょうか。

```
python check_boto3_method.py rds
```

実行の結果、RDS の場合に boto3にのみ用意されているメソッド は以下の1つでした。

* [modify_option_group](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/rds/client/modify_option_group.html)

オプショングループが Modify できないのは少々意外ですね。
こちらの [リファレンス](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_WorkingWithOptionGroups.html) に、以下の記載がありました。

> オプション設定を変更するには、変更するオプショングループおよびオプションを指定して、AWS CLI の add-option-to-option-group コマンドを使用します。

上記記載のように、[aws rds add-option-to-option-group](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/rds/add-option-to-option-group.html) や、[aws rds remove-option-from-option-group](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/rds/remove-option-from-option-group.html)　を使う、というのが、CLI から オプショングループを Modify する際のお作法、ということになるでしょうか。(こちらについては、複雑になりがちな気がするので、そもそも CLI から やりたくない、という向きが強そうな操作内容ではありますが。)

# まとめ

本記事では、スクリプトを使って、AWS CLI と boto3 でできることの差分を確認してみました。
今回確認した範囲では、興味深い？結果を見つけることはあまりできませんでしたが、kinesis の [subscribe_to_shard](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/kinesis/client/subscribe_to_shard.html) など、同様に AWS CLI が用意されていない boto3 メソッドは、他にもまだ埋もれていそうです。  
こういった(ある意味、何の役にも立たない)調査も通じて、AWS に関する知見を深めていけるといいな、と思っています。

ちなみにですが、上記の Python スクリプトの生成を手伝ってもらった AI は、ChatGPT でした。(そこは Bedrock だろ！と言われそうなので、Amazon Bedrock の Text Playground にも、触っていきたいと思います！)

---

* AWS は、米国その他の諸国における Amazon.com, Inc. またはその関連会社の商標です。
* その他、本資料に記述してある会社名、製品名は、各社の登録商品または商標です。