From 25fa31ffc500bb21d28139e2c3a3cba56150bbf4 Mon Sep 17 00:00:00 2001 From: Manali Latkar Date: Mon, 13 May 2013 12:16:49 +0530 Subject: [PATCH] Added tenant_id in verification of instanceexists and instanceusages --- .gitignore | 3 + ...id_to_instanceexists_and_instanceusage.sql | 6 + ...enant_id_in_instanceexists_from_rawdata.py | 43 +++ ...tenant_id_in_instanceusage_from_rawdata.py | 43 +++ stacktach/models.py | 5 +- stacktach/test_utils.py | 6 +- stacktach/views.py | 3 + tests/unit/test_stacktach.py | 258 +++++++++--------- tests/unit/test_verifier_db.py | 34 ++- tests/unit/utils.py | 13 +- verifier/dbverifier.py | 24 +- 11 files changed, 291 insertions(+), 147 deletions(-) create mode 100644 migrations/011_add_tenant_id_to_instanceexists_and_instanceusage.sql create mode 100644 migrations/011_populate_tenant_id_in_instanceexists_from_rawdata.py create mode 100644 migrations/011_populate_tenant_id_in_instanceusage_from_rawdata.py diff --git a/.gitignore b/.gitignore index ea3ade2..0e687b5 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ worker.log worker.log.* etc/stacktach_config.sh etc/stacktach_worker_config.json +etc/stacktach_verifier_config.json +verifier.log +verifier.log.* diff --git a/migrations/011_add_tenant_id_to_instanceexists_and_instanceusage.sql b/migrations/011_add_tenant_id_to_instanceexists_and_instanceusage.sql new file mode 100644 index 0000000..4d948b7 --- /dev/null +++ b/migrations/011_add_tenant_id_to_instanceexists_and_instanceusage.sql @@ -0,0 +1,6 @@ +ALTER TABLE stacktach_instanceexists ADD `tenant` varchar(50); +CREATE INDEX `stacktach_instanceexists_1384d482` ON `stacktach_instanceexists` (`tenant`); + +ALTER TABLE stacktach_instanceusage ADD `tenant` varchar(50); +CREATE INDEX `stacktach_instanceusage_1384d482` ON `stacktach_instanceusage` (`tenant`); + diff --git a/migrations/011_populate_tenant_id_in_instanceexists_from_rawdata.py b/migrations/011_populate_tenant_id_in_instanceexists_from_rawdata.py new file mode 100644 index 0000000..c12c831 --- /dev/null +++ b/migrations/011_populate_tenant_id_in_instanceexists_from_rawdata.py @@ -0,0 +1,43 @@ +# Copyright (c) 2013 - Rackspace Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +import os +import sys + +POSSIBLE_TOPDIR = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), + os.pardir, os.pardir)) +if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'stacktach')): + sys.path.insert(0, POSSIBLE_TOPDIR) + +from stacktach import models + +if __name__ != '__main__': + sys.exit(1) + + +def add_past_exists(instance_tenant_id_maps): + update_count = 0 + for map in instance_tenant_id_maps: + update_count += models.InstanceExists.objects.filter(instance=map['instance']).update(tenant=map['tenant']) + print "updated %s rows" % update_count + +distinct_exists_instances = models.InstanceExists.objects.all().values('instance').distinct() +instance_tenant_id_maps = models.RawData.objects.filter(instance__in=distinct_exists_instances).distinct().values('instance', 'tenant') +add_past_exists(instance_tenant_id_maps) \ No newline at end of file diff --git a/migrations/011_populate_tenant_id_in_instanceusage_from_rawdata.py b/migrations/011_populate_tenant_id_in_instanceusage_from_rawdata.py new file mode 100644 index 0000000..93ea9b8 --- /dev/null +++ b/migrations/011_populate_tenant_id_in_instanceusage_from_rawdata.py @@ -0,0 +1,43 @@ +# Copyright (c) 2013 - Rackspace Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +import os +import sys + +POSSIBLE_TOPDIR = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), + os.pardir, os.pardir)) +if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'stacktach')): + sys.path.insert(0, POSSIBLE_TOPDIR) + +from stacktach import models + +if __name__ != '__main__': + sys.exit(1) + + +def add_past_usages(instance_tenant_id_maps): + update_count = 0 + for map in instance_tenant_id_maps: + update_count += models.InstanceUsage.objects.filter(instance=map['instance']).update(tenant=map['tenant']) + print "updated %s rows" % update_count + +distinct_usage_instances = models.InstanceUsage.objects.all().values('instance').distinct() +instance_tenant_id_maps = models.RawData.objects.filter(instance__in=distinct_usage_instances).distinct().values('instance', 'tenant') +add_past_usages(instance_tenant_id_maps) diff --git a/stacktach/models.py b/stacktach/models.py index 98306ee..eabad54 100644 --- a/stacktach/models.py +++ b/stacktach/models.py @@ -86,7 +86,8 @@ class InstanceUsage(models.Model): null=True, blank=True, db_index=True) - + tenant = models.CharField(max_length=50, null=True, blank=True, + db_index=True) class InstanceDeletes(models.Model): instance = models.CharField(max_length=50, null=True, @@ -135,6 +136,8 @@ class InstanceExists(models.Model): usage = models.ForeignKey(InstanceUsage, related_name='+', null=True) delete = models.ForeignKey(InstanceDeletes, related_name='+', null=True) send_status = models.IntegerField(null=True, default=0, db_index=True) + tenant = models.CharField(max_length=50, null=True, blank=True, + db_index=True) class Timing(models.Model): diff --git a/stacktach/test_utils.py b/stacktach/test_utils.py index 8baec96..aa9d663 100644 --- a/stacktach/test_utils.py +++ b/stacktach/test_utils.py @@ -180,7 +180,8 @@ def make_resize_revert_end_json(launched_at, instance_type_id='1', def create_raw(deployment, when, event, instance=INSTANCE_ID_1, request_id=REQUEST_ID_1, state='active', old_task='', - host='compute', service='compute', json=''): + host='compute', service='compute', json='', + tenant='default_tenant_id'): raw_values = { 'deployment': deployment, 'host': host, @@ -191,7 +192,8 @@ def create_raw(deployment, when, event, instance=INSTANCE_ID_1, 'event': event, 'instance': instance, 'request_id': request_id, - 'json': json + 'json': json, + 'tenant': tenant } raw = RawData(**raw_values) raw.save() diff --git a/stacktach/views.py b/stacktach/views.py index a61eacf..3fbeaa6 100644 --- a/stacktach/views.py +++ b/stacktach/views.py @@ -240,6 +240,7 @@ def _process_usage_for_new_launch(raw, body): # though, because we may have already received the end event usage.launched_at = utils.str_time_to_unix(payload['launched_at']) + usage.tenant = payload['tenant_id'] STACKDB.save(usage) @@ -261,6 +262,7 @@ def _process_usage_for_updates(raw, body): elif raw.event == INSTANCE_EVENT['resize_prep_end']: usage.instance_type_id = payload['new_instance_type_id'] + usage.tenant = payload['tenant_id'] STACKDB.save(usage) @@ -302,6 +304,7 @@ def _process_exists(raw, body): if usage: values['usage'] = usage values['raw'] = raw + values['tenant'] = payload['tenant_id'] deleted_at = payload.get('deleted_at') if deleted_at and deleted_at != '': diff --git a/tests/unit/test_stacktach.py b/tests/unit/test_stacktach.py index 6a93bc1..3a89cf7 100644 --- a/tests/unit/test_stacktach.py +++ b/tests/unit/test_stacktach.py @@ -20,21 +20,18 @@ import datetime import json -import os -import sys import unittest import mox import utils from utils import INSTANCE_ID_1 -from utils import INSTANCE_ID_2 from utils import MESSAGE_ID_1 -from utils import MESSAGE_ID_2 from utils import REQUEST_ID_1 -from utils import REQUEST_ID_2 -from utils import REQUEST_ID_3 from utils import TENANT_ID_1 +from utils import INSTANCE_TYPE_ID_1 +from utils import DUMMY_TIME +from utils import INSTANCE_TYPE_ID_2 from stacktach import views @@ -415,7 +412,7 @@ class StacktachLifecycleTestCase(unittest.TestCase): self.mox.VerifyAll() -class StacktackUsageParsingTestCase(unittest.TestCase): +class StacktachUsageParsingTestCase(unittest.TestCase): def setUp(self): self.mox = mox.Mox() views.STACKDB = self.mox.CreateMockAnything() @@ -423,137 +420,142 @@ class StacktackUsageParsingTestCase(unittest.TestCase): 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) + def test_process_usage_for_new_launch_create_start(self): + kwargs = {'launched': str(DUMMY_TIME), 'tenant_id': TENANT_ID_1 } + notification = utils.create_nova_notif(request_id=REQUEST_ID_1, **kwargs) event = 'compute.instance.create.start' - raw = utils.create_raw(self.mox, when, event=event, json_str=json_str) - 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, notif[1]) + raw, usage = self._setup_process_usage_mocks(event, notification) + + views._process_usage_for_new_launch(raw, notification[1]) + self.assertEquals(usage.instance_type_id, '1') + self.assertEquals(usage.tenant, TENANT_ID_1) + self.mox.VerifyAll() - def test_process_usage_for_new_launch_resize_no_launched_at_in_db(self): - now = datetime.datetime.utcnow() - when = utils.decimal_utc(now) - notif = utils.create_nova_notif(request_id=REQUEST_ID_1, - launched=str(now)) - json_str = json.dumps(notif) - event = 'compute.instance.resize.prep.start' - raw = utils.create_raw(self.mox, when, event=event, json_str=json_str) - usage = self.mox.CreateMockAnything() + def test_process_usage_for_new_launch_rebuild_start(self): + kwargs = {'launched': str(DUMMY_TIME), 'tenant_id': TENANT_ID_1} + notification = utils.create_nova_notif(request_id=REQUEST_ID_1, **kwargs) + event = 'compute.instance.rebuild.start' + raw, usage = self._setup_process_usage_mocks(event, notification) + + views._process_usage_for_new_launch(raw, notification[1]) + + self.assertEquals(usage.instance_type_id, '1') + self.assertEquals(usage.tenant, TENANT_ID_1) + + self.mox.VerifyAll() + + def test_process_usage_for_new_launch_rebuild_start_when_no_launched_at_in_db(self): + kwargs = {'launched': str(DUMMY_TIME), 'tenant_id': TENANT_ID_1} + notification = utils.create_nova_notif(request_id=REQUEST_ID_1, **kwargs) + event = 'compute.instance.rebuild.start' + raw, usage = self._setup_process_usage_mocks(event, notification) 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_new_launch(raw, notif[1]) - self.assertEqual(usage.launched_at, when) + + views._process_usage_for_new_launch(raw, notification[1]) + + self.assertEqual(usage.launched_at, utils.decimal_utc(DUMMY_TIME)) + self.assertEquals(usage.tenant, TENANT_ID_1) + self.mox.VerifyAll() - def test_process_usage_for_new_launch_resize_launched_at_in_db(self): - now = datetime.datetime.utcnow() - when = utils.decimal_utc(now) - notif = utils.create_nova_notif(request_id=REQUEST_ID_1, - launched=str(now)) - json_str = json.dumps(notif) + def test_process_usage_for_new_launch_resize_prep_start_when_no_launched_at_in_db(self): + kwargs = {'launched': str(DUMMY_TIME), 'tenant_id': TENANT_ID_1} + notification = utils.create_nova_notif(request_id=REQUEST_ID_1, **kwargs) event = 'compute.instance.resize.prep.start' - raw = utils.create_raw(self.mox, when, event=event, json_str=json_str) - usage = self.mox.CreateMockAnything() - orig_launched_at = utils.decimal_utc(now - datetime.timedelta(days=1)) + raw, usage = self._setup_process_usage_mocks(event, notification) + usage.launched_at = None + + views._process_usage_for_new_launch(raw, notification[1]) + + self.assertEqual(usage.launched_at, utils.decimal_utc(DUMMY_TIME)) + self.assertEquals(usage.tenant, TENANT_ID_1) + + self.mox.VerifyAll() + + def test_process_usage_for_new_launch_resize_revert_start_when_no_launched_at_in_db(self): + kwargs = {'launched': str(DUMMY_TIME), 'tenant_id': TENANT_ID_1} + notification = utils.create_nova_notif(request_id=REQUEST_ID_1, **kwargs) + event = 'compute.instance.resize.revert.start' + raw, usage = self._setup_process_usage_mocks(event, notification) + usage.launched_at = None + + views._process_usage_for_new_launch(raw, notification[1]) + + self.assertEquals(usage.tenant, TENANT_ID_1) + self.assertEqual(usage.launched_at, utils.decimal_utc(DUMMY_TIME)) + + self.mox.VerifyAll() + + def test_process_usage_for_new_launch_resize_prep_start_when_launched_at_in_db(self): + kwargs = {'launched': str(DUMMY_TIME), 'tenant_id': TENANT_ID_1} + notification = utils.create_nova_notif(request_id=REQUEST_ID_1, **kwargs) + event = 'compute.instance.resize.prep.start' + raw, usage = self._setup_process_usage_mocks(event, notification) + orig_launched_at = utils.decimal_utc(DUMMY_TIME - datetime.timedelta(days=1)) usage.launched_at = orig_launched_at + + views._process_usage_for_new_launch(raw, notification[1]) + + self.assertEqual(usage.launched_at, orig_launched_at) + self.assertEqual(usage.tenant, TENANT_ID_1) + + self.mox.VerifyAll() + + def test_process_usage_for_updates_create_end(self): + kwargs = {'launched': str(DUMMY_TIME), 'tenant_id': TENANT_ID_1} + notification = utils.create_nova_notif(request_id=REQUEST_ID_1, **kwargs) + event = 'compute.instance.create.end' + raw, usage = self._setup_process_usage_mocks(event, notification) + + views._process_usage_for_updates(raw, notification[1]) + + self.assertEqual(usage.launched_at, utils.decimal_utc(DUMMY_TIME)) + self.assertEqual(usage.tenant, TENANT_ID_1) + + self.mox.VerifyAll() + + def test_process_usage_for_updates_revert_end(self): + kwargs = {'launched': str(DUMMY_TIME), 'type_id': INSTANCE_TYPE_ID_1, 'tenant_id': TENANT_ID_1} + notification = utils.create_nova_notif(request_id=REQUEST_ID_1, **kwargs) + event = 'compute.instance.resize.revert.end' + raw, usage = self._setup_process_usage_mocks(event, notification) + + views._process_usage_for_updates(raw, notification[1]) + + self.assertEqual(usage.instance_type_id, INSTANCE_TYPE_ID_1) + self.assertEqual(usage.launched_at, utils.decimal_utc(DUMMY_TIME)) + self.assertEquals(usage.tenant, TENANT_ID_1) + + self.mox.VerifyAll() + + def test_process_usage_for_updates_prep_end(self): + kwargs = {'launched': str(DUMMY_TIME), 'new_type_id': INSTANCE_TYPE_ID_2, 'tenant_id': TENANT_ID_1} + notification = utils.create_nova_notif(request_id=REQUEST_ID_1, **kwargs) + event = 'compute.instance.resize.prep.end' + raw, usage = self._setup_process_usage_mocks(event, notification) + + views._process_usage_for_updates(raw, notification[1]) + + self.assertEqual(usage.instance_type_id, INSTANCE_TYPE_ID_2) + self.assertEquals(usage.tenant, TENANT_ID_1) + + self.mox.VerifyAll() + + def _setup_process_usage_mocks(self, event, notification): + when_time = DUMMY_TIME + when_decimal = utils.decimal_utc(when_time) + json_str = json.dumps(notification) + raw = utils.create_raw(self.mox, when_decimal, event=event, + json_str=json_str) + 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, notif[1]) - self.assertEqual(usage.launched_at, orig_launched_at) - 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_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, notif[1]) - 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_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, notif[1]) - 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_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, notif[1]) - 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() + return raw, usage def test_process_delete(self): delete_time = datetime.datetime.utcnow() @@ -619,7 +621,8 @@ class StacktackUsageParsingTestCase(unittest.TestCase): audit_ending_decimal = utils.decimal_utc(current_time) notif = utils.create_nova_notif(launched=str(launch_time), audit_period_beginning=str(audit_beginning), - audit_period_ending=str(current_time)) + audit_period_ending=str(current_time), + tenant_id=TENANT_ID_1) json_str = json.dumps(notif) event = 'compute.instance.exists' raw = utils.create_raw(self.mox, current_decimal, event=event, @@ -638,6 +641,7 @@ class StacktackUsageParsingTestCase(unittest.TestCase): 'instance_type_id': '1', 'usage': usage, 'raw': raw, + 'tenant': TENANT_ID_1 } exists = self.mox.CreateMockAnything() views.STACKDB.create_instance_exists(**exists_values).AndReturn(exists) @@ -659,7 +663,8 @@ class StacktackUsageParsingTestCase(unittest.TestCase): notif = utils.create_nova_notif(launched=str(launch_time), deleted=str(deleted_time), audit_period_beginning=str(audit_beginning), - audit_period_ending=str(current_time)) + audit_period_ending=str(current_time), + tenant_id= TENANT_ID_1) json_str = json.dumps(notif) event = 'compute.instance.exists' raw = utils.create_raw(self.mox, current_decimal, event=event, @@ -684,6 +689,7 @@ class StacktackUsageParsingTestCase(unittest.TestCase): 'usage': usage, 'delete': delete, 'raw': raw, + 'tenant': TENANT_ID_1 } exists = self.mox.CreateMockAnything() views.STACKDB.create_instance_exists(**exists_values).AndReturn(exists) diff --git a/tests/unit/test_verifier_db.py b/tests/unit/test_verifier_db.py index 60ade14..54f7def 100644 --- a/tests/unit/test_verifier_db.py +++ b/tests/unit/test_verifier_db.py @@ -32,10 +32,10 @@ import multiprocessing from stacktach import datetime_to_decimal as dt from stacktach import models -import utils from utils import INSTANCE_ID_1 -from utils import INSTANCE_ID_2 -from utils import REQUEST_ID_1 +from utils import TENANT_ID_1 +from utils import TENANT_ID_2 +from utils import INSTANCE_TYPE_ID_1 from verifier import dbverifier from verifier import AmbiguousResults @@ -75,14 +75,18 @@ class VerifierTestCase(unittest.TestCase): def test_verify_for_launch(self): exist = self.mox.CreateMockAnything() - exist.usage = self.mox.CreateMockAnything() exist.launched_at = decimal.Decimal('1.1') - exist.instance_type_id = 2 + exist.instance_type_id = INSTANCE_TYPE_ID_1 + exist.tenant = TENANT_ID_1 + + exist.usage = self.mox.CreateMockAnything() exist.usage.launched_at = decimal.Decimal('1.1') - exist.usage.instance_type_id = 2 + exist.usage.instance_type_id = INSTANCE_TYPE_ID_1 + exist.usage.tenant = TENANT_ID_1 self.mox.ReplayAll() dbverifier._verify_for_launch(exist) + self.mox.VerifyAll() def test_verify_for_launch_launched_at_in_range(self): @@ -137,6 +141,24 @@ class VerifierTestCase(unittest.TestCase): self.mox.VerifyAll() + def test_verify_for_launch_tenant_id_mismatch(self): + exist = self.mox.CreateMockAnything() + exist.tenant = TENANT_ID_1 + + exist.usage = self.mox.CreateMockAnything() + exist.usage.tenant = TENANT_ID_2 + self.mox.ReplayAll() + + with self.assertRaises(FieldMismatch) as cm: + dbverifier._verify_for_launch(exist) + exception = cm.exception + + self.assertEqual(exception.field_name, 'tenant') + self.assertEqual(exception.expected, TENANT_ID_1) + self.assertEqual(exception.actual, TENANT_ID_2) + + self.mox.VerifyAll() + def test_verify_for_launch_late_usage(self): exist = self.mox.CreateMockAnything() exist.usage = None diff --git a/tests/unit/utils.py b/tests/unit/utils.py index 5dc9d4c..2353525 100644 --- a/tests/unit/utils.py +++ b/tests/unit/utils.py @@ -19,17 +19,20 @@ # IN THE SOFTWARE. import datetime -import os -import sys -import unittest TENANT_ID_1 = 'testtenantid1' +TENANT_ID_2 = 'testtenantid2' from stacktach import datetime_to_decimal as dt INSTANCE_ID_1 = "08f685d9-6352-4dbc-8271-96cc54bf14cd" INSTANCE_ID_2 = "515adf96-41d3-b86d-5467-e584edc61dab" +INSTANCE_TYPE_ID_1 = "12345" +INSTANCE_TYPE_ID_2 = '54321' + +DUMMY_TIME = datetime.datetime.utcnow() + MESSAGE_ID_1 = "7f28f81b-29a2-43f2-9ba1-ccb3e53ab6c8" MESSAGE_ID_2 = "4d596126-0f04-4329-865f-7b9a7bd69bcf" @@ -45,7 +48,7 @@ def decimal_utc(t = datetime.datetime.utcnow()): 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, audit_period_beginning=None, - audit_period_ending=None): + audit_period_ending=None, tenant_id = None): notif = ['', { 'message_id': message_id, 'payload': { @@ -66,6 +69,8 @@ def create_nova_notif(request_id=None, instance=INSTANCE_ID_1, type_id='1', notif[1]['payload']['audit_period_beginning'] = audit_period_beginning if audit_period_ending: notif[1]['payload']['audit_period_ending'] = audit_period_ending + if tenant_id: + notif[1]['payload']['tenant_id'] = tenant_id return notif diff --git a/verifier/dbverifier.py b/verifier/dbverifier.py index d8bd553..f54f6a8 100644 --- a/verifier/dbverifier.py +++ b/verifier/dbverifier.py @@ -126,6 +126,21 @@ def _verify_date_field(d1, d2, same_second=False): return False +def _verify_field_mismatch(exists, launch): + if not _verify_date_field(launch.launched_at, exists.launched_at, + same_second=True): + raise FieldMismatch('launched_at', exists.launched_at, + launch.launched_at) + + if launch.instance_type_id != exists.instance_type_id: + raise FieldMismatch('instance_type_id', exists.instance_type_id, + launch.instance_type_id) + + if launch.tenant != exists.tenant: + raise FieldMismatch('tenant', exists.tenant, + launch.tenant) + + def _verify_for_launch(exist): if exist.usage: launch = exist.usage @@ -147,14 +162,7 @@ def _verify_for_launch(exist): else: raise NotFound('InstanceUsage', {'instance': exist.instance}) - if not _verify_date_field(launch.launched_at, exist.launched_at, - same_second=True): - raise FieldMismatch('launched_at', exist.launched_at, - launch.launched_at) - - if launch.instance_type_id != exist.instance_type_id: - raise FieldMismatch('instance_type_id', exist.instance_type_id, - launch.instance_type_id) + _verify_field_mismatch(exist, launch) def _verify_for_delete(exist):