Skip to content
Open
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
33 changes: 32 additions & 1 deletion src/azure-cli/azure/cli/command_modules/vm/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
validate_asg_names_or_ids, validate_keyvault, _validate_proximity_placement_group,
validate_vm_name_for_monitor_metrics)

from azure.cli.command_modules.vm._vm_utils import MSI_LOCAL_ID, CachingTypes, UpgradeMode
from azure.cli.command_modules.vm._vm_utils import (MSI_LOCAL_ID, CachingTypes, UpgradeMode, DiskStorageAlignment,
FaultDomainAlignment)
from azure.cli.command_modules.vm._image_builder import ScriptType

from azure.cli.command_modules.monitor.validators import validate_metric_dimension
Expand Down Expand Up @@ -486,6 +487,18 @@ def load_arguments(self, _):
c.argument('source_snapshots_or_disks_size_gb', options_list=['--source-snapshots-or-disks-size-gb', '--source-resource-size'], nargs='+', type=int, min_api='2024-03-01', help='The size of the source disk in GB')
c.argument('source_disk_restore_point', options_list=['--source-disk-restore-point', '--source-disk-rp'], nargs='+', min_api='2024-03-01', help='create a data disk from a disk restore point. Can use the ID of a disk restore point.')
c.argument('source_disk_restore_point_size_gb', options_list=['--source-disk-restore-point-size-gb', '--source-rp-size'], nargs='+', type=int, min_api='2024-03-01', help='The size of the source disk restore point in GB')
c.argument(
'data_disk_storage_fault_domain_alignment',
options_list=['--data-disk-storage-fault-domain-alignment', '--data-disk-storage-fda'],
arg_type=get_enum_type(DiskStorageAlignment),
help='Specifies the storage fault domain alignment type for the disk.'
)
Comment on lines +491 to +495
c.argument(
'os_disk_storage_fault_domain_alignment',
options_list=['--os-disk-storage-fault-domain-alignment', '--os-disk-storage-fda'],
arg_type=get_enum_type(DiskStorageAlignment),
help='Specifies the storage fault domain alignment type for the disk.'
)

with self.argument_context('vm create', arg_group='Dedicated Host', min_api='2019-03-01') as c:
c.argument('dedicated_host_group', options_list=['--host-group'], is_preview=True, help="Name or resource ID of the dedicated host group that the VM will reside in. --host and --host-group can't be used together.")
Expand Down Expand Up @@ -818,6 +831,24 @@ def load_arguments(self, _):
'to a single availability zone in the virtual machine scale set. '
'Valid values are integers between 1 and 100.'
)
c.argument(
'data_disk_storage_fault_domain_alignment',
options_list=['--data-disk-storage-fault-domain-alignment', '--data-disk-storage-fda'],
arg_type=get_enum_type(DiskStorageAlignment),
help='Specifies the storage fault domain alignment type for the disk.'
)
c.argument(
'os_disk_storage_fault_domain_alignment',
options_list=['--os-disk-storage-fault-domain-alignment', '--os-disk-storage-fda'],
arg_type=get_enum_type(DiskStorageAlignment),
help='Specifies the storage fault domain alignment type for the disk.'
)
c.argument(
'zonal_platform_fault_domain_align_mode',
options_list=['--zonal-platform-fault-domain-align-mode', '--zonal-fda'],
arg_type=get_enum_type(FaultDomainAlignment),
Comment on lines +837 to +849
help='Specifies the align mode between Virtual Machine Scale Set compute and storage Fault Domain count.'
)

with self.argument_context('vmss create', arg_group='Network Balancer') as c:
c.argument('application_gateway', help='Name to use when creating a new application gateway (default) or referencing an existing one. Can also reference an existing application gateway by ID or specify "" for none.', options_list=['--app-gateway'])
Expand Down
24 changes: 20 additions & 4 deletions src/azure-cli/azure/cli/command_modules/vm/_template_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,8 @@ def build_vm_resource( # pylint: disable=too-many-locals, too-many-statements,
zone_placement_policy=None, include_zones=None, exclude_zones=None, align_regional_disks_to_vm_zone=None,
wire_server_mode=None, imds_mode=None, wire_server_access_control_profile_reference_id=None,
imds_access_control_profile_reference_id=None, key_incarnation_id=None, add_proxy_agent_extension=None,
disk_iops_read_write=None, disk_mbps_read_write=None, zone_movement=None):
disk_iops_read_write=None, disk_mbps_read_write=None, zone_movement=None,
os_disk_storage_fault_domain_alignment=None, data_disk_storage_fault_domain_alignment=None):

