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)
	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(uint(d.Get("rearm_seconds").(int)))
	}
	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
	}

	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"].(int); ok {
			condition.Duration = librato.Uint(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 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"].(int); ok {
				condition.Duration = librato.Uint(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)
}