Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Resource: azurerm_monitor_scheduled_query_rules_alert & azurerm_monitor_scheduled_query_rules_log #5053

Merged
merged 31 commits into from
Mar 4, 2020
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
81f2521
New Resource: `azurerm_monitor_scheduled_query_rules`
mcdafydd Sep 28, 2019
5303ecd
Acceptance tests passing
mcdafydd Dec 3, 2019
607a00d
Fix linting errors; minor cleanup
mcdafydd Dec 3, 2019
ebf84e9
Minor updates and bug fixes
mcdafydd Dec 5, 2019
ce59b1a
Remove heredoc in docs example
mcdafydd Dec 5, 2019
03cdd53
Merge remote-tracking branch 'upstream/master' into r/scheduled-query…
mcdafydd Dec 10, 2019
f3245e1
Merge remote-tracking branch 'upstream/master' into r/scheduled-query…
mcdafydd Dec 11, 2019
a1bf9ba
fix response import
mcdafydd Dec 11, 2019
7b785a0
Merge remote-tracking branch 'upstream/master' into r/scheduled-query…
mcdafydd Dec 12, 2019
e4e4c9e
Merge remote-tracking branch 'upstream/master' into r/scheduled-query…
mcdafydd Dec 27, 2019
8acb500
Update tests and docs to pass checks
mcdafydd Dec 27, 2019
7b25b37
Add moved tests to registration
mcdafydd Dec 28, 2019
88a2788
First pass update docs post-review
mcdafydd Jan 28, 2020
3dcea9c
First pass at separating into two resources
mcdafydd Jan 28, 2020
27f7f4f
Rename action to alert in docs
mcdafydd Jan 29, 2020
7dfdeb3
Fix code review items
mcdafydd Feb 1, 2020
7220ba4
Fix lint issues and minor typos
mcdafydd Feb 1, 2020
3fa8441
Fix lint issues #2
mcdafydd Feb 1, 2020
d2a15de
Fix lint issues #3
mcdafydd Feb 1, 2020
04d4a12
Fix documentation error
mcdafydd Feb 5, 2020
d835ced
Merge remote-tracking branch 'upstream/master' into r/scheduled-query…
mcdafydd Feb 6, 2020
78ddff0
Add monitor helpers
mcdafydd Feb 9, 2020
e9ce243
First pass address latest review
mcdafydd Feb 10, 2020
14d0825
Validate metric_trigger query; add example to docs
mcdafydd Feb 11, 2020
651c41f
Address review comments
mcdafydd Feb 15, 2020
db64f0d
Fix type assertions; simplify cross-resource query example
mcdafydd Feb 22, 2020
37b2c39
Review updates
mcdafydd Feb 22, 2020
347753a
Add MaxItems for cross-resource query
Feb 22, 2020
7689b82
Merge remote-tracking branch 'upstream/master' into r/scheduled-query…
mcdafydd Feb 23, 2020
27ad7ae
Address review comments
mcdafydd Mar 3, 2020
0625b05
Fix markdown formatting
mcdafydd Mar 3, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
141 changes: 141 additions & 0 deletions azurerm/helpers/azure/monitor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package azure

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{} {
mcdafydd marked this conversation as resolved.
Show resolved Hide resolved
result := make([]interface{}, 0)
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
}
result = append(result, v)

return result
mcdafydd marked this conversation as resolved.
Show resolved Hide resolved
}

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
}
5 changes: 5 additions & 0 deletions azurerm/internal/services/monitor/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand All @@ -53,5 +57,6 @@ func NewClient(o *common.ClientOptions) *Client {
DiagnosticSettingsCategoryClient: &DiagnosticSettingsCategoryClient,
LogProfilesClient: &LogProfilesClient,
MetricAlertsClient: &MetricAlertsClient,
ScheduledQueryRulesClient: &ScheduledQueryRulesClient,
}
}
Original file line number Diff line number Diff line change
@@ -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", azure.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", azure.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)
}