os_caching = disk_info['os'].get('caching')

Expand Down Expand Up @@ -560,6 +561,8 @@ def _build_storage_profile():
profile['osDisk']['writeAcceleratorEnabled'] = disk_info['os']['writeAcceleratorEnabled']
if os_disk_delete_option is not None:
profile['osDisk']['deleteOption'] = os_disk_delete_option
if os_disk_storage_fault_domain_alignment is not None:
profile['osDisk']['storageFaultDomainAlignment'] = os_disk_storage_fault_domain_alignment
Comment on lines +564 to +565
data_disks = [v for k, v in disk_info.items() if k != 'os']
if data_disk_encryption_sets:
if len(data_disk_encryption_sets) != len(data_disks):
Expand All @@ -574,6 +577,8 @@ def _build_storage_profile():
data_disk['diskIOPSReadWrite'] = disk_iops_read_write
if disk_mbps_read_write is not None:
data_disk['diskMBPSReadWrite'] = disk_mbps_read_write
if data_disk_storage_fault_domain_alignment is not None:
data_disk['storageFaultDomainAlignment'] = data_disk_storage_fault_domain_alignment
if disk_info['os'].get('diffDiskSettings'):
profile['osDisk']['diffDiskSettings'] = disk_info['os']['diffDiskSettings']

Expand Down Expand Up @@ -747,7 +752,7 @@ def _build_storage_profile():
}

vm = {
'apiVersion': '2025-04-01',
'apiVersion': '2025-11-01',
'type': 'Microsoft.Compute/virtualMachines',
'name': name,
'location': location,
Expand Down Expand Up @@ -1066,7 +1071,8 @@ def build_vmss_resource(cmd, name, computer_name_prefix, location, tags, overpro
automatic_zone_balancing_strategy=None, automatic_zone_balancing_behavior=None,
enable_automatic_repairs=None, zone_placement_policy=None, include_zones=None,
exclude_zones=None, max_zone_count=None, instance_percent_policy=None,
max_instance_percent=None):
max_instance_percent=None, data_disk_storage_fault_domain_alignment=None,
os_disk_storage_fault_domain_alignment=None, zonal_platform_fault_domain_align_mode=None):

