Update EMC Manila driver framework using stevedore

Alternative way of registering plugins in EMC Manila driver framework
using the module *stevedore*.

Change-Id: I3c38a2dbc9575a81c83e64180cd37916abe68334
Implements: blueprint register-emc-manila-plugin-with-stevedore
This commit is contained in:
Jay Xu 2014-12-10 01:01:31 -05:00
parent 5433fdafc7
commit e8709c8005
6 changed files with 60 additions and 53 deletions

View File

@ -24,10 +24,7 @@ from oslo.config import cfg
from manila.openstack.common import log from manila.openstack.common import log
from manila.share import driver from manila.share import driver
from manila.share.drivers.emc.plugins import \ from manila.share.drivers.emc import plugin_manager as manager
registry as emc_plugins_registry
# TODO(jay.xu): Implement usage of stevedore for plugins.
from manila.share.drivers.emc.plugins.vnx import connection # noqa
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
@ -71,50 +68,53 @@ class EMCShareDriver(driver.ShareDriver):
if self.configuration: if self.configuration:
self.configuration.append_config_values(EMC_NAS_OPTS) self.configuration.append_config_values(EMC_NAS_OPTS)
self._storage_conn = None self.plugin_manager = manager.EMCPluginManager(
namespace='manila.share.drivers.emc.plugins')
self.plugin = None
def create_share(self, context, share, share_server=None): def create_share(self, context, share, share_server=None):
"""Is called to create share.""" """Is called to create share."""
location = self._storage_conn.create_share(self, context, share, location = self.plugin.create_share(self, context, share,
share_server) share_server)
return location return location
def create_share_from_snapshot(self, context, share, snapshot, def create_share_from_snapshot(self, context, share, snapshot,
share_server=None): share_server=None):
"""Is called to create share from snapshot.""" """Is called to create share from snapshot."""
location = self._storage_conn.create_share_from_snapshot( location = self.plugin.create_share_from_snapshot(
self, context, share, snapshot, share_server) self, context, share, snapshot, share_server)
return location return location
def create_snapshot(self, context, snapshot, share_server=None): def create_snapshot(self, context, snapshot, share_server=None):
"""Is called to create snapshot.""" """Is called to create snapshot."""
self._storage_conn.create_snapshot(self, context, snapshot, self.plugin.create_snapshot(self, context, snapshot,
share_server) share_server)
def delete_share(self, context, share, share_server=None): def delete_share(self, context, share, share_server=None):
"""Is called to remove share.""" """Is called to remove share."""
self._storage_conn.delete_share(self, context, share, share_server) self.plugin.delete_share(self, context, share, share_server)
def delete_snapshot(self, context, snapshot, share_server=None): def delete_snapshot(self, context, snapshot, share_server=None):
"""Is called to remove snapshot.""" """Is called to remove snapshot."""
self._storage_conn.delete_snapshot(self, context, snapshot, self.plugin.delete_snapshot(self, context, snapshot,
share_server) share_server)
def ensure_share(self, context, share, share_server=None): def ensure_share(self, context, share, share_server=None):
"""Invoked to sure that share is exported.""" """Invoked to sure that share is exported."""
self._storage_conn.ensure_share(self, context, share, share_server) self.plugin.ensure_share(self, context, share, share_server)
def allow_access(self, context, share, access, share_server=None): def allow_access(self, context, share, access, share_server=None):
"""Allow access to the share.""" """Allow access to the share."""
self._storage_conn.allow_access(self, context, share, access, self.plugin.allow_access(self, context, share, access,
share_server) share_server)
def deny_access(self, context, share, access, share_server=None): def deny_access(self, context, share, access, share_server=None):
"""Deny access to the share.""" """Deny access to the share."""
self._storage_conn.deny_access(self, context, share, access, self.plugin.deny_access(self, context, share, access,
share_server) share_server)
def check_for_setup_error(self): def check_for_setup_error(self):
"""Check for setup error.""" """Check for setup error."""
@ -122,9 +122,11 @@ class EMCShareDriver(driver.ShareDriver):
def do_setup(self, context): def do_setup(self, context):
"""Any initialization the share driver does while starting.""" """Any initialization the share driver does while starting."""
self._storage_conn = emc_plugins_registry.create_storage_connection( backend_name = self.configuration.safe_get('emc_share_backend')
self.configuration.safe_get('emc_share_backend'), LOG)
self._storage_conn.connect(self, context) self.plugin = self.plugin_manager.load_plugin(backend_name, LOG)
self.plugin.connect(self, context)
def get_share_stats(self, refresh=False): def get_share_stats(self, refresh=False):
"""Get share stats. """Get share stats.
@ -152,19 +154,19 @@ class EMCShareDriver(driver.ShareDriver):
data['free_capacity_gb'] = 'infinite' data['free_capacity_gb'] = 'infinite'
data['reserved_percentage'] = 0 data['reserved_percentage'] = 0
data['QoS_support'] = False data['QoS_support'] = False
self._storage_conn.update_share_stats(data) self.plugin.update_share_stats(data)
self._stats = data self._stats = data
def get_network_allocations_number(self): def get_network_allocations_number(self):
"""Returns number of network allocations for creating VIFs.""" """Returns number of network allocations for creating VIFs."""
return self._storage_conn.get_network_allocations_number(self) return self.plugin.get_network_allocations_number(self)
def setup_server(self, network_info, metadata=None): def setup_server(self, network_info, metadata=None):
"""Set up and configures share server with given network parameters.""" """Set up and configures share server with given network parameters."""
return self._storage_conn.setup_server(self, network_info, metadata) return self.plugin.setup_server(self, network_info, metadata)
def teardown_server(self, server_details, security_services=None): def teardown_server(self, server_details, security_services=None):
"""Teardown share server.""" """Teardown share server."""
return self._storage_conn.teardown_server(self, return self.plugin.teardown_server(self,
server_details, server_details,
security_services) security_services)

