AWS CloudFormationスタックをCUI(Python Fabric)から操作するライブラリを作りました

AWS CloudFormation のスタックを、Python製のコマンドラインツール [Fabric](http://www.fabfile.org) を使ってCUIから作成／更新／削除／確認できるライブラリを作りました。

**[fabricawscfn](https://github.com/crossroad0201/fabric-aws-cloudformation)・・・Fabric task generator for AWS CloudFormation.**

AWSリソースの管理には CloudFormation を使う機会が多いですが、AWSコンソールからのGUI操作では手間も多く自動化も難しくなります。
AWS CLIなどのAPIを使うことで自動化できますが、いちいち定型的なスクリプトを書くのも面倒です。

fabricawscfn を使うと、Fabricスクリプト（`fabfile.py`）でスタックの名前やテンプレートファイルを指定するだけで、スタックを操作するための基本的なタスクが自動的に生成されます。

```python:fabfile.py
from fabricawscfn import *

StackGroup('my-cfn-templates', 'example', 'templates')\
  .define_stack('foo', 'example-foo', 'foo.yaml')\
  .define_stack('bar', 'example-bar', 'bar.yaml', Tags=[{'Key':'example', 'Value':'EXAMPLE'}])\
  .generate_task(globals())
```

これだけで、スタックの作成／更新／削除／一覧表示／詳細表示などのFabricタスクが自動的に生成されて利用可能になります。

各タスクの実行結果は、基本的にAWSコンソールのUIをそのままCUI化した感じになるようになっています。

```bash
$ fab -l
Available commands:

    create_bar         create stack bar.
    create_foo         create stack foo.
    delete_bar         delete stack bar.
    delete_foo         delete stack foo.
    desc_stack         Describe existing stack.
    list_exports       List exports.
    list_resources     List existing stack resources.
    list_stacks        List stacks.
    params             Set parameters. (Applies to all tasks)
    sync_templates     Synchronize templates local dir to S3 bucket.
    update_bar         update stack bar.
    update_foo         update stack foo.
    validate_template  Validate template on local dir.
```

## セットアップ

### 必要なソフトウェアのインストール

* Python 2.x と pip をインストールしておきます。
Python 3.x は動作確認していません。

* [AWS CLI](http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-set-up.html) をインストールします。

* Fabricをインストールします。
```
$ pip install fabric
```

### fabricawscfn のインストール

```bash
$ pip install git+https://github.com/crossroad0201/fabric-aws-cloudformation.git
```

## 使用例

Fabricスクリプト `fabfile.py` を作成し、前述の例のように `fabricawscfn` を使ってスタックを定義します。 

詳細は [GitHubのREADME](https://github.com/crossroad0201/fabric-aws-cloudformation) を参照してください。

### スタックの一覧を確認する

```bash
$ fab list_stacks
Stacks:
+------------+----------------------+-----------------+----------------------------------+-------------+-------------+
| StackAlias | StackName            |      Status     |           CreatedTime            | UpdatedTime | Description |
+------------+----------------------+-----------------+----------------------------------+-------------+-------------+
| foo        | fabricawscfn-dev-foo | CREATE_COMPLETE | 2017-03-05 04:35:12.823000+00:00 |      -      | Foo bucket. |
| bar        | fabricawscfn-dev-bar |   Not created   |                -                 |      -      | -           |
+------------+----------------------+-----------------+----------------------------------+-------------+-------------+
```

### スタックの詳細を確認する

```bash
$ fab desc_stack:foo
Stack:
+----------------------+-----------------+----------------------------------+-------------+-------------+
| StackName            |      Status     |           CreatedTime            | UpdatedTime | Description |
+----------------------+-----------------+----------------------------------+-------------+-------------+
| fabricawscfn-dev-foo | CREATE_COMPLETE | 2017-03-05 04:35:12.823000+00:00 |     None    | Foo bucket. |
+----------------------+-----------------+----------------------------------+-------------+-------------+
Parameters:
+---------+--------+
| Key     | Value  |
+---------+--------+
| Param4  | PARAM4 |
| Param3  | PARAM3 |
| Param2  | PARAM2 |
| Param1  | PARAM1 |
| EnvName | dev    |
+---------+--------+
Outputs:
+--------+-----------------+-------------+
| Key    | Value           | Description |
+--------+-----------------+-------------+
| Bucket | sandbox-dev-foo | Foo bucket. |
+--------+-----------------+-------------+
Events(last 20):
+----------------------------------+--------------------+----------------------------+----------------------+-----------------------------+
| Timestamp                        |       Status       | Type                       | LogicalID            | StatusReason                |
+----------------------------------+--------------------+----------------------------+----------------------+-----------------------------+
| 2017-03-05 04:35:55.694000+00:00 |  CREATE_COMPLETE   | AWS::CloudFormation::Stack | fabricawscfn-dev-foo | None                        |
| 2017-03-05 04:35:53.009000+00:00 |  CREATE_COMPLETE   | AWS::S3::Bucket            | Bucket               | None                        |
| 2017-03-05 04:35:32.308000+00:00 | CREATE_IN_PROGRESS | AWS::S3::Bucket            | Bucket               | Resource creation Initiated |
| 2017-03-05 04:35:31.102000+00:00 | CREATE_IN_PROGRESS | AWS::S3::Bucket            | Bucket               | None                        |
| 2017-03-05 04:35:12.823000+00:00 | CREATE_IN_PROGRESS | AWS::CloudFormation::Stack | fabricawscfn-dev-foo | User Initiated              |
+----------------------------------+--------------------+----------------------------+----------------------+-----------------------------+
```

### スタックを作成する

```bash
$ fab create_bar
Creating stack...
  Stack Name: fabricawscfn-dev-bar
  Template  : https://s3.amazonaws.com/crossroad0201-fabricawscfn/example/dev/subdir/bar.yaml
  Parameters: [{'ParameterValue': 'dev', 'ParameterKey': 'EnvName'}]
Waiting for complete...
Finish.
```

## おわりに

* ここのところ何かちょっとした自動化をするとなると、もっぱら Fabric を使うようになりました。今回もあれこれとトライアンドエラーを繰り返しながらでしたがだいぶ理解が深まりました。
* CUIで表を出力するPythonライブラリ [prettytablle](https://github.com/dprince/python-prettytable) がナイスです。
* 作ったPythonライブラリを、GitHubから pip で配布できるのが便利。

まだ荒削りで実際のプロダクト開発で使うと細かい改善点が出て来るはずなので、随時改善していきます。

## 参考にさせていただいたサイト

* [一歩すすんだ Fabric のタスク定義のしかた](https://nulab-inc.com/ja/blog/backlog/fabric-advanced/)
* [Python製デプロイツール Fabricを初めて使う際に役立つTip](http://dekokun.github.io/posts/2013-04-07.html)

* [GithubにPythonのライブラリをあげてpipでインストールする](http://blog.junion.org/pip-github-test/)
* [Pythonによる CLI ツールの実装と配布](http://developer.wonderpla.net/entry/blog/engineer/python_cli_tool_implementation_and_distribution/)

* [PythonのPrettyTableでプリティーなASCIIテーブルを作る](http://momijiame.tumblr.com/post/44704474054/python-の-prettytable-でプリティーな-ascii-テーブルを作る)

## 関連リンク

* [(2017年12月時点) 私的 CloudFormation ベストプラクティス](https://qiita.com/yasuhiroki/items/8463eed1c78123313a6f)
* [Scalaによるtype-safeなCloudFormation DSL](https://qiita.com/mshibuya/items/b8c5ace340e638af0f95)
* [AWS CloudFormationの実行をInvokeで管理する](https://tech-blog.monotaro.com/entry/2018/03/13/093000)