Skip to content

Commit

Permalink
New data source: azurerm_advisor_recommendations (hashicorp#6867)
Browse files Browse the repository at this point in the history
  • Loading branch information
yupwei68 authored and pbrit committed May 31, 2020
1 parent a1b8d32 commit d319069
Show file tree
Hide file tree
Showing 20 changed files with 3,450 additions and 0 deletions.
1 change: 1 addition & 0 deletions .teamcity/components/generated/services.kt
@@ -1,6 +1,7 @@
// NOTE: this is Generated from the Service Definitions - manual changes will be lost
// to re-generate this file, run 'make generate' in the root of the repository
var services = mapOf(
"advisor" to "Advisor",
"analysisservices" to "Analysis Services",
"apimanagement" to "API Management",
"appconfiguration" to "App Configuration",
Expand Down
11 changes: 11 additions & 0 deletions azurerm/helpers/azure/resource_group.go
Expand Up @@ -46,6 +46,17 @@ func SchemaResourceGroupNameOptionalComputed() *schema.Schema {
}
}

func SchemaResourceGroupNameSetOptional() *schema.Schema {
return &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validateResourceGroupName,
},
}
}

func validateResourceGroupName(v interface{}, k string) (warnings []string, errors []error) {
value := v.(string)

Expand Down
3 changes: 3 additions & 0 deletions azurerm/internal/clients/client.go
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/Azure/go-autorest/autorest"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/common"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features"
advisor "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/advisor/client"
analysisServices "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/analysisservices/client"
apiManagement "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/apimanagement/client"
appConfiguration "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/appconfiguration/client"
Expand Down Expand Up @@ -87,6 +88,7 @@ type Client struct {
Account *ResourceManagerAccount
Features features.UserFeatures

Advisor *advisor.Client
AnalysisServices *analysisServices.Client
ApiManagement *apiManagement.Client
AppConfiguration *appConfiguration.Client
Expand Down Expand Up @@ -169,6 +171,7 @@ func (client *Client) Build(ctx context.Context, o *common.ClientOptions) error
client.Features = o.Features
client.StopContext = ctx

client.Advisor = advisor.NewClient(o)
client.AnalysisServices = analysisServices.NewClient(o)
client.ApiManagement = apiManagement.NewClient(o)
client.AppConfiguration = appConfiguration.NewClient(o)
Expand Down
2 changes: 2 additions & 0 deletions azurerm/internal/provider/services.go
@@ -1,6 +1,7 @@
package provider

import (
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/advisor"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/analysisservices"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/apimanagement"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/appconfiguration"
Expand Down Expand Up @@ -80,6 +81,7 @@ import (

func SupportedServices() []common.ServiceRegistration {
return []common.ServiceRegistration{
advisor.Registration{},
analysisservices.Registration{},
apimanagement.Registration{},
appconfiguration.Registration{},
Expand Down
19 changes: 19 additions & 0 deletions azurerm/internal/services/advisor/client/client.go
@@ -0,0 +1,19 @@
package client

import (
"github.com/Azure/azure-sdk-for-go/services/advisor/mgmt/2020-01-01/advisor"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/common"
)

type Client struct {
RecommendationsClient *advisor.RecommendationsClient
}

func NewClient(o *common.ClientOptions) *Client {
recommendationsClient := advisor.NewRecommendationsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&recommendationsClient.Client, o.ResourceManagerAuthorizer)

return &Client{
RecommendationsClient: &recommendationsClient,
}
}
@@ -0,0 +1,212 @@
package advisor

import (
"fmt"
"strings"
"time"

"github.com/Azure/azure-sdk-for-go/services/advisor/mgmt/2020-01-01/advisor"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
uuid "github.com/satori/go.uuid"
"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/timeouts"
)

func dataSourceArmAdvisorRecommendations() *schema.Resource {
return &schema.Resource{
Read: dataSourceArmAdvisorRecommendationsRead,

Timeouts: &schema.ResourceTimeout{
Read: schema.DefaultTimeout(10 * time.Minute),
},

Schema: map[string]*schema.Schema{
"filter_by_category": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice([]string{
string(advisor.HighAvailability),
string(advisor.Security),
string(advisor.Performance),
string(advisor.Cost),
string(advisor.OperationalExcellence)}, true),
},
},

"filter_by_resource_groups": azure.SchemaResourceGroupNameSetOptional(),

"recommendations": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"category": {
Type: schema.TypeString,
Computed: true,
},

"description": {
Type: schema.TypeString,
Computed: true,
},

"impact": {
Type: schema.TypeString,
Computed: true,
},

"recommendation_name": {
Type: schema.TypeString,
Computed: true,
},

"recommendation_type_id": {
Type: schema.TypeString,
Computed: true,
},

"resource_name": {
Type: schema.TypeString,
Computed: true,
},

"resource_type": {
Type: schema.TypeString,
Computed: true,
},

"suppression_names": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},

"updated_time": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
},
}
}

func dataSourceArmAdvisorRecommendationsRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Advisor.RecommendationsClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

filterList := make([]string, 0)
if categories := expandAzureRmAdvisorRecommendationsMapString("Category", d.Get("filter_by_category").(*schema.Set).List()); categories != "" {
filterList = append(filterList, categories)
}
if resGroups := expandAzureRmAdvisorRecommendationsMapString("ResourceGroup", d.Get("filter_by_resource_groups").(*schema.Set).List()); resGroups != "" {
filterList = append(filterList, resGroups)
}

var recommends []advisor.ResourceRecommendationBase
for recommendationIterator, err := client.ListComplete(ctx, strings.Join(filterList, " and "), nil, ""); recommendationIterator.NotDone(); err = recommendationIterator.NextWithContext(ctx) {
if err != nil {
return fmt.Errorf("loading Advisor Recommendation List: %+v", err)
}

if recommendationIterator.Value().Name == nil || *recommendationIterator.Value().Name == "" {
return fmt.Errorf("advisor Recommendation Name was nil or empty")
}

recommends = append(recommends, recommendationIterator.Value())
}

if err := d.Set("recommendations", flattenAzureRmAdvisorRecommendations(recommends)); err != nil {
return fmt.Errorf("setting `recommendations`: %+v", err)
}

d.SetId(fmt.Sprintf("avdisor/recommendations/%s", time.Now().UTC().String()))

return nil
}

func flattenAzureRmAdvisorRecommendations(recommends []advisor.ResourceRecommendationBase) []interface{} {
result := make([]interface{}, 0)

if len(recommends) == 0 {
return result
}

for _, v := range recommends {
var category, description, impact, recTypeId, resourceName, resourceType, updatedTime string
var suppressionIds []interface{}
if v.Category != "" {
category = string(v.Category)
}

if v.ShortDescription != nil && v.ShortDescription.Problem != nil {
description = *v.ShortDescription.Problem
}

if v.Impact != "" {
impact = string(v.Impact)
}

if v.RecommendationTypeID != nil {
recTypeId = *v.RecommendationTypeID
}

if v.ImpactedValue != nil {
resourceName = *v.ImpactedValue
}

if v.ImpactedField != nil {
resourceType = *v.ImpactedField
}

if v.SuppressionIds != nil {
suppressionIds = flattenSuppressionSlice(v.SuppressionIds)
}
if v.LastUpdated != nil && !v.LastUpdated.IsZero() {
updatedTime = v.LastUpdated.Format(time.RFC3339)
}

result = append(result, map[string]interface{}{
"category": category,
"description": description,
"impact": impact,
"recommendation_name": *v.Name,
"recommendation_type_id": recTypeId,
"resource_name": resourceName,
"resource_type": resourceType,
"suppression_names": suppressionIds,
"updated_time": updatedTime,
})
}

return result
}

func expandAzureRmAdvisorRecommendationsMapString(t string, input []interface{}) string {
if len(input) == 0 {
return ""
}
result := make([]string, 0)
for _, v := range input {
result = append(result, fmt.Sprintf("%s eq '%s'", t, v.(string)))
}
return "(" + strings.Join(result, " or ") + ")"
}

func flattenSuppressionSlice(input *[]uuid.UUID) []interface{} {
result := make([]interface{}, 0)
if input != nil {
for _, item := range *input {
result = append(result, item.String())
}
}
return result
}
31 changes: 31 additions & 0 deletions azurerm/internal/services/advisor/registration.go
@@ -0,0 +1,31 @@
package advisor

import (
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

type Registration struct{}

// Name is the name of this Service
func (r Registration) Name() string {
return "Advisor"
}

// WebsiteCategories returns a list of categories which can be used for the sidebar
func (r Registration) WebsiteCategories() []string {
return []string{
"Advisor",
}
}

// SupportedDataSources returns the supported Data Sources supported by this Service
func (r Registration) SupportedDataSources() map[string]*schema.Resource {
return map[string]*schema.Resource{
"azurerm_advisor_recommendations": dataSourceArmAdvisorRecommendations(),
}
}

// SupportedResources returns the supported Resources supported by this Service
func (r Registration) SupportedResources() map[string]*schema.Resource {
return map[string]*schema.Resource{}
}

0 comments on commit d319069

Please sign in to comment.