Skip to content

Commit fb357c0

Browse files
hemarinaMenghua1
authored andcommitted
fix bug where windows logic app passed isLinuxWebApp (#4073)
* logic app windows has "" in LinuxFxVersion * make sure app service kind is linux web app only, add test * add check if response is empty, fall to original deployment * add 404 resource not found case
1 parent 97ec109 commit fb357c0

File tree

3 files changed

+137
-8
lines changed

3 files changed

+137
-8
lines changed

cli/azd/pkg/azsdk/zip_deploy_client.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,11 @@ func logWebAppDeploymentStatus(
187187
traceId string,
188188
progressLog func(string),
189189
) error {
190+
if (res == armappservice.WebAppsClientGetProductionSiteDeploymentStatusResponse{} ||
191+
res.CsmDeploymentStatus == armappservice.CsmDeploymentStatus{} ||
192+
res.CsmDeploymentStatus.Properties == nil) {
193+
return fmt.Errorf("response or its properties are empty")
194+
}
190195
properties := res.CsmDeploymentStatus.Properties
191196
inProgressNumber := int(*properties.NumberOfInstancesInProgress)
192197
successNumber := int(*properties.NumberOfInstancesSuccessful)

cli/azd/pkg/tools/azcli/azcli_linuxwebapp_test.go

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"testing"
1212

1313
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/appservice/armappservice/v2"
14+
"github.com/azure/azure-dev/cli/azd/pkg/azsdk"
1415
"github.com/azure/azure-dev/cli/azd/pkg/convert"
1516
"github.com/azure/azure-dev/cli/azd/test/mocks"
1617
"github.com/stretchr/testify/require"
@@ -67,6 +68,31 @@ func Test_DeployTrackLinuxWebAppStatus(t *testing.T) {
6768
require.True(t, ran)
6869
require.Error(t, err)
6970
})
71+
72+
t.Run("Error", func(t *testing.T) {
73+
ran := false
74+
mockContext := mocks.NewMockContext(context.Background())
75+
azCli := newAzCliFromMockContext(mockContext)
76+
77+
registerLogicAppMocks(mockContext, &ran)
78+
registerLogicAppZipDeployMocks(mockContext, &ran)
79+
registerLogicAppPollingMocks(mockContext, &ran)
80+
81+
zipFile := bytes.NewReader([]byte{})
82+
83+
res, err := azCli.DeployAppServiceZip(
84+
*mockContext.Context,
85+
"SUBSCRIPTION_ID",
86+
"RESOURCE_GROUP_ID",
87+
"WINDOWS_LOGIC_APP_NAME",
88+
zipFile,
89+
func(s string) {},
90+
)
91+
92+
require.NoError(t, err)
93+
require.True(t, ran)
94+
require.NotNil(t, res)
95+
})
7096
}
7197

