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
Original file line number Diff line number Diff line change
Expand Up @@ -2047,7 +2047,7 @@ interactions:
User-Agent:
- AZURECLI/2.78.0 azsdk-python-core/1.35.0 Python/3.11.9 (Windows-10-10.0.26200-SP0)
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"clitest-vm000003\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003\",\r\n
Expand Down Expand Up @@ -2170,7 +2170,7 @@ interactions:
User-Agent:
- AZURECLI/2.78.0 azsdk-python-core/1.35.0 Python/3.11.9 (Windows-10-10.0.26200-SP0)
method: PUT
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"clitest-vm000003\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003\",\r\n
Expand Down Expand Up @@ -2550,7 +2550,7 @@ interactions:
User-Agent:
- AZURECLI/2.78.0 azsdk-python-core/1.35.0 Python/3.11.9 (Windows-10-10.0.26200-SP0)
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"clitest-vm000003\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003\",\r\n
Expand Down Expand Up @@ -2656,7 +2656,7 @@ interactions:
User-Agent:
- AZURECLI/2.78.0 azsdk-python-core/1.35.0 Python/3.11.9 (Windows-10-10.0.26200-SP0)
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"clitest-vm000003\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003\",\r\n
Expand Down Expand Up @@ -2787,7 +2787,7 @@ interactions:
User-Agent:
- AZURECLI/2.78.0 azsdk-python-core/1.35.0 Python/3.11.9 (Windows-10-10.0.26200-SP0)
method: PUT
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"clitest-vm000003\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003\",\r\n
Expand Down Expand Up @@ -3066,7 +3066,7 @@ interactions:
User-Agent:
- AZURECLI/2.78.0 azsdk-python-core/1.35.0 Python/3.11.9 (Windows-10-10.0.26200-SP0)
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"clitest-vm000003\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003\",\r\n
Expand Down Expand Up @@ -3177,7 +3177,7 @@ interactions:
User-Agent:
- AZURECLI/2.78.0 azsdk-python-core/1.35.0 Python/3.11.9 (Windows-10-10.0.26200-SP0)
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"clitest-vm000003\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003\",\r\n
Expand Down Expand Up @@ -3316,7 +3316,7 @@ interactions:
User-Agent:
- AZURECLI/2.78.0 azsdk-python-core/1.35.0 Python/3.11.9 (Windows-10-10.0.26200-SP0)
method: PUT
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"clitest-vm000003\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003\",\r\n
Expand Down Expand Up @@ -3600,7 +3600,7 @@ interactions:
User-Agent:
- AZURECLI/2.78.0 azsdk-python-core/1.35.0 Python/3.11.9 (Windows-10-10.0.26200-SP0)
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"clitest-vm000003\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AzureBackupRG_clitest_000001/providers/Microsoft.Compute/virtualMachines/clitest-vm000003\",\r\n
Expand Down
133 changes: 94 additions & 39 deletions src/azure-cli/azure/cli/command_modules/vm/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,22 @@ def _get_disk_lun(data_disks):
if not data_disks:
return 0

existing_luns = sorted([d.lun for d in data_disks])
try:
existing_luns = sorted([
(d.get('lun') if isinstance(d, dict) else getattr(d, 'lun'))
for d in data_disks
])
except (AttributeError, TypeError, ValueError, KeyError):
existing_luns = []
for d in data_disks:
try:
lun = d.get('lun') if isinstance(d, dict) else getattr(d, 'lun', None)
if lun is not None:
existing_luns.append(lun)
except (AttributeError, TypeError, ValueError, KeyError):
pass
existing_luns = sorted(existing_luns)

for i, current in enumerate(existing_luns):
if current != i:
return i
Expand Down Expand Up @@ -2321,12 +2336,14 @@ def attach_managed_data_disk(cmd, resource_group_name, vm_name, disk=None, ids=N
source_snapshots_or_disks=None, source_disk_restore_point=None,
new_names_of_source_snapshots_or_disks=None, new_names_of_source_disk_restore_point=None):
# attach multiple managed disks using disk attach API
vm = get_vm_to_update(cmd, resource_group_name, vm_name)
from .operations.vm import convert_show_result_to_snake_case as to_snake_case
vm = to_snake_case(get_vm_by_aaz(cmd, resource_group_name, vm_name) or {}) or {}

if not new and not sku and not size_gb and disk_ids is not None:
if lun:
disk_lun = lun
else:
disk_lun = _get_disk_lun(vm.storage_profile.data_disks)
disk_lun = _get_disk_lun(vm.get('storage_profile', {}).get('data_disks') or [])

