def detach_disk(self, instance): """Detaches the storage adapters from the image disk. :param instance: Instance to disconnect the image for. :return: A list of all the backing storage elements that were disconnected from the I/O Server and VM. """ lpar_uuid = vm.get_pvm_uuid(instance) # Build the match function match_func = tsk_map.gen_match_func(pvm_stg.VDisk) vios_w = pvm_vios.VIOS.get(self._adapter, uuid=self._vios_uuid, xag=[pvm_const.XAG.VIO_SMAP]) # Remove the mappings. mappings = tsk_map.remove_maps(vios_w, lpar_uuid, match_func=match_func) # Update the VIOS with the removed mappings. vios_w.update() return [x.backing_storage for x in mappings]
def dlt_vopt(self, instance, stg_ftsk): """Deletes the virtual optical and scsi mappings for a VM. :param instance: The nova instance whose VOpt(s) are to be removed. :param stg_ftsk: A FeedTask. The actions to modify the storage will be added as batched functions onto the FeedTask. """ lpar_uuid = vm.get_pvm_uuid(instance) # The matching function for find_maps, remove_maps match_func = tsk_map.gen_match_func(pvm_stg.VOptMedia) # Add a function to remove the mappings stg_ftsk.wrapper_tasks[self.vios_uuid].add_functor_subtask( tsk_map.remove_maps, lpar_uuid, match_func=match_func) # Find the VOpt device based from the mappings media_mappings = tsk_map.find_maps(stg_ftsk.get_wrapper( self.vios_uuid).scsi_mappings, client_lpar_id=lpar_uuid, match_func=match_func) media_elems = [x.backing_storage for x in media_mappings] def rm_vopt(): LOG.info("Removing virtual optical storage.", instance=instance) vg_wrap = pvm_stg.VG.get(self.adapter, uuid=self.vg_uuid, parent_type=pvm_vios.VIOS, parent_uuid=self.vios_uuid) tsk_stg.rm_vg_storage(vg_wrap, vopts=media_elems) # Add task to remove the media if it exists if media_elems: stg_ftsk.add_post_execute(task.FunctorTask(rm_vopt))
def _check_host_mappings(self, vios_wrap, device_name): """Checks if the given hdisk has multiple mappings :param vio_wrap: The Virtual I/O Server wrapper to remove the disk from. :param device_name: The hdisk name to remove. :return: True is there are multiple instances using the given hdisk """ vios_scsi_mappings = next(v.scsi_mappings for v in self.stg_ftsk.feed if v.uuid == vios_wrap.uuid) mappings = tsk_map.find_maps( vios_scsi_mappings, None, tsk_map.gen_match_func(pvm_stor.PV, names=[device_name])) LOG.info("%(num)d storage mappings found for %(dev)s on VIOS %(vios)s", { 'num': len(mappings), 'dev': device_name, 'vios': vios_wrap.name }, instance=self.instance) # the mapping is still present as the task feed removes # the mapping later return len(mappings) > 1
def _disconnect_volume(self, slot_mgr): # 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 not in self.vios_uuids: return None LOG.info("Disconnecting storage disks.", instance=self.instance) removed_maps = tsk_map.remove_maps(vios_w, self.vm_uuid, match_func=match_func) for rm_map in removed_maps: slot_mgr.drop_vscsi_mapping(rm_map) return removed_maps self.stg_ftsk.add_functor_subtask(rm_func) # Find the disk directly. vios_w = self.stg_ftsk.wrapper_tasks[self.vios_uuids[0]].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 dlt_vopt(self, instance, stg_ftsk): """Deletes the virtual optical and scsi mappings for a VM. :param instance: The nova instance whose VOpt(s) are to be removed. :param stg_ftsk: A FeedTask. The actions to modify the storage will be added as batched functions onto the FeedTask. """ lpar_uuid = vm.get_pvm_uuid(instance) # The matching function for find_maps, remove_maps match_func = tsk_map.gen_match_func(pvm_stg.VOptMedia) # Add a function to remove the mappings stg_ftsk.wrapper_tasks[self.vios_uuid].add_functor_subtask( tsk_map.remove_maps, lpar_uuid, match_func=match_func) # Find the VOpt device based from the mappings media_mappings = tsk_map.find_maps( stg_ftsk.get_wrapper(self.vios_uuid).scsi_mappings, client_lpar_id=lpar_uuid, match_func=match_func) media_elems = [x.backing_storage for x in media_mappings] def rm_vopt(): LOG.info("Removing virtual optical storage.", instance=instance) vg_wrap = pvm_stg.VG.get(self.adapter, uuid=self.vg_uuid, parent_type=pvm_vios.VIOS, parent_uuid=self.vios_uuid) tsk_stg.rm_vg_storage(vg_wrap, vopts=media_elems) # Add task to remove the media if it exists if media_elems: stg_ftsk.add_post_execute(task.FunctorTask(rm_vopt))
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 disconnect_disk(self, instance, stg_ftsk=None, disk_type=None): """Disconnects the storage adapters from the image disk. :param instance: instance to disconnect the image for. :param stg_ftsk: (Optional) The pypowervm transaction FeedTask for the I/O Operations. If provided, the Virtual I/O Server mapping updates will be added to the FeedTask. This defers the updates to some later point in time. If the FeedTask is not provided, the updates will be run immediately when this method is executed. :param disk_type: The list of disk types to remove or None which means to remove all disks from the VM. :return: A list of all the backing storage elements that were disconnected from the I/O Server and VM. """ if stg_ftsk is None: stg_ftsk = tsk_par.build_active_vio_feed_task( self.adapter, name='ssp', xag=[pvm_const.XAG.VIO_SMAP]) lpar_uuid = vm.get_pvm_uuid(instance) match_func = tsk_map.gen_match_func(pvm_stg.LU, prefixes=disk_type) # Delay run function to remove the mapping between the VM and the LU def rm_func(vios_w): LOG.info("Removing SSP disk connection to VIOS %(vios)s.", {'vios': vios_w.name}, instance=instance) return tsk_map.remove_maps(vios_w, lpar_uuid, match_func=match_func) # Add the mapping to *each* VIOS on the LPAR's host. # The LPAR's host has to be self.host_uuid, else the PowerVM API will # fail. # # Note - this may not be all the VIOSes on the system...just the ones # in the SSP cluster. # # The mappings will normally be the same on all VIOSes, unless a VIOS # was down when a disk was added. So for the return value, we need to # collect the union of all relevant mappings from all VIOSes. lu_set = set() for vios_uuid in self.vios_uuids: # Add the remove for the VIO stg_ftsk.wrapper_tasks[vios_uuid].add_functor_subtask(rm_func) # Find the active LUs so that a delete op knows what to remove. vios_w = stg_ftsk.wrapper_tasks[vios_uuid].wrapper mappings = tsk_map.find_maps(vios_w.scsi_mappings, client_lpar_id=lpar_uuid, match_func=match_func) if mappings: lu_set.update([x.backing_storage for x in mappings]) # Run the FeedTask if it was built locally if stg_ftsk.name == 'ssp': stg_ftsk.execute() return list(lu_set)
def add_dlt_vopt_tasks(self, lpar_uuid, stg_ftsk, remove_mappings=True): """Deletes the virtual optical and (optionally) scsi mappings for a VM. :param lpar_uuid: The pypowervm UUID of the LPAR whose vopt is to be removed. :param stg_ftsk: A FeedTask handling storage I/O. The task to remove the mappings and media from the VM will be deferred on to the FeedTask passed in. The execute can be done all in one method (batched together). No updates are actually made here; they are simply added to the FeedTask. :param remove_mappings: (Optional, Default: True) If set to true, will remove the SCSI mappings as part of the operation. If false, will leave the mapping but detach the storage from it. If the VM is running, it may be necessary to do the latter as some operating systems will not allow the removal. """ # The function to find the VOpt match_func = tsk_map.gen_match_func(pvm_stg.VOptMedia) def rm_vopt_mapping(vios_w): return tsk_map.remove_maps(vios_w, lpar_uuid, match_func=match_func) def detach_vopt_from_map(vios_w): return tsk_map.detach_storage(vios_w, lpar_uuid, match_func=match_func) # Add a function to remove the map or detach the vopt stg_ftsk.wrapper_tasks[self.vios_uuid].add_functor_subtask( rm_vopt_mapping if remove_mappings else detach_vopt_from_map) # Find the vOpt device (before the remove is done) so that it can be # removed. partition_id = vm.get_vm_id(self.adapter, lpar_uuid) media_mappings = tsk_map.find_maps(stg_ftsk.get_wrapper( self.vios_uuid).scsi_mappings, client_lpar_id=partition_id, match_func=match_func) media_elems = [x.backing_storage for x in media_mappings] def rm_vopt(): LOG.info(_LI("Removing virtual optical for VM with UUID %s."), lpar_uuid) vg_wrap = pvm_stg.VG.get(self.adapter, uuid=self.vg_uuid, parent_type=pvm_vios.VIOS, parent_uuid=self.vios_uuid) tsk_stg.rm_vg_storage(vg_wrap, vopts=media_elems) # Don't add this task if there is no media to delete (eg. config drive) if media_elems: stg_ftsk.add_post_execute(task.FunctorTask(rm_vopt))
def rm_func(vios_w): LOG.info("Removing vSCSI mapping from physical volume %(dev)s " "on vios %(vios)s", {'dev': device_name, 'vios': vios_w.name}, instance=self.instance) removed_maps = tsk_map.remove_maps( vios_w, vm_uuid, tsk_map.gen_match_func(pvm_stor.PV, names=[device_name])) return removed_maps
def rm_func(vios_w): LOG.info(_LI("Removing vSCSI mapping from Physical Volume %(dev)s " "to VM %(vm)s") % {'dev': device_name, 'vm': vm_uuid}) removed_maps = tsk_map.remove_maps( vios_w, vm_uuid, tsk_map.gen_match_func(pvm_stor.PV, names=[device_name])) for rm_map in removed_maps: slot_mgr.drop_vscsi_mapping(rm_map) return removed_maps
def disconnect_image_disk(self, context, instance, stg_ftsk=None, disk_type=None): """Disconnects the storage adapters from the image disk. :param context: nova context for operation :param instance: instance to disconnect the image for. :param stg_ftsk: (Optional) The pypowervm transaction FeedTask for the I/O Operations. If provided, the Virtual I/O Server mapping updates will be added to the FeedTask. This defers the updates to some later point in time. If the FeedTask is not provided, the updates will be run immediately when this method is executed. :param disk_type: The list of disk types to remove or None which means to remove all disks from the VM. :return: A list of all the backing storage elements that were disconnected from the I/O Server and VM. """ lpar_uuid = vm.get_pvm_uuid(instance) # Ensure we have a transaction manager. if stg_ftsk is None: stg_ftsk = vios.build_tx_feed_task( self.adapter, self.host_uuid, name='localdisk', xag=[pvm_vios.VIOS.xags.SCSI_MAPPING]) # Build the match function match_func = tsk_map.gen_match_func(pvm_stg.VDisk, prefixes=disk_type) # Make sure the remove function will run within the transaction manager def rm_func(vios_w): LOG.info( _LI("Disconnecting instance %(inst)s from storage disks.") % {'inst': instance.name}) return tsk_map.remove_maps(vios_w, lpar_uuid, match_func=match_func) stg_ftsk.wrapper_tasks[self._vios_uuid].add_functor_subtask(rm_func) # Find the disk directly. vios_w = stg_ftsk.wrapper_tasks[self._vios_uuid].wrapper mappings = tsk_map.find_maps(vios_w.scsi_mappings, client_lpar_id=lpar_uuid, match_func=match_func) # Run the transaction manager if built locally. Must be done after # the find to make sure the mappings were found previously. if stg_ftsk.name == 'localdisk': stg_ftsk.execute() return [x.backing_storage for x in mappings]
def rm_func(vios_w): LOG.info( _LI("Removing vSCSI mapping from Physical Volume %(dev)s " "to VM %(vm)s") % { 'dev': device_name, 'vm': vm_uuid }) return tsk_map.remove_maps( vios_w, vm_uuid, tsk_map.gen_match_func(pvm_stor.PV, names=[device_name]))
def rm_func(vios_w): LOG.info("Removing vSCSI mapping from physical volume %(dev)s.", {'dev': device_name}, instance=self.instance) removed_maps = tsk_map.remove_maps( vios_w, vm_uuid, tsk_map.gen_match_func(pvm_stor.PV, names=[device_name])) for rm_map in removed_maps: slot_mgr.drop_vscsi_mapping(rm_map) return removed_maps
def _disk_match_func(disk_type, instance): """Return a matching function to locate the disk for an instance. :param disk_type: One of the DiskType enum values. :param instance: The instance whose disk is to be found. :return: Callable suitable for the match_func parameter of the pypowervm.tasks.scsi_mapper.find_maps method. """ disk_name = SSPDiskAdapter._get_disk_name(disk_type, instance) return tsk_map.gen_match_func(pvm_stg.LU, names=[disk_name])
def _disk_match_func(disk_type, instance): """Return a matching function to locate the disk for an instance. :param disk_type: One of the DiskType enum values. :param instance: The instance whose disk is to be found. :return: Callable suitable for the match_func parameter of the pypowervm.tasks.scsi_mapper.find_maps method. """ disk_name = LocalStorage._get_disk_name( disk_type, instance, short=True) return tsk_map.gen_match_func(pvm_stg.VDisk, names=[disk_name])
def add_dlt_vopt_tasks(self, lpar_uuid, stg_ftsk, remove_mappings=True): """Deletes the virtual optical and (optionally) scsi mappings for a VM. :param lpar_uuid: The pypowervm UUID of the LPAR whose vopt is to be removed. :param stg_ftsk: A FeedTask handling storage I/O. The task to remove the mappings and media from the VM will be deferred on to the FeedTask passed in. The execute can be done all in one method (batched together). No updates are actually made here; they are simply added to the FeedTask. :param remove_mappings: (Optional, Default: True) If set to true, will remove the SCSI mappings as part of the operation. If false, will leave the mapping but detach the storage from it. If the VM is running, it may be necessary to do the latter as some operating systems will not allow the removal. """ # The function to find the VOpt match_func = tsk_map.gen_match_func(pvm_stg.VOptMedia) def rm_vopt_mapping(vios_w): return tsk_map.remove_maps(vios_w, lpar_uuid, match_func=match_func) def detach_vopt_from_map(vios_w): return tsk_map.detach_storage(vios_w, lpar_uuid, match_func=match_func) # Add a function to remove the map or detach the vopt stg_ftsk.wrapper_tasks[self.vios_uuid].add_functor_subtask( rm_vopt_mapping if remove_mappings else detach_vopt_from_map) # Find the vOpt device (before the remove is done) so that it can be # removed. partition_id = vm.get_vm_id(self.adapter, lpar_uuid) media_mappings = tsk_map.find_maps( stg_ftsk.get_wrapper(self.vios_uuid).scsi_mappings, client_lpar_id=partition_id, match_func=match_func) media_elems = [x.backing_storage for x in media_mappings] def rm_vopt(): LOG.info(_LI("Removing virtual optical for VM with UUID %s."), lpar_uuid) vg_rsp = self.adapter.read(pvm_vios.VIOS.schema_type, root_id=self.vios_uuid, child_type=pvm_stg.VG.schema_type, child_id=self.vg_uuid) tsk_stg.rm_vg_storage(pvm_stg.VG.wrap(vg_rsp), vopts=media_elems) # Don't add this task if there is no media to delete (eg. config drive) if media_elems: stg_ftsk.add_post_execute(task.FunctorTask(rm_vopt))
def rm_func(vios_w): LOG.info( _LI("Removing vSCSI mapping from Physical Volume %(dev)s " "to VM %(vm)s"), { 'dev': device_name, 'vm': vm_uuid }) removed_maps = tsk_map.remove_maps( vios_w, vm_uuid, tsk_map.gen_match_func(pvm_stor.PV, names=[device_name])) for rm_map in removed_maps: slot_mgr.drop_vscsi_mapping(rm_map) return removed_maps
def disconnect_image_disk(self, context, instance, stg_ftsk=None, disk_type=None): """Disconnects the storage adapters from the image disk. :param context: nova context for operation :param instance: instance to disconnect the image for. :param stg_ftsk: (Optional) The pypowervm transaction FeedTask for the I/O Operations. If provided, the Virtual I/O Server mapping updates will be added to the FeedTask. This defers the updates to some later point in time. If the FeedTask is not provided, the updates will be run immediately when this method is executed. :param disk_type: The list of disk types to remove or None which means to remove all disks from the VM. :return: A list of all the backing storage elements that were disconnected from the I/O Server and VM. """ lpar_uuid = vm.get_pvm_uuid(instance) # Ensure we have a transaction manager. if stg_ftsk is None: stg_ftsk = vios.build_tx_feed_task( self.adapter, self.host_uuid, name='localdisk', xag=[pvm_vios.VIOS.xags.SCSI_MAPPING]) # Build the match function match_func = tsk_map.gen_match_func(pvm_stg.VDisk, prefixes=disk_type) # Make sure the remove function will run within the transaction manager def rm_func(vios_w): LOG.info(_LI("Disconnecting instance %(inst)s from storage disks.") % {'inst': instance.name}) return tsk_map.remove_maps(vios_w, lpar_uuid, match_func=match_func) stg_ftsk.wrapper_tasks[self._vios_uuid].add_functor_subtask(rm_func) # Find the disk directly. vios_w = stg_ftsk.wrapper_tasks[self._vios_uuid].wrapper mappings = tsk_map.find_maps(vios_w.scsi_mappings, client_lpar_id=lpar_uuid, match_func=match_func) # Run the transaction manager if built locally. Must be done after # the find to make sure the mappings were found previously. if stg_ftsk.name == 'localdisk': stg_ftsk.execute() return [x.backing_storage for x in mappings]
def disk_match_func(self, disk_type, instance): """Return a matching function to locate the disk for an instance. :param disk_type: One of the DiskType enum values. :param instance: The instance whose disk is to be found. :return: Callable suitable for the match_func parameter of the pypowervm.tasks.scsi_mapper.find_maps method, with the following specification: def match_func(storage_elem) param storage_elem: A backing storage element wrapper (VOpt, VDisk, PV, or LU) to be analyzed. return: True if the storage_elem's mapping should be included; False otherwise. """ disk_name = self._get_disk_name(disk_type, instance, short=True) return tsk_map.gen_match_func(pvm_stg.VDisk, names=[disk_name])
def _check_host_mappings(self, vios_wrap, device_name): """Checks if the given hdisk has multiple mappings :param vio_wrap: The Virtual I/O Server wrapper to remove the disk from. :param device_name: The hdisk name to remove. :return: True is there are multiple instances using the given hdisk """ vios_scsi_mappings = next(v.scsi_mappings for v in self.stg_ftsk.feed if v.uuid == vios_wrap.uuid) mappings = tsk_map.find_maps(vios_scsi_mappings, None, tsk_map.gen_match_func(pvm_stor.PV, names=[device_name])) LOG.info(_LI("%(num)d Storage Mappings found for %(dev)s"), {"num": len(mappings), "dev": device_name}) # the mapping is still present as the task feed removes # the mapping later return len(mappings) > 1
def detach_disk(self, instance): """Detaches the storage adapters from the disk. :param instance: instance from which to detach the image. :return: A list of all the backing storage elements that were detached from the I/O Server and VM. """ stg_ftsk = tsk_par.build_active_vio_feed_task( self._adapter, name='ssp', xag=[pvm_const.XAG.VIO_SMAP]) lpar_uuid = vm.get_pvm_uuid(instance) match_func = tsk_map.gen_match_func(pvm_stg.LU) def rm_func(vwrap): LOG.info("Removing SSP disk connection to VIOS %s.", vwrap.name, instance=instance) return tsk_map.remove_maps(vwrap, lpar_uuid, match_func=match_func) # Remove the mapping from *each* VIOS on the LPAR's host. # The LPAR's host has to be self._host_uuid, else the PowerVM API will # fail. # # Note - this may not be all the VIOSes on the system...just the ones # in the SSP cluster. # # The mappings will normally be the same on all VIOSes, unless a VIOS # was down when a disk was added. So for the return value, we need to # collect the union of all relevant mappings from all VIOSes. lu_set = set() for vios_uuid in self._vios_uuids: # Add the remove for the VIO stg_ftsk.wrapper_tasks[vios_uuid].add_functor_subtask(rm_func) # Find the active LUs so that a delete op knows what to remove. vios_w = stg_ftsk.wrapper_tasks[vios_uuid].wrapper mappings = tsk_map.find_maps(vios_w.scsi_mappings, client_lpar_id=lpar_uuid, match_func=match_func) if mappings: lu_set.update([x.backing_storage for x in mappings]) stg_ftsk.execute() return list(lu_set)
def detach_disk(self, instance): """Detaches the storage adapters from the disk. :param instance: instance from which to detach the image. :return: A list of all the backing storage elements that were detached from the I/O Server and VM. """ stg_ftsk = tsk_par.build_active_vio_feed_task( self._adapter, name='ssp', xag=[pvm_const.XAG.VIO_SMAP]) lpar_uuid = vm.get_pvm_uuid(instance) match_func = tsk_map.gen_match_func(pvm_stg.LU) def rm_func(vwrap): LOG.info("Removing SSP disk connection to VIOS %s.", vwrap.name, instance=instance) return tsk_map.remove_maps(vwrap, lpar_uuid, match_func=match_func) # Remove the mapping from *each* VIOS on the LPAR's host. # The LPAR's host has to be self.host_uuid, else the PowerVM API will # fail. # # Note - this may not be all the VIOSes on the system...just the ones # in the SSP cluster. # # The mappings will normally be the same on all VIOSes, unless a VIOS # was down when a disk was added. So for the return value, we need to # collect the union of all relevant mappings from all VIOSes. lu_set = set() for vios_uuid in self._vios_uuids: # Add the remove for the VIO stg_ftsk.wrapper_tasks[vios_uuid].add_functor_subtask(rm_func) # Find the active LUs so that a delete op knows what to remove. vios_w = stg_ftsk.wrapper_tasks[vios_uuid].wrapper mappings = tsk_map.find_maps(vios_w.scsi_mappings, client_lpar_id=lpar_uuid, match_func=match_func) if mappings: lu_set.update([x.backing_storage for x in mappings]) stg_ftsk.execute() return list(lu_set)
def _check_host_mappings(self, vios_wrap, device_name): """Checks if the given hdisk has multiple mappings :param vio_wrap: The Virtual I/O Server wrapper to remove the disk from. :param device_name: The hdisk name to remove. :return: True if there are multiple instances using the given hdisk """ vios_scsi_mappings = next(v.scsi_mappings for v in self.stg_ftsk.feed if v.uuid == vios_wrap.uuid) mappings = tsk_map.find_maps( vios_scsi_mappings, None, tsk_map.gen_match_func(pvm_stor.PV, names=[device_name])) LOG.debug("%(num)d storage mapping(s) found for %(dev)s on VIOS " "%(vios)s", {'num': len(mappings), 'dev': device_name, 'vios': vios_wrap.name}, instance=self.instance) # The mapping is still present as the task feed removes it later. return len(mappings) > 1
def add_dlt_vopt_tasks(self, lpar_uuid, stg_ftsk): """Deletes the virtual optical and scsi mappings for a VM. :param lpar_uuid: The pypowervm UUID of the LPAR to remove. :param stg_ftsk: A FeedTask handling storage I/O. The task to remove the mappings and media from the VM will be deferred on to the FeedTask passed in. The execute can be done all in one method (batched together). No updates are actually made here; they are simply added to the FeedTask. """ # The function to find the VOpt match_func = tsk_map.gen_match_func(pvm_stg.VOptMedia) def rm_vopt_mapping(vios_w): return tsk_map.remove_maps(vios_w, lpar_uuid, match_func=match_func) # Add a function to remove the map stg_ftsk.wrapper_tasks[self.vios_uuid].add_functor_subtask( rm_vopt_mapping) # Find the vOpt device (before the remove is done) so that it can be # removed. partition_id = vm.get_vm_id(self.adapter, lpar_uuid) media_mappings = tsk_map.find_maps(stg_ftsk.get_wrapper( self.vios_uuid).scsi_mappings, client_lpar_id=partition_id, match_func=match_func) media_elems = [x.backing_storage for x in media_mappings] def rm_vopt(): LOG.info(_LI("Removing virtual optical for VM with UUID %s."), lpar_uuid) vg_rsp = self.adapter.read(pvm_vios.VIOS.schema_type, root_id=self.vios_uuid, child_type=pvm_stg.VG.schema_type, child_id=self.vg_uuid) tsk_stg.rm_vg_storage(pvm_stg.VG.wrap(vg_rsp), vopts=media_elems) stg_ftsk.add_post_execute(task.FunctorTask(rm_vopt))
def add_dlt_vopt_tasks(self, lpar_uuid, stg_ftsk): """Deletes the virtual optical and scsi mappings for a VM. :param lpar_uuid: The pypowervm UUID of the LPAR to remove. :param stg_ftsk: A FeedTask handling storage I/O. The task to remove the mappings and media from the VM will be deferred on to the FeedTask passed in. The execute can be done all in one method (batched together). No updates are actually made here; they are simply added to the FeedTask. """ # The function to find the VOpt match_func = tsk_map.gen_match_func(pvm_stg.VOptMedia) def rm_vopt_mapping(vios_w): return tsk_map.remove_maps(vios_w, lpar_uuid, match_func=match_func) # Add a function to remove the map stg_ftsk.wrapper_tasks[self.vios_uuid].add_functor_subtask( rm_vopt_mapping) # Find the vOpt device (before the remove is done) so that it can be # removed. partition_id = vm.get_vm_id(self.adapter, lpar_uuid) media_mappings = tsk_map.find_maps( stg_ftsk.get_wrapper(self.vios_uuid).scsi_mappings, client_lpar_id=partition_id, match_func=match_func) media_elems = [x.backing_storage for x in media_mappings] def rm_vopt(): LOG.info(_LI("Removing virtual optical for VM with UUID %s."), lpar_uuid) vg_rsp = self.adapter.read(pvm_vios.VIOS.schema_type, root_id=self.vios_uuid, child_type=pvm_stg.VG.schema_type, child_id=self.vg_uuid) tsk_stg.rm_vg_storage(pvm_stg.VG.wrap(vg_rsp), vopts=media_elems) stg_ftsk.add_post_execute(task.FunctorTask(rm_vopt))
def detach_disk(self, instance): """Detaches the storage adapters from the image disk. :param instance: Instance to disconnect the image for. :return: A list of all the backing storage elements that were disconnected from the I/O Server and VM. """ lpar_uuid = vm.get_pvm_uuid(instance) # Build the match function match_func = tsk_map.gen_match_func(pvm_stg.VDisk) vios_w = pvm_vios.VIOS.get( self._adapter, uuid=self._vios_uuid, xag=[pvm_const.XAG.VIO_SMAP]) # Remove the mappings. mappings = tsk_map.remove_maps( vios_w, lpar_uuid, match_func=match_func) # Update the VIOS with the removed mappings. vios_w.update() return [x.backing_storage for x in mappings]
def test_gen_match_func(self): """Tests for gen_match_func.""" # Class must match mfunc = scsi_mapper.gen_match_func(str) self.assertFalse(mfunc(1)) self.assertTrue(mfunc('foo')) # Match names elem = mock.Mock() elem.name = 'foo' # 'False' names/prefixes ignored mfunc = scsi_mapper.gen_match_func(mock.Mock, names=[]) self.assertTrue(mfunc(elem)) mfunc = scsi_mapper.gen_match_func(mock.Mock, prefixes=[]) self.assertTrue(mfunc(elem)) mfunc = scsi_mapper.gen_match_func(mock.Mock, names=[], prefixes=[]) self.assertTrue(mfunc(elem)) mfunc = scsi_mapper.gen_match_func(mock.Mock, names=['bar', 'baz']) self.assertFalse(mfunc(elem)) mfunc = scsi_mapper.gen_match_func(mock.Mock, names=['bar', 'foobar', 'baz']) self.assertFalse(mfunc(elem)) mfunc = scsi_mapper.gen_match_func(mock.Mock, names=['bar', 'foo', 'baz']) self.assertTrue(mfunc(elem)) # Prefixes are ignored if names specified mfunc = scsi_mapper.gen_match_func(mock.Mock, prefixes='x', names=['bar', 'foo', 'baz']) self.assertTrue(mfunc(elem)) mfunc = scsi_mapper.gen_match_func(mock.Mock, names=['bar', 'baz'], prefixes=['f']) self.assertFalse(mfunc(elem)) # Prefixes mfunc = scsi_mapper.gen_match_func(mock.Mock, prefixes=['f']) self.assertTrue(mfunc(elem)) mfunc = scsi_mapper.gen_match_func(mock.Mock, prefixes=['foo']) self.assertTrue(mfunc(elem)) mfunc = scsi_mapper.gen_match_func(mock.Mock, prefixes=['foo', 'x']) self.assertTrue(mfunc(elem)) mfunc = scsi_mapper.gen_match_func(mock.Mock, prefixes=['x']) self.assertFalse(mfunc(elem)) mfunc = scsi_mapper.gen_match_func(mock.Mock, prefixes=['xfoo', 'foox', 'xfoox']) self.assertFalse(mfunc(elem)) # Alternate key for the name property elem = mock.Mock(alt_name='foo') mfunc = scsi_mapper.gen_match_func(mock.Mock, name_prop='alt_name', names=[]) self.assertTrue(mfunc(elem)) mfunc = scsi_mapper.gen_match_func(mock.Mock, names=['bar', 'baz']) self.assertFalse(mfunc(elem)) mfunc = scsi_mapper.gen_match_func(mock.Mock, name_prop='alt_name', names=['bar', 'baz']) self.assertFalse(mfunc(elem)) mfunc = scsi_mapper.gen_match_func(mock.Mock, names=['bar', 'foo', 'baz']) self.assertFalse(mfunc(elem)) mfunc = scsi_mapper.gen_match_func(mock.Mock, name_prop='alt_name', names=['bar', 'foo', 'baz']) self.assertTrue(mfunc(elem))
def test_detach_storage(self): """Detach storage from some mappings.""" # In v1wrap, all five maps are associated with LPAR 2 num_matches = 5 self.assertEqual(num_matches, len(self.v1wrap.scsi_mappings)) # Beforehand, four of them have storage and one does not. self.assertEqual( 4, len([ sm.backing_storage for sm in self.v1wrap.scsi_mappings if sm.backing_storage is not None ])) removals = scsi_mapper.detach_storage(self.v1wrap, 2) # The number of mappings is the same afterwards. self.assertEqual(num_matches, len(self.v1wrap.scsi_mappings)) # But now the mappings have no storage for smap in self.v1wrap.scsi_mappings: self.assertIsNone(smap.backing_storage) # The return list contains all the mappings self.assertEqual(num_matches, len(removals)) # The return list members contain the storage (the four that had it # beforehand). self.assertEqual( 4, len([ sm.backing_storage for sm in removals if sm.backing_storage is not None ])) # In v2wrap, there are four VOptMedia mappings num_matches = 4 match_class = pvm_stor.VOptMedia # Number of mappings should be the same before and after. len_before = len(self.v2wrap.scsi_mappings) self.assertEqual( num_matches, len([ 1 for sm in self.v2wrap.scsi_mappings if isinstance(sm.backing_storage, match_class) ])) removals = scsi_mapper.detach_storage( self.v2wrap, None, match_func=scsi_mapper.gen_match_func(match_class)) self.assertEqual(num_matches, len(removals)) # The number of mappings is the same as beforehand. self.assertEqual(len_before, len(self.v2wrap.scsi_mappings)) # Now there should be no mappings with VOptMedia self.assertEqual( 0, len([ 1 for sm in self.v2wrap.scsi_mappings if isinstance(sm.backing_storage, match_class) ])) # The removals contain the storage self.assertEqual( num_matches, len([ 1 for sm in removals if isinstance(sm.backing_storage, match_class) ]))
def disconnect_image_disk(self, context, instance, stg_ftsk=None, disk_type=None): """Disconnects the storage adapters from the image disk. :param context: nova context for operation :param instance: instance to disconnect the image for. :param stg_ftsk: (Optional) The pypowervm transaction FeedTask for the I/O Operations. If provided, the Virtual I/O Server mapping updates will be added to the FeedTask. This defers the updates to some later point in time. If the FeedTask is not provided, the updates will be run immediately when this method is executed. :param disk_type: The list of disk types to remove or None which means to remove all disks from the VM. :return: A list of all the backing storage elements that were disconnected from the I/O Server and VM. """ if stg_ftsk is None: stg_ftsk = vios.build_tx_feed_task( self.adapter, self.host_uuid, name='ssp', xag=[pvm_vios.VIOS.xags.SCSI_MAPPING]) lpar_uuid = vm.get_pvm_uuid(instance) match_func = tsk_map.gen_match_func(pvm_stg.LU, prefixes=disk_type) # Delay run function to remove the mapping between the VM and the LU def rm_func(vios_w): LOG.info(_LI("Removing SSP disk connection between VM %(vm)s and " "VIOS %(vios)s."), {'vm': instance.name, 'vios': vios_w.name}) return tsk_map.remove_maps(vios_w, lpar_uuid, match_func=match_func) # Add the mapping to *each* VIOS on the LPAR's host. # The LPAR's host has to be self.host_uuid, else the PowerVM API will # fail. # # Note - this may not be all the VIOSes on the system...just the ones # in the SSP cluster. # # The mappings will normally be the same on all VIOSes, unless a VIOS # was down when a disk was added. So for the return value, we need to # collect the union of all relevant mappings from all VIOSes. lu_set = set() for vios_uuid in self.vios_uuids: # Add the remove for the VIO stg_ftsk.wrapper_tasks[vios_uuid].add_functor_subtask(rm_func) # Find the active LUs so that a delete op knows what to remove. vios_w = stg_ftsk.wrapper_tasks[vios_uuid].wrapper mappings = tsk_map.find_maps(vios_w.scsi_mappings, client_lpar_id=lpar_uuid, match_func=match_func) if mappings: lu_set.update([x.backing_storage for x in mappings]) # Run the FeedTask if it was built locally if stg_ftsk.name == 'ssp': stg_ftsk.execute() return list(lu_set)
def rm_func(vios_w): LOG.info( _LI("Removing vSCSI mapping from Physical Volume %(dev)s " "to VM %(vm)s") % {"dev": device_name, "vm": vm_uuid} ) return tsk_map.remove_maps(vios_w, vm_uuid, tsk_map.gen_match_func(pvm_stor.PV, names=[device_name]))