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

azurerm_monitor_activity_log_alert - support for levels, resource_providers, resource_types, resource_groups, resource_ids, statuses,and sub_statuses properties #21367

Merged
merged 4 commits into from May 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
222 changes: 207 additions & 15 deletions internal/services/monitor/monitor_activity_log_alert_resource.go
Expand Up @@ -85,12 +85,14 @@ func resourceMonitorActivityLogAlert() *pluginsdk.Resource {
}, false),
},
"operation_name": {
Type: pluginsdk.TypeString,
Optional: true,
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringIsNotEmpty,
},
"caller": {
Type: pluginsdk.TypeString,
Optional: true,
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringIsNotEmpty,
},
"level": {
Type: pluginsdk.TypeString,
Expand All @@ -102,31 +104,112 @@ func resourceMonitorActivityLogAlert() *pluginsdk.Resource {
"Error",
"Critical",
}, false),
ConflictsWith: []string{"criteria.0.levels"},
},
"levels": {
Type: pluginsdk.TypeList,
Optional: true,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
ValidateFunc: validation.StringInSlice([]string{
"Verbose",
"Informational",
"Warning",
"Error",
"Critical",
Comment on lines +115 to +119
Copy link
Collaborator

Choose a reason for hiding this comment

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

are there not constants for these in the SDK? if not could we open an issue on the rest specs to have them added?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The API only specifies the condition should be key-value pairs, and there is no enum for values.

And more details on property mappings:
level corresponds to:

{
      "field": "level",
      "equals": "Verbose"
},

levels corresponds to:

{
    "anyOf": [
        {
            "field": "level",
            "equals": "Verbose"
        },
        {
            "field": "level",
            "equals": "Informational"
        }
    ]
},

or

{
      "field": "level",
      "containsAny": ["Verbose", "Informational"]
},

since levels may map to 2 REST API schemas, here I am using the anyOf one in create/update, but accept either one in read.

}, false),
},
ConflictsWith: []string{"criteria.0.level"},
},
"resource_provider": {
Type: pluginsdk.TypeString,
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringIsNotEmpty,
ConflictsWith: []string{"criteria.0.resource_providers"},
},
"resource_providers": {
Type: pluginsdk.TypeList,
Optional: true,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
ValidateFunc: validation.StringIsNotEmpty,
},
ConflictsWith: []string{"criteria.0.resource_provider"},
},
"resource_type": {
Type: pluginsdk.TypeString,
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringIsNotEmpty,
ConflictsWith: []string{"criteria.0.resource_types"},
},
"resource_types": {
Type: pluginsdk.TypeList,
Optional: true,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
ValidateFunc: validation.StringIsNotEmpty,
},
ConflictsWith: []string{"criteria.0.resource_type"},
},
"resource_group": {
Type: pluginsdk.TypeString,
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringIsNotEmpty,
ConflictsWith: []string{"criteria.0.resource_groups"},
},
"resource_groups": {
Type: pluginsdk.TypeList,
Optional: true,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
ValidateFunc: validation.StringIsNotEmpty,
},
ConflictsWith: []string{"criteria.0.resource_group"},
},
"resource_id": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: azure.ValidateResourceID,
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: azure.ValidateResourceID,
ConflictsWith: []string{"criteria.0.resource_ids"},
},
"resource_ids": {
Type: pluginsdk.TypeList,
Optional: true,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
ValidateFunc: validation.StringIsNotEmpty,
},
ConflictsWith: []string{"criteria.0.resource_id"},
},
"status": {
Type: pluginsdk.TypeString,
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringIsNotEmpty,
ConflictsWith: []string{"criteria.0.statuses"},
},
"statuses": {
Type: pluginsdk.TypeList,
Optional: true,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
ValidateFunc: validation.StringIsNotEmpty,
},
ConflictsWith: []string{"criteria.0.status"},
},
"sub_status": {
Type: pluginsdk.TypeString,
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringIsNotEmpty,
ConflictsWith: []string{"criteria.0.sub_statuses"},
},
"sub_statuses": {
Type: pluginsdk.TypeList,
Optional: true,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
ValidateFunc: validation.StringIsNotEmpty,
},
ConflictsWith: []string{"criteria.0.sub_status"},
},
"recommendation_category": {
Type: pluginsdk.TypeString,
Expand Down Expand Up @@ -156,6 +239,7 @@ func resourceMonitorActivityLogAlert() *pluginsdk.Resource {
"recommendation_type": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringIsNotEmpty,
ConflictsWith: []string{"criteria.0.recommendation_category", "criteria.0.recommendation_impact"},
},
// lintignore:XS003
Expand Down Expand Up @@ -432,60 +516,112 @@ func expandMonitorActivityLogAlertCriteria(input []interface{}) activitylogalert
Equals: utils.String(category),
})
}

