AWSサービス上限緩和の状況を一覧で取得したい

---
#1. はじめに
エンジニアとしてAWSを利用していると、お客様（非エンジニア）とのギャップに気づくことが多々あります。
エンジニアとしては「コンソールから見れば済むのに」という内容も、お客様にとってはパラメータシートなど資料に起こして管理したいと思うこともあるようです。

今回は、サービス上限緩和の状況を一覧で取得しようと思います。
※プログラム歴が浅く、コード上の改善案があればコメント頂けると幸いです:sunny:


#2. 本記事の内容
いくつかの参考記事をベースにPythonのBotoCoreを使い
サービス上限緩和の状況をJSON形式で一覧として取得します。


#3.  実装内容
 1. ``list_services()``APIを使い、サービスコード一覧作成
 - 1.の結果をINPUTにして``list_service_quotas()API``を使い、最新の上限緩和状況を取得
 - 1.の結果をINPUTにして``list_aws_default_service_quotas()``APIを使い、デフォルトの上限緩和状況を取得
 - 2.と3.の内容を抽出＆結合し、一覧を作成


#4. 参考
 - [Boto3 Docs 1.20.4 documentation - ServiceQuotas -](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/service-quotas.html#id25)
 - [AWS Docs - リファレンスガイド(AWS サービスクォータ) -](https://docs.aws.amazon.com/ja_jp/general/latest/gr/aws_service_limits.html?id=docs_gateway)


#5. 実装
###5-1. ソース
```python:
import boto3

region='ap-northeast-1'

result_quotas={'Quotas': []}

# サービスコード一覧作成
service_list = boto3.client('service-quotas', region_name=region).list_services()
tmp_result_service_list = service_list

if 'NextToken' in tmp_result_service_list:
    while 'NextToken' in tmp_result_service_list:
      next_token = tmp_result_service_list['NextToken']
      tmp_result_service_list = boto3.client('service-quotas', region_name=region).list_services(NextToken=next_token)
      service_list['Services'].extend(tmp_result_service_list['Services'])

# サービスクォータ一覧作成
for service_code in service_list['Services']:
    service_quotas = boto3.client(
        'service-quotas', 
        region_name=region
        ).list_service_quotas(
            ServiceCode=service_code['ServiceCode']
            )
    tmp_service_quotas = service_quotas
    if 'NextToken' in tmp_service_quotas:
        while 'NextToken' in tmp_service_quotas:
            next_token = tmp_service_quotas['NextToken']
            tmp_service_quotas = boto3.client(
                'service-quotas', 
                region_name=region
                ).list_service_quotas(
                    ServiceCode=service_code['ServiceCode'],
                    NextToken=next_token
                    )
            service_quotas['Quotas'].extend(tmp_service_quotas['Quotas'])
    result_quotas['Quotas'].extend(service_quotas['Quotas'])

# デフォルトサービスクォータ一覧作成
service_default_quotas = {}
result_default_quotas={'Quotas': []}
for service_code in service_list['Services']:
    service_default_quotas = boto3.client(
        'service-quotas', 
        region_name=region
        ).list_aws_default_service_quotas(
            ServiceCode=service_code['ServiceCode']
            )
    tmp_service_default_quotas = service_default_quotas
    if 'NextToken' in tmp_service_default_quotas:
        while 'NextToken' in tmp_service_default_quotas:
            next_token = tmp_service_default_quotas['NextToken']
            tmp_service_default_quotas = boto3.client(
                'service-quotas', 
                region_name=region
                ).list_aws_default_service_quotas(
                    ServiceCode=service_code['ServiceCode']
                    ,NextToken=next_token
                    )
            service_default_quotas['Quotas'].extend(tmp_service_default_quotas['Quotas'])
    result_default_quotas['Quotas'].extend(service_default_quotas['Quotas'])

# サービスクォータ一覧とデフォルトサービスクォータ一覧をマージ
for service_default_quota in result_default_quotas['Quotas']:
    for service_quota in result_quotas['Quotas']:
        num_quota = result_quotas['Quotas'].index(service_quota)
        if service_quota['QuotaCode'] == service_default_quota['QuotaCode']:
            result_quotas['Quotas'][num_quota]['DefaultValue'] = service_default_quota['Value']

with open('result_quotas.txt', 'a') as f:
    print(result_quotas, file=f)
```

###5-2. サービス一覧結果イメージ
`ServiceCode`は、Service-Quotas系APIにおいて、AWSサービスを分別するために使用されます。

```text:
{
	'NextToken': '＊＊＊', 
	'Services': 
		[
			{
				'ServiceCode': 'AWSCloudMap', 
				'ServiceName': 'AWS Cloud Map'
			}, 
			{
				'ServiceCode': 'access-analyzer', 
				'ServiceName': 'Access Analyzer'
			}, 
			{
				'ServiceCode': 'acm', 
				'ServiceName': 'AWS Certificate Manager (ACM)'
			}, 
			{
～略～

```


###5-3. 最新の上限緩和一覧　結果イメージ
`QuotaCode`は、クォータひとつひとつに割り当てられている識別子です。
`QuotaName`は、人間が理解しやすいクォータ名です。
`Value` は、実際に上限緩和されている値が取得されます。一度も上限緩和されていない場合はデフォルト値が取得されます。
`Unit` は、実態はNULLで取得されることが多いようです。
`Adjustable` は、調整可能なクォータかどうかがTRUE/FALSEで取得されます。
`GlobalQuota`は、リージョンごとかグローバルのクォータかどうかがTRUE/FALSEで取得されます。
他にもレスポンス構造がありますが割愛します。


```text:
{
	'Quotas': 
		[
			{
				'ServiceCode': 'AWSCloudMap', 
				'ServiceName': 'AWS Cloud Map', 
				'QuotaArn': 'arn:aws:servicequotas:ap-northeast-1:＊＊＊:AWSCloudMap/L-＊', 
				'QuotaCode': 'L-＊', 
				'QuotaName': 'DiscoverInstances operation per account burst rate', 
				'Value': 2000.0, 
				'Unit': 'None', 
				'Adjustable': True, 
				'GlobalQuota': False
			}, 
			{
～略～

```

###5-4. デフォルトの上限緩和一覧　結果イメージ
5-3の差分のみ説明します。
`Value` は、デフォルトの上限値が取得されます。

```text:
{
	'Quotas': 
		[
			{
				'ServiceCode': 'AWSCloudMap', 
				'ServiceName': 'AWS Cloud Map', 
				'QuotaArn': 'arn:aws:servicequotas:ap-northeast-1:＊＊＊:AWSCloudMap/L-＊', 
				'QuotaCode': 'L-＊', 
				'QuotaName': 'Custom attributes per instance', 
				'Value': 30.0, 
				'Unit': 'None', 
				'Adjustable': False, 
				'GlobalQuota': False
			}, 
			{
～略～

```

###5-5. 最終結果イメージ
5-4のValueをDefaultValueと置き換えてマージしています。

```text:
{
	'Quotas': 
		[
			{
				'ServiceCode': 'AWSCloudMap', 
				'ServiceName': 'AWS Cloud Map', 
				'QuotaArn': 'arn:aws:servicequotas:ap-northeast-1:＊＊＊:AWSCloudMap/L-＊', 
				'QuotaCode': 'L-＊', 
				'QuotaName': 'DiscoverInstances operation per account burst rate', 
				'Value': 2000.0, 
				'Unit': 'None', 
				'Adjustable': True, 
				'GlobalQuota': False, 
				'DefaultValue': 2000.0
			}, 
			{
～略～

```

#6. まとめ
一回のAPI実行では全件取得できず、nextpagetokenを指定する様にループ処理を実装しないといけない点が初心者には難しかったです。

最終結果の項目数が1000件以上になるので、JSONファイルのままでは取り扱いしにくいと思います。
エクセルファイル化する処理を追加するなどして、より利用しやすくすると良いかもしれません。