Terraform 1.3がGAになりました

2022.09.24

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

2022/09/22 にTerrafrom 1.3 がGA(generally available)になりました。新機能をチェックしていきましょう。

ObjectタイプのVariableに任意のattributesを設定可能に

Variableのtypeでobjectを指定した際の新機能です。

1.3以前でも、オブジェクトの必須attributeは設定することができました。

必須attributeの例

variables.tf

variable "hoge" {
  type = object({
    a = string
  })
}

terraform.tfvars

hoge = {
  b = "bbb"  
}

必須attributeのaが無いからエラー

% terraform plan
╷
│ Error: Invalid value for input variable
│ 
│   on terraform.tfvars line 1:
│    1: hoge = {
│    2:   b = "bbb"  
│    3: }
│ 
│ The given value is not suitable for var.hoge declared at varables.tf:1,1-16: attribute "a" is required.

必須attributeを追加します。

terraform.tfvars

hoge = {
  a = "aaa"	
  b = "bbb"  
}

デバッグ用に以下のoutputも定義しておきます。

output "hoge_result" {
  value = var.hoge
}

apply結果

% terraform apply 
(略)
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

hoge_result = {
  "a" = "aaa"
}

apply成功しました。かつ、variable定義で記載していなかった b attributeは削除されていますね。

任意のattribute例

1.3からoptional関数が追加されました。これが使用されたattributeは任意attributeになります。

variables.tf

  variable "hoge" {
    type = object({
      a = string
+     b = optional(string)
    })
  }

terraform.tfvars

hoge = {
  a = "aaa"	
}
% terraform apply
(略)
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

hoge_result = {
  "a" = "aaa"
  "b" = tostring(null)
}

optional attributeなbにはnullが入りましたね。

デフォルト値も設定できる

optional関数の第二引数にデフォルト値を設定できます。

variables.tf

  variable "hoge" {
    type = object({
      a = string
-     b = optional(string)
+     b = optional(string, "this is default value")
    })
  }
% terraform apply
(略)
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

hoge_result = {
  "a" = "aaa"
  "b" = "this is default value"
}

ユースケース

いろんなパターンに対応したいようなモジュールでは活躍しそうな気がしますね。Terraform RegistryやGitHubに公開されているようなモジュールがこれに当てはまることが多いと思います。最近私は aws-ia/terraform-aws-eks-blueprints: 内のサブモジュールを利用することが多いのですが、これがまさしくobject型で配下に大量のattributesを持つ形式のvariables()が多く、必要ないattributesもとりあえず定義して渡す必要がありました。このあたりoptional関数を駆使してvariablesを定義してもらえるとより使いやすいモジュールになりそうです。

movedブロックのtoで外部moduleを指定可能に

Version 1.1で導入された moved blockが改良されました。

これまでの movedブロックは fromがローカルで定義したリソース(=ローカルのsub module内やroot module直下のリソース)の場合、toに外部module(Terraform RegistryやGitHub上になどあるmodule)を指定できませんでした。

# resource "aws_vpc" "main" {
#   cidr_block = "10.0.0.0/16"
#   tags = {
#     Name = "my-vpc"
#   }
# }

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "3.14.4"

  name = "my-vpc"
  cidr = "10.0.0.0/16"
}

moved {
  from = aws_vpc.main
  to = module.vpc.aws_vpc.this[0]
}

Terraform 1.2.9での実行結果

% terraform apply
module.vpc.aws_vpc.this[0]: Refreshing state... [id=vpc-0810dce1ba1a574d9]
╷
│ Error: Cross-package move statement
│ 
│   on vpc.tf line 9:
│    9: moved {
│ 
│ This statement declares a move to an object declared in external module package "registry.terraform.io/terraform-aws-modules/vpc/aws". Move statements can be only within a single module package.
╵

これが1.3では実行可能になりました。

% terraform apply
module.vpc.aws_vpc.this[0]: Refreshing state... [id=vpc-07cc8f31365d58b4b]

Terraform will perform the following actions:

  # aws_vpc.main has moved to module.vpc.aws_vpc.this[0]
    resource "aws_vpc" "this" {
        id                               = "vpc-07cc8f31365d58b4b"
        tags                             = {
            "Name" = "my-vpc"
        }
        # (16 unchanged attributes hidden)
    }

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

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes


Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

地味なアップデートではありますが、できることが増えるのは嬉しいですね。

ちなみにこういうのは1.3以前からできます

逆 (external → ローカル)

# module "vpc" {
#   source  = "terraform-aws-modules/vpc/aws"
#   version = "3.14.4"

#   name = "my-vpc"
#   cidr = "10.0.0.0/16"
# }

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name = "my-vpc"
  }
}

moved {
  from = module.vpc.aws_vpc.this[0]
  to = aws_vpc.main
}

external → external

# module "vpc" {
module "vpc_rename" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "3.14.4"

  name = "my-vpc"
  cidr = "10.0.0.0/16"
}
moved {
  from = module.vpc
  to   = module.vpc_rename
}

startswith(), endswith()関数で文字列のprefix、suffixがチェック可能に

% terraform console
> startswith("classmethod", "class")
true
> startswith("classmethod", "glass")
false
> endswith("classmethod", "method")
true
> endswith("classmethod", "meth")
false

あまりユースケースを思いつけませんでしたが、セキュリティグループIDなどprefix(もしくはsuffix)が決まっているものをvariablesにする場合のvalidationに使うことができますね。

variable "sg_id" {
  type = string
  validation {
    condition     = startswith(var.sg_id, "sg-")
    error_message = "Security Group ID must starts with 'sg-' "
  }
}

一応1.3以前でも正規表現を使えば実装できますが、startswith(endswith)の方がわかりやすいですね。

variable "sg_id" {
  type = string
  validation {
    condition     = length(regexall("^sg-", var.sg_id)) > 0
    error_message = "Security Group ID must starts with 'sg-' "
  }
}

参考情報