Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions internal/provider/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ func TestResourcesSupportCustomTimeouts(t *testing.T) {
"azurerm_key_vault_key": true,
"azurerm_key_vault_secret": true,
"azurerm_key_vault_certificate": true,
// The `azurerm_resource_provider_registration` resource has a longer read timeout due to extensive polling being required to work around
// API inconsistency issues
"azurerm_resource_provider_registration": true,
}
if !exceptionResources[resourceName] {
t.Fatalf("Read timeouts shouldn't be more than 5 minutes, this indicates a bug which needs to be fixed")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright IBM Corp. 2014, 2025
// SPDX-License-Identifier: MPL-2.0

package custompollers

import (
"context"
"fmt"
"strings"
"time"

"github.com/hashicorp/go-azure-helpers/lang/pointer"

"github.com/hashicorp/go-azure-sdk/resource-manager/resources/2022-09-01/providers"
"github.com/hashicorp/go-azure-sdk/sdk/client/pollers"
)

var _ pollers.PollerType = &ResourceProviderExistencePoller{}

// NewResourceProviderExistencePoller - Checks for RPs in a "Registered" state, retrying n times
func NewResourceProviderExistencePoller(client *providers.ProvidersClient, id providers.SubscriptionProviderId, maxRetries int) *ResourceProviderExistencePoller {
return &ResourceProviderExistencePoller{
client: client,
id: id,
maxRetries: maxRetries,
}
}

type ResourceProviderExistencePoller struct {
client *providers.ProvidersClient
id providers.SubscriptionProviderId
maxRetries int
}

func (p *ResourceProviderExistencePoller) Poll(ctx context.Context) (*pollers.PollResult, error) {
if p.maxRetries == 0 {
return &pollers.PollResult{
Status: pollers.PollingStatusCancelled,
}, pollers.PollingCancelledError{Message: "maximum retries exceeded"}
}

resp, err := p.client.Get(ctx, p.id, providers.DefaultGetOperationOptions())
if err != nil {
return nil, pollers.PollingFailedError{Message: fmt.Sprintf("retrieving %s: %+v", p.id, err)}
}

if resp.Model == nil {
return nil, pollers.PollingFailedError{Message: fmt.Sprintf("retrieving %s: `model` was nil", p.id)}
}

if strings.EqualFold(pointer.From(resp.Model.RegistrationState), "Registered") {
return &pollers.PollResult{
Status: pollers.PollingStatusSucceeded,
}, nil
} else {
p.maxRetries -= 1
}

return &pollers.PollResult{
Status: pollers.PollingStatusInProgress,
PollInterval: 10 * time.Second,
}, nil
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package custompollers

import (
"context"
"fmt"
"strings"
"time"

"github.com/hashicorp/go-azure-sdk/resource-manager/resources/2022-09-01/providers"
"github.com/hashicorp/go-azure-sdk/sdk/client/pollers"
)

var _ pollers.PollerType = &ResourceProviderRegistrationPoller{}

// NewResourceProviderRegistrationPollerDefault - Polls for an expected registration state, accounting for API inconsistency by requiring 10 continuous occurrences
func NewResourceProviderRegistrationPollerDefault(client *providers.ProvidersClient, id providers.SubscriptionProviderId, target string) *ResourceProviderRegistrationPoller {
return NewResourceProviderRegistrationPoller(client, id, target, 10)
}

// NewResourceProviderRegistrationPoller - Polls for an expected registration state, accounting for API inconsistency by requiring n continuous occurrences
func NewResourceProviderRegistrationPoller(client *providers.ProvidersClient, id providers.SubscriptionProviderId, target string, continuousTargetOccurrence int) *ResourceProviderRegistrationPoller {
return &ResourceProviderRegistrationPoller{
client: client,
id: id,
targetState: target,
continuousTargetOccurrence: continuousTargetOccurrence,
}
}

type ResourceProviderRegistrationPoller struct {
client *providers.ProvidersClient
id providers.SubscriptionProviderId
targetState string
continuousTargetOccurrence int
currentOccurrenceCount int
}

func (p *ResourceProviderRegistrationPoller) Poll(ctx context.Context) (*pollers.PollResult, error) {
resp, err := p.client.Get(ctx, p.id, providers.DefaultGetOperationOptions())
if err != nil {
return nil, fmt.Errorf("retrieving %s: %+v", p.id, err)
}

registrationState := ""
if model := resp.Model; model != nil && model.RegistrationState != nil {
registrationState = *model.RegistrationState
}

if strings.EqualFold(registrationState, p.targetState) {
if p.continuousTargetOccurrence == p.currentOccurrenceCount {
return &pollers.PollResult{
Status: pollers.PollingStatusSucceeded,
PollInterval: 10 * time.Second,
}, nil
}
p.currentOccurrenceCount += 1
} else {
p.currentOccurrenceCount = 0
}

// Processing
return &pollers.PollResult{
Status: pollers.PollingStatusInProgress,
PollInterval: 10 * time.Second,
}, nil
}

This file was deleted.

2 changes: 1 addition & 1 deletion internal/resourceproviders/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func registerWithSubscription(ctx context.Context, client *providers.ProvidersCl
}

log.Printf("[DEBUG] Waiting for %s to finish registering..", providerId)
pollerType := custompollers.NewResourceProviderRegistrationPoller(client, providerId)
pollerType := custompollers.NewResourceProviderRegistrationPoller(client, providerId, "Registered", 1)
poller := pollers.NewPoller(pollerType, 10*time.Second, pollers.DefaultNumberOfDroppedConnectionsToAllow)
if err := poller.PollUntilDone(ctx); err != nil {
return fmt.Errorf("waiting for %s to be registered: %s", providerId, err)
Expand Down
Loading
Loading