Skip to content

Updated AlertPolicy resource to include sql condition types. #12971

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

Merged
merged 7 commits into from
Feb 6, 2025
144 changes: 144 additions & 0 deletions mmv1/products/monitoring/AlertPolicy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,150 @@ properties:

Users with the `monitoring.alertPolicyViewer` role are able to see the
name of the non-existent metric in the alerting policy condition.
- name: 'conditionSql'
type: NestedObject
description: |
A condition that allows alerting policies to be defined using GoogleSQL.
SQL conditions examine a sliding window of logs using GoogleSQL.
Alert policies with SQL conditions may incur additional billing.
properties:
- name: 'query'
type: String
description: |
The Log Analytics SQL query to run, as a string. The query must
conform to the required shape. Specifically, the query must not try to
filter the input by time. A filter will automatically be applied
to filter the input so that the query receives all rows received
since the last time the query was run.
required: true
- name: 'minutes'
type: NestedObject
description: |
Used to schedule the query to run every so many minutes.
properties:
- name: 'periodicity'
type: Integer
description: |
Number of minutes between runs. The interval must be greater than or
equal to 5 minutes and less than or equal to 1440 minutes.
required: true
exactly_one_of:
- 'minutes'
- 'hourly'
- 'daily'
- name: 'hourly'
type: NestedObject
description: |
Used to schedule the query to run every so many hours.
properties:
- name: 'periodicity'
type: Integer
description: |
Number of hours between runs. The interval must be greater than or
equal to 1 hour and less than or equal to 48 hours.
required: true
- name: 'minuteOffset'
type: Integer
description: |
The number of minutes after the hour (in UTC) to run the query.
Must be greater than or equal to 0 minutes and less than or equal to
59 minutes. If left unspecified, then an arbitrary offset is used.
exactly_one_of:
- 'minutes'
- 'hourly'
- 'daily'
- name: 'daily'
type: NestedObject
description: |
Used to schedule the query to run every so many days.
properties:
- name: periodicity
type: Integer
description: |
The number of days between runs. Must be greater than or equal
to 1 day and less than or equal to 30 days.
required: true
- name: 'executionTime'
type: NestedObject
description: |
The time of day (in UTC) at which the query should run. If left
unspecified, the server picks an arbitrary time of day and runs
the query at the same time each day.
properties:
- name: 'hours'
type: Integer
description: |
Hours of a day in 24 hour format. Must be greater than or equal
to 0 and typically must be less than or equal to 23. An API may
choose to allow the value "24:00:00" for scenarios like business
closing time.
- name: 'minutes'
type: Integer
description: |
Minutes of an hour. Must be greater than or equal to 0 and
less than or equal to 59.
- name: 'seconds'
type: Integer
description: |
Seconds of a minute. Must be greater than or equal to 0 and
typically must be less than or equal to 59. An API may allow the
value 60 if it allows leap-seconds.
- name: 'nanos'
type: Integer
description: |
Fractions of seconds, in nanoseconds. Must be greater than or
equal to 0 and less than or equal to 999,999,999.
exactly_one_of:
- 'minutes'
- 'hourly'
- 'daily'
- name: 'rowCountTest'
type: NestedObject
description: |
Test the row count against a threshold.
properties:
- name: 'comparison'
type: Enum
description: |
The comparison to apply between the time
series (indicated by filter and aggregation)
and the threshold (indicated by
threshold_value). The comparison is applied
on each time series, with the time series on
the left-hand side and the threshold on the
right-hand side. Only COMPARISON_LT and
COMPARISON_GT are supported currently.
enum_values:
- 'COMPARISON_GT'
- 'COMPARISON_GE'
- 'COMPARISON_LT'
- 'COMPARISON_LE'
- 'COMPARISON_EQ'
- 'COMPARISON_NE'
required: true
- name: 'threshold'
type: Integer
description: |
Test the boolean value in the indicated column.
required: true
exactly_one_of:
- 'rowCountTest'
- 'booleanTest'
- name: 'booleanTest'
type: NestedObject
description: |
The start date and time of the query. If left unspecified, then the
query will start immediately.
properties:
- name: 'column'
type: String
description: |
The name of the column containing the boolean value. If the value
in a row is NULL, that row is ignored.
required: true
exactly_one_of:
- 'rowCountTest'
- 'booleanTest'
- name: 'notificationChannels'
type: Array
# TODO chrisst - turn this into a resource ref
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func TestAccMonitoringAlertPolicy(t *testing.T) {
"log": testAccMonitoringAlertPolicy_log,
"forecast": testAccMonitoringAlertPolicy_forecast,
"promql": testAccMonitoringAlertPolicy_promql,
"sql": testAccMonitoringAlertPolicy_sql,
}

for name, tc := range testCases {
Expand Down Expand Up @@ -235,6 +236,28 @@ func testAccMonitoringAlertPolicy_promql(t *testing.T) {
})
}

func testAccMonitoringAlertPolicy_sql(t *testing.T) {

alertName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10))
conditionName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10))

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckAlertPolicyDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccMonitoringAlertPolicy_sqlCfg(alertName, conditionName),
},
{
ResourceName: "google_monitoring_alert_policy.sql",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccMonitoringAlertPolicy_basicCfg(alertName, conditionName, aligner, filter, severity string) string {
return fmt.Sprintf(`
resource "google_monitoring_alert_policy" "basic" {
Expand Down Expand Up @@ -479,3 +502,41 @@ resource "google_monitoring_alert_policy" "promql" {
}
`, alertName, conditionName)
}

func testAccMonitoringAlertPolicy_sqlCfg(alertName, conditionName string) string {
return fmt.Sprintf(`
resource "google_monitoring_alert_policy" "sql" {
display_name = "%s"
combiner = "OR"
enabled = true

conditions {
display_name = "%s"

condition_sql {
query = "SELECT severity, resource FROM project.global._Default._AllLogs WHERE severity IS NOT NULL"
duration = "60s"
Copy link
Contributor

@hao-nan-li hao-nan-li Feb 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this field is not expected here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah - duration isn't valid with SQL. I've updated the tests.

minutes {
periodicity = 600
}
row_count_test {
comparison = "COMPARISON_GT"
threshold = "0"
}
}
}

severity = "WARNING"

documentation {
content = "test content"
mime_type = "text/markdown"
subject = "test subject"
links {
display_name = "link display name"
url = "http://mydomain.com"
}
}
}
`, alertName, conditionName)
}
Loading