【小ネタ】Terraformがv0.7.7でマップとリストの算術演算をサポートしました

2016.10.20

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

はじめに

こんにちは、中山です。

2016年10月18日、Terraformのv0.7.7がリリースされました。CHANGELOGはこちらです。さまざまなアップデートがあるのですが、個人的にはリストとマップの算術演算サポートに注目しています。このアップデートによってより表現力の高い簡潔な記述が可能になりました。

早速使ってみたのでレポートします。

使ってみた

サンプルとなるコードは以下のとおりです。分かりやすいように1つのファイルにまとめています。

variable "region" {
  default = "ap-northeast-1"
}

variable "env" {
  default = [
    "dev",
    "prd",
  ]
}

variable "vpc_cidrs" {
  default = {
    dev_1 = "172.16.0.0/16"
    dev_2 = "172.17.0.0/16"
    prd_1 = "172.18.0.0/16"
    prd_2 = "172.19.0.0/16"
  }
}

provider "aws" {
  region = "${var.region}"
}

resource "aws_vpc" "vpc" {
  count                = "${length(var.vpc_cidrs)}"
  cidr_block           = "${var.vpc_cidrs["${var.env[count.index / 2]}_${count.index % 2 + 1}"]}"
  enable_dns_support   = true
  enable_dns_hostnames = true
}

内容的にはVPCを4つ作成しているだけです。ハイライトしている箇所に注目していただきたいのですが、以下の内容を記述しています。

  • 5-10行: マップのキーをリストとして定義
  • 12-19行: dev_<num>prd_<num> というキーでVPC用CIDRをマップとして定義
  • 27行: 今回サポートした算術演算を利用してマップのバリューに変数を展開

今までは27行目のような算術演算が使えなかったので、(今回の例で言うと) aws_vpc リソースを複数定義したりする冗長な記述をする必要がありました。今回のアップデートによりマップとリストを組み合わせてより簡潔なコードの記述が可能になっています。

27行目の内容を解説すると以下の処理を行っています。

  • ${var.env[count.index / 2]} では count.index (0から3が入る)を2で割って商を求めています。0/0/1/1と算出されるので結果として devprd 毎に連続して展開されます。
  • ${count.index % 2 + 1} では count.index を2で割って余りを求めています。余りは0と1が交互に算出されるのでそれに1を足すと1/2/1/2となります。
  • 最終的に(例えば count.index に0が入っていると) "${var.vpc_cidrs["dev_1"]}" になるのでマップの一番初めのバリューである 172.16.0.0/16 へ展開されます。

実行してみる

まず最初に以前のバージョン(v0.7.6)で上記コードを実行してみます。恐らく以下のようにクラッシュしてしまうと思います。

$ terraform version
Terraform v0.7.6

Your version of Terraform is out of date! The latest version
is 0.7.7. You can update by downloading from www.terraform.io
$ terraform plan
panic: runtime error: index out of range
<snip>
!!!!!!!!!!!!!!!!!!!!!!!!!!! TERRAFORM CRASH !!!!!!!!!!!!!!!!!!!!!!!!!!!!

Terraform crashed! This is always indicative of a bug within Terraform.
A crash log has been placed at "crash.log" relative to your current
working directory. It would be immensely helpful if you could please
report the crash with Terraform[1] so that we can fix this.

When reporting bugs, please include your terraform version. That
information is available on the first line of crash.log. You can also
get it by running 'terraform --version' on the command line.

[1]: https://github.com/hashicorp/terraform/issues

!!!!!!!!!!!!!!!!!!!!!!!!!!! TERRAFORM CRASH !!!!!!!!!!!!!!!!!!!!!!!!!!!!

それでは続いてv0.7.7のTerraformで実行してみます。

$ terraform version
Terraform v0.7.7

$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but
will not be persisted to local or remote state storage.


The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed. Cyan entries are data sources to be read.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

+ aws_vpc.vpc.0
    cidr_block:                "172.16.0.0/16"
    default_network_acl_id:    "<computed>"
    default_route_table_id:    "<computed>"
    default_security_group_id: "<computed>"
    dhcp_options_id:           "<computed>"
    enable_classiclink:        "<computed>"
    enable_dns_hostnames:      "true"
    enable_dns_support:        "true"
    instance_tenancy:          "<computed>"
    main_route_table_id:       "<computed>"

+ aws_vpc.vpc.1
    cidr_block:                "172.17.0.0/16"
    default_network_acl_id:    "<computed>"
    default_route_table_id:    "<computed>"
    default_security_group_id: "<computed>"
    dhcp_options_id:           "<computed>"
    enable_classiclink:        "<computed>"
    enable_dns_hostnames:      "true"
    enable_dns_support:        "true"
    instance_tenancy:          "<computed>"
    main_route_table_id:       "<computed>"

+ aws_vpc.vpc.2
    cidr_block:                "172.18.0.0/16"
    default_network_acl_id:    "<computed>"
    default_route_table_id:    "<computed>"
    default_security_group_id: "<computed>"
    dhcp_options_id:           "<computed>"
    enable_classiclink:        "<computed>"
    enable_dns_hostnames:      "true"
    enable_dns_support:        "true"
    instance_tenancy:          "<computed>"
    main_route_table_id:       "<computed>"

+ aws_vpc.vpc.3
    cidr_block:                "172.19.0.0/16"
    default_network_acl_id:    "<computed>"
    default_route_table_id:    "<computed>"
    default_security_group_id: "<computed>"
    dhcp_options_id:           "<computed>"
    enable_classiclink:        "<computed>"
    enable_dns_hostnames:      "true"
    enable_dns_support:        "true"
    instance_tenancy:          "<computed>"
    main_route_table_id:       "<computed>"


Plan: 4 to add, 0 to change, 0 to destroy.

正常に実行できました。やりましたね。

まとめ

いかがだったでしょうか。

Terraformの表現力が増えていくのはユーザにとってとてもうれしいアップデートだと思います。このままどんどん進化してほしいと思います。個人的には変数内での変数展開をサポートして欲しいなと思っています。

本エントリがみなさんの参考になれば幸いです。