From 489188f190267dfa26ce10d8297e218c4cbef81f Mon Sep 17 00:00:00 2001 From: Junyi Yi Date: Fri, 21 Sep 2018 15:08:47 -0700 Subject: [PATCH 1/9] Define the schema of activity log alert resource --- azurerm/config.go | 9 +- .../resource_arm_monitor_activitylog_alert.go | 135 ++++++++++++++++++ ...urce_arm_monitor_activitylog_alert_test.go | 1 + 3 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 azurerm/resource_arm_monitor_activitylog_alert.go create mode 100644 azurerm/resource_arm_monitor_activitylog_alert_test.go diff --git a/azurerm/config.go b/azurerm/config.go index 37381c6d908b..4e0992f0062a 100644 --- a/azurerm/config.go +++ b/azurerm/config.go @@ -181,8 +181,9 @@ type ArmClient struct { managementGroupsSubscriptionClient managementgroups.SubscriptionsClient // Monitor - actionGroupsClient insights.ActionGroupsClient - monitorAlertRulesClient insights.AlertRulesClient + actionGroupsClient insights.ActionGroupsClient + monitorActivityLogAlertsClient insights.ActivityLogAlertsClient + monitorAlertRulesClient insights.AlertRulesClient // MSI userAssignedIdentitiesClient msi.UserAssignedIdentitiesClient @@ -757,6 +758,10 @@ func (c *ArmClient) registerMonitorClients(endpoint, subscriptionId string, auth c.configureClient(&actionGroupsClient.Client, auth) c.actionGroupsClient = actionGroupsClient + alac := insights.NewActivityLogAlertsClientWithBaseURI(endpoint, subscriptionId) + c.configureClient(&alac.Client, auth) + c.monitorActivityLogAlertsClient = alac + arc := insights.NewAlertRulesClientWithBaseURI(endpoint, subscriptionId) c.configureClient(&arc.Client, auth) c.monitorAlertRulesClient = arc diff --git a/azurerm/resource_arm_monitor_activitylog_alert.go b/azurerm/resource_arm_monitor_activitylog_alert.go new file mode 100644 index 000000000000..2116f4153c80 --- /dev/null +++ b/azurerm/resource_arm_monitor_activitylog_alert.go @@ -0,0 +1,135 @@ +package azurerm + +import ( + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +func resourceArmMonitorActivityLogAlert() *schema.Resource { + return &schema.Resource{ + Create: resourceArmMonitorActivityLogAlertCreateOrUpdate, + Read: resourceArmMonitorActivityLogAlertRead, + Update: resourceArmMonitorActivityLogAlertCreateOrUpdate, + Delete: resourceArmMonitorActivityLogAlertDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.NoZeroValues, + }, + + "resource_group_name": resourceGroupNameSchema(), + + "scopes": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: azure.ValidateResourceID, + }, + }, + + "criteria": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "caller": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.NoZeroValues, + }, + "category": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.NoZeroValues, + }, + "level": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.NoZeroValues, + }, + "operation_name": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.NoZeroValues, + }, + "resource_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: azure.ValidateResourceID, + }, + "status": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.NoZeroValues, + }, + "sub_status": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.NoZeroValues, + }, + }, + }, + }, + + "action": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action_group_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: azure.ValidateResourceID, + }, + "webhook_properties": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.NoZeroValues, + }, + + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + + "tags": tagsSchema(), + }, + } +} + +func resourceArmMonitorActivityLogAlertCreateOrUpdate(d *schema.ResourceData, meta interface{}) error { + return nil +} + +func resourceArmMonitorActivityLogAlertRead(d *schema.ResourceData, meta interface{}) error { + return nil +} + +func resourceArmMonitorActivityLogAlertDelete(d *schema.ResourceData, meta interface{}) error { + return nil +} diff --git a/azurerm/resource_arm_monitor_activitylog_alert_test.go b/azurerm/resource_arm_monitor_activitylog_alert_test.go new file mode 100644 index 000000000000..96f5b5587ee2 --- /dev/null +++ b/azurerm/resource_arm_monitor_activitylog_alert_test.go @@ -0,0 +1 @@ +package azurerm From 05063ddedfff8a1fd052e8b9739bf7a59d5d17cf Mon Sep 17 00:00:00 2001 From: Junyi Yi Date: Fri, 21 Sep 2018 15:22:45 -0700 Subject: [PATCH 2/9] Implement delete operation of activity log alert --- azurerm/provider.go | 1 + .../resource_arm_monitor_activitylog_alert.go | 21 ++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/azurerm/provider.go b/azurerm/provider.go index 739e563c86f0..8efbffcb1e40 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -205,6 +205,7 @@ func Provider() terraform.ResourceProvider { "azurerm_management_group": resourceArmManagementGroup(), "azurerm_metric_alertrule": resourceArmMetricAlertRule(), "azurerm_monitor_action_group": resourceArmMonitorActionGroup(), + "azurerm_monitor_activitylog_alert": resourceArmMonitorActivityLogAlert(), "azurerm_mysql_configuration": resourceArmMySQLConfiguration(), "azurerm_mysql_database": resourceArmMySqlDatabase(), "azurerm_mysql_firewall_rule": resourceArmMySqlFirewallRule(), diff --git a/azurerm/resource_arm_monitor_activitylog_alert.go b/azurerm/resource_arm_monitor_activitylog_alert.go index 2116f4153c80..ea4ddfc9d99d 100644 --- a/azurerm/resource_arm_monitor_activitylog_alert.go +++ b/azurerm/resource_arm_monitor_activitylog_alert.go @@ -1,9 +1,12 @@ package azurerm import ( + "fmt" + "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/response" ) func resourceArmMonitorActivityLogAlert() *schema.Resource { @@ -123,7 +126,7 @@ func resourceArmMonitorActivityLogAlert() *schema.Resource { } func resourceArmMonitorActivityLogAlertCreateOrUpdate(d *schema.ResourceData, meta interface{}) error { - return nil + return resourceArmMonitorActivityLogAlertRead(d, meta) } func resourceArmMonitorActivityLogAlertRead(d *schema.ResourceData, meta interface{}) error { @@ -131,5 +134,21 @@ func resourceArmMonitorActivityLogAlertRead(d *schema.ResourceData, meta interfa } func resourceArmMonitorActivityLogAlertDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).monitorActivityLogAlertsClient + ctx := meta.(*ArmClient).StopContext + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + resGroup := id.ResourceGroup + name := id.Path["activityLogAlerts"] + + if resp, err := client.Delete(ctx, resGroup, name); err != nil { + if !response.WasNotFound(resp.Response) { + return fmt.Errorf("Error deleting activity log alert %q (resource group %q): %+v", name, resGroup, err) + } + } + return nil } From cadf3c033416516ea908f1435ab8d8b3b7ce138d Mon Sep 17 00:00:00 2001 From: Junyi Yi Date: Mon, 24 Sep 2018 14:04:20 -0700 Subject: [PATCH 3/9] Implement skeleton of create/update and read operations of activity log alert --- .../resource_arm_monitor_activitylog_alert.go | 60 ++++++++++++++++++- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/azurerm/resource_arm_monitor_activitylog_alert.go b/azurerm/resource_arm_monitor_activitylog_alert.go index ea4ddfc9d99d..6bdff209800a 100644 --- a/azurerm/resource_arm_monitor_activitylog_alert.go +++ b/azurerm/resource_arm_monitor_activitylog_alert.go @@ -3,10 +3,12 @@ package azurerm import ( "fmt" + "github.com/Azure/azure-sdk-for-go/services/preview/monitor/mgmt/2018-03-01/insights" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/response" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) func resourceArmMonitorActivityLogAlert() *schema.Resource { @@ -109,9 +111,8 @@ func resourceArmMonitorActivityLogAlert() *schema.Resource { }, "description": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.NoZeroValues, + Type: schema.TypeString, + Optional: true, }, "enabled": { @@ -126,10 +127,63 @@ func resourceArmMonitorActivityLogAlert() *schema.Resource { } func resourceArmMonitorActivityLogAlertCreateOrUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).monitorActivityLogAlertsClient + ctx := meta.(*ArmClient).StopContext + + name := d.Get("name").(string) + resGroup := d.Get("resource_group_name").(string) + + tags := d.Get("tags").(map[string]interface{}) + expandedTags := expandTags(tags) + + parameters := insights.ActivityLogAlertResource{ + Location: utils.String(azureRMNormalizeLocation("Global")), + ActivityLogAlert: &insights.ActivityLogAlert{}, + Tags: expandedTags, + } + + if _, err := client.CreateOrUpdate(ctx, resGroup, name, parameters); err != nil { + return fmt.Errorf("Error creating or updating activity log alert %q (resource group %q): %+v", name, resGroup, err) + } + + read, err := client.Get(ctx, resGroup, name) + if err != nil { + return err + } + if read.ID == nil { + return fmt.Errorf("Activity log alert %q (resource group %q) ID is empty", name, resGroup) + } + d.SetId(*read.ID) + return resourceArmMonitorActivityLogAlertRead(d, meta) } func resourceArmMonitorActivityLogAlertRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).monitorActivityLogAlertsClient + ctx := meta.(*ArmClient).StopContext + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + resGroup := id.ResourceGroup + name := id.Path["activityLogAlerts"] + + resp, err := client.Get(ctx, resGroup, name) + if err != nil { + if response.WasNotFound(resp.Response.Response) { + d.SetId("") + return nil + } + return fmt.Errorf("Error getting activity log alert %q (resource group %q): %+v", name, resGroup, err) + } + + d.Set("name", name) + d.Set("resource_group_name", resGroup) + if alert := resp.ActivityLogAlert; alert != nil { + } + flattenAndSetTags(d, resp.Tags) + return nil } From 7c75a0759c195c703cb53bec7ece9bd1764c35f0 Mon Sep 17 00:00:00 2001 From: Junyi Yi Date: Tue, 25 Sep 2018 16:20:44 -0700 Subject: [PATCH 4/9] Implement expand and flatten of activity log alert --- .../resource_arm_monitor_activitylog_alert.go | 171 +++++++++++++++--- 1 file changed, 150 insertions(+), 21 deletions(-) diff --git a/azurerm/resource_arm_monitor_activitylog_alert.go b/azurerm/resource_arm_monitor_activitylog_alert.go index 6bdff209800a..a541096af6e2 100644 --- a/azurerm/resource_arm_monitor_activitylog_alert.go +++ b/azurerm/resource_arm_monitor_activitylog_alert.go @@ -2,6 +2,7 @@ package azurerm import ( "fmt" + "strings" "github.com/Azure/azure-sdk-for-go/services/preview/monitor/mgmt/2018-03-01/insights" "github.com/hashicorp/terraform/helper/schema" @@ -50,24 +51,20 @@ func resourceArmMonitorActivityLogAlert() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "caller": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.NoZeroValues, + Type: schema.TypeString, + Optional: true, }, "category": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.NoZeroValues, + Type: schema.TypeString, + Optional: true, }, "level": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.NoZeroValues, + Type: schema.TypeString, + Optional: true, }, "operation_name": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.NoZeroValues, + Type: schema.TypeString, + Optional: true, }, "resource_id": { Type: schema.TypeString, @@ -75,14 +72,12 @@ func resourceArmMonitorActivityLogAlert() *schema.Resource { ValidateFunc: azure.ValidateResourceID, }, "status": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.NoZeroValues, + Type: schema.TypeString, + Optional: true, }, "sub_status": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.NoZeroValues, + Type: schema.TypeString, + Optional: true, }, }, }, @@ -133,13 +128,25 @@ func resourceArmMonitorActivityLogAlertCreateOrUpdate(d *schema.ResourceData, me name := d.Get("name").(string) resGroup := d.Get("resource_group_name").(string) + enabled := d.Get("enabled").(bool) + description := d.Get("description").(string) + scopesRaw := d.Get("scopes").([]interface{}) + criteriaRaw := d.Get("criteria.0").(map[string]interface{}) + actionRaw := d.Get("action").([]interface{}) + tags := d.Get("tags").(map[string]interface{}) expandedTags := expandTags(tags) parameters := insights.ActivityLogAlertResource{ - Location: utils.String(azureRMNormalizeLocation("Global")), - ActivityLogAlert: &insights.ActivityLogAlert{}, - Tags: expandedTags, + Location: utils.String(azureRMNormalizeLocation("Global")), + ActivityLogAlert: &insights.ActivityLogAlert{ + Enabled: utils.Bool(enabled), + Description: utils.String(description), + Scopes: expandMonitorActivityLogAlertScopes(scopesRaw), + Condition: expandMonitorActivityLogAlertCriteria(criteriaRaw), + Actions: expandMonitorActivityLogAlertAction(actionRaw), + }, + Tags: expandedTags, } if _, err := client.CreateOrUpdate(ctx, resGroup, name, parameters); err != nil { @@ -181,6 +188,17 @@ func resourceArmMonitorActivityLogAlertRead(d *schema.ResourceData, meta interfa d.Set("name", name) d.Set("resource_group_name", resGroup) if alert := resp.ActivityLogAlert; alert != nil { + d.Set("enabled", alert.Enabled) + d.Set("description", alert.Description) + if err := d.Set("scopes", flattenMonitorActivityLogAlertScopes(alert.Scopes)); err != nil { + return err + } + if err := d.Set("criteria", flattenMonitorActivityLogAlertCriteria(alert.Condition)); err != nil { + return err + } + if err := d.Set("action", flattenMonitorActivityLogAlertAction(alert.Actions)); err != nil { + return err + } } flattenAndSetTags(d, resp.Tags) @@ -206,3 +224,114 @@ func resourceArmMonitorActivityLogAlertDelete(d *schema.ResourceData, meta inter return nil } + +func expandMonitorActivityLogAlertScopes(v []interface{}) *[]string { + scopes := make([]string, 0) + for _, scope := range v { + scopes = append(scopes, scope.(string)) + } + return &scopes +} + +func expandMonitorActivityLogAlertCriteria(v map[string]interface{}) *insights.ActivityLogAlertAllOfCondition { + conditions := make([]insights.ActivityLogAlertLeafCondition, 0) + + appendCondition := func(schemaName, fieldName string) { + if val, ok := v[schemaName]; ok { + conditions = append(conditions, insights.ActivityLogAlertLeafCondition{ + Field: utils.String(fieldName), + Equals: utils.String(val.(string)), + }) + } + } + appendCondition("caller", "caller") + appendCondition("category", "category") + appendCondition("level", "level") + appendCondition("operation_name", "operationName") + appendCondition("resource_id", "resourceId") + appendCondition("status", "status") + appendCondition("sub_status", "subStatus") + + return &insights.ActivityLogAlertAllOfCondition{ + AllOf: &conditions, + } +} + +func expandMonitorActivityLogAlertAction(v []interface{}) *insights.ActivityLogAlertActionList { + ags := make([]insights.ActivityLogAlertActionGroup, 0) + for _, agValue := range v { + val := agValue.(map[string]interface{}) + + agID := val["action_group_id"].(string) + props := make(map[string]*string) + if propsValue, ok := val["webhook_properties"]; ok { + for k, v := range propsValue.(map[string]interface{}) { + props[k] = utils.String(v.(string)) + } + } + + ag := insights.ActivityLogAlertActionGroup{ + ActionGroupID: utils.String(agID), + WebhookProperties: props, + } + ags = append(ags, ag) + } + return &insights.ActivityLogAlertActionList{ + ActionGroups: &ags, + } +} + +func flattenMonitorActivityLogAlertScopes(v *[]string) []interface{} { + result := make([]interface{}, 0) + if v != nil { + for _, scope := range *v { + result = append(result, scope) + } + } + return result +} + +func flattenMonitorActivityLogAlertCriteria(v *insights.ActivityLogAlertAllOfCondition) []interface{} { + result := make(map[string]interface{}) + if v != nil && v.AllOf != nil { + for _, condition := range *v.AllOf { + if condition.Field != nil && condition.Equals != nil { + switch strings.ToLower(*condition.Field) { + case "operationname": + result["operation_name"] = *condition.Equals + case "resourceid": + result["resource_id"] = *condition.Equals + case "substatus": + result["sub_status"] = *condition.Equals + case "caller", "category", "level", "status": + result[*condition.Field] = *condition.Equals + } + } + } + } + return []interface{}{result} +} + +func flattenMonitorActivityLogAlertAction(v *insights.ActivityLogAlertActionList) []interface{} { + result := make([]interface{}, 0) + if v != nil && v.ActionGroups != nil { + for _, ag := range *v.ActionGroups { + val := make(map[string]interface{}, 0) + + if ag.ActionGroupID != nil { + val["action_group_id"] = *ag.ActionGroupID + } + + props := make(map[string]string) + for k, v := range ag.WebhookProperties { + if v != nil { + props[k] = *v + } + } + val["webhook_properties"] = props + + result = append(result, val) + } + } + return result +} From 2bc812e1b41eb49a24768274278f078a46908a9b Mon Sep 17 00:00:00 2001 From: Junyi Yi Date: Tue, 25 Sep 2018 18:02:21 -0700 Subject: [PATCH 5/9] Adjust some schema definition according to Azure documentation. --- .../resource_arm_monitor_activitylog_alert.go | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/azurerm/resource_arm_monitor_activitylog_alert.go b/azurerm/resource_arm_monitor_activitylog_alert.go index a541096af6e2..5ecc199421aa 100644 --- a/azurerm/resource_arm_monitor_activitylog_alert.go +++ b/azurerm/resource_arm_monitor_activitylog_alert.go @@ -39,7 +39,7 @@ func resourceArmMonitorActivityLogAlert() *schema.Resource { MinItems: 1, Elem: &schema.Schema{ Type: schema.TypeString, - ValidateFunc: azure.ValidateResourceID, + ValidateFunc: validation.NoZeroValues, }, }, @@ -50,21 +50,31 @@ func resourceArmMonitorActivityLogAlert() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "caller": { - Type: schema.TypeString, - Optional: true, - }, "category": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, }, - "level": { + "operation_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + "caller": { Type: schema.TypeString, Optional: true, }, - "operation_name": { + "level": { Type: schema.TypeString, Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "Verbose", + "Informational", + "Warning", + "Error", + "Critical", + }, true), + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, }, "resource_id": { Type: schema.TypeString, @@ -237,7 +247,7 @@ func expandMonitorActivityLogAlertCriteria(v map[string]interface{}) *insights.A conditions := make([]insights.ActivityLogAlertLeafCondition, 0) appendCondition := func(schemaName, fieldName string) { - if val, ok := v[schemaName]; ok { + if val, ok := v[schemaName]; ok && val != "" { conditions = append(conditions, insights.ActivityLogAlertLeafCondition{ Field: utils.String(fieldName), Equals: utils.String(val.(string)), From d26ba2a629aacaeadcc6b3a34a531f9e59355165 Mon Sep 17 00:00:00 2001 From: Junyi Yi Date: Wed, 26 Sep 2018 17:55:46 -0700 Subject: [PATCH 6/9] Add simple test cases to activity log alert. --- .../resource_arm_monitor_activitylog_alert.go | 21 +- ...urce_arm_monitor_activitylog_alert_test.go | 299 ++++++++++++++++++ 2 files changed, 310 insertions(+), 10 deletions(-) diff --git a/azurerm/resource_arm_monitor_activitylog_alert.go b/azurerm/resource_arm_monitor_activitylog_alert.go index 5ecc199421aa..7e89048af759 100644 --- a/azurerm/resource_arm_monitor_activitylog_alert.go +++ b/azurerm/resource_arm_monitor_activitylog_alert.go @@ -46,7 +46,6 @@ func resourceArmMonitorActivityLogAlert() *schema.Resource { "criteria": { Type: schema.TypeList, Required: true, - MinItems: 1, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -246,21 +245,23 @@ func expandMonitorActivityLogAlertScopes(v []interface{}) *[]string { func expandMonitorActivityLogAlertCriteria(v map[string]interface{}) *insights.ActivityLogAlertAllOfCondition { conditions := make([]insights.ActivityLogAlertLeafCondition, 0) - appendCondition := func(schemaName, fieldName string) { - if val, ok := v[schemaName]; ok && val != "" { + for schemaName, val := range v { + if val != "" { + fieldName := schemaName + switch schemaName { + case "operation_name": + fieldName = "operationName" + case "resource_id": + fieldName = "resourceId" + case "sub_status": + fieldName = "subStatus" + } conditions = append(conditions, insights.ActivityLogAlertLeafCondition{ Field: utils.String(fieldName), Equals: utils.String(val.(string)), }) } } - appendCondition("caller", "caller") - appendCondition("category", "category") - appendCondition("level", "level") - appendCondition("operation_name", "operationName") - appendCondition("resource_id", "resourceId") - appendCondition("status", "status") - appendCondition("sub_status", "subStatus") return &insights.ActivityLogAlertAllOfCondition{ AllOf: &conditions, diff --git a/azurerm/resource_arm_monitor_activitylog_alert_test.go b/azurerm/resource_arm_monitor_activitylog_alert_test.go index 96f5b5587ee2..760001f62dd3 100644 --- a/azurerm/resource_arm_monitor_activitylog_alert_test.go +++ b/azurerm/resource_arm_monitor_activitylog_alert_test.go @@ -1 +1,300 @@ package azurerm + +import ( + "fmt" + "net/http" + "strings" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAzureRMMonitorActivityLogAlert_basic(t *testing.T) { + resourceName := "azurerm_monitor_activitylog_alert.test" + ri := acctest.RandInt() + config := testAccAzureRMMonitorActivityLogAlert_basic(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMMonitorActivityLogAlertDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMMonitorActivityLogAlertExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "scopes.#", "1"), + resource.TestCheckResourceAttr(resourceName, "criteria.#", "1"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.operation_name", "Microsoft.Storage/storageAccounts/write"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.category", "Recommendation"), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "action.0.action_group_id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMMonitorActivityLogAlert_singleResource(t *testing.T) { + resourceName := "azurerm_monitor_activitylog_alert.test" + ri := acctest.RandInt() + rs := strings.ToLower(acctest.RandString(11)) + config := testAccAzureRMMonitorActivityLogAlert_singleResource(ri, rs, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMMonitorActivityLogAlertDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMMonitorActivityLogAlertExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "scopes.#", "1"), + resource.TestCheckResourceAttr(resourceName, "criteria.#", "1"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.operation_name", "Microsoft.Storage/storageAccounts/write"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.category", "Recommendation"), + resource.TestCheckResourceAttrSet(resourceName, "criteria.0.resource_id"), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "action.0.action_group_id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMMonitorActivityLogAlert_full(t *testing.T) { + resourceName := "azurerm_monitor_activitylog_alert.test" + ri := acctest.RandInt() + rs := strings.ToLower(acctest.RandString(11)) + config := testAccAzureRMMonitorActivityLogAlert_full(ri, rs, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMMonitorActivityLogAlertDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMMonitorActivityLogAlertExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "description", "This is just a test resource."), + resource.TestCheckResourceAttr(resourceName, "scopes.#", "2"), + resource.TestCheckResourceAttr(resourceName, "criteria.#", "1"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.operation_name", "Microsoft.Storage/storageAccounts/write"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.category", "Recommendation"), + resource.TestCheckResourceAttrSet(resourceName, "criteria.0.resource_id"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.caller", "user@example.com"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.level", "Error"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.status", "Failed"), + resource.TestCheckResourceAttr(resourceName, "action.#", "2"), + resource.TestCheckResourceAttrSet(resourceName, "action.0.action_group_id"), + resource.TestCheckResourceAttrSet(resourceName, "action.1.action_group_id"), + resource.TestCheckResourceAttr(resourceName, "action.1.webhook_properties.%", "2"), + resource.TestCheckResourceAttr(resourceName, "action.1.webhook_properties.from", "terraform test"), + resource.TestCheckResourceAttr(resourceName, "action.1.webhook_properties.to", "microsoft azure"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccAzureRMMonitorActivityLogAlert_basic(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_monitor_action_group" "test" { + name = "acctestActionGroup-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + short_name = "acctestag" +} + +resource "azurerm_monitor_activitylog_alert" "test" { + name = "acctestActivityLogAlert-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + scopes = ["${azurerm_resource_group.test.id}"] + + criteria { + operation_name = "Microsoft.Storage/storageAccounts/write" + category = "Recommendation" + } + + action { + action_group_id = "${azurerm_monitor_action_group.test.id}" + } +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMMonitorActivityLogAlert_singleResource(rInt int, rString, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_monitor_action_group" "test" { + name = "acctestActionGroup-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + short_name = "acctestag" +} + +resource "azurerm_storage_account" "test" { + name = "acctestsa%s" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_monitor_activitylog_alert" "test" { + name = "acctestActivityLogAlert-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + scopes = ["${azurerm_resource_group.test.id}"] + + criteria { + operation_name = "Microsoft.Storage/storageAccounts/write" + category = "Recommendation" + resource_id = "${azurerm_storage_account.test.id}" + } + + action { + action_group_id = "${azurerm_monitor_action_group.test.id}" + } +} +`, rInt, location, rInt, rString, rInt) +} + +func testAccAzureRMMonitorActivityLogAlert_full(rInt int, rString, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_monitor_action_group" "test" { + name = "acctestActionGroup-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + short_name = "acctestag" +} + +resource "azurerm_storage_account" "test" { + name = "acctestsa%s" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_monitor_activitylog_alert" "test" { + name = "acctestActivityLogAlert-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + enabled = true + description = "This is just a test resource." + scopes = [ + "${azurerm_resource_group.test.id}", + "${azurerm_storage_account.test.id}" + ] + + criteria { + operation_name = "Microsoft.Storage/storageAccounts/write" + category = "Recommendation" + resource_id = "${azurerm_storage_account.test.id}" + caller = "user@example.com" + level = "Error" + status = "Failed" + } + + action { + action_group_id = "${azurerm_monitor_action_group.test.id}" + } + + action { + action_group_id = "${azurerm_monitor_action_group.test.id}" + webhook_properties { + from = "terraform test" + to = "microsoft azure" + } + } +} +`, rInt, location, rInt, rString, rInt) +} + +func testCheckAzureRMMonitorActivityLogAlertDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*ArmClient).monitorActivityLogAlertsClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_monitor_activitylog_alert" { + continue + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + resp, err := conn.Get(ctx, resourceGroup, name) + + if err != nil { + return nil + } + + if resp.StatusCode != http.StatusNotFound { + return fmt.Errorf("Activity log alert still exists:\n%#v", resp) + } + } + + return nil +} + +func testCheckAzureRMMonitorActivityLogAlertExists(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + // Ensure we have enough information in state to look up in API + rs, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + + resourceName := rs.Primary.Attributes["name"] + resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] + if !hasResourceGroup { + return fmt.Errorf("Bad: no resource group found in state for Activity Log Alert Instance: %s", resourceName) + } + + conn := testAccProvider.Meta().(*ArmClient).monitorActivityLogAlertsClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + resp, err := conn.Get(ctx, resourceGroup, resourceName) + if err != nil { + return fmt.Errorf("Bad: Get on monitorActivityLogAlertsClient: %+v", err) + } + + if resp.StatusCode == http.StatusNotFound { + return fmt.Errorf("Bad: Activity Log Alert Instance %q (resource group: %q) does not exist", resourceName, resourceGroup) + } + + return nil + } +} From 3340f61ac018a712935d44f2f7ce843033422f80 Mon Sep 17 00:00:00 2001 From: Junyi Yi Date: Thu, 27 Sep 2018 13:40:14 -0700 Subject: [PATCH 7/9] Add documentation of activity log alert. --- .../resource_arm_monitor_activitylog_alert.go | 14 +- website/azurerm.erb | 4 + .../r/monitor_activitylog_alert.html.markdown | 144 ++++++++++++++++++ 3 files changed, 159 insertions(+), 3 deletions(-) create mode 100644 website/docs/r/monitor_activitylog_alert.html.markdown diff --git a/azurerm/resource_arm_monitor_activitylog_alert.go b/azurerm/resource_arm_monitor_activitylog_alert.go index 7e89048af759..f6a74bd733f2 100644 --- a/azurerm/resource_arm_monitor_activitylog_alert.go +++ b/azurerm/resource_arm_monitor_activitylog_alert.go @@ -50,9 +50,17 @@ func resourceArmMonitorActivityLogAlert() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "category": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.NoZeroValues, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "Administrative", + "Autoscale", + "Policy", + "Recommendation", + "Security", + "Service Health", + }, true), + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, }, "operation_name": { Type: schema.TypeString, diff --git a/website/azurerm.erb b/website/azurerm.erb index 653c6839100f..7caa858ab92e 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -740,6 +740,10 @@ azurerm_monitor_action_group + > + azurerm_monitor_activitylog_alert + + > azurerm_autoscale_setting diff --git a/website/docs/r/monitor_activitylog_alert.html.markdown b/website/docs/r/monitor_activitylog_alert.html.markdown new file mode 100644 index 000000000000..87a43986dbde --- /dev/null +++ b/website/docs/r/monitor_activitylog_alert.html.markdown @@ -0,0 +1,144 @@ +--- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_monitor_activitylog_alert" +sidebar_current: "docs-azurerm-resource-monitor-activitylog-alert" +description: |- + Manages Azure monitor alerts on activity log +--- + +# azurerm_monitor_activitylog_alert + +Manages Azure monitor alerts on activity log. + +## Example Usage (Monitor all storage account updates in the current subscription) + +```hcl +resource "azurerm_resource_group" "main" { + name = "ActivityLogAlertTestRG" + location = "West US" +} + +resource "azurerm_monitor_action_group" "main" { + name = "ActivityLogAlertTestAction" + resource_group_name = "${azurerm_resource_group.main.name}" + short_name = "p0action" + + webhook_receiver { + name = "callmyapi" + service_uri = "http://example.com/alert" + } +} + +data "azurerm_client_config" "current" {} + +resource "azurerm_monitor_activitylog_alert" "main" { + name = "AppServiceStateTestActivityLog" + resource_group_name = "${azurerm_resource_group.main.name}" + scopes = ["/subscriptions/${data.azurerm_client_config.current.subscription_id}"] + description = "This alert will monitor all storage account updates in the subscription." + + criteria { + operation_name = "Microsoft.Storage/storageAccounts/write" + category = "Recommendation" + } + + action { + action_group_id = "${azurerm_monitor_action_group.main.id}" + } +} +``` + +## Example Usage (Monitor one specific storage account updates) + +```hcl +resource "azurerm_resource_group" "main" { + name = "ActivityLogAlertTestRG" + location = "West US" +} + +resource "azurerm_monitor_action_group" "main" { + name = "ActivityLogAlertTestAction" + resource_group_name = "${azurerm_resource_group.main.name}" + short_name = "p0action" + + webhook_receiver { + name = "callmyapi" + service_uri = "http://example.com/alert" + } +} + +resource "azurerm_storage_account" "to_monitor" { + name = "actlogtestmonitoredsa" + resource_group_name = "${azurerm_resource_group.main.name}" + location = "${azurerm_resource_group.main.location}" + account_tier = "Standard" + account_replication_type = "GRS" +} + +resource "azurerm_monitor_activitylog_alert" "main" { + name = "AppServiceStateTestActivityLog" + resource_group_name = "${azurerm_resource_group.main.name}" + scopes = ["${azurerm_resource_group.main.id}"] + description = "This alert will monitor a specific storage account updates." + + criteria { + resource_id = "${azurerm_storage_account.to_monitor.id}" + operation_name = "Microsoft.Storage/storageAccounts/write" + category = "Recommendation" + } + + action { + action_group_id = "${azurerm_monitor_action_group.main.id}" + + webhook_properties { + from = "terraform" + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the activity log alert. Changing this forces a new resource to be created. +* `resource_group_name` - (Required) The name of the resource group in which to create the activity log alert instance. +* `scopes` - (Required) The individual resource or set of resources for which the alert on activity log is defined. For example, a subscription ID, or a resource group ID. +* `criteria` - (Required) One and only one `criteria` block as defined below. The condition that will cause this alert to activate. +* `action` - (Required) One or more `action` blocks as defined below. The actions that will activate when the condition (defined through `criteria`) is met. +* `enabled` - (Optional) Whether this activity log alert is enabled. Defaults to `true`. +* `description` - (Optional) The description of this activity log alert. +* `tags` - (Optional) A mapping of tags to assign to the resource. + +--- + +`criteria` supports the following: + +* `category` - (Required) The category of the operation. Possible values are `Administrative`, `Autoscale`, `Policy`, `Recommendation`, `Security` and `Service Health`. +* `operation_name` - (Required) The Resource Manager Role-Based Access Control operation name. Supported operation should be of the form: `//`. +* `resource_id` - (Optional) The specific resource monitored by the activity log alert. It should be within one of the `scopes`. +* `caller` - (Optional) The email address or Azure Active Directory identifier of the user who performed the operation. +* `level` - (Optional) The severity level of the event. Possible values are `Verbose`, `Informational`, `Warning`, `Error`, and `Critical`. +* `status` - (Optional) The status of the event. for example, `Started`, `Failed`, or `Succeeded`. +* `sub_status` - (Optional) The sub status of the event. + +--- + +`action` supports the following: + +* `action_group_id` - (Required) The resource ID of an action group (`azurerm_monitor_action_group`). +* `webhook_properties` - (Optional) The map of custom string properties to include with the post operation. These data are appended to the webhook payload. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the activity log alert. + +## Import + +Activity log alerts can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_monitor_activitylog_alert.test /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/microsoft.insights/activityLogAlerts/myalertname +``` From 8cf3bf47f6b54a2b072cdcaf37b91805bd741ef0 Mon Sep 17 00:00:00 2001 From: Junyi Yi Date: Thu, 27 Sep 2018 14:30:51 -0700 Subject: [PATCH 8/9] Add update test case for activity log alert --- ...urce_arm_monitor_activitylog_alert_test.go | 83 ++++++++++++++++++- 1 file changed, 80 insertions(+), 3 deletions(-) diff --git a/azurerm/resource_arm_monitor_activitylog_alert_test.go b/azurerm/resource_arm_monitor_activitylog_alert_test.go index 760001f62dd3..eb1cf444f9f6 100644 --- a/azurerm/resource_arm_monitor_activitylog_alert_test.go +++ b/azurerm/resource_arm_monitor_activitylog_alert_test.go @@ -77,11 +77,11 @@ func TestAccAzureRMMonitorActivityLogAlert_singleResource(t *testing.T) { }) } -func TestAccAzureRMMonitorActivityLogAlert_full(t *testing.T) { +func TestAccAzureRMMonitorActivityLogAlert_complete(t *testing.T) { resourceName := "azurerm_monitor_activitylog_alert.test" ri := acctest.RandInt() rs := strings.ToLower(acctest.RandString(11)) - config := testAccAzureRMMonitorActivityLogAlert_full(ri, rs, testLocation()) + config := testAccAzureRMMonitorActivityLogAlert_complete(ri, rs, testLocation()) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -119,6 +119,83 @@ func TestAccAzureRMMonitorActivityLogAlert_full(t *testing.T) { }) } +func TestAccAzureRMMonitorActivityLogAlert_basicAndCompleteUpdate(t *testing.T) { + resourceName := "azurerm_monitor_activitylog_alert.test" + ri := acctest.RandInt() + rs := strings.ToLower(acctest.RandString(11)) + location := testLocation() + basicConfig := testAccAzureRMMonitorActivityLogAlert_basic(ri, location) + completeConfig := testAccAzureRMMonitorActivityLogAlert_complete(ri, rs, location) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMMonitorActionGroupDestroy, + Steps: []resource.TestStep{ + { + Config: basicConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMMonitorActivityLogAlertExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "scopes.#", "1"), + resource.TestCheckResourceAttr(resourceName, "criteria.#", "1"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.operation_name", "Microsoft.Storage/storageAccounts/write"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.category", "Recommendation"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.resource_id", ""), + resource.TestCheckResourceAttr(resourceName, "criteria.0.caller", ""), + resource.TestCheckResourceAttr(resourceName, "criteria.0.level", ""), + resource.TestCheckResourceAttr(resourceName, "criteria.0.status", ""), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "action.0.action_group_id"), + resource.TestCheckResourceAttr(resourceName, "action.0.webhook_properties.%", "0"), + ), + }, + { + Config: completeConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMMonitorActivityLogAlertExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "description", "This is just a test resource."), + resource.TestCheckResourceAttr(resourceName, "scopes.#", "2"), + resource.TestCheckResourceAttr(resourceName, "criteria.#", "1"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.operation_name", "Microsoft.Storage/storageAccounts/write"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.category", "Recommendation"), + resource.TestCheckResourceAttrSet(resourceName, "criteria.0.resource_id"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.caller", "user@example.com"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.level", "Error"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.status", "Failed"), + resource.TestCheckResourceAttr(resourceName, "action.#", "2"), + resource.TestCheckResourceAttrSet(resourceName, "action.0.action_group_id"), + resource.TestCheckResourceAttrSet(resourceName, "action.1.action_group_id"), + resource.TestCheckResourceAttr(resourceName, "action.1.webhook_properties.%", "2"), + resource.TestCheckResourceAttr(resourceName, "action.1.webhook_properties.from", "terraform test"), + resource.TestCheckResourceAttr(resourceName, "action.1.webhook_properties.to", "microsoft azure"), + ), + }, + { + Config: basicConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMMonitorActivityLogAlertExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "scopes.#", "1"), + resource.TestCheckResourceAttr(resourceName, "criteria.#", "1"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.operation_name", "Microsoft.Storage/storageAccounts/write"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.category", "Recommendation"), + resource.TestCheckResourceAttr(resourceName, "criteria.0.resource_id", ""), + resource.TestCheckResourceAttr(resourceName, "criteria.0.caller", ""), + resource.TestCheckResourceAttr(resourceName, "criteria.0.level", ""), + resource.TestCheckResourceAttr(resourceName, "criteria.0.status", ""), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "action.0.action_group_id"), + resource.TestCheckResourceAttr(resourceName, "action.0.webhook_properties.%", "0"), + ), + }, + }, + }) +} + func testAccAzureRMMonitorActivityLogAlert_basic(rInt int, location string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { @@ -188,7 +265,7 @@ resource "azurerm_monitor_activitylog_alert" "test" { `, rInt, location, rInt, rString, rInt) } -func testAccAzureRMMonitorActivityLogAlert_full(rInt int, rString, location string) string { +func testAccAzureRMMonitorActivityLogAlert_complete(rInt int, rString, location string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { name = "acctestRG-%d" From 3b8784182957f27d60799c4ba439af86cb4ecb35 Mon Sep 17 00:00:00 2001 From: Junyi Yi Date: Thu, 11 Oct 2018 17:28:09 -0700 Subject: [PATCH 9/9] ignore the empty element in action set --- ...resource_arm_monitor_activity_log_alert.go | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/azurerm/resource_arm_monitor_activity_log_alert.go b/azurerm/resource_arm_monitor_activity_log_alert.go index 3352a3ca0617..d93ad7839370 100644 --- a/azurerm/resource_arm_monitor_activity_log_alert.go +++ b/azurerm/resource_arm_monitor_activity_log_alert.go @@ -301,18 +301,19 @@ func expandMonitorActivityLogAlertAction(input []interface{}) *insights.Activity actions := make([]insights.ActivityLogAlertActionGroup, 0) for _, item := range input { v := item.(map[string]interface{}) - - props := make(map[string]*string) - if pVal, ok := v["webhook_properties"]; ok { - for pk, pv := range pVal.(map[string]interface{}) { - props[pk] = utils.String(pv.(string)) + if agID := v["action_group_id"].(string); agID != "" { + props := make(map[string]*string) + if pVal, ok := v["webhook_properties"]; ok { + for pk, pv := range pVal.(map[string]interface{}) { + props[pk] = utils.String(pv.(string)) + } } - } - actions = append(actions, insights.ActivityLogAlertActionGroup{ - ActionGroupID: utils.String(v["action_group_id"].(string)), - WebhookProperties: props, - }) + actions = append(actions, insights.ActivityLogAlertActionGroup{ + ActionGroupID: utils.String(agID), + WebhookProperties: props, + }) + } } return &insights.ActivityLogAlertActionList{ ActionGroups: &actions,