LanguageExtensionsを利用したスタックを更新する時には「既存テンプレートを置き換える」を選択しよう

2024.02.21

こんにちは、AWS事業部の木村です。

以下の記事を参考にCloudWatchアラーム群を定期的にON, OFFする仕組みをCloudFormationを利用して作成しました。

停止期間を変更するためにパラメーターを調整してスタックの更新を行おうとしたのですが、変更が認識されずテンプレートの更新が行えないという事象に直面しました。

当初AWS::LanguageExtensionsを利用していることが理由とは気付けず、
TypeがAWS::Scheduler::Scheduleの時に発生する事象だと思っていました。

テンプレートを置き換えることで更新ができることはわかっていたのですが、自分では事象が発生している原因に辿りつくことができずAWSサポートの方に教えていただきましたので共有させていただきます。

いきなり結論

タイトルの通りですが、AWS::LanguageExtensionsを利用したスタックを更新する際には、テンプレートに変更がない場合でも「既存テンプレートを置き換える」を選択してスタックの更新が必要です。

AWS::LanguageExtensionsに関するドキュメントにも以下のように記載がありました。

If you update a stack using a different parameter value, don't use the --use-previous-template option where the original template contains the transform. Use the original template, before transformation, in the UpdateStack call. The stack will update with the new parameter values.

(簡単に意訳)

パラメーターを変更するためにスタック更新が必要な時は「現在のテンプレートの使用」を選択しないで「既存テンプレートを置き換える」を選択してください。

AWS::LanguageExtensions transform(AWS公式ドキュメント)

やってみた

というわけでここからは実際に試してみていきたいと思います。

テンプレートは先ほど紹介させていただいた記事の以下のものを利用してスタックを作成します。

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::LanguageExtensions
Parameters:
  Project:
    Type: String
  ScheduleExpressionOFF:
    Type: String
  ScheduleExpressionON:
    Type: String
  AlarmNames:
    Type: CommaDelimitedList

Resources:
  # EventBridge Scheduler (Disable CloudWatch Alarms)
  ScheduleCWAlarmOFF:
    Type: AWS::Scheduler::Schedule
    Properties:
      Name: !Sub "${Project}-cwalarm-off"
      Description: !Sub "Disable ${Project} CloudWatch Alarms"
      ScheduleExpression: !Ref ScheduleExpressionOFF
      ScheduleExpressionTimezone: "Japan"
      FlexibleTimeWindow:
        Mode: "OFF"
      State: ENABLED
      Target:
        Arn: arn:aws:scheduler:::aws-sdk:cloudwatch:disableAlarmActions
        Input:
          Fn::ToJsonString:
            AlarmNames: !Ref AlarmNames
        RoleArn: !GetAtt "SchedulerRole.Arn"

  # EventBridge Scheduler (Enable CloudWatch Alarms)
  ScheduleCWAlarmON:
    Type: AWS::Scheduler::Schedule
    Properties:
      Name: !Sub "${Project}-cwalarm-on"
      Description: !Sub "Enable ${Project} CloudWatch Alarms"
      ScheduleExpression: !Ref ScheduleExpressionON
      ScheduleExpressionTimezone: "Japan"
      FlexibleTimeWindow:
        Mode: "OFF"
      State: ENABLED
      Target:
        Arn: arn:aws:scheduler:::aws-sdk:cloudwatch:enableAlarmActions
        Input:
          Fn::ToJsonString:
            AlarmNames: !Ref AlarmNames
        RoleArn: !GetAtt "SchedulerRole.Arn"

  # Role for EventBridge Scheduler
  SchedulerRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "${Project}-scheduler-role-for-cwalarm"
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - scheduler.amazonaws.com
          Action:
          - sts:AssumeRole
      Path: "/"
      Policies:
        - PolicyName: CloudWatchAlarmONOFF
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - cloudwatch:DisableAlarmActions
                  - cloudwatch:EnableAlarmActions
                Resource:
                  - "*"

「現在のテンプレートの使用」を選択してスタックの更新を試みる

まずAWS公式ドキュメントにて使用しないでくださいと言及されていた「既存のテンプレートの使用」を利用して更新を行ってみます。

まずテンプレートの準備の画面で「現在のテンプレートの使用」を選択します。

次にリソースに変更が行われるようにScheduleExpressionOFFの値を
cron(30 01 * * ? *)からcron(30 02 * * ? *)に変更します。

  • 変更前

  • 変更後

この内容でスタックの更新を進めていきます。AWS::LanguageExtensionsを利用していないテンプレートであれば、リソースの内容に変更があるのでスタックの更新が行える想定です。

パラメーターが変更されていることも確認画面では認識されているようでした。

しかし変更セットのプレビューを見てみると、以下の様に「この変更セットの作成中にエラーが発生しました」という様に表示されてしまいます。

変更セットを作成してみると同様にエラーが発生しており更新を行うことができません。

理由の箇所を見てみると、「The submitted information didn't contain changes. Submit different information to create a change set.」と表示されておりリソースの変更が認識されていない様でした。

変更セットの作成を行わず、スタックの更新の内容を送信してみても「No updates are to be performed.」と表示され更新を行うことができませんでした。

「現在のテンプレートの使用」を選択すると、リソースに変更が発生するパラメーターの入力を行ってもCloudFormationにて変更内容を捕捉できないため更新が行えないようです。

「既存テンプレートを置き換える」を選択してスタックの更新を試みる

続いてAWS公式ドキュメントにて選択してくださいと指定されていた「既存テンプレートを置き換える」を指定して更新を行ってみます。

まずテンプレートの準備の画面で「既存テンプレートを置き換える」を選択し、スタック作成の際に指定したS3のURLを指定します。(テンプレートの内容の更新は一切行っておりません)

次に先ほどと同様にリソースに変更が行われるようにScheduleExpressionOFFの値を
cron(30 01 * * ? *)からcron(30 02 * * ? *)に変更します。

  • 変更前

  • 変更後

この内容でスタックの更新を進めていきます。「既存テンプレートを置き換える」以外は全く同じ内容を選択しております。

変更セットのプレビューを確認すると、今度は変更が認識されていそうです。

変更セット作成してみても問題なく更新が行えそうでした。

スタックの更新を行ってみたところ無事更新を行うことができました。

念の為スタックで作成しているEventBridge Schedulerを確認しましたがこちらも更新が反映されておりました!

  • 更新前

  • 更新後

テンプレートに変更がない場合でも「既存テンプレートを置き換える」を選択すれば更新ができることが確認できました。

まとめ

更新できない事象に遭遇した際にはもしかしてバグ?と思っておりましたが、想定の仕様通りだったということがわかりました。

同じような事象に直面した形の疑問を解決する際の一助になれれば幸いです。

以上AWS事業部の木村でした。