Skip to content

Commit

Permalink
azurerm_monitor_scheduled_query_rules_alert_v2 - support identity (
Browse files Browse the repository at this point in the history
  • Loading branch information
teowa authored Mar 26, 2024
1 parent 0c43127 commit 0b76d88
Show file tree
Hide file tree
Showing 3 changed files with 228 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"github.com/hashicorp/go-azure-helpers/lang/response"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema"
"github.com/hashicorp/go-azure-helpers/resourcemanager/identity"
"github.com/hashicorp/go-azure-helpers/resourcemanager/location"
"github.com/hashicorp/go-azure-sdk/resource-manager/insights/2023-03-15-preview/scheduledqueryrules"
"github.com/hashicorp/terraform-provider-azurerm/helpers/azure"
Expand All @@ -20,28 +21,29 @@ import (
)

type ScheduledQueryRulesAlertV2Model struct {
Name string `tfschema:"name"`
ResourceGroupName string `tfschema:"resource_group_name"`
Actions []ScheduledQueryRulesAlertV2ActionsModel `tfschema:"action"`
AutoMitigate bool `tfschema:"auto_mitigation_enabled"`
CheckWorkspaceAlertsStorageConfigured bool `tfschema:"workspace_alerts_storage_enabled"`
Criteria []ScheduledQueryRulesAlertV2CriteriaModel `tfschema:"criteria"`
Description string `tfschema:"description"`
DisplayName string `tfschema:"display_name"`
Enabled bool `tfschema:"enabled"`
EvaluationFrequency string `tfschema:"evaluation_frequency"`
Location string `tfschema:"location"`
MuteActionsDuration string `tfschema:"mute_actions_after_alert_duration"`
OverrideQueryTimeRange string `tfschema:"query_time_range_override"`
Scopes []string `tfschema:"scopes"`
Severity scheduledqueryrules.AlertSeverity `tfschema:"severity"`
SkipQueryValidation bool `tfschema:"skip_query_validation"`
Tags map[string]string `tfschema:"tags"`
TargetResourceTypes []string `tfschema:"target_resource_types"`
WindowSize string `tfschema:"window_duration"`
CreatedWithApiVersion string `tfschema:"created_with_api_version"`
IsLegacyLogAnalyticsRule bool `tfschema:"is_a_legacy_log_analytics_rule"`
IsWorkspaceAlertsStorageConfigured bool `tfschema:"is_workspace_alerts_storage_configured"`
Name string `tfschema:"name"`
ResourceGroupName string `tfschema:"resource_group_name"`
Actions []ScheduledQueryRulesAlertV2ActionsModel `tfschema:"action"`
AutoMitigate bool `tfschema:"auto_mitigation_enabled"`
CheckWorkspaceAlertsStorageConfigured bool `tfschema:"workspace_alerts_storage_enabled"`
Criteria []ScheduledQueryRulesAlertV2CriteriaModel `tfschema:"criteria"`
Description string `tfschema:"description"`
DisplayName string `tfschema:"display_name"`
Enabled bool `tfschema:"enabled"`
EvaluationFrequency string `tfschema:"evaluation_frequency"`
Location string `tfschema:"location"`
MuteActionsDuration string `tfschema:"mute_actions_after_alert_duration"`
OverrideQueryTimeRange string `tfschema:"query_time_range_override"`
Scopes []string `tfschema:"scopes"`
Severity scheduledqueryrules.AlertSeverity `tfschema:"severity"`
SkipQueryValidation bool `tfschema:"skip_query_validation"`
Tags map[string]string `tfschema:"tags"`
TargetResourceTypes []string `tfschema:"target_resource_types"`
WindowSize string `tfschema:"window_duration"`
CreatedWithApiVersion string `tfschema:"created_with_api_version"`
IsLegacyLogAnalyticsRule bool `tfschema:"is_a_legacy_log_analytics_rule"`
IsWorkspaceAlertsStorageConfigured bool `tfschema:"is_workspace_alerts_storage_configured"`
Identity []identity.ModelSystemAssignedUserAssigned `tfschema:"identity"`
}

type ScheduledQueryRulesAlertV2ActionsModel struct {
Expand Down Expand Up @@ -374,6 +376,8 @@ func (r ScheduledQueryRulesAlertV2Resource) Arguments() map[string]*pluginsdk.Sc
Optional: true,
},

"identity": commonschema.SystemOrUserAssignedIdentityOptional(),

"tags": commonschema.Tags(),

"target_resource_types": {
Expand Down Expand Up @@ -426,6 +430,12 @@ func (r ScheduledQueryRulesAlertV2Resource) Create() sdk.ResourceFunc {
if !response.WasNotFound(existing.HttpResponse) {
return metadata.ResourceRequiresImport(r.ResourceType(), id)
}

ExpanededIdentity, err := identity.ExpandSystemOrUserAssignedMapFromModel(model.Identity)
if err != nil {
return fmt.Errorf("expanding SystemOrUserAssigned Identity: %+v", err)
}

kind := scheduledqueryrules.KindLogAlert
properties := &scheduledqueryrules.ScheduledQueryRuleResource{
Kind: &kind,
Expand All @@ -439,7 +449,8 @@ func (r ScheduledQueryRulesAlertV2Resource) Create() sdk.ResourceFunc {
SkipQueryValidation: &model.SkipQueryValidation,
TargetResourceTypes: &model.TargetResourceTypes,
},
Tags: &model.Tags,
Identity: ExpanededIdentity,
Tags: &model.Tags,
}

properties.Properties.Actions = expandScheduledQueryRulesAlertV2ActionsModel(model.Actions)
Expand Down Expand Up @@ -584,6 +595,13 @@ func (r ScheduledQueryRulesAlertV2Resource) Update() sdk.ResourceFunc {
}
}

if metadata.ResourceData.HasChange("identity") {
model.Identity, err = identity.ExpandSystemOrUserAssignedMapFromModel(resourceModel.Identity)
if err != nil {
return fmt.Errorf("expanding SystemOrUserAssigned Identity: %+v", err)
}
}

if metadata.ResourceData.HasChange("tags") {
model.Tags = &resourceModel.Tags
}
Expand Down Expand Up @@ -622,10 +640,16 @@ func (r ScheduledQueryRulesAlertV2Resource) Read() sdk.ResourceFunc {
return fmt.Errorf("retrieving %s: model was nil", id)
}

flattenedIdentity, err := identity.FlattenSystemOrUserAssignedMapToModel(model.Identity)
if err != nil {
return fmt.Errorf("flattening SystemOrUserAssigned Identity: %+v", err)
}

state := ScheduledQueryRulesAlertV2Model{
Name: id.ScheduledQueryRuleName,
ResourceGroupName: id.ResourceGroupName,
Location: location.Normalize(model.Location),
Identity: *flattenedIdentity,
}

properties := &model.Properties
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,69 @@ func TestAccMonitorScheduledQueryRulesAlertV2_update(t *testing.T) {
})
}

