Skip to content

Update GenVmSizes to query all Azure regions for comprehensive VM size list#16313

Merged
mitchdenny merged 2 commits intomainfrom
dev/update-aks-vm-sizes
Apr 20, 2026
Merged

Update GenVmSizes to query all Azure regions for comprehensive VM size list#16313
mitchdenny merged 2 commits intomainfrom
dev/update-aks-vm-sizes

Conversation

@mitchdenny
Copy link
Copy Markdown
Member

Description

The GenVmSizes.cs tool previously only queried 9 US regions for VM SKUs, resulting in the AksNodeVmSizes.Generated.cs file missing many VM sizes that are available exclusively in non-US regions.

Changes

Tool (GenVmSizes.cs):

  • Replaced hardcoded US region list with the unfiltered Microsoft.Compute/skus API endpoint, which returns all SKUs across all Azure regions in a single paginated response
  • Added nextLink pagination support for the SKU API response
  • Added AzureCloud verification to prevent accidental use with government/sovereign clouds
  • Added deterministic deduplication (sort by name + location before grouping for stable output across runs)
  • Fixed az CLI path resolution for cross-platform compatibility (Windows .cmd files weren't found by Process.Start)
  • Removed unused using directive and suppressed CS1591 for the tool-only types

Generated output (AksNodeVmSizes.Generated.cs):

  • Regenerated from ~50 hand-curated entries to 1,373 VM sizes
  • Categories now use Azure SKU family names from the API (e.g., StandardDSv5, StandardFSv2) instead of hand-curated names

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
    • No
  • Does the change require an update in our Aspire docs?
    • Yes
    • No

Copilot AI review requested due to automatic review settings April 20, 2026 00:16
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 20, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 16313

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 16313"

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the Azure Kubernetes VM size generation tool to query the full Azure Compute SKUs catalog (all regions) and regenerates the VM size constants to include region-specific sizes that were previously missing.

Changes:

  • Switched GenVmSizes.cs from a hardcoded US-region loop to the unfiltered Microsoft.Compute/skus endpoint with nextLink pagination.
  • Added a public-cloud (AzureCloud) verification step and improved az CLI path resolution for Windows.
  • Regenerated AksNodeVmSizes.Generated.cs to include the complete, API-derived VM size set and family-based groupings.

Reviewed changes

Copilot reviewed 1 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/Aspire.Hosting.Azure.Kubernetes/tools/GenVmSizes.cs Expands SKU discovery to all regions via paginated SKUs API; adds AzureCloud guard and az resolution changes.
src/Aspire.Hosting.Azure.Kubernetes/AksNodeVmSizes.Generated.cs Regenerated VM size constants to reflect the new comprehensive SKU input and updated grouping scheme.

Console.WriteLine($"Using subscription: {subscriptionId}");
// Verify we're targeting the public Azure cloud
var cloudName = await RunAzCommand("cloud show --query name -o tsv").ConfigureAwait(false);
cloudName = cloudName?.Trim();
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If RunAzCommand("cloud show ...") fails (e.g., az not installed / command error) cloudName will be null/empty, and this check reports a misleading "active cloud is ''" message instead of the underlying failure. Consider explicitly handling null/whitespace cloudName as a separate error (fail fast with a message like "Failed to determine active Azure cloud"), so users don’t get directed to switch clouds when the real issue is az execution/login.

Suggested change
cloudName = cloudName?.Trim();
cloudName = cloudName?.Trim();
if (string.IsNullOrWhiteSpace(cloudName))
{
Console.Error.WriteLine("Error: Failed to determine the active Azure cloud. Ensure the Azure CLI is installed and that you are logged in with 'az login'.");
return 1;
}

Copilot uses AI. Check for mistakes.
Comment on lines +158 to +169
// Try common names: 'az' on Linux/macOS, 'az.cmd' on Windows
var pathDirs = Environment.GetEnvironmentVariable("PATH")?.Split(Path.PathSeparator) ?? [];
string[] candidates = OperatingSystem.IsWindows()
? ["az.cmd", "az.bat", "az.exe"]
: ["az"];

foreach (var dir in pathDirs)
{
foreach (var candidate in candidates)
{
var fullPath = Path.Combine(dir, candidate);
if (File.Exists(fullPath))
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FindAzCli reimplements PATH lookup but is less robust than the repository’s existing PathLookupHelper.FindFullPathFromPath (e.g., it doesn’t use PATHEXT and doesn’t remove empty PATH entries). This increases the chance of subtle cross-platform lookup failures and duplicates logic already used elsewhere for resolving az. Consider reusing PathLookupHelper (or aligning this implementation with it) to keep command resolution consistent across the repo.

Suggested change
// Try common names: 'az' on Linux/macOS, 'az.cmd' on Windows
var pathDirs = Environment.GetEnvironmentVariable("PATH")?.Split(Path.PathSeparator) ?? [];
string[] candidates = OperatingSystem.IsWindows()
? ["az.cmd", "az.bat", "az.exe"]
: ["az"];
foreach (var dir in pathDirs)
{
foreach (var candidate in candidates)
{
var fullPath = Path.Combine(dir, candidate);
if (File.Exists(fullPath))
const string commandName = "az";
var pathDirs = (Environment.GetEnvironmentVariable("PATH") ?? string.Empty)
.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
string[] candidates;
if (OperatingSystem.IsWindows())
{
var pathExt = (Environment.GetEnvironmentVariable("PATHEXT") ?? ".COM;.EXE;.BAT;.CMD")
.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
candidates =
[
commandName,
.. pathExt.Select(ext => commandName + ext.ToLowerInvariant()),
.. pathExt.Select(ext => commandName + ext.ToUpperInvariant()),
];
}
else
{
candidates = [commandName];
}
var visitedPaths = new HashSet<string>(OperatingSystem.IsWindows() ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal);
foreach (var dir in pathDirs)
{
foreach (var candidate in candidates)
{
var fullPath = Path.Combine(dir, candidate);
if (visitedPaths.Add(fullPath) && File.Exists(fullPath))

Copilot uses AI. Check for mistakes.
Comment on lines 22 to +25
/// <summary>
/// General purpose VM sizes optimized for balanced CPU-to-memory ratio.
/// VM sizes in the Standard NCASv3_T4 Family family.
/// </summary>
public static class GeneralPurpose
public static class StandardNCASv3T4
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generated family summary repeats the word “family” when the Azure SKU family already contains “Family” (e.g., "Standard NCASv3_T4 Family family"). Consider adjusting the generator to strip a trailing "Family" from the displayed family name so the XML docs read cleanly.

Copilot uses AI. Check for mistakes.
…ilter

The GenVmSizes tool previously only queried 9 US regions, missing VM sizes
available exclusively in other regions. Updated to use the unfiltered
Microsoft.Compute/skus API endpoint which returns all SKUs across all
regions in a single paginated response.

Additionally, the tool now filters to only AKS-compatible VM sizes per
https://learn.microsoft.com/azure/aks/quotas-skus-regions#restricted-vm-sizes:
- Requires minimum 2 vCPUs
- Requires minimum 2 GB RAM
- Excludes Basic tier VMs

Changes:
- Replace hardcoded US region list with unfiltered SKU API call
- Add pagination support via nextLink
- Add AzureCloud verification to prevent accidental use with gov/sovereign clouds
- Add deterministic deduplication (sort by name+location before grouping)
- Add AKS node pool compatibility filtering
- Fix az CLI path resolution for cross-platform compatibility
- Regenerated AksNodeVmSizes.Generated.cs: 1351 VM sizes (up from ~50)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mitchdenny mitchdenny force-pushed the dev/update-aks-vm-sizes branch from 5f3748e to c09342e Compare April 20, 2026 01:09
Copy link
Copy Markdown
Member

@JamesNK JamesNK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found: 1 stale reference (breaking code examples in XML docs and spec), 1 comment/code mismatch (Av1 filter documented but not implemented).

/// </summary>
public static class GeneralPurpose
public static class StandardNCASv3T4
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR removes the GpuAccelerated nested class and moves StandardNC6sV3 into StandardNCSv3. However, AzureKubernetesEnvironmentExtensions.cs (line 235) and docs/specs/aks-support.md (line 398) both contain XML doc / spec examples referencing the now-removed AksNodeVmSizes.GpuAccelerated.StandardNC6sV3. These should be updated to match the new class structure (e.g., AksNodeVmSizes.StandardNCSv3.StandardNC6sV3) so the example code compiles.

// - VM sizes with fewer than 2 vCPUs are restricted
// - VM sizes with fewer than 2 GB RAM are restricted for user node pools
// - Basic tier VMs are not supported
// - Av1 series VMs are not recommended (deprecated)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment above lists "Av1 series VMs are not recommended (deprecated)" as an AKS restriction, but IsAksCompatible does not implement any Av1 filter. Either remove this bullet from the comment (if it's intentionally not filtered) or add the missing filter to IsAksCompatible.

- Update stale references to AksNodeVmSizes.GpuAccelerated.StandardNC6sV3
  to AksNodeVmSizes.StandardNCSv3.StandardNC6sV3 in extension XML docs
  and aks-support.md spec
- Fix Av1 comment/code mismatch: clarify that Av1 is 'not recommended'
  (not restricted) and intentionally included in the output
- Update spec checklist to reflect new family-based category structure

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mitchdenny mitchdenny enabled auto-merge (squash) April 20, 2026 03:43
@mitchdenny mitchdenny merged commit 3ca7a67 into main Apr 20, 2026
560 of 565 checks passed
@github-actions github-actions Bot added this to the 13.3 milestone Apr 20, 2026
@github-actions
Copy link
Copy Markdown
Contributor

🎬 CLI E2E Test Recordings — 72 recordings uploaded (commit 05c76be)

View recordings
Test Recording
AddPackageInteractiveWhileAppHostRunningDetached ▶️ View Recording
AddPackageWhileAppHostRunningDetached ▶️ View Recording
AgentCommands_AllHelpOutputs_AreCorrect ▶️ View Recording
AgentInitCommand_DefaultSelection_InstallsSkillOnly ▶️ View Recording
AgentInitCommand_MigratesDeprecatedConfig ▶️ View Recording
AspireAddPackageVersionToDirectoryPackagesProps ▶️ View Recording
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps ▶️ View Recording
Banner_DisplayedOnFirstRun ▶️ View Recording
Banner_DisplayedWithExplicitFlag ▶️ View Recording
Banner_NotDisplayedWithNoLogoFlag ▶️ View Recording
CertificatesClean_RemovesCertificates ▶️ View Recording
CertificatesTrust_WithNoCert_CreatesAndTrustsCertificate ▶️ View Recording
CertificatesTrust_WithUntrustedCert_TrustsCertificate ▶️ View Recording
ConfigSetGet_CreatesNestedJsonFormat ▶️ View Recording
CreateAndRunAspireStarterProject ▶️ View Recording
CreateAndRunAspireStarterProjectWithBundle ▶️ View Recording
CreateAndRunEmptyAppHostProject ▶️ View Recording
CreateAndRunJavaEmptyAppHostProject ▶️ View Recording
CreateAndRunJsReactProject ▶️ View Recording
CreateAndRunPythonReactProject ▶️ View Recording
CreateAndRunTypeScriptEmptyAppHostProject ▶️ View Recording
CreateAndRunTypeScriptStarterProject ▶️ View Recording
CreateJavaAppHostWithViteApp ▶️ View Recording
CreateTypeScriptAppHostWithViteApp ▶️ View Recording
DashboardRunWithOtelTracesReturnsNoTraces ▶️ View Recording
DeployK8sBasicApiService ▶️ View Recording
DeployK8sWithGarnet ▶️ View Recording
DeployK8sWithMongoDB ▶️ View Recording
DeployK8sWithMySql ▶️ View Recording
DeployK8sWithPostgres ▶️ View Recording
DeployK8sWithRabbitMQ ▶️ View Recording
DeployK8sWithRedis ▶️ View Recording
DeployK8sWithSqlServer ▶️ View Recording
DeployK8sWithValkey ▶️ View Recording
DeployTypeScriptAppToKubernetes ▶️ View Recording
DescribeCommandResolvesReplicaNames ▶️ View Recording
DescribeCommandShowsRunningResources ▶️ View Recording
DetachFormatJsonProducesValidJson ▶️ View Recording
DetachFormatJsonProducesValidJsonWhenRestartingExistingInstance ▶️ View Recording
DoListStepsShowsPipelineSteps ▶️ View Recording
DoctorCommand_DetectsDeprecatedAgentConfig ▶️ View Recording
DoctorCommand_WithSslCertDir_ShowsTrusted ▶️ View Recording
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted ▶️ View Recording
GlobalMigration_HandlesCommentsAndTrailingCommas ▶️ View Recording
GlobalMigration_HandlesMalformedLegacyJson ▶️ View Recording
GlobalMigration_PreservesAllValueTypes ▶️ View Recording
GlobalMigration_SkipsWhenNewConfigExists ▶️ View Recording
GlobalSettings_MigratedFromLegacyFormat ▶️ View Recording
InitTypeScriptAppHost_AugmentsExistingViteRepoAtRoot ▶️ View Recording
InvalidAppHostPathWithComments_IsHealedOnRun ▶️ View Recording
LegacySettingsMigration_AdjustsRelativeAppHostPath ▶️ View Recording
LogsCommandShowsResourceLogs ▶️ View Recording
OtelLogsReturnsStructuredLogsFromStarterApp ▶️ View Recording
PsCommandListsRunningAppHost ▶️ View Recording
PsFormatJsonOutputsOnlyJsonToStdout ▶️ View Recording
PublishWithConfigureEnvFileUpdatesEnvOutput ▶️ View Recording
PublishWithDockerComposeServiceCallbackSucceeds ▶️ View Recording
PublishWithoutOutputPathUsesAppHostDirectoryDefault ▶️ View Recording
RestoreGeneratesSdkFiles ▶️ View Recording
RestoreRefreshesGeneratedSdkAfterAddingIntegration ▶️ View Recording
RestoreSupportsConfigOnlyHelperPackageAndCrossPackageTypes ▶️ View Recording
RunFromParentDirectory_UsesExistingConfigNearAppHost ▶️ View Recording
SecretCrudOnDotNetAppHost ▶️ View Recording
SecretCrudOnTypeScriptAppHost ▶️ View Recording
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels ▶️ View Recording
StartAndWaitForTypeScriptSqlServerAppHostWithNativeAssets ▶️ View Recording
StopAllAppHostsFromAppHostDirectory ▶️ View Recording
StopAllAppHostsFromUnrelatedDirectory ▶️ View Recording
StopNonInteractiveMultipleAppHostsShowsError ▶️ View Recording
StopNonInteractiveSingleAppHost ▶️ View Recording
StopWithNoRunningAppHostExitsSuccessfully ▶️ View Recording
UnAwaitedChainsCompileWithAutoResolvePromises ▶️ View Recording

📹 Recordings uploaded automatically from CI run #24646365591

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants