Skip to content

Commit cae3061

Browse files
authored
azurerm_windows_web_app[_slot] - add support for the virtual_network_image_pull_enabled property (#30920)
[ENHANCEMENT] * `azurerm_windows_web_app` - add support for the `virtual_network_image_pull_enabled` property
1 parent e1dcc8c commit cae3061

File tree

7 files changed

+310
-23
lines changed

7 files changed

+310
-23
lines changed

internal/services/appservice/windows_web_app_resource.go

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/hashicorp/go-azure-helpers/resourcemanager/location"
1919
"github.com/hashicorp/go-azure-sdk/resource-manager/web/2023-01-01/resourceproviders"
2020
"github.com/hashicorp/go-azure-sdk/resource-manager/web/2023-12-01/webapps"
21+
"github.com/hashicorp/terraform-provider-azurerm/internal/features"
2122
"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
2223
"github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/helpers"
2324
"github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/migration"
@@ -66,15 +67,18 @@ type WindowsWebAppModel struct {
6667
ZipDeployFile string `tfschema:"zip_deploy_file"`
6768
Tags map[string]string `tfschema:"tags"`
6869
VirtualNetworkBackupRestoreEnabled bool `tfschema:"virtual_network_backup_restore_enabled"`
70+
VirtualNetworkImagePullEnabled bool `tfschema:"virtual_network_image_pull_enabled"`
6971
VirtualNetworkSubnetID string `tfschema:"virtual_network_subnet_id"`
7072
}
7173

72-
var _ sdk.ResourceWithCustomImporter = WindowsWebAppResource{}
73-
74-
var _ sdk.ResourceWithStateMigration = WindowsWebAppResource{}
74+
var (
75+
_ sdk.ResourceWithCustomImporter = WindowsWebAppResource{}
76+
_ sdk.ResourceWithCustomizeDiff = WindowsWebAppResource{}
77+
_ sdk.ResourceWithStateMigration = WindowsWebAppResource{}
78+
)
7579

7680
func (r WindowsWebAppResource) Arguments() map[string]*pluginsdk.Schema {
77-
return map[string]*pluginsdk.Schema{
81+
s := map[string]*pluginsdk.Schema{
7882
"name": {
7983
Type: pluginsdk.TypeString,
8084
Required: true,
@@ -199,12 +203,28 @@ func (r WindowsWebAppResource) Arguments() map[string]*pluginsdk.Schema {
199203
Default: false,
200204
},
201205

206+
"virtual_network_image_pull_enabled": {
207+
Type: pluginsdk.TypeBool,
208+
Optional: true,
209+
Default: false,
210+
},
211+
202212
"virtual_network_subnet_id": {
203213
Type: pluginsdk.TypeString,
204214
Optional: true,
205215
ValidateFunc: commonids.ValidateSubnetID,
206216
},
207217
}
218+
219+
if !features.FivePointOh() {
220+
s["virtual_network_image_pull_enabled"] = &pluginsdk.Schema{
221+
Type: pluginsdk.TypeBool,
222+
Optional: true,
223+
Computed: true,
224+
}
225+
}
226+
227+
return s
208228
}
209229

210230
func (r WindowsWebAppResource) Attributes() map[string]*pluginsdk.Schema {
@@ -386,6 +406,19 @@ func (r WindowsWebAppResource) Create() sdk.ResourceFunc {
386406
},
387407
}
388408

409+
if !features.FivePointOh() {
410+
rawVnetImagePullEnabled, err := metadata.GetRawConfigAt("virtual_network_image_pull_enabled")
411+
if err != nil {
412+
return err
413+
}
414+
415+
if !rawVnetImagePullEnabled.IsNull() {
416+
siteEnvelope.Properties.VnetImagePullEnabled = pointer.To(webApp.VirtualNetworkImagePullEnabled)
417+
}
418+
} else {
419+
siteEnvelope.Properties.VnetImagePullEnabled = pointer.To(webApp.VirtualNetworkImagePullEnabled)
420+
}
421+
389422
pna := helpers.PublicNetworkAccessEnabled
390423
if !webApp.PublicNetworkAccess {
391424
pna = helpers.PublicNetworkAccessDisabled
@@ -657,6 +690,7 @@ func (r WindowsWebAppResource) Read() sdk.ResourceFunc {
657690
state.PossibleOutboundIPAddressList = strings.Split(pointer.From(props.PossibleOutboundIPAddresses), ",")
658691
state.PublicNetworkAccess = !strings.EqualFold(pointer.From(props.PublicNetworkAccess), helpers.PublicNetworkAccessDisabled)
659692
state.VirtualNetworkBackupRestoreEnabled = pointer.From(props.VnetBackupRestoreEnabled)
693+
state.VirtualNetworkImagePullEnabled = pointer.From(props.VnetImagePullEnabled)
660694

661695
serverFarmId, err := commonids.ParseAppServicePlanIDInsensitively(pointer.From(props.ServerFarmId))
662696
if err != nil {
@@ -853,6 +887,10 @@ func (r WindowsWebAppResource) Update() sdk.ResourceFunc {
853887
model.Properties.VnetBackupRestoreEnabled = pointer.To(state.VirtualNetworkBackupRestoreEnabled)
854888
}
855889

890+
if metadata.ResourceData.HasChange("virtual_network_image_pull_enabled") {
891+
model.Properties.VnetImagePullEnabled = pointer.To(state.VirtualNetworkImagePullEnabled)
892+
}
893+
856894
if metadata.ResourceData.HasChange("virtual_network_subnet_id") {
857895
subnetId := metadata.ResourceData.Get("virtual_network_subnet_id").(string)
858896
if subnetId == "" {
@@ -1085,6 +1123,51 @@ func (r WindowsWebAppResource) CustomImporter() sdk.ResourceRunFunc {
10851123
}
10861124
}
10871125

1126+
func (r WindowsWebAppResource) CustomizeDiff() sdk.ResourceFunc {
1127+
return sdk.ResourceFunc{
1128+
Timeout: 5 * time.Minute,
1129+
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
1130+
client := metadata.Client.AppService.ServicePlanClient
1131+
1132+
model := WindowsWebAppModel{}
1133+
if err := metadata.DecodeDiff(&model); err != nil {
1134+
return fmt.Errorf("decoding: %w", err)
1135+
}
1136+
1137+
if metadata.ResourceDiff.HasChange("virtual_network_image_pull_enabled") {
1138+
planId := model.ServicePlanId
1139+
if planId == "" {
1140+
return nil
1141+
}
1142+
1143+
_, newValue := metadata.ResourceDiff.GetChange("virtual_network_image_pull_enabled")
1144+
if newValue.(bool) {
1145+
return nil
1146+
}
1147+
1148+
servicePlanID, err := commonids.ParseAppServicePlanID(planId)
1149+
if err != nil {
1150+
return err
1151+
}
1152+
1153+
resp, err := client.Get(ctx, *servicePlanID)
1154+
if err != nil {
1155+
return fmt.Errorf("retrieving %s: %w", *servicePlanID, err)
1156+
}
1157+
1158+
if aspModel := resp.Model; aspModel != nil {
1159+
if aspModel.Properties != nil && aspModel.Properties.HostingEnvironmentProfile != nil &&
1160+
pointer.From(aspModel.Properties.HostingEnvironmentProfile.Id) != "" && !newValue.(bool) {
1161+
return fmt.Errorf("`virtual_network_image_pull_enabled` cannot be disabled for app running in an app service environment")
1162+
}
1163+
}
1164+
}
1165+
1166+
return nil
1167+
},
1168+
}
1169+
}
1170+
10881171
func (r WindowsWebAppResource) StateUpgraders() sdk.StateUpgradeData {
10891172
return sdk.StateUpgradeData{
10901173
SchemaVersion: 1,

internal/services/appservice/windows_web_app_resource_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance"
1717
"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check"
1818
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
19+
"github.com/hashicorp/terraform-provider-azurerm/internal/features"
1920
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
2021
)
2122

@@ -3514,6 +3515,21 @@ resource "azurerm_windows_web_app" "test" {
35143515

35153516
// Note - this test omits the features block as the referenced template is a complete test on Service Plan
35163517
func (r WindowsWebAppResource) withASEV3(data acceptance.TestData) string {
3518+
if !features.FivePointOh() {
3519+
return fmt.Sprintf(`
3520+
%s
3521+
3522+
resource "azurerm_windows_web_app" "test" {
3523+
name = "acctestWA-%d"
3524+
location = azurerm_resource_group.test.location
3525+
resource_group_name = azurerm_resource_group.test.name
3526+
service_plan_id = azurerm_service_plan.test.id
3527+
3528+
site_config {}
3529+
}
3530+
`, ServicePlanResource{}.aseV3(data), data.RandomInteger)
3531+
}
3532+
35173533
return fmt.Sprintf(`
35183534
%s
35193535
@@ -3524,6 +3540,8 @@ resource "azurerm_windows_web_app" "test" {
35243540
service_plan_id = azurerm_service_plan.test.id
35253541
35263542
site_config {}
3543+
3544+
virtual_network_image_pull_enabled = true
35273545
}
35283546
`, ServicePlanResource{}.aseV3(data), data.RandomInteger)
35293547
}
@@ -4210,6 +4228,8 @@ resource "azurerm_windows_web_app" "test" {
42104228
service_plan_id = azurerm_service_plan.test.id
42114229
virtual_network_subnet_id = azurerm_subnet.test1.id
42124230
site_config {}
4231+
4232+
virtual_network_image_pull_enabled = true
42134233
}
42144234
`, r.baseTemplate(data), data.RandomInteger, data.RandomInteger)
42154235
}

internal/services/appservice/windows_web_app_slot_resource.go

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"github.com/hashicorp/go-azure-helpers/resourcemanager/identity"
1818
"github.com/hashicorp/go-azure-helpers/resourcemanager/location"
1919
"github.com/hashicorp/go-azure-sdk/resource-manager/web/2023-12-01/webapps"
20+
"github.com/hashicorp/terraform-provider-azurerm/internal/features"
2021
"github.com/hashicorp/terraform-provider-azurerm/internal/locks"
2122
"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
2223
"github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/helpers"
@@ -64,12 +65,15 @@ type WindowsWebAppSlotModel struct {
6465
ZipDeployFile string `tfschema:"zip_deploy_file"`
6566
Tags map[string]string `tfschema:"tags"`
6667
VirtualNetworkBackupRestoreEnabled bool `tfschema:"virtual_network_backup_restore_enabled"`
68+
VirtualNetworkImagePullEnabled bool `tfschema:"virtual_network_image_pull_enabled"`
6769
VirtualNetworkSubnetID string `tfschema:"virtual_network_subnet_id"`
6870
}
6971

70-
var _ sdk.ResourceWithUpdate = WindowsWebAppSlotResource{}
71-
72-
var _ sdk.ResourceWithStateMigration = WindowsWebAppSlotResource{}
72+
var (
73+
_ sdk.ResourceWithCustomizeDiff = WindowsWebAppSlotResource{}
74+
_ sdk.ResourceWithUpdate = WindowsWebAppSlotResource{}
75+
_ sdk.ResourceWithStateMigration = WindowsWebAppSlotResource{}
76+
)
7377

7478
func (r WindowsWebAppSlotResource) ModelObject() interface{} {
7579
return &WindowsWebAppSlotModel{}
@@ -84,7 +88,7 @@ func (r WindowsWebAppSlotResource) IDValidationFunc() pluginsdk.SchemaValidateFu
8488
}
8589

8690
func (r WindowsWebAppSlotResource) Arguments() map[string]*pluginsdk.Schema {
87-
return map[string]*pluginsdk.Schema{
91+
s := map[string]*pluginsdk.Schema{
8892
"name": {
8993
Type: pluginsdk.TypeString,
9094
Required: true,
@@ -210,12 +214,28 @@ func (r WindowsWebAppSlotResource) Arguments() map[string]*pluginsdk.Schema {
210214
Default: false,
211215
},
212216

217+
"virtual_network_image_pull_enabled": {
218+
Type: pluginsdk.TypeBool,
219+
Optional: true,
220+
Default: false,
221+
},
222+
213223
"virtual_network_subnet_id": {
214224
Type: pluginsdk.TypeString,
215225
Optional: true,
216226
ValidateFunc: commonids.ValidateSubnetID,
217227
},
218228
}
229+
230+
if !features.FivePointOh() {
231+
s["virtual_network_image_pull_enabled"] = &pluginsdk.Schema{
232+
Type: pluginsdk.TypeBool,
233+
Optional: true,
234+
Computed: true,
235+
}
236+
}
237+
238+
return s
219239
}
220240

221241
func (r WindowsWebAppSlotResource) Attributes() map[string]*pluginsdk.Schema {
@@ -360,6 +380,19 @@ func (r WindowsWebAppSlotResource) Create() sdk.ResourceFunc {
360380
},
361381
}
362382

383+
if !features.FivePointOh() {
384+
rawVnetImagePullEnabled, err := metadata.GetRawConfigAt("virtual_network_image_pull_enabled")
385+
if err != nil {
386+
return err
387+
}
388+
389+
if !rawVnetImagePullEnabled.IsNull() {
390+
siteEnvelope.Properties.VnetImagePullEnabled = pointer.To(webAppSlot.VirtualNetworkImagePullEnabled)
391+
}
392+
} else {
393+
siteEnvelope.Properties.VnetImagePullEnabled = pointer.To(webAppSlot.VirtualNetworkImagePullEnabled)
394+
}
395+
363396
if differentServicePlanToParent {
364397
siteEnvelope.Properties.ServerFarmId = pointer.To(servicePlanId.ID())
365398
}
@@ -633,6 +666,7 @@ func (r WindowsWebAppSlotResource) Read() sdk.ResourceFunc {
633666
state.PossibleOutboundIPAddressList = strings.Split(pointer.From(props.PossibleOutboundIPAddresses), ",")
634667
state.PublicNetworkAccess = !strings.EqualFold(pointer.From(props.PublicNetworkAccess), helpers.PublicNetworkAccessDisabled)
635668
state.VirtualNetworkBackupRestoreEnabled = pointer.From(props.VnetBackupRestoreEnabled)
669+
state.VirtualNetworkImagePullEnabled = pointer.From(props.VnetImagePullEnabled)
636670

637671
if hostingEnv := props.HostingEnvironmentProfile; hostingEnv != nil {
638672
hostingEnvId, err := parse.AppServiceEnvironmentIDInsensitively(*hostingEnv.Id)
@@ -861,6 +895,10 @@ func (r WindowsWebAppSlotResource) Update() sdk.ResourceFunc {
861895
model.Properties.VnetBackupRestoreEnabled = pointer.To(state.VirtualNetworkBackupRestoreEnabled)
862896
}
863897

898+
if metadata.ResourceData.HasChange("virtual_network_image_pull_enabled") {
899+
model.Properties.VnetImagePullEnabled = pointer.To(state.VirtualNetworkImagePullEnabled)
900+
}
901+
864902
if metadata.ResourceData.HasChange("virtual_network_subnet_id") {
865903
subnetId := metadata.ResourceData.Get("virtual_network_subnet_id").(string)
866904
if subnetId == "" {
@@ -1021,3 +1059,48 @@ func (r WindowsWebAppSlotResource) StateUpgraders() sdk.StateUpgradeData {
10211059
},
10221060
}
10231061
}
1062+
1063+
func (r WindowsWebAppSlotResource) CustomizeDiff() sdk.ResourceFunc {
1064+
return sdk.ResourceFunc{
1065+
Timeout: 5 * time.Minute,
1066+
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
1067+
client := metadata.Client.AppService.WebAppsClient
1068+
1069+
model := WindowsWebAppSlotModel{}
1070+
if err := metadata.DecodeDiff(&model); err != nil {
1071+
return fmt.Errorf("decoding: %w", err)
1072+
}
1073+
1074+
if metadata.ResourceDiff.HasChange("virtual_network_image_pull_enabled") {
1075+
appServiceId := model.AppServiceId
1076+
if appServiceId == "" {
1077+
return nil
1078+
}
1079+
1080+
_, newValue := metadata.ResourceDiff.GetChange("virtual_network_image_pull_enabled")
1081+
if newValue.(bool) {
1082+
return nil
1083+
}
1084+
1085+
appServiceID, err := commonids.ParseAppServiceID(appServiceId)
1086+
if err != nil {
1087+
return err
1088+
}
1089+
1090+
resp, err := client.Get(ctx, *appServiceID)
1091+
if err != nil {
1092+
return fmt.Errorf("retrieving %s: %w", *appServiceID, err)
1093+
}
1094+
1095+
if webAppModel := resp.Model; webAppModel != nil {
1096+
if webAppModel.Properties != nil && webAppModel.Properties.HostingEnvironmentProfile != nil &&
1097+
pointer.From(webAppModel.Properties.HostingEnvironmentProfile.Id) != "" && !newValue.(bool) {
1098+
return fmt.Errorf("`virtual_network_image_pull_enabled` cannot be disabled for app running in an app service environment")
1099+
}
1100+
}
1101+
}
1102+
1103+
return nil
1104+
},
1105+
}
1106+
}

0 commit comments

Comments
 (0)