Skip to content

Commit

Permalink
azurerm_dashboard_grafana: add support for SMTP (#24717)
Browse files Browse the repository at this point in the history
* azurerm_dashboard_grafana: add support for SMTP

* sort imports

* address comments

* fix basic test

* fix gosimple

* fix update test
  • Loading branch information
jiaweitao001 authored Feb 9, 2024
1 parent 360ab3e commit aa77b34
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 3 deletions.
140 changes: 140 additions & 0 deletions internal/services/dashboard/dashboard_grafana_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import (
"regexp"
"time"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/lang/response"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema"
"github.com/hashicorp/go-azure-helpers/resourcemanager/identity"
"github.com/hashicorp/go-azure-helpers/resourcemanager/location"
"github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2023-09-01/grafanaresource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
Expand All @@ -25,6 +27,7 @@ type DashboardGrafanaModel struct {
ResourceGroupName string `tfschema:"resource_group_name"`
ApiKeyEnabled bool `tfschema:"api_key_enabled"`
AutoGeneratedDomainNameLabelScope grafanaresource.AutoGeneratedDomainNameLabelScope `tfschema:"auto_generated_domain_name_label_scope"`
SMTP []SMTPConfigurationModel `tfschema:"smtp"`
DeterministicOutboundIPEnabled bool `tfschema:"deterministic_outbound_ip_enabled"`
AzureMonitorWorkspaceIntegrations []AzureMonitorWorkspaceIntegrationModel `tfschema:"azure_monitor_workspace_integrations"`
Location string `tfschema:"location"`
Expand All @@ -42,6 +45,17 @@ type AzureMonitorWorkspaceIntegrationModel struct {
ResourceId string `tfschema:"resource_id"`
}

type SMTPConfigurationModel struct {
SMTPEnabled bool `tfschema:"enabled"`
FromAddress string `tfschema:"from_address"`
FromName string `tfschema:"from_name"`
Host string `tfschema:"host"`
Password string `tfschema:"password"`
SkipVerify bool `tfschema:"verification_skip_enabled"`
User string `tfschema:"user"`
StartTLSPolicy string `tfschema:"start_tls_policy"`
}

type DashboardGrafanaResource struct{}

var _ sdk.ResourceWithUpdate = DashboardGrafanaResource{}
Expand Down Expand Up @@ -89,6 +103,61 @@ func (r DashboardGrafanaResource) Arguments() map[string]*pluginsdk.Schema {
}, false),
},

"smtp": {
Type: pluginsdk.TypeList,
Optional: true,
MaxItems: 1,
Elem: &pluginsdk.Resource{
Schema: map[string]*schema.Schema{
"enabled": {
Type: pluginsdk.TypeBool,
Optional: true,
Default: false,
},
"from_address": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validation.StringIsNotEmpty,
},
"from_name": {
Type: pluginsdk.TypeString,
Optional: true,
Default: "Azure Managed Grafana Notification",
ValidateFunc: validation.StringIsNotEmpty,
},
"host": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validation.StringIsNotEmpty,
},
"password": {
Type: pluginsdk.TypeString,
Required: true,
Sensitive: true,
},
"verification_skip_enabled": {
Type: pluginsdk.TypeBool,
Optional: true,
Default: false,
},
"user": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validation.StringIsNotEmpty,
},
"start_tls_policy": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{
string(grafanaresource.StartTLSPolicyOpportunisticStartTLS),
string(grafanaresource.StartTLSPolicyMandatoryStartTLS),
string(grafanaresource.StartTLSPolicyNoStartTLS),
}, false),
},
},
},
},

