Skip to content

Commit

Permalink
[datadog_dashboard] Support Formula and Function requests in heatmap …
Browse files Browse the repository at this point in the history
…widget (#2103)

* add fnf request fields to heatmap widget definition

* make docs

* documentation suggestions

* APM env capitalization change, basing off docs from the datadog site.
  • Loading branch information
nkzou authored Sep 18, 2023
1 parent 2fe58df commit e7f213c
Show file tree
Hide file tree
Showing 7 changed files with 796 additions and 122 deletions.
46 changes: 40 additions & 6 deletions datadog/resource_datadog_dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -2624,6 +2624,9 @@ func getHeatmapRequestSchema() map[string]*schema.Schema {
"rum_query": getApmLogNetworkRumSecurityAuditQuerySchema(),
"security_query": getApmLogNetworkRumSecurityAuditQuerySchema(),
"process_query": getProcessQuerySchema(),
// "query" and "formula" go together
"query": getFormulaQuerySchema(),
"formula": getFormulaSchema(),
// Settings specific to Heatmap requests
"style": {
Description: "The style of the widget graph. One nested block is allowed using the structure below.",
Expand Down Expand Up @@ -2662,6 +2665,32 @@ func buildDatadogHeatmapRequests(terraformRequests *[]interface{}) *[]datadogV1.
} else if v, ok := terraformRequest["security_query"].([]interface{}); ok && len(v) > 0 {
securityQuery := v[0].(map[string]interface{})
datadogHeatmapRequest.SecurityQuery = buildDatadogApmOrLogQuery(securityQuery)
} else if v, ok := terraformRequest["query"].([]interface{}); ok && len(v) > 0 {
queries := make([]datadogV1.FormulaAndFunctionQueryDefinition, len(v))
for i, q := range v {
query := q.(map[string]interface{})
if w, ok := query["event_query"].([]interface{}); ok && len(w) > 0 {
queries[i] = *buildDatadogEventQuery(w[0].(map[string]interface{}))
} else if w, ok := query["metric_query"].([]interface{}); ok && len(w) > 0 {
queries[i] = *buildDatadogMetricQuery(w[0].(map[string]interface{}))
} else if w, ok := query["process_query"].([]interface{}); ok && len(w) > 0 {
queries[i] = *buildDatadogFormulaAndFunctionProcessQuery(w[0].(map[string]interface{}))
} else if w, ok := query["slo_query"].([]interface{}); ok && len(w) > 0 {
queries[i] = *buildDatadogFormulaAndFunctionSLOQuery(w[0].(map[string]interface{}))
}
}
datadogHeatmapRequest.SetQueries(queries)
datadogHeatmapRequest.SetResponseFormat(datadogV1.FormulaAndFunctionResponseFormat("timeseries"))
}
if v, ok := terraformRequest["formula"].([]interface{}); ok && len(v) > 0 {
formulas := make([]datadogV1.WidgetFormula, len(v))
for i, formula := range v {
if formula == nil {
continue
}
formulas[i] = *buildDatadogFormula(formula.(map[string]interface{}))
}
datadogHeatmapRequest.SetFormulas(formulas)
}
if style, ok := terraformRequest["style"].([]interface{}); ok && len(style) > 0 {
if v, ok := style[0].(map[string]interface{}); ok && len(v) > 0 {
Expand Down Expand Up @@ -2693,6 +2722,11 @@ func buildTerraformHeatmapRequests(datadogHeatmapRequests *[]datadogV1.HeatMapWi
} else if v, ok := datadogRequest.GetSecurityQueryOk(); ok {
terraformQuery := buildTerraformApmOrLogQuery(*v)
terraformRequest["security_query"] = []map[string]interface{}{terraformQuery}
} else if v, ok := datadogRequest.GetQueriesOk(); ok {
terraformRequest["query"] = buildTerraformQuery(v)
}
if v, ok := datadogRequest.GetFormulasOk(); ok {
terraformRequest["formula"] = buildTerraformFormula(v)
}
if v, ok := datadogRequest.GetStyleOk(); ok {
style := buildTerraformWidgetStyle(*v)
Expand Down Expand Up @@ -6256,7 +6290,7 @@ func getFormulaSchema() *schema.Schema {
"count": {
Type: schema.TypeInt,
Optional: true,
Description: "The number of results to return",
Description: "The number of results to return.",
},
"order": {
Type: schema.TypeString,
Expand Down Expand Up @@ -6297,7 +6331,7 @@ func getFormulaSchema() *schema.Schema {
"palette": {
Type: schema.TypeString,
Optional: true,
Description: "The color palette used to display the formula. A guide to the available color palettes can be found at https://docs.datadoghq.com/dashboards/guide/widget_colors",
Description: "The color palette used to display the formula. A guide to the available color palettes can be found at https://docs.datadoghq.com/dashboards/guide/widget_colors.",
},
"palette_index": {
Type: schema.TypeInt,
Expand Down Expand Up @@ -6545,7 +6579,7 @@ func getFormulaQuerySchema() *schema.Schema {
"env": {
Type: schema.TypeString,
Required: true,
Description: "APM Environment.",
Description: "APM environment.",
},
"stat": {
Type: schema.TypeString,
Expand Down Expand Up @@ -6607,7 +6641,7 @@ func getFormulaQuerySchema() *schema.Schema {
"env": {
Type: schema.TypeString,
Required: true,
Description: "APM Environment.",
Description: "APM environment.",
},
"name": {
Type: schema.TypeString,
Expand Down Expand Up @@ -6658,14 +6692,14 @@ func getFormulaQuerySchema() *schema.Schema {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Description: "The slo query using formulas and functions.",
Description: "The SLO query using formulas and functions.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"data_source": {
Type: schema.TypeString,
Required: true,
ValidateDiagFunc: validators.ValidateEnumValue(datadogV1.NewFormulaAndFunctionSLODataSourceFromValue),
Description: "The data source for slo queries.",
Description: "The data source for SLO queries.",
},
"slo_id": {
Type: schema.TypeString,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2023-09-13T14:30:00.577449-04:00
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
version: 1
interactions:
- request:
body: |
{"description":"Created using the Datadog provider in Terraform","id":"","is_read_only":true,"layout_type":"ordered","notify_list":[],"tags":[],"template_variable_presets":[],"template_variables":[],"title":"tf-TestAccDatadogDashboardHeatMapFormulaAndFunction-local-1694629800","widgets":[{"definition":{"custom_links":[{"label":"Test Custom Link label","link":"https://app.datadoghq.com/dashboard/lists"},{"is_hidden":true,"link":"https://app.datadoghq.com/dashboard/lists","override_label":"logs"}],"events":[{"q":"env:prod","tags_execution":"and"}],"legend_size":"2","requests":[{"formulas":[{"formula":"query1"}],"queries":[{"data_source":"metrics","name":"query1","query":"avg:system.cpu.user{*}"}],"response_format":"timeseries","style":{"palette":"dog_classic"}}],"show_legend":true,"time":{"live_span":"1mo"},"title":"Avg of system.cpu.user over account:prod by app","title_align":"center","title_size":"16","type":"heatmap","yaxis":{"include_zero":false,"max":"100"}}}]}
form: {}
headers:
Accept:
- application/json
Content-Type:
- application/json
url: https://api.datadoghq.com/api/v1/dashboard
method: POST
response:
body: |
{"id":"ipf-9ci-s78","title":"tf-TestAccDatadogDashboardHeatMapFormulaAndFunction-local-1694629800","description":"Created using the Datadog provider in Terraform","author_handle":"[email protected]","author_name":null,"layout_type":"ordered","url":"/dashboard/ipf-9ci-s78/tf-testaccdatadogdashboardheatmapformulaandfunction-local-1694629800","is_read_only":true,"template_variables":[],"widgets":[{"definition":{"custom_links":[{"label":"Test Custom Link label","link":"https://app.datadoghq.com/dashboard/lists"},{"is_hidden":true,"link":"https://app.datadoghq.com/dashboard/lists","override_label":"logs"}],"events":[{"q":"env:prod","tags_execution":"and"}],"legend_size":"2","requests":[{"formulas":[{"formula":"query1"}],"queries":[{"data_source":"metrics","name":"query1","query":"avg:system.cpu.user{*}"}],"response_format":"timeseries","style":{"palette":"dog_classic"}}],"show_legend":true,"time":{"live_span":"1mo"},"title":"Avg of system.cpu.user over account:prod by app","title_align":"center","title_size":"16","type":"heatmap","yaxis":{"include_zero":false,"max":"100"}},"id":4307744427665324}],"notify_list":[],"created_at":"2023-09-13T18:30:03.195371+00:00","modified_at":"2023-09-13T18:30:03.195371+00:00","template_variable_presets":[],"tags":[]}
headers:
Content-Type:
- application/json
status: 200 OK
code: 200
duration: ""
- request:
body: ""
form: {}
headers:
Accept:
- application/json
url: https://api.datadoghq.com/api/v1/dashboard/ipf-9ci-s78
method: GET
response:
body: |
{"id":"ipf-9ci-s78","title":"tf-TestAccDatadogDashboardHeatMapFormulaAndFunction-local-1694629800","description":"Created using the Datadog provider in Terraform","author_handle":"[email protected]","author_name":null,"layout_type":"ordered","url":"/dashboard/ipf-9ci-s78/tf-testaccdatadogdashboardheatmapformulaandfunction-local-1694629800","is_read_only":true,"template_variables":[],"widgets":[{"definition":{"custom_links":[{"label":"Test Custom Link label","link":"https://app.datadoghq.com/dashboard/lists"},{"is_hidden":true,"link":"https://app.datadoghq.com/dashboard/lists","override_label":"logs"}],"events":[{"q":"env:prod","tags_execution":"and"}],"legend_size":"2","requests":[{"formulas":[{"formula":"query1"}],"queries":[{"data_source":"metrics","name":"query1","query":"avg:system.cpu.user{*}"}],"response_format":"timeseries","style":{"palette":"dog_classic"}}],"show_legend":true,"time":{"live_span":"1mo"},"title":"Avg of system.cpu.user over account:prod by app","title_align":"center","title_size":"16","type":"heatmap","yaxis":{"include_zero":false,"max":"100"}},"id":4307744427665324}],"notify_list":[],"created_at":"2023-09-13T18:30:03.195371+00:00","modified_at":"2023-09-13T18:30:03.195371+00:00","template_variable_presets":[],"tags":[]}
headers:
Content-Type:
- application/json
status: 200 OK
code: 200
duration: ""
- request:
body: ""
form: {}
headers:
Accept:
- application/json
url: https://api.datadoghq.com/api/v1/dashboard/ipf-9ci-s78
method: GET
response:
body: |
{"id":"ipf-9ci-s78","title":"tf-TestAccDatadogDashboardHeatMapFormulaAndFunction-local-1694629800","description":"Created using the Datadog provider in Terraform","author_handle":"[email protected]","author_name":null,"layout_type":"ordered","url":"/dashboard/ipf-9ci-s78/tf-testaccdatadogdashboardheatmapformulaandfunction-local-1694629800","is_read_only":true,"template_variables":[],"widgets":[{"definition":{"custom_links":[{"label":"Test Custom Link label","link":"https://app.datadoghq.com/dashboard/lists"},{"is_hidden":true,"link":"https://app.datadoghq.com/dashboard/lists","override_label":"logs"}],"events":[{"q":"env:prod","tags_execution":"and"}],"legend_size":"2","requests":[{"formulas":[{"formula":"query1"}],"queries":[{"data_source":"metrics","name":"query1","query":"avg:system.cpu.user{*}"}],"response_format":"timeseries","style":{"palette":"dog_classic"}}],"show_legend":true,"time":{"live_span":"1mo"},"title":"Avg of system.cpu.user over account:prod by app","title_align":"center","title_size":"16","type":"heatmap","yaxis":{"include_zero":false,"max":"100"}},"id":4307744427665324}],"notify_list":[],"created_at":"2023-09-13T18:30:03.195371+00:00","modified_at":"2023-09-13T18:30:03.195371+00:00","template_variable_presets":[],"tags":[]}
headers:
Content-Type:
- application/json
status: 200 OK
code: 200
duration: ""
- request:
body: ""
form: {}
headers:
Accept:
- application/json
url: https://api.datadoghq.com/api/v1/dashboard/ipf-9ci-s78
method: GET
response:
body: |
{"id":"ipf-9ci-s78","title":"tf-TestAccDatadogDashboardHeatMapFormulaAndFunction-local-1694629800","description":"Created using the Datadog provider in Terraform","author_handle":"[email protected]","author_name":null,"layout_type":"ordered","url":"/dashboard/ipf-9ci-s78/tf-testaccdatadogdashboardheatmapformulaandfunction-local-1694629800","is_read_only":true,"template_variables":[],"widgets":[{"definition":{"custom_links":[{"label":"Test Custom Link label","link":"https://app.datadoghq.com/dashboard/lists"},{"is_hidden":true,"link":"https://app.datadoghq.com/dashboard/lists","override_label":"logs"}],"events":[{"q":"env:prod","tags_execution":"and"}],"legend_size":"2","requests":[{"formulas":[{"formula":"query1"}],"queries":[{"data_source":"metrics","name":"query1","query":"avg:system.cpu.user{*}"}],"response_format":"timeseries","style":{"palette":"dog_classic"}}],"show_legend":true,"time":{"live_span":"1mo"},"title":"Avg of system.cpu.user over account:prod by app","title_align":"center","title_size":"16","type":"heatmap","yaxis":{"include_zero":false,"max":"100"}},"id":4307744427665324}],"notify_list":[],"created_at":"2023-09-13T18:30:03.195371+00:00","modified_at":"2023-09-13T18:30:03.195371+00:00","template_variable_presets":[],"tags":[]}
headers:
Content-Type:
- application/json
status: 200 OK
code: 200
duration: ""
- request:
body: ""
form: {}
headers:
Accept:
- application/json
url: https://api.datadoghq.com/api/v1/dashboard/ipf-9ci-s78
method: DELETE
response:
body: |
{"deleted_dashboard_id":"ipf-9ci-s78"}
headers:
Content-Type:
- application/json
status: 200 OK
code: 200
duration: ""
- request:
body: ""
form: {}
headers:
Accept:
- application/json
url: https://api.datadoghq.com/api/v1/dashboard/ipf-9ci-s78
method: GET
response:
body: '{"errors":["Dashboard with ID ipf-9ci-s78 not found"]}'
headers:
Content-Type:
- application/json
status: 404 Not Found
code: 404
duration: ""
106 changes: 97 additions & 9 deletions datadog/tests/resource_datadog_dashboard_heatmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,36 @@ resource "datadog_dashboard" "heatmap_dashboard" {
}
}
`
const datadogDashboardHeatMapConfigImport = `

var datadogDashboardHeatMapAsserts = []string{
"title = {{uniq}}",
"description = Created using the Datadog provider in Terraform",
"layout_type = ordered",
"is_read_only = true",
"widget.0.heatmap_definition.0.title = Avg of system.cpu.user over account:prod by app",
"widget.0.heatmap_definition.0.title_align = center",
"widget.0.heatmap_definition.0.title_size = 16",
"widget.0.heatmap_definition.0.request.0.q = avg:system.cpu.user{account:prod} by {app}",
"widget.0.heatmap_definition.0.request.0.style.0.palette = blue",
"widget.0.heatmap_definition.0.yaxis.0.include_zero = false",
"widget.0.heatmap_definition.0.yaxis.0.label =",
"widget.0.heatmap_definition.0.yaxis.0.max = 100",
"widget.0.heatmap_definition.0.yaxis.0.scale =",
"widget.0.heatmap_definition.0.yaxis.0.min =",
"widget.0.heatmap_definition.0.live_span = 1mo",
"widget.0.heatmap_definition.0.event.0.q = env:prod",
"widget.0.heatmap_definition.0.event.0.tags_execution = and",
"widget.0.heatmap_definition.0.show_legend = true",
"widget.0.heatmap_definition.0.legend_size = 2",
"widget.0.heatmap_definition.0.custom_link.# = 2",
"widget.0.heatmap_definition.0.custom_link.0.label = Test Custom Link label",
"widget.0.heatmap_definition.0.custom_link.0.link = https://app.datadoghq.com/dashboard/lists",
"widget.0.heatmap_definition.0.custom_link.1.override_label = logs",
"widget.0.heatmap_definition.0.custom_link.1.link = https://app.datadoghq.com/dashboard/lists",
"widget.0.heatmap_definition.0.custom_link.1.is_hidden = true",
}

const datadogDashboardHeatMapFormulaAndFunctionConfig = `
resource "datadog_dashboard" "heatmap_dashboard" {
title = "{{uniq}}"
description = "Created using the Datadog provider in Terraform"
Expand All @@ -62,11 +91,20 @@ resource "datadog_dashboard" "heatmap_dashboard" {
max = "100"
}
request {
q = "avg:system.cpu.user{account:prod} by {app}"
style {
palette = "blue"
}
}
formula {
formula_expression = "query1"
}
query {
metric_query {
data_source = "metrics"
name = "query1"
query = "avg:system.cpu.user{*}"
}
}
style {
palette = "dog_classic"
}
}
live_span = "1mo"
event {
Expand All @@ -79,21 +117,29 @@ resource "datadog_dashboard" "heatmap_dashboard" {
link = "https://app.datadoghq.com/dashboard/lists"
label = "Test Custom Link label"
}
custom_link {
link = "https://app.datadoghq.com/dashboard/lists"
is_hidden = true
override_label = "logs"
}
}
}
}
`

var datadogDashboardHeatMapAsserts = []string{
var datadogDashboardHeatMapFormulaAndFunctionAsserts = []string{
"title = {{uniq}}",
"description = Created using the Datadog provider in Terraform",
"layout_type = ordered",
"is_read_only = true",
"widget.0.heatmap_definition.0.title = Avg of system.cpu.user over account:prod by app",
"widget.0.heatmap_definition.0.title_align = center",
"widget.0.heatmap_definition.0.title_size = 16",
"widget.0.heatmap_definition.0.request.0.q = avg:system.cpu.user{account:prod} by {app}",
"widget.0.heatmap_definition.0.request.0.style.0.palette = blue",
"widget.0.heatmap_definition.0.request.0.formula.0.formula_expression = query1",
"widget.0.heatmap_definition.0.request.0.query.0.metric_query.0.data_source = metrics",
"widget.0.heatmap_definition.0.request.0.query.0.metric_query.0.name = query1",
"widget.0.heatmap_definition.0.request.0.query.0.metric_query.0.query = avg:system.cpu.user{*}",
"widget.0.heatmap_definition.0.request.0.style.0.palette = dog_classic",
"widget.0.heatmap_definition.0.yaxis.0.include_zero = false",
"widget.0.heatmap_definition.0.yaxis.0.label =",
"widget.0.heatmap_definition.0.yaxis.0.max = 100",
Expand All @@ -112,10 +158,52 @@ var datadogDashboardHeatMapAsserts = []string{
"widget.0.heatmap_definition.0.custom_link.1.is_hidden = true",
}

const datadogDashboardHeatMapConfigImport = `
resource "datadog_dashboard" "heatmap_dashboard" {
title = "{{uniq}}"
description = "Created using the Datadog provider in Terraform"
layout_type = "ordered"
is_read_only = "true"
widget {
heatmap_definition {
title = "Avg of system.cpu.user over account:prod by app"
title_align = "center"
title_size = "16"
yaxis {
max = "100"
}
request {
q = "avg:system.cpu.user{account:prod} by {app}"
style {
palette = "blue"
}
}
live_span = "1mo"
event {
q = "env:prod"
tags_execution = "and"
}
show_legend = true
legend_size = "2"
custom_link {
link = "https://app.datadoghq.com/dashboard/lists"
label = "Test Custom Link label"
}
}
}
}
`

func TestAccDatadogDashboardHeatMap(t *testing.T) {
testAccDatadogDashboardWidgetUtil(t, datadogDashboardHeatMapConfig, "datadog_dashboard.heatmap_dashboard", datadogDashboardHeatMapAsserts)
}

func TestAccDatadogDashboardHeatMapFormulaAndFunction(t *testing.T) {
testAccDatadogDashboardWidgetUtil(t, datadogDashboardHeatMapFormulaAndFunctionConfig, "datadog_dashboard.heatmap_dashboard", datadogDashboardHeatMapFormulaAndFunctionAsserts)
}

func TestAccDatadogDashboardHeatMap_import(t *testing.T) {
testAccDatadogDashboardWidgetUtilImport(t, datadogDashboardHeatMapConfigImport, "datadog_dashboard.heatmap_dashboard")
}
Loading

0 comments on commit e7f213c

Please sign in to comment.