From 3a6f442856f22df34a44619aa7f2d0a3eff0ee79 Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Wed, 27 Oct 2021 13:17:35 -0400 Subject: [PATCH] Support removing VM interfaces by MAC Provides a way to handle multiple interfaces in the same network gracefully, while making the previous behaviour explicit. --- client-cli/pvc/cli_lib/vm.py | 28 ++++++++++++++++++++++------ client-cli/pvc/pvc.py | 14 +++++++++++--- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/client-cli/pvc/cli_lib/vm.py b/client-cli/pvc/cli_lib/vm.py index bc6edaa0..c54b71b5 100644 --- a/client-cli/pvc/cli_lib/vm.py +++ b/client-cli/pvc/cli_lib/vm.py @@ -813,9 +813,9 @@ def vm_networks_add(config, vm, network, macaddr, model, sriov, sriov_mode, live return retcode, retmsg -def vm_networks_remove(config, vm, network, sriov, live, restart): +def vm_networks_remove(config, vm, network, macaddr, sriov, live, restart): """ - Remove a network to the VM + Remove a network from the VM, optionally by MAC Calls vm_info to get the VM XML. @@ -826,6 +826,9 @@ def vm_networks_remove(config, vm, network, sriov, live, restart): from lxml.objectify import fromstring from lxml.etree import tostring + if network is None and macaddr is None: + return False, "A network or MAC address must be specified for removal." + status, domain_information = vm_info(config, vm) if not status: return status, domain_information @@ -845,17 +848,26 @@ def vm_networks_remove(config, vm, network, sriov, live, restart): if sriov: if interface.attrib.get('type') == 'hostdev': if_dev = str(interface.sriov_device) - if network == if_dev: + if macaddr is None and network == if_dev: + interface.getparent().remove(interface) + changed = True + elif macaddr is not None and macaddr == interface.mac.attrib.get('address'): interface.getparent().remove(interface) changed = True elif interface.attrib.get('type') == 'direct': if_dev = str(interface.source.attrib.get('dev')) - if network == if_dev: + if macaddr is None and network == if_dev: + interface.getparent().remove(interface) + changed = True + elif macaddr is not None and macaddr == interface.mac.attrib.get('address'): interface.getparent().remove(interface) changed = True else: if_vni = re.match(r'[vm]*br([0-9a-z]+)', interface.source.attrib.get('bridge')).group(1) - if network == if_vni: + if macaddr is None and network == if_vni: + interface.getparent().remove(interface) + changed = True + elif macaddr is not None and macaddr == interface.mac.attrib.get('address'): interface.getparent().remove(interface) changed = True if changed: @@ -866,8 +878,12 @@ def vm_networks_remove(config, vm, network, sriov, live, restart): new_xml = tostring(parsed_xml, pretty_print=True) except Exception: return False, 'ERROR: Failed to dump XML data.' - else: + elif not changed and network is not None: return False, 'ERROR: Network "{}" does not exist on VM.'.format(network) + elif not changed and macaddr is not None: + return False, 'ERROR: Interface with MAC "{}" does not exist on VM.'.format(macaddr) + else: + return False, 'ERROR: Unspecified error finding interface to remove.' modify_retcode, modify_retmsg = vm_modify(config, vm, new_xml, restart) diff --git a/client-cli/pvc/pvc.py b/client-cli/pvc/pvc.py index 7197a4ba..ee8d2f95 100755 --- a/client-cli/pvc/pvc.py +++ b/client-cli/pvc/pvc.py @@ -1541,7 +1541,11 @@ def vm_network_add(domain, net, macaddr, model, sriov_flag, sriov_mode, live_fla 'domain' ) @click.argument( - 'net' + 'net', required=False, default=None +) +@click.option( + '-m', '--mac-address', 'macaddr', default=None, + help='Remove an interface with this MAC address; required if NET is unspecified.' ) @click.option( '-s', '--sriov', 'sriov_flag', is_flag=True, default=False, @@ -1561,11 +1565,15 @@ def vm_network_add(domain, net, macaddr, model, sriov_flag, sriov_mode, live_fla help='Confirm the restart.' ) @cluster_req -def vm_network_remove(domain, net, sriov_flag, live_flag, restart_flag, confirm_flag): +def vm_network_remove(domain, net, macaddr, sriov_flag, live_flag, restart_flag, confirm_flag): """ Remove the network NET from the virtual machine DOMAIN. NET may be a PVC network VNI, which is added as a bridged device, or a SR-IOV VF device connected in the given mode. + + NET is optional if the '-m'/'--mac-address' option is specified. If it is, then the specific device with that MAC address is removed instead. + + If multiple interfaces are present on the VM in network NET, and '-m'/'--mac-address' is not specified, then all interfaces in that network will be removed. """ if restart_flag and live_flag: click.echo('WARNING: Live flag and restart flag both specified; this can cause unintended behaviour. To disable live changes, use "--no-live".') @@ -1577,7 +1585,7 @@ def vm_network_remove(domain, net, sriov_flag, live_flag, restart_flag, confirm_ except Exception: restart_flag = False - retcode, retmsg = pvc_vm.vm_networks_remove(config, domain, net, sriov_flag, live_flag, restart_flag) + retcode, retmsg = pvc_vm.vm_networks_remove(config, domain, net, macaddr, sriov_flag, live_flag, restart_flag) cleanup(retcode, retmsg)