13
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

AWS CloudFormation のマクロ機能を使ってみた

Posted at

概要

AWS CloudFormation Macros について
ということで、先日発表されました AWS CloudFormation のマクロを早速試してみました。

マクロとは?

AWS CloudFormation Macros は、CloudFormation テンプレートで、検索や置換などの単純な操作からテンプレート全体の変換までカスタム処理を実行できます。

以前は、AWS::Include 変換および AWS::Serverless 変換を使用して、CloudFormation によってホストされたテンプレートを処理できました。今は、CloudFormation Macros を使用して独自のカスタム変換を作成できるようになりました。

つまり、CloudFormation のテンプレートの実行時に、独自の処理を行うことができるもののようです。
実際にどのようなことができるのかというと、下記のような例がありました。

  • テンプレート内に python コードを記述
  • リソース定義表現を短くする
  • カスタム CloudWatch metrics の出力
  • 文字列を関数としてテンプレート内で使う

(aws-cloudformation-templates/aws/services/CloudFormation/MacrosExamples at master · awslabs/aws-cloudformation-templates · GitHub より)

なにやらいろいろできそうな気がします。
自分は、1回の記述で同じリソースを複数個作るマクロを作ってみました。

マクロを作る

マクロを知る

まずはどのようにマクロが動くかを調べます。
AWS CloudFormation を AWS Lambda によるマクロで拡張するUsing AWS CloudFormation Macros to Perform Custom Processing on Templates によると、

  1. マクロの実態は Lambda 関数
  2. その関数の ARN を AWS::CloudFormation::Macro リソースに指定することでスタックが作られる際に関数が実行される

とのことです。
この時、Lambda 関数が受け取るペイロードは以下のようです。

{
    "region" : "us-east-1", 
    "accountId" : "$ACCOUNT_ID", 
    "fragment" : { ... }, 
    "transformId" : "$TRANSFORM_ID", 
    "params" : { ... }, 
    "requestId" : "$REQUEST_ID",
    "templateParameterValues" : { ... } 
}

この中で一番大事なパラメータが fragment で、この中に処理するテンプレートの内容が含まれます。

Lambda 関数のレスポンスはというと、

{
    "requestId" : "$REQUEST_ID", 
    "status" : "$STATUS", 
    "fragment" : { ... } 
}

こちらの fragment が JSON形式の CloudFormation テンプレートとして適用されるようです。

マクロとなる Lambda 関数の作成

まずはマクロの本体となる Lambda 関数を作ります。
今回は、

AWSTemplateFormatVersion: "2010-09-09"

Resources:
  Resource:
    Type: AWS::SNS::Topic
    Properties:
      DisplayName: test topic
      TopicName: TestTopic

↑こんな感じのテンプレートの1回の実行で、指定した回数分の SNS トピックが作成できる
という感じのマクロを作ります。

テンプレート&使いかたをはじめに出しておくと、

template.yml
AWSTemplateFormatVersion: "2010-09-09"
Transform: [MultiplexResourceMacro]

Parameters:
  NumberOfRepeats:
    Type: Number
    Default: 1

Resources:
  Resource:
    Type: AWS::SNS::Topic
    Properties:
      DisplayName: test topic
      TopicName: TestTopic

このようなテンプレートを実行すると、NumberOfRepeats に指定した個数の SNS トピックが作成できる、といったものです。

Lambda 関数でやることは、Resources 以下をとってきて指定された回数ループし、新しく Resouses
として返すといった内容になります。

実際の処理は以下のような感じです。(Lambda のランタイムは node.js 8.10)

index.js
'use strict'

const getPropertyGenerator = (type) => {
  switch (type) {
    case 'AWS::SNS::Topic':
      return createSNSTopic
  }
}

const createSNSTopic = (properties, count) => {
  return {
    DisplayName: properties.DisplayName,
    TopicName: `${properties.TopicName}-${count}`
  }
}

exports.handler = async (event, context, callback) => {
  const numberOfRepeats = event.templateParameterValues.NumberOfRepeats
  const resources = event.fragment.Resources

  const keys = Object.keys(resources)
  if (keys.length > 1) {
    throw Error('Number of resources shouud be 1')
  }

  const resource = resources[keys[0]]

  const resourceType = resource.Type
  const properties = resource.Properties

  for (let i = 0; i < numberOfRepeats; i++) {
    const ret = {
      Type: resourceType,
      Properties: getPropertyGenerator(resourceType)(properties, i)
    }
    resources[`${keys[0]}${i}`] = ret
  }

  delete resources[keys[0]]
  return {
    'requestId': event['requestId'],
    'status': 'success',
    'fragment': event['fragment']
  }
}

これをデプロイします。
デプロイに以下の Template を使います。
ここでは、AWS::Serverless::Function タイプのリソースを MultiplexResourceMacro という名前で作り、Function の ARN を登録しています。

template.yml
Transform: AWS::Serverless-2016-10-31
Description: Macro for cloudformation

Resources:
  Function:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: ./index.js
      Handler: index.handler
      Runtime: nodejs8.10

  Macro:
    Type: AWS::CloudFormation::Macro
    Properties:
      Name: MultiplexResourceMacro
      FunctionName: !GetAtt Function.Arn

これを、↓こんな感じでデプロイします。

aws cloudformation package --template-file macro.yaml --output-template-file cfn-transformed-template.yaml --s3-bucket <S3_BUCKET_NAME>

aws cloudformation deploy --template-file ./cfn-transformed-template.yaml --capabilities CAPABILITY_IAM --stack-name <STACK_NAME>

マクロを使ってみる

といった感じで作ったマクロを使ってみます。
上に書いている SNS 作成テンプレートを指定し以下のコマンドで実行します。

aws cloudformation deploy --template-file template.yml --stack-name TestSNS --parameter-overrides NumberOfRepeats=5

すると、

20180908-224637.png

↑こんな感じで5個のトピックが無事作成できました。

感想

今回作ったマクロはコード見ても分かる通り全く汎用性がないので、改善の余地大ありです。
ただマクロ機能自体は便利なので、うまく使えればかなり色んなことができそうだなと思いました。
パッと思いついたものだと、テンプレート構文的には正しくても運用ポリシー上イケてないテンプレートを弾く、みたいな使い方だと簡単にできそうかなーと感じました。

ちなみに今回作ったマクロ/使ったテンプレートは以下のリポジトリにありますので、よかったら使ってみてください。

13
7
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
13
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?