summaryrefslogtreecommitdiff
path: root/nova/virt/powervm/tasks/storage.py
diff options
context:
space:
mode:
Diffstat (limited to 'nova/virt/powervm/tasks/storage.py')
-rw-r--r--nova/virt/powervm/tasks/storage.py142
1 files changed, 142 insertions, 0 deletions
diff --git a/nova/virt/powervm/tasks/storage.py b/nova/virt/powervm/tasks/storage.py
index 5b72ac010c..839046be54 100644
--- a/nova/virt/powervm/tasks/storage.py
+++ b/nova/virt/powervm/tasks/storage.py
@@ -14,10 +14,13 @@
from oslo_log import log as logging
from pypowervm import exceptions as pvm_exc
+from pypowervm.tasks import scsi_mapper as pvm_smap
from taskflow import task
from taskflow.types import failure as task_fail
+from nova import exception
from nova.virt.powervm import media
+from nova.virt.powervm import mgmt
LOG = logging.getLogger(__name__)
@@ -205,3 +208,142 @@ class DeleteVOpt(task.Task):
def execute(self):
media_builder = media.ConfigDrivePowerVM(self.adapter)
media_builder.dlt_vopt(self.instance, stg_ftsk=self.stg_ftsk)
+
+
+class InstanceDiskToMgmt(task.Task):
+
+ """The task to connect an instance's disk to the management partition."
+
+ This task will connect the instance's disk to the management partition and
+ discover it. We do these two pieces together because their reversion
+ happens in the same order.
+ """
+
+ def __init__(self, disk_dvr, instance):
+ """Create the Task for connecting boot disk to mgmt partition.
+
+ Provides:
+ stg_elem: The storage element wrapper (pypowervm LU, PV, etc.) that was
+ connected.
+ vios_wrap: The Virtual I/O Server wrapper from which the storage
+ element was mapped.
+ disk_path: The local path to the mapped-and-discovered device, e.g.
+ '/dev/sde'.
+
+ :param disk_dvr: The disk driver.
+ :param instance: The nova instance whose boot disk is to be connected.
+ """
+ super(InstanceDiskToMgmt, self).__init__(
+ name='instance_disk_to_mgmt',
+ provides=['stg_elem', 'vios_wrap', 'disk_path'])
+ self.disk_dvr = disk_dvr
+ self.instance = instance
+ self.stg_elem = None
+ self.vios_wrap = None
+ self.disk_path = None
+
+ def execute(self):
+ """Map the instance's boot disk and discover it."""
+
+ # Search for boot disk on the NovaLink partition.
+ if self.disk_dvr.mp_uuid in self.disk_dvr._vios_uuids:
+ dev_name = self.disk_dvr.get_bootdisk_path(
+ self.instance, self.disk_dvr.mp_uuid)
+ if dev_name is not None:
+ return None, None, dev_name
+
+ self.stg_elem, self.vios_wrap = (
+ self.disk_dvr.connect_instance_disk_to_mgmt(self.instance))
+ new_maps = pvm_smap.find_maps(
+ self.vios_wrap.scsi_mappings, client_lpar_id=self.disk_dvr.mp_uuid,
+ stg_elem=self.stg_elem)
+ if not new_maps:
+ raise exception.NewMgmtMappingNotFoundException(
+ stg_name=self.stg_elem.name, vios_name=self.vios_wrap.name)
+
+ # new_maps should be length 1, but even if it's not - i.e. we somehow
+ # matched more than one mapping of the same dev to the management
+ # partition from the same VIOS - it is safe to use the first one.
+ mapping = new_maps[0]
+ # Scan the SCSI bus, discover the disk, find its canonical path.
+ LOG.info("Discovering device and path for mapping of %(dev_name)s "
+ "on the management partition.",
+ {'dev_name': self.stg_elem.name}, instance=self.instance)
+ self.disk_path = mgmt.discover_vscsi_disk(mapping)
+ return self.stg_elem, self.vios_wrap, self.disk_path
+
+ def revert(self, result, flow_failures):
+ """Unmap the disk and then remove it from the management partition.
+
+ We use this order to avoid rediscovering the device in case some other
+ thread scans the SCSI bus between when we remove and when we unmap.
+ """
+ if self.vios_wrap is None or self.stg_elem is None:
+ # We never even got connected - nothing to do.
+ return
+ LOG.warning("Unmapping boot disk %(disk_name)s from the management "
+ "partition via Virtual I/O Server %(vioname)s.",
+ {'disk_name': self.stg_elem.name,
+ 'vioname': self.vios_wrap.name}, instance=self.instance)
+ self.disk_dvr.disconnect_disk_from_mgmt(self.vios_wrap.uuid,
+ self.stg_elem.name)
+
+ if self.disk_path is None:
+ # We did not discover the disk - nothing else to do.
+ return
+ LOG.warning("Removing disk %(dpath)s from the management partition.",
+ {'dpath': self.disk_path}, instance=self.instance)
+ try:
+ mgmt.remove_block_dev(self.disk_path)
+ except pvm_exc.Error:
+ # Don't allow revert exceptions to interrupt the revert flow.
+ LOG.exception("Remove disk failed during revert. Ignoring.",
+ instance=self.instance)
+
+
+class RemoveInstanceDiskFromMgmt(task.Task):
+
+ """Unmap and remove an instance's boot disk from the mgmt partition."""
+
+ def __init__(self, disk_dvr, instance):
+ """Create task to unmap and remove an instance's boot disk from mgmt.
+
+ Requires (from InstanceDiskToMgmt):
+ stg_elem: The storage element wrapper (pypowervm LU, PV, etc.) that was
+ connected.
+ vios_wrap: The Virtual I/O Server wrapper.
+ (pypowervm.wrappers.virtual_io_server.VIOS) from which the
+ storage element was mapped.
+ disk_path: The local path to the mapped-and-discovered device, e.g.
+ '/dev/sde'.
+ :param disk_dvr: The disk driver.
+ :param instance: The nova instance whose boot disk is to be connected.
+ """
+ self.disk_dvr = disk_dvr
+ self.instance = instance
+ super(RemoveInstanceDiskFromMgmt, self).__init__(
+ name='remove_inst_disk_from_mgmt',
+ requires=['stg_elem', 'vios_wrap', 'disk_path'])
+
+ def execute(self, stg_elem, vios_wrap, disk_path):
+ """Unmap and remove an instance's boot disk from the mgmt partition.
+
+ Input parameters ('requires') provided by InstanceDiskToMgmt task.
+ :param stg_elem: The storage element wrapper (pypowervm LU, PV, etc.)
+ to be disconnected.
+ :param vios_wrap: The Virtual I/O Server wrapper from which the
+ mapping is to be removed.
+ :param disk_path: The local path to the disk device to be removed, e.g.
+ '/dev/sde'
+ """
+ # stg_elem is None if boot disk was not mapped to management partition.
+ if stg_elem is None:
+ return
+ LOG.info("Unmapping boot disk %(disk_name)s from the management "
+ "partition via Virtual I/O Server %(vios_name)s.",
+ {'disk_name': stg_elem.name, 'vios_name': vios_wrap.name},
+ instance=self.instance)
+ self.disk_dvr.disconnect_disk_from_mgmt(vios_wrap.uuid, stg_elem.name)
+ LOG.info("Removing disk %(disk_path)s from the management partition.",
+ {'disk_path': disk_path}, instance=self.instance)
+ mgmt.remove_block_dev(disk_path)