provider/datadog: Improve datadog timeboard support (#10027)

* Update to latest version of go-datadog-api

* Updates to  latest go-datadog-api version, which adds more complete
timeboard support.

* Add more complete timeboard support

* Adds in support for missing timeboard fields, so now we can have nice
things like conditional formats and more.

* Document new fields in datadog_timeboard resource

* Add acceptance test for datadog timeboard changes
This commit is contained in:
Brendan Shaklovitz 2016-12-05 07:16:47 -06:00 committed by Paul Stack
parent f13a92b52e
commit 122e2f8170
14 changed files with 690 additions and 1343 deletions

View File

@ -19,7 +19,7 @@ func resourceDatadogMonitor() *schema.Resource {
Delete: resourceDatadogMonitorDelete,
Exists: resourceDatadogMonitorExists,
Importer: &schema.ResourceImporter{
State: resourceDatadogImport,
State: resourceDatadogMonitorImport,
},
Schema: map[string]*schema.Schema{
@ -73,7 +73,7 @@ func resourceDatadogMonitor() *schema.Resource {
},
},
},
DiffSuppressFunc: supressDataDogFloatIntDiff,
DiffSuppressFunc: suppressDataDogFloatIntDiff,
},
"notify_no_data": &schema.Schema{
Type: schema.TypeBool,
@ -393,7 +393,7 @@ func resourceDatadogMonitorDelete(d *schema.ResourceData, meta interface{}) erro
return nil
}
func resourceDatadogImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
func resourceDatadogMonitorImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
if err := resourceDatadogMonitorRead(d, meta); err != nil {
return nil, err
}
@ -402,7 +402,7 @@ func resourceDatadogImport(d *schema.ResourceData, meta interface{}) ([]*schema.
// Ignore any diff that results from the mix of ints or floats returned from the
// DataDog API.
func supressDataDogFloatIntDiff(k, old, new string, d *schema.ResourceData) bool {
func suppressDataDogFloatIntDiff(k, old, new string, d *schema.ResourceData) bool {
oF, err := strconv.ParseFloat(old, 64)
if err != nil {
log.Printf("Error parsing float of old value (%s): %s", old, err)

View File

@ -1,6 +1,7 @@
package datadog
import (
"encoding/json"
"fmt"
"log"
"strconv"
@ -11,7 +12,6 @@ import (
)
func resourceDatadogTimeboard() *schema.Resource {
request := &schema.Schema{
Type: schema.TypeList,
Required: true,
@ -35,6 +35,91 @@ func resourceDatadogTimeboard() *schema.Resource {
Type: schema.TypeMap,
Optional: true,
},
"conditional_format": &schema.Schema{
Type: schema.TypeList,
Optional: true,
Description: "A list of conditional formatting rules.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"palette": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "The palette to use if this condition is met.",
},
"comparator": &schema.Schema{
Type: schema.TypeString,
Required: true,
Description: "Comparator (<, >, etc)",
},
"custom_bg_color": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "Custom background color (e.g., #205081)",
},
"value": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "Value that is threshold for conditional format",
},
"custom_fg_color": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "Custom foreground color (e.g., #59afe1)",
},
},
},
},
"change_type": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "Type of change for change graphs.",
},
"order_direction": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "Sort change graph in ascending or descending order.",
},
"compare_to": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "The time period to compare change against in change graphs.",
},
"increase_good": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Description: "Decides whether to represent increases as good or bad in change graphs.",
},
"order_by": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "The field a change graph will be ordered by.",
},
"extra_col": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "If set to 'present', this will include the present values in change graphs.",
},
},
},
}
marker := &schema.Schema{
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"type": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"value": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"label": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
},
},
}
@ -50,11 +135,74 @@ func resourceDatadogTimeboard() *schema.Resource {
Required: true,
Description: "The name of the graph.",
},
"events": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Description: "Filter for events to be overlayed on the graph.",
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"viz": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"request": request,
"marker": marker,
"yaxis": &schema.Schema{
Type: schema.TypeMap,
Optional: true,
},
"autoscale": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Description: "Automatically scale graphs",
},
"text_align": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "How to align text",
},
"precision": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "How many digits to show",
},
"custom_unit": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "Use a custom unit (like 'users')",
},
"style": &schema.Schema{
Type: schema.TypeMap,
Optional: true,
},
"group": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Description: "A list of groupings for hostmap type graphs.",
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"include_no_metric_hosts": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Description: "Include hosts without metrics in hostmap graphs",
},
"scope": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Description: "A list of scope filters for hostmap type graphs.",
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"include_ungrouped_hosts": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Description: "Include ungrouped hosts in hostmap graphs",
},
},
},
}
@ -90,6 +238,9 @@ func resourceDatadogTimeboard() *schema.Resource {
Read: resourceDatadogTimeboardRead,
Delete: resourceDatadogTimeboardDelete,
Exists: resourceDatadogTimeboardExists,
Importer: &schema.ResourceImporter{
State: resourceDatadogTimeboardImport,
},
Schema: map[string]*schema.Schema{
"title": &schema.Schema{
@ -113,6 +264,33 @@ func resourceDatadogTimeboard() *schema.Resource {
}
}
func appendConditionalFormats(datadogRequest *datadog.GraphDefinitionRequest, terraformFormats *[]interface{}) {
for _, t_ := range *terraformFormats {
t := t_.(map[string]interface{})
d := datadog.DashboardConditionalFormat{
Comparator: t["comparator"].(string),
}
if palette, ok := t["palette"]; ok {
d.Palette = palette.(string)
}
if customBgColor, ok := t["custom_bg_color"]; ok {
d.CustomBgColor = customBgColor.(string)
}
if customFgColor, ok := t["custom_fg_color"]; ok {
d.CustomFgColor = customFgColor.(string)
}
if value, ok := t["value"]; ok {
d.Value = json.Number(value.(string))
}
datadogRequest.ConditionalFormats = append(datadogRequest.ConditionalFormats, d)
}
}
func buildTemplateVariables(terraformTemplateVariables *[]interface{}) *[]datadog.TemplateVariable {
datadogTemplateVariables := make([]datadog.TemplateVariable, len(*terraformTemplateVariables))
for i, t_ := range *terraformTemplateVariables {
@ -137,14 +315,84 @@ func appendRequests(datadogGraph *datadog.Graph, terraformRequests *[]interface{
}
if style, ok := t["style"]; ok {
s, _ := style.(map[string]interface{})
if palette, ok := s["palette"]; ok {
d.Style.Palette = palette.(string)
style := struct {
Palette *string `json:"palette,omitempty"`
Width *string `json:"width,omitempty"`
Type *string `json:"type,omitempty"`
}{}
if palette_, ok := s["palette"]; ok {
palette := palette_.(string)
style.Palette = &palette
}
if width, ok := s["width"]; ok {
width := width.(string)
style.Width = &width
}
if type_, ok := s["type"]; ok {
style_type := type_.(string)
style.Type = &style_type
}
d.Style = &style
}
if changeType, ok := t["change_type"]; ok {
d.ChangeType = changeType.(string)
}
if compareTo, ok := t["compare_to"]; ok {
d.CompareTo = compareTo.(string)
}
if increaseGood, ok := t["increase_good"]; ok {
d.IncreaseGood = increaseGood.(bool)
}
if orderBy, ok := t["order_by"]; ok {
d.OrderBy = orderBy.(string)
}
if extraCol, ok := t["extra_col"]; ok {
d.ExtraCol = extraCol.(string)
}
if orderDirection, ok := t["order_direction"]; ok {
d.OrderDirection = orderDirection.(string)
}
if terraformConditionalFormats, ok := t["conditional_format"]; ok {
formats := terraformConditionalFormats.([]interface{})
appendConditionalFormats(&d, &formats)
}
datadogGraph.Definition.Requests = append(datadogGraph.Definition.Requests, d)
}
}
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)
}
}
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),
}
if label, ok := t["label"]; ok {
d.Label = label.(string)
}
datadogGraph.Definition.Markers = append(datadogGraph.Definition.Markers, d)
}
}
func buildGraphs(terraformGraphs *[]interface{}) *[]datadog.Graph {
datadogGraphs := make([]datadog.Graph, len(*terraformGraphs))
for i, t_ := range *terraformGraphs {
@ -152,6 +400,85 @@ func buildGraphs(terraformGraphs *[]interface{}) *[]datadog.Graph {
datadogGraphs[i] = datadog.Graph{Title: t["title"].(string)}
d := &datadogGraphs[i]
d.Definition.Viz = 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 max_, ok := yaxis["max"]; ok {
max, _ := strconv.ParseFloat(max_.(string), 64)
d.Definition.Yaxis.Max = &max
}
if scale_, ok := yaxis["scale"]; ok {
scale := scale_.(string)
d.Definition.Yaxis.Scale = &scale
}
}
if autoscale, ok := t["autoscale"]; ok {
d.Definition.Autoscale = autoscale.(bool)
}
if textAlign, ok := t["text_align"]; ok {
d.Definition.TextAlign = textAlign.(string)
}
if precision, ok := t["precision"]; ok {
d.Definition.Precision = precision.(string)
}
if customUnit, ok := t["custom_unit"]; ok {
d.Definition.CustomUnit = customUnit.(string)
}
if style, ok := t["style"]; ok {
s := style.(map[string]interface{})
style := struct {
Palette *string `json:"palette,omitempty"`
PaletteFlip *bool `json:"paletteFlip,omitempty"`
}{}
if palette_, ok := s["palette"]; ok {
palette := palette_.(string)
style.Palette = &palette
}
if paletteFlip_, ok := s["palette_flip"]; ok {
paletteFlip, _ := strconv.ParseBool(paletteFlip_.(string))
style.PaletteFlip = &paletteFlip
}
d.Definition.Style = &style
}
if groups, ok := t["group"]; ok {
for _, g := range groups.(*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)
}
if scopes, ok := t["scope"]; ok {
for _, s := range scopes.(*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)
}
terraformMarkers := t["marker"].([]interface{})
appendMarkers(d, &terraformMarkers)
terraformEvents := t["events"].(*schema.Set).List()
appendEvents(d, &terraformEvents)
terraformRequests := t["request"].([]interface{})
appendRequests(d, &terraformRequests)
}
@ -203,6 +530,115 @@ func resourceDatadogTimeboardUpdate(d *schema.ResourceData, meta interface{}) er
return resourceDatadogTimeboardRead(d, meta)
}
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 {
style := map[string]string{}
if datadogRequest.Style.Palette != nil {
style["palette"] = *datadogRequest.Style.Palette
}
if datadogRequest.Style.Type != nil {
style["type"] = *datadogRequest.Style.Type
}
if datadogRequest.Style.Width != nil {
style["width"] = *datadogRequest.Style.Width
}
request["style"] = style
}
conditionalFormats := []map[string]interface{}{}
for _, cf := range datadogRequest.ConditionalFormats {
conditionalFormat := map[string]interface{}{
"palette": cf.Palette,
"comparator": cf.Comparator,
"custom_bg_color": cf.CustomBgColor,
"value": cf.Value,
"custom_fg_color": cf.CustomFgColor,
}
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
*requests = append(*requests, request)
}
}
func buildTerraformGraph(datadog_graph datadog.Graph) map[string]interface{} {
graph := map[string]interface{}{}
graph["title"] = datadog_graph.Title
definition := datadog_graph.Definition
graph["viz"] = definition.Viz
events := []string{}
for _, datadog_event := range definition.Events {
events = append(events, datadog_event.Query)
}
graph["events"] = events
markers := []map[string]interface{}{}
for _, datadog_marker := range definition.Markers {
marker := map[string]interface{}{
"type": datadog_marker.Type,
"value": datadog_marker.Value,
"label": datadog_marker.Label,
}
markers = append(markers, marker)
}
graph["marker"] = markers
yaxis := map[string]string{}
if definition.Yaxis.Min != nil {
yaxis["min"] = strconv.FormatFloat(*definition.Yaxis.Min, 'f', -1, 64)
}
if definition.Yaxis.Max != nil {
yaxis["max"] = strconv.FormatFloat(*definition.Yaxis.Max, 'f', -1, 64)
}
if definition.Yaxis.Scale != nil {
yaxis["scale"] = *definition.Yaxis.Scale
}
graph["yaxis"] = yaxis
graph["autoscale"] = definition.Autoscale
graph["text_align"] = definition.TextAlign
graph["precision"] = definition.Precision
graph["custom_unit"] = definition.CustomUnit
if definition.Style != nil {
style := map[string]string{}
if definition.Style.Palette != nil {
style["palette"] = *definition.Style.Palette
}
if definition.Style.PaletteFlip != nil {
style["palette_flip"] = strconv.FormatBool(*definition.Style.PaletteFlip)
}
graph["style"] = style
}
graph["group"] = definition.Groups
graph["include_no_metric_hosts"] = definition.IncludeNoMetricHosts
graph["scope"] = definition.Scopes
graph["include_ungrouped_hosts"] = definition.IncludeUngroupedHosts
requests := []map[string]interface{}{}
appendTerraformGraphRequests(definition.Requests, &requests)
graph["request"] = requests
return graph
}
func resourceDatadogTimeboardRead(d *schema.ResourceData, meta interface{}) error {
id, err := strconv.Atoi(d.Id())
if err != nil {
@ -215,8 +651,24 @@ func resourceDatadogTimeboardRead(d *schema.ResourceData, meta interface{}) erro
log.Printf("[DEBUG] timeboard: %v", timeboard)
d.Set("title", timeboard.Title)
d.Set("description", timeboard.Description)
d.Set("graphs", timeboard.Graphs)
d.Set("template_variables", timeboard.TemplateVariables)
graphs := []map[string]interface{}{}
for _, datadog_graph := range timeboard.Graphs {
graphs = append(graphs, buildTerraformGraph(datadog_graph))
}
d.Set("graph", graphs)
templateVariables := []map[string]string{}
for _, templateVariable := range timeboard.TemplateVariables {
tv := map[string]string{
"name": templateVariable.Name,
"prefix": templateVariable.Prefix,
"default": templateVariable.Default,
}
templateVariables = append(templateVariables, tv)
}
d.Set("template_variable", templateVariables)
return nil
}
@ -231,6 +683,13 @@ func resourceDatadogTimeboardDelete(d *schema.ResourceData, meta interface{}) er
return nil
}
func resourceDatadogTimeboardImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
if err := resourceDatadogTimeboardRead(d, meta); err != nil {
return nil, err
}
return []*schema.ResourceData{d}, nil
}
func resourceDatadogTimeboardExists(d *schema.ResourceData, meta interface{}) (b bool, e error) {
id, err := strconv.Atoi(d.Id())
if err != nil {

View File

@ -14,7 +14,7 @@ import (
const config1 = `
resource "datadog_timeboard" "acceptance_test" {
title = "Acceptance Test Timeboard"
description = "Created using the Datadog prodivider in Terraform"
description = "Created using the Datadog provider in Terraform"
read_only = true
graph {
title = "Top System CPU by Docker container"
@ -29,7 +29,7 @@ resource "datadog_timeboard" "acceptance_test" {
const config2 = `
resource "datadog_timeboard" "acceptance_test" {
title = "Acceptance Test Timeboard"
description = "Created using the Datadog prodivider in Terraform"
description = "Created using the Datadog provider in Terraform"
graph {
title = "Redis latency (ms)"
viz = "timeseries"
@ -62,6 +62,56 @@ resource "datadog_timeboard" "acceptance_test" {
}
`
const config3 = `
resource "datadog_timeboard" "acceptance_test" {
title = "Acceptance Test Timeboard"
description = "Created using the Datadog provider in Terraform"
graph {
title = "Redis latency (ms)"
viz = "timeseries"
request {
q = "avg:redis.info.latency_ms{$host}"
}
events = ["sources:capistrano"]
marker {
label = "High Latency"
type = "error solid"
value = "y > 100"
}
yaxis {
max = "50"
scale = "sqrt"
}
}
graph {
title = "ELB Requests"
viz = "query_value"
request {
q = "sum:aws.elb.request_count{*}.as_count()"
type = "line"
conditional_format {
comparator = ">"
value = "1000"
palette = "white_on_red"
}
conditional_format {
comparator = "<="
value = "1000"
palette = "white_on_green"
}
}
custom_unit = "hits"
precision = "*"
text_align = "left"
}
template_variable {
name = "host"
prefix = "host"
}
}
`
func TestAccDatadogTimeboard_update(t *testing.T) {
step1 := resource.TestStep{
@ -69,7 +119,7 @@ func TestAccDatadogTimeboard_update(t *testing.T) {
Check: resource.ComposeTestCheckFunc(
checkExists,
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "title", "Acceptance Test Timeboard"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "description", "Created using the Datadog prodivider in Terraform"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "description", "Created using the Datadog provider in Terraform"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "read_only", "true"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.0.title", "Top System CPU by Docker container"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.0.viz", "toplist"),
@ -82,7 +132,7 @@ func TestAccDatadogTimeboard_update(t *testing.T) {
Check: resource.ComposeTestCheckFunc(
checkExists,
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "title", "Acceptance Test Timeboard"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "description", "Created using the Datadog prodivider in Terraform"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "description", "Created using the Datadog provider in Terraform"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.0.title", "Redis latency (ms)"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.0.viz", "timeseries"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.0.request.0.q", "avg:redis.info.latency_ms{$host}"),
@ -98,11 +148,44 @@ func TestAccDatadogTimeboard_update(t *testing.T) {
),
}
step3 := resource.TestStep{
Config: config3,
Check: resource.ComposeTestCheckFunc(
checkExists,
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "title", "Acceptance Test Timeboard"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "description", "Created using the Datadog provider in Terraform"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.0.title", "Redis latency (ms)"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.0.viz", "timeseries"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.0.request.0.q", "avg:redis.info.latency_ms{$host}"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.0.events.#", "1"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.0.marker.0.label", "High Latency"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.0.marker.0.type", "error solid"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.0.marker.0.value", "y > 100"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.0.yaxis.max", "50"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.0.yaxis.scale", "sqrt"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.1.title", "ELB Requests"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.1.viz", "query_value"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.1.request.0.q", "sum:aws.elb.request_count{*}.as_count()"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.1.request.0.type", "line"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.1.request.0.conditional_format.0.comparator", ">"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.1.request.0.conditional_format.0.value", "1000"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.1.request.0.conditional_format.0.palette", "white_on_red"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.1.request.0.conditional_format.1.comparator", "<="),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.1.request.0.conditional_format.1.value", "1000"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.1.request.0.conditional_format.1.palette", "white_on_green"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.1.custom_unit", "hits"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.1.precision", "*"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "graph.1.text_align", "left"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "template_variable.0.name", "host"),
resource.TestCheckResourceAttr("datadog_timeboard.acceptance_test", "template_variable.0.prefix", "host"),
),
}
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: checkDestroy,
Steps: []resource.TestStep{step1, step2},
Steps: []resource.TestStep{step1, step2, step3},
})
}

View File

@ -3,16 +3,16 @@ package datadog
type Check struct {
Check string `json:"check"`
HostName string `json:"host_name"`
Status status `json:"status"`
Status Status `json:"status"`
Timestamp string `json:"timestamp,omitempty"`
Message string `json:"message,omitempty"`
Tags []string `json:"tags,omitempty"`
}
type status int
type Status int
const (
OK status = iota
OK Status = iota
WARNING
CRITICAL
UNKNOWN

View File

@ -9,6 +9,7 @@
package datadog
import (
"encoding/json"
"fmt"
)
@ -19,18 +20,63 @@ type GraphDefinitionRequest struct {
Aggregator string
ConditionalFormats []DashboardConditionalFormat `json:"conditional_formats,omitempty"`
Type string `json:"type,omitempty"`
Style struct {
Palette string `json:"palette,omitempty"`
Style *struct {
Palette *string `json:"palette,omitempty"`
Width *string `json:"width,omitempty"`
Type *string `json:"type,omitempty"`
} `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"`
Events []struct{} `json:"events"`
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"`
}
@ -74,12 +120,12 @@ type reqGetDashboard struct {
}
type DashboardConditionalFormat struct {
Palette string `json:"palette,omitempty"`
Comparator string `json:"comparator,omitempty"`
CustomBgColor string `json:"custom_bg_color,omitempty"`
Value float64 `json:"value,omitempty"`
Inverted bool `json:"invert,omitempty"`
CustomFgColor string `json:"custom_fg_color,omitempty"`
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.

View File

@ -25,10 +25,11 @@ type Event struct {
AlertType string `json:"alert_type,omitempty"`
Host string `json:"host,omitempty"`
Aggregation string `json:"aggregation_key,omitempty"`
SourceType string `json:"source_type,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"`
}
// reqGetEvent is the container for receiving a single event.

View File

@ -1,138 +0,0 @@
package integration
import (
"github.com/zorkian/go-datadog-api"
"testing"
)
func init() {
client = initTest()
}
func TestCreateAndDeleteDashboard(t *testing.T) {
expected := getTestDashboard()
// create the dashboard and compare it
actual, err := client.CreateDashboard(expected)
if err != nil {
t.Fatalf("Creating a dashboard failed when it shouldn't. (%s)", err)
}
defer cleanUpDashboard(t, actual.Id)
assertDashboardEquals(t, actual, expected)
// now try to fetch it freshly and compare it again
actual, err = client.GetDashboard(actual.Id)
if err != nil {
t.Fatalf("Retrieving a dashboard failed when it shouldn't. (%s)", err)
}
assertDashboardEquals(t, actual, expected)
}
func TestUpdateDashboard(t *testing.T) {
expected := getTestDashboard()
board, err := client.CreateDashboard(expected)
if err != nil {
t.Fatalf("Creating a dashboard failed when it shouldn't. (%s)", err)
}
defer cleanUpDashboard(t, board.Id)
board.Title = "___New-Test-Board___"
if err := client.UpdateDashboard(board); err != nil {
t.Fatalf("Updating a dashboard failed when it shouldn't: %s", err)
}
actual, err := client.GetDashboard(board.Id)
if err != nil {
t.Fatalf("Retrieving a dashboard failed when it shouldn't: %s", err)
}
assertDashboardEquals(t, actual, board)
}
func TestGetDashboards(t *testing.T) {
boards, err := client.GetDashboards()
if err != nil {
t.Fatalf("Retrieving dashboards failed when it shouldn't: %s", err)
}
num := len(boards)
board := createTestDashboard(t)
defer cleanUpDashboard(t, board.Id)
boards, err = client.GetDashboards()
if err != nil {
t.Fatalf("Retrieving dashboards failed when it shouldn't: %s", err)
}
if num+1 != len(boards) {
t.Fatalf("Number of dashboards didn't match expected: %d != %d", len(boards), num+1)
}
}
func getTestDashboard() *datadog.Dashboard {
return &datadog.Dashboard{
Title: "___Test-Board___",
Description: "Testboard description",
TemplateVariables: []datadog.TemplateVariable{},
Graphs: createGraph(),
}
}
func createTestDashboard(t *testing.T) *datadog.Dashboard {
board := getTestDashboard()
board, err := client.CreateDashboard(board)
if err != nil {
t.Fatalf("Creating a dashboard failed when it shouldn't: %s", err)
}
return board
}
func cleanUpDashboard(t *testing.T, id int) {
if err := client.DeleteDashboard(id); err != nil {
t.Fatalf("Deleting a dashboard failed when it shouldn't. Manual cleanup needed. (%s)", err)
}
deletedBoard, err := client.GetDashboard(id)
if deletedBoard != nil {
t.Fatal("Dashboard hasn't been deleted when it should have been. Manual cleanup needed.")
}
if err == nil {
t.Fatal("Fetching deleted dashboard didn't lead to an error. Manual cleanup needed.")
}
}
type TestGraphDefintionRequests struct {
Query string `json:"q"`
Stacked bool `json:"stacked"`
}
func createGraph() []datadog.Graph {
graphDefinition := datadog.Graph{}.Definition
graphDefinition.Viz = "timeseries"
r := datadog.Graph{}.Definition.Requests
graphDefinition.Requests = append(r, TestGraphDefintionRequests{Query: "avg:system.mem.free{*}", Stacked: false})
graph := datadog.Graph{Title: "Mandatory graph", Definition: graphDefinition}
graphs := []datadog.Graph{}
graphs = append(graphs, graph)
return graphs
}
func assertDashboardEquals(t *testing.T, actual, expected *datadog.Dashboard) {
if actual.Title != expected.Title {
t.Errorf("Dashboard title does not match: %s != %s", actual.Title, expected.Title)
}
if actual.Description != expected.Description {
t.Errorf("Dashboard description does not match: %s != %s", actual.Description, expected.Description)
}
if len(actual.Graphs) != len(expected.Graphs) {
t.Errorf("Number of Dashboard graphs does not match: %d != %d", len(actual.Graphs), len(expected.Graphs))
}
if len(actual.TemplateVariables) != len(expected.TemplateVariables) {
t.Errorf("Number of Dashboard template variables does not match: %d != %d", len(actual.TemplateVariables), len(expected.TemplateVariables))
}
}

View File

@ -1,110 +0,0 @@
package integration
import (
"github.com/stretchr/testify/assert"
"github.com/zorkian/go-datadog-api"
"testing"
)
func init() {
client = initTest()
}
func TestCreateAndDeleteDowntime(t *testing.T) {
expected := getTestDowntime()
// create the downtime and compare it
actual := createTestDowntime(t)
defer cleanUpDowntime(t, actual.Id)
// Set ID of our original struct to zero we we can easily compare the results
expected.Id = actual.Id
assert.Equal(t, expected, actual)
actual, err := client.GetDowntime(actual.Id)
if err != nil {
t.Fatalf("Retrieving a downtime failed when it shouldn't: (%s)", err)
}
assert.Equal(t, expected, actual)
}
func TestUpdateDowntime(t *testing.T) {
downtime := createTestDowntime(t)
downtime.Scope = []string{"env:downtime_test", "env:downtime_test2"}
defer cleanUpDowntime(t, downtime.Id)
if err := client.UpdateDowntime(downtime); err != nil {
t.Fatalf("Updating a downtime failed when it shouldn't: %s", err)
}
actual, err := client.GetDowntime(downtime.Id)
if err != nil {
t.Fatalf("Retrieving a downtime failed when it shouldn't: %s", err)
}
assert.Equal(t, downtime, actual)
}
func TestGetDowntime(t *testing.T) {
downtimes, err := client.GetDowntimes()
if err != nil {
t.Fatalf("Retrieving downtimes failed when it shouldn't: %s", err)
}
num := len(downtimes)
downtime := createTestDowntime(t)
defer cleanUpDowntime(t, downtime.Id)
downtimes, err = client.GetDowntimes()
if err != nil {
t.Fatalf("Retrieving downtimes failed when it shouldn't: %s", err)
}
if num+1 != len(downtimes) {
t.Fatalf("Number of downtimes didn't match expected: %d != %d", len(downtimes), num+1)
}
}
func getTestDowntime() *datadog.Downtime {
r := &datadog.Recurrence{
Type: "weeks",
Period: 1,
WeekDays: []string{"Mon", "Tue", "Wed", "Thu", "Fri"},
}
return &datadog.Downtime{
Message: "Test downtime message",
Scope: []string{"env:downtime_test"},
Start: 1577836800,
End: 1577840400,
Recurrence: r,
}
}
func createTestDowntime(t *testing.T) *datadog.Downtime {
downtime := getTestDowntime()
downtime, err := client.CreateDowntime(downtime)
if err != nil {
t.Fatalf("Creating a downtime failed when it shouldn't: %s", err)
}
return downtime
}
func cleanUpDowntime(t *testing.T, id int) {
if err := client.DeleteDowntime(id); err != nil {
t.Fatalf("Deleting a downtime failed when it shouldn't. Manual cleanup needed. (%s)", err)
}
deletedDowntime, err := client.GetDowntime(id)
if deletedDowntime != nil && deletedDowntime.Canceled == 0 {
t.Fatal("Downtime hasn't been deleted when it should have been. Manual cleanup needed.")
}
if err == nil && deletedDowntime.Canceled == 0 {
t.Fatal("Fetching deleted downtime didn't lead to an error and downtime Canceled not set.")
}
}

View File

@ -1,152 +0,0 @@
package integration
import (
"github.com/stretchr/testify/assert"
"github.com/zorkian/go-datadog-api"
"testing"
)
func init() {
client = initTest()
}
func TestCreateAndDeleteMonitor(t *testing.T) {
expected := getTestMonitor()
// create the monitor and compare it
actual := createTestMonitor(t)
defer cleanUpMonitor(t, actual.Id)
// Set ID of our original struct to zero we we can easily compare the results
expected.Id = actual.Id
assert.Equal(t, expected, actual)
actual, err := client.GetMonitor(actual.Id)
if err != nil {
t.Fatalf("Retrieving a monitor failed when it shouldn't: (%s)", err)
}
assert.Equal(t, expected, actual)
}
func TestUpdateMonitor(t *testing.T) {
monitor := createTestMonitor(t)
defer cleanUpMonitor(t, monitor.Id)
monitor.Name = "___New-Test-Monitor___"
if err := client.UpdateMonitor(monitor); err != nil {
t.Fatalf("Updating a monitor failed when it shouldn't: %s", err)
}
actual, err := client.GetMonitor(monitor.Id)
if err != nil {
t.Fatalf("Retrieving a monitor failed when it shouldn't: %s", err)
}
assert.Equal(t, monitor, actual)
}
func TestGetMonitor(t *testing.T) {
monitors, err := client.GetMonitors()
if err != nil {
t.Fatalf("Retrieving monitors failed when it shouldn't: %s", err)
}
num := len(monitors)
monitor := createTestMonitor(t)
defer cleanUpMonitor(t, monitor.Id)
monitors, err = client.GetMonitors()
if err != nil {
t.Fatalf("Retrieving monitors failed when it shouldn't: %s", err)
}
if num+1 != len(monitors) {
t.Fatalf("Number of monitors didn't match expected: %d != %d", len(monitors), num+1)
}
}
func TestMuteUnmuteMonitor(t *testing.T) {
monitor := createTestMonitor(t)
defer cleanUpMonitor(t, monitor.Id)
// Mute
err := client.MuteMonitor(monitor.Id)
if err != nil {
t.Fatalf("Failed to mute monitor")
}
monitor, err = client.GetMonitor(monitor.Id)
if err != nil {
t.Fatalf("Retrieving monitors failed when it shouldn't: %s", err)
}
// Mute without options will result in monitor.Options.Silenced
// to have a key of "*" with value 0
assert.Equal(t, 0, monitor.Options.Silenced["*"])
// Unmute
err = client.UnmuteMonitor(monitor.Id)
if err != nil {
t.Fatalf("Failed to unmute monitor")
}
// Update remote state
monitor, err = client.GetMonitor(monitor.Id)
if err != nil {
t.Fatalf("Retrieving monitors failed when it shouldn't: %s", err)
}
// Assert this map is empty
assert.Equal(t, 0, len(monitor.Options.Silenced))
}
/*
Testing of global mute and unmuting has not been added for following reasons:
* Disabling and enabling of global monitoring does an @all mention which is noisy
* It exposes risk to users that run integration tests in their main account
* There is no endpoint to verify success
*/
func getTestMonitor() *datadog.Monitor {
o := datadog.Options{
NotifyNoData: true,
NoDataTimeframe: 60,
Silenced: map[string]int{},
}
return &datadog.Monitor{
Message: "Test message",
Query: "avg(last_15m):avg:system.disk.in_use{*} by {host,device} > 0.8",
Name: "Test monitor",
Options: o,
Type: "metric alert",
}
}
func createTestMonitor(t *testing.T) *datadog.Monitor {
monitor := getTestMonitor()
monitor, err := client.CreateMonitor(monitor)
if err != nil {
t.Fatalf("Creating a monitor failed when it shouldn't: %s", err)
}
return monitor
}
func cleanUpMonitor(t *testing.T, id int) {
if err := client.DeleteMonitor(id); err != nil {
t.Fatalf("Deleting a monitor failed when it shouldn't. Manual cleanup needed. (%s)", err)
}
deletedMonitor, err := client.GetMonitor(id)
if deletedMonitor != nil {
t.Fatal("Monitor hasn't been deleted when it should have been. Manual cleanup needed.")
}
if err == nil {
t.Fatal("Fetching deleted monitor didn't lead to an error.")
}
}

View File

@ -1,766 +0,0 @@
package integration
import (
"testing"
"github.com/zorkian/go-datadog-api"
)
func TestAlertValueWidget(t *testing.T) {
board := createTestScreenboard(t)
defer cleanUpScreenboard(t, board.Id)
expected := datadog.Widget{}.AlertValueWidget
expected.X = 1
expected.Y = 1
expected.Width = 5
expected.Height = 5
expected.TitleText = "foo"
expected.TitleAlign = "center"
expected.TitleSize = 1
expected.Title = true
expected.TextSize = "auto"
expected.Precision = 2
expected.AlertId = 1
expected.Type = "alert_value"
expected.Unit = "auto"
expected.AddTimeframe = false
w := datadog.Widget{AlertValueWidget: expected}
board.Widgets = append(board.Widgets, w)
if err := client.UpdateScreenboard(board); err != nil {
t.Fatalf("Updating a screenboard failed: %s", err)
}
actual, err := client.GetScreenboard(board.Id)
if err != nil {
t.Fatalf("Retrieving a screenboard failed: %s", err)
}
actualWidget := actual.Widgets[0].AlertValueWidget
assertEquals(t, "x", actualWidget.X, expected.X)
assertEquals(t, "y", actualWidget.Y, expected.Y)
assertEquals(t, "height", actualWidget.Height, expected.Height)
assertEquals(t, "width", actualWidget.Width, expected.Width)
assertEquals(t, "title_text", actualWidget.TitleText, expected.TitleText)
assertEquals(t, "title_size", actualWidget.TitleSize, expected.TitleSize)
assertEquals(t, "title_align", actualWidget.TitleAlign, expected.TitleAlign)
assertEquals(t, "title", actualWidget.Title, expected.Title)
assertEquals(t, "text_size", actualWidget.TextSize, expected.TextSize)
assertEquals(t, "precision", actualWidget.Precision, expected.Precision)
assertEquals(t, "alert_id", actualWidget.AlertId, expected.AlertId)
assertEquals(t, "type", actualWidget.Type, expected.Type)
assertEquals(t, "unit", actualWidget.Unit, expected.Unit)
assertEquals(t, "add_timeframe", actualWidget.AddTimeframe, expected.AddTimeframe)
}
func TestChangeWidget(t *testing.T) {
board := createTestScreenboard(t)
defer cleanUpScreenboard(t, board.Id)
expected := datadog.Widget{}.ChangeWidget
expected.X = 1
expected.Y = 1
expected.Width = 5
expected.Height = 5
expected.TitleText = "foo"
expected.TitleAlign = "center"
expected.TitleSize = 1
expected.Title = true
expected.Aggregator = "min"
expected.TileDef = datadog.TileDef{}
w := datadog.Widget{ChangeWidget: expected}
board.Widgets = append(board.Widgets, w)
if err := client.UpdateScreenboard(board); err != nil {
t.Fatalf("Updating a screenboard failed: %s", err)
}
actual, err := client.GetScreenboard(board.Id)
if err != nil {
t.Fatalf("Retrieving a screenboard failed: %s", err)
}
actualWidget := actual.Widgets[0].ChangeWidget
assertEquals(t, "x", actualWidget.X, expected.X)
assertEquals(t, "y", actualWidget.Y, expected.Y)
assertEquals(t, "height", actualWidget.Height, expected.Height)
assertEquals(t, "width", actualWidget.Width, expected.Width)
assertEquals(t, "title_text", actualWidget.TitleText, expected.TitleText)
assertEquals(t, "title_size", actualWidget.TitleSize, expected.TitleSize)
assertEquals(t, "title_align", actualWidget.TitleAlign, expected.TitleAlign)
assertEquals(t, "title", actualWidget.Title, expected.Title)
assertEquals(t, "aggregator", actualWidget.Aggregator, expected.Aggregator)
assertTileDefEquals(t, actualWidget.TileDef, expected.TileDef)
}
func TestGraphWidget(t *testing.T) {
board := createTestScreenboard(t)
defer cleanUpScreenboard(t, board.Id)
expected := datadog.Widget{}.GraphWidget
expected.X = 1
expected.Y = 1
expected.Width = 5
expected.Height = 5
expected.TitleText = "foo"
expected.TitleAlign = "center"
expected.TitleSize = 1
expected.Title = true
expected.Timeframe = "1d"
expected.Type = "alert_graph"
expected.Legend = true
expected.LegendSize = 5
expected.TileDef = datadog.TileDef{}
w := datadog.Widget{GraphWidget: expected}
board.Widgets = append(board.Widgets, w)
if err := client.UpdateScreenboard(board); err != nil {
t.Fatalf("Updating a screenboard failed: %s", err)
}
actual, err := client.GetScreenboard(board.Id)
if err != nil {
t.Fatalf("Retrieving a screenboard failed: %s", err)
}
actualWidget := actual.Widgets[0].GraphWidget
assertEquals(t, "x", actualWidget.X, expected.X)
assertEquals(t, "y", actualWidget.Y, expected.Y)
assertEquals(t, "height", actualWidget.Height, expected.Height)
assertEquals(t, "width", actualWidget.Width, expected.Width)
assertEquals(t, "title_text", actualWidget.TitleText, expected.TitleText)
assertEquals(t, "title_size", actualWidget.TitleSize, expected.TitleSize)
assertEquals(t, "title_align", actualWidget.TitleAlign, expected.TitleAlign)
assertEquals(t, "title", actualWidget.Title, expected.Title)
assertEquals(t, "type", actualWidget.Type, expected.Type)
assertEquals(t, "timeframe", actualWidget.Timeframe, expected.Timeframe)
assertEquals(t, "legend", actualWidget.Legend, expected.Legend)
assertEquals(t, "legend_size", actualWidget.LegendSize, expected.LegendSize)
assertTileDefEquals(t, actualWidget.TileDef, expected.TileDef)
}
func TestEventTimelineWidget(t *testing.T) {
board := createTestScreenboard(t)
defer cleanUpScreenboard(t, board.Id)
expected := datadog.Widget{}.EventTimelineWidget
expected.X = 1
expected.Y = 1
expected.Width = 5
expected.Height = 5
expected.TitleText = "foo"
expected.TitleAlign = "center"
expected.TitleSize = 1
expected.Title = true
expected.Query = "avg:system.load.1{foo} by {bar}"
expected.Timeframe = "1d"
expected.Type = "alert_graph"
w := datadog.Widget{EventTimelineWidget: expected}
board.Widgets = append(board.Widgets, w)
if err := client.UpdateScreenboard(board); err != nil {
t.Fatalf("Updating a screenboard failed: %s", err)
}
actual, err := client.GetScreenboard(board.Id)
if err != nil {
t.Fatalf("Retrieving a screenboard failed: %s", err)
}
actualWidget := actual.Widgets[0].EventTimelineWidget
assertEquals(t, "x", actualWidget.X, expected.X)
assertEquals(t, "y", actualWidget.Y, expected.Y)
assertEquals(t, "height", actualWidget.Height, expected.Height)
assertEquals(t, "width", actualWidget.Width, expected.Width)
assertEquals(t, "title_text", actualWidget.TitleText, expected.TitleText)
assertEquals(t, "title_size", actualWidget.TitleSize, expected.TitleSize)
assertEquals(t, "title_align", actualWidget.TitleAlign, expected.TitleAlign)
assertEquals(t, "title", actualWidget.Title, expected.Title)
assertEquals(t, "type", actualWidget.Type, expected.Type)
assertEquals(t, "query", actualWidget.Query, expected.Query)
assertEquals(t, "timeframe", actualWidget.Timeframe, expected.Timeframe)
}
func TestAlertGraphWidget(t *testing.T) {
board := createTestScreenboard(t)
defer cleanUpScreenboard(t, board.Id)
expected := datadog.Widget{}.AlertGraphWidget
expected.X = 1
expected.Y = 1
expected.Width = 5
expected.Height = 5
expected.TitleText = "foo"
expected.TitleAlign = "center"
expected.TitleSize = 1
expected.Title = true
expected.VizType = ""
expected.Timeframe = "1d"
expected.AddTimeframe = false
expected.AlertId = 1
expected.Type = "alert_graph"
w := datadog.Widget{AlertGraphWidget: expected}
board.Widgets = append(board.Widgets, w)
if err := client.UpdateScreenboard(board); err != nil {
t.Fatalf("Updating a screenboard failed: %s", err)
}
actual, err := client.GetScreenboard(board.Id)
if err != nil {
t.Fatalf("Retrieving a screenboard failed: %s", err)
}
actualWidget := actual.Widgets[0].AlertGraphWidget
assertEquals(t, "x", actualWidget.X, expected.X)
assertEquals(t, "y", actualWidget.Y, expected.Y)
assertEquals(t, "height", actualWidget.Height, expected.Height)
assertEquals(t, "width", actualWidget.Width, expected.Width)
assertEquals(t, "title_text", actualWidget.TitleText, expected.TitleText)
assertEquals(t, "title_size", actualWidget.TitleSize, expected.TitleSize)
assertEquals(t, "title_align", actualWidget.TitleAlign, expected.TitleAlign)
assertEquals(t, "title", actualWidget.Title, expected.Title)
assertEquals(t, "type", actualWidget.Type, expected.Type)
assertEquals(t, "viz_type", actualWidget.VizType, expected.VizType)
assertEquals(t, "timeframe", actualWidget.Timeframe, expected.Timeframe)
assertEquals(t, "add_timeframe", actualWidget.AddTimeframe, expected.AddTimeframe)
assertEquals(t, "alert_id", actualWidget.AlertId, expected.AlertId)
}
func TestHostMapWidget(t *testing.T) {
board := createTestScreenboard(t)
defer cleanUpScreenboard(t, board.Id)
expected := datadog.Widget{}.HostMapWidget
expected.X = 1
expected.Y = 1
expected.Width = 5
expected.Height = 5
expected.TitleText = "foo"
expected.TitleAlign = "center"
expected.TitleSize = 1
expected.Title = true
expected.Type = "check_status"
expected.Query = "avg:system.load.1{foo} by {bar}"
expected.Timeframe = "1d"
expected.Legend = true
expected.LegendSize = 5
expected.TileDef = datadog.TileDef{}
w := datadog.Widget{HostMapWidget: expected}
board.Widgets = append(board.Widgets, w)
if err := client.UpdateScreenboard(board); err != nil {
t.Fatalf("Updating a screenboard failed: %s", err)
}
actual, err := client.GetScreenboard(board.Id)
if err != nil {
t.Fatalf("Retrieving a screenboard failed: %s", err)
}
actualWidget := actual.Widgets[0].HostMapWidget
assertEquals(t, "x", actualWidget.X, expected.X)
assertEquals(t, "y", actualWidget.Y, expected.Y)
assertEquals(t, "height", actualWidget.Height, expected.Height)
assertEquals(t, "width", actualWidget.Width, expected.Width)
assertEquals(t, "title_text", actualWidget.TitleText, expected.TitleText)
assertEquals(t, "title_size", actualWidget.TitleSize, expected.TitleSize)
assertEquals(t, "title_align", actualWidget.TitleAlign, expected.TitleAlign)
assertEquals(t, "title", actualWidget.Title, expected.Title)
assertEquals(t, "type", actualWidget.Type, expected.Type)
assertEquals(t, "query", actualWidget.Query, expected.Query)
assertEquals(t, "timeframe", actualWidget.Timeframe, expected.Timeframe)
assertEquals(t, "query", actualWidget.Query, expected.Query)
assertEquals(t, "legend", actualWidget.Legend, expected.Legend)
assertEquals(t, "legend_size", actualWidget.LegendSize, expected.LegendSize)
assertTileDefEquals(t, actualWidget.TileDef, expected.TileDef)
}
func TestCheckStatusWidget(t *testing.T) {
board := createTestScreenboard(t)
defer cleanUpScreenboard(t, board.Id)
expected := datadog.Widget{}.CheckStatusWidget
expected.X = 1
expected.Y = 1
expected.Width = 5
expected.Height = 5
expected.TitleText = "foo"
expected.TitleAlign = "center"
expected.TitleSize = 1
expected.Title = true
expected.Type = "check_status"
expected.Tags = "foo"
expected.Timeframe = "1d"
expected.Timeframe = "1d"
expected.Check = "datadog.agent.up"
expected.Group = "foo"
expected.Grouping = "check"
w := datadog.Widget{CheckStatusWidget: expected}
board.Widgets = append(board.Widgets, w)
if err := client.UpdateScreenboard(board); err != nil {
t.Fatalf("Updating a screenboard failed: %s", err)
}
actual, err := client.GetScreenboard(board.Id)
if err != nil {
t.Fatalf("Retrieving a screenboard failed: %s", err)
}
actualWidget := actual.Widgets[0].CheckStatusWidget
assertEquals(t, "x", actualWidget.X, expected.X)
assertEquals(t, "y", actualWidget.Y, expected.Y)
assertEquals(t, "height", actualWidget.Height, expected.Height)
assertEquals(t, "width", actualWidget.Width, expected.Width)
assertEquals(t, "title_text", actualWidget.TitleText, expected.TitleText)
assertEquals(t, "title_size", actualWidget.TitleSize, expected.TitleSize)
assertEquals(t, "title_align", actualWidget.TitleAlign, expected.TitleAlign)
assertEquals(t, "title", actualWidget.Title, expected.Title)
assertEquals(t, "type", actualWidget.Type, expected.Type)
assertEquals(t, "tags", actualWidget.Tags, expected.Tags)
assertEquals(t, "timeframe", actualWidget.Timeframe, expected.Timeframe)
assertEquals(t, "check", actualWidget.Check, expected.Check)
assertEquals(t, "group", actualWidget.Group, expected.Group)
assertEquals(t, "grouping", actualWidget.Grouping, expected.Grouping)
}
func TestIFrameWidget(t *testing.T) {
board := createTestScreenboard(t)
defer cleanUpScreenboard(t, board.Id)
expected := datadog.Widget{}.IFrameWidget
expected.X = 1
expected.Y = 1
expected.Width = 5
expected.Height = 5
expected.TitleText = "foo"
expected.TitleAlign = "center"
expected.TitleSize = 1
expected.Title = true
expected.Url = "http://www.example.com"
expected.Type = "iframe"
w := datadog.Widget{IFrameWidget: expected}
board.Widgets = append(board.Widgets, w)
if err := client.UpdateScreenboard(board); err != nil {
t.Fatalf("Updating a screenboard failed: %s", err)
}
actual, err := client.GetScreenboard(board.Id)
if err != nil {
t.Fatalf("Retrieving a screenboard failed: %s", err)
}
actualWidget := actual.Widgets[0].IFrameWidget
assertEquals(t, "x", actualWidget.X, expected.X)
assertEquals(t, "y", actualWidget.Y, expected.Y)
assertEquals(t, "height", actualWidget.Height, expected.Height)
assertEquals(t, "width", actualWidget.Width, expected.Width)
assertEquals(t, "title_text", actualWidget.TitleText, expected.TitleText)
assertEquals(t, "title_size", actualWidget.TitleSize, expected.TitleSize)
assertEquals(t, "title_align", actualWidget.TitleAlign, expected.TitleAlign)
assertEquals(t, "title", actualWidget.Title, expected.Title)
assertEquals(t, "url", actualWidget.Url, expected.Url)
assertEquals(t, "type", actualWidget.Type, expected.Type)
}
func TestNoteWidget(t *testing.T) {
board := createTestScreenboard(t)
defer cleanUpScreenboard(t, board.Id)
expected := datadog.Widget{}.NoteWidget
expected.X = 1
expected.Y = 1
expected.Width = 5
expected.Height = 5
expected.TitleText = "foo"
expected.TitleAlign = "center"
expected.TitleSize = 1
expected.Title = true
expected.Color = "green"
expected.FontSize = 5
expected.RefreshEvery = 60
expected.TickPos = "foo"
expected.TickEdge = "bar"
expected.Html = "<strong>baz</strong>"
expected.Tick = false
expected.Note = "quz"
expected.AutoRefresh = false
w := datadog.Widget{NoteWidget: expected}
board.Widgets = append(board.Widgets, w)
if err := client.UpdateScreenboard(board); err != nil {
t.Fatalf("Updating a screenboard failed: %s", err)
}
actual, err := client.GetScreenboard(board.Id)
if err != nil {
t.Fatalf("Retrieving a screenboard failed: %s", err)
}
actualWidget := actual.Widgets[0].NoteWidget
assertEquals(t, "x", actualWidget.X, expected.X)
assertEquals(t, "y", actualWidget.Y, expected.Y)
assertEquals(t, "height", actualWidget.Height, expected.Height)
assertEquals(t, "width", actualWidget.Width, expected.Width)
assertEquals(t, "title_text", actualWidget.TitleText, expected.TitleText)
assertEquals(t, "title_size", actualWidget.TitleSize, expected.TitleSize)
assertEquals(t, "title_align", actualWidget.TitleAlign, expected.TitleAlign)
assertEquals(t, "title", actualWidget.Title, expected.Title)
assertEquals(t, "color", actualWidget.Color, expected.Color)
assertEquals(t, "front_size", actualWidget.FontSize, expected.FontSize)
assertEquals(t, "refresh_every", actualWidget.RefreshEvery, expected.RefreshEvery)
assertEquals(t, "tick_pos", actualWidget.TickPos, expected.TickPos)
assertEquals(t, "tick_edge", actualWidget.TickEdge, expected.TickEdge)
assertEquals(t, "tick", actualWidget.Tick, expected.Tick)
assertEquals(t, "html", actualWidget.Html, expected.Html)
assertEquals(t, "note", actualWidget.Note, expected.Note)
assertEquals(t, "auto_refresh", actualWidget.AutoRefresh, expected.AutoRefresh)
}
func TestToplistWidget(t *testing.T) {
board := createTestScreenboard(t)
defer cleanUpScreenboard(t, board.Id)
expected := datadog.Widget{}.ToplistWidget
expected.X = 1
expected.Y = 1
expected.Width = 5
expected.Height = 5
expected.Type = "toplist"
expected.TitleText = "foo"
expected.TitleSize.Auto = false
expected.TitleSize.Size = 5
expected.TitleAlign = "center"
expected.Title = false
expected.Timeframe = "5m"
expected.Legend = false
expected.LegendSize = 5
w := datadog.Widget{ToplistWidget: expected}
board.Widgets = append(board.Widgets, w)
if err := client.UpdateScreenboard(board); err != nil {
t.Fatalf("Updating a screenboard failed: %s", err)
}
actual, err := client.GetScreenboard(board.Id)
if err != nil {
t.Fatalf("Retrieving a screenboard failed: %s", err)
}
actualWidget := actual.Widgets[0].ToplistWidget
assertEquals(t, "x", actualWidget.X, expected.X)
assertEquals(t, "y", actualWidget.Y, expected.Y)
assertEquals(t, "height", actualWidget.Height, expected.Height)
assertEquals(t, "width", actualWidget.Width, expected.Width)
assertEquals(t, "title_text", actualWidget.TitleText, expected.TitleText)
assertEquals(t, "title_size", actualWidget.TitleSize, expected.TitleSize)
assertEquals(t, "title_align", actualWidget.TitleAlign, expected.TitleAlign)
assertEquals(t, "legend", actualWidget.Legend, expected.Legend)
assertEquals(t, "legend_size", actualWidget.LegendSize, expected.LegendSize)
}
func TestEventSteamWidget(t *testing.T) {
board := createTestScreenboard(t)
defer cleanUpScreenboard(t, board.Id)
expected := datadog.Widget{}.EventStreamWidget
expected.EventSize = "1"
expected.Width = 1
expected.Height = 1
expected.X = 1
expected.Y = 1
expected.Query = "foo"
expected.Timeframe = "5w"
expected.Title = false
expected.TitleAlign = "center"
expected.TitleSize.Auto = false
expected.TitleSize.Size = 5
expected.TitleText = "bar"
expected.Type = "baz"
w := datadog.Widget{EventStreamWidget: expected}
board.Widgets = append(board.Widgets, w)
if err := client.UpdateScreenboard(board); err != nil {
t.Fatalf("Updating a screenboard failed: %s", err)
}
actual, err := client.GetScreenboard(board.Id)
if err != nil {
t.Fatalf("Retrieving a screenboard failed: %s", err)
}
actualWidget := actual.Widgets[0].EventStreamWidget
assertEquals(t, "event_size", actualWidget.EventSize, expected.EventSize)
assertEquals(t, "width", actualWidget.Width, expected.Width)
assertEquals(t, "height", actualWidget.Height, expected.Height)
assertEquals(t, "x", actualWidget.X, expected.X)
assertEquals(t, "y", actualWidget.Y, expected.Y)
assertEquals(t, "query", actualWidget.Query, expected.Query)
assertEquals(t, "timeframe", actualWidget.Timeframe, expected.Timeframe)
assertEquals(t, "title", actualWidget.Title, expected.Title)
assertEquals(t, "title_align", actualWidget.TitleAlign, expected.TitleAlign)
assertEquals(t, "title_size", actualWidget.TitleSize, expected.TitleSize)
assertEquals(t, "title_text", actualWidget.TitleText, expected.TitleText)
assertEquals(t, "type", actualWidget.Type, expected.Type)
}
func TestImageWidget(t *testing.T) {
board := createTestScreenboard(t)
defer cleanUpScreenboard(t, board.Id)
expected := datadog.Widget{}.ImageWidget
expected.Width = 1
expected.Height = 1
expected.X = 1
expected.Y = 1
expected.Title = false
expected.TitleAlign = "center"
expected.TitleSize.Auto = false
expected.TitleSize.Size = 5
expected.TitleText = "bar"
expected.Type = "baz"
expected.Url = "qux"
expected.Sizing = "quuz"
w := datadog.Widget{ImageWidget: expected}
board.Widgets = append(board.Widgets, w)
if err := client.UpdateScreenboard(board); err != nil {
t.Fatalf("Updating a screenboard failed: %s", err)
}
actual, err := client.GetScreenboard(board.Id)
if err != nil {
t.Fatalf("Retrieving a screenboard failed: %s", err)
}
actualWidget := actual.Widgets[0].ImageWidget
assertEquals(t, "width", actualWidget.Width, expected.Width)
assertEquals(t, "height", actualWidget.Height, expected.Height)
assertEquals(t, "x", actualWidget.X, expected.X)
assertEquals(t, "y", actualWidget.Y, expected.Y)
assertEquals(t, "title", actualWidget.Title, expected.Title)
assertEquals(t, "title_align", actualWidget.TitleAlign, expected.TitleAlign)
assertEquals(t, "title_size", actualWidget.TitleSize, expected.TitleSize)
assertEquals(t, "title_text", actualWidget.TitleText, expected.TitleText)
assertEquals(t, "type", actualWidget.Type, expected.Type)
assertEquals(t, "url", actualWidget.Url, expected.Url)
assertEquals(t, "sizing", actualWidget.Sizing, expected.Sizing)
}
func TestFreeTextWidget(t *testing.T) {
board := createTestScreenboard(t)
defer cleanUpScreenboard(t, board.Id)
expected := datadog.Widget{}.FreeTextWidget
expected.X = 1
expected.Y = 1
expected.Height = 10
expected.Width = 10
expected.Text = "Test"
expected.FontSize = "16"
expected.TextAlign = "center"
w := datadog.Widget{FreeTextWidget: expected}
board.Widgets = append(board.Widgets, w)
if err := client.UpdateScreenboard(board); err != nil {
t.Fatalf("Updating a screenboard failed: %s", err)
}
actual, err := client.GetScreenboard(board.Id)
if err != nil {
t.Fatalf("Retrieving a screenboard failed: %s", err)
}
actualWidget := actual.Widgets[0].FreeTextWidget
assertEquals(t, "font-size", actualWidget.FontSize, expected.FontSize)
assertEquals(t, "height", actualWidget.Height, expected.Height)
assertEquals(t, "width", actualWidget.Width, expected.Width)
assertEquals(t, "x", actualWidget.X, expected.X)
assertEquals(t, "y", actualWidget.Y, expected.Y)
assertEquals(t, "text", actualWidget.Text, expected.Text)
assertEquals(t, "text-align", actualWidget.TextAlign, expected.TextAlign)
assertEquals(t, "type", actualWidget.Type, expected.Type)
}
func TestTimeseriesWidget(t *testing.T) {
board := createTestScreenboard(t)
defer cleanUpScreenboard(t, board.Id)
expected := datadog.Widget{}.TimeseriesWidget
expected.X = 1
expected.Y = 1
expected.Width = 20
expected.Height = 30
expected.Title = true
expected.TitleAlign = "centre"
expected.TitleSize = datadog.TextSize{Size: 16}
expected.TitleText = "Test"
expected.Timeframe = "1m"
w := datadog.Widget{TimeseriesWidget: expected}
board.Widgets = append(board.Widgets, w)
if err := client.UpdateScreenboard(board); err != nil {
t.Fatalf("Updating a screenboard failed: %s", err)
}
actual, err := client.GetScreenboard(board.Id)
if err != nil {
t.Fatalf("Retrieving a screenboard failed: %s", err)
}
actualWidget := actual.Widgets[0].TimeseriesWidget
assertEquals(t, "height", actualWidget.Height, expected.Height)
assertEquals(t, "width", actualWidget.Width, expected.Width)
assertEquals(t, "x", actualWidget.X, expected.X)
assertEquals(t, "y", actualWidget.Y, expected.Y)
assertEquals(t, "title", actualWidget.Title, expected.Title)
assertEquals(t, "title-align", actualWidget.TitleAlign, expected.TitleAlign)
assertEquals(t, "title-size.size", actualWidget.TitleSize.Size, expected.TitleSize.Size)
assertEquals(t, "title-size.auto", actualWidget.TitleSize.Auto, expected.TitleSize.Auto)
assertEquals(t, "title-text", actualWidget.TitleText, expected.TitleText)
assertEquals(t, "type", actualWidget.Type, expected.Type)
assertEquals(t, "timeframe", actualWidget.Timeframe, expected.Timeframe)
assertEquals(t, "legend", actualWidget.Legend, expected.Legend)
assertTileDefEquals(t, actualWidget.TileDef, expected.TileDef)
}
func TestQueryValueWidget(t *testing.T) {
board := createTestScreenboard(t)
defer cleanUpScreenboard(t, board.Id)
expected := datadog.Widget{}.QueryValueWidget
expected.X = 1
expected.Y = 1
expected.Width = 20
expected.Height = 30
expected.Title = true
expected.TitleAlign = "centre"
expected.TitleSize = datadog.TextSize{Size: 16}
expected.TitleText = "Test"
expected.Timeframe = "1m"
expected.TimeframeAggregator = "sum"
expected.Aggregator = "min"
expected.Query = "docker.containers.running"
expected.MetricType = "standard"
/* TODO: add test for conditional formats
"conditional_formats": [{
"comparator": ">",
"color": "white_on_red",
"custom_bg_color": null,
"value": 1,
"invert": false,
"custom_fg_color": null}],
*/
expected.IsValidQuery = true
expected.ResultCalcFunc = "raw"
expected.Aggregator = "avg"
expected.CalcFunc = "raw"
w := datadog.Widget{QueryValueWidget: expected}
board.Widgets = append(board.Widgets, w)
if err := client.UpdateScreenboard(board); err != nil {
t.Fatalf("Updating a screenboard failed: %s", err)
}
actual, err := client.GetScreenboard(board.Id)
if err != nil {
t.Fatalf("Retrieving a screenboard failed: %s", err)
}
actualWidget := actual.Widgets[0].QueryValueWidget
assertEquals(t, "height", actualWidget.Height, expected.Height)
assertEquals(t, "width", actualWidget.Width, expected.Width)
assertEquals(t, "x", actualWidget.X, expected.X)
assertEquals(t, "y", actualWidget.Y, expected.Y)
assertEquals(t, "title", actualWidget.Title, expected.Title)
assertEquals(t, "title-align", actualWidget.TitleAlign, expected.TitleAlign)
assertEquals(t, "title-size.size", actualWidget.TitleSize.Size, expected.TitleSize.Size)
assertEquals(t, "title-size.auto", actualWidget.TitleSize.Auto, expected.TitleSize.Auto)
assertEquals(t, "title-text", actualWidget.TitleText, expected.TitleText)
assertEquals(t, "type", actualWidget.Type, expected.Type)
assertEquals(t, "timeframe", actualWidget.Timeframe, expected.Timeframe)
assertEquals(t, "timeframe-aggregator", actualWidget.TimeframeAggregator, expected.TimeframeAggregator)
assertEquals(t, "aggregator", actualWidget.Aggregator, expected.Aggregator)
assertEquals(t, "query", actualWidget.Query, expected.Query)
assertEquals(t, "is_valid_query", actualWidget.IsValidQuery, expected.IsValidQuery)
assertEquals(t, "res_calc_func", actualWidget.ResultCalcFunc, expected.ResultCalcFunc)
assertEquals(t, "aggr", actualWidget.Aggregator, expected.Aggregator)
}
func assertTileDefEquals(t *testing.T, actual datadog.TileDef, expected datadog.TileDef) {
assertEquals(t, "num-events", len(actual.Events), len(expected.Events))
assertEquals(t, "num-requests", len(actual.Requests), len(expected.Requests))
assertEquals(t, "viz", actual.Viz, expected.Viz)
for i, event := range actual.Events {
assertEquals(t, "event-query", event.Query, expected.Events[i].Query)
}
for i, request := range actual.Requests {
assertEquals(t, "request-query", request.Query, expected.Requests[i].Query)
assertEquals(t, "request-type", request.Type, expected.Requests[i].Type)
}
}
func assertEquals(t *testing.T, attribute string, a, b interface{}) {
if a != b {
t.Errorf("The two %s values '%v' and '%v' are not equal", attribute, a, b)
}
}

View File

@ -1,143 +0,0 @@
package integration
import (
"github.com/zorkian/go-datadog-api"
"testing"
)
func init() {
client = initTest()
}
func TestCreateAndDeleteScreenboard(t *testing.T) {
expected := getTestScreenboard()
// create the screenboard and compare it
actual, err := client.CreateScreenboard(expected)
if err != nil {
t.Fatalf("Creating a screenboard failed when it shouldn't. (%s)", err)
}
defer cleanUpScreenboard(t, actual.Id)
assertScreenboardEquals(t, actual, expected)
// now try to fetch it freshly and compare it again
actual, err = client.GetScreenboard(actual.Id)
if err != nil {
t.Fatalf("Retrieving a screenboard failed when it shouldn't. (%s)", err)
}
assertScreenboardEquals(t, actual, expected)
}
func TestShareAndRevokeScreenboard(t *testing.T) {
expected := getTestScreenboard()
// create the screenboard
actual, err := client.CreateScreenboard(expected)
if err != nil {
t.Fatalf("Creating a screenboard failed when it shouldn't: %s", err)
}
defer cleanUpScreenboard(t, actual.Id)
// share screenboard and verify it was shared
var response datadog.ScreenShareResponse
err = client.ShareScreenboard(actual.Id, &response)
if err != nil {
t.Fatalf("Failed to share screenboard: %s", err)
}
// revoke screenboard
err = client.RevokeScreenboard(actual.Id)
if err != nil {
t.Fatalf("Failed to revoke sharing of screenboard: %s", err)
}
}
func TestUpdateScreenboard(t *testing.T) {
board := createTestScreenboard(t)
defer cleanUpScreenboard(t, board.Id)
board.Title = "___New-Test-Board___"
if err := client.UpdateScreenboard(board); err != nil {
t.Fatalf("Updating a screenboard failed when it shouldn't: %s", err)
}
actual, err := client.GetScreenboard(board.Id)
if err != nil {
t.Fatalf("Retrieving a screenboard failed when it shouldn't: %s", err)
}
assertScreenboardEquals(t, actual, board)
}
func TestGetScreenboards(t *testing.T) {
boards, err := client.GetScreenboards()
if err != nil {
t.Fatalf("Retrieving screenboards failed when it shouldn't: %s", err)
}
num := len(boards)
board := createTestScreenboard(t)
defer cleanUpScreenboard(t, board.Id)
boards, err = client.GetScreenboards()
if err != nil {
t.Fatalf("Retrieving screenboards failed when it shouldn't: %s", err)
}
if num+1 != len(boards) {
t.Fatalf("Number of screenboards didn't match expected: %d != %d", len(boards), num+1)
}
}
func getTestScreenboard() *datadog.Screenboard {
return &datadog.Screenboard{
Title: "___Test-Board___",
Height: "600",
Width: "800",
Widgets: []datadog.Widget{},
}
}
func createTestScreenboard(t *testing.T) *datadog.Screenboard {
board := getTestScreenboard()
board, err := client.CreateScreenboard(board)
if err != nil {
t.Fatalf("Creating a screenboard failed when it shouldn't: %s", err)
}
return board
}
func cleanUpScreenboard(t *testing.T, id int) {
if err := client.DeleteScreenboard(id); err != nil {
t.Fatalf("Deleting a screenboard failed when it shouldn't. Manual cleanup needed. (%s)", err)
}
deletedBoard, err := client.GetScreenboard(id)
if deletedBoard != nil {
t.Fatal("Screenboard hasn't been deleted when it should have been. Manual cleanup needed.")
}
if err == nil {
t.Fatal("Fetching deleted screenboard didn't lead to an error. Manual cleanup needed.")
}
}
func assertScreenboardEquals(t *testing.T, actual, expected *datadog.Screenboard) {
if actual.Title != expected.Title {
t.Errorf("Screenboard title does not match: %s != %s", actual.Title, expected.Title)
}
if actual.Width != expected.Width {
t.Errorf("Screenboard width does not match: %s != %s", actual.Width, expected.Width)
}
if actual.Height != expected.Height {
t.Errorf("Screenboard width does not match: %s != %s", actual.Height, expected.Height)
}
if len(actual.Widgets) != len(expected.Widgets) {
t.Errorf("Number of Screenboard widgets does not match: %d != %d", len(actual.Widgets), len(expected.Widgets))
}
}

View File

@ -11,7 +11,9 @@ package datadog
import (
"encoding/json"
"fmt"
"net/url"
"strconv"
"strings"
)
type ThresholdCount struct {
@ -104,6 +106,36 @@ func (self *Client) GetMonitor(id int) (*Monitor, error) {
return &out, nil
}
// GetMonitor retrieves monitors by name
func (self *Client) GetMonitorsByName(name string) ([]Monitor, error) {
var out reqMonitors
query, err := url.ParseQuery(fmt.Sprintf("name=%v", name))
if err != nil {
return nil, err
}
err = self.doJsonRequest("GET", fmt.Sprintf("/v1/monitor?%v", query.Encode()), nil, &out.Monitors)
if err != nil {
return nil, err
}
return out.Monitors, nil
}
// GetMonitor retrieves monitors by a slice of tags
func (self *Client) GetMonitorsByTags(tags []string) ([]Monitor, error) {
var out reqMonitors
query, err := url.ParseQuery(fmt.Sprintf("monitor_tags=%v", strings.Join(tags, ",")))
if err != nil {
return nil, err
}
err = self.doJsonRequest("GET", fmt.Sprintf("/v1/monitor?%v", query.Encode()), nil, &out.Monitors)
if err != nil {
return nil, err
}
return out.Monitors, nil
}
// DeleteMonitor removes a monitor from the system
func (self *Client) DeleteMonitor(id int) error {
return self.doJsonRequest("DELETE", fmt.Sprintf("/v1/monitor/%d", id),

6
vendor/vendor.json vendored
View File

@ -2296,10 +2296,10 @@
"revision": "75ce5fbba34b1912a3641adbd58cf317d7315821"
},
{
"checksumSHA1": "jBiNbkwHKwnuGfkaccnLc/1rzto=",
"checksumSHA1": "U817qc0NaamC2zeUcZknLpnkrOw=",
"path": "github.com/zorkian/go-datadog-api",
"revision": "f9f89391f35f5c8eafed4b75b5797b9b23851908",
"revisionTime": "2016-10-04T18:54:04Z"
"revision": "73d5b59ca18ee5e94fb449e001ed3f724fa0634e",
"revisionTime": "2016-11-30T17:19:56Z"
},
{
"path": "golang.org/x/crypto/curve25519",

View File

@ -28,7 +28,7 @@ resource "datadog_timeboard" "redis" {
type = "bars"
}
}
graph {
title = "Redis memory usage"
viz = "timeseries"
@ -76,6 +76,33 @@ Nested `graph` blocks have the following structure:
* `title` - (Required) The name of the graph.
* `viz` - (Required) The type of visualization to use for the graph. Valid choices are "change", "distribution", "heatmap", "hostmap", "query_value", timeseries", and "toplist".
* `request` - Nested block describing a graph definition request (a metric query to plot on the graph). The structure of this block is described below. Multiple request blocks are allowed within a graph block.
* `events` - (Optional) A list of event filter strings. Note that, while supported by the Datadog API, the Datadog UI does not (currently) support multiple event filters very well, so use at your own risk.
* `autoscale` - (Optional) Boolean that determines whether to autoscale graphs.
* `precision` - (Optional) Number of digits displayed, use `*` for full precision.
* `custom_unit` - (Optional) Display a custom unit on the graph (such as 'hertz')
* `text_align` - (Optional) How to align text in the graph, can be one of 'left', 'center', or 'right'.
* `style` - (Optional) Nested block describing hostmaps. The structure of this block is described below.
* `group` - (Optional) List of groups for hostmaps (shown as 'group by' in the UI).
* `include_no_metric_hosts` - (Optional) If set to true, will display hosts on hostmap that have no reported metrics.
* `include_ungrouped_hosts` - (Optional) If set to true, will display hosts without groups on hostmaps.
* `scope` - (Optional) List of scopes for hostmaps (shown as 'filter by' in the UI).
* `yaxis` - (Optional) Nested block describing modifications to the yaxis rendering. The structure of this block is described below.
* `marker` - (Optional) Nested block describing lines / ranges added to graph for formatting. The structure of this block is described below. Multiple marker blocks are allowed within a graph block.
#### Nested `graph` `marker` blocks
Nested `graph` `marker` blocks have the following structure:
* `type` - (Required) How the marker lines will look. Possible values are {"error", "warning", "info", "ok"} {"dashed", "solid", "bold"}. Example: "error dashed".
* `value` - (Required) Mathematical expression describing the marker. Examples: "y > 1", "-5 < y < 0", "y = 19".
* `label` - (Optional) A label for the line or range.
{error, warning, info, ok} {dashed, solid, bold}
#### Nested `graph` `yaxis` block
* `min` - (Optional) Minimum bound for the graph's yaxis, a string.
* `max` - (Optional) Maximum bound for the graph's yaxis, a string.
* `scale` - (Optional) How to scale the yaxis. Possible values are: "linear", "log", "sqrt", "pow##" (eg. pow2, pow0.5, 2 is used if only "pow" was provided). Default: "linear".
#### Nested `graph` `request` blocks
@ -86,11 +113,19 @@ Nested `graph` `request` blocks have the following structure:
* `type` - (Optional) Choose how to draw the graph. For example: "lines", "bars" or "areas". Default: "lines".
* `style` - (Optional) Nested block to customize the graph style.
### Nested `style` block
### Nested `graph` `style` block
The nested `style` block is used specifically for styling `hostmap` graphs, and has the following structure:
The nested `style` blocks has the following structure (only `palette` is supported right now):
* `palette` - (Optional) Spectrum of colors to use when styling a hostmap. For example: "green_to_orange", "yellow_to_green", "YlOrRd", or "hostmap_blues". Default: "green_to_orange".
* `palette_flip` - (Optional) Flip how the hostmap is rendered. For example, with the default palette, low values are represented as green, with high values as orange. If palette_flip is "true", then low values will be orange, and high values will be green.
### Nested `graph` `request` `style` block
The nested `style` blocks has the following structure:
* `palette` - (Optional) Color of the line drawn. For example: "classic", "cool", "warm", "purple", "orange" or "gray". Default: "classic".
* `width` - (Optional) Line width. Possible values: "thin", "normal", "thick". Default: "normal".
* `type` - (Optional) Type of line drawn. Possible values: "dashed", "solid", "dotted". Default: "solid".
### Nested `template_variable` blocks