All skills
microsoft avatar

/azure-upgrade

@b3c238e
by microsoftmicrosoft/skills3.1k stars
351

Assess and upgrade Azure workloads between plans, tiers, or SKUs, or modernize Azure SDK dependencies in source code. WHEN: upgrade Consumption to Flex Consumption, upgrade Azure Functions plan, change hosting plan, function app SKU, migrate App Service to Container Apps, modernize legacy Azure Java SDKs (com.microsoft.azure to com.azure), migrate Azure Cache for Redis (ACR/ACRE) to Azure Managed Redis (AMR).

Use this Skill: https://skilld.dev/gh/microsoft/skills/azure-upgrade

This session only. Nothing lands on disk.

referencesservicesfunctionsautomation.md

≈3.5k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Automation: Consumption to Flex Consumption Upgrade

These are the Azure CLI scripts to automate the upgrade from Linux Consumption plan to Flex Consumption plan. All scripts use bash syntax compatible with Azure Cloud Shell. For PowerShell, adapt accordingly.

Source docs: Linux migration guide

Prerequisites

# Ensure Azure CLI v2.77.0+
az --version

# Install resource-graph extension
az extension add --name resource-graph

# Login and set subscription
az login
az account set --subscription <SUBSCRIPTION_ID>

Step 1: Identify Candidate Apps

# List all Linux Consumption apps with eligibility status
az functionapp flex-migration list

This returns two arrays:

  • eligible_apps — apps that can be migrated to Flex Consumption
  • ineligible_apps — apps with specific reasons why not

The output includes app name, resource group, location, and runtime stack for each app.


Step 2: Assessment Checks

Set variables for your app:

appName=<APP_NAME>
rgName=<RESOURCE_GROUP>

2a. Confirm Region Compatibility

# List all regions where Flex Consumption is available
az functionapp list-flexconsumption-locations --query "sort_by(@, &name)[].{Region:name}" -o table

2b. Verify Language Stack Compatibility

Supported stacks: dotnet-isolated, node, java, python, powershell, custom. Not supported: dotnet (in-process) — must migrate to isolated first.

2c. Verify Stack Version Compatibility

# Check supported versions for a specific runtime in a specific region
az functionapp list-flexconsumption-runtimes --location <REGION> --runtime <LANGUAGE_STACK> \
    --query '[].{version:version}' -o tsv

Replace <REGION> with the app's region and <LANGUAGE_STACK> with one of: dotnet-isolated, java, node, powershell, python.

2d. Check Deployment Slots

# List any deployment slots
az functionapp deployment slot list --name $appName --resource-group $rgName --output table

If this returns entries, the app has slots. Flex Consumption does NOT support slots — plan accordingly.

2e. Check TLS/SSL Certificates

# List certificates available to the app
az webapp config ssl list --resource-group $rgName

If this returns output, the app likely uses certificates. Flex Consumption does NOT support certs yet.

2f. Check Blob Storage Triggers

# Find blob triggers NOT using EventGrid source
az functionapp function list --name $appName --resource-group $rgName \
  --query "[?config.bindings[0].type=='blobTrigger' && config.bindings[0].source!='EventGrid'].{Function:name,TriggerType:config.bindings[0].type,Source:config.bindings[0].source}" \
  --output table

If this returns rows, convert those blob triggers from LogsAndContainerScan to EventGrid before upgrading.


Step 3: Pre-Migration — Collect Settings

3a. Collect App Settings

appName=<APP_NAME>
rgName=<RESOURCE_GROUP>

# Get all app settings as JSON
app_settings=$(az functionapp config appsettings list --name $appName --resource-group $rgName)
echo "$app_settings"

3b. Collect Application Configurations

appName=<APP_NAME>
rgName=<RESOURCE_GROUP>

echo "Getting commonly used site settings..."
az functionapp config show --name $appName --resource-group $rgName \
    --query "{http20Enabled:http20Enabled, httpsOnly:httpsOnly, minTlsVersion:minTlsVersion, \
    minTlsCipherSuite:minTlsCipherSuite, clientCertEnabled:clientCertEnabled, \
    clientCertMode:clientCertMode, clientCertExclusionPaths:clientCertExclusionPaths}"

echo "Checking for SCM basic publishing credentials policies..."
az resource show --resource-group $rgName --name scm --namespace Microsoft.Web \
    --resource-type basicPublishingCredentialsPolicies --parent sites/$appName --query properties