# Build IP configuration
ip_configuration = {}
Expand Down Expand Up @@ -1260,6 +1266,13 @@ def build_vmss_resource(cmd, name, computer_name_prefix, location, tags, overpro
if disk_controller_type is not None:
storage_properties['diskControllerType'] = disk_controller_type

# Aligned Zonal Fault Domains: per-disk storage fault domain alignment overrides.
if os_disk_storage_fault_domain_alignment is not None and 'osDisk' in storage_properties:
storage_properties['osDisk']['storageFaultDomainAlignment'] = os_disk_storage_fault_domain_alignment
if data_disk_storage_fault_domain_alignment is not None and storage_properties.get('dataDisks'):
for data_disk in storage_properties['dataDisks']:
data_disk['storageFaultDomainAlignment'] = data_disk_storage_fault_domain_alignment

# Build OS Profile
os_profile = {}
if computer_name_prefix:
Expand Down Expand Up @@ -1489,6 +1502,9 @@ def build_vmss_resource(cmd, name, computer_name_prefix, location, tags, overpro
min_api='2017-12-01', operation_group='virtual_machine_scale_sets'):
vmss_properties['platformFaultDomainCount'] = platform_fault_domain_count

if zonal_platform_fault_domain_align_mode is not None:
vmss_properties['zonalPlatformFaultDomainAlignMode'] = zonal_platform_fault_domain_align_mode

if ultra_ssd_enabled is not None:
if cmd.supported_api_version(min_api='2019-03-01', operation_group='virtual_machine_scale_sets'):
vmss_properties['additionalCapabilities'] = {'ultraSSDEnabled': ultra_ssd_enabled}
Expand Down Expand Up @@ -1717,7 +1733,7 @@ def build_vmss_resource(cmd, name, computer_name_prefix, location, tags, overpro
'name': name,
'location': location,
'tags': tags,
'apiVersion': '2025-04-01',
'apiVersion': '2025-11-01',
'dependsOn': [],
'properties': vmss_properties
}
Expand Down
56 changes: 51 additions & 5 deletions src/azure-cli/azure/cli/command_modules/vm/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,37 @@ def _validate_vm_create_availability_set(cmd, namespace):
logger.debug("adding to specified availability set '%s'", namespace.availability_set)


def _validate_vm_create_disk_alignment(cmd, namespace):
from .operations.vmss import VMSSShow
from azure.mgmt.core.tools import parse_resource_id

if namespace.data_disk_storage_fault_domain_alignment is None \
and namespace.os_disk_storage_fault_domain_alignment is None:
return

if not namespace.vmss:
raise ArgumentUsageError('usage error: --data-disk-storage-fault-domain-alignment/ '
'--os-disk-storage-fault-domain-alignment '
'is only available for VM in a Flex VMSS.')

Comment on lines +762 to +766
vmss_show = VMSSShow(cmd.cli_ctx)(command_args={
'resource_group': namespace.resource_group_name,
'vm_scale_set_name': parse_resource_id(namespace.vmss)['name']
})

flexible_str = 'Flexible'

if vmss_show.get('orchestrationMode') != flexible_str:
raise ArgumentUsageError('usage error: --data-disk-storage-fault-domain-alignment/ '
'--os-disk-storage-fault-domain-alignment '
'is only available for VM in a Flex VMSS.')

if len(vmss_show.get('zones', [])) != 1:
raise ArgumentUsageError('usage error: --data-disk-storage-fault-domain-alignment/ '
'--os-disk-storage-fault-domain-alignment '
'is only available for VM in a single Availability Zone VMSS.')


def _validate_vm_create_vmss(cmd, namespace):
from azure.mgmt.core.tools import parse_resource_id, resource_id
from azure.cli.core.commands.client_factory import get_subscription_id
Expand Down Expand Up @@ -1613,6 +1644,7 @@ def process_vm_create_namespace(cmd, namespace):
_validate_vm_create_storage_account(cmd, namespace)

_validate_vm_create_availability_set(cmd, namespace)
_validate_vm_create_disk_alignment(cmd, namespace)
_validate_vm_create_vmss(cmd, namespace)
_validate_vm_vmss_create_vnet(cmd, namespace)
_validate_vm_create_nsg(cmd, namespace)
Expand Down Expand Up @@ -1805,13 +1837,27 @@ def process_vmss_create_namespace(cmd, namespace):

if namespace.os_disk_delete_option is not None or namespace.data_disk_delete_option is not None:
if namespace.orchestration_mode.lower() != flexible_str.lower():
raise InvalidArgumentValueError('usage error: --os-disk-delete-option/--data-disk-delete-option is only'
' available for VMSS with flexible orchestration mode')
raise InvalidArgumentValueError('usage error: --os-disk-delete-option/--data-disk-delete-option is only '
'available for VMSS with flexible orchestration mode')

if namespace.regular_priority_count is not None or namespace.regular_priority_percentage is not None:
if namespace.orchestration_mode.lower() != flexible_str.lower():
raise InvalidArgumentValueError('usage error: --regular-priority-count/--regular-priority-percentage is'
' only available for VMSS with flexible orchestration mode')
raise InvalidArgumentValueError('usage error: --regular-priority-count/--regular-priority-percentage is '
'only available for VMSS with flexible orchestration mode')

if namespace.data_disk_storage_fault_domain_alignment is not None \
or namespace.os_disk_storage_fault_domain_alignment is not None \
or namespace.zonal_platform_fault_domain_align_mode is not None:
if namespace.orchestration_mode.lower() != flexible_str.lower():
raise ArgumentUsageError('usage error: --data-disk-storage-fault-domain-alignment/ '
'--os-disk-storage-fault-domain-alignment/ '
'--zonal-platform-fault-domain-align-mode '
'is only available for VMSS with flexible orchestration mode')
if not namespace.zones and len(namespace.zones) != 1:
raise ArgumentUsageError('usage error: --data-disk-storage-fault-domain-alignment/ '
'--os-disk-storage-fault-domain-alignment/ '
'--zonal-platform-fault-domain-align-mode '
'is only available for VMSS with single Availability Zone')

if namespace.orchestration_mode.lower() == flexible_str.lower():

Expand Down Expand Up @@ -1890,7 +1936,7 @@ def process_vmss_create_namespace(cmd, namespace):
namespace.authentication_type, namespace.os_type]):
_validate_vm_vmss_create_auth(namespace, cmd)
if namespace.assign_identity == '[system]':
raise InvalidArgumentValueError('usage error: only user assigned indetity is suppoprted for Flex mode.')
raise InvalidArgumentValueError('usage error: only user assigned identity is supported for Flex mode.')
if namespace.assign_identity is not None:
_validate_vm_vmss_msi(cmd, namespace) # -- UserAssignedOnly
_validate_proximity_placement_group(cmd, namespace)
Expand Down
11 changes: 11 additions & 0 deletions src/azure-cli/azure/cli/command_modules/vm/_vm_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -842,3 +842,14 @@ class OrchestrationServiceNames(Enum):
class OrchestrationServiceStateAction(Enum):
RESUME = 'Resume'
SUSPEND = 'Suspend'


