diff --git a/stacktach/db.py b/stacktach/db.py index 9d5290b..905ad47 100644 --- a/stacktach/db.py +++ b/stacktach/db.py @@ -18,5 +18,14 @@ def create_request_tracker(**kwargs): def find_request_trackers(**kwargs): return models.RequestTracker.objects.filter(**kwargs) +def create_instance_usage(**kwargs): + return models.InstanceUsage(**kwargs) + +def get_instance_usage(**kwargs): + return models.InstanceUsage.objects.get(**kwargs) + +def create_instance_exists(**kwargs): + return models.InstanceExists(**kwargs) + def save(obj): obj.save() \ No newline at end of file diff --git a/stacktach/views.py b/stacktach/views.py index b53755f..ec9d02c 100644 --- a/stacktach/views.py +++ b/stacktach/views.py @@ -224,8 +224,8 @@ def _process_usage_for_new_launch(raw): if raw.event == INSTANCE_EVENT['create_start']: values['instance_type_id'] = payload['instance_type_id'] - usage = models.InstanceUsage(**values) - usage.save() + usage = STACKDB.create_instance_usage(**values) + STACKDB.save(usage) def _process_usage_for_updates(raw): @@ -233,20 +233,20 @@ def _process_usage_for_updates(raw): payload = notif[1]['payload'] instance_id = payload['instance_id'] request_id = notif[1]['_context_request_id'] - instance = models.InstanceUsage.objects.get(instance=instance_id, - request_id=request_id) + usage = STACKDB.get_instance_usage(instance=instance_id, + request_id=request_id) if raw.event in [INSTANCE_EVENT['create_end'], INSTANCE_EVENT['resize_finish_end'], INSTANCE_EVENT['resize_revert_end']]: - instance.launched_at = str_time_to_unix(payload['launched_at']) + usage.launched_at = str_time_to_unix(payload['launched_at']) if raw.event == INSTANCE_EVENT['resize_revert_end']: - instance.instance_type_id = payload['instance_type_id'] + usage.instance_type_id = payload['instance_type_id'] elif raw.event == INSTANCE_EVENT['resize_prep_end']: - instance.instance_type_id = payload['new_instance_type_id'] + usage.instance_type_id = payload['new_instance_type_id'] - instance.save() + STACKDB.save(usage) def _process_delete(raw): @@ -255,10 +255,10 @@ def _process_delete(raw): instance_id = payload['instance_id'] launched_at = payload['launched_at'] launched_at = str_time_to_unix(launched_at) - instance = models.InstanceUsage.objects.get(instance=instance_id, + instance = STACKDB.get_instance_usage(instance=instance_id, launched_at=launched_at) instance.deleted_at = str_time_to_unix(payload['deleted_at']) - instance.save() + STACKDB.save(instance) def _process_exists(raw): @@ -267,8 +267,8 @@ def _process_exists(raw): instance_id = payload['instance_id'] launched_at = payload['launched_at'] launched_at = str_time_to_unix(launched_at) - usage = models.InstanceUsage.objects.get(instance=instance_id, - launched_at=launched_at) + usage = STACKDB.get_instance_usage(instance=instance_id, + launched_at=launched_at) values = {} values['message_id'] = notif[1]['message_id'] values['instance'] = instance_id @@ -282,8 +282,8 @@ def _process_exists(raw): deleted_at = str_time_to_unix(deleted_at) values['deleted_at'] = deleted_at - exists = models.InstanceExists(**values) - exists.save() + exists = STACKDB.create_instance_exists(**values) + STACKDB.save(exists) USAGE_PROCESS_MAPPING = { diff --git a/tests/unit/test_stacktach.py b/tests/unit/test_stacktach.py index 2d093a1..d3236b8 100644 --- a/tests/unit/test_stacktach.py +++ b/tests/unit/test_stacktach.py @@ -1,4 +1,5 @@ import datetime +import json import os import sys import unittest @@ -42,7 +43,7 @@ class StacktachLifecycleTestCase(unittest.TestCase): def test_start_kpi_tracking(self): lifecycle = self.mox.CreateMockAnything() tracker = self.mox.CreateMockAnything() - when = utils.decimal_utcnow() + when = utils.decimal_utc() raw = utils.create_raw(self.mox, when, 'compute.instance.update', host='api') views.STACKDB.create_request_tracker(lifecycle=lifecycle, @@ -60,24 +61,24 @@ class StacktachLifecycleTestCase(unittest.TestCase): raw = self.mox.CreateMockAnything() raw.request_id = REQUEST_ID_1 views.STACKDB.find_request_trackers(request_id=REQUEST_ID_1)\ - .AndReturn([]) + .AndReturn([]) self.mox.ReplayAll() views.update_kpi(None, raw) self.mox.VerifyAll() def test_update_kpi(self): lifecycle = self.mox.CreateMockAnything() - end = utils.decimal_utcnow() + end = utils.decimal_utc() raw = self.mox.CreateMockAnything() raw.request_id = REQUEST_ID_1 raw.when=end timing = utils.create_timing(self.mox, 'compute.instance.create', lifecycle, end_when=end) - start = utils.decimal_utcnow() + start = utils.decimal_utc() tracker = utils.create_tracker(self.mox, REQUEST_ID_1, lifecycle, start) views.STACKDB.find_request_trackers(request_id=REQUEST_ID_1)\ - .AndReturn([tracker]) + .AndReturn([tracker]) views.STACKDB.save(tracker) self.mox.ReplayAll() views.update_kpi(timing, raw) @@ -104,12 +105,15 @@ class StacktachLifecycleTestCase(unittest.TestCase): views.STACKDB.find_lifecycles(instance=INSTANCE_ID_1).AndReturn([]) lifecycle = self.mox.CreateMockAnything() lifecycle.instance = INSTANCE_ID_1 - views.STACKDB.create_lifecycle(instance=INSTANCE_ID_1).AndReturn(lifecycle) + views.STACKDB.create_lifecycle(instance=INSTANCE_ID_1)\ + .AndReturn(lifecycle) views.STACKDB.save(lifecycle) - views.STACKDB.find_timings(name=event_name, lifecycle=lifecycle).AndReturn([]) + views.STACKDB.find_timings(name=event_name, lifecycle=lifecycle)\ + .AndReturn([]) timing = utils.create_timing(self.mox, event_name, lifecycle) - views.STACKDB.create_timing(lifecycle=lifecycle, name=event_name).AndReturn(timing) + views.STACKDB.create_timing(lifecycle=lifecycle, name=event_name)\ + .AndReturn(timing) views.STACKDB.save(timing) self.mox.ReplayAll() @@ -137,13 +141,15 @@ class StacktachLifecycleTestCase(unittest.TestCase): lifecycle = utils.create_lifecycle(self.mox, INSTANCE_ID_1, 'active', '', start_raw) - views.STACKDB.find_lifecycles(instance=INSTANCE_ID_1).AndReturn([lifecycle]) + views.STACKDB.find_lifecycles(instance=INSTANCE_ID_1)\ + .AndReturn([lifecycle]) views.STACKDB.save(lifecycle) timing = utils.create_timing(self.mox, event_name, lifecycle, start_raw=start_raw, start_when=start_when) - views.STACKDB.find_timings(name=event_name, lifecycle=lifecycle).AndReturn([timing]) + views.STACKDB.find_timings(name=event_name, lifecycle=lifecycle)\ + .AndReturn([timing]) self.mox.StubOutWithMock(views, "update_kpi") views.update_kpi(timing, end_raw) @@ -186,3 +192,199 @@ class StacktachLifecycleTestCase(unittest.TestCase): self.assertEqual(lifecycle.last_task_state, 'reboot') self.mox.VerifyAll() + + +class StacktackUsageParsingTestCase(unittest.TestCase): + def setUp(self): + self.mox = mox.Mox() + views.STACKDB = self.mox.CreateMockAnything() + + def tearDown(self): + self.mox.UnsetStubs() + + def test_process_usage_for_new_launch(self): + when = utils.decimal_utc() + notif = utils.create_nova_notif(request_id=REQUEST_ID_1) + json_str = json.dumps(notif) + event = 'compute.instance.create.start' + raw = utils.create_raw(self.mox, when, event=event, json_str=json_str) + usage = self.mox.CreateMockAnything() + views.STACKDB.create_instance_usage(instance=INSTANCE_ID_1, + request_id=REQUEST_ID_1, + instance_type_id = '1')\ + .AndReturn(usage) + views.STACKDB.save(usage) + self.mox.ReplayAll() + views._process_usage_for_new_launch(raw) + self.mox.VerifyAll() + + def test_process_usage_for_updates_create_end(self): + when_time = datetime.datetime.utcnow() + when_str = str(when_time) + when_decimal = utils.decimal_utc(when_time) + notif = utils.create_nova_notif(request_id=REQUEST_ID_1, + launched=str(when_time)) + json_str = json.dumps(notif) + event = 'compute.instance.create.end' + raw = utils.create_raw(self.mox, when_decimal, event=event, + json_str=json_str) + usage = self.mox.CreateMockAnything() + usage.instance = INSTANCE_ID_1 + usage.request_id = REQUEST_ID_1 + usage.instance_type_id = '1' + views.STACKDB.get_instance_usage(instance=INSTANCE_ID_1, + request_id=REQUEST_ID_1)\ + .AndReturn(usage) + views.STACKDB.save(usage) + self.mox.ReplayAll() + + views._process_usage_for_updates(raw) + self.assertEqual(usage.instance, INSTANCE_ID_1) + self.assertEqual(usage.request_id, REQUEST_ID_1) + self.assertEqual(usage.instance_type_id, '1') + self.assertEqual(usage.launched_at, when_decimal) + self.mox.VerifyAll() + + def test_process_usage_for_updates_revert_end(self): + when_time = datetime.datetime.utcnow() + when_decimal = utils.decimal_utc(when_time) + notif = utils.create_nova_notif(request_id=REQUEST_ID_1, + launched=str(when_time)) + json_str = json.dumps(notif) + event = 'compute.instance.resize.revert.end' + raw = utils.create_raw(self.mox, when_decimal, event=event, + json_str=json_str) + usage = self.mox.CreateMockAnything() + usage.instance = INSTANCE_ID_1 + usage.request_id = REQUEST_ID_1 + usage.instance_type_id = '1' + views.STACKDB.get_instance_usage(instance=INSTANCE_ID_1, + request_id=REQUEST_ID_1)\ + .AndReturn(usage) + views.STACKDB.save(usage) + self.mox.ReplayAll() + + views._process_usage_for_updates(raw) + self.assertEqual(usage.instance, INSTANCE_ID_1) + self.assertEqual(usage.request_id, REQUEST_ID_1) + self.assertEqual(usage.instance_type_id, '1') + self.assertEqual(usage.launched_at, when_decimal) + self.mox.VerifyAll() + + def test_process_usage_for_updates_prep_end(self): + when_time = datetime.datetime.utcnow() + when_decimal = utils.decimal_utc(when_time) + notif = utils.create_nova_notif(request_id=REQUEST_ID_1, + new_type_id='2') + json_str = json.dumps(notif) + event = 'compute.instance.resize.prep.end' + raw = utils.create_raw(self.mox, when_decimal, event=event, + json_str=json_str) + usage = self.mox.CreateMockAnything() + usage.instance = INSTANCE_ID_1 + usage.request_id = REQUEST_ID_1 + views.STACKDB.get_instance_usage(instance=INSTANCE_ID_1, + request_id=REQUEST_ID_1)\ + .AndReturn(usage) + views.STACKDB.save(usage) + self.mox.ReplayAll() + + views._process_usage_for_updates(raw) + self.assertEqual(usage.instance, INSTANCE_ID_1) + self.assertEqual(usage.request_id, REQUEST_ID_1) + self.assertEqual(usage.instance_type_id, '2') + self.mox.VerifyAll() + + def test_process_delete(self): + delete_time = datetime.datetime.utcnow() + launch_time = delete_time-datetime.timedelta(days=1) + launch_decimal = utils.decimal_utc(launch_time) + delete_decimal = utils.decimal_utc(delete_time) + notif = utils.create_nova_notif(request_id=REQUEST_ID_1, + launched=str(launch_time), + deleted=str(delete_time)) + json_str = json.dumps(notif) + event = 'compute.instance.delete.end' + raw = utils.create_raw(self.mox, delete_decimal, event=event, + json_str=json_str) + usage = self.mox.CreateMockAnything() + usage.instance = INSTANCE_ID_1 + usage.request_id = REQUEST_ID_1 + usage.instance_type_id = '1' + usage.launched_at = launch_decimal + views.STACKDB.get_instance_usage(instance=INSTANCE_ID_1, + launched_at=launch_decimal)\ + .AndReturn(usage) + views.STACKDB.save(usage) + self.mox.ReplayAll() + + views._process_delete(raw) + self.assertEqual(usage.instance, INSTANCE_ID_1) + self.assertEqual(usage.request_id, REQUEST_ID_1) + self.assertEqual(usage.instance_type_id, '1') + self.assertEqual(usage.launched_at, launch_decimal) + self.assertEqual(usage.deleted_at, delete_decimal) + self.mox.VerifyAll() + + def test_process_exists(self): + launch_time = datetime.datetime.utcnow()-datetime.timedelta(hours=23) + launch_decimal = utils.decimal_utc(launch_time) + current_time = datetime.datetime.utcnow() + current_decimal = utils.decimal_utc(current_time) + notif = utils.create_nova_notif(launched=str(launch_time)) + json_str = json.dumps(notif) + event = 'compute.instance.exists' + raw = utils.create_raw(self.mox, current_decimal, event=event, + json_str=json_str) + usage = self.mox.CreateMockAnything() + views.STACKDB.get_instance_usage(instance=INSTANCE_ID_1, + launched_at=launch_decimal)\ + .AndReturn(usage) + exists_values = { + 'message_id': MESSAGE_ID_1, + 'instance': INSTANCE_ID_1, + 'launched_at': launch_decimal, + 'instance_type_id': '1', + 'usage': usage, + 'raw': raw, + } + exists = self.mox.CreateMockAnything() + views.STACKDB.create_instance_exists(**exists_values).AndReturn(exists) + views.STACKDB.save(exists) + self.mox.ReplayAll() + views._process_exists(raw) + self.mox.VerifyAll() + + def test_process_exists_with_deleted_at(self): + launch_time = datetime.datetime.utcnow()-datetime.timedelta(hours=23) + launch_decimal = utils.decimal_utc(launch_time) + deleted_time = datetime.datetime.utcnow()-datetime.timedelta(hours=12) + deleted_decimal = utils.decimal_utc(deleted_time) + current_time = datetime.datetime.utcnow() + current_decimal = utils.decimal_utc(current_time) + notif = utils.create_nova_notif(launched=str(launch_time), + deleted=str(deleted_time)) + json_str = json.dumps(notif) + event = 'compute.instance.exists' + raw = utils.create_raw(self.mox, current_decimal, event=event, + json_str=json_str) + usage = self.mox.CreateMockAnything() + views.STACKDB.get_instance_usage(instance=INSTANCE_ID_1, + launched_at=launch_decimal)\ + .AndReturn(usage) + exists_values = { + 'message_id': MESSAGE_ID_1, + 'instance': INSTANCE_ID_1, + 'launched_at': launch_decimal, + 'deleted_at': deleted_decimal, + 'instance_type_id': '1', + 'usage': usage, + 'raw': raw, + } + exists = self.mox.CreateMockAnything() + views.STACKDB.create_instance_exists(**exists_values).AndReturn(exists) + views.STACKDB.save(exists) + self.mox.ReplayAll() + views._process_exists(raw) + self.mox.VerifyAll() + diff --git a/tests/unit/utils.py b/tests/unit/utils.py index 742285e..6294d1a 100644 --- a/tests/unit/utils.py +++ b/tests/unit/utils.py @@ -31,12 +31,37 @@ setup_sys_path() setup_environment() from stacktach import datetime_to_decimal as dt -def decimal_utcnow(): - return dt.dt_to_decimal(datetime.datetime.utcnow()) + +def decimal_utc(t = datetime.datetime.utcnow()): + return dt.dt_to_decimal(t) + + +def create_nova_notif(request_id=None, instance=INSTANCE_ID_1, type_id='1', + launched=None, deleted = None, new_type_id=None, + message_id=MESSAGE_ID_1): + notif = ['', { + 'message_id': message_id, + 'payload': { + 'instance_id': instance, + 'instance_type_id': type_id, + } + }] + + if request_id: + notif[1]['_context_request_id'] = request_id + if launched: + notif[1]['payload']['launched_at'] = launched + if deleted: + notif[1]['payload']['deleted_at'] = deleted + if new_type_id: + notif[1]['payload']['new_instance_type_id'] = new_type_id + + return notif + def create_raw(mox, when, event, instance=INSTANCE_ID_1, request_id=REQUEST_ID_1, state='active', old_task='', - host='compute', json=''): + host='compute', json_str=''): raw = mox.CreateMockAnything() raw.host = host raw.instance = instance @@ -45,7 +70,7 @@ def create_raw(mox, when, event, instance=INSTANCE_ID_1, raw.state = state raw.old_task = old_task raw.request_id = request_id - raw.json = json + raw.json = json_str return raw def create_lifecycle(mox, instance, last_state, last_task_state, last_raw):