7298
func registerIsLinuxWebAppMocks(mockContext *mocks.MockContext, ran *bool) {
@@ -79,7 +105,7 @@ func registerIsLinuxWebAppMocks(mockContext *mocks.MockContext, ran *bool) {
79105
response := armappservice.WebAppsClientGetResponse{
80106
Site: armappservice.Site{
81107
Location: convert.RefOf("eastus2"),
82-
Kind: convert.RefOf("appserivce"),
108+
Kind: convert.RefOf("app,linux"),
83109
Name: convert.RefOf("LINUX_WEB_APP_NAME"),
84110
Properties: &armappservice.SiteProperties{
85111
DefaultHostName: convert.RefOf("LINUX_WEB_APP_NAME.azurewebsites.net"),
@@ -100,6 +126,61 @@ func registerIsLinuxWebAppMocks(mockContext *mocks.MockContext, ran *bool) {
100126
})
101127
}
102128

129+
func registerLogicAppMocks(mockContext *mocks.MockContext, ran *bool) {
130+
mockContext.HttpClient.When(func(request *http.Request) bool {
131+
return request.Method == http.MethodGet &&
132+
strings.Contains(request.URL.Path,
133+
"/subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP_ID/providers/Microsoft.Web/sites/WINDOWS_LOGIC_APP_NAME")
134+
}).RespondFn(func(request *http.Request) (*http.Response, error) {
135+
*ran = true
136+
response := armappservice.WebAppsClientGetResponse{
137+
Site: armappservice.Site{
138+
Location: convert.RefOf("eastus2"),
139+
Kind: convert.RefOf("functionapp"),
140+
Name: convert.RefOf("WINDOWS_LOGIC_APP_NAME"),
141+
Properties: &armappservice.SiteProperties{
142+
DefaultHostName: convert.RefOf("WINDOWS_LOGIC_APP_NAME.azurewebsites.net"),
143+
SiteConfig: &armappservice.SiteConfig{
144+
LinuxFxVersion: convert.RefOf(""),
145+
},
146+
HostNameSSLStates: []*armappservice.HostNameSSLState{
147+
{
148+
HostType: convert.RefOf(armappservice.HostTypeRepository),
149+
Name: convert.RefOf("WINDOWS_LOGIC_APP_SCM_HOST"),
150+
},
151+
},
152+
},
153+
},
154+
}
155+
156+
return mocks.CreateHttpResponseWithBody(request, http.StatusOK, response)
157+
})
158+
}
159+
160+
func registerLogicAppPollingMocks(mockContext *mocks.MockContext, ran *bool) {
161+
// Polling call to check on the deployment status
162+
mockContext.HttpClient.When(func(request *http.Request) bool {
163+
return request.Method == http.MethodGet && strings.Contains(request.URL.Path, "/deployments/latest")
164+
}).RespondFn(func(request *http.Request) (*http.Response, error) {
165+
*ran = true
166+
completeStatus := azsdk.DeployStatusResponse{
167+
DeployStatus: azsdk.DeployStatus{
168+
Id: "ID",
169+
Status: http.StatusOK,
170+
StatusText: "OK",
171+
Message: "Deployment Complete",
172+
Progress: nil,
173+
Complete: true,
174+
Active: true,
175+
SiteName: "WINDOWS_LOGIC_APP_NAME",
176+
LogUrl: "https://log.url",
177+
},
178+
}
179+
180+
return mocks.CreateHttpResponseWithBody(request, http.StatusOK, completeStatus)
181+
})
182+
}
183+
103184
func registerLinuxWebAppDeployRuntimeSuccessfulMocks(mockContext *mocks.MockContext, ran *bool) {
104185
mockContext.HttpClient.When(func(request *http.Request) bool {
105186
//nolint:lll
@@ -158,6 +239,21 @@ func registerLinuxWebAppDeployRuntimeFailedMocks(mockContext *mocks.MockContext,
158239
})
159240
}
160241

242+
func registerLogicAppZipDeployMocks(mockContext *mocks.MockContext, ran *bool) {
243+
// Original call to start the deployment operation
244+
mockContext.HttpClient.When(func(request *http.Request) bool {
245+
return request.Method == http.MethodPost &&
246+
request.URL.Host == "WINDOWS_LOGIC_APP_SCM_HOST" &&
247+
strings.Contains(request.URL.Path, "/api/zipdeploy")
248+
}).RespondFn(func(request *http.Request) (*http.Response, error) {
249+
*ran = true
250+
response, _ := mocks.CreateEmptyHttpResponse(request, http.StatusAccepted)
251+
response.Header.Set("Location", "https://WINDOWS_LOGIC_APP_SCM_HOST/deployments/latest")
252+
253+
return response, nil
254+
})
255+
}
256+
161257
func registerLinuxWebAppZipDeployMocks(mockContext *mocks.MockContext, ran *bool) {
162258
mockContext.HttpClient.When(func(request *http.Request) bool {
163259
return request.Method == http.MethodPost &&

cli/azd/pkg/tools/azcli/webapp.go

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ package azcli
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"io"
8+
"strings"
79

10+
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
811
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/appservice/armappservice/v2"
912
"github.com/azure/azure-dev/cli/azd/pkg/azsdk"
1013
"github.com/azure/azure-dev/cli/azd/pkg/convert"
@@ -50,8 +53,9 @@ func (cli *azCli) appService(
5053
}
5154

5255
func isLinuxWebApp(response *armappservice.WebAppsClientGetResponse) bool {
53-
if response.Properties != nil && response.Properties.SiteConfig != nil &&
54-
response.Properties.SiteConfig.LinuxFxVersion != nil {
56+
if *response.Kind == "app,linux" && response.Properties != nil && response.Properties.SiteConfig != nil &&
57+
response.Properties.SiteConfig.LinuxFxVersion != nil &&
58+
*response.Properties.SiteConfig.LinuxFxVersion != "" {
5559
return true
5660
}
5761
return false
@@ -76,6 +80,28 @@ func appServiceRepositoryHost(
7680
return hostName, nil
7781
}
7882

83+
func resumeDeployment(err error, progressLog func(msg string)) bool {
84+
if strings.Contains(err.Error(), "empty deployment status id") {
85+
progressLog("Deployment status id is empty. Failed to enable tracking runtime status." +
86+
"Resuming deployment without tracking status.")
87+
return true
88+
}
89+
90+
if strings.Contains(err.Error(), "response or its properties are empty") {
91+
progressLog("Response or its properties are empty. Failed to enable tracking runtime status." +
92+
"Resuming deployment without tracking status.")
93+
return true
94+
}
95+
96+
var httpErr *azcore.ResponseError
97+
if errors.As(err, &httpErr) && httpErr.StatusCode == 404 {
98+
progressLog("Resource not found. Failed to enable tracking runtime status." +
99+
"Resuming deployment without tracking status.")
100+
return true
101+
}
102+
return false
103+
}
104+
79105
func (cli *azCli) DeployAppServiceZip(
80106
ctx context.Context,
81107
subscriptionId string,
@@ -102,12 +128,14 @@ func (cli *azCli) DeployAppServiceZip(
102128
// Deployment Status API only support linux web app for now
103129
if isLinuxWebApp(app) {
104130
if err := client.DeployTrackStatus(ctx, deployZipFile, subscriptionId, resourceGroup, appName, progressLog); err != nil {
105-
return nil, err
131+
if !resumeDeployment(err, progressLog) {
132+
return nil, err
133+
}
134+
} else {
135+
// Deployment is successful
136+
statusText := "OK"
137+
return convert.RefOf(statusText), nil
106138
}
107-
108-
// Deployment is successful
109-
statusText := "OK"
110-
return convert.RefOf(statusText), nil
111139
}
112140

113141
response, err := client.Deploy(ctx, deployZipFile)

0 commit comments

Comments
 (0)