ããã¯ããªã«ãããããŠæžãããã®ïŒ
Terraform 1.6ã§ãTerraformã®testing frameworkïŒterraform testã³ãã³ãïŒãè¿œå ããããããªã®ã§ãè©ŠããŠã¿ããããªãšã
Terraform 1.6 adds a test framework for enhanced code validation
ä»ãŸã§Terraformã®ãã¹ããšããã°lintãšTerratestã ã£ããšæããŸãããéžæè¢ãåºããããã§ããã
- GitHub - terraform-linters/tflint: A Pluggable Terraform Linter
- Terratest | Automated tests for your infrastructure code.
Terraform testing framework
Terraform 1.6ã«é¢ãããªãªãŒã¹ããã°ã¯ãã¡ãã
Terraform 1.6 adds a test framework for enhanced code validation
ãã®äžã«ãTerraform test frameworkãšããèŠåºãããããŸãã
ããã¯ãéå»ã«æäŸããŠããå®éšçæ©èœã眮ãæãããã¹ããã¬ãŒã ã¯ãŒã¯ãå°å
¥ãããã®ã®ããã§ãã
å®éšçæ©èœãšããã®ã¯ã0.15ã§è¿œå ãããterraform test
ã®ããšã®ããã§ãã
Module Testing Experiment - Configuration Language | Terraform | HashiCorp Developer
ãŸããTerraformã«ã¯ä»¥åãã以äžã®ãããªæ©èœããããŸããã
- Custom Conditions / Input Variable Validation
- Custom Conditions / Preconditions and Postconditions
- Custom Conditions / Checks with Assertions
ãšã¯ããããããã§ã¯ãã¹ãã®ããŒãºãæºããããšãã§ããŸãããããã§ç»å Žããã®ãTerraform test frameworkã§ãããšã
Terraform testing frameworkã¯ããã£ãã以äžã®æãã®ãã®ã®ããã§ãã
terraform test
ã§å®è¡ãã- ãã¹ããã¡ã€ã«ã¯ããã¡ã€ã«åã®æ«å°Ÿã
.tftest.hcl
ãšãªã run
ãããã¯ã§å®çŸ©ããããã¹ãã«åºã¥ããŠãæ§æãããããžã§ãã³ã°ãã- ã«ã¹ã¿ã ã¢ãµãŒã·ã§ã³ãè©äŸ¡
- ãã¹ãçµäºæã«ã¯ãããããžã§ãã³ã°ãããªãœãŒã¹ãç Žæ£
ã€ãŸããå®éã«ãªãœãŒã¹ãäœæããŠãæ€èšŒããŠç Žæ£ãããšããæµãã«ãªããŸãã
Terraform testing frameworkã«é¢ããããã¥ã¡ã³ãã¯ããã®ãããã§ããã
- CLIã«ã€ããŠ
- ãã¹ããã¡ã€ã«ã®æ§æ解説
- ãã¥ãŒããªã¢ã«
ãŸããCLIã«ã€ããŠè¿œã£ãŠã¿ãŸããããæŠèŠããã
Testing Terraform - Terraform CLI | Terraform | HashiCorp Developer
testing frameworkã¯ãåäœãã¹ãããã³ã€ã³ãã°ã¬ãŒã·ã§ã³ãã¹ããã¿ãŒã²ããã«ããŠããŸãã
terraform test
ã³ãã³ãã§å®è¡ããæ§æãã£ã¬ã¯ããªå
ã§ãã¹ããã¡ã€ã«ãèŠã€ããŠãã¹ããè¡ããŸãïŒãã£ããããšæžããå
容ãšåãïŒã
ãã¹ããã¡ã€ã«ã¯ãç¬èªã®æ§æã§æžãããšã«ãªããŸãã
Tests - Configuration Language | Terraform | HashiCorp Developer
ã³ãã³ãèªäœã®èª¬æãèŠãŠã¿ãŸãã
Command: test | Terraform | HashiCorp Developer
terraform test
ã¯ã以äžã®åäœãè¡ãããã§ãã
- çŸåšã®ãã£ã¬ã¯ããªãšæå®ããããã¹ããã£ã¬ã¯ããªïŒããã©ã«ãã§
tests
ïŒã§ãã¹ããã¡ã€ã«ãæ€çŽ¢ãããã¹ããå®è¡ãã - ãã¹ããã¡ã€ã«ã®ä»æ§ã«åŸã£ãŠã
terraform plan
ããã³terraform apply
ãè¡ã - ãã¹ããã¡ã€ã«ã®ä»æ§ã«åŸã£ãŠããã©ã³ãã¡ã€ã«ãšã¹ããŒããã¡ã€ã«ã®æ€èšŒãè¡ã
- ã¹ããŒãã¯ã¡ã¢ãªãŒäžã§ä¿æãã空ããéå§ããŠæ¢åã®ã¹ããŒãã«åœ±é¿ãäžããªã
- ãã¹ãçšã®ã€ã³ãã©ãªãœãŒã¹ãäœæãããã¹ãã®çµäºæã«ç Žæ£ãããç Žæ£ã§ããªãã£ãå Žåã¯ã察象ã®ãªãœãŒã¹ã®ãªã¹ããã¬ããŒããã
䜿ããããªãªãã·ã§ã³ãšããŠã¯ããã¹ããã¡ã€ã«ãéå®ãã-filter
ããã¹ããã£ã¬ã¯ããªãæå®ãã-test-directory
ïŒããã©ã«ãã§ã¯tests
ïŒã
ãã¹ããã¡ã€ã«å
ã®run
ã«åºã¥ããŠåãããã¯ã®ãã©ã³ããã³ã¹ããŒããåºåãã-verbose
ãããã§ããããã
ããšã¯ããã¥ãŒããªã¢ã«ãèŠãŠã¿ãŸãããã
Write Terraform Tests | Terraform | HashiCorp Developer
ãã¥ãŒããªã¢ã«ãèŠãŠãããšããã¹ãå
ã§ãã¹ãã®ãã«ããŒã¢ãžã¥ãŒã«ïŒéåžžã®.tf
ãã¡ã€ã«ïŒãäœæããããšãããããã§ããã
ããã¥ã¡ã³ããçºããã®ã¯ãããããã«ããŠãå®éã«äœ¿ã£ãŠãã£ãŠã¿ãŸãããã
ç°å¢
ä»åã®ç°å¢ã¯ããã¡ãã
$ terraform version Terraform v1.6.0 on linux_amd64
ãã¹ã察象ã®ãªãœãŒã¹äœæã«ã¯ãLocalStackã䜿ãããšã«ããŸãã
$ python3 -V Python 3.10.12 $ localstack --version 2.3.2
èµ·åã
$ localstack start
AWS CLIïŒLocalStackïŒã䜿ããŸãããã
$ awslocal --version aws-cli/2.13.25 Python/3.11.5 Linux/5.15.0-86-generic exe/x86_64.ubuntu.22 prompt/off
ãã¹ã察象ã®ã¢ãžã¥ãŒã«ãäœæãã
ãŸãã¯ãã¹ã察象ã®ã«ãŒãã¢ãžã¥ãŒã«ãäœæããŸããä»åã¯ãAmazon S3ãã±ãããäœãããšã«ããŸãããã
versions.tf
terraform { required_version = "1.6.0" required_providers { aws = { source = "hashicorp/aws" version = "5.20.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_s3_bucket" "standalone_bucket" { bucket = var.standalone_bucket_name } resource "aws_s3_bucket" "with_content_bucket" { bucket = var.with_content_bucket_name } resource "aws_s3_object" "content" { bucket = aws_s3_bucket.with_content_bucket.bucket key = var.content_key content = var.content_value }
variables.tf
variable "standalone_bucket_name" { type = string } variable "with_content_bucket_name" { type = string } variable "content_key" { type = string default = "test.txt" } variable "content_value" { type = string default = "Hello World" }
outputs.tf
output "standalone_bucket_name" { value = aws_s3_bucket.standalone_bucket.bucket } output "with_content_bucket_name" { value = aws_s3_bucket.with_content_bucket.bucket } output "content_key" { value = aws_s3_object.content.key }
ãšãããããæšæºã¢ãžã¥ãŒã«æ§æã«ç¿ã£ãŠã¿ãŸããã
. âââ main.tf âââ outputs.tf âââ variables.tf âââ versions.tf 0 directories, 4 files
Amazon S3ãã±ããåã¯ãå¿ é ã®å€æ°ãšããŠããŸãã
確èªããŠãããŸãããã
$ terraform init $ terraform plan -var 'standalone_bucket_name=my-bucket' -var 'with_content_bucket_name=my-with-content-bucket' $ terraform apply -var 'standalone_bucket_name=my-bucket' -var 'with_content_bucket_name=my-with-content-bucket'
OKã§ããã
Apply complete! Resources: 3 added, 0 changed, 0 destroyed. Outputs: content_key = "test.txt" standalone_bucket_name = "my-bucket" with_content_bucket_name = "my-with-content-bucket"
AWS CLIã§ã確èªããŠãããŸãã
$ awslocal s3 ls 2023-10-08 21:07:29 my-with-content-bucket 2023-10-08 21:07:29 my-bucket $ awslocal s3 ls my-with-content-bucket/ 2023-10-08 21:07:29 11 test.txt $ awslocal s3 cp s3://my-with-content-bucket/test.txt - Hello World
倧äžå€«ãããªã®ã§ããªãœãŒã¹ãç Žæ£ããŠãããŸãã
$ terraform destroy -var 'standalone_bucket_name=my-bucket' -var 'with_content_bucket_name=my-with-content-bucket'
ãã¹ããæžããŠã¿ã
ããã§ã¯ããã¹ããæžããŠã¿ãŸãããã¹ãã¯ããã©ã«ãã§ã¯tests
ãã£ã¬ã¯ããªã«çœ®ããããã®ã§ãä»åã¯ããã«ç¿ãããšã«ããŸãã
$ mkdir tests
ãããªãã¹ããäœæããã¹ãã¯HCLïŒHashiCorp Configuration LanguageïŒã§èšè¿°ããŸãã
tests/create_s3_buckets.tftest.hcl
run "create_buckets" { assert { condition = aws_s3_bucket.standalone_bucket.bucket == "my-bucket" error_message = "standalone S3 bucket name did not match expected" } assert { condition = aws_s3_bucket.with_content_bucket.bucket == "my-with-content-bucket" error_message = "with content S3 bucket name did not match expected" } assert { condition = aws_s3_object.content.key == "test.txt" error_message = "content key did not match expected" } }
terraform test
ãå®è¡ããŠã¿ãŸãã
$ terraform test
ãããšãå€æ°ã®æå®ããªããšæãããŸãã
tests/create_s3_buckets.tftest.hcl... in progress run "create_buckets"... fail â· â Error: No value for required variable â â on variables.tf line 1: â 1: variable "standalone_bucket_name" { â â The module under test for run block "create_buckets" has a required variable "standalone_bucket_name" with no set value. Use a -var or -var-file command line argument or add this variable â into a "variables" block within the test file or run block. âµ â· â Error: No value for required variable â â on variables.tf line 5: â 5: variable "with_content_bucket_name" { â â The module under test for run block "create_buckets" has a required variable "with_content_bucket_name" with no set value. Use a -var or -var-file command line argument or add this â variable into a "variables" block within the test file or run block. âµ tests/create_s3_buckets.tftest.hcl... tearing down tests/create_s3_buckets.tftest.hcl... fail Failure! 0 passed, 1 failed.
ã§ã¯ãvariables
ãè¿œå ããŠæå®ã
run "create_buckets" { variables { standalone_bucket_name = "my-bucket" with_content_bucket_name = "my-with-content-bucket" } assert { condition = aws_s3_bucket.standalone_bucket.bucket == "my-bucket" error_message = "standalone S3 bucket name did not match expected" } assert { condition = aws_s3_bucket.with_content_bucket.bucket == "my-with-content-bucket" error_message = "with content S3 bucket name did not match expected" } assert { condition = aws_s3_object.content.key == "test.txt" error_message = "content key did not match expected" } }
å®è¡ã
$ terraform test
ä»åºŠã¯OKã§ããã
tests/create_s3_buckets.tftest.hcl... pass Success! 1 passed, 0 failed.
æžãããã¹ããèŠè¿ããŠã¿ãŸãããã
ãã¹ããã¡ã€ã«ã«èšè¿°ã§ããå 容ã¯ããã¡ãã§ãã
Tests - Configuration Language | Terraform | HashiCorp Developer
run
ãããã¯ã«ã¯ãTerraformã®ã³ãã³ããã©ã®ããã«å®è¡ããã®ããšãå€æ°ãã¢ãµãŒã·ã§ã³ãå®çŸ©ããŸãã
ã¢ãµãŒã·ã§ã³ã®å®çŸ©ã¯Custom Conditionãšåãã§ãã
Custom Conditions - Configuration Language | Terraform | HashiCorp Developer
condition
ã«ã¯ç¢ºèªããå
容ãbool
ã§è©äŸ¡ã§ãããã®ã§æå®ãã倱æããå Žåã¯error_message
ã«æå®ããå
容ã衚瀺ãããŸãã
倱æããã¢ãµãŒã·ã§ã³ã«ããŠã¿ãŸãããã
assert { condition = aws_s3_bucket.standalone_bucket.bucket == "bucket" error_message = "standalone S3 bucket name did not match expected" } assert { condition = aws_s3_object.content.key == "test" error_message = "content key did not match expected" }
確èªã
$ terraform test
ãããšããã®ãããªçµæã«ãªããŸããã
â Error: Test assertion failed â â on tests/create_s3_buckets.tftest.hcl line 8, in run "create_buckets": â 8: condition = aws_s3_bucket.standalone_bucket.bucket == "bucket" â âââââââââââââââââ â â aws_s3_bucket.standalone_bucket.bucket is "my-bucket" â â standalone S3 bucket name did not match expected âµ â· â Error: Test assertion failed â â on tests/create_s3_buckets.tftest.hcl line 18, in run "create_buckets": â 18: condition = aws_s3_object.content.key == "test" â âââââââââââââââââ â â aws_s3_object.content.key is "test.txt" â â content key did not match expected
ãã¹ãã倱æã§ããã
Failure! 0 passed, 1 failed.
ãŸãããã¹ãã®ã¹ããããèŠè¿ããŠã¿ãŸãã
tests/create_s3_buckets.tftest.hcl... in progress run "create_buckets"... pass tests/create_s3_buckets.tftest.hcl... tearing down tests/create_s3_buckets.tftest.hcl... pass
ãin progressããšåºåãããŠãããšããã§ãå®éã«ãªãœãŒã¹ãäœæãããŸãããã®æã«å®éã®ãªãœãŒã¹ãèŠãŠã¿ããšããªãœãŒã¹ãäœæãããŠ
ããããšã確èªã§ãããšæããŸãããããŠãtearing downãã§åé€ãããŸãã
ãªã®ã§ãå®éã«ãªãœãŒã¹ãäœæãããããšã¯ææ¡ããŠããããšã倧åã§ããã
variables
ã¯ãrun
ãšåã䞊ã³ã«æžãããšãã§ããŸãã
tests/create_s3_buckets2.tftest.hcl
variables { standalone_bucket_name = "my-bucket" with_content_bucket_name = "my-with-content-bucket" } run "create_buckets" { assert { condition = aws_s3_bucket.standalone_bucket.bucket == "my-bucket" error_message = "standalone S3 bucket name did not match expected" } assert { condition = aws_s3_bucket.with_content_bucket.bucket == "my-with-content-bucket" error_message = "with content S3 bucket name did not match expected" } assert { condition = aws_s3_object.content.key == "test.txt" error_message = "content key did not match expected" } }
ãããããšãrun
ãããã¯ãè€æ°ããå Žåã¯ãããã¬ãã«ã§æå®ããvariables
ã®å
容ãæž¡ãããããšã«ãªããŸãããŸããrun
ãããã¯å
ã§
variables
ãå®çŸ©ããŠããããã¬ãã«ã§å®çŸ©ããå
容ãäžæžãããããšãã§ããŸãã
output
ã®å
容ãåç
§ããããšãã§ããŸãã
tests/create_s3_buckets_condition_outputs.tftest.hcl
run "create_buckets" { variables { standalone_bucket_name = "my-bucket" with_content_bucket_name = "my-with-content-bucket" } assert { condition = output.standalone_bucket_name == "my-bucket" error_message = "standalone S3 bucket name did not match expected" } assert { condition = output.with_content_bucket_name == "my-with-content-bucket" error_message = "with content S3 bucket name did not match expected" } assert { condition = output.content_key == "test.txt" error_message = "content key did not match expected" } }
ä»åã¯ãäŸç€ºããªãœãŒã¹ã®å±æ§ãèŠãŠããããšãå€ãã®ã§ããªãœãŒã¹ã®å±æ§ãèŠãããšã«ããŸãã
planãšapplyã§ãã¹ãããŠã¿ã
run
ãããã¯ã§ã¯Terraformã®ã³ãã³ããå®è¡ããããšæžããŸããããããã©ã«ãã§ã¯terraform apply
ãè¡ãããŸãã
ãããterraform plan
ã«å€æŽããããšãã§ããŸãããŸãrun
ãããã¯ã«ã¯terraform plan
çšã®ãªãã·ã§ã³ãããããã§ããã
ãããªæãã«ããŠã¿ãŸããã
tests/create_s3_buckets_plan_and_apply.tftest.hcl
variables { standalone_bucket_name = "my-bucket" with_content_bucket_name = "my-with-content-bucket" } run "create_buckets_plan" { command = plan assert { condition = aws_s3_bucket.standalone_bucket.bucket == "my-bucket" error_message = "standalone S3 bucket name did not match expected" } # Condition expression could not be evaluated at this time. This means you have executed a `run` block with `command = plan` and one of the values your condition depended on is not known # until after the plan has been applied. Either remove this value from your condition, or execute an `apply` command from this `run` block. # assert { # condition = aws_s3_bucket.standalone_bucket.arn == "arn:aws:s3:::my-bucket" # error_message = "standalone S3 bucket arn did not match expected" # } assert { condition = aws_s3_bucket.with_content_bucket.bucket == "my-with-content-bucket" error_message = "with content S3 bucket name did not match expected" } # Condition expression could not be evaluated at this time. This means you have executed a `run` block with `command = plan` and one of the values your condition depended on is not known # until after the plan has been applied. Either remove this value from your condition, or execute an `apply` command from this `run` block. # assert { # condition = aws_s3_bucket.with_content_bucket.arn == "arn:aws:s3:::my-with-content-bucket" # error_message = "with content S3 bucket arn did not match expected" # } assert { condition = aws_s3_object.content.key == "test.txt" error_message = "content key did not match expected" } } run "create_buckets_apply" { command = apply assert { condition = aws_s3_bucket.standalone_bucket.bucket == "my-bucket" error_message = "standalone S3 bucket name did not match expected" } assert { condition = aws_s3_bucket.standalone_bucket.arn == "arn:aws:s3:::my-bucket" error_message = "standalone S3 bucket arn did not match expected" } assert { condition = aws_s3_bucket.with_content_bucket.bucket == "my-with-content-bucket" error_message = "with content S3 bucket name did not match expected" } assert { condition = aws_s3_bucket.with_content_bucket.arn == "arn:aws:s3:::my-with-content-bucket" error_message = "with content S3 bucket arn did not match expected" } assert { condition = aws_s3_object.content.key == "test.txt" error_message = "content key did not match expected" } }
ãã€ã³ãã¯ã以äžã®æå®ã§ããã
command = plan
äžèŠãplan
ãšapply
ã§å·®ããªãããã«èŠããŸããã以äžã®ããã«plan
ã§ã¯ç¢ºèªã§ããªããã®ããããŸãã
# Condition expression could not be evaluated at this time. This means you have executed a `run` block with `command = plan` and one of the values your condition depended on is not known # until after the plan has been applied. Either remove this value from your condition, or execute an `apply` command from this `run` block. # assert { # condition = aws_s3_bucket.standalone_bucket.arn == "arn:aws:s3:::my-bucket" # error_message = "standalone S3 bucket arn did not match expected" # } # Condition expression could not be evaluated at this time. This means you have executed a `run` block with `command = plan` and one of the values your condition depended on is not known # until after the plan has been applied. Either remove this value from your condition, or execute an `apply` command from this `run` block. # assert { # condition = aws_s3_bucket.with_content_bucket.arn == "arn:aws:s3:::my-with-content-bucket" # error_message = "with content S3 bucket arn did not match expected" # }
ããã¯ãšã©ãŒã¡ãã»ãŒãžãšterraform plan
ã®çµæãå®éã«èŠããšæ³åãã€ããŸããããknown after applyãã€ãŸãterraform apply
åŸã§ãªããš
ããããªãå€ã«ã€ããŠã¯ãcommand = plan
ãæå®ããæã«ã¢ãµãŒã·ã§ã³ããããšãã§ããŸããã
# aws_s3_bucket.standalone_bucket will be created + resource "aws_s3_bucket" "standalone_bucket" { + acceleration_status = (known after apply) + acl = (known after apply) + arn = (known after apply) + bucket = "my-bucket" + bucket_domain_name = (known after apply) + bucket_prefix = (known after apply) + bucket_regional_domain_name = (known after apply) + force_destroy = false + hosted_zone_id = (known after apply) + id = (known after apply) + object_lock_enabled = (known after apply) + policy = (known after apply) + region = (known after apply) + request_payer = (known after apply) + tags_all = (known after apply) + website_domain = (known after apply) + website_endpoint = (known after apply) }
ã³ã¡ã³ãã«ãæžããŠããŸãããã ãªã«äœ¿ã£ãŠã以äžã®ãããªãšã©ãŒã¡ãã»ãŒãžãè¿ã£ãŠããŸãã
â Error: Unknown condition value â â on tests/create_s3_buckets_plan_and_apply.tftest.hcl line 17, in run "create_buckets_plan": â 17: condition = aws_s3_bucket.standalone_bucket.arn == "arn:aws:s3:::my-bucket" â âââââââââââââââââ â â aws_s3_bucket.standalone_bucket.arn is a string â â Condition expression could not be evaluated at this time. This means you have executed a `run` block with `command = plan` and one of the values your condition depended on is not known â until after the plan has been applied. Either remove this value from your condition, or execute an `apply` command from this `run` block.
ã¢ãžã¥ãŒã«ã䜿ã
ãã¹ãå ã§ã¢ãžã¥ãŒã«ã䜿ãããšãã§ããŸãã
ããšãã°ãä»åã®ãã¹ãã§ã¯æåã«terraform apply
ããæãšåãå€ãvariables
ã«æå®ããŠããŸãã
ãã£ãŠãterraform apply
ããŠ
$ terraform plan -var 'standalone_bucket_name=my-bucket' -var 'with_content_bucket_name=my-with-content-bucket'
ãã¹ããå®è¡ãããšïŒä»åã¯ã²ãšã€ã®ãã¹ããã¡ã€ã«ã«çµã£ãŠããŸãïŒ
$ terraform test -filter=tests/create_s3_buckets.tftest.hcl
以äžã®ããã«ãªãœãŒã¹ã競åããã®ã§å€±æããŸãã
â Error: creating Amazon S3 (Simple Storage) Bucket (my-bucket): bucket already exists â â with aws_s3_bucket.standalone_bucket, â on main.tf line 33, in resource "aws_s3_bucket" "standalone_bucket": â 33: resource "aws_s3_bucket" "standalone_bucket" { â âµ â· â Error: creating Amazon S3 (Simple Storage) Bucket (my-with-content-bucket): bucket already exists â â with aws_s3_bucket.with_content_bucket, â on main.tf line 37, in resource "aws_s3_bucket" "with_content_bucket": â 37: resource "aws_s3_bucket" "with_content_bucket" { â âµ
ãã®åŸãã¯ãªãŒã³ã¢ãããåããŸãããã§ã«äœææžã¿ã®ãªãœãŒã¹ã¯åé€ãããŸããããã¹ãå
ã§ãäœæã«æåãããªãœãŒã¹ã®ã¿ã
åé€ããããã§ãã
ã§ã¯ããã¹ãã§äœæãããªãœãŒã¹ãæ¢åã®ãã®ãšç«¶åããªãããã«variables
ãèšå®ããã°ããããã§ãããä»åã¯ãããã©ã³ãã ã«
ããŠã¿ãŸãããã
5æ¡ã®ã©ã³ãã æŽæ°ãçæããã¢ãžã¥ãŒã«ãäœæã
tests/setup/random/main.tf
terraform { required_providers { random = { source = "hashicorp/random" version = "3.5.1" } } } resource "random_integer" "bucket_prefix" { min = 10000 max = 99999 } output "bucket_prefix" { value = random_integer.bucket_prefix.id }
ãã®ã¢ãžã¥ãŒã«ãå®è¡ããrun
ãããã¯ãå«ãããã¹ããã¡ã€ã«ãäœæã
tests/create_s3_buckets_with_module.tftest.hcl
run "generate_random" { module { source = "./tests/setup/random" } } run "create_buckets" { variables { standalone_bucket_name = "${run.generate_random.bucket_prefix}-my-bucket" with_content_bucket_name = "${run.generate_random.bucket_prefix}-my-with-content-bucket" } assert { condition = aws_s3_bucket.standalone_bucket.bucket == "${run.generate_random.bucket_prefix}-my-bucket" error_message = "standalone S3 bucket name did not match expected" } assert { condition = aws_s3_bucket.standalone_bucket.arn == "arn:aws:s3:::${run.generate_random.bucket_prefix}-my-bucket" error_message = "standalone S3 bucket arn did not match expected" } assert { condition = aws_s3_bucket.with_content_bucket.bucket == "${run.generate_random.bucket_prefix}-my-with-content-bucket" error_message = "with content S3 bucket name did not match expected" } assert { condition = aws_s3_bucket.with_content_bucket.arn == "arn:aws:s3:::${run.generate_random.bucket_prefix}-my-with-content-bucket" error_message = "with content S3 bucket arn did not match expected" } assert { condition = aws_s3_object.content.key == "test.txt" error_message = "content key did not match expected" } }
ãã€ã³ãã¯ãã¡ãã§ããã
run "generate_random" { module { source = "./tests/setup/random" } }
module
ã®source
ã«ã¯ãterraform
ã³ãã³ããå®è¡ããäœçœ®ããã®ãã¹ãæå®ããå¿
èŠããããŸãããã®ãã¡ã€ã«ããã®çžå¯Ÿãã¹ã§ã¯
ãããŸããã
ãŸããã¢ãžã¥ãŒã«ã®output
ã¯ä»¥äžã®ããã«run.[ãããã¯å].[outputå]
ã§åç
§ã§ããŸãã
run "create_buckets" { variables { standalone_bucket_name = "${run.generate_random.bucket_prefix}-my-bucket" with_content_bucket_name = "${run.generate_random.bucket_prefix}-my-with-content-bucket" } assert { condition = aws_s3_bucket.standalone_bucket.bucket == "${run.generate_random.bucket_prefix}-my-bucket" error_message = "standalone S3 bucket name did not match expected" }
ã§ã¯ãå®è¡ã
$ terraform test
ãããšãã¢ãžã¥ãŒã«ãã€ã³ã¹ããŒã«ãããŠããªããšèšãããã®ã§
â· â Error: Module not installed â â on tests/create_s3_buckets_with_module.tftest.hcl line 2, in run "generate_random": â 2: module { â â This module is not yet installed. Run "terraform init" to install all modules required by this configuration. âµ
terraform init
ãå®è¡ããŸããtests
ãã£ã¬ã¯ããªå
ããã¢ãžã¥ãŒã«ã®ãããã£ã¬ã¯ããªã«ç§»åããå¿
èŠã¯ãããŸããã
$ terraform init
ä»åºŠã¯ãã¹ãã«æåããŸãã
tests/create_s3_buckets_with_module.tftest.hcl... in progress run "generate_random"... pass run "create_buckets"... pass tests/create_s3_buckets_with_module.tftest.hcl... tearing down tests/create_s3_buckets_with_module.tftest.hcl... pass
ã¢ãµãŒã·ã§ã³ã工倫ãã
ã¢ãµãŒã·ã§ã³ã¯ãbool
ã§æå®ããã°ãããã®ãæžãã°ããã®ã§ããã
Custom Conditions / Condition Expressions
Terraformã®ããã¥ã¡ã³ãã§ã¯åçŽã«å€ãçå€æ¯èŒããŠãããã®ãå€ãã®ã§ãããé¢æ°ãªã©ã䜿ããã®ããªãšã
ãšããããã§ãå ã»ã©ã®ã¢ãžã¥ãŒã«ã䜿ã£ãã©ã³ãã æŽæ°ã®ç®æãæ£èŠè¡šçŸã§ç¢ºèªããããã«ããŠã¿ãŸããã
tests/create_s3_buckets_assertion.tftest.hcl
run "generate_random" { module { source = "./tests/setup/random" } } run "create_buckets" { variables { standalone_bucket_name = "${run.generate_random.bucket_prefix}-my-bucket" with_content_bucket_name = "${run.generate_random.bucket_prefix}-my-with-content-bucket" } assert { condition = regex("\\d{5}-my-bucket", aws_s3_bucket.standalone_bucket.bucket) == aws_s3_bucket.standalone_bucket.bucket error_message = "standalone S3 bucket name did not match expected" } assert { condition = regex("\\d{5}-my-with-content-bucket", aws_s3_bucket.with_content_bucket.bucket) == aws_s3_bucket.with_content_bucket.bucket error_message = "with content S3 bucket name did not match expected" } assert { condition = aws_s3_object.content.key == "test.txt" error_message = "content key did not match expected" } }
çµå±ãæåŸã¯çå€æ¯èŒããŠããã®ã§ãããæ£èŠè¡šçŸãããã¯ã䜿ããããªãã®ã§ã¯ïŒãšããæ°ãããã®ã§ã
æååå
ã«${}
ãåã蟌ã以å€ã«ããããããããããªãããšã¯ãããšæãã®ã§ãé¢æ°ã䜿ãããšãèããŠãããšããã®ããªãšã
ãªãã±
䜿ããªãã£ããã®
ä»åã觊ããŠããªãèŠçŽ ãšããŠprovider
ãšexpect_failures
ããããŸãã
provider
ã䜿ããšãã¡ã€ã³ãšãªãæ§æãã¡ã€ã«ã§äœ¿çšããŠããTerraform ProviderããªãŒããŒã©ã€ãã§ããããã§ããalias
ãèæ
®ããã
ããã§ãã
expect_failures
ã¯ãã¡ã€ã³ãšãªãæ§æãã¡ã€ã«ã§check
ã䜿çšããŠããå Žåã§ããã€ãã¹ãã§ããã倱æããããšãããã£ãŠããå Žåã¯
ææ¢ã§ããæ©èœã§ãã
Custom Conditions / Checks with Assertions
å®è¡ãããã¹ããçµã蟌ã
terraform test
ã¯ãterraform apply
ãè¡ã£ãŠãªãœãŒã¹ãäœæããã®ã§ãæéãããããªãœãŒã¹ãäœæããå Žåã¯ãã¹ãã«ãæéãããããŸãã
ããããæã«terraform test
ã§äžæ¬ããŠå®è¡ãããšæéããããã®ã§ã-filter
ãªãã·ã§ã³ã§å®è¡ãããã¹ããæå®ãããšäŸ¿å©ãããããŸããã
$ terraform test -filter=tests/create_s3_buckets.tftest.hcl
ãšã¯ãããããããç¶æ³ã§ã¯ãã¹ããããããäœããªãæ¹ãããæ°ã¯ããŸããâŠã
ãããã°ãã
åã¢ãžã¥ãŒã«ãã©ã®ãããªåäœãããŠããã確èªãããå Žåã¯ã-verbose
ãªãã·ã§ã³ãä»ããŠå®è¡ãããšããã§ãããã
â» -filter
ã¯å®è¡ãããã¹ããçµã£ãŠããã ãã§ã
$ terraform test -filter=tests/create_s3_buckets_with_module.tftest.hcl -verbose
ãããšããããªæãã§äœæããããªãœãŒã¹ã®çµæãªã©ã確èªã§ããŸãã
$ terraform test -filter=tests/create_s3_buckets_with_module.tftest.hcl -verbose tests/create_s3_buckets_with_module.tftest.hcl... in progress run "generate_random"... pass # random_integer.bucket_prefix: resource "random_integer" "bucket_prefix" { id = "41773" max = 99999 min = 10000 result = 41773 } Outputs: bucket_prefix = "41773" run "create_buckets"... pass # aws_s3_bucket.standalone_bucket: resource "aws_s3_bucket" "standalone_bucket" { arn = "arn:aws:s3:::41773-my-bucket" bucket = "41773-my-bucket" bucket_domain_name = "41773-my-bucket.s3.amazonaws.com" bucket_regional_domain_name = "41773-my-bucket.s3.us-east-1.amazonaws.com" force_destroy = false hosted_zone_id = "Z3AQBSTGFYJSTF" id = "41773-my-bucket" object_lock_enabled = false region = "us-east-1" request_payer = "BucketOwner" tags_all = {} grant { id = "75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a" permissions = [ "FULL_CONTROL", ] type = "CanonicalUser" } versioning { enabled = false mfa_delete = false } } # aws_s3_bucket.with_content_bucket: resource "aws_s3_bucket" "with_content_bucket" { arn = "arn:aws:s3:::41773-my-with-content-bucket" bucket = "41773-my-with-content-bucket" bucket_domain_name = "41773-my-with-content-bucket.s3.amazonaws.com" bucket_regional_domain_name = "41773-my-with-content-bucket.s3.us-east-1.amazonaws.com" force_destroy = false hosted_zone_id = "Z3AQBSTGFYJSTF" id = "41773-my-with-content-bucket" object_lock_enabled = false region = "us-east-1" request_payer = "BucketOwner" tags_all = {} grant { id = "75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a" permissions = [ "FULL_CONTROL", ] type = "CanonicalUser" } versioning { enabled = false mfa_delete = false } } # aws_s3_object.content: resource "aws_s3_object" "content" { bucket = "41773-my-with-content-bucket" bucket_key_enabled = false content = "Hello World" content_type = "application/octet-stream" etag = "b10a8db164e0754105b7a99be72e3fe5" force_destroy = false id = "test.txt" key = "test.txt" storage_class = "STANDARD" tags_all = {} } Outputs: content_key = "test.txt" standalone_bucket_name = "41773-my-bucket" with_content_bucket_name = "41773-my-with-content-bucket" â· â Warning: AWS account ID not found for provider â â with provider["registry.terraform.io/hashicorp/aws"], â on main.tf line 1, in provider "aws": â 1: provider "aws" { â â See https://www.terraform.io/docs/providers/aws/index.html#skip_requesting_account_id for implications. â â (and one more similar warning elsewhere) âµ tests/create_s3_buckets_with_module.tftest.hcl... tearing down â· â Warning: AWS account ID not found for provider â â with provider["registry.terraform.io/hashicorp/aws"], â on main.tf line 1, in provider "aws": â 1: provider "aws" { â â See https://www.terraform.io/docs/providers/aws/index.html#skip_requesting_account_id for implications. â â (and one more similar warning elsewhere) âµ tests/create_s3_buckets_with_module.tftest.hcl... pass Success! 2 passed, 0 failed.
ãã¡ãã®èŠåã¯ä»ãŸã§ç«¯æã£ãŠããã®ã§ãããLocalStackã䜿ã£ãŠããé¢ä¿ã§åºãŠããã®ã§ä»åã¯ç¡èŠã§
â· â Warning: AWS account ID not found for provider â â with provider["registry.terraform.io/hashicorp/aws"], â on main.tf line 1, in provider "aws": â 1: provider "aws" { â â See https://www.terraform.io/docs/providers/aws/index.html#skip_requesting_account_id for implications. â â (and one more similar warning elsewhere) âµ
ãããªãšããã§ããããã
ãããã«
Terraform 1.6ã§è¿œå ããããTerraform testing frameworkãè©ŠããŠã¿ãŸããã
å®éã«ãªãœãŒã¹ãäœãã®ãè¯ãæãããã°ããã§ãªãæãããæ°ã¯ããŸãããTerratestãšã¯ç°ãªãHCLã§ãã¹ããæžããã®ãè¯ãã§ããã
䜿ãããšããã§ã¯äœ¿ã£ãŠãããŸãããã