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
160 changes: 113 additions & 47 deletions src/azure-cli/azure/cli/command_modules/vm/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -2878,13 +2878,42 @@ def show_vm_nic(cmd, resource_group_name, vm_name, nic):

NicShow = import_aaz_by_profile(cmd.cli_ctx.cloud.profile, "network.nic").Show

vm = get_vm(cmd, resource_group_name, vm_name)
found = next(
(n for n in vm.network_profile.network_interfaces if nic.lower() == n.id.lower()), None
# pylint: disable=no-member
)
vm = get_vm_to_update_by_aaz(cmd, resource_group_name, vm_name) or {}
nics = (vm.get('networkProfile') or {}).get('networkInterfaces') or []

nic_in = (nic or "").strip()
nic_in_lower = nic_in.lower()

def _safe_id(n):
_id = (n or {}).get('id')
return _id.strip() if isinstance(_id, str) else None

found = None
if "/subscriptions/" in nic_in_lower and "/networkinterfaces/" in nic_in_lower:
found = next(
(n for n in nics if (_safe_id(n) or "").lower() == nic_in_lower),
None
)

if not found:
for n in nics:
_id = _safe_id(n)
if not _id:
continue
try:
if parse_resource_id(_id).get('name', '').lower() == nic_in_lower:
found = n
break
except Exception:
continue

