From a997a6a1024c256ec851f0e28e08fc8f6c2c8e63 Mon Sep 17 00:00:00 2001 From: Manali Latkar Date: Wed, 13 Nov 2013 10:22:10 +0530 Subject: [PATCH] Added db APIs for Glance --- .gitignore | 1 + stacktach/dbapi.py | 52 ++++++++--- stacktach/models.py | 4 + tests/unit/test_dbapi.py | 195 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 235 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 40780a1..6abacdf 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ etc/stacktach_worker_config.json etc/stacktach_verifier_config.json verifier.log verifier.log.* +.gitattributes diff --git a/stacktach/dbapi.py b/stacktach/dbapi.py index abed81f..60d07cf 100644 --- a/stacktach/dbapi.py +++ b/stacktach/dbapi.py @@ -79,13 +79,6 @@ def _log_api_exception(cls, ex, request): stacklog.error(msg) -def _exists_model_factory(service): - if service == 'glance': - return models.ImageExists - elif service == 'nova': - return models.InstanceExists - - def api_call(func): @functools.wraps(func) @@ -108,28 +101,59 @@ def api_call(func): return handled +def _usage_model_factory(service): + if service == 'nova': + return {'klass': models.InstanceUsage, 'order_by': 'launched_at'} + if service == 'glance': + return {'klass': models.ImageUsage, 'order_by': 'created_at'} + + +def _exists_model_factory(service): + if service == 'nova': + return {'klass': models.InstanceExists, 'order_by': 'id'} + if service == 'glance': + return {'klass': models.ImageExists, 'order_by': 'id'} + + +def _deletes_model_factory(service): + if service == 'nova': + return {'klass': models.InstanceDeletes, 'order_by': 'launched_at'} + if service == 'glance': + return {'klass': models.ImageDeletes, 'order_by': 'deleted_at'} + + @api_call def list_usage_launches(request): - objects = get_db_objects(models.InstanceUsage, request, 'launched_at') + service = request.GET.get('service', 'nova') + model = _usage_model_factory(service) + objects = get_db_objects(model['klass'], request, + model['order_by']) dicts = _convert_model_list(objects) return {'launches': dicts} @api_call def get_usage_launch(request, launch_id): - return {'launch': _get_model_by_id(models.InstanceUsage, launch_id)} + service = request.GET.get('service', 'nova') + model = _usage_model_factory(service) + return {'launch': _get_model_by_id(model['klass'], launch_id)} @api_call def list_usage_deletes(request): - objects = get_db_objects(models.InstanceDeletes, request, 'launched_at') + service = request.GET.get('service', 'nova') + model = _deletes_model_factory(service) + objects = get_db_objects(model['klass'], request, + model['order_by']) dicts = _convert_model_list(objects) return {'deletes': dicts} @api_call def get_usage_delete(request, delete_id): - return {'delete': _get_model_by_id(models.InstanceDeletes, delete_id)} + service = request.GET.get('service', 'nova') + model = _deletes_model_factory(service) + return {'delete': _get_model_by_id(model['klass'], delete_id)} def _exists_extra_values(exist): @@ -139,6 +163,8 @@ def _exists_extra_values(exist): @api_call def list_usage_exists(request): + service = request.GET.get('service', 'nova') + model = _exists_model_factory(service) try: custom_filters = {} if 'received_min' in request.GET: @@ -155,7 +181,7 @@ def list_usage_exists(request): msg = "Range filters must be dates." raise BadRequestException(message=msg) - objects = get_db_objects(models.InstanceExists, request, 'id', + objects = get_db_objects(model['klass'], request, 'id', custom_filters=custom_filters) dicts = _convert_model_list(objects, _exists_extra_values) return {'exists': dicts} @@ -210,7 +236,7 @@ def _find_exists_with_message_id(msg_id, exists_model, service): def _ping_processing_with_service(pings, service): - exists_model = _exists_model_factory(service) + exists_model = _exists_model_factory(service)['klass'] with transaction.commit_on_success(): for msg_id, status_code in pings.items(): try: diff --git a/stacktach/models.py b/stacktach/models.py index 6cb930a..2666e14 100644 --- a/stacktach/models.py +++ b/stacktach/models.py @@ -437,6 +437,10 @@ class ImageUsage(models.Model): size = models.BigIntegerField(max_length=20) last_raw = models.ForeignKey(GlanceRawData, null=True) + @property + def launched_at(self): + return self.created_at + class ImageDeletes(models.Model): uuid = models.CharField(max_length=50, db_index=True) diff --git a/tests/unit/test_dbapi.py b/tests/unit/test_dbapi.py index 1265d29..8c539c6 100644 --- a/tests/unit/test_dbapi.py +++ b/tests/unit/test_dbapi.py @@ -326,12 +326,26 @@ class DBAPITestCase(StacktachBaseTestCase): self.mox.VerifyAll() - def test_list_usage_exists_no_custom_filters(self): + def test_list_usage_exists_no_custom_filters_for_nova(self): fake_request = self.mox.CreateMockAnything() - fake_request.GET = {} + fake_request.GET = {'service': 'glance'} self.mox.StubOutWithMock(dbapi, 'get_db_objects') objects = self.mox.CreateMockAnything() - dbapi.get_db_objects(models.InstanceExists, fake_request, 'id', + dbapi.get_db_objects(models.ImageExists, fake_request, 'id', + custom_filters={}).AndReturn(objects) + self.mox.StubOutWithMock(dbapi, '_convert_model_list') + dbapi._convert_model_list(objects, dbapi._exists_extra_values) + self.mox.ReplayAll() + resp = dbapi.list_usage_exists(fake_request) + self.assertEqual(resp.status_code, 200) + self.mox.VerifyAll() + + def test_list_usage_exists_no_custom_filters_for_glance(self): + fake_request = self.mox.CreateMockAnything() + fake_request.GET = {'service': 'glance'} + self.mox.StubOutWithMock(dbapi, 'get_db_objects') + objects = self.mox.CreateMockAnything() + dbapi.get_db_objects(models.ImageExists, fake_request, 'id', custom_filters={}).AndReturn(objects) self.mox.StubOutWithMock(dbapi, '_convert_model_list') dbapi._convert_model_list(objects, dbapi._exists_extra_values) @@ -361,15 +375,16 @@ class DBAPITestCase(StacktachBaseTestCase): fake_request = self.mox.CreateMockAnything() date = str(datetime.datetime.utcnow()) fake_request.GET = {'received_max': date} - self.mox.StubOutWithMock(dbapi, 'get_db_objects') unix_date = stacktach_utils.str_time_to_unix(date) custom_filters = {'received_max': {'raw__when__lte': unix_date}} objects = self.mox.CreateMockAnything() + self.mox.StubOutWithMock(dbapi, 'get_db_objects') dbapi.get_db_objects(models.InstanceExists, fake_request, 'id', custom_filters=custom_filters).AndReturn(objects) self.mox.StubOutWithMock(dbapi, '_convert_model_list') dbapi._convert_model_list(objects, dbapi._exists_extra_values) self.mox.ReplayAll() + resp = dbapi.list_usage_exists(fake_request) self.assertEqual(resp.status_code, 200) self.mox.VerifyAll() @@ -734,3 +749,175 @@ class DBAPITestCase(StacktachBaseTestCase): msg = "'messages' missing from request body" self.assertEqual(body.get('message'), msg) self.mox.VerifyAll() + + def test_list_usage_launches_without_service(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'GET' + fake_request.GET = {} + self.mox.StubOutWithMock(dbapi, 'get_db_objects') + mock_objects = self.mox.CreateMockAnything() + launches = {'a': 1} + self.mox.StubOutWithMock(dbapi, '_convert_model_list') + dbapi._convert_model_list(mock_objects).AndReturn(launches) + dbapi.get_db_objects(models.InstanceUsage, fake_request, 'launched_at').AndReturn(mock_objects) + self.mox.ReplayAll() + + resp = dbapi.list_usage_launches(fake_request) + self.assertEqual(resp.status_code, 200) + self.assertEqual(json.loads(resp.content), {'launches': launches}) + self.mox.VerifyAll() + + def test_list_usage_launches_for_glance(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'GET' + fake_request.GET = {'service': 'glance'} + self.mox.StubOutWithMock(dbapi, 'get_db_objects') + mock_objects = self.mox.CreateMockAnything() + launches = {'a': 1} + self.mox.StubOutWithMock(dbapi, '_convert_model_list') + dbapi._convert_model_list(mock_objects).AndReturn(launches) + dbapi.get_db_objects(models.ImageUsage, fake_request, 'created_at').AndReturn(mock_objects) + self.mox.ReplayAll() + + resp = dbapi.list_usage_launches(fake_request) + self.assertEqual(resp.status_code, 200) + self.assertEqual(json.loads(resp.content), {'launches': launches}) + self.mox.VerifyAll() + + def test_list_usage_launches_for_nova(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'GET' + fake_request.GET = {'service': 'nova'} + self.mox.StubOutWithMock(dbapi, 'get_db_objects') + mock_objects = self.mox.CreateMockAnything() + launches = {'a': 1} + self.mox.StubOutWithMock(dbapi, '_convert_model_list') + dbapi._convert_model_list(mock_objects).AndReturn(launches) + dbapi.get_db_objects(models.InstanceUsage, fake_request, 'launched_at').AndReturn(mock_objects) + self.mox.ReplayAll() + + resp = dbapi.list_usage_launches(fake_request) + self.assertEqual(resp.status_code, 200) + self.assertEqual(json.loads(resp.content), {'launches': launches}) + self.mox.VerifyAll() + + def test_get_usage_launch_with_no_service(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'GET' + fake_request.GET = {} + launch = {'a': 1} + self.mox.StubOutWithMock(dbapi, '_get_model_by_id') + dbapi._get_model_by_id(models.InstanceUsage, 1).AndReturn(launch) + self.mox.ReplayAll() + + resp = dbapi.get_usage_launch(fake_request, 1) + self.assertEqual(resp.status_code, 200) + self.assertEqual(json.loads(resp.content), {'launch': {'a': 1}}) + self.mox.VerifyAll() + + def test_get_usage_launch_for_nova(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'GET' + fake_request.GET = {'service': 'nova'} + launch = {'a': 1} + self.mox.StubOutWithMock(dbapi, '_get_model_by_id') + dbapi._get_model_by_id(models.InstanceUsage, 1).AndReturn(launch) + self.mox.ReplayAll() + + resp = dbapi.get_usage_launch(fake_request, 1) + self.assertEqual(resp.status_code, 200) + self.assertEqual(json.loads(resp.content), {'launch': {'a': 1}}) + self.mox.VerifyAll() + + def test_get_usage_launch_for_glance(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'GET' + fake_request.GET = {'service': 'glance'} + launch = {'a': 1} + self.mox.StubOutWithMock(dbapi, '_get_model_by_id') + dbapi._get_model_by_id(models.ImageUsage, 1).AndReturn(launch) + self.mox.ReplayAll() + + resp = dbapi.get_usage_launch(fake_request, 1) + self.assertEqual(resp.status_code, 200) + self.assertEqual(json.loads(resp.content), {'launch': {'a': 1}}) + self.mox.VerifyAll() + + def test_get_usage_delete_for_nova(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'GET' + fake_request.GET = {'service': 'nova'} + delete = {'a': 1} + self.mox.StubOutWithMock(dbapi, '_get_model_by_id') + dbapi._get_model_by_id(models.InstanceDeletes, 1).AndReturn(delete) + self.mox.ReplayAll() + + resp = dbapi.get_usage_delete(fake_request, 1) + self.assertEqual(resp.status_code, 200) + self.assertEqual(json.loads(resp.content), {'delete': {'a': 1}}) + self.mox.VerifyAll() + + def test_get_usage_delete_for_glance(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'GET' + fake_request.GET = {'service': 'glance'} + delete = {'a': 1} + self.mox.StubOutWithMock(dbapi, '_get_model_by_id') + dbapi._get_model_by_id(models.ImageDeletes, 1).AndReturn(delete) + self.mox.ReplayAll() + + resp = dbapi.get_usage_delete(fake_request, 1) + self.assertEqual(resp.status_code, 200) + self.assertEqual(json.loads(resp.content), {'delete': {'a': 1}}) + self.mox.VerifyAll() + + def test_list_usage_deletes_with_no_service(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'GET' + fake_request.GET = {} + self.mox.StubOutWithMock(dbapi, 'get_db_objects') + mock_objects = self.mox.CreateMockAnything() + deletes = {'a': 1} + self.mox.StubOutWithMock(dbapi, '_convert_model_list') + dbapi._convert_model_list(mock_objects).AndReturn(deletes) + dbapi.get_db_objects(models.InstanceDeletes, fake_request, 'launched_at').AndReturn(mock_objects) + self.mox.ReplayAll() + + resp = dbapi.list_usage_deletes(fake_request) + self.assertEqual(resp.status_code, 200) + self.assertEqual(json.loads(resp.content), {'deletes': deletes}) + self.mox.VerifyAll() + + def test_list_usage_deletes_for_nova(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'GET' + fake_request.GET = {'service': 'nova'} + self.mox.StubOutWithMock(dbapi, 'get_db_objects') + mock_objects = self.mox.CreateMockAnything() + deletes = {'a': 1} + self.mox.StubOutWithMock(dbapi, '_convert_model_list') + dbapi._convert_model_list(mock_objects).AndReturn(deletes) + dbapi.get_db_objects(models.InstanceDeletes, fake_request, 'launched_at').AndReturn(mock_objects) + self.mox.ReplayAll() + + resp = dbapi.list_usage_deletes(fake_request) + self.assertEqual(resp.status_code, 200) + self.assertEqual(json.loads(resp.content), {'deletes': deletes}) + self.mox.VerifyAll() + + def test_list_usage_deletes_for_glance(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'GET' + fake_request.GET = {'service': 'glance'} + self.mox.StubOutWithMock(dbapi, 'get_db_objects') + mock_objects = self.mox.CreateMockAnything() + deletes = {'a': 1} + self.mox.StubOutWithMock(dbapi, '_convert_model_list') + dbapi._convert_model_list(mock_objects).AndReturn(deletes) + dbapi.get_db_objects(models.ImageDeletes, fake_request, 'deleted_at').AndReturn(mock_objects) + self.mox.ReplayAll() + + resp = dbapi.list_usage_deletes(fake_request) + self.assertEqual(resp.status_code, 200) + self.assertEqual(json.loads(resp.content), {'deletes': deletes}) + self.mox.VerifyAll()