Datadog Terraform Provider Version
v4.3.0
Terraform Version
v1.14.7
What resources or data sources are affected?
Terraform Configuration Files
resource "datadog_dashboard" "datadog_cost" {
title = "Datadog Cost Overview"
layout_type = "ordered"
widget {
group_definition {
title = "Summary"
layout_type = "ordered"
widget {
query_value_definition {
title = "Estimated MTD Datadog Spend"
live_span = "1mo"
request {
formula {
formula_expression = "query1"
}
query {
metric_query {
name = "query1"
data_source = "cloud_cost"
query = "sum:datadog.cost.estimated{cost_type:usage}"
aggregator = "sum"
}
}
}
}
}
}
}
}
Relevant debug or panic output
JSON plan output showing the drift on every metric_query block:
data_source: "metrics" → "cloud_cost"
Full list of diffs from terraform show -json on the plan:
widget[0].group.widget[0].query_value.request[0].query[0].metric_query[0].data_source: "metrics" -> "cloud_cost"
widget[0].group.widget[1].query_value.request[0].query[0].metric_query[0].data_source: "metrics" -> "cloud_cost"
widget[1].group.widget[0].timeseries.request[0].query[0].metric_query[0].data_source: "metrics" -> "cloud_cost"
widget[1].group.widget[1].timeseries.request[0].query[0].metric_query[0].data_source: "metrics" -> "cloud_cost"
widget[2].group.widget[0].toplist.request[0].query[0].metric_query[0].data_source: "metrics" -> "cloud_cost"
widget[2].group.widget[1].toplist.request[0].query[0].metric_query[0].data_source: "metrics" -> "cloud_cost"
widget[3].group.widget[0].change.request[0].query[0].metric_query[0].data_source: "metrics" -> "cloud_cost"
Expected Behavior
Setting data_source = "cloud_cost" on a metric_query block inside a dashboard widget should be persisted in state after apply. Subsequent plans should show no changes.
Actual Behavior
After a successful apply, the next terraform plan (or refresh) reads the data_source attribute back from the Datadog API as "metrics" instead of "cloud_cost". This causes every plan to show an update for every widget that uses cloud cost queries, even though the dashboard is configured correctly in the Datadog UI.
The drift is purely in the provider's read/flatten logic — the dashboard itself works fine and shows cloud cost data as expected.
Steps to Reproduce
- Create a
datadog_dashboard with any widget using metric_query { data_source = "cloud_cost" ... }
terraform apply — applies successfully
terraform plan — shows update needed on every widget with data_source: "metrics" -> "cloud_cost"
- Repeat step 2-3 indefinitely — the diff never resolves
Important Factoids
Root cause
The bug is in buildDatadogMetricQuery in resource_datadog_dashboard.go. The function hardcodes data_source to "metrics" and never reads the user-supplied value from the HCL input:
func buildDatadogMetricQuery(data map[string]interface{}) *datadogV1.FormulaAndFunctionQueryDefinition {
dataSource := datadogV1.FormulaAndFunctionMetricDataSource("metrics") // <-- hardcoded, ignores data["data_source"]
metricQuery := datadogV1.NewFormulaAndFunctionMetricQueryDefinition(dataSource, data["name"].(string), data["query"].(string))
// ...
}
The read path (buildTerraformQuery) correctly reads data_source from the API response via GetDataSourceOk(), so state accurately reflects what the API returns. But since the write path always sends "metrics", the API stores or returns "metrics", and Terraform detects drift against the HCL-specified "cloud_cost".
Suggested fix
Read data_source from the HCL input instead of hardcoding it, matching the pattern used by other query builders (e.g., buildDatadogFormulaAndFunctionAPMResourceStatsQuery which uses data["data_source"].(string)):
func buildDatadogMetricQuery(data map[string]interface{}) *datadogV1.FormulaAndFunctionQueryDefinition {
dataSource := datadogV1.FormulaAndFunctionMetricDataSource("metrics")
if v, ok := data["data_source"].(string); ok && len(v) != 0 {
dataSource = datadogV1.FormulaAndFunctionMetricDataSource(v)
}
metricQuery := datadogV1.NewFormulaAndFunctionMetricQueryDefinition(dataSource, data["name"].(string), data["query"].(string))
// ...
}
This preserves backwards compatibility (defaulting to "metrics" when data_source is unset, which aligns with the schema Default: "metrics"), while correctly honoring data_source = "cloud_cost" when explicitly set.
References
Datadog Terraform Provider Version
v4.3.0
Terraform Version
v1.14.7
What resources or data sources are affected?
Terraform Configuration Files
Relevant debug or panic output
JSON plan output showing the drift on every
metric_queryblock:Full list of diffs from
terraform show -jsonon the plan:Expected Behavior
Setting
data_source = "cloud_cost"on ametric_queryblock inside a dashboard widget should be persisted in state after apply. Subsequent plans should show no changes.Actual Behavior
After a successful apply, the next
terraform plan(or refresh) reads thedata_sourceattribute back from the Datadog API as"metrics"instead of"cloud_cost". This causes every plan to show an update for every widget that uses cloud cost queries, even though the dashboard is configured correctly in the Datadog UI.The drift is purely in the provider's read/flatten logic — the dashboard itself works fine and shows cloud cost data as expected.
Steps to Reproduce
datadog_dashboardwith any widget usingmetric_query { data_source = "cloud_cost" ... }terraform apply— applies successfullyterraform plan— shows update needed on every widget withdata_source: "metrics" -> "cloud_cost"Important Factoids
Root cause
The bug is in
buildDatadogMetricQueryinresource_datadog_dashboard.go. The function hardcodesdata_sourceto"metrics"and never reads the user-supplied value from the HCL input:The read path (
buildTerraformQuery) correctly readsdata_sourcefrom the API response viaGetDataSourceOk(), so state accurately reflects what the API returns. But since the write path always sends"metrics", the API stores or returns"metrics", and Terraform detects drift against the HCL-specified"cloud_cost".Suggested fix
Read
data_sourcefrom the HCL input instead of hardcoding it, matching the pattern used by other query builders (e.g.,buildDatadogFormulaAndFunctionAPMResourceStatsQuerywhich usesdata["data_source"].(string)):This preserves backwards compatibility (defaulting to
"metrics"whendata_sourceis unset, which aligns with the schemaDefault: "metrics"), while correctly honoringdata_source = "cloud_cost"when explicitly set.References