def unplug(self, vif, cna_w_list=None): """Unplugs a virtual interface (network) from a VM. :param vif: The virtual interface to plug into the instance. :param cna_w_list: (Optional, Default: None) The list of Client Network Adapters from pypowervm. Providing this input allows for an improvement in operation speed. :return cna_w: The deleted Client Network Adapter or None if the CNA is not found. """ # This is a default implementation that most implementations will # require. # Need to find the adapters if they were not provided if not cna_w_list: cna_w_list = vm.get_cnas(self.adapter, self.instance) cna_w = self._find_cna_for_vif(cna_w_list, vif) if not cna_w: LOG.warning( 'Unable to unplug VIF with mac %(mac)s. The VIF was ' 'not found on the instance.', {'mac': vif['address']}, instance=self.instance) return None LOG.info('Deleting VIF with mac %(mac)s.', {'mac': vif['address']}, instance=self.instance) try: cna_w.delete() except Exception as e: LOG.exception('Unable to unplug VIF with mac %(mac)s.', {'mac': vif['address']}, instance=self.instance) raise exception.VirtualInterfaceUnplugException(reason=str(e)) return cna_w
def unplug(self, vif, cna_w_list=None): """Unplugs a virtual interface (network) from a VM. :param vif: The virtual interface to plug into the instance. :param cna_w_list: (Optional, Default: None) The list of Client Network Adapters from pypowervm. Providing this input allows for an improvement in operation speed. :return cna_w: The deleted Client Network Adapter or None if the CNA is not found. """ # This is a default implementation that most implementations will # require. # Need to find the adapters if they were not provided if not cna_w_list: cna_w_list = vm.get_cnas(self.adapter, self.instance) cna_w = self._find_cna_for_vif(cna_w_list, vif) if not cna_w: LOG.warning('Unable to unplug VIF with mac %(mac)s. The VIF was ' 'not found on the instance.', {'mac': vif['address']}, instance=self.instance) return None LOG.info('Deleting VIF with mac %(mac)s.', {'mac': vif['address']}, instance=self.instance) try: cna_w.delete() except Exception as e: LOG.exception('Unable to unplug VIF with mac %(mac)s.', {'mac': vif['address']}, instance=self.instance) raise exception.VirtualInterfaceUnplugException( reason=six.text_type(e)) return cna_w
def unplug(self, vif, cna_w_list=None): """Unplugs a virtual interface (network) from a VM. Extends the base implementation, but before calling it will remove the adapter from the Open vSwitch and delete the trunk. :param vif: The virtual interface to plug into the instance. :param cna_w_list: (Optional, Default: None) The list of Client Network Adapters from pypowervm. Providing this input allows for an improvement in operation speed. :return cna_w: The deleted Client Network Adapter or None if the CNA is not found. """ # Need to find the adapters if they were not provided if not cna_w_list: cna_w_list = vm.get_cnas(self.adapter, self.instance) # Find the CNA for this vif. cna_w = self._find_cna_for_vif(cna_w_list, vif) if not cna_w: LOG.warning('Unable to unplug VIF with mac %s for instance. The ' 'VIF was not found on the instance.', vif['address'], instance=self.instance) return None # Find and delete the trunk adapters trunks = pvm_cna.find_trunks(self.adapter, cna_w) for trunk in trunks: trunk.delete() # Delete the client CNA return super(PvmOvsVifDriver, self).unplug(vif, cna_w_list=cna_w_list)
def unplug(self, vif, cna_w_list=None): """Unplugs a virtual interface (network) from a VM. Extends the base implementation, but before calling it will remove the adapter from the Open vSwitch and delete the trunk. :param vif: The virtual interface to plug into the instance. :param cna_w_list: (Optional, Default: None) The list of Client Network Adapters from pypowervm. Providing this input allows for an improvement in operation speed. :return cna_w: The deleted Client Network Adapter or None if the CNA is not found. """ # Need to find the adapters if they were not provided if not cna_w_list: cna_w_list = vm.get_cnas(self.adapter, self.instance) # Find the CNA for this vif. cna_w = self._find_cna_for_vif(cna_w_list, vif) if not cna_w: LOG.warning( 'Unable to unplug VIF with mac %s for instance. The ' 'VIF was not found on the instance.', vif['address'], instance=self.instance) return None # Find and delete the trunk adapters trunks = pvm_cna.find_trunks(self.adapter, cna_w) for trunk in trunks: trunk.delete() # Delete the client CNA return super(PvmOvsVifDriver, self).unplug(vif, cna_w_list=cna_w_list)
def execute(self, vm_cnas): LOG.info('Plugging the Management Network Interface to instance.', instance=self.instance) # Determine if we need to create the secure RMC VIF. This should only # be needed if there is not a VIF on the secure RMC vSwitch vswitch = None vswitches = pvm_net.VSwitch.search( self.adapter, parent_type=pvm_ms.System.schema_type, parent_uuid=self.adapter.sys_uuid, name=SECURE_RMC_VSWITCH) if len(vswitches) == 1: vswitch = vswitches[0] if vswitch is None: LOG.warning('No management VIF created for instance due to lack ' 'of Management Virtual Switch', instance=self.instance) return None # This next check verifies that there are no existing NICs on the # vSwitch, so that the VM does not end up with multiple RMC VIFs. if vm_cnas is None: has_mgmt_vif = vm.get_cnas(self.adapter, self.instance, vswitch_uri=vswitch.href) else: has_mgmt_vif = vswitch.href in [cna.vswitch_uri for cna in vm_cnas] if has_mgmt_vif: LOG.debug('Management VIF already created for instance', instance=self.instance) return None lpar_uuid = vm.get_pvm_uuid(self.instance) return pvm_cna.crt_cna(self.adapter, None, lpar_uuid, SECURE_RMC_VLAN, vswitch=SECURE_RMC_VSWITCH, crt_vswitch=True)
def test_get_cnas(self, mock_get, mock_search, mock_uuid): # No kwargs: get self.assertEqual(mock_get.return_value, vm.get_cnas(self.apt, 'inst')) mock_uuid.assert_called_once_with('inst') mock_get.assert_called_once_with(self.apt, parent_type=pvm_lpar.LPAR, parent_uuid=mock_uuid.return_value) mock_search.assert_not_called() # With kwargs: search mock_get.reset_mock() mock_uuid.reset_mock() self.assertEqual(mock_search.return_value, vm.get_cnas( self.apt, 'inst', one=2, three=4)) mock_uuid.assert_called_once_with('inst') mock_search.assert_called_once_with( self.apt, parent_type=pvm_lpar.LPAR, parent_uuid=mock_uuid.return_value, one=2, three=4) mock_get.assert_not_called()
def test_get_cnas(self, mock_get, mock_search, mock_uuid): # No kwargs: get self.assertEqual(mock_get.return_value, vm.get_cnas(self.apt, 'inst')) mock_uuid.assert_called_once_with('inst') mock_get.assert_called_once_with(self.apt, parent_type=pvm_lpar.LPAR, parent_uuid=mock_uuid.return_value) mock_search.assert_not_called() # With kwargs: search mock_get.reset_mock() mock_uuid.reset_mock() self.assertEqual(mock_search.return_value, vm.get_cnas(self.apt, 'inst', one=2, three=4)) mock_uuid.assert_called_once_with('inst') mock_search.assert_called_once_with(self.apt, parent_type=pvm_lpar.LPAR, parent_uuid=mock_uuid.return_value, one=2, three=4) mock_get.assert_not_called()
def _vif_exists(self, network_info): """Does the instance have a CNA for a given net? :param network_info: A network information dict. This method expects it to contain key 'address' (MAC address). :return: True if a CNA with the network_info's MAC address exists on the instance. False otherwise. """ if self.cnas is None: self.cnas = vm.get_cnas(self.adapter, self.instance) vifs = self.cnas return network_info['address'] in [vm.norm_mac(v.mac) for v in vifs]
def unplug(self, vif, cna_w_list=None): """Unplugs a virtual interface (network) from a VM. This will remove the adapter from the Open vSwitch and delete the trunk adapters. :param vif: The virtual interface to plug into the instance. :param cna_w_list: (Optional, Default: None) The list of Client Network Adapters from pypowervm. Providing this input allows for an improvement in operation speed. :return cna_w: The deleted Client Network Adapter or None if the CNA is not found. """ # Need to find the adapters if they were not provided if not cna_w_list: cna_w_list = vm.get_cnas(self.adapter, self.instance) # Find the CNA for this vif. cna_w = self._find_cna_for_vif(cna_w_list, vif) if not cna_w: LOG.warning( 'Unable to unplug VIF with mac %s for instance. The ' 'VIF was not found on the instance.', vif['address'], instance=self.instance) return None # Find and delete the trunk adapters trunks = pvm_cna.find_trunks(self.adapter, cna_w) for trunk in trunks: trunk.delete() # Now delete the client CNA LOG.info('Deleting VIF with mac %s for instance.', vif['address'], instance=self.instance) try: cna_w.delete() except Exception as e: LOG.error('Unable to unplug VIF with mac %s for instance.', vif['address'], instance=self.instance) raise exception.VirtualInterfaceUnplugException( reason=six.text_type(e)) return cna_w
def revert(self, lpar_wrap, result, flow_failures): if not self.network_infos: return LOG.warning('VIF creation being rolled back for instance.', instance=self.instance) # Get the current adapters on the system cna_w_list = vm.get_cnas(self.adapter, self.instance) for network_info in self.crt_network_infos: try: vif.unplug(self.adapter, self.instance, network_info, cna_w_list=cna_w_list) except Exception: LOG.exception("An exception occurred during an unplug in the " "vif rollback. Ignoring.", instance=self.instance)
def execute(self): # If the LPAR is not in an OK state for deleting, then throw an # error up front. lpar_wrap = vm.get_instance_wrapper(self.adapter, self.instance) modifiable, reason = lpar_wrap.can_modify_io() if not modifiable: LOG.error("Unable to remove VIFs from instance in the system's " "current state. The reason reported by the system is: " "%s", reason, instance=self.instance) raise exception.VirtualInterfaceUnplugException(reason=reason) # Get all the current Client Network Adapters (CNA) on the VM itself. cna_w_list = vm.get_cnas(self.adapter, self.instance) # Walk through the VIFs and delete the corresponding CNA on the VM. for network_info in self.network_infos: vif.unplug(self.adapter, self.instance, network_info, cna_w_list=cna_w_list)
def execute(self, vm_cnas): LOG.info('Plugging the Management Network Interface to instance.', instance=self.instance) # Determine if we need to create the secure RMC VIF. This should only # be needed if there is not a VIF on the secure RMC vSwitch vswitch = None vswitches = pvm_net.VSwitch.search( self.adapter, parent_type=pvm_ms.System.schema_type, parent_uuid=self.adapter.sys_uuid, name=SECURE_RMC_VSWITCH) if len(vswitches) == 1: vswitch = vswitches[0] if vswitch is None: LOG.warning( 'No management VIF created for instance due to lack ' 'of Management Virtual Switch', instance=self.instance) return None # This next check verifies that there are no existing NICs on the # vSwitch, so that the VM does not end up with multiple RMC VIFs. if vm_cnas is None: has_mgmt_vif = vm.get_cnas(self.adapter, self.instance, vswitch_uri=vswitch.href) else: has_mgmt_vif = vswitch.href in [cna.vswitch_uri for cna in vm_cnas] if has_mgmt_vif: LOG.debug('Management VIF already created for instance', instance=self.instance) return None lpar_uuid = vm.get_pvm_uuid(self.instance) return pvm_cna.crt_cna(self.adapter, None, lpar_uuid, SECURE_RMC_VLAN, vswitch=SECURE_RMC_VSWITCH, crt_vswitch=True)
def revert(self, lpar_wrap, result, flow_failures): if not self.network_infos: return LOG.warning('VIF creation being rolled back for instance.', instance=self.instance) # Get the current adapters on the system cna_w_list = vm.get_cnas(self.adapter, self.instance) for network_info in self.crt_network_infos: try: vif.unplug(self.adapter, self.instance, network_info, cna_w_list=cna_w_list) except Exception: LOG.exception( "An exception occurred during an unplug in the " "vif rollback. Ignoring.", instance=self.instance)
def execute(self): # If the LPAR is not in an OK state for deleting, then throw an # error up front. lpar_wrap = vm.get_instance_wrapper(self.adapter, self.instance) modifiable, reason = lpar_wrap.can_modify_io() if not modifiable: LOG.error( "Unable to remove VIFs from instance in the system's " "current state. The reason reported by the system is: " "%s", reason, instance=self.instance) raise exception.VirtualInterfaceUnplugException(reason=reason) # Get all the current Client Network Adapters (CNA) on the VM itself. cna_w_list = vm.get_cnas(self.adapter, self.instance) # Walk through the VIFs and delete the corresponding CNA on the VM. for network_info in self.network_infos: vif.unplug(self.adapter, self.instance, network_info, cna_w_list=cna_w_list)
def plug(self, vif, new_vif=True): """Plugs a virtual interface (network) into a VM. Creates a 'peer to peer' connection between the Management partition hosting the Linux I/O and the client VM. There will be one trunk adapter for a given client adapter. The device will be 'up' on the mgmt partition. Will make sure that the trunk device has the appropriate metadata (e.g. port id) set on it so that the Open vSwitch agent picks it up properly. :param vif: The virtual interface to plug into the instance. :param new_vif: (Optional, Default: True) If set, indicates that it is a brand new VIF. If False, it indicates that the VIF is already on the client but should be treated on the bridge. :return: The new vif that was created. Only returned if new_vif is set to True. Otherwise None is expected. """ # Create the trunk and client adapter. lpar_uuid = vm.get_pvm_uuid(self.instance) mgmt_uuid = pvm_par.get_this_partition(self.adapter).uuid mtu = vif['network'].get_meta('mtu') if 'devname' in vif: dev_name = vif['devname'] else: dev_name = ("nic" + vif['id'])[:network_model.NIC_NAME_LEN] meta_attrs = ','.join([ 'iface-id=%s' % (vif.get('ovs_interfaceid') or vif['id']), 'iface-status=active', 'attached-mac=%s' % vif['address'], 'vm-uuid=%s' % self.instance.uuid ]) if new_vif: return pvm_cna.crt_p2p_cna(self.adapter, None, lpar_uuid, [mgmt_uuid], NOVALINK_VSWITCH, crt_vswitch=True, mac_addr=vif['address'], dev_name=dev_name, ovs_bridge=vif['network']['bridge'], ovs_ext_ids=meta_attrs, configured_mtu=mtu)[0] else: # Bug : https://bugs.launchpad.net/nova-powervm/+bug/1731548 # When a host is rebooted, something is discarding tap devices for # VMs deployed with OVS vif. To prevent VMs losing network # connectivity, this is fixed by recreating the tap devices during # init of the nova compute service, which will call vif plug with # new_vif==False. # Find the CNA for this vif. # TODO(esberglu) improve performance by caching VIOS wrapper(s) and # CNA lists (in case >1 vif per VM). cna_w_list = vm.get_cnas(self.adapter, self.instance) cna_w = self._find_cna_for_vif(cna_w_list, vif) if not cna_w: LOG.warning( 'Unable to plug VIF with mac %s for instance. The ' 'VIF was not found on the instance.', vif['address'], instance=self.instance) return None # Find the corresponding trunk adapter trunks = pvm_cna.find_trunks(self.adapter, cna_w) for trunk in trunks: # Set MTU, OVS external ids, and OVS bridge metadata trunk.configured_mtu = mtu trunk.ovs_ext_ids = meta_attrs trunk.ovs_bridge = vif['network']['bridge'] # Updating the trunk adapter will cause NovaLink to reassociate # the tap device. trunk.update()
def plug(self, vif, new_vif=True): """Plugs a virtual interface (network) into a VM. Creates a 'peer to peer' connection between the Management partition hosting the Linux I/O and the client VM. There will be one trunk adapter for a given client adapter. The device will be 'up' on the mgmt partition. Will make sure that the trunk device has the appropriate metadata (e.g. port id) set on it so that the Open vSwitch agent picks it up properly. :param vif: The virtual interface to plug into the instance. :param new_vif: (Optional, Default: True) If set, indicates that it is a brand new VIF. If False, it indicates that the VIF is already on the client but should be treated on the bridge. :return: The new vif that was created. Only returned if new_vif is set to True. Otherwise None is expected. """ # Create the trunk and client adapter. lpar_uuid = vm.get_pvm_uuid(self.instance) mgmt_uuid = pvm_par.get_this_partition(self.adapter).uuid mtu = vif['network'].get_meta('mtu') if 'devname' in vif: dev_name = vif['devname'] else: dev_name = ("nic" + vif['id'])[:network_model.NIC_NAME_LEN] meta_attrs = ','.join([ 'iface-id=%s' % (vif.get('ovs_interfaceid') or vif['id']), 'iface-status=active', 'attached-mac=%s' % vif['address'], 'vm-uuid=%s' % self.instance.uuid]) if new_vif: return pvm_cna.crt_p2p_cna( self.adapter, None, lpar_uuid, [mgmt_uuid], NOVALINK_VSWITCH, crt_vswitch=True, mac_addr=vif['address'], dev_name=dev_name, ovs_bridge=vif['network']['bridge'], ovs_ext_ids=meta_attrs, configured_mtu=mtu)[0] else: # Bug : https://bugs.launchpad.net/nova-powervm/+bug/1731548 # When a host is rebooted, something is discarding tap devices for # VMs deployed with OVS vif. To prevent VMs losing network # connectivity, this is fixed by recreating the tap devices during # init of the nova compute service, which will call vif plug with # new_vif==False. # Find the CNA for this vif. # TODO(esberglu) improve performance by caching VIOS wrapper(s) and # CNA lists (in case >1 vif per VM). cna_w_list = vm.get_cnas(self.adapter, self.instance) cna_w = self._find_cna_for_vif(cna_w_list, vif) if not cna_w: LOG.warning('Unable to plug VIF with mac %s for instance. The ' 'VIF was not found on the instance.', vif['address'], instance=self.instance) return None # Find the corresponding trunk adapter trunks = pvm_cna.find_trunks(self.adapter, cna_w) for trunk in trunks: # Set MTU, OVS external ids, and OVS bridge metadata trunk.configured_mtu = mtu trunk.ovs_ext_ids = meta_attrs trunk.ovs_bridge = vif['network']['bridge'] # Updating the trunk adapter will cause NovaLink to reassociate # the tap device. trunk.update()