From f81383e22a6ff2f936c321a03aeab0c7c3a57816 Mon Sep 17 00:00:00 2001 From: Andrew Melton Date: Fri, 13 Sep 2013 16:31:51 -0400 Subject: [PATCH 1/2] Consuming rescue notifications from Nova for Usage --- stacktach/views.py | 11 +++- tests/unit/test_stacktach.py | 103 +++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 3 deletions(-) diff --git a/stacktach/views.py b/stacktach/views.py index a6699bf..7746946 100644 --- a/stacktach/views.py +++ b/stacktach/views.py @@ -158,6 +158,8 @@ INSTANCE_EVENT = { 'resize_revert_start': 'compute.instance.resize.revert.start', 'resize_revert_end': 'compute.instance.resize.revert.end', 'resize_finish_end': 'compute.instance.finish_resize.end', + 'rescue_start': 'compute.instance.rescue.start', + 'rescue_end': 'compute.instance.rescue.end', 'delete_end': 'compute.instance.delete.end', 'exists': 'compute.instance.exists', } @@ -171,12 +173,14 @@ def _process_usage_for_new_launch(raw, notification): (usage, new) = STACKDB.get_or_create_instance_usage(**values) if raw.event in [INSTANCE_EVENT['create_start'], - INSTANCE_EVENT['rebuild_start']]: + INSTANCE_EVENT['rebuild_start'], + INSTANCE_EVENT['rescue_start']]: usage.instance_type_id = notification.instance_type_id if raw.event in [INSTANCE_EVENT['rebuild_start'], INSTANCE_EVENT['resize_prep_start'], - INSTANCE_EVENT['resize_revert_start']] and\ + INSTANCE_EVENT['resize_revert_start'], + INSTANCE_EVENT['rescue_start']] and\ usage.launched_at is None: # Grab the launched_at so if this action spans the audit period, # we will have a launch record corresponding to the exists. @@ -205,7 +209,8 @@ def _process_usage_for_updates(raw, notification): if raw.event in [INSTANCE_EVENT['create_end'], INSTANCE_EVENT['rebuild_end'], INSTANCE_EVENT['resize_finish_end'], - INSTANCE_EVENT['resize_revert_end']]: + INSTANCE_EVENT['resize_revert_end'], + INSTANCE_EVENT['rescue_end']]: usage.launched_at = utils.str_time_to_unix(notification.launched_at) if raw.event == INSTANCE_EVENT['resize_revert_end']: diff --git a/tests/unit/test_stacktach.py b/tests/unit/test_stacktach.py index b770cd9..e1a9ebf 100644 --- a/tests/unit/test_stacktach.py +++ b/tests/unit/test_stacktach.py @@ -336,6 +336,39 @@ class StacktachUsageParsingTestCase(StacktachBaseTestCase): self.mox.VerifyAll() + def test_process_usage_for_new_launch_rescue_start(self): + notification = self.mox.CreateMockAnything() + notification.launched_at = str(DUMMY_TIME) + notification.tenant = TENANT_ID_1 + notification.rax_options = RAX_OPTIONS_1 + notification.os_architecture = OS_ARCH_1 + notification.os_version = OS_VERSION_1 + notification.os_distro = OS_DISTRO_1 + notification.instance = INSTANCE_ID_1 + notification.request_id = REQUEST_ID_1 + notification.instance_type_id = INSTANCE_TYPE_ID_1 + + raw = self.mox.CreateMockAnything() + raw.event = 'compute.instance.rescue.start' + + usage = self.mox.CreateMockAnything() + views.STACKDB.get_or_create_instance_usage(instance=INSTANCE_ID_1, + request_id=REQUEST_ID_1) \ + .AndReturn((usage, True)) + views.STACKDB.save(usage) + self.mox.ReplayAll() + + views._process_usage_for_new_launch(raw, notification) + + self.assertEquals(usage.instance_type_id, INSTANCE_TYPE_ID_1) + self.assertEquals(usage.tenant, TENANT_ID_1) + self.assertEquals(usage.os_architecture, OS_ARCH_1) + self.assertEquals(usage.os_version, OS_VERSION_1) + self.assertEquals(usage.os_distro, OS_DISTRO_1) + self.assertEquals(usage.rax_options, RAX_OPTIONS_1) + + self.mox.VerifyAll() + def test_process_usage_for_new_launch_rebuild_start(self): notification = self.mox.CreateMockAnything() notification.launched_at = str(DUMMY_TIME) @@ -506,6 +539,41 @@ class StacktachUsageParsingTestCase(StacktachBaseTestCase): self.mox.VerifyAll() + def test_process_usage_for_new_launch_rescue_start_when_launched_at_in_db(self): + notification = self.mox.CreateMockAnything() + notification.launched_at = str(DUMMY_TIME) + notification.tenant = TENANT_ID_1 + notification.rax_options = RAX_OPTIONS_1 + notification.os_architecture = OS_ARCH_1 + notification.os_version = OS_VERSION_1 + notification.os_distro = OS_DISTRO_1 + notification.instance = INSTANCE_ID_1 + notification.request_id = REQUEST_ID_1 + notification.instance_type_id = INSTANCE_TYPE_ID_1 + + raw = self.mox.CreateMockAnything() + raw.event = 'compute.instance.rescue.start' + + orig_launched_at = utils.decimal_utc(DUMMY_TIME - datetime.timedelta(days=1)) + usage = self.mox.CreateMockAnything() + usage.launched_at = orig_launched_at + views.STACKDB.get_or_create_instance_usage(instance=INSTANCE_ID_1, + request_id=REQUEST_ID_1) \ + .AndReturn((usage, True)) + views.STACKDB.save(usage) + self.mox.ReplayAll() + + views._process_usage_for_new_launch(raw, notification) + + self.assertEqual(usage.launched_at, orig_launched_at) + self.assertEqual(usage.tenant, TENANT_ID_1) + self.assertEquals(usage.os_architecture, OS_ARCH_1) + self.assertEquals(usage.os_version, OS_VERSION_1) + self.assertEquals(usage.os_distro, OS_DISTRO_1) + self.assertEquals(usage.rax_options, RAX_OPTIONS_1) + + self.mox.VerifyAll() + def test_process_usage_for_updates_create_end(self): notification = self.mox.CreateMockAnything() notification.launched_at = str(DUMMY_TIME) @@ -541,6 +609,41 @@ class StacktachUsageParsingTestCase(StacktachBaseTestCase): self.mox.VerifyAll() + def test_process_usage_for_updates_rescue_end(self): + notification = self.mox.CreateMockAnything() + notification.launched_at = str(DUMMY_TIME) + notification.tenant = TENANT_ID_1 + notification.rax_options = RAX_OPTIONS_1 + notification.os_architecture = OS_ARCH_1 + notification.os_version = OS_VERSION_1 + notification.os_distro = OS_DISTRO_1 + notification.instance = INSTANCE_ID_1 + notification.request_id = REQUEST_ID_1 + notification.instance_type_id = INSTANCE_TYPE_ID_1 + notification.message = None + + raw = self.mox.CreateMockAnything() + raw.event = 'compute.instance.rescue.end' + + usage = self.mox.CreateMockAnything() + usage.launched_at = None + views.STACKDB.get_or_create_instance_usage(instance=INSTANCE_ID_1, + request_id=REQUEST_ID_1) \ + .AndReturn((usage, True)) + views.STACKDB.save(usage) + self.mox.ReplayAll() + + views._process_usage_for_updates(raw, notification) + + self.assertEqual(usage.launched_at, utils.decimal_utc(DUMMY_TIME)) + self.assertEqual(usage.tenant, TENANT_ID_1) + self.assertEquals(usage.os_architecture, OS_ARCH_1) + self.assertEquals(usage.os_version, OS_VERSION_1) + self.assertEquals(usage.os_distro, OS_DISTRO_1) + self.assertEquals(usage.rax_options, RAX_OPTIONS_1) + + self.mox.VerifyAll() + def test_process_usage_for_updates_create_end_success_message(self): notification = self.mox.CreateMockAnything() notification.launched_at = str(DUMMY_TIME) From 0d1ac8682a6dbaad52bb88cd86df839bc5f85845 Mon Sep 17 00:00:00 2001 From: Andrew Melton Date: Mon, 16 Sep 2013 13:41:04 -0400 Subject: [PATCH 2/2] Mapping rescue events to process functions --- stacktach/views.py | 2 ++ tests/unit/test_stacktach.py | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/stacktach/views.py b/stacktach/views.py index 7746946..1342e46 100644 --- a/stacktach/views.py +++ b/stacktach/views.py @@ -306,11 +306,13 @@ USAGE_PROCESS_MAPPING = { INSTANCE_EVENT['rebuild_start']: _process_usage_for_new_launch, INSTANCE_EVENT['resize_prep_start']: _process_usage_for_new_launch, INSTANCE_EVENT['resize_revert_start']: _process_usage_for_new_launch, + INSTANCE_EVENT['rescue_start']: _process_usage_for_new_launch, INSTANCE_EVENT['create_end']: _process_usage_for_updates, INSTANCE_EVENT['rebuild_end']: _process_usage_for_updates, INSTANCE_EVENT['resize_prep_end']: _process_usage_for_updates, INSTANCE_EVENT['resize_finish_end']: _process_usage_for_updates, INSTANCE_EVENT['resize_revert_end']: _process_usage_for_updates, + INSTANCE_EVENT['rescue_end']: _process_usage_for_updates, INSTANCE_EVENT['delete_end']: _process_delete, INSTANCE_EVENT['exists']: _process_exists } diff --git a/tests/unit/test_stacktach.py b/tests/unit/test_stacktach.py index e1a9ebf..3c8da30 100644 --- a/tests/unit/test_stacktach.py +++ b/tests/unit/test_stacktach.py @@ -303,6 +303,11 @@ class StacktachUsageParsingTestCase(StacktachBaseTestCase): else: stacklog.get_logger(name=name).AndReturn(self.log) + def test_all_instance_events_have_mapping(self): + for key, value in views.INSTANCE_EVENT.items(): + msg = "'%s' does not have a process function mapping." % value + self.assertTrue(value in views.USAGE_PROCESS_MAPPING, msg) + def test_process_usage_for_new_launch_create_start(self): notification = self.mox.CreateMockAnything() notification.launched_at = str(DUMMY_TIME)