Azure App Service deploy task option to remove files in container upon deployment
F

2

6

I am deploying a python web app using Web App on Linux service and using a DevOps release pipeline. The pipeline task that I am using is called AzureRmWebAppDeployment@4.

Between deployments, the files in the container are not being removed and this is causing issues.

I noticed if I am using a different type of app service (i.e. Web App on Windows) and if the deployment method is set to Web Deploy the option for Remove additional files at destination exists (see screenshot). However we are using a Zip Deploy method and prefer to be using a linux service. without that combination of app service and deployment method, this option is not available to me.

enter image description here

Can anybody suggest an alternate method for deleting the container contents upon deployment? Also, any insight as to why this option is not available through the pipeline task when using Zip Deploy and Linux?

Thanks in advance for any help provided.

Fabiano answered 1/6, 2020 at 19:2 Comment(0)
U
7

You can use kudu command api to clean the wwwroot folder on your webapp server. The kudu command rest api will execute the command in the specified directory on the server.

{
    command = "find . -mindepth 1 -delete"  
    dir = "/home/site/wwwroot
} 

Add an Azure powershell task before Azure app service deploy task, and run below inline scripts.

$ResGroupName = ""
$WebAppName = ""

# Get publishing profile for web application
$WebApp = Get-AzWebApp -Name $WebAppName -ResourceGroupName $ResGroupName
[xml]$publishingProfile = Get-AzWebAppPublishingProfile -WebApp $WebApp

# Create Base64 authorization header
$username = $publishingProfile.publishData.publishProfile[0].userName
$password = $publishingProfile.publishData.publishProfile[0].userPWD
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username,$password)))

$bodyToPOST = @{  
                  command = "find . -mindepth 1 -delete"  
                  dir = "/home/site/wwwroot"  
}  
# Splat all parameters together in $param  
$param = @{  
            # command REST API url  
            Uri = "https://$WebAppName.scm.azurewebsites.net/api/command"  
            Headers = @{Authorization=("Basic {0}" -f $base64AuthInfo)}  
            Method = "POST"  
            Body = (ConvertTo-Json $bodyToPOST)  
            ContentType = "application/json"  
}  
# Invoke REST call  
Invoke-RestMethod @param  

Above scripts will empty the folder /home/site/wwwroot before each deployment.

If you need to delete specific files on the app server, you can use kudu delete rest api:

DELETE /api/vfs/{path}
Delete the file at path.

For more examples you can check here.

Unclean answered 2/6, 2020 at 8:15 Comment(6)
Thank you, this seems like a very promising solution. I have been trying to run the Azure Powershell task and keep running into this error: Could not find the modules: 'Az.Accounts' with Version: '1.0.0'. If the module was recently installed, retry after restarting the Azure Pipelines task agent I found this article and tried the suggestions but still not working out. Are you familiar with this error message?Fabiano
What is your pipeline agent? what is the azure powershell task version and Azure PowerShell Version? I ran above scripts successfully on agent ubuntu 18.04 with azure powershell task version 4 and the latest installed Azure PowerShell VersionUnclean
Thanks, that was the issue. I was using the incorrect agent. I am accepting your answer. Much appreciatedFabiano
do you know a way to make your answer above specific to a slot? I am running into issue now because the az powershell task is wiping out the production slot. Ideally it would wipe out the staging slot, to which we deploy.Fabiano
You can try changing the Uri in $param to Uri = "https://$WebAppName-$slotName.scm.azurewebsites.net/api/command"Unclean
as an update to your suggestion above, this does not seem to work. I am getting an error when running the script: Error 403 - This web app is stopped. The web app you have attempted to reach is currently stopped and does not accept any requests.. This is despite the fact that the web app is not stopped.Fabiano
S
2

This is a slight modification to Levi Lu-MSFT's answer that will work for production or slots:

$ResGroupName = ""
$WebAppName = ""
$SlotName = ""

# Get publishing profile for web application
if([string]::IsNullOrEmpty($SlotName)) {
  $WebApp = Get-AzWebApp -Name $WebAppName -ResourceGroupName $ResGroupName
  [xml]$publishingProfile = Get-AzWebAppPublishingProfile -WebApp $WebApp
  $Uri = "https://$WebAppName.scm.azurewebsites.net/api/command"
} else {
  $WebApp = Get-AzWebAppSlot -Name $WebAppName -ResourceGroupName $ResGroupName -Slot $SlotName    
  [xml]$publishingProfile = Get-AzWebAppSlotPublishingProfile -WebApp $WebApp  
  $Uri = "https://$WebAppName-$SlotName.scm.azurewebsites.net/api/command"
}

# Create Base64 authorization header
$username = $publishingProfile.publishData.publishProfile[0].userName
$password = $publishingProfile.publishData.publishProfile[0].userPWD
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username,$password)))

$bodyToPOST = @{  
                  command = "find . -mindepth 1 -delete"  
                  dir = "/home/site/wwwroot"  
}  
# Splat all parameters together in $param  
$param = @{  
            # command REST API url  
            Uri = $Uri  
            Headers = @{Authorization=("Basic {0}" -f $base64AuthInfo)}  
            Method = "POST"  
            Body = (ConvertTo-Json $bodyToPOST)  
            ContentType = "application/json"  
}  
# Invoke REST call  
Invoke-RestMethod @param   
Siam answered 1/6, 2021 at 21:10 Comment(2)
Welcome to Stack Overflow, and thank you for your contribution. Given the length of the script, can you further clarify what you changed from Levi's solution, and why you feel this is a better approach?Algicide
Hi @JeremyCaney, Levi's solution only works on the default production slot of an Azure App Services instance. Often, it's desirable to test on a non-prod deployment slot first. By providing the name of the deplotment slot as $SlotName, it will affect change on the slot only, which is the value add of my changes. If $SlotName is null or empty, it will affect change on the default production slot just like Levi's solution.Siam

© 2022 - 2025 — McMap. All rights reserved.