[アップデート] AWS Systems Manager Automationでループ実行などの機能が増えました

2023.11.21

しばたです。

先日よりAWS Systems Manager Automation (SSM Automation)のランブックにおいてループ実行など幾つかの機能が増えました。  

AWSからのアナウンスはこちらになります。

更新点について

AWSのアナウンスが結構ふわっとした内容だったため実際の更新点を把握するまでにかなりの時間を要しました...
具体的な更新内容はSSM全体のドキュメント履歴に記載されており、

  • aws:loopアクションの追加
  • aws:updateVariableアクションの追加
  • アウトプットデータのキャストサポート
  • JSONPathでフィルター式(([?(expression)]))のサポート

の4機能となります。

1. aws:loopアクションの追加

aws:loopアクションは名前の通りループ処理を表現するアクションです。
条件を満たすあいだ処理を繰り返すdo while形式とコレクションの要素を繰り返すfor each形式の2種類記述することができます。

以下にAWSのドキュメントにある例を転記します。

do while形式

Stepsに繰り返す処理を記述します。
LoopConditionに継続条件を記述し、記載の例だとLambda関数の実行結果ShouldRetryの値がtrueの場合ループを繰り返す事になります。
そして、ループの最大回数をMaxIterationsで指定することもできます。

do whileループ例

name: RepeatMyLambdaFunctionUntilOutputIsReturned
action: aws:loop
inputs:
  Steps:
    - name: invokeMyLambda
      action: aws:invokeLambdaFunction
      inputs:
        FunctionName: LambdaFunctionName
      outputs:
        - Name: ShouldRetry
          Selector: $.Retry
          Type: Boolean
  LoopCondition:
  Variable: "{{ invokeMyLambda.ShouldRetry }}"
  BooleanEquals: true
  MaxIterations: 3

for each形式

Stepsに繰り返す処理を記述します。
Iteratorsに処理を繰り返す元になるコレクションを、コレクション要素の型をIteratorDataTypeに記述します。

現在の要素は{{ステップ名.CurrentIteratorValue}}で取得可能でコレクションの全要素を繰り返せば処理は終了します。

for eachループ例

name: stopAllInstancesWithWaitTime
action: aws:loop
inputs:
  Iterators: "{{ DescribeInstancesStep.InstanceIds }}"
  IteratorDataType: "String"
  Steps:
    - name: stopOneInstance
      action: aws:changeInstanceState
      inputs:
        InstanceIds:
          - "{{stopAllInstancesWithWaitTime.CurrentIteratorValue}}"
        CheckStateOnly: false
        DesiredState: stopped
    - name: wait10Seconds
      action: aws:sleep
      inputs:
        Duration: PT10S

動作確認

今回は手っ取り早く動作確認できるfor each形式のほうを試してみます。

私の検証用AWSアカウントの東京リージョンに以下の内容で新規にランブックを作成します。

※注意※
このランブックは「全てのEC2インスタンスをリストアップし、順に停止させる」内容となっていますので実際の環境で試す場合はご注意ください。

Loop-Sample-Runnbookランブック

description: "Loop action sample"
schemaVersion: '0.3'
mainSteps:
- name: describeInstancesStep
  action: aws:executeAwsApi
  onFailure: Abort
  inputs:
    Service: ec2
    Api: DescribeInstances
  outputs:
    - Name: instanceIds
      Selector: "$.Reservations..Instances..InstanceId"
      Type: StringList
- name: stopAllInstancesWithWaitTime
  action: aws:loop
  inputs:
    Iterators: "{{ describeInstancesStep.instanceIds }}"
    IteratorDataType: "String"
    Steps:
    - name: stopOneInstance
      action: aws:changeInstanceState
      inputs:
        InstanceIds:
          - "{{stopAllInstancesWithWaitTime.CurrentIteratorValue}}"
        CheckStateOnly: false
        DesiredState: stopped
    - name: wait10Seconds
      action: aws:sleep
      inputs:
        Duration: PT10S

