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-' "
}
}
参考情報
- Release v1.3.0 · hashicorp/terraform
- Terraform 1.3 Improves Extensibility and Maintainability of Terraform Modules
- Optional Object Type Attributes | Type Constraints - Configuration Language | Terraform | HashiCorp Developer
- startswith - Functions - Configuration Language | Terraform | HashiCorp Developer
- endswith - Functions - Configuration Language | Terraform | HashiCorp Developer