この記事でできるようになること
どうも、IoTエンジニアのDangoと言います。AWSを用いたIoTシステムを構築していることが多いです。
今回はPythonでAWS SSM Parameter StoreにあるNameをフィルターして取得し、List化します。
前提
AWS SSM Parameter Storeの詳しい仕様については割愛します。
Python3 + boto3で操作する前提です(AWS CLIなどでもやることは大体同じですが)。
IAMの設定も済んでいる前提です。
基本操作
まずはboto3でssmを操作する方法を簡単に。
最初に、ssmのclientを作ります。
import boto3
REGION = "ap-northeast-1"
ssm = boto3.client("ssm",region_name=REGION)
そして、次のように操作します。
戻り値 = ssm.メソッド(引数)
#やりたいこと
AWS SSM Parameter Storeから読み出すとき、
Name(=パラメーター名)が決まっていれば、ssm.get_parameters
にその値を入れて終わりなのですが、
「Nameの一部だけを知っている」場合に、同じ部分を持ったNameをListで取得できると、
ssm.get_parameters
で一気にValue(=パラメーターの値)を取得できて便利です。
※ssm.get_parametersの使い方については、以下をご覧ください。
https://dev.classmethod.jp/articles/get-data-from-system-manager-parameter-store-using-boto3-ja/
##Nameの一部だけを知っている例
例えば、次のようなNameのparameterがあったとします。
hoge-sub
hoge-main
fuga-main
fuga-sub
これを、
- 「"hoge-"から始まる」
- 「"fuga-"から始まる」
- 「"main"を含む」
- 「"sub"を含む」
といった条件で検索できたら、該当するNameの中身を一度に読めて便利です。
どうすれば実現できるでしょうか。
実現方法
ssm.describe_parameters
を使用します。
※補足
Nameが"-"などではなく"/"区切りになっている場合、ssm.get_parameter_by_path
で済む話なのですが、命名規則に"/"が採用されていない場合でも、前方一致(BeginWith)や部分一致(Contains)で調べられます。
以下は、公式ドキュメントのdescribe_parametersの項目を解釈した内容です。
より詳しい情報は公式ドキュメントをご覧ください。
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.describe_parameters
describe_parametersの基本
Nameが"hoge"で始まる。と検索する場合、次のように書きます。
ret = ssm.describe_parameters(
ParameterFilters=[
{
"Key":"Name",
"Option":"BeginsWith",
"Values":["hoge"]
}
]
)
Nameに"main"を含む。という場合、次のように書きます。
ret = ssm.describe_parameters(
ParameterFilters=[
{
"Key":"Name",
"Option":"Contains",
"Values":["main"]
}
]
)
Valuesの部分は、Listですので、複数検索語句を含めれば「or」で検索可能です。
戻り値
次のような構造の辞書が返ってきます(公式ドキュメントより)。
{
'Parameters': [
{
'Name': 'string',
'Type': 'String'|'StringList'|'SecureString',
'KeyId': 'string',
'LastModifiedDate': datetime(2015, 1, 1),
'LastModifiedUser': 'string',
'Description': 'string',
'AllowedPattern': 'string',
'Version': 123,
'Tier': 'Standard'|'Advanced'|'Intelligent-Tiering',
'Policies': [
{
'PolicyText': 'string',
'PolicyType': 'string',
'PolicyStatus': 'string'
},
],
'DataType': 'string'
},
],
'NextToken': 'string'
}
今はNameが欲しいので、こんな感じでListとして取り出しましょう。
name_list=[]
for parameter in ret["Parameters"]:
name_list.append(parameter["Name"])
NextToken
しかし、話はこれで終わりではありません。
条件に一致するParameterが多い場合(確かデフォルトでは10より多い場合)、一回のdescribe_parameters
ではパラメーターを全て読み出すことはできません。
一度に読み出せるパラメーター数がキーワード引数MaxResults
によって決まっているからです。
以下のようにして変更できますが、最大でも50までです。
ret = ssm.describe_parameters(
ParameterFilters = [
{
"Key":"Name",
"Option":"Contains",
"Values":["main"]
}
],
MaxResults = 50 # 1~50
)
51以上parameterの数が超える可能性がある場合、どうやって条件に当てはまるパラメータを全て取得するのでしょうか。
ここでNextTokenが登場します。
これは返り値の中に含まれています。
next_token = ret['NextToken']
これは、いわば本の「しおり」のようなもので、
parameterのうち何件まで読み出したかをハッシュ値で返してくれています。
50件まで読み込んだのなら、51件以降はこのNextTokenを使って「続きから」読めます。
使い方は、次のような感じでdescribe_parameters
の引数に指定します。
ret = ssm.describe_parameters(
ParameterFilters = [
{
"Key":"Name",
"Option":"Contains",
"Values":["main"]
}
],
MaxResults = 50, # 1~50
NextToken = next_token # 追加
)
※補足
NextTokenやMaxResultsの機能は、もともとパラメーターの一覧をページネーションで切り替えられるようにした機能のようです。1ページ〇〇件と指定して、「次へ」を押すとNextTokenで次の〇〇件を取得する、という機能です。
#全体像
あとは、next_tokenが返って来なくなるまでdescribe_parameters
し続ければ、全件読み出し完了、というわけです。
whileループで読み出しましょう。
import boto3
REGION = "ap-northeast-1"
ssm = boto3.client("ssm",region_name=REGION)
names = [] # target
desc_args={
"ParameterFilters":[
{
"Key":"Name",
"Option":"BeginsWith",
"Values":["hoge"]
}
]
}
# NextTokenが空になるまでループを回す
while (True):
ret = ssm.describe_parameters(**desc_args) #キーワード引数の展開
for parameter in ret["Parameters"]:
names.append(parameter["Name"])
if(not "NextToken" in ret):
break
else:
desc_args["NextToken"]=ret["NextToken"]
なお、一回目のdescribeと二回目以降のdescribeでは、NextTokenに値を入れるかどうかで引数の使い方が異なるため、普通に書くとssm.describe_parametersを二回書くことになります。
**を使ってキーワード引数をアンパックすることにより、キーワード引数の数に関係なく一回のssm.describe_parametersで簡潔に記述できます。