Skip to content

Commit

Permalink
Merge pull request #24688 from hashicorp/f/web-api-swap-apps
Browse files Browse the repository at this point in the history
`appservice` - update to `go-azure-sdk`  and API version `2023-01-01`
  • Loading branch information
jackofallops authored Feb 1, 2024
2 parents 29adfc2 + 9bf1f8a commit af17bdc
Show file tree
Hide file tree
Showing 90 changed files with 5,645 additions and 7,666 deletions.
25 changes: 18 additions & 7 deletions internal/services/appservice/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@ import (
"fmt"

"github.com/hashicorp/go-azure-sdk/resource-manager/web/2023-01-01/appserviceplans"
_ "github.com/hashicorp/go-azure-sdk/resource-manager/web/2023-01-01/resourceproviders"
_ "github.com/hashicorp/go-azure-sdk/resource-manager/web/2023-01-01/webapps"
"github.com/hashicorp/go-azure-sdk/resource-manager/web/2023-01-01/resourceproviders"
"github.com/hashicorp/go-azure-sdk/resource-manager/web/2023-01-01/webapps"
"github.com/hashicorp/terraform-provider-azurerm/internal/common"
"github.com/tombuildsstuff/kermit/sdk/web/2022-09-01/web"
)

type Client struct {
AppServiceEnvironmentClient *web.AppServiceEnvironmentsClient
BaseClient *web.BaseClient
ResourceProvidersClient *resourceproviders.ResourceProvidersClient
ServicePlanClient *appserviceplans.AppServicePlansClient
WebAppsClient *web.AppsClient
WebAppsClient *webapps.WebAppsClient
}

func NewClient(o *common.ClientOptions) (*Client, error) {
Expand All @@ -27,19 +28,29 @@ func NewClient(o *common.ClientOptions) (*Client, error) {
baseClient := web.NewWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&baseClient.Client, o.ResourceManagerAuthorizer)

webAppServiceClient := web.NewAppsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&webAppServiceClient.Client, o.ResourceManagerAuthorizer)
webAppServiceClient, err := webapps.NewWebAppsClientWithBaseURI(o.Environment.ResourceManager)
if err != nil {
return nil, fmt.Errorf("building WebApps client: %+v", err)
}
o.Configure(webAppServiceClient.Client, o.Authorizers.ResourceManager)

resourceProvidersClient, err := resourceproviders.NewResourceProvidersClientWithBaseURI(o.Environment.ResourceManager)
if err != nil {
return nil, fmt.Errorf("building ResourceProviders client: %+v", err)
}
o.Configure(resourceProvidersClient.Client, o.Authorizers.ResourceManager)

servicePlanClient, err := appserviceplans.NewAppServicePlansClientWithBaseURI(o.Environment.ResourceManager)
if err != nil {
return nil, fmt.Errorf("building Api client: %+v", err)
return nil, fmt.Errorf("building ServicePlan client: %+v", err)
}
o.Configure(servicePlanClient.Client, o.Authorizers.ResourceManager)

return &Client{
AppServiceEnvironmentClient: &appServiceEnvironmentClient,
BaseClient: &baseClient,
ResourceProvidersClient: resourceProvidersClient,
ServicePlanClient: servicePlanClient,
WebAppsClient: &webAppServiceClient,
WebAppsClient: webAppServiceClient,
}, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package custompollers

import (
"context"
"fmt"
"time"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonids"
"github.com/hashicorp/go-azure-sdk/resource-manager/web/2023-01-01/webapps"
"github.com/hashicorp/go-azure-sdk/sdk/client/pollers"
)

var _ pollers.PollerType = &appServiceActiveSlotPoller{}

type appServiceActiveSlotPoller struct {
client *webapps.WebAppsClient
id webapps.SlotId
appId commonids.AppServiceId
}

var (
pollingSuccess = pollers.PollResult{
Status: pollers.PollingStatusSucceeded,
PollInterval: 10 * time.Second,
}
pollingInProgress = pollers.PollResult{
Status: pollers.PollingStatusInProgress,
PollInterval: 10 * time.Second,
}
)

func NewAppServiceActiveSlotPoller(client *webapps.WebAppsClient, id commonids.AppServiceId, slotId webapps.SlotId) *appServiceActiveSlotPoller {
return &appServiceActiveSlotPoller{
client: client,
id: slotId,
appId: id,
}
}