if found:
nic_name = parse_resource_id(found.id)['name']
found_id = _safe_id(found)
if not found_id:
raise ResourceNotFoundError(
f"NIC '{nic}' is attached to VM '{vm_name}' but NIC id is missing in VM network profile."
)
nic_name = parse_resource_id(found_id)['name']
return NicShow(cli_ctx=cmd.cli_ctx)(command_args={
'name': nic_name,
'resource_group': resource_group_name
Expand All @@ -2893,88 +2922,125 @@ def show_vm_nic(cmd, resource_group_name, vm_name, nic):


def list_vm_nics(cmd, resource_group_name, vm_name):
vm = get_vm(cmd, resource_group_name, vm_name)
return vm.network_profile.network_interfaces # pylint: disable=no-member
vm = get_vm_to_update_by_aaz(cmd, resource_group_name, vm_name) or {}
nics = (vm.get('networkProfile') or {}).get('networkInterfaces') or []

normalized = []
for nic in nics:
nic = nic or {}
normalized.append({
"id": nic.get("id"),
"resourceGroup": nic.get("resourceGroup") or resource_group_name,
"primary": nic.get("primary"),
"deleteOption": nic.get("deleteOption"),
})
return normalized


def add_vm_nic(cmd, resource_group_name, vm_name, nics, primary_nic=None):
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_to_update_by_aaz(cmd, resource_group_name, vm_name) or {}) or {}
new_nics = _build_nic_list(cmd, nics)
existing_nics = _get_existing_nics(vm)
return _update_vm_nics(cmd, vm, existing_nics + new_nics, primary_nic)

return _update_vm_nics(
cmd, vm, existing_nics + new_nics, primary_nic,
resource_group_name=resource_group_name,
vm_name=vm_name)


def remove_vm_nic(cmd, resource_group_name, vm_name, nics, primary_nic=None):
from .operations.vm import convert_show_result_to_snake_case as to_snake_case

def to_delete(nic_id):
return [n for n in nics_to_delete if n.id.lower() == nic_id.lower()]
vm = to_snake_case(get_vm_to_update_by_aaz(cmd, resource_group_name, vm_name) or {}) or {}

vm = get_vm_to_update(cmd, resource_group_name, vm_name)
nics_to_delete = _build_nic_list(cmd, nics)
existing_nics = _get_existing_nics(vm)
survived = [x for x in existing_nics if not to_delete(x.id)]
return _update_vm_nics(cmd, vm, survived, primary_nic)

delete_ids = {n["id"].lower() for n in nics_to_delete if n.get("id")}

survived = [x for x in existing_nics if (x.get("id") or "").lower() not in delete_ids]
if not survived:
# aligns with platform behavior
# (https://learn.microsoft.com/en-us/azure/virtual-network/virtual-network-network-interface-vm)
raise ValidationError("A virtual machine must have at least one network interface. "
"You cannot detach the only NIC from a VM.")

return _update_vm_nics(
cmd, vm, survived, primary_nic,
resource_group_name=resource_group_name,
vm_name=vm_name)


def set_vm_nic(cmd, resource_group_name, vm_name, nics, primary_nic=None):
vm = get_vm_to_update(cmd, resource_group_name, vm_name)
nics = _build_nic_list(cmd, nics)
return _update_vm_nics(cmd, vm, nics, primary_nic)
from .operations.vm import convert_show_result_to_snake_case as to_snake_case

vm = to_snake_case(get_vm_to_update_by_aaz(cmd, resource_group_name, vm_name) or {}) or {}
nic_list = _build_nic_list(cmd, nics)

# VM must have at least one NIC
if not nic_list:
raise ValidationError(
"A virtual machine must have at least one network interface. "
"The '--nics' parameter cannot be empty."
)

return _update_vm_nics(
cmd, vm, nic_list, primary_nic,
resource_group_name=resource_group_name,
vm_name=vm_name,
)


def _build_nic_list(cmd, nic_ids):
NicShow = import_aaz_by_profile(cmd.cli_ctx.cloud.profile, "network.nic").Show

NetworkInterfaceReference = cmd.get_models('NetworkInterfaceReference')
nic_list = []
if nic_ids:
# pylint: disable=no-member
for nic_id in nic_ids:
rg, name = _parse_rg_name(nic_id)
nic = NicShow(cli_ctx=cmd.cli_ctx)(command_args={
'name': name,
'resource_group': rg
})
nic_list.append(NetworkInterfaceReference(id=nic['id'], primary=False))
nic = NicShow(cli_ctx=cmd.cli_ctx)(command_args={'name': name, 'resource_group': rg})
nic_list.append({"id": nic["id"], "primary": False})
return nic_list


def _get_existing_nics(vm):
network_profile = getattr(vm, 'network_profile', None)
nics = []
if network_profile is not None:
nics = network_profile.network_interfaces or []
return nics
return (vm.get("network_profile") or {}).get("network_interfaces") or []


def _update_vm_nics(cmd, vm, nics, primary_nic):
NetworkProfile = cmd.get_models('NetworkProfile')

def _update_vm_nics(cmd, vm, nics, primary_nic, resource_group_name, vm_name):
if primary_nic:
try:
_, primary_nic_name = _parse_rg_name(primary_nic)
except IndexError:
primary_nic_name = primary_nic

matched = [n for n in nics if _parse_rg_name(n.id)[1].lower() == primary_nic_name.lower()]
matched = [n for n in nics if _parse_rg_name(n["id"])[1].lower() == primary_nic_name.lower()]
if not matched:
raise CLIError('Primary Nic {} is not found'.format(primary_nic))
raise CLIError(f'Primary Nic {primary_nic} is not found')
if len(matched) > 1:
raise CLIError('Duplicate Nic entries with name {}'.format(primary_nic))
raise CLIError(f'Duplicate Nic entries with name {primary_nic}')
for n in nics:
n.primary = False
matched[0].primary = True
n["primary"] = False
matched[0]["primary"] = True
elif nics:
if not [n for n in nics if n.primary]:
nics[0].primary = True
if not any(n.get("primary") for n in nics):
nics[0]["primary"] = True

network_profile = getattr(vm, 'network_profile', None)
if network_profile is None:
vm.network_profile = NetworkProfile(network_interfaces=nics)
else:
network_profile.network_interfaces = nics
vm.setdefault("network_profile", {})
vm["network_profile"]["network_interfaces"] = nics

vm.pop("resources", None)

vm["resource_group"] = resource_group_name
vm["vm_name"] = vm_name

from .operations.vm import VMCreate

poller = VMCreate(cli_ctx=cmd.cli_ctx)(command_args=vm)
result = LongRunningOperation(cmd.cli_ctx)(poller)

return set_vm(cmd, vm).network_profile.network_interfaces
return (result.get("networkProfile") or {}).get("networkInterfaces") or []
# endregion


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3053,7 +3053,7 @@ interactions:
User-Agent:
- AZURECLI/2.71.0 azsdk-python-core/1.31.0 Python/3.10.11 (Windows-10-10.0.26100-SP0)
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"multinicvm1\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1\",\r\n
Expand Down Expand Up @@ -3129,7 +3129,7 @@ interactions:
User-Agent:
- AZURECLI/2.71.0 azsdk-python-core/1.31.0 Python/3.10.11 (Windows-10-10.0.26100-SP0)
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"multinicvm1\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1\",\r\n
Expand Down Expand Up @@ -3255,7 +3255,7 @@ interactions:
User-Agent:
- AZURECLI/2.71.0 azsdk-python-core/1.31.0 Python/3.10.11 (Windows-10-10.0.26100-SP0)
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"multinicvm1\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1\",\r\n
Expand Down Expand Up @@ -3398,7 +3398,7 @@ interactions:
User-Agent:
- AZURECLI/2.71.0 azsdk-python-core/1.31.0 Python/3.10.11 (Windows-10-10.0.26100-SP0)
method: PUT
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"multinicvm1\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1\",\r\n
Expand Down Expand Up @@ -3536,7 +3536,7 @@ interactions:
User-Agent:
- AZURECLI/2.71.0 azsdk-python-core/1.31.0 Python/3.10.11 (Windows-10-10.0.26100-SP0)
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"multinicvm1\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1\",\r\n
Expand Down Expand Up @@ -3612,7 +3612,7 @@ interactions:
User-Agent:
- AZURECLI/2.71.0 azsdk-python-core/1.31.0 Python/3.10.11 (Windows-10-10.0.26100-SP0)
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"multinicvm1\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1\",\r\n
Expand Down Expand Up @@ -3756,7 +3756,7 @@ interactions:
User-Agent:
- AZURECLI/2.71.0 azsdk-python-core/1.31.0 Python/3.10.11 (Windows-10-10.0.26100-SP0)
method: PUT
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"multinicvm1\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1\",\r\n
Expand Down Expand Up @@ -3947,7 +3947,7 @@ interactions:
User-Agent:
- AZURECLI/2.71.0 azsdk-python-core/1.31.0 Python/3.10.11 (Windows-10-10.0.26100-SP0)
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"multinicvm1\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1\",\r\n
Expand Down Expand Up @@ -4023,7 +4023,7 @@ interactions:
User-Agent:
- AZURECLI/2.71.0 azsdk-python-core/1.31.0 Python/3.10.11 (Windows-10-10.0.26100-SP0)
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"multinicvm1\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1\",\r\n
Expand Down Expand Up @@ -4215,7 +4215,7 @@ interactions:
User-Agent:
- AZURECLI/2.71.0 azsdk-python-core/1.31.0 Python/3.10.11 (Windows-10-10.0.26100-SP0)
method: PUT
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"multinicvm1\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1\",\r\n
Expand Down Expand Up @@ -4406,7 +4406,7 @@ interactions:
User-Agent:
- AZURECLI/2.71.0 azsdk-python-core/1.31.0 Python/3.10.11 (Windows-10-10.0.26100-SP0)
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2024-11-01
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1?api-version=2025-04-01
response:
body:
string: "{\r\n \"name\": \"multinicvm1\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_multi_nic_vm000001/providers/Microsoft.Compute/virtualMachines/multinicvm1\",\r\n
Expand Down
Loading