From b1db1eb8f3c18dd40dbc7af48a7e2fc339ab4b86 Mon Sep 17 00:00:00 2001
From: Manali Latkar <manalil@thoughtworks.com>
Date: Fri, 14 Mar 2014 15:08:29 +0530
Subject: [PATCH] modified api to store AH event id along with send_status sent
 by yagi

---
 docs/dbapi.rst                                |  48 ++++
 stacktach/dbapi.py                            |  47 ++--
 ...event_id__add_field_imageexists_event_i.py | 239 ++++++++++++++++++
 stacktach/models.py                           |   3 +
 tests/unit/test_dbapi.py                      |  67 ++++-
 tests/unit/utils.py                           |   1 +
 6 files changed, 383 insertions(+), 22 deletions(-)
 create mode 100644 stacktach/migrations/0012_auto__add_field_instanceexists_event_id__add_field_imageexists_event_i.py

diff --git a/docs/dbapi.rst b/docs/dbapi.rst
index 53e4195..9132da6 100644
--- a/docs/dbapi.rst
+++ b/docs/dbapi.rst
@@ -89,6 +89,54 @@ Uses the provided message_id's and http status codes to update image and instanc
         ]
         "version": 1
       }
+
+  **Example V2 request**:
+
+   .. sourcecode:: http
+
+      PUT db/confirm/usage/exists/batch/ HTTP/1.1
+      Host: example.com
+      Accept: application/json
+
+      {
+        "messages":
+        [
+          {
+            "nova":
+            [
+              {"nova_message_id1":
+                  {
+                    "event_id": "AH_event_id_1",
+                    "status": 201
+                  }
+              },
+              {"nova_message_id2":
+                  {
+                    "event_id": "AH_event_id_2",
+                    "status": 201
+                  }
+              }
+            ],
+            "glance":
+            [
+              {"glance_message_id1":
+                   {
+                    "event_id": "AH_event_id_3",
+                    "status": 201},
+                    }
+              },
+              {"glance_message_id2":
+                   {
+                    "event_id": "AH_event_id_3",
+                    "status": 201
+                    }
+              }
+            ]
+          }
+        ]
+        "version": 2
+      }
+
   **Example response**:
 
    .. sourcecode:: http
diff --git a/stacktach/dbapi.py b/stacktach/dbapi.py
index 032c458..b231f54 100644
--- a/stacktach/dbapi.py
+++ b/stacktach/dbapi.py
@@ -284,24 +284,29 @@ def _find_exists_with_message_id(msg_id, exists_model, service):
                 .get(message_id=msg_id)]
 
 
-def _ping_processing_with_service(pings, service):
+def _ping_processing_with_service(pings, service, version=1):
     exists_model = _exists_model_factory(service)['klass']
     with transaction.commit_on_success():
-        for msg_id, status_code in pings.items():
-            try:
-                exists = _find_exists_with_message_id(msg_id, exists_model,
-                                                      service)
-                for exists in exists:
-                    exists.send_status = status_code
-                    exists.save()
-            except exists_model.DoesNotExist:
-                msg = "Could not find Exists record with message_id = '%s' for %s"
-                msg = msg % (msg_id, service)
-                raise NotFoundException(message=msg)
-            except exists_model.MultipleObjectsReturned:
-                msg = "Multiple Exists records with message_id = '%s' for %s"
-                msg = msg % (msg_id, service)
-                raise APIException(message=msg)
+            for msg_id, status_info in pings.items():
+                try:
+                    exists = _find_exists_with_message_id(msg_id, exists_model,
+                                                          service)
+                    for exists in exists:
+                        if version == 1:
+                            exists.send_status = status_info
+                        elif version == 2:
+                            exists.send_status = status_info.get("status", 0)
+                            exists.event_id = status_info.get("event_id", "")
+                        exists.save()
+                except exists_model.DoesNotExist:
+                    msg = "Could not find Exists record with message_id = '%s' for %s"
+                    msg = msg % (msg_id, service)
+                    raise NotFoundException(message=msg)
+                except exists_model.MultipleObjectsReturned:
+                    msg = "Multiple Exists records with message_id = '%s' for %s"
+                    msg = msg % (msg_id, service)
+                    print msg
+                    raise APIException(message=msg)
 
 
 def _exists_send_status_batch(request):
