Skip to content

Commit 33f796c

Browse files
authored
Merge pull request #499 from SumoLogic/jinkane-multi-burn-rate
SUMO-213711 added new fields for multi window multi burn monitor
2 parents 20f9a37 + 1a9fd13 commit 33f796c

File tree

5 files changed

+314
-45
lines changed

5 files changed

+314
-45
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
## 2.21.1 (Unreleased)
22
FEATURES:
3+
* resource/sumologic_monitor: Added support for creating SLO Monitors with multiple burn rates (GH-499)
34
* Add new optional `resolution_payload` field to connection resource and `resolution_payload_override` field to notifications section of monitor resource (GH-482)
45

56
BUG FIXES:
67
* Remove thresholdType field under searchSchedule in content resource (GH-483)
78

9+
DEPRECATIONS:
10+
11+
* resource/sumologic_monitor: Deprecated `burn_rate_threshold` and `time_range` in favor of `burn_rate` inside `slo_burn_rate_condition` block (GH-499)
12+
813
## 2.21.0 (February 27, 2023)
914
FEATURES:
1015
* **New Resource:** sumologic_cse_first_seen_rule (GH-476)

sumologic/resource_sumologic_monitors_library_monitor.go

Lines changed: 99 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package sumologic
22

33
import (
4+
"fmt"
45
"log"
56
"regexp"
67
"strings"
@@ -555,23 +556,38 @@ var sloSLITriggerConditionSchema = map[string]*schema.Schema{
555556

556557
var sloBurnRateTriggerConditionSchema = map[string]*schema.Schema{
557558
"critical": nestedWithAtleastOneOfKeys(true, schemaMap{
558-
"time_range": &timeRangeSchema,
559-
"burn_rate_threshold": {
560-
Type: schema.TypeFloat,
561-
Required: true,
562-
ValidateFunc: validation.FloatAtLeast(0),
563-
},
559+
"time_range": getSloBurnRateTimeRangeSchema("critical"),
560+
"burn_rate_threshold": getSloBurnRateThresholdSchema("critical"),
561+
"burn_rate": getBurnRateSchema("critical"),
564562
}, sloBurnRateConditionCriticalOrWarningAtleastOneKeys),
565563
"warning": nestedWithAtleastOneOfKeys(true, schemaMap{
566-
"time_range": &timeRangeSchema,
567-
"burn_rate_threshold": {
568-
Type: schema.TypeFloat,
569-
Required: true,
570-
ValidateFunc: validation.FloatAtLeast(0),
571-
},
564+
"time_range": getSloBurnRateTimeRangeSchema("warning"),
565+
"burn_rate_threshold": getSloBurnRateThresholdSchema("warning"),
566+
"burn_rate": getBurnRateSchema("warning"),
572567
}, sloBurnRateConditionCriticalOrWarningAtleastOneKeys),
573568
}
574569

570+
func getBurnRateSchema(triggerType string) *schema.Schema {
571+
burnRateThresholdConflict := fmt.Sprintf("trigger_conditions.0.slo_burn_rate_condition.0.%s.0.burn_rate_threshold", triggerType)
572+
timeRangeConflict := fmt.Sprintf("trigger_conditions.0.slo_burn_rate_condition.0.%s.0.time_range", triggerType)
573+
574+
return &schema.Schema{
575+
Optional: true,
576+
Type: schema.TypeList,
577+
ConflictsWith: []string{burnRateThresholdConflict, timeRangeConflict},
578+
Elem: &schema.Resource{
579+
Schema: map[string]*schema.Schema{
580+
"burn_rate_threshold": {
581+
Type: schema.TypeFloat,
582+
Required: true,
583+
ValidateFunc: validation.FloatAtLeast(0),
584+
},
585+
"time_range": &timeRangeSchema,
586+
},
587+
},
588+
}
589+
}
590+
575591
var occurrenceTypeSchema = schema.Schema{
576592
Type: schema.TypeString,
577593
Required: true,
@@ -611,10 +627,37 @@ var consecutiveSchema = schema.Schema{
611627
var timeRangeSchema = schema.Schema{
612628
Type: schema.TypeString,
613629
Required: true,
614-
ValidateFunc: validation.StringMatch(regexp.MustCompile(`^-?(\d)+[smhd]$`), "Time range must be in the format '-?\\d+[smhd]'. Examples: -15m, 1d, etc."),
630+
ValidateFunc: timeRangeValidation,
615631
DiffSuppressFunc: SuppressEquivalentTimeDiff(false),
616632
}
617633

634+
func getSloBurnRateThresholdSchema(triggerType string) *schema.Schema {
635+
requiredWith := fmt.Sprintf("trigger_conditions.0.slo_burn_rate_condition.0.%s.0.time_range", triggerType)
636+
conflictsWith := fmt.Sprintf("trigger_conditions.0.slo_burn_rate_condition.0.%s.0.burn_rate", triggerType)
637+
return &schema.Schema{
638+
Type: schema.TypeFloat,
639+
Optional: true,
640+
ValidateFunc: validation.FloatAtLeast(0),
641+
RequiredWith: []string{requiredWith},
642+
ConflictsWith: []string{conflictsWith},
643+
}
644+
}
645+
646+
func getSloBurnRateTimeRangeSchema(triggerType string) *schema.Schema {
647+
requiredWith := fmt.Sprintf("trigger_conditions.0.slo_burn_rate_condition.0.%s.0.burn_rate_threshold", triggerType)
648+
conflictsWith := fmt.Sprintf("trigger_conditions.0.slo_burn_rate_condition.0.%s.0.burn_rate", triggerType)
649+
return &schema.Schema{
650+
Type: schema.TypeString,
651+
Optional: true,
652+
ValidateFunc: timeRangeValidation,
653+
DiffSuppressFunc: SuppressEquivalentTimeDiff(false),
654+
RequiredWith: []string{requiredWith},
655+
ConflictsWith: []string{conflictsWith},
656+
}
657+
}
658+
659+
var timeRangeValidation = validation.StringMatch(regexp.MustCompile(`^-?(\d)+[smhd]$`), "Time range must be in the format '-?\\d+[smhd]'. Examples: -15m, 1d, etc.")
660+
618661
var resolutionWindowSchema = schema.Schema{
619662
Type: schema.TypeString,
620663
Optional: true,
@@ -635,6 +678,7 @@ var thresholdTypeSchema = schema.Schema{
635678

636679
func resourceSumologicMonitorsLibraryMonitorCreate(d *schema.ResourceData, meta interface{}) error {
637680
c := meta.(*Client)
681+
638682
if d.Id() == "" {
639683
monitor := resourceToMonitorsLibraryMonitor(d)
640684
if monitor.ParentID == "" {
@@ -1351,22 +1395,21 @@ func jsonToSloBurnRateConditionBlock(conditions []TriggerCondition) map[string]i
13511395
var criticalAlrt, warningAlrt = dict{}, dict{}
13521396
block := map[string]interface{}{}
13531397

1354-
block["critical"] = toSingletonArray(criticalAlrt)
1355-
block["warning"] = toSingletonArray(warningAlrt)
1356-
13571398
var hasCritical, hasWarning = false, false
13581399
for _, condition := range conditions {
13591400
switch condition.TriggerType {
13601401
case "Critical":
13611402
hasCritical = true
1362-
criticalAlrt["time_range"] = condition.TimeRange
1363-
criticalAlrt["burn_rate_threshold"] = condition.BurnRateThreshold
1403+
criticalAlrt = getAlertBlock(condition)
13641404
case "Warning":
13651405
hasWarning = true
1366-
warningAlrt["time_range"] = condition.TimeRange
1367-
warningAlrt["burn_rate_threshold"] = condition.BurnRateThreshold
1406+
warningAlrt = getAlertBlock(condition)
13681407
}
13691408
}
1409+
1410+
block["critical"] = toSingletonArray(criticalAlrt)
1411+
block["warning"] = toSingletonArray(warningAlrt)
1412+
13701413
if !hasCritical {
13711414
delete(block, "critical")
13721415
}
@@ -1376,6 +1419,24 @@ func jsonToSloBurnRateConditionBlock(conditions []TriggerCondition) map[string]i
13761419
return block
13771420
}
13781421

1422+
func getAlertBlock(condition TriggerCondition) dict {
1423+
var alert = dict{}
1424+
burnRates := make([]interface{}, len(condition.BurnRates))
1425+
alert["time_range"] = condition.TimeRange
1426+
alert["burn_rate_threshold"] = condition.BurnRateThreshold
1427+
1428+
for i := range condition.BurnRates {
1429+
burnRateBlock := map[string]interface{}{}
1430+
burnRateBlock["burn_rate_threshold"] = condition.BurnRates[i].BurnRateThreshold
1431+
burnRateBlock["time_range"] = condition.BurnRates[i].TimeRange
1432+
burnRates[i] = burnRateBlock
1433+
}
1434+
if len(burnRates) > 0 {
1435+
alert["burn_rate"] = burnRates
1436+
}
1437+
return alert
1438+
}
1439+
13791440
func jsonToLogsMissingDataConditionBlock(conditions []TriggerCondition) map[string]interface{} {
13801441
block := map[string]interface{}{}
13811442
firstCondition := conditions[0]
@@ -1625,15 +1686,33 @@ func (base TriggerCondition) sloCloneReadingFromNestedBlocks(block map[string]in
16251686

16261687
if critical, ok := fromSingletonArray(block, "critical"); ok {
16271688
criticalCondition.readFrom(critical)
1689+
criticalCondition.computeBurnRates(critical)
16281690
conditions = append(conditions, criticalCondition)
16291691
}
16301692
if warning, ok := fromSingletonArray(block, "warning"); ok {
16311693
warningCondition.readFrom(warning)
1694+
warningCondition.computeBurnRates(warning)
16321695
conditions = append(conditions, warningCondition)
16331696
}
16341697
return conditions
16351698
}
16361699

1700+
func (condition *TriggerCondition) computeBurnRates(block map[string]interface{}) {
1701+
if burnRatesResource, ok := block["burn_rate"].([]interface{}); ok {
1702+
burnRates := make([]BurnRate, len(burnRatesResource))
1703+
for i := range burnRatesResource {
1704+
burnRateResource := burnRatesResource[i].(map[string]interface{})
1705+
burnRates[i] = BurnRate{
1706+
BurnRateThreshold: burnRateResource["burn_rate_threshold"].(float64),
1707+
TimeRange: burnRateResource["time_range"].(string),
1708+
}
1709+
}
1710+
condition.BurnRates = burnRates
1711+
} else {
1712+
condition.BurnRates = []BurnRate{}
1713+
}
1714+
}
1715+
16371716
func toSingletonArray(m map[string]interface{}) []map[string]interface{} {
16381717
return []map[string]interface{}{m}
16391718
}

0 commit comments

Comments
 (0)