AWS CDKでCloudFormationのJSONを取得するAPIをServerless Frameworkで作る

CloudFormationのテンプレートを作るAPIを、AWS CDKで実装してServerless Frameworkでデプロイしてみました。

ちょっと何言っているかわからない。

モチベーション

  • よく使うCloudFormationのテンプレートを一発で作りたかった
  • 可能なら、動的に値を変えれるといいよね
  • ボイラープレートを秘伝のタレ実装なしで作りたい

思考の流れ

  • AWS CDKがJavaScriptなのでなんとかなりそう
  • CLIのsynthコマンドをJSで動かせばいけるのでは
  • JSON取れたらあとはYAMLに変えるだけだから、とりあえずJSONとろう
  • 実験APIだからsls createでさっさと作ってためそう

できたもの

serverless.ymlはただGETのAPIはやしてるだけなので省略。CDKはcdk initせずにそのままnpm install -Sしました。

'use strict';
const cdk = require('@aws-cdk/cdk')
const sam = require('@aws-cdk/aws-sam')

class CdkTestStack extends cdk.Stack {
  constructor(scope, id, props) {
    super(scope, id, props);
    new sam.CfnFunction(
      this,
      'function',
      {
        handler: 'index.handler',
        runtime: 'nodejs8.10',
        codeUri: 'src'
      }
    )

  }
}

module.exports.hello = async (event) => {
  const app = new cdk.App();
  new CdkTestStack(app, 'CdkTestStack');
  const { template } = app.synthesizeStack('CdkTestStack')
  return {
    statusCode: 200,
    body: JSON.stringify(template),
  };
};

動かしてみる

$ curl  https://xxxxx.execute-api.us-east-1.amazonaws.com/dev/stack | jq .

{
  "Transform": "AWS::Serverless-2016-10-31",
  "Resources": {
    "function": {
      "Type": "AWS::Serverless::Function",
      "Properties": {
        "CodeUri": "src",
        "Handler": "index.handler",
        "Runtime": "nodejs8.10"
      }
    }
  }
}

CloudFormationのJSONがとれました。

YAMLがとれるようにもしてみる

js-yamlを使うことで、レスポンスをJSON / YAML切り替えれるようにできます。

'use strict';
const cdk = require('@aws-cdk/cdk')
const sam = require('@aws-cdk/aws-sam')
const yaml = require('js-yaml')

class CdkTestStack extends cdk.Stack {
  constructor(scope, id, props) {
    super(scope, id, props);
    new sam.CfnFunction(
      this,
      'function',
      {
        handler: 'index.handler',
        runtime: 'nodejs8.10',
        codeUri: 'src'
      }
    )

  }
}

const makeStack = (template, format = 'json') => {
  const type = format === 'yaml' ? 'yaml': 'json'
  if (type === 'json') return JSON.stringify(template)
  return yaml.safeDump(template)
}

module.exports.hello = async (event) => {
  const { queryStringParameters } = event
  const format = queryStringParameters.format || 'json'

  const app = new cdk.App();
  new CdkTestStack(app, 'CdkTestStack');
  const { template } = app.synthesizeStack('CdkTestStack')

  return {
    statusCode: 200,
    body: makeStack(template, format),
  };
};

こんな感じです。

$ curl  https://xxxxx.execute-api.us-east-1.amazonaws.com/dev/stack?format=yaml | jq .

Transform: 'AWS::Serverless-2016-10-31'
Resources:
  function:
    Type: 'AWS::Serverless::Function'
    Properties:
      CodeUri: src
      Handler: index.handler
      Runtime: nodejs8.10

使いどころとか

これだけなら「で?」で終わるのですが、引数を受け取るようにするといろいろ使い所は出てきそうです。

  • ボイラープレートCLI
  • 一部だけ設定を変えたスタックをダウンロードできるAPI
  • スタックをカスタマイズしてDLするAPI
  • 動的にカスタムしてスタック立ち上げまで実行できるようにする
  • etc…

オフィシャルのテンプレートビルダーで、Lambdaでもローカル環境でも動かせるのはかなりメリットかなと思いますので、いろいろ試してみようかなと思います。

Comment