librato: Work around eventual consistency of the API (#12816)
This commit is contained in:
parent
cb8afe4164
commit
6ff5561947
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
|
@ -27,10 +28,6 @@ func resourceLibratoAlert() *schema.Resource {
|
|||
Required: true,
|
||||
ForceNew: false,
|
||||
},
|
||||
"id": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
},
|
||||
"description": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
|
@ -214,6 +211,7 @@ func resourceLibratoAlertCreate(d *schema.ResourceData, meta interface{}) error
|
|||
if err != nil {
|
||||
return fmt.Errorf("Error creating Librato alert %s: %s", *alert.Name, err)
|
||||
}
|
||||
log.Printf("[INFO] Created Librato alert: %s", *alertResult)
|
||||
|
||||
resource.Retry(1*time.Minute, func() *resource.RetryError {
|
||||
_, _, err := client.Alerts.Get(*alertResult.ID)
|
||||
|
@ -226,7 +224,9 @@ func resourceLibratoAlertCreate(d *schema.ResourceData, meta interface{}) error
|
|||
return nil
|
||||
})
|
||||
|
||||
return resourceLibratoAlertReadResult(d, alertResult)
|
||||
d.SetId(strconv.FormatUint(uint64(*alertResult.ID), 10))
|
||||
|
||||
return resourceLibratoAlertRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceLibratoAlertRead(d *schema.ResourceData, meta interface{}) error {
|
||||
|
@ -236,6 +236,7 @@ func resourceLibratoAlertRead(d *schema.ResourceData, meta interface{}) error {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Reading Librato Alert: %d", id)
|
||||
alert, _, err := client.Alerts.Get(uint(id))
|
||||
if err != nil {
|
||||
if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 {
|
||||
|
@ -244,23 +245,22 @@ func resourceLibratoAlertRead(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
return fmt.Errorf("Error reading Librato Alert %s: %s", d.Id(), err)
|
||||
}
|
||||
log.Printf("[INFO] Received Librato Alert: %s", *alert)
|
||||
|
||||
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)
|
||||
d.Set("services", schema.NewSet(schema.HashString, services))
|
||||
|
||||
conditions := resourceLibratoAlertConditionsGather(d, alert.Conditions)
|
||||
d.Set("condition", conditions)
|
||||
d.Set("condition", schema.NewSet(resourceLibratoAlertConditionsHash, conditions))
|
||||
|
||||
attributes := resourceLibratoAlertAttributesGather(d, alert.Attributes)
|
||||
d.Set("attributes", attributes)
|
||||
|
@ -268,8 +268,8 @@ func resourceLibratoAlertReadResult(d *schema.ResourceData, alert *librato.Alert
|
|||
return nil
|
||||
}
|
||||
|
||||
func resourceLibratoAlertServicesGather(d *schema.ResourceData, services []interface{}) []string {
|
||||
retServices := make([]string, 0, len(services))
|
||||
func resourceLibratoAlertServicesGather(d *schema.ResourceData, services []interface{}) []interface{} {
|
||||
retServices := make([]interface{}, 0, len(services))
|
||||
|
||||
for _, s := range services {
|
||||
serviceData := s.(map[string]interface{})
|
||||
|
@ -280,8 +280,8 @@ func resourceLibratoAlertServicesGather(d *schema.ResourceData, services []inter
|
|||
return retServices
|
||||
}
|
||||
|
||||
func resourceLibratoAlertConditionsGather(d *schema.ResourceData, conditions []librato.AlertCondition) []map[string]interface{} {
|
||||
retConditions := make([]map[string]interface{}, 0, len(conditions))
|
||||
func resourceLibratoAlertConditionsGather(d *schema.ResourceData, conditions []librato.AlertCondition) []interface{} {
|
||||
retConditions := make([]interface{}, 0, len(conditions))
|
||||
for _, c := range conditions {
|
||||
condition := make(map[string]interface{})
|
||||
if c.Type != nil {
|
||||
|
@ -300,7 +300,7 @@ func resourceLibratoAlertConditionsGather(d *schema.ResourceData, conditions []l
|
|||
condition["detect_reset"] = *c.MetricName
|
||||
}
|
||||
if c.Duration != nil {
|
||||
condition["duration"] = *c.Duration
|
||||
condition["duration"] = int(*c.Duration)
|
||||
}
|
||||
if c.SummaryFunction != nil {
|
||||
condition["summary_function"] = *c.SummaryFunction
|
||||
|
@ -334,16 +334,25 @@ func resourceLibratoAlertUpdate(d *schema.ResourceData, meta interface{}) error
|
|||
return err
|
||||
}
|
||||
|
||||
// Just to have whole object for comparison before/after update
|
||||
fullAlert, _, err := client.Alerts.Get(uint(alertID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
alert := new(librato.Alert)
|
||||
alert.Name = librato.String(d.Get("name").(string))
|
||||
if d.HasChange("description") {
|
||||
alert.Description = librato.String(d.Get("description").(string))
|
||||
fullAlert.Description = alert.Description
|
||||
}
|
||||
if d.HasChange("active") {
|
||||
alert.Active = librato.Bool(d.Get("active").(bool))
|
||||
fullAlert.Active = alert.Active
|
||||
}
|
||||
if d.HasChange("rearm_seconds") {
|
||||
alert.RearmSeconds = librato.Uint(uint(d.Get("rearm_seconds").(int)))
|
||||
fullAlert.RearmSeconds = alert.RearmSeconds
|
||||
}
|
||||
if d.HasChange("services") {
|
||||
vs := d.Get("services").(*schema.Set)
|
||||
|
@ -352,6 +361,7 @@ func resourceLibratoAlertUpdate(d *schema.ResourceData, meta interface{}) error
|
|||
services[i] = librato.String(serviceData.(string))
|
||||
}
|
||||
alert.Services = services
|
||||
fullAlert.RearmSeconds = alert.RearmSeconds
|
||||
}
|
||||
|
||||
vs := d.Get("condition").(*schema.Set)
|
||||
|
@ -382,6 +392,7 @@ func resourceLibratoAlertUpdate(d *schema.ResourceData, meta interface{}) error
|
|||
}
|
||||
conditions[i] = condition
|
||||
alert.Conditions = conditions
|
||||
fullAlert.Conditions = conditions
|
||||
}
|
||||
if d.HasChange("attributes") {
|
||||
attributeData := d.Get("attributes").([]interface{})
|
||||
|
@ -397,14 +408,42 @@ func resourceLibratoAlertUpdate(d *schema.ResourceData, meta interface{}) error
|
|||
attributes.RunbookURL = librato.String(v)
|
||||
}
|
||||
alert.Attributes = attributes
|
||||
fullAlert.Attributes = attributes
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Updating Librato alert: %s", alert)
|
||||
_, err = client.Alerts.Edit(uint(alertID), alert)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating Librato alert: %s", err)
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Updated Librato alert %d", alertID)
|
||||
|
||||
// Wait for propagation since Librato updates are eventually consistent
|
||||
wait := resource.StateChangeConf{
|
||||
Pending: []string{fmt.Sprintf("%t", false)},
|
||||
Target: []string{fmt.Sprintf("%t", true)},
|
||||
Timeout: 5 * time.Minute,
|
||||
MinTimeout: 2 * time.Second,
|
||||
ContinuousTargetOccurence: 5,
|
||||
Refresh: func() (interface{}, string, error) {
|
||||
log.Printf("[DEBUG] Checking if Librato Alert %d was updated yet", alertID)
|
||||
changedAlert, _, err := client.Alerts.Get(uint(alertID))
|
||||
if err != nil {
|
||||
return changedAlert, "", err
|
||||
}
|
||||
isEqual := reflect.DeepEqual(*fullAlert, *changedAlert)
|
||||
log.Printf("[DEBUG] Updated Librato Alert %d match: %t", alertID, isEqual)
|
||||
return changedAlert, fmt.Sprintf("%t", isEqual), nil
|
||||
},
|
||||
}
|
||||
|
||||
_, err = wait.WaitForState()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed updating Librato Alert %d: %s", alertID, err)
|
||||
}
|
||||
|
||||
return resourceLibratoAlertRead(d, meta)
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
|
@ -124,6 +125,7 @@ func resourceLibratoServiceRead(d *schema.ResourceData, meta interface{}) error
|
|||
return err
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Reading Librato Service: %d", id)
|
||||
service, _, err := client.Services.Get(uint(id))
|
||||
if err != nil {
|
||||
if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 {
|
||||
|
@ -132,6 +134,7 @@ func resourceLibratoServiceRead(d *schema.ResourceData, meta interface{}) error
|
|||
}
|
||||
return fmt.Errorf("Error reading Librato Service %s: %s", d.Id(), err)
|
||||
}
|
||||
log.Printf("[INFO] Received Librato Service: %s", service)
|
||||
|
||||
return resourceLibratoServiceReadResult(d, service)
|
||||
}
|
||||
|
@ -155,12 +158,20 @@ func resourceLibratoServiceUpdate(d *schema.ResourceData, meta interface{}) erro
|
|||
return err
|
||||
}
|
||||
|
||||
// Just to have whole object for comparison before/after update
|
||||
fullService, _, err := client.Services.Get(uint(serviceID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
service := new(librato.Service)
|
||||
if d.HasChange("type") {
|
||||
service.Type = librato.String(d.Get("type").(string))
|
||||
fullService.Type = service.Type
|
||||
}
|
||||
if d.HasChange("title") {
|
||||
service.Title = librato.String(d.Get("title").(string))
|
||||
fullService.Title = service.Title
|
||||
}
|
||||
if d.HasChange("settings") {
|
||||
res, err := resourceLibratoServicesExpandSettings(normalizeJson(d.Get("settings").(string)))
|
||||
|
@ -168,12 +179,39 @@ func resourceLibratoServiceUpdate(d *schema.ResourceData, meta interface{}) erro
|
|||
return fmt.Errorf("Error expanding Librato service settings: %s", err)
|
||||
}
|
||||
service.Settings = res
|
||||
fullService.Settings = res
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Updating Librato Service %d: %s", serviceID, service)
|
||||
_, err = client.Services.Edit(uint(serviceID), service)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating Librato service: %s", err)
|
||||
}
|
||||
log.Printf("[INFO] Updated Librato Service %d", serviceID)
|
||||
|
||||
// Wait for propagation since Librato updates are eventually consistent
|
||||
wait := resource.StateChangeConf{
|
||||
Pending: []string{fmt.Sprintf("%t", false)},
|
||||
Target: []string{fmt.Sprintf("%t", true)},
|
||||
Timeout: 5 * time.Minute,
|
||||
MinTimeout: 2 * time.Second,
|
||||
ContinuousTargetOccurence: 5,
|
||||
Refresh: func() (interface{}, string, error) {
|
||||
log.Printf("[DEBUG] Checking if Librato Service %d was updated yet", serviceID)
|
||||
changedService, _, err := client.Services.Get(uint(serviceID))
|
||||
if err != nil {
|
||||
return changedService, "", err
|
||||
}
|
||||
isEqual := reflect.DeepEqual(*fullService, *changedService)
|
||||
log.Printf("[DEBUG] Updated Librato Service %d match: %t", serviceID, isEqual)
|
||||
return changedService, fmt.Sprintf("%t", isEqual), nil
|
||||
},
|
||||
}
|
||||
|
||||
_, err = wait.WaitForState()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed updating Librato Service %d: %s", serviceID, err)
|
||||
}
|
||||
|
||||
return resourceLibratoServiceRead(d, meta)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
|
@ -339,9 +340,16 @@ func resourceLibratoSpaceChartUpdate(d *schema.ResourceData, meta interface{}) e
|
|||
return err
|
||||
}
|
||||
|
||||
// Just to have whole object for comparison before/after update
|
||||
fullChart, _, err := client.Spaces.GetChart(spaceID, uint(chartID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
spaceChart := new(librato.SpaceChart)
|
||||
if d.HasChange("name") {
|
||||
spaceChart.Name = librato.String(d.Get("name").(string))
|
||||
fullChart.Name = spaceChart.Name
|
||||
}
|
||||
if d.HasChange("min") {
|
||||
if math.IsNaN(d.Get("min").(float64)) {
|
||||
|
@ -349,6 +357,7 @@ func resourceLibratoSpaceChartUpdate(d *schema.ResourceData, meta interface{}) e
|
|||
} else {
|
||||
spaceChart.Min = librato.Float(d.Get("min").(float64))
|
||||
}
|
||||
fullChart.Min = spaceChart.Min
|
||||
}
|
||||
if d.HasChange("max") {
|
||||
if math.IsNaN(d.Get("max").(float64)) {
|
||||
|
@ -356,12 +365,15 @@ func resourceLibratoSpaceChartUpdate(d *schema.ResourceData, meta interface{}) e
|
|||
} else {
|
||||
spaceChart.Max = librato.Float(d.Get("max").(float64))
|
||||
}
|
||||
fullChart.Max = spaceChart.Max
|
||||
}
|
||||
if d.HasChange("label") {
|
||||
spaceChart.Label = librato.String(d.Get("label").(string))
|
||||
fullChart.Label = spaceChart.Label
|
||||
}
|
||||
if d.HasChange("related_space") {
|
||||
spaceChart.RelatedSpace = librato.Uint(d.Get("related_space").(uint))
|
||||
fullChart.RelatedSpace = spaceChart.RelatedSpace
|
||||
}
|
||||
if d.HasChange("stream") {
|
||||
vs := d.Get("stream").(*schema.Set)
|
||||
|
@ -405,6 +417,7 @@ func resourceLibratoSpaceChartUpdate(d *schema.ResourceData, meta interface{}) e
|
|||
streams[i] = stream
|
||||
}
|
||||
spaceChart.Streams = streams
|
||||
fullChart.Streams = streams
|
||||
}
|
||||
|
||||
_, err = client.Spaces.EditChart(spaceID, uint(chartID), spaceChart)
|
||||
|
@ -412,6 +425,30 @@ func resourceLibratoSpaceChartUpdate(d *schema.ResourceData, meta interface{}) e
|
|||
return fmt.Errorf("Error updating Librato space chart %s: %s", *spaceChart.Name, err)
|
||||
}
|
||||
|
||||
// Wait for propagation since Librato updates are eventually consistent
|
||||
wait := resource.StateChangeConf{
|
||||
Pending: []string{fmt.Sprintf("%t", false)},
|
||||
Target: []string{fmt.Sprintf("%t", true)},
|
||||
Timeout: 5 * time.Minute,
|
||||
MinTimeout: 2 * time.Second,
|
||||
ContinuousTargetOccurence: 5,
|
||||
Refresh: func() (interface{}, string, error) {
|
||||
log.Printf("[DEBUG] Checking if Librato Space Chart %d was updated yet", chartID)
|
||||
changedChart, _, err := client.Spaces.GetChart(spaceID, uint(chartID))
|
||||
if err != nil {
|
||||
return changedChart, "", err
|
||||
}
|
||||
isEqual := reflect.DeepEqual(*fullChart, *changedChart)
|
||||
log.Printf("[DEBUG] Updated Librato Space Chart %d match: %t", chartID, isEqual)
|
||||
return changedChart, fmt.Sprintf("%t", isEqual), nil
|
||||
},
|
||||
}
|
||||
|
||||
_, err = wait.WaitForState()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed updating Librato Space Chart %d: %s", chartID, err)
|
||||
}
|
||||
|
||||
return resourceLibratoSpaceChartRead(d, meta)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue