Skip to content

Commit 2031a73

Browse files
Merge branch 'dev' into agent-assist/azure-azure-cli-issue-34063-338c19fac314
2 parents 8a99192 + 1866360 commit 2031a73

10 files changed

Lines changed: 4172 additions & 7158 deletions

‎src/azure-cli/azure/cli/command_modules/vm/_help.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,12 @@
11211121
az vm create -n MyVm -g MyResourceGroup --public-ip-address-dns-name MyUniqueDnsName \\
11221122
--image Ubuntu2204 --data-disk-sizes-gb 10 20 --size Standard_DS2_v2 \\
11231123
--generate-ssh-keys
1124+
- name: Create a VM in a single-zone Flexible VMSS with aligned OS and data disks.
1125+
text: |
1126+
az vm create -g MyResourceGroup -n MyVm --location eastus2 --vmss MyFlexibleVmss \\
1127+
--platform-fault-domain 0 --image Ubuntu2204 --size Standard_D4s_v5 \\
1128+
--data-disk-sizes-gb 10 --os-disk-storage-fd-alignment Aligned \\
1129+
--data-disk-storage-fd-alignment BestEffortAligned
11241130
- name: Create a Debian11 VM using Key Vault secrets.
11251131
text: >
11261132
az keyvault certificate create --vault-name vaultname -n cert1 \\
@@ -2297,6 +2303,14 @@
22972303
supported-profiles: latest
22982304
text: >
22992305
az vmss create -n MyVmss -g MyResourceGroup --image CentOS85Gen2 --zones 1
2306+
- name: Create a single-zone Flexible VMSS with aligned compute and storage fault domains.
2307+
text: |
2308+
az vmss create -g MyResourceGroup -n MyVmss --location eastus2 --zones 1 \\
2309+
--orchestration-mode Flexible --platform-fault-domain-count 3 \\
2310+
--zonal-fault-domain-align-mode BestEffortAligned \\
2311+
--os-disk-storage-fd-alignment Aligned --data-disk-sizes-gb 10 \\
2312+
--data-disk-storage-fd-alignment BestEffortAligned \\
2313+
--image Ubuntu2204 --vm-sku Standard_D4s_v5
23002314
- name: Create a VMSS that supports SpotRestore.
23012315
text: >
23022316
az vmss create -n MyVmss -g MyResourceGroup --location NorthEurope --instance-count 2 --image CentOS85Gen2 --priority Spot --eviction-policy Deallocate --single-placement-group --enable-spot-restore True --spot-restore-timeout PT1H

‎src/azure-cli/azure/cli/command_modules/vm/_params.py‎

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
validate_asg_names_or_ids, validate_keyvault, _validate_proximity_placement_group,
2525
validate_vm_name_for_monitor_metrics)
2626

27-
from azure.cli.command_modules.vm._vm_utils import MSI_LOCAL_ID, CachingTypes, UpgradeMode
27+
from azure.cli.command_modules.vm._vm_utils import (MSI_LOCAL_ID, CachingTypes, UpgradeMode, DiskStorageAlignment,
28+
FaultDomainAlignment)
2829
from azure.cli.command_modules.vm._image_builder import ScriptType
2930

3031
from azure.cli.command_modules.monitor.validators import validate_metric_dimension
@@ -515,6 +516,24 @@ def load_arguments(self, _):
515516
c.argument('source_snapshots_or_disks_size_gb', options_list=['--source-snapshots-or-disks-size-gb', '--source-resource-size'], nargs='+', type=int, help='The size of the source disk in GB')
516517
c.argument('source_disk_restore_point', options_list=['--source-disk-restore-point', '--source-disk-rp'], nargs='+', help='create a data disk from a disk restore point. Can use the ID of a disk restore point.')
517518
c.argument('source_disk_restore_point_size_gb', options_list=['--source-disk-restore-point-size-gb', '--source-rp-size'], nargs='+', type=int, help='The size of the source disk restore point in GB')
519+
c.argument(
520+
'data_disk_storage_fault_domain_alignment',
521+
options_list=['--data-disk-storage-fd-alignment', '--data-disk-fda'],
522+
arg_type=get_enum_type(DiskStorageAlignment),
523+
is_preview=True,
524+
help='Specifies the storage fault domain alignment type for data disks. This option is only valid when '
525+
'the VM joins a single-zone Flexible VMSS and is set at create time. Omit this option to leave '
526+
'data disks unaligned.'
527+
)
528+
c.argument(
529+
'os_disk_storage_fault_domain_alignment',
530+
options_list=['--os-disk-storage-fd-alignment', '--os-disk-fda'],
531+
arg_type=get_enum_type(DiskStorageAlignment),
532+
is_preview=True,
533+
help='Specifies the storage fault domain alignment type for the OS disk. This option is only valid when '
534+
'the VM joins a single-zone Flexible VMSS and is set at create time. Omit this option to leave '
535+
'the OS disk unaligned.'
536+
)
518537

