Skip to content

Commit 9461cc1

Browse files
committed
SUMO-207606, added validations to fail on terraform plan if empty trigger conditions are provided in monitor resource
1 parent ee19934 commit 9461cc1

File tree

2 files changed

+125
-24
lines changed

2 files changed

+125
-24
lines changed

sumologic/resource_sumologic_monitors_library_monitor.go

Lines changed: 62 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,23 @@ import (
99
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
1010
)
1111

12+
var (
13+
triggerConditionsAtleatOneKey = []string{
14+
"trigger_conditions.0.logs_static_condition",
15+
"trigger_conditions.0.metrics_static_condition",
16+
"trigger_conditions.0.logs_outlier_condition",
17+
"trigger_conditions.0.metrics_outlier_condition",
18+
"trigger_conditions.0.logs_missing_data_condition",
19+
"trigger_conditions.0.metrics_missing_data_condition",
20+
"trigger_conditions.0.slo_sli_condition",
21+
"trigger_conditions.0.slo_burn_rate_condition",
22+
}
23+
criticalOrWarningAtleastOneKeys = []string{
24+
"trigger_conditions.0.logs_static_condition.0.warning",
25+
"trigger_conditions.0.logs_static_condition.0.critical",
26+
}
27+
)
28+
1229
func resourceSumologicMonitorsLibraryMonitor() *schema.Resource {
1330
return &schema.Resource{
1431
Create: resourceSumologicMonitorsLibraryMonitorCreate,
@@ -146,6 +163,7 @@ func resourceSumologicMonitorsLibraryMonitor() *schema.Resource {
146163
Elem: &schema.Resource{
147164
Schema: logsStaticTriggerConditionSchema,
148165
},
166+
AtLeastOneOf: triggerConditionsAtleatOneKey,
149167
},
150168
"metrics_static_condition": {
151169
Type: schema.TypeList,
@@ -377,7 +395,7 @@ var logsStaticTriggerConditionSchema = map[string]*schema.Schema{
377395
Type: schema.TypeString,
378396
Optional: true,
379397
},
380-
"critical": nested(true, schemaMap{
398+
"critical": nestedWithAtleastOneOfKeys(true, schemaMap{
381399
"time_range": &timeRangeSchema,
382400
"alert": nested(false, schemaMap{
383401
"threshold": &thresholdSchema,
@@ -388,8 +406,8 @@ var logsStaticTriggerConditionSchema = map[string]*schema.Schema{
388406
"threshold_type": &thresholdTypeSchema,
389407
"resolution_window": &resolutionWindowSchema,
390408
}),
391-
}),
392-
"warning": nested(true, schemaMap{
409+
}, criticalOrWarningAtleastOneKeys),
410+
"warning": nestedWithAtleastOneOfKeys(true, schemaMap{
393411
"time_range": &timeRangeSchema,
394412
"alert": nested(false, schemaMap{
395413
"threshold": &thresholdSchema,
@@ -400,11 +418,11 @@ var logsStaticTriggerConditionSchema = map[string]*schema.Schema{
400418
"threshold_type": &thresholdTypeSchema,
401419
"resolution_window": &resolutionWindowSchema,
402420
}),
403-
}),
421+
}, criticalOrWarningAtleastOneKeys),
404422
}
405423

406424
var metricsStaticTriggerConditionSchema = map[string]*schema.Schema{
407-
"critical": nested(true, schemaMap{
425+
"critical": nestedWithAtleastOneOfKeys(true, schemaMap{
408426
"time_range": &timeRangeSchema,
409427
"occurrence_type": &occurrenceTypeSchema,
410428
"alert": nested(false, schemaMap{
@@ -416,8 +434,8 @@ var metricsStaticTriggerConditionSchema = map[string]*schema.Schema{
416434
"threshold_type": &thresholdTypeSchema,
417435
"occurrence_type": &occurrenceTypeOptSchema,
418436
}),
419-
}),
420-
"warning": nested(true, schemaMap{
437+
}, criticalOrWarningAtleastOneKeys),
438+
"warning": nestedWithAtleastOneOfKeys(true, schemaMap{
421439
"time_range": &timeRangeSchema,
422440
"occurrence_type": &occurrenceTypeSchema,
423441
"alert": nested(false, schemaMap{
@@ -429,7 +447,7 @@ var metricsStaticTriggerConditionSchema = map[string]*schema.Schema{
429447
"threshold_type": &thresholdTypeSchema,
430448
"occurrence_type": &occurrenceTypeOptSchema,
431449
}),
432-
}),
450+
}, criticalOrWarningAtleastOneKeys),
433451
}
434452

435453
var logsOutlierTriggerConditionSchema = map[string]*schema.Schema{
@@ -442,16 +460,16 @@ var logsOutlierTriggerConditionSchema = map[string]*schema.Schema{
442460
Optional: true,
443461
ValidateFunc: validation.StringInSlice([]string{"Both", "Up", "Down"}, false),
444462
},
445-
"critical": nested(true, schemaMap{
463+
"critical": nestedWithAtleastOneOfKeys(true, schemaMap{
446464
"window": &windowSchema,
447465
"consecutive": &consecutiveSchema,
448466
"threshold": &thresholdSchema,
449-
}),
450-
"warning": nested(true, schemaMap{
467+
}, criticalOrWarningAtleastOneKeys),
468+
"warning": nestedWithAtleastOneOfKeys(true, schemaMap{
451469
"window": &windowSchema,
452470
"consecutive": &consecutiveSchema,
453471
"threshold": &thresholdSchema,
454-
}),
472+
}, criticalOrWarningAtleastOneKeys),
455473
}
456474

457475
var metricsOutlierTriggerConditionSchema = map[string]*schema.Schema{
@@ -460,14 +478,14 @@ var metricsOutlierTriggerConditionSchema = map[string]*schema.Schema{
460478
Optional: true,
461479
ValidateFunc: validation.StringInSlice([]string{"Both", "Up", "Down"}, false),
462480
},
463-
"critical": nested(true, schemaMap{
481+
"critical": nestedWithAtleastOneOfKeys(true, schemaMap{
464482
"baseline_window": &baselineWindowSchema,
465483
"threshold": &thresholdSchema,
466-
}),
467-
"warning": nested(true, schemaMap{
484+
}, criticalOrWarningAtleastOneKeys),
485+
"warning": nestedWithAtleastOneOfKeys(true, schemaMap{
468486
"baseline_window": &baselineWindowSchema,
469487
"threshold": &thresholdSchema,
470-
}),
488+
}, criticalOrWarningAtleastOneKeys),
471489
}
472490

473491
var logsMissingDataTriggerConditionSchema = map[string]*schema.Schema{
@@ -484,39 +502,39 @@ var metricsMissingDataTriggerConditionSchema = map[string]*schema.Schema{
484502
}
485503

486504
var sloSLITriggerConditionSchema = map[string]*schema.Schema{
487-
"critical": nested(true, schemaMap{
505+
"critical": nestedWithAtleastOneOfKeys(true, schemaMap{
488506
"sli_threshold": {
489507
Type: schema.TypeFloat,
490508
Required: true,
491509
ValidateFunc: validation.FloatBetween(0, 100),
492510
},
493-
}),
494-
"warning": nested(true, schemaMap{
511+
}, criticalOrWarningAtleastOneKeys),
512+
"warning": nestedWithAtleastOneOfKeys(true, schemaMap{
495513
"sli_threshold": {
496514
Type: schema.TypeFloat,
497515
Required: true,
498516
ValidateFunc: validation.FloatBetween(0, 100),
499517
},
500-
}),
518+
}, criticalOrWarningAtleastOneKeys),
501519
}
502520

503521
var sloBurnRateTriggerConditionSchema = map[string]*schema.Schema{
504-
"critical": nested(true, schemaMap{
522+
"critical": nestedWithAtleastOneOfKeys(true, schemaMap{
505523
"time_range": &timeRangeSchema,
506524
"burn_rate_threshold": {
507525
Type: schema.TypeFloat,
508526
Required: true,
509527
ValidateFunc: validation.FloatAtLeast(0),
510528
},
511-
}),
512-
"warning": nested(true, schemaMap{
529+
}, criticalOrWarningAtleastOneKeys),
530+
"warning": nestedWithAtleastOneOfKeys(true, schemaMap{
513531
"time_range": &timeRangeSchema,
514532
"burn_rate_threshold": {
515533
Type: schema.TypeFloat,
516534
Required: true,
517535
ValidateFunc: validation.FloatAtLeast(0),
518536
},
519-
}),
537+
}, criticalOrWarningAtleastOneKeys),
520538
}
521539

522540
var occurrenceTypeSchema = schema.Schema{
@@ -1430,6 +1448,26 @@ func nested(optional bool, sch map[string]*schema.Schema) *schema.Schema {
14301448
}
14311449
}
14321450

1451+
func nestedWithAtleastOneOfKeys(optional bool, sch map[string]*schema.Schema, atleastOneOfKeys []string) *schema.Schema {
1452+
if optional {
1453+
return &schema.Schema{
1454+
Type: schema.TypeList,
1455+
Optional: true,
1456+
MaxItems: 1,
1457+
Elem: toResource(sch),
1458+
AtLeastOneOf: atleastOneOfKeys,
1459+
}
1460+
} else {
1461+
return &schema.Schema{
1462+
Type: schema.TypeList,
1463+
Required: true,
1464+
MaxItems: 1,
1465+
Elem: toResource(sch),
1466+
AtLeastOneOf: atleastOneOfKeys,
1467+
}
1468+
}
1469+
}
1470+
14331471
func (condition *TriggerCondition) readFrom(block map[string]interface{}) {
14341472
for k, v := range block {
14351473
switch k {

sumologic/resource_sumologic_monitors_library_monitor_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,27 @@ func TestAccSumologicMonitorsLibraryMonitor_create_all_monitor_types(t *testing.
312312
}
313313
}
314314

315+
func TestAccSumologicMonitorsLibraryMonitorFail_scenarios(t *testing.T) {
316+
var monitorsLibraryMonitor MonitorsLibraryMonitor
317+
for _, monitorConfig := range allInvalidMonitors {
318+
testNameSuffix := acctest.RandString(16)
319+
320+
testName := "terraform_test_invalid_monitor_" + testNameSuffix
321+
322+
resource.Test(t, resource.TestCase{
323+
PreCheck: func() { testAccPreCheck(t) },
324+
Providers: testAccProviders,
325+
CheckDestroy: testAccCheckMonitorsLibraryMonitorDestroy(monitorsLibraryMonitor),
326+
Steps: []resource.TestStep{
327+
{
328+
Config: monitorConfig(testName),
329+
ExpectError: regexp.MustCompile("config is invalid"),
330+
},
331+
},
332+
})
333+
}
334+
}
335+
315336
func TestAccSumologicMonitorsLibraryMonitor_update(t *testing.T) {
316337
var monitorsLibraryMonitor MonitorsLibraryMonitor
317338
testNameSuffix := acctest.RandString(16)
@@ -1210,6 +1231,26 @@ var allExampleMonitors = []func(testName string) string{
12101231
exampleMetricsMissingDataMonitor,
12111232
}
12121233

1234+
func testAccSumologicMonitorsLibraryMonitorWithInvalidTriggerCondition(testName string, triggerCondition string) string {
1235+
return fmt.Sprintf(`
1236+
resource "sumologic_monitor" "test" {
1237+
name = "terraform_test_monitor_%s"
1238+
description = "terraform_test_monitor_description"
1239+
type = "MonitorsLibraryMonitor"
1240+
is_disabled = false
1241+
content_type = "Monitor"
1242+
monitor_type = "Logs"
1243+
evaluation_delay = "60m"
1244+
queries {
1245+
row_id = "A"
1246+
query = "_sourceCategory=monitor-manager error"
1247+
}
1248+
trigger_conditions {
1249+
%s
1250+
}
1251+
}`, testName, triggerCondition)
1252+
}
1253+
12131254
func exampleLogsStaticTriggerCondition(triggerType string, threshold float64, thresholdType string) TriggerCondition {
12141255
return TriggerCondition{
12151256
TimeRange: "30m",
@@ -1348,3 +1389,25 @@ func testAccCheckMonitorsLibraryMonitorFGPBackend(
13481389
return nil
13491390
}
13501391
}
1392+
1393+
var allInvalidMonitors = []func(testName string) string{
1394+
invalidExampleWithNoTriggerCondition,
1395+
invalidExampleWithEmptyLogStaticTriggerCondition,
1396+
invalidExampleWithEmptyMetricsStaticTriggerCondition,
1397+
}
1398+
1399+
func invalidExampleWithNoTriggerCondition(testName string) string {
1400+
query := "error | timeslice 1m | count as field by _timeslice"
1401+
return exampleMonitorWithTriggerCondition(testName, "Logs", query,
1402+
` `, []string{"Critical", "ResolvedCritical"})
1403+
}
1404+
func invalidExampleWithEmptyLogStaticTriggerCondition(testName string) string {
1405+
query := "error | timeslice 1m | count as field by _timeslice"
1406+
return exampleMonitorWithTriggerCondition(testName, "Logs", query,
1407+
`logs_static_condition {}`, []string{"Critical", "ResolvedCritical"})
1408+
}
1409+
func invalidExampleWithEmptyMetricsStaticTriggerCondition(testName string) string {
1410+
query := "error | timeslice 1m | count as field by _timeslice"
1411+
return exampleMonitorWithTriggerCondition(testName, "Logs", query,
1412+
`metrics_static_condition {}`, []string{"Critical", "ResolvedCritical"})
1413+
}

0 commit comments

Comments
 (0)