View File

@ -12,20 +12,20 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
"""EMC Share Driver Plugin Framework.""" """EMC Share Driver Plugin Framework."""
from stevedore import extension
g_registered_storage_backends = {}
def register_storage_backend(share_backend_name, storage_conn_class): class EMCPluginManager(object):
"""register a backend storage plugins.""" def __init__(self, namespace):
g_registered_storage_backends[ self.namespace = namespace
share_backend_name.upper()] = storage_conn_class
self.extension_manager = extension.ExtensionManager(namespace)
def create_storage_connection(share_backend_name, logger): def load_plugin(self, name, logger=None):
"""create an instance of plugins.""" for ext in self.extension_manager.extensions:
storage_conn_class = g_registered_storage_backends[ if ext.name == name:
share_backend_name.upper()] storage_conn = ext.plugin(logger)
return storage_conn_class(logger) return storage_conn
return None

View File

@ -24,7 +24,6 @@ from manila.i18n import _LE
from manila.i18n import _LW from manila.i18n import _LW
from manila.openstack.common import log from manila.openstack.common import log
from manila.share.drivers.emc.plugins import base as driver from manila.share.drivers.emc.plugins import base as driver
from manila.share.drivers.emc.plugins import registry
from manila.share.drivers.emc.plugins.vnx import constants from manila.share.drivers.emc.plugins.vnx import constants
from manila.share.drivers.emc.plugins.vnx import helper from manila.share.drivers.emc.plugins.vnx import helper
from manila.share.drivers.emc.plugins.vnx import utils as vnx_utils from manila.share.drivers.emc.plugins.vnx import utils as vnx_utils
@ -918,6 +917,3 @@ class VNXStorageConnection(driver.StorageConnection):
msg = _("Only single security service with " msg = _("Only single security service with "
"type 'active_directory' supported") "type 'active_directory' supported")
raise exception.EMCVnxXMLAPIError(err=msg) raise exception.EMCVnxXMLAPIError(err=msg)
registry.register_storage_backend("vnx", VNXStorageConnection)

View File