"deterministic_outbound_ip_enabled": {
Type: pluginsdk.TypeBool,
Optional: true,
Expand Down Expand Up @@ -221,6 +290,7 @@ func (r DashboardGrafanaResource) Create() sdk.ResourceFunc {
Properties: &grafanaresource.ManagedGrafanaProperties{
ApiKey: &apiKey,
AutoGeneratedDomainNameLabelScope: &model.AutoGeneratedDomainNameLabelScope,
GrafanaConfigurations: expandSMTPConfigurationModel(model.SMTP),
DeterministicOutboundIP: &deterministicOutboundIP,
GrafanaIntegrations: expandGrafanaIntegrationsModel(model.AzureMonitorWorkspaceIntegrations),
GrafanaMajorVersion: &model.GrafanaMajorVersion,
Expand Down Expand Up @@ -367,6 +437,10 @@ func (r DashboardGrafanaResource) Read() sdk.ResourceFunc {
state.AutoGeneratedDomainNameLabelScope = *properties.AutoGeneratedDomainNameLabelScope
}

if properties.GrafanaConfigurations != nil {
state.SMTP = flattenSMTPConfigurationModel(properties.GrafanaConfigurations.Smtp, metadata.ResourceData)
}

if properties.DeterministicOutboundIP != nil {
if *properties.DeterministicOutboundIP == grafanaresource.DeterministicOutboundIPEnabled {
state.DeterministicOutboundIPEnabled = true
Expand Down Expand Up @@ -445,6 +519,29 @@ func (r DashboardGrafanaResource) Delete() sdk.ResourceFunc {
}
}

func expandSMTPConfigurationModel(input []SMTPConfigurationModel) *grafanaresource.GrafanaConfigurations {
if len(input) == 0 {
return nil
}

v := input[0]
smtp := grafanaresource.Smtp{
Enabled: pointer.To(v.SMTPEnabled),
FromAddress: pointer.To(v.FromAddress),
FromName: pointer.To(v.FromName),
Host: pointer.To(v.Host),
Password: pointer.To(v.Password),
SkipVerify: pointer.To(v.SkipVerify),
User: pointer.To(v.User),
StartTLSPolicy: (*grafanaresource.StartTLSPolicy)(pointer.To(v.StartTLSPolicy)),
}

return pointer.To(
grafanaresource.GrafanaConfigurations{
Smtp: pointer.To(smtp),
})
}

func expandGrafanaIntegrationsModel(inputList []AzureMonitorWorkspaceIntegrationModel) *grafanaresource.GrafanaIntegrations {
if len(inputList) == 0 {
return nil
Expand Down Expand Up @@ -483,6 +580,49 @@ func expandLegacySystemAndUserAssignedMap(input []interface{}) *identity.LegacyS
}
}

func flattenSMTPConfigurationModel(input *grafanaresource.Smtp, data *schema.ResourceData) []SMTPConfigurationModel {
var outputList []SMTPConfigurationModel
if input == nil || !pointer.From(input.Enabled) {
return outputList
}

var output SMTPConfigurationModel

if input.Enabled != nil {
output.SMTPEnabled = pointer.From(input.Enabled)
}

if input.FromAddress != nil {
output.FromAddress = pointer.From(input.FromAddress)
}

if input.FromName != nil {
output.FromName = pointer.From(input.FromName)
}

if input.Host != nil {
output.Host = pointer.From(input.Host)
}

if input.SkipVerify != nil {
output.SkipVerify = pointer.From(input.SkipVerify)
}

if input.User != nil {
output.User = pointer.From(input.User)
}

if input.StartTLSPolicy != nil {
output.StartTLSPolicy = string(pointer.From(input.StartTLSPolicy))
}

output.Password = data.Get("smtp.0.password").(string)

outputList = append(outputList, output)

return outputList
}

func flattenAzureMonitorWorkspaceIntegrationModelArray(inputList *[]grafanaresource.AzureMonitorWorkspaceIntegration) []AzureMonitorWorkspaceIntegrationModel {
var outputList []AzureMonitorWorkspaceIntegrationModel
if inputList == nil {
Expand Down
15 changes: 12 additions & 3 deletions internal/services/dashboard/dashboard_grafana_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func TestAccDashboardGrafana_complete(t *testing.T) {
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
data.ImportStep("smtp.0.password"),
})
}

Expand Down Expand Up @@ -85,14 +85,14 @@ func TestAccDashboardGrafana_update(t *testing.T) {
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
data.ImportStep("smtp.0.password"),
{
Config: r.update(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
data.ImportStep("smtp.0.password"),
})
}

Expand Down Expand Up @@ -217,6 +217,15 @@ resource "azurerm_dashboard_grafana" "test" {
deterministic_outbound_ip_enabled = true
public_network_access_enabled = false
grafana_major_version = "9"
smtp {
enabled = true
host = "localhost:25"
user = "user"
password = "password"
from_address = "[email protected]"
from_name = "Grafana"
start_tls_policy = "OpportunisticStartTLS"
}
identity {
type = "UserAssigned"
Expand Down
22 changes: 22 additions & 0 deletions website/docs/r/dashboard_grafana.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ The following arguments are supported:

* `grafana_major_version` - (Optional) Which major version of Grafana to deploy. Defaults to `9`. Possible values are `9`, `10`. Changing this forces a new resource to be created.

* `smtp` - (Optional) A `smtp` block as defined below.

* `azure_monitor_workspace_integrations` - (Optional) A `azure_monitor_workspace_integrations` block as defined below.

* `identity` - (Optional) An `identity` block as defined below. Changing this forces a new Dashboard Grafana to be created.
Expand All @@ -68,6 +70,26 @@ The following arguments are supported:

---

A `smtp` block supports the following:

* `enabled` - (Optional) Whether to enable the smtp setting of the Grafana instance. Defaults to `false`.

* `host` - (Required) SMTP server hostname with port, e.g. test.email.net:587

* `user` - (Required) User of SMTP authentication.

* `password` - (Required) Password of SMTP authentication.
*
* `start_tls_policy` - (Required) Whether to use TLS when connecting to SMTP server. Possible values are `OpportunisticStartTLS`, `NoStartTLS`, `MandatoryStartTLS`.

* `from_address` - (Required) Address used when sending emails.

* `from_name` - (Optional) Name used when sending emails. Defaults to `Azure Managed Grafana Notification`.

* `verification_skip_enabled` - (Optional) Whether verify SSL for SMTP server. Defaults to `false`.

---

An `azure_monitor_workspace_integrations` block supports the following:

* `resource_id` - (Required) Specifies the resource ID of the connected Azure Monitor Workspace.
Expand Down

0 comments on commit aa77b34

Please sign in to comment.