From 4ae21c10d58f8ece663f59f28aab564211c1ef7b Mon Sep 17 00:00:00 2001 From: Madhvi Date: Fri, 3 May 2024 19:25:46 +0530 Subject: [PATCH] TestLocation And EscalationChain Stage Fix --- examples/escalation_chain/resource.tf | 31 +++-- examples/website/resource.tf | 8 ++ logicmonitor/schemata/chain_schema.go | 5 +- .../schemata/website_collector_info_schema.go | 70 ++++++++++ .../schemata/website_location_schema.go | 82 +++++++++++ logicmonitor/schemata/website_schema.go | 22 +++ logicmonitor/utils/helper_functions.go | 54 ++++++-- models/escalation_chain.go | 8 +- models/website.go | 52 +++++++ models/website_location.go | 127 ++++++++++++++++++ website/docs/index.markdown | 42 +++++- website/docs/r/escalation_chain.markdown | 29 +++- website/docs/r/website.markdown | 19 +++ 13 files changed, 511 insertions(+), 38 deletions(-) create mode 100644 logicmonitor/schemata/website_collector_info_schema.go create mode 100644 logicmonitor/schemata/website_location_schema.go create mode 100644 models/website_location.go diff --git a/examples/escalation_chain/resource.tf b/examples/escalation_chain/resource.tf index ce7a0b2..b879310 100644 --- a/examples/escalation_chain/resource.tf +++ b/examples/escalation_chain/resource.tf @@ -4,19 +4,34 @@ resource "logicmonitor_escalation_chain" "my_escalation_chain"{ destinations = [ { period = [{ - week_days = 2 + week_days = [2,3] timezone = "UTC" start_minutes = 10 end_minutes = 15 + }] + stages = [ + [ + { + type = "Admin" + addr = "unicornsparkles@rainbow.io" + method = "EMAIL" + contact = "78362637" + }, + { + type = "Admin" + addr = "unicornsparkles@rainbow.io" + method = "EMAIL" + contact = "78362637" }], - stages = [{ - type = "Admin" - addr = "unicornsparkles@rainbow.io" - method = "EMAIL" - contact = "78362637" + [{ + type = "Admin" + addr = "unicornsparkles@rainbow.io" + method = "EMAIL" + contact = "78362637" }] - type = "timebased" - } + ] + type = "timebased" + } ] name = "Escalation Chain Test" description = "escalation chain test" diff --git a/examples/website/resource.tf b/examples/website/resource.tf index 2f6af34..3784652 100644 --- a/examples/website/resource.tf +++ b/examples/website/resource.tf @@ -7,6 +7,14 @@ resource "logicmonitor_website" "my_website"{ disable_alerting = true stop_monitoring = true user_permission = "string" + test_location = [ + { + all = false + collector_ids = [1, 2, 3] + collectors = null + smg_ids = [85, 90] + } + ] group_id = 8 individual_sm_alert_enable = false steps = [ diff --git a/logicmonitor/schemata/chain_schema.go b/logicmonitor/schemata/chain_schema.go index dfaf1d3..1383014 100644 --- a/logicmonitor/schemata/chain_schema.go +++ b/logicmonitor/schemata/chain_schema.go @@ -19,8 +19,9 @@ func ChainSchema() map[string]*schema.Schema { "stages": { Type: schema.TypeList, //GoType: [][]*Recipient - Elem: &schema.Resource{ - Schema: RecipientSchema(), + Elem: &schema.Schema{ + Type: schema.TypeList, + Elem: &schema.Resource{Schema: RecipientSchema()}, }, ConfigMode: schema.SchemaConfigModeAttr, Required: true, diff --git a/logicmonitor/schemata/website_collector_info_schema.go b/logicmonitor/schemata/website_collector_info_schema.go new file mode 100644 index 0000000..ca6b0d6 --- /dev/null +++ b/logicmonitor/schemata/website_collector_info_schema.go @@ -0,0 +1,70 @@ +package schemata + +import ( + "terraform-provider-logicmonitor/models" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func WebsiteCollectorInfoSchema() map[string]*schema.Schema { + return map[string]*schema.Schema{ + "collector_group_id": { + Type: schema.TypeInt, + Computed: true, + }, + + "collector_group_name": { + Type: schema.TypeString, + Computed: true, + }, + + "description": { + Type: schema.TypeString, + Computed: true, + }, + + "hostname": { + Type: schema.TypeString, + Computed: true, + }, + + "id": { + Type: schema.TypeInt, + Computed: true, + }, + + "status": { + Type: schema.TypeString, + Computed: true, + }, + + } +} + +func SetWebsiteCollectorInfoSubResourceData(m []*models.WebsiteCollectorInfo) (d []*map[string]interface{}) { + for _, websiteCollectorInfo := range m { + if websiteCollectorInfo != nil { + properties := make(map[string]interface{}) + properties["collector_group_id"] = websiteCollectorInfo.CollectorGroupID + properties["collector_group_name"] = websiteCollectorInfo.CollectorGroupName + properties["description"] = websiteCollectorInfo.Description + properties["hostname"] = websiteCollectorInfo.Hostname + properties["id"] = websiteCollectorInfo.ID + properties["status"] = websiteCollectorInfo.Status + d = append(d, &properties) + } + } + return +} + +func WebsiteCollectorInfoModel(d map[string]interface{}) *models.WebsiteCollectorInfo { + // assume that the incoming map only contains the relevant resource data + + return &models.WebsiteCollectorInfo { + } +} + +func GetWebsiteCollectorInfoPropertyFields() (t []string) { + return []string{ + "id", + } +} \ No newline at end of file diff --git a/logicmonitor/schemata/website_location_schema.go b/logicmonitor/schemata/website_location_schema.go new file mode 100644 index 0000000..3c40be9 --- /dev/null +++ b/logicmonitor/schemata/website_location_schema.go @@ -0,0 +1,82 @@ +package schemata + +import ( + "terraform-provider-logicmonitor/logicmonitor/utils" + "terraform-provider-logicmonitor/models" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func WebsiteLocationSchema() map[string]*schema.Schema { + return map[string]*schema.Schema{ + "all": { + Type: schema.TypeBool, + Optional: true, + }, + + "collector_ids": { + Type: schema.TypeList, //GoType: []int32 + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + ConfigMode: schema.SchemaConfigModeAttr, + Optional: true, + }, + + "collectors": { + Type: schema.TypeList, //GoType: []*WebsiteCollectorInfo + Elem: &schema.Resource{ + Schema: WebsiteCollectorInfoSchema(), + }, + ConfigMode: schema.SchemaConfigModeAttr, + Optional: true, + }, + + "smg_ids": { + Type: schema.TypeList, //GoType: []int32 + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + ConfigMode: schema.SchemaConfigModeAttr, + Optional: true, + }, + + } +} + +func SetWebsiteLocationSubResourceData(m []*models.WebsiteLocation) (d []*map[string]interface{}) { + for _, websiteLocation := range m { + if websiteLocation != nil { + properties := make(map[string]interface{}) + properties["all"] = websiteLocation.All + properties["collector_ids"] = websiteLocation.CollectorIds + properties["collectors"] = SetWebsiteCollectorInfoSubResourceData(websiteLocation.Collectors) + properties["smg_ids"] = websiteLocation.SmgIds + d = append(d, &properties) + } + } + return +} + +func WebsiteLocationModel(d map[string]interface{}) *models.WebsiteLocation { + // assume that the incoming map only contains the relevant resource data + all := d["all"].(bool) + collectorIds := utils.ConvertSetToInt32Slice(d["collectorIds"].([]interface{})) + collectors := d["collectors"].([]*models.WebsiteCollectorInfo) + smgIds := utils.ConvertSetToInt32Slice(d["smgIds"].([]interface{})) + + return &models.WebsiteLocation { + All: all, + CollectorIds: collectorIds, + Collectors: collectors, + SmgIds: smgIds, + } +} + +func GetWebsiteLocationPropertyFields() (t []string) { + return []string{ + "all", + "collector_ids", + "collectors", + "smg_ids", + } +} \ No newline at end of file diff --git a/logicmonitor/schemata/website_schema.go b/logicmonitor/schemata/website_schema.go index 81c3f21..27f8601 100644 --- a/logicmonitor/schemata/website_schema.go +++ b/logicmonitor/schemata/website_schema.go @@ -111,6 +111,15 @@ func WebsiteSchema() map[string]*schema.Schema { Optional: true, }, + "test_location": { + Type: schema.TypeList, //GoType: WebsiteLocation + Elem: &schema.Resource{ + Schema: WebsiteLocationSchema(), + }, + ConfigMode: schema.SchemaConfigModeAttr, + Optional: true, + }, + "transition": { Type: schema.TypeInt, Optional: true, @@ -247,6 +256,14 @@ func DataSourceWebsiteSchema() map[string]*schema.Schema { Optional: true, }, + "test_location": { + Type: schema.TypeList, //GoType: WebsiteLocation + Elem: &schema.Resource{ + Schema: WebsiteLocationSchema(), + }, + Optional: true, + }, + "transition": { Type: schema.TypeInt, Optional: true, @@ -299,6 +316,7 @@ func SetWebsiteResourceData(d *schema.ResourceData, m *models.Website) { d.Set("stop_monitoring", m.StopMonitoring) d.Set("stop_monitoring_by_folder", m.StopMonitoringByFolder) d.Set("template", m.Template) + d.Set("test_location", SetWebsiteLocationSubResourceData([]*models.WebsiteLocation{m.TestLocation})) d.Set("transition", m.Transition) d.Set("type", m.Type) d.Set("use_default_alert_setting", m.UseDefaultAlertSetting) @@ -329,6 +347,7 @@ func SetWebsiteSubResourceData(m []*models.Website) (d []*map[string]interface{} properties["stop_monitoring"] = website.StopMonitoring properties["stop_monitoring_by_folder"] = website.StopMonitoringByFolder properties["template"] = website.Template + properties["test_location"] = SetWebsiteLocationSubResourceData([]*models.WebsiteLocation{website.TestLocation}) properties["transition"] = website.Transition properties["type"] = website.Type properties["use_default_alert_setting"] = website.UseDefaultAlertSetting @@ -357,6 +376,7 @@ func WebsiteModel(d *schema.ResourceData) *models.Website { steps := utils.GetPropFromSteps(d, "steps") stopMonitoring := d.Get("stop_monitoring").(bool) template := d.Get("template") + testLocation := utils.GetPropFromLocationMap(d, "test_location") transition := int32(d.Get("transition").(int)) typeVar := d.Get("type").(string) useDefaultAlertSetting := d.Get("use_default_alert_setting").(bool) @@ -380,6 +400,7 @@ func WebsiteModel(d *schema.ResourceData) *models.Website { Steps: steps, StopMonitoring: stopMonitoring, Template: template, + TestLocation: testLocation, Transition: transition, Type: &typeVar, UseDefaultAlertSetting: useDefaultAlertSetting, @@ -405,6 +426,7 @@ func GetWebsitePropertyFields() (t []string) { "steps", "stop_monitoring", "template", + "test_location", "transition", "type", "use_default_alert_setting", diff --git a/logicmonitor/utils/helper_functions.go b/logicmonitor/utils/helper_functions.go index 30995be..1abd2bd 100644 --- a/logicmonitor/utils/helper_functions.go +++ b/logicmonitor/utils/helper_functions.go @@ -285,21 +285,31 @@ func getPropFromDesInterface(r interface{}) (t []*models.Chain) { return } func GetRecipient(d []interface{}) (t [][]*models.Recipient) { - for _, i := range d { - if m, ok := i.(map[string]interface{}); ok { - var addr = m["addr"].(string) - var contact = m["contact"].(string) - var method = m["method"].(string) - var Type = m["type"].(string) - + for _, stageData := range d { + stage, ok := stageData.([]interface{}) + if !ok { + continue + } + var stageRecipients []*models.Recipient + for _, recipientData := range stage { + recipient, ok := recipientData.(map[string]interface{}) + if !ok { + continue + } + var addr = recipient["addr"].(string) + var contact = recipient["contact"].(string) + var method = recipient["method"].(string) + var Type = recipient["type"].(string) + model := &models.Recipient{ - Addr: addr, + Addr: addr, Contact: contact, - Method: &method, - Type: &Type, + Method: &method, + Type: &Type, } - t = append(t, []*models.Recipient{model}) + stageRecipients = append(stageRecipients, model) } + t = append(t, stageRecipients) } return } @@ -474,4 +484,26 @@ func getPropFromDPInterface(r interface{}) (t []*models.DataPoint ) { } } return +} +func GetPropFromLocationMap(d *schema.ResourceData, key string) (t *models.WebsiteLocation) { + if r, ok := d.GetOk(key); ok { + return getPropFromLocInterface(r) + } + return +} +func getPropFromLocInterface(r interface{}) (t *models.WebsiteLocation) { + for _, i := range r.([]interface{}) { + if m, ok := i.(map[string]interface{}); ok { + var smgIds = ConvertSetToInt32Slice(m["smg_ids"]) + var collectorIds = ConvertSetToInt32Slice(m["collector_ids"]) + var all = m["all"].(bool) + model := &models.WebsiteLocation{ + CollectorIds: collectorIds, + SmgIds: smgIds, + All: all, + } + t = model + } + } + return } \ No newline at end of file diff --git a/models/escalation_chain.go b/models/escalation_chain.go index 20df0a0..3433a7f 100644 --- a/models/escalation_chain.go +++ b/models/escalation_chain.go @@ -32,7 +32,7 @@ type EscalationChain struct { // Required: true Destinations []*Chain `json:"destinations"` - // enable throttling + // if throttle needs to be enabled then true if not then false. // Example: true EnableThrottling bool `json:"enableThrottling,omitempty"` @@ -44,16 +44,16 @@ type EscalationChain struct { // Read Only: true InAlerting *bool `json:"inAlerting,omitempty"` - // name + // the chain name // Example: NOC Team // Required: true Name *string `json:"name"` - // throttling alerts + // max number of alert can send during a throttle period // Example: 40 ThrottlingAlerts int32 `json:"throttlingAlerts,omitempty"` - // throttling period + // the throttle period // Example: 30 ThrottlingPeriod int32 `json:"throttlingPeriod,omitempty"` } diff --git a/models/website.go b/models/website.go index c455a11..4236655 100644 --- a/models/website.go +++ b/models/website.go @@ -107,6 +107,15 @@ type Website struct { // The website template Template interface{} `json:"template,omitempty"` + // The locations from which the website is monitored. If the website is internal, this field should include Collectors. If Non-Internal, possible test locations are: + // 1 : US - LA + // 2 : US - DC + // 3 : US - SF + // 4 : Europe - Dublin + // 5 : Asia - Singapore + // 6 : Australia - Sydney + TestLocation *WebsiteLocation `json:"testLocation,omitempty"` + // 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 30 | 60 // The number of checks that must fail before an alert is triggered // Example: 1 @@ -143,6 +152,10 @@ func (m *Website) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateTestLocation(formats); err != nil { + res = append(res, err) + } + if err := m.validateType(formats); err != nil { res = append(res, err) } @@ -188,6 +201,25 @@ func (m *Website) validateSteps(formats strfmt.Registry) error { return nil } +func (m *Website) validateTestLocation(formats strfmt.Registry) error { + if swag.IsZero(m.TestLocation) { // not required + return nil + } + + if m.TestLocation != nil { + if err := m.TestLocation.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("testLocation") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("testLocation") + } + return err + } + } + + return nil +} + func (m *Website) validateType(formats strfmt.Registry) error { if err := validate.Required("type", "body", m.Type); err != nil { @@ -221,6 +253,10 @@ func (m *Website) ContextValidate(ctx context.Context, formats strfmt.Registry) res = append(res, err) } + if err := m.contextValidateTestLocation(ctx, formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { return errors.CompositeValidationError(res...) } @@ -283,6 +319,22 @@ func (m *Website) contextValidateStopMonitoringByFolder(ctx context.Context, for return nil } +func (m *Website) contextValidateTestLocation(ctx context.Context, formats strfmt.Registry) error { + + if m.TestLocation != nil { + if err := m.TestLocation.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("testLocation") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("testLocation") + } + return err + } + } + + return nil +} + // MarshalBinary interface implementation func (m *Website) MarshalBinary() ([]byte, error) { if m == nil { diff --git a/models/website_location.go b/models/website_location.go new file mode 100644 index 0000000..0b34310 --- /dev/null +++ b/models/website_location.go @@ -0,0 +1,127 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// WebsiteLocation website location +// +// swagger:model WebsiteLocation +type WebsiteLocation struct { + + // all + // Example: true + All bool `json:"all,omitempty"` + + // collector ids + CollectorIds []int32 `json:"collectorIds"` + + // collectors + Collectors []*WebsiteCollectorInfo `json:"collectors"` + + // smg ids + // Example: [1, 2, 4, 3, 5, 6] + SmgIds []int32 `json:"smgIds"` +} + +// Validate validates this website location +func (m *WebsiteLocation) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateCollectors(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *WebsiteLocation) validateCollectors(formats strfmt.Registry) error { + if swag.IsZero(m.Collectors) { // not required + return nil + } + + for i := 0; i < len(m.Collectors); i++ { + if swag.IsZero(m.Collectors[i]) { // not required + continue + } + + if m.Collectors[i] != nil { + if err := m.Collectors[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("collectors" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("collectors" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +// ContextValidate validate this website location based on the context it is used +func (m *WebsiteLocation) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateCollectors(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *WebsiteLocation) contextValidateCollectors(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Collectors); i++ { + + if m.Collectors[i] != nil { + if err := m.Collectors[i].ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("collectors" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("collectors" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *WebsiteLocation) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *WebsiteLocation) UnmarshalBinary(b []byte) error { + var res WebsiteLocation + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/website/docs/index.markdown b/website/docs/index.markdown index 447785e..509a16b 100644 --- a/website/docs/index.markdown +++ b/website/docs/index.markdown @@ -189,16 +189,38 @@ resource "logicmonitor_escalation_chain" "my_escalation_chain" { start_minutes = 10 end_minutes = 15 }], - stages = [{ - type = "Admin" - addr = "unicornsparkles@rainbow.io" - method = "EMAIL" - contact = "78362637" - }] + stages = [ + [{ + type = "Admin" + addr = "unicornsparkles@rainbow.io" + method = "EMAIL" + contact = "78362637" + }, + { + type = "Admin" + addr = "unicornsparkles@rainbow.io" + method = "EMAIL" + contact = "78362637" + }], + [{ + type = "Admin" + addr = "unicornsparkles@rainbow.io" + method = "EMAIL" + contact = "78362637" + }] + ] type = "timebased" } ] description = "LM Escalation Chain testing" + cc_destinations = [ + { + method = "EMAIL" + contact = "string" + type = "Admin" + addr = "unicornsparkles@rainbow.io" + } + ] throttling_alerts = 40 enable_throttling = true throttling_period = 30 @@ -218,6 +240,14 @@ resource "logicmonitor_website" "my_website" { disable_alerting = true stop_monitoring = true user_permission = "string" + test_location = [ + { + all = false + collector_ids = [1, 2, 3] + collectors = null + smg_ids = [85, 90] + } + ] group_id = 8 individual_sm_alert_enable = false steps = [ diff --git a/website/docs/r/escalation_chain.markdown b/website/docs/r/escalation_chain.markdown index 6543674..74a87b1 100644 --- a/website/docs/r/escalation_chain.markdown +++ b/website/docs/r/escalation_chain.markdown @@ -22,15 +22,30 @@ resource "logicmonitor_escalation_chain" "my_escalation_chain" { timezone = "UTC" start_minutes = 10 end_minutes = 15 + }] + stages = [ + [ + { + type = "Admin" + addr = "unicornsparkles@rainbow.io" + method = "EMAIL" + contact = "78362637" + }, + { + type = "Admin" + addr = "unicornsparkles@rainbow.io" + method = "EMAIL" + contact = "78362637" }], - stages = [{ - type = "Admin" - addr = "unicornsparkles@rainbow.io" - method = "EMAIL" - contact = "78362637" + [{ + type = "Admin" + addr = "unicornsparkles@rainbow.io" + method = "EMAIL" + contact = "78362637" }] - type = "timebased" - } + ] + type = "timebased" + } ] cc_destinations = [ { diff --git a/website/docs/r/website.markdown b/website/docs/r/website.markdown index 83b5633..174b28a 100644 --- a/website/docs/r/website.markdown +++ b/website/docs/r/website.markdown @@ -64,6 +64,14 @@ resource "logicmonitor_website" "my_website" { ] stop_monitoring = template = + test_location = [ + { + all = false + collector_ids = [1, 2, 3] + collectors = null + smg_ids = [85, 90] + } + ] transition = 1 type = "webcheck" use_default_alert_setting = true @@ -137,6 +145,17 @@ The polling interval for the website, in units of minutes. This value indicates false: monitoring is enabled for the website If stopMonitoring=true, then alerting will also by default be disabled for the website * `template` - The website template +* `test_location` - The locations from which the website is monitored. If the website is internal, this field should include Collectors. If Non-Internal, possible test locations are: +1 : US - LA +2 : US - DC +3 : US - SF +4 : Europe - Dublin +5 : Asia - Singapore +6 : Australia - Sydney + + `all` - (true | false) Indicates that the service will be monitored from all checkpoint locations + + `collectorIds` - indicates that the service will be monitored from checkpoint locations 1, 2 and 3 + + `collectors` - Need to pass 'null' value + + `smgIds` - indicates that the service will be monitored by Collectors 85 and 90 * `transition` - 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 30 | 60 The number of checks that must fail before an alert is triggered * `use_default_alert_setting` - true: The alert settings configured in the website Default Settings will be used