Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(alerts): adds support for signal_seasonality for NRQL baseline conditions #2844

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions newrelic/resource_newrelic_nrql_alert_condition.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,15 @@ func resourceNewRelicNrqlAlertCondition() *schema.Resource {
return strings.EqualFold(old, new) // Case fold this attribute when diffing
},
},
"signal_seasonality": {
Type: schema.TypeString,
Optional: true,
Description: "Seasonality under which a condition's signal(s) are evaluated. Valid values are: 'HOURLY', 'DAILY', 'WEEKLY', 'NONE', or null. To have New Relic calculate seasonality automatically, set to null (default). To turn off seasonality completely, set to 'NONE'.",
ValidateFunc: validation.StringInSlice([]string{"HOURLY", "DAILY", "WEEKLY", "NONE"}, true),
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
return strings.EqualFold(old, new) // Case fold this attribute when diffing
},
},
},
Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(30 * time.Second),
Expand Down
104 changes: 104 additions & 0 deletions newrelic/resource_newrelic_nrql_alert_condition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,39 @@ func TestAccNewRelicNrqlAlertCondition_TitleTemplate(t *testing.T) {
})
}

func TestAccNewRelicNrqlAlertCondition_SignalSeasonality(t *testing.T) {
resourceName := "newrelic_nrql_alert_condition.foo"
rName := acctest.RandString(5)
signalSeasonality := "daily"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheckEnvVars(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckNewRelicNrqlAlertConditionDestroy,
Steps: []resource.TestStep{
// Test: Create baselin condition with signal seasonality
{
Config: testAccNewRelicNrqlAlertConditionWithSignalSeasonality(
rName,
signalSeasonality,
),
Check: resource.ComposeTestCheckFunc(
testAccCheckNewRelicNrqlAlertConditionExists(resourceName),
),
},
// Test: Signal seasonality is nullable
{
Config: testAccNewRelicNrqlAlertConditionNullSignalSeasonality(
rName,
),
Check: resource.ComposeTestCheckFunc(
testAccCheckNewRelicNrqlAlertConditionExists(resourceName),
),
},
},
})
}

