Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions nova/db/main/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4176,6 +4176,12 @@ def _get_fk_stmts(metadata, conn, table, column, records):
fk_column = fk_table.c.id

for fk in fk_table.foreign_keys:
if table != fk.column.table:
# if the foreign key doesn't actually point to the table we're
# archiving entries from then it's not relevant; trying to
# resolve this would result in a cartesian product
continue

# We need to find the records in the referring (child) table that
# correspond to the records in our (parent) table so we can archive
# them.
Expand Down Expand Up @@ -4225,6 +4231,7 @@ def _get_fk_stmts(metadata, conn, table, column, records):
# deque.
fk_delete = fk_table.delete().where(fk_column.in_(fk_records))
deletes.appendleft(fk_delete)

# Repeat for any possible nested child tables.
i, d = _get_fk_stmts(metadata, conn, fk_table, fk_column, fk_records)
inserts.extendleft(i)
Expand Down
12 changes: 8 additions & 4 deletions nova/objects/cell_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,11 +279,15 @@ def _get_by_project_id_from_db(context, project_id):
# SELECT DISTINCT cell_id FROM instance_mappings \
# WHERE project_id = $project_id;
cell_ids = context.session.query(
api_db_models.InstanceMapping.cell_id).filter_by(
project_id=project_id).distinct().subquery()
api_db_models.InstanceMapping.cell_id
).filter_by(
project_id=project_id
).distinct()
# SELECT cell_mappings WHERE cell_id IN ($cell_ids);
return context.session.query(api_db_models.CellMapping).filter(
api_db_models.CellMapping.id.in_(cell_ids)).all()
return context.session.query(
api_db_models.CellMapping).filter(
api_db_models.CellMapping.id.in_(cell_ids)
).all()

@classmethod
def get_by_project_id(cls, context, project_id):
Expand Down
10 changes: 10 additions & 0 deletions nova/tests/fixtures/nova.py
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,16 @@ def setUp(self):
message='Implicit coercion of SELECT and textual SELECT .*',
category=sqla_exc.SADeprecationWarning)

# Enable general SQLAlchemy warnings also to ensure we're not doing
# silly stuff. It's possible that we'll need to filter things out here
# with future SQLAlchemy versions, but that's a good thing

warnings.filterwarnings(
'error',
module='nova',
category=sqla_exc.SAWarning,
)

self.addCleanup(self._reset_warning_filters)

def _reset_warning_filters(self):
Expand Down
45 changes: 38 additions & 7 deletions nova/tests/functional/regressions/test_bug_1888395.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,8 @@
from nova.tests.functional.libvirt import base as libvirt_base


class TestLiveMigrationWithoutMultiplePortBindings(
class TestLiveMigrationWithoutMultiplePortBindingsBase(
libvirt_base.ServersTestBase):
"""Regression test for bug 1888395.

This regression test asserts that Live migration works when
neutron does not support the binding-extended api extension
and the legacy single port binding workflow is used.
"""

ADMIN_API = True
microversion = 'latest'
Expand Down Expand Up @@ -72,6 +66,16 @@ def setUp(self):
'nova.tests.fixtures.libvirt.Domain.migrateToURI3',
self._migrate_stub))


class TestLiveMigrationWithoutMultiplePortBindings(
TestLiveMigrationWithoutMultiplePortBindingsBase):
"""Regression test for bug 1888395.

This regression test asserts that Live migration works when
neutron does not support the binding-extended api extension
and the legacy single port binding workflow is used.
"""

def _migrate_stub(self, domain, destination, params, flags):
"""Stub out migrateToURI3."""

Expand Down Expand Up @@ -124,3 +128,30 @@ def test_live_migrate(self):
server, {'OS-EXT-SRV-ATTR:host': 'end_host', 'status': 'ACTIVE'})
msg = "NotImplementedError: Cannot load 'vif_type' in the base class"
self.assertNotIn(msg, self.stdlog.logger.output)


class TestLiveMigrationRollbackWithoutMultiplePortBindings(
TestLiveMigrationWithoutMultiplePortBindingsBase):

def _migrate_stub(self, domain, destination, params, flags):
source = self.computes['start_host']
conn = source.driver._host.get_connection()
dom = conn.lookupByUUIDString(self.server['id'])
dom.fail_job()

def test_live_migration_rollback(self):
self.server = self._create_server(
host='start_host',
networks=[{'port': self.neutron.port_1['id']}])

self.assertFalse(
self.neutron_api.has_port_binding_extension(self.ctxt))
# FIXME(artom) Until bug 1969980 is fixed, this will fail with a
# NotImplementedError.
self._live_migrate(self.server, migration_expected_state='error',
server_expected_state='ERROR')
server = self.api.get_server(self.server['id'])
self.assertIn(
"NotImplementedError: Cannot load 'vifs' in the base class",
server['fault']['details']
)