Azure

Automate SQL Server DR Licensing on Azure for Max Cost Savings

Managing SQL Server licensing for a disaster recovery (DR) environment in Azure can be a delicate balancing act. While Azure’s free DR license benefit is a powerful tool for cost savings on passive replicas, a manual failover can easily lead to costly compliance gaps. How do you ensure your DR server‘s license is automatically switched to AHUB after it becomes active for an extended period, and then seamlessly reverted upon failback?

This guide provides the definitive answer. We’ll walk you through a complete, production-ready architectural blueprint for automating your SQL Server DR licensing workflow. Forget manual checklists and compliance worries. You’ll learn how to integrate Azure Automation, Logic Apps, and Table Storage to build a resilient, stateful system that intelligently detects failovers, manages the 30-day grace period, and executes license changes with zero downtime. Dive in to discover the scripts, workflows, and strategies to build a truly cost-optimized and automated DR solution on Azure. GigXP | Automating Cost-Optimized SQL Server DR Licensing on Azure

Architect's Guide to Automating SQL Server DR Licensing on Azure

A deep dive into building a cost-optimized, resilient, and fully automated licensing workflow for your SQL Server disaster recovery environment.

1. The Licensing Framework

Effective license management is a strategic imperative for optimizing costs. In a DR context, understanding the `DR` vs. `AHUB` license types is key. The best part? Switching between them is a non-disruptive, metadata-only operation with zero downtime, made possible by the SQL IaaS Agent Extension.

Interactive License Comparison

License Type Use Case Cost Implication Key Requirement Automation Flag
DR Passive, warm standby replica. No SQL license cost. Pay only for compute/storage. Instance must not serve active workloads. DR
AHUB Active production workloads (BYOL). No SQL license cost. Base rate for compute. Active Software Assurance (SA). AHUB
PAYG Active workloads without existing licenses. Highest cost. Includes full SQL license. None. Default for marketplace images. PAYG

Programmatic Control Snippets

Use these non-disruptive commands in your automation scripts to flip the license type on the fly.

# PowerShell: Switch to DR
Update-AzSqlVM -Name 'YourSqlVM' `
  -ResourceGroupName 'YourRG' `
  -LicenseType DR

# PowerShell: Switch to AHUB
Update-AzSqlVM -Name 'YourSqlVM' `
  -ResourceGroupName 'YourRG' `
  -LicenseType AHUB
# Azure CLI: Switch to DR
az sql vm update -n 'YourSqlVM' 
  -g 'YourRG' --license-type DR

# Azure CLI: Switch to AHUB
az sql vm update -n 'YourSqlVM' 
  -g 'YourRG' --license-type AHUB

2. Architectural Blueprint

A simple script won't cut it for a 30-day stateful process. We need a resilient architecture combining several Azure services for detection, orchestration, action, and state management.

Solution Components Infographic

Azure Automation (Detection Runbook) Logic Apps (Orchestration) Automation (Action Runbooks) Table Storage (State Management) Writes State Reads State

3. The Detection Engine

A failover in an IaaS VM is an in-guest event, invisible to the Azure Activity Log. This means we can't use simple event-based alerts. We must actively poll the VM's state using a scheduled runbook and the powerful `Invoke-AzVMRunCommand`.

Pro Tip: The key challenge is that an IaaS failover doesn't generate an ARM event. Our detection logic must query the SQL instance *inside* the VM to determine its true role.

Detection Runbook

This PowerShell runbook authenticates using a Managed Identity, queries the VM's SQL role, compares it to the state in Table Storage, and triggers the appropriate Logic App.


# Authenticate to Azure using Managed Identity
$AzureContext = (Connect-AzAccount -Identity).context
$AzureContext = Set-AzContext -SubscriptionName $AzureContext.Subscription -DefaultProfile $AzureContext