519538
with self.argument_context('vm create', arg_group='Dedicated Host', min_api='2019-03-01') as c:
520539
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.")
@@ -845,6 +864,32 @@ def load_arguments(self, _):
845864
'to a single availability zone in the virtual machine scale set. '
846865
'Valid values are integers between 1 and 100.'
847866
)
867+
c.argument(
868+
'data_disk_storage_fault_domain_alignment',
869+
options_list=['--data-disk-storage-fd-alignment', '--data-disk-fda'],
870+
arg_type=get_enum_type(DiskStorageAlignment),
871+
is_preview=True,
872+
help='Specifies the storage fault domain alignment type for data disks. This option is only valid for '
873+
'a single-zone Flexible VMSS and is set at create time. Omit this option to leave data disks '
874+
'unaligned.'
875+
)
876+
c.argument(
877+
'os_disk_storage_fault_domain_alignment',
878+
options_list=['--os-disk-storage-fd-alignment', '--os-disk-fda'],
879+
arg_type=get_enum_type(DiskStorageAlignment),
880+
is_preview=True,
881+
help='Specifies the storage fault domain alignment type for the OS disk. This option is only valid for '
882+
'a single-zone Flexible VMSS and is set at create time. Omit this option to leave the OS disk '
883+
'unaligned.'
884+
)
885+
c.argument(
886+
'zonal_platform_fault_domain_align_mode',
887+
options_list=['--zonal-fault-domain-align-mode', '--zonal-fda'],
888+
arg_type=get_enum_type(FaultDomainAlignment),
889+
is_preview=True,
890+
help='Specifies the alignment mode between Virtual Machine Scale Set compute and storage fault domains. '
891+
'This option is only valid for a single-zone Flexible VMSS.'
892+
)
848893

849894
with self.argument_context('vmss create', arg_group='Network Balancer') as c:
850895
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'])

‎src/azure-cli/azure/cli/command_modules/vm/_template_builder.py‎

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,8 @@ def build_vm_resource( # pylint: disable=too-many-locals, too-many-statements,
324324
wire_server_mode=None, wire_server_use_local_file_rules=None, imds_mode=None,
325325
wire_server_access_control_profile_reference_id=None,
326326
imds_access_control_profile_reference_id=None, key_incarnation_id=None, add_proxy_agent_extension=None,
327-
disk_iops_read_write=None, disk_mbps_read_write=None, zone_movement=None):
327+
disk_iops_read_write=None, disk_mbps_read_write=None, zone_movement=None,
328+
os_disk_storage_fault_domain_alignment=None, data_disk_storage_fault_domain_alignment=None):
328329

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

@@ -572,6 +573,8 @@ def _build_storage_profile():
572573
profile['osDisk']['writeAcceleratorEnabled'] = disk_info['os']['writeAcceleratorEnabled']
573574
if os_disk_delete_option is not None:
574575
profile['osDisk']['deleteOption'] = os_disk_delete_option
576+
if os_disk_storage_fault_domain_alignment is not None:
577+
profile['osDisk']['storageFaultDomainAlignment'] = os_disk_storage_fault_domain_alignment
575578
data_disks = [v for k, v in disk_info.items() if k != 'os']
576579
if data_disk_encryption_sets:
577580
if len(data_disk_encryption_sets) != len(data_disks):
@@ -586,6 +589,8 @@ def _build_storage_profile():
586589
data_disk['diskIOPSReadWrite'] = disk_iops_read_write
587590
if disk_mbps_read_write is not None:
588591
data_disk['diskMBPSReadWrite'] = disk_mbps_read_write
592+
if data_disk_storage_fault_domain_alignment is not None:
593+
data_disk['storageFaultDomainAlignment'] = data_disk_storage_fault_domain_alignment
589594
if disk_info['os'].get('diffDiskSettings'):
590595
profile['osDisk']['diffDiskSettings'] = disk_info['os']['diffDiskSettings']
591596

@@ -1092,7 +1097,8 @@ def build_vmss_resource(cmd, name, computer_name_prefix, location, tags, overpro
10921097
automatic_zone_balancing_strategy=None, automatic_zone_balancing_behavior=None,
10931098
enable_automatic_repairs=None, zone_placement_policy=None, include_zones=None,
10941099
exclude_zones=None, max_zone_count=None, instance_percent_policy=None,
1095-
max_instance_percent=None):
1100+
max_instance_percent=None, data_disk_storage_fault_domain_alignment=None,
1101+
os_disk_storage_fault_domain_alignment=None, zonal_platform_fault_domain_align_mode=None):
10961102

