provider/datadog: Various enhancements
- Don't drop wildcard if it's the only one. - Remove monitor resource, it's been replaced by metric_alert, outlier_alert and service_check - Refactor to be closer to the API; each resource creates exactly *one* resource, not 2, this removes much unneeded complexity. A warning threshold is now supported by the API. - Remove fuzzy resources like graph, and resources that used them for dashboard and screenboards. I'd welcome these resources, but the current state of Terraform and the Datadog API does not allow these to be implemented in a clean way. - Support multiple thresholds for metric alerts, remove notify argument.
This commit is contained in:
parent
1b84048aef
commit
f407eea3f7
|
@ -0,0 +1,23 @@
|
|||
package datadog
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/zorkian/go-datadog-api"
|
||||
)
|
||||
|
||||
// Config holds API and APP keys to authenticate to Datadog.
|
||||
type Config struct {
|
||||
APIKey string
|
||||
APPKey string
|
||||
}
|
||||
|
||||
// Client returns a new Datadog client.
|
||||
func (c *Config) Client() (*datadog.Client, error) {
|
||||
|
||||
client := datadog.NewClient(c.APIKey, c.APPKey)
|
||||
|
||||
log.Printf("[INFO] Datadog Client configured ")
|
||||
|
||||
return client, nil
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
package datadog
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
// Provider returns a terraform.ResourceProvider.
|
||||
func Provider() terraform.ResourceProvider {
|
||||
return &schema.Provider{
|
||||
Schema: map[string]*schema.Schema{
|
||||
|
@ -19,15 +22,25 @@ func Provider() terraform.ResourceProvider {
|
|||
DefaultFunc: schema.EnvDefaultFunc("DATADOG_APP_KEY", nil),
|
||||
},
|
||||
},
|
||||
|
||||
ResourcesMap: map[string]*schema.Resource{
|
||||
"datadog_monitor_metric": datadogMonitorResource(),
|
||||
"datadog_service_check": resourceDatadogServiceCheck(),
|
||||
"datadog_metric_alert": resourceDatadogMetricAlert(),
|
||||
"datadog_outlier_alert": resourceDatadogOutlierAlert(),
|
||||
},
|
||||
|
||||
ConfigureFunc: providerConfigure,
|
||||
}
|
||||
}
|
||||
|
||||
func providerConfigure(rd *schema.ResourceData) (interface{}, error) {
|
||||
apiKey := rd.Get("api_key").(string)
|
||||
appKey := rd.Get("app_key").(string)
|
||||
return map[string]string{"api_key": apiKey, "app_key": appKey}, nil
|
||||
// ProviderConfigure returns a configured client.
|
||||
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
|
||||
|
||||
config := Config{
|
||||
APIKey: d.Get("api_key").(string),
|
||||
APPKey: d.Get("app_key").(string),
|
||||
}
|
||||
|
||||
log.Println("[INFO] Initializing Datadog client")
|
||||
return config.Client()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package datadog
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
var testAccProviders map[string]terraform.ResourceProvider
|
||||
var testAccProvider *schema.Provider
|
||||
|
||||
func init() {
|
||||
testAccProvider = Provider().(*schema.Provider)
|
||||
testAccProviders = map[string]terraform.ResourceProvider{
|
||||
"datadog": testAccProvider,
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvider(t *testing.T) {
|
||||
if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvider_impl(t *testing.T) {
|
||||
var _ terraform.ResourceProvider = Provider()
|
||||
}
|
||||
|
||||
func testAccPreCheck(t *testing.T) {
|
||||
if v := os.Getenv("DATADOG_API_KEY"); v == "" {
|
||||
t.Fatal("DATADOG_API_KEY must be set for acceptance tests")
|
||||
}
|
||||
if v := os.Getenv("DATADOG_APP_KEY"); v == "" {
|
||||
t.Fatal("DATADOG_APP_KEY must be set for acceptance tests")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
package datadog
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/zorkian/go-datadog-api"
|
||||
)
|
||||
|
||||
// resourceDatadogMetricAlert is a Datadog monitor resource
|
||||
func resourceDatadogMetricAlert() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceDatadogMetricAlertCreate,
|
||||
Read: resourceDatadogGenericRead,
|
||||
Update: resourceDatadogMetricAlertUpdate,
|
||||
Delete: resourceDatadogGenericDelete,
|
||||
Exists: resourceDatadogGenericExists,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"metric": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"tags": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
"keys": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
"time_aggr": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"time_window": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"space_aggr": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"operator": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"message": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"thresholds": thresholdSchema(),
|
||||
|
||||
// Additional Settings
|
||||
"notify_no_data": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
},
|
||||
|
||||
"no_data_timeframe": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"renotify_interval": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// buildMonitorStruct returns a monitor struct
|
||||
func buildMetricAlertStruct(d *schema.ResourceData) *datadog.Monitor {
|
||||
name := d.Get("name").(string)
|
||||
message := d.Get("message").(string)
|
||||
timeAggr := d.Get("time_aggr").(string)
|
||||
timeWindow := d.Get("time_window").(string)
|
||||
spaceAggr := d.Get("space_aggr").(string)
|
||||
metric := d.Get("metric").(string)
|
||||
|
||||
// Tags are are no separate resource/gettable, so some trickery is needed
|
||||
var buffer bytes.Buffer
|
||||
if raw, ok := d.GetOk("tags"); ok {
|
||||
list := raw.([]interface{})
|
||||
length := (len(list) - 1)
|
||||
for i, v := range list {
|
||||
buffer.WriteString(fmt.Sprintf("%s", v))
|
||||
if i != length {
|
||||
buffer.WriteString(",")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
tagsParsed := buffer.String()
|
||||
|
||||
// Keys are used for multi alerts
|
||||
var b bytes.Buffer
|
||||
if raw, ok := d.GetOk("keys"); ok {
|
||||
list := raw.([]interface{})
|
||||
b.WriteString("by {")
|
||||
length := (len(list) - 1)
|
||||
for i, v := range list {
|
||||
b.WriteString(fmt.Sprintf("%s", v))
|
||||
if i != length {
|
||||
b.WriteString(",")
|
||||
}
|
||||
|
||||
}
|
||||
b.WriteString("}")
|
||||
}
|
||||
|
||||
keys := b.String()
|
||||
|
||||
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))
|
||||
|
||||
o := datadog.Options{
|
||||
NotifyNoData: d.Get("notify_no_data").(bool),
|
||||
NoDataTimeframe: d.Get("no_data_timeframe").(int),
|
||||
RenotifyInterval: d.Get("renotify_interval").(int),
|
||||
Thresholds: thresholds,
|
||||
}
|
||||
|
||||
m := datadog.Monitor{
|
||||
Type: "metric alert",
|
||||
Query: query,
|
||||
Name: name,
|
||||
Message: message,
|
||||
Options: o,
|
||||
}
|
||||
|
||||
return &m
|
||||
}
|
||||
|
||||
// resourceDatadogMetricAlertCreate creates a monitor.
|
||||
func resourceDatadogMetricAlertCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
|
||||
m := buildMetricAlertStruct(d)
|
||||
if err := monitorCreator(d, meta, m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceDatadogMetricAlertUpdate updates a monitor.
|
||||
func resourceDatadogMetricAlertUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
log.Printf("[DEBUG] running update.")
|
||||
|
||||
m := buildMetricAlertStruct(d)
|
||||
if err := monitorUpdater(d, meta, m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
package datadog
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/zorkian/go-datadog-api"
|
||||
)
|
||||
|
||||
func TestAccDatadogMetricAlert_Basic(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckDatadogMetricAlertDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccCheckDatadogMetricAlertConfigBasic,
|
||||
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", "metric", "aws.ec2.cpu"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_metric_alert.foo", "tags.0", "environment:foo"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_metric_alert.foo", "tags.1", "host:foo"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_metric_alert.foo", "tags.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_metric_alert.foo", "keys.0", "host"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_metric_alert.foo", "keys.#", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_metric_alert.foo", "time_aggr", "avg"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_metric_alert.foo", "time_window", "last_1h"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_metric_alert.foo", "space_aggr", "avg"),
|
||||
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)
|
||||
|
||||
if err := destroyHelper(s, client); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckDatadogMetricAlertExists(n string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*datadog.Client)
|
||||
if err := existsHelper(s, client); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
const testAccCheckDatadogMetricAlertConfigBasic = `
|
||||
resource "datadog_metric_alert" "foo" {
|
||||
name = "name for metric_alert foo"
|
||||
message = <<EOF
|
||||
{{#is_alert}}Metric alert foo is critical{{/is_alert}}
|
||||
{{#is_warning}}Metric alert foo is at warning level{{/is_warning}}
|
||||
{{#is_recovery}}Metric alert foo has recovered{{/is_recovery}}
|
||||
Notify: @hipchat-channel
|
||||
EOF
|
||||
|
||||
metric = "aws.ec2.cpu"
|
||||
tags = ["environment:foo", "host:foo"]
|
||||
keys = ["host"]
|
||||
|
||||
time_aggr = "avg" // avg, sum, max, min, change, or pct_change
|
||||
time_window = "last_1h" // last_#m (5, 10, 15, 30), last_#h (1, 2, 4), or last_1d
|
||||
space_aggr = "avg" // avg, sum, min, or max
|
||||
operator = ">" // <, <=, >, >=, ==, or !=
|
||||
|
||||
thresholds {
|
||||
ok = 0
|
||||
warning = 1
|
||||
critical = 2
|
||||
}
|
||||
|
||||
notify_no_data = false
|
||||
renotify_interval = 60
|
||||
}
|
||||
`
|
|
@ -1,235 +0,0 @@
|
|||
package datadog
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
const (
|
||||
monitorEndpoint = "https://app.datadoghq.com/api/v1/monitor"
|
||||
)
|
||||
|
||||
func datadogMonitorResource() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceMonitorCreate,
|
||||
Read: resourceMonitorRead,
|
||||
Update: resourceMonitorUpdate,
|
||||
Delete: resourceMonitorDelete,
|
||||
Exists: resourceMonitorExists,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
// Metric and Monitor settings
|
||||
"metric": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"metric_tags": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Default: "*",
|
||||
},
|
||||
"time_aggr": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"time_window": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"space_aggr": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"operator": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"message": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
// Alert Settings
|
||||
"warning": &schema.Schema{
|
||||
Type: schema.TypeMap,
|
||||
Required: true,
|
||||
},
|
||||
"critical": &schema.Schema{
|
||||
Type: schema.TypeMap,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
// Additional Settings
|
||||
"notify_no_data": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
},
|
||||
|
||||
"no_data_timeframe": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getIDFromResponse(h *http.Response) (string, error) {
|
||||
body, err := ioutil.ReadAll(h.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
h.Body.Close()
|
||||
log.Println(h)
|
||||
log.Println(string(body))
|
||||
v := map[string]interface{}{}
|
||||
err = json.Unmarshal(body, &v)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if id, ok := v["id"]; ok {
|
||||
return strconv.Itoa(int(id.(float64))), nil
|
||||
}
|
||||
return "", fmt.Errorf("error getting ID from response %s", h.Status)
|
||||
}
|
||||
|
||||
func marshalMetric(d *schema.ResourceData, typeStr string) ([]byte, error) {
|
||||
name := d.Get("name").(string)
|
||||
message := d.Get("message").(string)
|
||||
timeAggr := d.Get("time_aggr").(string)
|
||||
timeWindow := d.Get("time_window").(string)
|
||||
spaceAggr := d.Get("space_aggr").(string)
|
||||
metric := d.Get("metric").(string)
|
||||
tags := d.Get("metric_tags").(string)
|
||||
operator := d.Get("operator").(string)
|
||||
query := fmt.Sprintf("%s(%s):%s:%s{%s} %s %s", timeAggr, timeWindow, spaceAggr, metric, tags, operator, d.Get(fmt.Sprintf("%s.threshold", typeStr)))
|
||||
|
||||
log.Println(query)
|
||||
m := map[string]interface{}{
|
||||
"type": "metric alert",
|
||||
"query": query,
|
||||
"name": fmt.Sprintf("[%s] %s", typeStr, name),
|
||||
"message": fmt.Sprintf("%s %s", message, d.Get(fmt.Sprintf("%s.notify", typeStr))),
|
||||
"options": map[string]interface{}{
|
||||
"notify_no_data": d.Get("notify_no_data").(bool),
|
||||
"no_data_timeframe": d.Get("no_data_timeframe").(int),
|
||||
},
|
||||
}
|
||||
return json.Marshal(m)
|
||||
}
|
||||
|
||||
func authSuffix(meta interface{}) string {
|
||||
m := meta.(map[string]string)
|
||||
return fmt.Sprintf("?api_key=%s&application_key=%s", m["api_key"], m["app_key"])
|
||||
}
|
||||
|
||||
func resourceMonitorCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
warningBody, err := marshalMetric(d, "warning")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
criticalBody, err := marshalMetric(d, "critical")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resW, err := http.Post(fmt.Sprintf("%s%s", monitorEndpoint, authSuffix(meta)), "application/json", bytes.NewReader(warningBody))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating warning: %s", err.Error())
|
||||
}
|
||||
|
||||
resC, err := http.Post(fmt.Sprintf("%s%s", monitorEndpoint, authSuffix(meta)), "application/json", bytes.NewReader(criticalBody))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating critical: %s", err.Error())
|
||||
}
|
||||
|
||||
warningMonitorID, err := getIDFromResponse(resW)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
criticalMonitorID, err := getIDFromResponse(resC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.SetId(fmt.Sprintf("%s__%s", warningMonitorID, criticalMonitorID))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceMonitorDelete(d *schema.ResourceData, meta interface{}) (e error) {
|
||||
for _, v := range strings.Split(d.Id(), "__") {
|
||||
client := http.Client{}
|
||||
req, _ := http.NewRequest("DELETE", fmt.Sprintf("%s/%s%s", monitorEndpoint, v, authSuffix(meta)), nil)
|
||||
_, err := client.Do(req)
|
||||
e = err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func resourceMonitorExists(d *schema.ResourceData, meta interface{}) (b bool, e error) {
|
||||
b = true
|
||||
for _, v := range strings.Split(d.Id(), "__") {
|
||||
res, err := http.Get(fmt.Sprintf("%s/%s%s", monitorEndpoint, v, authSuffix(meta)))
|
||||
if err != nil {
|
||||
e = err
|
||||
continue
|
||||
}
|
||||
if res.StatusCode > 400 {
|
||||
b = false
|
||||
continue
|
||||
}
|
||||
b = b && true
|
||||
}
|
||||
if !b {
|
||||
e = resourceMonitorDelete(d, meta)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func resourceMonitorRead(d *schema.ResourceData, meta interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceMonitorUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
split := strings.Split(d.Id(), "__")
|
||||
warningID, criticalID := split[0], split[1]
|
||||
|
||||
warningBody, _ := marshalMetric(d, "warning")
|
||||
criticalBody, _ := marshalMetric(d, "critical")
|
||||
|
||||
client := http.Client{}
|
||||
|
||||
reqW, _ := http.NewRequest("PUT", fmt.Sprintf("%s/%s%s", monitorEndpoint, warningID, authSuffix(meta)), bytes.NewReader(warningBody))
|
||||
resW, err := client.Do(reqW)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error updating warning: %s", err.Error())
|
||||
}
|
||||
resW.Body.Close()
|
||||
if resW.StatusCode > 400 {
|
||||
return fmt.Errorf("error updating warning monitor: %s", resW.Status)
|
||||
}
|
||||
|
||||
reqC, _ := http.NewRequest("PUT", fmt.Sprintf("%s/%s%s", monitorEndpoint, criticalID, authSuffix(meta)), bytes.NewReader(criticalBody))
|
||||
resC, err := client.Do(reqC)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error updating critical: %s", err.Error())
|
||||
}
|
||||
resW.Body.Close()
|
||||
if resW.StatusCode > 400 {
|
||||
return fmt.Errorf("error updating critical monitor: %s", resC.Status)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
package datadog
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/zorkian/go-datadog-api"
|
||||
)
|
||||
|
||||
// resourceDatadogOutlierAlert is a Datadog monitor resource
|
||||
func resourceDatadogOutlierAlert() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceDatadogOutlierAlertCreate,
|
||||
Read: resourceDatadogGenericRead,
|
||||
Update: resourceDatadogOutlierAlertUpdate,
|
||||
Delete: resourceDatadogGenericDelete,
|
||||
Exists: resourceDatadogGenericExists,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"metric": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"tags": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
"keys": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
"time_aggr": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"time_window": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"space_aggr": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"message": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"threshold": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
// Additional Settings
|
||||
"notify_no_data": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
},
|
||||
|
||||
"no_data_timeframe": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"algorithm": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Default: "dbscan",
|
||||
},
|
||||
|
||||
"renotify_interval": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// buildMonitorStruct returns a monitor struct
|
||||
func buildOutlierAlertStruct(d *schema.ResourceData) *datadog.Monitor {
|
||||
name := d.Get("name").(string)
|
||||
message := d.Get("message").(string)
|
||||
timeAggr := d.Get("time_aggr").(string)
|
||||
timeWindow := d.Get("time_window").(string)
|
||||
spaceAggr := d.Get("space_aggr").(string)
|
||||
metric := d.Get("metric").(string)
|
||||
algorithm := d.Get("algorithm").(string)
|
||||
|
||||
// Tags are are no separate resource/gettable, so some trickery is needed
|
||||
var buffer bytes.Buffer
|
||||
if raw, ok := d.GetOk("tags"); ok {
|
||||
list := raw.([]interface{})
|
||||
length := (len(list) - 1)
|
||||
for i, v := range list {
|
||||
if length > 1 && v == "*" {
|
||||
log.Print(fmt.Sprintf("[DEBUG] found wildcard, this is not supported for this type: %s", v))
|
||||
continue
|
||||
}
|
||||
buffer.WriteString(fmt.Sprintf("%s", v))
|
||||
if i != length {
|
||||
buffer.WriteString(",")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
tagsParsed := buffer.String()
|
||||
|
||||
// Keys are used for multi alerts
|
||||
var b bytes.Buffer
|
||||
if raw, ok := d.GetOk("keys"); ok {
|
||||
list := raw.([]interface{})
|
||||
b.WriteString("by {")
|
||||
length := (len(list) - 1)
|
||||
for i, v := range list {
|
||||
b.WriteString(fmt.Sprintf("%s", v))
|
||||
if i != length {
|
||||
b.WriteString(",")
|
||||
}
|
||||
|
||||
}
|
||||
b.WriteString("}")
|
||||
}
|
||||
|
||||
keys := b.String()
|
||||
|
||||
query := fmt.Sprintf("%s(%s):outliers(%s:%s{%s} %s, '%s',%s) > 0", timeAggr,
|
||||
timeWindow,
|
||||
spaceAggr,
|
||||
metric,
|
||||
tagsParsed,
|
||||
keys,
|
||||
algorithm,
|
||||
d.Get("threshold"))
|
||||
|
||||
log.Print(fmt.Sprintf("[DEBUG] submitting query: %s", query))
|
||||
|
||||
o := datadog.Options{
|
||||
NotifyNoData: d.Get("notify_no_data").(bool),
|
||||
NoDataTimeframe: d.Get("no_data_timeframe").(int),
|
||||
RenotifyInterval: d.Get("renotify_interval").(int),
|
||||
}
|
||||
|
||||
m := datadog.Monitor{
|
||||
Type: "query alert",
|
||||
Query: query,
|
||||
Name: name,
|
||||
Message: message,
|
||||
Options: o,
|
||||
}
|
||||
|
||||
return &m
|
||||
}
|
||||
|
||||
// resourceDatadogOutlierAlertCreate creates a monitor.
|
||||
func resourceDatadogOutlierAlertCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
|
||||
m := buildOutlierAlertStruct(d)
|
||||
if err := monitorCreator(d, meta, m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceDatadogOutlierAlertUpdate updates a monitor.
|
||||
func resourceDatadogOutlierAlertUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
log.Printf("[DEBUG] running update.")
|
||||
|
||||
m := buildOutlierAlertStruct(d)
|
||||
if err := monitorUpdater(d, meta, m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package datadog
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/zorkian/go-datadog-api"
|
||||
)
|
||||
|
||||
func TestAccDatadogOutlierAlert_Basic(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckDatadogOutlierAlertDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccCheckDatadogOutlierAlertConfigBasic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckDatadogOutlierAlertExists("datadog_outlier_alert.foo"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_outlier_alert.foo", "name", "name for outlier_alert foo"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_outlier_alert.foo", "message", "description for outlier_alert foo @hipchat-name"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_outlier_alert.foo", "metric", "system.load.5"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_outlier_alert.foo", "tags.0", "environment:foo"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_outlier_alert.foo", "tags.1", "host:foo"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_outlier_alert.foo", "tags.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_outlier_alert.foo", "keys.0", "host"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_outlier_alert.foo", "keys.#", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_outlier_alert.foo", "time_aggr", "avg"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_outlier_alert.foo", "time_window", "last_1h"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_outlier_alert.foo", "space_aggr", "avg"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_outlier_alert.foo", "notify_no_data", "false"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_outlier_alert.foo", "algorithm", "mad"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_outlier_alert.foo", "renotify_interval", "60"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_outlier_alert.foo", "threshold", "2"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckDatadogOutlierAlertDestroy(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*datadog.Client)
|
||||
|
||||
if err := destroyHelper(s, client); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckDatadogOutlierAlertExists(n string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*datadog.Client)
|
||||
if err := existsHelper(s, client); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
const testAccCheckDatadogOutlierAlertConfigBasic = `
|
||||
resource "datadog_outlier_alert" "foo" {
|
||||
name = "name for outlier_alert foo"
|
||||
message = "description for outlier_alert foo @hipchat-name"
|
||||
|
||||
algorithm = "mad"
|
||||
|
||||
metric = "system.load.5"
|
||||
tags = ["environment:foo", "host:foo"]
|
||||
keys = ["host"]
|
||||
|
||||
time_aggr = "avg" // avg, sum, max, min, change, or pct_change
|
||||
time_window = "last_1h" // last_#m (5, 10, 15, 30), last_#h (1, 2, 4), or last_1d
|
||||
space_aggr = "avg" // avg, sum, min, or max
|
||||
|
||||
threshold = 2.0
|
||||
|
||||
notify_no_data = false
|
||||
renotify_interval = 60
|
||||
|
||||
}
|
||||
`
|
|
@ -0,0 +1,163 @@
|
|||
package datadog
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/zorkian/go-datadog-api"
|
||||
)
|
||||
|
||||
// resourceDatadogServiceCheck is a Datadog monitor resource
|
||||
func resourceDatadogServiceCheck() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceDatadogServiceCheckCreate,
|
||||
Read: resourceDatadogGenericRead,
|
||||
Update: resourceDatadogServiceCheckUpdate,
|
||||
Delete: resourceDatadogGenericDelete,
|
||||
Exists: resourceDatadogGenericExists,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"check": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"thresholds": thresholdSchema(),
|
||||
|
||||
"tags": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
"keys": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
"message": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
// Additional Settings
|
||||
"notify_no_data": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
},
|
||||
|
||||
"no_data_timeframe": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
},
|
||||
"renotify_interval": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// buildServiceCheckStruct returns a monitor struct
|
||||
func buildServiceCheckStruct(d *schema.ResourceData) *datadog.Monitor {
|
||||
log.Print("[DEBUG] building monitor struct")
|
||||
name := d.Get("name").(string)
|
||||
message := d.Get("message").(string)
|
||||
|
||||
// Tags are are no separate resource/gettable, so some trickery is needed
|
||||
var buffer bytes.Buffer
|
||||
if raw, ok := d.GetOk("tags"); ok {
|
||||
list := raw.([]interface{})
|
||||
length := (len(list) - 1)
|
||||
for i, v := range list {
|
||||
buffer.WriteString(fmt.Sprintf("\"%s\"", v))
|
||||
if i != length {
|
||||
buffer.WriteString(",")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
tagsParsed := buffer.String()
|
||||
|
||||
// Keys are used for multi alerts
|
||||
var b bytes.Buffer
|
||||
if raw, ok := d.GetOk("keys"); ok {
|
||||
list := raw.([]interface{})
|
||||
b.WriteString(".by(")
|
||||
length := (len(list) - 1)
|
||||
for i, v := range list {
|
||||
b.WriteString(fmt.Sprintf("\"%s\"", v))
|
||||
if i != length {
|
||||
b.WriteString(",")
|
||||
}
|
||||
|
||||
}
|
||||
b.WriteString(")")
|
||||
}
|
||||
|
||||
keys := b.String()
|
||||
|
||||
var monitorName string
|
||||
var query string
|
||||
|
||||
check := d.Get("check").(string)
|
||||
|
||||
// Examples queries
|
||||
// "http.can_connect".over("instance:buildeng_http","production").last(2).count_by_status()
|
||||
// "http.can_connect".over("*").by("host","instance","url").last(2).count_by_status()
|
||||
|
||||
checkCount, thresholds := getThresholds(d)
|
||||
|
||||
query = fmt.Sprintf("\"%s\".over(%s)%s.last(%s).count_by_status()", check, tagsParsed, keys, checkCount)
|
||||
log.Print(fmt.Sprintf("[DEBUG] submitting query: %s", query))
|
||||
monitorName = name
|
||||
|
||||
o := datadog.Options{
|
||||
NotifyNoData: d.Get("notify_no_data").(bool),
|
||||
NoDataTimeframe: d.Get("no_data_timeframe").(int),
|
||||
RenotifyInterval: d.Get("renotify_interval").(int),
|
||||
Thresholds: thresholds,
|
||||
}
|
||||
|
||||
m := datadog.Monitor{
|
||||
Type: "service check",
|
||||
Query: query,
|
||||
Name: monitorName,
|
||||
Message: message,
|
||||
Options: o,
|
||||
}
|
||||
|
||||
return &m
|
||||
}
|
||||
|
||||
// resourceDatadogServiceCheckCreate creates a monitor.
|
||||
func resourceDatadogServiceCheckCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
log.Print("[DEBUG] creating monitor")
|
||||
|
||||
m := buildServiceCheckStruct(d)
|
||||
if err := monitorCreator(d, meta, m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceDatadogServiceCheckUpdate updates a monitor.
|
||||
func resourceDatadogServiceCheckUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
log.Printf("[DEBUG] running update.")
|
||||
|
||||
m := buildServiceCheckStruct(d)
|
||||
if err := monitorUpdater(d, meta, m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package datadog
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/zorkian/go-datadog-api"
|
||||
)
|
||||
|
||||
func TestAccDatadogServiceCheck_Basic(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckDatadogServiceCheckDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccCheckDatadogServiceCheckConfigBasic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckDatadogServiceCheckExists("datadog_service_check.bar"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_service_check.bar", "name", "name for service check bar"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_service_check.bar", "message", "{{#is_alert}}Service check bar is critical"+
|
||||
"{{/is_alert}}\n{{#is_warning}}Service check bar is at warning "+
|
||||
"level{{/is_warning}}\n{{#is_recovery}}Service check bar has "+
|
||||
"recovered{{/is_recovery}}\nNotify: @hipchat-channel\n"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_service_check.bar", "check", "datadog.agent.up"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_service_check.bar", "notify_no_data", "false"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_service_check.bar", "tags.0", "environment:foo"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_service_check.bar", "tags.1", "host:bar"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_service_check.bar", "tags.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_service_check.bar", "keys.0", "foo"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_service_check.bar", "keys.1", "bar"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_service_check.bar", "keys.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_service_check.bar", "thresholds.ok", "0"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_service_check.bar", "thresholds.warning", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"datadog_service_check.bar", "thresholds.critical", "2"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckDatadogServiceCheckDestroy(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*datadog.Client)
|
||||
|
||||
if err := destroyHelper(s, client); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckDatadogServiceCheckExists(n string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*datadog.Client)
|
||||
if err := existsHelper(s, client); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
const testAccCheckDatadogServiceCheckConfigBasic = `
|
||||
resource "datadog_service_check" "bar" {
|
||||
name = "name for service check bar"
|
||||
message = <<EOF
|
||||
{{#is_alert}}Service check bar is critical{{/is_alert}}
|
||||
{{#is_warning}}Service check bar is at warning level{{/is_warning}}
|
||||
{{#is_recovery}}Service check bar has recovered{{/is_recovery}}
|
||||
Notify: @hipchat-channel
|
||||
EOF
|
||||
tags = ["environment:foo", "host:bar"]
|
||||
keys = ["foo", "bar"]
|
||||
check = "datadog.agent.up"
|
||||
|
||||
thresholds {
|
||||
ok = 0
|
||||
warning = 1
|
||||
critical = 2
|
||||
}
|
||||
|
||||
notify_no_data = false
|
||||
}
|
||||
`
|
|
@ -0,0 +1,138 @@
|
|||
package datadog
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/zorkian/go-datadog-api"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func thresholdSchema() *schema.Schema {
|
||||
return &schema.Schema{
|
||||
Type: schema.TypeMap,
|
||||
Required: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"ok": &schema.Schema{
|
||||
Type: schema.TypeFloat,
|
||||
Optional: true,
|
||||
},
|
||||
"warning": &schema.Schema{
|
||||
Type: schema.TypeFloat,
|
||||
Optional: true,
|
||||
},
|
||||
"critical": &schema.Schema{
|
||||
Type: schema.TypeFloat,
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getThresholds(d *schema.ResourceData) (string, datadog.ThresholdCount) {
|
||||
t := datadog.ThresholdCount{}
|
||||
|
||||
var threshold string
|
||||
|
||||
if r, ok := d.GetOk("thresholds.ok"); ok {
|
||||
t.Ok = json.Number(r.(string))
|
||||
}
|
||||
|
||||
if r, ok := d.GetOk("thresholds.warning"); ok {
|
||||
t.Warning = json.Number(r.(string))
|
||||
}
|
||||
|
||||
if r, ok := d.GetOk("thresholds.critical"); ok {
|
||||
threshold = r.(string)
|
||||
t.Critical = json.Number(r.(string))
|
||||
}
|
||||
|
||||
return threshold, t
|
||||
}
|
||||
|
||||
func resourceDatadogGenericDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*datadog.Client)
|
||||
|
||||
i, err := strconv.Atoi(d.Id())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = client.DeleteMonitor(i); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceDatadogGenericExists(d *schema.ResourceData, meta interface{}) (b bool, e error) {
|
||||
// Exists - This is called to verify a resource still exists. It is called prior to Read,
|
||||
// and lowers the burden of Read to be able to assume the resource exists.
|
||||
client := meta.(*datadog.Client)
|
||||
|
||||
// Workaround to handle upgrades from < 0.0.4
|
||||
if strings.Contains(d.Id(), "__") {
|
||||
return false, fmt.Errorf("Monitor ID contains __, which is pre v0.0.4 old behaviour.\n You have the following options:\n" +
|
||||
" * Run https://github.com/ojongerius/terraform-provider-datadog/blob/master/scripts/migration_helper.py to generate a new statefile and clean up monitors\n" +
|
||||
" * Mannualy fix this by deleting all your metric_check resources and recreate them, " +
|
||||
"or manually remove half of the resources and hack the state file.\n")
|
||||
}
|
||||
|
||||
i, err := strconv.Atoi(d.Id())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if _, err = client.GetMonitor(i); err != nil {
|
||||
if strings.Contains(err.Error(), "404 Not Found") {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func resourceDatadogGenericRead(d *schema.ResourceData, meta interface{}) error {
|
||||
// TODO: Add support for read function.
|
||||
/* Read - This is called to resync the local state with the remote state.
|
||||
Terraform guarantees that an existing ID will be set. This ID should be
|
||||
used to look up the resource. Any remote data should be updated into the
|
||||
local data. No changes to the remote resource are to be made.
|
||||
*/
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func monitorCreator(d *schema.ResourceData, meta interface{}, m *datadog.Monitor) error {
|
||||
client := meta.(*datadog.Client)
|
||||
|
||||
m, err := client.CreateMonitor(m)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error updating montor: %s", err.Error())
|
||||
}
|
||||
|
||||
d.SetId(strconv.Itoa(m.Id))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func monitorUpdater(d *schema.ResourceData, meta interface{}, m *datadog.Monitor) error {
|
||||
client := meta.(*datadog.Client)
|
||||
|
||||
i, err := strconv.Atoi(d.Id())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.Id = i
|
||||
|
||||
if err = client.UpdateMonitor(m); err != nil {
|
||||
return fmt.Errorf("error updating montor: %s", err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package datadog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/zorkian/go-datadog-api"
|
||||
)
|
||||
|
||||
func destroyHelper(s *terraform.State, client *datadog.Client) error {
|
||||
for _, r := range s.RootModule().Resources {
|
||||
i, _ := strconv.Atoi(r.Primary.ID)
|
||||
if _, err := client.GetMonitor(i); err != nil {
|
||||
if strings.Contains(err.Error(), "404 Not Found") {
|
||||
continue
|
||||
}
|
||||
return fmt.Errorf("Received an error retrieving monitor %s", err)
|
||||
}
|
||||
return fmt.Errorf("Monitor still exists")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func existsHelper(s *terraform.State, client *datadog.Client) error {
|
||||
for _, r := range s.RootModule().Resources {
|
||||
i, _ := strconv.Atoi(r.Primary.ID)
|
||||
if _, err := client.GetMonitor(i); err != nil {
|
||||
return fmt.Errorf("Received an error retrieving monitor %s", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue