This commit adds is_working method to base Manager class that can be
used to indicate that service has some problems and isn't running
correctly. This is used to block refreshing Service heartbeats if
Manager will return False from is_working.
The method is implemented in c-vol Manager to return initialization
state of the underlying volume driver.
Closes-Bug:
1446750
DocImpact
Change-Id: I809b2b777a0f84d12f39f2233920ec961f74f846
config[key] = CONF.get(key, None)
return config
+ def is_working(self):
+ """Method indicating if service is working correctly.
+
+ This method is supposed to be overriden by subclasses and return if
+ manager is working correctly.
+ """
+ return True
+
class SchedulerDependentManager(Manager):
"""Periodically send capability updates to the Scheduler services.
def report_state(self):
"""Update the state of this service in the datastore."""
+ if not self.manager.is_working():
+ # NOTE(dulek): If manager reports a problem we're not sending
+ # heartbeats - to indicate that service is actually down.
+ LOG.error(_LE('Manager for service %s is reporting problems, skip '
+ 'sending heartbeat. Service will appear "down".'),
+ self.binary)
+ return
+
ctxt = context.get_admin_context()
zone = CONF.storage_availability_zone
state_catalog = {}
serv.start()
serv.report_state()
self.assertTrue(serv.model_disconnected)
+ self.assertFalse(mock_db.service_update.called)
def test_report_state_newly_connected(self):
host = 'foo'
serv.report_state()
self.assertFalse(serv.model_disconnected)
+ self.assertTrue(mock_db.service_update.called)
+
+ def test_report_state_manager_not_working(self):
+ host = 'foo'
+ binary = 'bar'
+ topic = 'test'
+ service_ref = {'host': host,
+ 'binary': binary,
+ 'topic': topic,
+ 'report_count': 0,
+ 'availability_zone': 'nova',
+ 'id': 1}
+ with mock.patch.object(service, 'db') as mock_db:
+ mock_db.service_get.return_value = service_ref
+
+ serv = service.Service(
+ host,
+ binary,
+ topic,
+ 'cinder.tests.unit.test_service.FakeManager'
+ )
+ serv.manager.is_working = mock.Mock(return_value=False)
+ serv.start()
+ serv.report_state()
+
+ serv.manager.is_working.assert_called_once_with()
+ self.assertFalse(mock_db.service_update.called)
def test_service_with_long_report_interval(self):
self.override_config('service_down_time', 10)
manager.init_host()
self.assertEqual(0, mock_add_p_task.call_count)
+ def test_is_working(self):
+ # By default we have driver mocked to be initialized...
+ self.assertTrue(self.volume.is_working())
+
+ # ...lets switch it and check again!
+ self.volume.driver._initialized = False
+ self.assertFalse(self.volume.is_working())
+
def test_create_volume_fails_with_creating_and_downloading_status(self):
"""Test init_host in case of volume.
resource={'type': 'driver',
'id': self.driver.__class__.__name__})
+ def is_working(self):
+ """Return if Manager is ready to accept requests.
+
+ This is to inform Service class that in case of volume driver
+ initialization failure the manager is actually down and not ready to
+ accept any requests.
+ """
+ return self.driver.initialized
+
def create_volume(self, context, volume_id, request_spec=None,
filter_properties=None, allow_reschedule=True,
snapshot_id=None, image_id=None, source_volid=None,