Consolidate exceptions and extend NovaException

Consolidate all nova-powervm exception classes into a new module,
nova_powervm.virt.powervm.exception, and make sure they all inherit from
NovaException.

Change-Id: Iec10ed588192be19188e0b4d68df3f1eb73e48a2
This commit is contained in:
Eric Fried
2015-06-18 16:44:43 -05:00
parent a4cf2edc61
commit 3e88aaa8b7
11 changed files with 129 additions and 121 deletions

View File

@@ -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'})

View File

@@ -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)

View File

@@ -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')

View File

@@ -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)

View File

@@ -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)

View File

@@ -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.

View File

@@ -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(

View File

@@ -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)

View File

@@ -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.")

View File

@@ -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.

View File

@@ -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