1つのSSMドキュメントで複数OSのEC2インスタンスに対し、OSごとに異なるコマンドを実行する
はじめに
通常、異なるOSに対してAWS Systems Manager オートメーションでコマンドを実行する場合、OSごとに個別のSSMドキュメントを作成します。
しかし、1つのSSMドキュメントでOS別のコマンドを実行する方が、以下の利点があります。
- 一度の実行で完了
- EC2インスタンスを指定する場合、タグの管理が1つで済ませられる
本記事では、1つのSSMドキュメント(以降、オートメーションランブック)で、複数OSのEC2インスタンスに対してOS別のコマンドを実行する方法を紹介します。
オートメーションランブックを作成
各OSに対して実行するオートメーションランブックを作成します。
SSMドキュメントに遷移し、[ドキュメントの作成]から[オートメーション]を選択します。
以下のコードを貼り付けます。
schemaVersion: '0.3'
description: Check OS settings using SSM Automation with loop.
assumeRole: '{{ AutomationAssumeRole }}'
parameters:
AutomationAssumeRole:
type: String
description: (Optional) The ARN of the role that allows Automation to perform the actions on your behalf.
InstanceId:
type: StringList
description: The IDs of the EC2 instances to check.
CheckHostname:
type: String
default: check
description: Check hostname or skip.
allowedValues:
- check
- skip
mainSteps:
- name: ProcessInstances
action: aws:loop
isEnd: true
inputs:
Iterators: '{{ InstanceId }}'
Steps:
- name: GetInstancePlatform
action: aws:executeAwsApi
nextStep: CheckPlatform
isEnd: false
inputs:
Service: ec2
Api: DescribeInstances
InstanceIds:
- '{{ ProcessInstances.CurrentIteratorValue }}'
outputs:
- Name: Platform
Selector: $.Reservations[0].Instances[0].PlatformDetails
Type: String
- name: CheckPlatform
action: aws:branch
inputs:
Choices:
- NextStep: RunWindowsCommand
Variable: '{{ GetInstancePlatform.Platform }}'
Contains: Windows
- NextStep: RunLinuxCommand
Variable: '{{ GetInstancePlatform.Platform }}'
Contains: Linux
Default: ThrowError
- name: ThrowError
action: aws:executeScript
isEnd: true
inputs:
Runtime: python3.11
Handler: throw_error
Script: |
def throw_error(events, context):
raise Exception("Unsupported platform detected. Only Linux and Windows are supported.")
- name: RunLinuxCommand
action: aws:runCommand
maxAttempts: 1
timeoutSeconds: 10
isEnd: true
inputs:
DocumentName: AWS-RunShellScript
Parameters:
commands:
- if [[ "{{ CheckHostname }}" == "check" ]]; then hostname; else echo "Skipping hostname check"; fi
executionTimeout: '10'
InstanceIds:
- '{{ ProcessInstances.CurrentIteratorValue }}'
- name: RunWindowsCommand
action: aws:runCommand
maxAttempts: 1
timeoutSeconds: 180
isEnd: true
inputs:
DocumentName: AWS-RunPowerShellScript
Parameters:
commands:
- chcp 65001
- hostname
InstanceIds:
- '{{ ProcessInstances.CurrentIteratorValue }}'
各ステップの内容の概要を説明します。
aws:loop
aws:loopアクションは、指定されたEC2インスタンスの数だけ処理を繰り返します(for each処理)。
'{{ InstanceId }}'
ステップ名はProcessInstancesです。
aws:executeAwsApi
EC2のDescribeInstances
APIを使用して、インスタンスのOS情報を取得します。
platform-details
- The platform (Linux/UNIX | Red Hat BYOL Linux | Red Hat Enterprise Linux | Red Hat Enterprise Linux with HA | Red Hat Enterprise Linux with SQL Server Standard and HA | Red Hat Enterprise Linux with SQL Server Enterprise and HA | Red Hat Enterprise Linux with SQL Server Standard | Red Hat Enterprise Linux with SQL Server Web | Red Hat Enterprise Linux with SQL Server Enterprise | SQL Server Enterprise | SQL Server Standard | SQL Server Web | SUSE Linux | Ubuntu Pro | Windows | Windows BYOL | Windows with SQL Server Enterprise | Windows with SQL Server Standard | Windows with SQL Server Web
aws:loopアクションから以下の値が利用可能です。以下は、2つのEC2インスタンスを実行した場合の例です。
{"CurrentIteration":1,"CurrentIteratorValue":"i-aaaaaaaaa"}
このステップが終了後、loopしますので、次に、以下の値が取得できます。
{"CurrentIteration":1,"CurrentIteratorValue":"i-bbbbbbbbb"}
そのため、inputとしてEC2インスタンスIDを取得します。
- 名前:InstanceIds
- 入力値:
- '{{ ProcessInstances.CurrentIteratorValue }}'
EC2インスタンス情報の取得結果からOSのみを出力します。
- 名前:Platform
- セレクター:
$.Reservations[0].Instances[0].PlatformDetails
ステップ名はGetInstancePlatformです。
aws:branch
aws:branchアクションにより、OSタイプに応じて以下の3つに分岐します。
- Windows
- Linux
- その他
分岐条件は以下の通りです。
-
Windows判定(ルール #1)
- 条件:
{{ GetInstancePlatform.Platform }} contains "Windows"
- 結果:Windowsコマンド実行ステップへ移行
- 条件:
-
Linux判定(ルール #2)
- 条件:
{{ GetInstancePlatform.Platform }} contains "Linux"
- 結果:Linuxコマンド実行ステップへ移行
- 条件:
-
その他(デフォルト)
- 上記以外の場合
- 結果:エラー処理ステップへ移行
以降のステップ
WindowsやLinuxステップに遷移すると、それぞれaws:runCommandでコマンドを実行します。
コマンド内容は、hostnameの出力です。
Linux/Windows以外のOSの場合、以下の処理を実行します。
- aws:executeScriptアクションを使用してPythonスクリプトを実行
- Exceptionを発生させ、エラーメッセージを表示
def throw_error(events, context):
raise Exception("Unsupported platform detected. Only Linux and Windows are supported.")
実行してみる
EC2インスタンス2台を対象に、AWS CloudShellから以下の設定でSSMオートメーションを実行します。
なお、対象のEC2インスタンスには以下のタグを付与しています。
- キー名:ssm-automation
- 値:true
aws ssm start-automation-execution \
--document-name "check-linux-windows" \
--parameters "AutomationAssumeRole=arn:aws:iam::012345678901:role/AWS-SystemsManager-AutomationExecutionRole,\
CheckHostname=check" \
--target-parameter-name InstanceId \
--targets Key=tag:ssm-automation,Values=true
実行結果は以下の通りです。各EC2インスタンスの実行結果を個別に確認できます。
Windowsの実行結果です。
Linuxの実行結果です。
OSごとに異なるステップに分岐し、コマンド実行できていることが確認できました。
なお、Automationでは、条件分岐などの条件付きアクションにおいて実行条件を満たさないステップは、オートメーション完了後もPendingステータスのまま残ります。
そのため、使用されなかったステップは Pending ステータスとなります。
Pending
ステップの実行が開始されていません。オートメーションで条件付きアクションが使用されている場合、ステップを実行するための条件が満たされなかった場合、オートメーションが完了した後も、ステップはこの状態のままになります。ステップが実行される前にオートメーションがキャンセルされた場合も、ステップはこの状態のままになります。
https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/automation-statuses.html
参考