A deployed API can exist in Terraform state yet fail to answer requests. A check block lets you test that kind of operational expectation with assertions in your configuration. Checks are intended for long-lived infrastructure, including production systems, as well as newly created resources. section 10.6 section 10.6.2
A check resembles a postcondition, but the failure behavior matters: a failed check reports a problem without stopping Terraform from continuing. One check block can contain multiple assertions. By contrast, the illustrated postconditions each need their own block and can stop execution when their requirements fail. Use a check to report health without blocking changes. section 10.6.2
Check an API health endpoint
Place an HTTP data source inside check "health_check", request the API’s /health URL, then assert that its status code is at least 200 and below 300. The data source is scoped to the check: its result can be used by that check’s assertion, but not elsewhere in the configuration. If the data source fails, Terraform issues a warning rather than stopping execution. section 10.6.2
Listing 10.32 check block with scoped data sources
check "health_check" {
data "http" "api" { #1
url = "${module.api.url}/health" #2
request_headers = {
Accept = "application/json"
}
}
assert {
condition = data.http.api.status_code >= 200 &&
data.http.api.status_code < 300 #3
error_message = "Healthcheck failed with status code
${data.http.api.status_code} and content ${data.http.api.request_body}."
}
}
#1 If this block fails it won’t stop execution as it’s part of the check block.
#2 You can use attributes and variables inside of these blocks.
#3 You refer to the data block just like you would outside of a check, but these are accessible only inside of the check.
The configuration shows the scoped HTTP request, the status-code assertion, and the failure message together. section 10.6.2
Check the dependency before relying on a health result. A URL built from a module output supplies an implicit dependency. If the URL comes only from an input variable, the check may run during the first plan, before the API exists. Put depends_on = [module.api] on the scoped data source in that case. Scoped data sources accept provider and depends_on, but no other lifecycle arguments. section 10.6.2
Listing 10.33 check block with data source dependencies
check "health_check" {
data "http" "api" {
url = var.healthcheck_endpoint #1
request_headers = {
Accept = "application/json"
}
depends_on = [module.api] #2
}
assert {
condition = data.http.api.status_code >= 200 &&
data.http.api.status_code < 300
error_message = "Healthcheck failed with status code
${data.http.api.status_code} and content ${data.http.api.request_body}."
}
}
#1 Since we are using a variable there is no implicit dependency on this data source.
#2 To prevent the first run of this check from failing we need to make this block depend on the module that launches the API.
The variable-based endpoint example places depends_on on the scoped HTTP data source so the API module launches first. section 10.6.2
Terraform saves check results in state, including results from child modules and every assertion in a check block. This preserves the reported status alongside the infrastructure state; it does not make a failed check a deployment blocker. section 6.3.4 section 10.6.2
