Skip to content

Commit

Permalink
error when service_plan_id is the same as the parent service_plan_id (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
mbfrahry authored Dec 11, 2023
1 parent 3541e1c commit 7e23b87
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 19 deletions.
45 changes: 36 additions & 9 deletions internal/services/appservice/linux_web_app_slot_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,20 +299,28 @@ func (r LinuxWebAppSlotResource) Create() sdk.ResourceFunc {
}

var servicePlanId *parse.ServicePlanId
if webApp.SiteProperties == nil || webApp.SiteProperties.ServerFarmID == nil {
return fmt.Errorf("could not determine Service Plan ID for %s: %+v", id, err)
}

servicePlanId, err = parse.ServicePlanID(*webApp.SiteProperties.ServerFarmID)
if err != nil {
return err
}

if webAppSlot.ServicePlanID != "" {
servicePlanId, err = parse.ServicePlanID(webAppSlot.ServicePlanID)
newServicePlanId, err := parse.ServicePlanID(webAppSlot.ServicePlanID)
if err != nil {
return err
}
} else {
if props := webApp.SiteProperties; props == nil || props.ServerFarmID == nil {
return fmt.Errorf("could not determine Service Plan ID for %s: %+v", id, err)
} else {
servicePlanId, err = parse.ServicePlanID(*props.ServerFarmID)
if err != nil {
return err
}
// we only set `service_plan_id` when it differs from the parent `service_plan_id` which is causing issues
// https://github.com/hashicorp/terraform-provider-azurerm/issues/21024
// we'll error here if the `service_plan_id` equals the parent `service_plan_id`
if strings.EqualFold(newServicePlanId.ID(), servicePlanId.ID()) {
return fmt.Errorf("`service_plan_id` should only be specified when it differs from the `service_plan_id` of the associated Web App")
}

servicePlanId = newServicePlanId
}

existing, err := client.GetSlot(ctx, id.ResourceGroup, id.SiteName, id.SlotName)
Expand Down Expand Up @@ -731,6 +739,18 @@ func (r LinuxWebAppSlotResource) Update() sdk.ResourceFunc {
}

if metadata.ResourceData.HasChange("service_plan_id") {
webApp, err := client.Get(ctx, id.ResourceGroup, id.SiteName)
if err != nil {
return fmt.Errorf("reading parent Windows Web App for %s: %+v", id, err)
}
if webApp.SiteProperties == nil || webApp.SiteProperties.ServerFarmID == nil {
return fmt.Errorf("could not determine Service Plan ID for %s: %+v", id, err)
}
parentServicePlanId, err := parse.ServicePlanID(*webApp.SiteProperties.ServerFarmID)
if err != nil {
return err
}

o, n := metadata.ResourceData.GetChange("service_plan_id")
oldPlan, err := parse.ServicePlanID(o.(string))
if err != nil {
Expand All @@ -741,6 +761,13 @@ func (r LinuxWebAppSlotResource) Update() sdk.ResourceFunc {
if err != nil {
return err
}

// we only set `service_plan_id` when it differs from the parent `service_plan_id` which is causing issues
// https://github.com/hashicorp/terraform-provider-azurerm/issues/21024
// we'll error here if the `service_plan_id` equals the parent `service_plan_id`
if strings.EqualFold(newPlan.ID(), parentServicePlanId.ID()) {
return fmt.Errorf("`service_plan_id` should only be specified when it differs from the `service_plan_id` of the associated Web App")
}
locks.ByID(oldPlan.ID())
defer locks.UnlockByID(oldPlan.ID())
locks.ByID(newPlan.ID())
Expand Down
50 changes: 50 additions & 0 deletions internal/services/appservice/linux_web_app_slot_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package appservice_test
import (
"context"
"fmt"
"regexp"
"testing"

"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance"
Expand Down Expand Up @@ -101,6 +102,29 @@ func TestAccLinuxWebAppSlot_separateStandardPlanUpdate(t *testing.T) {
})
}

func TestAccLinuxWebAppSlot_parentStandardPlanError(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_linux_web_app_slot", "test")
r := LinuxWebAppSlotResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.parentStandardPlanError(data),
ExpectError: regexp.MustCompile("`service_plan_id` should only be specified when it differs from the `service_plan_id` of the associated Web App"),
},
{
Config: r.separatePlan(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
{
Config: r.parentStandardPlanError(data),
ExpectError: regexp.MustCompile("`service_plan_id` should only be specified when it differs from the `service_plan_id` of the associated Web App"),
},
})
}

// Complete

func TestAccLinuxWebAppSlot_complete(t *testing.T) {
Expand Down Expand Up @@ -2578,6 +2602,32 @@ resource "azurerm_linux_web_app_slot" "test" {
`, r.baseTemplate(data), data.RandomInteger, SkuStandardPlan, SkuPremiumPlan)
}

func (r LinuxWebAppSlotResource) parentStandardPlanError(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
%s
resource "azurerm_service_plan" "test2" {
name = "acctestASP2-%[2]d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
os_type = "Linux"
sku_name = "%[3]s"
}
resource "azurerm_linux_web_app_slot" "test" {
name = "acctestWAS-%[2]d"
app_service_id = azurerm_linux_web_app.test.id
service_plan_id = azurerm_service_plan.test.id
site_config {}
}
`, r.baseTemplate(data), data.RandomInteger, SkuStandardPlan)
}

func (r LinuxWebAppSlotResource) publicNetworkAccessDisabled(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
Expand Down
45 changes: 36 additions & 9 deletions internal/services/appservice/windows_web_app_slot_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,20 +290,28 @@ func (r WindowsWebAppSlotResource) Create() sdk.ResourceFunc {
}

var servicePlanId *parse.ServicePlanId
if webApp.SiteProperties == nil || webApp.SiteProperties.ServerFarmID == nil {
return fmt.Errorf("could not determine Service Plan ID for %s: %+v", id, err)
}

servicePlanId, err = parse.ServicePlanID(*webApp.SiteProperties.ServerFarmID)
if err != nil {
return err
}

if webAppSlot.ServicePlanID != "" {
servicePlanId, err = parse.ServicePlanID(webAppSlot.ServicePlanID)
newServicePlanId, err := parse.ServicePlanID(webAppSlot.ServicePlanID)
if err != nil {
return err
}
} else {
if props := webApp.SiteProperties; props == nil || props.ServerFarmID == nil {
return fmt.Errorf("could not determine Service Plan ID for %s: %+v", id, err)
} else {
servicePlanId, err = parse.ServicePlanID(*props.ServerFarmID)
if err != nil {
return err
}
// we only set `service_plan_id` when it differs from the parent `service_plan_id` which is causing issues
// https://github.com/hashicorp/terraform-provider-azurerm/issues/21024
// we'll error here if the `service_plan_id` equals the parent `service_plan_id`
if strings.EqualFold(newServicePlanId.ID(), servicePlanId.ID()) {
return fmt.Errorf("`service_plan_id` should only be specified when it differs from the `service_plan_id` of the associated Web App")
}

servicePlanId = newServicePlanId
}

existing, err := client.GetSlot(ctx, id.ResourceGroup, id.SiteName, id.SlotName)
Expand Down Expand Up @@ -750,6 +758,18 @@ func (r WindowsWebAppSlotResource) Update() sdk.ResourceFunc {
}

if metadata.ResourceData.HasChange("service_plan_id") {
webApp, err := client.Get(ctx, id.ResourceGroup, id.SiteName)
if err != nil {
return fmt.Errorf("reading parent Windows Web App for %s: %+v", id, err)
}
if webApp.SiteProperties == nil || webApp.SiteProperties.ServerFarmID == nil {
return fmt.Errorf("could not determine Service Plan ID for %s: %+v", id, err)
}
parentServicePlanId, err := parse.ServicePlanID(*webApp.SiteProperties.ServerFarmID)
if err != nil {
return err
}

o, n := metadata.ResourceData.GetChange("service_plan_id")
oldPlan, err := parse.ServicePlanID(o.(string))
if err != nil {
Expand All @@ -760,6 +780,13 @@ func (r WindowsWebAppSlotResource) Update() sdk.ResourceFunc {
if err != nil {
return err
}

// we only set `service_plan_id` when it differs from the parent `service_plan_id` which is causing issues
// https://github.com/hashicorp/terraform-provider-azurerm/issues/21024
// we'll error here if the `service_plan_id` equals the parent `service_plan_id`
if strings.EqualFold(newPlan.ID(), parentServicePlanId.ID()) {
return fmt.Errorf("`service_plan_id` should only be specified when it differs from the `service_plan_id` of the associated Web App")
}
locks.ByID(oldPlan.ID())
defer locks.UnlockByID(oldPlan.ID())
locks.ByID(newPlan.ID())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package appservice_test
import (
"context"
"fmt"
"regexp"
"testing"

"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance"
Expand Down Expand Up @@ -64,7 +65,7 @@ func TestAccWindowsWebAppSlot_autoSwap(t *testing.T) {
})
}

func TestAccWidowsWebAppSlot_separateStandardPlan(t *testing.T) {
func TestAccWindowsWebAppSlot_separateStandardPlan(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_windows_web_app_slot", "test")
r := WindowsWebAppSlotResource{}

Expand Down Expand Up @@ -101,6 +102,29 @@ func TestAccWindowsWebAppSlot_separateStandardPlanUpdate(t *testing.T) {
})
}

func TestAccWindowsWebAppSlot_parentStandardPlanError(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_windows_web_app_slot", "test")
r := WindowsWebAppSlotResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.parentStandardPlanError(data),
ExpectError: regexp.MustCompile("`service_plan_id` should only be specified when it differs from the `service_plan_id` of the associated Web App"),
},
{
Config: r.separatePlan(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
{
Config: r.parentStandardPlanError(data),
ExpectError: regexp.MustCompile("`service_plan_id` should only be specified when it differs from the `service_plan_id` of the associated Web App"),
},
})
}

// Complete

func TestAccWindowsWebAppSlot_complete(t *testing.T) {
Expand Down Expand Up @@ -2160,6 +2184,32 @@ resource "azurerm_windows_web_app_slot" "test" {
`, r.baseTemplate(data), data.RandomInteger, SkuStandardPlan, SkuPremiumPlan)
}

func (r WindowsWebAppSlotResource) parentStandardPlanError(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
%s
resource "azurerm_service_plan" "test2" {
name = "acctestASP2-%[2]d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
os_type = "Windows"
sku_name = "%[3]s"
}
resource "azurerm_windows_web_app_slot" "test" {
name = "acctestWAS-%[2]d"
app_service_id = azurerm_windows_web_app.test.id
service_plan_id = azurerm_service_plan.test.id
site_config {}
}
`, r.baseTemplate(data), data.RandomInteger, SkuStandardPlan)
}

func (r WindowsWebAppSlotResource) publicNetworkAccessDisabled(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
Expand Down
2 changes: 2 additions & 0 deletions website/docs/r/linux_web_app_slot.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ The following arguments are supported:

* `service_plan_id` - (Optional) The ID of the Service Plan in which to run this slot. If not specified the same Service Plan as the Linux Web App will be used.

~> **Note:** `service_plan_id` should only be specified if it differs from the Service Plan of the associated Linux Web App.

* `storage_account` - (Optional) One or more `storage_account` blocks as defined below.

* `virtual_network_subnet_id` - (Optional) The subnet id which will be used by this Web App Slot for [regional virtual network integration](https://docs.microsoft.com/en-us/azure/app-service/overview-vnet-integration#regional-virtual-network-integration).
Expand Down
2 changes: 2 additions & 0 deletions website/docs/r/windows_web_app_slot.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ The following arguments are supported:

* `service_plan_id` - (Optional) The ID of the Service Plan in which to run this slot. If not specified the same Service Plan as the Windows Web App will be used.

~> **Note:** `service_plan_id` should only be specified if it differs from the Service Plan of the associated Windows Web App.

* `storage_account` - (Optional) One or more `storage_account` blocks as defined below.

~> **Note:** Using this value requires `WEBSITE_RUN_FROM_PACKAGE=1` to be set on the App in `app_settings`. Refer to the [Azure docs](https://docs.microsoft.com/en-us/azure/app-service/deploy-run-package) for further details.
Expand Down

0 comments on commit 7e23b87

Please sign in to comment.