diff --git a/azurerm/internal/services/monitor/client/client.go b/azurerm/internal/services/monitor/client/client.go index 2b846aa811ba..15a3ddd0734a 100644 --- a/azurerm/internal/services/monitor/client/client.go +++ b/azurerm/internal/services/monitor/client/client.go @@ -17,6 +17,7 @@ type Client struct { DiagnosticSettingsCategoryClient *insights.DiagnosticSettingsCategoryClient LogProfilesClient *insights.LogProfilesClient MetricAlertsClient *insights.MetricAlertsClient + ScheduledQueryRulesClient *insights.ScheduledQueryRulesClient } func NewClient(o *common.ClientOptions) *Client { @@ -44,6 +45,9 @@ func NewClient(o *common.ClientOptions) *Client { MetricAlertsClient := insights.NewMetricAlertsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&MetricAlertsClient.Client, o.ResourceManagerAuthorizer) + ScheduledQueryRulesClient := insights.NewScheduledQueryRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&ScheduledQueryRulesClient.Client, o.ResourceManagerAuthorizer) + return &Client{ AutoscaleSettingsClient: &AutoscaleSettingsClient, ActionGroupsClient: &ActionGroupsClient, @@ -53,5 +57,6 @@ func NewClient(o *common.ClientOptions) *Client { DiagnosticSettingsCategoryClient: &DiagnosticSettingsCategoryClient, LogProfilesClient: &LogProfilesClient, MetricAlertsClient: &MetricAlertsClient, + ScheduledQueryRulesClient: &ScheduledQueryRulesClient, } } diff --git a/azurerm/internal/services/monitor/common_monitor.go b/azurerm/internal/services/monitor/common_monitor.go new file mode 100644 index 000000000000..0754ff8aa411 --- /dev/null +++ b/azurerm/internal/services/monitor/common_monitor.go @@ -0,0 +1,138 @@ +package monitor + +import ( + "fmt" + + "github.com/Azure/azure-sdk-for-go/services/preview/monitor/mgmt/2019-06-01/insights" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func flattenAzureRmScheduledQueryRulesAlertAction(input *insights.AzNsActionGroup) []interface{} { + v := make(map[string]interface{}) + + if input != nil { + if input.ActionGroup != nil { + v["action_group"] = *input.ActionGroup + } + v["email_subject"] = input.EmailSubject + v["custom_webhook_payload"] = input.CustomWebhookPayload + } + return []interface{}{v} +} + +func expandMonitorScheduledQueryRulesCommonSource(d *schema.ResourceData) *insights.Source { + authorizedResourceIDs := d.Get("authorized_resource_ids").(*schema.Set).List() + dataSourceID := d.Get("data_source_id").(string) + query, ok := d.GetOk("query") + source := insights.Source{ + AuthorizedResources: utils.ExpandStringSlice(authorizedResourceIDs), + DataSourceID: utils.String(dataSourceID), + QueryType: insights.ResultCount, + } + if ok { + source.Query = utils.String(query.(string)) + } + + return &source +} + +func flattenAzureRmScheduledQueryRulesAlertMetricTrigger(input *insights.LogMetricTrigger) []interface{} { + result := make(map[string]interface{}) + + if input == nil { + return []interface{}{} + } + + result["operator"] = string(input.ThresholdOperator) + + if input.Threshold != nil { + result["threshold"] = *input.Threshold + } + + result["metric_trigger_type"] = string(input.MetricTriggerType) + + if input.MetricColumn != nil { + result["metric_column"] = *input.MetricColumn + } + return []interface{}{result} +} + +func flattenAzureRmScheduledQueryRulesAlertTrigger(input *insights.TriggerCondition) []interface{} { + result := make(map[string]interface{}) + + result["operator"] = string(input.ThresholdOperator) + + if input.Threshold != nil { + result["threshold"] = *input.Threshold + } + + if input.MetricTrigger != nil { + result["metric_trigger"] = flattenAzureRmScheduledQueryRulesAlertMetricTrigger(input.MetricTrigger) + } + + return []interface{}{result} +} + +func flattenAzureRmScheduledQueryRulesLogCriteria(input *[]insights.Criteria) []interface{} { + result := make([]interface{}, 0) + + if input != nil { + for _, criteria := range *input { + v := make(map[string]interface{}) + + v["dimension"] = flattenAzureRmScheduledQueryRulesLogDimension(criteria.Dimensions) + v["metric_name"] = *criteria.MetricName + + result = append(result, v) + } + } + + return result +} + +func flattenAzureRmScheduledQueryRulesLogDimension(input *[]insights.Dimension) []interface{} { + result := make([]interface{}, 0) + + if input != nil { + for _, dimension := range *input { + v := make(map[string]interface{}) + + if dimension.Name != nil { + v["name"] = *dimension.Name + } + + if dimension.Operator != nil { + v["operator"] = *dimension.Operator + } + + if dimension.Values != nil { + v["values"] = *dimension.Values + } + + result = append(result, v) + } + } + + return result +} + +// ValidateThreshold checks that a threshold value is between 0 and 10000 +// and is a whole number. The azure-sdk-for-go expects this value to be a float64 +// but the user validation rules want an integer. +func validateMonitorScheduledQueryRulesAlertThreshold(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(float64) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %q to be float64", k)) + } + + if v != float64(int64(v)) { + errors = append(errors, fmt.Errorf("%q must be a whole number", k)) + } + + if v < 0 || v > 10000 { + errors = append(errors, fmt.Errorf("%q must be between 0 and 10000 (inclusive)", k)) + } + + return warnings, errors +} diff --git a/azurerm/internal/services/monitor/data_source_monitor_scheduled_query_rules_alert.go b/azurerm/internal/services/monitor/data_source_monitor_scheduled_query_rules_alert.go new file mode 100644 index 000000000000..44e6634a01d9 --- /dev/null +++ b/azurerm/internal/services/monitor/data_source_monitor_scheduled_query_rules_alert.go @@ -0,0 +1,218 @@ +package monitor + +import ( + "fmt" + "strconv" + "time" + + "github.com/Azure/azure-sdk-for-go/services/preview/monitor/mgmt/2019-06-01/insights" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func dataSourceArmMonitorScheduledQueryRulesAlert() *schema.Resource { + return &schema.Resource{ + Read: dataSourceArmMonitorScheduledQueryRulesAlertRead, + + Timeouts: &schema.ResourceTimeout{ + Read: schema.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + + "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), + + "location": azure.SchemaLocationForDataSource(), + + "authorized_resource_ids": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "action": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action_group": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "custom_webhook_payload": { + Type: schema.TypeString, + Computed: true, + }, + "email_subject": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "data_source_id": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "frequency": { + Type: schema.TypeInt, + Computed: true, + }, + "query": { + Type: schema.TypeString, + Computed: true, + }, + "query_type": { + Type: schema.TypeString, + Computed: true, + }, + "severity": { + Type: schema.TypeInt, + Computed: true, + }, + "throttling": { + Type: schema.TypeInt, + Computed: true, + }, + "time_window": { + Type: schema.TypeInt, + Computed: true, + }, + "trigger": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metric_trigger": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metric_column": { + Type: schema.TypeString, + Computed: true, + }, + "metric_trigger_type": { + Type: schema.TypeString, + Computed: true, + }, + "operator": { + Type: schema.TypeString, + Computed: true, + }, + "threshold": { + Type: schema.TypeFloat, + Computed: true, + }, + }, + }, + }, + "operator": { + Type: schema.TypeString, + Computed: true, + }, + "threshold": { + Type: schema.TypeFloat, + Computed: true, + }, + }, + }, + }, + + "tags": tags.SchemaDataSource(), + }, + } +} + +func dataSourceArmMonitorScheduledQueryRulesAlertRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Monitor.ScheduledQueryRulesClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + resourceGroup := d.Get("resource_group_name").(string) + name := d.Get("name").(string) + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("[DEBUG] Scheduled Query Rule %q was not found in Resource Group %q: %+v", name, resourceGroup, err) + } + return fmt.Errorf("Error getting Scheduled Query Rule %q (resource group %q): %+v", name, resourceGroup, err) + } + + d.SetId(*resp.ID) + + d.Set("name", name) + d.Set("resource_group_name", resourceGroup) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + + d.Set("description", resp.Description) + if resp.Enabled == insights.True { + d.Set("enabled", true) + } else { + d.Set("enabled", false) + } + + action, ok := resp.Action.(insights.AlertingAction) + if !ok { + return fmt.Errorf("Wrong action type in Scheduled Query Rule %q (resource group %q): %T", name, resourceGroup, resp.Action) + } + if err = d.Set("action", flattenAzureRmScheduledQueryRulesAlertAction(action.AznsAction)); err != nil { + return fmt.Errorf("Error setting `action`: %+v", err) + } + severity, err := strconv.Atoi(string(action.Severity)) + if err != nil { + return fmt.Errorf("Error converting action.Severity %q in query rule %q to int (resource group %q): %+v", action.Severity, name, resourceGroup, err) + } + d.Set("severity", severity) + d.Set("throttling", action.ThrottlingInMin) + if err = d.Set("trigger", flattenAzureRmScheduledQueryRulesAlertTrigger(action.Trigger)); err != nil { + return fmt.Errorf("Error setting `trigger`: %+v", err) + } + + if schedule := resp.Schedule; schedule != nil { + if schedule.FrequencyInMinutes != nil { + d.Set("frequency", schedule.FrequencyInMinutes) + } + if schedule.TimeWindowInMinutes != nil { + d.Set("time_window", schedule.TimeWindowInMinutes) + } + } + + if source := resp.Source; source != nil { + if source.AuthorizedResources != nil { + d.Set("authorized_resource_ids", utils.FlattenStringSlice(source.AuthorizedResources)) + } + if source.DataSourceID != nil { + d.Set("data_source_id", source.DataSourceID) + } + if source.Query != nil { + d.Set("query", source.Query) + } + d.Set("query_type", string(source.QueryType)) + } + + return tags.FlattenAndSet(d, resp.Tags) +} diff --git a/azurerm/internal/services/monitor/data_source_monitor_scheduled_query_rules_log.go b/azurerm/internal/services/monitor/data_source_monitor_scheduled_query_rules_log.go new file mode 100644 index 000000000000..3710667bcf8d --- /dev/null +++ b/azurerm/internal/services/monitor/data_source_monitor_scheduled_query_rules_log.go @@ -0,0 +1,152 @@ +package monitor + +import ( + "fmt" + "time" + + "github.com/Azure/azure-sdk-for-go/services/preview/monitor/mgmt/2019-06-01/insights" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func dataSourceArmMonitorScheduledQueryRulesLog() *schema.Resource { + return &schema.Resource{ + Read: dataSourceArmMonitorScheduledQueryRulesLogRead, + + Timeouts: &schema.ResourceTimeout{ + Read: schema.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + + "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), + + "location": azure.SchemaLocationForDataSource(), + + "authorized_resource_ids": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "criteria": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dimension": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "operator": { + Type: schema.TypeString, + Computed: true, + }, + "values": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "metric_name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "data_source_id": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "enabled": { + Type: schema.TypeBool, + Computed: true, + }, + + "tags": tags.SchemaDataSource(), + }, + } +} + +func dataSourceArmMonitorScheduledQueryRulesLogRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Monitor.ScheduledQueryRulesClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + resourceGroup := d.Get("resource_group_name").(string) + name := d.Get("name").(string) + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("[DEBUG] Scheduled Query Rule %q was not found in Resource Group %q: %+v", name, resourceGroup, err) + } + return fmt.Errorf("Error getting Scheduled Query Rule %q (resource group %q): %+v", name, resourceGroup, err) + } + + d.SetId(*resp.ID) + + d.Set("name", name) + d.Set("resource_group_name", resourceGroup) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + + d.Set("description", resp.Description) + if resp.Enabled == insights.True { + d.Set("enabled", true) + } else { + d.Set("enabled", false) + } + + action, ok := resp.Action.(insights.LogToMetricAction) + if !ok { + return fmt.Errorf("Wrong action type in Scheduled Query Rule %q (resource group %q): %T", name, resourceGroup, resp.Action) + } + if err = d.Set("criteria", flattenAzureRmScheduledQueryRulesLogCriteria(action.Criteria)); err != nil { + return fmt.Errorf("Error setting `criteria`: %+v", err) + } + + if schedule := resp.Schedule; schedule != nil { + if schedule.FrequencyInMinutes != nil { + d.Set("frequency", schedule.FrequencyInMinutes) + } + if schedule.TimeWindowInMinutes != nil { + d.Set("time_window", schedule.TimeWindowInMinutes) + } + } + + if source := resp.Source; source != nil { + if source.AuthorizedResources != nil { + d.Set("authorized_resource_ids", utils.FlattenStringSlice(source.AuthorizedResources)) + } + if source.DataSourceID != nil { + d.Set("data_source_id", source.DataSourceID) + } + } + + return tags.FlattenAndSet(d, resp.Tags) +} diff --git a/azurerm/internal/services/monitor/registration.go b/azurerm/internal/services/monitor/registration.go index b1ccab0aef1a..09676940ddb3 100644 --- a/azurerm/internal/services/monitor/registration.go +++ b/azurerm/internal/services/monitor/registration.go @@ -21,18 +21,22 @@ func (r Registration) WebsiteCategories() []string { // SupportedDataSources returns the supported Data Sources supported by this Service func (r Registration) SupportedDataSources() map[string]*schema.Resource { return map[string]*schema.Resource{ - "azurerm_monitor_action_group": dataSourceArmMonitorActionGroup(), - "azurerm_monitor_diagnostic_categories": dataSourceArmMonitorDiagnosticCategories(), - "azurerm_monitor_log_profile": dataSourceArmMonitorLogProfile()} + "azurerm_monitor_action_group": dataSourceArmMonitorActionGroup(), + "azurerm_monitor_diagnostic_categories": dataSourceArmMonitorDiagnosticCategories(), + "azurerm_monitor_log_profile": dataSourceArmMonitorLogProfile(), + "azurerm_monitor_scheduled_query_rules_alert": dataSourceArmMonitorScheduledQueryRulesAlert(), + "azurerm_monitor_scheduled_query_rules_log": dataSourceArmMonitorScheduledQueryRulesLog()} } // SupportedResources returns the supported Resources supported by this Service func (r Registration) SupportedResources() map[string]*schema.Resource { return map[string]*schema.Resource{ - "azurerm_monitor_autoscale_setting": resourceArmMonitorAutoScaleSetting(), - "azurerm_monitor_action_group": resourceArmMonitorActionGroup(), - "azurerm_monitor_activity_log_alert": resourceArmMonitorActivityLogAlert(), - "azurerm_monitor_diagnostic_setting": resourceArmMonitorDiagnosticSetting(), - "azurerm_monitor_log_profile": resourceArmMonitorLogProfile(), - "azurerm_monitor_metric_alert": resourceArmMonitorMetricAlert()} + "azurerm_monitor_autoscale_setting": resourceArmMonitorAutoScaleSetting(), + "azurerm_monitor_action_group": resourceArmMonitorActionGroup(), + "azurerm_monitor_activity_log_alert": resourceArmMonitorActivityLogAlert(), + "azurerm_monitor_diagnostic_setting": resourceArmMonitorDiagnosticSetting(), + "azurerm_monitor_log_profile": resourceArmMonitorLogProfile(), + "azurerm_monitor_metric_alert": resourceArmMonitorMetricAlert(), + "azurerm_monitor_scheduled_query_rules_alert": resourceArmMonitorScheduledQueryRulesAlert(), + "azurerm_monitor_scheduled_query_rules_log": resourceArmMonitorScheduledQueryRulesLog()} } diff --git a/azurerm/internal/services/monitor/resource_arm_monitor_scheduled_query_rules_alert.go b/azurerm/internal/services/monitor/resource_arm_monitor_scheduled_query_rules_alert.go new file mode 100644 index 000000000000..e8ad5526e7c4 --- /dev/null +++ b/azurerm/internal/services/monitor/resource_arm_monitor_scheduled_query_rules_alert.go @@ -0,0 +1,484 @@ +package monitor + +import ( + "fmt" + "log" + "strconv" + "strings" + "time" + + "github.com/Azure/azure-sdk-for-go/services/preview/monitor/mgmt/2019-06-01/insights" + "github.com/hashicorp/go-azure-helpers/response" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmMonitorScheduledQueryRulesAlert() *schema.Resource { + return &schema.Resource{ + Create: resourceArmMonitorScheduledQueryRulesAlertCreateUpdate, + Read: resourceArmMonitorScheduledQueryRulesAlertRead, + Update: resourceArmMonitorScheduledQueryRulesAlertCreateUpdate, + Delete: resourceArmMonitorScheduledQueryRulesAlertDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringDoesNotContainAny("<>*%&:\\?+/"), + }, + + "resource_group_name": azure.SchemaResourceGroupName(), + + "location": azure.SchemaLocation(), + + "authorized_resource_ids": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 100, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: azure.ValidateResourceID, + }, + }, + "action": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action_group": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: azure.ValidateResourceID, + }, + }, + "custom_webhook_payload": { + Type: schema.TypeString, + Optional: true, + Default: "{}", + ValidateFunc: validation.StringIsJSON, + }, + "email_subject": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + "data_source_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: azure.ValidateResourceID, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 4096), + }, + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "frequency": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(5, 1440), + }, + "query": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "query_type": { + Type: schema.TypeString, + Optional: true, + Default: "ResultCount", + ValidateFunc: validation.StringInSlice([]string{ + "ResultCount", + }, false), + }, + "severity": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(0, 4), + }, + "throttling": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(0, 10000), + }, + "time_window": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(5, 2880), + }, + "trigger": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metric_trigger": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metric_column": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "metric_trigger_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "Consecutive", + "Total", + }, false), + }, + "operator": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "GreaterThan", + "LessThan", + "Equal", + }, false), + }, + "threshold": { + Type: schema.TypeFloat, + Required: true, + ValidateFunc: validateMonitorScheduledQueryRulesAlertThreshold, + }, + }, + }, + }, + "operator": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "GreaterThan", + "LessThan", + "Equal", + }, false), + }, + "threshold": { + Type: schema.TypeFloat, + Required: true, + ValidateFunc: validateMonitorScheduledQueryRulesAlertThreshold, + }, + }, + }, + }, + + "tags": tags.Schema(), + }, + } +} + +func resourceArmMonitorScheduledQueryRulesAlertCreateUpdate(d *schema.ResourceData, meta interface{}) error { + action := expandMonitorScheduledQueryRulesAlertingAction(d) + schedule := expandMonitorScheduledQueryRulesAlertSchedule(d) + client := meta.(*clients.Client).Monitor.ScheduledQueryRulesClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group_name").(string) + + frequency := d.Get("frequency").(int) + timeWindow := d.Get("time_window").(int) + if timeWindow < frequency { + return fmt.Errorf("Error in parameter values for Scheduled Query Rules %q (Resource Group %q): time_window must be greater than or equal to frequency", name, resourceGroup) + } + + query := d.Get("query").(string) + _, ok := d.GetOk("metric_trigger") + if ok { + if !(strings.Contains(query, "summarize") && + strings.Contains(query, "AggregatedValue") && + strings.Contains(query, "bin")) { + return fmt.Errorf("Error in parameter values for Scheduled Query Rules %q (Resource Group %q): query must contain summarize, AggregatedValue, and bin when metric_trigger is specified", name, resourceGroup) + } + } + + if features.ShouldResourcesBeImported() && d.IsNewResource() { + existing, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("Error checking for presence of existing Monitor Scheduled Query Rules %q (Resource Group %q): %s", name, resourceGroup, err) + } + } + + if existing.ID != nil && *existing.ID != "" { + return tf.ImportAsExistsError("azurerm_monitor_scheduled_query_rules_alert", *existing.ID) + } + } + + description := d.Get("description").(string) + enabledRaw := d.Get("enabled").(bool) + + enabled := insights.True + if !enabledRaw { + enabled = insights.False + } + + location := azure.NormalizeLocation(d.Get("location")) + + source := expandMonitorScheduledQueryRulesCommonSource(d) + + t := d.Get("tags").(map[string]interface{}) + expandedTags := tags.Expand(t) + + parameters := insights.LogSearchRuleResource{ + Location: utils.String(location), + LogSearchRule: &insights.LogSearchRule{ + Description: utils.String(description), + Enabled: enabled, + Source: source, + Schedule: schedule, + Action: action, + }, + Tags: expandedTags, + } + + if _, err := client.CreateOrUpdate(ctx, resourceGroup, name, parameters); err != nil { + return fmt.Errorf("Error creating or updating Scheduled Query Rule %q (resource group %q): %+v", name, resourceGroup, err) + } + + read, err := client.Get(ctx, resourceGroup, name) + if err != nil { + return err + } + if read.ID == nil { + return fmt.Errorf("Scheduled query rule %q (resource group %q) ID is empty", name, resourceGroup) + } + d.SetId(*read.ID) + + return resourceArmMonitorScheduledQueryRulesAlertRead(d, meta) +} + +func resourceArmMonitorScheduledQueryRulesAlertRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Monitor.ScheduledQueryRulesClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroup := id.ResourceGroup + name := id.Path["scheduledqueryrules"] + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[DEBUG] Scheduled Query Rule %q was not found in Resource Group %q", name, resourceGroup) + d.SetId("") + return nil + } + return fmt.Errorf("Error getting Scheduled Query Rule %q (resource group %q): %+v", name, resourceGroup, err) + } + + d.Set("name", name) + d.Set("resource_group_name", resourceGroup) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + + d.Set("description", resp.Description) + if resp.Enabled == insights.True { + d.Set("enabled", true) + } else { + d.Set("enabled", false) + } + + action, ok := resp.Action.(insights.AlertingAction) + if !ok { + return fmt.Errorf("Wrong action type in Scheduled Query Rule %q (resource group %q): %T", name, resourceGroup, resp.Action) + } + if err = d.Set("action", flattenAzureRmScheduledQueryRulesAlertAction(action.AznsAction)); err != nil { + return fmt.Errorf("Error setting `action`: %+v", err) + } + severity, err := strconv.Atoi(string(action.Severity)) + if err != nil { + return fmt.Errorf("Error converting action.Severity %q in query rule %q to int (resource group %q): %+v", action.Severity, name, resourceGroup, err) + } + d.Set("severity", severity) + d.Set("throttling", action.ThrottlingInMin) + if err = d.Set("trigger", flattenAzureRmScheduledQueryRulesAlertTrigger(action.Trigger)); err != nil { + return fmt.Errorf("Error setting `trigger`: %+v", err) + } + + if schedule := resp.Schedule; schedule != nil { + if schedule.FrequencyInMinutes != nil { + d.Set("frequency", schedule.FrequencyInMinutes) + } + if schedule.TimeWindowInMinutes != nil { + d.Set("time_window", schedule.TimeWindowInMinutes) + } + } + + if source := resp.Source; source != nil { + if source.AuthorizedResources != nil { + d.Set("authorized_resource_ids", utils.FlattenStringSlice(source.AuthorizedResources)) + } + if source.DataSourceID != nil { + d.Set("data_source_id", source.DataSourceID) + } + if source.Query != nil { + d.Set("query", source.Query) + } + d.Set("query_type", string(source.QueryType)) + } + + return tags.FlattenAndSet(d, resp.Tags) +} + +func resourceArmMonitorScheduledQueryRulesAlertDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Monitor.ScheduledQueryRulesClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroup := id.ResourceGroup + name := id.Path["scheduledqueryrules"] + + if resp, err := client.Delete(ctx, resourceGroup, name); err != nil { + if !response.WasNotFound(resp.Response) { + return fmt.Errorf("Error deleting Scheduled Query Rule %q (resource group %q): %+v", name, resourceGroup, err) + } + } + + return nil +} + +func expandMonitorScheduledQueryRulesAlertingAction(d *schema.ResourceData) *insights.AlertingAction { + alertActionRaw := d.Get("action").([]interface{}) + alertAction := expandMonitorScheduledQueryRulesAlertAction(alertActionRaw) + severityRaw := d.Get("severity").(int) + severity := strconv.Itoa(severityRaw) + throttling := d.Get("throttling").(int) + + triggerRaw := d.Get("trigger").([]interface{}) + trigger := expandMonitorScheduledQueryRulesAlertTrigger(triggerRaw) + + action := insights.AlertingAction{ + AznsAction: alertAction, + Severity: insights.AlertSeverity(severity), + ThrottlingInMin: utils.Int32(int32(throttling)), + Trigger: trigger, + OdataType: insights.OdataTypeMicrosoftWindowsAzureManagementMonitoringAlertsModelsMicrosoftAppInsightsNexusDataContractsResourcesScheduledQueryRulesAlertingAction, + } + + return &action +} + +func expandMonitorScheduledQueryRulesAlertAction(input []interface{}) *insights.AzNsActionGroup { + result := insights.AzNsActionGroup{} + + if len(input) == 0 { + return &result + } + for _, item := range input { + if item == nil { + continue + } + + v, ok := item.(map[string]interface{}) + if !ok { + continue + } + actionGroups := v["action_group"].(*schema.Set).List() + result.ActionGroup = utils.ExpandStringSlice(actionGroups) + result.EmailSubject = utils.String(v["email_subject"].(string)) + result.CustomWebhookPayload = utils.String(v["custom_webhook_payload"].(string)) + } + + return &result +} + +func expandMonitorScheduledQueryRulesAlertMetricTrigger(input []interface{}) *insights.LogMetricTrigger { + if len(input) == 0 { + return nil + } + + result := insights.LogMetricTrigger{} + for _, item := range input { + if item == nil { + continue + } + v, ok := item.(map[string]interface{}) + if !ok { + continue + } + result.ThresholdOperator = insights.ConditionalOperator(v["operator"].(string)) + result.Threshold = utils.Float(v["threshold"].(float64)) + result.MetricTriggerType = insights.MetricTriggerType(v["metric_trigger_type"].(string)) + result.MetricColumn = utils.String(v["metric_column"].(string)) + } + + return &result +} + +func expandMonitorScheduledQueryRulesAlertSchedule(d *schema.ResourceData) *insights.Schedule { + frequency := d.Get("frequency").(int) + timeWindow := d.Get("time_window").(int) + + schedule := insights.Schedule{ + FrequencyInMinutes: utils.Int32(int32(frequency)), + TimeWindowInMinutes: utils.Int32(int32(timeWindow)), + } + + return &schedule +} + +func expandMonitorScheduledQueryRulesAlertTrigger(input []interface{}) *insights.TriggerCondition { + result := insights.TriggerCondition{} + if len(input) == 0 { + return &result + } + + for _, item := range input { + if item == nil { + continue + } + v, ok := item.(map[string]interface{}) + if !ok { + continue + } + metricTriggerRaw := v["metric_trigger"].([]interface{}) + + result.ThresholdOperator = insights.ConditionalOperator(v["operator"].(string)) + result.Threshold = utils.Float(v["threshold"].(float64)) + result.MetricTrigger = expandMonitorScheduledQueryRulesAlertMetricTrigger(metricTriggerRaw) + } + + return &result +} diff --git a/azurerm/internal/services/monitor/resource_arm_monitor_scheduled_query_rules_log.go b/azurerm/internal/services/monitor/resource_arm_monitor_scheduled_query_rules_log.go new file mode 100644 index 000000000000..4efacb839a5a --- /dev/null +++ b/azurerm/internal/services/monitor/resource_arm_monitor_scheduled_query_rules_log.go @@ -0,0 +1,313 @@ +package monitor + +import ( + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/preview/monitor/mgmt/2019-06-01/insights" + "github.com/hashicorp/go-azure-helpers/response" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmMonitorScheduledQueryRulesLog() *schema.Resource { + return &schema.Resource{ + Create: resourceArmMonitorScheduledQueryRulesLogCreateUpdate, + Read: resourceArmMonitorScheduledQueryRulesLogRead, + Update: resourceArmMonitorScheduledQueryRulesLogCreateUpdate, + Delete: resourceArmMonitorScheduledQueryRulesLogDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringDoesNotContainAny("<>*%&:\\?+/"), + }, + + "resource_group_name": azure.SchemaResourceGroupName(), + + "location": azure.SchemaLocation(), + + "authorized_resource_ids": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: azure.ValidateResourceID, + }, + }, + + "criteria": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dimension": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "operator": { + Type: schema.TypeString, + Optional: true, + Default: "Include", + ValidateFunc: validation.StringInSlice([]string{ + "Include", + }, false), + }, + "values": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + }, + "metric_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + "data_source_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: azure.ValidateResourceID, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 4096), + }, + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + + "tags": tags.Schema(), + }, + } +} + +func resourceArmMonitorScheduledQueryRulesLogCreateUpdate(d *schema.ResourceData, meta interface{}) error { + action := expandMonitorScheduledQueryRulesLogToMetricAction(d) + + client := meta.(*clients.Client).Monitor.ScheduledQueryRulesClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group_name").(string) + + if features.ShouldResourcesBeImported() && d.IsNewResource() { + existing, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("Error checking for presence of existing Monitor Scheduled Query Rules %q (Resource Group %q): %s", name, resourceGroup, err) + } + } + + if existing.ID != nil && *existing.ID != "" { + return tf.ImportAsExistsError("azurerm_monitor_scheduled_query_rules_alert", *existing.ID) + } + } + + description := d.Get("description").(string) + enabledRaw := d.Get("enabled").(bool) + + enabled := insights.True + if !enabledRaw { + enabled = insights.False + } + + location := azure.NormalizeLocation(d.Get("location")) + + source := expandMonitorScheduledQueryRulesCommonSource(d) + + t := d.Get("tags").(map[string]interface{}) + expandedTags := tags.Expand(t) + + parameters := insights.LogSearchRuleResource{ + Location: utils.String(location), + LogSearchRule: &insights.LogSearchRule{ + Description: utils.String(description), + Enabled: enabled, + Source: source, + Action: action, + }, + Tags: expandedTags, + } + + if _, err := client.CreateOrUpdate(ctx, resourceGroup, name, parameters); err != nil { + return fmt.Errorf("Error creating or updating Scheduled Query Rule %q (resource group %q): %+v", name, resourceGroup, err) + } + + read, err := client.Get(ctx, resourceGroup, name) + if err != nil { + return err + } + if read.ID == nil { + return fmt.Errorf("Scheduled query rule %q (resource group %q) ID is empty", name, resourceGroup) + } + d.SetId(*read.ID) + + return resourceArmMonitorScheduledQueryRulesLogRead(d, meta) +} + +func resourceArmMonitorScheduledQueryRulesLogRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Monitor.ScheduledQueryRulesClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroup := id.ResourceGroup + name := id.Path["scheduledqueryrules"] + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[DEBUG] Scheduled Query Rule %q was not found in Resource Group %q", name, resourceGroup) + d.SetId("") + return nil + } + return fmt.Errorf("Error getting Scheduled Query Rule %q (resource group %q): %+v", name, resourceGroup, err) + } + + d.Set("name", name) + d.Set("resource_group_name", resourceGroup) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + + d.Set("description", resp.Description) + if resp.Enabled == insights.True { + d.Set("enabled", true) + } else { + d.Set("enabled", false) + } + + action, ok := resp.Action.(insights.LogToMetricAction) + if !ok { + return fmt.Errorf("Wrong action type in Scheduled Query Rule %q (resource group %q): %T", name, resourceGroup, resp.Action) + } + if err = d.Set("criteria", flattenAzureRmScheduledQueryRulesLogCriteria(action.Criteria)); err != nil { + return fmt.Errorf("Error setting `criteria`: %+v", err) + } + + if source := resp.Source; source != nil { + if source.AuthorizedResources != nil { + d.Set("authorized_resource_ids", utils.FlattenStringSlice(source.AuthorizedResources)) + } + if source.DataSourceID != nil { + d.Set("data_source_id", source.DataSourceID) + } + } + + return tags.FlattenAndSet(d, resp.Tags) +} + +func resourceArmMonitorScheduledQueryRulesLogDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Monitor.ScheduledQueryRulesClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroup := id.ResourceGroup + name := id.Path["scheduledqueryrules"] + + if resp, err := client.Delete(ctx, resourceGroup, name); err != nil { + if !response.WasNotFound(resp.Response) { + return fmt.Errorf("Error deleting Scheduled Query Rule %q (resource group %q): %+v", name, resourceGroup, err) + } + } + + return nil +} + +func expandMonitorScheduledQueryRulesLogCriteria(input []interface{}) *[]insights.Criteria { + criteria := make([]insights.Criteria, 0) + if len(input) == 0 { + return &criteria + } + + for _, item := range input { + if item == nil { + continue + } + v, ok := item.(map[string]interface{}) + if !ok { + continue + } + + dimensions := make([]insights.Dimension, 0) + for _, dimension := range v["dimension"].(*schema.Set).List() { + if dimension == nil { + continue + } + dVal, ok := dimension.(map[string]interface{}) + if !ok { + continue + } + dimensions = append(dimensions, insights.Dimension{ + Name: utils.String(dVal["name"].(string)), + Operator: utils.String(dVal["operator"].(string)), + Values: utils.ExpandStringSlice(dVal["values"].([]interface{})), + }) + } + + criteria = append(criteria, insights.Criteria{ + MetricName: utils.String(v["metric_name"].(string)), + Dimensions: &dimensions, + }) + } + return &criteria +} + +func expandMonitorScheduledQueryRulesLogToMetricAction(d *schema.ResourceData) *insights.LogToMetricAction { + criteriaRaw := d.Get("criteria").([]interface{}) + criteria := expandMonitorScheduledQueryRulesLogCriteria(criteriaRaw) + + action := insights.LogToMetricAction{ + Criteria: criteria, + OdataType: insights.OdataTypeMicrosoftWindowsAzureManagementMonitoringAlertsModelsMicrosoftAppInsightsNexusDataContractsResourcesScheduledQueryRulesLogToMetricAction, + } + + return &action +} diff --git a/azurerm/internal/services/monitor/tests/data_source_monitor_scheduled_query_rules_alert_test.go b/azurerm/internal/services/monitor/tests/data_source_monitor_scheduled_query_rules_alert_test.go new file mode 100644 index 000000000000..382002fc4d03 --- /dev/null +++ b/azurerm/internal/services/monitor/tests/data_source_monitor_scheduled_query_rules_alert_test.go @@ -0,0 +1,70 @@ +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" +) + +func TestAccDataSourceAzureRMMonitorScheduledQueryRules_AlertingAction(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_monitor_scheduled_query_rules_alert", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAzureRMMonitorScheduledQueryRules_AlertingActionConfig(data), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(data.ResourceName, "id"), + ), + }, + }, + }) +} + +func TestAccDataSourceAzureRMMonitorScheduledQueryRules_AlertingActionCrossResource(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_monitor_scheduled_query_rules_alert", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAzureRMMonitorScheduledQueryRules_AlertingActionCrossResourceConfig(data), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(data.ResourceName, "id"), + ), + }, + }, + }) +} + +func testAccDataSourceAzureRMMonitorScheduledQueryRules_AlertingActionConfig(data acceptance.TestData) string { + ts := time.Now().Format(time.RFC3339) + template := testAccAzureRMMonitorScheduledQueryRules_AlertingActionConfigBasic(data, ts) + + return fmt.Sprintf(` +%s + +data "azurerm_monitor_scheduled_query_rules_alert" "test" { + name = basename(azurerm_monitor_scheduled_query_rules_alert.test.id) + resource_group_name = "${azurerm_resource_group.test.name}" +} +`, template) +} + +func testAccDataSourceAzureRMMonitorScheduledQueryRules_AlertingActionCrossResourceConfig(data acceptance.TestData) string { + template := testAccAzureRMMonitorScheduledQueryRules_AlertingActionCrossResourceConfig(data) + return fmt.Sprintf(` +%s + +data "azurerm_monitor_scheduled_query_rules_alert" "test" { + name = basename(azurerm_monitor_scheduled_query_rules_alert.test.id) + resource_group_name = "${azurerm_resource_group.test.name}" +} +`, template) +} diff --git a/azurerm/internal/services/monitor/tests/data_source_monitor_scheduled_query_rules_log_test.go b/azurerm/internal/services/monitor/tests/data_source_monitor_scheduled_query_rules_log_test.go new file mode 100644 index 000000000000..6c23137eb96f --- /dev/null +++ b/azurerm/internal/services/monitor/tests/data_source_monitor_scheduled_query_rules_log_test.go @@ -0,0 +1,38 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" +) + +func TestAccDataSourceAzureRMMonitorScheduledQueryRules_LogToMetricAction(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_monitor_scheduled_query_rules_log", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAzureRMMonitorScheduledQueryRules_LogToMetricActionConfig(data), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(data.ResourceName, "id"), + ), + }, + }, + }) +} + +func testAccDataSourceAzureRMMonitorScheduledQueryRules_LogToMetricActionConfig(data acceptance.TestData) string { + template := testAccAzureRMMonitorScheduledQueryRules_LogToMetricActionConfigBasic(data) + return fmt.Sprintf(` +%s + +data "azurerm_monitor_scheduled_query_rules_log" "test" { + name = basename(azurerm_monitor_scheduled_query_rules_log.test.id) + resource_group_name = "${azurerm_resource_group.test.name}" +} +`, template) +} diff --git a/azurerm/internal/services/monitor/tests/resource_arm_monitor_scheduled_query_rules_alert_test.go b/azurerm/internal/services/monitor/tests/resource_arm_monitor_scheduled_query_rules_alert_test.go new file mode 100644 index 000000000000..65106b7ad9b7 --- /dev/null +++ b/azurerm/internal/services/monitor/tests/resource_arm_monitor_scheduled_query_rules_alert_test.go @@ -0,0 +1,374 @@ +package tests + +import ( + "fmt" + "net/http" + "testing" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" +) + +func TestAccAzureRMMonitorScheduledQueryRules_AlertingActionBasic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_scheduled_query_rules_alert", "test") + ts := time.Now().Format(time.RFC3339) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMMonitorScheduledQueryRules_AlertDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMMonitorScheduledQueryRules_AlertingActionConfigBasic(data, ts), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMMonitorScheduledQueryRules_AlertExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMMonitorScheduledQueryRules_AlertingActionUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_scheduled_query_rules_alert", "test") + ts := time.Now().Format(time.RFC3339) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMMonitorScheduledQueryRules_AlertDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMMonitorScheduledQueryRules_AlertingActionConfigBasic(data, ts), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMMonitorScheduledQueryRules_AlertExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMMonitorScheduledQueryRules_AlertingActionConfigUpdate(data, ts), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMMonitorScheduledQueryRules_AlertExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMMonitorScheduledQueryRules_AlertingActionComplete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_scheduled_query_rules_alert", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMMonitorScheduledQueryRules_AlertDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMMonitorScheduledQueryRules_AlertingActionConfigComplete(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMMonitorScheduledQueryRules_AlertExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMMonitorScheduledQueryRules_AlertingActionCrossResource(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_scheduled_query_rules_alert", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMMonitorScheduledQueryRules_AlertDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMMonitorScheduledQueryRules_AlertingActionCrossResourceConfig(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMMonitorScheduledQueryRules_AlertExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func testAccAzureRMMonitorScheduledQueryRules_AlertingActionConfigBasic(data acceptance.TestData, ts string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-monitor-%d" + location = "%s" +} + +resource "azurerm_application_insights" "test" { + name = "acctestAppInsights-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + application_type = "web" +} + +resource "azurerm_monitor_action_group" "test" { + name = "acctestActionGroup-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + short_name = "acctestag" +} + +resource "azurerm_monitor_scheduled_query_rules_alert" "test" { + name = "acctestsqr-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + + data_source_id = "${azurerm_application_insights.test.id}" + query = <<-QUERY + let d=datatable(TimeGenerated: datetime, usage_percent: double) [ '%s', 25.4, '%s', 75.4 ]; + d | summarize AggregatedValue=avg(usage_percent) by bin(TimeGenerated, 1h) + QUERY + + frequency = 60 + time_window = 60 + + action { + action_group = ["${azurerm_monitor_action_group.test.id}"] + } + + trigger { + operator = "GreaterThan" + threshold = 5000 + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, ts, ts) +} + +func testAccAzureRMMonitorScheduledQueryRules_AlertingActionConfigUpdate(data acceptance.TestData, ts string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-monitor-%d" + location = "%s" +} + +resource "azurerm_application_insights" "test" { + name = "acctestAppInsights-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + application_type = "web" +} + +resource "azurerm_monitor_action_group" "test" { + name = "acctestActionGroup-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + short_name = "acctestag" +} + +resource "azurerm_monitor_scheduled_query_rules_alert" "test" { + name = "acctestsqr-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + + data_source_id = "${azurerm_application_insights.test.id}" + query = <<-QUERY + let d=datatable(TimeGenerated: datetime, usage_percent: double) [ '%s', 25.4, '%s', 75.4 ]; + d | summarize AggregatedValue=avg(usage_percent) by bin(TimeGenerated, 1h) + QUERY + + enabled = false + description = "test description" + + frequency = 30 + time_window = 30 + + action { + action_group = ["${azurerm_monitor_action_group.test.id}"] + } + + trigger { + operator = "GreaterThan" + threshold = 1000 + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, ts, ts) +} + +func testAccAzureRMMonitorScheduledQueryRules_AlertingActionConfigComplete(data acceptance.TestData) string { + ts := time.Now().Format(time.RFC3339) + + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-monitor-%d" + location = "%s" +} + +resource "azurerm_application_insights" "test" { + name = "acctestAppInsights-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + application_type = "web" +} + +resource "azurerm_monitor_action_group" "test" { + name = "acctestActionGroup-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + short_name = "acctestag" +} + +resource "azurerm_monitor_scheduled_query_rules_alert" "test" { + name = "acctestsqr-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + description = "test alerting action" + enabled = true + + data_source_id = "${azurerm_application_insights.test.id}" + query = "let d=datatable(TimeGenerated: datetime, usage_percent: double) [ '%s', 25.4, '%s', 75.4 ]; d | summarize AggregatedValue=avg(usage_percent) by bin(TimeGenerated, 1h)" + + frequency = 60 + time_window = 60 + + severity = 3 + throttling = 5 + action { + action_group = ["${azurerm_monitor_action_group.test.id}"] + email_subject = "Custom alert email subject" + custom_webhook_payload = "{}" + } + + trigger { + operator = "GreaterThan" + threshold = 5000 + metric_trigger { + operator = "GreaterThan" + threshold = 1 + metric_trigger_type = "Total" + metric_column = "TimeGenerated" + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, ts, ts) +} + +func testAccAzureRMMonitorScheduledQueryRules_AlertingActionCrossResourceConfig(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-monitor-%d" + location = "%s" +} + +resource "azurerm_application_insights" "test" { + name = "acctestAppInsights-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + application_type = "web" +} + +resource "azurerm_log_analytics_workspace" "test" { + name = "acctestWorkspace-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + sku = "PerGB2018" + retention_in_days = 30 +} + +resource "azurerm_monitor_action_group" "test" { + name = "acctestActionGroup-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + short_name = "acctestag" +} + +resource "azurerm_monitor_scheduled_query_rules_alert" "test" { + name = "acctestsqr-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + description = "test alerting action cross-resource" + enabled = true + + authorized_resource_ids = ["${azurerm_application_insights.test.id}", "${azurerm_log_analytics_workspace.test.id}"] + data_source_id = "${azurerm_application_insights.test.id}" + query = format(<<-QUERY + let a=workspace('%%s').Perf + | where Computer='dependency' and TimeGenerated > ago(1h) + | where ObjectName == 'Processor' and CounterName == '%%%% Processor Time' + | summarize cpu=avg(CounterValue) by bin(TimeGenerated, 1m) + | extend ts=tostring(TimeGenerated); let b=requests + | where resultCode == '200' and timestamp > ago(1h) + | summarize reqs=count() by bin(timestamp, 1m) + | extend ts = tostring(timestamp); a + | join b on $left.ts == $right.ts + | where cpu > 50 and reqs > 5 +QUERY + , azurerm_log_analytics_workspace.test.id) + + frequency = 60 + time_window = 60 + + severity = 3 + action { + action_group = ["${azurerm_monitor_action_group.test.id}"] + email_subject = "Custom alert email subject" + } + + trigger { + operator = "GreaterThan" + threshold = 5000 + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} + +func testCheckAzureRMMonitorScheduledQueryRules_AlertDestroy(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).Monitor.ScheduledQueryRulesClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_monitor_scheduled_query_rules_alert" { + continue + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + resp, err := client.Get(ctx, resourceGroup, name) + + if err != nil { + return nil + } + + if resp.StatusCode != http.StatusNotFound { + return fmt.Errorf("Scheduled Query Rule still exists:\n%#v", resp) + } + } + + return nil +} + +func testCheckAzureRMMonitorScheduledQueryRules_AlertExists(resourceName 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[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + name := 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 Scheduled Query Rule Instance: %s", name) + } + + client := acceptance.AzureProvider.Meta().(*clients.Client).Monitor.ScheduledQueryRulesClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + return fmt.Errorf("Bad: Get on monitorScheduledQueryRulesClient: %+v", err) + } + + if resp.StatusCode == http.StatusNotFound { + return fmt.Errorf("Bad: Scheduled Query Rule Instance %q (resource group: %q) does not exist", name, resourceGroup) + } + + return nil + } +} diff --git a/azurerm/internal/services/monitor/tests/resource_arm_monitor_scheduled_query_rules_log_test.go b/azurerm/internal/services/monitor/tests/resource_arm_monitor_scheduled_query_rules_log_test.go new file mode 100644 index 000000000000..c62f37193cd3 --- /dev/null +++ b/azurerm/internal/services/monitor/tests/resource_arm_monitor_scheduled_query_rules_log_test.go @@ -0,0 +1,263 @@ +package tests + +import ( + "fmt" + "net/http" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" +) + +func TestAccAzureRMMonitorScheduledQueryRules_LogToMetricActionBasic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_scheduled_query_rules_log", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMMonitorScheduledQueryRules_LogDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMMonitorScheduledQueryRules_LogToMetricActionConfigBasic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMMonitorScheduledQueryRules_LogExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMMonitorScheduledQueryRules_LogToMetricActionUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_scheduled_query_rules_log", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMMonitorScheduledQueryRules_LogDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMMonitorScheduledQueryRules_LogToMetricActionConfigBasic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMMonitorScheduledQueryRules_LogExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMMonitorScheduledQueryRules_LogToMetricActionConfigUpdate(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMMonitorScheduledQueryRules_LogExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMMonitorScheduledQueryRules_LogToMetricActionComplete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_monitor_scheduled_query_rules_log", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMMonitorScheduledQueryRules_LogDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMMonitorScheduledQueryRules_LogToMetricActionConfigComplete(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMMonitorScheduledQueryRules_LogExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func testAccAzureRMMonitorScheduledQueryRules_LogToMetricActionConfigBasic(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-monitor-%d" + location = "%s" +} + +resource "azurerm_log_analytics_workspace" "test" { + name = "acctestWorkspace-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + sku = "PerGB2018" + retention_in_days = 30 +} + +resource "azurerm_monitor_scheduled_query_rules_log" "test" { + name = "acctestsqr-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + + data_source_id = "${azurerm_log_analytics_workspace.test.id}" + + criteria { + metric_name = "Average_%% Idle Time" + dimension { + name = "InstanceName" + operator = "Include" + values = ["1"] + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func testAccAzureRMMonitorScheduledQueryRules_LogToMetricActionConfigUpdate(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-monitor-%d" + location = "%s" +} + +resource "azurerm_log_analytics_workspace" "test" { + name = "acctestWorkspace-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + sku = "PerGB2018" + retention_in_days = 30 +} + +resource "azurerm_monitor_scheduled_query_rules_log" "test" { + name = "acctestsqr-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + description = "test log to metric action" + enabled = true + + data_source_id = "${azurerm_log_analytics_workspace.test.id}" + + criteria { + metric_name = "Average_%% Idle Time" + dimension { + name = "InstanceName" + operator = "Include" + values = ["2"] + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func testAccAzureRMMonitorScheduledQueryRules_LogToMetricActionConfigComplete(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-monitor-%d" + location = "%s" +} + +resource "azurerm_log_analytics_workspace" "test" { + name = "acctestWorkspace-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + sku = "PerGB2018" + retention_in_days = 30 +} + +resource "azurerm_monitor_action_group" "test" { + name = "acctestActionGroup-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + short_name = "acctestag" +} + +resource "azurerm_monitor_scheduled_query_rules_log" "test" { + name = "acctestsqr-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + description = "test log to metric action" + enabled = true + + data_source_id = "${azurerm_log_analytics_workspace.test.id}" + + criteria { + metric_name = "Average_%% Idle Time" + dimension { + name = "Computer" + operator = "Include" + values = ["*"] + } + } +} + +resource "azurerm_monitor_metric_alert" "test" { + name = "acctestmal-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + scopes = ["${azurerm_log_analytics_workspace.test.id}"] + description = "Action will be triggered when Average %% Idle Time is less than 10." + + criteria { + metric_namespace = "Microsoft.OperationalInsights/workspaces" + metric_name = "${azurerm_monitor_scheduled_query_rules_log.test.criteria[0].metric_name}" + aggregation = "Average" + operator = "LessThan" + threshold = 10 + } + + action { + action_group_id = "${azurerm_monitor_action_group.test.id}" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} + +func testCheckAzureRMMonitorScheduledQueryRules_LogDestroy(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).Monitor.ScheduledQueryRulesClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_monitor_scheduled_query_rules_log" { + continue + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + resp, err := client.Get(ctx, resourceGroup, name) + + if err != nil { + return nil + } + + if resp.StatusCode != http.StatusNotFound { + return fmt.Errorf("Scheduled Query Rule still exists:\n%#v", resp) + } + } + + return nil +} + +func testCheckAzureRMMonitorScheduledQueryRules_LogExists(resourceName 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[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + name := 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 Scheduled Query Rule Instance: %s", name) + } + + client := acceptance.AzureProvider.Meta().(*clients.Client).Monitor.ScheduledQueryRulesClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + return fmt.Errorf("Bad: Get on monitorScheduledQueryRulesClient: %+v", err) + } + + if resp.StatusCode == http.StatusNotFound { + return fmt.Errorf("Bad: Scheduled Query Rule Instance %q (resource group: %q) does not exist", name, resourceGroup) + } + + return nil + } +} diff --git a/website/azurerm.erb b/website/azurerm.erb index 53ffe06eec70..88f177bed221 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -318,6 +318,14 @@ azurerm_monitor_log_profile +