@ -14,13 +14,12 @@
# under the License. # under the License.
import mock import mock
from stevedore import extension
from manila.openstack.common import log as logging from manila.openstack.common import log as logging
from manila.share import configuration as conf from manila.share import configuration as conf
from manila.share.drivers.emc import driver as emcdriver from manila.share.drivers.emc import driver as emcdriver
from manila.share.drivers.emc.plugins import base from manila.share.drivers.emc.plugins import base
from manila.share.drivers.emc.plugins import \
registry as emc_plugins_registry
from manila import test from manila import test
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -89,8 +88,20 @@ class FakeConnection(base.StorageConnection):
FAKE_BACKEND = 'fake_backend' FAKE_BACKEND = 'fake_backend'
class FakeEMCExtensionManager():
def __init__(self):
self.extensions = []
self.extensions.append(
extension.Extension(name=FAKE_BACKEND,
plugin=FakeConnection,
entry_point=None,
obj=None))
class EMCShareFrameworkTestCase(test.TestCase): class EMCShareFrameworkTestCase(test.TestCase):
@mock.patch('stevedore.extension.ExtensionManager',
mock.Mock(return_value=FakeEMCExtensionManager()))
def setUp(self): def setUp(self):
super(EMCShareFrameworkTestCase, self).setUp() super(EMCShareFrameworkTestCase, self).setUp()
self.configuration = conf.Configuration(None) self.configuration = conf.Configuration(None)
@ -101,18 +112,15 @@ class EMCShareFrameworkTestCase(test.TestCase):
configuration=self.configuration) configuration=self.configuration)
def test_driver_setup(self): def test_driver_setup(self):
emc_plugins_registry.register_storage_backend(
FAKE_BACKEND, FakeConnection)
FakeConnection.connect = mock.Mock() FakeConnection.connect = mock.Mock()
self.driver.do_setup(None) self.driver.do_setup(None)
self.assertIsInstance(self.driver._storage_conn, FakeConnection, self.assertIsInstance(self.driver.plugin, FakeConnection,
"Not an instance of FakeConnection") "Not an instance of FakeConnection")
FakeConnection.connect.assert_called_with(self.driver, None) FakeConnection.connect.assert_called_with(self.driver, None)
def test_update_share_stats(self): def test_update_share_stats(self):
data = {} data = {}
self.driver._storage_conn = mock.Mock() self.driver.plugin = mock.Mock()
self.driver._update_share_stats() self.driver._update_share_stats()
data["share_backend_name"] = FAKE_BACKEND data["share_backend_name"] = FAKE_BACKEND
data["vendor_name"] = 'EMC' data["vendor_name"] = 'EMC'
@ -122,8 +130,7 @@ class EMCShareFrameworkTestCase(test.TestCase):
data['free_capacity_gb'] = 'infinite' data['free_capacity_gb'] = 'infinite'
data['reserved_percentage'] = 0 data['reserved_percentage'] = 0
data['QoS_support'] = False data['QoS_support'] = False
self.driver._storage_conn.\ self.driver.plugin.update_share_stats.assert_called_with(data)
update_share_stats.assert_called_with(data)
def _fake_safe_get(self, value): def _fake_safe_get(self, value):
if value in ['emc_share_backend', 'share_backend_name']: if value in ['emc_share_backend', 'share_backend_name']:

View File

@ -1201,7 +1201,7 @@ class EMCShareDriverVNXTestCase(test.TestCase):
] ]
helper.XMLAPIConnector.request.assert_has_calls(expected_calls) helper.XMLAPIConnector.request.assert_has_calls(expected_calls)
helper.XMLAPIConnector.do_setup.assert_called_once_with() helper.XMLAPIConnector.do_setup.assert_called_once_with()
pool_id = self.driver._storage_conn._pool['id'] pool_id = self.driver.plugin._pool['id']
self.assertEqual(pool_id, TD.storage_pool_id_default, self.assertEqual(pool_id, TD.storage_pool_id_default,
"Storage pool id parse error") "Storage pool id parse error")

View File

@ -52,6 +52,8 @@ oslo.messaging.notify.drivers =
manila.openstack.common.notifier.test_notifier = oslo.messaging.notify._impl_test:TestDriver manila.openstack.common.notifier.test_notifier = oslo.messaging.notify._impl_test:TestDriver
oslo.config.opts = oslo.config.opts =
manila = manila.opts:list_opts manila = manila.opts:list_opts
manila.share.drivers.emc.plugins =
vnx = manila.share.drivers.emc.plugins.vnx.connection:VNXStorageConnection
[build_sphinx] [build_sphinx]
all_files = 1 all_files = 1