diff --git a/Tasks/AzureRmWebAppDeployment/Strings/resources.resjson/en-US/resources.resjson b/Tasks/AzureRmWebAppDeployment/Strings/resources.resjson/en-US/resources.resjson index 5fa2ee009283..e451eba420b2 100644 --- a/Tasks/AzureRmWebAppDeployment/Strings/resources.resjson/en-US/resources.resjson +++ b/Tasks/AzureRmWebAppDeployment/Strings/resources.resjson/en-US/resources.resjson @@ -210,5 +210,6 @@ "loc.messages.UpdatedAppServiceConfigurationSettings": "Updated App Service Configuration settings.", "loc.messages.UpdatingAppServiceApplicationSettings": "Updating App Service Application settings. Data: %s", "loc.messages.UpdatedAppServiceApplicationSettings": "Updated App Service Application settings and Kudu Application settings.", - "loc.messages.MultipleResourceGroupFoundForAppService": "Multiple resource group found for App Service '%s'." + "loc.messages.MultipleResourceGroupFoundForAppService": "Multiple resource group found for App Service '%s'.", + "loc.messages.WarDeploymentRetry": "Retrying war file deployment as it did not expand successfully earlier." } \ No newline at end of file diff --git a/Tasks/AzureRmWebAppDeployment/azurermwebappdeployment.ts b/Tasks/AzureRmWebAppDeployment/azurermwebappdeployment.ts index eda0db747ef0..d31f73d0461f 100644 --- a/Tasks/AzureRmWebAppDeployment/azurermwebappdeployment.ts +++ b/Tasks/AzureRmWebAppDeployment/azurermwebappdeployment.ts @@ -13,6 +13,7 @@ import { TaskParameters, TaskParametersUtility } from './operations/TaskParamete import { FileTransformsUtility } from './operations/FileTransformsUtility'; import * as ParameterParser from './parameterparser' import { addReleaseAnnotation } from './operations/ReleaseAnnotationUtility'; +import { DeployWar } from './operations/WarDeploymentUtilities'; var packageUtility = require('webdeployment-common/packageUtility.js'); @@ -87,9 +88,14 @@ async function main() { } var msDeployPublishingProfile = await appServiceUtility.getWebDeployPublishingProfile(); - await msDeploy.DeployUsingMSDeploy(webPackage, taskParams.WebAppName, msDeployPublishingProfile, taskParams.RemoveAdditionalFilesFlag, + if (webPackage.toString().toLowerCase().endsWith('.war')) { + await DeployWar(webPackage, taskParams, msDeployPublishingProfile, kuduService, appServiceUtility); + } + else { + await msDeploy.DeployUsingMSDeploy(webPackage, taskParams.WebAppName, msDeployPublishingProfile, taskParams.RemoveAdditionalFilesFlag, taskParams.ExcludeFilesFromAppDataFlag, taskParams.TakeAppOfflineFlag, taskParams.VirtualApplication, taskParams.SetParametersFile, taskParams.AdditionalArguments, isFolderBasedDeployment, taskParams.UseWebDeploy); + } } else { tl.debug("Initiated deployment via kudu service for webapp package : "); @@ -102,7 +108,7 @@ async function main() { var customApplicationSettings = ParameterParser.parse(taskParams.AppSettings); await appServiceUtility.updateAndMonitorAppSettings(customApplicationSettings); } - + if(taskParams.ConfigurationSettings) { var customApplicationSettings = ParameterParser.parse(taskParams.ConfigurationSettings); await appServiceUtility.updateConfigurationSettings(customApplicationSettings); @@ -113,7 +119,7 @@ async function main() { } if(taskParams.ScriptType) { - await kuduServiceUtility.runPostDeploymentScript(taskParams, virtualApplicationPath); + await kuduServiceUtility.runPostDeploymentScript(taskParams, virtualApplicationPath); } await appServiceUtility.updateScmTypeAndConfigurationDetails(); diff --git a/Tasks/AzureRmWebAppDeployment/operations/WarDeploymentUtilities.ts b/Tasks/AzureRmWebAppDeployment/operations/WarDeploymentUtilities.ts new file mode 100644 index 000000000000..e3ca19259baa --- /dev/null +++ b/Tasks/AzureRmWebAppDeployment/operations/WarDeploymentUtilities.ts @@ -0,0 +1,69 @@ +import tl = require('vsts-task-lib/task'); +import fs = require('fs'); +import path = require('path'); +import { Kudu } from 'azure-arm-rest/azure-arm-app-service-kudu'; +import { AzureAppServiceUtility } from './AzureAppServiceUtility'; +import { TaskParameters } from './TaskParameters'; +import { sleepFor } from 'azure-arm-rest/webClient'; + +var msDeploy = require('webdeployment-common/deployusingmsdeploy.js'); + +export async function DeployWar(webPackage, taskParams: TaskParameters, msDeployPublishingProfile, kuduService: Kudu, appServiceUtility: AzureAppServiceUtility): Promise { + // get list of files before deploying to the web app. + var listOfFilesBeforeDeployment: any = await kuduService.listDir('/site/wwwroot/webapps/'); + tl.debug("Listing file structure of webapps folder before deployment starts => " + JSON.stringify(listOfFilesBeforeDeployment)); + + // Strip package path and only keep the package name. + var warFileName = path.basename(webPackage).split('.war')[0]; + + // Find if directory with same name as war file, existed before deployment + var directoryWithSameNameBeforeDeployment; + if (listOfFilesBeforeDeployment) { + listOfFilesBeforeDeployment.some(item => { + if (item.name == warFileName && item.mime == "inode/directory") { + directoryWithSameNameBeforeDeployment = item; + return true; + } + return false; + }); + } + + var retryCount = 3; + while (retryCount > 0) { + await msDeploy.DeployUsingMSDeploy(webPackage, taskParams.WebAppName, msDeployPublishingProfile, taskParams.RemoveAdditionalFilesFlag, + taskParams.ExcludeFilesFromAppDataFlag, taskParams.TakeAppOfflineFlag, taskParams.VirtualApplication, taskParams.SetParametersFile, + taskParams.AdditionalArguments, false, taskParams.UseWebDeploy); + + // verify if the war file has expanded + // if not expanded, deploy using msdeploy once more, to make it work. + var hasWarExpandedSuccessfully: boolean = await HasWarExpandedSuccessfully(kuduService, directoryWithSameNameBeforeDeployment, warFileName, appServiceUtility); + if (!hasWarExpandedSuccessfully) { + console.log(tl.loc("WarDeploymentRetry")); + // If the war file is exactly same, MSDeploy doesn't update the war file in webapp. + // So by changing ModifiedTime, we ensure it will be updated. + var currentTime = new Date(Date.now()); + var modifiedTime = new Date(Date.now()); + fs.utimesSync(webPackage, currentTime, modifiedTime); + } + else { + break; + } + + retryCount--; + } +} + +export async function HasWarExpandedSuccessfully(kuduService: Kudu, directoryWithSameNameBeforeDeployment: any, warFileName: string, appServiceUtility: AzureAppServiceUtility): Promise { + // Waiting for war to expand + await sleepFor(10); + + // do a get call on the target web app. + await appServiceUtility.pingApplication(); + var filesAfterDeployment: any = await kuduService.listDir('/site/wwwroot/webapps/'); + tl.debug("Listing file structure of webapps folder after deployment has completed => " + JSON.stringify(filesAfterDeployment)); + + // Verify if the content of that war file has successfully expanded. This is can be concluded if + // directory with same name as war file exists after deployment and if it existed before deployment, then the directory should contain content of new war file + // which can be concluded if the modified time of the directory has changed. + return filesAfterDeployment.some(item => { return item.name == warFileName && item.mime == "inode/directory" && (!directoryWithSameNameBeforeDeployment || item.mtime != directoryWithSameNameBeforeDeployment.mtime) }); +} \ No newline at end of file diff --git a/Tasks/AzureRmWebAppDeployment/task.json b/Tasks/AzureRmWebAppDeployment/task.json index 9418a8a8a7ef..106db7753267 100644 --- a/Tasks/AzureRmWebAppDeployment/task.json +++ b/Tasks/AzureRmWebAppDeployment/task.json @@ -16,7 +16,7 @@ "version": { "Major": 3, "Minor": 3, - "Patch": 41 + "Patch": 42 }, "releaseNotes": "What's new in Version 3.0:
  Supports File Transformations (XDT)
  Supports Variable Substitutions(XML, JSON)