func (p appServiceActiveSlotPoller) Poll(ctx context.Context) (*pollers.PollResult, error) {
resp, err := p.client.Get(ctx, p.appId)
if err == nil {
if resp.Model != nil && resp.Model.Properties != nil {
swapStatus := resp.Model.Properties.SlotSwapStatus
if swapStatus == nil || pointer.From(swapStatus.SourceSlotName) != p.id.SlotName {
return &pollingInProgress, err
}
return &pollingSuccess, nil
}
}
return nil, fmt.Errorf("retrieving %s: %+v", p.appId, err)
}
51 changes: 27 additions & 24 deletions internal/services/appservice/function_app_active_slot_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import (
"fmt"
"time"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/lang/response"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonids"
"github.com/hashicorp/go-azure-sdk/resource-manager/web/2023-01-01/webapps"
"github.com/hashicorp/go-azure-sdk/sdk/client/pollers"
"github.com/hashicorp/terraform-provider-azurerm/internal/locks"
"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/parse"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/validate"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/custompollers"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/utils"
"github.com/tombuildsstuff/kermit/sdk/web/2022-09-01/web"
)

type FunctionAppActiveSlotResource struct{}
Expand All @@ -36,7 +38,7 @@ func (r FunctionAppActiveSlotResource) ResourceType() string {
}

func (r FunctionAppActiveSlotResource) IDValidationFunc() pluginsdk.SchemaValidateFunc {
return validate.FunctionAppID
return commonids.ValidateFunctionAppID
}

func (r FunctionAppActiveSlotResource) Arguments() map[string]*pluginsdk.Schema {
Expand All @@ -45,7 +47,7 @@ func (r FunctionAppActiveSlotResource) Arguments() map[string]*pluginsdk.Schema
Type: pluginsdk.TypeString,
Required: true,
Description: "The ID of the Slot to swap with `Production`.",
ValidateFunc: validate.FunctionAppSlotID,
ValidateFunc: webapps.ValidateSlotID,
},

