From c58a2c7c65feb7a9aa74c1f116865e14da511614 Mon Sep 17 00:00:00 2001 From: Gregory Thiemonge Date: Fri, 18 Jun 2021 08:05:31 +0200 Subject: [PATCH] Fix new errors with SQLAlchemy 1.4 Fixed in Repositories.get_amphora_stats: TypeError: unsupported operand type(s) for +: 'ImmutableColumnCollection' and 'list' Fixed in many places: KeyError: "Deferred loader for attribute 'id' failed to populate correctly" Modifying an object without using a transaction created some issues with the next query. SQLAlchemy flushed and expired the modified object while it still needed to read one attribute. This is a weird behavior in SQLAlchemy>=1.4 (perhaps a bug), but using transactions seems the correct way to update the objects. Note: The message in the SQLAlchemy exception is totally bogus. Change-Id: I64b5c70fca7f1cacb2ef10c2b61f28b9000c7504 --- octavia/db/repositories.py | 5 +++-- octavia/tests/functional/db/test_models.py | 16 ++++++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/octavia/db/repositories.py b/octavia/db/repositories.py index 362c3b9cdd..7c50b44b36 100644 --- a/octavia/db/repositories.py +++ b/octavia/db/repositories.py @@ -807,7 +807,7 @@ class Repositories(object): :returns: An amphora stats dictionary """ with session.begin(subtransactions=True): - columns = (models.ListenerStatistics.__table__.columns + + columns = (list(models.ListenerStatistics.__table__.columns) + [models.Amphora.load_balancer_id]) amp_records = ( session.query(*columns) @@ -1920,7 +1920,8 @@ class L7PolicyRepository(BaseRepository): listener.l7policies.reorder() session.flush() - l7policy.updated_at = None + with session.begin(subtransactions=True): + l7policy.updated_at = None return self.get(session, id=l7policy.id) def delete(self, session, id, **filters): diff --git a/octavia/tests/functional/db/test_models.py b/octavia/tests/functional/db/test_models.py index 0cb1b77eca..60bc8d9d4a 100644 --- a/octavia/tests/functional/db/test_models.py +++ b/octavia/tests/functional/db/test_models.py @@ -494,7 +494,8 @@ class HealthMonitorModelTest(base.OctaviaDBTestBase, ModelTestMixin): def test_update(self): health_monitor = self.create_health_monitor(self.session, self.pool.id) - health_monitor.name = 'test1' + with self.session.begin(): + health_monitor.name = 'test1' new_health_monitor = self.session.query( models.HealthMonitor).filter_by( pool_id=health_monitor.pool_id).first() @@ -585,7 +586,8 @@ class VipModelTest(base.OctaviaDBTestBase, ModelTestMixin): def test_update(self): vip = self.create_vip(self.session, self.load_balancer.id) - vip.ip_address = "10.0.0.1" + with self.session.begin(): + vip.ip_address = "10.0.0.1" new_vip = self.session.query(models.Vip).filter_by( load_balancer_id=self.load_balancer.id).first() self.assertEqual("10.0.0.1", new_vip.ip_address) @@ -718,8 +720,9 @@ class L7PolicyModelTest(base.OctaviaDBTestBase, ModelTestMixin): def test_update(self): l7policy = self.create_l7policy(self.session, self.listener.id) pool = self.create_pool(self.session) - l7policy.action = constants.L7POLICY_ACTION_REDIRECT_TO_POOL - l7policy.redirect_pool_id = pool.id + with self.session.begin(): + l7policy.action = constants.L7POLICY_ACTION_REDIRECT_TO_POOL + l7policy.redirect_pool_id = pool.id new_l7policy = self.session.query( models.L7Policy).filter_by(id=l7policy.id).first() self.assertEqual(pool.id, new_l7policy.redirect_pool_id) @@ -758,8 +761,9 @@ class L7PolicyModelTest(base.OctaviaDBTestBase, ModelTestMixin): def test_pool_relationship(self): l7policy = self.create_l7policy(self.session, self.listener.id) self.create_pool(self.session, id=self.FAKE_UUID_2) - l7policy.action = constants.L7POLICY_ACTION_REDIRECT_TO_POOL - l7policy.redirect_pool_id = self.FAKE_UUID_2 + with self.session.begin(): + l7policy.action = constants.L7POLICY_ACTION_REDIRECT_TO_POOL + l7policy.redirect_pool_id = self.FAKE_UUID_2 new_l7policy = self.session.query( models.L7Policy).filter_by(id=l7policy.id).first() self.assertIsNotNone(new_l7policy.redirect_pool)