From 534d2367e83f5f9fd895daf86de0177ce884a73f Mon Sep 17 00:00:00 2001 From: Boris Pavlovic Date: Mon, 18 Feb 2013 04:45:42 +0400 Subject: [PATCH] Remove race condition (in Networks) Soft delete all duplicate rows with the same vlan except one with the biggest value in `id` column. Create UC on fields (vlan, deleted) Replace Select then Insert -> Try to Insert. Fix error in network_update method. We were able to update vlan to duplicate. Fix typo in description of method drop_old_duplicate_entries_from_table() blueprint db-enforce-unique-keys Change-Id: Ia1b58ab5a5e369a1939de0b5c2f89aee6fc2c40b --- nova/tests/test_db_api.py | 10 ++++++++++ nova/tests/test_migrations.py | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py index cf81cca7..346e0b2b 100644 --- a/nova/tests/test_db_api.py +++ b/nova/tests/test_db_api.py @@ -334,6 +334,16 @@ class DbApiTestCase(test.TestCase): self.assertRaises(exception.DuplicateVlan, db.network_create_safe, ctxt, values2) + def test_network_update_with_duplicate_vlan(self): + ctxt = context.get_admin_context() + values1 = {'host': 'localhost', 'project_id': 'project1', 'vlan': 1} + values2 = {'host': 'something', 'project_id': 'project1', 'vlan': 2} + network_ref = db.network_create_safe(ctxt, values1) + db.network_create_safe(ctxt, values2) + self.assertRaises(exception.DuplicateVlan, + db.network_update, + ctxt, network_ref["id"], values2) + def test_instance_update_with_instance_uuid(self): # test instance_update() works when an instance UUID is passed. ctxt = context.get_admin_context() diff --git a/nova/tests/test_migrations.py b/nova/tests/test_migrations.py index fafe3348..6f55ce84 100644 --- a/nova/tests/test_migrations.py +++ b/nova/tests/test_migrations.py @@ -860,6 +860,26 @@ class TestNovaMigrations(BaseMigrationTestCase): # recheck the 149 data self._check_149(engine, data) + def _prerun_158(self, engine): + networks = get_table(engine, 'networks') + data = [ + {'vlan': 1, 'deleted': 0}, + {'vlan': 1, 'deleted': 0}, + {'vlan': 1, 'deleted': 0}, + ] + + for item in data: + networks.insert().values(item).execute() + return data + + def _check_158(self, engine, data): + networks = get_table(engine, 'networks') + rows = networks.select().\ + where(networks.c.deleted != networks.c.id).\ + execute().\ + fetchall() + self.assertEqual(len(rows), 1) + class TestBaremetalMigrations(BaseMigrationTestCase): """Test sqlalchemy-migrate migrations."""