diff --git a/nova_powervm/tests/virt/powervm/disk/test_localdisk.py b/nova_powervm/tests/virt/powervm/disk/test_localdisk.py index ac5f0a03..c1f3c1b8 100644 --- a/nova_powervm/tests/virt/powervm/disk/test_localdisk.py +++ b/nova_powervm/tests/virt/powervm/disk/test_localdisk.py @@ -27,6 +27,7 @@ from pypowervm.wrappers import virtual_io_server as pvm_vios from nova_powervm.tests.virt.powervm import fixtures as fx from nova_powervm.virt.powervm.disk import driver as disk_dvr from nova_powervm.virt.powervm.disk import localdisk as ld +from nova_powervm.virt.powervm import exception as npvmex VOL_GRP_WITH_VIOS = 'fake_volume_group_with_vio_data.txt' @@ -268,7 +269,7 @@ class TestLocalDisk(test.TestCase): # Not found mock_add.reset_mock() self.apt.read.return_value = vios2.entry - self.assertRaises(disk_dvr.InstanceDiskMappingFailed, + self.assertRaises(npvmex.InstanceDiskMappingFailed, local.connect_instance_disk_to_mgmt, inst) self.assertEqual(0, mock_add.call_count) @@ -276,7 +277,7 @@ class TestLocalDisk(test.TestCase): mock_add.reset_mock() self.apt.read.return_value = vios1.entry mock_add.side_effect = Exception("mapping failed") - self.assertRaises(disk_dvr.InstanceDiskMappingFailed, + self.assertRaises(npvmex.InstanceDiskMappingFailed, local.connect_instance_disk_to_mgmt, inst) self.assertEqual(1, mock_add.call_count) @@ -349,6 +350,6 @@ class TestLocalDiskFindVG(test.TestCase): self.flags(volume_group_name='rootvg', volume_group_vios_name='invalid_vios') - self.assertRaises(ld.VGNotFound, ld.LocalStorage, + self.assertRaises(npvmex.VGNotFound, ld.LocalStorage, {'adapter': self.apt, 'host_uuid': 'host_uuid', 'mp_uuid': 'mp_uuid'}) diff --git a/nova_powervm/tests/virt/powervm/disk/test_ssp.py b/nova_powervm/tests/virt/powervm/disk/test_ssp.py index 63145557..12126f1c 100644 --- a/nova_powervm/tests/virt/powervm/disk/test_ssp.py +++ b/nova_powervm/tests/virt/powervm/disk/test_ssp.py @@ -29,8 +29,8 @@ from pypowervm.wrappers import storage as pvm_stg from pypowervm.wrappers import virtual_io_server as pvm_vios from nova_powervm.tests.virt.powervm import fixtures as fx -from nova_powervm.virt.powervm.disk import driver from nova_powervm.virt.powervm.disk import ssp +from nova_powervm.virt.powervm import exception as npvmex SSP = 'fake_ssp.txt' @@ -172,7 +172,7 @@ class TestSSPDiskAdapter(test.TestCase): def test_init_ClusterNotFoundByName(self): """Empty feed comes back from search - no cluster by that name.""" self.mock_search.return_value = self._bld_resp(status=204) - self.assertRaises(ssp.ClusterNotFoundByName, self._get_ssp_stor) + self.assertRaises(npvmex.ClusterNotFoundByName, self._get_ssp_stor) def test_init_TooManyClustersFound(self): """Search-by-name returns more than one result.""" @@ -184,13 +184,13 @@ class TestSSPDiskAdapter(test.TestCase): pvm_clust.Node.bld(None, 'vios2')) self.mock_search.return_value = self._bld_resp( entry_or_list=[clust1.entry, clust2.entry]) - self.assertRaises(ssp.TooManyClustersFound, self._get_ssp_stor) + self.assertRaises(npvmex.TooManyClustersFound, self._get_ssp_stor) def test_init_NoConfigNoClusterFound(self): """No cluster name specified in config, no clusters on host.""" self.flags(cluster_name='') self.apt.read.return_value = self._bld_resp(status=204) - self.assertRaises(ssp.NoConfigNoClusterFound, self._get_ssp_stor) + self.assertRaises(npvmex.NoConfigNoClusterFound, self._get_ssp_stor) def test_init_NoConfigTooManyClusters(self): """No SSP name specified in config, more than one SSP on host.""" @@ -203,7 +203,7 @@ class TestSSPDiskAdapter(test.TestCase): pvm_clust.Node.bld(None, 'vios2')) self.apt.read.return_value = self._bld_resp( entry_or_list=[clust1.entry, clust2.entry]) - self.assertRaises(ssp.NoConfigTooManyClusters, self._get_ssp_stor) + self.assertRaises(npvmex.NoConfigTooManyClusters, self._get_ssp_stor) def test_refresh_cluster(self): """_refresh_cluster with cached wrapper.""" @@ -550,7 +550,7 @@ class TestSSPDiskAdapter(test.TestCase): # No hits mock_add.reset_mock() self.apt.read.side_effect = [rsp3, rsp3] - self.assertRaises(driver.InstanceDiskMappingFailed, + self.assertRaises(npvmex.InstanceDiskMappingFailed, ssp_stor.connect_instance_disk_to_mgmt, inst) self.assertEqual(0, mock_add.call_count) diff --git a/nova_powervm/tests/virt/powervm/test_media.py b/nova_powervm/tests/virt/powervm/test_media.py index 45dd681b..10387b03 100644 --- a/nova_powervm/tests/virt/powervm/test_media.py +++ b/nova_powervm/tests/virt/powervm/test_media.py @@ -22,6 +22,7 @@ from pypowervm.tests.wrappers.util import pvmhttp from pypowervm.wrappers import storage as pvm_stor from nova_powervm.tests.virt.powervm import fixtures as fx +from nova_powervm.virt.powervm import exception as npvmex from nova_powervm.virt.powervm import media as m VOL_GRP_DATA = 'fake_volume_group.txt' @@ -136,7 +137,7 @@ class TestConfigDrivePowerVM(test.TestCase): def test_validate_opt_vg_fail(self): self.apt.read.side_effect = [self.vio_feed_no_vg, self.vol_grp_novg_resp] - self.assertRaises(m.NoMediaRepoVolumeGroupFound, + self.assertRaises(npvmex.NoMediaRepoVolumeGroupFound, m.ConfigDrivePowerVM, self.apt, 'fake_host') @mock.patch('pypowervm.tasks.scsi_mapper.remove_vopt_mapping') diff --git a/nova_powervm/tests/virt/powervm/test_mgmt.py b/nova_powervm/tests/virt/powervm/test_mgmt.py index 774b2956..aefd5864 100644 --- a/nova_powervm/tests/virt/powervm/test_mgmt.py +++ b/nova_powervm/tests/virt/powervm/test_mgmt.py @@ -22,6 +22,7 @@ from pypowervm.tests.wrappers.util import pvmhttp from pypowervm.wrappers import logical_partition as pvm_lpar from nova_powervm.tests.virt.powervm import fixtures as fx +from nova_powervm.virt.powervm import exception as npvmex from nova_powervm.virt.powervm import mgmt LPAR_HTTPRESP_FILE = "lpar.txt" @@ -77,11 +78,11 @@ class TestMgmt(test.TestCase): mapping.backing_storage.udid = udid # No disks found mock_glob.side_effect = [['path'], []] - self.assertRaises(mgmt.UniqueDiskDiscoveryException, + self.assertRaises(npvmex.UniqueDiskDiscoveryException, mgmt.discover_vscsi_disk, mapping) # Multiple disks found mock_glob.side_effect = [['path'], ['/dev/sde', '/dev/sdf']] - self.assertRaises(mgmt.UniqueDiskDiscoveryException, + self.assertRaises(npvmex.UniqueDiskDiscoveryException, mgmt.discover_vscsi_disk, mapping) @mock.patch('os.path.realpath') @@ -126,8 +127,8 @@ class TestMgmt(test.TestCase): mock_exec.reset_mock() mock_stat.reset_mock() mock_stat.side_effect = (None, None, None) - self.assertRaises(mgmt.DeviceDeletionException, mgmt.remove_block_dev, - link) + self.assertRaises( + npvmex.DeviceDeletionException, mgmt.remove_block_dev, link) # stat was called thrice; exec was called once self.assertEqual(3, mock_stat.call_count) self.assertEqual(1, mock_exec.call_count) diff --git a/nova_powervm/virt/powervm/disk/__init__.py b/nova_powervm/virt/powervm/disk/__init__.py index af8639ef..e69de29b 100644 --- a/nova_powervm/virt/powervm/disk/__init__.py +++ b/nova_powervm/virt/powervm/disk/__init__.py @@ -1,26 +0,0 @@ -# Copyright 2015 IBM Corp. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import abc - -import six - - -@six.add_metaclass(abc.ABCMeta) -class AbstractDiskException(Exception): - def __init__(self, **kwds): - msg = self.msg_fmt % kwds - super(AbstractDiskException, self).__init__(msg) diff --git a/nova_powervm/virt/powervm/disk/driver.py b/nova_powervm/virt/powervm/disk/driver.py index 42b01e13..b9cf942e 100644 --- a/nova_powervm/virt/powervm/disk/driver.py +++ b/nova_powervm/virt/powervm/disk/driver.py @@ -21,13 +21,13 @@ import oslo_log.log as logging from oslo_utils import units import six -from nova.i18n import _, _LW +from nova.i18n import _LW from nova import image import pypowervm.tasks.scsi_mapper as tsk_map import pypowervm.util as pvm_util import pypowervm.wrappers.virtual_io_server as pvm_vios -from nova_powervm.virt.powervm import disk +from nova_powervm.virt.powervm import exception as npvmex from nova_powervm.virt.powervm import vm LOG = logging.getLogger(__name__) @@ -39,11 +39,6 @@ class DiskType(object): IMAGE = 'image' -class InstanceDiskMappingFailed(disk.AbstractDiskException): - msg_fmt = _("Failed to map boot disk of instance %(instance_name)s to " - "the management partition from any Virtual I/O Server.") - - class IterableToFileAdapter(object): """A degenerate file-like so that an iterable could be read like a file. @@ -174,7 +169,7 @@ class DiskAdapter(object): "%(vios_name)s: %(exc)s"), msg_args) # Try the next hit, if available. # We either didn't find the boot dev, or failed all attempts to map it. - raise InstanceDiskMappingFailed(**msg_args) + raise npvmex.InstanceDiskMappingFailed(**msg_args) def disconnect_disk_from_mgmt(self, vios_uuid, disk_name): """Disconnect a disk from the management partition. diff --git a/nova_powervm/virt/powervm/disk/localdisk.py b/nova_powervm/virt/powervm/disk/localdisk.py index dc5765ce..09cd5ea9 100644 --- a/nova_powervm/virt/powervm/disk/localdisk.py +++ b/nova_powervm/virt/powervm/disk/localdisk.py @@ -20,7 +20,7 @@ from oslo_config import cfg from oslo_log import log as logging from nova import exception as nova_exc -from nova.i18n import _, _LI, _LE +from nova.i18n import _LI, _LE from pypowervm import exceptions as pvm_exc from pypowervm.tasks import scsi_mapper as tsk_map from pypowervm.tasks import storage as tsk_stg @@ -28,8 +28,8 @@ from pypowervm.wrappers import managed_system as pvm_ms from pypowervm.wrappers import storage as pvm_stg from pypowervm.wrappers import virtual_io_server as pvm_vios -import nova_powervm.virt.powervm.disk as disk from nova_powervm.virt.powervm.disk import driver as disk_dvr +from nova_powervm.virt.powervm import exception as npvmex from nova_powervm.virt.powervm import vm localdisk_opts = [ @@ -53,11 +53,6 @@ CONF = cfg.CONF CONF.register_opts(localdisk_opts) -class VGNotFound(disk.AbstractDiskException): - msg_fmt = _("Unable to locate the volume group '%(vg_name)s' for this " - "operation.") - - class LocalStorage(disk_dvr.DiskAdapter): def __init__(self, connection): super(LocalStorage, self).__init__(connection) @@ -294,7 +289,7 @@ class LocalStorage(disk_dvr.DiskAdapter): if name == vol_grp.name: return vios_wrap.uuid, vol_grp.uuid - raise VGNotFound(vg_name=name) + raise npvmex.VGNotFound(vg_name=name) def _get_vg(self): vg_rsp = self.adapter.read( diff --git a/nova_powervm/virt/powervm/disk/ssp.py b/nova_powervm/virt/powervm/disk/ssp.py index 7fe4ee68..50311387 100644 --- a/nova_powervm/virt/powervm/disk/ssp.py +++ b/nova_powervm/virt/powervm/disk/ssp.py @@ -19,8 +19,7 @@ import random from oslo_config import cfg import oslo_log.log as logging -from nova.i18n import _, _LI, _LE -import nova_powervm.virt.powervm.disk as disk +from nova.i18n import _LI, _LE from nova_powervm.virt.powervm.disk import driver as disk_drv from nova_powervm.virt.powervm import vm @@ -30,6 +29,8 @@ import pypowervm.util as pvm_u import pypowervm.wrappers.cluster as pvm_clust import pypowervm.wrappers.storage as pvm_stg +from nova_powervm.virt.powervm import exception as npvmex + ssp_opts = [ cfg.StrOpt('cluster_name', default='', @@ -44,25 +45,6 @@ CONF = cfg.CONF CONF.register_opts(ssp_opts) -class ClusterNotFoundByName(disk.AbstractDiskException): - msg_fmt = _("Unable to locate the Cluster '%(clust_name)s' for this " - "operation.") - - -class NoConfigNoClusterFound(disk.AbstractDiskException): - msg_fmt = _('Unable to locate any Cluster for this operation.') - - -class TooManyClustersFound(disk.AbstractDiskException): - msg_fmt = _("Unexpectedly found %(clust_count)d Clusters " - "matching name '%(clust_name)s'.") - - -class NoConfigTooManyClusters(disk.AbstractDiskException): - msg_fmt = _("No cluster_name specified. Refusing to select one of the " - "%(clust_count)d Clusters found.") - - class SSPDiskAdapter(disk_drv.DiskAdapter): """Provides a disk adapter for Shared Storage Pools. @@ -318,19 +300,20 @@ class SSPDiskAdapter(disk_drv.DiskAdapter): resp = pvm_clust.Cluster.search(self.adapter, name=clust_name) wraps = pvm_clust.Cluster.wrap(resp) if len(wraps) == 0: - raise ClusterNotFoundByName(clust_name=clust_name) + raise npvmex.ClusterNotFoundByName(clust_name=clust_name) if len(wraps) > 1: - raise TooManyClustersFound(clust_count=len(wraps), - clust_name=clust_name) + raise npvmex.TooManyClustersFound(clust_count=len(wraps), + clust_name=clust_name) else: # Otherwise, pull the entire feed of Clusters and, if # exactly one result, use it. resp = self.adapter.read(pvm_clust.Cluster.schema_type) wraps = pvm_clust.Cluster.wrap(resp) if len(wraps) == 0: - raise NoConfigNoClusterFound() + raise npvmex.NoConfigNoClusterFound() if len(wraps) > 1: - raise NoConfigTooManyClusters(clust_count=len(wraps)) + raise npvmex.NoConfigTooManyClusters( + clust_count=len(wraps)) clust_wrap = wraps[0] except Exception as e: LOG.exception(e.message) diff --git a/nova_powervm/virt/powervm/exception.py b/nova_powervm/virt/powervm/exception.py new file mode 100644 index 00000000..f2731755 --- /dev/null +++ b/nova_powervm/virt/powervm/exception.py @@ -0,0 +1,86 @@ +# Copyright 2015 IBM Corp. +# +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""Exceptions specific to the powervm nova driver.""" + +import abc +from nova import exception as nex +from nova.i18n import _ + +import six + + +@six.add_metaclass(abc.ABCMeta) +class AbstractMediaException(nex.NovaException): + pass + + +@six.add_metaclass(abc.ABCMeta) +class AbstractDiskException(nex.NovaException): + pass + + +class NoMediaRepoVolumeGroupFound(AbstractMediaException): + msg_fmt = _("Unable to locate the volume group %(vol_grp)s to store the " + "virtual optical media within. Unable to create the " + "media repository.") + + +class ManagementPartitionNotFoundException(nex.NovaException): + """Couldn't find exactly one management partition on the system.""" + msg_fmt = _("Expected to find exactly one management partition; found " + "%(count)d.") + + +class UniqueDiskDiscoveryException(nex.NovaException): + """Expected to discover exactly one disk, but discovered 0 or >1.""" + msg_fmt = _("Expected to find exactly one disk on the management " + "partition at %(path_pattern)s; found %(count)d.") + + +class DeviceDeletionException(nex.NovaException): + """Expected to delete a disk, but the disk is still present afterward.""" + msg_fmt = _("Device %(devpath)s is still present on the management " + "partition after attempting to delete it.") + + +class InstanceDiskMappingFailed(AbstractDiskException): + msg_fmt = _("Failed to map boot disk of instance %(instance_name)s to " + "the management partition from any Virtual I/O Server.") + + +class VGNotFound(AbstractDiskException): + msg_fmt = _("Unable to locate the volume group '%(vg_name)s' for this " + "operation.") + + +class ClusterNotFoundByName(AbstractDiskException): + msg_fmt = _("Unable to locate the Cluster '%(clust_name)s' for this " + "operation.") + + +class NoConfigNoClusterFound(AbstractDiskException): + msg_fmt = _('Unable to locate any Cluster for this operation.') + + +class TooManyClustersFound(AbstractDiskException): + msg_fmt = _("Unexpectedly found %(clust_count)d Clusters " + "matching name '%(clust_name)s'.") + + +class NoConfigTooManyClusters(AbstractDiskException): + msg_fmt = _("No cluster_name specified. Refusing to select one of the " + "%(clust_count)d Clusters found.") diff --git a/nova_powervm/virt/powervm/media.py b/nova_powervm/virt/powervm/media.py index 145fe4e5..9af815e5 100644 --- a/nova_powervm/virt/powervm/media.py +++ b/nova_powervm/virt/powervm/media.py @@ -14,10 +14,9 @@ # License for the specific language governing permissions and limitations # under the License. -import abc import copy from nova.api.metadata import base as instance_metadata -from nova.i18n import _, _LI, _LW +from nova.i18n import _LI, _LW from nova.network import model as network_model from nova.virt import configdrive import os @@ -33,8 +32,7 @@ from pypowervm.wrappers import managed_system as pvm_ms from pypowervm.wrappers import storage as pvm_stg from pypowervm.wrappers import virtual_io_server as pvm_vios -import six - +from nova_powervm.virt.powervm import exception as npvmex from nova_powervm.virt.powervm import vm LOG = logging.getLogger(__name__) @@ -42,19 +40,6 @@ LOG = logging.getLogger(__name__) CONF = cfg.CONF -@six.add_metaclass(abc.ABCMeta) -class AbstractMediaException(Exception): - def __init__(self, **kwargs): - msg = self.msg_fmt % kwargs - super(AbstractMediaException, self).__init__(msg) - - -class NoMediaRepoVolumeGroupFound(AbstractMediaException): - msg_fmt = _('Unable to locate the volume group %(vol_grp)s to store the ' - 'virtual optical media within. Unable to create the ' - 'media repository.') - - class ConfigDrivePowerVM(object): _cur_vios_uuid = None @@ -87,7 +72,7 @@ class ConfigDrivePowerVM(object): :param injected_files: A list of file paths that will be injected into the ISO. :param network_info: The network_info from the nova spawn method. - :param admin_password: Optional password to inject for the VM. + :param admin_pass: Optional password to inject for the VM. :return iso_path: The path to the ISO :return file_name: The file name for the ISO """ @@ -242,7 +227,7 @@ class ConfigDrivePowerVM(object): # this is user specified, and if it was not found is a proper # exception path. if found_vg is None: - raise NoMediaRepoVolumeGroupFound( + raise npvmex.NoMediaRepoVolumeGroupFound( vol_grp=CONF.vopt_media_volume_group) # Ensure that there is a virtual optical media repository within it. diff --git a/nova_powervm/virt/powervm/mgmt.py b/nova_powervm/virt/powervm/mgmt.py index 4d7afe27..385ecb81 100644 --- a/nova_powervm/virt/powervm/mgmt.py +++ b/nova_powervm/virt/powervm/mgmt.py @@ -24,7 +24,7 @@ The PowerVM Nova Compute service runs on the management partition. """ import glob from nova import exception -from nova.i18n import _, _LI +from nova.i18n import _LI from nova.storage import linuxscsi import os from os import path @@ -33,19 +33,11 @@ from oslo_log import log as logging from pypowervm.wrappers import logical_partition as pvm_lpar +from nova_powervm.virt.powervm import exception as npvmex + LOG = logging.getLogger(__name__) -class UniqueDiskDiscoveryException(Exception): - """Expected to discover exactly one disk, but discovered 0 or >1.""" - pass - - -class DeviceDeletionException(Exception): - """Expected to delete a disk, but the disk is still present afterward.""" - pass - - def get_mgmt_partition(adapter): """Get the LPAR wrapper for this host's management partition. @@ -53,7 +45,7 @@ def get_mgmt_partition(adapter): """ wraps = pvm_lpar.LPAR.search(adapter, is_mgmt_partition=True) if len(wraps) != 1: - raise Exception(_("Unable to find a single management partition.")) + raise npvmex.ManagementPartitionNotFoundException(count=len(wraps)) return wraps[0] @@ -97,10 +89,8 @@ def discover_vscsi_disk(mapping): dpathpat = '/dev/disk/by-id/*%s' % udid disks = glob.glob(dpathpat) if len(disks) != 1: - raise UniqueDiskDiscoveryException( - _("Expected to find exactly one disk on the management partition " - "at %(path_pattern)s; found %(count)d.") % - {'path_pattern': dpathpat, 'count': len(disks)}) + raise npvmex.UniqueDiskDiscoveryException(path_pattern=dpathpat, + count=len(disks)) # The by-id path is a symlink. Resolve to the /dev/sdX path dpath = path.realpath(disks[0]) @@ -142,10 +132,7 @@ def remove_block_dev(devpath): linuxscsi.echo_scsi_command(delpath, '1') try: os.stat(devpath) - raise DeviceDeletionException( - _("Device %(devpath)s is still present on the management " - "partition after attempting to delete it."), - {'devpath': devpath}) + raise npvmex.DeviceDeletionException(devpath=devpath) except OSError: # Device special file is absent, as expected pass