if op := v["operation_name"].(string); op != "" {
conditions = append(conditions, activitylogalertsapis.AlertRuleAnyOfOrLeafCondition{
Field: utils.String("operationName"),
Equals: utils.String(op),
})
}

if caller := v["caller"].(string); caller != "" {
conditions = append(conditions, activitylogalertsapis.AlertRuleAnyOfOrLeafCondition{
Field: utils.String("caller"),
Equals: utils.String(caller),
})
}

if level := v["level"].(string); level != "" {
conditions = append(conditions, activitylogalertsapis.AlertRuleAnyOfOrLeafCondition{
Field: utils.String("level"),
Equals: utils.String(level),
})
}

if levels := v["levels"].([]interface{}); len(levels) > 0 {
conditions = append(conditions, activitylogalertsapis.AlertRuleAnyOfOrLeafCondition{
AnyOf: expandAnyOfCondition(levels, "level"),
})
}

if resourceProvider := v["resource_provider"].(string); resourceProvider != "" {
conditions = append(conditions, activitylogalertsapis.AlertRuleAnyOfOrLeafCondition{
Field: utils.String("resourceProvider"),
Equals: utils.String(resourceProvider),
})
}

if resourceProviders := v["resource_providers"].([]interface{}); len(resourceProviders) > 0 {
conditions = append(conditions, activitylogalertsapis.AlertRuleAnyOfOrLeafCondition{
AnyOf: expandAnyOfCondition(resourceProviders, "resourceProvider"),
})
}

if resourceType := v["resource_type"].(string); resourceType != "" {
conditions = append(conditions, activitylogalertsapis.AlertRuleAnyOfOrLeafCondition{
Field: utils.String("resourceType"),
Equals: utils.String(resourceType),
})
}

if resourceTypes := v["resource_types"].([]interface{}); len(resourceTypes) > 0 {
conditions = append(conditions, activitylogalertsapis.AlertRuleAnyOfOrLeafCondition{
AnyOf: expandAnyOfCondition(resourceTypes, "resourceType"),
})
}

if resourceGroup := v["resource_group"].(string); resourceGroup != "" {
conditions = append(conditions, activitylogalertsapis.AlertRuleAnyOfOrLeafCondition{
Field: utils.String("resourceGroup"),
Equals: utils.String(resourceGroup),
})
}

if resourceGroups := v["resource_groups"].([]interface{}); len(resourceGroups) > 0 {
conditions = append(conditions, activitylogalertsapis.AlertRuleAnyOfOrLeafCondition{
AnyOf: expandAnyOfCondition(resourceGroups, "resourceGroup"),
})
}

if id := v["resource_id"].(string); id != "" {
conditions = append(conditions, activitylogalertsapis.AlertRuleAnyOfOrLeafCondition{
Field: utils.String("resourceId"),
Equals: utils.String(id),
})
}

if resourceIds := v["resource_ids"].([]interface{}); len(resourceIds) > 0 {
conditions = append(conditions, activitylogalertsapis.AlertRuleAnyOfOrLeafCondition{
AnyOf: expandAnyOfCondition(resourceIds, "resourceId"),
})
}

if status := v["status"].(string); status != "" {
conditions = append(conditions, activitylogalertsapis.AlertRuleAnyOfOrLeafCondition{
Field: utils.String("status"),
Equals: utils.String(status),
})
}

if statuses := v["statuses"].([]interface{}); len(statuses) > 0 {
conditions = append(conditions, activitylogalertsapis.AlertRuleAnyOfOrLeafCondition{
AnyOf: expandAnyOfCondition(statuses, "status"),
})
}

if subStatus := v["sub_status"].(string); subStatus != "" {
conditions = append(conditions, activitylogalertsapis.AlertRuleAnyOfOrLeafCondition{
Field: utils.String("subStatus"),
Equals: utils.String(subStatus),
})
}

