Merge branch 'elblivion-librato-alerts'
This commit is contained in:
commit
019a13eb7f
|
@ -28,6 +28,8 @@ func Provider() terraform.ResourceProvider {
|
||||||
ResourcesMap: map[string]*schema.Resource{
|
ResourcesMap: map[string]*schema.Resource{
|
||||||
"librato_space": resourceLibratoSpace(),
|
"librato_space": resourceLibratoSpace(),
|
||||||
"librato_space_chart": resourceLibratoSpaceChart(),
|
"librato_space_chart": resourceLibratoSpaceChart(),
|
||||||
|
"librato_alert": resourceLibratoAlert(),
|
||||||
|
"librato_service": resourceLibratoService(),
|
||||||
},
|
},
|
||||||
|
|
||||||
ConfigureFunc: providerConfigure,
|
ConfigureFunc: providerConfigure,
|
||||||
|
|
|
@ -0,0 +1,440 @@
|
||||||
|
package librato
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/hashcode"
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/henrikhodne/go-librato/librato"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceLibratoAlert() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceLibratoAlertCreate,
|
||||||
|
Read: resourceLibratoAlertRead,
|
||||||
|
Update: resourceLibratoAlertUpdate,
|
||||||
|
Delete: resourceLibratoAlertDelete,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
"id": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"description": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"active": &schema.Schema{
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: true,
|
||||||
|
},
|
||||||
|
"rearm_seconds": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Default: 600,
|
||||||
|
},
|
||||||
|
"services": &schema.Schema{
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
|
Set: schema.HashString,
|
||||||
|
},
|
||||||
|
"condition": &schema.Schema{
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"type": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"metric_name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"source": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"detect_reset": &schema.Schema{
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"duration": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"threshold": &schema.Schema{
|
||||||
|
Type: schema.TypeFloat,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"summary_function": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Set: resourceLibratoAlertConditionsHash,
|
||||||
|
},
|
||||||
|
"attributes": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"runbook_url": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceLibratoAlertConditionsHash(v interface{}) int {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
m := v.(map[string]interface{})
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-", m["type"].(string)))
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-", m["metric_name"].(string)))
|
||||||
|
|
||||||
|
source, present := m["source"]
|
||||||
|
if present {
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-", source.(string)))
|
||||||
|
}
|
||||||
|
|
||||||
|
detect_reset, present := m["detect_reset"]
|
||||||
|
if present {
|
||||||
|
buf.WriteString(fmt.Sprintf("%t-", detect_reset.(bool)))
|
||||||
|
}
|
||||||
|
|
||||||
|
duration, present := m["duration"]
|
||||||
|
if present {
|
||||||
|
buf.WriteString(fmt.Sprintf("%d-", duration.(int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
threshold, present := m["threshold"]
|
||||||
|
if present {
|
||||||
|
buf.WriteString(fmt.Sprintf("%f-", threshold.(float64)))
|
||||||
|
}
|
||||||
|
|
||||||
|
summary_function, present := m["summary_function"]
|
||||||
|
if present {
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-", summary_function.(string)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return hashcode.String(buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceLibratoAlertCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
client := meta.(*librato.Client)
|
||||||
|
|
||||||
|
alert := new(librato.Alert)
|
||||||
|
if v, ok := d.GetOk("name"); ok {
|
||||||
|
alert.Name = librato.String(v.(string))
|
||||||
|
}
|
||||||
|
if v, ok := d.GetOk("description"); ok {
|
||||||
|
alert.Description = librato.String(v.(string))
|
||||||
|
}
|
||||||
|
// GetOK returns not OK for false boolean values, use Get
|
||||||
|
alert.Active = librato.Bool(d.Get("active").(bool))
|
||||||
|
if v, ok := d.GetOk("rearm_seconds"); ok {
|
||||||
|
alert.RearmSeconds = librato.Uint(uint(v.(int)))
|
||||||
|
}
|
||||||
|
if v, ok := d.GetOk("services"); ok {
|
||||||
|
vs := v.(*schema.Set)
|
||||||
|
services := make([]*string, vs.Len())
|
||||||
|
for i, serviceData := range vs.List() {
|
||||||
|
services[i] = librato.String(serviceData.(string))
|
||||||
|
}
|
||||||
|
alert.Services = services
|
||||||
|
}
|
||||||
|
if v, ok := d.GetOk("condition"); ok {
|
||||||
|
vs := v.(*schema.Set)
|
||||||
|
conditions := make([]librato.AlertCondition, vs.Len())
|
||||||
|
for i, conditionDataM := range vs.List() {
|
||||||
|
conditionData := conditionDataM.(map[string]interface{})
|
||||||
|
var condition librato.AlertCondition
|
||||||
|
if v, ok := conditionData["type"].(string); ok && v != "" {
|
||||||
|
condition.Type = librato.String(v)
|
||||||
|
}
|
||||||
|
if v, ok := conditionData["threshold"].(float64); ok && !math.IsNaN(v) {
|
||||||
|
condition.Threshold = librato.Float(v)
|
||||||
|
}
|
||||||
|
if v, ok := conditionData["metric_name"].(string); ok && v != "" {
|
||||||
|
condition.MetricName = librato.String(v)
|
||||||
|
}
|
||||||
|
if v, ok := conditionData["source"].(string); ok && v != "" {
|
||||||
|
condition.Source = librato.String(v)
|
||||||
|
}
|
||||||
|
if v, ok := conditionData["detect_reset"].(bool); ok {
|
||||||
|
condition.DetectReset = librato.Bool(v)
|
||||||
|
}
|
||||||
|
if v, ok := conditionData["duration"].(uint); ok {
|
||||||
|
condition.Duration = librato.Uint(v)
|
||||||
|
}
|
||||||
|
if v, ok := conditionData["summary_function"].(string); ok && v != "" {
|
||||||
|
condition.SummaryFunction = librato.String(v)
|
||||||
|
}
|
||||||
|
conditions[i] = condition
|
||||||
|
}
|
||||||
|
alert.Conditions = conditions
|
||||||
|
}
|
||||||
|
if v, ok := d.GetOk("attributes"); ok {
|
||||||
|
attributeData := v.([]interface{})
|
||||||
|
if len(attributeData) > 1 {
|
||||||
|
return fmt.Errorf("Only one set of attributes per alert is supported")
|
||||||
|
} else if len(attributeData) == 1 {
|
||||||
|
if attributeData[0] == nil {
|
||||||
|
return fmt.Errorf("No attributes found in attributes block")
|
||||||
|
}
|
||||||
|
attributeDataMap := attributeData[0].(map[string]interface{})
|
||||||
|
attributes := new(librato.AlertAttributes)
|
||||||
|
if v, ok := attributeDataMap["runbook_url"].(string); ok && v != "" {
|
||||||
|
attributes.RunbookURL = librato.String(v)
|
||||||
|
}
|
||||||
|
alert.Attributes = attributes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
alertResult, _, err := client.Alerts.Create(alert)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error creating Librato alert %s: %s", *alert.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resource.Retry(1*time.Minute, func() *resource.RetryError {
|
||||||
|
_, _, err := client.Alerts.Get(*alertResult.ID)
|
||||||
|
if err != nil {
|
||||||
|
if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 {
|
||||||
|
return resource.RetryableError(err)
|
||||||
|
}
|
||||||
|
return resource.NonRetryableError(err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return resourceLibratoAlertReadResult(d, alertResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceLibratoAlertRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
client := meta.(*librato.Client)
|
||||||
|
id, err := strconv.ParseUint(d.Id(), 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
alert, _, err := client.Alerts.Get(uint(id))
|
||||||
|
if err != nil {
|
||||||
|
if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 {
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Error reading Librato Alert %s: %s", d.Id(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resourceLibratoAlertReadResult(d, alert)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceLibratoAlertReadResult(d *schema.ResourceData, alert *librato.Alert) error {
|
||||||
|
d.SetId(strconv.FormatUint(uint64(*alert.ID), 10))
|
||||||
|
d.Set("id", *alert.ID)
|
||||||
|
d.Set("name", *alert.Name)
|
||||||
|
d.Set("description", *alert.Description)
|
||||||
|
d.Set("active", *alert.Active)
|
||||||
|
d.Set("rearm_seconds", *alert.RearmSeconds)
|
||||||
|
|
||||||
|
services := resourceLibratoAlertServicesGather(d, alert.Services.([]interface{}))
|
||||||
|
d.Set("services", services)
|
||||||
|
|
||||||
|
conditions := resourceLibratoAlertConditionsGather(d, alert.Conditions)
|
||||||
|
d.Set("condition", conditions)
|
||||||
|
|
||||||
|
attributes := resourceLibratoAlertAttributesGather(d, alert.Attributes)
|
||||||
|
d.Set("attributes", attributes)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceLibratoAlertServicesGather(d *schema.ResourceData, services []interface{}) []string {
|
||||||
|
retServices := make([]string, 0, len(services))
|
||||||
|
|
||||||
|
for _, s := range services {
|
||||||
|
serviceData := s.(map[string]interface{})
|
||||||
|
// ID field is returned as float64, for whatever reason
|
||||||
|
retServices = append(retServices, fmt.Sprintf("%.f", serviceData["id"]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return retServices
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceLibratoAlertConditionsGather(d *schema.ResourceData, conditions []librato.AlertCondition) []map[string]interface{} {
|
||||||
|
retConditions := make([]map[string]interface{}, 0, len(conditions))
|
||||||
|
for _, c := range conditions {
|
||||||
|
condition := make(map[string]interface{})
|
||||||
|
if c.Type != nil {
|
||||||
|
condition["type"] = *c.Type
|
||||||
|
}
|
||||||
|
if c.Threshold != nil {
|
||||||
|
condition["threshold"] = *c.Threshold
|
||||||
|
}
|
||||||
|
if c.MetricName != nil {
|
||||||
|
condition["metric_name"] = *c.MetricName
|
||||||
|
}
|
||||||
|
if c.Source != nil {
|
||||||
|
condition["source"] = *c.Source
|
||||||
|
}
|
||||||
|
if c.DetectReset != nil {
|
||||||
|
condition["detect_reset"] = *c.MetricName
|
||||||
|
}
|
||||||
|
if c.Duration != nil {
|
||||||
|
condition["duration"] = *c.Duration
|
||||||
|
}
|
||||||
|
if c.SummaryFunction != nil {
|
||||||
|
condition["summary_function"] = *c.SummaryFunction
|
||||||
|
}
|
||||||
|
retConditions = append(retConditions, condition)
|
||||||
|
}
|
||||||
|
|
||||||
|
return retConditions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flattens an attributes hash into something that flatmap.Flatten() can handle
|
||||||
|
func resourceLibratoAlertAttributesGather(d *schema.ResourceData, attributes *librato.AlertAttributes) []map[string]interface{} {
|
||||||
|
result := make([]map[string]interface{}, 0, 1)
|
||||||
|
|
||||||
|
if attributes != nil {
|
||||||
|
retAttributes := make(map[string]interface{})
|
||||||
|
if attributes.RunbookURL != nil {
|
||||||
|
retAttributes["runbook_url"] = *attributes.RunbookURL
|
||||||
|
}
|
||||||
|
result = append(result, retAttributes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceLibratoAlertUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
client := meta.(*librato.Client)
|
||||||
|
|
||||||
|
alertID, err := strconv.ParseUint(d.Id(), 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
alert := new(librato.Alert)
|
||||||
|
if d.HasChange("name") {
|
||||||
|
alert.Name = librato.String(d.Get("name").(string))
|
||||||
|
}
|
||||||
|
if d.HasChange("description") {
|
||||||
|
alert.Description = librato.String(d.Get("description").(string))
|
||||||
|
}
|
||||||
|
if d.HasChange("active") {
|
||||||
|
alert.Active = librato.Bool(d.Get("active").(bool))
|
||||||
|
}
|
||||||
|
if d.HasChange("rearm_seconds") {
|
||||||
|
alert.RearmSeconds = librato.Uint(d.Get("rearm_seconds").(uint))
|
||||||
|
}
|
||||||
|
if d.HasChange("services") {
|
||||||
|
vs := d.Get("services").(*schema.Set)
|
||||||
|
services := make([]*string, vs.Len())
|
||||||
|
for i, serviceData := range vs.List() {
|
||||||
|
services[i] = librato.String(serviceData.(string))
|
||||||
|
}
|
||||||
|
alert.Services = services
|
||||||
|
}
|
||||||
|
if d.HasChange("condition") {
|
||||||
|
vs := d.Get("condition").(*schema.Set)
|
||||||
|
conditions := make([]librato.AlertCondition, vs.Len())
|
||||||
|
for i, conditionDataM := range vs.List() {
|
||||||
|
conditionData := conditionDataM.(map[string]interface{})
|
||||||
|
var condition librato.AlertCondition
|
||||||
|
if v, ok := conditionData["type"].(string); ok && v != "" {
|
||||||
|
condition.Type = librato.String(v)
|
||||||
|
}
|
||||||
|
if v, ok := conditionData["threshold"].(float64); ok && !math.IsNaN(v) {
|
||||||
|
condition.Threshold = librato.Float(v)
|
||||||
|
}
|
||||||
|
if v, ok := conditionData["metric_name"].(string); ok && v != "" {
|
||||||
|
condition.MetricName = librato.String(v)
|
||||||
|
}
|
||||||
|
if v, ok := conditionData["source"].(string); ok && v != "" {
|
||||||
|
condition.Source = librato.String(v)
|
||||||
|
}
|
||||||
|
if v, ok := conditionData["detect_reset"].(bool); ok {
|
||||||
|
condition.DetectReset = librato.Bool(v)
|
||||||
|
}
|
||||||
|
if v, ok := conditionData["duration"].(uint); ok {
|
||||||
|
condition.Duration = librato.Uint(v)
|
||||||
|
}
|
||||||
|
if v, ok := conditionData["summary_function"].(string); ok && v != "" {
|
||||||
|
condition.SummaryFunction = librato.String(v)
|
||||||
|
}
|
||||||
|
conditions[i] = condition
|
||||||
|
}
|
||||||
|
alert.Conditions = conditions
|
||||||
|
}
|
||||||
|
if d.HasChange("attributes") {
|
||||||
|
attributeData := d.Get("attributes").([]interface{})
|
||||||
|
if len(attributeData) > 1 {
|
||||||
|
return fmt.Errorf("Only one set of attributes per alert is supported")
|
||||||
|
} else if len(attributeData) == 1 {
|
||||||
|
if attributeData[0] == nil {
|
||||||
|
return fmt.Errorf("No attributes found in attributes block")
|
||||||
|
}
|
||||||
|
attributeDataMap := attributeData[0].(map[string]interface{})
|
||||||
|
attributes := new(librato.AlertAttributes)
|
||||||
|
if v, ok := attributeDataMap["runbook_url"].(string); ok && v != "" {
|
||||||
|
attributes.RunbookURL = librato.String(v)
|
||||||
|
}
|
||||||
|
alert.Attributes = attributes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = client.Alerts.Edit(uint(alertID), alert)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error updating Librato alert: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resourceLibratoAlertRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceLibratoAlertDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
client := meta.(*librato.Client)
|
||||||
|
id, err := strconv.ParseUint(d.Id(), 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[INFO] Deleting Alert: %d", id)
|
||||||
|
_, err = client.Alerts.Delete(uint(id))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error deleting Alert: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resource.Retry(1*time.Minute, func() *resource.RetryError {
|
||||||
|
_, _, err := client.Alerts.Get(uint(id))
|
||||||
|
if err != nil {
|
||||||
|
if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return resource.NonRetryableError(err)
|
||||||
|
}
|
||||||
|
return resource.RetryableError(fmt.Errorf("alert still exists"))
|
||||||
|
})
|
||||||
|
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,191 @@
|
||||||
|
package librato
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
"github.com/henrikhodne/go-librato/librato"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccLibratoAlert_Basic(t *testing.T) {
|
||||||
|
var alert librato.Alert
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckLibratoAlertDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccCheckLibratoAlertConfig_basic,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckLibratoAlertExists("librato_alert.foobar", &alert),
|
||||||
|
testAccCheckLibratoAlertName(&alert, "FooBar"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"librato_alert.foobar", "name", "FooBar"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccLibratoAlert_Full(t *testing.T) {
|
||||||
|
var alert librato.Alert
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckLibratoAlertDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccCheckLibratoAlertConfig_full,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckLibratoAlertExists("librato_alert.foobar", &alert),
|
||||||
|
testAccCheckLibratoAlertName(&alert, "FooBar"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"librato_alert.foobar", "name", "FooBar"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccLibratoAlert_Updated(t *testing.T) {
|
||||||
|
var alert librato.Alert
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckLibratoAlertDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccCheckLibratoAlertConfig_basic,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckLibratoAlertExists("librato_alert.foobar", &alert),
|
||||||
|
testAccCheckLibratoAlertName(&alert, "FooBar"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"librato_alert.foobar", "name", "FooBar"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccCheckLibratoAlertConfig_new_value,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckLibratoAlertExists("librato_alert.foobar", &alert),
|
||||||
|
testAccCheckLibratoAlertName(&alert, "BarBaz"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"librato_alert.foobar", "name", "BarBaz"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckLibratoAlertDestroy(s *terraform.State) error {
|
||||||
|
client := testAccProvider.Meta().(*librato.Client)
|
||||||
|
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
if rs.Type != "librato_alert" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := strconv.ParseUint(rs.Primary.ID, 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("ID not a number")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err = client.Alerts.Get(uint(id))
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
return fmt.Errorf("Alert still exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckLibratoAlertName(alert *librato.Alert, name string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
|
||||||
|
if alert.Name == nil || *alert.Name != name {
|
||||||
|
return fmt.Errorf("Bad name: %s", *alert.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckLibratoAlertExists(n string, alert *librato.Alert) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, ok := s.RootModule().Resources[n]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Not found: %s", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rs.Primary.ID == "" {
|
||||||
|
return fmt.Errorf("No Alert ID is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
client := testAccProvider.Meta().(*librato.Client)
|
||||||
|
|
||||||
|
id, err := strconv.ParseUint(rs.Primary.ID, 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("ID not a number")
|
||||||
|
}
|
||||||
|
|
||||||
|
foundAlert, _, err := client.Alerts.Get(uint(id))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if foundAlert.ID == nil || *foundAlert.ID != uint(id) {
|
||||||
|
return fmt.Errorf("Alert not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
*alert = *foundAlert
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccCheckLibratoAlertConfig_basic = `
|
||||||
|
resource "librato_alert" "foobar" {
|
||||||
|
name = "FooBar"
|
||||||
|
description = "A Test Alert"
|
||||||
|
}`
|
||||||
|
|
||||||
|
const testAccCheckLibratoAlertConfig_new_value = `
|
||||||
|
resource "librato_alert" "foobar" {
|
||||||
|
name = "BarBaz"
|
||||||
|
description = "A Test Alert"
|
||||||
|
}`
|
||||||
|
|
||||||
|
const testAccCheckLibratoAlertConfig_full = `
|
||||||
|
resource "librato_service" "foobar" {
|
||||||
|
title = "Foo Bar"
|
||||||
|
type = "mail"
|
||||||
|
settings = <<EOF
|
||||||
|
{
|
||||||
|
"addresses": "admin@example.com"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "librato_alert" "foobar" {
|
||||||
|
name = "FooBar"
|
||||||
|
description = "A Test Alert"
|
||||||
|
services = [ "${librato_service.foobar.id}" ]
|
||||||
|
condition {
|
||||||
|
type = "above"
|
||||||
|
threshold = 10
|
||||||
|
metric_name = "librato.cpu.percent.idle"
|
||||||
|
}
|
||||||
|
attributes {
|
||||||
|
runbook_url = "https://www.youtube.com/watch?v=oHg5SJYRHA0"
|
||||||
|
}
|
||||||
|
active = false
|
||||||
|
rearm_seconds = 300
|
||||||
|
}`
|
|
@ -0,0 +1,207 @@
|
||||||
|
package librato
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/henrikhodne/go-librato/librato"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceLibratoService() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceLibratoServiceCreate,
|
||||||
|
Read: resourceLibratoServiceRead,
|
||||||
|
Update: resourceLibratoServiceUpdate,
|
||||||
|
Delete: resourceLibratoServiceDelete,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"id": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"type": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"title": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"settings": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
StateFunc: normalizeJson,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Takes JSON in a string. Decodes JSON into
|
||||||
|
// settings hash
|
||||||
|
func resourceLibratoServicesExpandSettings(rawSettings string) (map[string]string, error) {
|
||||||
|
var settings map[string]string
|
||||||
|
|
||||||
|
settings = make(map[string]string)
|
||||||
|
err := json.Unmarshal([]byte(rawSettings), &settings)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error decoding JSON: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return settings, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encodes a settings hash into a JSON string
|
||||||
|
func resourceLibratoServicesFlatten(settings map[string]string) (string, error) {
|
||||||
|
byteArray, err := json.Marshal(settings)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Error encoding to JSON: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(byteArray), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizeJson(jsonString interface{}) string {
|
||||||
|
if jsonString == nil || jsonString == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
var j interface{}
|
||||||
|
err := json.Unmarshal([]byte(jsonString.(string)), &j)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("Error parsing JSON: %s", err)
|
||||||
|
}
|
||||||
|
b, _ := json.Marshal(j)
|
||||||
|
return string(b[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceLibratoServiceCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
client := meta.(*librato.Client)
|
||||||
|
|
||||||
|
service := new(librato.Service)
|
||||||
|
if v, ok := d.GetOk("type"); ok {
|
||||||
|
service.Type = librato.String(v.(string))
|
||||||
|
}
|
||||||
|
if v, ok := d.GetOk("title"); ok {
|
||||||
|
service.Title = librato.String(v.(string))
|
||||||
|
}
|
||||||
|
if v, ok := d.GetOk("settings"); ok {
|
||||||
|
res, err := resourceLibratoServicesExpandSettings(normalizeJson(v.(string)))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error expanding Librato service settings: %s", err)
|
||||||
|
}
|
||||||
|
service.Settings = res
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceResult, _, err := client.Services.Create(service)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error creating Librato service: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resource.Retry(1*time.Minute, func() *resource.RetryError {
|
||||||
|
_, _, err := client.Services.Get(*serviceResult.ID)
|
||||||
|
if err != nil {
|
||||||
|
if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 {
|
||||||
|
return resource.RetryableError(err)
|
||||||
|
}
|
||||||
|
return resource.NonRetryableError(err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return resourceLibratoServiceReadResult(d, serviceResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceLibratoServiceRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
client := meta.(*librato.Client)
|
||||||
|
id, err := strconv.ParseUint(d.Id(), 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
service, _, err := client.Services.Get(uint(id))
|
||||||
|
if err != nil {
|
||||||
|
if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 {
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Error reading Librato Service %s: %s", d.Id(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resourceLibratoServiceReadResult(d, service)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceLibratoServiceReadResult(d *schema.ResourceData, service *librato.Service) error {
|
||||||
|
d.SetId(strconv.FormatUint(uint64(*service.ID), 10))
|
||||||
|
d.Set("id", *service.ID)
|
||||||
|
d.Set("type", *service.Type)
|
||||||
|
d.Set("title", *service.Title)
|
||||||
|
settings, _ := resourceLibratoServicesFlatten(service.Settings)
|
||||||
|
d.Set("settings", settings)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceLibratoServiceUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
client := meta.(*librato.Client)
|
||||||
|
|
||||||
|
serviceID, err := strconv.ParseUint(d.Id(), 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
service := new(librato.Service)
|
||||||
|
if d.HasChange("type") {
|
||||||
|
service.Type = librato.String(d.Get("type").(string))
|
||||||
|
}
|
||||||
|
if d.HasChange("title") {
|
||||||
|
service.Title = librato.String(d.Get("title").(string))
|
||||||
|
}
|
||||||
|
if d.HasChange("settings") {
|
||||||
|
res, err := resourceLibratoServicesExpandSettings(normalizeJson(d.Get("settings").(string)))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error expanding Librato service settings: %s", err)
|
||||||
|
}
|
||||||
|
service.Settings = res
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = client.Services.Edit(uint(serviceID), service)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error updating Librato service: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resourceLibratoServiceRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceLibratoServiceDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
client := meta.(*librato.Client)
|
||||||
|
id, err := strconv.ParseUint(d.Id(), 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[INFO] Deleting Service: %d", id)
|
||||||
|
_, err = client.Services.Delete(uint(id))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error deleting Service: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resource.Retry(1*time.Minute, func() *resource.RetryError {
|
||||||
|
_, _, err := client.Services.Get(uint(id))
|
||||||
|
if err != nil {
|
||||||
|
if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return resource.NonRetryableError(err)
|
||||||
|
}
|
||||||
|
return resource.RetryableError(fmt.Errorf("service still exists"))
|
||||||
|
})
|
||||||
|
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,153 @@
|
||||||
|
package librato
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
"github.com/henrikhodne/go-librato/librato"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccLibratoService_Basic(t *testing.T) {
|
||||||
|
var service librato.Service
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckLibratoServiceDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccCheckLibratoServiceConfig_basic,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckLibratoServiceExists("librato_service.foobar", &service),
|
||||||
|
testAccCheckLibratoServiceTitle(&service, "Foo Bar"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"librato_service.foobar", "title", "Foo Bar"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccLibratoService_Updated(t *testing.T) {
|
||||||
|
var service librato.Service
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckLibratoServiceDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccCheckLibratoServiceConfig_basic,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckLibratoServiceExists("librato_service.foobar", &service),
|
||||||
|
testAccCheckLibratoServiceTitle(&service, "Foo Bar"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"librato_service.foobar", "title", "Foo Bar"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccCheckLibratoServiceConfig_new_value,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckLibratoServiceExists("librato_service.foobar", &service),
|
||||||
|
testAccCheckLibratoServiceTitle(&service, "Bar Baz"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"librato_service.foobar", "title", "Bar Baz"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckLibratoServiceDestroy(s *terraform.State) error {
|
||||||
|
client := testAccProvider.Meta().(*librato.Client)
|
||||||
|
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
if rs.Type != "librato_service" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := strconv.ParseUint(rs.Primary.ID, 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("ID not a number")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err = client.Services.Get(uint(id))
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
return fmt.Errorf("Service still exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckLibratoServiceTitle(service *librato.Service, title string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
|
||||||
|
if service.Title == nil || *service.Title != title {
|
||||||
|
return fmt.Errorf("Bad title: %s", *service.Title)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckLibratoServiceExists(n string, service *librato.Service) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, ok := s.RootModule().Resources[n]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Not found: %s", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rs.Primary.ID == "" {
|
||||||
|
return fmt.Errorf("No Service ID is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
client := testAccProvider.Meta().(*librato.Client)
|
||||||
|
|
||||||
|
id, err := strconv.ParseUint(rs.Primary.ID, 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("ID not a number")
|
||||||
|
}
|
||||||
|
|
||||||
|
foundService, _, err := client.Services.Get(uint(id))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if foundService.ID == nil || *foundService.ID != uint(id) {
|
||||||
|
return fmt.Errorf("Service not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
*service = *foundService
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccCheckLibratoServiceConfig_basic = `
|
||||||
|
resource "librato_service" "foobar" {
|
||||||
|
title = "Foo Bar"
|
||||||
|
type = "mail"
|
||||||
|
settings = <<EOF
|
||||||
|
{
|
||||||
|
"addresses": "admin@example.com"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}`
|
||||||
|
|
||||||
|
const testAccCheckLibratoServiceConfig_new_value = `
|
||||||
|
resource "librato_service" "foobar" {
|
||||||
|
title = "Bar Baz"
|
||||||
|
type = "mail"
|
||||||
|
settings = <<EOF
|
||||||
|
{
|
||||||
|
"addresses": "admin@example.com"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}`
|
|
@ -0,0 +1,110 @@
|
||||||
|
package librato
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AlertsService handles communication with the Librato API methods related to
|
||||||
|
// alerts.
|
||||||
|
type AlertsService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alert represents a Librato Alert.
|
||||||
|
type Alert struct {
|
||||||
|
Name *string `json:"name"`
|
||||||
|
ID *uint `json:"id,omitempty"`
|
||||||
|
Conditions []AlertCondition `json:"conditions,omitempty"`
|
||||||
|
// These are interface{} because the Librato API asks for integers
|
||||||
|
// on Create and returns hashes on Get
|
||||||
|
Services interface{} `json:"services,omitempty"`
|
||||||
|
Attributes *AlertAttributes `json:"attributes,omitempty"`
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
Active *bool `json:"active,omitempty"`
|
||||||
|
RearmSeconds *uint `json:"rearm_seconds,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Alert) String() string {
|
||||||
|
return Stringify(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AlertCondition represents an alert trigger condition.
|
||||||
|
type AlertCondition struct {
|
||||||
|
Type *string `json:"type,omitempty"`
|
||||||
|
MetricName *string `json:"metric_name,omitempty"`
|
||||||
|
Source *string `json:"source,omitempty"`
|
||||||
|
DetectReset *bool `json:"detect_reset,omitempty"`
|
||||||
|
Threshold *float64 `json:"threshold,omitempty"`
|
||||||
|
SummaryFunction *string `json:"summary_function,omitempty"`
|
||||||
|
Duration *uint `json:"duration,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AlertAttributes represents the attributes of an alert.
|
||||||
|
type AlertAttributes struct {
|
||||||
|
RunbookURL *string `json:"runbook_url,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get an alert by ID
|
||||||
|
//
|
||||||
|
// Librato API docs: https://www.librato.com/docs/api/#retrieve-alert-by-id
|
||||||
|
func (a *AlertsService) Get(id uint) (*Alert, *http.Response, error) {
|
||||||
|
urlStr := fmt.Sprintf("alerts/%d", id)
|
||||||
|
|
||||||
|
req, err := a.client.NewRequest("GET", urlStr, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
alert := new(Alert)
|
||||||
|
resp, err := a.client.Do(req, alert)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return alert, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an alert
|
||||||
|
//
|
||||||
|
// Librato API docs: https://www.librato.com/docs/api/?shell#create-an-alert
|
||||||
|
func (a *AlertsService) Create(alert *Alert) (*Alert, *http.Response, error) {
|
||||||
|
req, err := a.client.NewRequest("POST", "alerts", alert)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
al := new(Alert)
|
||||||
|
resp, err := a.client.Do(req, al)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return al, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Edit an alert.
|
||||||
|
//
|
||||||
|
// Librato API docs: https://www.librato.com/docs/api/?shell#update-alert
|
||||||
|
func (a *AlertsService) Edit(alertID uint, alert *Alert) (*http.Response, error) {
|
||||||
|
u := fmt.Sprintf("alerts/%d", alertID)
|
||||||
|
req, err := a.client.NewRequest("PUT", u, alert)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete an alert
|
||||||
|
//
|
||||||
|
// Librato API docs: https://www.librato.com/docs/api/?shell#delete-alert
|
||||||
|
func (a *AlertsService) Delete(id uint) (*http.Response, error) {
|
||||||
|
u := fmt.Sprintf("alerts/%d", id)
|
||||||
|
req, err := a.client.NewRequest("DELETE", u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.client.Do(req, nil)
|
||||||
|
}
|
|
@ -45,6 +45,9 @@ type Client struct {
|
||||||
|
|
||||||
// Services used to manipulate API entities.
|
// Services used to manipulate API entities.
|
||||||
Spaces *SpacesService
|
Spaces *SpacesService
|
||||||
|
Metrics *MetricsService
|
||||||
|
Alerts *AlertsService
|
||||||
|
Services *ServicesService
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient returns a new Librato API client bound to the public Librato API.
|
// NewClient returns a new Librato API client bound to the public Librato API.
|
||||||
|
@ -74,6 +77,9 @@ func NewClientWithBaseURL(baseURL *url.URL, email, token string) *Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Spaces = &SpacesService{client: c}
|
c.Spaces = &SpacesService{client: c}
|
||||||
|
c.Metrics = &MetricsService{client: c}
|
||||||
|
c.Alerts = &AlertsService{client: c}
|
||||||
|
c.Services = &ServicesService{client: c}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
@ -89,7 +95,6 @@ func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Requ
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
u := c.BaseURL.ResolveReference(rel)
|
u := c.BaseURL.ResolveReference(rel)
|
||||||
|
|
||||||
var buf io.ReadWriter
|
var buf io.ReadWriter
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
package librato
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MetricsService handles communication with the Librato API methods related to
|
||||||
|
// metrics.
|
||||||
|
type MetricsService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metric represents a Librato Metric.
|
||||||
|
type Metric struct {
|
||||||
|
Name *string `json:"name"`
|
||||||
|
Period *uint `json:"period,omitempty"`
|
||||||
|
DisplayName *string `json:"display_name,omitempty"`
|
||||||
|
Attributes *MetricAttributes `json:"attributes,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MetricAttributes struct {
|
||||||
|
Color *string `json:"color"`
|
||||||
|
// These are interface{} because sometimes the Librato API
|
||||||
|
// returns strings, and sometimes it returns integers
|
||||||
|
DisplayMax interface{} `json:"display_max"`
|
||||||
|
DisplayMin interface{} `json:"display_min"`
|
||||||
|
DisplayUnitsShort string `json:"display_units_short"`
|
||||||
|
DisplayStacked bool `json:"display_stacked"`
|
||||||
|
DisplayTransform string `json:"display_transform"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListMetricsOptions struct {
|
||||||
|
*PaginationMeta
|
||||||
|
Name string `url:"name,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance to the specified page in result set, while retaining
|
||||||
|
// the filtering options.
|
||||||
|
func (l *ListMetricsOptions) AdvancePage(next *PaginationMeta) ListMetricsOptions {
|
||||||
|
return ListMetricsOptions{
|
||||||
|
PaginationMeta: next,
|
||||||
|
Name: l.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListMetricsResponse struct {
|
||||||
|
ThisPage *PaginationResponseMeta
|
||||||
|
NextPage *PaginationMeta
|
||||||
|
}
|
||||||
|
|
||||||
|
// List metrics using the provided options.
|
||||||
|
//
|
||||||
|
// Librato API docs: https://www.librato.com/docs/api/#retrieve-metrics
|
||||||
|
func (m *MetricsService) List(opts *ListMetricsOptions) ([]Metric, *ListMetricsResponse, error) {
|
||||||
|
u, err := urlWithOptions("metrics", opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := m.client.NewRequest("GET", u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var metricsResponse struct {
|
||||||
|
Query PaginationResponseMeta
|
||||||
|
Metrics []Metric
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = m.client.Do(req, &metricsResponse)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return metricsResponse.Metrics,
|
||||||
|
&ListMetricsResponse{
|
||||||
|
ThisPage: &metricsResponse.Query,
|
||||||
|
NextPage: metricsResponse.Query.nextPage(opts.PaginationMeta),
|
||||||
|
},
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a metric by name
|
||||||
|
//
|
||||||
|
// Librato API docs: https://www.librato.com/docs/api/#retrieve-metric-by-name
|
||||||
|
func (m *MetricsService) Get(name string) (*Metric, *http.Response, error) {
|
||||||
|
u := fmt.Sprintf("metrics/%s", name)
|
||||||
|
req, err := m.client.NewRequest("GET", u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
metric := new(Metric)
|
||||||
|
resp, err := m.client.Do(req, metric)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return metric, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type MeasurementSubmission struct {
|
||||||
|
MeasureTime *uint `json:"measure_time,omitempty"`
|
||||||
|
Source *string `json:"source,omitempty"`
|
||||||
|
Gauges []*GaugeMeasurement `json:"gauges,omitempty"`
|
||||||
|
Counters []*Measurement `json:"counters,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Measurement struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value *float64 `json:"value,omitempty"`
|
||||||
|
MeasureTime *uint `json:"measure_time,omitempty"`
|
||||||
|
Source *string `json:"source,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GaugeMeasurement struct {
|
||||||
|
*Measurement
|
||||||
|
Count *uint `json:"count,omitempty"`
|
||||||
|
Sum *float64 `json:"sum,omitempty"`
|
||||||
|
Max *float64 `json:"max,omitempty"`
|
||||||
|
Min *float64 `json:"min,omitempty"`
|
||||||
|
SumSquares *float64 `json:"sum_squares,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Submit metrics
|
||||||
|
//
|
||||||
|
// Librato API docs: https://www.librato.com/docs/api/#submit-metrics
|
||||||
|
func (m *MetricsService) Submit(measurements *MeasurementSubmission) (*http.Response, error) {
|
||||||
|
req, err := m.client.NewRequest("POST", "/metrics", measurements)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Edit a metric.
|
||||||
|
//
|
||||||
|
// Librato API docs: https://www.librato.com/docs/api/#update-metric-by-name
|
||||||
|
func (m *MetricsService) Edit(metric *Metric) (*http.Response, error) {
|
||||||
|
u := fmt.Sprintf("metrics/%s", *metric.Name)
|
||||||
|
|
||||||
|
req, err := m.client.NewRequest("PUT", u, metric)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete a metric.
|
||||||
|
//
|
||||||
|
// Librato API docs: https://www.librato.com/docs/api/#delete-metric-by-name
|
||||||
|
func (m *MetricsService) Delete(name string) (*http.Response, error) {
|
||||||
|
u := fmt.Sprintf("metrics/%s", name)
|
||||||
|
req, err := m.client.NewRequest("DELETE", u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.client.Do(req, nil)
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package librato
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PaginationResponseMeta contains pagination metadata from Librato API
|
||||||
|
// responses.
|
||||||
|
type PaginationResponseMeta struct {
|
||||||
|
Offset uint `json:"offset"`
|
||||||
|
Length uint `json:"length"`
|
||||||
|
Total uint `json:"total"`
|
||||||
|
Found uint `json:"found"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the pagination metadata for the next page of the result set.
|
||||||
|
// Takes the metadata used to request the current page so that it can use the
|
||||||
|
// same sort/orderby options
|
||||||
|
func (p *PaginationResponseMeta) nextPage(originalQuery *PaginationMeta) (next *PaginationMeta) {
|
||||||
|
nextOffset := p.Offset + p.Length
|
||||||
|
|
||||||
|
if nextOffset >= p.Found {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
next = &PaginationMeta{}
|
||||||
|
next.Offset = nextOffset
|
||||||
|
next.Length = p.Length
|
||||||
|
|
||||||
|
if originalQuery != nil {
|
||||||
|
next.OrderBy = originalQuery.OrderBy
|
||||||
|
next.Sort = originalQuery.Sort
|
||||||
|
}
|
||||||
|
|
||||||
|
return next
|
||||||
|
}
|
||||||
|
|
||||||
|
// PaginationMeta contains metadata that the Librato API requires for pagination
|
||||||
|
// http://dev.librato.com/v1/pagination
|
||||||
|
type PaginationMeta struct {
|
||||||
|
Offset uint `url:"offset,omitempty"`
|
||||||
|
Length uint `url:"length,omitempty"`
|
||||||
|
OrderBy string `url:"orderby,omitempty"`
|
||||||
|
Sort string `url:"sort,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeValues is implemented to allow other strucs to embed PaginationMeta and
|
||||||
|
// still use github.com/google/go-querystring/query to encode the struct. It
|
||||||
|
// makes PaginationMeta implement query.Encoder.
|
||||||
|
func (m *PaginationMeta) EncodeValues(name string, values *url.Values) error {
|
||||||
|
if m == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Offset != 0 {
|
||||||
|
values.Set("offset", fmt.Sprintf("%d", m.Offset))
|
||||||
|
}
|
||||||
|
if m.Length != 0 {
|
||||||
|
values.Set("length", fmt.Sprintf("%d", m.Length))
|
||||||
|
}
|
||||||
|
if m.OrderBy != "" {
|
||||||
|
values.Set("orderby", m.OrderBy)
|
||||||
|
}
|
||||||
|
if m.Sort != "" {
|
||||||
|
values.Set("sort", m.Sort)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
package librato
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ServicesService handles communication with the Librato API methods related to
|
||||||
|
// notification services.
|
||||||
|
type ServicesService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Service represents a Librato Service.
|
||||||
|
type Service struct {
|
||||||
|
ID *uint `json:"id,omitempty"`
|
||||||
|
Type *string `json:"type,omitempty"`
|
||||||
|
Title *string `json:"title,omitempty"`
|
||||||
|
// This is an interface{} because it's a hash of settings
|
||||||
|
// specific to each service.
|
||||||
|
Settings map[string]string `json:"settings,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Service) String() string {
|
||||||
|
return Stringify(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a service by ID
|
||||||
|
//
|
||||||
|
// Librato API docs: https://www.librato.com/docs/api/#retrieve-specific-service
|
||||||
|
func (s *ServicesService) Get(id uint) (*Service, *http.Response, error) {
|
||||||
|
urlStr := fmt.Sprintf("services/%d", id)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", urlStr, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
service := new(Service)
|
||||||
|
resp, err := s.client.Do(req, service)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return service, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a service
|
||||||
|
//
|
||||||
|
// Librato API docs: https://www.librato.com/docs/api/#create-a-service
|
||||||
|
func (s *ServicesService) Create(service *Service) (*Service, *http.Response, error) {
|
||||||
|
req, err := s.client.NewRequest("POST", "services", service)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sv := new(Service)
|
||||||
|
resp, err := s.client.Do(req, sv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sv, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Edit a service.
|
||||||
|
//
|
||||||
|
// Librato API docs: https://www.librato.com/docs/api/#update-a-service
|
||||||
|
func (s *ServicesService) Edit(serviceID uint, service *Service) (*http.Response, error) {
|
||||||
|
u := fmt.Sprintf("services/%d", serviceID)
|
||||||
|
req, err := s.client.NewRequest("PUT", u, service)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete a service
|
||||||
|
//
|
||||||
|
// Librato API docs: https://www.librato.com/docs/api/#delete-a-service
|
||||||
|
func (s *ServicesService) Delete(id uint) (*http.Response, error) {
|
||||||
|
u := fmt.Sprintf("services/%d", id)
|
||||||
|
req, err := s.client.NewRequest("DELETE", u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
|
@ -1259,8 +1259,11 @@
|
||||||
"revision": "df949784da9ed028ee76df44652e42d37a09d7e4"
|
"revision": "df949784da9ed028ee76df44652e42d37a09d7e4"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"checksumSHA1": "jq2E42bB0kwKaerHXwJslUea4eM=",
|
||||||
|
"origin": "github.com/hashicorp/terraform/vendor/github.com/henrikhodne/go-librato/librato",
|
||||||
"path": "github.com/henrikhodne/go-librato/librato",
|
"path": "github.com/henrikhodne/go-librato/librato",
|
||||||
"revision": "613abdebf4922c4d9d46bcb4bcf14ee18c08d7de"
|
"revision": "6e9aa4b1a8a8b735ad14b4f1c9542ef183e82dc2",
|
||||||
|
"revisionTime": "2016-08-11T07:26:26Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"comment": "v0.0.2-37-g5cd82f0",
|
"comment": "v0.0.2-37-g5cd82f0",
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
---
|
||||||
|
layout: "librato"
|
||||||
|
page_title: "Librato: librato_alert"
|
||||||
|
sidebar_current: "docs-librato-resource-alert"
|
||||||
|
description: |-
|
||||||
|
Provides a Librato Alert resource. This can be used to create and manage alerts on Librato.
|
||||||
|
---
|
||||||
|
|
||||||
|
# librato\_alert
|
||||||
|
|
||||||
|
Provides a Librato Alert resource. This can be used to
|
||||||
|
create and manage alerts on Librato.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
# Create a new Librato alert
|
||||||
|
resource "librato_alert" "myalert" {
|
||||||
|
name = "MyAlert"
|
||||||
|
description = "A Test Alert"
|
||||||
|
services = [ "${librato_service.myservice.id}" ]
|
||||||
|
condition {
|
||||||
|
type = "above"
|
||||||
|
threshold = 10
|
||||||
|
metric_name = "librato.cpu.percent.idle"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `name` - (Required) The name of the alert.
|
||||||
|
* `description` - (Required) Description of the alert.
|
||||||
|
* `active` - whether the alert is active (can be triggered). Defaults to true.
|
||||||
|
* `rearm_seconds` - minimum amount of time between sending alert notifications, in seconds.
|
||||||
|
* `services` - list of notification service IDs.
|
||||||
|
* `condition` - A trigger condition for the alert. Conditions documented below.
|
||||||
|
* `attributes` - A hash of additional attribtues for the alert. Attributes documented below.
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
The following attributes are exported:
|
||||||
|
|
||||||
|
* `id` - The ID of the alert.
|
||||||
|
* `name` - The name of the alert.
|
||||||
|
* `description` - (Required) Description of the alert.
|
||||||
|
* `active` - whether the alert is active (can be triggered). Defaults to true.
|
||||||
|
* `rearm_seconds` - minimum amount of time between sending alert notifications, in seconds.
|
||||||
|
* `services` - list of notification service IDs.
|
||||||
|
* `condition` - A trigger condition for the alert. Conditions documented below.
|
||||||
|
|
||||||
|
Conditions (`condition`) support the following:
|
||||||
|
|
||||||
|
* `type` - The type of condition. Must be one of `above`, `below` or `absent`.
|
||||||
|
* `metric_name`- The name of the metric this alert condition applies to.
|
||||||
|
* `source`- A source expression which identifies which sources for the given metric to monitor.
|
||||||
|
* `detect_reset` - boolean: toggles the method used to calculate the delta from the previous sample when the summary_function is `derivative`.
|
||||||
|
* `duration` - number of seconds condition must be true to fire the alert (required for type `absent`).
|
||||||
|
* `threshold` - float: measurements over this number will fire the alert (only for `above` or `below`).
|
||||||
|
* `summary_function` - Indicates which statistic of an aggregated measurement to alert on. ((only for `above` or `below`).
|
||||||
|
|
||||||
|
Attributes (`attributes`) support the following:
|
||||||
|
|
||||||
|
* `runbook_url` - a URL for the runbook to be followed when this alert is firing. Used in the Librato UI if set.
|
|
@ -0,0 +1,44 @@
|
||||||
|
---
|
||||||
|
layout: "librato"
|
||||||
|
page_title: "Librato: librato_service"
|
||||||
|
sidebar_current: "docs-librato-resource-service"
|
||||||
|
description: |-
|
||||||
|
Provides a Librato service resource. This can be used to create and manage notification services on Librato.
|
||||||
|
---
|
||||||
|
|
||||||
|
# librato\_service
|
||||||
|
|
||||||
|
Provides a Librato Service resource. This can be used to
|
||||||
|
create and manage notification services on Librato.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
# Create a new Librato service
|
||||||
|
resource "librato_service" "email" {
|
||||||
|
title = "Email the admins"
|
||||||
|
type = "mail"
|
||||||
|
settings = <<EOF
|
||||||
|
{
|
||||||
|
"addresses": "admin@example.com"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported. Please check the [relevant documentation](https://github.com/librato/librato-services/tree/master/services) for each type of alert.
|
||||||
|
|
||||||
|
* `type` - (Required) The type of notificaion.
|
||||||
|
* `title` - (Required) The alert title.
|
||||||
|
* `settings` - (Required) a JSON hash of settings specific to the alert type.
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
The following attributes are exported:
|
||||||
|
|
||||||
|
* `id` - The ID of the alert.
|
||||||
|
* `type` - The type of notificaion.
|
||||||
|
* `title` - The alert title.
|
||||||
|
* `settings` - a JSON hash of settings specific to the alert type.
|
|
@ -13,6 +13,12 @@
|
||||||
<li<%= sidebar_current(/^docs-librato-resource/) %>>
|
<li<%= sidebar_current(/^docs-librato-resource/) %>>
|
||||||
<a href="#">Resources</a>
|
<a href="#">Resources</a>
|
||||||
<ul class="nav nav-visible">
|
<ul class="nav nav-visible">
|
||||||
|
<li<%= sidebar_current("docs-librato-resource-alert") %>>
|
||||||
|
<a href="/docs/providers/librato/r/alert.html">librato_alert</a>
|
||||||
|
</li>
|
||||||
|
<li<%= sidebar_current("docs-librato-resource-service") %>>
|
||||||
|
<a href="/docs/providers/librato/r/service.html">librato_service</a>
|
||||||
|
</li>
|
||||||
<li<%= sidebar_current("docs-librato-resource-space") %>>
|
<li<%= sidebar_current("docs-librato-resource-space") %>>
|
||||||
<a href="/docs/providers/librato/r/space.html">librato_space</a>
|
<a href="/docs/providers/librato/r/space.html">librato_space</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
Loading…
Reference in New Issue