Skip to content

Commit a8d216e

Browse files
authored
azurerm_resource_provider_registration - implement additional pollers and update existing ones to account for inconsistency in API (#31909)
[BUG] * `azurerm_resource_provider_registration` - add additional polling logic to prevent errors due to inconsistent API behaviour
1 parent ea3307e commit a8d216e

8 files changed

+225
-153
lines changed

internal/provider/provider_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ func TestResourcesSupportCustomTimeouts(t *testing.T) {
9797
"azurerm_key_vault_key": true,
9898
"azurerm_key_vault_secret": true,
9999
"azurerm_key_vault_certificate": true,
100+
// The `azurerm_resource_provider_registration` resource has a longer read timeout due to extensive polling being required to work around
101+
// API inconsistency issues
102+
"azurerm_resource_provider_registration": true,
100103
}
101104
if !exceptionResources[resourceName] {
102105
t.Fatalf("Read timeouts shouldn't be more than 5 minutes, this indicates a bug which needs to be fixed")
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright IBM Corp. 2014, 2025
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package custompollers
5+
6+
import (
7+
"context"
8+
"fmt"
9+
"strings"
10+
"time"
11+
12+
"github.com/hashicorp/go-azure-helpers/lang/pointer"
13+
14+
"github.com/hashicorp/go-azure-sdk/resource-manager/resources/2022-09-01/providers"
15+
"github.com/hashicorp/go-azure-sdk/sdk/client/pollers"
16+
)
17+
18+
var _ pollers.PollerType = &ResourceProviderExistencePoller{}
19+
20+
// NewResourceProviderExistencePoller - Checks for RPs in a "Registered" state, retrying n times
21+
func NewResourceProviderExistencePoller(client *providers.ProvidersClient, id providers.SubscriptionProviderId, maxRetries int) *ResourceProviderExistencePoller {
22+
return &ResourceProviderExistencePoller{
23+
client: client,
24+
id: id,
25+
maxRetries: maxRetries,
26+
}
27+
}
28+
29+
type ResourceProviderExistencePoller struct {
30+
client *providers.ProvidersClient
31+
id providers.SubscriptionProviderId
32+
maxRetries int
33+
}
34+
35+
func (p *ResourceProviderExistencePoller) Poll(ctx context.Context) (*pollers.PollResult, error) {
36+
if p.maxRetries == 0 {
37+
return &pollers.PollResult{
38+
Status: pollers.PollingStatusCancelled,
39+
}, pollers.PollingCancelledError{Message: "maximum retries exceeded"}
40+
}
41+
42+
resp, err := p.client.Get(ctx, p.id, providers.DefaultGetOperationOptions())
43+
if err != nil {
44+
return nil, pollers.PollingFailedError{Message: fmt.Sprintf("retrieving %s: %+v", p.id, err)}
45+
}
46+
47+
if resp.Model == nil {
48+
return nil, pollers.PollingFailedError{Message: fmt.Sprintf("retrieving %s: `model` was nil", p.id)}
49+
}
50+
51+
if strings.EqualFold(pointer.From(resp.Model.RegistrationState), "Registered") {
52+
return &pollers.PollResult{
53+
Status: pollers.PollingStatusSucceeded,
54+
}, nil
55+
} else {
56+
p.maxRetries -= 1
57+
}
58+
59+
return &pollers.PollResult{
60+
Status: pollers.PollingStatusInProgress,
61+
PollInterval: 10 * time.Second,
62+
}, nil
63+
}

internal/resourceproviders/custompollers/resource_provider_register_poller.go

Lines changed: 0 additions & 53 deletions
This file was deleted.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package custompollers
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
"time"
8+
9+
"github.com/hashicorp/go-azure-sdk/resource-manager/resources/2022-09-01/providers"
10+
"github.com/hashicorp/go-azure-sdk/sdk/client/pollers"
11+
)
12+
13+
var _ pollers.PollerType = &ResourceProviderRegistrationPoller{}
14+
15+
// NewResourceProviderRegistrationPollerDefault - Polls for an expected registration state, accounting for API inconsistency by requiring 10 continuous occurrences
16+
func NewResourceProviderRegistrationPollerDefault(client *providers.ProvidersClient, id providers.SubscriptionProviderId, target string) *ResourceProviderRegistrationPoller {
17+
return NewResourceProviderRegistrationPoller(client, id, target, 10)
18+
}
19+
20+
// NewResourceProviderRegistrationPoller - Polls for an expected registration state, accounting for API inconsistency by requiring n continuous occurrences
21+
func NewResourceProviderRegistrationPoller(client *providers.ProvidersClient, id providers.SubscriptionProviderId, target string, continuousTargetOccurrence int) *ResourceProviderRegistrationPoller {
22+
return &ResourceProviderRegistrationPoller{
23+
client: client,
24+
id: id,
25+
targetState: target,
26+
continuousTargetOccurrence: continuousTargetOccurrence,
27+
}
28+
}
29+
30+
type ResourceProviderRegistrationPoller struct {
31+
client *providers.ProvidersClient
32+
id providers.SubscriptionProviderId
33+
targetState string
34+
continuousTargetOccurrence int
35+
currentOccurrenceCount int
36+
}
37+
38+
func (p *ResourceProviderRegistrationPoller) Poll(ctx context.Context) (*pollers.PollResult, error) {
39+
resp, err := p.client.Get(ctx, p.id, providers.DefaultGetOperationOptions())
40+
if err != nil {
41+
return nil, fmt.Errorf("retrieving %s: %+v", p.id, err)
42+
}
43+
44+
registrationState := ""
45+
if model := resp.Model; model != nil && model.RegistrationState != nil {
46+
registrationState = *model.RegistrationState
47+
}
48+
49+
if strings.EqualFold(registrationState, p.targetState) {
50+
if p.continuousTargetOccurrence == p.currentOccurrenceCount {
51+
return &pollers.PollResult{
52+
Status: pollers.PollingStatusSucceeded,
53+
PollInterval: 10 * time.Second,
54+
}, nil
55+
}
56+
p.currentOccurrenceCount += 1
57+
} else {
58+
p.currentOccurrenceCount = 0
59+
}
60+
61+
// Processing
62+
return &pollers.PollResult{
63+
Status: pollers.PollingStatusInProgress,
64+
PollInterval: 10 * time.Second,
65+
}, nil
66+
}

internal/resourceproviders/custompollers/resource_provider_unregister_poller.go

Lines changed: 0 additions & 53 deletions
This file was deleted.

internal/resourceproviders/registration.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ func registerWithSubscription(ctx context.Context, client *providers.ProvidersCl
9494
}
9595

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

0 commit comments

Comments
 (0)