@@ -314,13 +319,13 @@ def _exists_send_status_batch(request):
             nova_pings = messages
             if nova_pings:
                 _ping_processing_with_service(nova_pings, service)
-        if version == 1:
-            nova_pings = messages['nova']
-            glance_pings = messages['glance']
+        if version == 1 or version == 2:
+            nova_pings = messages.get('nova', {})
+            glance_pings = messages.get('glance', {})
             if nova_pings:
-                _ping_processing_with_service(nova_pings, 'nova')
+                _ping_processing_with_service(nova_pings, 'nova', version)
             if glance_pings:
-                _ping_processing_with_service(glance_pings, 'glance')
+                _ping_processing_with_service(glance_pings, 'glance', version)
     else:
         msg = "'messages' missing from request body"
         raise BadRequestException(message=msg)
diff --git a/stacktach/migrations/0012_auto__add_field_instanceexists_event_id__add_field_imageexists_event_i.py b/stacktach/migrations/0012_auto__add_field_instanceexists_event_id__add_field_imageexists_event_i.py
new file mode 100644
index 0000000..74779b4
--- /dev/null
+++ b/stacktach/migrations/0012_auto__add_field_instanceexists_event_id__add_field_imageexists_event_i.py
@@ -0,0 +1,239 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        # Adding field 'InstanceExists.event_id'
+        db.add_column(u'stacktach_instanceexists', 'event_id',
+                      self.gf('django.db.models.fields.CharField')(max_length=50, null=True, blank=True),
+                      keep_default=False)
+
+        # Adding field 'ImageExists.event_id'
+        db.add_column(u'stacktach_imageexists', 'event_id',
+                      self.gf('django.db.models.fields.CharField')(max_length=50, null=True, blank=True),
+                      keep_default=False)
+
+
+    def backwards(self, orm):
+        # Deleting field 'InstanceExists.event_id'
+        db.delete_column(u'stacktach_instanceexists', 'event_id')
+
+        # Deleting field 'ImageExists.event_id'
+        db.delete_column(u'stacktach_imageexists', 'event_id')
+
+
+    models = {
+        u'stacktach.deployment': {
+            'Meta': {'object_name': 'Deployment'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        u'stacktach.genericrawdata': {
+            'Meta': {'object_name': 'GenericRawData'},
+            'deployment': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['stacktach.Deployment']"}),
+            'event': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'host': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'instance': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'json': ('django.db.models.fields.TextField', [], {}),
+            'message_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'publisher': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'request_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'routing_key': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'service': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'tenant': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'when': ('django.db.models.fields.DecimalField', [], {'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'})
+        },
+        u'stacktach.glancerawdata': {
+            'Meta': {'object_name': 'GlanceRawData'},
+            'deployment': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['stacktach.Deployment']"}),
+            'event': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'host': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'image_type': ('django.db.models.fields.IntegerField', [], {'default': '0', 'null': 'True', 'db_index': 'True'}),
+            'instance': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'json': ('django.db.models.fields.TextField', [], {}),
+            'owner': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'publisher': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'request_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'routing_key': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'service': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'status': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'db_index': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '36', 'null': 'True', 'blank': 'True'}),
+            'when': ('django.db.models.fields.DecimalField', [], {'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'})
+        },
+        u'stacktach.imagedeletes': {
+            'Meta': {'object_name': 'ImageDeletes'},
+            'deleted_at': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'raw': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['stacktach.GlanceRawData']", 'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'})
+        },
+        u'stacktach.imageexists': {
+            'Meta': {'object_name': 'ImageExists'},
+            'audit_period_beginning': ('django.db.models.fields.DecimalField', [], {'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'}),
+            'audit_period_ending': ('django.db.models.fields.DecimalField', [], {'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'}),
+            'created_at': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'}),
+            'delete': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'to': u"orm['stacktach.ImageDeletes']"}),
+            'deleted_at': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'}),
+            'event_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'fail_reason': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'message_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'owner': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'db_index': 'True'}),
+            'raw': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': u"orm['stacktach.GlanceRawData']"}),
+            'send_status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'db_index': 'True'}),
+            'size': ('django.db.models.fields.BigIntegerField', [], {'max_length': '20'}),
+            'status': ('django.db.models.fields.CharField', [], {'default': "'pending'", 'max_length': '50', 'db_index': 'True'}),
+            'usage': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'to': u"orm['stacktach.ImageUsage']"}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'db_index': 'True'})
+        },
+        u'stacktach.imageusage': {
+            'Meta': {'object_name': 'ImageUsage'},
+            'created_at': ('django.db.models.fields.DecimalField', [], {'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'last_raw': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['stacktach.GlanceRawData']", 'null': 'True'}),
+            'owner': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'db_index': 'True'}),
+            'size': ('django.db.models.fields.BigIntegerField', [], {'max_length': '20'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'})
+        },
+        u'stacktach.instancedeletes': {
+            'Meta': {'object_name': 'InstanceDeletes'},
+            'deleted_at': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'instance': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'launched_at': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'}),
+            'raw': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['stacktach.RawData']", 'null': 'True'})
+        },
+        u'stacktach.instanceexists': {
+            'Meta': {'object_name': 'InstanceExists'},
+            'audit_period_beginning': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'}),
+            'audit_period_ending': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'}),
+            'bandwidth_public_out': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+            'delete': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'to': u"orm['stacktach.InstanceDeletes']"}),
+            'deleted_at': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'}),
+            'event_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'fail_reason': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '300', 'null': 'True', 'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'instance': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'instance_flavor_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'instance_type_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'launched_at': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'}),
+            'message_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'os_architecture': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'os_distro': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'os_version': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'raw': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'to': u"orm['stacktach.RawData']"}),
+            'rax_options': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'send_status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'null': 'True', 'db_index': 'True'}),
+            'status': ('django.db.models.fields.CharField', [], {'default': "'pending'", 'max_length': '50', 'db_index': 'True'}),
+            'tenant': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'usage': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'to': u"orm['stacktach.InstanceUsage']"})
+        },
+        u'stacktach.instancereconcile': {
+            'Meta': {'object_name': 'InstanceReconcile'},
+            'deleted_at': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'instance': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'instance_flavor_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'instance_type_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'launched_at': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'}),
+            'os_architecture': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'os_distro': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'os_version': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'rax_options': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'row_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'row_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'source': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '150', 'null': 'True', 'blank': 'True'}),
+            'tenant': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'})
+        },
+        u'stacktach.instanceusage': {
+            'Meta': {'object_name': 'InstanceUsage'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'instance': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'instance_flavor_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'instance_type_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'launched_at': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'}),
+            'os_architecture': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'os_distro': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'os_version': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'rax_options': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'request_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'tenant': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'})
+        },
+        u'stacktach.jsonreport': {
+            'Meta': {'object_name': 'JsonReport'},
+            'created': ('django.db.models.fields.DecimalField', [], {'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'json': ('django.db.models.fields.TextField', [], {}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'period_end': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
+            'period_start': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
+            'version': ('django.db.models.fields.IntegerField', [], {'default': '1'})
+        },
+        u'stacktach.lifecycle': {
+            'Meta': {'object_name': 'Lifecycle'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'instance': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'last_raw': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['stacktach.RawData']", 'null': 'True'}),
+            'last_state': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'last_task_state': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'})
+        },
+        u'stacktach.rawdata': {
+            'Meta': {'object_name': 'RawData'},
+            'deployment': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['stacktach.Deployment']"}),
+            'event': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'host': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'image_type': ('django.db.models.fields.IntegerField', [], {'default': '0', 'null': 'True', 'db_index': 'True'}),
+            'instance': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'json': ('django.db.models.fields.TextField', [], {}),
+            'old_state': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '20', 'null': 'True', 'blank': 'True'}),
+            'old_task': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '30', 'null': 'True', 'blank': 'True'}),
+            'publisher': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'request_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'routing_key': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'service': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'state': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '20', 'null': 'True', 'blank': 'True'}),
+            'task': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '30', 'null': 'True', 'blank': 'True'}),
+            'tenant': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'when': ('django.db.models.fields.DecimalField', [], {'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'})
+        },
+        u'stacktach.rawdataimagemeta': {
+            'Meta': {'object_name': 'RawDataImageMeta'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'os_architecture': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'os_distro': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'os_version': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'raw': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['stacktach.RawData']"}),
+            'rax_options': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+        },
+        u'stacktach.requesttracker': {
+            'Meta': {'object_name': 'RequestTracker'},
+            'completed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+            'duration': ('django.db.models.fields.DecimalField', [], {'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'last_timing': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['stacktach.Timing']", 'null': 'True'}),
+            'lifecycle': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['stacktach.Lifecycle']"}),
+            'request_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'start': ('django.db.models.fields.DecimalField', [], {'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'})
+        },
+        u'stacktach.timing': {
+            'Meta': {'object_name': 'Timing'},
+            'diff': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '20', 'decimal_places': '6', 'db_index': 'True'}),
+            'end_raw': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'to': u"orm['stacktach.RawData']"}),
+            'end_when': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '20', 'decimal_places': '6'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'lifecycle': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['stacktach.Lifecycle']"}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'start_raw': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'to': u"orm['stacktach.RawData']"}),
+            'start_when': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '20', 'decimal_places': '6'})
+        }
+    }
+
+    complete_apps = ['stacktach']
\ No newline at end of file
diff --git a/stacktach/models.py b/stacktach/models.py
index 4a1ae9d..f17f40f 100644
--- a/stacktach/models.py
+++ b/stacktach/models.py
@@ -305,6 +305,7 @@ class InstanceExists(models.Model):
     bandwidth_public_out = models.BigIntegerField(default=0)
     instance_flavor_id = models.CharField(max_length=100, null=True,
                                           blank=True, db_index=True)