func testAccCheckNewRelicNrqlAlertConditionDestroy(s *terraform.State) error {
providerConfig := testAccProvider.Meta().(*ProviderConfig)
client := providerConfig.NewClient
Expand Down Expand Up @@ -1423,3 +1456,74 @@ resource "newrelic_nrql_alert_condition" "foo" {
}
`, name, predictBy)
}

func testAccNewRelicNrqlAlertConditionWithSignalSeasonality(
name string,
signalSeasonality string,
) string {
return fmt.Sprintf(`
resource "newrelic_alert_policy" "foo" {
name = "tf-test-%[1]s"
}

resource "newrelic_nrql_alert_condition" "foo" {
policy_id = newrelic_alert_policy.foo.id

name = "tf-test-%[1]s"
type = "baseline"
enabled = false
signal_seasonality = "%[2]s"
violation_time_limit_seconds = 3600
baseline_direction = "lower_only"
aggregation_delay = 120
aggregation_method = "event_flow"

nrql {
query = "SELECT uniqueCount(hostname) FROM ComputeSample"
}

critical {
operator = "above"
threshold = 1.0
threshold_duration = 120
threshold_occurrences = "ALL"
}
}

`, name, signalSeasonality)
}

func testAccNewRelicNrqlAlertConditionNullSignalSeasonality(
name string,
) string {
return fmt.Sprintf(`
resource "newrelic_alert_policy" "foo" {
name = "tf-test-%[1]s"
}

resource "newrelic_nrql_alert_condition" "foo" {
policy_id = newrelic_alert_policy.foo.id

name = "tf-test-%[1]s"
type = "baseline"
enabled = false
signal_seasonality = null
violation_time_limit_seconds = 3600
baseline_direction = "lower_only"
aggregation_delay = 120
aggregation_method = "event_flow"

nrql {
query = "SELECT uniqueCount(hostname) FROM ComputeSample"
}

critical {
operator = "above"
threshold = 1.0
threshold_duration = 120
threshold_occurrences = "ALL"
}
}

`, name)
}
18 changes: 18 additions & 0 deletions newrelic/structures_newrelic_nrql_alert_condition.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@
}
}

if conditionType == "baseline" {
if attr, ok := d.GetOk("signal_seasonality"); ok {
seasonality := alerts.NrqlSignalSeasonality(strings.ToUpper(attr.(string)))

Check failure on line 77 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / lint

undefined: alerts.NrqlSignalSeasonality

Check failure on line 77 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / lint

undefined: alerts.NrqlSignalSeasonality

Check failure on line 77 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / compile (1.22.x, ubuntu-latest)

undefined: alerts.NrqlSignalSeasonality

Check failure on line 77 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / test-unit

undefined: alerts.NrqlSignalSeasonality

Check failure on line 77 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / test-unit

undefined: alerts.NrqlSignalSeasonality

Check failure on line 77 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / compile (1.22.x, macos-latest)

undefined: alerts.NrqlSignalSeasonality
input.SignalSeasonality = &seasonality

Check failure on line 78 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / lint

input.SignalSeasonality undefined (type alerts.NrqlConditionCreateInput has no field or method SignalSeasonality)

Check failure on line 78 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / lint

input.SignalSeasonality undefined (type alerts.NrqlConditionCreateInput has no field or method SignalSeasonality)

Check failure on line 78 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / compile (1.22.x, ubuntu-latest)

input.SignalSeasonality undefined (type alerts.NrqlConditionCreateInput has no field or method SignalSeasonality)

Check failure on line 78 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / test-unit

input.SignalSeasonality undefined (type alerts.NrqlConditionCreateInput has no field or method SignalSeasonality)

Check failure on line 78 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / test-unit

input.SignalSeasonality undefined (type alerts.NrqlConditionCreateInput has no field or method SignalSeasonality)

Check failure on line 78 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / compile (1.22.x, macos-latest)

input.SignalSeasonality undefined (type alerts.NrqlConditionCreateInput has no field or method SignalSeasonality)
}
}

if runbookURL, ok := d.GetOk("runbook_url"); ok {
input.RunbookURL = runbookURL.(string)
}
Expand Down Expand Up @@ -132,6 +139,13 @@
}
}

if conditionType == "baseline" {
if attr, ok := d.GetOk("signal_seasonality"); ok {
seasonality := alerts.NrqlSignalSeasonality(strings.ToUpper(attr.(string)))

Check failure on line 144 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / lint

undefined: alerts.NrqlSignalSeasonality

Check failure on line 144 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / lint

undefined: alerts.NrqlSignalSeasonality

Check failure on line 144 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / compile (1.22.x, ubuntu-latest)

undefined: alerts.NrqlSignalSeasonality

Check failure on line 144 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / test-unit

undefined: alerts.NrqlSignalSeasonality

Check failure on line 144 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / test-unit

undefined: alerts.NrqlSignalSeasonality

Check failure on line 144 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / compile (1.22.x, macos-latest)

undefined: alerts.NrqlSignalSeasonality
input.SignalSeasonality = &seasonality

Check failure on line 145 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / lint

input.SignalSeasonality undefined (type alerts.NrqlConditionUpdateInput has no field or method SignalSeasonality)

Check failure on line 145 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / compile (1.22.x, ubuntu-latest)

input.SignalSeasonality undefined (type alerts.NrqlConditionUpdateInput has no field or method SignalSeasonality)

Check failure on line 145 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / test-unit

input.SignalSeasonality undefined (type alerts.NrqlConditionUpdateInput has no field or method SignalSeasonality)

Check failure on line 145 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / test-unit

input.SignalSeasonality undefined (type alerts.NrqlConditionUpdateInput has no field or method SignalSeasonality)

Check failure on line 145 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / compile (1.22.x, macos-latest)

input.SignalSeasonality undefined (type alerts.NrqlConditionUpdateInput has no field or method SignalSeasonality)
}
}

if runbookURL, ok := d.GetOk("runbook_url"); ok {
input.RunbookURL = runbookURL.(string)
}
Expand Down Expand Up @@ -569,6 +583,10 @@

if conditionType == "baseline" {
_ = d.Set("baseline_direction", string(*condition.BaselineDirection))

if condition.SignalSeasonality != nil {

Check failure on line 587 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / lint

condition.SignalSeasonality undefined (type *alerts.NrqlAlertCondition has no field or method SignalSeasonality)

Check failure on line 587 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / compile (1.22.x, ubuntu-latest)

condition.SignalSeasonality undefined (type *alerts.NrqlAlertCondition has no field or method SignalSeasonality)

Check failure on line 587 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / test-unit

condition.SignalSeasonality undefined (type *alerts.NrqlAlertCondition has no field or method SignalSeasonality)

Check failure on line 587 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / compile (1.22.x, macos-latest)

condition.SignalSeasonality undefined (type *alerts.NrqlAlertCondition has no field or method SignalSeasonality)
_ = d.Set("signal_seasonality", string(*condition.SignalSeasonality))

Check failure on line 588 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / lint

condition.SignalSeasonality undefined (type *alerts.NrqlAlertCondition has no field or method SignalSeasonality)) (typecheck)

Check failure on line 588 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / compile (1.22.x, ubuntu-latest)

condition.SignalSeasonality undefined (type *alerts.NrqlAlertCondition has no field or method SignalSeasonality)

Check failure on line 588 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / test-unit

condition.SignalSeasonality undefined (type *alerts.NrqlAlertCondition has no field or method SignalSeasonality)

Check failure on line 588 in newrelic/structures_newrelic_nrql_alert_condition.go

View workflow job for this annotation

GitHub Actions / compile (1.22.x, macos-latest)

condition.SignalSeasonality undefined (type *alerts.NrqlAlertCondition has no field or method SignalSeasonality)
}
}

configuredNrql := d.Get("nrql.0").(map[string]interface{})
Expand Down
22 changes: 22 additions & 0 deletions newrelic/structures_newrelic_nrql_alert_condition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ func TestExpandNrqlAlertConditionInput(t *testing.T) {

titleTemplate := "Title {{template}}"

signalSeasonality := alerts.NrqlSignalSeasonalities.Daily

cases := map[string]struct {
Data map[string]interface{}
ExpectErr bool
Expand Down Expand Up @@ -398,6 +400,25 @@ func TestExpandNrqlAlertConditionInput(t *testing.T) {
},
},
},
"signal seasonality not nil": {
Data: map[string]interface{}{
"nrql": []interface{}{nrql},
"signal_seasonality": "daily",
},
Expanded: &alerts.NrqlConditionCreateInput{
NrqlConditionCreateBase: alerts.NrqlConditionCreateBase{},
SignalSeasonality: &signalSeasonality,
},
},
"signal seasonality nil": {
Data: map[string]interface{}{
"nrql": []interface{}{nrql},
"signal_seasonality": nil,
},
Expanded: &alerts.NrqlConditionCreateInput{
NrqlConditionCreateBase: alerts.NrqlConditionCreateBase{},
},
},
}

r := resourceNewRelicNrqlAlertCondition()
Expand Down Expand Up @@ -606,6 +627,7 @@ func TestFlattenNrqlAlertCondition(t *testing.T) {
nrqlConditionBaseline.Type = alerts.NrqlConditionTypes.Baseline
nrqlConditionBaseline.BaselineDirection = &alerts.NrqlBaselineDirections.LowerOnly
nrqlConditionBaseline.EntityGUID = common.EntityGUID("NDAwMzA0fEFPTkRJVElPTnwxNDMzNjc3")
nrqlConditionBaseline.SignalSeasonality = &alerts.NrqlSignalSeasonalities.Daily

// Static
nrqlConditionStatic := nrqlCondition
Expand Down
2 changes: 2 additions & 0 deletions website/docs/r/nrql_alert_condition.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ The following arguments are supported:
- `aggregation_timer` - (Optional) How long we wait after each data point arrives to make sure we've processed the whole batch. Use `aggregation_timer` with the `event_timer` method. The timer value can range from 0 seconds to 1200 seconds (20 minutes); the default is 60 seconds. `aggregation_timer` cannot be set with `nrql.evaluation_offset`.
- `evaluation_delay` - (Optional) How long we wait until the signal starts evaluating. The maximum delay is 7200 seconds (120 minutes).
- `slide_by` - (Optional) Gathers data in overlapping time windows to smooth the chart line, making it easier to spot trends. The `slide_by` value is specified in seconds and must be smaller than and a factor of the `aggregation_window`.
- `signal_seasonality` - (Optional) Seasonality under which a condition's signal(s) are evaluated. Only available for baseline conditions. Valid values are: 'HOURLY', 'DAILY', 'WEEKLY', 'NONE', or null. To have New Relic calculate seasonality automatically, set to null. To turn off seasonality completely, set to 'NONE'.

## NRQL

Expand Down Expand Up @@ -180,6 +181,7 @@ resource "newrelic_nrql_alert_condition" "foo" {

# baseline type only
baseline_direction = "upper_only"
signal_seasonality = "none"

nrql {
query = "SELECT percentile(duration, 95) FROM Transaction WHERE appName = 'ExampleAppName'"
Expand Down
Loading