最初のdescribeInstancesStepステップで取得したEC2インスタンスIDのリスト{{ describeInstancesStep.instanceIds }}を元データとして、stopAllInstancesWithWaitTimeステップで各要素(各インスタンスID)のインスタンスを停止する内容となっています。

細かい作業手順は端折りますがランブックの作成結果はこんな感じです。

なお、現時点ではaws:loopアクションはビルダーでサポートされて無いためエディタで直接YAMLを書く必要があります。

(現時点ではビルダーのアクションにaws:loopは存在せず)

このランブックを実行すると、以下の様にaws:loopアクションの親ステップとそれに続く各子ステップが順に実行されていきます。

最終的にすべてのステップが完了して処理が終了します。

2. aws:updateVariableアクションの追加

aws:updateVariableアクションは指定したドキュメント変数(variables)の内容を更新するシンプルなものになります。
あくまで内容の更新であり型変換はできませんのでご注意ください。

AWSのドキュメントにある例を転記すると以下の様な使い方をします。割と見たままかと思います。

updateVariable例

name: updateStringList
action: aws:updateVariable
inputs:
  Name: variable:variable name
  Value:
    - "1"
    - "2"

動作確認

こちらも簡単なランブックを用意して動作確認します。
StringListpayload変数を更新して終わりという非常にシンプルなものです。

Update-Value-Sampleランブック

description: "Update value sample"
schemaVersion: '0.3'
variables:
  payload:
    type: StringList
    default: []
mainSteps:
- name: updateStringList
  action: aws:updateVariable
  inputs:
    Name: variable:payload
    Value:
      - "1"
      - "2"

当然ですが実行自体はあっさり成功します。
Variablesが期待した値に更新されていることが分かりますね。

3. アウトプットデータのキャストサポート

従来outputsの利用においてTypeで定義したデータ型とステップを実行して引き渡される実データの型は厳密に一致している必要がありました。
今回の更新により一定のルールに基づいてTypeで定義したデータ型へのキャストを試みる様になったとのことです。

ドキュメントによれば以下のキャストが可能とのことです。

実データの型 変換可能なデータ型
String StringList, Integer, Boolean
Integer String, StringList
Boolean String, StringList
要素が1つだけのStringList String
要素が1つだけのIntegerList Integer
要素が1つだけのBooleanList Boolean

あくまでキャストだけであり動的な型変換をするわけでは無いのでご注意ください。

4.JSONPathでフィルター式のサポート

従来ランブックではJSONPathの一部機能をサポートしていました。

今回の更新によりフィルター式(([?(<expression>)]))を追加でサポートしたとのことです。

上記ドキュメントにある例を出すと、例えばEC2のDescribeInstancesAPIを実行した結果に対して

$.Reservations..Instances[?(@.State.Name == "running")]

といった記述をすることで起動中のインスタンスのみを抽出対象にすることができる様になりました。

動作確認

簡単なランブックを用意して動作確認します。
動作中(running)のEC2インスタンスIDを列挙するだけのものになります。

JSONPath-Filter-Sampleランブック

description: "JSONPath filter sample"
schemaVersion: '0.3'
mainSteps:
- name: describeInstancesStep
  action: aws:executeAwsApi
  onFailure: Abort
  inputs:
    Service: ec2
    Api: DescribeInstances
  outputs:
    - Name: instanceIds
      Selector: "$.Reservations..Instances[?(@.State.Name == 'running')].InstanceId"
      Type: StringList

予め1台だけEC2インスタンスを起動しておき実行した結果はこんな感じです。

これだけだと分かりにくいでしょうが、実際に意図した通りフィルターされています。

余談 : aws:createOpsTaskアクションについて

今回の検証をしている際に気が付いたのですが、ランブックのビルダーでドキュメントに記載の無いaws:createOpsTaskアクションの存在を確認しました。

ただ、現状このアクションを選択してもUIに変化が無く実用するのは難しそうです。
名前からしてAWS Systems Manager OpsCenterのOpsItemsを追加するものっぽいですが確証は無いので今後の情報に期待しましょう。

最後に

以上となります。

SSM Automationランブックの記述がより柔軟にできる更新です。
機会があれば活用してみてください。