入力されたパラメーターの数に応じてCloudFormationテンプレートファイルを動的に変化させてみた
AWS CloudFormationでループ処理させたいな
こんにちは、のんピ(@non____97)です。
AWS CloudFormationを使って同じようなリソースを作る際にループ処理があれば良いなぁと思ったことはありますか? 私はあります。
ループ処理はマクロやAWS CDKを使えば対応可能ですが、以下のような要件がある場合は難しいです。
- AWS CloudFormationもしくは、AWS SAMを使う必要がある
- ループして作成されたリソース毎にパラメーターが異なる
ループ処理をするマクロの例
そこで、完全な力技ですが、シェルスクリプトを使って、入力されたパラメーターの数に応じてCloudFormationテンプレートファイルを動的に変化させてみました。
構成の紹介
ベースとなる環境は以下の記事で紹介したAWS Step FunctionsのCI/CD環境です。
CodeCommit上のリポジトリに変更が発生すると、CodeBuildでAWS SAMを使ってステートマシンやEventBridgeルールなどの各種リソースを作成しています。
CodeBuildでは以下の処理を行なっています。
- yqやAWS SAM CLIなどをインストールする
- 事前にS3バケットにアップロードしていた
pre_build_command.sh
とbuild_command.sh
をダウンロードする pre_build_command.sh
を実行する- リポジトリ上の設定ファイルからCron式やイベントパターン、タグなどの情報を読み込む
- 事前にS3バケットにアップロードしていた
sam-template.yml
をダウンロードする
build_command.sh
を実行する- 必要があればAssume Roleをし、一時認証情報を環境変数にセットする
- AWS SAM CLIで設定ファイルに記入されたリソースをデプロイする
yqはjqのYAML版のようなものです。yqはPython製とGo製の2つがあります。
Python製のyq
Go製のyq
今回はPython製のyqを使用しています。yqの操作方法については上述のリポジトリや以下記事をご覧ください。
Python製のyqの場合、基本的な操作はjqと同じなのでjqのマニュアルもオススメです。
変更前の各種ファイル
sam-template.yml
が使用するCloudFormationのテンプレートファイルです。このファイルは698行もあります。
CloudFormationのテンプレートファイルでは、EventBridgeルールに設定するCron式やイベントパターン、イベントバスをそれぞれ最大5つずつ設定できるようにしています。CloudFormationではループ処理ができないので、それぞれ5つ分のリソースを定義しており、かなりのボリュームがあります。
ScheduledRule1: Condition: ExistsCron1 Type: AWS::Events::Rule Properties: Description: ScheduledRule ScheduleExpression: !Sub ${Cron1} State: ENABLED Targets: - Arn: !Ref StateMachine Id: !GetAtt StateMachine.Name RoleArn: !GetAtt ExecuteStateMachineRole.Arn ScheduledRule2: Condition: ExistsCron2 Type: AWS::Events::Rule Properties: Description: ScheduledRule ScheduleExpression: !Sub ${Cron2} State: ENABLED Targets: - Arn: !Ref StateMachine Id: !GetAtt StateMachine.Name RoleArn: !GetAtt ExecuteStateMachineRole.Arn ScheduledRule3: Condition: ExistsCron3 Type: AWS::Events::Rule Properties: Description: ScheduledRule ScheduleExpression: !Sub ${Cron3} State: ENABLED Targets: - Arn: !Ref StateMachine Id: !GetAtt StateMachine.Name RoleArn: !GetAtt ExecuteStateMachineRole.Arn ScheduledRule4: Condition: ExistsCron4 Type: AWS::Events::Rule Properties: Description: ScheduledRule ScheduleExpression: !Sub ${Cron4} State: ENABLED Targets: - Arn: !Ref StateMachine Id: !GetAtt StateMachine.Name RoleArn: !GetAtt ExecuteStateMachineRole.Arn ScheduledRule5: Condition: ExistsCron5 Type: AWS::Events::Rule Properties: Description: ScheduledRule ScheduleExpression: !Sub ${Cron5} State: ENABLED Targets: - Arn: !Ref StateMachine Id: !GetAtt StateMachine.Name RoleArn: !GetAtt ExecuteStateMachineRole.Arn
また、pre_build_command.sh
とbuild_command.sh
は以下の通りです。※ 長いので折り畳みます。
pre_build_command.sh
とbuild_command.sh
#!/bin/bash # -x to display the command to be executed set -x bucket_name="$1" sam_file_name="$2" repository_path="$3" deployment_destination_account_iam_role_arn=$(yq -r ".Settings.deployment_destination_account_iam_role_arn" ${repository_path}StateMachineSettings.yml) echo deployment_destination_account_iam_role_arn : ${deployment_destination_account_iam_role_arn} i=0 IFS=$'\n'; for cron in $(yq -rc ".Settings.event_bridge_rule[].cron? | select(.!=null)" ${repository_path}StateMachineSettings.yml); do cron_array[$((i++))]=$(echo ${cron}) done echo "${cron_array[@]}" i=0 IFS=$'\n'; for event_pattern in $(yq -rc ".Settings.event_bridge_rule[].event_pattern? | select(.!=null)" ${repository_path}StateMachineSettings.yml); do event_pattern_array[$((i++))]=$(echo ${event_pattern}) done echo "${event_pattern_array[@]}" i=0 IFS=$'\n'; for event_bus_arn in $(yq -rc ".Settings.event_bridge_rule[].event_bus_arn? | select(.!=null)" ${repository_path}StateMachineSettings.yml); do event_bus_arn_array[$((i++))]=$(echo ${event_bus_arn}) done echo "${event_bus_arn_array[@]}" i=0 IFS=$'\n'; for target_event_bus_arn in $(yq -rc ".Settings.target_event_bus_arn[]" ${repository_path}StateMachineSettings.yml); do target_event_bus_arn_array[$((i++))]=$(echo ${target_event_bus_arn}) done echo "${target_event_bus_arn_array[@]}" xray_tracing=$(yq -r ".Settings.xray_tracing" ${repository_path}StateMachineSettings.yml) echo xray_tracing : ${xray_tracing} iam_policy_document=$(yq -r ".Settings.iam_policy_document" ${repository_path}StateMachineSettings.yml) echo iam_policy_document : ${iam_policy_document} IFS=$'\n'; for tag in $(yq -rc ".Settings.tags[]" ${repository_path}StateMachineSettings.yml); do key=$(echo ${tag} | jq -r .Key) value=$(echo ${tag} | jq -r .Value) tags_list+=$(echo "'${key}'"="'${value}' ") done echo tags_list : ${tags_list} # Download the AWS SAM template file from the S3 bucket aws s3 cp s3://${bucket_name}/${sam_file_name} ${sam_file_name} cat StateMachineWorkFlow.asl.json # Move the necessary files to the AWS SAM directory mkdir -p sam-sfn/state_machine cp -p ${repository_path}StateMachineWorkFlow.asl.json ./sam-sfn/state_machine/StateMachineWorkFlow.asl.json cp -p ${sam_file_name} ./sam-sfn/${sam_file_name} _cron_array=$(IFS=';'; echo "${cron_array[*]}") _event_pattern_array=$(IFS=';'; echo "${event_pattern_array[*]}") _event_bus_arn_array=$(IFS=';'; echo "${event_bus_arn_array[*]}") _target_event_bus_arn_array=$(IFS=';'; echo "${target_event_bus_arn_array[*]}")
#!/bin/bash # -x to display the command to be executed set -x bucket_name="$1" sam_file_name="$2" state_machine_name="$3" stack_unique_id="$4" echo deployment_destination_account_iam_role_arn : ${deployment_destination_account_iam_role_arn} IFS=';'; cron_array=(${_cron_array}); unset IFS IFS=';'; event_pattern_array=(${_event_pattern_array}); unset IFS IFS=';'; event_bus_arn_array=(${_event_bus_arn_array}); unset IFS IFS=';'; target_event_bus_arn_array=(${_target_event_bus_arn_array}); unset IFS echo "${cron_array[@]}" echo "${event_pattern_array[@]}" echo "${event_bus_arn_array[@]}" echo "${target_event_bus_arn_array[@]}" echo xray_tracing : ${xray_tracing} echo iam_policy_document : ${iam_policy_document} echo tags_list : ${tags_list} cd sam-sfn ls -l ./state_machine/StateMachineWorkFlow.asl.json if [[ "${deployment_destination_account_iam_role_arn}" != null ]]; then before=$(aws sts get-caller-identity | jq -r .Arn) output=$(aws sts assume-role --role-arn ${deployment_destination_account_iam_role_arn} --role-session-name sam-deploy-session) AWS_ACCESS_KEY_ID=$(echo ${output} | jq -r .Credentials.AccessKeyId) AWS_SECRET_ACCESS_KEY=$(echo ${output} | jq -r .Credentials.SecretAccessKey) AWS_SESSION_TOKEN=$(echo ${output} | jq -r .Credentials.SessionToken) after=$(aws sts get-caller-identity | jq -r .Arn) fi AWS_ACCOUNT=$(aws sts get-caller-identity | jq -r .Account) if [[ -s ./state_machine/StateMachineWorkFlow.asl.json ]]; then sam build \ --template-file ${sam_file_name} sam package \ --template-file ${sam_file_name} \ --s3-bucket ${bucket_name} \ --s3-prefix ${state_machine_name}_${AWS_ACCOUNT} \ --output-template-file output.yml deploy_command=(sam deploy \ --template-file output.yml \ --s3-bucket ${bucket_name} \ --s3-prefix ${state_machine_name}_${AWS_ACCOUNT} \ --stack-name ${state_machine_name} \ --capabilities CAPABILITY_IAM \ --no-fail-on-empty-changeset \ --parameter-overrides \ StateMachineName=${state_machine_name} \ StackUniqueId=${stack_unique_id} \ Cron1="'${cron_array[0]}'" \ Cron2="'${cron_array[1]}'" \ Cron3="'${cron_array[2]}'" \ Cron4="'${cron_array[3]}'" \ Cron5="'${cron_array[4]}'" \ EventPattern1="'${event_pattern_array[0]}'" \ EventPattern2="'${event_pattern_array[1]}'" \ EventPattern3="'${event_pattern_array[2]}'" \ EventPattern4="'${event_pattern_array[3]}'" \ EventPattern5="'${event_pattern_array[4]}'" \ EventBusArn1="'${event_bus_arn_array[0]}'" \ EventBusArn2="'${event_bus_arn_array[1]}'" \ EventBusArn3="'${event_bus_arn_array[2]}'" \ EventBusArn4="'${event_bus_arn_array[3]}'" \ EventBusArn5="'${event_bus_arn_array[4]}'" \ TargetEventBusArn1="'${target_event_bus_arn_array[0]}'" \ TargetEventBusArn2="'${target_event_bus_arn_array[1]}'" \ TargetEventBusArn3="'${target_event_bus_arn_array[2]}'" \ TargetEventBusArn4="'${target_event_bus_arn_array[3]}'" \ TargetEventBusArn5="'${target_event_bus_arn_array[4]}'" \ XRayTracing=${xray_tracing} \ IamPolicyDocument="'${iam_policy_document}'") if [[ -n "${tags_list}" ]]; then "${deploy_command[@]}" \ --tags "'${tags_list}'" else "${deploy_command[@]}" fi aws cloudformation describe-stacks --stack-name ${state_machine_name} else # If the ASL file is empty, delete the stack yes | \ sam delete \ --stack-name ${state_machine_name} fi
このようなテンプレートファイルとシェルスクリプトだと、各リソースを5つ以上設定できるようにしたい場合にテンプレートファイルもシェルスクリプトも変更する必要があるなどメンテナンスも大変です。
これを次章以降、設定ファイルに入力されたパラメーターの数に応じて、CloudFormationテンプレートファイルを動的に変化するように変更します。
シェルスクリプト魔改造してみた
CloudFormationテンプレートファイル
シェルスクリプトを魔改造して、入力されたパラメーターの数に応じてCloudFormationテンプレートファイルを動的に変化するようにします。
まず、テンプレートファイルから修正します。
テンプレートファイルないには繰り返し定義されているものと、そうでないものとの2種類があります。
これを区別するために、ループ処理の対象にIndex
から始まる区切り文字を付与します。
例) 入力されたCron式の数によって動的に変化するもの : CronIndexCron
,ScheduledRuleIndexCron
また、yqではYAMLのタグを保持できません。そのため、ループ処理させたい箇所の組み込み関数は!Ref
や!Sub
など短縮記法ではなく、Ref:
やFn::Sub:
で定義します。
行数は234行とかなり減りました。
実際のテンプレートファイルは以下の通りです。
AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 Description: > sfn-sam Sample SAM Template for sfn-sam Parameters: StateMachineName: Description: Please type the Step Functions State Machine Name. Type: String Default: sfn-sam-state-machine StackUniqueId: Description: Please type the Stack unique ID. Type: String Default: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx CronIndexCron: Description: Please type the Cron. Type: String Default: "null" EventPatternIndexEventPattern: Description: Please type the EventPattern. Type: String Default: "null" EventBusArnIndexEventBusArn: Description: Please type the Event Bus ARN. Type: String Default: "null" TargetEventBusArnIndexTargetEventBusArn: Description: Please type the target event bus arn after execution. Type: String Default: "null" XRayTracing: Description: Please type the AWS X-Ray trace to enable or not. Type: String Default: false AllowedValues: - true - false IamPolicyDocument: Description: Please type the IAM Policy Document. Type: String Conditions: IsEnabledXRayTracing: !Equals - !Sub ${XRayTracing} - true ExistsIamPolicyDocument: !Not - !Equals - !Sub ${IamPolicyDocument} - "null" Resources: StateMachine: Type: AWS::Serverless::StateMachine Properties: Name: !Sub ${StateMachineName} DefinitionUri: state_machine/StateMachineWorkFlow.asl.json Role: !GetAtt StateMachineRole.Arn Logging: Level: ALL IncludeExecutionData: True Destinations: - CloudWatchLogsLogGroup: LogGroupArn: !GetAtt StateMachineLogGroup.Arn Tracing: Enabled: !Sub ${XRayTracing} StateMachineLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName : !Sub '/aws/vendedlogs/states/${StateMachineName}-${StackUniqueId}-Logs' RetentionInDays: 731 StateMachineRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - states.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyDocument: { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogDelivery", "logs:GetLogDelivery", "logs:UpdateLogDelivery", "logs:DeleteLogDelivery", "logs:ListLogDeliveries", "logs:PutResourcePolicy", "logs:DescribeResourcePolicies", "logs:DescribeLogGroups" ], "Resource": "*" } ] } PolicyName: CloudWatchLogsDeliveryFullAccessPolicy - !If - IsEnabledXRayTracing - PolicyDocument: { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "xray:PutTraceSegments", "xray:PutTelemetryRecords", "xray:GetSamplingRules", "xray:GetSamplingTargets" ], "Resource": [ "*" ] } ] } PolicyName: XRayAccessPolicy - !Ref AWS::NoValue - !If - ExistsIamPolicyDocument - PolicyDocument: !Sub ${IamPolicyDocument} PolicyName: IamPolicyForExecuteStateMachine - !Ref AWS::NoValue ScheduledRuleIndexCron: Type: AWS::Events::Rule Properties: Description: ScheduledRule ScheduleExpression: Fn::Sub: ${CronIndexCron} State: ENABLED Targets: - Arn: Ref: StateMachine Id: Fn::GetAtt: StateMachine.Name RoleArn: Fn::GetAtt: ExecuteStateMachineRole.Arn EventPatternRuleIndexEventPattern: Type: AWS::Events::Rule Properties: Description: EventPatternRule EventPattern: Fn::Sub: ${EventPatternIndexEventPattern} EventBusName: Fn::Sub: ${EventBusArnIndexEventBusArn} State: ENABLED Targets: - Arn: Ref: StateMachine Id: Fn::GetAtt: StateMachine.Name RoleArn: Fn::GetAtt: ExecuteStateMachineRole.Arn ExecuteStateMachineRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - events.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyName: states_StartExecution PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - states:StartExecution Resource: - !Ref StateMachine TargetEventBusArnRuleIndexTargetEventBusArn: Type: AWS::Events::Rule Properties: Description: TargetEventBusArnRule EventPattern: { "source": ["aws.states"], "detail-type": ["Step Functions Execution Status Change"], "detail": { "status": ["SUCCEEDED"], "stateMachineArn": [Ref: StateMachine] } } State: ENABLED Targets: - Arn: Ref: TargetEventBusArnIndexTargetEventBusArn Id: TargetEventBusArnIndexTargetEventBusArn RoleArn: Fn::GetAtt: InvokeEventBusRoleIndexTargetEventBusArn.Arn InvokeEventBusRoleIndexTargetEventBusArn: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - events.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyName: InvokeEventBus PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - events:PutEvents Resource: - Ref: TargetEventBusArnIndexTargetEventBusArn
シェルスクリプト
build_command.sh
CloudFormationのテンプレートファイルの修正が終わったら、次はbuild_command.sh
の修正です。
build_command.sh
はsam build
やsam deploy
などAWS SAM CLIを実行しています。
sam deploy
時にテンプレートファイルに渡すパラメーターの数が動的に変化する必要があります。
そのため、CloudFormationのテンプレートファイルと同様に、ループ処理の対象にIndex
から始まる区切り文字を付与します。
実際のコードは以下の通りです。
#!/bin/bash # -x to display the command to be executed set -x bucket_name="$1" sam_file_name="$2" state_machine_name="$3" stack_unique_id="$4" # Check variables echo deployment_destination_account_iam_role_arn : ${deployment_destination_account_iam_role_arn} IFS=';'; cron_array=(${tmp_cron_array}); unset IFS IFS=';'; event_pattern_array=(${tmp_event_pattern_array}); unset IFS IFS=';'; event_bus_arn_array=(${tmp_event_bus_arn_array}); unset IFS IFS=';'; target_event_bus_arn_array=(${tmp_target_event_bus_arn_array}); unset IFS echo "${cron_array[@]}" echo "${event_pattern_array[@]}" echo "${event_bus_arn_array[@]}" echo "${target_event_bus_arn_array[@]}" echo xray_tracing : ${xray_tracing} echo iam_policy_document : ${iam_policy_document} echo tags_list : ${tags_list} # Change to the directory where AWS SAM CLI is to be executed cd sam-sfn # Check that the State Machine workflow exists ls -l ./state_machine/StateMachineWorkFlow.asl.json # Assume Role if the deployment destination is a different AWS account if [[ "${deployment_destination_account_iam_role_arn}" != null ]]; then before=$(aws sts get-caller-identity | jq -r .Arn) output=$(aws sts assume-role --role-arn ${deployment_destination_account_iam_role_arn} --role-session-name sam-deploy-session) AWS_ACCESS_KEY_ID=$(echo ${output} | jq -r .Credentials.AccessKeyId) AWS_SECRET_ACCESS_KEY=$(echo ${output} | jq -r .Credentials.SecretAccessKey) AWS_SESSION_TOKEN=$(echo ${output} | jq -r .Credentials.SessionToken) after=$(aws sts get-caller-identity | jq -r .Arn) fi AWS_ACCOUNT=$(aws sts get-caller-identity | jq -r .Account) # If the "StateMachineWorkFlow.asl.json" is not empty, then Deploying resources with AWS SAM CLI if [[ -s ./state_machine/StateMachineWorkFlow.asl.json ]]; then sam build \ --template-file ${sam_file_name} sam package \ --template-file ${sam_file_name} \ --s3-bucket ${bucket_name} \ --s3-prefix ${state_machine_name}_${AWS_ACCOUNT} \ --output-template-file output.yml deploy_command=(sam deploy \ --template-file output.yml \ --s3-bucket ${bucket_name} \ --s3-prefix ${state_machine_name}_${AWS_ACCOUNT} \ --stack-name ${state_machine_name} \ --capabilities CAPABILITY_IAM \ --no-fail-on-empty-changeset \ --parameter-overrides \ StateMachineName=${state_machine_name} \ StackUniqueId=${stack_unique_id} \ CronIndexCron="'${cron_array[IndexCron]}'" \ EventPatternIndexEventPattern="'${event_pattern_array[IndexEventPattern]}'" \ EventBusArnIndexEventBusArn="'${event_bus_arn_array[IndexEventBusArn]}'" \ TargetEventBusArnIndexTargetEventBusArn="'${target_event_bus_arn_array[IndexTargetEventBusArn]}'" \ XRayTracing=${xray_tracing} \ IamPolicyDocument="'${iam_policy_document}'") # If tags are specified, add an option to specify tags if [[ -n "${tags_list}" ]]; then "${deploy_command[@]}" \ --tags "'${tags_list}'" else "${deploy_command[@]}" fi # After deployment, the stack is displayed aws cloudformation describe-stacks --stack-name ${state_machine_name} else # If the "StateMachineWorkFlow.asl.json" is empty, delete the stack yes | \ sam delete \ --stack-name ${state_machine_name} fi
pre_build_command.sh
最後にpre_build_command.sh
を修正します。
pre_build_command.sh
内で行なっている、リソース毎の処理の流れは以下の通りです。
- テンプレートファイル上で繰り返し定義したい内容を変数に保存する
- テンプレートファイル上の繰り返し定義したい内容を削除する
- 設定ファイルに入力されたパラメーターの数分、次の処理を繰り返す
build_dcommand.sh
上のIndex
から始まる区切り文字を含む行をコピーして、次の行に貼り付ける- 変数に保存していた繰り返し定義したい内容をテンプレートファイルに追加する。その際、
Index
から始まる区切り文字をループした回数に置換する。
- 例) 区切り文字が
IndexCron
でループ回数が0
回の場合は、IndexCron
を0
に置換する。
- 配列に設定ファイルに入力されたパラメーターを保存する
build_dcommand.sh
上のIndex
から始まる区切り文字を含む行を削除する
これを各リソース毎におこないます。
ここではsed
とyq
が大活躍します。
sedはパターンスペースとホールドスペースの動きを理解することが必要です。その際、ITmediaさんの以下記事が非常に参考になりました。
実際のコードは以下の通りです。
#!/bin/bash # -x to display the command to be executed set -x bucket_name="$1" sam_file_name="$2" repository_path="$3" # Download the AWS SAM template file from the S3 bucket aws s3 cp s3://${bucket_name}/${sam_file_name} ${sam_file_name} # Display State Machine workflow cat StateMachineWorkFlow.asl.json # Move the necessary files to the AWS SAM directory mkdir -p sam-sfn/state_machine cp -p ${repository_path}StateMachineWorkFlow.asl.json ./sam-sfn/state_machine/StateMachineWorkFlow.asl.json cp -p ${sam_file_name} ./sam-sfn/${sam_file_name} # Get the ARN of the IAM role to be used when deploying deployment_destination_account_iam_role_arn=$(yq -r ".Settings.deployment_destination_account_iam_role_arn" ${repository_path}StateMachineSettings.yml) echo deployment_destination_account_iam_role_arn : ${deployment_destination_account_iam_role_arn} # Get the Cron expression of the EventBridge rule associated with the State Machine # Template delimiter delimiter=IndexCron # Get the template part of Parameters and Resources template_parameter=$(yq -r ".Parameters.Cron${delimiter}" ./sam-sfn/${sam_file_name}) template_resource=$(yq -r ".Resources.ScheduledRule${delimiter}" ./sam-sfn/${sam_file_name}) # Remove the template parts of Parameters and Resources from the template file cat ./sam-sfn/${sam_file_name} | \ yq 'del(.Parameters.Cron'${delimiter}')' -Y | \ yq 'del(.Resources.ScheduledRule'${delimiter}')' -Y | \ tee ./sam-sfn/tmp_${sam_file_name} mv ./sam-sfn/tmp_${sam_file_name} ./sam-sfn/${sam_file_name} i=0 IFS=$'\n'; for cron in $(yq -rc ".Settings.event_bridge_rule[].cron? | select(.!=null)" ${repository_path}StateMachineSettings.yml); do # Copy and paste the line with the delimiter on "build_command.sh" to the next line sed -i -e "/${delimiter}/{ h; s/${delimiter}/${i}/g; G; }" build_command.sh # Add Parameters and Resources to the template file cat ./sam-sfn/${sam_file_name} | \ yq --argjson object "${template_parameter}" '.Parameters += {Cron'${i}': $object}' -Y | \ yq --argjson object "${template_resource}" '.Resources += {ScheduledRule'${i}': $object}' -Y | \ sed -e 's/Cron'${delimiter}'/Cron'${i}'/' | \ tee ./sam-sfn/tmp_${sam_file_name} mv ./sam-sfn/tmp_${sam_file_name} ./sam-sfn/${sam_file_name} # Store values entered in the configuration file as an array cron_array[$((i++))]=$(echo ${cron}) done # Delete lines with delimiters on "build_command.sh sed -i "/${delimiter}/d" build_command.sh # Check values in an array echo "${cron_array[@]}" # Get the ARN of the Event Bus of the EventBridge rule event pattern associated with the State Machine # Template delimiter delimiter=IndexEventBusArn i=0 IFS=$'\n'; for event_bus_arn in $(yq -rc ".Settings.event_bridge_rule[].event_bus_arn? | select(.!=null)" ${repository_path}StateMachineSettings.yml); do # Copy and paste the line with the delimiter on "build_command.sh" to the next line sed -i -e "/${delimiter}/{ h; s/${delimiter}/${i}/g; G; }" build_command.sh # Store values entered in the configuration file as an array event_bus_arn_array[$((i++))]=$(echo ${event_bus_arn}) done # Delete lines with delimiters on "build_command.sh sed -i "/${delimiter}/d" build_command.sh # Check values in an array echo "${event_bus_arn_array[@]}" # Get the event pattern of the EventBridge rule associated with the State Machine # Template delimiter delimiter_event_pattern=IndexEventPattern delimiter_event_bus_arn=IndexEventBusArn # Get the template part of Parameters and Resources template_parameter_event_pattern=$(yq -r ".Parameters.EventPattern${delimiter_event_pattern}" ./sam-sfn/${sam_file_name}) template_parameter_event_bus_arn=$(yq -r ".Parameters.EventBusArn${delimiter_event_bus_arn}" ./sam-sfn/${sam_file_name}) template_resource_event_pattern=$(yq -r ".Resources.EventPatternRule${delimiter_event_pattern}" ./sam-sfn/${sam_file_name}) # Remove the template parts of Parameters and Resources from the template file cat ./sam-sfn/${sam_file_name} | \ yq 'del(.Parameters.EventPattern'${delimiter_event_pattern}')' -Y | \ yq 'del(.Parameters.EventBusArn'${delimiter_event_bus_arn}')' -Y | \ yq 'del(.Resources.EventPatternRule'${delimiter_event_pattern}')' -Y | \ tee ./sam-sfn/tmp_${sam_file_name} mv ./sam-sfn/tmp_${sam_file_name} ./sam-sfn/${sam_file_name} i=0 IFS=$'\n'; for event_pattern in $(yq -rc ".Settings.event_bridge_rule[].event_pattern? | select(.!=null)" ${repository_path}StateMachineSettings.yml); do # Copy and paste the line with the delimiter on "build_command.sh" to the next line sed -i -e "/${delimiter_event_pattern}/{ h; s/${delimiter_event_pattern}/${i}/g; G; }" build_command.sh # Add Parameters and Resources to the template file cat ./sam-sfn/${sam_file_name} | \ yq --argjson object "${template_parameter_event_pattern}" '.Parameters += {EventPattern'${i}': $object}' -Y | \ yq --argjson object "${template_parameter_event_bus_arn}" '.Parameters += {EventBusArn'${i}': $object}' -Y | \ yq --argjson object "${template_resource_event_pattern}" '.Resources += {EventPatternRule'${i}': $object}' -Y | \ sed -e 's/EventPattern'${delimiter_event_pattern}'/EventPattern'${i}'/' | \ sed -e 's/EventBusArn'${delimiter_event_bus_arn}'/EventBusArn'${i}'/' | \ tee ./sam-sfn/tmp_${sam_file_name} mv ./sam-sfn/tmp_${sam_file_name} ./sam-sfn/${sam_file_name} # Store values entered in the configuration file as an array event_pattern_array[$((i++))]=$(echo ${event_pattern}) done # Delete lines with delimiters on "build_command.sh sed -i "/${delimiter_event_pattern}/d" build_command.sh # Check values in an array echo "${event_pattern_array[@]}" # Get the ARN of the Event Bus that puts an event when the State Machine finishes successfully # Template delimiter delimiter=IndexTargetEventBusArn # Get the template part of Parameters and Resources template_parameter_target_event_bus_arn=$(yq -r ".Parameters.TargetEventBusArn${delimiter}" ./sam-sfn/${sam_file_name}) template_resource_target_event_bus_arn_rule=$(yq -r ".Resources.TargetEventBusArnRule${delimiter}" ./sam-sfn/${sam_file_name}) template_resource_target_event_bus_arn_role=$(yq -r ".Resources.InvokeEventBusRole${delimiter}" ./sam-sfn/${sam_file_name}) # Remove the template parts of Parameters and Resources from the template file cat ./sam-sfn/${sam_file_name} | \ yq 'del(.Parameters.TargetEventBusArn'${delimiter}')' -Y | \ yq 'del(.Resources.TargetEventBusArnRule'${delimiter}')' -Y | \ yq 'del(.Resources.InvokeEventBusRole'${delimiter}')' -Y | \ tee ./sam-sfn/tmp_${sam_file_name} mv ./sam-sfn/tmp_${sam_file_name} ./sam-sfn/${sam_file_name} i=0 IFS=$'\n'; for target_event_bus_arn in $(yq -rc ".Settings.target_event_bus_arn[]" ${repository_path}StateMachineSettings.yml); do # Copy and paste the line with the delimiter on "build_command.sh" to the next line sed -i -e "/${delimiter}/{ h; s/${delimiter}/${i}/g; G; }" build_command.sh # Add Parameters and Resources to the template file cat ./sam-sfn/${sam_file_name} | \ yq --argjson object "${template_parameter_target_event_bus_arn}" '.Parameters += {TargetEventBusArn'${i}': $object}' -Y | \ yq --argjson object "${template_resource_target_event_bus_arn_rule}" '.Resources += {TargetEventBusArnRule'${i}': $object}' -Y | \ yq --argjson object "${template_resource_target_event_bus_arn_role}" '.Resources += {InvokeEventBusRole'${i}': $object}' -Y | \ sed -e 's/TargetEventBusArn'${delimiter}'/TargetEventBusArn'${i}'/g' | \ sed -e 's/InvokeEventBusRole'${delimiter}'/InvokeEventBusRole'${i}'/g' | \ tee ./sam-sfn/tmp_${sam_file_name} mv ./sam-sfn/tmp_${sam_file_name} ./sam-sfn/${sam_file_name} # Store values entered in the configuration file as an array target_event_bus_arn_array[$((i++))]=$(echo ${target_event_bus_arn}) done # Delete lines with delimiters on "build_command.sh sed -i "/${delimiter}/d" build_command.sh # Check values in an array echo "${target_event_bus_arn_array[@]}" # Get whether State Machine enables X-Ray tracing xray_tracing=$(yq -r ".Settings.xray_tracing" ${repository_path}StateMachineSettings.yml) echo xray_tracing : ${xray_tracing} # Get the IAM Policy document to attach to the IAM Role associated with the State Machine iam_policy_document=$(yq -r ".Settings.iam_policy_document" ${repository_path}StateMachineSettings.yml) echo iam_policy_document : ${iam_policy_document} # Get tags to attach to resources created by CloudFormation IFS=$'\n'; for tag in $(yq -rc ".Settings.tags[]" ${repository_path}StateMachineSettings.yml); do key=$(echo ${tag} | jq -r .Key) value=$(echo ${tag} | jq -r .Value) tags_list+=$(echo "'${key}'"="'${value}' ") done echo tags_list : ${tags_list} # Change arrays temporarily to strings tmp_cron_array=$(IFS=';'; echo "${cron_array[*]}") tmp_event_pattern_array=$(IFS=';'; echo "${event_pattern_array[*]}") tmp_event_bus_arn_array=$(IFS=';'; echo "${event_bus_arn_array[*]}") tmp_target_event_bus_arn_array=$(IFS=';'; echo "${target_event_bus_arn_array[*]}")
デプロイしてみた
それでは実際に修正したテンプレートファイル、シェルスクリプトを使ってデプロイしてみます。
設定ファイル(StateMachineSettings.yml
)は以下のように入力しました。
Settings: deployment_destination_account_iam_role_arn: event_bridge_rule: - cron: cron(15 11 * * ? *) - cron: cron(15 23 * * ? *) - event_pattern: { "source": ["aws.states"], "detail-type": ["Step Functions Execution Status Change"], "detail": { "status": ["SUCCEEDED"], "stateMachineArn": ["arn:aws:states:us-east-1:<AWSアカウントID>:stateMachine:nonpi"] } } event_bus_arn: arn:aws:events:us-east-1:<AWSアカウントID>:event-bus/default - event_pattern: { "source": ["aws.states"], "detail-type": ["Step Functions Execution Status Change"], "detail": { "status": ["SUCCEEDED"], "stateMachineArn": ["arn:aws:states:us-east-1:<AWSアカウントID>:stateMachine:aaaaaaaaaaaaabbbbbccccdddefg"] } } event_bus_arn: arn:aws:events:us-east-1:<AWSアカウントID>:event-bus/default target_event_bus_arn: - arn:aws:events:us-east-1:<AWSアカウントID>:event-bus/StateMachineEventBus - arn:aws:events:us-east-2:<AWSアカウントID>:event-bus/default xray_tracing: true iam_policy_document: { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ec2:stopInstances" ], "Resource": [ "arn:aws:ec2:us-east-1:<AWSアカウントID>:instance/i-0a3b8c7357a46b183", "arn:aws:ec2:us-east-1:<AWSアカウントID>:instance/i-0a3b8c7357a46dddd", "arn:aws:ec2:us-east-1:<AWSアカウントID>:instance/i-0cb6e117c54a102f4" ] } ] } tags: - Key: System Name Value: System 2 - Key: Environment Value: production - Key: Auther Value: non-97 - Key: Corporate Value: Classmethod
コミットしてしばらくすると、スタックが作成されていました。作成されたスタックの情報をマネージメントコンソールから確認すると、設定ファイルに入力した通りのタグが付与されていることが確認できました。
次に、リソース
タブをクリックすると、設定ファイルに入力した通りのリソースが作成されていました。
続いて、テンプレート
タブをクリックして、このスタックのテンプレートファイルを確認します。
Cron式を2つ入力したので、Cron0
やCron1
、ScheduledRule0
、ScheduledRule1
と入力されたCron式の数に応じてテンプレートファイルが変化していることが確認できます。
CloudFormationのテンプレートファイル
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: 'sfn-sam Sample SAM Template for sfn-sam ' Parameters: StateMachineName: Description: Please type the Step Functions State Machine Name. Type: String Default: sfn-sam-state-machine StackUniqueId: Description: Please type the Stack unique ID. Type: String Default: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx XRayTracing: Description: Please type the AWS X-Ray trace to enable or not. Type: String Default: false AllowedValues: - true - false IamPolicyDocument: Description: Please type the IAM Policy Document. Type: String Cron0: Description: Please type the Cron. Type: String Default: 'null' Cron1: Description: Please type the Cron. Type: String Default: 'null' EventPattern0: Description: Please type the EventPattern. Type: String Default: 'null' EventBusArn0: Description: Please type the Event Bus ARN. Type: String Default: 'null' EventPattern1: Description: Please type the EventPattern. Type: String Default: 'null' EventBusArn1: Description: Please type the Event Bus ARN. Type: String Default: 'null' TargetEventBusArn0: Description: Please type the target event bus arn after execution. Type: String Default: 'null' TargetEventBusArn1: Description: Please type the target event bus arn after execution. Type: String Default: 'null' Conditions: IsEnabledXRayTracing: Fn::Equals: - Fn::Sub: ${XRayTracing} - true ExistsIamPolicyDocument: Fn::Not: - Fn::Equals: - Fn::Sub: ${IamPolicyDocument} - 'null' Resources: StateMachine: Type: AWS::Serverless::StateMachine Properties: Name: Fn::Sub: ${StateMachineName} DefinitionUri: Bucket: artifactbucketstack-artifactbucket7410c9ef-mpyyu6apfoxt Key: StateMachineTest002_984900217833/b1d331f56a2e20e252e7d04171aecc16 Role: Fn::GetAtt: - StateMachineRole - Arn Logging: Level: ALL IncludeExecutionData: true Destinations: - CloudWatchLogsLogGroup: LogGroupArn: Fn::GetAtt: - StateMachineLogGroup - Arn Tracing: Enabled: Fn::Sub: ${XRayTracing} StateMachineLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: Fn::Sub: /aws/vendedlogs/states/${StateMachineName}-${StackUniqueId}-Logs RetentionInDays: 731 StateMachineRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - states.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - logs:CreateLogDelivery - logs:GetLogDelivery - logs:UpdateLogDelivery - logs:DeleteLogDelivery - logs:ListLogDeliveries - logs:PutResourcePolicy - logs:DescribeResourcePolicies - logs:DescribeLogGroups Resource: '*' PolicyName: CloudWatchLogsDeliveryFullAccessPolicy - Fn::If: - IsEnabledXRayTracing - PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - xray:PutTraceSegments - xray:PutTelemetryRecords - xray:GetSamplingRules - xray:GetSamplingTargets Resource: - '*' PolicyName: XRayAccessPolicy - Ref: AWS::NoValue - Fn::If: - ExistsIamPolicyDocument - PolicyDocument: Fn::Sub: ${IamPolicyDocument} PolicyName: IamPolicyForExecuteStateMachine - Ref: AWS::NoValue ExecuteStateMachineRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - events.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyName: states_StartExecution PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - states:StartExecution Resource: - Ref: StateMachine ScheduledRule0: Type: AWS::Events::Rule Properties: Description: ScheduledRule ScheduleExpression: Fn::Sub: ${Cron0} State: ENABLED Targets: - Arn: Ref: StateMachine Id: Fn::GetAtt: StateMachine.Name RoleArn: Fn::GetAtt: ExecuteStateMachineRole.Arn ScheduledRule1: Type: AWS::Events::Rule Properties: Description: ScheduledRule ScheduleExpression: Fn::Sub: ${Cron1} State: ENABLED Targets: - Arn: Ref: StateMachine Id: Fn::GetAtt: StateMachine.Name RoleArn: Fn::GetAtt: ExecuteStateMachineRole.Arn EventPatternRule0: Type: AWS::Events::Rule Properties: Description: EventPatternRule EventPattern: Fn::Sub: ${EventPattern0} EventBusName: Fn::Sub: ${EventBusArn0} State: ENABLED Targets: - Arn: Ref: StateMachine Id: Fn::GetAtt: StateMachine.Name RoleArn: Fn::GetAtt: ExecuteStateMachineRole.Arn EventPatternRule1: Type: AWS::Events::Rule Properties: Description: EventPatternRule EventPattern: Fn::Sub: ${EventPattern1} EventBusName: Fn::Sub: ${EventBusArn1} State: ENABLED Targets: - Arn: Ref: StateMachine Id: Fn::GetAtt: StateMachine.Name RoleArn: Fn::GetAtt: ExecuteStateMachineRole.Arn TargetEventBusArnRule0: Type: AWS::Events::Rule Properties: Description: TargetEventBusArnRule EventPattern: source: - aws.states detail-type: - Step Functions Execution Status Change detail: status: - SUCCEEDED stateMachineArn: - Ref: StateMachine State: ENABLED Targets: - Arn: Ref: TargetEventBusArn0 Id: TargetEventBusArn0 RoleArn: Fn::GetAtt: InvokeEventBusRole0.Arn InvokeEventBusRole0: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - events.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyName: InvokeEventBus PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - events:PutEvents Resource: - Ref: TargetEventBusArn0 TargetEventBusArnRule1: Type: AWS::Events::Rule Properties: Description: TargetEventBusArnRule EventPattern: source: - aws.states detail-type: - Step Functions Execution Status Change detail: status: - SUCCEEDED stateMachineArn: - Ref: StateMachine State: ENABLED Targets: - Arn: Ref: TargetEventBusArn1 Id: TargetEventBusArn1 RoleArn: Fn::GetAtt: InvokeEventBusRole1.Arn InvokeEventBusRole1: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - events.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyName: InvokeEventBus PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - events:PutEvents Resource: - Ref: TargetEventBusArn1
設定ファイルを編集して、もう一度デプロイしてみます。
cron(11 20 * * ? *)
というCron式のEventBridgeルールを追加で作成するように、設定ファイル(StateMachineSettings.yml
)を更新しました。
Settings: deployment_destination_account_iam_role_arn: event_bridge_rule: - cron: cron(15 11 * * ? *) - cron: cron(15 23 * * ? *) - cron: cron(11 20 * * ? *) - event_pattern: { "source": ["aws.states"], "detail-type": ["Step Functions Execution Status Change"], "detail": { "status": ["SUCCEEDED"], "stateMachineArn": ["arn:aws:states:us-east-1:984900217833:stateMachine:nonpi"] } } event_bus_arn: arn:aws:events:us-east-1:984900217833:event-bus/default - event_pattern: { "source": ["aws.states"], "detail-type": ["Step Functions Execution Status Change"], "detail": { "status": ["SUCCEEDED"], "stateMachineArn": ["arn:aws:states:us-east-1:984900217833:stateMachine:aaaaaaaaaaaaabbbbbccccdddefg"] } } event_bus_arn: arn:aws:events:us-east-1:984900217833:event-bus/default target_event_bus_arn: - arn:aws:events:us-east-1:984900217833:event-bus/StateMachineEventBus - arn:aws:events:us-east-2:984900217833:event-bus/default xray_tracing: true iam_policy_document: { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ec2:stopInstances" ], "Resource": [ "arn:aws:ec2:us-east-1:984900217833:instance/i-0a3b8c7357a46b183", "arn:aws:ec2:us-east-1:984900217833:instance/i-0a3b8c7357a46dddd", "arn:aws:ec2:us-east-1:984900217833:instance/i-0cb6e117c54a102f4" ] } ] } tags: - Key: System Name Value: System 2 - Key: Environment Value: production - Key: Auther Value: non-97 - Key: Corporate Value: Classmethod
コミットしてしばらくすると、スタックが更新されていました。更新されたスタックのリソース一覧をマネージメントコンソールから確認すると、EventBridgeルールが追加されていることが確認できました。
次に、パラメータ
タブをクリックすると、設定ファイルに入力した通りのパラメーターが指定されていました。
続いて、テンプレート
タブをクリックして、このスタックのテンプレートファイルを確認します。
Cron式を3つ入力したので、Cron0
やCron1
、Cron2
、ScheduledRule0
、ScheduledRule1
、ScheduledRule2
と入力されたCron式の数に応じてテンプレートファイルが変化していることが確認できます。
リソース追加後のCloudFormationのテンプレートファイル
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: 'sfn-sam Sample SAM Template for sfn-sam ' Parameters: StateMachineName: Description: Please type the Step Functions State Machine Name. Type: String Default: sfn-sam-state-machine StackUniqueId: Description: Please type the Stack unique ID. Type: String Default: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx XRayTracing: Description: Please type the AWS X-Ray trace to enable or not. Type: String Default: false AllowedValues: - true - false IamPolicyDocument: Description: Please type the IAM Policy Document. Type: String Cron0: Description: Please type the Cron. Type: String Default: 'null' Cron1: Description: Please type the Cron. Type: String Default: 'null' Cron2: Description: Please type the Cron. Type: String Default: 'null' EventPattern0: Description: Please type the EventPattern. Type: String Default: 'null' EventBusArn0: Description: Please type the Event Bus ARN. Type: String Default: 'null' EventPattern1: Description: Please type the EventPattern. Type: String Default: 'null' EventBusArn1: Description: Please type the Event Bus ARN. Type: String Default: 'null' TargetEventBusArn0: Description: Please type the target event bus arn after execution. Type: String Default: 'null' TargetEventBusArn1: Description: Please type the target event bus arn after execution. Type: String Default: 'null' Conditions: IsEnabledXRayTracing: Fn::Equals: - Fn::Sub: ${XRayTracing} - true ExistsIamPolicyDocument: Fn::Not: - Fn::Equals: - Fn::Sub: ${IamPolicyDocument} - 'null' Resources: StateMachine: Type: AWS::Serverless::StateMachine Properties: Name: Fn::Sub: ${StateMachineName} DefinitionUri: Bucket: artifactbucketstack-artifactbucket7410c9ef-mpyyu6apfoxt Key: StateMachineTest002_984900217833/b1d331f56a2e20e252e7d04171aecc16 Role: Fn::GetAtt: - StateMachineRole - Arn Logging: Level: ALL IncludeExecutionData: true Destinations: - CloudWatchLogsLogGroup: LogGroupArn: Fn::GetAtt: - StateMachineLogGroup - Arn Tracing: Enabled: Fn::Sub: ${XRayTracing} StateMachineLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: Fn::Sub: /aws/vendedlogs/states/${StateMachineName}-${StackUniqueId}-Logs RetentionInDays: 731 StateMachineRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - states.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - logs:CreateLogDelivery - logs:GetLogDelivery - logs:UpdateLogDelivery - logs:DeleteLogDelivery - logs:ListLogDeliveries - logs:PutResourcePolicy - logs:DescribeResourcePolicies - logs:DescribeLogGroups Resource: '*' PolicyName: CloudWatchLogsDeliveryFullAccessPolicy - Fn::If: - IsEnabledXRayTracing - PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - xray:PutTraceSegments - xray:PutTelemetryRecords - xray:GetSamplingRules - xray:GetSamplingTargets Resource: - '*' PolicyName: XRayAccessPolicy - Ref: AWS::NoValue - Fn::If: - ExistsIamPolicyDocument - PolicyDocument: Fn::Sub: ${IamPolicyDocument} PolicyName: IamPolicyForExecuteStateMachine - Ref: AWS::NoValue ExecuteStateMachineRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - events.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyName: states_StartExecution PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - states:StartExecution Resource: - Ref: StateMachine ScheduledRule0: Type: AWS::Events::Rule Properties: Description: ScheduledRule ScheduleExpression: Fn::Sub: ${Cron0} State: ENABLED Targets: - Arn: Ref: StateMachine Id: Fn::GetAtt: StateMachine.Name RoleArn: Fn::GetAtt: ExecuteStateMachineRole.Arn ScheduledRule1: Type: AWS::Events::Rule Properties: Description: ScheduledRule ScheduleExpression: Fn::Sub: ${Cron1} State: ENABLED Targets: - Arn: Ref: StateMachine Id: Fn::GetAtt: StateMachine.Name RoleArn: Fn::GetAtt: ExecuteStateMachineRole.Arn ScheduledRule2: Type: AWS::Events::Rule Properties: Description: ScheduledRule ScheduleExpression: Fn::Sub: ${Cron2} State: ENABLED Targets: - Arn: Ref: StateMachine Id: Fn::GetAtt: StateMachine.Name RoleArn: Fn::GetAtt: ExecuteStateMachineRole.Arn EventPatternRule0: Type: AWS::Events::Rule Properties: Description: EventPatternRule EventPattern: Fn::Sub: ${EventPattern0} EventBusName: Fn::Sub: ${EventBusArn0} State: ENABLED Targets: - Arn: Ref: StateMachine Id: Fn::GetAtt: StateMachine.Name RoleArn: Fn::GetAtt: ExecuteStateMachineRole.Arn EventPatternRule1: Type: AWS::Events::Rule Properties: Description: EventPatternRule EventPattern: Fn::Sub: ${EventPattern1} EventBusName: Fn::Sub: ${EventBusArn1} State: ENABLED Targets: - Arn: Ref: StateMachine Id: Fn::GetAtt: StateMachine.Name RoleArn: Fn::GetAtt: ExecuteStateMachineRole.Arn TargetEventBusArnRule0: Type: AWS::Events::Rule Properties: Description: TargetEventBusArnRule EventPattern: source: - aws.states detail-type: - Step Functions Execution Status Change detail: status: - SUCCEEDED stateMachineArn: - Ref: StateMachine State: ENABLED Targets: - Arn: Ref: TargetEventBusArn0 Id: TargetEventBusArn0 RoleArn: Fn::GetAtt: InvokeEventBusRole0.Arn InvokeEventBusRole0: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - events.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyName: InvokeEventBus PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - events:PutEvents Resource: - Ref: TargetEventBusArn0 TargetEventBusArnRule1: Type: AWS::Events::Rule Properties: Description: TargetEventBusArnRule EventPattern: source: - aws.states detail-type: - Step Functions Execution Status Change detail: status: - SUCCEEDED stateMachineArn: - Ref: StateMachine State: ENABLED Targets: - Arn: Ref: TargetEventBusArn1 Id: TargetEventBusArn1 RoleArn: Fn::GetAtt: InvokeEventBusRole1.Arn InvokeEventBusRole1: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - events.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyName: InvokeEventBus PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - events:PutEvents Resource: - Ref: TargetEventBusArn1
それシェルスクリプトで出来るかも
シェルスクリプトを使って、入力されたパラメーターの数に応じてCloudFormationテンプレートファイルを動的に変化させてみました。
かなりのパワープレイですが、AWS CDKやマクロを使わずにAWS CloudFomationでループ処理を実装したい場合は、このようにテンプレートファイルを直接編集するスクリプトを作ることになるのかなと思います。
そのような場面に備えてスクリプトを書く力を鍛えておくことが重要そうですね。
今回シェルスクリプトを書くにあたっては、GoogleのShell Style Guideを参考にしました。
この記事が誰かの助けになれば幸いです。
以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!