LoginSignup
3
2

More than 3 years have passed since last update.

AWS SAMのテンプレートではリソースごとに!Refと!GetAttの戻り値が違う

Posted at

はじめに

この記事では、AWS SAMテンプレートでAWS Lambda、AmazonAPI Gateway、AmazonSNSを使用したサーバレスアプリケーションを作ろうとしたときに躓いたポイントを紹介します。

AWS SAM テンプレートとは

AWS SAMのテンプレートはAWS CloudFormation テンプレートの拡張で基本的にはCloudFormationのテンプレートの書き方と同じですがSAM特有の便利なコンポーネントも追加されています。
もっと詳しく知りたい方はこちらを参考にしてみてください。
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-reference.html

CloudFormationの組み込み関数

CloudFormationにはスタックの管理に便利な組み込み関数があります。ここではそれらの関数のうち2つを紹介します。便利な使い方としては、実行するまでわからない値(SAMテンプレートで作成したLambda関数のAmazonリソースネーム (ARN)だったり、SNSのTopicNameだったり)を取得してプロパティに代入することができます。

Fn::GetAtt(!GetAtt)

まずFn::GetAtt(!GetAtt)について紹介します。短縮形の構文で!GetAttとかかれることが大きので以下!GetAttとして説明します。!GetAtt組み込み関数は戻り値としてテンプレートのリソースから属性の値(リソース名やARNなど)を返します。例えばテンプレートで以下のようにLambdaを定義したとしましょう。

template.yaml
Resources:
  SampleLambda:
    Type:AWS::Serverless::Function
    Properties:
      FunctionName: SampleFunction
      Runtime: python3.7
      CodeUri: test/
      Handler: app.lambda_handler

テンプレートにLambdaを定義しただけではLambda関数は作成されません。当然、buildとdeployをしなければなりません。buildとdeployを行うとLambda関数が作成されARNなどの値も生成されます。ということは、もしテンプレートを書いてリソースなどを定義している段階でLambdaのARNが必要になったとしてもdeployしてから手動でARNをコピーしてテンプレートに付け足してまたdeployしなければいけないの??とその時は悲しい気持ちでテンプレートを書いてました。そこで発見したのがこの!GetAttという組み込み関数です。以下の例を参考に使い方をみていきます。

template.yaml
Resources:
  SampleLambda:
    Type:AWS::Serverless::Function
    Properties:
      FunctionName: SampleFunction
      Runtime: python3.7
      CodeUri: test/
      Handler: app.lambda_handler
      Role: !GetAtt SampleIamRole.Arn

  SampleIamRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: 'Allow'
            Principal:
              Service: lambda.amazonaws.com
            Action: 'sts:AssumeRole'

SampleLambdaに対するSampleIamRoleというRoleを定義しました。このRoleをLambdaに紐付けるときに使用するのが!GettAtt関数です。

template.yaml
Role: !GettAtt SampleIamRole.Arn

これを付け足すと作成したRoleのARNを取得しLambdaに紐づけてくれます。すごく便利です。

Fn::Ref(!Ref)

次にFn::Ref(!Ref)について紹介します。短縮形の構文で!Refとかかれることが大きので以下!Refとして説明します。!Ref組み込み関数は戻り値として指定したパラメータまたはリソースの値を返します。先ほどと同じようにテンプレートで以下のようにLambdaを定義します。

template.yaml
Resources:
  SampleLambda:
    Type:AWS::Serverless::Function
    Properties:
      FunctionName: SampleFunction
      Runtime: python3.7
      CodeUri: test/
      Handler: app.lambda_handler
      Events:
        SNS:
          Type: SNS
          Properties:
            Topic: !Ref SampleTopic

  SampleTopic:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: SampleTopic

Lambdaのトリガー(イベント)としてSNSのトピックを定義しました。イベントとしてSNSのトピックを設定するときはトピックのARNが必要です。そこで先ほどの!GetAtt関数を使用してARNを取得しようとしてもうまくいきません。ここが今回紹介する躓きポイントです。ドキュメントをみてみるとこんなことが書かれています。

戻り値
参照番号
トピック ARN (例: arn:aws:sns:us-east-1:123456789012:mystack-mytopic-NZJ5JSMVGFIE) このリソースの論理 ID を組み込みの Ref 関数に渡すと、Ref は次を返します: 。
For more information about using the Ref function, see Ref.
Fn::GetAtt
Fn::GetAtt 組み込み関数は、このタイプの指定された属性の値を返します。以下には、利用可能な属性とサンプル戻り値のリストが示されます。
Fn::GetAtt 組み込み関数の使用方法の詳細については、「Fn::GetAtt」を参照してください。
TopicName
Amazon SNS トピックの名前を返します。

AWS::SNS::Topicタイプリソースに対して!GetAtt関数を使用すると戻り値として返ってくるのはARNではなくSNS トピックの名前です。!Refを使用すると戻り値としてSNSトピックののARNが返ってきます。
ARNを取得しようとして!GetAttや!Refを使用してもリソースによっては!Refで取得できたり、!GetAttで取得できる違いがあるようです。

まとめ

  • 取得したい値によって!GetAttや!Refを使い分けるだけではなく、同じような値(ARNやリソース名など)を取得するにしてもリソースによって使い分けなければいけない
  • とにかくドキュメントに全て書いてあるから読み込む

というのがすごく大事だなと痛感しました。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2