func TestAccMonitorScheduledQueryRulesAlertV2_identitySystemAssigned(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_monitor_scheduled_query_rules_alert_v2", "test")
r := MonitorScheduledQueryRulesAlertV2Resource{}
data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.identitySystemAssigned(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("identity.#").HasValue("1"),
check.That(data.ResourceName).Key("identity.0.type").HasValue("SystemAssigned"),
check.That(data.ResourceName).Key("identity.0.principal_id").IsUUID(),
check.That(data.ResourceName).Key("identity.0.tenant_id").IsUUID(),
),
},
data.ImportStep(),
})
}

func TestAccMonitorScheduledQueryRulesAlertV2_identityUpdate(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_monitor_scheduled_query_rules_alert_v2", "test")
r := MonitorScheduledQueryRulesAlertV2Resource{}
data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.basic(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("identity.#").HasValue("0"),
),
},
data.ImportStep(),
{
Config: r.identitySystemAssigned(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("identity.#").HasValue("1"),
check.That(data.ResourceName).Key("identity.0.type").HasValue("SystemAssigned"),
check.That(data.ResourceName).Key("identity.0.principal_id").IsUUID(),
check.That(data.ResourceName).Key("identity.0.tenant_id").IsUUID(),
),
},
data.ImportStep(),
{
Config: r.identityUserAssigned(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("identity.0.type").HasValue("UserAssigned"),
check.That(data.ResourceName).Key("identity.0.identity_ids.#").HasValue("1"),
check.That(data.ResourceName).Key("identity.0.principal_id").IsEmpty(),
check.That(data.ResourceName).Key("identity.0.tenant_id").IsUUID(),
),
},
data.ImportStep(),
{
Config: r.basic(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("identity.#").HasValue("0"),
),
},
data.ImportStep(),
})
}

func (r MonitorScheduledQueryRulesAlertV2Resource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) {
id, err := scheduledqueryrules.ParseScheduledQueryRuleID(state.ID)
if err != nil {
Expand Down Expand Up @@ -129,6 +192,18 @@ resource "azurerm_monitor_action_group" "test" {
resource_group_name = azurerm_resource_group.test.name
short_name = "test mag"
}
resource "azurerm_user_assigned_identity" "test" {
name = "acctestUAI-%[1]d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
}
resource "azurerm_role_assignment" "test" {
scope = azurerm_application_insights.test.id
role_definition_name = "Reader"
principal_id = azurerm_user_assigned_identity.test.principal_id
}
`, data.RandomInteger, data.Locations.Primary)
}

Expand Down Expand Up @@ -297,3 +372,65 @@ resource "azurerm_monitor_scheduled_query_rules_alert_v2" "test" {
}
`, template, data.RandomInteger, data.Locations.Primary)
}

