From 950ae44ed09ea28454c9d3bd42917e0a40980c13 Mon Sep 17 00:00:00 2001 From: Keisuke Nitta Date: Wed, 29 May 2024 16:46:34 +0900 Subject: [PATCH 1/3] chore(deps): update github.com/mackerelio/mackerel-client-go from v0.31.0 to v.0.33.0 --- go.mod | 5 ++--- go.sum | 6 ++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 8f924c1..c0e39b0 100644 --- a/go.mod +++ b/go.mod @@ -4,10 +4,11 @@ go 1.21 require ( github.com/golangci/golangci-lint v1.50.1 + github.com/hashicorp/terraform-plugin-framework v1.8.0 github.com/hashicorp/terraform-plugin-go v0.23.0 github.com/hashicorp/terraform-plugin-mux v0.16.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0 - github.com/mackerelio/mackerel-client-go v0.31.0 + github.com/mackerelio/mackerel-client-go v0.33.0 ) require ( @@ -91,8 +92,6 @@ require ( github.com/hashicorp/logutils v1.0.0 // indirect github.com/hashicorp/terraform-exec v0.21.0 // indirect github.com/hashicorp/terraform-json v0.22.1 // indirect - github.com/hashicorp/terraform-plugin-framework v1.8.0 // indirect - github.com/hashicorp/terraform-plugin-framework-validators v0.12.0 // indirect github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect github.com/hashicorp/terraform-registry-address v0.2.3 // indirect github.com/hashicorp/terraform-svchost v0.1.1 // indirect diff --git a/go.sum b/go.sum index dfe6692..315974b 100644 --- a/go.sum +++ b/go.sum @@ -342,8 +342,6 @@ github.com/hashicorp/terraform-json v0.22.1 h1:xft84GZR0QzjPVWs4lRUwvTcPnegqlyS7 github.com/hashicorp/terraform-json v0.22.1/go.mod h1:JbWSQCLFSXFFhg42T7l9iJwdGXBYV8fmmD6o/ML4p3A= github.com/hashicorp/terraform-plugin-framework v1.8.0 h1:P07qy8RKLcoBkCrY2RHJer5AEvJnDuXomBgou6fD8kI= github.com/hashicorp/terraform-plugin-framework v1.8.0/go.mod h1:/CpTukO88PcL/62noU7cuyaSJ4Rsim+A/pa+3rUVufY= -github.com/hashicorp/terraform-plugin-framework-validators v0.12.0 h1:HOjBuMbOEzl7snOdOoUfE2Jgeto6JOjLVQ39Ls2nksc= -github.com/hashicorp/terraform-plugin-framework-validators v0.12.0/go.mod h1:jfHGE/gzjxYz6XoUwi/aYiiKrJDeutQNUtGQXkaHklg= github.com/hashicorp/terraform-plugin-go v0.23.0 h1:AALVuU1gD1kPb48aPQUjug9Ir/125t+AAurhqphJ2Co= github.com/hashicorp/terraform-plugin-go v0.23.0/go.mod h1:1E3Cr9h2vMlahWMbsSEcNrOCxovCZhOOIXjFHbjc/lQ= github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= @@ -422,8 +420,8 @@ github.com/leonklingele/grouper v1.1.0/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7s github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCEtOM= github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= -github.com/mackerelio/mackerel-client-go v0.31.0 h1:oUBwuJzZkvhSFf7C7zpOBej8jM0kITUz7eVMAINIfO4= -github.com/mackerelio/mackerel-client-go v0.31.0/go.mod h1:b4qVMQi+w4rxtKQIFycLWXNBtIi9d0r571RzYmg/aXo= +github.com/mackerelio/mackerel-client-go v0.33.0 h1:dMv0pyR3Exvtxxq3l7xzGF6D/5ky2Jgftzmp4aAoFYg= +github.com/mackerelio/mackerel-client-go v0.33.0/go.mod h1:b4qVMQi+w4rxtKQIFycLWXNBtIi9d0r571RzYmg/aXo= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI= From 98023ec53b63d288575e71fddd7a451ec0c15eb7 Mon Sep 17 00:00:00 2001 From: Keisuke Nitta Date: Wed, 15 May 2024 20:25:18 +0900 Subject: [PATCH 2/3] feat: added support for dashboard widgets with queries --- mackerel/data_source_mackerel_dashboard.go | 32 ++++ .../data_source_mackerel_dashboard_test.go | 91 +++++++++- mackerel/resource_mackerel_dashboard.go | 157 +++++++++++++----- mackerel/resource_mackerel_dashboard_test.go | 46 ++++- mackerel/structure_flattens.go | 18 ++ 5 files changed, 297 insertions(+), 47 deletions(-) diff --git a/mackerel/data_source_mackerel_dashboard.go b/mackerel/data_source_mackerel_dashboard.go index d0cc660..fb09812 100644 --- a/mackerel/data_source_mackerel_dashboard.go +++ b/mackerel/data_source_mackerel_dashboard.go @@ -112,6 +112,22 @@ var dashboardMetricDataResource = &schema.Resource{ }, }, }, + "query": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "query": { + Type: schema.TypeString, + Computed: true, + }, + "legend": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, }, } @@ -216,6 +232,22 @@ func dataSourceMackerelDashboard() *schema.Resource { }, }, }, + "query": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "query": { + Type: schema.TypeString, + Computed: true, + }, + "legend": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, "range": { Type: schema.TypeList, Computed: true, diff --git a/mackerel/data_source_mackerel_dashboard_test.go b/mackerel/data_source_mackerel_dashboard_test.go index f36f052..2694bfe 100644 --- a/mackerel/data_source_mackerel_dashboard_test.go +++ b/mackerel/data_source_mackerel_dashboard_test.go @@ -24,7 +24,7 @@ func TestAccDataSourceMackerelDashboardGraph(t *testing.T) { resource.TestCheckResourceAttr(dsName, "title", title), resource.TestCheckResourceAttr(dsName, "memo", "This dashboard is managed by Terraform."), resource.TestCheckResourceAttr(dsName, "url_path", rand), - resource.TestCheckResourceAttr(dsName, "graph.#", "2"), + resource.TestCheckResourceAttr(dsName, "graph.#", "3"), resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(dsName, "graph.0.title", "test graph role"), resource.TestCheckResourceAttr(dsName, "graph.0.role.0.role_fullname", fmt.Sprintf("tf-service-%s-include:tf-role-%s-include", rand, rand)), @@ -43,6 +43,15 @@ func TestAccDataSourceMackerelDashboardGraph(t *testing.T) { resource.TestCheckResourceAttr(dsName, "graph.1.layout.0.y", "32"), resource.TestCheckResourceAttr(dsName, "graph.1.layout.0.width", "10"), resource.TestCheckResourceAttr(dsName, "graph.1.layout.0.height", "8"), + resource.TestCheckResourceAttr(dsName, "graph.2.title", "test graph query"), + resource.TestCheckResourceAttr(dsName, "graph.2.query.0.query", "container.cpu.utilization{k8s.deployment.name=\"httpbin\"}"), + resource.TestCheckResourceAttr(dsName, "graph.2.query.0.legend", "{{k8s.node.name}}"), + resource.TestCheckResourceAttr(dsName, "graph.2.range.0.relative.0.period", "3600"), + resource.TestCheckResourceAttr(dsName, "graph.2.range.0.relative.0.offset", "1800"), + resource.TestCheckResourceAttr(dsName, "graph.2.layout.0.x", "0"), + resource.TestCheckResourceAttr(dsName, "graph.2.layout.0.y", "52"), + resource.TestCheckResourceAttr(dsName, "graph.2.layout.0.width", "10"), + resource.TestCheckResourceAttr(dsName, "graph.2.layout.0.height", "8"), ), ), }, @@ -79,6 +88,27 @@ func TestAccDataSourceMackerelDashboardValue(t *testing.T) { ), ), }, + { + Config: testAccDataSourceMackerelDashboardConfigValue_Query(rand, title), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(dsName, "id"), + resource.TestCheckResourceAttr(dsName, "title", title), + resource.TestCheckResourceAttr(dsName, "memo", "This dashboard is managed by Terraform."), + resource.TestCheckResourceAttr(dsName, "url_path", rand), + resource.TestCheckResourceAttr(dsName, "value.#", "1"), + resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dsName, "value.0.title", "test value query"), + resource.TestCheckResourceAttr(dsName, "value.0.metric.0.query.0.query", "avg(avg_over_time(container.cpu.utilization{k8s.deployment.name=\"httpbin\"}[1h]))"), + resource.TestCheckResourceAttr(dsName, "value.0.metric.0.query.0.legend", "average utilization"), + resource.TestCheckResourceAttr(dsName, "value.0.fraction_size", "10"), + resource.TestCheckResourceAttr(dsName, "value.0.suffix", "test query suffix"), + resource.TestCheckResourceAttr(dsName, "value.0.layout.0.x", "3"), + resource.TestCheckResourceAttr(dsName, "value.0.layout.0.y", "15"), + resource.TestCheckResourceAttr(dsName, "value.0.layout.0.width", "3"), + resource.TestCheckResourceAttr(dsName, "value.0.layout.0.height", "4"), + ), + ), + }, }, }) } @@ -204,6 +234,25 @@ resource "mackerel_dashboard" "foo" { height = 8 } } + graph { + title = "test graph query" + query { + query = "container.cpu.utilization{k8s.deployment.name=\"httpbin\"}" + legend = "{{k8s.node.name}}" + } + range { + relative { + period = 3600 + offset = 1800 + } + } + layout { + x = 0 + y = 52 + width = 10 + height = 8 + } + } } @@ -252,6 +301,46 @@ data "mackerel_dashboard" "foo" { `, rand, rand, title, rand) } +func testAccDataSourceMackerelDashboardConfigValue_Query(rand, title string) string { + return fmt.Sprintf(` +resource "mackerel_service" "include" { + name = "tf-service-%s-include" +} + +resource "mackerel_role" "include" { + service = mackerel_service.include.name + name = "tf-role-%s-include" +} + +resource "mackerel_dashboard" "foo" { + title = "%s" + memo = "This dashboard is managed by Terraform." + url_path = "%s" + value { + title = "test value query" + metric { + query { + query = "avg(avg_over_time(container.cpu.utilization{k8s.deployment.name=\"httpbin\"}[1h]))" + legend = "average utilization" + } + } + fraction_size = 10 + suffix = "test query suffix" + layout { + x = 3 + y = 15 + width = 3 + height = 4 + } + } +} + +data "mackerel_dashboard" "foo" { + id = mackerel_dashboard.foo.id +} +`, rand, rand, title, rand) +} + func testAccDataSourceMackerelDashboardConfigMarkdown(rand, title string) string { return fmt.Sprintf(` resource "mackerel_dashboard" "foo" { diff --git a/mackerel/resource_mackerel_dashboard.go b/mackerel/resource_mackerel_dashboard.go index 55faba5..4cc87f6 100644 --- a/mackerel/resource_mackerel_dashboard.go +++ b/mackerel/resource_mackerel_dashboard.go @@ -112,6 +112,22 @@ var dashboardMetricResource = &schema.Resource{ }, }, }, + "query": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "query": { + Type: schema.TypeString, + Required: true, + }, + "legend": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, }, } @@ -215,6 +231,23 @@ func resourceMackerelDashboard() *schema.Resource { }, }, }, + "query": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "query": { + Type: schema.TypeString, + Required: true, + }, + "legend": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, "range": { Type: schema.TypeList, Optional: true, @@ -368,40 +401,52 @@ func expandDashboardWidgets(d *schema.ResourceData) []mackerel.Widget { if v, ok := g["range"].([]interface{}); ok && len(v) > 0 { r = expandDashboardRange(v) } - if len(g["host"].([]interface{})) > 0 { + title := g["title"].(string) + layout := expandDashboardLayout(g["layout"].([]interface{})[0].(map[string]interface{})) + + if host := g["host"].([]interface{}); len(host) > 0 { + widgets = append(widgets, mackerel.Widget{ + Type: "graph", + Title: title, + Graph: expandDashboardGraphHost(host), + Range: r, + Layout: layout, + }) + } + if role := g["role"].([]interface{}); len(role) > 0 { widgets = append(widgets, mackerel.Widget{ Type: "graph", - Title: g["title"].(string), - Graph: expandDashboardGraphHost(g["host"].([]interface{})), + Title: title, + Graph: expandDashboardGraphRole(role), Range: r, - Layout: expandDashboardLayout(g["layout"].([]interface{})[0].(map[string]interface{})), + Layout: layout, }) } - if len(g["role"].([]interface{})) > 0 { + if service := g["service"].([]interface{}); len(service) > 0 { widgets = append(widgets, mackerel.Widget{ Type: "graph", - Title: g["title"].(string), - Graph: expandDashboardGraphRole(g["role"].([]interface{})), + Title: title, + Graph: expandDashboardGraphService(service), Range: r, - Layout: expandDashboardLayout(g["layout"].([]interface{})[0].(map[string]interface{})), + Layout: layout, }) } - if len(g["service"].([]interface{})) > 0 { + if expression := g["expression"].([]interface{}); len(expression) > 0 { widgets = append(widgets, mackerel.Widget{ Type: "graph", - Title: g["title"].(string), - Graph: expandDashboardGraphService(g["service"].([]interface{})), + Title: title, + Graph: expandDashboardGraphExpression(expression), Range: r, - Layout: expandDashboardLayout(g["layout"].([]interface{})[0].(map[string]interface{})), + Layout: layout, }) } - if len(g["expression"].([]interface{})) > 0 { + if query := g["query"].([]interface{}); len(query) > 0 { widgets = append(widgets, mackerel.Widget{ Type: "graph", - Title: g["title"].(string), - Graph: expandDashboardGraphExpression(g["expression"].([]interface{})), + Title: title, + Graph: expandDashboardGraphQuery(query), Range: r, - Layout: expandDashboardLayout(g["layout"].([]interface{})[0].(map[string]interface{})), + Layout: layout, }) } } @@ -410,37 +455,53 @@ func expandDashboardWidgets(d *schema.ResourceData) []mackerel.Widget { values := d.Get("value").([]interface{}) for _, value := range values { v := value.(map[string]interface{}) - host := v["metric"].([]interface{})[0].(map[string]interface{})["host"].([]interface{}) - service := v["metric"].([]interface{})[0].(map[string]interface{})["service"].([]interface{}) - expression := v["metric"].([]interface{})[0].(map[string]interface{})["expression"].([]interface{}) - if len(host) > 0 { + title := v["title"].(string) + metric := v["metric"].([]interface{})[0].(map[string]interface{}) + var fractionSize int64 + if fs, ok := v["fraction_size"].(int); ok { + fractionSize = int64(fs) + } + suffix := v["suffix"].(string) + layout := expandDashboardLayout(v["layout"].([]interface{})[0].(map[string]interface{})) + + if host := metric["host"].([]interface{}); len(host) > 0 { widgets = append(widgets, mackerel.Widget{ Type: "value", - Title: v["title"].(string), + Title: title, Metric: expandDashboardValueHost(host), - FractionSize: pointer(int64(v["fraction_size"].(int))), - Suffix: v["suffix"].(string), - Layout: expandDashboardLayout(v["layout"].([]interface{})[0].(map[string]interface{})), + FractionSize: &fractionSize, + Suffix: suffix, + Layout: layout, }) } - if len(service) > 0 { + if service := metric["service"].([]interface{}); len(service) > 0 { widgets = append(widgets, mackerel.Widget{ Type: "value", - Title: v["title"].(string), + Title: title, Metric: expandDashboardValueService(service), - FractionSize: pointer(int64(v["fraction_size"].(int))), - Suffix: v["suffix"].(string), - Layout: expandDashboardLayout(v["layout"].([]interface{})[0].(map[string]interface{})), + FractionSize: &fractionSize, + Suffix: suffix, + Layout: layout, }) } - if len(expression) > 0 { + if expression := metric["expression"].([]interface{}); len(expression) > 0 { widgets = append(widgets, mackerel.Widget{ Type: "value", - Title: v["title"].(string), + Title: title, Metric: expandDashboardValueExpression(expression), - FractionSize: pointer(int64(v["fraction_size"].(int))), - Suffix: v["suffix"].(string), - Layout: expandDashboardLayout(v["layout"].([]interface{})[0].(map[string]interface{})), + FractionSize: &fractionSize, + Suffix: suffix, + Layout: layout, + }) + } + if query := metric["query"].([]interface{}); len(query) > 0 { + widgets = append(widgets, mackerel.Widget{ + Type: "value", + Title: title, + Metric: expandDashboardValueQuery(query), + FractionSize: &fractionSize, + Suffix: suffix, + Layout: layout, }) } } @@ -473,10 +534,6 @@ func expandDashboardWidgets(d *schema.ResourceData) []mackerel.Widget { return widgets } -func pointer(x int64) *int64 { - return &x -} - func expandDashboardGraphHost(host []interface{}) mackerel.Graph { return mackerel.Graph{ Type: "host", @@ -509,6 +566,18 @@ func expandDashboardGraphExpression(expression []interface{}) mackerel.Graph { } } +func expandDashboardGraphQuery(query []interface{}) mackerel.Graph { + q := query[0].(map[string]interface{}) + g := mackerel.Graph{ + Type: "query", + Query: q["query"].(string), + } + if legend, ok := q["legend"].(string); ok { + g.Legend = legend + } + return g +} + func expandDashboardValueHost(host []interface{}) mackerel.Metric { return mackerel.Metric{ Type: "host", @@ -532,6 +601,18 @@ func expandDashboardValueExpression(expression []interface{}) mackerel.Metric { } } +func expandDashboardValueQuery(query []interface{}) mackerel.Metric { + q := query[0].(map[string]interface{}) + m := mackerel.Metric{ + Type: "query", + Query: q["query"].(string), + } + if legend, ok := q["legend"]; ok { + m.Legend = legend.(string) + } + return m +} + func expandDashboardRange(r []interface{}) mackerel.Range { if len(r[0].(map[string]interface{})["relative"].([]interface{})) > 0 { return mackerel.Range{ diff --git a/mackerel/resource_mackerel_dashboard_test.go b/mackerel/resource_mackerel_dashboard_test.go index 07c23b6..df650c9 100644 --- a/mackerel/resource_mackerel_dashboard_test.go +++ b/mackerel/resource_mackerel_dashboard_test.go @@ -47,7 +47,7 @@ func TestAccMackerelDashboardGraph(t *testing.T) { testAccCheckMackerelDashboardExists(resourceName), resource.TestCheckResourceAttr(resourceName, "title", titleUpdated), resource.TestCheckResourceAttr(resourceName, "url_path", rand), - resource.TestCheckResourceAttr(resourceName, "graph.#", "2"), + resource.TestCheckResourceAttr(resourceName, "graph.#", "3"), resource.TestCheckResourceAttr(resourceName, "graph.0.title", "test graph role"), resource.TestCheckResourceAttr(resourceName, "graph.0.role.0.role_fullname", fmt.Sprintf("tf-service-%s-include:tf-role-%s-include", rand, rand)), resource.TestCheckResourceAttr(resourceName, "graph.0.role.0.name", "loadavg5"), @@ -65,6 +65,15 @@ func TestAccMackerelDashboardGraph(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "graph.1.layout.0.y", "32"), resource.TestCheckResourceAttr(resourceName, "graph.1.layout.0.width", "10"), resource.TestCheckResourceAttr(resourceName, "graph.1.layout.0.height", "8"), + resource.TestCheckResourceAttr(resourceName, "graph.2.title", "test graph query"), + resource.TestCheckResourceAttr(resourceName, "graph.2.query.0.query", "container.cpu.utilization{k8s.deployment.name=\"httpbin\"}"), + resource.TestCheckResourceAttr(resourceName, "graph.2.query.0.legend", "{{k8s.node.name}}"), + resource.TestCheckResourceAttr(resourceName, "graph.2.range.0.relative.0.period", "3600"), + resource.TestCheckResourceAttr(resourceName, "graph.2.range.0.relative.0.offset", "1800"), + resource.TestCheckResourceAttr(resourceName, "graph.2.layout.0.x", "0"), + resource.TestCheckResourceAttr(resourceName, "graph.2.layout.0.y", "52"), + resource.TestCheckResourceAttr(resourceName, "graph.2.layout.0.width", "10"), + resource.TestCheckResourceAttr(resourceName, "graph.2.layout.0.height", "8"), ), }, // Test: Import @@ -119,11 +128,12 @@ func TestAccMackerelDashboardValue(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "url_path", rand), resource.TestCheckResourceAttr(resourceName, "value.#", "1"), resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "value.0.title", "test value expression"), - resource.TestCheckResourceAttr(resourceName, "value.0.metric.0.expression.0.expression", fmt.Sprintf("role(tf-service-%s-include:tf-role-%s-include, loadavg5)", rand, rand)), + resource.TestCheckResourceAttr(resourceName, "value.0.title", "test value query"), + resource.TestCheckResourceAttr(resourceName, "value.0.metric.0.query.0.query", "avg(avg_over_time(container.cpu.utilization{k8s.deployment.name=\"httpbin\"}[1h]))"), + resource.TestCheckResourceAttr(resourceName, "value.0.metric.0.query.0.legend", "average utilization"), resource.TestCheckResourceAttr(resourceName, "value.0.fraction_size", "10"), resource.TestCheckResourceAttr(resourceName, "value.0.suffix", "test suffix"), - resource.TestCheckResourceAttr(resourceName, "value.0.layout.0.x", "6"), + resource.TestCheckResourceAttr(resourceName, "value.0.layout.0.x", "0"), resource.TestCheckResourceAttr(resourceName, "value.0.layout.0.y", "15"), resource.TestCheckResourceAttr(resourceName, "value.0.layout.0.width", "10"), resource.TestCheckResourceAttr(resourceName, "value.0.layout.0.height", "7"), @@ -399,6 +409,25 @@ resource "mackerel_dashboard" "graph" { height = 8 } } + graph { + title = "test graph query" + query { + query = "container.cpu.utilization{k8s.deployment.name=\"httpbin\"}" + legend = "{{k8s.node.name}}" + } + range { + relative { + period = 3600 + offset = 1800 + } + } + layout { + x = 0 + y = 52 + width = 10 + height = 8 + } + } } `, rand, rand, title, rand) } @@ -454,16 +483,17 @@ resource "mackerel_dashboard" "value" { memo = "This dashboard is managed by Terraform." url_path = "%s" value { - title = "test value expression" + title = "test value query" metric { - expression { - expression = "role(${mackerel_service.include.name}:${mackerel_role.include.name}, loadavg5)" + query { + query = "avg(avg_over_time(container.cpu.utilization{k8s.deployment.name=\"httpbin\"}[1h]))" + legend = "average utilization" } } fraction_size = 10 suffix = "test suffix" layout { - x = 6 + x = 0 y = 15 width = 10 height = 7 diff --git a/mackerel/structure_flattens.go b/mackerel/structure_flattens.go index 57874f1..7df2af2 100644 --- a/mackerel/structure_flattens.go +++ b/mackerel/structure_flattens.go @@ -440,6 +440,17 @@ func flattenDashboard(dashboard *mackerel.Dashboard, d *schema.ResourceData) (di "range": []map[string][]map[string]int64{g_range}, "layout": []map[string]int{layout}, }) + case "query": + query := map[string]interface{}{ + "query": widget.Graph.Query, + "legend": widget.Graph.Legend, + } + graphs = append(graphs, map[string]interface{}{ + "title": widget.Title, + "query": []map[string]interface{}{query}, + "range": []map[string][]map[string]int64{g_range}, + "layout": []map[string]int{layout}, + }) } case "value": var metric map[string][]map[string]string @@ -464,6 +475,13 @@ func flattenDashboard(dashboard *mackerel.Dashboard, d *schema.ResourceData) (di "expression": widget.Metric.Expression, }}, } + case "query": + metric = map[string][]map[string]string{ + "query": {{ + "query": widget.Metric.Query, + "legend": widget.Metric.Legend, + }}, + } } values = append(values, map[string]interface{}{ "title": widget.Title, From 7d9fe6d6b812aa734aeb6da1db0ee82828842ffb Mon Sep 17 00:00:00 2001 From: Keisuke Nitta Date: Wed, 22 May 2024 12:13:15 +0900 Subject: [PATCH 3/3] docs: update for dashboards with queries --- docs/data-sources/dashboard.md | 6 ++++++ docs/resources/dashboard.md | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/docs/data-sources/dashboard.md b/docs/data-sources/dashboard.md index 4840690..38ab1fa 100644 --- a/docs/data-sources/dashboard.md +++ b/docs/data-sources/dashboard.md @@ -42,6 +42,9 @@ data "mackerel_dashboard" "this" { * `name` - The name of graph. * `expression` - The expression graph. * `expression` - The expression for graphs. + * `query` - The query graph. + * `query` - The PromQL-style query. + * `legend` - The query legend. * `range` - The display period for graphs. If unspecified, it will be variable and the display period can be changed from the controller displayed at the top of the dashboard. * `relative` - (The period from (current time + `offset` - `period`) to (current time + `offset`) is displayed. Negative values for `offset` can be used to display graphs for a specified period in the past. * `period` - Duration (seconds). @@ -65,6 +68,9 @@ data "mackerel_dashboard" "this" { * `name` - The name of metric. * `expression` - The expression metric. * `expression` - The expression for metric. + * `query` - The query metric. + * `query` - The PromQL-style query. + * `legend` - The query legend. * `fraction_size` - Number of decimal places to display (0-16). * `suffix` - Units to be displayed after the numerical value. * `layout` - The coordinates are specified with the upper left corner of the widget display area as the origin (x = 0, y = 0), with the x axis in the right direction and they axis in the down direction as the positive direction. diff --git a/docs/resources/dashboard.md b/docs/resources/dashboard.md index cb04a64..ba0d835 100644 --- a/docs/resources/dashboard.md +++ b/docs/resources/dashboard.md @@ -155,6 +155,9 @@ resource "mackerel_dashboard" "alert_status" { * `name` - (Required) The name of graph. * `expression` - The expression graph. * `expression` - (Required) The expression for graphs. +* `query` - The query graph. + * `query` - (Required) The PromQL-style query. + * `legend` - The query legend. * `range` - The display period for graphs. If unspecified, it will be variable and thedisplay period can be changed from the controller displayed at the top of the dashboard. * `relative` - (The period from (current time + `offset` - `period`) to (current time + `offset`) is displayed. Negative values for `offset` can be used to display graphs for a specified period in the past. * `period` - (Required) Duration (seconds). @@ -180,6 +183,9 @@ resource "mackerel_dashboard" "alert_status" { * `name` - (Required) The name of metric. * `expression` - The expression metric. * `expression` - (Required) The expression for metric. + * `query` - The query metric. + * `query` - (Required) The PromQL-style query. + * `legend` - The query legend. * `fraction_size` - Number of decimal places to display (0-16). * `suffix` - Units to be displayed after the numerical value. * `layout` - (Required) The coordinates are specified with the upper left corner of the widget display area as the origin (x = 0, y = 0), with the x axis in the right direction and they axis in the down direction as the positive direction.