echo "Checking for the maximum scale-out limit configuration..."
az functionapp config appsettings list --name $appName --resource-group $rgName \
    --query "[?name=='WEBSITE_MAX_DYNAMIC_APPLICATION_SCALE_OUT'].value" -o tsv

echo "Checking for any file share mount configurations..."
az webapp config storage-account list --name $appName --resource-group $rgName

echo "Checking for any custom domains..."
az functionapp config hostname list --webapp-name $appName --resource-group $rgName \
    --query "[?contains(name, 'azurewebsites.net')==\`false\`]" --output table

echo "Checking for any CORS settings..."
az functionapp cors show --name $appName --resource-group $rgName

3c. Identify Managed Identities and Role Assignments

appName=<APP_NAME>
rgName=<RESOURCE_GROUP>

echo "Checking for a system-assigned managed identity..."
systemUserId=$(az functionapp identity show --name $appName --resource-group $rgName \
    --query "principalId" -o tsv)

if [[ -n "$systemUserId" ]]; then
    echo "System-assigned identity principal ID: $systemUserId"
    echo "Checking for role assignments..."
    az role assignment list --assignee $systemUserId --all
else
    echo "No system-assigned identity found."
fi

echo "Checking for user-assigned managed identities..."
userIdentities=$(az functionapp identity show --name $appName --resource-group $rgName \
    --query 'userAssignedIdentities' -o json)

if [[ "$userIdentities" != "{}" && "$userIdentities" != "null" ]]; then
    echo "$userIdentities" | jq -c 'to_entries[]' | while read -r identity; do
        echo "User-assigned identity: $(echo "$identity" | jq -r '.key' | sed 's|.*/userAssignedIdentities/||')"
        echo "Checking for role assignments..."
        az role assignment list --assignee $(echo "$identity" | jq -r '.value.principalId') --all --output json
        echo
    done
else
    echo "No user-assigned identities found."
fi

3d. Check Built-in Authentication

az webapp auth show --name $appName --resource-group $rgName

3e. Review Inbound Access Restrictions

az functionapp config access-restriction show --name $appName --resource-group $rgName

3f. Get Deployment Package (if needed)

Ideally your project files are in source control and you can redeploy from there. If not:

Check WEBSITE_RUN_FROM_PACKAGE
az functionapp config appsettings list --name $appName --resource-group $rgName \
    --query "[?name=='WEBSITE_RUN_FROM_PACKAGE'].value" -o tsv

If this returns a URL, download the package from that remote location.

Download from scm-releases blob container

Linux Consumption apps store deployment packages in the scm-releases blob container (in squashfs format).

appName=<APP_NAME>
rgName=<RESOURCE_GROUP>

echo "Getting the storage account connection string..."
storageConnection=$(az functionapp config appsettings list --name $appName --resource-group $rgName \
    --query "[?name=='AzureWebJobsStorage'].value" -o tsv)

echo "Getting the package name..."
packageName=$(az storage blob list --connection-string $storageConnection --container-name scm-releases \
    --query "[0].name" -o tsv)

echo "Downloading package: $packageName"
az storage blob download --connection-string $storageConnection --container-name scm-releases \
    --name $packageName --file $packageName

💡 If your storage account is restricted to managed identity access only, you may need to grant your Azure account the Storage Blob Data Reader role.


Step 4: Create the Flex Consumption App

# Automated migration — creates new app and migrates most configurations
az functionapp flex-migration start \
    --source-name <SOURCE_APP_NAME> \
    --source-resource-group <SOURCE_RESOURCE_GROUP> \
    --name <NEW_APP_NAME> \
    --resource-group <RESOURCE_GROUP>

Optional flags:

  • --storage-account <ACCOUNT> — use a different storage account
  • --maximum-instance-count <COUNT> — set max scale-out instances
  • --skip-access-restrictions — skip migrating IP access restrictions
  • --skip-cors — skip migrating CORS settings
  • --skip-hostnames — skip migrating custom domains
  • --skip-managed-identities — skip migrating managed identity configurations
  • --skip-storage-mount — skip migrating storage mount configurations

The command automatically:

  • Assesses your source app for Flex Consumption compatibility
  • Creates a new function app in the Flex Consumption plan
  • Migrates app settings, identity assignments, storage mounts, CORS, custom domains, and access restrictions

Verify Migration Results

# Verify new app exists and is configured
az functionapp show --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> \
    --query "{name:name, kind:kind, sku:properties.sku}" --output table

# Review migrated app settings
az functionapp config appsettings list --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> \
    --output table

# Check managed identity
az functionapp identity show --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP>

