CloudFormationのデプロイ済みスタックのテンプレートをawscliでYAMLやJSONのフォーマットで取得する方法です。
aws cloudformation get-template
コマンドでテンプレートを取得できるのですが、デプロイ時YAMLとJSONのどちらを使ったかによって返ってくるフォーマットが違い、毎回試行錯誤してしまうので、メモしておきます。
テンプレートを取得するワンライナー
YAMLでデプロイしたスタックをYAMLで取得
$ aws cloudformation get-template --stack-name $STACKNAME | jq .TemplateBody -r
JSONでデプロイしたスタックをJSONで取得
$ aws cloudformation get-template --stack-name $STACKNAME | jq .TemplateBody
YAMLでデプロイしたスタックをJSONで取得
$ aws cloudformation get-template --stack-name $STACKNAME | jq .TemplateBody -r | yq
$ aws cloudformation get-template --stack-name $STACKNAME | ruby -rjson -ryaml -e 'puts JSON.pretty_generate(YAML.load(JSON.load(ARGF)["TemplateBody"]))'
$ aws cloudformation get-template --stack-name $STACKNAME | jq .TemplateBody -r | python -c 'import sys; import json; from awscli.customizations.cloudformation.yamlhelper import yaml_parse; print(json.dumps(yaml_parse(sys.stdin.read()), indent=4))'
1つ目と2つ目は !GetAtt
みたいなのには非対応です。Pythonのboto3がある環境では、3つ目のようにがんばれば !GetAtt
みたいなのに対応できます。
JSONでデプロイしたスタックをYAMLで取得
$ aws cloudformation get-template --stack-name $STACKNAME | yq .TemplateBody -y
$ aws cloudformation get-template --stack-name $STACKNAME | ruby -ryaml -e 'puts YAML.dump(YAML.load(ARGF)["TemplateBody"])'
試してみる
テンプレートファイル
RDSのインスタンスを作るシンプルなテンプレートで試します。
AWSTemplateFormatVersion: '2010-09-09'
Resources:
SampleRDS:
Type: AWS::RDS::DBInstance
Properties:
Engine: postgres
EngineVersion: 12.5
DBInstanceIdentifier: samplerdsinstance1
DBInstanceClass: db.t3.micro
StorageType: gp2
AllocatedStorage: 20 # GiB
DBName: mydb
MasterUsername: myuser
MasterUserPassword: mypassword
Outputs:
SampleRDSEndpoint:
Value: !GetAtt SampleRDS.Endpoint.Address
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"SampleRDS": {
"Type": "AWS::RDS::DBInstance",
"Properties": {
"Engine": "postgres",
"EngineVersion": 12.5,
"DBInstanceIdentifier": "samplerdsinstance2",
"DBInstanceClass": "db.t3.micro",
"StorageType": "gp2",
"AllocatedStorage": 20,
"DBName": "mydb",
"MasterUsername": "myuser",
"MasterUserPassword": "mypassword"
}
}
},
"Outputs": {
"SampleRDSEndpoint": {
"Value": {
"Fn::GetAtt": ["SampleRDS", "Endpoint.Address"]
}
}
}
}
デプロイ
$ aws cloudformation deploy --template-file template.yaml --stack-name sample-yaml
$ aws cloudformation deploy --template-file template.json --stack-name sample-json
aws cloudformation get-templateコマンド
デプロイ時のYAML/JSONでコマンドの出力がだいぶ違うんですよね。。。
YAMLの場合は、YAMLのコードがそのまま文字列になってJSONに埋め込まれている。JSONの場合は、そのままJSON。
$ aws cloudformation get-template --stack-name sample-yaml
{
"TemplateBody": "AWSTemplateFormatVersion: '2010-09-09'\n\nResources:\n SampleRDS:\n Type: AWS::RDS::DBInstance\n Properties:\n Engine: postgres\n EngineVersion: 12.5\n DBInstanceIdentifier: samplerdsinstance1\n DBInstanceClass: db.t3.micro\n StorageType: gp2\n AllocatedStorage: 20 # GiB\n DBName: mydb\n MasterUsername: myuser\n MasterUserPassword: mypassword\n\nOutputs:\n SampleRDSEndpoint:\n Value: !GetAtt SampleRDS.Endpoint.Address\n",
"StagesAvailable": [
"Original",
"Processed"
]
}
$ aws cloudformation get-template --stack-name sample-json
{
"TemplateBody": {
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"SampleRDS": {
"Type": "AWS::RDS::DBInstance",
"Properties": {
"Engine": "postgres",
"EngineVersion": 12.5,
"DBInstanceIdentifier": "samplerdsinstance2",
"DBInstanceClass": "db.t3.micro",
"StorageType": "gp2",
"AllocatedStorage": 20,
"DBName": "mydb",
"MasterUsername": "myuser",
"MasterUserPassword": "mypassword"
}
}
},
"Outputs": {
"SampleRDSEndpoint": {
"Value": {
"Fn::GetAtt": [
"SampleRDS",
"Endpoint.Address"
]
}
}
}
},
"StagesAvailable": [
"Original",
"Processed"
]
}
テンプレート取得
YAMLデプロイのスタックをYAMLで取得。YAML自体がJSONの文字列になっているのでjqコマンドに -r
オプションを付ける。
$ aws cloudformation get-template --stack-name sample-yaml | jq .TemplateBody -r
AWSTemplateFormatVersion: '2010-09-09'
Resources:
SampleRDS:
Type: AWS::RDS::DBInstance
Properties:
Engine: postgres
EngineVersion: 12.5
DBInstanceIdentifier: samplerdsinstance1
DBInstanceClass: db.t3.micro
StorageType: gp2
AllocatedStorage: 20 # GiB
DBName: mydb
MasterUsername: myuser
MasterUserPassword: mypassword
Outputs:
SampleRDSEndpoint:
Value: !GetAtt SampleRDS.Endpoint.Address
JSONデプロイのスタックをJSONで取得。
$ aws cloudformation get-template --stack-name sample-json | jq .TemplateBody
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"SampleRDS": {
"Type": "AWS::RDS::DBInstance",
"Properties": {
"Engine": "postgres",
"EngineVersion": 12.5,
"DBInstanceIdentifier": "samplerdsinstance2",
"DBInstanceClass": "db.t3.micro",
"StorageType": "gp2",
"AllocatedStorage": 20,
"DBName": "mydb",
"MasterUsername": "myuser",
"MasterUserPassword": "mypassword"
}
}
},
"Outputs": {
"SampleRDSEndpoint": {
"Value": {
"Fn::GetAtt": [
"SampleRDS",
"Endpoint.Address"
]
}
}
}
}
YAMLとJSONを変換したければ、冒頭に書いた通りyqコマンドやワンライナーで変換できます。
コマンドのインストール
jqコマンド
jq
のインストールはUbuntuならば
$ sudo apt install -y jq
CentOS 8ならば
$ sudo yum install -y jq
yqコマンド
yq
はPythonで書かれており、pipでインストールできます。
$ pip install yq
内部でjq
を呼び出しているようで、jq
がないと次のようなエラーになります。
yq: Error starting jq: FileNotFoundError: [Errno 2] No such file or directory: 'jq'. Is jq installed and available on PATH?