diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 09e7822..74804d7 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -12,6 +12,10 @@ categories: - 'bug' - title: '🧰 Maintenance' label: 'chore' + - title: '📄 Documentation' + labels: + - 'documentation' + - 'docs' change-template: '- $TITLE @$AUTHOR (#$NUMBER)' change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks. version-template: "$MAJOR.$MINOR" diff --git a/.github/workflows/build-and-draft-release.yml b/.github/workflows/build-and-draft-release.yml index 738d99f..daae64c 100644 --- a/.github/workflows/build-and-draft-release.yml +++ b/.github/workflows/build-and-draft-release.yml @@ -5,25 +5,14 @@ on: branches: [main] paths: - 'build/**' + - 'workbooks/**' pull_request: branches: [main] paths: - 'build/**' + - 'workbooks/**' workflow_dispatch: -# on: -# push: -# # branches to consider in the event; optional, defaults to all -# branches: -# - main -# # pull_request event is required only for autolabeler -# pull_request: -# # Only following types are handled by the action, but one can default to all as well -# types: [opened, reopened, synchronize] -# # pull_request_target event is required for autolabeler to support PRs from forks -# pull_request_target: -# types: [opened, reopened, synchronize] - permissions: contents: read diff --git a/README.md b/README.md index edeca53..04d9a79 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,9 @@ This Reliability Workbook consists of several co-workbooks. For easy deployment, ```shell ./deploy-workbook.sh -s 00000000-0000-0000-0000-000000000000 -g myResourceGroup -c -l japaneast ``` + + If there are any issues with the deployment script, review the `deploy-workbook.sh` script in `scripts/deploy-workbook.sh` for any errors or misconfigurations. + ### Deploy only Export Workbook easily If you only want to deploy the Export workbook, you can deploy from the following button. diff --git a/ReliabilityWorkbookIntegration.workbook b/ReliabilityWorkbookIntegration.workbook new file mode 100644 index 0000000..23a8220 --- /dev/null +++ b/ReliabilityWorkbookIntegration.workbook @@ -0,0 +1,188 @@ +{ + "version": "Notebook/1.0", + "items": [ + { + "type": 9, + "content": { + "version": "KqlParameterItem/1.0", + "parameters": [ + { + "id": "aa0176d8-14ff-4dc5-9ae7-b8029f565674", + "version": "KqlParameterItem/1.0", + "name": "Subscriptions", + "label": "Subscriptions", + "type": 6, + "isRequired": true, + "multiSelect": true, + "quote": "'", + "delimiter": ",", + "typeSettings": { + "additionalResourceOptions": [ + "value::all" + ], + "includeAll": false, + "showDefault": false + }, + "defaultValue": "value::all" + }, + { + "id": "91aa9ba3-ed60-4472-8dd9-1c2cb6255757", + "version": "KqlParameterItem/1.0", + "name": "ResourceGroup", + "label": "Resource Group", + "type": 2, + "isRequired": true, + "multiSelect": true, + "quote": "'", + "delimiter": ",", + "query": "resources\r\n| distinct resourceGroup", + "crossComponentResources": [ + "{Subscriptions}" + ], + "typeSettings": { + "additionalResourceOptions": [ + "value::all" + ], + "showDefault": false + }, + "defaultValue": "value::all", + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + { + "id": "5a4f6d34-9f89-4ef8-b4ee-fb0580ec016d", + "version": "KqlParameterItem/1.0", + "name": "Environment", + "label": "Environment", + "type": 2, + "multiSelect": true, + "quote": "'", + "delimiter": ",", + "query": "resources\r\n| extend Environment = case(\r\ntags.Environment <> \"\", replace(\"\\\\\\\\\", \"\", tostring(tags.Environment)),\r\ntags.environment <> \"\", replace(\"\\\\\\\\\", \"\", tostring(tags.environment)),\r\ntags.Env <> \"\", replace(\"\\\\\\\\\", \"\", tostring(tags.Env)),\r\ntags.env <> \"\", replace(\"\\\\\\\\\", \"\", tostring(tags.env)),\r\ntolower(name) contains \"prod\", \"Production\",\r\ntolower(name) contains \"dev\", \"Development\",\r\ntolower(name) contains \"qa\", \"QA\",\r\ntolower(name) contains \"uat\", \"UAT\",\r\ntolower(name) contains \"sit\", \"SIT\",\r\ntolower(name) contains \"test\", \"Test\",\r\n\"Undefined\")\r\n| distinct Environment", + "crossComponentResources": [ + "{Subscriptions}" + ], + "typeSettings": { + "additionalResourceOptions": [ + "value::all" + ], + "showDefault": false + }, + "defaultValue": "value::all", + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources" + }, + { + "id": "9d6afcdc-172c-4bef-8bab-dc372c5d3bb4", + "version": "KqlParameterItem/1.0", + "name": "TagName", + "label": "Tag Name", + "multiSelect": true, + "quote": "'", + "delimiter": ",", + "type": 2, + "query": "Resources\r\n| where tags != '' and tags != '[]'\r\n| mvexpand tags\r\n| extend tagName = replace(\"\\\\\\\\\", \"\", tostring(bag_keys(tags)[0]))\r\n| distinct tagName\r\n| sort by tagName asc", + "crossComponentResources": [ + "{Subscriptions}" + ], + "typeSettings": { + "additionalResourceOptions": [ + "value::all" + ], + "selectAllValue": "*" + }, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources", + "value": [ + "value::all" + ] + }, + { + "id": "95781001-338b-4ed3-81dc-ce16f2a98bf0", + "version": "KqlParameterItem/1.0", + "name": "TagValue", + "label": "Tag Value", + "type": 2, + "multiSelect": true, + "quote": "'", + "delimiter": ",", + "query": "Resources\r\n| mvexpand tags\r\n| extend tagName = replace(\"\\\\\\\\\", \"\", tostring(bag_keys(tags)[0]))\r\n| extend tagValue = replace(\"\\\\\\\\\", \"\", tostring(tags[tagName]))\r\n| where tags != '' and tags != '[]' \r\n| where ('*' in (dynamic([{TagName}])) or tagName in (dynamic([{TagName}]))) \r\n| distinct tagValue\r\n| sort by tagValue asc", + "crossComponentResources": [ + "{Subscriptions}" + ], + "typeSettings": { + "additionalResourceOptions": [ + "value::all" + ], + "selectAllValue": "*" + }, + "queryType": 1, + "resourceType": "microsoft.resourcegraph/resources", + "value": [ + "value::all" + ] + }, + { + "id": "e929bc01-08ec-45fe-bc6a-4e0267460dfa", + "version": "KqlParameterItem/1.0", + "name": "SLA", + "label": "Show SLA", + "type": 10, + "description": "This will show the SLA information for the focus area", + "isRequired": true, + "typeSettings": { + "additionalResourceOptions": [], + "showDefault": false + }, + "jsonData": "[{ \"value\": \"Yes\", \"label\": \"Yes\", \"selected\":true},\r\n {\"value\": \"No\", \"label\": \"No\"}]" + }, + { + "id": "9581cbc6-0f0f-42be-8ae8-6fe94de00ab8", + "version": "KqlParameterItem/1.0", + "name": "Help", + "label": "Show Help", + "type": 10, + "isRequired": true, + "typeSettings": { + "additionalResourceOptions": [] + }, + "jsonData": "[{\"value\": \"Yes\", \"label\": \"Yes\", \"selected\":true },\r\n {\"value\": \"No\", \"label\": \"No\"}]" + } + ], + "style": "pills", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces" + }, + "name": "parameters - 13" + }, + { + "type": 1, + "content": { + "json": "[SLA for API Management](https://azure.microsoft.com/support/legal/sla/api-management/)\r\n* We guarantee that API Management Service instances running in the Consumption Tier, Basic Tier, Standard Tier, and Premium Tier deployments scaled within a single region will respond to requests to perform operations at least 99.95% of the time.\r\n* We guarantee that API Management Service instances running in the Premium Tier with deployments scaled across two or more regions will respond to requests to perform operations at least 99.99% of the time.\r\n* No SLA is provided for the following:​\r\n * Developer tier of the API Management Service.\r\n * Any self-hosted API Management components.​\r\n \r\n> SLA accurate at time of release. Latest information is available [here](https://azure.microsoft.com/support/legal/sla/api-management/)", + "style": "upsell" + }, + "conditionalVisibility": { + "parameterName": "SLA", + "comparison": "isEqualTo", + "value": "Yes" + }, + "name": "text - 2 - Copy" + }, + { + "type": 1, + "content": { + "json": "* Please note the Developer tier is for non-production use cases and evaluations. It does not offer an SLA.\r\n* API Management instances deleted using 2020-01-01-preview and later API versions will be soft-deleted and recoverable. APIM instances deleted using previous API versions will continue to be hard-deleted. Azure PowerShell and Azure CLI currently do not use the 2020-06-01-preview version and will also result in hard-delete behavior. Refer to [API Management soft-delete (preview)](https://learn.microsoft.com/azure/api-management/soft-delete) for more information.\r\n\r\n", + "style": "info" + }, + "conditionalVisibility": { + "parameterName": "Help", + "comparison": "isEqualTo", + "value": "Yes" + }, + "name": "text - 3 - Copy - Copy" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "resources\n| where resourceGroup in ({ResourceGroup})\n| extend environment = case(\n tags.Environment \u003c\u003e \"\", replace(\"\\\\\\\\\", \"\u003cBackslash\u003e\", tostring(tags.Environment)),\n tags.environment \u003c\u003e \"\", replace(\"\\\\\\\\\", \"\u003cBackslash\u003e\", tostring(tags.environment)),\n tags.Env \u003c\u003e \"\", replace(\"\\\\\\\\\", \"\u003cBackslash\u003e\", tostring(tags.Env)),\n tags.env \u003c\u003e \"\", replace(\"\\\\\\\\\", \"\u003cBackslash\u003e\", tostring(tags.env)),\n tolower(name) contains \"prod\", \"Production\",\n tolower(name) contains \"dev\", \"Development\",\n tolower(name) contains \"qa\", \"QA\",\n tolower(name) contains \"uat\", \"UAT\",\n tolower(name) contains \"sit\", \"SIT\",\n tolower(name) contains \"test\", \"Test\",\n \"Undefined\")\n| where environment in ({Environment})\n| join kind = inner(\n resources\n | extend tagName = replace(\"\\\\\\\\\", \"\u003cBackslash\u003e\", tostring(bag_keys(tags)[0]))\n | extend tagValue = replace(\"\\\\\\\\\", \"\u003cBackslash\u003e\", tostring(tags[tagName]))\n | distinct tagName,tagValue,id\n | where (('*' in (dynamic([{TagName}])) or tagName in (dynamic([{TagName}])))) and (('*' in (dynamic([{TagValue}])) or tagValue in (dynamic([{TagValue}]))))\n | distinct id\n)\non id\n| where \n (type == 'microsoft.compute/virtualmachines') or \n (type == 'microsoft.classiccompute/virtualmachines') or \n (type == \"microsoft.compute/virtualmachinescalesets\" and tags.aksEngineVersion !contains \"aks-gomod\") or\n (type == 'microsoft.web/sites') or \n (type == 'microsoft.web/serverfarms') or\n (type == \"microsoft.containerservice/managedclusters\") or \n (type == 'microsoft.sql/servers/databases') or \n (type == 'microsoft.documentdb/databaseaccounts') or \n (type == 'microsoft.dbformysql/servers') or \n (type == 'microsoft.dbformysql/flexibleservers') or\n (type == 'microsoft.dbforpostgresql/servers') or \n (type == 'microsoft.dbforpostgresql/flexibleservers') or \n (type == 'microsoft.cache/redis') or\n (type == \"microsoft.apimanagement/service\") or \n (type == \"microsoft.storage/storageaccounts\" or type == \"microsoft.classicstorage/storageaccounts\") or \n (type == \"microsoft.network/azurefirewalls\") or \n (type == \"microsoft.network/frontdoors\") or\n (type == \"microsoft.cdn/profiles\") or\n (type == \"microsoft.network/applicationgateways\") or \n (type == \"microsoft.network/loadbalancers\") or \n (type == \"microsoft.network/publicipaddresses\" or type == \"microsoft.network/publicipprefixes\") or \n (type == \"microsoft.network/virtualnetworkgateways\") or \n (type == \"microsoft.recoveryservices/vaults\")\n| join kind=leftouter (\n resources \n | where type == \"microsoft.containerservice/managedclusters\"\n // Expand per node pool to get using zone for all node pool\n | mv-expand agentPoolProfiles = properties.agentPoolProfiles\n | extend AvZones = agentPoolProfiles.availabilityZones\n | extend AksNodeResourceGroup = tolower(tostring(properties.nodeResourceGroup))\n // Get number of using zone per node pool VMSS. If it doesn't use any zone, return 0\n | extend useAvZone = case(\n array_length( AvZones ) \u003e 0, array_length( AvZones ), 0\n )\n | join kind=leftouter(\n resources\n | where type == 'microsoft.compute/virtualmachinescalesets'\n | extend resourceGroup = tolower(tostring(resourceGroup))\n | extend VmssCapacity = sku.capacity\n | extend vmssStorageAccountType = iff(\n properties.virtualMachineProfile.storageProfile.osDisk.diffDiskSettings.option == \"Local\", \"Ephemeral\", properties.virtualMachineProfile.storageProfile.osDisk.managedDisk.storageAccountType\n )\n ) on $left.AksNodeResourceGroup == $right.resourceGroup // Match AKS and VMSS with nodeResourceGroup\n | summarize AvZones=min(useAvZone), AksMinimumNodePoolCount=min(toint(VmssCapacity)), AksNodePoolStorageAccountType=make_set(vmssStorageAccountType), FaultDomainCount=min(toint(properties1.platformFaultDomainCount)) by id, name, type, tenantId, kind, location, resourceGroup, subscriptionId, tostring(sku), tostring(plan), tostring(properties), AksNodeResourceGroup\n | extend AksNodePoolStorageAccountType = iff(\n tolower(tostring(AksNodePoolStorageAccountType)) contains \"standard_lrs\", \"standard_lrs\", tolower(tostring(strcat_array(AksNodePoolStorageAccountType, \",\")))\n )\n // If there are some node pools within AKS cluster, it returns minimum number of zones. \n // If even one node pool is not using a zone, it will be \"Not Configured\".\n | extend AvZones = iff(tostring(AvZones) == \"0\", \"Not Configured\", tostring(AvZones)), AvSets = \"Scale Sets\"\n) on id\n// Start - Azure Load Balancer additional logic\n| mv-expand LbFeIpConfig = properties.frontendIPConfigurations\n| extend LbUseAvZone = iff(array_length(LbFeIpConfig.zones ) \u003e 0, array_length(LbFeIpConfig.zones ), 0)\n| extend LbIpType = iff(isnotnull(LbFeIpConfig.properties.publicIPAddress), \"Public\", \"Private\")\n//| summarize LbAvZones = min(LbUseAvZone) by id, name, type, tenantId, kind, location, resourceGroup, subscriptionId, tostring(sku), plan, tostring(properties)\n//| extend properties = todynamic(properties), sku = todynamic(sku), \n| summarize LbAvZones = arg_min(LbUseAvZone, *) by id\n// End - Azure Load Balancer additional logic\n| extend state = case(\n type == 'microsoft.compute/virtualmachines', tostring(properties.extended.instanceView.powerState.displayStatus),\n type == 'microsoft.classiccompute/virtualmachines', tostring(properties.instanceView.powerState),\n type == 'microsoft.compute/virtualmachinescalesets', tostring(properties.provisioningState),\n type == 'microsoft.web/sites', tostring(properties.state),\n type == 'microsoft.web/serverfarms', tostring(properties.status),\n type == 'microsoft.containerservice/managedclusters', tostring(properties.provisioningState),\n type == 'microsoft.sql/servers/databases', tostring(properties.status),\n type == 'microsoft.documentdb/databaseaccounts', tostring(properties.provisioningState),\n type == 'microsoft.dbformysql/servers', tostring(properties.userVisibleState),\n type == 'microsoft.dbformysql/flexibleservers', tostring(properties.state),\n type == 'microsoft.dbforpostgresql/servers', tostring(properties.userVisibleState),\n type == 'microsoft.dbforpostgresql/flexibleservers', tostring(properties.state),\n type == 'microsoft.cache/redis', tostring(properties.provisioningState),\n type == \"microsoft.apimanagement/service\", tostring(properties.provisioningState),\n type contains \"storageaccounts\", tostring(properties.provisioningState),\n type == \"microsoft.network/azurefirewalls\", tostring(properties.provisioningState),\n type == \"microsoft.network/frontdoors\", tostring(properties.resourceState),\n type == \"microsoft.cdn/profiles\", tostring(properties.resourceState),\n type == \"microsoft.network/applicationgateways\", tostring(properties.operationalState),\n type == \"microsoft.network/loadbalancers\", tostring(properties.provisioningState),\n type contains \"publicip\", tostring(properties.provisioningState),\n type == \"microsoft.network/virtualnetworkgateways\", tostring(properties.provisioningState),\n type == \"microsoft.recoveryservices/vaults\", tostring(properties.provisioningState),\n \"Undefined\"\n )\n| extend skuName = case(\n type == 'microsoft.compute/virtualmachines', tostring(properties.hardwareProfile.vmSize),\n type == 'microsoft.classiccompute/virtualmachines', tostring(properties.hardwareProfile.size),\n type == 'microsoft.compute/virtualmachinescalesets', tostring(sku.name),\n type == 'microsoft.web/sites', tostring(properties.sku),\n type == 'microsoft.web/serverfarms', tostring(sku.tier),\n type == 'microsoft.containerservice/managedclusters', tostring(properties.agentPoolProfiles[0].vmSize),\n type == 'microsoft.sql/servers/databases', tostring(sku.tier),\n type == 'microsoft.documentdb/databaseaccounts', tostring(properties.databaseAccountOfferType),\n type == 'microsoft.dbformysql/servers', tostring(sku.tier),\n type == 'microsoft.dbformysql/flexibleservers', tostring(sku.tier),\n type == 'microsoft.dbforpostgresql/servers', tostring(sku.tier),\n type == 'microsoft.dbforpostgresql/flexibleservers', tostring(sku.tier),\n type == 'microsoft.cache/redis', tostring(properties.sku.name),\n type == \"microsoft.apimanagement/service\", tostring(sku.name),\n type contains 'storageaccounts', tostring(replace('-', '_', tostring(iff(type =~ \"microsoft.storage/storageaccounts\", sku.name, properties.accountType)))),\n type == \"microsoft.network/azurefirewalls\", tostring(properties.sku.name),\n type == \"microsoft.network/frontdoors\", \"classic_frontdoor\",\n type == \"microsoft.cdn/profiles\", tostring(sku.name),\n type == \"microsoft.network/applicationgateways\", tostring(properties.sku.name),\n type == \"microsoft.network/loadbalancers\", iff(sku.tier == 'Global', 'Global', tostring(sku.name)),\n type contains \"publicip\", iff(sku.tier == 'Global', 'Global', tostring(sku.name)),\n type == \"microsoft.network/virtualnetworkgateways\", tostring(properties.sku.name),\n type == \"microsoft.recoveryservices/vaults\", tostring(iif(isnotnull(sku.tier), sku.tier, sku.name)),\n \"Undefined\"\n )\n| extend avZones = case(\n // reffer to: https://learn.microsoft.com/en-us/azure/reliability/availability-zones-service-support#azure-regions-with-availability-zone-support\n location !in~ ('brazilsouth', 'canadacentral', 'centralus', 'eastus', 'eastus2', 'southcentralus', 'usgovvirginia', 'westus2', 'westus3', 'francecentral', 'germanywestcentral', 'northeurope', 'norwayeast', 'uksouth', 'westeurope', 'swedencentral', 'switzerlandnorth', 'polandcentral', 'qatarcentral', 'uaenorth', 'southafricanorth', 'australiaeast', 'centralindia', 'japaneast', 'koreacentral', 'southeastasia', 'eastasia', 'chinanorth3', 'italynorth', 'israelcentral'), 'Not Applicable',\n (type == 'microsoft.compute/virtualmachines'), coalesce(tostring(zones[0]), 'Not Configured'),\n (type == 'microsoft.classiccompute/virtualmachines'), 'Not Applicable',\n (type == 'microsoft.compute/virtualmachinescalesets'), coalesce(tostring(array_length(parse_json(zones))), 'Not Configured'),\n (type == 'microsoft.containerservice/managedclusters' and AvZones \u003c\u003e \"\"), AvZones,\n (type == 'microsoft.containerservice/managedclusters' and isempty(AvZones)), \"Not Configured\",\n (type == 'microsoft.web/sites'), \"ASP AZ config\",\n (type == 'microsoft.web/serverfarms'), iff(properties.zoneRedundant == 'true', 'Configured', 'Not Configured'),\n (type == 'microsoft.sql/servers/databases' and sku.tier \u003c\u003e 'DataWarehouse'), case( //SQL AZ SKU \u0026 region availability filter\n sku.tier == 'Basic' or sku.tier == 'Standard' or sku.name == 'System', 'Not Applicable',\n // Outside of these regions, SQL DB is not available in AZ. Refer to: https://learn.microsoft.com/en-us/azure/azure-sql/database/high-availability-sla?view=azuresql\u0026tabs=azure-powershell#general-purpose-service-tier-zone-redundant-availability\n sku.tier == 'GeneralPurpose' and location !in~ ('brazilsouth', 'eastus', 'eastus2', 'southcentralus', 'westus2', 'westus3', 'francecentral', 'germanywestcentral', 'northeurope', 'norwayeast', 'uksouth', 'westeurope', 'swedencentral', 'switzerlandnorth', 'polandcentral', 'qatarcentral', 'uaenorth', 'southafricanorth', 'australiaeast', 'centralindia', 'japaneast', 'koreacentral', 'southeastasia', 'eastasia', 'chinanorth3', 'italynorth', 'israelcentral'), 'Not Applicable',\n properties.zoneRedundant == 'true', 'Configured',\n 'Not Configured'\n ),\n (type == 'microsoft.sql/servers/databases' and sku.tier == 'DataWarehouse'), \"Not Applicable\",\n (type == 'microsoft.documentdb/databaseaccounts'), iif(properties.locations[0].isZoneRedundant == \"false\", 'Not Configured', 'Configured'), \n (type == 'microsoft.dbformysql/servers'), \"Not Applicable\",\n (type == 'microsoft.dbformysql/flexibleservers'),case(\n properties.highAvailability.mode == \"ZoneRedundant\", \"Configured\",\n properties.replicationRole == \"Replica\", \"Not Applicable\",\n 'Not Configured'\n ),\n (type == 'microsoft.dbforpostgresql/servers'), \"Not Applicable\",\n (type == 'microsoft.dbforpostgresql/flexibleservers'),case(\n properties.highAvailability.mode == \"ZoneRedundant\", \"Configured\",\n properties.replicationRole contains \"Replica\", \"Not Applicable\",\n 'Not Configured'\n ),\n (type == 'microsoft.cache/redis'), coalesce(tostring(array_length(parse_json(zones))), 'Not Configured'),\n (type == \"microsoft.apimanagement/service\"), coalesce(tostring(array_length(parse_json(zones))), 'Not Configured'),\n (type contains 'storageaccounts'), case(split(skuName, '_', 1)[0] contains \"zrs\", \"Configured\", \"Not Configured\"),\n (type == \"microsoft.network/azurefirewalls\"), iif(isnotnull(zones), \"Configured\", \"Not Configured\"),\n (type == \"microsoft.network/frontdoors\"), \"Not Applicable\",\n (type == \"microsoft.cdn/profiles\"), \"Not Applicable\",\n (type == \"microsoft.network/applicationgateways\"), iif(isnotnull(zones), \"Configured\", \"Not Configured\"),\n (type == \"microsoft.network/loadbalancers\"), case( \n skuName =~ \"Basic\" or skuName =~ \"Global\", \"Not Applicable\",\n LbIpType =~ \"Public\", \"Public IP AZ Config\",\n tostring(LbAvZones) =~ \"0\", \"Not Configured\",\n tostring(LbAvZones)\n ),\n (type contains \"publicip\"), case( \n skuName =~ \"Basic\" or skuName =~ \"Global\", \"Not Applicable\",\n coalesce(tostring(array_length(parse_json(zones))), 'Not Configured')\n ),\n (type == \"microsoft.network/virtualnetworkgateways\"), \"Public IP AZ Config\",\n (type == \"microsoft.recoveryservices/vaults\"), \"Not Applicable\",\n \"Undefined\"\n )\n| extend avSets = case(\n type == 'microsoft.compute/virtualmachines' and avZones in ('1', '2', '3'), \"Not Applicable\",\n type == 'microsoft.compute/virtualmachines', (coalesce(extract('/availabilitySets/(.*)', 1, tostring(properties.availabilitySet.id)), 'Not Configured')),\n type == 'microsoft.classiccompute/virtualmachines', iff(isnotnull(properties.hardwareProfile.availabilitySet), 'Configured', 'Not Configured'),\n type == 'microsoft.compute/virtualmachinescalesets' and avZones in ('1', '2', '3'), \"Not Applicable\",\n type == 'microsoft.compute/virtualmachinescalesets', 'A regional (non-zonal) scale set uses placement groups, which act as an implicit availability set with five fault domains and five update domains.',\n type == 'microsoft.web/sites', 'Not Applicable',\n type == 'microsoft.web/serverfarms', 'Not Applicable',\n type == 'microsoft.containerservice/managedclusters', case(\n AvSets == 'Scale Sets' and avZones in ('1', '2', '3'), \"Not Applicable\",\n AvSets == 'Scale Sets', \"A regional (non-zonal) scale set uses placement groups, which act as an implicit availability set with five fault domains and five update domains.\",\n \"Scale Sets Not Configured\"\n ),\n type == 'microsoft.sql/servers/databases', 'Not Applicable',\n type == 'microsoft.documentdb/databaseaccounts', 'Not Applicable',\n type == 'microsoft.dbformysql/servers', \"Not Applicable\",\n type == 'microsoft.dbformysql/flexibleservers', \"Not Applicable\",\n type == 'microsoft.dbforpostgresql/servers', \"Not Applicable\",\n type == 'microsoft.dbforpostgresql/flexibleservers', \"Not Applicable\",\n type == 'microsoft.cache/redis', \"Not Applicable\",\n type == \"microsoft.apimanagement/service\", \"Not Applicable\",\n type contains \"storageaccounts\", \"Not Applicable\",\n type == \"microsoft.network/azurefirewalls\", \"Not Applicable\",\n type == \"microsoft.network/frontdoors\", \"Not Applicable\",\n type == \"microsoft.cdn/profiles\", \"Not Applicable\",\n type == \"microsoft.network/applicationgateways\", \"Not Applicable\",\n type == \"microsoft.network/loadbalancers\", \"Not Applicable\",\n type contains \"publicip\", tostring(properties.publicIPAddressVersion), //Field Override\n type == \"microsoft.network/virtualnetworkgateways\", tostring(properties.gatewayType), //Field Override\n type == \"microsoft.recoveryservices/vaults\", \"Not Applicable\",\n \"Undefined\"\n )\n| extend Capacity = case(\n type == 'microsoft.compute/virtualmachines', \"Not Applicable\",\n type == 'microsoft.classiccompute/virtualmachines', \"Not Applicable\",\n type == 'microsoft.compute/virtualmachinescalesets', tostring(sku.capacity),\n type == 'microsoft.web/sites', \"ASP Config\",\n type == 'microsoft.web/serverfarms', tostring(sku.capacity),\n type == 'microsoft.containerservice/managedclusters', iif(isnotempty(AksMinimumNodePoolCount), tostring(AksMinimumNodePoolCount), \"0\"), // AKS with or without VMSS\n type == 'microsoft.sql/servers/databases', tostring(sku.capacity),\n type == 'microsoft.documentdb/databaseaccounts', 'Not Applicable',\n type == 'microsoft.dbformysql/servers', tostring(sku.capacity),\n type == 'microsoft.dbformysql/flexibleservers', tostring(sku.capacity),\n type == 'microsoft.dbforpostgresql/servers', tostring(sku.capacity),\n type == 'microsoft.dbforpostgresql/flexibleservers', tostring(sku.capacity),\n type == 'microsoft.cache/redis', strcat(properties.sku.family, properties.sku.capacity),\n type == \"microsoft.apimanagement/service\", tostring(sku.capacity),\n type contains \"storageaccounts\", \"Not Applicable\", \n type == \"microsoft.network/azurefirewalls\", \"Not Applicable\",\n type == \"microsoft.network/frontdoors\", \"Not Applicable\",\n type == \"microsoft.cdn/profiles\", \"Not Applicable\",\n type == \"microsoft.network/applicationgateways\", tostring(iif(isnotempty(properties.autoscaleConfiguration), properties.autoscaleConfiguration.minCapacity, properties.sku.capacity)),\n type == \"microsoft.network/loadbalancers\", \"Not Applicable\",\n type contains \"publicip\", iif(type == \"microsoft.network/publicipprefixes\", \"PIP-prefix\", \"Single\"), //Field Override\n type == \"microsoft.network/virtualnetworkgateways\", tostring(properties.sku.capacity),\n type == \"microsoft.recoveryservices/vaults\", \"Not Applicable\",\n \"Undefined\"\n )\n| extend FaultDomain = case(\n type == 'microsoft.compute/virtualmachines', \"Not Applicable\",\n type == 'microsoft.classiccompute/virtualmachines', \"Not Applicable\",\n type == 'microsoft.compute/virtualmachinescalesets', iif(isnotempty(properties.platformFaultDomainCount), properties.platformFaultDomainCount, \"0\"), // 1 - AZ, 5 - Regional VMSS\n type == 'microsoft.web/sites', \"Not Applicable\",\n type == 'microsoft.web/serverfarms', 'Not Applicable',\n type == 'microsoft.containerservice/managedclusters', iif(isnotempty(tostring(FaultDomainCount)), tostring(FaultDomainCount), \"0\"),\n type == 'microsoft.sql/servers/databases', \"Not Applicable\",\n type == 'microsoft.documentdb/databaseaccounts', 'Not Applicable',\n type == 'microsoft.dbformysql/servers', 'Not Applicable',\n type == 'microsoft.dbformysql/flexibleservers', 'Not Applicable',\n type == 'microsoft.dbforpostgresql/servers', 'Not Applicable',\n type == 'microsoft.dbforpostgresql/flexibleservers', 'Not Applicable',\n type == 'microsoft.cache/redis', 'Not Applicable',\n type == \"microsoft.apimanagement/service\", \"Not Applicable\",\n type contains \"storageaccounts\", \"Not Applicable\",\n type == \"microsoft.network/azurefirewalls\", \"Not Applicable\",\n type == \"microsoft.network/frontdoors\", \"Not Applicable\",\n type == \"microsoft.cdn/profiles\", \"Not Applicable\",\n type == \"microsoft.network/applicationgateways\", \"Not Applicable\",\n type == \"microsoft.network/loadbalancers\", \"Not Applicable\",\n type contains \"publicip\", \"Not Applicable\",\n type == \"microsoft.network/virtualnetworkgateways\", iff(properties.gatewayType == \"ExpressRoute\" and properties.vpnType == \"PolicyBased\", \"ErPolicyBased\", tostring(properties.vpnType)), //Field Override\n type == \"microsoft.recoveryservices/vaults\", \"Not Applicable\",\n \"Undefined\"\n )\n| extend osDisk = case(\n type == 'microsoft.compute/virtualmachines', iif(properties.storageProfile.osDisk.diffDiskSettings.option == \"Local\", \"Ephemeral\", properties.storageProfile.osDisk.managedDisk.storageAccountType),\n type == 'microsoft.classiccompute/virtualmachines', 'Classic',\n type == 'microsoft.compute/virtualmachinescalesets', iif(properties.virtualMachineProfile.storageProfile.osDisk.diffDiskSettings.option == \"Local\", \"Ephemeral\", properties.virtualMachineProfile.storageProfile.osDisk.managedDisk.storageAccountType),\n type == 'microsoft.web/sites', 'Not Applicable',\n type == 'microsoft.web/serverfarms', 'Not Applicable',\n type == 'microsoft.containerservice/managedclusters', AksNodePoolStorageAccountType,\n type == 'microsoft.sql/servers/databases', properties.currentBackupStorageRedundancy,\n type == 'microsoft.documentdb/databaseaccounts', 'Not Applicable',\n type == 'microsoft.dbformysql/servers', 'Not Applicable',\n type == 'microsoft.dbformysql/flexibleservers', 'Not Applicable',\n type == 'microsoft.dbforpostgresql/servers', 'Not Applicable',\n type == 'microsoft.dbforpostgresql/flexibleservers', 'Not Applicable',\n type == 'microsoft.cache/redis', 'Not Applicable',\n type == \"microsoft.apimanagement/service\", tostring(properties.platformVersion), //Field Override\n type contains \"storageaccounts\", tostring(split(skuName, '_', 0)[0]),\n type == \"microsoft.network/azurefirewalls\", \"Not Applicable\",\n type == \"microsoft.network/frontdoors\", \"Not Applicable\",\n type == \"microsoft.cdn/profiles\", \"Not Applicable\",\n type == \"microsoft.network/applicationgateways\", \"Not Applicable\",\n type == \"microsoft.network/loadbalancers\", tostring(LbIpType), //Field Override\n type contains \"publicip\", tostring(properties.publicIPAllocationMethod), //Field Override\n type == \"microsoft.network/virtualnetworkgateways\", tostring(properties.vpnGatewayGeneration), //Field Override\n type == \"microsoft.recoveryservices/vaults\", \"Not Applicable\",\n 'Not Applicable'\n )\n| extend OSDisk = case(\n isnotempty(osDisk), osDisk,\n isempty(osDisk) and (type == 'microsoft.compute/virtualmachines') and state \u003c\u003e 'VM running', 'Unknown, start VM to get disk information.',\n isempty(osDisk) and (type == 'microsoft.compute/virtualmachines') and isnotempty(properties.storageProfile.osDisk.vhd.uri), 'Unmanaged',\n \"Unknown\")\n| extend ReadReplica = case (\n type in ('microsoft.compute/virtualmachines', 'microsoft.classiccompute/virtualmachines', 'microsoft.compute/virtualmachinescalesets', 'microsoft.web/sites', 'microsoft.web/serverfarms', 'microsoft.containerservice/managedclusters'), \"Not Applicable\",\n (type == 'microsoft.sql/servers/databases' and sku.tier \u003c\u003e 'DataWarehouse'), tostring(properties.readReplicaCount), // SQL DB\n (type == 'microsoft.sql/servers/databases' and sku.tier == 'DataWarehouse'), \"Not Applicable\", // Synapse\n type == 'microsoft.documentdb/databaseaccounts', tostring(array_length(parse_json(properties.readLocations))),\n type == 'microsoft.dbformysql/servers', \"Not Applicable\",\n type == 'microsoft.dbformysql/flexibleservers', \"Not Applicable\",\n type == 'microsoft.dbforpostgresql/servers', \"Not Applicable\",\n type == 'microsoft.dbforpostgresql/flexibleservers', \"Not Applicable\",\n type == 'microsoft.cache/redis', 'Not Applicable',\n type == \"microsoft.apimanagement/service\", tostring(properties.additionalLocations),\n type contains \"storageaccounts\", case(\n // Use the following query to get 3+0 regions: az account list-locations -o table --query '[?availabilityZoneMappings \u0026\u0026 (!metadata.pairedRegion || length(metadata.pairedRegion) == `0`)]'\n location in~ ('qatarcentral', 'polandcentral', 'israelcentral', 'italynorth') and split(skuName, '_', 1)[0] startswith \"zrs\" , 'Configured',\n split(skuName, '_', 1)[0] startswith \"ra\", \"Configured\",\n \"Not Configured\"\n ),\n type == \"microsoft.network/azurefirewalls\", \"Not Applicable\",\n type == \"microsoft.network/frontdoors\", \"Not Applicable\",\n type == \"microsoft.cdn/profiles\", \"Not Applicable\",\n type == \"microsoft.network/applicationgateways\", \"Not Applicable\",\n type == \"microsoft.network/loadbalancers\", \"Not Applicable\",\n type contains \"publicip\", \"Not Applicable\",\n type == \"microsoft.network/virtualnetworkgateways\", iff(properties.gatewayType == \"ExpressRoute\", \"Not Applicable\", tostring(properties.activeActive)), //Field Override,\n type == \"microsoft.recoveryservices/vaults\", \"Not Applicable\",\n \"Undefined\"\n )\n| extend AutomaticFailover = case(\n type in ('microsoft.compute/virtualmachines', 'microsoft.classiccompute/virtualmachines', 'microsoft.compute/virtualmachinescalesets', 'microsoft.web/sites', 'microsoft.web/serverfarms', 'microsoft.containerservice/managedclusters', 'microsoft.sql/servers/databases'), \"Not Applicable\",\n (type == 'microsoft.documentdb/databaseaccounts' and properties.enableAutomaticFailover == \"false\" and properties.enableMultipleWriteLocations == \"false\" and toint(ReadReplica) \u003e 1), \"Not Configured\",\n (type == 'microsoft.documentdb/databaseaccounts' and properties.enableAutomaticFailover == \"true\"), \"Configured\",\n (type == 'microsoft.documentdb/databaseaccounts'), \"Not Applicable\",\n type == 'microsoft.dbformysql/servers', \"Not Applicable\",\n type == 'microsoft.dbformysql/flexibleservers', case(\n properties.highAvailability.mode == \"Disabled\" and properties.replicationRole != \"Replica\" , \"Not Configured\",\n properties.replicationRole == \"Replica\", \"Not Applicable\",\n properties.highAvailability.mode == \"ZoneRedundant\", \"Zone Redundant\",\n properties.highAvailability.mode == \"SameZone\", \"Same Zone\",\n properties.highAvailability.mode\n ),\n type == 'microsoft.dbforpostgresql/servers', \"Not Applicable\",\n type == 'microsoft.dbforpostgresql/flexibleservers', case( \n properties.highAvailability.mode == \"Disabled\" and properties.replicationRole !contains \"AsyncReplica\", \"Not Configured\",\n properties.replicationRole == \"GeoAsync