Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/aks-preview/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ To release a new version, please select a new version number (usually plus 1 to
Pending
+++++++
* Fix `match_condition` kwarg leaking to HTTP transport by overriding `put_mc` and `add_agentpool` to pass `if_match` / `if_none_match` directly to the vendored SDK. This change fixes the compatibility issue as azure-cli/acs module adopts TypeSpec emitted SDKs while azure-cli-extensions/aks-preview still uses the autorest emitted SDK.
+ `az aks list-vm-skus`: New command to list available VM SKUs for AKS clusters in a given region.

19.0.0b27
+++++++
Expand Down
4 changes: 4 additions & 0 deletions src/aks-preview/azext_aks_preview/_client_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,7 @@ def cf_load_balancers(cli_ctx, *_):

def cf_jwt_authenticators(cli_ctx, *_):
return get_container_service_client(cli_ctx).jwt_authenticators


def cf_vm_skus(cli_ctx, *_):
return get_container_service_client(cli_ctx).vm_skus
61 changes: 61 additions & 0 deletions src/aks-preview/azext_aks_preview/_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -551,3 +551,64 @@ def _get_jwtauthenticator_table_row(result):
('hasClaimRules', has_claim_rules),
('hasUserRules', has_user_rules),
])


def aks_list_vm_skus_table_format(results):
"""Format a list of VM SKUs as summary results for display with '-o table'."""
return [_aks_vm_sku_table_format(r) for r in results]


def _aks_vm_sku_table_format(sku):
"""Format a single ResourceSku for table display."""
# sku may be a model object or a dict depending on how the SDK returns it
def _get(obj, attr):
if isinstance(obj, dict):
return obj.get(attr)
return getattr(obj, attr, None)

name = _get(sku, 'name') or ''
tier = _get(sku, 'tier') or ''
size = _get(sku, 'size') or ''
family = _get(sku, 'family') or ''

# Extract zones from the first location_info entry
location_info = _get(sku, 'location_info') or _get(sku, 'locationInfo') or []
if location_info:
first_loc = location_info[0]
zones_list = _get(first_loc, 'zones') or []
zones = ', '.join(sorted(zones_list)) if zones_list else ''
else:
zones = ''

# Summarise restrictions
restrictions = _get(sku, 'restrictions') or []
if not restrictions:
restrictions_summary = 'None'
else:
reasons = []
for r in restrictions:
reason_code = _get(r, 'reason_code') or _get(r, 'reasonCode') or ''
r_type = _get(r, 'type') or ''
if reason_code:
reasons.append(f'{r_type}/{reason_code}')
restrictions_summary = '; '.join(reasons) if reasons else 'Restricted'

# Summarise capabilities as key=value pairs for compact display
capabilities = _get(sku, 'capabilities') or []
cap_parts = []
for cap in capabilities:
cap_name = _get(cap, 'name') or ''
cap_value = _get(cap, 'value') or ''
if cap_name:
cap_parts.append(f'{cap_name}={cap_value}')
capabilities_summary = ', '.join(cap_parts) if cap_parts else ''

return OrderedDict([
('name', name),
('tier', tier),
('size', size),
('family', family),
('zones', zones),
('restrictions', restrictions_summary),
('capabilities', capabilities_summary),
])
29 changes: 29 additions & 0 deletions src/aks-preview/azext_aks_preview/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -3201,6 +3201,35 @@ def load_arguments(self, _):
c.argument('config_file', options_list=['--config-file'], type=file_type, completer=FilesCompleter(),
help='Path to the JSON configuration file containing JWT authenticator properties.')

# aks list-vm-skus command
with self.argument_context("aks list-vm-skus") as c:
c.argument(
"location",
options_list=["--location", "-l"],
help="Location. Values from: 'az account list-locations'.",
required=True,
)
c.argument(
"size",
options_list=["--size", "-s"],
help="VM size name filter, partial name is accepted.",
)
c.argument(
"zone",
options_list=["--zone", "-z"],
action="store_true",
help="Show only VM SKUs that support availability zones.",
)
# TODO: Eventually deprecate the -all param.
# The List VM SKUs API already performs regional filtering so once AZ filtering is also implemented
# within the API, this param will no longer be required.
c.argument(
"show_all",
options_list=["--all"],
action="store_true",
help="Show all VM SKU information including those not available for the current subscription.",
)


def _get_default_install_location(exe_name):
system = platform.system()
Expand Down
18 changes: 18 additions & 0 deletions src/aks-preview/azext_aks_preview/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
cf_load_balancers,
cf_identity_bindings,
cf_jwt_authenticators,
cf_vm_skus,
)

from azext_aks_preview._format import (
Expand Down Expand Up @@ -50,6 +51,7 @@
aks_extension_type_version_show_table_format,
aks_jwtauthenticator_list_table_format,
aks_jwtauthenticator_show_table_format,
aks_list_vm_skus_table_format,
)

from knack.log import get_logger
Expand Down Expand Up @@ -151,6 +153,12 @@ def load_command_table(self, _):
client_factory=cf_jwt_authenticators,
)

vm_skus_sdk = CliCommandType(
operations_tmpl="azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks."
"operations._vm_skus_operations#VmSkusOperations.{}",
client_factory=cf_vm_skus,
)

# AKS managed cluster commands
with self.command_group(
"aks",
Expand Down Expand Up @@ -595,6 +603,16 @@ def load_command_table(self, _):
table_transformer=aks_jwtauthenticator_show_table_format
)

# AKS list-vm-skus command
with self.command_group(
"aks", vm_skus_sdk, client_factory=cf_vm_skus
) as g:
g.custom_command(
"list-vm-skus",
"aks_list_vm_skus",
table_transformer=aks_list_vm_skus_table_format,
)

# AKS safeguards commands - override generated commands with custom classes
with self.command_group('aks safeguards'):
from .aks_safeguards_custom import AKSSafeguardsShowCustom as Show
Expand Down
29 changes: 29 additions & 0 deletions src/aks-preview/azext_aks_preview/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -3451,6 +3451,35 @@ def aks_get_versions(cmd, client, location): # pylint: disable=unused-argumen
return client.list_kubernetes_versions(location)


def aks_list_vm_skus(cmd, client, location, size=None, zone=None, show_all=None): # pylint: disable=unused-argument
"""Lists the VM SKUs accepted by AKS when creating node pools in a specified location.

AKS will perform a best effort approach to provision the requested VM SKUs, but availability is not guaranteed.

:param location: Azure region to query.
:param size: Optional partial VM size name filter (case-insensitive).
:param zone: When True, show only SKUs that support availability zones.
:param show_all: When True, include SKUs not available to the current subscription.
"""
from azext_aks_preview.vm_skus_util import _aks_is_vm_sku_available

result = list(client.list(location))

if not show_all:
result = [sku for sku in result if _aks_is_vm_sku_available(sku, zone)]

if size:
result = [sku for sku in result if sku.name and size.lower() in sku.name.lower()]

if zone:
result = [
sku for sku in result
if sku.location_info and sku.location_info[0].zones
]

return result


def get_aks_custom_headers(aks_custom_headers=None):
headers = {}
if aks_custom_headers is not None:
Expand Down
Loading
Loading