+    event_id = models.CharField(max_length=50, null=True,blank=True)
 
     def deployment(self):
         return self.raw.deployment
@@ -525,6 +526,8 @@ class ImageExists(models.Model):
     size = models.BigIntegerField(max_length=20)
     message_id = models.CharField(max_length=50, null=True,
                                   blank=True, db_index=True)
+    event_id = models.CharField(max_length=50, null=True,blank=True)
+
 
     def update_status(self, new_status):
         self.status = new_status
diff --git a/tests/unit/test_dbapi.py b/tests/unit/test_dbapi.py
index 3ee87e5..5440184 100644
--- a/tests/unit/test_dbapi.py
+++ b/tests/unit/test_dbapi.py
@@ -19,7 +19,6 @@
 # IN THE SOFTWARE.
 
 import datetime
-from decimal import Decimal
 import json
 
 from django.db.models import Count
@@ -36,6 +35,7 @@ from utils import INSTANCE_ID_1
 from utils import MESSAGE_ID_1
 from utils import MESSAGE_ID_2
 from utils import MESSAGE_ID_3
+from utils import MESSAGE_ID_4
 
 
 class DBAPITestCase(StacktachBaseTestCase):
@@ -645,6 +645,71 @@ class DBAPITestCase(StacktachBaseTestCase):
         self.assertEqual(resp.status_code, 200)
         self.mox.VerifyAll()
 
