Merge "Support 'shelve' and 'reboot' instance notifications"
This commit is contained in:
commit
ae09e6ae39
|
@ -43,6 +43,25 @@ class InstanceHandler(base.NotificationBase):
|
|||
_provisioning_states = {'networking': None,
|
||||
'block_device_mapping': 'networking',
|
||||
'spawning': 'block_device_mapping'}
|
||||
_reboot_states = {
|
||||
# Hard reboot
|
||||
'reboot_pending_hard': 'rebooting_hard',
|
||||
'reboot_started_hard': 'reboot_pending_hard',
|
||||
# Soft reboot
|
||||
'reboot_pending': 'rebooting',
|
||||
'reboot_started': 'reboot_pending',
|
||||
}
|
||||
_shelve_states = {
|
||||
'shelving_image_pending_upload': 'shelving',
|
||||
'shelving_image_uploading': 'shelving_image_pending_upload',
|
||||
# shelving_image_uploading -> shelving_image_pending_upload and
|
||||
# shelving_image_pending_upload -> shelving_image_uploading will
|
||||
# be ignored.
|
||||
'shelving_offloading': 'shelving_image_uploading',
|
||||
}
|
||||
_unshelve_states = {
|
||||
'spawning': 'unshelving'
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def _get_notification_exchanges(cls):
|
||||
|
@ -68,8 +87,13 @@ class InstanceHandler(base.NotificationBase):
|
|||
'compute.instance.unpause.end': self.index_from_api,
|
||||
|
||||
'compute.instance.shutdown.end': self.index_from_api,
|
||||
'compute.instance.reboot.end': self.index_from_api,
|
||||
'compute.instance.delete.end': self.delete,
|
||||
|
||||
'compute.instance.shelve.end': self.index_from_api,
|
||||
'compute.instance.shelve_offload.end': self.index_from_api,
|
||||
'compute.instance.unshelve.end': self.index_from_api,
|
||||
|
||||
'compute.instance.volume.attach': self.index_from_api,
|
||||
'compute.instance.volume.detach': self.index_from_api,
|
||||
|
||||
|
@ -127,13 +151,43 @@ class InstanceHandler(base.NotificationBase):
|
|||
# and indicates the end of the init sequence; ignore this one in
|
||||
# favor of create.end
|
||||
ignore_update = True
|
||||
elif (new_state == 'active' and
|
||||
new_task_state is None and old_task_state is None):
|
||||
ignore_update = True
|
||||
elif new_task_state is None and old_task_state is not None:
|
||||
# These happen right before a corresponding .end event
|
||||
ignore_update = True
|
||||
elif new_task_state is not None and new_task_state == old_task_state:
|
||||
# Ignore spawning -> spawning for shelved_offloaded instance and
|
||||
# shelving_offloading -> shelving_offloading for shelved instance.
|
||||
if (new_task_state == 'shelving_offloading' or
|
||||
(new_state == 'shelved_offloaded' and
|
||||
new_task_state == 'spawning')):
|
||||
ignore_update = True
|
||||
else:
|
||||
update_if_state_matches = dict(
|
||||
state=new_state,
|
||||
new_task_state=None)
|
||||
elif new_task_state in self._reboot_states:
|
||||
update_if_state_matches = dict(
|
||||
state=new_state,
|
||||
new_task_state=self._reboot_states[new_task_state])
|
||||
elif new_task_state in self._shelve_states:
|
||||
if (new_state == 'active' or
|
||||
(new_state == 'shelved' and
|
||||
new_task_state == 'shelving_offloading')):
|
||||
update_if_state_matches = dict(
|
||||
state='active',
|
||||
new_task_state=self._shelve_states[new_task_state])
|
||||
elif new_state == 'shelved_offloaded':
|
||||
if new_task_state is not None:
|
||||
update_if_state_matches = dict(
|
||||
state=new_state,
|
||||
new_task_state=self._unshelve_states[new_task_state])
|
||||
else:
|
||||
update_if_state_matches = dict(
|
||||
state='shelved',
|
||||
new_task_state='shelving_offloading')
|
||||
|
||||
if ignore_update:
|
||||
LOG.debug("Skipping update or indexing for %s; event contains no "
|
||||
|
|
|
@ -977,3 +977,316 @@ class TestServerLoaderPlugin(test_utils.BaseTestCase):
|
|||
"compute.instance.pause.end",
|
||||
expect_handled=False)
|
||||
assert_call_counts(get=1, save=1, es_gets=1)
|
||||
|
||||
@mock.patch(nova_version_getter, return_value=fake_version_list)
|
||||
def test_reboot_state_change_notifications(self, mock_version):
|
||||
mock_engine = mock.Mock()
|
||||
self.plugin.engine = mock_engine
|
||||
|
||||
reboot_events = [
|
||||
('compute.instance.update',
|
||||
dict(state_description='rebooting', state='active',
|
||||
old_task_state='rebooting', new_task_state='rebooting'),
|
||||
'2016-07-17 19:52:13.523135'),
|
||||
('compute.instance.reboot.start',
|
||||
dict(state_description='rebooting', state='active'),
|
||||
'2016-07-17 19:52:13.628180'),
|
||||
('compute.instance.update',
|
||||
dict(state_description='', state='active',
|
||||
old_task_state='rebooting', new_task_state='reboot_pending'),
|
||||
'2016-07-17 19:52:13.771604'),
|
||||
('compute.instance.update',
|
||||
dict(state_description='', state='active',
|
||||
old_task_state='reboot_pending',
|
||||
new_task_state='reboot_started'),
|
||||
'2016-07-17 19:52:13.781605'),
|
||||
('compute.instance.update',
|
||||
dict(state_description='', state='active',
|
||||
old_task_state='reboot_started', new_task_state=None),
|
||||
'2016-07-17 19:52:13.791605'),
|
||||
('compute.instance.reboot.end',
|
||||
dict(state_description='', state='active'),
|
||||
'2016-07-17 19:52:13.808362')
|
||||
]
|
||||
|
||||
for event in reboot_events:
|
||||
event[1]["instance_id"] = u"a380287d-1f61-4887-959c-8c5ab8f75f8f"
|
||||
|
||||
handler = self.plugin.get_notification_handler()
|
||||
event_handlers = handler.get_event_handlers()
|
||||
|
||||
def handle_message(message, expected_event_type, expect_handled=True):
|
||||
self.assertEqual(expected_event_type, message[0],
|
||||
"Expected event type doesn't match test "
|
||||
"message type.")
|
||||
# type, payload, timestamp
|
||||
type_handler = event_handlers.get(message[0], None)
|
||||
if type_handler:
|
||||
type_handler(message[1], message[2])
|
||||
else:
|
||||
if expect_handled:
|
||||
self.fail("Expected event '%s' to be handled" %
|
||||
expected_event_type)
|
||||
|
||||
with mock.patch.object(self.plugin.index_helper,
|
||||
'save_documents') as mock_save, \
|
||||
mock.patch.object(self.plugin.index_helper,
|
||||
'get_document') as mock_es_getter, \
|
||||
mock.patch(nova_server_getter,
|
||||
return_value=self.instance1) as nova_getter:
|
||||
|
||||
def assert_call_counts(get=0, save=0, es_gets=0):
|
||||
# Helper to reduce copy pasta
|
||||
self.assertEqual(get, nova_getter.call_count)
|
||||
self.assertEqual(save, mock_save.call_count)
|
||||
self.assertEqual(es_gets, mock_es_getter.call_count)
|
||||
|
||||
handle_message(reboot_events[0],
|
||||
"compute.instance.update")
|
||||
assert_call_counts(get=0, save=0, es_gets=1)
|
||||
|
||||
handle_message(reboot_events[1],
|
||||
"compute.instance.reboot.start",
|
||||
expect_handled=False)
|
||||
assert_call_counts(get=0, save=0, es_gets=1)
|
||||
|
||||
handle_message(reboot_events[2],
|
||||
"compute.instance.update")
|
||||
assert_call_counts(get=0, save=0, es_gets=2)
|
||||
|
||||
handle_message(reboot_events[3],
|
||||
"compute.instance.update")
|
||||
assert_call_counts(get=0, save=0, es_gets=3)
|
||||
|
||||
handle_message(reboot_events[4],
|
||||
"compute.instance.update")
|
||||
assert_call_counts(get=0, save=0, es_gets=3)
|
||||
|
||||
handle_message(reboot_events[5],
|
||||
"compute.instance.reboot.end",
|
||||
expect_handled=False)
|
||||
assert_call_counts(get=1, save=1, es_gets=3)
|
||||
|
||||
@mock.patch(nova_version_getter, return_value=fake_version_list)
|
||||
def test_shelve_state_change_notifications(self, mock_version):
|
||||
mock_engine = mock.Mock()
|
||||
self.plugin.engine = mock_engine
|
||||
|
||||
shelve_events = [
|
||||
('compute.instance.update',
|
||||
dict(state_description='shelving', state='active',
|
||||
old_task_state='shelving', new_task_state='shelving'),
|
||||
'2016-07-17 19:52:13.523135'),
|
||||
('compute.instance.shelve.start',
|
||||
dict(state_description='shelving', state='active'),
|
||||
'2016-07-17 19:52:13.628180'),
|
||||
('compute.instance.update',
|
||||
dict(state_description='', state='active',
|
||||
old_task_state='shelving',
|
||||
new_task_state='shelving_image_pending_upload'),
|
||||
'2016-07-17 19:52:13.771604'),
|
||||
('compute.instance.update',
|
||||
dict(state_description='', state='active',
|
||||
old_task_state='shelving_image_pending_upload',
|
||||
new_task_state='shelving_image_uploading'),
|
||||
'2016-07-17 19:52:13.781605'),
|
||||
('compute.instance.update',
|
||||
dict(state_description='', state='active',
|
||||
old_task_state='shelving_image_uploading',
|
||||
new_task_state='shelving_image_pending_upload'),
|
||||
'2016-07-17 19:52:13.791605'),
|
||||
('compute.instance.update',
|
||||
dict(state_description='', state='active',
|
||||
old_task_state='shelving_image_pending_upload',
|
||||
new_task_state='shelving_image_uploading'),
|
||||
'2016-07-17 19:52:13.801605'),
|
||||
('compute.instance.update',
|
||||
dict(state_description='', state='shelved',
|
||||
old_task_state='shelving_image_uploading',
|
||||
new_task_state='shelving_offloading'),
|
||||
'2016-07-17 19:52:13.811605'),
|
||||
('compute.instance.update',
|
||||
dict(state_description='', state='shelved',
|
||||
old_task_state='shelving_offloading',
|
||||
new_task_state='shelving_offloading'),
|
||||
'2016-07-17 19:52:13.821605'),
|
||||
('compute.instance.update',
|
||||
dict(state_description='', state='shelved_offloaded',
|
||||
old_task_state='shelving_offloading',
|
||||
new_task_state=None),
|
||||
'2016-07-17 19:52:13.831605'),
|
||||
('compute.instance.shelve.end',
|
||||
dict(state_description='', state='active'),
|
||||
'2016-07-17 19:52:13.858362')
|
||||
]
|
||||
|
||||
for event in shelve_events:
|
||||
event[1]["instance_id"] = u"a380287d-1f61-4887-959c-8c5ab8f75f8f"
|
||||
|
||||
handler = self.plugin.get_notification_handler()
|
||||
event_handlers = handler.get_event_handlers()
|
||||
|
||||
def handle_message(message, expected_event_type, expect_handled=True):
|
||||
self.assertEqual(expected_event_type, message[0],
|
||||
"Expected event type doesn't match test "
|
||||
"message type.")
|
||||
# type, payload, timestamp
|
||||
type_handler = event_handlers.get(message[0], None)
|
||||
if type_handler:
|
||||
type_handler(message[1], message[2])
|
||||
else:
|
||||
if expect_handled:
|
||||
self.fail("Expected event '%s' to be handled" %
|
||||
expected_event_type)
|
||||
|
||||
with mock.patch.object(self.plugin.index_helper,
|
||||
'save_documents') as mock_save, \
|
||||
mock.patch.object(self.plugin.index_helper,
|
||||
'get_document') as mock_es_getter, \
|
||||
mock.patch(nova_server_getter,
|
||||
return_value=self.instance1) as nova_getter:
|
||||
|
||||
def assert_call_counts(get=0, save=0, es_gets=0):
|
||||
# Helper to reduce copy pasta
|
||||
self.assertEqual(get, nova_getter.call_count)
|
||||
self.assertEqual(save, mock_save.call_count)
|
||||
self.assertEqual(es_gets, mock_es_getter.call_count)
|
||||
|
||||
handle_message(shelve_events[0],
|
||||
"compute.instance.update")
|
||||
assert_call_counts(get=0, save=0, es_gets=1)
|
||||
|
||||
handle_message(shelve_events[1],
|
||||
"compute.instance.shelve.start",
|
||||
expect_handled=False)
|
||||
assert_call_counts(get=0, save=0, es_gets=1)
|
||||
|
||||
handle_message(shelve_events[2],
|
||||
"compute.instance.update")
|
||||
assert_call_counts(get=0, save=0, es_gets=2)
|
||||
|
||||
handle_message(shelve_events[3],
|
||||
"compute.instance.update")
|
||||
assert_call_counts(get=0, save=0, es_gets=3)
|
||||
|
||||
handle_message(shelve_events[4],
|
||||
"compute.instance.update")
|
||||
assert_call_counts(get=0, save=0, es_gets=4)
|
||||
|
||||
handle_message(shelve_events[5],
|
||||
"compute.instance.update")
|
||||
assert_call_counts(get=0, save=0, es_gets=5)
|
||||
|
||||
handle_message(shelve_events[6],
|
||||
"compute.instance.update")
|
||||
assert_call_counts(get=0, save=0, es_gets=6)
|
||||
|
||||
handle_message(shelve_events[7],
|
||||
"compute.instance.update")
|
||||
assert_call_counts(get=0, save=0, es_gets=6)
|
||||
|
||||
handle_message(shelve_events[8],
|
||||
"compute.instance.update")
|
||||
assert_call_counts(get=0, save=0, es_gets=6)
|
||||
|
||||
handle_message(shelve_events[9],
|
||||
"compute.instance.shelve.end",
|
||||
expect_handled=False)
|
||||
assert_call_counts(get=1, save=1, es_gets=6)
|
||||
|
||||
@mock.patch(nova_version_getter, return_value=fake_version_list)
|
||||
def test_unshelve_state_change_notifications(self, mock_version):
|
||||
mock_engine = mock.Mock()
|
||||
self.plugin.engine = mock_engine
|
||||
|
||||
unshelve_events = [
|
||||
('compute.instance.update',
|
||||
dict(state_description='unshelving', state='shelved_offloaded',
|
||||
old_task_state='unshelving', new_task_state='unshelving'),
|
||||
'2016-07-17 19:52:13.523135'),
|
||||
('compute.instance.unshelve.start',
|
||||
dict(state_description='unshelving', state='shelved_offloaded'),
|
||||
'2016-07-17 19:52:13.628180'),
|
||||
('compute.instance.update',
|
||||
dict(state_description='', state='shelved_offloaded',
|
||||
old_task_state='unshelving', new_task_state='unshelving'),
|
||||
'2016-07-17 19:52:13.771604'),
|
||||
('compute.instance.update',
|
||||
dict(state_description='', state='shelved_offloaded',
|
||||
old_task_state='unshelving',
|
||||
new_task_state='spawning'),
|
||||
'2016-07-17 19:52:13.781605'),
|
||||
('compute.instance.update',
|
||||
dict(state_description='', state='shelved_offloaded',
|
||||
old_task_state='spawning', new_task_state='spawning'),
|
||||
'2016-07-17 19:52:13.791605'),
|
||||
('compute.instance.update',
|
||||
dict(state_description='', state='active',
|
||||
old_task_state='spawning', new_task_state=None),
|
||||
'2016-07-17 19:52:13.801605'),
|
||||
('compute.instance.unshelve.end',
|
||||
dict(state_description='', state='active'),
|
||||
'2016-07-17 19:52:13.818362')
|
||||
]
|
||||
|
||||
for event in unshelve_events:
|
||||
event[1]["instance_id"] = u"a380287d-1f61-4887-959c-8c5ab8f75f8f"
|
||||
|
||||
handler = self.plugin.get_notification_handler()
|
||||
event_handlers = handler.get_event_handlers()
|
||||
|
||||
def handle_message(message, expected_event_type, expect_handled=True):
|
||||
self.assertEqual(expected_event_type, message[0],
|
||||
"Expected event type doesn't match test "
|
||||
"message type.")
|
||||
# type, payload, timestamp
|
||||
type_handler = event_handlers.get(message[0], None)
|
||||
if type_handler:
|
||||
type_handler(message[1], message[2])
|
||||
else:
|
||||
if expect_handled:
|
||||
self.fail("Expected event '%s' to be handled" %
|
||||
expected_event_type)
|
||||
|
||||
with mock.patch.object(self.plugin.index_helper,
|
||||
'save_documents') as mock_save, \
|
||||
mock.patch.object(self.plugin.index_helper,
|
||||
'get_document') as mock_es_getter, \
|
||||
mock.patch(nova_server_getter,
|
||||
return_value=self.instance1) as nova_getter:
|
||||
|
||||
def assert_call_counts(get=0, save=0, es_gets=0):
|
||||
# Helper to reduce copy pasta
|
||||
self.assertEqual(get, nova_getter.call_count)
|
||||
self.assertEqual(save, mock_save.call_count)
|
||||
self.assertEqual(es_gets, mock_es_getter.call_count)
|
||||
|
||||
handle_message(unshelve_events[0],
|
||||
"compute.instance.update")
|
||||
assert_call_counts(get=0, save=0, es_gets=1)
|
||||
|
||||
handle_message(unshelve_events[1],
|
||||
"compute.instance.unshelve.start",
|
||||
expect_handled=False)
|
||||
assert_call_counts(get=0, save=0, es_gets=1)
|
||||
|
||||
handle_message(unshelve_events[2],
|
||||
"compute.instance.update")
|
||||
assert_call_counts(get=0, save=0, es_gets=2)
|
||||
|
||||
handle_message(unshelve_events[3],
|
||||
"compute.instance.update")
|
||||
assert_call_counts(get=0, save=0, es_gets=3)
|
||||
|
||||
handle_message(unshelve_events[4],
|
||||
"compute.instance.update")
|
||||
assert_call_counts(get=0, save=0, es_gets=3)
|
||||
|
||||
handle_message(unshelve_events[5],
|
||||
"compute.instance.update")
|
||||
assert_call_counts(get=0, save=0, es_gets=3)
|
||||
|
||||
handle_message(unshelve_events[6],
|
||||
"compute.instance.unshelve.end",
|
||||
expect_handled=False)
|
||||
assert_call_counts(get=1, save=1, es_gets=3)
|
||||
|
|
Loading…
Reference in New Issue