From 775a3f88262394c8f954df4954920a9ac1eb30d3 Mon Sep 17 00:00:00 2001 From: Kelvin Law Date: Sat, 23 Jan 2016 17:51:53 +1100 Subject: [PATCH] provider/datadog: Add `query` parameter to `metric_alert` `query` is used when it is specified by the user, if not `metric`/`tags`/`keys`/`time_aggr`/`window` is used instead. --- .../datadog/resource_datadog_metric_alert.go | 63 ++++++++++++------- .../resource_datadog_metric_alert_test.go | 59 +++++++++++++++++ 2 files changed, 101 insertions(+), 21 deletions(-) diff --git a/builtin/providers/datadog/resource_datadog_metric_alert.go b/builtin/providers/datadog/resource_datadog_metric_alert.go index a817d0313..d92591631 100644 --- a/builtin/providers/datadog/resource_datadog_metric_alert.go +++ b/builtin/providers/datadog/resource_datadog_metric_alert.go @@ -24,8 +24,9 @@ func resourceDatadogMetricAlert() *schema.Resource { Required: true, }, "metric": &schema.Schema{ - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"query"}, }, "tags": &schema.Schema{ Type: schema.TypeList, @@ -33,21 +34,25 @@ func resourceDatadogMetricAlert() *schema.Resource { Elem: &schema.Schema{Type: schema.TypeString}, }, "keys": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + ConflictsWith: []string{"query"}, }, "time_aggr": &schema.Schema{ - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"query"}, }, "time_window": &schema.Schema{ - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"query"}, }, "space_aggr": &schema.Schema{ - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"query"}, }, "operator": &schema.Schema{ Type: schema.TypeString, @@ -58,6 +63,14 @@ func resourceDatadogMetricAlert() *schema.Resource { Required: true, }, + // Optional Query for custom monitors + + "query": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"time_aggr", "time_window", "space_aggr", "metric", "keys"}, + }, + "thresholds": thresholdSchema(), // Additional Settings @@ -89,6 +102,7 @@ func buildMetricAlertStruct(d *schema.ResourceData) *datadog.Monitor { timeWindow := d.Get("time_window").(string) spaceAggr := d.Get("space_aggr").(string) metric := d.Get("metric").(string) + query := d.Get("query").(string) // Tags are are no separate resource/gettable, so some trickery is needed var buffer bytes.Buffer @@ -127,16 +141,23 @@ func buildMetricAlertStruct(d *schema.ResourceData) *datadog.Monitor { threshold, thresholds := getThresholds(d) operator := d.Get("operator").(string) - query := fmt.Sprintf("%s(%s):%s:%s{%s} %s %s %s", timeAggr, - timeWindow, - spaceAggr, - metric, - tagsParsed, - keys, - operator, - threshold) - log.Print(fmt.Sprintf("[DEBUG] submitting query: %s", query)) + var q string + + if query == "" { + q = fmt.Sprintf("%s(%s):%s:%s{%s} %s %s %s", timeAggr, + timeWindow, + spaceAggr, + metric, + tagsParsed, + keys, + operator, + threshold) + } else { + q = fmt.Sprintf("%s %s %s", query, operator, threshold) + } + + log.Print(fmt.Sprintf("[DEBUG] submitting query: %s", q)) o := datadog.Options{ NotifyNoData: d.Get("notify_no_data").(bool), @@ -147,7 +168,7 @@ func buildMetricAlertStruct(d *schema.ResourceData) *datadog.Monitor { m := datadog.Monitor{ Type: "metric alert", - Query: query, + Query: q, Name: name, Message: message, Options: o, diff --git a/builtin/providers/datadog/resource_datadog_metric_alert_test.go b/builtin/providers/datadog/resource_datadog_metric_alert_test.go index 6bfcb751c..8bf2d21d8 100644 --- a/builtin/providers/datadog/resource_datadog_metric_alert_test.go +++ b/builtin/providers/datadog/resource_datadog_metric_alert_test.go @@ -61,6 +61,43 @@ func TestAccDatadogMetricAlert_Basic(t *testing.T) { }) } +func TestAccDatadogMetricAlert_Query(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckDatadogMetricAlertDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckDatadogMetricAlertConfigQuery, + Check: resource.ComposeTestCheckFunc( + testAccCheckDatadogMetricAlertExists("datadog_metric_alert.foo"), + resource.TestCheckResourceAttr( + "datadog_metric_alert.foo", "name", "name for metric_alert foo"), + resource.TestCheckResourceAttr( + "datadog_metric_alert.foo", "message", "{{#is_alert}}Metric alert foo is critical"+ + "{{/is_alert}}\n{{#is_warning}}Metric alert foo is at warning "+ + "level{{/is_warning}}\n{{#is_recovery}}Metric alert foo has "+ + "recovered{{/is_recovery}}\nNotify: @hipchat-channel\n"), + resource.TestCheckResourceAttr( + "datadog_metric_alert.foo", "query", "avg(last_1h):avg:aws.ec2.cpu{environment:foo,host:foo} by {host}"), + resource.TestCheckResourceAttr( + "datadog_metric_alert.foo", "operator", ">"), + resource.TestCheckResourceAttr( + "datadog_metric_alert.foo", "notify_no_data", "false"), + resource.TestCheckResourceAttr( + "datadog_metric_alert.foo", "renotify_interval", "60"), + resource.TestCheckResourceAttr( + "datadog_metric_alert.foo", "thresholds.ok", "0"), + resource.TestCheckResourceAttr( + "datadog_metric_alert.foo", "thresholds.warning", "1"), + resource.TestCheckResourceAttr( + "datadog_metric_alert.foo", "thresholds.critical", "2"), + ), + }, + }, + }) +} + func testAccCheckDatadogMetricAlertDestroy(s *terraform.State) error { client := testAccProvider.Meta().(*datadog.Client) @@ -109,3 +146,25 @@ EOF renotify_interval = 60 } ` +const testAccCheckDatadogMetricAlertConfigQuery = ` +resource "datadog_metric_alert" "foo" { + name = "name for metric_alert foo" + message = <, >=, ==, or != + query = "avg(last_1h):avg:aws.ec2.cpu{environment:foo,host:foo} by {host}" + + thresholds { + ok = 0 + warning = 1 + critical = 2 + } + + notify_no_data = false + renotify_interval = 60 +} +`