github.com/richardbowden/terraform@v0.6.12-0.20160901200758-30ea22c25211/builtin/providers/datadog/resource_datadog_monitor.go (about) 1 package datadog 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "log" 7 "strconv" 8 "strings" 9 10 "github.com/hashicorp/terraform/helper/schema" 11 "github.com/zorkian/go-datadog-api" 12 ) 13 14 func resourceDatadogMonitor() *schema.Resource { 15 return &schema.Resource{ 16 Create: resourceDatadogMonitorCreate, 17 Read: resourceDatadogMonitorRead, 18 Update: resourceDatadogMonitorUpdate, 19 Delete: resourceDatadogMonitorDelete, 20 Exists: resourceDatadogMonitorExists, 21 Importer: &schema.ResourceImporter{ 22 State: resourceDatadogImport, 23 }, 24 25 Schema: map[string]*schema.Schema{ 26 "name": &schema.Schema{ 27 Type: schema.TypeString, 28 Required: true, 29 }, 30 "message": &schema.Schema{ 31 Type: schema.TypeString, 32 Required: true, 33 StateFunc: func(val interface{}) string { 34 return strings.TrimSpace(val.(string)) 35 }, 36 }, 37 "escalation_message": &schema.Schema{ 38 Type: schema.TypeString, 39 Optional: true, 40 StateFunc: func(val interface{}) string { 41 return strings.TrimSpace(val.(string)) 42 }, 43 }, 44 "query": &schema.Schema{ 45 Type: schema.TypeString, 46 Required: true, 47 StateFunc: func(val interface{}) string { 48 return strings.TrimSpace(val.(string)) 49 }, 50 }, 51 "type": &schema.Schema{ 52 Type: schema.TypeString, 53 Required: true, 54 }, 55 56 // Options 57 "thresholds": &schema.Schema{ 58 Type: schema.TypeMap, 59 Required: true, 60 Elem: &schema.Resource{ 61 Schema: map[string]*schema.Schema{ 62 "ok": &schema.Schema{ 63 Type: schema.TypeFloat, 64 Optional: true, 65 }, 66 "warning": &schema.Schema{ 67 Type: schema.TypeFloat, 68 Optional: true, 69 }, 70 "critical": &schema.Schema{ 71 Type: schema.TypeFloat, 72 Required: true, 73 }, 74 }, 75 }, 76 }, 77 "notify_no_data": &schema.Schema{ 78 Type: schema.TypeBool, 79 Optional: true, 80 Default: true, 81 }, 82 "no_data_timeframe": &schema.Schema{ 83 Type: schema.TypeInt, 84 Optional: true, 85 }, 86 "renotify_interval": &schema.Schema{ 87 Type: schema.TypeInt, 88 Optional: true, 89 }, 90 "notify_audit": &schema.Schema{ 91 Type: schema.TypeBool, 92 Optional: true, 93 }, 94 "timeout_h": &schema.Schema{ 95 Type: schema.TypeInt, 96 Optional: true, 97 }, 98 "require_full_window": &schema.Schema{ 99 Type: schema.TypeBool, 100 Optional: true, 101 }, 102 "locked": &schema.Schema{ 103 Type: schema.TypeBool, 104 Optional: true, 105 }, 106 // TODO should actually be map[string]int 107 "silenced": &schema.Schema{ 108 Type: schema.TypeMap, 109 Optional: true, 110 Elem: &schema.Schema{ 111 Type: schema.TypeString, 112 Elem: &schema.Schema{ 113 Type: schema.TypeInt}, 114 }, 115 }, 116 "include_tags": &schema.Schema{ 117 Type: schema.TypeBool, 118 Optional: true, 119 }, 120 "tags": &schema.Schema{ 121 Type: schema.TypeMap, 122 Optional: true, 123 Elem: &schema.Schema{ 124 Type: schema.TypeString, 125 Elem: &schema.Schema{ 126 Type: schema.TypeString}, 127 }, 128 }, 129 }, 130 } 131 } 132 133 func buildMonitorStruct(d *schema.ResourceData) *datadog.Monitor { 134 135 var thresholds datadog.ThresholdCount 136 137 if r, ok := d.GetOk("thresholds.ok"); ok { 138 thresholds.Ok = json.Number(r.(string)) 139 } 140 if r, ok := d.GetOk("thresholds.warning"); ok { 141 thresholds.Warning = json.Number(r.(string)) 142 } 143 if r, ok := d.GetOk("thresholds.critical"); ok { 144 thresholds.Critical = json.Number(r.(string)) 145 } 146 147 o := datadog.Options{ 148 Thresholds: thresholds, 149 } 150 if attr, ok := d.GetOk("silenced"); ok { 151 s := make(map[string]int) 152 // TODO: this is not very defensive, test if we can fail on non int input 153 for k, v := range attr.(map[string]interface{}) { 154 s[k], _ = strconv.Atoi(v.(string)) 155 } 156 o.Silenced = s 157 } 158 if attr, ok := d.GetOk("notify_no_data"); ok { 159 o.NotifyNoData = attr.(bool) 160 } 161 if attr, ok := d.GetOk("no_data_timeframe"); ok { 162 o.NoDataTimeframe = datadog.NoDataTimeframe(attr.(int)) 163 } 164 if attr, ok := d.GetOk("renotify_interval"); ok { 165 o.RenotifyInterval = attr.(int) 166 } 167 if attr, ok := d.GetOk("notify_audit"); ok { 168 o.NotifyAudit = attr.(bool) 169 } 170 if attr, ok := d.GetOk("timeout_h"); ok { 171 o.TimeoutH = attr.(int) 172 } 173 if attr, ok := d.GetOk("escalation_message"); ok { 174 o.EscalationMessage = attr.(string) 175 } 176 if attr, ok := d.GetOk("include_tags"); ok { 177 o.IncludeTags = attr.(bool) 178 } 179 if attr, ok := d.GetOk("require_full_window"); ok { 180 o.RequireFullWindow = attr.(bool) 181 } 182 if attr, ok := d.GetOk("locked"); ok { 183 o.Locked = attr.(bool) 184 } 185 186 m := datadog.Monitor{ 187 Type: d.Get("type").(string), 188 Query: d.Get("query").(string), 189 Name: d.Get("name").(string), 190 Message: d.Get("message").(string), 191 Options: o, 192 } 193 194 if attr, ok := d.GetOk("tags"); ok { 195 s := make([]string, 0) 196 for k, v := range attr.(map[string]interface{}) { 197 s = append(s, fmt.Sprintf("%s:%s", k, v.(string))) 198 } 199 m.Tags = s 200 } 201 202 return &m 203 } 204 205 func resourceDatadogMonitorExists(d *schema.ResourceData, meta interface{}) (b bool, e error) { 206 // Exists - This is called to verify a resource still exists. It is called prior to Read, 207 // and lowers the burden of Read to be able to assume the resource exists. 208 client := meta.(*datadog.Client) 209 210 i, err := strconv.Atoi(d.Id()) 211 if err != nil { 212 return false, err 213 } 214 215 if _, err = client.GetMonitor(i); err != nil { 216 if strings.Contains(err.Error(), "404 Not Found") { 217 return false, nil 218 } 219 return false, err 220 } 221 222 return true, nil 223 } 224 225 func resourceDatadogMonitorCreate(d *schema.ResourceData, meta interface{}) error { 226 227 client := meta.(*datadog.Client) 228 229 m := buildMonitorStruct(d) 230 m, err := client.CreateMonitor(m) 231 if err != nil { 232 return fmt.Errorf("error updating montor: %s", err.Error()) 233 } 234 235 d.SetId(strconv.Itoa(m.Id)) 236 237 return nil 238 } 239 240 func resourceDatadogMonitorRead(d *schema.ResourceData, meta interface{}) error { 241 client := meta.(*datadog.Client) 242 243 i, err := strconv.Atoi(d.Id()) 244 if err != nil { 245 return err 246 } 247 248 m, err := client.GetMonitor(i) 249 if err != nil { 250 return err 251 } 252 253 thresholds := make(map[string]string) 254 for k, v := range map[string]json.Number{ 255 "ok": m.Options.Thresholds.Ok, 256 "warning": m.Options.Thresholds.Warning, 257 "critical": m.Options.Thresholds.Critical, 258 } { 259 s := v.String() 260 if s != "" { 261 thresholds[k] = s 262 } 263 } 264 265 tags := make(map[string]string) 266 for _, s := range m.Tags { 267 tag := strings.Split(s, ":") 268 tags[tag[0]] = tag[1] 269 } 270 271 log.Printf("[DEBUG] monitor: %v", m) 272 d.Set("name", m.Name) 273 d.Set("message", m.Message) 274 d.Set("query", m.Query) 275 d.Set("type", m.Type) 276 d.Set("thresholds", thresholds) 277 d.Set("notify_no_data", m.Options.NotifyNoData) 278 d.Set("no_data_timeframe", m.Options.NoDataTimeframe) 279 d.Set("renotify_interval", m.Options.RenotifyInterval) 280 d.Set("notify_audit", m.Options.NotifyAudit) 281 d.Set("timeout_h", m.Options.TimeoutH) 282 d.Set("escalation_message", m.Options.EscalationMessage) 283 d.Set("silenced", m.Options.Silenced) 284 d.Set("include_tags", m.Options.IncludeTags) 285 d.Set("tags", tags) 286 d.Set("require_full_window", m.Options.RequireFullWindow) 287 d.Set("locked", m.Options.Locked) 288 289 return nil 290 } 291 292 func resourceDatadogMonitorUpdate(d *schema.ResourceData, meta interface{}) error { 293 client := meta.(*datadog.Client) 294 295 m := &datadog.Monitor{} 296 297 i, err := strconv.Atoi(d.Id()) 298 if err != nil { 299 return err 300 } 301 302 m.Id = i 303 if attr, ok := d.GetOk("name"); ok { 304 m.Name = attr.(string) 305 } 306 if attr, ok := d.GetOk("message"); ok { 307 m.Message = attr.(string) 308 } 309 if attr, ok := d.GetOk("query"); ok { 310 m.Query = attr.(string) 311 } 312 313 if attr, ok := d.GetOk("tags"); ok { 314 s := make([]string, 0) 315 for k, v := range attr.(map[string]interface{}) { 316 s = append(s, fmt.Sprintf("%s:%s", k, v.(string))) 317 } 318 m.Tags = s 319 } 320 321 o := datadog.Options{} 322 if attr, ok := d.GetOk("thresholds"); ok { 323 thresholds := attr.(map[string]interface{}) 324 if thresholds["ok"] != nil { 325 o.Thresholds.Ok = json.Number(thresholds["ok"].(string)) 326 } 327 if thresholds["warning"] != nil { 328 o.Thresholds.Warning = json.Number(thresholds["warning"].(string)) 329 } 330 if thresholds["critical"] != nil { 331 o.Thresholds.Critical = json.Number(thresholds["critical"].(string)) 332 } 333 } 334 335 if attr, ok := d.GetOk("notify_no_data"); ok { 336 o.NotifyNoData = attr.(bool) 337 } 338 if attr, ok := d.GetOk("no_data_timeframe"); ok { 339 o.NoDataTimeframe = datadog.NoDataTimeframe(attr.(int)) 340 } 341 if attr, ok := d.GetOk("renotify_interval"); ok { 342 o.RenotifyInterval = attr.(int) 343 } 344 if attr, ok := d.GetOk("notify_audit"); ok { 345 o.NotifyAudit = attr.(bool) 346 } 347 if attr, ok := d.GetOk("timeout_h"); ok { 348 o.TimeoutH = attr.(int) 349 } 350 if attr, ok := d.GetOk("escalation_message"); ok { 351 o.EscalationMessage = attr.(string) 352 } 353 if attr, ok := d.GetOk("silenced"); ok { 354 // TODO: this is not very defensive, test if we can fail non int input 355 s := make(map[string]int) 356 for k, v := range attr.(map[string]interface{}) { 357 s[k], _ = strconv.Atoi(v.(string)) 358 } 359 o.Silenced = s 360 } 361 if attr, ok := d.GetOk("include_tags"); ok { 362 o.IncludeTags = attr.(bool) 363 } 364 if attr, ok := d.GetOk("require_full_window"); ok { 365 o.RequireFullWindow = attr.(bool) 366 } 367 if attr, ok := d.GetOk("locked"); ok { 368 o.Locked = attr.(bool) 369 } 370 371 m.Options = o 372 373 if err = client.UpdateMonitor(m); err != nil { 374 return fmt.Errorf("error updating monitor: %s", err.Error()) 375 } 376 377 return resourceDatadogMonitorRead(d, meta) 378 } 379 380 func resourceDatadogMonitorDelete(d *schema.ResourceData, meta interface{}) error { 381 client := meta.(*datadog.Client) 382 383 i, err := strconv.Atoi(d.Id()) 384 if err != nil { 385 return err 386 } 387 388 if err = client.DeleteMonitor(i); err != nil { 389 return err 390 } 391 392 return nil 393 } 394 395 func resourceDatadogImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { 396 if err := resourceDatadogMonitorRead(d, meta); err != nil { 397 return nil, err 398 } 399 return []*schema.ResourceData{d}, nil 400 }