Lazy Load Services

When the Manila share service starts, it instantiates
the Neutron network helper, which makes a call to the
Neutron service. If the service is started and the
Neutron service is unaccessible, the share service will
fail to even start.

This patch lazy loads those parameters so that they are
only loaded when needed (and presumably when the Neutron
service is up).

Change-Id: I1857c0cb6fc41afd0d01916addc1fd216070ffd7
Closes-Bug: #1481331
This commit is contained in:
Ryan Hefner 2015-08-24 14:45:54 -04:00
parent 74f09b7379
commit 4f861423a0
4 changed files with 80 additions and 28 deletions

View File

@ -22,6 +22,7 @@ from manila import exception
from manila import network
from manila.network.neutron import api as neutron_api
from manila.network.neutron import constants as neutron_constants
from manila import utils
neutron_single_network_plugin_opts = [
cfg.StrOpt(
@ -50,7 +51,17 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
def __init__(self, *args, **kwargs):
db_driver = kwargs.pop('db_driver', None)
super(NeutronNetworkPlugin, self).__init__(db_driver=db_driver)
self.neutron_api = neutron_api.API(*args, **kwargs)
self._neutron_api = None
self._neutron_api_args = args
self._neutron_api_kwargs = kwargs
@property
@utils.synchronized("instantiate_neutron_api")
def neutron_api(self):
if not self._neutron_api:
self._neutron_api = neutron_api.API(*self._neutron_api_args,
**self._neutron_api_kwargs)
return self._neutron_api
def allocate_network(self, context, share_server, share_network, **kwargs):
"""Allocate network resources using given network information.

View File

@ -216,8 +216,15 @@ class ServiceInstanceManager(object):
if self.get_config_option("driver_handles_share_servers"):
self.path_to_public_key = self.get_config_option(
"path_to_public_key")
self.network_helper = self._get_network_helper()
self.network_helper.setup_connectivity_with_service_instances()
self._network_helper = None
@property
@utils.synchronized("instantiate_network_helper")
def network_helper(self):
if not self._network_helper:
self._network_helper = self._get_network_helper()
self._network_helper.setup_connectivity_with_service_instances()
return self._network_helper
def get_common_server(self):
data = {
@ -630,14 +637,14 @@ class NeutronNetworkHelper(BaseNetworkhelper):
self.get_config_option("interface_driver"))()
if service_instance_manager.driver_config:
network_config_group = (
self._network_config_group = (
service_instance_manager.driver_config.network_config_group or
service_instance_manager.driver_config.config_group)
else:
network_config_group = None
self._network_config_group = None
self.neutron_api = neutron.API(config_group_name=network_config_group)
self.service_network_id = self.get_service_network_id()
self._neutron_api = None
self._service_network_id = None
self.connect_share_server_to_tenant_network = (
self.get_config_option('connect_share_server_to_tenant_network'))
@ -649,13 +656,28 @@ class NeutronNetworkHelper(BaseNetworkhelper):
def admin_project_id(self):
return self.neutron_api.admin_project_id
@property
@utils.synchronized("instantiate_neutron_api_neutron_net_helper")
def neutron_api(self):
if not self._neutron_api:
self._neutron_api = neutron.API(
config_group_name=self._network_config_group)
return self._neutron_api
@property
@utils.synchronized("service_network_id_neutron_net_helper")
def service_network_id(self):
if not self._service_network_id:
self._service_network_id = self._get_service_network_id()
return self._service_network_id
def get_network_name(self, network_info):
"""Returns name of network for service instance."""
net = self.neutron_api.get_network(network_info['neutron_net_id'])
return net['name']
@utils.synchronized("service_instance_get_service_network", external=True)
def get_service_network_id(self):
def _get_service_network_id(self):
"""Finds existing or creates new service network."""
service_network_name = self.get_config_option("service_network_name")
networks = []

View File

@ -200,6 +200,20 @@ class TestCase(base_test.BaseTestCase):
self.addCleanup(patcher.stop)
return new_attr
def mock_class(self, class_name, new_val=None, **kwargs):
"""Use python mock to mock a class
Mocks the specified objects attribute with the given value.
Automatically performs 'addCleanup' for the mock.
"""
if not new_val:
new_val = mock.Mock()
patcher = mock.patch(class_name, new_val, **kwargs)
patcher.start()
self.addCleanup(patcher.stop)
return new_val
# Useful assertions
def assertDictMatch(self, d1, d2, approx_equal=False, tolerance=0.001):
"""Assert two dicts are equivalent.

View File

@ -163,6 +163,7 @@ class ServiceInstanceManagerTestCase(test.TestCase):
service_instance_network_helper_type=service_instance.NOVA_NAME))
with test_utils.create_temp_config_with_opts(config_data):
self._manager = service_instance.ServiceInstanceManager()
self._manager.network_helper
service_instance.NovaNetworkHelper.assert_called_once_with(
self._manager)
self.assertFalse(service_instance.NeutronNetworkHelper.called)
@ -178,6 +179,7 @@ class ServiceInstanceManagerTestCase(test.TestCase):
)
with test_utils.create_temp_config_with_opts(config_data):
self._manager = service_instance.ServiceInstanceManager()
self._manager.network_helper
service_instance.NeutronNetworkHelper.assert_called_once_with(
self._manager)
self.assertFalse(service_instance.NovaNetworkHelper.called)
@ -196,9 +198,9 @@ class ServiceInstanceManagerTestCase(test.TestCase):
driver_handles_share_servers=True,
service_instance_network_helper_type=value))
with test_utils.create_temp_config_with_opts(config_data):
self.assertRaises(
exception.ManilaException,
service_instance.ServiceInstanceManager)
manager = service_instance.ServiceInstanceManager()
self.assertRaises(exception.ManilaException,
lambda: manager.network_helper)
self.assertFalse(service_instance.NeutronNetworkHelper.called)
self.assertFalse(service_instance.NovaNetworkHelper.called)
@ -1266,7 +1268,7 @@ class NeutronNetworkHelperTestCase(test.TestCase):
def _init_neutron_network_plugin(self):
self.mock_object(
service_instance.NeutronNetworkHelper, 'get_service_network_id',
service_instance.NeutronNetworkHelper, '_get_service_network_id',
mock.Mock(return_value='fake_service_network_id'))
return service_instance.NeutronNetworkHelper(self.fake_manager)
@ -1278,7 +1280,7 @@ class NeutronNetworkHelperTestCase(test.TestCase):
'connect_share_server_to_tenant_network', 'get_config_option']
for attr in attrs:
self.assertTrue(hasattr(instance, attr), "No attr '%s'" % attr)
service_instance.NeutronNetworkHelper.get_service_network_id.\
service_instance.NeutronNetworkHelper._get_service_network_id.\
assert_called_once_with()
self.assertEqual('DEFAULT', instance.neutron_api.config_group_name)
@ -1304,7 +1306,7 @@ class NeutronNetworkHelperTestCase(test.TestCase):
def test_admin_project_id(self):
instance = self._init_neutron_network_plugin()
admin_project_id = 'fake_admin_project_id'
instance.neutron_api = mock.Mock()
self.mock_class('manila.network.neutron.api.API', mock.Mock())
instance.neutron_api.admin_project_id = admin_project_id
self.assertEqual(admin_project_id, instance.admin_project_id)
@ -1337,13 +1339,12 @@ class NeutronNetworkHelperTestCase(test.TestCase):
mock.Mock(return_value=network))
instance = service_instance.NeutronNetworkHelper(self.fake_manager)
result = instance.get_service_network_id()
result = instance._get_service_network_id()
self.assertEqual(network['id'], result)
service_instance.neutron.API.get_all_admin_project_networks.\
assert_has_calls([mock.call(), mock.call()])
self.assertTrue(service_instance.neutron.API.
get_all_admin_project_networks.called)
service_instance.neutron.API.network_create.assert_has_calls([
mock.call(instance.admin_project_id, service_network_name),
mock.call(instance.admin_project_id, service_network_name)])
def test_get_service_network_id_one_exist(self):
@ -1358,11 +1359,11 @@ class NeutronNetworkHelperTestCase(test.TestCase):
mock.Mock(return_value=admin_project_id))
instance = service_instance.NeutronNetworkHelper(self.fake_manager)
result = instance.get_service_network_id()
result = instance._get_service_network_id()
self.assertEqual(network['id'], result)
service_instance.neutron.API.get_all_admin_project_networks.\
assert_has_calls([mock.call(), mock.call()])
self.assertTrue(service_instance.neutron.API.
get_all_admin_project_networks.called)
def test_get_service_network_id_two_exist(self):
service_network_name = fake_get_config_option('service_network_name')
@ -1371,9 +1372,9 @@ class NeutronNetworkHelperTestCase(test.TestCase):
service_instance.neutron.API, 'get_all_admin_project_networks',
mock.Mock(return_value=[network, network]))
self.assertRaises(
exception.ServiceInstanceException,
service_instance.NeutronNetworkHelper, self.fake_manager)
helper = service_instance.NeutronNetworkHelper(self.fake_manager)
self.assertRaises(exception.ManilaException,
lambda: helper.service_network_id)
service_instance.neutron.API.get_all_admin_project_networks.\
assert_has_calls([mock.call()])
@ -1599,7 +1600,8 @@ class NeutronNetworkHelperTestCase(test.TestCase):
service_subnet = dict(id='fake_service_subnet')
instance = self._init_neutron_network_plugin()
instance.connect_share_server_to_tenant_network = True
instance.service_network_id = 'fake_service_network_id'
self.mock_object(instance, '_get_service_network_id',
mock.Mock(return_value='fake_service_network_id'))
self.mock_object(
service_instance.neutron.API, 'admin_project_id',
mock.Mock(return_value=admin_project_id))
@ -1647,7 +1649,8 @@ class NeutronNetworkHelperTestCase(test.TestCase):
service_subnet = dict(id='fake_service_subnet')
instance = self._init_neutron_network_plugin()
instance.connect_share_server_to_tenant_network = False
instance.service_network_id = 'fake_service_network_id'
self.mock_object(instance, '_get_service_network_id',
mock.Mock(return_value='fake_service_network_id'))
router = dict(id='fake_router_id')
self.mock_object(
service_instance.neutron.API, 'admin_project_id',
@ -1695,7 +1698,8 @@ class NeutronNetworkHelperTestCase(test.TestCase):
service_subnet = dict(id='fake_service_subnet')
instance = self._init_neutron_network_plugin()
instance.connect_share_server_to_tenant_network = False
instance.service_network_id = 'fake_service_network_id'
self.mock_object(instance, '_get_service_network_id',
mock.Mock(return_value='fake_service_network_id'))
router = dict(id='fake_router_id')
self.mock_object(
instance, '_get_private_router', mock.Mock(return_value=router))
@ -1728,7 +1732,8 @@ class NeutronNetworkHelperTestCase(test.TestCase):
service_subnet = dict(id='fake_service_subnet')
instance = self._init_neutron_network_plugin()
instance.connect_share_server_to_tenant_network = False
instance.service_network_id = 'fake_service_network_id'
self.mock_object(instance, '_get_service_network_id',
mock.Mock(return_value='fake_service_network_id'))
router = dict(id='fake_router_id')
self.mock_object(
service_instance.neutron.API, 'admin_project_id',