+    def test_send_status_batch_accepts_post_for_nova_and_glance_when_version_is_2(
+            self):
+        fake_request = self.mox.CreateMockAnything()
+        fake_request.method = 'POST'
+        fake_request.GET = {'service': 'glance'}
+        messages = {
+            'nova': {MESSAGE_ID_3: {'status': 201,
+                                    'event_id':
+                                        '95347e4d-4737-4438-b774-6a9219d78d2a'},
+                     MESSAGE_ID_4: {'status': 201,
+                                    'event_id':
+                                        '895347e4d-4737-4438-b774-6a9219d78d2a'}
+            },
+            'glance': {MESSAGE_ID_1: {'status': 201,
+                                      'event_id':
+                                          '95347e4d-4737-4438-b774-6a9219d78d2a'},
+                       MESSAGE_ID_2: {'status': 201,
+                                      'event_id':
+                                          '895347e4d-4737-4438-b774-6a9219d78d2a'}
+            }
+        }
+        body_dict = {'version': 2, 'messages': messages}
+        body = json.dumps(body_dict)
+        fake_request.body = body
+        self.mox.StubOutWithMock(transaction, 'commit_on_success')
+        trans_obj = self.mox.CreateMockAnything()
+        transaction.commit_on_success().AndReturn(trans_obj)
+        trans_obj.__enter__()
+        results1 = self.mox.CreateMockAnything()
+        results2 = self.mox.CreateMockAnything()
+        models.InstanceExists.objects.select_for_update().AndReturn(results1)
+        exists1 = self.mox.CreateMockAnything()
+        results1.get(message_id=MESSAGE_ID_4).AndReturn(exists1)
+        exists1.save()
+        models.InstanceExists.objects.select_for_update().AndReturn(results2)
+        exists2 = self.mox.CreateMockAnything()
+        results2.get(message_id=MESSAGE_ID_3).AndReturn(exists2)
+        exists2.save()
+        trans_obj.__exit__(None, None, None)
+        trans_obj = self.mox.CreateMockAnything()
+        transaction.commit_on_success().AndReturn(trans_obj)
+        trans_obj.__enter__()
+        results1 = self.mox.CreateMockAnything()
+        models.ImageExists.objects.select_for_update().AndReturn(results1)
+        exists1A = self.mox.CreateMockAnything()
+        exists1B = self.mox.CreateMockAnything()
+        results1.filter(message_id=MESSAGE_ID_2).AndReturn(
+            [exists1A, exists1B])
+        exists1A.save()
+        exists1B.save()
+        results2 = self.mox.CreateMockAnything()
+        models.ImageExists.objects.select_for_update().AndReturn(results2)
+        exists2A = self.mox.CreateMockAnything()
+        exists2B = self.mox.CreateMockAnything()
+        results2.filter(message_id=MESSAGE_ID_1).AndReturn(
+            [exists2A, exists2B])
+        exists2A.save()
+        exists2B.save()
+        trans_obj.__exit__(None, None, None)
+        self.mox.ReplayAll()
+
+        resp = dbapi.exists_send_status(fake_request, 'batch')
+        self.assertEqual(resp.status_code, 200)
+        self.mox.VerifyAll()
+
     def test_send_status_batch_not_found(self):
         fake_request = self.mox.CreateMockAnything()
         fake_request.method = 'PUT'
diff --git a/tests/unit/utils.py b/tests/unit/utils.py
index 581c7e4..0ccdbe3 100644
--- a/tests/unit/utils.py
+++ b/tests/unit/utils.py
@@ -43,6 +43,7 @@ DECIMAL_DUMMY_TIME = dt.dt_to_decimal(DUMMY_TIME)
 MESSAGE_ID_1 = "7f28f81b-29a2-43f2-9ba1-ccb3e53ab6c8"
 MESSAGE_ID_2 = "4d596126-0f04-4329-865f-7b9a7bd69bcf"
 MESSAGE_ID_3 = "4d596126-0f04-4329-865f-797387adf45c"
+MESSAGE_ID_4 = "4d596126-0f04-4329-865f-797387adf45e"
 
 BANDWIDTH_PUBLIC_OUTBOUND = 1697240969