10971103
# Build IP configuration
10981104
ip_configuration = {}
@@ -1286,6 +1292,13 @@ def build_vmss_resource(cmd, name, computer_name_prefix, location, tags, overpro
12861292
if disk_controller_type is not None:
12871293
storage_properties['diskControllerType'] = disk_controller_type
12881294

1295+
# Aligned Zonal Fault Domains: per-disk storage fault domain alignment overrides.
1296+
if os_disk_storage_fault_domain_alignment is not None and 'osDisk' in storage_properties:
1297+
storage_properties['osDisk']['storageFaultDomainAlignment'] = os_disk_storage_fault_domain_alignment
1298+
if data_disk_storage_fault_domain_alignment is not None and storage_properties.get('dataDisks'):
1299+
for data_disk in storage_properties['dataDisks']:
1300+
data_disk['storageFaultDomainAlignment'] = data_disk_storage_fault_domain_alignment
1301+
12891302
# Build OS Profile
12901303
os_profile = {}
12911304
if computer_name_prefix:
@@ -1518,6 +1531,9 @@ def build_vmss_resource(cmd, name, computer_name_prefix, location, tags, overpro
15181531
min_api='2017-12-01', operation_group='virtual_machine_scale_sets'):
15191532
vmss_properties['platformFaultDomainCount'] = platform_fault_domain_count
15201533

1534+
if zonal_platform_fault_domain_align_mode is not None:
1535+
vmss_properties['zonalPlatformFaultDomainAlignMode'] = zonal_platform_fault_domain_align_mode
1536+
15211537
if ultra_ssd_enabled is not None:
15221538
if cmd.supported_api_version(min_api='2019-03-01', operation_group='virtual_machine_scale_sets'):
15231539
vmss_properties['additionalCapabilities'] = {'ultraSSDEnabled': ultra_ssd_enabled}

‎src/azure-cli/azure/cli/command_modules/vm/_validators.py‎

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,68 @@ def _validate_vm_create_availability_set(cmd, namespace):
761761
logger.debug("adding to specified availability set '%s'", namespace.availability_set)
762762

763763

764+
def _validate_vm_create_disk_alignment(cmd, namespace):
765+
from .operations.vmss import VMSSShow
766+
from azure.mgmt.core.tools import parse_resource_id
767+
768+
if namespace.data_disk_storage_fault_domain_alignment is None \
769+
and namespace.os_disk_storage_fault_domain_alignment is None:
770+
return
771+
772+
if not namespace.vmss:
773+
raise ArgumentUsageError('usage error: --data-disk-storage-fd-alignment/ '
774+
'--os-disk-storage-fd-alignment '
775+
'is only available for VM in a Flex VMSS.')
776+
777+
vmss_id = parse_resource_id(namespace.vmss)
778+
vmss_show = VMSSShow(cli_ctx=cmd.cli_ctx)(command_args={
779+
'resource_group': vmss_id.get('resource_group', namespace.resource_group_name),
780+
'vm_scale_set_name': vmss_id['name']
781+
})
782+
783+
if vmss_show.get('orchestrationMode', '').lower() != 'flexible':
784+
raise ArgumentUsageError('usage error: --data-disk-storage-fd-alignment/ '
785+
'--os-disk-storage-fd-alignment '
786+
'is only available for VM in a Flex VMSS.')
787+
788+
if len(vmss_show.get('zones', [])) != 1:
789+
raise ArgumentUsageError('usage error: --data-disk-storage-fd-alignment/ '
790+
'--os-disk-storage-fd-alignment '
791+
'is only available for VM in a single Availability Zone VMSS.')
792+
793+
_validate_data_disk_alignment(namespace)
794+
795+
796+
def _validate_data_disk_alignment(namespace):
797+
if namespace.data_disk_storage_fault_domain_alignment is None:
798+
return
799+
800+
data_disks = [disk for name, disk in getattr(namespace, 'disk_info', {}).items() if name != 'os']
801+
if not data_disks:
802+
raise ArgumentUsageError(
803+
'usage error: --data-disk-storage-fd-alignment requires at least one data disk.')
804+
805+
806+
def _validate_vmss_create_alignment(namespace):
807+
disk_alignment_requested = namespace.data_disk_storage_fault_domain_alignment is not None \
808+
or namespace.os_disk_storage_fault_domain_alignment is not None
809+
alignment_mode_requested = namespace.zonal_platform_fault_domain_align_mode is not None
810+
811+
if not disk_alignment_requested and not alignment_mode_requested:
812+
return
813+
814+
if (namespace.orchestration_mode or '').lower() != 'flexible':
815+
raise ArgumentUsageError('usage error: --data-disk-storage-fd-alignment/ '
816+
'--os-disk-storage-fd-alignment/ '
817+
'--zonal-fault-domain-align-mode '
818+
'is only available for VMSS with flexible orchestration mode')
819+
if not namespace.zones or len(namespace.zones) != 1:
820+
raise ArgumentUsageError('usage error: --data-disk-storage-fd-alignment/ '
821+
'--os-disk-storage-fd-alignment/ '
822+
'--zonal-fault-domain-align-mode '
823+
'is only available for VMSS with single Availability Zone')
824+
825+
764826
def _validate_vm_create_vmss(cmd, namespace):
765827
from azure.mgmt.core.tools import parse_resource_id, resource_id
766828
from azure.cli.core.commands.client_factory import get_subscription_id
@@ -1611,6 +1673,7 @@ def process_vm_create_namespace(cmd, namespace):
16111673

16121674
_validate_vm_create_availability_set(cmd, namespace)
16131675
_validate_vm_create_vmss(cmd, namespace)
1676+
_validate_vm_create_disk_alignment(cmd, namespace)
16141677
_validate_vm_vmss_create_vnet(cmd, namespace)
16151678
_validate_vm_create_nsg(cmd, namespace)
16161679
_validate_vm_vmss_create_public_ip(cmd, namespace)
@@ -1802,13 +1865,15 @@ def process_vmss_create_namespace(cmd, namespace):
18021865

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

18081871
if namespace.regular_priority_count is not None or namespace.regular_priority_percentage is not None:
18091872
if namespace.orchestration_mode.lower() != flexible_str.lower():
1810-
raise InvalidArgumentValueError('usage error: --regular-priority-count/--regular-priority-percentage is'
1811-
' only available for VMSS with flexible orchestration mode')
1873+
raise InvalidArgumentValueError('usage error: --regular-priority-count/--regular-priority-percentage is '
1874+
'only available for VMSS with flexible orchestration mode')
1875+
1876+
_validate_vmss_create_alignment(namespace)
18121877

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

@@ -1868,6 +1933,7 @@ def process_vmss_create_namespace(cmd, namespace):
18681933

18691934
if getattr(namespace, 'attach_os_disk', None) or namespace.image is not None:
18701935
_validate_vm_create_storage_profile(cmd, namespace, for_scale_set=True)
1936+
_validate_data_disk_alignment(namespace)
18711937

18721938
if namespace.vnet_name or namespace.subnet or namespace.image:
18731939
_validate_vm_vmss_create_vnet(cmd, namespace, for_scale_set=True)
@@ -1887,7 +1953,7 @@ def process_vmss_create_namespace(cmd, namespace):
18871953
namespace.authentication_type, namespace.os_type]):
18881954
_validate_vm_vmss_create_auth(namespace, cmd)
18891955
if namespace.assign_identity == '[system]':
1890-
raise InvalidArgumentValueError('usage error: only user assigned indetity is suppoprted for Flex mode.')
1956+
raise InvalidArgumentValueError('usage error: only user assigned identity is supported for Flex mode.')
18911957
if namespace.assign_identity is not None:
18921958
_validate_vm_vmss_msi(cmd, namespace) # -- UserAssignedOnly
18931959
_validate_proximity_placement_group(cmd, namespace)
@@ -1918,6 +1984,7 @@ def process_vmss_create_namespace(cmd, namespace):
19181984
validate_edge_zone(cmd, namespace)
19191985
validate_asg_names_or_ids(cmd, namespace)
19201986
_validate_vm_create_storage_profile(cmd, namespace, for_scale_set=True)
1987+
_validate_data_disk_alignment(namespace)
19211988
_validate_vm_vmss_create_vnet(cmd, namespace, for_scale_set=True)
19221989

19231990
_validate_vmss_single_placement_group(namespace)

‎src/azure-cli/azure/cli/command_modules/vm/_vm_utils.py‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,3 +842,14 @@ class OrchestrationServiceNames(Enum):
842842
class OrchestrationServiceStateAction(Enum):
843843
RESUME = 'Resume'
844844
SUSPEND = 'Suspend'
845+
846+
847+
class DiskStorageAlignment(Enum):
848+
ALIGNED = 'Aligned'
849+
BEST_EFFORT_ALIGNED = 'BestEffortAligned'
850+
851+
852+
class FaultDomainAlignment(Enum):
853+
ALIGNED = 'Aligned'
854+
BEST_EFFORT_ALIGNED = 'BestEffortAligned'
855+
UNALIGNED = 'Unaligned'

0 commit comments

Comments
 (0)