func (r MonitorScheduledQueryRulesAlertV2Resource) identitySystemAssigned(data acceptance.TestData) string {
template := r.template(data)
return fmt.Sprintf(`
%s
resource "azurerm_monitor_scheduled_query_rules_alert_v2" "test" {
name = "acctest-isqr-%d"
resource_group_name = azurerm_resource_group.test.name
location = "%s"
evaluation_frequency = "PT5M"
window_duration = "PT5M"
scopes = [azurerm_application_insights.test.id]
severity = 3
criteria {
query = <<-QUERY
requests
| summarize CountByCountry=count() by client_CountryOrRegion
QUERY
time_aggregation_method = "Count"
threshold = 5.0
operator = "Equal"
}
identity {
type = "SystemAssigned"
}
}
`, template, data.RandomInteger, data.Locations.Primary)
}

func (r MonitorScheduledQueryRulesAlertV2Resource) identityUserAssigned(data acceptance.TestData) string {
template := r.template(data)
return fmt.Sprintf(`
%s
resource "azurerm_monitor_scheduled_query_rules_alert_v2" "test" {
name = "acctest-isqr-%[2]d"
resource_group_name = azurerm_resource_group.test.name
location = "%s"
evaluation_frequency = "PT5M"
window_duration = "PT5M"
scopes = [azurerm_application_insights.test.id]
severity = 3
criteria {
query = <<-QUERY
requests
| summarize CountByCountry=count() by client_CountryOrRegion
QUERY
time_aggregation_method = "Count"
threshold = 5.0
operator = "Equal"
}
identity {
type = "UserAssigned"
identity_ids = [
azurerm_user_assigned_identity.test.id,
]
}
depends_on = [azurerm_role_assignment.test]
}
`, template, data.RandomInteger, data.Locations.Primary)
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ resource "azurerm_monitor_action_group" "example" {
short_name = "test mag"
}
resource "azurerm_user_assigned_identity" "example" {
name = "example-uai"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
}
resource "azurerm_role_assignment" "example" {
scope = azurerm_application_insights.example.id
role_definition_name = "Reader"
principal_id = azurerm_user_assigned_identity.example.principal_id
}
resource "azurerm_monitor_scheduled_query_rules_alert_v2" "example" {
name = "example-msqrv2"
resource_group_name = azurerm_resource_group.example.name
Expand Down Expand Up @@ -77,10 +89,18 @@ resource "azurerm_monitor_scheduled_query_rules_alert_v2" "example" {
}
}
identity {
type = "UserAssigned"
identity_ids = [
azurerm_user_assigned_identity.example.id,
]
}
tags = {
key = "value"
key2 = "value2"
}
depends_on = [azurerm_role_assignment.example]
}
```

Expand Down Expand Up @@ -134,6 +154,8 @@ The following arguments are supported:

* `target_resource_types` - (Optional) List of resource type of the target resource(s) on which the alert is created/updated. For example if the scope is a resource group and targetResourceTypes is `Microsoft.Compute/virtualMachines`, then a different alert will be fired for each virtual machine in the resource group which meet the alert criteria.

* `identity` - (Optional) An `identity` block as defined below.

---

An `action` block supports the following:
Expand Down Expand Up @@ -186,6 +208,16 @@ A `failing_periods` block supports the following:

-> **Note** `number_of_evaluation_periods` must be `1` for queries that do not project timestamp column

---

An `identity` block supports the following:

* `type` - (Required) Specifies the type of Managed Service Identity that should be configured on this Scheduled Query Rule. Possible values are `SystemAssigned`, `UserAssigned`.

* `identity_ids` - (Optional) A list of User Assigned Managed Identity IDs to be assigned to this Scheduled Query Rule.

~> **NOTE:** This is required when `type` is set to `UserAssigned`. The identity associated must have required roles, read the [Azure documentation](https://learn.microsoft.com/en-us/azure/azure-monitor/alerts/alerts-create-log-alert-rule#configure-the-alert-rule-details) for more information.

## Attributes Reference

In addition to the Arguments listed above - the following Attributes are exported:
Expand All @@ -198,6 +230,18 @@ In addition to the Arguments listed above - the following Attributes are exporte

* `is_workspace_alerts_storage_configured` - The flag indicates whether this Scheduled Query Rule has been configured to be stored in the customer's storage.

* `identity` - An `identity` block as defined below.

---

A `identity` block exports the following:

* `principal_id` - The Principal ID for the Service Principal associated with the Managed Service Identity of this App Service slot.

* `tenant_id` - The Tenant ID for the Service Principal associated with the Managed Service Identity of this App Service slot.

-> You can access the Principal ID via `azurerm_monitor_scheduled_query_rules_alert_v2.example.identity[0].principal_id` and the Tenant ID via `azurerm_monitor_scheduled_query_rules_alert_v2.example.identity[0].tenant_id`

## Timeouts

The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions:
Expand Down

0 comments on commit 0b76d88

Please sign in to comment.