CloudFormationテンプレートパラメーターから派生した、よく使用される値のショートカットを定義する方法はありますか?
たとえば、ELB名がproject
のマルチAZプロジェクトスタックを作成するスクリプトと、ELBの背後にあるproject-1
およびproject-2
という2つのインスタンスがあります。テンプレートにELBHostName
パラメータを渡すだけで、後でそれを使用して構成します:
"Fn::Join": [
".", [
{ "Fn::Join": [ "", [ { "Ref": "ELBHostName" }, "-1" ] ] },
{ "Ref": "EnvironmentVersioned" },
{ "Ref": "HostedZone" }
]
]
この構成または非常に類似した構成は、テンプレート全体で何度も繰り返されます。EC2ホスト名、Route53レコードなどを作成するためです。
それを何度も繰り返す代わりに、Fn::Join
の出力をある種の変数に割り当てて、"Ref":
ステートメントでできるように、それだけを参照したいと思います。
理想的には次のようなもの:
Var::HostNameFull = "Fn::Join": [ ... ]
...
{ "Name": { "Ref": "Var::HostNameFull" } }
または同様に簡単なもの。
Amazon CloudFormationでそれは可能ですか?
同じ機能を探していました。 SpoonMeiserの提案どおりにネストされたスタックを使用することを思いついたのですが、実際に必要なのはカスタム関数であることがわかりました。幸いCloudFormationは AWS :: CloudFormation :: CustomResource の使用を許可します。少しの作業で、それを行うことができます。これは単なる変数(最初にCloudFormationにあるはずだったと私が主張するもの)に対してはやり過ぎのように感じられますが、それで仕事が完了するだけでなく、(python/nodeを自由に選択できます)/Java)。ラムダ関数はコストがかかることに注意してください。ただし、スタックを1時間に複数回作成/削除しない限り、ここでは数ペニーを話しています。
最初のステップは、ラムダ関数を作成することです このページ これは、入力値を取り、それを出力にコピーするだけです。ラムダ関数であらゆる種類のクレイジーなことを実行することができますが、いったん識別関数があれば、他のことは簡単です。または、スタック自体にラムダ関数を作成することもできます。私は1つのアカウントで多くのスタックを使用しているので、残りのラムダ関数とロールがたくさんあります(すべてのスタックは--capabilities=CAPABILITY_IAM
でも作成する必要があります。ロールも必要だからです。
index.handler
次に、以下のコードをコードフィールドにコピーして貼り付けます。関数の先頭は cfn-response python module からのコードであり、ラムダ関数がCloudFormationを介して作成された場合にのみ自動インストールされます。いくつかの奇妙な理由handler
関数は、一目瞭然です。
from __future__ import print_function
import json
try:
from urllib2 import HTTPError, build_opener, HTTPHandler, Request
except ImportError:
from urllib.error import HTTPError
from urllib.request import build_opener, HTTPHandler, Request
SUCCESS = "SUCCESS"
FAILED = "FAILED"
def send(event, context, response_status, reason=None, response_data=None, physical_resource_id=None):
response_data = response_data or {}
response_body = json.dumps(
{
'Status': response_status,
'Reason': reason or "See the details in CloudWatch Log Stream: " + context.log_stream_name,
'PhysicalResourceId': physical_resource_id or context.log_stream_name,
'StackId': event['StackId'],
'RequestId': event['RequestId'],
'LogicalResourceId': event['LogicalResourceId'],
'Data': response_data
}
)
if event["ResponseURL"] == "http://pre-signed-S3-url-for-response":
print("Would send back the following values to Cloud Formation:")
print(response_data)
return
opener = build_opener(HTTPHandler)
request = Request(event['ResponseURL'], data=response_body)
request.add_header('Content-Type', '')
request.add_header('Content-Length', len(response_body))
request.get_method = lambda: 'PUT'
try:
response = opener.open(request)
print("Status code: {}".format(response.getcode()))
print("Status message: {}".format(response.msg))
return True
except HTTPError as exc:
print("Failed executing HTTP request: {}".format(exc.code))
return False
def handler(event, context):
responseData = event['ResourceProperties']
send(event, context, SUCCESS, None, responseData, "CustomResourcePhysicalID")
「テスト」ボタンを選択してラムダ関数をテストし、サンプルテンプレートとして「CloudFormation作成リクエスト」を選択できます。ログに、供給された変数が返されることが表示されます。
これでラムダ関数ができたので、CloudFormationテンプレートで使用できます。最初にラムダ関数Arnを書き留めます( lambda home page に移動し、作成した関数をクリックします。Arnはarn:aws:lambda:region:12345:function:CloudFormationIdentity
のような右上にあるはずです)。
テンプレートのリソースセクションで、次のように変数を指定します。
Identity:
Type: "Custom::Variable"
Properties:
ServiceToken: "arn:aws:lambda:region:12345:function:CloudFormationIdentity"
Arn: "arn:aws:lambda:region:12345:function:CloudFormationIdentity"
ClientBucketVar:
Type: "Custom::Variable"
Properties:
ServiceToken: !GetAtt [Identity, Arn]
Name: !Join ["-", [my-client-bucket, !Ref ClientName]]
Arn: !Join [":", [arn, aws, s3, "", "", !Join ["-", [my-client-bucket, !Ref ClientName]]]]
ClientBackupBucketVar:
Type: "Custom::Variable"
Properties:
ServiceToken: !GetAtt [Identity, Arn]
Name: !Join ["-", [my-client-bucket, !Ref ClientName, backup]]
Arn: !Join [":", [arn, aws, s3, "", "", !Join ["-", [my-client-bucket, !Ref ClientName, backup]]]]
最初に、ラムダ関数のArnを含むIdentity
変数を指定します。これを変数に入れると、指定する必要があるのは1回だけです。すべての変数をCustom::Variable
タイプの変数にします。 CloudFormationでは、カスタムリソースに対してCustom::
で始まる任意のタイプ名を使用できます。
Identity
変数には、ラムダ関数のArnが2回含まれていることに注意してください。一度使用するラムダ関数を指定します。変数の値として2回目。
Identity
変数を取得したので、ServiceToken: !GetAtt [Identity, Arn]
を使用して新しい変数を定義できます(JSONコードは"ServiceToken": {"Fn::GetAtt": ["Identity", "Arn"]}
のようになるはずです)。 2つの新しい変数を作成し、それぞれにNameとArnの2つのフィールドを設定します。テンプレートの残りの部分では、必要なときにいつでも!GetAtt [ClientBucketVar, Name]
または!GetAtt [ClientBucketVar, Arn]
を使用できます。
カスタムリソースを使用している場合、ラムダ関数がクラッシュすると、CloudFormationが(クラッシュした)関数からの応答を1時間待ってから中止するため、1〜2時間スタックします。したがって、ラムダ関数の開発中にスタックの短いタイムアウトを指定することをお勧めします。
答えはありませんが、Fn::Sub
代わりに Fn::Join
{ "Fn::Sub": "${ELBHostName"}-1.${EnvironmentVersioned}.${HostedZone}"}
置き換え
"Fn::Join": [
".", [
{ "Fn::Join": [ "", [ { "Ref": "ELBHostName" }, "-1" ] ] },
{ "Ref": "EnvironmentVersioned" },
{ "Ref": "HostedZone" }
]
]
いいえ、試しましたが、空っぽになりました。私にとって意味のある方法は、「CustomVariables」と呼ばれるマッピングエントリを作成し、それにすべての変数を格納することでした。単純な文字列に対しては機能しますが、 Mappings 内の組み込み関数(Refs、Fn :: Joinsなど)は使用できません。
作品:
"Mappings" : {
"CustomVariables" : {
"Variable1" : { "Value" : "foo" },
"Variable2" : { "Value" : "bar" }
}
}
動作しません:
"Variable3" : { "Value" : { "Ref" : "AWS::Region" } }
これは単なる例です。スタンドアロンのRefを変数に入れません。
出力のすべての変数を解決するネストされたスタックを使用してから、Fn::GetAtt
そのスタックから出力を読み取る
ネストされたテンプレートを使用して、外部テンプレートのすべての変数を「解決」し、それらを別のテンプレートに渡すことができます。