diff --git a/compute_hyperv/nova/cluster/driver.py b/compute_hyperv/nova/cluster/driver.py index a280581b..5e44ffbf 100644 --- a/compute_hyperv/nova/cluster/driver.py +++ b/compute_hyperv/nova/cluster/driver.py @@ -16,6 +16,7 @@ from compute_hyperv.nova.cluster import clusterops from compute_hyperv.nova.cluster import livemigrationops +from compute_hyperv.nova.cluster import volumeops from compute_hyperv.nova import driver @@ -25,6 +26,7 @@ class HyperVClusterDriver(driver.HyperVDriver): self._clops = clusterops.ClusterOps() self._livemigrationops = livemigrationops.ClusterLiveMigrationOps() + self._volumeops = volumeops.ClusterVolumeOps() self._clops.start_failover_listener_daemon() self._clops.reclaim_failovered_instances() diff --git a/compute_hyperv/nova/cluster/volumeops.py b/compute_hyperv/nova/cluster/volumeops.py new file mode 100644 index 00000000..d6dd450b --- /dev/null +++ b/compute_hyperv/nova/cluster/volumeops.py @@ -0,0 +1,49 @@ +# Copyright 2018 Cloudbase Solutions Srl +# +# 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. + +from nova import exception +from oslo_log import log as logging + +from compute_hyperv.nova import constants +from compute_hyperv.nova import volumeops + +LOG = logging.getLogger(__name__) + + +class ClusterVolumeOps(volumeops.VolumeOps): + def _load_volume_drivers(self): + self.volume_drivers = { + constants.STORAGE_PROTOCOL_SMBFS: volumeops.SMBFSVolumeDriver() + } + + def _get_volume_driver(self, connection_info): + driver_type = connection_info.get('driver_volume_type') + if driver_type in [constants.STORAGE_PROTOCOL_ISCSI, + constants.STORAGE_PROTOCOL_FC]: + err_msg = ( + "The Hyper-V Cluster driver does not currently support " + "passthrough disks (e.g. iSCSI/FC disks). The reason is " + "that the volumes need to be available on the destination " + "host side during an unexpected instance failover. In order " + "to leverage your storage backend, you may either use the " + "*standard* Nova Hyper-V driver or use the Cinder SMB volume " + "driver (which may imply deploying CSVs on top of LUNs " + "exposed by your storage backend).") + LOG.error(err_msg) + raise exception.VolumeDriverNotFound(driver_type=driver_type) + + return super(ClusterVolumeOps, self)._get_volume_driver( + connection_info) diff --git a/compute_hyperv/nova/volumeops.py b/compute_hyperv/nova/volumeops.py index cba02618..ebe27c4e 100644 --- a/compute_hyperv/nova/volumeops.py +++ b/compute_hyperv/nova/volumeops.py @@ -77,6 +77,10 @@ class VolumeOps(object): self._vmutils = utilsfactory.get_vmutils() self._default_root_device = 'vda' + + self._load_volume_drivers() + + def _load_volume_drivers(self): self.volume_drivers = { constants.STORAGE_PROTOCOL_SMBFS: SMBFSVolumeDriver(), constants.STORAGE_PROTOCOL_ISCSI: ISCSIVolumeDriver(), diff --git a/compute_hyperv/tests/unit/cluster/test_volumeops.py b/compute_hyperv/tests/unit/cluster/test_volumeops.py new file mode 100644 index 00000000..5db4e10f --- /dev/null +++ b/compute_hyperv/tests/unit/cluster/test_volumeops.py @@ -0,0 +1,50 @@ +# Copyright 2018 Cloudbase Solutions Srl +# +# 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. + +from nova import exception + +from compute_hyperv.nova.cluster import volumeops +from compute_hyperv.nova import constants +from compute_hyperv.nova import volumeops as base_volumeops +from compute_hyperv.tests.unit import test_base + + +class ClusterVolumeOpsTestCase(test_base.HyperVBaseTestCase): + _autospec_classes = [ + base_volumeops.cinder.API, + ] + + def setUp(self): + super(ClusterVolumeOpsTestCase, self).setUp() + self._volumeops = volumeops.ClusterVolumeOps() + + def test_loaded_volume_drivers(self): + self.assertEqual(set([constants.STORAGE_PROTOCOL_SMBFS]), + set(self._volumeops.volume_drivers.keys())) + + def test_get_blacklisted_volume_driver(self): + conn_info = dict(driver_volume_type=constants.STORAGE_PROTOCOL_ISCSI) + + self.assertRaises( + exception.VolumeDriverNotFound, + self._volumeops._get_volume_driver, + conn_info) + + def test_get_supported_volume_driver(self): + conn_info = dict(driver_volume_type=constants.STORAGE_PROTOCOL_SMBFS) + drv = self._volumeops._get_volume_driver(conn_info) + + self.assertIsInstance(drv, base_volumeops.SMBFSVolumeDriver)