VPCをAnsibleで作成する


#はじめに
AnsibleにはAWSのリソースを操作できるモジュールが豊富に用意されています。

今回はVPCを操作するモジュールを利用して、AnsibleでVPCを作成します。

#やること
- VPC作成
- サブネット作成
- インターネットゲートウェイ作成
- ルートテーブル作成


##ポイント
- 作成したVPCのidを`ec2_vpc_net_facts`モジュールで取得し、後続のタスクで利用する

#前提
AWS関連のモジュール実行にはbotoが必要です。
credential情報は環境変数か`aws configure`でセットしてある必要があります。

#sample

以下のようなVPCを作成します。

- CIDR
	- 10.0.0.0/16
- サブネット
	- パブリック
		- 10.0.1.0/24(AZ-a)
		- 10.0.2.0/24(AZ-c)
	- プライベート
		- 10.0.11.0/24(AZ-a)
		- 10.0.12.0/24(AZ-c)


##ディレクトリ構成

```bash:ディレクトリ構成
site.yml
roles/
|--vpc/
|  |--tasks/
|  |  |--main.yml
hosts/aws    #inventory
host_vars/
|--localhost.yml
```

##inventory

AWSリソース関連モジュールはすべてlocalhostで実行するので、下記のようなインベントリファイルを用意します。

```bash:hosts/aws
[aws]
localhost
```

##vars

こんな感じに変数を定義します。今回はhost_varsで定義しました。

```yaml:host_vars/localhost.yml
---
my_vars:
  aws:
    common:
      region: ap-northeast-1
    vpc:
      name: AnsibleVPC
      cidr_block: 10.0.0.0/16
      tags:
        tag1: tag1
        tag2: tag2
      subnet:
        subnet1:
          tags:
            Name: public-a
          cidr: 10.0.1.0/24
          zone: a
        subnet2:
          tags:
            Name: public-c
          cidr: 10.0.2.0/24
          zone: c
        subnet3:
          tags:
            Name: private-a
          cidr: 10.0.11.0/24
          zone: a
        subnet4:
          tags:
            Name: private-c
          cidr: 10.0.12.0/24
          zone: c
      route_table:
        public:
          name: public
          subnets:
            - 10.0.1.0/24
            - 10.0.2.0/24
          routes:
            - dest: 0.0.0.0/0
              gateway_id: igw
```

##Role

まず、VPCを作成します。
作成後、`ec2_vpc_net_facts`でアサインされたVPCのidを保持しておきます。

後続タスクでは、そのidを用いて対象VPCを指定します。

ルートテーブル作成では、対象サブネットをリストで渡す必要があるのですが、with_dictを使ってループさせている関係でそのままではうまく渡せません。
そこで、jinja2のフィルタを使ってリストに整形しています。
要素が１つの場合と複数の場合で処理を分けています。

```yaml:roles/vpc/tasks/main.yml
---
- name: VPC作成
  ec2_vpc_net:
    name: "{{ my_vars.aws.vpc.name }}"
    cidr_block: "{{ my_vars.aws.vpc.cidr_block }}"
    region: "{{ my_vars.aws.common.region }}"
    tags: "{{ my_vars.aws.vpc.tags }}"
    tenancy: default
  register: vpc_net

- debug: var=vpc_net

- name: vpc_id取得
  ec2_vpc_net_facts:
    region: "{{ my_vars.aws.common.region }}"
    filters:
      "tag:Name": "{{ my_vars.aws.vpc.name }}"
  register: vpc_net_fact
  check_mode: no

- debug: var=vpc_net_fact

- name: Internet Gateway作成
  ec2_vpc_igw:
    region: "{{ my_vars.aws.common.region }}"
    vpc_id: "{{ vpc_net_fact.vpcs[0].id }}"
    state: present
  register: igw

- debug: var=igw

- name: subnet作成
  ec2_vpc_subnet:
    region: "{{ my_vars.aws.common.region }}"
    state: present
    vpc_id: "{{ vpc_net_fact.vpcs[0].id }}"
    az: "{{ my_vars.aws.common.region }}{{ item.value.zone }}"
    cidr: "{{ item.value.cidr }}"
    tags: "{{ item.value.tags }}"
  with_dict: "{{ my_vars.aws.vpc.subnet }}"
  register: vpc_subnet

- debug: var=vpc_subnet

- name: route table作成
  ec2_vpc_route_table:
    vpc_id: "{{ vpc_net_fact.vpcs[0].id }}"
    region: "{{ my_vars.aws.common.region }}"
    tags:
      Name: "{{ item.value.name }}"
    subnets: "{{ item.value.subnets }}"
    routes: >-
      {%- if item.value.routes|length == 1 -%}
        {{ item.value.routes }}
      {%- else -%}
        {{ item.value.routes | join(',') }}
      {%- endif -%}
  with_dict: "{{ my_vars.aws.vpc.route_table }}"
  register: route_table

- debug: var=route_table
```

##site.yml
```YAML:site.yml
---
- name: vpc
  hosts: localhost
  connection: local
  roles:
    - role: vpc
```

##実行
```bash:Command
$ ansible-playbook -i hosts/aws -l localhost site.yml
```

#まとめ
VPC関連モジュールではvpc_idが必須なのですが、CIDRブロックと名前でVPCを管理できるので便利かと思います。