class DiskStorageAlignment(Enum):
ALIGNED = 'Aligned'
BEST_EFFORT_ALIGNED = 'BestEffortAligned'


class FaultDomainAlignment(Enum):
ALIGNED = 'Aligned'
BEST_EFFORT_ALIGNED = 'BestEffortAligned'
UNALIGNED = 'Unaligned'
15 changes: 11 additions & 4 deletions src/azure-cli/azure/cli/command_modules/vm/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -940,7 +940,8 @@ def create_vm(cmd, vm_name, resource_group_name, image=None, size='Standard_D2s_
exclude_zones=None, align_regional_disks_to_vm_zone=None, wire_server_mode=None, imds_mode=None,
wire_server_access_control_profile_reference_id=None, imds_access_control_profile_reference_id=None,
key_incarnation_id=None, add_proxy_agent_extension=None, disk_iops_read_write=None,
disk_mbps_read_write=None, zone_movement=None):
disk_mbps_read_write=None, zone_movement=None,
os_disk_storage_fault_domain_alignment=None, data_disk_storage_fault_domain_alignment=None):

from azure.cli.core.commands.client_factory import get_subscription_id
from azure.cli.core.util import random_string, hash_string
Expand Down Expand Up @@ -1172,7 +1173,8 @@ def create_vm(cmd, vm_name, resource_group_name, image=None, size='Standard_D2s_
imds_access_control_profile_reference_id=imds_access_control_profile_reference_id,
key_incarnation_id=key_incarnation_id, add_proxy_agent_extension=add_proxy_agent_extension,
disk_iops_read_write=disk_iops_read_write, disk_mbps_read_write=disk_mbps_read_write,
zone_movement=zone_movement)
zone_movement=zone_movement, os_disk_storage_fault_domain_alignment=os_disk_storage_fault_domain_alignment,
data_disk_storage_fault_domain_alignment=data_disk_storage_fault_domain_alignment)

vm_resource['dependsOn'] = vm_dependencies

Expand Down Expand Up @@ -3770,7 +3772,9 @@ def create_vmss(cmd, vmss_name, resource_group_name, image=None,
imds_access_control_profile_reference_id=None, enable_automatic_zone_balancing=None,
automatic_zone_balancing_strategy=None, automatic_zone_balancing_behavior=None,
enable_automatic_repairs=None, zone_placement_policy=None, include_zones=None,
exclude_zones=None, max_zone_count=None, instance_percent_policy=None, max_instance_percent=None):
exclude_zones=None, max_zone_count=None, instance_percent_policy=None, max_instance_percent=None,
data_disk_storage_fault_domain_alignment=None, os_disk_storage_fault_domain_alignment=None,
zonal_platform_fault_domain_align_mode=None):
from azure.cli.core.commands.client_factory import get_subscription_id
from azure.cli.core.util import random_string, hash_string
from azure.cli.core.commands.arm import ArmTemplateBuilder
Expand Down Expand Up @@ -4096,7 +4100,10 @@ def _get_public_ip_address_allocation(value, sku):
automatic_zone_balancing_behavior=automatic_zone_balancing_behavior,
enable_automatic_repairs=enable_automatic_repairs, zone_placement_policy=zone_placement_policy,
include_zones=include_zones, exclude_zones=exclude_zones, max_zone_count=max_zone_count,
instance_percent_policy=instance_percent_policy, max_instance_percent=max_instance_percent)
instance_percent_policy=instance_percent_policy, max_instance_percent=max_instance_percent,
data_disk_storage_fault_domain_alignment=data_disk_storage_fault_domain_alignment,
os_disk_storage_fault_domain_alignment=os_disk_storage_fault_domain_alignment,
zonal_platform_fault_domain_align_mode=zonal_platform_fault_domain_align_mode)

vmss_resource['dependsOn'] = vmss_dependencies

Expand Down
Loading
Loading