Skip to content

Instantly share code, notes, and snippets.

@bneutra
Created July 28, 2023 20:45
Show Gist options
  • Save bneutra/437b4832b347d720466a995c8780b8e3 to your computer and use it in GitHub Desktop.
Save bneutra/437b4832b347d720466a995c8780b8e3 to your computer and use it in GitHub Desktop.
terraform_check_examples.tf
# precondition vs check
# precondition:
# - raises
# - stop you at plan
# check:
# - warns
# - to be used with TFC "Continuous Validation"
# - i.e. alert when check warnings emerge
# Uses for precondition and check
# - validate dependencies in a more user friendly way than a data source ("Not Found")
# - e.g. AMI lookup (e.g. can't find AMI with the right architecture)
# - e.g. certificate status (e.g. cert is now expird)
# - validate arbitrary things about input resources (len(subnet_ids) > 2)
# - ??? validate required external services with the "http" data source
# - e.g used to ensure you've properly orchestrated a multi-stage change
# i.e. some external service needs to be available before creating this resource
resource "aws_acm_certificate" "cert" {
domain_name = "brendan.test.neutra.com"
validation_method = "DNS"
}
# Validate by using a data source
# - this will hard fail but without a helpful message
# Error: no certificate for domain "brendan.test.neutra.com" found in this Region
data "aws_acm_certificate" "mycert" {
domain = "brendan.test.neutra.com"
statuses = ["ISSUED"]
depends_on = [
aws_acm_certificate.cert
]
}
# Validate with check tf 1.5
# - check is only informational (so not that useful from preventing harm)
# - but could be used with TFC "Continuous Validation" (useful for detecting emerging harm)
# to continually run plans to see if checks are now failing
#
# │ Warning: Check block assertion failed
# │
# │ on check.tf line 34, in check "certificate":
# │ 34: condition = aws_acm_certificate.cert.status == "ISSUED"
# │ ├────────────────
# │ │ aws_acm_certificate.cert.status is "PENDING_VALIDATION"
check "certificate" {
assert {
condition = aws_acm_certificate.cert.status == "ISSUED"
error_message = "Certificate status is ${aws_acm_certificate.cert.status}"
}
}
# Validate with lifecycle precondition
# - this will hard fail with a helpful message
# │ Error: Resource precondition failed
# │
# │ on check.tf line 57, in resource "aws_instance" "web":
# │ 57: condition = aws_acm_certificate.cert.status == "ISSUED"
# │ ├────────────────
# │ │ aws_acm_certificate.cert.status is "PENDING_VALIDATION"
resource "aws_instance" "web" {
ami = "ami-123"
instance_type = "t3.micro"
# pretend_required_cert = aws_acm_certificate.cert
tags = {
Name = "HelloWorld"
}
lifecycle {
precondition {
condition = aws_acm_certificate.cert.status == "ISSUED"
error_message = "Certificate status is ${aws_acm_certificate.cert.status}"
}
}
}
# A more interesting check example
# i.e. with TFC Continuous Validation this could alert when an instance
# is not currently using the latest available AMI
check "ami_version_check" {
data "aws_instance" "hashiapp_current" {
instance_tags = {
Name = "hashiapp"
}
}
assert {
condition = aws_instance.hashiapp.ami == data.hcp_packer_image.hashiapp_image.cloud_image_id
error_message = "Must use the latest available AMI, ${data.hcp_packer_image.hashiapp_image.cloud_image_id}."
}
}
# Possibly more interesting use of pre-condition
# Check that a required http service is up before creating a resource
data "http" "healthcheck" {
url = "https://www.example.com"
}
resource "aws_instance" "web" {
ami = "ami-123"
instance_type = "t3.micro"
tags = {
Name = "HelloWorld"
}
lifecycle {
precondition {
condition = data.http.healthcheck.status_code == 200
error_message = "${data.http.healthcheck.url} returned an unhealthy status code"
}
}
}
# postcondition examples:
# - "http" data source (check your service is responding?)
#
# counter examples (imo)
# - check that the resource I created with attribute X, exists and has attribute X
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment