Don't send heartbeats if driver not initializing correctly

This commit adds is_service_ready method to base Manager class that can be
used to indicate that service is not ready or initialzed success. This is
used to block refreshing Service heartbeats if manager will return false
from is_service_ready.

Closes-Bug:#1853940

Change-Id: Ib85468c703dfa51b03d1838bd422c9b2669bc747
This commit is contained in:
haixin 2019-12-09 03:48:48 -05:00
parent 572be43bb0
commit 37a9e5388d
6 changed files with 51 additions and 0 deletions

View File

@ -115,6 +115,15 @@ class Manager(base.Base, PeriodicTasks):
config[key] = CONF.get(key, None)
return config
def is_service_ready(self):
"""Method indicating if service is ready.
This method should be overridden by subclasses which will return False
when the back end is not ready yet.
"""
return True
class SchedulerDependentManager(Manager):
"""Periodically send capability updates to the Scheduler services.

View File

@ -245,6 +245,14 @@ class Service(service.Service):
def report_state(self):
"""Update the state of this service in the datastore."""
if not self.manager.is_service_ready():
# NOTE(haixin): If the service is still initializing or failed to
# intialize.
LOG.error('Manager for service %s is not ready yet, skipping state'
' update routine. Service will appear "down".',
self.binary)
return
ctxt = context.get_admin_context()
state_catalog = {}
try:

View File

@ -331,6 +331,16 @@ class ShareManager(manager.SchedulerDependentManager):
{"driver": self.driver.__class__.__name__,
"host": self.host})
def is_service_ready(self):
"""Return if Manager is ready to accept requests.
This is to inform Service class that in case of manila driver
initialization failure the manager is actually down and not ready to
accept any requests.
"""
return self.driver.initialized
def ensure_driver_resources(self, ctxt):
old_backend_info = self.db.backend_info_get(ctxt, self.host)
old_backend_info_hash = (old_backend_info.get('info_hash')

View File

@ -174,6 +174,13 @@ class ShareManagerTestCase(test.TestCase):
context=self.context,
periodic_hook_data=hook_data_mock.return_value)
def test_is_service_ready(self):
self.assertTrue(self.share_manager.is_service_ready())
# switch it to false and check again
self.share_manager.driver.initialized = False
self.assertFalse(self.share_manager.is_service_ready())
def test_init_host_with_no_shares(self):
self.mock_object(self.share_manager.db,
'share_instances_get_all_by_host',

View File

@ -199,6 +199,17 @@ class ServiceTestCase(test.TestCase):
service.db.service_update.assert_called_once_with(
mock.ANY, service_ref['id'], mock.ANY)
def test_report_state_service_not_ready(self):
with mock.patch.object(service, 'db') as mock_db:
mock_db.service_get.return_value = service_ref
serv = service.Service(host, binary, topic, CONF.fake_manager)
serv.manager.is_service_ready = mock.Mock(return_value=False)
serv.start()
serv.report_state()
serv.manager.is_service_ready.assert_called_once()
mock_db.service_update.assert_not_called()
class TestWSGIService(test.TestCase):

View File

@ -0,0 +1,6 @@
---
fixes:
- |
This bug fix avoids request failures while drivers are still initializing
or when they fail to initialize by reporting the share service as down
until the driver has been initialized.