CLOVER🍀

That was when it all began.

Terraform 1.4で追加された、terraform_data resourceを試してみる

これは、なにをしたくて書いたもの?

Terraformには、nullというプロバイダーがあります。

null_resource

null Providerにはnull_resourceというリソースが含まれており、こちらを使うことで他のリソースの状態変化に合わせてコマンドを
実行させたりできていました。

Terraform 1.4で、null_resourceの代替となるterraform_dataというリソースができているようなので、少し試してみたいと思います。

terraform_dataリソース

Terraform 1.4のリリースブログは、こちら。

Terraform 1.4 improves the CLI experience for Terraform Cloud

この中に、terraform_dataリソースの内容が含まれています。以下の箇所ですね。

Native replacement for null_resource

nullプロバイダーは、Terraform Registryで3番目に多くダウンロードされているプロバイダーだそうです。

In fact it’s so widely used, it’s the 3rd most-downloaded provider in the Terraform Registry.

Terraform 1.4からは、null_resourceを置き換えるビルトインの代替としてterraform_dataリソースが追加されたそうです。
機能的には、null_resourceと同じ機能をサポートしているとか。

Terraform 1.4 introduces a new terraform_data resource as a built-in replacement for the null resource. This removes the need to include the null provider in your configuration and supports all the same capabilities as null_resource.

terraform_dataリソースのドキュメントは、こちらです。

The terraform_data Managed Resource Type | Terraform | HashiCorp Developer

簡単に試してみましょう。

環境

今回の環境は、こちら。

$ terraform version
Terraform v1.6.3
on linux_amd64

操作対象は、LocalStackとします。

$ python3 -V
Python 3.10.12


$ localstack --version
2.3.2

起動。

$ localstack start

CLIツールも用意。

$ awslocal --version
aws-cli/2.13.32 Python/3.11.6 Linux/5.15.0-88-generic exe/x86_64.ubuntu.22 prompt/off

terraform_dataリソースを試してみる

今回はAmazon SQSキューを作成し、その時にAmazon SQSのキューの一覧をAWS CLIで出力する、というお題にしましょう。

TerraformとAWS Providerのバージョン。

versions.tf

terraform {
  required_version = "1.6.3"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "5.24.0"
    }
  }
}

リソースの定義。

main.tf

provider "aws" {
  access_key                  = "mock_access_key"
  secret_key                  = "mock_secret_key"
  region                      = "us-east-1"
  s3_use_path_style           = true
  skip_credentials_validation = true
  skip_metadata_api_check     = true
  skip_requesting_account_id  = true

  endpoints {
    apigateway     = "http://localhost:4566"
    cloudformation = "http://localhost:4566"
    cloudwatch     = "http://localhost:4566"
    dynamodb       = "http://localhost:4566"
    es             = "http://localhost:4566"
    firehose       = "http://localhost:4566"
    iam            = "http://localhost:4566"
    kinesis        = "http://localhost:4566"
    lambda         = "http://localhost:4566"
    route53        = "http://localhost:4566"
    redshift       = "http://localhost:4566"
    s3             = "http://localhost:4566"
    secretsmanager = "http://localhost:4566"
    ses            = "http://localhost:4566"
    sns            = "http://localhost:4566"
    sqs            = "http://localhost:4566"
    ssm            = "http://localhost:4566"
    stepfunctions  = "http://localhost:4566"
    sts            = "http://localhost:4566"
  }
}

resource "aws_sqs_queue" "my_queue" {
  name = "my-queue"
}

resource "terraform_data" "trigger_describe_queue" {
  triggers_replace = [
    aws_sqs_queue.my_queue.id
  ]

  provisioner "local-exec" {
    command = "awslocal sqs list-queues"
  }
}

terraform_dataリソースを使っているのは、こちら。

resource "terraform_data" "trigger_describe_queue" {
  triggers_replace = [
    aws_sqs_queue.my_queue.id
  ]

  provisioner "local-exec" {
    command = "awslocal sqs list-queues"
  }
}