Click [here](https://aka.ms/azurermwebdeployreadme) for more Information.", "minimumAgentVersion": "2.104.1", @@ -138,7 +138,7 @@ "EditableOptions": "false", "PopulateDefaultValue": "true" }, - "helpMarkDown": "App Service on Linux offers two different options to publish your application
Custom image deployment or App deployment with a built-in platform image. [Learn More](https://go.microsoft.com/fwlink/?linkid=862490)", + "helpMarkDown": "App Service on Linux offers two different options to publish your application
Custom image deployment or App deployment with a built-in platform image. [Learn More](https://go.microsoft.com/fwlink/?linkid=862490)", "visibleRule": "WebAppKind = applinux || WebAppKind = linux" }, { @@ -570,7 +570,7 @@ "endpointId": "$(ConnectedServiceName)", "dataSourceName": "AzureContainerRegistryTags", "parameters": { - "AzureContainerRegistryLoginServer": "$(AzureContainerRegistryLoginServer)", + "AzureContainerRegistryLoginServer": "$(AzureContainerRegistryLoginServer)", "AzureContainerRegistryImage": "$(AzureContainerRegistryImage)" } }, @@ -601,14 +601,14 @@ "endpointId": "$(RegistryConnectedServiceName)", "endpointUrl": "{{endpoint.url}}v2/_catalog", "resultSelector": "jsonpath:$.repositories[*]", - "authorizationHeader": "Basic {{ #base64 endpoint.username \":\" endpoint.password }}" + "authorizationHeader": "Basic {{ #base64 endpoint.username \":\" endpoint.password }}" }, { "target": "PrivateRegistryTag", "endpointId": "$(RegistryConnectedServiceName)", "endpointUrl": "{{endpoint.url}}v2/$(PrivateRegistryImage)/tags/list", "resultSelector": "jsonpath:$.tags[*]", - "authorizationHeader": "Basic {{ #base64 endpoint.username \":\" endpoint.password }}" + "authorizationHeader": "Basic {{ #base64 endpoint.username \":\" endpoint.password }}" } ], "instanceNameFormat": "Azure App Service Deploy: $(WebAppName)", @@ -739,6 +739,7 @@ "UpdatedAppServiceConfigurationSettings": "Updated App Service Configuration settings.", "UpdatingAppServiceApplicationSettings": "Updating App Service Application settings. Data: %s", "UpdatedAppServiceApplicationSettings": "Updated App Service Application settings and Kudu Application settings.", - "MultipleResourceGroupFoundForAppService": "Multiple resource group found for App Service '%s'." + "MultipleResourceGroupFoundForAppService": "Multiple resource group found for App Service '%s'.", + "WarDeploymentRetry": "Retrying war file deployment as it did not expand successfully earlier." } } diff --git a/Tasks/AzureRmWebAppDeployment/task.loc.json b/Tasks/AzureRmWebAppDeployment/task.loc.json index b8a1fc8e451a..7ee6eff24bfb 100644 --- a/Tasks/AzureRmWebAppDeployment/task.loc.json +++ b/Tasks/AzureRmWebAppDeployment/task.loc.json @@ -16,7 +16,7 @@ "version": { "Major": 3, "Minor": 3, - "Patch": 41 + "Patch": 42 }, "releaseNotes": "ms-resource:loc.releaseNotes", "minimumAgentVersion": "2.104.1", @@ -751,6 +751,7 @@ "UpdatedAppServiceConfigurationSettings": "ms-resource:loc.messages.UpdatedAppServiceConfigurationSettings", "UpdatingAppServiceApplicationSettings": "ms-resource:loc.messages.UpdatingAppServiceApplicationSettings", "UpdatedAppServiceApplicationSettings": "ms-resource:loc.messages.UpdatedAppServiceApplicationSettings", - "MultipleResourceGroupFoundForAppService": "ms-resource:loc.messages.MultipleResourceGroupFoundForAppService" + "MultipleResourceGroupFoundForAppService": "ms-resource:loc.messages.MultipleResourceGroupFoundForAppService", + "WarDeploymentRetry": "ms-resource:loc.messages.WarDeploymentRetry" } } \ No newline at end of file