Skip to content

Commit f407eea

Browse files
ojongeriusjen20
authored andcommitted
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.
1 parent 1b84048 commit f407eea

12 files changed

Lines changed: 1082 additions & 240 deletions
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package datadog
2+
3+
import (
4+
"log"
5+
6+
"github.com/zorkian/go-datadog-api"
7+
)
8+
9+
// Config holds API and APP keys to authenticate to Datadog.
10+
type Config struct {
11+
APIKey string
12+
APPKey string
13+
}
14+
15+
// Client returns a new Datadog client.
16+
func (c *Config) Client() (*datadog.Client, error) {
17+
18+
client := datadog.NewClient(c.APIKey, c.APPKey)
19+
20+
log.Printf("[INFO] Datadog Client configured ")
21+
22+
return client, nil
23+
}

builtin/providers/datadog/provider.go

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package datadog
22

33
import (
4+
"log"
5+
46
"github.com/hashicorp/terraform/helper/schema"
57
"github.com/hashicorp/terraform/terraform"
68
)
79

10+
// Provider returns a terraform.ResourceProvider.
811
func Provider() terraform.ResourceProvider {
912
return &schema.Provider{
1013
Schema: map[string]*schema.Schema{
@@ -19,15 +22,25 @@ func Provider() terraform.ResourceProvider {
1922
DefaultFunc: schema.EnvDefaultFunc("DATADOG_APP_KEY", nil),
2023
},
2124
},
25+
2226
ResourcesMap: map[string]*schema.Resource{
23-
"datadog_monitor_metric": datadogMonitorResource(),
27+
"datadog_service_check": resourceDatadogServiceCheck(),
28+
"datadog_metric_alert": resourceDatadogMetricAlert(),
29+
"datadog_outlier_alert": resourceDatadogOutlierAlert(),
2430
},
31+
2532
ConfigureFunc: providerConfigure,
2633
}
2734
}
2835

