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

cache resource providers to reduce expensive api call #20050

5 changes: 4 additions & 1 deletion internal/clients/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,10 @@ func Build(ctx context.Context, builder ClientBuilder) (*Client, error) {

if features.EnhancedValidationEnabled() {
location.CacheSupportedLocations(ctx, *resourceManagerEndpoint)
resourceproviders.CacheSupportedProviders(ctx, client.Resource.ProvidersClient)
_, err := resourceproviders.CachedSupportedProviders(ctx, client.Resource.ProvidersClient)
if err != nil {
log.Printf("[DEBUG] error retrieving providers: %+v. Enhanced validation will be unavailable", err)
}
}

return &client, nil
Expand Down
4 changes: 2 additions & 2 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -453,14 +453,14 @@ func buildClient(ctx context.Context, p *schema.Provider, d *schema.ResourceData
if !skipProviderRegistration {
// List all the available providers and their registration state to avoid unnecessary
// requests. This also lets us check if the provider credentials are correct.
providerList, err := client.Resource.ProvidersClient.List(ctx, nil, "")
providerList, err := resourceproviders.CachedSupportedProviders(ctx, client.Resource.ProvidersClient)
if err != nil {
return nil, diag.Errorf("Unable to list provider registration status, it is possible that this is due to invalid "+
"credentials or the service principal does not have permission to use the Resource Manager API, Azure "+
"error: %s", err)
}

availableResourceProviders := providerList.Values()
availableResourceProviders := *providerList
requiredResourceProviders := resourceproviders.Required()

if err := resourceproviders.EnsureRegistered(ctx, *client.Resource.ProvidersClient, availableResourceProviders, requiredResourceProviders); err != nil {
Expand Down
18 changes: 3 additions & 15 deletions internal/resourceproviders/azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,10 @@ import (
"github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/resources/mgmt/resources"
)

func availableResourceProviders(ctx context.Context, client *resources.ProvidersClient) (*[]string, error) {
providerNames := make([]string, 0)
providers, err := client.ListComplete(ctx, nil, "")
func availableResourceProviders(ctx context.Context, client *resources.ProvidersClient) ([]resources.Provider, error) {
providers, err := client.List(ctx, nil, "")
if err != nil {
return nil, fmt.Errorf("listing Resource Providers: %+v", err)
}
for providers.NotDone() {
provider := providers.Value()
if provider.Namespace != nil {
providerNames = append(providerNames, *provider.Namespace)
}

if err := providers.NextWithContext(ctx); err != nil {
return nil, err
}
}

return &providerNames, nil
return providers.Values(), nil
}
24 changes: 16 additions & 8 deletions internal/resourceproviders/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,30 @@ package resourceproviders

import (
"context"
"log"

"github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/resources/mgmt/resources"
)

// cachedResourceProviders can be (validly) nil - as such this shouldn't be relied on
var cachedResourceProviders *[]string
var cachedResourceProviders *[]resources.Provider
ms-henglu marked this conversation as resolved.
Show resolved Hide resolved

// CacheSupportedProviders attempts to retrieve the supported Resource Providers from the Resource Manager API
// CachedSupportedProviders returns cached the supported Resource Providers, if not cached it attempts to retrieve from the Resource Manager API
// and caches them, for used in enhanced validation
func CacheSupportedProviders(ctx context.Context, client *resources.ProvidersClient) {
func CachedSupportedProviders(ctx context.Context, client *resources.ProvidersClient) (*[]resources.Provider, error) {
if cachedResourceProviders != nil {
return cachedResourceProviders, nil
}
providers, err := availableResourceProviders(ctx, client)
if err != nil {
log.Printf("[DEBUG] error retrieving providers: %s. Enhanced validation will be unavailable", err)
return
return nil, err
}

cachedResourceProviders = providers
cached := make([]resources.Provider, 0)
for _, provider := range providers {
cached = append(cached, resources.Provider{
Namespace: provider.Namespace,
RegistrationState: provider.RegistrationState,
})
}
cachedResourceProviders = &cached
return cachedResourceProviders, nil
}
10 changes: 8 additions & 2 deletions internal/resourceproviders/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,19 @@ func enhancedValidation(i interface{}, k string) ([]string, []error) {

found := false
for _, provider := range *cachedResourceProviders {
if provider == v {
if provider.Namespace != nil && *provider.Namespace == v {
found = true
}
}

if !found {
providersJoined := strings.Join(*cachedResourceProviders, ", ")
cachedResourceProvidersNames := make([]string, 0)
for _, provider := range *cachedResourceProviders {
if provider.Namespace != nil {
cachedResourceProvidersNames = append(cachedResourceProvidersNames, *provider.Namespace)
}
}
providersJoined := strings.Join(cachedResourceProvidersNames, ", ")
return nil, []error{
fmt.Errorf("%q was not found in the list of supported Resource Providers: %q", v, providersJoined),
}
Expand Down
4 changes: 3 additions & 1 deletion internal/resourceproviders/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package resourceproviders
import (
"testing"

"github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/resources/mgmt/resources"
"github.com/hashicorp/terraform-provider-azurerm/internal/features"
"github.com/hashicorp/terraform-provider-azurerm/utils"
)

func TestEnhancedValidationDisabled(t *testing.T) {
Expand Down Expand Up @@ -68,7 +70,7 @@ func TestEnhancedValidationEnabled(t *testing.T) {
},
}
enhancedEnabled = true
cachedResourceProviders = &[]string{"Microsoft.Compute"}
cachedResourceProviders = &[]resources.Provider{{Namespace: utils.String("Microsoft.Compute")}}
ms-henglu marked this conversation as resolved.
Show resolved Hide resolved
defer func() {
enhancedEnabled = features.EnhancedValidationEnabled()
cachedResourceProviders = nil
Expand Down