Skip to content

Commit

Permalink
Add support for log alert (#5565) (#3968)
Browse files Browse the repository at this point in the history
Signed-off-by: Modular Magician <magic-modules@google.com>
  • Loading branch information
modular-magician authored Jan 7, 2022
1 parent a52ca41 commit a019db8
Show file tree
Hide file tree
Showing 5 changed files with 366 additions and 22 deletions.
3 changes: 3 additions & 0 deletions .changelog/5565.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
monitoring: added `conditionMatchedLog` and `alertStrategy` fields to `google_monitoring_alert_policy` resource
```
239 changes: 239 additions & 0 deletions google-beta/resource_monitoring_alert_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,34 @@ condition to be triggered.`,
},
},
},
"condition_matched_log": {
Type: schema.TypeList,
Optional: true,
Description: `A condition that checks for log messages matching given constraints.
If set, no other conditions can be present.`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"filter": {
Type: schema.TypeString,
Required: true,
Description: `A logs-based filter.`,
},
"label_extractors": {
Type: schema.TypeMap,
Optional: true,
Description: `A map from a label key to an extractor expression, which is used to
extract the value for this label key. Each entry in this map is
a specification for how data should be extracted from log entries that
match filter. Each combination of extracted values is treated as
a separate rule for the purposes of triggering notifications.
Label keys and corresponding values can be used in notifications
generated by this condition.`,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
},
},
"condition_monitoring_query_language": {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -679,6 +707,37 @@ dashboards, notifications, and incidents. To avoid confusion, don't use
the same display name for multiple policies in the same project. The
name is limited to 512 Unicode characters.`,
},
"alert_strategy": {
Type: schema.TypeList,
Optional: true,
Description: `Control over how this alert policy's notification channels are notified.`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"auto_close": {
Type: schema.TypeString,
Optional: true,
Description: `If an alert policy that was active has no data for this long, any open incidents will close.`,
},
"notification_rate_limit": {
Type: schema.TypeList,
Optional: true,
Description: `Required for alert policies with a LogMatch condition.
This limit is not implemented for alert policies that are not log-based.`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"period": {
Type: schema.TypeString,
Optional: true,
Description: `Not more than one notification per period.`,
},
},
},
},
},
},
},
"documentation": {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -816,6 +875,12 @@ func resourceMonitoringAlertPolicyCreate(d *schema.ResourceData, meta interface{
} else if v, ok := d.GetOkExists("notification_channels"); !isEmptyValue(reflect.ValueOf(notificationChannelsProp)) && (ok || !reflect.DeepEqual(v, notificationChannelsProp)) {
obj["notificationChannels"] = notificationChannelsProp
}
alertStrategyProp, err := expandMonitoringAlertPolicyAlertStrategy(d.Get("alert_strategy"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("alert_strategy"); !isEmptyValue(reflect.ValueOf(alertStrategyProp)) && (ok || !reflect.DeepEqual(v, alertStrategyProp)) {
obj["alertStrategy"] = alertStrategyProp
}
userLabelsProp, err := expandMonitoringAlertPolicyUserLabels(d.Get("user_labels"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -948,6 +1013,9 @@ func resourceMonitoringAlertPolicyRead(d *schema.ResourceData, meta interface{})
if err := d.Set("notification_channels", flattenMonitoringAlertPolicyNotificationChannels(res["notificationChannels"], d, config)); err != nil {
return fmt.Errorf("Error reading AlertPolicy: %s", err)
}
if err := d.Set("alert_strategy", flattenMonitoringAlertPolicyAlertStrategy(res["alertStrategy"], d, config)); err != nil {
return fmt.Errorf("Error reading AlertPolicy: %s", err)
}
if err := d.Set("user_labels", flattenMonitoringAlertPolicyUserLabels(res["userLabels"], d, config)); err != nil {
return fmt.Errorf("Error reading AlertPolicy: %s", err)
}
Expand Down Expand Up @@ -1004,6 +1072,12 @@ func resourceMonitoringAlertPolicyUpdate(d *schema.ResourceData, meta interface{
} else if v, ok := d.GetOkExists("notification_channels"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, notificationChannelsProp)) {
obj["notificationChannels"] = notificationChannelsProp
}
alertStrategyProp, err := expandMonitoringAlertPolicyAlertStrategy(d.Get("alert_strategy"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("alert_strategy"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, alertStrategyProp)) {
obj["alertStrategy"] = alertStrategyProp
}
userLabelsProp, err := expandMonitoringAlertPolicyUserLabels(d.Get("user_labels"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -1052,6 +1126,10 @@ func resourceMonitoringAlertPolicyUpdate(d *schema.ResourceData, meta interface{
updateMask = append(updateMask, "notificationChannels")
}

if d.HasChange("alert_strategy") {
updateMask = append(updateMask, "alertStrategy")
}

if d.HasChange("user_labels") {
updateMask = append(updateMask, "userLabels")
}
Expand Down Expand Up @@ -1195,6 +1273,7 @@ func flattenMonitoringAlertPolicyConditions(v interface{}, d *schema.ResourceDat
"condition_monitoring_query_language": flattenMonitoringAlertPolicyConditionsConditionMonitoringQueryLanguage(original["conditionMonitoringQueryLanguage"], d, config),
"condition_threshold": flattenMonitoringAlertPolicyConditionsConditionThreshold(original["conditionThreshold"], d, config),
"display_name": flattenMonitoringAlertPolicyConditionsDisplayName(original["displayName"], d, config),
"condition_matched_log": flattenMonitoringAlertPolicyConditionsConditionMatchedLog(original["conditionMatchedLog"], d, config),
})
}
return transformed
Expand Down Expand Up @@ -1525,10 +1604,69 @@ func flattenMonitoringAlertPolicyConditionsDisplayName(v interface{}, d *schema.
return v
}

func flattenMonitoringAlertPolicyConditionsConditionMatchedLog(v interface{}, d *schema.ResourceData, config *Config) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
if len(original) == 0 {
return nil
}
transformed := make(map[string]interface{})
transformed["filter"] =
flattenMonitoringAlertPolicyConditionsConditionMatchedLogFilter(original["filter"], d, config)
transformed["label_extractors"] =
flattenMonitoringAlertPolicyConditionsConditionMatchedLogLabelExtractors(original["labelExtractors"], d, config)
return []interface{}{transformed}
}
func flattenMonitoringAlertPolicyConditionsConditionMatchedLogFilter(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return v
}

func flattenMonitoringAlertPolicyConditionsConditionMatchedLogLabelExtractors(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return v
}

func flattenMonitoringAlertPolicyNotificationChannels(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return v
}

func flattenMonitoringAlertPolicyAlertStrategy(v interface{}, d *schema.ResourceData, config *Config) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
if len(original) == 0 {
return nil
}
transformed := make(map[string]interface{})
transformed["notification_rate_limit"] =
flattenMonitoringAlertPolicyAlertStrategyNotificationRateLimit(original["notificationRateLimit"], d, config)
transformed["auto_close"] =
flattenMonitoringAlertPolicyAlertStrategyAutoClose(original["autoClose"], d, config)
return []interface{}{transformed}
}
func flattenMonitoringAlertPolicyAlertStrategyNotificationRateLimit(v interface{}, d *schema.ResourceData, config *Config) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
if len(original) == 0 {
return nil
}
transformed := make(map[string]interface{})
transformed["period"] =
flattenMonitoringAlertPolicyAlertStrategyNotificationRateLimitPeriod(original["period"], d, config)
return []interface{}{transformed}
}
func flattenMonitoringAlertPolicyAlertStrategyNotificationRateLimitPeriod(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return v
}

func flattenMonitoringAlertPolicyAlertStrategyAutoClose(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return v
}

func flattenMonitoringAlertPolicyUserLabels(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return v
}
Expand Down Expand Up @@ -1613,6 +1751,13 @@ func expandMonitoringAlertPolicyConditions(v interface{}, d TerraformResourceDat
transformed["displayName"] = transformedDisplayName
}

transformedConditionMatchedLog, err := expandMonitoringAlertPolicyConditionsConditionMatchedLog(original["condition_matched_log"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedConditionMatchedLog); val.IsValid() && !isEmptyValue(val) {
transformed["conditionMatchedLog"] = transformedConditionMatchedLog
}

req = append(req, transformed)
}
return req, nil
Expand Down Expand Up @@ -2082,10 +2227,104 @@ func expandMonitoringAlertPolicyConditionsDisplayName(v interface{}, d Terraform
return v, nil
}

func expandMonitoringAlertPolicyConditionsConditionMatchedLog(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
return nil, nil
}
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedFilter, err := expandMonitoringAlertPolicyConditionsConditionMatchedLogFilter(original["filter"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedFilter); val.IsValid() && !isEmptyValue(val) {
transformed["filter"] = transformedFilter
}

transformedLabelExtractors, err := expandMonitoringAlertPolicyConditionsConditionMatchedLogLabelExtractors(original["label_extractors"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedLabelExtractors); val.IsValid() && !isEmptyValue(val) {
transformed["labelExtractors"] = transformedLabelExtractors
}

return transformed, nil
}

func expandMonitoringAlertPolicyConditionsConditionMatchedLogFilter(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandMonitoringAlertPolicyConditionsConditionMatchedLogLabelExtractors(v interface{}, d TerraformResourceData, config *Config) (map[string]string, error) {
if v == nil {
return map[string]string{}, nil
}
m := make(map[string]string)
for k, val := range v.(map[string]interface{}) {
m[k] = val.(string)
}
return m, nil
}

func expandMonitoringAlertPolicyNotificationChannels(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandMonitoringAlertPolicyAlertStrategy(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
return nil, nil
}
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedNotificationRateLimit, err := expandMonitoringAlertPolicyAlertStrategyNotificationRateLimit(original["notification_rate_limit"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedNotificationRateLimit); val.IsValid() && !isEmptyValue(val) {
transformed["notificationRateLimit"] = transformedNotificationRateLimit
}

transformedAutoClose, err := expandMonitoringAlertPolicyAlertStrategyAutoClose(original["auto_close"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedAutoClose); val.IsValid() && !isEmptyValue(val) {
transformed["autoClose"] = transformedAutoClose
}

return transformed, nil
}

func expandMonitoringAlertPolicyAlertStrategyNotificationRateLimit(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
return nil, nil
}
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedPeriod, err := expandMonitoringAlertPolicyAlertStrategyNotificationRateLimitPeriod(original["period"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedPeriod); val.IsValid() && !isEmptyValue(val) {
transformed["period"] = transformedPeriod
}

return transformed, nil
}

func expandMonitoringAlertPolicyAlertStrategyNotificationRateLimitPeriod(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandMonitoringAlertPolicyAlertStrategyAutoClose(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandMonitoringAlertPolicyUserLabels(v interface{}, d TerraformResourceData, config *Config) (map[string]string, error) {
if v == nil {
return map[string]string{}, nil
Expand Down
56 changes: 56 additions & 0 deletions google-beta/resource_monitoring_alert_policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func TestAccMonitoringAlertPolicy(t *testing.T) {
"full": testAccMonitoringAlertPolicy_full,
"update": testAccMonitoringAlertPolicy_update,
"mql": testAccMonitoringAlertPolicy_mql,
"log": testAccMonitoringAlertPolicy_log,
}

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

func testAccMonitoringAlertPolicy_log(t *testing.T) {

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

vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAlertPolicyDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccMonitoringAlertPolicy_logCfg(alertName, conditionName),
},
{
ResourceName: "google_monitoring_alert_policy.log",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccCheckAlertPolicyDestroyProducer(t *testing.T) func(s *terraform.State) error {
return func(s *terraform.State) error {
config := googleProviderConfig(t)
Expand Down Expand Up @@ -277,3 +300,36 @@ resource "google_monitoring_alert_policy" "mql" {
}
`, alertName, conditionName)
}

func testAccMonitoringAlertPolicy_logCfg(alertName, conditionName string) string {
return fmt.Sprintf(`
resource "google_monitoring_alert_policy" "log" {
display_name = "%s"
combiner = "OR"
enabled = true
conditions {
display_name = "%s"
condition_matched_log {
filter = "protoPayload.methodName=\"google.cloud.bigquery.v2.TableService.DeleteTable\""
label_extractors = {
"test" = "EXTRACT(protoPayload.request)"
}
}
}
alert_strategy {
notification_rate_limit {
period = "300s"
}
auto_close = "2000s"
}
documentation {
content = "test content"
mime_type = "text/markdown"
}
}
`, alertName, conditionName)
}
Loading

0 comments on commit a019db8

Please sign in to comment.