From 8034a9e097ae87ea7fa6b16fa519f6aef2966576 Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Thu, 12 Sep 2019 17:23:55 -0400 Subject: [PATCH 01/22] Make alert resource compatible with new appoptics SDK --- appoptics/resource_librato_alert.go | 331 ++++++++++++++++------------ 1 file changed, 188 insertions(+), 143 deletions(-) diff --git a/appoptics/resource_librato_alert.go b/appoptics/resource_librato_alert.go index a4fad62..3caeba7 100644 --- a/appoptics/resource_librato_alert.go +++ b/appoptics/resource_librato_alert.go @@ -8,7 +8,7 @@ import ( "strconv" "time" - "github.com/akahn/go-librato/librato" + "github.com/appoptics/appoptics-api-go" "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" @@ -54,15 +54,32 @@ func resourceAppOpticsAlert() *schema.Resource { Schema: map[string]*schema.Schema{ "type": { Type: schema.TypeString, - Required: true, + Optional: true, }, "metric_name": { Type: schema.TypeString, - Required: true, + Optional: true, }, - "source": { - Type: schema.TypeString, + "tag": { + Type: schema.TypeList, Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + }, + "grouped": { + Type: schema.TypeBool, + Optional: true, + }, + "values": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, }, "detect_reset": { Type: schema.TypeBool, @@ -85,17 +102,8 @@ func resourceAppOpticsAlert() *schema.Resource { Set: resourceAppOpticsAlertConditionsHash, }, "attributes": { - Type: schema.TypeList, + Type: schema.TypeMap, Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "runbook_url": { - Type: schema.TypeString, - Optional: true, - }, - }, - }, }, }, } @@ -107,9 +115,9 @@ func resourceAppOpticsAlertConditionsHash(v interface{}) int { 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))) + tags, present := m["tag"].([]interface{}) + if present && len(tags) > 0 { + buf.WriteString(fmt.Sprintf("%d-", tagsHash(tags))) } detectReset, present := m["detect_reset"] @@ -135,57 +143,92 @@ func resourceAppOpticsAlertConditionsHash(v interface{}) int { return hashcode.String(buf.String()) } +func tagsHash(tags []interface{}) int { + var buf bytes.Buffer + for _, v := range tags { + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", m["name"])) + buf.WriteString(fmt.Sprintf("%s-", m["grouped"])) + buf.WriteString(fmt.Sprintf("%d-", tagsValuesHash(m["values"].([]interface{})))) + } + + return hashcode.String(buf.String()) +} + +func tagsValuesHash(s []interface{}) int { + var buf bytes.Buffer + for _, v := range s { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + + return hashcode.String(buf.String()) +} + func resourceAppOpticsAlertCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*librato.Client) + client := meta.(*appoptics.Client) - alert := librato.Alert{ - Name: librato.String(d.Get("name").(string)), + alert := appoptics.Alert{ + Name: d.Get("name").(string), } if v, ok := d.GetOk("description"); ok { - alert.Description = librato.String(v.(string)) + alert.Description = v.(string) } // GetOK returns not OK for false boolean values, use Get - alert.Active = librato.Bool(d.Get("active").(bool)) + alert.Active = d.Get("active").(bool) if v, ok := d.GetOk("rearm_seconds"); ok { - alert.RearmSeconds = librato.Uint(uint(v.(int))) + alert.RearmSeconds = v.(int) } if v, ok := d.GetOk("services"); ok { vs := v.(*schema.Set) - services := make([]*string, vs.Len()) + services := make([]*appoptics.Service, vs.Len()) for i, serviceData := range vs.List() { - services[i] = librato.String(serviceData.(string)) + services[i] = serviceData.(*appoptics.Service) } alert.Services = services } if v, ok := d.GetOk("condition"); ok { vs := v.(*schema.Set) - conditions := make([]librato.AlertCondition, vs.Len()) + conditions := make([]*appoptics.AlertCondition, vs.Len()) + for i, conditionDataM := range vs.List() { conditionData := conditionDataM.(map[string]interface{}) - var condition librato.AlertCondition + condition := appoptics.AlertCondition{} + if v, ok := conditionData["type"].(string); ok && v != "" { - condition.Type = librato.String(v) + condition.Type = v } if v, ok := conditionData["threshold"].(float64); ok && !math.IsNaN(v) { - condition.Threshold = librato.Float(v) + condition.Threshold = 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) + condition.MetricName = v } - if v, ok := conditionData["detect_reset"].(bool); ok { - condition.DetectReset = librato.Bool(v) + if v, ok := conditionData["tag"].([]interface{}); ok { + tags := make([]*appoptics.Tag, len(v)) + for i, tagData := range v { + tag := appoptics.Tag{} + tag.Grouped = tagData.(map[string]interface{})["grouped"].(bool) + tag.Name = tagData.(map[string]interface{})["name"].(string) + values := tagData.(map[string]interface{})["values"].([]interface{}) + valuesInStrings := make([]string, len(values)) + for i, v := range values { + valuesInStrings[i] = v.(string) + } + tag.Values = valuesInStrings + tags[i] = &tag + } + + condition.Tags = tags } if v, ok := conditionData["duration"].(int); ok { - condition.Duration = librato.Uint(uint(v)) + condition.Duration = v } if v, ok := conditionData["summary_function"].(string); ok && v != "" { - condition.SummaryFunction = librato.String(v) + condition.SummaryFunction = v } - conditions[i] = condition + conditions[i] = &condition } + alert.Conditions = conditions } if v, ok := d.GetOk("attributes"); ok { @@ -196,26 +239,22 @@ func resourceAppOpticsAlertCreate(d *schema.ResourceData, meta interface{}) erro 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 + // The only attribute here should be the runbook_url + alert.Attributes = attributeData[0].(map[string]interface{}) } } - alertResult, _, err := client.Alerts.Create(&alert) + alertResult, err := client.AlertsService().Create(&alert) if err != nil { - return fmt.Errorf("Error creating AppOptics alert %s: %s", *alert.Name, err) + return fmt.Errorf("Error creating AppOptics alert %s: %s", alert.Name, err) } log.Printf("[INFO] Created AppOptics alert: %s", *alertResult) retryErr := resource.Retry(1*time.Minute, func() *resource.RetryError { - _, _, err := client.Alerts.Get(*alertResult.ID) + _, err := client.AlertsService().Retrieve(alertResult.ID) if err != nil { - if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 { + if errResp, ok := err.(*appoptics.ErrorResponse); ok && errResp.Response.StatusCode == 404 { return resource.RetryableError(err) } return resource.NonRetryableError(err) @@ -223,25 +262,25 @@ func resourceAppOpticsAlertCreate(d *schema.ResourceData, meta interface{}) erro return nil }) if retryErr != nil { - return fmt.Errorf("Error creating librato alert: %s", err) + return fmt.Errorf("Error creating AppOptics alert: %s", err) } - d.SetId(strconv.FormatUint(uint64(*alertResult.ID), 10)) + d.SetId(strconv.FormatUint(uint64(alertResult.ID), 10)) return resourceAppOpticsAlertRead(d, meta) } func resourceAppOpticsAlertRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*librato.Client) + client := meta.(*appoptics.Client) id, err := strconv.ParseUint(d.Id(), 10, 0) if err != nil { return err } log.Printf("[INFO] Reading AppOptics Alert: %d", id) - alert, _, err := client.Alerts.Get(uint(id)) + alert, err := client.AlertsService().Retrieve(int(id)) if err != nil { - if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 { + if errResp, ok := err.(*appoptics.ErrorResponse); ok && errResp.Response.StatusCode == 404 { d.SetId("") return nil } @@ -251,173 +290,179 @@ func resourceAppOpticsAlertRead(d *schema.ResourceData, meta interface{}) error d.Set("name", alert.Name) - if alert.Description != nil { - if err := d.Set("description", alert.Description); err != nil { - return err - } + if err := d.Set("description", alert.Description); err != nil { + return err } - if alert.Active != nil { - if err := d.Set("active", alert.Active); err != nil { - return err - } + + if err := d.Set("active", alert.Active); err != nil { + return err } - if alert.RearmSeconds != nil { - if err := d.Set("rearm_seconds", alert.RearmSeconds); err != nil { - return err - } + + if err := d.Set("rearm_seconds", alert.RearmSeconds); err != nil { + return err } // Since the following aren't simple terraform types (TypeList), it's best to // catch the error returned from the d.Set() function, and handle accordingly. - services := resourceAppOpticsAlertServicesGather(d, alert.Services.([]interface{})) + services := flattenServices(d, alert.Services) + // TODO: does this need `schema.NewSet(...)`? if err := d.Set("services", schema.NewSet(schema.HashString, services)); err != nil { return err } - conditions := resourceAppOpticsAlertConditionsGather(d, alert.Conditions) - if err := d.Set("condition", schema.NewSet(resourceAppOpticsAlertConditionsHash, conditions)); err != nil { + conditions := flattenCondition(d, alert.Conditions) + if err := d.Set("condition", conditions); err != nil { return err } - attributes := resourceAppOpticsAlertAttributesGather(d, alert.Attributes) - if err := d.Set("attributes", attributes); err != nil { + if err := d.Set("attributes", alert.Attributes); err != nil { return err } return nil } -func resourceAppOpticsAlertServicesGather(d *schema.ResourceData, services []interface{}) []interface{} { +func flattenServices(d *schema.ResourceData, services []*appoptics.Service) []interface{} { retServices := make([]interface{}, 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"])) + for _, serviceData := range services { + retServices = append(retServices, fmt.Sprintf("%.f", serviceData.ID)) } return retServices } -func resourceAppOpticsAlertConditionsGather(d *schema.ResourceData, conditions []librato.AlertCondition) []interface{} { +func flattenCondition(d *schema.ResourceData, conditions []*appoptics.AlertCondition) []interface{} { retConditions := make([]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"] = int(*c.Duration) - } - if c.SummaryFunction != nil { - condition["summary_function"] = *c.SummaryFunction - } + condition["type"] = c.Type + condition["threshold"] = c.Threshold + condition["metric_name"] = c.MetricName + condition["tag"] = flattenConditionTags(c.Tags) + // TODO: once we upgrade the appoptics-api-go dependency, + // we need to add a `condition["detect_reset"] = c.DetectReset` below + // SEE: https://github.com/appoptics/terraform-provider-appoptics/issues/12 + // condition["detect_reset"] = c.DetectReset + condition["duration"] = int(c.Duration) + condition["summary_function"] = c.SummaryFunction retConditions = append(retConditions, condition) } return retConditions } -// Flattens an attributes hash into something that flatmap.Flatten() can handle -func resourceAppOpticsAlertAttributesGather(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 +func flattenConditionTags(in []*appoptics.Tag) []interface{} { + var out = make([]interface{}, 0, len(in)) + for _, v := range in { + m := make(map[string]interface{}) + m["name"] = v.Name + m["grouped"] = v.Grouped + if len(v.Values) > 0 { + m["values"] = flattenConditionTagsValues(v.Values) } - result = append(result, retAttributes) + out = append(out, m) } - return result + return out +} + +func flattenConditionTagsValues(in []string) []interface{} { + vs := make([]interface{}, 0, len(in)) + for _, v := range in { + vs = append(vs, v) + } + return vs } func resourceAppOpticsAlertUpdate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*librato.Client) + client := meta.(*appoptics.Client) - id, err := strconv.ParseUint(d.Id(), 10, 0) + id, err := strconv.ParseInt(d.Id(), 10, 0) if err != nil { return err } - alert := new(librato.Alert) - alert.Name = librato.String(d.Get("name").(string)) + alert := new(appoptics.Alert) + alert.ID = int(id) + alert.Name = d.Get("name").(string) if d.HasChange("description") { - alert.Description = librato.String(d.Get("description").(string)) + alert.Description = d.Get("description").(string) } if d.HasChange("active") { - alert.Active = librato.Bool(d.Get("active").(bool)) + alert.Active = d.Get("active").(bool) } if d.HasChange("rearm_seconds") { - alert.RearmSeconds = librato.Uint(uint(d.Get("rearm_seconds").(int))) + alert.RearmSeconds = d.Get("rearm_seconds").(int) } if d.HasChange("services") { vs := d.Get("services").(*schema.Set) - services := make([]*string, vs.Len()) + services := make([]*appoptics.Service, vs.Len()) for i, serviceData := range vs.List() { - services[i] = librato.String(serviceData.(string)) + services[i] = serviceData.(*appoptics.Service) } alert.Services = services } + // We always have to send the conditions hash, from the API docs: + // + // NOTE: This method requires the conditions hash. + // If conditions is not included in the payload, the alert conditions will be removed. vs := d.Get("condition").(*schema.Set) - conditions := make([]librato.AlertCondition, vs.Len()) + conditions := make([]*appoptics.AlertCondition, vs.Len()) + for i, conditionDataM := range vs.List() { conditionData := conditionDataM.(map[string]interface{}) - var condition librato.AlertCondition + condition := appoptics.AlertCondition{} + if v, ok := conditionData["type"].(string); ok && v != "" { - condition.Type = librato.String(v) + condition.Type = v } if v, ok := conditionData["threshold"].(float64); ok && !math.IsNaN(v) { - condition.Threshold = librato.Float(v) + condition.Threshold = v } if v, ok := conditionData["metric_name"].(string); ok && v != "" { - condition.MetricName = librato.String(v) + condition.MetricName = 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["tag"].([]interface{}); ok { + tags := make([]*appoptics.Tag, len(v)) + for i, tagData := range v { + tag := appoptics.Tag{} + tag.Grouped = tagData.(map[string]interface{})["grouped"].(bool) + tag.Name = tagData.(map[string]interface{})["name"].(string) + values := tagData.(map[string]interface{})["values"].([]interface{}) + valuesInStrings := make([]string, len(values)) + for i, v := range values { + valuesInStrings[i] = v.(string) + } + tag.Values = valuesInStrings + tags[i] = &tag + } + + condition.Tags = tags } if v, ok := conditionData["duration"].(int); ok { - condition.Duration = librato.Uint(uint(v)) + condition.Duration = v } if v, ok := conditionData["summary_function"].(string); ok && v != "" { - condition.SummaryFunction = librato.String(v) + condition.SummaryFunction = v } - conditions[i] = condition - alert.Conditions = conditions + conditions[i] = &condition } + alert.Conditions = conditions + if d.HasChange("attributes") { attributeData := d.Get("attributes").([]interface{}) 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 + + alert.Attributes = attributeData[0].(map[string]interface{}) } log.Printf("[INFO] Updating AppOptics alert: %s", alert) - _, updErr := client.Alerts.Update(uint(id), alert) + updErr := client.AlertsService().Update(alert) if updErr != nil { return fmt.Errorf("Error updating AppOptics alert: %s", updErr) } @@ -433,7 +478,7 @@ func resourceAppOpticsAlertUpdate(d *schema.ResourceData, meta interface{}) erro ContinuousTargetOccurence: 5, Refresh: func() (interface{}, string, error) { log.Printf("[DEBUG] Checking if AppOptics Alert %d was updated yet", id) - changedAlert, _, getErr := client.Alerts.Get(uint(id)) + changedAlert, getErr := client.AlertsService().Retrieve(int(id)) if getErr != nil { return changedAlert, "", getErr } @@ -450,22 +495,22 @@ func resourceAppOpticsAlertUpdate(d *schema.ResourceData, meta interface{}) erro } func resourceAppOpticsAlertDelete(d *schema.ResourceData, meta interface{}) error { - client := meta.(*librato.Client) + client := meta.(*appoptics.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)) + err = client.AlertsService().Delete(int(id)) if err != nil { return fmt.Errorf("Error deleting Alert: %s", err) } retryErr := resource.Retry(1*time.Minute, func() *resource.RetryError { - _, _, err := client.Alerts.Get(uint(id)) + _, err := client.AlertsService().Retrieve(int(id)) if err != nil { - if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 { + if errResp, ok := err.(*appoptics.ErrorResponse); ok && errResp.Response.StatusCode == 404 { return nil } return resource.NonRetryableError(err) From fbfaba9b783bbcf4bb8938cd808bb8119a25601d Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Sat, 14 Sep 2019 15:20:30 -0400 Subject: [PATCH 02/22] Rename alert resource file from librato --- .../{resource_librato_alert.go => resource_appoptics_alert.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename appoptics/{resource_librato_alert.go => resource_appoptics_alert.go} (100%) diff --git a/appoptics/resource_librato_alert.go b/appoptics/resource_appoptics_alert.go similarity index 100% rename from appoptics/resource_librato_alert.go rename to appoptics/resource_appoptics_alert.go From ab5759220631c810037a583543aa90b3c49c33d2 Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Mon, 16 Sep 2019 08:55:35 -0400 Subject: [PATCH 03/22] Fix tests --- appoptics/resource_librato_space_chart_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appoptics/resource_librato_space_chart_test.go b/appoptics/resource_librato_space_chart_test.go index 7e95632..25451ab 100644 --- a/appoptics/resource_librato_space_chart_test.go +++ b/appoptics/resource_librato_space_chart_test.go @@ -40,7 +40,7 @@ func TestAccAppOpticsSpaceChart_Full(t *testing.T) { CheckDestroy: testAccCheckAppOpticsSpaceChartDestroy, Steps: []resource.TestStep{ resource.TestStep{ - Config: testAccCheckAppOpticsSpaceChartConfig_full, + Config: testAccCheckAppOpticsSpaceChartConfigFull, Check: resource.ComposeTestCheckFunc( testAccCheckAppOpticsSpaceChartExists("appoptics_space_chart.foobar", &spaceChart), testAccCheckAppOpticsSpaceChartName(&spaceChart, "Foo Bar"), From 1d98b8a6cd51efce6cfcbae3aa00ed957f47eeaa Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Mon, 16 Sep 2019 09:29:52 -0400 Subject: [PATCH 04/22] Fix type references --- appoptics/resource_appoptics_alert.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/appoptics/resource_appoptics_alert.go b/appoptics/resource_appoptics_alert.go index 3caeba7..a826869 100644 --- a/appoptics/resource_appoptics_alert.go +++ b/appoptics/resource_appoptics_alert.go @@ -249,7 +249,7 @@ func resourceAppOpticsAlertCreate(d *schema.ResourceData, meta interface{}) erro if err != nil { return fmt.Errorf("Error creating AppOptics alert %s: %s", alert.Name, err) } - log.Printf("[INFO] Created AppOptics alert: %s", *alertResult) + log.Printf("[INFO] Created AppOptics alert: %s", alertResult.Name) retryErr := resource.Retry(1*time.Minute, func() *resource.RetryError { _, err := client.AlertsService().Retrieve(alertResult.ID) @@ -286,7 +286,7 @@ func resourceAppOpticsAlertRead(d *schema.ResourceData, meta interface{}) error } return fmt.Errorf("Error reading AppOptics Alert %s: %s", d.Id(), err) } - log.Printf("[INFO] Received AppOptics Alert: %s", *alert) + log.Printf("[INFO] Received AppOptics Alert: %s", alert.Name) d.Set("name", alert.Name) @@ -326,7 +326,7 @@ func flattenServices(d *schema.ResourceData, services []*appoptics.Service) []in retServices := make([]interface{}, 0, len(services)) for _, serviceData := range services { - retServices = append(retServices, fmt.Sprintf("%.f", serviceData.ID)) + retServices = append(retServices, fmt.Sprintf("%.d", serviceData.ID)) } return retServices @@ -461,7 +461,7 @@ func resourceAppOpticsAlertUpdate(d *schema.ResourceData, meta interface{}) erro alert.Attributes = attributeData[0].(map[string]interface{}) } - log.Printf("[INFO] Updating AppOptics alert: %s", alert) + log.Printf("[INFO] Updating AppOptics alert: %s", alert.Name) updErr := client.AlertsService().Update(alert) if updErr != nil { return fmt.Errorf("Error updating AppOptics alert: %s", updErr) From 80c9e25c098c2ebd7a85aa77f13f7dd64f72fd53 Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Mon, 16 Sep 2019 09:30:24 -0400 Subject: [PATCH 05/22] Update alert resource tests for new SDK --- appoptics/resource_librato_alert_test.go | 84 ++++++++++++------------ 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/appoptics/resource_librato_alert_test.go b/appoptics/resource_librato_alert_test.go index bfbf498..c2878c3 100644 --- a/appoptics/resource_librato_alert_test.go +++ b/appoptics/resource_librato_alert_test.go @@ -5,14 +5,14 @@ import ( "strconv" "testing" - "github.com/akahn/go-librato/librato" + "github.com/appoptics/appoptics-api-go" "github.com/hashicorp/terraform/helper/acctest" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" ) -func TestAccAppOpticsAlert_Minimal(t *testing.T) { - var alert librato.Alert +func TestAccAppOpticsAlertMinimal(t *testing.T) { + var alert appoptics.Alert name := acctest.RandString(10) resource.Test(t, resource.TestCase{ @@ -21,7 +21,7 @@ func TestAccAppOpticsAlert_Minimal(t *testing.T) { CheckDestroy: testAccCheckAppOpticsAlertDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckAppOpticsAlertConfig_minimal(name), + Config: testAccCheckAppOpticsAlertConfigMinimal(name), Check: resource.ComposeTestCheckFunc( testAccCheckAppOpticsAlertExists("appoptics_alert.foobar", &alert), testAccCheckAppOpticsAlertName(&alert, name), @@ -33,8 +33,8 @@ func TestAccAppOpticsAlert_Minimal(t *testing.T) { }) } -func TestAccAppOpticsAlert_Basic(t *testing.T) { - var alert librato.Alert +func TestAccAppOpticsAlertBasic(t *testing.T) { + var alert appoptics.Alert name := acctest.RandString(10) resource.Test(t, resource.TestCase{ @@ -43,7 +43,7 @@ func TestAccAppOpticsAlert_Basic(t *testing.T) { CheckDestroy: testAccCheckAppOpticsAlertDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckAppOpticsAlertConfig_basic(name), + Config: testAccCheckAppOpticsAlertConfigBasic(name), Check: resource.ComposeTestCheckFunc( testAccCheckAppOpticsAlertExists("appoptics_alert.foobar", &alert), testAccCheckAppOpticsAlertName(&alert, name), @@ -56,8 +56,8 @@ func TestAccAppOpticsAlert_Basic(t *testing.T) { }) } -func TestAccAppOpticsAlert_Full(t *testing.T) { - var alert librato.Alert +func TestAccAppOpticsAlertFull(t *testing.T) { + var alert appoptics.Alert name := acctest.RandString(10) resource.Test(t, resource.TestCase{ @@ -66,7 +66,7 @@ func TestAccAppOpticsAlert_Full(t *testing.T) { CheckDestroy: testAccCheckAppOpticsAlertDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckAppOpticsAlertConfig_full(name), + Config: testAccCheckAppOpticsAlertConfigFull(name), Check: resource.ComposeTestCheckFunc( testAccCheckAppOpticsAlertExists("appoptics_alert.foobar", &alert), testAccCheckAppOpticsAlertName(&alert, name), @@ -74,7 +74,7 @@ func TestAccAppOpticsAlert_Full(t *testing.T) { resource.TestCheckResourceAttr( "appoptics_alert.foobar", "name", name), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.836525194.metric_name", "librato.cpu.percent.idle"), + "appoptics_alert.foobar", "condition.836525194.metric_name", "appoptics.cpu.percent.idle"), resource.TestCheckResourceAttr( "appoptics_alert.foobar", "condition.836525194.type", "above"), resource.TestCheckResourceAttr( @@ -87,8 +87,8 @@ func TestAccAppOpticsAlert_Full(t *testing.T) { }) } -func TestAccAppOpticsAlert_Updated(t *testing.T) { - var alert librato.Alert +func TestAccAppOpticsAlertUpdated(t *testing.T) { + var alert appoptics.Alert name := acctest.RandString(10) resource.Test(t, resource.TestCase{ @@ -97,7 +97,7 @@ func TestAccAppOpticsAlert_Updated(t *testing.T) { CheckDestroy: testAccCheckAppOpticsAlertDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckAppOpticsAlertConfig_basic(name), + Config: testAccCheckAppOpticsAlertConfigBasic(name), Check: resource.ComposeTestCheckFunc( testAccCheckAppOpticsAlertExists("appoptics_alert.foobar", &alert), testAccCheckAppOpticsAlertDescription(&alert, "A Test Alert"), @@ -106,7 +106,7 @@ func TestAccAppOpticsAlert_Updated(t *testing.T) { ), }, { - Config: testAccCheckAppOpticsAlertConfig_new_value(name), + Config: testAccCheckAppOpticsAlertConfigNewValue(name), Check: resource.ComposeTestCheckFunc( testAccCheckAppOpticsAlertExists("appoptics_alert.foobar", &alert), testAccCheckAppOpticsAlertDescription(&alert, "A modified Test Alert"), @@ -118,8 +118,8 @@ func TestAccAppOpticsAlert_Updated(t *testing.T) { }) } -func TestAccAppOpticsAlert_Rename(t *testing.T) { - var alert librato.Alert +func TestAccAppOpticsAlertRename(t *testing.T) { + var alert appoptics.Alert name := acctest.RandString(10) newName := acctest.RandString(10) @@ -129,7 +129,7 @@ func TestAccAppOpticsAlert_Rename(t *testing.T) { CheckDestroy: testAccCheckAppOpticsAlertDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckAppOpticsAlertConfig_basic(name), + Config: testAccCheckAppOpticsAlertConfigBasic(name), Check: resource.ComposeTestCheckFunc( testAccCheckAppOpticsAlertExists("appoptics_alert.foobar", &alert), resource.TestCheckResourceAttr( @@ -137,7 +137,7 @@ func TestAccAppOpticsAlert_Rename(t *testing.T) { ), }, { - Config: testAccCheckAppOpticsAlertConfig_basic(newName), + Config: testAccCheckAppOpticsAlertConfigBasic(newName), Check: resource.ComposeTestCheckFunc( testAccCheckAppOpticsAlertExists("appoptics_alert.foobar", &alert), resource.TestCheckResourceAttr( @@ -148,8 +148,8 @@ func TestAccAppOpticsAlert_Rename(t *testing.T) { }) } -func TestAccAppOpticsAlert_FullUpdate(t *testing.T) { - var alert librato.Alert +func TestAccAppOpticsAlertFullUpdate(t *testing.T) { + var alert appoptics.Alert name := acctest.RandString(10) resource.Test(t, resource.TestCase{ @@ -158,7 +158,7 @@ func TestAccAppOpticsAlert_FullUpdate(t *testing.T) { CheckDestroy: testAccCheckAppOpticsAlertDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckAppOpticsAlertConfig_full_update(name), + Config: testAccCheckAppOpticsAlertConfigFullUpdate(name), Check: resource.ComposeTestCheckFunc( testAccCheckAppOpticsAlertExists("appoptics_alert.foobar", &alert), testAccCheckAppOpticsAlertName(&alert, name), @@ -168,7 +168,7 @@ func TestAccAppOpticsAlert_FullUpdate(t *testing.T) { resource.TestCheckResourceAttr( "appoptics_alert.foobar", "rearm_seconds", "1200"), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.2524844643.metric_name", "librato.cpu.percent.idle"), + "appoptics_alert.foobar", "condition.2524844643.metric_name", "appoptics.cpu.percent.idle"), resource.TestCheckResourceAttr( "appoptics_alert.foobar", "condition.2524844643.type", "above"), resource.TestCheckResourceAttr( @@ -182,7 +182,7 @@ func TestAccAppOpticsAlert_FullUpdate(t *testing.T) { } func testAccCheckAppOpticsAlertDestroy(s *terraform.State) error { - client := testAccProvider.Meta().(*librato.Client) + client := testAccProvider.Meta().(*appoptics.Client) for _, rs := range s.RootModule().Resources { if rs.Type != "appoptics_alert" { @@ -194,7 +194,7 @@ func testAccCheckAppOpticsAlertDestroy(s *terraform.State) error { return fmt.Errorf("ID not a number") } - _, _, err = client.Alerts.Get(uint(id)) + _, err = client.AlertsService().Retrieve(int(id)) if err == nil { return fmt.Errorf("Alert still exists") @@ -204,29 +204,29 @@ func testAccCheckAppOpticsAlertDestroy(s *terraform.State) error { return nil } -func testAccCheckAppOpticsAlertName(alert *librato.Alert, name string) resource.TestCheckFunc { +func testAccCheckAppOpticsAlertName(alert *appoptics.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) + if alert.Name != name { + return fmt.Errorf("Bad name: %s", alert.Name) } return nil } } -func testAccCheckAppOpticsAlertDescription(alert *librato.Alert, description string) resource.TestCheckFunc { +func testAccCheckAppOpticsAlertDescription(alert *appoptics.Alert, description string) resource.TestCheckFunc { return func(s *terraform.State) error { - if alert.Description == nil || *alert.Description != description { - return fmt.Errorf("Bad description: %s", *alert.Description) + if alert.Description != description { + return fmt.Errorf("Bad description: %s", alert.Description) } return nil } } -func testAccCheckAppOpticsAlertExists(n string, alert *librato.Alert) resource.TestCheckFunc { +func testAccCheckAppOpticsAlertExists(n string, alert *appoptics.Alert) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -238,20 +238,20 @@ func testAccCheckAppOpticsAlertExists(n string, alert *librato.Alert) resource.T return fmt.Errorf("No Alert ID is set") } - client := testAccProvider.Meta().(*librato.Client) + client := testAccProvider.Meta().(*appoptics.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)) + foundAlert, err := client.AlertsService().Retrieve(int(id)) if err != nil { return err } - if foundAlert.ID == nil || *foundAlert.ID != uint(id) { + if foundAlert.ID == 0 { return fmt.Errorf("Alert not found") } @@ -261,14 +261,14 @@ func testAccCheckAppOpticsAlertExists(n string, alert *librato.Alert) resource.T } } -func testAccCheckAppOpticsAlertConfig_minimal(name string) string { +func testAccCheckAppOpticsAlertConfigMinimal(name string) string { return fmt.Sprintf(` resource "appoptics_alert" "foobar" { name = "%s" }`, name) } -func testAccCheckAppOpticsAlertConfig_basic(name string) string { +func testAccCheckAppOpticsAlertConfigBasic(name string) string { return fmt.Sprintf(` resource "appoptics_alert" "foobar" { name = "%s" @@ -276,7 +276,7 @@ resource "appoptics_alert" "foobar" { }`, name) } -func testAccCheckAppOpticsAlertConfig_new_value(name string) string { +func testAccCheckAppOpticsAlertConfigNewValue(name string) string { return fmt.Sprintf(` resource "appoptics_alert" "foobar" { name = "%s" @@ -284,7 +284,7 @@ resource "appoptics_alert" "foobar" { }`, name) } -func testAccCheckAppOpticsAlertConfig_full(name string) string { +func testAccCheckAppOpticsAlertConfigFull(name string) string { return fmt.Sprintf(` resource "appoptics_service" "foobar" { title = "Foo Bar" @@ -304,7 +304,7 @@ resource "appoptics_alert" "foobar" { type = "above" threshold = 10 duration = 600 - metric_name = "librato.cpu.percent.idle" + metric_name = "appoptics.cpu.percent.idle" } attributes { runbook_url = "https://www.youtube.com/watch?v=oHg5SJYRHA0" @@ -314,7 +314,7 @@ resource "appoptics_alert" "foobar" { }`, name) } -func testAccCheckAppOpticsAlertConfig_full_update(name string) string { +func testAccCheckAppOpticsAlertConfigFullUpdate(name string) string { return fmt.Sprintf(` resource "appoptics_service" "foobar" { title = "Foo Bar" @@ -334,7 +334,7 @@ resource "appoptics_alert" "foobar" { type = "above" threshold = 10 duration = 60 - metric_name = "librato.cpu.percent.idle" + metric_name = "appoptics.cpu.percent.idle" } attributes { runbook_url = "https://www.youtube.com/watch?v=oHg5SJYRHA0" From 5bef42870fd73036426977286bf925ce83a33e88 Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Mon, 16 Sep 2019 09:30:59 -0400 Subject: [PATCH 06/22] Move alert test to use appoptics naming --- ...rce_librato_alert_test.go => resource_appoptics_alert_test.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename appoptics/{resource_librato_alert_test.go => resource_appoptics_alert_test.go} (100%) diff --git a/appoptics/resource_librato_alert_test.go b/appoptics/resource_appoptics_alert_test.go similarity index 100% rename from appoptics/resource_librato_alert_test.go rename to appoptics/resource_appoptics_alert_test.go From 18708ee97147d46e3b6590572e158c92602299b2 Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Mon, 16 Sep 2019 11:06:57 -0400 Subject: [PATCH 07/22] Change variable names --- appoptics/resource_appoptics_alert.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/appoptics/resource_appoptics_alert.go b/appoptics/resource_appoptics_alert.go index a826869..0098804 100644 --- a/appoptics/resource_appoptics_alert.go +++ b/appoptics/resource_appoptics_alert.go @@ -333,7 +333,7 @@ func flattenServices(d *schema.ResourceData, services []*appoptics.Service) []in } func flattenCondition(d *schema.ResourceData, conditions []*appoptics.AlertCondition) []interface{} { - retConditions := make([]interface{}, 0, len(conditions)) + out := make([]interface{}, 0, len(conditions)) for _, c := range conditions { condition := make(map[string]interface{}) condition["type"] = c.Type @@ -346,10 +346,10 @@ func flattenCondition(d *schema.ResourceData, conditions []*appoptics.AlertCondi // condition["detect_reset"] = c.DetectReset condition["duration"] = int(c.Duration) condition["summary_function"] = c.SummaryFunction - retConditions = append(retConditions, condition) + out = append(out, condition) } - return retConditions + return out } func flattenConditionTags(in []*appoptics.Tag) []interface{} { @@ -368,11 +368,11 @@ func flattenConditionTags(in []*appoptics.Tag) []interface{} { } func flattenConditionTagsValues(in []string) []interface{} { - vs := make([]interface{}, 0, len(in)) + out := make([]interface{}, 0, len(in)) for _, v := range in { - vs = append(vs, v) + out = append(out, v) } - return vs + return out } func resourceAppOpticsAlertUpdate(d *schema.ResourceData, meta interface{}) error { From 034c24b7927c47149a23b7ca35b7152a67810b30 Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Wed, 18 Sep 2019 08:42:10 -0400 Subject: [PATCH 08/22] Add condition block when creating any test alerts (it's required) --- appoptics/resource_appoptics_alert_test.go | 74 +++++++++++++--------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/appoptics/resource_appoptics_alert_test.go b/appoptics/resource_appoptics_alert_test.go index c2878c3..ac2b206 100644 --- a/appoptics/resource_appoptics_alert_test.go +++ b/appoptics/resource_appoptics_alert_test.go @@ -25,8 +25,7 @@ func TestAccAppOpticsAlertMinimal(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAppOpticsAlertExists("appoptics_alert.foobar", &alert), testAccCheckAppOpticsAlertName(&alert, name), - resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "name", name), + resource.TestCheckResourceAttr("appoptics_alert.foobar", "name", name), ), }, }, @@ -264,7 +263,12 @@ func testAccCheckAppOpticsAlertExists(n string, alert *appoptics.Alert) resource func testAccCheckAppOpticsAlertConfigMinimal(name string) string { return fmt.Sprintf(` resource "appoptics_alert" "foobar" { - name = "%s" + name = "%s" + condition { + type = "above" + threshold = 10 + metric_name = "system.cpu.utilization" + } }`, name) } @@ -272,15 +276,25 @@ func testAccCheckAppOpticsAlertConfigBasic(name string) string { return fmt.Sprintf(` resource "appoptics_alert" "foobar" { name = "%s" - description = "A Test Alert" + description = "A Test Alert" + condition { + type = "above" + threshold = 10 + metric_name = "system.cpu.utilization" + } }`, name) } func testAccCheckAppOpticsAlertConfigNewValue(name string) string { return fmt.Sprintf(` resource "appoptics_alert" "foobar" { - name = "%s" - description = "A modified Test Alert" + name = "%s" + description = "A modified Test Alert" + condition { + type = "above" + threshold = 10 + metric_name = "system.cpu.utilization" + } }`, name) } @@ -297,20 +311,19 @@ EOF } resource "appoptics_alert" "foobar" { - name = "%s" - description = "A Test Alert" - services = [ "${appoptics_service.foobar.id}" ] - condition { - type = "above" - threshold = 10 - duration = 600 - metric_name = "appoptics.cpu.percent.idle" - } - attributes { - runbook_url = "https://www.youtube.com/watch?v=oHg5SJYRHA0" - } - active = false - rearm_seconds = 300 + name = "%s" + description = "A Test Alert" + services = [ "${appoptics_service.foobar.id}" ] + condition { + type = "above" + threshold = 10 + metric_name = "system.cpu.utilization" + } + attributes { + runbook_url = "https://www.youtube.com/watch?v=oHg5SJYRHA0" + } + active = false + rearm_seconds = 300 }`, name) } @@ -330,16 +343,15 @@ resource "appoptics_alert" "foobar" { name = "%s" description = "A Test Alert" services = [ "${appoptics_service.foobar.id}" ] - condition { - type = "above" - threshold = 10 - duration = 60 - metric_name = "appoptics.cpu.percent.idle" - } - attributes { - runbook_url = "https://www.youtube.com/watch?v=oHg5SJYRHA0" - } - active = false - rearm_seconds = 1200 + condition { + type = "above" + threshold = 10 + metric_name = "system.cpu.utilization" + } + attributes { + runbook_url = "https://www.youtube.com/watch?v=oHg5SJYRHA0" + } + active = false + rearm_seconds = 1200 }`, name) } From 8b5dab3d225a2425b71e6e0d420b4cbe6ff4c93e Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Fri, 20 Sep 2019 07:55:14 -0400 Subject: [PATCH 09/22] Fix services data structure to be valid --- appoptics/resource_appoptics_alert.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/appoptics/resource_appoptics_alert.go b/appoptics/resource_appoptics_alert.go index 0098804..b0b06a8 100644 --- a/appoptics/resource_appoptics_alert.go +++ b/appoptics/resource_appoptics_alert.go @@ -181,8 +181,10 @@ func resourceAppOpticsAlertCreate(d *schema.ResourceData, meta interface{}) erro if v, ok := d.GetOk("services"); ok { vs := v.(*schema.Set) services := make([]*appoptics.Service, vs.Len()) - for i, serviceData := range vs.List() { - services[i] = serviceData.(*appoptics.Service) + for i, serviceID := range vs.List() { + service := new(appoptics.Service) + service.ID = serviceID.(int) + services[i] = service } alert.Services = services } @@ -399,8 +401,10 @@ func resourceAppOpticsAlertUpdate(d *schema.ResourceData, meta interface{}) erro if d.HasChange("services") { vs := d.Get("services").(*schema.Set) services := make([]*appoptics.Service, vs.Len()) - for i, serviceData := range vs.List() { - services[i] = serviceData.(*appoptics.Service) + for i, serviceID := range vs.List() { + service := new(appoptics.Service) + service.ID = serviceID.(int) + services[i] = service } alert.Services = services } From e943f61d594a7105e0eae0bee49e2ef096fdef46 Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Fri, 20 Sep 2019 08:01:01 -0400 Subject: [PATCH 10/22] Use proper type for returned ID --- appoptics/resource_appoptics_alert.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/appoptics/resource_appoptics_alert.go b/appoptics/resource_appoptics_alert.go index b0b06a8..1ab274e 100644 --- a/appoptics/resource_appoptics_alert.go +++ b/appoptics/resource_appoptics_alert.go @@ -403,7 +403,10 @@ func resourceAppOpticsAlertUpdate(d *schema.ResourceData, meta interface{}) erro services := make([]*appoptics.Service, vs.Len()) for i, serviceID := range vs.List() { service := new(appoptics.Service) - service.ID = serviceID.(int) + service.ID, err = strconv.Atoi(serviceID.(string)) + if err != nil { + return err + } services[i] = service } alert.Services = services From a8dd137664ef84a77e08a837e185e754f82112f6 Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Fri, 20 Sep 2019 08:02:23 -0400 Subject: [PATCH 11/22] Apply previous fix in other function --- appoptics/resource_appoptics_alert.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/appoptics/resource_appoptics_alert.go b/appoptics/resource_appoptics_alert.go index 1ab274e..036767a 100644 --- a/appoptics/resource_appoptics_alert.go +++ b/appoptics/resource_appoptics_alert.go @@ -183,7 +183,10 @@ func resourceAppOpticsAlertCreate(d *schema.ResourceData, meta interface{}) erro services := make([]*appoptics.Service, vs.Len()) for i, serviceID := range vs.List() { service := new(appoptics.Service) - service.ID = serviceID.(int) + service.ID, err = strconv.Atoi(serviceID.(string)) + if err != nil { + return err + } services[i] = service } alert.Services = services From 1b6fb2de27082db1a60d291af92127cde93dbdb6 Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Fri, 20 Sep 2019 09:19:45 -0400 Subject: [PATCH 12/22] Fix types and flesh out tests --- appoptics/resource_appoptics_alert.go | 11 ++++---- appoptics/resource_appoptics_alert_test.go | 32 ++++++++++++++++++---- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/appoptics/resource_appoptics_alert.go b/appoptics/resource_appoptics_alert.go index 036767a..b3aa3ad 100644 --- a/appoptics/resource_appoptics_alert.go +++ b/appoptics/resource_appoptics_alert.go @@ -183,6 +183,7 @@ func resourceAppOpticsAlertCreate(d *schema.ResourceData, meta interface{}) erro services := make([]*appoptics.Service, vs.Len()) for i, serviceID := range vs.List() { service := new(appoptics.Service) + var err error service.ID, err = strconv.Atoi(serviceID.(string)) if err != nil { return err @@ -237,15 +238,12 @@ func resourceAppOpticsAlertCreate(d *schema.ResourceData, meta interface{}) erro alert.Conditions = conditions } if v, ok := d.GetOk("attributes"); ok { - attributeData := v.([]interface{}) + attributeData := v.(map[string]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") - } // The only attribute here should be the runbook_url - alert.Attributes = attributeData[0].(map[string]interface{}) + alert.Attributes = attributeData } } @@ -267,7 +265,7 @@ func resourceAppOpticsAlertCreate(d *schema.ResourceData, meta interface{}) erro return nil }) if retryErr != nil { - return fmt.Errorf("Error creating AppOptics alert: %s", err) + return fmt.Errorf("Error creating AppOptics alert %s: %s", alert.Name, err) } d.SetId(strconv.FormatUint(uint64(alertResult.ID), 10)) @@ -406,6 +404,7 @@ func resourceAppOpticsAlertUpdate(d *schema.ResourceData, meta interface{}) erro services := make([]*appoptics.Service, vs.Len()) for i, serviceID := range vs.List() { service := new(appoptics.Service) + var err error service.ID, err = strconv.Atoi(serviceID.(string)) if err != nil { return err diff --git a/appoptics/resource_appoptics_alert_test.go b/appoptics/resource_appoptics_alert_test.go index ac2b206..03acd50 100644 --- a/appoptics/resource_appoptics_alert_test.go +++ b/appoptics/resource_appoptics_alert_test.go @@ -73,13 +73,35 @@ func TestAccAppOpticsAlertFull(t *testing.T) { resource.TestCheckResourceAttr( "appoptics_alert.foobar", "name", name), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.836525194.metric_name", "appoptics.cpu.percent.idle"), + "appoptics_alert.foobar", "active", "true"), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.836525194.type", "above"), + "appoptics_alert.foobar", "condition.#", "1"), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.836525194.threshold", "10"), + "appoptics_alert.foobar", "condition.3796868183.detect_reset", ""), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.836525194.duration", "600"), + "appoptics_alert.foobar", "condition.3796868183.duration", "600"), + resource.TestCheckResourceAttr( + "appoptics_alert.foobar", "condition.3796868183.metric_name", "system.cpu.utilization"), + resource.TestCheckResourceAttr( + "appoptics_alert.foobar", "condition.3796868183.summary_function", ""), + resource.TestCheckResourceAttr( + "appoptics_alert.foobar", "condition.3796868183.tag.#", "1"), + resource.TestCheckResourceAttr( + "appoptics_alert.foobar", "condition.3796868183.tag.0.grouped", "true"), + resource.TestCheckResourceAttr( + "appoptics_alert.foobar", "condition.3796868183.tag.0.name", "hostname"), + resource.TestCheckResourceAttr( + "appoptics_alert.foobar", "condition.3796868183.tag.0.values.#", "2"), + resource.TestCheckResourceAttr( + "appoptics_alert.foobar", "condition.3796868183.tag.0.values.0", "host1"), + resource.TestCheckResourceAttr( + "appoptics_alert.foobar", "condition.3796868183.tag.0.values.1", "host2"), + resource.TestCheckResourceAttr( + "appoptics_alert.foobar", "condition.3796868183.threshold", "10"), + resource.TestCheckResourceAttr( + "appoptics_alert.foobar", "condition.3796868183.type", "above"), + resource.TestCheckResourceAttr( + "appoptics_alert.foobar", "rearm_seconds", "600"), ), }, }, @@ -167,7 +189,7 @@ func TestAccAppOpticsAlertFullUpdate(t *testing.T) { resource.TestCheckResourceAttr( "appoptics_alert.foobar", "rearm_seconds", "1200"), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.2524844643.metric_name", "appoptics.cpu.percent.idle"), + "appoptics_alert.foobar", "condition.2524844643.metric_name", "system.cpu.utilization"), resource.TestCheckResourceAttr( "appoptics_alert.foobar", "condition.2524844643.type", "above"), resource.TestCheckResourceAttr( From 56500648d98096226cec66ed0f65d760096bfa28 Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Tue, 24 Sep 2019 08:26:47 -0400 Subject: [PATCH 13/22] Update tests to include tag block on alert resource creaetion --- appoptics/resource_appoptics_alert_test.go | 50 ++++++++++------------ 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/appoptics/resource_appoptics_alert_test.go b/appoptics/resource_appoptics_alert_test.go index 03acd50..07e29bd 100644 --- a/appoptics/resource_appoptics_alert_test.go +++ b/appoptics/resource_appoptics_alert_test.go @@ -73,35 +73,27 @@ func TestAccAppOpticsAlertFull(t *testing.T) { resource.TestCheckResourceAttr( "appoptics_alert.foobar", "name", name), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "active", "true"), + "appoptics_alert.foobar", "attributes.runbook_url", "https://www.youtube.com/watch?v=oHg5SJYRHA0"), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.#", "1"), + "appoptics_alert.foobar", "condition.411654007.metric_name", "system.cpu.utilization"), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.3796868183.detect_reset", ""), + "appoptics_alert.foobar", "condition.411654007.summary_function", ""), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.3796868183.duration", "600"), + "appoptics_alert.foobar", "condition.411654007.threshold", "10"), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.3796868183.metric_name", "system.cpu.utilization"), + "appoptics_alert.foobar", "condition.411654007.type", "above"), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.3796868183.summary_function", ""), + "appoptics_alert.foobar", "condition.411654007.tag.0.grouped", "true"), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.3796868183.tag.#", "1"), + "appoptics_alert.foobar", "condition.411654007.tag.0.name", "hostname"), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.3796868183.tag.0.grouped", "true"), + "appoptics_alert.foobar", "condition.411654007.tag.0.values.#", "2"), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.3796868183.tag.0.name", "hostname"), + "appoptics_alert.foobar", "condition.411654007.tag.0.values.0", "host1"), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.3796868183.tag.0.values.#", "2"), + "appoptics_alert.foobar", "condition.411654007.tag.0.values.1", "host2"), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.3796868183.tag.0.values.0", "host1"), - resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.3796868183.tag.0.values.1", "host2"), - resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.3796868183.threshold", "10"), - resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.3796868183.type", "above"), - resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "rearm_seconds", "600"), + "appoptics_alert.foobar", "rearm_seconds", "300"), ), }, }, @@ -189,13 +181,11 @@ func TestAccAppOpticsAlertFullUpdate(t *testing.T) { resource.TestCheckResourceAttr( "appoptics_alert.foobar", "rearm_seconds", "1200"), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.2524844643.metric_name", "system.cpu.utilization"), - resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.2524844643.type", "above"), + "appoptics_alert.foobar", "condition.498665064.metric_name", "system.cpu.utilization"), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.2524844643.threshold", "10"), + "appoptics_alert.foobar", "condition.498665064.type", "above"), resource.TestCheckResourceAttr( - "appoptics_alert.foobar", "condition.2524844643.duration", "60"), + "appoptics_alert.foobar", "condition.498665064.threshold", "10"), ), }, }, @@ -340,11 +330,16 @@ resource "appoptics_alert" "foobar" { type = "above" threshold = 10 metric_name = "system.cpu.utilization" + + tag { + name = "hostname" + grouped = true + values = ["host1", "host2"] + } } attributes { runbook_url = "https://www.youtube.com/watch?v=oHg5SJYRHA0" } - active = false rearm_seconds = 300 }`, name) } @@ -363,8 +358,8 @@ EOF resource "appoptics_alert" "foobar" { name = "%s" - description = "A Test Alert" - services = [ "${appoptics_service.foobar.id}" ] + description = "A Test Alert" + services = [ "${appoptics_service.foobar.id}" ] condition { type = "above" threshold = 10 @@ -373,7 +368,6 @@ resource "appoptics_alert" "foobar" { attributes { runbook_url = "https://www.youtube.com/watch?v=oHg5SJYRHA0" } - active = false rearm_seconds = 1200 }`, name) } From 1659c1e0925acddc5e7eb0d03e696ac13f2cb266 Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Thu, 19 Sep 2019 21:53:45 -0400 Subject: [PATCH 14/22] Convert service to new SDK --- appoptics/resource_librato_service.go | 62 +++++++++++----------- appoptics/resource_librato_service_test.go | 26 +++++---- 2 files changed, 43 insertions(+), 45 deletions(-) diff --git a/appoptics/resource_librato_service.go b/appoptics/resource_librato_service.go index f9755a0..b396e6b 100644 --- a/appoptics/resource_librato_service.go +++ b/appoptics/resource_librato_service.go @@ -8,7 +8,7 @@ import ( "strconv" "time" - "github.com/akahn/go-librato/librato" + "github.com/appoptics/appoptics-api-go" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" ) @@ -77,14 +77,14 @@ func normalizeJSON(jsonString interface{}) string { } func resourceAppOpticsServiceCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*librato.Client) + client := meta.(*appoptics.Client) - service := new(librato.Service) + service := new(appoptics.Service) if v, ok := d.GetOk("type"); ok { - service.Type = librato.String(v.(string)) + service.Type = v.(string) } if v, ok := d.GetOk("title"); ok { - service.Title = librato.String(v.(string)) + service.Title = v.(string) } if v, ok := d.GetOk("settings"); ok { res, expandErr := resourceAppOpticsServicesExpandSettings(normalizeJSON(v.(string))) @@ -94,16 +94,16 @@ func resourceAppOpticsServiceCreate(d *schema.ResourceData, meta interface{}) er service.Settings = res } - serviceResult, _, err := client.Services.Create(service) + serviceResult, err := client.ServicesService().Create(service) if err != nil { return fmt.Errorf("Error creating AppOptics service: %s", err) } resource.Retry(1*time.Minute, func() *resource.RetryError { - _, _, err := client.Services.Get(*serviceResult.ID) + _, err := client.ServicesService().Retrieve(serviceResult.ID) if err != nil { - if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 { + if errResp, ok := err.(*appoptics.ErrorResponse); ok && errResp.Response.StatusCode == 404 { return resource.RetryableError(err) } return resource.NonRetryableError(err) @@ -111,35 +111,35 @@ func resourceAppOpticsServiceCreate(d *schema.ResourceData, meta interface{}) er return nil }) - d.SetId(strconv.Itoa(int(*serviceResult.ID))) - return resourceAppOpticsServiceReadResult(d, serviceResult) + d.SetId(strconv.Itoa(serviceResult.ID)) + return resourceAppOpticsServiceReadResult(d, *serviceResult) } func resourceAppOpticsServiceRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*librato.Client) + client := meta.(*appoptics.Client) id, err := strconv.ParseUint(d.Id(), 10, 0) if err != nil { return err } log.Printf("[INFO] Reading AppOptics Service: %d", id) - service, _, err := client.Services.Get(uint(id)) + service, err := client.ServicesService().Retrieve(int(id)) if err != nil { - if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 { + if errResp, ok := err.(*appoptics.ErrorResponse); ok && errResp.Response.StatusCode == 404 { d.SetId("") return nil } return fmt.Errorf("Error reading AppOptics Service %s: %s", d.Id(), err) } - log.Printf("[INFO] Received AppOptics Service: %s", service) + log.Printf("[INFO] Received AppOptics Service: %s", service.Title) - return resourceAppOpticsServiceReadResult(d, service) + return resourceAppOpticsServiceReadResult(d, *service) } -func resourceAppOpticsServiceReadResult(d *schema.ResourceData, service *librato.Service) error { - d.SetId(strconv.FormatUint(uint64(*service.ID), 10)) - d.Set("type", *service.Type) - d.Set("title", *service.Title) +func resourceAppOpticsServiceReadResult(d *schema.ResourceData, service appoptics.Service) error { + d.SetId(strconv.FormatUint(uint64(service.ID), 10)) + d.Set("type", service.Type) + d.Set("title", service.Title) settings, _ := resourceAppOpticsServicesFlatten(service.Settings) d.Set("settings", settings) @@ -147,7 +147,7 @@ func resourceAppOpticsServiceReadResult(d *schema.ResourceData, service *librato } func resourceAppOpticsServiceUpdate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*librato.Client) + client := meta.(*appoptics.Client) serviceID, err := strconv.ParseUint(d.Id(), 10, 0) if err != nil { @@ -155,18 +155,18 @@ func resourceAppOpticsServiceUpdate(d *schema.ResourceData, meta interface{}) er } // Just to have whole object for comparison before/after update - fullService, _, err := client.Services.Get(uint(serviceID)) + fullService, err := client.ServicesService().Retrieve(int(serviceID)) if err != nil { return err } - service := new(librato.Service) + service := new(appoptics.Service) if d.HasChange("type") { - service.Type = librato.String(d.Get("type").(string)) + service.Type = d.Get("type").(string) fullService.Type = service.Type } if d.HasChange("title") { - service.Title = librato.String(d.Get("title").(string)) + service.Title = d.Get("title").(string) fullService.Title = service.Title } if d.HasChange("settings") { @@ -178,8 +178,8 @@ func resourceAppOpticsServiceUpdate(d *schema.ResourceData, meta interface{}) er fullService.Settings = res } - log.Printf("[INFO] Updating AppOptics Service %d: %s", serviceID, service) - _, err = client.Services.Update(uint(serviceID), service) + log.Printf("[INFO] Updating AppOptics Service %d: %s", serviceID, service.Title) + err = client.ServicesService().Update(service) if err != nil { return fmt.Errorf("Error updating AppOptics service: %s", err) } @@ -194,7 +194,7 @@ func resourceAppOpticsServiceUpdate(d *schema.ResourceData, meta interface{}) er ContinuousTargetOccurence: 5, Refresh: func() (interface{}, string, error) { log.Printf("[DEBUG] Checking if AppOptics Service %d was updated yet", serviceID) - changedService, _, getErr := client.Services.Get(uint(serviceID)) + changedService, getErr := client.ServicesService().Retrieve(int(serviceID)) if getErr != nil { return changedService, "", getErr } @@ -213,22 +213,22 @@ func resourceAppOpticsServiceUpdate(d *schema.ResourceData, meta interface{}) er } func resourceAppOpticsServiceDelete(d *schema.ResourceData, meta interface{}) error { - client := meta.(*librato.Client) + client := meta.(*appoptics.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)) + err = client.ServicesService().Delete(int(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)) + _, err := client.ServicesService().Retrieve(int(id)) if err != nil { - if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 { + if errResp, ok := err.(*appoptics.ErrorResponse); ok && errResp.Response.StatusCode == 404 { return nil } return resource.NonRetryableError(err) diff --git a/appoptics/resource_librato_service_test.go b/appoptics/resource_librato_service_test.go index 6e9c067..835cb7e 100644 --- a/appoptics/resource_librato_service_test.go +++ b/appoptics/resource_librato_service_test.go @@ -5,13 +5,13 @@ import ( "strconv" "testing" - "github.com/akahn/go-librato/librato" + "github.com/appoptics/appoptics-api-go" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" ) func TestAccAppOpticsServiceBasic(t *testing.T) { - var service librato.Service + var service appoptics.Service resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -32,7 +32,7 @@ func TestAccAppOpticsServiceBasic(t *testing.T) { } func TestAccAppOpticsService_Updated(t *testing.T) { - var service librato.Service + var service appoptics.Service resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -62,7 +62,7 @@ func TestAccAppOpticsService_Updated(t *testing.T) { } func testAccCheckAppOpticsServiceDestroy(s *terraform.State) error { - client := testAccProvider.Meta().(*librato.Client) + client := testAccProvider.Meta().(*appoptics.Client) for _, rs := range s.RootModule().Resources { if rs.Type != "appoptics_service" { @@ -74,7 +74,7 @@ func testAccCheckAppOpticsServiceDestroy(s *terraform.State) error { return fmt.Errorf("ID not a number") } - _, _, err = client.Services.Get(uint(id)) + _, err = client.ServicesService().Retrieve(int(id)) if err == nil { return fmt.Errorf("Service still exists") @@ -84,18 +84,18 @@ func testAccCheckAppOpticsServiceDestroy(s *terraform.State) error { return nil } -func testAccCheckAppOpticsServiceTitle(service *librato.Service, title string) resource.TestCheckFunc { +func testAccCheckAppOpticsServiceTitle(service *appoptics.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) + if service.Title != title { + return fmt.Errorf("Bad title: %s", service.Title) } return nil } } -func testAccCheckAppOpticsServiceExists(n string, service *librato.Service) resource.TestCheckFunc { +func testAccCheckAppOpticsServiceExists(n string, service *appoptics.Service) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -107,25 +107,23 @@ func testAccCheckAppOpticsServiceExists(n string, service *librato.Service) reso return fmt.Errorf("No Service ID is set") } - client := testAccProvider.Meta().(*librato.Client) + client := testAccProvider.Meta().(*appoptics.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)) + foundService, err := client.ServicesService().Retrieve(int(id)) if err != nil { return err } - if foundService.ID == nil || *foundService.ID != uint(id) { + if foundService.ID != int(id) { return fmt.Errorf("Service not found") } - *service = *foundService - return nil } } From 2778ac35ddcf23590b03ff917fd02eeec6e11065 Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Thu, 19 Sep 2019 21:54:21 -0400 Subject: [PATCH 15/22] Rename to new name format for service --- ...{resource_librato_service.go => resource_appoptics_service.go} | 0 ...librato_service_test.go => resource_appoptics_service_test.go} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename appoptics/{resource_librato_service.go => resource_appoptics_service.go} (100%) rename appoptics/{resource_librato_service_test.go => resource_appoptics_service_test.go} (100%) diff --git a/appoptics/resource_librato_service.go b/appoptics/resource_appoptics_service.go similarity index 100% rename from appoptics/resource_librato_service.go rename to appoptics/resource_appoptics_service.go diff --git a/appoptics/resource_librato_service_test.go b/appoptics/resource_appoptics_service_test.go similarity index 100% rename from appoptics/resource_librato_service_test.go rename to appoptics/resource_appoptics_service_test.go From 3f85ec01a070cc86740c635b90035f3cbab7482d Mon Sep 17 00:00:00 2001 From: solarchad <50369843+solarchad@users.noreply.github.com> Date: Wed, 18 Sep 2019 12:14:52 -0400 Subject: [PATCH 16/22] Fail on provider test if APPOPTICS_TOKEN is not set OR empty (#16) --- appoptics/provider_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/appoptics/provider_test.go b/appoptics/provider_test.go index 9dfc7b3..8e0121b 100644 --- a/appoptics/provider_test.go +++ b/appoptics/provider_test.go @@ -29,7 +29,8 @@ func TestProvider_impl(t *testing.T) { } func testAccPreCheck(t *testing.T) { - if v := os.Getenv("APPOPTICS_TOKEN"); v == "" { + v, ok := os.LookupEnv("APPOPTICS_TOKEN") + if !ok || v == "" { t.Fatal("APPOPTICS_TOKEN must be set for acceptance tests") } } From 0d7f3d7b57e7133d6ef3f12125e3393efe389ff6 Mon Sep 17 00:00:00 2001 From: solarchad <50369843+solarchad@users.noreply.github.com> Date: Tue, 24 Sep 2019 17:19:30 -0400 Subject: [PATCH 17/22] Upgrade appoptics api client to the latest version (#17) --- Gopkg.lock | 6 ++-- .../appoptics/appoptics-api-go/alerts.go | 34 ++++++++++++++----- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index ac8ee7a..e0693b1 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -50,12 +50,12 @@ version = "v1.0.0" [[projects]] - digest = "1:b001ffd79a6d8a07223b4769c1df55718686f35210eb3ec75b76ac1f73086770" + digest = "1:9bb1929078c6e8d1857efae76cfa04c1bf692f6747336e204d8a17617be92bee" name = "github.com/appoptics/appoptics-api-go" packages = ["."] pruneopts = "UT" - revision = "58702c0912a91c911b5997834de9742a6ed9aee1" - version = "0.3.0" + revision = "69abc66ddf3a4700e4c1400bafdab89ec947259c" + version = "0.3.2" [[projects]] digest = "1:c47f4964978e211c6e566596ec6246c329912ea92e9bb99c00798bb4564c5b09" diff --git a/vendor/github.com/appoptics/appoptics-api-go/alerts.go b/vendor/github.com/appoptics/appoptics-api-go/alerts.go index 6356e87..bcd4d01 100644 --- a/vendor/github.com/appoptics/appoptics-api-go/alerts.go +++ b/vendor/github.com/appoptics/appoptics-api-go/alerts.go @@ -4,6 +4,7 @@ import ( "fmt" ) +// Alert defines a policy for sending alarms to services when conditions are met type Alert struct { ID int `json:"id,omitempty"` Name string `json:"name,omitempty"` @@ -12,7 +13,21 @@ type Alert struct { RearmSeconds int `json:"rearm_seconds,omitempty"` Conditions []*AlertCondition `json:"conditions,omitempty"` Attributes map[string]interface{} `json:"attributes,omitempty"` - Services []*Service `json:"services,omitempty"` // correspond to IDs of Service objects + Services []*Service `json:"services,omitempty"` + CreatedAt int `json:"created_at,omitempty"` + UpdatedAt int `json:"updated_at,omitempty"` +} + +// AlertRequest is identical to Alert except for the fact that Services is a []int in AlertRequest +type AlertRequest struct { + ID int `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + Active bool `json:"active,omitempty"` + RearmSeconds int `json:"rearm_seconds,omitempty"` + Conditions []*AlertCondition `json:"conditions,omitempty"` + Attributes map[string]interface{} `json:"attributes,omitempty"` + Services []int `json:"services,omitempty"` // correspond to IDs of Service objects CreatedAt int `json:"created_at,omitempty"` UpdatedAt int `json:"updated_at,omitempty"` } @@ -24,6 +39,7 @@ type AlertCondition struct { Threshold float64 `json:"threshold,omitempty"` SummaryFunction string `json:"summary_function,omitempty"` Duration int `json:"duration,omitempty"` + DetectReset bool `json:"detect_reset,omitempty"` Tags []*Tag `json:"tags,omitempty"` } @@ -32,7 +48,7 @@ type AlertStatus struct { Status string `json:"status,omitempty"` } -type AlertsResponse struct { +type AlertsListResponse struct { Query QueryInfo `json:"query,omitempty"` Alerts []*Alert `json:"alerts,omitempty"` } @@ -42,10 +58,10 @@ type AlertsService struct { } type AlertsCommunicator interface { - List() (*AlertsResponse, error) + List() (*AlertsListResponse, error) Retrieve(int) (*Alert, error) - Create(*Alert) (*Alert, error) - Update(*Alert) error + Create(*AlertRequest) (*Alert, error) + Update(*AlertRequest) error AssociateToService(int, int) error DisassociateFromService(alertId, serviceId int) error Delete(int) error @@ -57,13 +73,13 @@ func NewAlertsService(c *Client) *AlertsService { } // List retrieves all Alerts -func (as *AlertsService) List() (*AlertsResponse, error) { +func (as *AlertsService) List() (*AlertsListResponse, error) { req, err := as.client.NewRequest("GET", "alerts", nil) if err != nil { return nil, err } - alertsResponse := &AlertsResponse{} + alertsResponse := &AlertsListResponse{} _, err = as.client.Do(req, &alertsResponse) @@ -93,7 +109,7 @@ func (as *AlertsService) Retrieve(id int) (*Alert, error) { } // Create creates the Alert -func (as *AlertsService) Create(a *Alert) (*Alert, error) { +func (as *AlertsService) Create(a *AlertRequest) (*Alert, error) { req, err := as.client.NewRequest("POST", "alerts", a) if err != nil { return nil, err @@ -110,7 +126,7 @@ func (as *AlertsService) Create(a *Alert) (*Alert, error) { } // Update updates the Alert -func (as *AlertsService) Update(a *Alert) error { +func (as *AlertsService) Update(a *AlertRequest) error { path := fmt.Sprintf("alerts/%d", a.ID) req, err := as.client.NewRequest("PUT", path, a) if err != nil { From b7559b73440d24971440f22a2ea3666fe27d65a7 Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Tue, 24 Sep 2019 18:05:20 -0400 Subject: [PATCH 18/22] Convert to AlertRequest struct --- appoptics/resource_appoptics_alert.go | 28 ++++++++------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/appoptics/resource_appoptics_alert.go b/appoptics/resource_appoptics_alert.go index b3aa3ad..e99d857 100644 --- a/appoptics/resource_appoptics_alert.go +++ b/appoptics/resource_appoptics_alert.go @@ -167,7 +167,7 @@ func tagsValuesHash(s []interface{}) int { func resourceAppOpticsAlertCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*appoptics.Client) - alert := appoptics.Alert{ + alert := appoptics.AlertRequest{ Name: d.Get("name").(string), } if v, ok := d.GetOk("description"); ok { @@ -178,17 +178,11 @@ func resourceAppOpticsAlertCreate(d *schema.ResourceData, meta interface{}) erro if v, ok := d.GetOk("rearm_seconds"); ok { alert.RearmSeconds = v.(int) } - if v, ok := d.GetOk("services"); ok { - vs := v.(*schema.Set) - services := make([]*appoptics.Service, vs.Len()) + if _, ok := d.GetOk("services"); ok { + vs := d.Get("services").(*schema.Set) + services := make([]int, vs.Len()) for i, serviceID := range vs.List() { - service := new(appoptics.Service) - var err error - service.ID, err = strconv.Atoi(serviceID.(string)) - if err != nil { - return err - } - services[i] = service + services[i] = serviceID.(int) } alert.Services = services } @@ -386,7 +380,7 @@ func resourceAppOpticsAlertUpdate(d *schema.ResourceData, meta interface{}) erro return err } - alert := new(appoptics.Alert) + alert := new(appoptics.AlertRequest) alert.ID = int(id) alert.Name = d.Get("name").(string) @@ -401,15 +395,9 @@ func resourceAppOpticsAlertUpdate(d *schema.ResourceData, meta interface{}) erro } if d.HasChange("services") { vs := d.Get("services").(*schema.Set) - services := make([]*appoptics.Service, vs.Len()) + services := make([]int, vs.Len()) for i, serviceID := range vs.List() { - service := new(appoptics.Service) - var err error - service.ID, err = strconv.Atoi(serviceID.(string)) - if err != nil { - return err - } - services[i] = service + services[i] = serviceID.(int) } alert.Services = services } From 8972e19b92c8a92d33bb189a1908013807432415 Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Tue, 24 Sep 2019 18:12:19 -0400 Subject: [PATCH 19/22] Convert service ID to an int --- appoptics/resource_appoptics_alert.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/appoptics/resource_appoptics_alert.go b/appoptics/resource_appoptics_alert.go index e99d857..1bfd290 100644 --- a/appoptics/resource_appoptics_alert.go +++ b/appoptics/resource_appoptics_alert.go @@ -182,7 +182,11 @@ func resourceAppOpticsAlertCreate(d *schema.ResourceData, meta interface{}) erro vs := d.Get("services").(*schema.Set) services := make([]int, vs.Len()) for i, serviceID := range vs.List() { - services[i] = serviceID.(int) + var err error + services[i], err = strconv.Atoi(serviceID.(string)) + if err != nil { + return fmt.Errorf("Error: %s", err) + } } alert.Services = services } @@ -397,7 +401,11 @@ func resourceAppOpticsAlertUpdate(d *schema.ResourceData, meta interface{}) erro vs := d.Get("services").(*schema.Set) services := make([]int, vs.Len()) for i, serviceID := range vs.List() { - services[i] = serviceID.(int) + var err error + services[i], err = strconv.Atoi(serviceID.(string)) + if err != nil { + return fmt.Errorf("Error: %s", err) + } } alert.Services = services } From b6176e3168bc5c6a7dc738dc2b75950abda15b59 Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Tue, 24 Sep 2019 18:29:28 -0400 Subject: [PATCH 20/22] Remove superflous test --- appoptics/resource_appoptics_service_test.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/appoptics/resource_appoptics_service_test.go b/appoptics/resource_appoptics_service_test.go index 835cb7e..cc86f4a 100644 --- a/appoptics/resource_appoptics_service_test.go +++ b/appoptics/resource_appoptics_service_test.go @@ -22,7 +22,6 @@ func TestAccAppOpticsServiceBasic(t *testing.T) { Config: testAccCheckAppOpticsServiceConfigBasic, Check: resource.ComposeTestCheckFunc( testAccCheckAppOpticsServiceExists("appoptics_service.foobar", &service), - testAccCheckAppOpticsServiceTitle(&service, "Foo Bar"), resource.TestCheckResourceAttr( "appoptics_service.foobar", "title", "Foo Bar"), ), @@ -43,7 +42,6 @@ func TestAccAppOpticsService_Updated(t *testing.T) { Config: testAccCheckAppOpticsServiceConfigBasic, Check: resource.ComposeTestCheckFunc( testAccCheckAppOpticsServiceExists("appoptics_service.foobar", &service), - testAccCheckAppOpticsServiceTitle(&service, "Foo Bar"), resource.TestCheckResourceAttr( "appoptics_service.foobar", "title", "Foo Bar"), ), @@ -52,7 +50,6 @@ func TestAccAppOpticsService_Updated(t *testing.T) { Config: testAccCheckAppOpticsServiceConfigNewValue, Check: resource.ComposeTestCheckFunc( testAccCheckAppOpticsServiceExists("appoptics_service.foobar", &service), - testAccCheckAppOpticsServiceTitle(&service, "Bar Baz"), resource.TestCheckResourceAttr( "appoptics_service.foobar", "title", "Bar Baz"), ), @@ -84,17 +81,6 @@ func testAccCheckAppOpticsServiceDestroy(s *terraform.State) error { return nil } -func testAccCheckAppOpticsServiceTitle(service *appoptics.Service, title string) resource.TestCheckFunc { - return func(s *terraform.State) error { - - if service.Title != title { - return fmt.Errorf("Bad title: %s", service.Title) - } - - return nil - } -} - func testAccCheckAppOpticsServiceExists(n string, service *appoptics.Service) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] From 49d5287d3ed10decd8323ed7f30e35eb6253a213 Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Thu, 26 Sep 2019 08:34:37 -0400 Subject: [PATCH 21/22] Fix issue where the full service was not sent when updating --- appoptics/resource_appoptics_service.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/appoptics/resource_appoptics_service.go b/appoptics/resource_appoptics_service.go index b396e6b..0ef02cc 100644 --- a/appoptics/resource_appoptics_service.go +++ b/appoptics/resource_appoptics_service.go @@ -154,20 +154,16 @@ func resourceAppOpticsServiceUpdate(d *schema.ResourceData, meta interface{}) er return err } - // Just to have whole object for comparison before/after update - fullService, err := client.ServicesService().Retrieve(int(serviceID)) + service, err := client.ServicesService().Retrieve(int(serviceID)) if err != nil { return err } - service := new(appoptics.Service) if d.HasChange("type") { service.Type = d.Get("type").(string) - fullService.Type = service.Type } if d.HasChange("title") { service.Title = d.Get("title").(string) - fullService.Title = service.Title } if d.HasChange("settings") { res, getErr := resourceAppOpticsServicesExpandSettings(normalizeJSON(d.Get("settings").(string))) @@ -175,7 +171,6 @@ func resourceAppOpticsServiceUpdate(d *schema.ResourceData, meta interface{}) er return fmt.Errorf("Error expanding AppOptics service settings: %s", getErr) } service.Settings = res - fullService.Settings = res } log.Printf("[INFO] Updating AppOptics Service %d: %s", serviceID, service.Title) @@ -198,7 +193,7 @@ func resourceAppOpticsServiceUpdate(d *schema.ResourceData, meta interface{}) er if getErr != nil { return changedService, "", getErr } - isEqual := reflect.DeepEqual(*fullService, *changedService) + isEqual := reflect.DeepEqual(*service, *changedService) log.Printf("[DEBUG] Updated AppOptics Service %d match: %t", serviceID, isEqual) return changedService, fmt.Sprintf("%t", isEqual), nil }, From e03e32fcdc47fcc52c490d9c02427dbabd8f1d63 Mon Sep 17 00:00:00 2001 From: Chad Bean Date: Thu, 26 Sep 2019 08:38:18 -0400 Subject: [PATCH 22/22] Make func name consistent --- appoptics/resource_appoptics_service_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appoptics/resource_appoptics_service_test.go b/appoptics/resource_appoptics_service_test.go index cc86f4a..d96966f 100644 --- a/appoptics/resource_appoptics_service_test.go +++ b/appoptics/resource_appoptics_service_test.go @@ -30,7 +30,7 @@ func TestAccAppOpticsServiceBasic(t *testing.T) { }) } -func TestAccAppOpticsService_Updated(t *testing.T) { +func TestAccAppOpticsServiceUpdated(t *testing.T) { var service appoptics.Service resource.Test(t, resource.TestCase{