PS Script to manage Azure Batch Application Version Retention - azure

We have an Azure Devops release that builds our repo, packages it, and deploys it to our Azure Batch service with the following PowerShell script:
New-AzureRmBatchApplicationPackage -AccountName "$(BatchAccountName)" -ResourceGroupName "$(ResourceGroupName)" -ApplicationId "$(ApplicationId)" -ApplicationVersion "$(Build.BuildNumber)-$(Release.ReleaseId)" -Format zip -FilePath "$(System.DefaultWorkingDirectory)/_artifact/artifact/bin/theapplication.zip"
Set-AzureRmBatchApplication -AccountName "$(BatchAccountName)" -ResourceGroupName "$(ResourceGroupName)" -ApplicationId "$(ApplicationId)" -DefaultVersion "$(Build.BuildNumber)-$(Release.ReleaseId)"
$Context = Get-AzureRmBatchAccount -AccountName "$(BatchAccountName)" -ResourceGroupName "$(ResourceGroupName)"
Get-AzureBatchComputeNode -PoolId "$(PoolId)" -BatchContext $Context | Restart-AzureBatchComputeNode -BatchContext $Context
The problem is, this doesn't seem to "clean up" old versions of the application package, and I don't see a way in the API documentation to do so. So every few weeks I get this sort of error message:
The maximum allowed number of application packages have already been
added for the specified application.
How can I change this script to deploy the application and clean up old versions so I don't have periodic failures in my deployment?