"overwrite_network_config": {
Expand Down Expand Up @@ -79,35 +81,36 @@ func (r FunctionAppActiveSlotResource) Create() sdk.ResourceFunc {
}

client := metadata.Client.AppService.WebAppsClient
id, err := parse.FunctionAppSlotID(activeSlot.SlotID)
appId := parse.NewWebAppID(id.SubscriptionId, id.ResourceGroup, id.SiteName)
id, err := webapps.ParseSlotID(activeSlot.SlotID)
if err != nil {
return fmt.Errorf("parsing App ID: %+v", err)
}
appId := commonids.NewAppServiceID(id.SubscriptionId, id.ResourceGroupName, id.SiteName)

app, err := client.Get(ctx, id.ResourceGroup, id.SiteName)
app, err := client.Get(ctx, appId)
if err != nil {
if utils.ResponseWasNotFound(app.Response) {
if response.WasNotFound(app.HttpResponse) {
return fmt.Errorf("%s was not found", id)
}
return fmt.Errorf("reading %s: %+v", id, err)
}

csmSlotEntity := web.CsmSlotEntity{
TargetSlot: &id.SlotName,
PreserveVnet: &activeSlot.OverwriteNetworking,
csmSlotEntity := webapps.CsmSlotEntity{
TargetSlot: id.SlotName,
PreserveVnet: activeSlot.OverwriteNetworking,
}

locks.ByID(appId.ID())
defer locks.UnlockByID(appId.ID())

future, err := client.SwapSlotWithProduction(ctx, id.ResourceGroup, id.SiteName, csmSlotEntity)
if err != nil {
if _, err := client.SwapSlotWithProduction(ctx, appId, csmSlotEntity); err != nil {
return fmt.Errorf("making %s the active slot: %+v", id.SlotName, err)
}

if err = future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("waiting for slot swap to complete: %+v", err)
pollerType := custompollers.NewAppServiceActiveSlotPoller(client, appId, *id)
poller := pollers.NewPoller(pollerType, 10*time.Second, pollers.DefaultNumberOfDroppedConnectionsToAllow)
if err := poller.PollUntilDone(ctx); err != nil {
return err
}

metadata.SetID(appId)
Expand All @@ -123,29 +126,29 @@ func (r FunctionAppActiveSlotResource) Read() sdk.ResourceFunc {
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.AppService.WebAppsClient

id, err := parse.FunctionAppID(metadata.ResourceData.Id())
id, err := commonids.ParseFunctionAppID(metadata.ResourceData.Id())
if err != nil {
return err
}

app, err := client.Get(ctx, id.ResourceGroup, id.SiteName)
app, err := client.Get(ctx, *id)
if err != nil {
if utils.ResponseWasNotFound(app.Response) {
if response.WasNotFound(app.HttpResponse) {
return metadata.MarkAsGone(id)
}
return fmt.Errorf("reading active slot for %s: %+v", id.SiteName, err)
}

if app.SiteProperties == nil || app.SiteProperties.SlotSwapStatus == nil {
if app.Model == nil || app.Model.Properties == nil || app.Model.Properties.SlotSwapStatus == nil {
return fmt.Errorf("reading site properties to determine active slot status: %+v", err)
}

activeSlot := FunctionAppActiveSlotModel{
LastSwap: app.SiteProperties.SlotSwapStatus.TimestampUtc.String(),
LastSwap: pointer.From(app.Model.Properties.SlotSwapStatus.TimestampUtc),
}

if slotName := app.SiteProperties.SlotSwapStatus.SourceSlotName; slotName != nil {
activeSlot.SlotID = parse.NewWebAppSlotID(id.SubscriptionId, id.ResourceGroup, id.SiteName, *slotName).ID()
if slotName := app.Model.Properties.SlotSwapStatus.SourceSlotName; slotName != nil {
activeSlot.SlotID = webapps.NewSlotID(id.SubscriptionId, id.ResourceGroupName, id.SiteName, *slotName).ID()
}

// Default value here for imports as this cannot be read from service as it's part of the swap request only and not stored
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ import (
"fmt"
"testing"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonids"
"github.com/hashicorp/go-azure-sdk/resource-manager/web/2023-01-01/webapps"
"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance"
"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check"
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/parse"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/utils"
)

type FunctionApActiveSlotResource struct{}
Expand Down Expand Up @@ -93,25 +94,25 @@ func TestAccFunctionAppActiveSlot_linuxUpdate(t *testing.T) {
}

func (r FunctionApActiveSlotResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) {
id, err := parse.FunctionAppID(state.ID)
id, err := commonids.ParseFunctionAppID(state.ID)
if err != nil {
return nil, err
}

slotId, err := parse.WebAppSlotID(state.Attributes["slot_id"])
slotId, err := webapps.ParseSlotID(state.Attributes["slot_id"])
if err != nil {
return nil, err
}

app, err := client.AppService.WebAppsClient.Get(ctx, id.ResourceGroup, id.SiteName)
app, err := client.AppService.WebAppsClient.Get(ctx, *id)
if err != nil {
return nil, fmt.Errorf("retreiving Function App %s for slot %s: %+v", id, slotId.SlotName, err)
}
if app.SiteProperties == nil || app.SiteProperties.SlotSwapStatus == nil || app.SiteProperties.SlotSwapStatus.SourceSlotName == nil {
if app.Model == nil || app.Model.Properties == nil || app.Model.Properties.SlotSwapStatus == nil || app.Model.Properties.SlotSwapStatus.SourceSlotName == nil {
return nil, fmt.Errorf("missing App Slot Properties for %s", id)
}

return utils.Bool(*app.SiteProperties.SlotSwapStatus.SourceSlotName == slotId.SlotName), nil
return pointer.To(*app.Model.Properties.SlotSwapStatus.SourceSlotName == slotId.SlotName), nil
}

func (r FunctionApActiveSlotResource) basicWindows(data acceptance.TestData) string {
Expand Down Expand Up @@ -256,15 +257,15 @@ resource "azurerm_storage_account" "test" {
}
resource "azurerm_service_plan" "test" {
name = "acctestASP-WAS-%[1]d"
name = "acctestASP-LAS-%[1]d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
os_type = "Linux"
sku_name = "EP1"
}
resource "azurerm_linux_function_app" "test" {
name = "acctestWA-%[1]d"
name = "acctestLA-%[1]d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
service_plan_id = azurerm_service_plan.test.id
Expand Down
Loading

0 comments on commit af17bdc

Please sign in to comment.