diff --git a/manila/common/constants.py b/manila/common/constants.py index 0b67610881..b3ed617ecd 100644 --- a/manila/common/constants.py +++ b/manila/common/constants.py @@ -51,3 +51,11 @@ PING_PORTS = ( SERVICE_INSTANCE_SECGROUP_DATA = ( CIFS_PORTS + NFS_PORTS + SSH_PORTS + PING_PORTS) + +SINGLE_SVM_MODE = 'single_svm' +MULTI_SVM_MODE = 'multi_svm' + +VALID_SHARE_DRIVER_MODES = ( + SINGLE_SVM_MODE, + MULTI_SVM_MODE, +) diff --git a/manila/share/driver.py b/manila/share/driver.py index 85346e871c..5d37d3cfde 100644 --- a/manila/share/driver.py +++ b/manila/share/driver.py @@ -20,7 +20,9 @@ Drivers for shares. import time from oslo.config import cfg +import six +from manila.common import constants from manila import exception from manila.i18n import _LE from manila import network @@ -51,6 +53,13 @@ share_opts = [ "If not set, the share backend's config group will be used." "If an option is not found within provided group, then" "'DEFAULT' group will be used for search of option."), + cfg.ListOpt( + 'share_driver_mode', + default=None, + help="One specific mode for driver to use. Available values: " + "%s. What modes are supported and can be used is " + "up to driver. If set None then default will be used." % + six.text_type(constants.VALID_SHARE_DRIVER_MODES)), ] ssh_opts = [ @@ -76,11 +85,8 @@ CONF.register_opts(ssh_opts) class ExecuteMixin(object): """Provides an executable functionality to a driver class.""" - def __init__(self, *args, **kwargs): - self.db = None - self.configuration = kwargs.get('configuration', None) + def init_execute_mixin(self, *args, **kwargs): if self.configuration: - self.configuration.append_config_values(share_opts) self.configuration.append_config_values(ssh_opts) self.set_execute(kwargs.pop('execute', utils.execute)) @@ -115,10 +121,58 @@ class ShareDriver(object): self.configuration.append_config_values(share_opts) network_config_group = (self.configuration.network_config_group or self.configuration.config_group) + self.mode = self.configuration.safe_get('share_driver_mode') else: network_config_group = None + self.mode = CONF.share_driver_mode + + if hasattr(self, 'init_execute_mixin'): + # Instance with 'ExecuteMixin' + self.init_execute_mixin(*args, **kwargs) # pylint: disable=E1101 self.network_api = network.API(config_group_name=network_config_group) + def _validate_driver_mode(self, mode): + valid = constants.VALID_SHARE_DRIVER_MODES + if mode not in valid: + data = {'mode': mode, 'valid': valid} + msg = ("Provided unsupported driver mode '%(mode)s'. List of " + "valid driver modes is %(valid)s." % data) + LOG.error(msg) + raise exception.InvalidParameterValue(msg) + return mode + + def get_driver_mode(self, supported_driver_modes): + """Verify and return driver mode. + + Call this method within share driver to get value for 'mode' attr, + + :param supported_driver_modes: list of supported modes by share driver, + see list of available values in + manila.common.constants.VALID_SHARE_DRIVER_MODES + :returns: text_type -- name of enabled driver mode. + :raises: exception.InvalidParameterValue + """ + msg = None + if not len(supported_driver_modes): + msg = "At least one mode should be supported by share driver." + elif self.mode: + if self.mode not in supported_driver_modes: + data = {'mode': self.mode, 'supported': supported_driver_modes} + msg = ("Unsupported driver mode '%(mode)s' is provided. " + "List of supported is %(supported)s." % data) + else: + return self._validate_driver_mode(self.mode) + elif len(supported_driver_modes) > 1: + msg = ("Driver mode was not specified explicitly and amount of " + "supported driver modes %s is bigger than one, please " + "specify it using config option 'share_driver_mode'." % + six.text_type(supported_driver_modes)) + + if msg: + LOG.error(msg) + raise exception.InvalidParameterValue(msg) + return self._validate_driver_mode(supported_driver_modes[0]) + def create_share(self, context, share, share_server=None): """Is called to create share.""" raise NotImplementedError() diff --git a/manila/share/drivers/generic.py b/manila/share/drivers/generic.py index 94e70b5382..1bd2704a49 100644 --- a/manila/share/drivers/generic.py +++ b/manila/share/drivers/generic.py @@ -114,6 +114,7 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver): self.db = db self.configuration.append_config_values(share_opts) self.configuration.append_config_values(service_instance.server_opts) + self.mode = self.get_driver_mode([const.MULTI_SVM_MODE, ]) self._helpers = {} self.backend_name = self.configuration.safe_get( 'share_backend_name') or "Cinder_Volumes" diff --git a/manila/tests/fake_driver.py b/manila/tests/fake_driver.py index 70308a467f..653f3b74cc 100644 --- a/manila/tests/fake_driver.py +++ b/manila/tests/fake_driver.py @@ -15,6 +15,7 @@ import mock +from manila.common import constants from manila.openstack.common import log as logging from manila.share import driver @@ -28,6 +29,7 @@ class FakeShareDriver(driver.ShareDriver): super(FakeShareDriver, self).__init__(execute=self.fake_execute, *args, **kwargs) self.db = mock.Mock() + self.mode = constants.MULTI_SVM_MODE def share_network_update(*args, **kwargs): pass diff --git a/manila/tests/share/drivers/test_generic.py b/manila/tests/share/drivers/test_generic.py index 164cbb05a2..572682c6c1 100644 --- a/manila/tests/share/drivers/test_generic.py +++ b/manila/tests/share/drivers/test_generic.py @@ -878,6 +878,34 @@ class GenericShareDriverTestCase(test.TestCase): ) self.assertEqual(ssh_output, result) + @mock.patch.object( + generic.service_instance, 'ServiceInstanceManager', mock.Mock()) + def test_driver_mode_valid_value(self): + mode = const.MULTI_SVM_MODE + CONF.set_override('share_driver_mode', mode) + + driver = generic.GenericShareDriver( + self._db, execute=self._execute, configuration=self.fake_conf) + + self.assertEqual(mode, driver.mode) + generic.service_instance.ServiceInstanceManager.\ + assert_called_once_with(self._db, driver_config=self.fake_conf) + + def test_driver_mode_invalid_value(self): + mode = const.SINGLE_SVM_MODE + CONF.set_override('share_driver_mode', mode) + + self.assertRaises( + exception.InvalidParameterValue, + generic.GenericShareDriver, + self._db, + execute=self._execute, + configuration=self.fake_conf) + + def test_driver_mode_default_share_driver_modes(self): + mode = const.MULTI_SVM_MODE + self.assertEqual(mode, self._driver.mode) + class NFSHelperTestCase(test.TestCase): """Test case for NFS helper of generic driver.""" diff --git a/manila/tests/share/test_driver.py b/manila/tests/share/test_driver.py index d7793c59f4..84e2db163c 100644 --- a/manila/tests/share/test_driver.py +++ b/manila/tests/share/test_driver.py @@ -19,6 +19,7 @@ import time import mock +from manila.common import constants from manila import exception from manila import network from manila.share import configuration @@ -35,6 +36,10 @@ def fake_sleep(duration): pass +class ShareDriverWithExecuteMixin(driver.ShareDriver, driver.ExecuteMixin): + pass + + class ShareDriverTestCase(test.TestCase): def setUp(self): @@ -45,7 +50,7 @@ class ShareDriverTestCase(test.TestCase): self.stubs.Set(self.time, 'sleep', fake_sleep) def test__try_execute(self): - execute_mixin = driver.ExecuteMixin( + execute_mixin = ShareDriverWithExecuteMixin( configuration=configuration.Configuration(None)) self.assertRaises(exception.ProcessExecutionError, execute_mixin._try_execute) @@ -67,6 +72,8 @@ class ShareDriverTestCase(test.TestCase): else: network.API.assert_called_once_with( config_group_name=config.config_group) + self.assertTrue(hasattr(share_driver, 'mode')) + return share_driver def test_instantiate_share_driver(self): self._instantiate_share_driver(None) @@ -81,3 +88,79 @@ class ShareDriverTestCase(test.TestCase): self.assertEqual(None, share_driver.configuration) network.API.assert_called_once_with(config_group_name=None) + + def test_get_driver_mode_empty_list(self): + share_driver = self._instantiate_share_driver(None) + self.assertRaises( + exception.InvalidParameterValue, + share_driver.get_driver_mode, []) + + def test_get_driver_mode_one_value_in_list_mode_is_not_set(self): + share_driver = self._instantiate_share_driver(None) + share_driver.mode = None + + mode = share_driver.get_driver_mode([constants.SINGLE_SVM_MODE, ]) + + self.assertEqual(constants.SINGLE_SVM_MODE, mode) + + def test_get_driver_mode_one_value_in_list_mode_is_set_and_equal(self): + share_driver = self._instantiate_share_driver(None) + share_driver.mode = constants.SINGLE_SVM_MODE + + mode = share_driver.get_driver_mode([constants.SINGLE_SVM_MODE, ]) + + self.assertEqual(constants.SINGLE_SVM_MODE, mode) + + def test_get_driver_mode_one_value_in_list_mode_is_set_and_not_equal(self): + share_driver = self._instantiate_share_driver(None) + share_driver.mode = constants.SINGLE_SVM_MODE + + self.assertRaises( + exception.InvalidParameterValue, + share_driver.get_driver_mode, + [constants.MULTI_SVM_MODE, ]) + + def test_get_driver_mode_two_values_in_list_mode_is_not_set(self): + share_driver = self._instantiate_share_driver(None) + share_driver.mode = None + + self.assertRaises( + exception.InvalidParameterValue, + share_driver.get_driver_mode, + [constants.SINGLE_SVM_MODE, constants.MULTI_SVM_MODE]) + + def test_get_driver_mode_two_values_in_list_mode_is_set(self): + share_driver = self._instantiate_share_driver(None) + share_driver.mode = constants.MULTI_SVM_MODE + + mode = share_driver.get_driver_mode( + [constants.SINGLE_SVM_MODE, constants.MULTI_SVM_MODE, ]) + + self.assertEqual(constants.MULTI_SVM_MODE, mode) + + def test_get_driver_mode_one_invalid_value_in_list_mode_is_not_set(self): + share_driver = self._instantiate_share_driver(None) + share_driver.mode = None + + self.assertRaises( + exception.InvalidParameterValue, + share_driver.get_driver_mode, + ['fake', ]) + + def test_get_driver_mode_one_valid_value_in_list_mode_is_invalid(self): + share_driver = self._instantiate_share_driver(None) + share_driver.mode = 'fake' + + self.assertRaises( + exception.InvalidParameterValue, + share_driver.get_driver_mode, + [constants.MULTI_SVM_MODE, ]) + + def test_get_driver_mode_two_values_in_list_invalid_mode_set(self): + share_driver = self._instantiate_share_driver(None) + share_driver.mode = 'fake' + + self.assertRaises( + exception.InvalidParameterValue, + share_driver.get_driver_mode, + [constants.SINGLE_SVM_MODE, constants.MULTI_SVM_MODE, ])