Depending on if you want to keep any history and how you version you should be able to call Get-AzBatchApplicationPackage to list application packages associated with an Application (https://learn.microsoft.com/en-us/powershell/module/az.batch/get-azbatchapplicationpackage?view=azps-1.7.0). Note that ApplicationVersion is actually optional for this call.
Then Remove-AzBatchApplicationPackage (https://learn.microsoft.com/en-us/powershell/module/Az.Batch/Remove-AzBatchApplicationPackage?view=azps-1.7.0) on any application packages you do not want to keep around, whether that is all application packages other than the one you added or some function on the version is up to you.

We use Azure CLI (in PowerShell), so the syntax is a bit different than yours. This is our script to achieve what you are asking for (and more). The key is to use the argument --query on some of the calls, to be able to count number of application versions, and get the oldest version:
$Environment = "dev"
$ResourceGroup="rg-name-$Environment"
$BatchAccount="batchname$Environment"
$BatchApplicationName="MyApplication"
$BatchApplicationVersion="1.2.3.4"
$SetAsDefaultVersion=$true
$MaxNumOfAppVersions=39
Write-Host "Uploading new version of application to batch service..."
$filename = "folder/file.zip"
$numOfVersions = az batch application package list --resource-group "$ResourceGroup" --name "$BatchAccount" --application-name "$BatchApplicationName" --query "length([].{name:name})"
Write-Host "There are currently $numOfVersions versions of the Application in the Batch Account"
if ($numOfVersions -gt $MaxNumOfAppVersions) {
# Do not automatically delete old version in the prod environment:
if (($Environment.ToLower() -eq "prod")) {
throw "The Batch Application $BatchApplicationName contains too many versions. Delete the oldest, after you have made sure that it is not in use in production."
}
$oldestAppVersion = az batch application package list --resource-group "$ResourceGroup" --name "$BatchAccount" --application-name "$BatchApplicationName" --query "sort_by([].{name:name, lastActivationTime:lastActivationTime}, &lastActivationTime)[0].{name:name}" -o tsv
Write-Host "Deleting the oldest version (by lastActivationTime) of the Application, $oldestAppVersion, to avoid the max limit"
az batch application package delete --resource-group "$ResourceGroup" --name "$BatchAccount" --application-name "$BatchApplicationName" --version-name $oldestAppVersion --yes
}
Write-Host "Uploading $filename..."
az batch application package create --resource-group "$ResourceGroup" --name "$BatchAccount" --application-name "$BatchApplicationName" --package-file "$filename" --version-name "$BatchApplicationVersion"
if ($SetAsDefaultVersion) {
Write-Host "Setting this new version $BatchApplicationVersion as the default version..."
az batch application set --resource-group "$ResourceGroup" --name "$BatchAccount" --application-name "$BatchApplicationName" --default-version "$BatchApplicationVersion"
}
Write-Host "All done!"

Related

Azure CLI script variables giving errors

I'm trying to run the sample script found here: https://learn.microsoft.com/en-au/azure/service-fabric/service-fabric-quickstart-containers-linux#create-a-service-fabric-cluster
#!/bin/bash
# Variables
ResourceGroupName='containertestcluster'
ClusterName='containertestcluster'
Location='eastus'
Password='q6D7nN%6ck#6'
Subject='containertestcluster.eastus.cloudapp.azure.com'
VaultName='containertestvault'
VmPassword='Mypa$$word!321'
VmUserName='sfadminuser'
# Login to Azure and set the subscription
az login
az account set --subscription <mySubscriptionID>
# Create resource group
az group create --name $ResourceGroupName --location $Location
# Create secure five node Linux cluster. Creates a key vault in a resource group
# and creates a certficate in the key vault. The certificate's subject name must match
# the domain that you use to access the Service Fabric cluster. The certificate is downloaded locally.
az sf cluster create --resource-group $ResourceGroupName --location $Location --certificate-output-folder . --certificate-password $Password --certificate-subject-name $Subject --cluster-name $ClusterName --cluster-size 5 --os UbuntuServer1604 --vault-name $VaultName --vault-resource-group $ResourceGroupName --vm-password $VmPassword --vm-user-name $VmUserName
From the command prompt or PowerShell, I run "az login" and login, then I copy & paste this script into the console but get errors when it comes to the variables.
I see you use the Shell script, it's more appropriate to run in Linux. For Windows, the PowerShell script is more suitable. And in Windows, the variables need to be set like this:
$varName = 'xxxx'
So you need to change all the variables like above. And I suggest you change the script into a PowerShell script.

What is the right way to get Azure Cognitive service account endpoint from Azure-CLI

I was using the following command
$cogVisionEndpoint = (az cognitiveservices account show -n $accountName -g $resourceGroupName --query endpoint --output tsv)
but I found out that this stopped working when I ran this on another machine with a slightly newer version of Azure-CLI.
The JSON returned by the az cognitiveservices account show command is not consistent and looks like it has changed from version to a version.
How can I reliably get this not having to worry about the version of Azure CLI on the machine that I'm running on?
Or is there a completely different way to get the endpoint value?
With the newest version you will find endpoint in properties and since you rely on CLI version installed on the given machine you can simply modify your code to something like this:
$cogVisionEndpoint = (az cognitiveservices account show -n $accountName -g $resourceGroupName --query endpoint --output tsv)
if( !$cogVisionEndpoint ) {
$cogVisionEndpoint = (az cognitiveservices account show -n $accountName -g $resourceGroupName --query "properties.endpoint" --output tsv)
}

Converting Azure Powershell commands to Azure CLI

I have a Powershell script using Azure Powershell to update an Virtual Machine Scale Set (under Azure Service Fabric) to add/remove the certificates that are used by the associated service fabric virtual machines. This script works as intended and I have the following commands (I've removed some of the other logic to focus on the issue):
# This gets the Virtual Machine Scale Set object
$virtualMachineScaleSet = Get-Azvmss -ResourceGroupName $myResourceGroupName -VMScaleSetName $myVMScaleSetName
# Example of removing items from certificate items from the VMSS object.
$virtualMachineScaleSet.VirtualMachineProfile.osProfile.Secrets[$mySecretIndex].VaultCertificates.RemoveAt($myCertificateIndexThatIWantToRemove)
# Example of creating new certificate config
$newCertificateUrl = (Get-AzKeyVaultCertificate -VaultName $myKeyvaultName -Name $myCertificateName).SecretId
$newCertificateConfig = New-AzvmssVaultCertificateConfig -CertificateUrl $newCertificateUrl -CertificateStore "My"
# Example of adding new certificate to the VMSS object
$virtualMachineScaleSet.VirtualMachineProfile.OsProfile.Secrets[$mySecretIndex].VaultCertificates.Add($newCertificateConfig)
# Committing the update to VMSS
Update-Azvmss -ResourceGroupName $myResourceGroupName -VirtualMachineScaleSet $virtualMachineScaleSet -VMScaleSetName $myVMScaleSetName
The above script works fine. However, I'm now trying to convert each of the above commands to Azure CLI. The way the script will invoke means that I cannot mix and match Azure Powershell and Azure CLI commands in the same script. The commands I have so far are causing problems:
# This gets me the Virtual Machine Scale Set object
$virtualMachineScaleSet = az vmss show --name $myVMScaleSetName --resource-group $myResourceGroupName | ConvertFrom-Json
# Trying to RemoveAt gives the error: MethodInvocationException: Exception calling "RemoveAt" with "1" argument(s): "Collection was of a fixed size."
$virtualMachineScaleSet.VirtualMachineProfile.osProfile.Secrets[$mySecretIndex].VaultCertificates.RemoveAt($myCertificateIndexThatIWantToRemove)
# Not sure the CLI equivalent commands of this
$newCertificateUrl = (Get-AzKeyVaultCertificate -VaultName $myKeyvaultName -Name $myCertificateName).SecretId
$newCertificateConfig = New-AzvmssVaultCertificateConfig -CertificateUrl $newCertificateUrl -CertificateStore "My"
# Trying to Add gives the error: MethodInvocationException: Exception calling "RemoveAt" with "1" argument(s): "Collection was of a fixed size."
$virtualMachineScaleSet.VirtualMachineProfile.OsProfile.Secrets[$mySecretIndex].VaultCertificates.Add($newCertificateConfig)
So my questions are.
What are the CLI equivalent commands for the Azure Powershell script?
Why doesn't the VMSS object in the Azure CLI script seem to be the same? (At least in that I cannot change the VaultCertificates array)
Thank you in advance
All the PowerShell you used can change into two equivalent CLI commands.
One for remove:
az vmss update --resource-group $myResourceGroupName --name $myVMScaleSetName --remove virtualMachineProfile.osProfile.secrets index
One for add:
az vmss update --resource-group $myResourceGroupName --name $myVMScaleSetName --add virtualMachineProfile.osProfile.secrets '{"sourceVault": {"id": "resourceId"},"vaultCertificates": [{"certificateStore": null,"certificateUrl": "certificateUrl"}]}'

Error "The specified application package does not exist." While checking that if azure batch application package is exists or not from azure cli?

I want to create an application package via bit-bucket deployment pipeline and I want to check that the same application package name and version is already available or not.
If available, then I want to update package-file in it.
If Not available, then want to create new one
But, If application package is not available then getting an error "The specified application package does not exist."
How to get rid of this error and go ahead with package creation step even if application package is available?
Here is Azure CLI Script written in my bit-bucket deployment pipeline
id=$(az batch application package show --application-name testName1 --name testAppName1 --resource-group testResourceGroup1 --version-name 3.0.2556955)
if [ "$id" == "" ]; then
echo "Application not available then creating new with same version number - 3.0.2556955"
az batch application package create --resource-group testResourceGroup1 --name testAppName1 --application-name testName1 --package-file test1.zip --version-name 3.0.2556955
else
echo "Application available then append the package file in it"
echo $id
az batch application package create --resource-group testResourceGroup1 --name testAppName1 --application-name testName1 --package-file test1.zip --version-name 3.0.2556955
fi
A better alternative to check this would be the az batch application package list command.
Example:
id=$(az batch application package list --application-name testName1 --name testAppName1 --resource-group testResourceGroup1 --query "[?name=='<version-number>'].id" --output tsv)
This would yield the resource id of the application if present, else be empty (unlike the az batch application package show command that gives a ValidationError as above).

Restoring Azure App Service backup to different site

How can I use Restore-AzureRmWebAppBackup to restore an app service to a different existing site? This can usually be done in the portal, but for some reason the destination app service is not listed, even though it's in the same resource group.
How can I use Restore-AzureRmWebAppBackup to restore an app service to a different existing site?
Here is a sample code of restore web app from PowerShell.
$resourceGroupName = "target web app resource group name"
$appName = "target web app name"
$blobName = "backup blob name"
$storageAccountURL = "SAS URL of your blob container"
Restore-AzureRmWebAppBackup -ResourceGroupName $resourceGroupName -Name $appName -StorageAccountUrl $storageAccountURL -BlobName $blobName -Overwrite
We can find the blob name from the restore page after you backup your web app.
For more information, link below is for your reference.
Use PowerShell to back up and restore App Service apps
Following is the solution using Bash CLI:
prerequisite: A storage account with a container and the container URL for the same. The container URL contains the access the key (SAS). More information about the container URL can be found here: https://learn.microsoft.com/en-us/azure/storage/storage-dotnet-shared-access-signature-part-1
You can also use the following command to generate the SAS token:
az storage container generate-sas --name <container-name> --expiry <sas-expiry> --permissions <permissions> --account-name <account-name> --account-key <account-key>
To clone the app, use the following commands:
backupname=appname_`date "+%Y%m%d%H%M%S"`
az webapp config backup create --resource-group $OriginresourceGroupName --webapp-name $originAppName --backup-name $backupname --slot $OriginSlotName --container-url "$ContainerURL"
az webapp config backup restore --backup-name $backupname --container-url $ContainerURL --resource-group $TargetresourceGroupName --webapp-name $TargetAppname --overwrite --ignore-hostname-conflict
Use below cmdlets to restore last successful backup to slot or app
$resourceGroupName = "<<RG NAME>>"
$primarywebappname = "<<APP NAME>>"
$slotname = "<<SLOT NAME>>"
# Get the last Sucessfull BackupID of the backup you want to restore
$backupID=Get-AzWebAppBackupList -ResourceGroupName $resourceGroupName -Name `
$primarywebappname|where BackupStatus -EQ "Succeeded" |select -Last 1 |select BackupId
# Get the backup object that you want to restore by specifying the BackupID
$backup = (Get-AzWebAppBackupList -ResourceGroupName $resourceGroupName -Name
$primarywebappname | where {$PSItem.BackupId -eq $backupID.BackupId})
# Restore the app by overwriting it with the backup data in the slot
$backup |Restore-AzWebAppBackup -Slot $slotname -IgnoreConflictingHostNames -Overwrite
# Restore the app by overwriting into the exsisting App
$backup |Restore-AzWebAppBackup -Overwrite

Resources