# Check custom domains
az functionapp config hostname list --webapp-name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> \
    --output table

Configure Items Not Auto-Migrated

The flex-migration start command handles most settings, but these may need manual configuration:

Built-in Authentication
# Recreate auth settings if your original app used Easy Auth
az webapp auth update --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> \
    --enabled true --action <AUTH_ACTION>
Scale and Concurrency (if custom values needed)
# Set maximum scale-out (default: 100, range: 1-1000)
az functionapp scale config set --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> \
    --maximum-instance-count <MAX_SCALE_SETTING>

⚠️ Reducing below 40 for HTTP apps can cause frequent request failures.


Step 5: Deploy Code

⚠️ Code is NOT automatically migrated. The new app is created with config only — you must deploy code separately.

ask_user: Choose Deployment Method

Present these options to the user:

Your new Flex Consumption app <NEW_APP_NAME> has been created and configured. Now we need to deploy your function code. How would you like to proceed?

  1. Update CI/CD pipeline — I'll help you update your Azure Pipelines or GitHub Actions workflow to target the new app
  2. Deploy from local project — I'll run func azure functionapp publish <NEW_APP_NAME> from your project directory
  3. Deploy existing package — I'll deploy the package we downloaded earlier from the original app

Option A: Update CI/CD Pipeline (if user selects option 1)

Update your existing pipeline (Azure Pipelines or GitHub Actions) to target the new app name.

Option B: Deploy from Local Project (if user selects option 2)

# From your project directory
func azure functionapp publish <NEW_APP_NAME>

Option C: Deploy Existing Package (if user selects option 3)

# Deploy the zip package downloaded in Step 3
az functionapp deployment source config-zip --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> \
    --src <PACKAGE_PATH.zip>

After Successful Deployment

Inform the user:

Code deployed! Next steps to consider:

  • The original app is still running — keep it as rollback for a few days
  • Update any clients/pipelines to point to the new URL
  • Enable HTTPS-only and managed identity on the new app for better security
  • When confident, you can delete the original app

Step 6: Post-Upgrade Validation

Smoke Test (run this first)

# Minimum viability check — confirm the app is reachable at all
DEFAULT_HOST=$(az functionapp show --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> \
    --query "defaultHostName" -o tsv)

HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://$DEFAULT_HOST")
echo "App responded with HTTP $HTTP_STATUS"

# Expected: 2xx or 401/404 (means the host is up). 
# If 503 or connection refused → the app failed to start. Check logs:
#   az functionapp log tail --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP>

Verify Plan

az functionapp show --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> --query "serverFarmId"

Test HTTP Endpoints

# Test an HTTP trigger function
curl -s -o /dev/null -w "%{http_code}" "https://$DEFAULT_HOST/api/<FUNCTION_NAME>"

Performance Benchmarks (Application Insights KQL)

requests
| where timestamp > ago(1d)
| summarize percentiles(duration, 50, 95, 99) by bin(timestamp, 1h)
| render timechart

Check for Errors

traces
| where severityLevel == 3
| where cloud_RoleName == "<NEW_APP_NAME>"
| where timestamp > ago(1d)
| project timestamp, message, operation_Name, customDimensions
| order by timestamp desc

Step 7: Cleanup (Optional)

# ⛔ REQUIRES ask_user confirmation before executing

# Delete the original function app
az functionapp delete --name <ORIGINAL_APP_NAME> --resource-group <RESOURCE_GROUP>

💡 No rush. The Consumption plan only charges for actual usage, so keeping the old app (with triggers disabled) costs very little. We recommend keeping it for a few days/weeks.


Rollback

# Restart the original app if it was stopped
az functionapp start --name <ORIGINAL_APP_NAME> --resource-group <RESOURCE_GROUP>

# Optionally delete the new Flex Consumption app
az functionapp delete --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP>

Source: SKILL.md on GitHub

No alerts15d3 checks · Risk SAFE
  • Gen Agent Trust Hub15d

    This skill provides a structured framework for Azure workload upgrades and Java SDK modernization. It incorporates several security-focused practices, such as mandatory reviews to ensure the preservation of authentication and authorization controls during code migration. The skill utilizes standard development tools and follows official Microsoft guidance for Azure resource management.

  • Socket15d

    No alerts

  • Snyk15d

    Risk: LOW · No issues

Signed by skilld at b3c238e. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 19 hours ago.

Activeupdated 2 months ago
compatibility
python3.10+
metadata
{
  "author": "Microsoft",
  "version": "1.2.1"
}

README badge

README badge for microsoft/skills/azure-upgrade