def _disconnect_volume(self, slot_mgr): # Get the hosting UUID nl_vios_wrap = partition.get_mgmt_partition(self.adapter) vios_uuid = nl_vios_wrap.uuid # Build the match function match_func = tsk_map.gen_match_func(pvm_stg.VDisk, names=[self._get_path()]) # Make sure the remove function will run within the transaction manager def rm_func(vios_w): # If the vios doesn't match, just return if vios_w.uuid != vios_uuid: return None LOG.info(_LI("Disconnecting instance %(inst)s from storage " "disks."), {'inst': self.instance.name}, instance=self.instance) return tsk_map.remove_maps(vios_w, self.vm_uuid, match_func=match_func) self.stg_ftsk.add_functor_subtask(rm_func) # Find the disk directly. vios_w = self.stg_ftsk.wrapper_tasks[vios_uuid].wrapper mappings = tsk_map.find_maps(vios_w.scsi_mappings, client_lpar_id=self.vm_uuid, match_func=match_func) return [x.backing_storage for x in mappings]
def _connect_volume(self, slot_mgr): # Get the hosting UUID nl_vios_wrap = partition.get_mgmt_partition(self.adapter) vios_uuid = nl_vios_wrap.uuid # Get the File Path fio = pvm_stg.FileIO.bld( self.adapter, self._get_path(), backstore_type=pvm_stg.BackStoreType.USER_QCOW) def add_func(vios_w): # If the vios doesn't match, just return if vios_w.uuid != vios_uuid: return None LOG.info(_LI("Adding logical volume disk connection between VM " "%(vm)s and VIOS %(vios)s."), { 'vm': self.instance.name, 'vios': vios_w.name }, instance=self.instance) mapping = tsk_map.build_vscsi_mapping(self.host_uuid, vios_w, self.vm_uuid, fio) return tsk_map.add_map(vios_w, mapping) self.stg_ftsk.add_functor_subtask(add_func)
def vios_uuids(self): """List the UUIDs of the Virtual I/O Servers hosting the storage.""" # Get the hosting UUID if self._nl_vios_ids is None: nl_vios_wrap = partition.get_mgmt_partition(self.adapter) self._nl_vios_ids = [nl_vios_wrap.uuid] return self._nl_vios_ids
def test_get_mgmt_vio(self): "Happy path where the LPAR is the mgmt VM is a VIOS." self.adpt.read.side_effect = [self.mgmt_vio, self.nomgmt_lpar] mgmt_w = tpar.get_mgmt_partition(self.adpt) self.assertTrue(mgmt_w.is_mgmt_partition) self.assertEqual('7DBBE705-E4C4-4458-8223-3EBE07015CA9', mgmt_w.uuid) self.assertIsInstance(mgmt_w, vios.VIOS) self.assertEqual(1, self.adpt.read.call_count)
def test_get_mgmt_lpar(self): "Happy path where the LPAR is the mgmt VM is a LPAR." self.adpt.read.side_effect = [self.nomgmt_vio, self.mgmt_lpar] mgmt_w = tpar.get_mgmt_partition(self.adpt) self.assertTrue(mgmt_w.is_mgmt_partition) self.assertEqual('089FFB20-5D19-4A8C-BB80-13650627D985', mgmt_w.uuid) self.assertIsInstance(mgmt_w, lpar.LPAR) self.assertEqual(2, self.adpt.read.call_count)
def rollback_live_migration_at_destination(self, vif, vea_vlan_mappings): """Rolls back the pre live migrate on the destination host. Will delete the TrunkAdapter that pre_live_migrate_at_destination created with its unique hypervisor VLAN. This uses the vea_vlan_mappings to provide the information as to what TrunkAdapter it should remove. :param vif: The virtual interface that was being migrated. This may be called network_info in other portions of the code. :param vea_vlan_mappings: The VEA VLAN mappings. Key is the vif mac address, value is the destination's target hypervisor VLAN. """ LOG.warning("Rolling back the live migrate of VIF with mac %(mac)s.", {'mac': vif['address']}, instance=self.instance) # We know that we just attached the VIF to the NovaLink VM. Search # for a trunk adapter with the PVID and vSwitch that we specified # above. This is guaranteed to be unique. vlan = int(vea_vlan_mappings[vif['address']]) vswitch_id = pvm_net.VSwitch.search( self.adapter, parent_type=pvm_ms.System, one_result=True, name=CONF.powervm.pvm_vswitch_for_novalink_io).switch_id # Find the trunk mgmt_wrap = pvm_par.get_mgmt_partition(self.adapter) child_adpts = pvm_net.CNA.get(self.adapter, parent=mgmt_wrap) trunk = None for adpt in child_adpts: # We need a trunk adapter (so check trunk_pri). Then the trunk # is unique by PVID and PowerVM vSwitch ID. if (adpt.pvid == vlan and adpt.vswitch_id == vswitch_id and adpt.trunk_pri): trunk = adpt break if trunk: # Delete the peer'd trunk adapter. LOG.warning( "Deleting target side trunk adapter %(dev)s for " "rollback operation", {'dev': trunk.dev_name}, instance=self.instance) trunk.delete()
def pre_live_migrate_at_destination(self, vif, vea_vlan_mappings): """Performs the pre live migrate on the destination host. This method will create the trunk adapter on the destination host, set its link state up, and attach it to the integration OVS switch. It also updates the vea_vlan_mappings to indicate which unique hypervisor VLAN should be used for this VIF for the migration operation to complete properly. :param vif: The virtual interface that will be migrated. This may be called network_info in other portions of the code. :param vea_vlan_mappings: The VEA VLAN mappings. Key is the vif mac address, value is the destination's target hypervisor VLAN. """ self._cleanup_orphan_adapters(vif, CONF.powervm.pvm_vswitch_for_novalink_io) mgmt_wrap = pvm_par.get_mgmt_partition(self.adapter) dev = _get_trunk_dev_name(vif) meta_attrs = PvmMetaAttrs(vif, self.instance) mtu = vif['network'].get_meta('mtu') # Find a specific free VLAN and create the Trunk in a single atomic # action. cna_w = pvm_cna.crt_trunk_with_free_vlan( self.adapter, self.host_uuid, [mgmt_wrap.uuid], CONF.powervm.pvm_vswitch_for_novalink_io, dev_name=dev, ovs_bridge=vif['network']['bridge'], ovs_ext_ids=str(meta_attrs), configured_mtu=mtu)[0] # Save this data for the migration command. vea_vlan_mappings[vif['address']] = cna_w.pvid LOG.info( "VIF with mac %(mac)s is going on trunk %(dev)s with PVID " "%(pvid)s", { 'mac': vif['address'], 'dev': dev, 'pvid': cna_w.pvid }, instance=self.instance)
def get_iscsi_initiator(adapter): """Gets the iSCSI initiator. This is looked up once at process start up. Stored in memory thereafter. :param adapter: The pypowervm adapter. :return: The initiator name. If the NovaLink is not capable of supporting iSCSI, None will be returned. """ global _ISCSI_INITIATOR, _ISCSI_LOOKUP_COMPLETE if not _ISCSI_LOOKUP_COMPLETE: mgmt_w = partition.get_mgmt_partition(adapter) if isinstance(mgmt_w, pvm_vios.VIOS): _ISCSI_INITIATOR = hdisk.discover_iscsi_initiator( adapter, mgmt_w.uuid).strip() _ISCSI_LOOKUP_COMPLETE = True return _ISCSI_INITIATOR
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. """ if not new_vif: return None 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) # 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]
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()