def execute(self, lpar_wrap): # If the state is not in an OK state for deleting, then throw an # error up front. modifiable, reason = lpar_wrap.can_modify_io() if not modifiable: LOG.error( "Unable to remove VIFs in the instance's current state. " "The reason reported by the system is: %(reason)s", {'reason': 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.host_uuid, self.instance, network_info, self.slot_mgr, cna_w_list=cna_w_list) return cna_w_list
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. """ # 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. """ # 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 %(mac)s for. The VIF ' 'was not found on the instance.', {'mac': vif['address']}, instance=self.instance) return None # Find and delete the trunk adapters trunks = pvm_cna.find_trunks(self.adapter, cna_w) dev = self.get_trunk_dev_name(vif) linux_net.delete_ovs_vif_port(vif['network']['bridge'], dev) for trunk in trunks: trunk.delete() # Now 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. """ # 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(_LW('Unable to unplug VIF with mac %(mac)s for ' 'instance %(inst)s. The VIF was not found on ' 'the instance.'), {'mac': vif['address'], 'inst': self.instance.name}) return None # Find and delete the trunk adapters trunks = pvm_cna.find_trunks(self.adapter, cna_w) dev = self.get_trunk_dev_name(vif) linux_net.delete_ovs_vif_port(vif['network']['bridge'], dev) for trunk in trunks: trunk.delete() # Now 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. :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. """ # 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(_LW('Unable to unplug VIF with mac %(mac)s for ' 'instance %(inst)s. The VIF was not found on ' 'the instance.'), {'mac': vif['address'], 'inst': self.instance.name}) return None LOG.info(_LI('Deleting VIF with mac %(mac)s for instance %(inst)s.'), {'mac': vif['address'], 'inst': self.instance.name}) try: cna_w.delete() except Exception as e: LOG.error(_LE('Unable to unplug VIF with mac %(mac)s for instance ' '%(inst)s.'), {'mac': vif['address'], 'inst': self.instance.name}) LOG.exception(e) raise VirtualInterfaceUnplugException() return cna_w
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 execute(self, lpar_wrap): LOG.info(_LI('Plugging the Network Interfaces to instance %s'), self.instance.name) # Get the current adapters on the system cna_w_list = vm.get_cnas(self.adapter, self.instance, self.host_uuid) # Trim the VIFs down to the ones that haven't yet been created. crt_vifs = [] for vif in self.network_info: for cna_w in cna_w_list: if vm.norm_mac(cna_w.mac) == vif['address']: break else: crt_vifs.append(vif) # If there are no vifs to create, then just exit immediately. if len(crt_vifs) == 0: return [] # Check to see if the LPAR is OK to add VIFs to. modifiable, reason = lpar_wrap.can_modify_io() if not modifiable: LOG.error(_LE('Unable to create VIF(s) for instance %(sys)s. The ' 'VM was in a state where VIF plugging is not ' 'acceptable. The reason from the system is: ' '%(reason)s'), { 'sys': self.instance.name, 'reason': reason }, instance=self.instance) raise exception.VirtualInterfaceCreateException() # For the VIFs, run the creates (and wait for the events back) try: with self.virt_api.wait_for_instance_event( self.instance, self._get_vif_events(), deadline=CONF.vif_plugging_timeout, error_callback=self._vif_callback_failed): for vif in crt_vifs: LOG.info(_LI('Creating VIF with mac %(mac)s for instance ' '%(sys)s'), { 'mac': vif['address'], 'sys': self.instance.name }, instance=self.instance) vm.crt_vif(self.adapter, self.instance, self.host_uuid, vif) except eventlet.timeout.Timeout: LOG.error(_LE('Error waiting for VIF to be created for instance ' '%(sys)s'), {'sys': self.instance.name}, instance=self.instance) raise exception.VirtualInterfaceCreateException() # Return the list of created VIFs. return cna_w_list
def execute(self, lpar_wrap): LOG.info(_LI('Unplugging the Network Interfaces to instance %s'), self.instance.name) # If the state is not in an OK state for deleting, then throw an # error up front. modifiable, reason = lpar_wrap.can_modify_io() if not modifiable: LOG.error(_LE('Unable to remove VIFs from instance %(inst)s ' 'because the system is not in a correct state. ' 'The reason reported by the system is: %(reason)s'), { 'inst': self.instance.name, 'reason': reason }, instance=self.instance) raise VirtualInterfaceUnplugException() # Get all the current Client Network Adapters (CNA) on the VM itself. cna_w_list = vm.get_cnas(self.adapter, self.instance, self.host_uuid) # Walk through the VIFs and delete the corresponding CNA on the VM. for vif in self.network_info: for cna_w in cna_w_list: # If the MAC address matched, attempt the delete. if vm.norm_mac(cna_w.mac) == vif['address']: LOG.info(_LI('Deleting VIF with mac %(mac)s for instance ' '%(inst)s.'), { 'mac': vif['address'], 'inst': self.instance.name }, instance=self.instance) try: cna_w.delete() except Exception as e: LOG.error(_LE('Unable to unplug VIF with mac %(mac)s ' 'for instance %(inst)s.'), { 'mac': vif['address'], 'inst': self.instance.name }, instance=self.instance) LOG.error(e) raise VirtualInterfaceUnplugException() # Break from the loop as we had a successful unplug. # This prevents from going to 'else' loop. break else: LOG.warn(_LW('Unable to unplug VIF with mac %(mac)s for ' 'instance %(inst)s. The VIF was not found on ' 'the instance.'), { 'mac': vif['address'], 'inst': self.instance.name }, instance=self.instance) return 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 invoking it will remove itself from the bridge it is connected to and delete the corresponding trunk device on the mgmt partition. :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. """ # 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(_LW('Unable to unplug VIF with mac %(mac)s for ' 'instance %(inst)s. The VIF was not found on ' 'the instance.'), { 'mac': vif['address'], 'inst': self.instance.name }, instance=self.instance) return None # Find and delete the trunk adapters trunks = pvm_cna.find_trunks(self.adapter, cna_w) dev_name = self.get_trunk_dev_name(vif) utils.execute('ip', 'link', 'set', dev_name, 'down', run_as_root=True) try: utils.execute('brctl', 'delif', vif['network']['bridge'], dev_name, run_as_root=True) except Exception as e: LOG.warning(_LW('Unable to delete device %(dev_name)s from bridge ' '%(bridge)s. Error: %(error)s'), { 'dev_name': dev_name, 'bridge': vif['network']['bridge'], 'error': e.message }, instance=self.instance) for trunk in trunks: trunk.delete() # Now delete the client CNA return super(PvmLBVifDriver, self).unplug(vif, cna_w_list=cna_w_list)
def execute(self, lpar_wrap): LOG.info(_LI('Plugging the Network Interfaces to instance %s'), self.instance.name) # Get the current adapters on the system cna_w_list = vm.get_cnas(self.adapter, self.instance, self.host_uuid) # Trim the VIFs down to the ones that haven't yet been created. crt_vifs = [] for vif in self.network_info: for cna_w in cna_w_list: if vm.norm_mac(cna_w.mac) == vif['address']: break else: crt_vifs.append(vif) # If there are no vifs to create, then just exit immediately. if len(crt_vifs) == 0: return [] # Check to see if the LPAR is OK to add VIFs to. modifiable, reason = lpar_wrap.can_modify_io() if not modifiable: LOG.error(_LE('Unable to create VIF(s) for instance %(sys)s. The ' 'VM was in a state where VIF plugging is not ' 'acceptable. The reason from the system is: ' '%(reason)s'), {'sys': self.instance.name, 'reason': reason}, instance=self.instance) raise exception.VirtualInterfaceCreateException() # For the VIFs, run the creates (and wait for the events back) try: with self.virt_api.wait_for_instance_event( self.instance, self._get_vif_events(), deadline=CONF.vif_plugging_timeout, error_callback=self._vif_callback_failed): for vif in crt_vifs: LOG.info(_LI('Creating VIF with mac %(mac)s for instance ' '%(sys)s'), {'mac': vif['address'], 'sys': self.instance.name}, instance=self.instance) vm.crt_vif(self.adapter, self.instance, self.host_uuid, vif) except eventlet.timeout.Timeout: LOG.error(_LE('Error waiting for VIF to be created for instance ' '%(sys)s'), {'sys': self.instance.name}, instance=self.instance) raise exception.VirtualInterfaceCreateException() # Return the list of created VIFs. return cna_w_list
def execute(self, lpar_wrap): LOG.info(_LI('Unplugging the Network Interfaces to instance %s'), self.instance.name) # If the state is not in an OK state for deleting, then throw an # error up front. modifiable, reason = lpar_wrap.can_modify_io() if not modifiable: LOG.error(_LE('Unable to remove VIFs from instance %(inst)s ' 'because the system is not in a correct state. ' 'The reason reported by the system is: %(reason)s'), {'inst': self.instance.name, 'reason': reason}, instance=self.instance) raise VirtualInterfaceUnplugException() # Get all the current Client Network Adapters (CNA) on the VM itself. cna_w_list = vm.get_cnas(self.adapter, self.instance, self.host_uuid) # Walk through the VIFs and delete the corresponding CNA on the VM. for vif in self.network_info: for cna_w in cna_w_list: # If the MAC address matched, attempt the delete. if vm.norm_mac(cna_w.mac) == vif['address']: LOG.info(_LI('Deleting VIF with mac %(mac)s for instance ' '%(inst)s.'), {'mac': vif['address'], 'inst': self.instance.name}, instance=self.instance) try: cna_w.delete() except Exception as e: LOG.error(_LE('Unable to unplug VIF with mac %(mac)s ' 'for instance %(inst)s.'), {'mac': vif['address'], 'inst': self.instance.name}, instance=self.instance) LOG.error(e) raise VirtualInterfaceUnplugException() # Break from the loop as we had a successful unplug. # This prevents from going to 'else' loop. break else: LOG.warning(_LW('Unable to unplug VIF with mac %(mac)s for ' 'instance %(inst)s. The VIF was not found on ' 'the instance.'), {'mac': vif['address'], 'inst': self.instance.name}, instance=self.instance) return cna_w_list
def execute_impl(self, lpar_wrap): # If the state is not in an OK state for deleting, then throw an # error up front. modifiable, reason = lpar_wrap.can_modify_io() if not modifiable: LOG.error(_LE('Unable to remove VIFs from instance %(inst)s ' 'because the system is not in a correct state. ' 'The reason reported by the system is: %(reason)s'), {'inst': self.instance.name, 'reason': reason}, instance=self.instance) raise VirtualInterfaceUnplugException() # 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.host_uuid, self.instance, network_info, self.slot_mgr, cna_w_list=cna_w_list) return cna_w_list
def _vif_exists(self, network_info): """Does the instance have a CNA/VNIC (as appropriate) for a given net? :param network_info: A network information dict. This method expects it to contain keys 'vnic_type' (value is 'direct' for VNIC; otherwise assume CNA); and 'address' (MAC address). :return: True if a CNA/VNIC (as appropriate) with the network_info's MAC address exists on the instance. False otherwise. """ # Are we looking for a VNIC or a CNA? if network_info['vnic_type'] == 'direct': if self.vnics is None: self.vnics = vm.get_vnics(self.adapter, self.instance) vifs = self.vnics else: 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 revert_impl(self, lpar_wrap, result, flow_failures): if not self.network_infos: return # The parameters have to match the execute method, plus the response + # failures even if only a subset are used. LOG.warning(_LW('VIF creation being rolled back for instance ' '%(inst)s'), {'inst': self.instance.name}, 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.network_infos: try: vif.unplug(self.adapter, self.host_uuid, self.instance, network_info, self.slot_mgr, cna_w_list=cna_w_list) except Exception as e: LOG.exception(e) LOG.warning(_LW("An exception occurred during an unplug " "in the vif rollback. Ignoring."), instance=self.instance)
def revert_impl(self, lpar_wrap, result, flow_failures): if not self.network_infos: return # The parameters have to match the execute method, plus the response + # failures even if only a subset are used. LOG.warning(_LW('VIF creation being rolled back for instance ' '%(inst)s'), {'inst': self.instance.name}, 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.host_uuid, self.instance, network_info, self.slot_mgr, cna_w_list=cna_w_list) except Exception as e: LOG.exception(e) LOG.warning(_LW("An exception occurred during an unplug " "in the vif rollback. Ignoring."), instance=self.instance)
def execute(self, vm_cnas): # If configured to not use RMC mgmt vifs, then return None. Need to # return None because the Config Drive step (which may be used...may # not be) required the mgmt vif. if not CONF.powervm.use_rmc_mgmt_vif: LOG.debug( 'No management VIF created because ' 'CONF.powervm.use_rmc_mgmt_vif is False', instance=self.instance) return None LOG.info('Plugging the management network interface.', 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 = vif.get_secure_rmc_vswitch(self.adapter, self.host_uuid) if vswitch is None: LOG.warning( 'No management VIF created 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 exists.', instance=self.instance) return None # Return the created management CNA return vif.plug_secure_rmc_vif(self.adapter, self.instance, self.host_uuid, self.slot_mgr)
def unplug(self, vif, cna_w_list=None): """Unplugs a virtual interface (network) from a VM. Extends the base implementation, but before invoking it will remove itself from the bridge it is connected to and delete the corresponding trunk device on the mgmt partition. :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. """ # 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(_LW('Unable to unplug VIF with mac %(mac)s for ' 'instance %(inst)s. The VIF was not found on ' 'the instance.'), {'mac': vif['address'], 'inst': self.instance.name}) return None # Find and delete the trunk adapters trunks = pvm_cna.find_trunks(self.adapter, cna_w) dev_name = self.get_trunk_dev_name(vif) utils.execute('ip', 'link', 'set', dev_name, 'down', run_as_root=True) utils.execute('brctl', 'delif', vif['network']['bridge'], dev_name, run_as_root=True) for trunk in trunks: trunk.delete() # Now delete the client CNA return super(PvmLBVifDriver, self).unplug(vif, cna_w_list=cna_w_list)
def revert(self, lpar_wrap, result, flow_failures): if not self.network_infos: return # The parameters have to match the execute method, plus the response + # failures even if only a subset are used. LOG.warning('VIF creation is being rolled back.', 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.host_uuid, self.instance, network_info, self.slot_mgr, cna_w_list=cna_w_list) except Exception: LOG.exception( "Error unplugging during vif rollback. " "Ignoring.", instance=self.instance)
def execute_impl(self, lpar_wrap): # Get the current adapters on the system cna_w_list = vm.get_cnas(self.adapter, self.instance) # Trim the VIFs down to the ones that haven't yet been created. crt_network_infos = [] for network_info in self.network_infos: for cna_w in cna_w_list: if vm.norm_mac(cna_w.mac) == network_info['address']: break else: crt_network_infos.append(network_info) # If there are no vifs to create, then just exit immediately. if len(crt_network_infos) == 0: return [] # Check to see if the LPAR is OK to add VIFs to. modifiable, reason = lpar_wrap.can_modify_io() if not modifiable: LOG.error(_LE('Unable to create VIF(s) for instance %(sys)s. The ' 'VM was in a state where VIF plugging is not ' 'acceptable. The reason from the system is: ' '%(reason)s'), {'sys': self.instance.name, 'reason': reason}, instance=self.instance) raise exception.VirtualInterfaceCreateException() # TODO(KYLEH): We're setting up to wait for an instance event. The # event needs to come back to our compute manager so we need to ensure # the instance.host is set to our host. We shouldn't need to do this # but in the evacuate/recreate case it may reflect the old host. # See: https://bugs.launchpad.net/nova/+bug/1535918 undo_host_change = False if self.instance.host != CONF.host: LOG.warning(_LW('Instance was not assigned to this host. ' 'It was assigned to: %s'), self.instance.host, instance=self.instance) # Update the instance... old_host = self.instance.host self.instance.host = CONF.host self.instance.save() undo_host_change = True # For the VIFs, run the creates (and wait for the events back) try: with self.virt_api.wait_for_instance_event( self.instance, self._get_vif_events(), deadline=CONF.vif_plugging_timeout, error_callback=self._vif_callback_failed): for network_info in crt_network_infos: LOG.info(_LI('Creating VIF with mac %(mac)s for instance ' '%(sys)s'), {'mac': network_info['address'], 'sys': self.instance.name}, instance=self.instance) vif.plug(self.adapter, self.host_uuid, self.instance, network_info, self.slot_mgr) except eventlet.timeout.Timeout: LOG.error(_LE('Error waiting for VIF to be created for instance ' '%(sys)s'), {'sys': self.instance.name}, instance=self.instance) raise exception.VirtualInterfaceCreateException() finally: if undo_host_change: LOG.info(_LI('Undoing temporary host assignment to instance.'), instance=self.instance) self.instance.host = old_host self.instance.save() # Return the list of created VIFs. return cna_w_list
def execute(self, lpar_wrap): LOG.info(_LI('Plugging the Network Interfaces to instance %s'), self.instance.name) # Get the current adapters on the system cna_w_list = vm.get_cnas(self.adapter, self.instance, self.host_uuid) # Trim the VIFs down to the ones that haven't yet been created. crt_vifs = [] for vif in self.network_info: for cna_w in cna_w_list: if vm.norm_mac(cna_w.mac) == vif['address']: break else: crt_vifs.append(vif) # If there are no vifs to create, then just exit immediately. if len(crt_vifs) == 0: return [] # Check to see if the LPAR is OK to add VIFs to. modifiable, reason = lpar_wrap.can_modify_io() if not modifiable: LOG.error(_LE('Unable to create VIF(s) for instance %(sys)s. The ' 'VM was in a state where VIF plugging is not ' 'acceptable. The reason from the system is: ' '%(reason)s'), { 'sys': self.instance.name, 'reason': reason }, instance=self.instance) raise exception.VirtualInterfaceCreateException() # TODO(KYLEH): We're setting up to wait for an instance event. The # event needs to come back to our compute manager so we need to ensure # the instance.host is set to our host. We shouldn't need to do this # but in the evacuate/recreate case it may reflect the old host. # See: https://bugs.launchpad.net/nova/+bug/1535918 undo_host_change = False if self.instance.host != CONF.host: LOG.warning(_LW('Instance was not assigned to this host. ' 'It was assigned to: %s'), self.instance.host, instance=self.instance) # Update the instance... old_host = self.instance.host self.instance.host = CONF.host self.instance.save() undo_host_change = True # For the VIFs, run the creates (and wait for the events back) try: with self.virt_api.wait_for_instance_event( self.instance, self._get_vif_events(), deadline=CONF.vif_plugging_timeout, error_callback=self._vif_callback_failed): for vif in crt_vifs: LOG.info(_LI('Creating VIF with mac %(mac)s for instance ' '%(sys)s'), { 'mac': vif['address'], 'sys': self.instance.name }, instance=self.instance) vm.crt_vif(self.adapter, self.instance, self.host_uuid, vif) except eventlet.timeout.Timeout: LOG.error(_LE('Error waiting for VIF to be created for instance ' '%(sys)s'), {'sys': self.instance.name}, instance=self.instance) raise exception.VirtualInterfaceCreateException() finally: if undo_host_change: LOG.info(_LI('Undoing temporary host assignment to instance.'), instance=self.instance) self.instance.host = old_host self.instance.save() # Return the list of created VIFs. return cna_w_list
def plug(self, vif, slot_num, new_vif=True): """Plugs a virtual interface (network) into a VM. Extends the Lio implementation. Will make sure that the trunk device has the appropriate metadata (ex. 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 slot_num: Which slot number to plug the VIF into. May be None. :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. """ lpar_uuid = vm.get_pvm_uuid(self.instance) mgmt_uuid = pvm_par.get_mgmt_partition(self.adapter).uuid # There will only be one trunk wrap, as we have created with just # the mgmt lpar. Next step is to connect to the OVS. mtu = vif['network'].get_meta('mtu') dev_name = _get_trunk_dev_name(vif) meta_attrs = PvmMetaAttrs(vif, self.instance) if new_vif: # Create the trunk and client adapter. return pvm_cna.crt_p2p_cna( self.adapter, self.host_uuid, lpar_uuid, [mgmt_uuid], CONF.powervm.pvm_vswitch_for_novalink_io, crt_vswitch=True, mac_addr=vif['address'], dev_name=dev_name, slot_num=slot_num, ovs_bridge=vif['network']['bridge'], ovs_ext_ids=str(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(svenkat) 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) # 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 # TODO(svenkat) set_parm_value calls should be replaced once # pypowervm supports setting these values directly. trunk.set_parm_value('ConfiguredMTU', mtu, attrib=pvm_c.ATTR_KSV160) trunk.set_parm_value('OvsPortExternalIds', meta_attrs, attrib=pvm_c.ATTR_KSV160) trunk.set_parm_value('OvsBridge', vif['network']['bridge'], attrib=pvm_c.ATTR_KSV160) # Updating the trunk adapter will cause NovaLink to reassociate # the tap device. trunk.update()