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  }