From 5882349859355d2715ebc711582633a90b825b93 Mon Sep 17 00:00:00 2001 From: Harshavardhan Musanalli Date: Thu, 14 Dec 2023 18:16:10 +0100 Subject: [PATCH 1/2] #24225: New datasource azurerm_dashboard_grafana --- .../dashboard_grafana_data_source.go | 217 ++++++++++++++++++ .../dashboard_grafana_data_source_test.go | 37 +++ internal/services/dashboard/registration.go | 4 +- .../docs/d/dashboard_grafana.html.markdown | 76 ++++++ 4 files changed, 333 insertions(+), 1 deletion(-) create mode 100644 internal/services/dashboard/dashboard_grafana_data_source.go create mode 100644 internal/services/dashboard/dashboard_grafana_data_source_test.go create mode 100644 website/docs/d/dashboard_grafana.html.markdown diff --git a/internal/services/dashboard/dashboard_grafana_data_source.go b/internal/services/dashboard/dashboard_grafana_data_source.go new file mode 100644 index 000000000000..a7e1029a30bf --- /dev/null +++ b/internal/services/dashboard/dashboard_grafana_data_source.go @@ -0,0 +1,217 @@ +package dashboard + +import ( + "fmt" + "regexp" + "time" + + "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-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dashboard/2023-09-01/grafanaresource" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourceDashboardGrafana() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourceDashboardGrafanaRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringMatch( + regexp.MustCompile(`^[a-zA-Z][-a-zA-Z\d]{0,21}[a-zA-Z\d]$`), + `The name length must be from 2 to 23 characters. The name can only contain letters, numbers and dashes, and it must begin with a letter and end with a letter or digit.`, + ), + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "location": commonschema.LocationComputed(), + + "api_key_enabled": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + + "auto_generated_domain_name_label_scope": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "deterministic_outbound_ip_enabled": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + + "azure_monitor_workspace_integrations": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "resource_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + }, + }, + + "identity": commonschema.SystemOrUserAssignedIdentityOptionalForceNew(), + + "public_network_access_enabled": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + + "grafana_major_version": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "grafana_version": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "outbound_ips": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + + "endpoint": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "sku": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "zone_redundancy_enabled": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourceDashboardGrafanaRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Dashboard.GrafanaResourceClient + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id := grafanaresource.NewGrafanaID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) + resp, err := client.GrafanaGet(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("retrieving %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("name", id.GrafanaName) + d.Set("resource_group_name", id.ResourceGroupName) + + if model := resp.Model; model != nil { + d.Set("location", location.Normalize(*model.Location)) + if properties := model.Properties; properties != nil { + if properties.ApiKey != nil { + if *properties.ApiKey == grafanaresource.ApiKeyEnabled { + d.Set("api_key_enabled", true) + } else { + d.Set("api_key_enabled", false) + } + } + + if properties.AutoGeneratedDomainNameLabelScope != nil { + d.Set("auto_generated_domain_name_label_scope", string(*properties.AutoGeneratedDomainNameLabelScope)) + } + + if properties.DeterministicOutboundIP != nil { + if *properties.DeterministicOutboundIP == grafanaresource.DeterministicOutboundIPEnabled { + d.Set("deterministic_outbound_ip_enabled", true) + } else { + d.Set("deterministic_outbound_ip_enabled", false) + } + } + + if properties.Endpoint != nil { + d.Set("endpoint", properties.Endpoint) + } + + // TO-DO + /* + if properties.GrafanaIntegrations != nil && properties.GrafanaIntegrations.AzureMonitorWorkspaceIntegrations != nil { + d.Set("azure_monitor_workspace_integrations", flattenAzureMonitorWorkspaceIntegrationModelArray(properties.GrafanaIntegrations.AzureMonitorWorkspaceIntegrations)) + } + */ + + if properties.GrafanaVersion != nil { + d.Set("grafana_version", properties.GrafanaVersion) + } + + if properties.GrafanaMajorVersion != nil { + d.Set("grafana_major_version", properties.GrafanaMajorVersion) + } + + if properties.OutboundIPs != nil { + d.Set("outbound_ips", properties.OutboundIPs) + } + + if properties.PublicNetworkAccess != nil { + if *properties.PublicNetworkAccess == grafanaresource.PublicNetworkAccessEnabled { + d.Set("public_network_access_enabled", true) + } else { + d.Set("public_network_access_enabled", false) + } + } + + if properties.ZoneRedundancy != nil { + if *properties.ZoneRedundancy == grafanaresource.ZoneRedundancyEnabled { + d.Set("zone_redundancy_enabled", true) + } else { + d.Set("zone_redundancy_enabled", false) + } + } + } + + if model.Sku != nil { + d.Set("sku", model.Sku.Name) + } + + flattenedIdentity, err := identity.FlattenSystemAndUserAssignedMap((*identity.SystemAndUserAssignedMap)(model.Identity)) + if err != nil { + return fmt.Errorf("flattening `identity`: %+v", err) + } + + if err := d.Set("identity", flattenedIdentity); err != nil { + return fmt.Errorf("setting `identity`: %+v", err) + } + + if err := tags.FlattenAndSet(d, model.Tags); err != nil { + return err + } + } + + return nil +} diff --git a/internal/services/dashboard/dashboard_grafana_data_source_test.go b/internal/services/dashboard/dashboard_grafana_data_source_test.go new file mode 100644 index 000000000000..b8462cfe114a --- /dev/null +++ b/internal/services/dashboard/dashboard_grafana_data_source_test.go @@ -0,0 +1,37 @@ +package dashboard_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type DashboardGrafanaDataSource struct{} + +func TestAccDashboardGrafanaDataSource_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dashboard_grafana", "test") + r := DashboardGrafanaDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("grafana_major_version").HasValue("9"), + ), + }, + }) +} + +func (DashboardGrafanaDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_dashboard_grafana" "test" { + name = azurerm_dashboard_grafana.test.name + resource_group_name = azurerm_dashboard_grafana.test.resource_group_name +} +`, DashboardGrafanaResource{}.basic(data)) +} diff --git a/internal/services/dashboard/registration.go b/internal/services/dashboard/registration.go index a7fe4df90a14..f492fbd99f94 100644 --- a/internal/services/dashboard/registration.go +++ b/internal/services/dashboard/registration.go @@ -33,7 +33,9 @@ func (r Registration) WebsiteCategories() []string { // SupportedDataSources returns the supported Data Sources supported by this Service func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource { - return map[string]*pluginsdk.Resource{} + return map[string]*pluginsdk.Resource{ + "azurerm_dashboard_grafana": dataSourceDashboardGrafana(), + } } // SupportedResources returns the supported Resources supported by this Service diff --git a/website/docs/d/dashboard_grafana.html.markdown b/website/docs/d/dashboard_grafana.html.markdown new file mode 100644 index 000000000000..b0f619ff6383 --- /dev/null +++ b/website/docs/d/dashboard_grafana.html.markdown @@ -0,0 +1,76 @@ +--- +subcategory: "Dashboard" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_dashboard_grafana" +description: |- + Gets information about an existing Grafana Dashboard. +--- + +# Data Source: azurerm_dashboard_grafana + +Use this data source to access information about an existing Grafana Dashboard. + +## Example Usage + +```hcl +provider "azurerm" { + features {} +} + +data "azurerm_dashboard_grafana" "example" { + name = "example-grafana-dashboard" + resource_group_name = "example-rg" +} + +output "name" { + value = data.azurerm_dashboard_grafana.example.name +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) Name of the grafana dashboard. + +* `resource_group_name` - (Required) Name of the resource group where resource belongs to. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of Grafana Dashboard. + +* `location` - Azure location where the resource exists. + +* `api_key_enabled` - Whether tje api key setting of the Grafana instance is enabled. + +* `auto_generated_domain_name_label_scope` - Scope for dns deterministic name hash calculation. + +* `deterministic_outbound_ip_enabled` - Whether the Grafana instance uses deterministic outbound IPs. + +* `grafana_major_version` - Major version of Grafana instance. + +* `azure_monitor_workspace_integrations` - Integrations for Azure Monitor Workspace. + +* `identity` - The managed identity of the grafana resource. + +* `public_network_access_enabled` - Whether or not public endpoint access is allowed for this server. + +* `endpoint` - The endpoint of the Grafana instance. + +* `grafana_version` - The full Grafana software semantic version deployed. + +* `outbound_ip` - List of outbound IPs if deterministicOutboundIP is enabled. + +* `sku` - The name of the SKU used for the Grafana instance. + +* `zone_redundancy_enabled` - The zone redundancy setting of the Grafana instance. + +* `tags` - A mapping of tags to assigned to the resource. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: + +* `read` - (Defaults to 5 minutes) Used when retrieving the API Management API. From 4f09173283685a6d868f3e22f2221f025ab0c25a Mon Sep 17 00:00:00 2001 From: Harshavardhan Musanalli Date: Fri, 15 Dec 2023 11:10:07 +0100 Subject: [PATCH 2/2] #24225: Support for azure_monitor_workspace_integrations attribute --- .../dashboard_grafana_data_source.go | 24 ++++++++++++++----- .../docs/d/dashboard_grafana.html.markdown | 2 +- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/internal/services/dashboard/dashboard_grafana_data_source.go b/internal/services/dashboard/dashboard_grafana_data_source.go index a7e1029a30bf..263b55170487 100644 --- a/internal/services/dashboard/dashboard_grafana_data_source.go +++ b/internal/services/dashboard/dashboard_grafana_data_source.go @@ -159,12 +159,9 @@ func dataSourceDashboardGrafanaRead(d *pluginsdk.ResourceData, meta interface{}) d.Set("endpoint", properties.Endpoint) } - // TO-DO - /* - if properties.GrafanaIntegrations != nil && properties.GrafanaIntegrations.AzureMonitorWorkspaceIntegrations != nil { - d.Set("azure_monitor_workspace_integrations", flattenAzureMonitorWorkspaceIntegrationModelArray(properties.GrafanaIntegrations.AzureMonitorWorkspaceIntegrations)) - } - */ + if properties.GrafanaIntegrations != nil && properties.GrafanaIntegrations.AzureMonitorWorkspaceIntegrations != nil { + d.Set("azure_monitor_workspace_integrations", flattenAzureMonitorWorkspaceIntegrations(*properties.GrafanaIntegrations.AzureMonitorWorkspaceIntegrations)) + } if properties.GrafanaVersion != nil { d.Set("grafana_version", properties.GrafanaVersion) @@ -215,3 +212,18 @@ func dataSourceDashboardGrafanaRead(d *pluginsdk.ResourceData, meta interface{}) return nil } + +// AzureMonitorWorkspaceIntegration represents a struct for Azure Monitor Workspace Integration +type AzureMonitorWorkspaceIntegration struct { + AzureMonitorWorkspaceResourceId *string `json:"azureMonitorWorkspaceResourceId,omitempty"` +} + +func flattenAzureMonitorWorkspaceIntegrations(integrations []grafanaresource.AzureMonitorWorkspaceIntegration) []interface{} { + result := make([]interface{}, len(integrations)) + for i, integration := range integrations { + result[i] = map[string]interface{}{ + "resource_id": integration.AzureMonitorWorkspaceResourceId, + } + } + return result +} diff --git a/website/docs/d/dashboard_grafana.html.markdown b/website/docs/d/dashboard_grafana.html.markdown index b0f619ff6383..7b6689847f1f 100644 --- a/website/docs/d/dashboard_grafana.html.markdown +++ b/website/docs/d/dashboard_grafana.html.markdown @@ -43,7 +43,7 @@ The following attributes are exported: * `location` - Azure location where the resource exists. -* `api_key_enabled` - Whether tje api key setting of the Grafana instance is enabled. +* `api_key_enabled` - Whether the api key setting of the Grafana instance is enabled. * `auto_generated_domain_name_label_scope` - Scope for dns deterministic name hash calculation.