diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 46aa33c..98488a3 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -6028,22 +6028,21 @@ def instance_fault_get_by_instance_uuids(context, instance_uuids, # SELECT instance_uuid, MAX(id) AS max_id # FROM instance_faults # WHERE instance_uuid IN ( ... ) - # AND deleted IS NULL + # AND deleted = 0 # GROUP BY instance_uuid # ) AS latest_faults # ON instance_faults.id = latest_faults.max_id; faults_tbl = models.InstanceFault.__table__ - default_deleted = faults_tbl.c.deleted.default.arg - latest_faults = sql.select([ - faults_tbl.c.instance_uuid, - sql.func.max(faults_tbl.c.id).label('max_id'), - ]).where( + latest_faults = model_query( + context, models.InstanceFault, + [faults_tbl.c.instance_uuid, + sql.func.max(faults_tbl.c.id).label('max_id')], + read_deleted='no' + ).filter( faults_tbl.c.instance_uuid.in_(instance_uuids) - ).where( - faults_tbl.c.deleted == default_deleted ).group_by( faults_tbl.c.instance_uuid - ).alias(name="latest_faults") + ).subquery(name="latest_faults") join = sql.join( faults_tbl, @@ -6052,9 +6051,7 @@ def instance_fault_get_by_instance_uuids(context, instance_uuids, ) query = sql.select([faults_tbl]).select_from(join) - engine = get_engine(context) - conn = engine.connect() - rows = conn.execute(query).fetchall() + rows = context.session.execute(query).fetchall() output = {} for instance_uuid in instance_uuids: diff --git a/nova/tests/unit/db/test_db_api.py b/nova/tests/unit/db/test_db_api.py index e104000..f4c7605 100644 --- a/nova/tests/unit/db/test_db_api.py +++ b/nova/tests/unit/db/test_db_api.py @@ -4167,6 +4167,33 @@ class InstanceFaultTestCase(test.TestCase, ModelsObjectComparatorMixin): for uuid in uuids: self._assertEqualListsOfObjects(expected[uuid], faults[uuid]) + def test_instance_fault_get_latest_by_instance(self): + """Ensure we can retrieve only latest faults for instance.""" + uuids = [uuidsentinel.uuid1, uuidsentinel.uuid2] + fault_codes = [404, 500] + expected = {} + + # Create faults + for uuid in uuids: + db.instance_create(self.ctxt, {'uuid': uuid}) + + expected[uuid] = [] + for code in fault_codes: + fault_values = self._create_fault_values(uuid, code) + fault = db.instance_fault_create(self.ctxt, fault_values) + expected[uuid].append(fault) + + # We are only interested in the latest fault for each instance + for uuid in expected: + expected[uuid] = expected[uuid][-1:] + + # Ensure faults are saved + faults = db.instance_fault_get_by_instance_uuids(self.ctxt, uuids, + latest=True) + self.assertEqual(len(expected), len(faults)) + for uuid in uuids: + self._assertEqualListsOfObjects(expected[uuid], faults[uuid]) + def test_instance_faults_get_by_instance_uuids_no_faults(self): uuid = uuidsentinel.uuid1 # None should be returned when no faults exist.