triggers_replaceというのは、このインスタンスのステートに保存され、これが参照している値が変更されると置き換えられます。
ここでprovisionerを組み合わせて、コマンドを実行したりします。

他にも、inputなどもあります。こちらは、triggers_replaceがリソースの参照や属性のみが指定可能なのに対して、リテラルを指定
できるもののようです。

ドキュメントやリリースブログでは、リビジョンをリテラルで定義してinputで参照し、terraform_dataリソース自身の状態が
変わることをトリガーになんらかの処理を起こさせるようにしています。

Terraform 1.4 improves the CLI experience for Terraform Cloud

The terraform_data Managed Resource Type | Terraform | HashiCorp Developer

今回は、Amazon SQSキューのidが変わる(=再作成されるなど)と、aws sqs list-queuesをLocalStackのAWS CLIで行うことにします。

では、確認してみましょう。

$ terraform init

まずはterraform plan。

$ terraform plan

Amazon SQSキューと、terraform_dataリソースが変更内容として現れます。

  # aws_sqs_queue.my_queue will be created
  + resource "aws_sqs_queue" "my_queue" {
      + arn                               = (known after apply)
      + content_based_deduplication       = false
      + deduplication_scope               = (known after apply)
      + delay_seconds                     = 0
      + fifo_queue                        = false
      + fifo_throughput_limit             = (known after apply)
      + id                                = (known after apply)
      + kms_data_key_reuse_period_seconds = (known after apply)
      + max_message_size                  = 262144
      + message_retention_seconds         = 345600
      + name                              = "my-queue"
      + name_prefix                       = (known after apply)
      + policy                            = (known after apply)
      + receive_wait_time_seconds         = 0
      + redrive_allow_policy              = (known after apply)
      + redrive_policy                    = (known after apply)
      + sqs_managed_sse_enabled           = (known after apply)
      + tags_all                          = (known after apply)
      + url                               = (known after apply)
      + visibility_timeout_seconds        = 30
    }

  # terraform_data.trigger_describe_queue will be created
  + resource "terraform_data" "trigger_describe_queue" {
      + id               = (known after apply)
      + triggers_replace = [
          + (known after apply),
        ]
    }

terraform applyします。

$ terraform apply

実行時のログ。awslocal sqs list-queuesが実行されていることが確認できます。

