はじめに
以前、Step Functionsを使って、EC2上でコマンドを実行する方法の一つを記事としてまとめました。
上記記事ではEC2上のsuccess/failureを、StateMachine側からスリープを挟んでチェックしていました。
今回はEC2側からsuccess/failureを返す方法を記事にします。
概要
- StateMachineでEC2のコマンドを実行する方法として、Systems ManagerのSendCommandを使用
- EC2側からのコールバックを待つようにします
- StateMachie側からTaskTokenを渡します
- コールバックを待つ設定にすると、コンテキストオブジェクトに追加されます
- EC2側からは、
send-task-success
またはsend-task-failure
を実行し応答- その際にTaskTokenが必要です
- 対象のEC2には以下を付与します
- アクション:
states:SendTaskSuccess
、states:SendTaskFailure
の許可 - ポリシー:
AmazonSSMManagedInstanceCore
- SendCommandの実行に必要です
- アクション:
参考
ソース
概要の仕組みを作成するCloudFormationテンプレートは以下になります。
stop.shを実行するコマンドを指定しています。
AWSTemplateFormatVersion: 2010-09-09
Parameters:
InstanceId:
Type: String
Resources:
SMRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- states.amazonaws.com
Action:
- 'sts:AssumeRole'
Path: "/"
Policies:
- PolicyName: allowSsm
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- ssm:SendCommand
Resource: '*'
SendCommandToEc2StateMachine:
Type: AWS::StepFunctions::StateMachine
Properties:
RoleArn: !GetAtt SMRole.Arn
Definition:
StartAt: SendCommandToEc2
States:
SendCommandToEc2:
Type: Task
Resource: arn:aws:states:::aws-sdk:ssm:sendCommand.waitForTaskToken
Parameters:
DocumentName: AWS-RunShellScript
DocumentVersion: "1"
InstanceIds:
- !Ref InstanceId
MaxConcurrency: "50"
MaxErrors: "50"
Parameters:
workingDirectory:
- ""
executionTimeout:
- "3600"
commands.$:
"States.Array( States.Format( 'bash /home/ssm-user/scripts/stop.sh {}', $$.Task.Token ))"
TimeoutSeconds: 60
ResultPath: $.SendCommandOut
Next: Success
Catch:
-
ErrorEquals:
- States.ALL
Next: Fail
Success:
Type: Succeed
Fail:
Type: Fail
- SendCommandToEc2でコマンドを実行
-
SendTaskSuccess
が帰ってきたらSuccessに遷移 -
SendTaskFailure
を含む例外発生時はFailに遷移
-
コマンド部分について補足
commands.$:
"States.Array( States.Format( 'bash /home/ssm-user/scripts/stop.sh {}', $$.Task.Token ))"
-
commands
は配列で指定する必要があるためStates.Array
を使います-
$
を使う場合は[ ]
を配列として使えないです
-
-
stop.sh
の中でsend-task-success
/send-task-failure
を使う際にTaskeTokenを使うので、引数にTaskTokenを指定します-
States.Format
を使ってコマンドを生成しています
-
実行
success
EC2上で実行するファイルは以下になります。引数にTaskeTokenを指定して実行し、aws stepfunctions send-task-success
で用いて応答します。
/home/ssm-user/scripts/stop.sh
echo "Start Scripts:"`date '+%Y-%m-%d %H:%M:%S'` | tee -a /home/ssm-user/scripts/out.txt
sleep 7
aws stepfunctions send-task-success --task-token "$1" --task-output {}
echo "Stop Scripts:"`date '+%Y-%m-%d %H:%M:%S'` | tee -a /home/ssm-user/scripts/out.txt
exit 0
failure
aws stepfunctions send-task-failure
で応答して、例外扱いになるのかも確認するため、ファイルを一部修正します。
/home/ssm-user/scripts/stop.sh
echo "Start Scripts:"`date '+%Y-%m-%d %H:%M:%S'` | tee -a /home/ssm-user/scripts/out.txt
sleep 7
- aws stepfunctions send-task-success --task-token "$1" --task-output {}
+ aws stepfunctions send-task-failure --task-token "$1"
echo "Stop Scripts:"`date '+%Y-%m-%d %H:%M:%S'` | tee -a /home/ssm-user/scripts/out.txt
exit 0
おわりに
今回はStep FunctionsからEC2上のコマンドを実行し、結果を待つStateMachineを作ってみました。
以前の記事と比べて、かなりシンプルになりました。その分EC2側で配慮が必要になります。
どちらを使うかは、その時々の状況に合わせて選べばよいかと思います。
この記事がどなたかのお役に立てれば幸いです。