# Connect to state management table
$storageAccount = Get-AzStorageAccount -Name $StateStorageAccountName -ResourceGroupName $AzureContext.Subscription.Name
$tableContext = $storageAccount.Context
$stateTable = Get-AzTable -Name $StateTableName -Context $tableContext

# Iterate through each target VM
$vmResourceIds = $TargetVMs.Split(',')
foreach ($vmResourceId in $vmResourceIds) {
    # ... (get VM details)

    # Retrieve last known state from Table Storage
    $currentStateEntity = Get-AzTableRow -Table $stateTable -PartitionKey $partitionKey -RowKey $rowKey
    $lastKnownState = $currentStateEntity.CurrentState

    # Define the in-guest script to check the SQL replica role
    $scriptToRun = "Invoke-Sqlcmd -Query `"SELECT IIF(role_desc = 'PRIMARY', 'Primary', 'Secondary') FROM sys.dm_hadr_availability_replica_states WHERE is_local = 1`" -ServerInstance 'localhost'"

    # Execute the script inside the VM
    $runCommandResult = Invoke-AzVMRunCommand -ResourceGroupName $resourceGroupName -VMName $vmName -CommandId 'RunPowerShellScript' -ScriptString $scriptToRun
    $liveRole = ($runCommandResult.Value.Message).Trim()

    # State Comparison and Logic
    if ($liveRole -eq "Primary" -and $lastKnownState -eq "Passive") {
        # FAILOVER DETECTED: Trigger Failover Logic App
        Invoke-WebRequest -Uri $FailoverLogicAppUri -Method Post -Body $payload
        # Update state table to 'FailoverDetected'
        Add-AzTableRow -Table $stateTable -Entity $entity -Force
    }
    elseif ($liveRole -eq "Secondary" -and ($lastKnownState -eq "Primary" -or $lastKnownState -eq "FailoverDetected")) {
        # FAILBACK DETECTED: Trigger Failback Logic App
        Invoke-WebRequest -Uri $FailbackLogicAppUri -Method Post -Body $payload
    }
}
                    

4 & 5. Failover & Failback Workflows

We use two distinct Logic Apps to orchestrate the process. The Failover app manages the 30-day delay, while the Failback app provides immediate reversion and, critically, cancels the in-flight failover process.

Failover Workflow (30-Day Delay)

  1. HTTP Trigger received from detection.
  2. Update State Table: Set status to `FailoverDetected`, store `LogicAppRunID`.
  3. Start 30-Day Delay action.
  4. After delay, re-verify state from table.
  5. If state is still `FailoverDetected`:
    • Call `Set-LicenseToAHUB` runbook.
    • Update State Table: Set status to `Primary`.

Failback Workflow (Immediate Action)

  1. HTTP Trigger received from detection.
  2. Immediately call `Set-LicenseToDR` runbook.
  3. Get `LogicAppRunID` from State Table.
  4. Use "Cancel Run" action to terminate the in-flight Failover Logic App.
  5. Update State Table: Set status to `Passive`, clear run ID.

6. Deployment & Cost Impact

Deploying with IaC (Bicep/ARM) ensures consistency. Monitoring failures in the automation itself is key. But the real story is the cost savings.

Interactive Cost Savings Analysis

Adjust the slider to see the estimated monthly savings by using the `DR` license benefit instead of `PAYG` for a passive replica.

4 vCPUs 16 vCPUs 32 vCPUs 64 vCPUs

GigXP.com

© 2025 GigXP.com. All rights reserved.

Empowering cloud architects with actionable insights and automation.

Disclaimer: The Questions and Answers provided on https://gigxp.com are for general information purposes only. We make no representations or warranties of any kind, express or implied, about the completeness, accuracy, reliability, suitability or availability with respect to the website or the information, products, services, or related graphics contained on the website for any purpose.

What's your reaction?

Excited
0
Happy
0
In Love
0
Not Sure
0
Silly
0

Comments are closed.

More in:Azure

Next Article:

0 %