diff --git a/azurerm/provider.go b/azurerm/provider.go index 98092eabb107..25abef278703 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -251,6 +251,41 @@ func registerProviderWithSubscription(providerName string, client resources.Prov var providerRegistrationOnce sync.Once +func determineAzureResourceProvidersToRegister(providerList []resources.Provider) map[string]struct{} { + providers := map[string]struct{}{ + "Microsoft.Cache": struct{}{}, + "Microsoft.Cdn": struct{}{}, + "Microsoft.Compute": struct{}{}, + "Microsoft.ContainerRegistry": struct{}{}, + "Microsoft.ContainerService": struct{}{}, + "Microsoft.DocumentDB": struct{}{}, + "Microsoft.EventGrid": struct{}{}, + "Microsoft.EventHub": struct{}{}, + "Microsoft.KeyVault": struct{}{}, + "microsoft.insights": struct{}{}, + "Microsoft.Network": struct{}{}, + "Microsoft.Resources": struct{}{}, + "Microsoft.Search": struct{}{}, + "Microsoft.ServiceBus": struct{}{}, + "Microsoft.Sql": struct{}{}, + "Microsoft.Storage": struct{}{}, + } + + // filter out any providers already registered + for _, p := range providerList { + if _, ok := providers[*p.Namespace]; !ok { + continue + } + + if strings.ToLower(*p.RegistrationState) == "registered" { + log.Printf("[DEBUG] Skipping provider registration for namespace %s\n", *p.Namespace) + delete(providers, *p.Namespace) + } + } + + return providers +} + // registerAzureResourceProvidersWithSubscription uses the providers client to register // all Azure resource providers which the Terraform provider may require (regardless of // whether they are actually used by the configuration or not). It was confirmed by Microsoft @@ -258,36 +293,8 @@ var providerRegistrationOnce sync.Once func registerAzureResourceProvidersWithSubscription(providerList []resources.Provider, client resources.ProvidersClient) error { var err error providerRegistrationOnce.Do(func() { - providers := map[string]struct{}{ - "Microsoft.Cache": struct{}{}, - "Microsoft.Cdn": struct{}{}, - "Microsoft.Compute": struct{}{}, - "Microsoft.ContainerRegistry": struct{}{}, - "Microsoft.ContainerService": struct{}{}, - "Microsoft.DocumentDB": struct{}{}, - "Microsoft.EventGrid": struct{}{}, - "Microsoft.EventHub": struct{}{}, - "Microsoft.KeyVault": struct{}{}, - "Microsoft.Insights": struct{}{}, - "Microsoft.Network": struct{}{}, - "Microsoft.Resources": struct{}{}, - "Microsoft.Search": struct{}{}, - "Microsoft.ServiceBus": struct{}{}, - "Microsoft.Sql": struct{}{}, - "Microsoft.Storage": struct{}{}, - } - // filter out any providers already registered - for _, p := range providerList { - if _, ok := providers[*p.Namespace]; !ok { - continue - } - - if strings.ToLower(*p.RegistrationState) == "registered" { - log.Printf("[DEBUG] Skipping provider registration for namespace %s\n", *p.Namespace) - delete(providers, *p.Namespace) - } - } + providers := determineAzureResourceProvidersToRegister(providerList) var wg sync.WaitGroup wg.Add(len(providers)) diff --git a/azurerm/provider_test.go b/azurerm/provider_test.go index f4c8436cbe8f..19c3e0f6195e 100644 --- a/azurerm/provider_test.go +++ b/azurerm/provider_test.go @@ -6,6 +6,8 @@ import ( "testing" "github.com/Azure/go-autorest/autorest/azure" + "github.com/davecgh/go-spew/spew" + "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/terraform" ) @@ -56,12 +58,18 @@ func testAltLocation() string { return os.Getenv("ARM_TEST_LOCATION_ALT") } -func testArmEnvironment() (*azure.Environment, error) { +func testArmEnvironmentName() string { envName, exists := os.LookupEnv("ARM_ENVIRONMENT") if !exists { envName = "public" } + return envName +} + +func testArmEnvironment() (*azure.Environment, error) { + envName := testArmEnvironmentName() + // detect cloud from environment env, envErr := azure.EnvironmentFromName(envName) if envErr != nil { @@ -75,3 +83,47 @@ func testArmEnvironment() (*azure.Environment, error) { return &env, nil } + +func TestAccAzureRMResourceProviderRegistration(t *testing.T) { + environment := testArmEnvironmentName() + + if os.Getenv(resource.TestEnvVar) == "" { + t.Skip(fmt.Sprintf( + "Integration test skipped unless env '%s' set", + resource.TestEnvVar)) + return + } + + // we deliberately don't use the main config - since we care about + config := Config{ + SubscriptionID: os.Getenv("ARM_SUBSCRIPTION_ID"), + ClientID: os.Getenv("ARM_CLIENT_ID"), + TenantID: os.Getenv("ARM_TENANT_ID"), + ClientSecret: os.Getenv("ARM_CLIENT_SECRET"), + Environment: environment, + SkipProviderRegistration: false, + } + + armClient, err := config.getArmClient() + if err != nil { + t.Fatalf("Error building ARM Client: %+v", err) + } + + client := armClient.providers + providerList, err := client.List(nil, "") + if err != nil { + t.Fatalf("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) + } + + err = registerAzureResourceProvidersWithSubscription(*providerList.Value, client) + if err != nil { + t.Fatalf("Error registering Resource Providers: %+v", err) + } + + needingRegistration := determineAzureResourceProvidersToRegister(*providerList.Value) + if len(needingRegistration) > 0 { + t.Fatalf("'%d' Resource Providers are still Pending Registration: %s", len(needingRegistration), spew.Sprint(needingRegistration)) + } +}