if statuses := v["sub_statuses"].([]interface{}); len(statuses) > 0 {
conditions = append(conditions, activitylogalertsapis.AlertRuleAnyOfOrLeafCondition{
AnyOf: expandAnyOfCondition(statuses, "subStatus"),
})
}

if recommendationType := v["recommendation_type"].(string); recommendationType != "" {
conditions = append(conditions, activitylogalertsapis.AlertRuleAnyOfOrLeafCondition{
Field: utils.String("properties.recommendationType"),
Expand Down Expand Up @@ -520,6 +656,17 @@ func expandMonitorActivityLogAlertCriteria(input []interface{}) activitylogalert
}
}

func expandAnyOfCondition(input []interface{}, field string) *[]activitylogalertsapis.AlertRuleLeafCondition {
conditions := make([]activitylogalertsapis.AlertRuleLeafCondition, 0)
for _, v := range input {
conditions = append(conditions, activitylogalertsapis.AlertRuleLeafCondition{
Field: utils.String(field),
Equals: utils.String(v.(string)),
})
}
return &conditions
}

func expandResourceHealth(resourceHealth []interface{}, conditions []activitylogalertsapis.AlertRuleAnyOfOrLeafCondition) []activitylogalertsapis.AlertRuleAnyOfOrLeafCondition {
for _, serviceItem := range resourceHealth {
if serviceItem == nil {
Expand Down Expand Up @@ -668,6 +815,50 @@ func flattenMonitorActivityLogAlertCriteria(input activitylogalertsapis.AlertRul
result[*condition.Field] = *condition.Equals
}
}

if condition.Field != nil && condition.ContainsAny != nil && len(*condition.ContainsAny) > 0 {
switch strings.ToLower(*condition.Field) {
case "resourceprovider":
result["resource_providers"] = *condition.ContainsAny
case "resourcetype":
result["resource_types"] = *condition.ContainsAny
case "resourcegroup":
result["resource_groups"] = *condition.ContainsAny
case "resourceid":
result["resource_ids"] = *condition.ContainsAny
case "substatus":
result["sub_statuses"] = *condition.ContainsAny
case "level":
result["levels"] = *condition.ContainsAny
case "status":
result["statuses"] = *condition.ContainsAny
}
}

if condition.AnyOf != nil && len(*condition.AnyOf) > 0 {
values := make([]string, 0)
for _, leafCondition := range *condition.AnyOf {
if leafCondition.Field != nil && leafCondition.Equals != nil {
values = append(values, *leafCondition.Equals)
}
switch strings.ToLower(*leafCondition.Field) {
case "resourceprovider":
result["resource_providers"] = values
case "resourcetype":
result["resource_types"] = values
case "resourcegroup":
result["resource_groups"] = values
case "resourceid":
result["resource_ids"] = values
case "substatus":
result["sub_statuses"] = values
case "level":
result["levels"] = values
case "status":
result["statuses"] = values
}
}
}
}

if result["category"] == "ResourceHealth" {
Expand All @@ -683,9 +874,10 @@ func flattenMonitorActivityLogAlertCriteria(input activitylogalertsapis.AlertRul

func flattenMonitorActivityLogAlertResourceHealth(input activitylogalertsapis.AlertRuleAllOfCondition, result map[string]interface{}) {
rhResult := make(map[string]interface{})

for _, condition := range input.AllOf {
if condition.Field == nil && len(*condition.AnyOf) > 0 {
var values []string
if condition.Field == nil && condition.AnyOf != nil && len(*condition.AnyOf) > 0 {
values := []string{}
for _, cond := range *condition.AnyOf {
if cond.Field != nil && cond.Equals != nil {
values = append(values, *cond.Equals)
Expand Down Expand Up @@ -716,7 +908,7 @@ func flattenMonitorActivityLogAlertServiceHealth(input activitylogalertsapis.Ale
shResult["services"] = *condition.ContainsAny
}
}
if condition.Field == nil && len(*condition.AnyOf) > 0 {
if condition.Field == nil && condition.AnyOf != nil && len(*condition.AnyOf) > 0 {
events := []string{}
for _, evCond := range *condition.AnyOf {
if evCond.Field != nil && evCond.Equals != nil {
Expand Down