Skip to content

Commit cc44961

Browse files
katbytesreallymatt
andauthored
provider: change ARM_PROVIDER_ENHANCED_VALIDATION default to false in 5.0 (#31678)
Co-authored-by: sreallymatt <106555974+sreallymatt@users.noreply.github.com>
1 parent 8f9e39c commit cc44961

File tree

12 files changed

+264
-14
lines changed

12 files changed

+264
-14
lines changed

internal/clients/builder.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,19 @@ func Build(ctx context.Context, builder ClientBuilder) (*Client, error) {
156156
return nil, fmt.Errorf("building Client: %+v", err)
157157
}
158158

159-
if features.EnhancedValidationEnabled() {
159+
if builder.Features.EnhancedValidation.Locations {
160+
ctx2, cancel := context.WithTimeout(ctx, 10*time.Minute)
161+
defer cancel()
162+
163+
location.CacheSupportedLocations(ctx2, *resourceManagerEndpoint)
164+
}
165+
166+
if builder.Features.EnhancedValidation.ResourceProviders {
160167
subscriptionId := commonids.NewSubscriptionID(client.Account.SubscriptionId)
161168

162169
ctx2, cancel := context.WithTimeout(ctx, 10*time.Minute)
163170
defer cancel()
164171

165-
location.CacheSupportedLocations(ctx2, *resourceManagerEndpoint)
166172
if err := resourceproviders.CacheSupportedProviders(ctx2, client.Resource.ResourceProvidersClient, subscriptionId); err != nil {
167173
log.Printf("[DEBUG] error retrieving providers: %s. Enhanced validation will be unavailable", err)
168174
}

internal/features/defaults.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ func Default() UserFeatures {
1010
PurgeSoftDeleteOnDestroy: true,
1111
RecoverSoftDeleted: true,
1212
},
13+
EnhancedValidation: EnhancedValidationFeatures{
14+
Locations: !FivePointOh(),
15+
ResourceProviders: !FivePointOh(),
16+
},
1317
AppConfiguration: AppConfigurationFeatures{
1418
PurgeSoftDeleteOnDestroy: true,
1519
RecoverSoftDeleted: true,

internal/features/enhanced_validation.go

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,105 @@
44
package features
55

66
import (
7+
"fmt"
78
"os"
89
"strings"
910
)
1011

1112
// EnhancedValidationEnabled returns whether the feature for Enhanced Validation is enabled.
1213
//
1314
// This functionality calls out to the Azure MetaData Service to cache the list of supported
14-
// Azure Locations for the specified Endpoint - and then uses that to provide enhanced validation
15+
// Azure Locations and Resource Providers for the specified Endpoint - and then uses that to
16+
// provide enhanced validation. When enabled, invalid locations or resource providers are caught
17+
// at `terraform plan` time. When disabled, these errors are caught at `terraform apply` time
18+
// when Azure rejects the request.
1519
//
16-
// This is enabled by default as of version 2.20 of the Azure Provider, and can be disabled by
17-
// setting the Environment Variable `ARM_PROVIDER_ENHANCED_VALIDATION` to `false`.
20+
// This is enabled by default in version 4.x and disabled by default as of version 5.0 of the
21+
// Azure Provider. The default can be overridden by setting the Environment Variable
22+
// `ARM_PROVIDER_ENHANCED_VALIDATION` to `true` or `false`.
1823
func EnhancedValidationEnabled() bool {
1924
value := os.Getenv("ARM_PROVIDER_ENHANCED_VALIDATION")
2025
if value == "" {
21-
return true
26+
// In 5.0, default to disabled; in 4.x, default to enabled
27+
return !FivePointOh()
2228
}
2329

2430
return strings.EqualFold(value, "true")
2531
}
32+
33+
// EnhancedValidationLocationsEnabled returns whether Enhanced Validation for Locations is enabled.
34+
//
35+
// This checks the `ARM_PROVIDER_ENHANCED_VALIDATION_LOCATIONS` environment variable first,
36+
// falling back to the legacy `ARM_PROVIDER_ENHANCED_VALIDATION` environment variable, then to the
37+
// version default (enabled in 4.x, disabled in 5.0).
38+
func EnhancedValidationLocationsEnabled() bool {
39+
// Check the locations-specific env var first
40+
value := os.Getenv("ARM_PROVIDER_ENHANCED_VALIDATION_LOCATIONS")
41+
if value != "" {
42+
return strings.EqualFold(value, "true")
43+
}
44+
45+
// In 4.x, fall back to the legacy environment variable
46+
if !FivePointOh() {
47+
return EnhancedValidationEnabled()
48+
}
49+
50+
// In 5.0, default to disabled
51+
return false
52+
}
53+
54+
// EnhancedValidationResourceProvidersEnabled returns whether Enhanced Validation for Resource Providers is enabled.
55+
//
56+
// This checks the `ARM_PROVIDER_ENHANCED_VALIDATION_RESOURCE_PROVIDERS` environment variable first,
57+
// falling back to the legacy `ARM_PROVIDER_ENHANCED_VALIDATION` environment variable, then to the
58+
// version default (enabled in 4.x, disabled in 5.0).
59+
func EnhancedValidationResourceProvidersEnabled() bool {
60+
// Check the resource-providers-specific env var first
61+
value := os.Getenv("ARM_PROVIDER_ENHANCED_VALIDATION_RESOURCE_PROVIDERS")
62+
if value != "" {
63+
return strings.EqualFold(value, "true")
64+
}
65+
66+
// In 4.x, fall back to the legacy environment variable
67+
if !FivePointOh() {
68+
return EnhancedValidationEnabled()
69+
}
70+
71+
// In 5.0, default to disabled
72+
return false
73+
}
74+
75+
// ValidateEnhancedValidationEnvVars validates the enhanced validation environment variables.
76+
//
77+
// In version 5.0, the legacy `ARM_PROVIDER_ENHANCED_VALIDATION` environment variable has been
78+
// removed - an error is returned if it is set, directing users to migrate to the specific
79+
// environment variables or the `enhanced_validation` provider block.
80+
//
81+
// In version 4.x, the legacy environment variable is still supported, but it cannot be set
82+
// at the same time as any of the specific environment variables.
83+
func ValidateEnhancedValidationEnvVars() error {
84+
legacyEnv := os.Getenv("ARM_PROVIDER_ENHANCED_VALIDATION")
85+
if legacyEnv == "" {
86+
return nil
87+
}
88+
89+
// In 5.0, the legacy env var is no longer supported
90+
if FivePointOh() {
91+
return fmt.Errorf("the environment variable `ARM_PROVIDER_ENHANCED_VALIDATION` has been removed in v5.0 of the AzureRM Provider - please use the `enhanced_validation` provider block or the replacement environment variables `ARM_PROVIDER_ENHANCED_VALIDATION_LOCATIONS` and `ARM_PROVIDER_ENHANCED_VALIDATION_RESOURCE_PROVIDERS` instead")
92+
}
93+
94+
// In 4.x, check for conflicts with specific env vars
95+
var conflicts []string
96+
if v := os.Getenv("ARM_PROVIDER_ENHANCED_VALIDATION_LOCATIONS"); v != "" {
97+
conflicts = append(conflicts, "ARM_PROVIDER_ENHANCED_VALIDATION_LOCATIONS")
98+
}
99+
if v := os.Getenv("ARM_PROVIDER_ENHANCED_VALIDATION_RESOURCE_PROVIDERS"); v != "" {
100+
conflicts = append(conflicts, "ARM_PROVIDER_ENHANCED_VALIDATION_RESOURCE_PROVIDERS")
101+
}
102+
103+
if len(conflicts) > 0 {
104+
return fmt.Errorf("the environment variable `ARM_PROVIDER_ENHANCED_VALIDATION` cannot be set at the same time as %v - please either use the legacy `ARM_PROVIDER_ENHANCED_VALIDATION` or the replacement environment variables, but not both", conflicts)
105+
}
106+
107+
return nil
108+
}

internal/features/user_flags.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ type UserFeatures struct {
88
AppConfiguration AppConfigurationFeatures
99
ApplicationInsights ApplicationInsightFeatures
1010
CognitiveAccount CognitiveAccountFeatures
11+
EnhancedValidation EnhancedValidationFeatures
1112
VirtualMachine VirtualMachineFeatures
1213
VirtualMachineScaleSet VirtualMachineScaleSetFeatures
1314
KeyVault KeyVaultFeatures
@@ -29,6 +30,11 @@ type CognitiveAccountFeatures struct {
2930
PurgeSoftDeleteOnDestroy bool
3031
}
3132

33+
type EnhancedValidationFeatures struct {
34+
Locations bool
35+
ResourceProviders bool
36+
}
37+
3238
type VirtualMachineFeatures struct {
3339
DetachImplicitDataDiskOnDeletion bool
3440
DeleteOSDiskOnDeletion bool

internal/provider/features_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ func TestExpandFeatures(t *testing.T) {
3535
CognitiveAccount: features.CognitiveAccountFeatures{
3636
PurgeSoftDeleteOnDestroy: true,
3737
},
38+
EnhancedValidation: features.EnhancedValidationFeatures{
39+
Locations: true,
40+
ResourceProviders: true,
41+
},
3842
KeyVault: features.KeyVaultFeatures{
3943
PurgeSoftDeletedCertsOnDestroy: true,
4044
PurgeSoftDeletedKeysOnDestroy: true,
@@ -236,6 +240,10 @@ func TestExpandFeatures(t *testing.T) {
236240
CognitiveAccount: features.CognitiveAccountFeatures{
237241
PurgeSoftDeleteOnDestroy: true,
238242
},
243+
EnhancedValidation: features.EnhancedValidationFeatures{
244+
Locations: true,
245+
ResourceProviders: true,
246+
},
239247
KeyVault: features.KeyVaultFeatures{
240248
PurgeSoftDeletedCertsOnDestroy: true,
241249
PurgeSoftDeletedKeysOnDestroy: true,
@@ -437,6 +445,10 @@ func TestExpandFeatures(t *testing.T) {
437445
CognitiveAccount: features.CognitiveAccountFeatures{
438446
PurgeSoftDeleteOnDestroy: false,
439447
},
448+
EnhancedValidation: features.EnhancedValidationFeatures{
449+
Locations: true,
450+
ResourceProviders: true,
451+
},
440452
KeyVault: features.KeyVaultFeatures{
441453
PurgeSoftDeletedCertsOnDestroy: false,
442454
PurgeSoftDeletedKeysOnDestroy: false,

internal/provider/framework/config.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,36 @@ func (p *ProviderConfig) Load(ctx context.Context, data *ProviderModel, tfVersio
126126
p.clientBuilder.DisableCorrelationRequestID = getEnvBoolOrDefault(data.DisableCorrelationRequestId, "ARM_DISABLE_CORRELATION_REQUEST_ID", false)
127127
p.clientBuilder.DisableTerraformPartnerID = getEnvBoolOrDefault(data.DisableTerraformPartnerId, "ARM_DISABLE_TERRAFORM_PARTNER_ID", false)
128128
p.clientBuilder.StorageUseAzureAD = getEnvBoolOrDefault(data.StorageUseAzureAD, "ARM_STORAGE_USE_AZUREAD", false)
129+
// In 4.x, validate that the legacy and specific enhanced validation env vars don't conflict
130+
if !providerfeatures.FivePointOh() {
131+
if err := providerfeatures.ValidateEnhancedValidationEnvVars(); err != nil {
132+
diags.Append(diag.NewErrorDiagnostic("validating enhanced validation environment variables", err.Error()))
133+
return
134+
}
135+
} else if os.Getenv("ARM_PROVIDER_ENHANCED_VALIDATION") != "" {
136+
diags.Append(diag.NewErrorDiagnostic("unsupported environment variable", "the environment variable `ARM_PROVIDER_ENHANCED_VALIDATION` has been removed in v5.0 of the AzureRM Provider - please use the `enhanced_validation` provider block or the replacement environment variables `ARM_PROVIDER_ENHANCED_VALIDATION_LOCATIONS` and `ARM_PROVIDER_ENHANCED_VALIDATION_RESOURCE_PROVIDERS` instead"))
137+
return
138+
}
139+
140+
// Read enhanced_validation block
141+
enhancedValidationLocations := providerfeatures.EnhancedValidationLocationsEnabled()
142+
enhancedValidationResourceProviders := providerfeatures.EnhancedValidationResourceProvidersEnabled()
143+
if !data.EnhancedValidation.IsNull() && !data.EnhancedValidation.IsUnknown() {
144+
var evList []EnhancedValidationModel
145+
d := data.EnhancedValidation.ElementsAs(ctx, &evList, true)
146+
diags.Append(d...)
147+
if diags.HasError() {
148+
return
149+
}
150+
if len(evList) > 0 {
151+
if !evList[0].Locations.IsNull() && !evList[0].Locations.IsUnknown() {
152+
enhancedValidationLocations = evList[0].Locations.ValueBool()
153+
}
154+
if !evList[0].ResourceProviders.IsNull() && !evList[0].ResourceProviders.IsUnknown() {
155+
enhancedValidationResourceProviders = evList[0].ResourceProviders.ValueBool()
156+
}
157+
}
158+
}
129159

130160
f := providerfeatures.UserFeatures{}
131161

@@ -521,6 +551,9 @@ func (p *ProviderConfig) Load(ctx context.Context, data *ProviderModel, tfVersio
521551
}
522552
}
523553

554+
f.EnhancedValidation.Locations = enhancedValidationLocations
555+
f.EnhancedValidation.ResourceProviders = enhancedValidationResourceProviders
556+
524557
p.clientBuilder.Features = f
525558
p.clientBuilder.AuthConfig = authConfig
526559
p.clientBuilder.CustomCorrelationRequestID = os.Getenv("ARM_CORRELATION_REQUEST_ID")

internal/provider/framework/config_test.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,16 @@ func TestProviderConfig_LoadDefault(t *testing.T) {
2626
t.Skip("ARM_CLIENT_SECRET env var not set")
2727
}
2828

29-
// Skip enhanced validation
30-
t.Setenv("ARM_PROVIDER_ENHANCED_VALIDATION", "false")
29+
enhancedValidation, _ := basetypes.NewObjectValueFrom(context.Background(), EnhancedValidationModelAttributes, map[string]attr.Value{
30+
"locations": basetypes.NewBoolValue(false),
31+
"resource_providers": basetypes.NewBoolValue(false),
32+
})
33+
enhancedValidationList, _ := basetypes.NewListValue(types.ObjectType{}.WithAttributeTypes(EnhancedValidationModelAttributes), []attr.Value{enhancedValidation})
3134

3235
testData := &ProviderModel{
3336
ResourceProviderRegistrations: types.StringValue("none"),
3437
Features: defaultFeaturesList(),
38+
EnhancedValidation: enhancedValidationList,
3539
}
3640

3741
testConfig.Load(context.Background(), testData, "unittest", &diag.Diagnostics{})

internal/provider/framework/model.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ type ProviderModel struct {
3636
DisableCorrelationRequestId types.Bool `tfsdk:"disable_correlation_request_id"`
3737
DisableTerraformPartnerId types.Bool `tfsdk:"disable_terraform_partner_id"`
3838
StorageUseAzureAD types.Bool `tfsdk:"storage_use_azuread"`
39+
EnhancedValidation types.List `tfsdk:"enhanced_validation"`
3940
Features types.List `tfsdk:"features"`
4041
SkipProviderRegistration types.Bool `tfsdk:"skip_provider_registration"` // TODO - Remove in 5.0
4142
ResourceProviderRegistrations types.String `tfsdk:"resource_provider_registrations"`
@@ -281,3 +282,13 @@ type DatabricksWorkspace struct {
281282
var DatabricksWorkspaceAttributes = map[string]attr.Type{
282283
"force_delete": types.BoolType,
283284
}
285+
286+
type EnhancedValidationModel struct {
287+
Locations types.Bool `tfsdk:"locations"`
288+
ResourceProviders types.Bool `tfsdk:"resource_providers"`
289+
}
290+
291+
var EnhancedValidationModelAttributes = map[string]attr.Type{
292+
"locations": types.BoolType,
293+
"resource_providers": types.BoolType,
294+
}

internal/provider/framework/provider.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,23 @@ func (p *azureRmFrameworkProvider) Schema(_ context.Context, _ provider.SchemaRe
239239
},
240240

241241
Blocks: map[string]schema.Block{
242+
"enhanced_validation": schema.ListNestedBlock{
243+
Validators: []validator.List{
244+
listvalidator.SizeAtMost(1),
245+
},
246+
NestedObject: schema.NestedBlockObject{
247+
Attributes: map[string]schema.Attribute{
248+
"locations": schema.BoolAttribute{
249+
Optional: true,
250+
Description: "Should the AzureRM Provider validate location arguments against the list of supported Azure Locations? When enabled, invalid locations are caught at plan time; when disabled, they are caught at apply time.",
251+
},
252+
"resource_providers": schema.BoolAttribute{
253+
Optional: true,
254+
Description: "Should the AzureRM Provider validate Resource Provider arguments against the list of supported Resource Providers? When enabled, invalid resource providers are caught at plan time; when disabled, they are caught at apply time.",
255+
},
256+
},
257+
},
258+
},
242259
"features": schema.ListNestedBlock{
243260
Validators: []validator.List{
244261
listvalidator.SizeBetween(1, 1),

internal/provider/provider.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,28 @@ func azureProvider(supportLegacyTestSuite bool) *schema.Provider {
376376
DefaultFunc: schema.EnvDefaultFunc("ARM_STORAGE_USE_AZUREAD", false),
377377
Description: "Should the AzureRM Provider use Azure AD Authentication when accessing the Storage Data Plane APIs?",
378378
},
379+
380+
"enhanced_validation": {
381+
Type: schema.TypeList,
382+
Optional: true,
383+
MaxItems: 1,
384+
Elem: &schema.Resource{
385+
Schema: map[string]*schema.Schema{
386+
"locations": {
387+
Type: schema.TypeBool,
388+
Optional: true,
389+
DefaultFunc: schema.EnvDefaultFunc("ARM_PROVIDER_ENHANCED_VALIDATION_LOCATIONS", features.EnhancedValidationLocationsEnabled()),
390+
Description: "Should the AzureRM Provider validate location arguments against the list of supported Azure Locations? When enabled, invalid locations are caught at plan time; when disabled, they are caught at apply time.",
391+
},
392+
"resource_providers": {
393+
Type: schema.TypeBool,
394+
Optional: true,
395+
DefaultFunc: schema.EnvDefaultFunc("ARM_PROVIDER_ENHANCED_VALIDATION_RESOURCE_PROVIDERS", features.EnhancedValidationResourceProvidersEnabled()),
396+
Description: "Should the AzureRM Provider validate Resource Provider arguments against the list of supported Resource Providers? When enabled, invalid resource providers are caught at plan time; when disabled, they are caught at apply time.",
397+
},
398+
},
399+
},
400+
},
379401
},
380402

381403
DataSourcesMap: dataSources,
@@ -544,6 +566,29 @@ func buildClient(ctx context.Context, p *schema.Provider, d *schema.ResourceData
544566
CustomCorrelationRequestID: os.Getenv("ARM_CORRELATION_REQUEST_ID"),
545567
}
546568

569+
// In 4.x, validate that the legacy and specific enhanced validation env vars don't conflict
570+
if !features.FivePointOh() {
571+
if err := features.ValidateEnhancedValidationEnvVars(); err != nil {
572+
return nil, diag.FromErr(err)
573+
}
574+
} else if os.Getenv("ARM_PROVIDER_ENHANCED_VALIDATION") != "" {
575+
return nil, diag.Errorf("the environment variable `ARM_PROVIDER_ENHANCED_VALIDATION` has been removed in v5.0 of the AzureRM Provider - please use the `enhanced_validation` provider block or the replacement environment variables `ARM_PROVIDER_ENHANCED_VALIDATION_LOCATIONS` and `ARM_PROVIDER_ENHANCED_VALIDATION_RESOURCE_PROVIDERS` instead")
576+
}
577+
578+
// Read enhanced_validation block
579+
if raw, ok := d.GetOk("enhanced_validation"); ok {
580+
items := raw.([]interface{})
581+
if len(items) > 0 && items[0] != nil {
582+
evRaw := items[0].(map[string]interface{})
583+
if v, ok := evRaw["locations"]; ok {
584+
clientBuilder.Features.EnhancedValidation.Locations = v.(bool)
585+
}
586+
if v, ok := evRaw["resource_providers"]; ok {
587+
clientBuilder.Features.EnhancedValidation.ResourceProviders = v.(bool)
588+
}
589+
}
590+
}
591+
547592
//lint:ignore SA1019 SDKv2 migration - staticcheck's own linter directives are currently being ignored under golangci-lint
548593
stopCtx, ok := schema.StopContext(ctx) //nolint:staticcheck
549594
if !ok {

0 commit comments

Comments
 (0)