29-
func providerConfigure(rd *schema.ResourceData) (interface{}, error) {
30-
apiKey := rd.Get("api_key").(string)
31-
appKey := rd.Get("app_key").(string)
32-
return map[string]string{"api_key": apiKey, "app_key": appKey}, nil
36+
// ProviderConfigure returns a configured client.
37+
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
38+
39+
config := Config{
40+
APIKey: d.Get("api_key").(string),
41+
APPKey: d.Get("app_key").(string),
42+
}
43+
44+
log.Println("[INFO] Initializing Datadog client")
45+
return config.Client()
3346
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package datadog
2+
3+
import (
4+
"os"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform/helper/schema"
8+
"github.com/hashicorp/terraform/terraform"
9+
)
10+
11+
var testAccProviders map[string]terraform.ResourceProvider
12+
var testAccProvider *schema.Provider
13+
14+
func init() {
15+
testAccProvider = Provider().(*schema.Provider)
16+
testAccProviders = map[string]terraform.ResourceProvider{
17+
"datadog": testAccProvider,
18+
}
19+
}
20+
21+
func TestProvider(t *testing.T) {
22+
if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
23+
t.Fatalf("err: %s", err)
24+
}
25+
}
26+
27+
func TestProvider_impl(t *testing.T) {
28+
var _ terraform.ResourceProvider = Provider()
29+
}
30+
31+
func testAccPreCheck(t *testing.T) {
32+
if v := os.Getenv("DATADOG_API_KEY"); v == "" {
33+
t.Fatal("DATADOG_API_KEY must be set for acceptance tests")
34+
}
35+
if v := os.Getenv("DATADOG_APP_KEY"); v == "" {
36+
t.Fatal("DATADOG_APP_KEY must be set for acceptance tests")
37+
}
38+
}
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
package datadog
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"log"
7+
8+
"github.com/hashicorp/terraform/helper/schema"
9+
"github.com/zorkian/go-datadog-api"
10+
)
11+
12+
// resourceDatadogMetricAlert is a Datadog monitor resource
13+
func resourceDatadogMetricAlert() *schema.Resource {
14+
return &schema.Resource{
15+
Create: resourceDatadogMetricAlertCreate,
16+
Read: resourceDatadogGenericRead,
17+
Update: resourceDatadogMetricAlertUpdate,
18+
Delete: resourceDatadogGenericDelete,
19+
Exists: resourceDatadogGenericExists,
20+
21+
Schema: map[string]*schema.Schema{
22+
"name": &schema.Schema{
23+
Type: schema.TypeString,
24+
Required: true,
25+
},
26+
"metric": &schema.Schema{
27+
Type: schema.TypeString,
28+
Required: true,
29+
},
30+
"tags": &schema.Schema{
31+
Type: schema.TypeList,
32+
Optional: true,
33+
Elem: &schema.Schema{Type: schema.TypeString},
34+
},
35+
"keys": &schema.Schema{
36+
Type: schema.TypeList,
37+
Optional: true,
38+
Elem: &schema.Schema{Type: schema.TypeString},
39+
},
40+
"time_aggr": &schema.Schema{
41+
Type: schema.TypeString,
42+
Required: true,
43+
},
44+
"time_window": &schema.Schema{
45+
Type: schema.TypeString,
46+
Required: true,
47+
},
48+
"space_aggr": &schema.Schema{
49+
Type: schema.TypeString,
50+
Required: true,
51+
},
52+
"operator": &schema.Schema{
53+
Type: schema.TypeString,
54+
Required: true,
55+
},
56+
"message": &schema.Schema{
57+
Type: schema.TypeString,
58+
Required: true,
59+
},
60+
61+
"thresholds": thresholdSchema(),
62+
63+
// Additional Settings
64+
"notify_no_data": &schema.Schema{
65+
Type: schema.TypeBool,
66+
Optional: true,
67+
Default: true,
68+
},
69+
70+
"no_data_timeframe": &schema.Schema{
71+
Type: schema.TypeInt,
72+
Optional: true,
73+
},
74+
75+
"renotify_interval": &schema.Schema{
76+
Type: schema.TypeInt,
77+
Optional: true,
78+
Default: 0,
79+
},
80+
},
81+
}
82+
}
83+
84+
// buildMonitorStruct returns a monitor struct
85+
func buildMetricAlertStruct(d *schema.ResourceData) *datadog.Monitor {
86+
name := d.Get("name").(string)
87+
message := d.Get("message").(string)
88+
timeAggr := d.Get("time_aggr").(string)
89+
timeWindow := d.Get("time_window").(string)
90+
spaceAggr := d.Get("space_aggr").(string)
91+
metric := d.Get("metric").(string)
92+
93+
// Tags are are no separate resource/gettable, so some trickery is needed
94+
var buffer bytes.Buffer
95+
if raw, ok := d.GetOk("tags"); ok {
96+
list := raw.([]interface{})
97+
length := (len(list) - 1)
98+
for i, v := range list {
99+
buffer.WriteString(fmt.Sprintf("%s", v))
100+
if i != length {
101+
buffer.WriteString(",")
102+
}
103+
104+
}
105+
}
106+
107+
tagsParsed := buffer.String()
108+
109+
// Keys are used for multi alerts
110+
var b bytes.Buffer
111+
if raw, ok := d.GetOk("keys"); ok {
112+
list := raw.([]interface{})
113+
b.WriteString("by {")
114+
length := (len(list) - 1)
115+
for i, v := range list {
116+
b.WriteString(fmt.Sprintf("%s", v))
117+
if i != length {
118+
b.WriteString(",")
119+
}
120+
121+
}
122+
b.WriteString("}")
123+
}
124+
125+
keys := b.String()
126+
127+
threshold, thresholds := getThresholds(d)
128+
129+
operator := d.Get("operator").(string)
130+
query := fmt.Sprintf("%s(%s):%s:%s{%s} %s %s %s", timeAggr,
131+
timeWindow,
132+
spaceAggr,
133+
metric,
134+
tagsParsed,
135+
keys,
136+
operator,
137+
threshold)
138+
139+
log.Print(fmt.Sprintf("[DEBUG] submitting query: %s", query))
140+
141+
o := datadog.Options{
142+
NotifyNoData: d.Get("notify_no_data").(bool),
143+
NoDataTimeframe: d.Get("no_data_timeframe").(int),
144+
RenotifyInterval: d.Get("renotify_interval").(int),
145+
Thresholds: thresholds,
146+
}
147+
148+
m := datadog.Monitor{
149+
Type: "metric alert",
150+
Query: query,
151+
Name: name,
152+
Message: message,
153+
Options: o,
154+
}
155+
156+
return &m
157+
}
158+
159+
// resourceDatadogMetricAlertCreate creates a monitor.
160+
func resourceDatadogMetricAlertCreate(d *schema.ResourceData, meta interface{}) error {
161+
162+
m := buildMetricAlertStruct(d)
163+
if err := monitorCreator(d, meta, m); err != nil {
164+
return err
165+
}
166+
167+
return nil
168+
}
169+
170+
// resourceDatadogMetricAlertUpdate updates a monitor.
171+
func resourceDatadogMetricAlertUpdate(d *schema.ResourceData, meta interface{}) error {
172+
log.Printf("[DEBUG] running update.")
173+
174+
m := buildMetricAlertStruct(d)
175+
if err := monitorUpdater(d, meta, m); err != nil {
176+
return err
177+
}
178+
179+
return nil
180+
}

0 commit comments

Comments
 (0)