provider/datadog: Upgrade to Datadog API v2 (#12098)

* provider/datadog: Pulls v2 and removes v1 of library go-datadog-api.

    See https://github.com/zorkian/go-datadog-api/issues/56 for context.

    * Fixes bug in backoff implementation that decreased performance significantly.
    * Uses pointers for field types, providing support of distinguishing
        between if a value is set, or the default value for that type is
        effective.

* provider/datadog: Convert provider to use v2 of go-datadog-api.

* provider/datadog: Update vendored library.

* provider/datadog: Update dashboard resource to reflect API updates.
This commit is contained in:
Otto Jongerius 2017-02-21 01:48:32 +13:00 committed by Paul Stack
parent 6d5feaf526
commit 2310316666
33 changed files with 13091 additions and 958 deletions

View File

@ -3,7 +3,7 @@ package datadog
import (
"log"
"github.com/zorkian/go-datadog-api"
"gopkg.in/zorkian/go-datadog-api.v2"
)
// Config holds API and APP keys to authenticate to Datadog.

View File

@ -8,7 +8,7 @@ import (
"strings"
"github.com/hashicorp/terraform/helper/schema"
"github.com/zorkian/go-datadog-api"
"gopkg.in/zorkian/go-datadog-api.v2"
)
func resourceDatadogMonitor() *schema.Resource {
@ -137,18 +137,18 @@ func buildMonitorStruct(d *schema.ResourceData) *datadog.Monitor {
var thresholds datadog.ThresholdCount
if r, ok := d.GetOk("thresholds.ok"); ok {
thresholds.Ok = json.Number(r.(string))
thresholds.SetOk(json.Number(r.(string)))
}
if r, ok := d.GetOk("thresholds.warning"); ok {
thresholds.Warning = json.Number(r.(string))
thresholds.SetWarning(json.Number(r.(string)))
}
if r, ok := d.GetOk("thresholds.critical"); ok {
thresholds.Critical = json.Number(r.(string))
thresholds.SetCritical(json.Number(r.(string)))
}
o := datadog.Options{
Thresholds: thresholds,
NotifyNoData: d.Get("notify_no_data").(bool),
Thresholds: &thresholds,
NotifyNoData: datadog.Bool(d.Get("notify_no_data").(bool)),
}
if attr, ok := d.GetOk("silenced"); ok {
s := make(map[string]int)
@ -159,42 +159,42 @@ func buildMonitorStruct(d *schema.ResourceData) *datadog.Monitor {
o.Silenced = s
}
if attr, ok := d.GetOk("notify_no_data"); ok {
o.NotifyNoData = attr.(bool)
o.SetNotifyNoData(attr.(bool))
}
if attr, ok := d.GetOk("new_host_delay"); ok {
o.NewHostDelay = datadog.Int(attr.(int))
o.SetNewHostDelay(attr.(int))
}
if attr, ok := d.GetOk("no_data_timeframe"); ok {
o.NoDataTimeframe = datadog.NoDataTimeframe(attr.(int))
}
if attr, ok := d.GetOk("renotify_interval"); ok {
o.RenotifyInterval = attr.(int)
o.SetRenotifyInterval(attr.(int))
}
if attr, ok := d.GetOk("notify_audit"); ok {
o.NotifyAudit = attr.(bool)
o.SetNotifyAudit(attr.(bool))
}
if attr, ok := d.GetOk("timeout_h"); ok {
o.TimeoutH = attr.(int)
o.SetTimeoutH(attr.(int))
}
if attr, ok := d.GetOk("escalation_message"); ok {
o.EscalationMessage = attr.(string)
o.SetEscalationMessage(attr.(string))
}
if attr, ok := d.GetOk("include_tags"); ok {
o.IncludeTags = attr.(bool)
o.SetIncludeTags(attr.(bool))
}
if attr, ok := d.GetOk("require_full_window"); ok {
o.RequireFullWindow = attr.(bool)
o.SetRequireFullWindow(attr.(bool))
}
if attr, ok := d.GetOk("locked"); ok {
o.Locked = attr.(bool)
o.SetLocked(attr.(bool))
}
m := datadog.Monitor{
Type: d.Get("type").(string),
Query: d.Get("query").(string),
Name: d.Get("name").(string),
Message: d.Get("message").(string),
Options: o,
Type: datadog.String(d.Get("type").(string)),
Query: datadog.String(d.Get("query").(string)),
Name: datadog.String(d.Get("name").(string)),
Message: datadog.String(d.Get("message").(string)),
Options: &o,
}
if attr, ok := d.GetOk("tags"); ok {
@ -238,7 +238,7 @@ func resourceDatadogMonitorCreate(d *schema.ResourceData, meta interface{}) erro
return fmt.Errorf("error updating monitor: %s", err.Error())
}
d.SetId(strconv.Itoa(m.Id))
d.SetId(strconv.Itoa(m.GetId()))
return nil
}
@ -258,9 +258,9 @@ func resourceDatadogMonitorRead(d *schema.ResourceData, meta interface{}) error
thresholds := make(map[string]string)
for k, v := range map[string]json.Number{
"ok": m.Options.Thresholds.Ok,
"warning": m.Options.Thresholds.Warning,
"critical": m.Options.Thresholds.Critical,
"ok": m.Options.Thresholds.GetOk(),
"warning": m.Options.Thresholds.GetWarning(),
"critical": m.Options.Thresholds.GetCritical(),
} {
s := v.String()
if s != "" {
@ -274,24 +274,24 @@ func resourceDatadogMonitorRead(d *schema.ResourceData, meta interface{}) error
}
log.Printf("[DEBUG] monitor: %v", m)
d.Set("name", m.Name)
d.Set("message", m.Message)
d.Set("query", m.Query)
d.Set("type", m.Type)
d.Set("name", m.GetName())
d.Set("message", m.GetMessage())
d.Set("query", m.GetQuery())
d.Set("type", m.GetType())
d.Set("thresholds", thresholds)
d.Set("new_host_delay", m.Options.NewHostDelay)
d.Set("notify_no_data", m.Options.NotifyNoData)
d.Set("new_host_delay", m.Options.GetNewHostDelay())
d.Set("notify_no_data", m.Options.GetNotifyNoData())
d.Set("no_data_timeframe", m.Options.NoDataTimeframe)
d.Set("renotify_interval", m.Options.RenotifyInterval)
d.Set("notify_audit", m.Options.NotifyAudit)
d.Set("timeout_h", m.Options.TimeoutH)
d.Set("escalation_message", m.Options.EscalationMessage)
d.Set("renotify_interval", m.Options.GetRenotifyInterval())
d.Set("notify_audit", m.Options.GetNotifyAudit())
d.Set("timeout_h", m.Options.GetTimeoutH())
d.Set("escalation_message", m.Options.GetEscalationMessage())
d.Set("silenced", m.Options.Silenced)
d.Set("include_tags", m.Options.IncludeTags)
d.Set("include_tags", m.Options.GetIncludeTags())
d.Set("tags", tags)
d.Set("require_full_window", m.Options.RequireFullWindow)
d.Set("locked", m.Options.Locked)
d.Set("require_full_window", m.Options.GetRequireFullWindow()) // TODO Is this one of those options that we neeed to check?
d.Set("locked", m.Options.GetLocked())
return nil
}
@ -306,15 +306,15 @@ func resourceDatadogMonitorUpdate(d *schema.ResourceData, meta interface{}) erro
return err
}
m.Id = i
m.Id = datadog.Int(i)
if attr, ok := d.GetOk("name"); ok {
m.Name = attr.(string)
m.SetName(attr.(string))
}
if attr, ok := d.GetOk("message"); ok {
m.Message = attr.(string)
m.SetMessage(attr.(string))
}
if attr, ok := d.GetOk("query"); ok {
m.Query = attr.(string)
m.SetQuery(attr.(string))
}
if attr, ok := d.GetOk("tags"); ok {
@ -326,41 +326,42 @@ func resourceDatadogMonitorUpdate(d *schema.ResourceData, meta interface{}) erro
}
o := datadog.Options{
NotifyNoData: d.Get("notify_no_data").(bool),
NotifyNoData: datadog.Bool(d.Get("notify_no_data").(bool)),
}
if attr, ok := d.GetOk("thresholds"); ok {
thresholds := attr.(map[string]interface{})
o.Thresholds = &datadog.ThresholdCount{} // TODO: This is a little annoying..
if thresholds["ok"] != nil {
o.Thresholds.Ok = json.Number(thresholds["ok"].(string))
o.Thresholds.SetOk(json.Number(thresholds["ok"].(string)))
}
if thresholds["warning"] != nil {
o.Thresholds.Warning = json.Number(thresholds["warning"].(string))
o.Thresholds.SetWarning(json.Number(thresholds["warning"].(string)))
}
if thresholds["critical"] != nil {
o.Thresholds.Critical = json.Number(thresholds["critical"].(string))
o.Thresholds.SetCritical(json.Number(thresholds["critical"].(string)))
}
}
if attr, ok := d.GetOk("notify_no_data"); ok {
o.NotifyNoData = attr.(bool)
o.SetNotifyNoData(attr.(bool))
}
if attr, ok := d.GetOk("new_host_delay"); ok {
o.NewHostDelay = datadog.Int(attr.(int))
o.SetNewHostDelay(attr.(int))
}
if attr, ok := d.GetOk("no_data_timeframe"); ok {
o.NoDataTimeframe = datadog.NoDataTimeframe(attr.(int))
}
if attr, ok := d.GetOk("renotify_interval"); ok {
o.RenotifyInterval = attr.(int)
o.SetRenotifyInterval(attr.(int))
}
if attr, ok := d.GetOk("notify_audit"); ok {
o.NotifyAudit = attr.(bool)
o.SetNotifyAudit(attr.(bool))
}
if attr, ok := d.GetOk("timeout_h"); ok {
o.TimeoutH = attr.(int)
o.SetTimeoutH(attr.(int))
}
if attr, ok := d.GetOk("escalation_message"); ok {
o.EscalationMessage = attr.(string)
o.SetEscalationMessage(attr.(string))
}
if attr, ok := d.GetOk("silenced"); ok {
// TODO: this is not very defensive, test if we can fail non int input
@ -371,16 +372,16 @@ func resourceDatadogMonitorUpdate(d *schema.ResourceData, meta interface{}) erro
o.Silenced = s
}
if attr, ok := d.GetOk("include_tags"); ok {
o.IncludeTags = attr.(bool)
o.SetIncludeTags(attr.(bool))
}
if attr, ok := d.GetOk("require_full_window"); ok {
o.RequireFullWindow = attr.(bool)
o.SetRequireFullWindow(attr.(bool))
}
if attr, ok := d.GetOk("locked"); ok {
o.Locked = attr.(bool)
o.SetLocked(attr.(bool))
}
m.Options = o
m.Options = &o
if err = client.UpdateMonitor(m); err != nil {
return fmt.Errorf("error updating monitor: %s", err.Error())

View File

@ -8,7 +8,7 @@ import (
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"github.com/zorkian/go-datadog-api"
"gopkg.in/zorkian/go-datadog-api.v2"
)
func TestAccDatadogMonitor_Basic(t *testing.T) {

View File

@ -8,7 +8,7 @@ import (
"strings"
"github.com/hashicorp/terraform/helper/schema"
"github.com/zorkian/go-datadog-api"
"gopkg.in/zorkian/go-datadog-api.v2"
)
func resourceDatadogTimeboard() *schema.Resource {
@ -273,23 +273,23 @@ func appendConditionalFormats(datadogRequest *datadog.GraphDefinitionRequest, te
for _, t_ := range *terraformFormats {
t := t_.(map[string]interface{})
d := datadog.DashboardConditionalFormat{
Comparator: t["comparator"].(string),
Comparator: datadog.String(t["comparator"].(string)),
}
if palette, ok := t["palette"]; ok {
d.Palette = palette.(string)
if v, ok := t["palette"]; ok {
d.SetPalette(v.(string))
}
if customBgColor, ok := t["custom_bg_color"]; ok {
d.CustomBgColor = customBgColor.(string)
if v, ok := t["custom_bg_color"]; ok {
d.SetCustomBgColor(v.(string))
}
if customFgColor, ok := t["custom_fg_color"]; ok {
d.CustomFgColor = customFgColor.(string)
if v, ok := t["custom_fg_color"]; ok {
d.SetCustomFgColor(v.(string))
}
if value, ok := t["value"]; ok {
d.Value = json.Number(value.(string))
if v, ok := t["value"]; ok {
d.SetValue(json.Number(v.(string)))
}
datadogRequest.ConditionalFormats = append(datadogRequest.ConditionalFormats, d)
@ -301,9 +301,10 @@ func buildTemplateVariables(terraformTemplateVariables *[]interface{}) *[]datado
for i, t_ := range *terraformTemplateVariables {
t := t_.(map[string]interface{})
datadogTemplateVariables[i] = datadog.TemplateVariable{
Name: t["name"].(string),
Prefix: t["prefix"].(string),
Default: t["default"].(string)}
Name: datadog.String(t["name"].(string)),
Prefix: datadog.String(t["prefix"].(string)),
Default: datadog.String(t["default"].(string)),
}
}
return &datadogTemplateVariables
}
@ -312,58 +313,55 @@ func appendRequests(datadogGraph *datadog.Graph, terraformRequests *[]interface{
for _, t_ := range *terraformRequests {
t := t_.(map[string]interface{})
d := datadog.GraphDefinitionRequest{
Query: t["q"].(string),
Type: t["type"].(string),
Aggregator: t["aggregator"].(string),
Query: datadog.String(t["q"].(string)),
Type: datadog.String(t["type"].(string)),
Aggregator: datadog.String(t["aggregator"].(string)),
}
if stacked, ok := t["stacked"]; ok {
d.Stacked = stacked.(bool)
d.SetStacked(stacked.(bool))
}
if style, ok := t["style"]; ok {
s, _ := style.(map[string]interface{})
style := &datadog.GraphDefinitionRequestStyle{}
style := datadog.GraphDefinitionRequestStyle{}
if palette_, ok := s["palette"]; ok {
palette := palette_.(string)
style.Palette = &palette
if v, ok := s["palette"]; ok {
style.SetPalette(v.(string))
}
if width, ok := s["width"]; ok {
width := width.(string)
style.Width = &width
if v, ok := s["width"]; ok {
style.SetWidth(v.(string))
}
if type_, ok := s["type"]; ok {
style_type := type_.(string)
style.Type = &style_type
if v, ok := s["type"]; ok {
style.SetType(v.(string))
}
d.Style = style
d.SetStyle(style)
}
if changeType, ok := t["change_type"]; ok {
d.ChangeType = changeType.(string)
if v, ok := t["change_type"]; ok {
d.SetChangeType(v.(string))
}
if compareTo, ok := t["compare_to"]; ok {
d.CompareTo = compareTo.(string)
if v, ok := t["compare_to"]; ok {
d.SetCompareTo(v.(string))
}
if increaseGood, ok := t["increase_good"]; ok {
d.IncreaseGood = increaseGood.(bool)
if v, ok := t["increase_good"]; ok {
d.SetIncreaseGood(v.(bool))
}
if orderBy, ok := t["order_by"]; ok {
d.OrderBy = orderBy.(string)
if v, ok := t["order_by"]; ok {
d.SetOrderBy(v.(string))
}
if extraCol, ok := t["extra_col"]; ok {
d.ExtraCol = extraCol.(string)
if v, ok := t["extra_col"]; ok {
d.SetExtraCol(v.(string))
}
if orderDirection, ok := t["order_direction"]; ok {
d.OrderDirection = orderDirection.(string)
if v, ok := t["order_direction"]; ok {
d.SetOrderDirection(v.(string))
}
if terraformConditionalFormats, ok := t["conditional_format"]; ok {
formats := terraformConditionalFormats.([]interface{})
appendConditionalFormats(&d, &formats)
if v, ok := t["conditional_format"]; ok {
v_ := v.([]interface{})
appendConditionalFormats(&d, &v_)
}
datadogGraph.Definition.Requests = append(datadogGraph.Definition.Requests, d)
@ -372,12 +370,9 @@ func appendRequests(datadogGraph *datadog.Graph, terraformRequests *[]interface{
func appendEvents(datadogGraph *datadog.Graph, terraformEvents *[]interface{}) {
for _, t_ := range *terraformEvents {
d := struct {
Query string `json:"q"`
}{
t_.(string),
}
datadogGraph.Definition.Events = append(datadogGraph.Definition.Events, d)
datadogGraph.Definition.Events = append(datadogGraph.Definition.Events, datadog.GraphEvent{
Query: datadog.String(t_.(string)),
})
}
}
@ -385,11 +380,11 @@ func appendMarkers(datadogGraph *datadog.Graph, terraformMarkers *[]interface{})
for _, t_ := range *terraformMarkers {
t := t_.(map[string]interface{})
d := datadog.GraphDefinitionMarker{
Type: t["type"].(string),
Value: t["value"].(string),
Type: datadog.String(t["type"].(string)),
Value: datadog.String(t["value"].(string)),
}
if label, ok := t["label"]; ok {
d.Label = label.(string)
if v, ok := t["label"]; ok {
d.SetLabel(v.(string))
}
datadogGraph.Definition.Markers = append(datadogGraph.Definition.Markers, d)
}
@ -399,90 +394,90 @@ func buildGraphs(terraformGraphs *[]interface{}) *[]datadog.Graph {
datadogGraphs := make([]datadog.Graph, len(*terraformGraphs))
for i, t_ := range *terraformGraphs {
t := t_.(map[string]interface{})
datadogGraphs[i] = datadog.Graph{Title: t["title"].(string)}
datadogGraphs[i] = datadog.Graph{
Title: datadog.String(t["title"].(string)),
}
d := &datadogGraphs[i]
d.Definition.Viz = t["viz"].(string)
d.Definition = &datadog.GraphDefinition{}
d.Definition.SetViz(t["viz"].(string))
if yaxis_, ok := t["yaxis"]; ok {
yaxis := yaxis_.(map[string]interface{})
if min_, ok := yaxis["min"]; ok {
min, _ := strconv.ParseFloat(min_.(string), 64)
d.Definition.Yaxis.Min = &min
if v, ok := t["yaxis"]; ok {
yaxis := v.(map[string]interface{})
if v, ok := yaxis["min"]; ok {
min, _ := strconv.ParseFloat(v.(string), 64)
d.Definition.Yaxis.SetMin(min)
}
if max_, ok := yaxis["max"]; ok {
max, _ := strconv.ParseFloat(max_.(string), 64)
d.Definition.Yaxis.Max = &max
if v, ok := yaxis["max"]; ok {
max, _ := strconv.ParseFloat(v.(string), 64)
d.Definition.Yaxis.SetMax(max)
}
if scale_, ok := yaxis["scale"]; ok {
scale := scale_.(string)
d.Definition.Yaxis.Scale = &scale
if v, ok := yaxis["scale"]; ok {
d.Definition.Yaxis.SetScale(v.(string))
}
}
if autoscale, ok := t["autoscale"]; ok {
d.Definition.Autoscale = autoscale.(bool)
if v, ok := t["autoscale"]; ok {
d.Definition.SetAutoscale(v.(bool))
}
if textAlign, ok := t["text_align"]; ok {
d.Definition.TextAlign = textAlign.(string)
if v, ok := t["text_align"]; ok {
d.Definition.SetTextAlign(v.(string))
}
if precision, ok := t["precision"]; ok {
d.Definition.Precision = precision.(string)
d.Definition.SetPrecision(precision.(string))
}
if customUnit, ok := t["custom_unit"]; ok {
d.Definition.CustomUnit = customUnit.(string)
if v, ok := t["custom_unit"]; ok {
d.Definition.SetCustomUnit(v.(string))
}
if style, ok := t["style"]; ok {
s := style.(map[string]interface{})
style := struct {
Palette *string `json:"palette,omitempty"`
PaletteFlip *bool `json:"paletteFlip,omitempty"`
}{}
gs := datadog.Style{}
if palette_, ok := s["palette"]; ok {
palette := palette_.(string)
style.Palette = &palette
if v, ok := s["palette"]; ok {
gs.SetPalette(v.(string))
}
if paletteFlip_, ok := s["palette_flip"]; ok {
paletteFlip, _ := strconv.ParseBool(paletteFlip_.(string))
style.PaletteFlip = &paletteFlip
if v, ok := s["palette_flip"]; ok {
pf, _ := strconv.ParseBool(v.(string))
gs.SetPaletteFlip(pf)
}
d.Definition.Style = &style
d.Definition.SetStyle(gs)
}
if groups, ok := t["group"]; ok {
for _, g := range groups.(*schema.Set).List() {
if v, ok := t["group"]; ok {
for _, g := range v.(*schema.Set).List() {
d.Definition.Groups = append(d.Definition.Groups, g.(string))
}
}
if includeNoMetricHosts, ok := t["include_no_metric_hosts"]; ok {
d.Definition.IncludeNoMetricHosts = includeNoMetricHosts.(bool)
d.Definition.SetIncludeNoMetricHosts(includeNoMetricHosts.(bool))
}
if scopes, ok := t["scope"]; ok {
for _, s := range scopes.(*schema.Set).List() {
if v, ok := t["scope"]; ok {
for _, s := range v.(*schema.Set).List() {
d.Definition.Scopes = append(d.Definition.Groups, s.(string))
}
}
if includeUngroupedHosts, ok := t["include_ungrouped_hosts"]; ok {
d.Definition.IncludeUngroupedHosts = includeUngroupedHosts.(bool)
if v, ok := t["include_ungrouped_hosts"]; ok {
d.Definition.SetIncludeUngroupedHosts(v.(bool))
}
terraformMarkers := t["marker"].([]interface{})
appendMarkers(d, &terraformMarkers)
v := t["marker"].([]interface{})
appendMarkers(d, &v)
terraformEvents := t["events"].(*schema.Set).List()
appendEvents(d, &terraformEvents)
v = t["events"].(*schema.Set).List()
appendEvents(d, &v)
terraformRequests := t["request"].([]interface{})
appendRequests(d, &terraformRequests)
v = t["request"].([]interface{})
appendRequests(d, &v)
}
return &datadogGraphs
}
@ -499,10 +494,10 @@ func buildTimeboard(d *schema.ResourceData) (*datadog.Dashboard, error) {
terraformGraphs := d.Get("graph").([]interface{})
terraformTemplateVariables := d.Get("template_variable").([]interface{})
return &datadog.Dashboard{
Id: id,
Title: d.Get("title").(string),
Description: d.Get("description").(string),
ReadOnly: d.Get("read_only").(bool),
Id: datadog.Int(id),
Title: datadog.String(d.Get("title").(string)),
Description: datadog.String(d.Get("description").(string)),
ReadOnly: datadog.Bool(d.Get("read_only").(bool)),
Graphs: *buildGraphs(&terraformGraphs),
TemplateVariables: *buildTemplateVariables(&terraformTemplateVariables),
}, nil
@ -517,7 +512,7 @@ func resourceDatadogTimeboardCreate(d *schema.ResourceData, meta interface{}) er
if err != nil {
return fmt.Errorf("Failed to create timeboard using Datadog API: %s", err.Error())
}
d.SetId(strconv.Itoa(timeboard.Id))
d.SetId(strconv.Itoa(timeboard.GetId()))
return nil
}
@ -535,19 +530,19 @@ func resourceDatadogTimeboardUpdate(d *schema.ResourceData, meta interface{}) er
func appendTerraformGraphRequests(datadogRequests []datadog.GraphDefinitionRequest, requests *[]map[string]interface{}) {
for _, datadogRequest := range datadogRequests {
request := map[string]interface{}{}
request["q"] = datadogRequest.Query
request["stacked"] = datadogRequest.Stacked
request["type"] = datadogRequest.Type
if datadogRequest.Style != nil {
request["q"] = datadogRequest.GetQuery()
request["stacked"] = datadogRequest.GetStacked()
request["type"] = datadogRequest.GetType()
if v, ok := datadogRequest.GetStyleOk(); ok {
style := map[string]string{}
if datadogRequest.Style.Palette != nil {
style["palette"] = *datadogRequest.Style.Palette
if v, ok := v.GetPaletteOk(); ok {
style["palette"] = v
}
if datadogRequest.Style.Type != nil {
style["type"] = *datadogRequest.Style.Type
if v, ok := v.GetTypeOk(); ok {
style["type"] = v
}
if datadogRequest.Style.Width != nil {
style["width"] = *datadogRequest.Style.Width
if v, ok := v.GetWidthOk(); ok {
style["width"] = v
}
request["style"] = style
}
@ -563,12 +558,12 @@ func appendTerraformGraphRequests(datadogRequests []datadog.GraphDefinitionReque
conditionalFormats = append(conditionalFormats, conditionalFormat)
}
request["conditional_format"] = conditionalFormats
request["change_type"] = datadogRequest.ChangeType
request["order_direction"] = datadogRequest.OrderDirection
request["compare_to"] = datadogRequest.CompareTo
request["increase_good"] = datadogRequest.IncreaseGood
request["order_by"] = datadogRequest.OrderBy
request["extra_col"] = datadogRequest.ExtraCol
request["change_type"] = datadogRequest.GetChangeType()
request["order_direction"] = datadogRequest.GetOrderDirection()
request["compare_to"] = datadogRequest.GetCompareTo()
request["increase_good"] = datadogRequest.GetIncreaseGood()
request["order_by"] = datadogRequest.GetOrderBy()
request["extra_col"] = datadogRequest.GetExtraCol()
*requests = append(*requests, request)
}
@ -576,12 +571,12 @@ func appendTerraformGraphRequests(datadogRequests []datadog.GraphDefinitionReque
func buildTerraformGraph(datadog_graph datadog.Graph) map[string]interface{} {
graph := map[string]interface{}{}
graph["title"] = datadog_graph.Title
graph["title"] = datadog_graph.GetTitle()
definition := datadog_graph.Definition
graph["viz"] = definition.Viz
graph["viz"] = definition.GetViz()
events := []string{}
events := []*string{}
for _, datadog_event := range definition.Events {
events = append(events, datadog_event.Query)
}
@ -600,16 +595,16 @@ func buildTerraformGraph(datadog_graph datadog.Graph) map[string]interface{} {
yaxis := map[string]string{}
if definition.Yaxis.Min != nil {
yaxis["min"] = strconv.FormatFloat(*definition.Yaxis.Min, 'f', -1, 64)
if v, ok := definition.Yaxis.GetMinOk(); ok {
yaxis["min"] = strconv.FormatFloat(v, 'f', -1, 64)
}
if definition.Yaxis.Max != nil {
yaxis["max"] = strconv.FormatFloat(*definition.Yaxis.Max, 'f', -1, 64)
if v, ok := definition.Yaxis.GetMaxOk(); ok {
yaxis["max"] = strconv.FormatFloat(v, 'f', -1, 64)
}
if definition.Yaxis.Scale != nil {
yaxis["scale"] = *definition.Yaxis.Scale
if v, ok := definition.Yaxis.GetScaleOk(); ok {
yaxis["scale"] = v
}
graph["yaxis"] = yaxis
@ -619,13 +614,13 @@ func buildTerraformGraph(datadog_graph datadog.Graph) map[string]interface{} {
graph["precision"] = definition.Precision
graph["custom_unit"] = definition.CustomUnit
if definition.Style != nil {
if v, ok := definition.GetStyleOk(); ok {
style := map[string]string{}
if definition.Style.Palette != nil {
style["palette"] = *definition.Style.Palette
if v, ok := v.GetPaletteOk(); ok {
style["palette"] = v
}
if definition.Style.PaletteFlip != nil {
style["palette_flip"] = strconv.FormatBool(*definition.Style.PaletteFlip)
if v, ok := v.GetPaletteFlipOk(); ok {
style["palette_flip"] = strconv.FormatBool(v)
}
graph["style"] = style
}
@ -651,8 +646,8 @@ func resourceDatadogTimeboardRead(d *schema.ResourceData, meta interface{}) erro
return err
}
log.Printf("[DEBUG] timeboard: %v", timeboard)
d.Set("title", timeboard.Title)
d.Set("description", timeboard.Description)
d.Set("title", timeboard.GetTitle())
d.Set("description", timeboard.GetDescription())
graphs := []map[string]interface{}{}
for _, datadog_graph := range timeboard.Graphs {
@ -660,9 +655,9 @@ func resourceDatadogTimeboardRead(d *schema.ResourceData, meta interface{}) erro
}
d.Set("graph", graphs)
templateVariables := []map[string]string{}
templateVariables := []map[string]*string{}
for _, templateVariable := range timeboard.TemplateVariables {
tv := map[string]string{
tv := map[string]*string{
"name": templateVariable.Name,
"prefix": templateVariable.Prefix,
"default": templateVariable.Default,

View File

@ -8,7 +8,7 @@ import (
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"github.com/zorkian/go-datadog-api"
"gopkg.in/zorkian/go-datadog-api.v2"
)
const config1 = `

View File

@ -1,68 +0,0 @@
[![GoDoc](http://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/zorkian/go-datadog-api)
[![Build
status](https://travis-ci.org/zorkian/go-datadog-api.svg)](https://travis-ci.org/zorkian/go-datadog-api)
# Datadog API in Go
Hi!
This is a Go wrapper for the Datadog API. You should use this library if you need to interact
with the Datadog system. You can post metrics with it if you want, but this library is probably
mostly used for automating dashboards/alerting and retrieving data (events, etc).
The source API documentation is here: <http://docs.datadoghq.com/api/>
## USAGE
To use this project, include it in your code like:
``` go
import "github.com/zorkian/go-datadog-api"
```
Then, you can work with it:
``` go
client := datadog.NewClient("api key", "application key")
dash, err := client.GetDashboard(10880)
if err != nil {
log.Fatalf("fatal: %s\n", err)
}
log.Printf("dashboard %d: %s\n", dash.Id, dash.Title)
```
That's all; it's pretty easy to use. Check out the Godoc link for the
available API methods and, if you can't find the one you need,
let us know (or patches welcome)!
## DOCUMENTATION
Please see: <http://godoc.org/github.com/zorkian/go-datadog-api>
## BUGS/PROBLEMS/CONTRIBUTING
There are certainly some, but presently no known major bugs. If you do
find something that doesn't work as expected, please file an issue on
Github:
<https://github.com/zorkian/go-datadog-api/issues>
Thanks in advance! And, as always, patches welcome!
## DEVELOPMENT
* Run tests tests with `make test`.
* Integration tests can be run with `make testacc`. Run specific integration tests with `make testacc TESTARGS='-run=TestCreateAndDeleteMonitor'`
The acceptance tests require _DATADOG_API_KEY_ and _DATADOG_APP_KEY_ to be available
in your environment variables.
*Warning: the integrations tests will create and remove real resources in your Datadog account.*
## COPYRIGHT AND LICENSE
Please see the LICENSE file for the included license information.
Copyright 2013 by authors and contributors.

View File

@ -1,15 +0,0 @@
package datadog
// Int is a helper routine that allocates a new int value
// to store v and returns a pointer to it.
func Int(v int) *int { return &v }
// GetInt is a helper routine that returns a boolean representing
// if a value was set, and if so, dereferences the pointer to it.
func GetInt(v *int) (int, bool) {
if v != nil {
return *v, true
}
return 0, false
}

View File

@ -1,172 +0,0 @@
/*
* Datadog API for Go
*
* Please see the included LICENSE file for licensing information.
*
* Copyright 2013 by authors and contributors.
*/
package datadog
import (
"encoding/json"
"fmt"
)
// GraphDefinitionRequestStyle represents the graph style attributes
type GraphDefinitionRequestStyle struct {
Palette *string `json:"palette,omitempty"`
Width *string `json:"width,omitempty"`
Type *string `json:"type,omitempty"`
}
// GraphDefinitionRequest represents the requests passed into each graph.
type GraphDefinitionRequest struct {
Query string `json:"q"`
Stacked bool `json:"stacked"`
Aggregator string `json:"aggregator"`
ConditionalFormats []DashboardConditionalFormat `json:"conditional_formats,omitempty"`
Type string `json:"type,omitempty"`
Style *GraphDefinitionRequestStyle `json:"style,omitempty"`
// For change type graphs
ChangeType string `json:"change_type,omitempty"`
OrderDirection string `json:"order_dir,omitempty"`
CompareTo string `json:"compare_to,omitempty"`
IncreaseGood bool `json:"increase_good,omitempty"`
OrderBy string `json:"order_by,omitempty"`
ExtraCol string `json:"extra_col,omitempty"`
}
type GraphDefinitionMarker struct {
Type string `json:"type"`
Value string `json:"value"`
Label string `json:"label,omitempty"`
Val json.Number `json:"val,omitempty"`
Min json.Number `json:"min,omitempty"`
Max json.Number `json:"max,omitempty"`
}
// Graph represents a graph that might exist on a dashboard.
type Graph struct {
Title string `json:"title"`
Definition struct {
Viz string `json:"viz"`
Requests []GraphDefinitionRequest `json:"requests"`
Events []struct {
Query string `json:"q"`
} `json:"events"`
Markers []GraphDefinitionMarker `json:"markers,omitempty"`
// For timeseries type graphs
Yaxis struct {
Min *float64 `json:"min,omitempty"`
Max *float64 `json:"max,omitempty"`
Scale *string `json:"scale,omitempty"`
} `json:"yaxis,omitempty"`
// For query value type graphs
Autoscale bool `json:"austoscale,omitempty"`
TextAlign string `json:"text_align,omitempty"`
Precision string `json:"precision,omitempty"`
CustomUnit string `json:"custom_unit,omitempty"`
// For hostnamp type graphs
Style *struct {
Palette *string `json:"palette,omitempty"`
PaletteFlip *bool `json:"paletteFlip,omitempty"`
}
Groups []string `json:"group,omitempty"`
IncludeNoMetricHosts bool `json:"noMetricHosts,omitempty"`
Scopes []string `json:"scope,omitempty"`
IncludeUngroupedHosts bool `json:"noGroupHosts,omitempty"`
} `json:"definition"`
}
// Template variable represents a template variable that might exist on a dashboard
type TemplateVariable struct {
Name string `json:"name"`
Prefix string `json:"prefix"`
Default string `json:"default"`
}
// Dashboard represents a user created dashboard. This is the full dashboard
// struct when we load a dashboard in detail.
type Dashboard struct {
Id int `json:"id"`
Description string `json:"description"`
Title string `json:"title"`
Graphs []Graph `json:"graphs"`
TemplateVariables []TemplateVariable `json:"template_variables,omitempty"`
ReadOnly bool `json:"read_only"`
}
// DashboardLite represents a user created dashboard. This is the mini
// struct when we load the summaries.
type DashboardLite struct {
Id int `json:"id,string"` // TODO: Remove ',string'.
Resource string `json:"resource"`
Description string `json:"description"`
Title string `json:"title"`
}
// reqGetDashboards from /api/v1/dash
type reqGetDashboards struct {
Dashboards []DashboardLite `json:"dashes"`
}
// reqGetDashboard from /api/v1/dash/:dashboard_id
type reqGetDashboard struct {
Resource string `json:"resource"`
Url string `json:"url"`
Dashboard Dashboard `json:"dash"`
}
type DashboardConditionalFormat struct {
Palette string `json:"palette,omitempty"`
Comparator string `json:"comparator,omitempty"`
CustomBgColor string `json:"custom_bg_color,omitempty"`
Value json.Number `json:"value,omitempty"`
Inverted bool `json:"invert,omitempty"`
CustomFgColor string `json:"custom_fg_color,omitempty"`
}
// GetDashboard returns a single dashboard created on this account.
func (client *Client) GetDashboard(id int) (*Dashboard, error) {
var out reqGetDashboard
if err := client.doJsonRequest("GET", fmt.Sprintf("/v1/dash/%d", id), nil, &out); err != nil {
return nil, err
}
return &out.Dashboard, nil
}
// GetDashboards returns a list of all dashboards created on this account.
func (client *Client) GetDashboards() ([]DashboardLite, error) {
var out reqGetDashboards
if err := client.doJsonRequest("GET", "/v1/dash", nil, &out); err != nil {
return nil, err
}
return out.Dashboards, nil
}
// DeleteDashboard deletes a dashboard by the identifier.
func (client *Client) DeleteDashboard(id int) error {
return client.doJsonRequest("DELETE", fmt.Sprintf("/v1/dash/%d", id), nil, nil)
}
// CreateDashboard creates a new dashboard when given a Dashboard struct. Note
// that the Id, Resource, Url and similar elements are not used in creation.
func (client *Client) CreateDashboard(dash *Dashboard) (*Dashboard, error) {
var out reqGetDashboard
if err := client.doJsonRequest("POST", "/v1/dash", dash, &out); err != nil {
return nil, err
}
return &out.Dashboard, nil
}
// UpdateDashboard in essence takes a Dashboard struct and persists it back to
// the server. Use this if you've updated your local and need to push it back.
func (client *Client) UpdateDashboard(dash *Dashboard) error {
return client.doJsonRequest("PUT", fmt.Sprintf("/v1/dash/%d", dash.Id),
dash, nil)
}

View File

@ -1,26 +0,0 @@
package datadog
import (
"fmt"
"time"
)
type RateLimit struct {
Limit int
Period time.Duration
Remaining int
Reset time.Duration
}
func (r *RateLimit) Error() string {
return fmt.Sprintf("Rate limiting: Limit %d, Period %d, Remaining %d, Reset in %d", r.Limit, r.Period, r.Remaining, r.Reset)
}
func NewRateLimit(limit, period, remaining, reset int) *RateLimit {
return &RateLimit{
Limit: limit,
Period: time.Duration(period) * time.Second,
Remaining: remaining,
Reset: time.Duration(reset) * time.Second,
}
}

View File

@ -1,287 +0,0 @@
package datadog
type TextSize struct {
Size int
Auto bool
}
type TileDef struct {
Events []TileDefEvent `json:"events,omitempty"`
Markers []TimeseriesMarker `json:"markers,omitempty"`
Requests []TimeseriesRequest `json:"requests,omitempty"`
Viz string `json:"viz,omitempty"`
}
type TimeseriesRequest struct {
Query string `json:"q,omitempty"`
Type string `json:"type,omitempty"`
ConditionalFormats []ConditionalFormat `json:"conditional_formats,omitempty"`
Style TimeseriesRequestStyle `json:"style,omitempty"`
}
type TimeseriesRequestStyle struct {
Palette string `json:"palette,omitempty"`
}
type TimeseriesMarker struct {
Label string `json:"label,omitempty"`
Type string `json:"type,omitempty"`
Value string `json:"value,omitempty"`
}
type TileDefEvent struct {
Query string `json:"q"`
}
type AlertValueWidget struct {
TitleSize int `json:"title_size,omitempty"`
Title bool `json:"title,omitempty"`
TitleAlign string `json:"title_align,omitempty"`
TextAlign string `json:"text_align,omitempty"`
TitleText string `json:"title_text,omitempty"`
Precision int `json:"precision,omitempty"`
AlertId int `json:"alert_id,omitempty"`
Timeframe string `json:"timeframe,omitempty"`
AddTimeframe bool `json:"add_timeframe,omitempty"`
Y int `json:"y,omitempty"`
X int `json:"x,omitempty"`
TextSize string `json:"text_size,omitempty"`
Height int `json:"height,omitempty"`
Width int `json:"width,omitempty"`
Type string `json:"type,omitempty"`
Unit string `json:"unit,omitempty"`
}
type ChangeWidget struct {
TitleSize int `json:"title_size,omitempty"`
Title bool `json:"title,omitempty"`
TitleAlign string `json:"title_align,omitempty"`
TitleText string `json:"title_text,omitempty"`
Height int `json:"height,omitempty"`
Width int `json:"width,omitempty"`
X int `json:"y,omitempty"`
Y int `json:"x,omitempty"`
Aggregator string `json:"aggregator,omitempty"`
TileDef TileDef `json:"tile_def,omitempty"`
}
type GraphWidget struct {
TitleSize int `json:"title_size,omitempty"`
Title bool `json:"title,omitempty"`
TitleAlign string `json:"title_align,omitempty"`
TitleText string `json:"title_text,omitempty"`
Height int `json:"height,omitempty"`
Width int `json:"width,omitempty"`
X int `json:"y,omitempty"`
Y int `json:"x,omitempty"`
Type string `json:"type,omitempty"`
Timeframe string `json:"timeframe,omitempty"`
LegendSize int `json:"legend_size,omitempty"`
Legend bool `json:"legend,omitempty"`
TileDef TileDef `json:"tile_def,omitempty"`
}
type EventTimelineWidget struct {
TitleSize int `json:"title_size,omitempty"`
Title bool `json:"title,omitempty"`
TitleAlign string `json:"title_align,omitempty"`
TitleText string `json:"title_text,omitempty"`
Height int `json:"height,omitempty"`
Width int `json:"width,omitempty"`
X int `json:"y,omitempty"`
Y int `json:"x,omitempty"`
Type string `json:"type,omitempty"`
Timeframe string `json:"timeframe,omitempty"`
Query string `json:"query,omitempty"`
}
type AlertGraphWidget struct {
TitleSize int `json:"title_size,omitempty"`
VizType string `json:"timeseries,omitempty"`
Title bool `json:"title,omitempty"`
TitleAlign string `json:"title_align,omitempty"`
TitleText string `json:"title_text,omitempty"`
Height int `json:"height,omitempty"`
Width int `json:"width,omitempty"`
X int `json:"y,omitempty"`
Y int `json:"x,omitempty"`
AlertId int `json:"alert_id,omitempty"`
Timeframe string `json:"timeframe,omitempty"`
Type string `json:"type,omitempty"`
AddTimeframe bool `json:"add_timeframe,omitempty"`
}
type HostMapWidget struct {
TitleSize int `json:"title_size,omitempty"`
Title bool `json:"title,omitempty"`
TitleAlign string `json:"title_align,omitempty"`
TitleText string `json:"title_text,omitempty"`
Height int `json:"height,omitempty"`
Width int `json:"width,omitempty"`
X int `json:"y,omitempty"`
Y int `json:"x,omitempty"`
Query string `json:"query,omitempty"`
Timeframe string `json:"timeframe,omitempty"`
LegendSize int `json:"legend_size,omitempty"`
Type string `json:"type,omitempty"`
Legend bool `json:"legend,omitempty"`
TileDef TileDef `json:"tile_def,omitempty"`
}
type CheckStatusWidget struct {
TitleSize int `json:"title_size,omitempty"`
Title bool `json:"title,omitempty"`
TitleAlign string `json:"title_align,omitempty"`
TextAlign string `json:"text_align,omitempty"`
TitleText string `json:"title_text,omitempty"`
Height int `json:"height,omitempty"`
Width int `json:"width,omitempty"`
X int `json:"y,omitempty"`
Y int `json:"x,omitempty"`
Tags string `json:"tags,omitempty"`
Timeframe string `json:"timeframe,omitempty"`
TextSize string `json:"text_size,omitempty"`
Type string `json:"type,omitempty"`
Check string `json:"check,omitempty"`
Group string `json:"group,omitempty"`
Grouping string `json:"grouping,omitempty"`
}
type IFrameWidget struct {
TitleSize int `json:"title_size,omitempty"`
Title bool `json:"title,omitempty"`
Url string `json:"url,omitempty"`
TitleAlign string `json:"title_align,omitempty"`
TitleText string `json:"title_text,omitempty"`
Height int `json:"height,omitempty"`
Width int `json:"width,omitempty"`
X int `json:"y,omitempty"`
Y int `json:"x,omitempty"`
Type string `json:"type,omitempty"`
}
type NoteWidget struct {
TitleSize int `json:"title_size,omitempty"`
Title bool `json:"title,omitempty"`
RefreshEvery int `json:"refresh_every,omitempty"`
TickPos string `json:"tick_pos,omitempty"`
TitleAlign string `json:"title_align,omitempty"`
TickEdge string `json:"tick_edge,omitempty"`
TextAlign string `json:"text_align,omitempty"`
TitleText string `json:"title_text,omitempty"`
Height int `json:"height,omitempty"`
Color string `json:"bgcolor,omitempty"`
Html string `json:"html,omitempty"`
Y int `json:"y,omitempty"`
X int `json:"x,omitempty"`
FontSize int `json:"font_size,omitempty"`
Tick bool `json:"tick,omitempty"`
Note string `json:"type,omitempty"`
Width int `json:"width,omitempty"`
AutoRefresh bool `json:"auto_refresh,omitempty"`
}
type TimeseriesWidget struct {
Height int `json:"height,omitempty"`
Legend bool `json:"legend,omitempty"`
TileDef TileDef `json:"tile_def,omitempty"`
Timeframe string `json:"timeframe,omitempty"`
Title bool `json:"title,omitempty"`
TitleAlign string `json:"title_align,omitempty"`
TitleSize TextSize `json:"title_size,omitempty"`
TitleText string `json:"title_text,omitempty"`
Type string `json:"type,omitempty"`
Width int `json:"width,omitempty"`
X int `json:"x,omitempty"`
Y int `json:"y,omitempty"`
}
type QueryValueWidget struct {
Timeframe string `json:"timeframe,omitempty"`
TimeframeAggregator string `json:"aggr,omitempty"`
Aggregator string `json:"aggregator,omitempty"`
CalcFunc string `json:"calc_func,omitempty"`
ConditionalFormats []ConditionalFormat `json:"conditional_formats,omitempty"`
Height int `json:"height,omitempty"`
IsValidQuery bool `json:"is_valid_query,omitempty,omitempty"`
Metric string `json:"metric,omitempty"`
MetricType string `json:"metric_type,omitempty"`
Precision int `json:"precision,omitempty"`
Query string `json:"query,omitempty"`
ResultCalcFunc string `json:"res_calc_func,omitempty"`
Tags []string `json:"tags,omitempty"`
TextAlign string `json:"text_align,omitempty"`
TextSize TextSize `json:"text_size,omitempty"`
Title bool `json:"title,omitempty"`
TitleAlign string `json:"title_align,omitempty"`
TitleSize TextSize `json:"title_size,omitempty"`
TitleText string `json:"title_text,omitempty"`
Type string `json:"type,omitempty"`
Unit string `json:"auto,omitempty"`
Width int `json:"width,omitempty"`
X int `json:"x,omitempty"`
Y int `json:"y,omitempty"`
}
type ConditionalFormat struct {
Color string `json:"color,omitempty"`
Comparator string `json:"comparator,omitempty"`
Inverted bool `json:"invert,omitempty"`
Value int `json:"value,omitempty"`
}
type ToplistWidget struct {
Height int `json:"height,omitempty"`
Legend bool `json:"legend,omitempty"`
LegendSize int `json:"legend_size,omitempty"`
TileDef TileDef `json:"tile_def,omitempty"`
Timeframe string `json:"timeframe,omitempty"`
Title bool `json:"title,omitempty"`
TitleAlign string `json:"title_align,omitempty"`
TitleSize TextSize `json:"title_size,omitempty"`
TitleText string `json:"title_text,omitempty"`
Type string `json:"type,omitempty"`
Width int `json:"width,omitempty"`
X int `json:"x,omitempty"`
Y int `json:"y,omitempty"`
}
type EventStreamWidget struct {
EventSize string `json:"event_size,omitempty"`
Height int `json:"height,omitempty"`
Query string `json:"query,omitempty"`
Timeframe string `json:"timeframe,omitempty"`
Title bool `json:"title,omitempty"`
TitleAlign string `json:"title_align,omitempty"`
TitleSize TextSize `json:"title_size,omitempty"`
TitleText string `json:"title_text,omitempty"`
Type string `json:"type,omitempty"`
Width int `json:"width,omitempty"`
X int `json:"x,omitempty"`
Y int `json:"y,omitempty"`
}
type FreeTextWidget struct {
Color string `json:"color,omitempty"`
FontSize string `json:"font_size,omitempty"`
Height int `json:"height,omitempty"`
Text string `json:"text,omitempty"`
TextAlign string `json:"text_align,omitempty"`
Type string `json:"type,omitempty"`
Width int `json:"width,omitempty"`
X int `json:"x,omitempty"`
Y int `json:"y,omitempty"`
}
type ImageWidget struct {
Height int `json:"height,omitempty"`
Sizing string `json:"sizing,omitempty"`
Title bool `json:"title,omitempty"`
TitleAlign string `json:"title_align,omitempty"`
TitleSize TextSize `json:"title_size,omitempty"`
TitleText string `json:"title_text,omitempty"`
Type string `json:"type,omitempty"`
Url string `json:"url,omitempty"`
Width int `json:"width,omitempty"`
X int `json:"x,omitempty"`
Y int `json:"y,omitempty"`
}

View File

@ -4,6 +4,9 @@ GOFMT_FILES?=$$(find . -name '*.go' | grep -v vendor)
default: test fmt
generate:
go generate
# test runs the unit tests and vets the code
test:
go test . $(TESTARGS) -v -timeout=30s -parallel=4

118
vendor/gopkg.in/zorkian/go-datadog-api.v2/README.md generated vendored Normal file
View File

@ -0,0 +1,118 @@
[![GoDoc](http://img.shields.io/badge/godoc-reference-blue.svg)](https://godoc.org/gopkg.in/zorkian/go-datadog-api.v2)
[![Build
status](https://travis-ci.org/zorkian/go-datadog-api.svg)](https://travis-ci.org/zorkian/go-datadog-api)
# Datadog API in Go
**This is the v2.0 version of the API, and has breaking changes. Use the main or v1.0 branch if you need
legacy code to be supported.**
A Go wrapper for the Datadog API. Use this library if you need to interact
with the Datadog system. You can post metrics with it if you want, but this library is probably
mostly used for automating dashboards/alerting and retrieving data (events, etc).
The source API documentation is here: <http://docs.datadoghq.com/api/>
## Installation
To use the default branch, include it in your code like:
```go
import "github.com/zorkian/go-datadog-api"
```
Or, if you need to control which version to use, import using [gopkg.in](http://labix.org/gopkg.in). Like so:
```go
import "gopkg.in/zorkian/go-datadog-api.v2"
```
Using go get:
```bash
go get gopkg.in/zorkian/go-datadog-api.v2
```
## USAGE
This library uses pointers to be able to verify if values are set or not (vs the default value for the type). Like
protobuf there are helpers to enhance the API. You can decide to not use them, but you'll have to be careful handling
nil pointers.
Using the client:
```go
client := datadog.NewClient("api key", "application key")
dash, err := client.GetDashboard(datadog.Int(10880))
if err != nil {
log.Fatalf("fatal: %s\n", err)
}
log.Printf("dashboard %d: %s\n", dash.GetId(), dash.GetTitle())
```
An example using datadog.String(), which allocates a pointer for you:
```go
m := datadog.Monitor{
Name: datadog.String("Monitor other things"),
Creator: &datadog.Creator{
Name: datadog.String("Joe Creator"),
},
}
```
An example using the SetXx, HasXx, GetXx and GetXxOk accessors:
```go
m := datadog.Monitor{}
m.SetName("Monitor all the things")
m.SetMessage("Electromagnetic energy loss")
// Use HasMessage(), to verify we have interest in the message.
// Using GetMessage() always safe as it returns the actual or, if never set, default value for that type.
if m.HasMessage() {
fmt.Printf("Found message %s\n", m.GetMessage())
}
// Alternatively, use GetMessageOk(), it returns a tuple with the (default) value and a boolean expressing
// if it was set at all:
if v, ok := m.GetMessageOk(); ok {
fmt.Printf("Found message %s\n", v)
}
```
Check out the Godoc link for the available API methods and, if you can't find the one you need,
let us know (or patches welcome)!
## DOCUMENTATION
Please see: <https://godoc.org/gopkg.in/zorkian/go-datadog-api.v2>
## BUGS/PROBLEMS/CONTRIBUTING
There are certainly some, but presently no known major bugs. If you do
find something that doesn't work as expected, please file an issue on
Github:
<https://github.com/zorkian/go-datadog-api/issues>
Thanks in advance! And, as always, patches welcome!
## DEVELOPMENT
### Running tests
* Run tests tests with `make test`.
* Integration tests can be run with `make testacc`. Run specific integration tests with `make testacc TESTARGS='-run=TestCreateAndDeleteMonitor'`
The acceptance tests require _DATADOG_API_KEY_ and _DATADOG_APP_KEY_ to be available
in your environment variables.
*Warning: the integrations tests will create and remove real resources in your Datadog account.*
### Regenerating code
Accessors `HasXx`, `GetXx`, `GetOkXx` and `SetXx` are generated for each struct field type type that contains pointers.
When structs are updated a contributor has to regenerate these using `go generate` and commit these changes.
Optionally there is a make target for the generation:
```bash
make generate
```
## COPYRIGHT AND LICENSE
Please see the LICENSE file for the included license information.
Copyright 2017 by authors and contributors.

View File

@ -15,14 +15,14 @@ import (
// Alert represents the data of an alert: a query that can fire and send a
// message to the users.
type Alert struct {
Id int `json:"id,omitempty"`
Creator int `json:"creator,omitempty"`
Query string `json:"query,omitempty"`
Name string `json:"name,omitempty"`
Message string `json:"message,omitempty"`
Silenced bool `json:"silenced,omitempty"`
NotifyNoData bool `json:"notify_no_data,omitempty"`
State string `json:"state,omitempty"`
Id *int `json:"id,omitempty"`
Creator *int `json:"creator,omitempty"`
Query *string `json:"query,omitempty"`
Name *string `json:"name,omitempty"`
Message *string `json:"message,omitempty"`
Silenced *bool `json:"silenced,omitempty"`
NotifyNoData *bool `json:"notify_no_data,omitempty"`
State *string `json:"state,omitempty"`
}
// reqAlerts receives a slice of all alerts.

View File

@ -1,11 +1,11 @@
package datadog
type Check struct {
Check string `json:"check"`
HostName string `json:"host_name"`
Status Status `json:"status"`
Timestamp string `json:"timestamp,omitempty"`
Message string `json:"message,omitempty"`
Check *string `json:"check,omitempty"`
HostName *string `json:"host_name,omitempty"`
Status *Status `json:"status,omitempty"`
Timestamp *string `json:"timestamp,omitempty"`
Message *string `json:"message,omitempty"`
Tags []string `json:"tags,omitempty"`
}

View File

@ -44,6 +44,12 @@ func NewClient(apiKey, appKey string) *Client {
}
}
// SetKeys changes the value of apiKey and appKey.
func (c *Client) SetKeys(apiKey, appKey string) {
c.apiKey = apiKey
c.appKey = appKey
}
// Validate checks if the API and application keys are valid.
func (client *Client) Validate() (bool, error) {
var bodyreader io.Reader

View File

@ -14,27 +14,27 @@ import (
// Comment is a special form of event that appears in a stream.
type Comment struct {
Id int `json:"id"`
RelatedId int `json:"related_event_id"`
Handle string `json:"handle"`
Message string `json:"message"`
Resource string `json:"resource"`
Url string `json:"url"`
Id *int `json:"id,omitempty"`
RelatedId *int `json:"related_event_id,omitempty"`
Handle *string `json:"handle,omitempty"`
Message *string `json:"message,omitempty"`
Resource *string `json:"resource,omitempty"`
Url *string `json:"url,omitempty"`
}
// reqComment is the container for receiving commenst.
type reqComment struct {
Comment Comment `json:"comment"`
Comment *Comment `json:"comment,omitempty"`
}
// CreateComment adds a new comment to the system.
func (client *Client) CreateComment(handle, message string) (*Comment, error) {
var out reqComment
comment := Comment{Handle: handle, Message: message}
comment := Comment{Handle: String(handle), Message: String(message)}
if err := client.doJsonRequest("POST", "/v1/comments", &comment, &out); err != nil {
return nil, err
}
return &out.Comment, nil
return out.Comment, nil
}
// CreateRelatedComment adds a new comment, but lets you specify the related
@ -42,16 +42,16 @@ func (client *Client) CreateComment(handle, message string) (*Comment, error) {
func (client *Client) CreateRelatedComment(handle, message string,
relid int) (*Comment, error) {
var out reqComment
comment := Comment{Handle: handle, Message: message, RelatedId: relid}
comment := Comment{Handle: String(handle), Message: String(message), RelatedId: Int(relid)}
if err := client.doJsonRequest("POST", "/v1/comments", &comment, &out); err != nil {
return nil, err
}
return &out.Comment, nil
return out.Comment, nil
}
// EditComment changes the message and possibly handle of a particular comment.
func (client *Client) EditComment(id int, handle, message string) error {
comment := Comment{Handle: handle, Message: message}
comment := Comment{Handle: String(handle), Message: String(message)}
return client.doJsonRequest("PUT", fmt.Sprintf("/v1/comments/%d", id),
&comment, nil)
}

181
vendor/gopkg.in/zorkian/go-datadog-api.v2/dashboards.go generated vendored Normal file
View File

@ -0,0 +1,181 @@
/*
* Datadog API for Go
*
* Please see the included LICENSE file for licensing information.
*
* Copyright 2013 by authors and contributors.
*/
package datadog
import (
"encoding/json"
"fmt"
)
// GraphDefinitionRequestStyle represents the graph style attributes
type GraphDefinitionRequestStyle struct {
Palette *string `json:"palette,omitempty"`
Width *string `json:"width,omitempty"`
Type *string `json:"type,omitempty"`
}
// GraphDefinitionRequest represents the requests passed into each graph.
type GraphDefinitionRequest struct {
Query *string `json:"q,omitempty"`
Stacked *bool `json:"stacked,omitempty"`
Aggregator *string `json:"aggregator,omitempty"`
ConditionalFormats []DashboardConditionalFormat `json:"conditional_formats,omitempty"`
Type *string `json:"type,omitempty"`
Style *GraphDefinitionRequestStyle `json:"style,omitempty"`
// For change type graphs
ChangeType *string `json:"change_type,omitempty"`
OrderDirection *string `json:"order_dir,omitempty"`
CompareTo *string `json:"compare_to,omitempty"`
IncreaseGood *bool `json:"increase_good,omitempty"`
OrderBy *string `json:"order_by,omitempty"`
ExtraCol *string `json:"extra_col,omitempty"`
}
type GraphDefinitionMarker struct {
Type *string `json:"type,omitempty"`
Value *string `json:"value,omitempty"`
Label *string `json:"label,omitempty"`
Val *json.Number `json:"val,omitempty"`
Min *json.Number `json:"min,omitempty"`
Max *json.Number `json:"max,omitempty"`
}
type GraphEvent struct {
Query *string `json:"q,omitempty"`
}
type Yaxis struct {
Min *float64 `json:"min,omitempty"`
Max *float64 `json:"max,omitempty"`
Scale *string `json:"scale,omitempty"`
}
type Style struct {
Palette *string `json:"palette,omitempty"`
PaletteFlip *bool `json:"paletteFlip,omitempty"`
}
type GraphDefinition struct {
Viz *string `json:"viz,omitempty"`
Requests []GraphDefinitionRequest `json:"requests,omitempty"`
Events []GraphEvent `json:"events,omitempty"`
Markers []GraphDefinitionMarker `json:"markers,omitempty"`
// For timeseries type graphs
Yaxis Yaxis `json:"yaxis,omitempty"`
// For query value type graphs
Autoscale *bool `json:"austoscale,omitempty"`
TextAlign *string `json:"text_align,omitempty"`
Precision *string `json:"precision,omitempty"`
CustomUnit *string `json:"custom_unit,omitempty"`
// For hostname type graphs
Style *Style `json:"Style,omitempty"`
Groups []string `json:"group,omitempty"`
IncludeNoMetricHosts *bool `json:"noMetricHosts,omitempty"`
Scopes []string `json:"scope,omitempty"`
IncludeUngroupedHosts *bool `json:"noGroupHosts,omitempty"`
}
// Graph represents a graph that might exist on a dashboard.
type Graph struct {
Title *string `json:"title,omitempty"`
Definition *GraphDefinition `json:"definition"`
}
// Template variable represents a template variable that might exist on a dashboard
type TemplateVariable struct {
Name *string `json:"name,omitempty"`
Prefix *string `json:"prefix,omitempty"`
Default *string `json:"default,omitempty"`
}
// Dashboard represents a user created dashboard. This is the full dashboard
// struct when we load a dashboard in detail.
type Dashboard struct {
Id *int `json:"id,omitempty"`
Description *string `json:"description,omitempty"`
Title *string `json:"title,omitempty"`
Graphs []Graph `json:"graphs,omitempty"`
TemplateVariables []TemplateVariable `json:"template_variables,omitempty"`
ReadOnly *bool `json:"read_only,omitempty"`
}
// DashboardLite represents a user created dashboard. This is the mini
// struct when we load the summaries.
type DashboardLite struct {
Id *int `json:"id,string,omitempty"` // TODO: Remove ',string'.
Resource *string `json:"resource,omitempty"`
Description *string `json:"description,omitempty"`
Title *string `json:"title,omitempty"`
}
// reqGetDashboards from /api/v1/dash
type reqGetDashboards struct {
Dashboards []DashboardLite `json:"dashes,omitempty"`
}
// reqGetDashboard from /api/v1/dash/:dashboard_id
type reqGetDashboard struct {
Resource *string `json:"resource,omitempty"`
Url *string `json:"url,omitempty"`
Dashboard *Dashboard `json:"dash,omitempty"`
}
type DashboardConditionalFormat struct {
Palette *string `json:"palette,omitempty"`
Comparator *string `json:"comparator,omitempty"`
CustomBgColor *string `json:"custom_bg_color,omitempty"`
Value *json.Number `json:"value,omitempty"`
Inverted *bool `json:"invert,omitempty"`
CustomFgColor *string `json:"custom_fg_color,omitempty"`
}
// GetDashboard returns a single dashboard created on this account.
func (client *Client) GetDashboard(id int) (*Dashboard, error) {
var out reqGetDashboard
if err := client.doJsonRequest("GET", fmt.Sprintf("/v1/dash/%d", id), nil, &out); err != nil {
return nil, err
}
return out.Dashboard, nil
}
// GetDashboards returns a list of all dashboards created on this account.
func (client *Client) GetDashboards() ([]DashboardLite, error) {
var out reqGetDashboards
if err := client.doJsonRequest("GET", "/v1/dash", nil, &out); err != nil {
return nil, err
}
return out.Dashboards, nil
}
// DeleteDashboard deletes a dashboard by the identifier.
func (client *Client) DeleteDashboard(id int) error {
return client.doJsonRequest("DELETE", fmt.Sprintf("/v1/dash/%d", id), nil, nil)
}
// CreateDashboard creates a new dashboard when given a Dashboard struct. Note
// that the Id, Resource, Url and similar elements are not used in creation.
func (client *Client) CreateDashboard(dash *Dashboard) (*Dashboard, error) {
var out reqGetDashboard
if err := client.doJsonRequest("POST", "/v1/dash", dash, &out); err != nil {
return nil, err
}
return out.Dashboard, nil
}
// UpdateDashboard in essence takes a Dashboard struct and persists it back to
// the server. Use this if you've updated your local and need to push it back.
func (client *Client) UpdateDashboard(dash *Dashboard) error {
return client.doJsonRequest("PUT", fmt.Sprintf("/v1/dash/%d", *dash.Id),
dash, nil)
}

File diff suppressed because it is too large Load Diff

View File

@ -13,23 +13,23 @@ import (
)
type Recurrence struct {
Period int `json:"period,omitempty"`
Type string `json:"type,omitempty"`
UntilDate int `json:"until_date,omitempty"`
UntilOccurrences int `json:"until_occurrences,omitempty"`
Period *int `json:"period,omitempty"`
Type *string `json:"type,omitempty"`
UntilDate *int `json:"until_date,omitempty"`
UntilOccurrences *int `json:"until_occurrences,omitempty"`
WeekDays []string `json:"week_days,omitempty"`
}
type Downtime struct {
Active bool `json:"active,omitempty"`
Canceled int `json:"canceled,omitempty"`
Disabled bool `json:"disabled,omitempty"`
End int `json:"end,omitempty"`
Id int `json:"id,omitempty"`
Message string `json:"message,omitempty"`
Active *bool `json:"active,omitempty"`
Canceled *int `json:"canceled,omitempty"`
Disabled *bool `json:"disabled,omitempty"`
End *int `json:"end,omitempty"`
Id *int `json:"id,omitempty"`
Message *string `json:"message,omitempty"`
Recurrence *Recurrence `json:"recurrence,omitempty"`
Scope []string `json:"scope,omitempty"`
Start int `json:"start,omitempty"`
Start *int `json:"start,omitempty"`
}
// reqDowntimes retrieves a slice of all Downtimes.
@ -51,7 +51,7 @@ func (client *Client) CreateDowntime(downtime *Downtime) (*Downtime, error) {
// UpdateDowntime takes a downtime that was previously retrieved through some method
// and sends it back to the server.
func (client *Client) UpdateDowntime(downtime *Downtime) error {
return client.doJsonRequest("PUT", fmt.Sprintf("/v1/downtime/%d", downtime.Id),
return client.doJsonRequest("PUT", fmt.Sprintf("/v1/downtime/%d", *downtime.Id),
downtime, nil)
}

View File

@ -17,24 +17,24 @@ import (
// Event is a single event. If this is being used to post an event, then not
// all fields will be filled out.
type Event struct {
Id int `json:"id,omitempty"`
Title string `json:"title,omitempty"`
Text string `json:"text,omitempty"`
Time int `json:"date_happened,omitempty"` // UNIX time.
Priority string `json:"priority,omitempty"`
AlertType string `json:"alert_type,omitempty"`
Host string `json:"host,omitempty"`
Aggregation string `json:"aggregation_key,omitempty"`
SourceType string `json:"source_type_name,omitempty"`
Id *int `json:"id,omitempty"`
Title *string `json:"title,omitempty"`
Text *string `json:"text,omitempty"`
Time *int `json:"date_happened,omitempty"` // UNIX time.
Priority *string `json:"priority,omitempty"`
AlertType *string `json:"alert_type,omitempty"`
Host *string `json:"host,omitempty"`
Aggregation *string `json:"aggregation_key,omitempty"`
SourceType *string `json:"source_type_name,omitempty"`
Tags []string `json:"tags,omitempty"`
Url string `json:"url,omitempty"`
Resource string `json:"resource,omitempty"`
EventType string `json:"event_type,omitempty"`
Url *string `json:"url,omitempty"`
Resource *string `json:"resource,omitempty"`
EventType *string `json:"event_type,omitempty"`
}
// reqGetEvent is the container for receiving a single event.
type reqGetEvent struct {
Event Event `json:"event,omitempty"`
Event *Event `json:"event,omitempty"`
}
// reqGetEvents is for returning many events.
@ -48,7 +48,7 @@ func (client *Client) PostEvent(event *Event) (*Event, error) {
if err := client.doJsonRequest("POST", "/v1/events", event, &out); err != nil {
return nil, err
}
return &out.Event, nil
return out.Event, nil
}
// GetEvent gets a single event given an identifier.
@ -57,7 +57,7 @@ func (client *Client) GetEvent(id int) (*Event, error) {
if err := client.doJsonRequest("GET", fmt.Sprintf("/v1/events/%d", id), nil, &out); err != nil {
return nil, err
}
return &out.Event, nil
return out.Event, nil
}
// QueryEvents returns a slice of events from the query stream.

View File

@ -0,0 +1,3 @@
package datadog
//go:generate go run cmd/tools/gen-accessors.go -v

67
vendor/gopkg.in/zorkian/go-datadog-api.v2/helpers.go generated vendored Normal file
View File

@ -0,0 +1,67 @@
/*
* Datadog API for Go
*
* Please see the included LICENSE file for licensing information.
*
* Copyright 2017 by authors and contributors.
*/
package datadog
import "encoding/json"
// Bool is a helper routine that allocates a new bool value
// to store v and returns a pointer to it.
func Bool(v bool) *bool { return &v }
// GetBool is a helper routine that returns a boolean representing
// if a value was set, and if so, dereferences the pointer to it.
func GetBool(v *bool) (bool, bool) {
if v != nil {
return *v, true
}
return false, false
}
// Int is a helper routine that allocates a new int value
// to store v and returns a pointer to it.
func Int(v int) *int { return &v }
// GetInt is a helper routine that returns a boolean representing
// if a value was set, and if so, dereferences the pointer to it.
func GetIntOk(v *int) (int, bool) {
if v != nil {
return *v, true
}
return 0, false
}
// String is a helper routine that allocates a new string value
// to store v and returns a pointer to it.
func String(v string) *string { return &v }
// GetString is a helper routine that returns a boolean representing
// if a value was set, and if so, dereferences the pointer to it.
func GetStringOk(v *string) (string, bool) {
if v != nil {
return *v, true
}
return "", false
}
// JsonNumber is a helper routine that allocates a new string value
// to store v and returns a pointer to it.
func JsonNumber(v json.Number) *json.Number { return &v }
// GetJsonNumber is a helper routine that returns a boolean representing
// if a value was set, and if so, dereferences the pointer to it.
func GetJsonNumberOk(v *json.Number) (json.Number, bool) {
if v != nil {
return *v, true
}
return "", false
}

View File

@ -17,9 +17,9 @@ import (
)
type ThresholdCount struct {
Ok json.Number `json:"ok,omitempty"`
Critical json.Number `json:"critical,omitempty"`
Warning json.Number `json:"warning,omitempty"`
Ok *json.Number `json:"ok,omitempty"`
Critical *json.Number `json:"critical,omitempty"`
Warning *json.Number `json:"warning,omitempty"`
}
type NoDataTimeframe int
@ -40,38 +40,38 @@ func (tf *NoDataTimeframe) UnmarshalJSON(data []byte) error {
type Options struct {
NoDataTimeframe NoDataTimeframe `json:"no_data_timeframe,omitempty"`
NotifyAudit bool `json:"notify_audit,omitempty"`
NotifyNoData bool `json:"notify_no_data,omitempty"`
NotifyAudit *bool `json:"notify_audit,omitempty"`
NotifyNoData *bool `json:"notify_no_data,omitempty"`
RenotifyInterval *int `json:"renotify_interval,omitempty"`
NewHostDelay *int `json:"new_host_delay,omitempty"`
RenotifyInterval int `json:"renotify_interval,omitempty"`
Silenced map[string]int `json:"silenced,omitempty"`
TimeoutH int `json:"timeout_h,omitempty"`
EscalationMessage string `json:"escalation_message,omitempty"`
Thresholds ThresholdCount `json:"thresholds,omitempty"`
IncludeTags bool `json:"include_tags,omitempty"`
RequireFullWindow bool `json:"require_full_window,omitempty"`
Locked bool `json:"locked,omitempty"`
TimeoutH *int `json:"timeout_h,omitempty"`
EscalationMessage *string `json:"escalation_message,omitempty"`
Thresholds *ThresholdCount `json:"thresholds,omitempty"`
IncludeTags *bool `json:"include_tags,omitempty"`
RequireFullWindow *bool `json:"require_full_window,omitempty"`
Locked *bool `json:"locked,omitempty"`
}
// Monitor allows watching a metric or check that you care about,
// notifying your team when some defined threshold is exceeded
type Monitor struct {
Creator Creator `json:"creator,omitempty"`
Id int `json:"id,omitempty"`
Type string `json:"type,omitempty"`
Query string `json:"query,omitempty"`
Name string `json:"name,omitempty"`
Message string `json:"message,omitempty"`
Creator *Creator `json:"creator,omitempty"`
Id *int `json:"id,omitempty"`
Type *string `json:"type,omitempty"`
Query *string `json:"query,omitempty"`
Name *string `json:"name,omitempty"`
Message *string `json:"message,omitempty"`
Tags []string `json:"tags,omitempty"`
Options Options `json:"options,omitempty"`
Options *Options `json:"options,omitempty"`
}
// Creator contains the creator of the monitor
type Creator struct {
Email string `json:"email,omitempty"`
Handle string `json:"handle,omitempty"`
Id int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Email *string `json:"email,omitempty"`
Handle *string `json:"handle,omitempty"`
Id *int `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
}
// reqMonitors receives a slice of all monitors
@ -93,7 +93,7 @@ func (client *Client) CreateMonitor(monitor *Monitor) (*Monitor, error) {
// UpdateMonitor takes a monitor that was previously retrieved through some method
// and sends it back to the server
func (client *Client) UpdateMonitor(monitor *Monitor) error {
return client.doJsonRequest("PUT", fmt.Sprintf("/v1/monitor/%d", monitor.Id),
return client.doJsonRequest("PUT", fmt.Sprintf("/v1/monitor/%d", *monitor.Id),
monitor, nil)
}

View File

@ -11,26 +11,17 @@ package datadog
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"strconv"
"strings"
"time"
"github.com/cenkalti/backoff"
)
const (
RateLimitHeader = "X-RateLimit-Limit"
RatePeriodHeader = "X-RateLimit-Period"
RateRemainingHeader = "X-RateLimit-Remaining"
RateResetHeader = "X-RateLimit-Reset"
)
// uriForAPI is to be called with something like "/v1/events" and it will give
// the proper request URI to be posted to.
func (client *Client) uriForAPI(api string) string {
@ -69,9 +60,9 @@ func (client *Client) doJsonRequest(method, api string,
req.Header.Add("Content-Type", "application/json")
}
// Perform the request and retry it if it's not a POST request
// Perform the request and retry it if it's not a POST or PUT request
var resp *http.Response
if method == "POST" {
if method == "POST" || method == "PUT" {
resp, err = client.HttpClient.Do(req)
} else {
resp, err = client.doRequestWithRetries(req, client.RetryTimeout)
@ -81,12 +72,6 @@ func (client *Client) doJsonRequest(method, api string,
}
defer resp.Body.Close()
if err := client.getRateLimit(resp); err != nil {
if err.(*RateLimit).Remaining == 0 {
return err
}
}
if resp.StatusCode < 200 || resp.StatusCode > 299 {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
@ -118,54 +103,35 @@ func (client *Client) doJsonRequest(method, api string,
return nil
}
func (client *Client) getRateLimit(response *http.Response) error {
ratelimit := response.Header.Get(RateLimitHeader)
if ratelimit == "" {
return nil
}
rateperiod := response.Header.Get(RatePeriodHeader)
rateremaining := response.Header.Get(RateRemainingHeader)
ratereset := response.Header.Get(RateResetHeader)
limit, _ := strconv.Atoi(ratelimit)
period, _ := strconv.Atoi(rateperiod)
remaining, _ := strconv.Atoi(rateremaining)
reset, _ := strconv.Atoi(ratereset)
ratelimiterror := NewRateLimit(limit, period, remaining, reset)
return error(ratelimiterror)
}
// doRequestWithRetries performs an HTTP request repeatedly for maxTime or until
// no error and no HTTP response code higher than 299 is returned.
// no error and no acceptable HTTP response code was returned.
func (client *Client) doRequestWithRetries(req *http.Request, maxTime time.Duration) (*http.Response, error) {
var (
err error
resp *http.Response
bo = backoff.NewExponentialBackOff()
)
bo.MaxElapsedTime = maxTime
err = backoff.Retry(func() error {
operation := func() error {
resp, err = client.HttpClient.Do(req)
if err != nil {
return err
}
if err := client.getRateLimit(resp); err != nil {
if err.(*RateLimit).Remaining == 0 {
return err
}
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
// 2xx all done
return nil
} else if resp.StatusCode >= 400 && resp.StatusCode < 500 {
// 4xx are not retryable
return nil
}
if resp.StatusCode < 200 || resp.StatusCode > 299 {
return errors.New("API error: " + resp.Status)
}
return nil
}, bo)
return fmt.Errorf("Received HTTP status code %d", resp.StatusCode)
}
err = backoff.Retry(operation, bo)
return resp, err
}

View File

@ -0,0 +1,287 @@
package datadog
type TextSize struct {
Size *int
Auto *bool
}
type TileDef struct {
Events []TileDefEvent `json:"events,omitempty"`
Markers []TimeseriesMarker `json:"markers,omitempty"`
Requests []TimeseriesRequest `json:"requests,omitempty"`
Viz *string `json:"viz,omitempty"`
}
type TimeseriesRequest struct {
Query *string `json:"q,omitempty"`
Type *string `json:"type,omitempty"`
ConditionalFormats []ConditionalFormat `json:"conditional_formats,omitempty"`
Style *TimeseriesRequestStyle `json:"style,omitempty"`
}
type TimeseriesRequestStyle struct {
Palette *string `json:"palette,omitempty"`
}
type TimeseriesMarker struct {
Label *string `json:"label,omitempty"`
Type *string `json:"type,omitempty"`
Value *string `json:"value,omitempty"`
}
type TileDefEvent struct {
Query *string `json:"q"`
}
type AlertValueWidget struct {
TitleSize *int `json:"title_size,omitempty"`
Title *bool `json:"title,omitempty"`
TitleAlign *string `json:"title_align,omitempty"`
TextAlign *string `json:"text_align,omitempty"`
TitleText *string `json:"title_text,omitempty"`
Precision *int `json:"precision,omitempty"`
AlertId *int `json:"alert_id,omitempty"`
Timeframe *string `json:"timeframe,omitempty"`
AddTimeframe *bool `json:"add_timeframe,omitempty"`
Y *int `json:"y,omitempty"`
X *int `json:"x,omitempty"`
TextSize *string `json:"text_size,omitempty"`
Height *int `json:"height,omitempty"`
Width *int `json:"width,omitempty"`
Type *string `json:"type,omitempty"`
Unit *string `json:"unit,omitempty"`
}
type ChangeWidget struct {
TitleSize *int `json:"title_size,omitempty"`
Title *bool `json:"title,omitempty"`
TitleAlign *string `json:"title_align,omitempty"`
TitleText *string `json:"title_text,omitempty"`
Height *int `json:"height,omitempty"`
Width *int `json:"width,omitempty"`
X *int `json:"y,omitempty"`
Y *int `json:"x,omitempty"`
Aggregator *string `json:"aggregator,omitempty"`
TileDef *TileDef `json:"tile_def,omitempty"`
}
type GraphWidget struct {
TitleSize *int `json:"title_size,omitempty"`
Title *bool `json:"title,omitempty"`
TitleAlign *string `json:"title_align,omitempty"`
TitleText *string `json:"title_text,omitempty"`
Height *int `json:"height,omitempty"`
Width *int `json:"width,omitempty"`
X *int `json:"y,omitempty"`
Y *int `json:"x,omitempty"`
Type *string `json:"type,omitempty"`
Timeframe *string `json:"timeframe,omitempty"`
LegendSize *int `json:"legend_size,omitempty"`
Legend *bool `json:"legend,omitempty"`
TileDef *TileDef `json:"tile_def,omitempty"`
}
type EventTimelineWidget struct {
TitleSize *int `json:"title_size,omitempty"`
Title *bool `json:"title,omitempty"`
TitleAlign *string `json:"title_align,omitempty"`
TitleText *string `json:"title_text,omitempty"`
Height *int `json:"height,omitempty"`
Width *int `json:"width,omitempty"`
X *int `json:"y,omitempty"`
Y *int `json:"x,omitempty"`
Type *string `json:"type,omitempty"`
Timeframe *string `json:"timeframe,omitempty"`
Query *string `json:"query,omitempty"`
}
type AlertGraphWidget struct {
TitleSize *int `json:"title_size,omitempty"`
VizType *string `json:"timeseries,omitempty"`
Title *bool `json:"title,omitempty"`
TitleAlign *string `json:"title_align,omitempty"`
TitleText *string `json:"title_text,omitempty"`
Height *int `json:"height,omitempty"`
Width *int `json:"width,omitempty"`
X *int `json:"y,omitempty"`
Y *int `json:"x,omitempty"`
AlertId *int `json:"alert_id,omitempty"`
Timeframe *string `json:"timeframe,omitempty"`
Type *string `json:"type,omitempty"`
AddTimeframe *bool `json:"add_timeframe,omitempty"`
}
type HostMapWidget struct {
TitleSize *int `json:"title_size,omitempty"`
Title *bool `json:"title,omitempty"`
TitleAlign *string `json:"title_align,omitempty"`
TitleText *string `json:"title_text,omitempty"`
Height *int `json:"height,omitempty"`
Width *int `json:"width,omitempty"`
X *int `json:"y,omitempty"`
Y *int `json:"x,omitempty"`
Query *string `json:"query,omitempty"`
Timeframe *string `json:"timeframe,omitempty"`
LegendSize *int `json:"legend_size,omitempty"`
Type *string `json:"type,omitempty"`
Legend *bool `json:"legend,omitempty"`
TileDef *TileDef `json:"tile_def,omitempty"`
}
type CheckStatusWidget struct {
TitleSize *int `json:"title_size,omitempty"`
Title *bool `json:"title,omitempty"`
TitleAlign *string `json:"title_align,omitempty"`
TextAlign *string `json:"text_align,omitempty"`
TitleText *string `json:"title_text,omitempty"`
Height *int `json:"height,omitempty"`
Width *int `json:"width,omitempty"`
X *int `json:"y,omitempty"`
Y *int `json:"x,omitempty"`
Tags *string `json:"tags,omitempty"`
Timeframe *string `json:"timeframe,omitempty"`
TextSize *string `json:"text_size,omitempty"`
Type *string `json:"type,omitempty"`
Check *string `json:"check,omitempty"`
Group *string `json:"group,omitempty"`
Grouping *string `json:"grouping,omitempty"`
}
type IFrameWidget struct {
TitleSize *int `json:"title_size,omitempty"`
Title *bool `json:"title,omitempty"`
Url *string `json:"url,omitempty"`
TitleAlign *string `json:"title_align,omitempty"`
TitleText *string `json:"title_text,omitempty"`
Height *int `json:"height,omitempty"`
Width *int `json:"width,omitempty"`
X *int `json:"y,omitempty"`
Y *int `json:"x,omitempty"`
Type *string `json:"type,omitempty"`
}
type NoteWidget struct {
TitleSize *int `json:"title_size,omitempty"`
Title *bool `json:"title,omitempty"`
RefreshEvery *int `json:"refresh_every,omitempty"`
TickPos *string `json:"tick_pos,omitempty"`
TitleAlign *string `json:"title_align,omitempty"`
TickEdge *string `json:"tick_edge,omitempty"`
TextAlign *string `json:"text_align,omitempty"`
TitleText *string `json:"title_text,omitempty"`
Height *int `json:"height,omitempty"`
Color *string `json:"bgcolor,omitempty"`
Html *string `json:"html,omitempty"`
Y *int `json:"y,omitempty"`
X *int `json:"x,omitempty"`
FontSize *int `json:"font_size,omitempty"`
Tick *bool `json:"tick,omitempty"`
Note *string `json:"type,omitempty"`
Width *int `json:"width,omitempty"`
AutoRefresh *bool `json:"auto_refresh,omitempty"`
}
type TimeseriesWidget struct {
Height *int `json:"height,omitempty"`
Legend *bool `json:"legend,omitempty"`
TileDef *TileDef `json:"tile_def,omitempty"`
Timeframe *string `json:"timeframe,omitempty"`
Title *bool `json:"title,omitempty"`
TitleAlign *string `json:"title_align,omitempty"`
TitleSize *TextSize `json:"title_size,omitempty"`
TitleText *string `json:"title_text,omitempty"`
Type *string `json:"type,omitempty"`
Width *int `json:"width,omitempty"`
X *int `json:"x,omitempty"`
Y *int `json:"y,omitempty"`
}
type QueryValueWidget struct {
Timeframe *string `json:"timeframe,omitempty"`
TimeframeAggregator *string `json:"aggr,omitempty"`
Aggregator *string `json:"aggregator,omitempty"`
CalcFunc *string `json:"calc_func,omitempty"`
ConditionalFormats []ConditionalFormat `json:"conditional_formats,omitempty"`
Height *int `json:"height,omitempty"`
IsValidQuery *bool `json:"is_valid_query,omitempty,omitempty"`
Metric *string `json:"metric,omitempty"`
MetricType *string `json:"metric_type,omitempty"`
Precision *int `json:"precision,omitempty"`
Query *string `json:"query,omitempty"`
ResultCalcFunc *string `json:"res_calc_func,omitempty"`
Tags []string `json:"tags,omitempty"`
TextAlign *string `json:"text_align,omitempty"`
TextSize *TextSize `json:"text_size,omitempty"`
Title *bool `json:"title,omitempty"`
TitleAlign *string `json:"title_align,omitempty"`
TitleSize *TextSize `json:"title_size,omitempty"`
TitleText *string `json:"title_text,omitempty"`
Type *string `json:"type,omitempty"`
Unit *string `json:"auto,omitempty"`
Width *int `json:"width,omitempty"`
X *int `json:"x,omitempty"`
Y *int `json:"y,omitempty"`
}
type ConditionalFormat struct {
Color *string `json:"color,omitempty"`
Comparator *string `json:"comparator,omitempty"`
Inverted *bool `json:"invert,omitempty"`
Value *int `json:"value,omitempty"`
}
type ToplistWidget struct {
Height *int `json:"height,omitempty"`
Legend *bool `json:"legend,omitempty"`
LegendSize *int `json:"legend_size,omitempty"`
TileDef *TileDef `json:"tile_def,omitempty"`
Timeframe *string `json:"timeframe,omitempty"`
Title *bool `json:"title,omitempty"`
TitleAlign *string `json:"title_align,omitempty"`
TitleSize *TextSize `json:"title_size,omitempty"`
TitleText *string `json:"title_text,omitempty"`
Type *string `json:"type,omitempty"`
Width *int `json:"width,omitempty"`
X *int `json:"x,omitempty"`
Y *int `json:"y,omitempty"`
}
type EventStreamWidget struct {
EventSize *string `json:"event_size,omitempty"`
Height *int `json:"height,omitempty"`
Query *string `json:"query,omitempty"`
Timeframe *string `json:"timeframe,omitempty"`
Title *bool `json:"title,omitempty"`
TitleAlign *string `json:"title_align,omitempty"`
TitleSize *TextSize `json:"title_size,omitempty"`
TitleText *string `json:"title_text,omitempty"`
Type *string `json:"type,omitempty"`
Width *int `json:"width,omitempty"`
X *int `json:"x,omitempty"`
Y *int `json:"y,omitempty"`
}
type FreeTextWidget struct {
Color *string `json:"color,omitempty"`
FontSize *string `json:"font_size,omitempty"`
Height *int `json:"height,omitempty"`
Text *string `json:"text,omitempty"`
TextAlign *string `json:"text_align,omitempty"`
Type *string `json:"type,omitempty"`
Width *int `json:"width,omitempty"`
X *int `json:"x,omitempty"`
Y *int `json:"y,omitempty"`
}
type ImageWidget struct {
Height *int `json:"height,omitempty"`
Sizing *string `json:"sizing,omitempty"`
Title *bool `json:"title,omitempty"`
TitleAlign *string `json:"title_align,omitempty"`
TitleSize *TextSize `json:"title_size,omitempty"`
TitleText *string `json:"title_text,omitempty"`
Type *string `json:"type,omitempty"`
Url *string `json:"url,omitempty"`
Width *int `json:"width,omitempty"`
X *int `json:"x,omitempty"`
Y *int `json:"y,omitempty"`
}

View File

@ -15,50 +15,50 @@ import (
// Screenboard represents a user created screenboard. This is the full screenboard
// struct when we load a screenboard in detail.
type Screenboard struct {
Id int `json:"id,omitempty"`
Title string `json:"board_title,omitempty"`
Height string `json:"height,omitempty"`
Width string `json:"width,omitempty"`
Shared bool `json:"shared,omitempty"`
Templated bool `json:"templated,omitempty"`
Id *int `json:"id,omitempty"`
Title *string `json:"board_title,omitempty"`
Height *string `json:"height,omitempty"`
Width *string `json:"width,omitempty"`
Shared *bool `json:"shared,omitempty"`
Templated *bool `json:"templated,omitempty"`
TemplateVariables []TemplateVariable `json:"template_variables,omitempty"`
Widgets []Widget `json:"widgets,omitempty"`
ReadOnly bool `json:"read_only,omitempty"`
ReadOnly *bool `json:"read_only,omitempty"`
}
//type Widget struct {
type Widget struct {
Default string `json:"default,omitempty"`
Name string `json:"name,omitempty"`
Prefix string `json:"prefix,omitempty"`
TimeseriesWidget TimeseriesWidget `json:"timeseries,omitempty"`
QueryValueWidget QueryValueWidget `json:"query_value,omitempty"`
EventStreamWidget EventStreamWidget `json:"event_stream,omitempty"`
FreeTextWidget FreeTextWidget `json:"free_text,omitempty"`
ToplistWidget ToplistWidget `json:"toplist,omitempty"`
ImageWidget ImageWidget `json:"image,omitempty"`
ChangeWidget ChangeWidget `json:"change,omitempty"`
GraphWidget GraphWidget `json:"graph,omitempty"`
EventTimelineWidget EventTimelineWidget `json:"event_timeline,omitempty"`
AlertValueWidget AlertValueWidget `json:"alert_value,omitempty"`
AlertGraphWidget AlertGraphWidget `json:"alert_graph,omitempty"`
HostMapWidget HostMapWidget `json:"hostmap,omitempty"`
CheckStatusWidget CheckStatusWidget `json:"check_status,omitempty"`
IFrameWidget IFrameWidget `json:"iframe,omitempty"`
NoteWidget NoteWidget `json:"frame,omitempty"`
Default *string `json:"default,omitempty"`
Name *string `json:"name,omitempty"`
Prefix *string `json:"prefix,omitempty"`
TimeseriesWidget *TimeseriesWidget `json:"timeseries,omitempty"`
QueryValueWidget *QueryValueWidget `json:"query_value,omitempty"`
EventStreamWidget *EventStreamWidget `json:"event_stream,omitempty"`
FreeTextWidget *FreeTextWidget `json:"free_text,omitempty"`
ToplistWidget *ToplistWidget `json:"toplist,omitempty"`
ImageWidget *ImageWidget `json:"image,omitempty"`
ChangeWidget *ChangeWidget `json:"change,omitempty"`
GraphWidget *GraphWidget `json:"graph,omitempty"`
EventTimelineWidget *EventTimelineWidget `json:"event_timeline,omitempty"`
AlertValueWidget *AlertValueWidget `json:"alert_value,omitempty"`
AlertGraphWidget *AlertGraphWidget `json:"alert_graph,omitempty"`
HostMapWidget *HostMapWidget `json:"hostmap,omitempty"`
CheckStatusWidget *CheckStatusWidget `json:"check_status,omitempty"`
IFrameWidget *IFrameWidget `json:"iframe,omitempty"`
NoteWidget *NoteWidget `json:"frame,omitempty"`
}
// ScreenboardLite represents a user created screenboard. This is the mini
// struct when we load the summaries.
type ScreenboardLite struct {
Id int `json:"id,omitempty"`
Resource string `json:"resource,omitempty"`
Title string `json:"title,omitempty"`
Id *int `json:"id,omitempty"`
Resource *string `json:"resource,omitempty"`
Title *string `json:"title,omitempty"`
}
// reqGetScreenboards from /api/v1/screen
type reqGetScreenboards struct {
Screenboards []*ScreenboardLite `json:"screenboards"`
Screenboards []*ScreenboardLite `json:"screenboards,omitempty"`
}
// GetScreenboard returns a single screenboard created on this account.
@ -97,7 +97,7 @@ func (client *Client) CreateScreenboard(board *Screenboard) (*Screenboard, error
// UpdateScreenboard in essence takes a Screenboard struct and persists it back to
// the server. Use this if you've updated your local and need to push it back.
func (client *Client) UpdateScreenboard(board *Screenboard) error {
return client.doJsonRequest("PUT", fmt.Sprintf("/v1/screen/%d", board.Id), board, nil)
return client.doJsonRequest("PUT", fmt.Sprintf("/v1/screen/%d", *board.Id), board, nil)
}
type ScreenShareResponse struct {

View File

@ -17,25 +17,26 @@ type DataPoint [2]float64
// Metric represents a collection of data points that we might send or receive
// on one single metric line.
type Metric struct {
Metric string `json:"metric,omitempty"`
Metric *string `json:"metric,omitempty"`
Points []DataPoint `json:"points,omitempty"`
Type string `json:"type,omitempty"`
Host string `json:"host,omitempty"`
Type *string `json:"type,omitempty"`
Host *string `json:"host,omitempty"`
Tags []string `json:"tags,omitempty"`
Unit *string `json:"unit,omitempty"`
}
// Series represents a collection of data points we get when we query for timeseries data
type Series struct {
Metric string `json:"metric,omitempty"`
DisplayName string `json:"display_name,omitempty"`
Metric *string `json:"metric,omitempty"`
DisplayName *string `json:"display_name,omitempty"`
Points []DataPoint `json:"pointlist,omitempty"`
Start float64 `json:"start,omitempty"`
End float64 `json:"end,omitempty"`
Interval int `json:"interval,omitempty"`
Aggr string `json:"aggr,omitempty"`
Length int `json:"length,omitempty"`
Scope string `json:"scope,omitempty"`
Expression string `json:"expression,omitempty"`
Start *float64 `json:"start,omitempty"`
End *float64 `json:"end,omitempty"`
Interval *int `json:"interval,omitempty"`
Aggr *string `json:"aggr,omitempty"`
Length *int `json:"length,omitempty"`
Scope *string `json:"scope,omitempty"`
Expression *string `json:"expression,omitempty"`
}
// reqPostSeries from /api/v1/series

View File

@ -23,7 +23,7 @@ func (client *Client) Snapshot(query string, start, end time.Time, eventQuery st
v.Add("event_query", eventQuery)
out := struct {
SnapshotURL string `json:"snapshot_url"`
SnapshotURL string `json:"snapshot_url,omitempty"`
}{}
if err := client.doJsonRequest("GET", "/v1/graph/snapshot?"+v.Encode(), nil, &out); err != nil {
return "", err

View File

@ -13,7 +13,7 @@ type TagMap map[string][]string
// reqGetTags is the container for receiving tags.
type reqGetTags struct {
Tags TagMap `json:"tags,omitempty"`
Tags *TagMap `json:"tags,omitempty"`
}
// regGetHostTags is for receiving a slice of tags.
@ -31,7 +31,7 @@ func (client *Client) GetTags(source string) (TagMap, error) {
if err := client.doJsonRequest("GET", uri, nil, &out); err != nil {
return nil, err
}
return out.Tags, nil
return *out.Tags, nil
}
// GetHostTags returns a slice of tags for a given host and source.
@ -58,11 +58,11 @@ func (client *Client) GetHostTagsBySource(host, source string) (TagMap, error) {
if err := client.doJsonRequest("GET", uri, nil, &out); err != nil {
return nil, err
}
return out.Tags, nil
return *out.Tags, nil
}
// AddTagsToHost does exactly what it says on the tin. Given a list of tags,
// add them to the host. The source is optionally specificed, and defaults to
// add them to the host. The source is optionally specified, and defaults to
// "users" as per the API documentation.
func (client *Client) AddTagsToHost(host, source string, tags []string) error {
uri := "/v1/tags/hosts/" + host

View File

@ -9,13 +9,13 @@
package datadog
type User struct {
Handle string `json:"handle,omitempty"`
Email string `json:"email,omitempty"`
Name string `json:"name,omitempty"`
Role string `json:"role,omitempty"`
IsAdmin bool `json:"is_admin,omitempty"`
Verified bool `json:"verified,omitempty"`
Disabled bool `json:"disabled,omitempty"`
Handle *string `json:"handle,omitempty"`
Email *string `json:"email,omitempty"`
Name *string `json:"name,omitempty"`
Role *string `json:"role,omitempty"`
IsAdmin *bool `json:"is_admin,omitempty"`
Verified *bool `json:"verified,omitempty"`
Disabled *bool `json:"disabled,omitempty"`
}
// reqInviteUsers contains email addresses to send invitations to.
@ -30,10 +30,10 @@ func (client *Client) InviteUsers(emails []string) error {
}
// CreateUser creates an user account for an email address
func (self *Client) CreateUser(handle, name string) (*User, error) {
func (self *Client) CreateUser(handle, name *string) (*User, error) {
in := struct {
Handle string `json:"handle"`
Name string `json:"name"`
Handle *string `json:"handle"`
Name *string `json:"name"`
}{
Handle: handle,
Name: name,
@ -50,7 +50,7 @@ func (self *Client) CreateUser(handle, name string) (*User, error) {
// internal type to retrieve users from the api
type usersData struct {
Users []User `json:"users"`
Users []User `json:"users,omitempty"`
}
// GetUsers returns all user, or an error if not found
@ -79,7 +79,7 @@ func (client *Client) GetUser(handle string) (user User, err error) {
// UpdateUser updates a user with the content of `user`,
// and returns an error if the update failed
func (client *Client) UpdateUser(user User) error {
uri := "/v1/user/" + user.Handle
uri := "/v1/user/" + *user.Handle
return client.doJsonRequest("PUT", uri, user, nil)
}

24
vendor/vendor.json vendored
View File

@ -2155,18 +2155,18 @@
"path": "github.com/maximilien/softlayer-go/softlayer",
"revision": "85659debe44fab5792fc92cf755c04b115b9dc19"
},
{
"checksumSHA1": "OUZ1FFXyKs+Cfg9M9rmXqqweQck=",
"path": "github.com/miekg/dns",
"revision": "db96a2b759cdef4f11a34506a42eb8d1290c598e",
"revisionTime": "2016-07-26T03:20:27Z"
},
{
"checksumSHA1": "GSum+utW01N3KeMdvAPnsW0TemM=",
"path": "github.com/michaelklishin/rabbit-hole",
"revision": "88550829bcdcf614361c73459c903578eb44074e",
"revisionTime": "2016-07-06T11:10:56Z"
},
{
"checksumSHA1": "OUZ1FFXyKs+Cfg9M9rmXqqweQck=",
"path": "github.com/miekg/dns",
"revision": "db96a2b759cdef4f11a34506a42eb8d1290c598e",
"revisionTime": "2016-07-26T03:20:27Z"
},
{
"checksumSHA1": "7niW29CvYceZ6zbia6b/LT+yD/M=",
"path": "github.com/mitchellh/cli",
@ -2664,12 +2664,6 @@
"path": "github.com/ziutek/mymysql/thrsafe",
"revision": "75ce5fbba34b1912a3641adbd58cf317d7315821"
},
{
"checksumSHA1": "uynUzdKeOsfi7flpYWFx835Nafo=",
"path": "github.com/zorkian/go-datadog-api",
"revision": "6308094e4aca46eb16a227b50be29772242bf3aa",
"revisionTime": "2017-02-02T00:47:50Z"
},
{
"checksumSHA1": "9x64JhJGo6z8TS0Q33cGcR64kjA=",
"path": "golang.org/x/crypto/curve25519",
@ -3003,6 +2997,12 @@
"path": "gopkg.in/yaml.v2",
"revision": "a5b47d31c556af34a302ce5d659e6fea44d90de0",
"revisionTime": "2016-09-28T15:37:09Z"
},
{
"checksumSHA1": "OcJdNALtPXoFOieAZjznhm7ufuU=",
"path": "gopkg.in/zorkian/go-datadog-api.v2",
"revision": "f005bb24262365e93726b94d89e6cd8a26a7455e",
"revisionTime": "2017-02-20T05:26:33Z"
}
],
"rootPath": "github.com/hashicorp/terraform"