data_disks = []
for disk_item in disk_ids:
Expand All @@ -2347,35 +2364,56 @@ def attach_managed_data_disk(cmd, resource_group_name, vm_name, disk=None, ids=N
else:
# attach multiple managed disks using vm PUT API
from azure.mgmt.core.tools import parse_resource_id
DataDisk, ManagedDiskParameters, DiskCreateOption = cmd.get_models(
'DataDisk', 'ManagedDiskParameters', 'DiskCreateOptionTypes')

if size_gb is None:
default_size_gb = 1023

if disk_ids is not None:
disks = disk_ids

storage_profile = vm.get('storage_profile', {})
data_disks = storage_profile.get('data_disks')
if data_disks is None:
data_disks = []
storage_profile['data_disks'] = data_disks
vm['storage_profile'] = storage_profile

for disk_item in disks:
if lun:
disk_lun = lun
else:
disk_lun = _get_disk_lun(vm.storage_profile.data_disks)
disk_lun = _get_disk_lun(data_disks)

if new:
data_disk = DataDisk(lun=disk_lun, create_option=DiskCreateOption.empty,
name=parse_resource_id(disk_item)['name'],
disk_size_gb=size_gb if size_gb else default_size_gb, caching=caching,
managed_disk=ManagedDiskParameters(storage_account_type=sku))
data_disk = {
'lun': disk_lun,
'create_option': 'Empty',
'name': parse_resource_id(disk_item)['name'],
'diskSizeGb': size_gb if size_gb else default_size_gb,
'caching': caching,
'managedDisk': {
'storageAccountType': sku
} if sku else None
}
else:
params = ManagedDiskParameters(id=disk_item, storage_account_type=sku)
data_disk = DataDisk(lun=disk_lun, create_option=DiskCreateOption.attach, managed_disk=params,
caching=caching)
data_disk = {
'lun': disk_lun,
'create_option': 'Attach',
'managedDisk': {
'id': disk_item,
'storageAccountType': sku
} if sku else {
'id': disk_item
},
'caching': caching
}

if enable_write_accelerator:
data_disk.write_accelerator_enabled = enable_write_accelerator
data_disk['writeAcceleratorEnabled'] = enable_write_accelerator

data_disks.append(data_disk)

vm.storage_profile.data_disks.append(data_disk)
disk_lun = _get_disk_lun(vm.storage_profile.data_disks)
disk_lun = _get_disk_lun(data_disks)
if source_snapshots_or_disks is not None:
if new_names_of_source_snapshots_or_disks is None:
new_names_of_source_snapshots_or_disks = [None] * len(source_snapshots_or_disks)
Expand All @@ -2401,7 +2439,7 @@ def attach_managed_data_disk(cmd, resource_group_name, vm_name, disk=None, ids=N
}
})
disk_lun += 1
vm.storage_profile.data_disks.append(disk)
data_disks.append(disk)
if source_disk_restore_point is not None:
if new_names_of_source_disk_restore_point is None:
new_names_of_source_disk_restore_point = [None] * len(source_disk_restore_point)
Expand All @@ -2427,9 +2465,9 @@ def attach_managed_data_disk(cmd, resource_group_name, vm_name, disk=None, ids=N
}
})
disk_lun += 1
vm.storage_profile.data_disks.append(disk)
data_disks.append(disk)

set_vm(cmd, vm)
set_vm_by_aaz(cmd, vm)


def detach_unmanaged_data_disk(cmd, resource_group_name, vm_name, disk_name):
Expand Down Expand Up @@ -2458,27 +2496,44 @@ def detach_managed_data_disk(cmd, resource_group_name, vm_name, disk_name=None,
return result
else:
# here we handle managed disk
vm = get_vm_to_update(cmd, resource_group_name, vm_name)
if not force_detach:
# pylint: disable=no-member
leftovers = [d for d in vm.storage_profile.data_disks if d.name.lower() != disk_name.lower()]
if len(vm.storage_profile.data_disks) == len(leftovers):
raise ResourceNotFoundError("No disk with the name '{}' was found".format(disk_name))
from .operations.vm import convert_show_result_to_snake_case as to_snake_case
vm = to_snake_case(get_vm_by_aaz(cmd, resource_group_name, vm_name) or {}) or {}
target_disk = None
data_disks = vm.get('storage_profile', {}).get('data_disks', []) or []
for d in data_disks:
# Use dict-style access; AAZ returns dicts.
name = (d.get('name') or '').lower()
if name == (disk_name or '').lower():
target_disk = d
break

if not target_disk:
attached_names = [d.get('name') for d in (vm.get('storage_profile', {}).get('data_disks', []) or [])]
raise ResourceNotFoundError(
"No disk with the name '{}' was found. Attached: {}".format(disk_name, attached_names)
)
disk_id = target_disk.get('managed_disk', {}).get('id', None) or None
if not disk_id:
raise CLIError(
"Disk '{}' is not a managed disk (no managedDisk.id). Only managed disks are supported for this "
"operation."
.format(disk_name)
)

disk_payload = {'diskId': disk_id}
if force_detach:
disk_payload['toBeDetached'] = True
disk_payload['detachOption'] = 'ForceDetach'
else:
DiskDetachOptionTypes = cmd.get_models('DiskDetachOptionTypes', resource_type=ResourceType.MGMT_COMPUTE,
operation_group='virtual_machines')
leftovers = vm.storage_profile.data_disks
is_contains = False
for d in leftovers:
if d.name.lower() == disk_name.lower():
d.to_be_detached = True
d.detach_option = DiskDetachOptionTypes.FORCE_DETACH
is_contains = True
break
if not is_contains:
raise ResourceNotFoundError("No disk with the name '{}' was found".format(disk_name))
vm.storage_profile.data_disks = leftovers
set_vm(cmd, vm)
disk_payload['detachOption'] = 'Detach'

args = {
'vm_name': vm_name,
'resource_group': resource_group_name,
'data_disks_to_detach': [disk_payload],
}
result = AttachDetachDataDisk(cli_ctx=cmd.cli_ctx)(command_args=args)
return result
# endregion


Expand Down
Loading