Terraformの文法について?

最近Terraformを勉強してたんですが、日本語でTerraformの文法について説明しているものが見当たらなかったのではまった(?)ところまで書いてみました。

Terraformの文法?

正確にはHCL(HashiCorp Configuration Language)の文法です。 TerraformというツールにHCLという文法に従って書かれたファイルを食わせると、 その内容(意味)をツールが読み取って実行します。

設定ファイル

設定ファイルのトップレベルに書けるのは、コメントを除くと次の3つの要素です。

  • 属性
  • ブロック
  • 1行ブロック

設定ファイルにはこれらを複数(0個でもいい)並べられます。 例えば、ブロック、属性、属性、ブロック、1行ブロック・・・のような書き方が許されているということです。

これを公式ドキュメントでは

ConfigFile = Body;
Body       = (Attribute | Block | OneLineBlock)*;

と表しています。 正規表現とかBNFっぽいですね*1

ブロック

ブロックの定義はこのようになっています。

Block = Identifier (StringLit|Identifier)* "{" Newline Body "}" Newline;

さっきより複雑ですが、要は

terraform {
  required_version = "0.12.26"
}

とか

provider "aws" {
  region = "ap-northeast-1"
}

とか

resource "aws_instance" "hoge" {
  ...
}

とかしているのはすべてこの「ブロック」です。 terraform 構文や provider 構文や resource 構文などと個別に定義されてはいませんでした。 ということで、HCLは大体がブロックでできています。 ブロックの中身に Body が出てきますが、 Body は属性かブロックか1行ブロックのいずれかの複数の並びでした。 つまり、ブロックはネスト出来ます。

# 外側のブロック
resource "null_resource" "hoge" {
  # 内側のブロック
  provisioner "local-exec" {
    # これは属性(後述)
    command = "..."
  }
}

そして個人的に衝撃だったのは、例えば resource ブロック、こうも書けます。

resource aws_instance hoge {
  ...
}

今まで打ってきたダブルクォートを生まれる前に消し去りたい。

もう一度ブロックの定義を見てみましょう。

Block = Identifier (StringLit|Identifier)* "{" Newline Body "}" Newline;

(StringLit|Identifier)* となっている部分に注目してほしいのですが、 これは「(文字列リテラルか識別子)が0個以上並ぶ」ことを意味しています。

provider "aws" {
  region = "ap-northeast-1"
}

この "aws" が文字列リテラルで、

provider aws {
  region = "ap-northeast-1"
}

こっちの aws が識別子です(provider も識別子ですね)。 そしてこの部分を文字列リテラルで書いても識別子で書いても同じ意味です。 もっと早く公式の仕様を確認すべきでした。

他に面白い構文も特にないしやる気も尽きたので、ここまでにしておきます。 Terraform、ダブルクォートがだるいと思って避けている人もいるんじゃないかなと思うんですが、 別に書かなくていい場所になぜか書いている人が多いだけだよ、ということは広まってほしいですね。 公式のExample Usageがダブルクォート付きで書いているので、 お作法としては書くべきなのかもしれないですが面倒だし芋っぽいので自分は書かないことにします。

余談

Terraformは独自言語にもかかわらず、構文自体の説明は驚くほど少なくてびっくりします。 構文がシンプルなので説明不要でなんとなく使えるというのもあるんでしょうね。

CloudFormationはその点、文法はYAMLです、で説明がほぼ終わるのは利点ですよね。 関数とか独自機能もありますけど、YAML的にはvalidを保ったままの拡張なので、YAMLさえ知っていれば構文について覚えることは少なくて済みます*2

*1:ちなみにSyntax Notationを見ると + は定義されていないんですが、普通に使ってます。「へぇ、硬派(?)だ」とか思ったんですが・・・

*2:YAML自体の複雑さは見ないものとする