aws_sqs_queue.my_queue: Creating...
aws_sqs_queue.my_queue: Still creating... [10s elapsed]
aws_sqs_queue.my_queue: Still creating... [20s elapsed]
aws_sqs_queue.my_queue: Creation complete after 26s [id=http://localhost:4566/000000000000/my-queue]
terraform_data.trigger_describe_queue: Creating...
terraform_data.trigger_describe_queue: Provisioning with 'local-exec'...
terraform_data.trigger_describe_queue (local-exec): Executing: ["/bin/sh" "-c" "awslocal sqs list-queues"]
terraform_data.trigger_describe_queue (local-exec): {
terraform_data.trigger_describe_queue (local-exec):     "QueueUrls": [
terraform_data.trigger_describe_queue (local-exec):         "http://localhost:4566/000000000000/my-queue"
terraform_data.trigger_describe_queue (local-exec):     ]
terraform_data.trigger_describe_queue (local-exec): }
terraform_data.trigger_describe_queue: Creation complete after 3s [id=384ac258-f685-970f-b171-5db25d36bbfe]

この状態で、差分を確認。

$ terraform plan

特に変更はありません。

aws_sqs_queue.my_queue: Refreshing state... [id=http://localhost:4566/000000000000/my-queue]
terraform_data.trigger_describe_queue: Refreshing state... [id=384ac258-f685-970f-b171-5db25d36bbfe]

No changes. Your infrastructure matches the configuration.

では、今度はAmazon SQSのキューを、標準キューからFIFOキューに変更してみます。

resource "aws_sqs_queue" "my_queue" {
  name       = "my-queue.fifo"
  fifo_queue = true
}

resource "terraform_data" "trigger_describe_queue" {
  triggers_replace = [
    aws_sqs_queue.my_queue.id
  ]

  provisioner "local-exec" {
    command = "awslocal sqs list-queues"
  }
}

planで確認。

$ terraform plan

Amazon SQSキューは再作成になり、それに依存してterraform_dataリソース側も再作成扱いになります。

  # aws_sqs_queue.my_queue must be replaced
-/+ resource "aws_sqs_queue" "my_queue" {
      ~ arn                               = "arn:aws:sqs:us-east-1:000000000000:my-queue" -> (known after apply)
      + deduplication_scope               = (known after apply)
      ~ fifo_queue                        = false -> true # forces replacement
      + fifo_throughput_limit             = (known after apply)
      ~ id                                = "http://localhost:4566/000000000000/my-queue" -> (known after apply)
      ~ kms_data_key_reuse_period_seconds = 300 -> (known after apply)
      ~ name                              = "my-queue" -> "my-queue.fifo" # forces replacement
      + name_prefix                       = (known after apply)
      + policy                            = (known after apply)
      + redrive_allow_policy              = (known after apply)
      + redrive_policy                    = (known after apply)
      ~ sqs_managed_sse_enabled           = true -> (known after apply)
      - tags                              = {} -> null
      ~ tags_all                          = {} -> (known after apply)
      ~ url                               = "http://localhost:4566/000000000000/my-queue" -> (known after apply)
        # (6 unchanged attributes hidden)
    }

  # terraform_data.trigger_describe_queue must be replaced
-/+ resource "terraform_data" "trigger_describe_queue" {
      ~ id               = "384ac258-f685-970f-b171-5db25d36bbfe" -> (known after apply)
      ~ triggers_replace = [
          - "http://localhost:4566/000000000000/my-queue",
          + (known after apply),
        ]
    }

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

apply。

$ terraform apply

実行ログ。

terraform_data.trigger_describe_queue: Destroying... [id=384ac258-f685-970f-b171-5db25d36bbfe]
terraform_data.trigger_describe_queue: Destruction complete after 0s
aws_sqs_queue.my_queue: Destroying... [id=http://localhost:4566/000000000000/my-queue]
aws_sqs_queue.my_queue: Destruction complete after 2s
aws_sqs_queue.my_queue: Creating...
aws_sqs_queue.my_queue: Still creating... [10s elapsed]
aws_sqs_queue.my_queue: Still creating... [20s elapsed]
aws_sqs_queue.my_queue: Creation complete after 25s [id=http://localhost:4566/000000000000/my-queue.fifo]
terraform_data.trigger_describe_queue: Creating...
terraform_data.trigger_describe_queue: Provisioning with 'local-exec'...
terraform_data.trigger_describe_queue (local-exec): Executing: ["/bin/sh" "-c" "awslocal sqs list-queues"]
terraform_data.trigger_describe_queue (local-exec): {
terraform_data.trigger_describe_queue (local-exec):     "QueueUrls": [
terraform_data.trigger_describe_queue (local-exec):         "http://localhost:4566/000000000000/my-queue.fifo"
terraform_data.trigger_describe_queue (local-exec):     ]
terraform_data.trigger_describe_queue (local-exec): }
terraform_data.trigger_describe_queue: Creation complete after 3s [id=b560cb0e-2b42-fa13-02b2-67537a2a2cd4]

リソースが1度破棄されて再作成されるとともに、コマンド(awslocal sqs list-queues)が実行されていることが確認できました。

こんなところでしょうか。

おわりに

Terraform 1.4で追加された、terraform_dataリソースを試してみました。

個人的にはちょっと復習を兼ねたお題でもあったのですが、リリース内容を見ていないとふつうに置いていかれていることも
よくわかりました…。

Terraform自体は便利に使っているので、もうちょっと慣れておきたいですね。