2
votes

I'm working for an Azure project where the deployments can only be made using the ARM templates from Visual Studio CI and we have only read access to the Azure Portal.

Currently I'm getting the below error and can make no releases. I cannot delete deployments from Portal either since I have only permission to configure build and release phases, I was wondering if there is any phase I can create where the previous deployments are deleted.

So far I tried couple of things like using inline PowerShell command Remove-AzureRmResourceGroupDeployment , deleting resource group of type Microsoft.Resouces/deployments before the resource deployment phase but non of them worked.

[error]Creating the deployment 'azuredeploy-2017721-715' would exceed the quota of '800'. The current deployment count is '800', please delete some deployments before creating a new one. Please see https://aka.ms/arm-deploy for usage details.

2
Login-AzureRmAccount command opens a popup for logging in hence it seems that cannot be used during a deploymentOnur Kucukkece

2 Answers

1
votes

Here is a script that allows you to delete such deployments in a parallel manner. You can also use this for an Azure PowerShell task in Azure DevOps. If you have issues regarding authentication have a look here: Azure credentials have not been set up or have expired, please run Connect-AzAccount

Param(
    [string] 
    [Parameter(Mandatory = $true)]
    $subscriptionId,

    [string] 
    [Parameter(Mandatory = $true)]
    $tenantId,

    [string] 
    [Parameter(Mandatory = $true)]
    $resourceGroupName,

    [int] 
    [Parameter(Mandatory = $true)]
    $numberOfDeploymentsToKeep,

    [int] 
    [Parameter(Mandatory = $true)]
    $batchSize
)

try {
    $c = Get-AzContext
}
catch {
    $c = $null
}

if (!$c -or !$c.Account) {
    Connect-AzAccount -Subscription $subscriptionId -Tenant $tenantId
} else {
    Select-AzSubscription -Subscription $subscriptionId -Tenant $tenantId
}

# ----------------------------------
# Get Deployments
# ----------------------------------

#$dateBeforeDeleteDeployments = Get-Date -Year 2018 -Month 06 -Day 30
#$deploymentsToDelete = Get-AzResourceGroupDeployment -ResourceGroupName $resourceGroupName | Where-Object { $_.Timestamp -le $dateBeforeDeleteDeployments }

$currentDeployments = Get-AzResourceGroupDeployment -ResourceGroupName $resourceGroupName

$currentNumberOfDeployments = ($currentDeployments | Measure-Object).Count
$numberOfDeploymentsToRemove = $currentNumberOfDeployments - $numberOfDeploymentsToKeep

if ($numberOfDeploymentsToRemove -lt 0) {
    throw "Number of deployments to remove is < 0..."
} 
if ($numberOfDeploymentsToRemove -eq 0) {
    Write-Host "Number of deployments to remove is 0..."
    return
}

Write-Host "Number of Deployments to remove: '$numberOfDeploymentsToRemove'..."

$deploymentsToDelete = $currentDeployments | Sort-Object -Property Timestamp | Select-Object -First $numberOfDeploymentsToRemove

$deploymentsToDelete | ForEach-Object {$i=0; $j=0; $deploymentsToDeleteBatched=@{}} {
    if($i -ne $batchSize -and $deploymentsToDeleteBatched["Batch $j"]) { 
        $deploymentsToDeleteBatched["Batch $j"]+=$_
        $i+=1 
    }
    else {
        $i=1
        $j+=1
        $deploymentsToDeleteBatched["Batch $j"]=@($_)
    }
}

Write-Host "Created $($deploymentsToDeleteBatched.Count) batches..."

# ----------------------------------
# Execute deletion in parallel
# ----------------------------------
$jobNames = @()
foreach ($batchkey in $deploymentsToDeleteBatched.Keys) {
    $deploymentsToDeleteBatch = $deploymentsToDeleteBatched.$batchkey

    $logic = {
        Param(
            [object] 
            [Parameter(Mandatory = $true)]
            $ctx,

            [object] 
            [Parameter(Mandatory = $true)]
            $deploymentsToDeleteBatch,

            [string] 
            [Parameter(Mandatory = $true)]
            $resourceGroupName
        )

        foreach ($deploymentToDelete in $deploymentsToDeleteBatch) {
            $deploymentName = $deploymentToDelete.DeploymentName
            Remove-AzResourceGroupDeployment -ResourceGroupName $resourceGroupName -Name $deploymentName -DefaultProfile $ctx -ErrorAction Stop
            Write-Host "Deleted Deployment '$deploymentName' from '$($deploymentToDelete.Timestamp)'..."
        }  
    }

    $jobName = ([System.Guid]::NewGuid()).Guid
    $jobNames += $jobName
    $jobObject = Start-Job $logic -Name $jobName -ArgumentList (Get-AzContext), $deploymentsToDeleteBatch, $resourceGroupName
}

while (Get-Job -State "Running") {
    Write-Host "---------------------------------------------------------------"
    Write-Host "Jobs still running..."
    Get-Job | Format-Table
    Write-Host "---------------------------------------------------------------"
    Start-Sleep -Seconds 10
}

Write-Host "Jobs completed, getting output..."
Write-Host "---------------------------------------------------------------"

foreach ($jobName in $jobNames) {
    Write-Host "Output of Job '$jobName'..."
    Receive-Job -Name $jobName
    Write-Host "---------------------------------------------------------------"
}

Write-Host "Done..."
0
votes

Use the Azure PowerShell task. It takes care of authentication for you -- no need to call Login-AzureRmAccount.