[Boto3 Adv-Cal DAY11]CloudFormationでテンプレートをチェックしてスタックを生成してみた

boto3 で楽しむ AWS PythonLife 一人AdventCalendarです。11日目はCloudFormationにてテンプレートの精査とスタックの生成を実行してみました。
2018.12.11

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

boto3 で楽しむ AWS PythonLife 一人AdventCalendarです。

boto3のドキュメントを通して、サービス別にどういった事が出来るのかを理解したり、管理コンソールを通さずにTerminalだけで完結できるように検証していくことが目的になります。

11日目はCloudFormationで、S3のURLを元にTemplateの精査からスタックの生成までやってみました。

目次

boto3を通してCloudFormationで出来ること

ドキュメントは下記リンク先です。

ざっくりと以下のことができます。

  • スタックの操作(生成・削除・更新)
  • テンプレートの精査

Template指定時の判定順

TemplateBodyとTemplateURLのいずれかを指定する必要がありますが、両方の指定は不可能です。以下の順に判定が行われます。

  • TemplateBodyのチェック
  • TemplateURLのチェック
  • 両方エラーの場合は中断

TemplateURLの指定

S3上のファイルを指定しますが、スキーマはhttpsです。

s3://example/aws.json

の場合は

https://s3.amazonaws.com/example/aws.json

となります。

今回の操作

スタック名とテンプレートURLを指定して、スタックの作成を実行します。削除は行わないため、不要である場合は忘れずに削除してください。

% python main.py
Input Profile name [default]>>

Input stack name >> test

Input template url >> https://s3.amazonaws.com/example/aws.json

main.py

import boto3
from pprint import pprint

class CloudFormationWizard:
    _client_name = 'cloudformation'
    _session = None
    _template_file_url = None
    _stack_name = None
    
    def __init__(self, profile_name):
        self._session = boto3.Session(profile_name=profile_name)

    @property
    def session(self):
        return self._session

    def get_client(self, client_name=None):
        if not client_name:
            client_name = self._client_name
        return self.session.client(client_name)

    @property
    def client_name(self):
        return self._client_name

    @property
    def template_url(self):
        return self._template_file_url

    @property
    def stack_name(self):
        return self._stack_name

    def validate_template(self):
        params = {
            'TemplateURL': self.template_url
        }
        return self.get_client().validate_template(**params)

    def create_stack(self):
        params = {
            'StackName': self.stack_name,
            'TemplateURL': self.template_url
        }
        self.get_client().create_stack(**params)

    def prompt_base(self, message):
        value = None
        while True:
            value = input("\n{} >> ".format(message))
            if value and len(value) != 0:
                break
        return value

    def prompt_template_file_url(self):
        self._template_file_url = self.prompt_base('Input template url')

    def prompt_stack_name(self):
        self._stack_name = self.prompt_base('Input stack name')

    @staticmethod
    def prompt():
        default_profile_name = 'default'
        profile_name = input('Input Profile name [{}]>> '.format(default_profile_name))
        if len(profile_name) == 0:
            profile_name = default_profile_name
        wizard = CloudFormationWizard(profile_name)

        wizard.prompt_stack_name()
        wizard.prompt_template_file_url()
        wizard.validate_template()
        wizard.create_stack()

if __name__ == '__main__':
    CloudFormationWizard.prompt()

まとめ

create_stackまで実行させないことで、テンプレートの精査用コマンドにすることも可能です。

今回は求められるURLについて触れるため、必要なURLを直接渡す形にしてみました。bucketとファイル名からURLを生成する仕組みにすると入力の手間を減らせると思います。