Handle templated cell mappings in nova-status
The nova-status upgrade check code is intentionally written to not use versioned objects and just work with the data model directly. However, CellMapping database_connection template support was added in Rocky and the template URL is only formatted when using the object on read from the database, which means if you are using a template for the database_connection nova-status will break since the get_engine() code is getting a template string rather than a properly formatted URL. This change fixes the bug by using the CellMapping object code to pull the mappings from the database which will format the database connection URL. Note that we cannot simply update the sqlalchemy RowProxy objects we get normally since those are read-only, and because of how the mappings are used as objects with attribute access rather than as a dict we cannot just convert the RowProxy to a dict - we would have to put it in some kind of object for attribute access and if we are going to do that we might as well just use the CellMapping objects we have so that's what we do in this change. Change-Id: I5ce175517f6feb6e82ba507078a565b71427a4b0 Closes-Bug: #1818047
This commit is contained in:
parent
047f8c71c2
commit
38f2ce549c
|
@ -99,8 +99,8 @@ class UpgradeCommands(upgradecheck.UpgradeCommands):
|
||||||
meta = MetaData()
|
meta = MetaData()
|
||||||
meta.bind = db_session.get_api_engine()
|
meta.bind = db_session.get_api_engine()
|
||||||
|
|
||||||
cell_mappings = Table('cell_mappings', meta, autoload=True)
|
cell_mappings = self._get_cell_mappings()
|
||||||
count = select([sqlfunc.count()]).select_from(cell_mappings).scalar()
|
count = len(cell_mappings)
|
||||||
# Two mappings are required at a minimum, cell0 and your first cell
|
# Two mappings are required at a minimum, cell0 and your first cell
|
||||||
if count < 2:
|
if count < 2:
|
||||||
msg = _('There needs to be at least two cell mappings, one for '
|
msg = _('There needs to be at least two cell mappings, one for '
|
||||||
|
@ -109,10 +109,8 @@ class UpgradeCommands(upgradecheck.UpgradeCommands):
|
||||||
'retry.')
|
'retry.')
|
||||||
return upgradecheck.Result(upgradecheck.Code.FAILURE, msg)
|
return upgradecheck.Result(upgradecheck.Code.FAILURE, msg)
|
||||||
|
|
||||||
count = select([sqlfunc.count()]).select_from(cell_mappings).where(
|
cell0 = any(mapping.is_cell0() for mapping in cell_mappings)
|
||||||
cell_mappings.c.uuid ==
|
if not cell0:
|
||||||
cell_mapping_obj.CellMapping.CELL0_UUID).scalar()
|
|
||||||
if count != 1:
|
|
||||||
msg = _('No cell0 mapping found. Run command '
|
msg = _('No cell0 mapping found. Run command '
|
||||||
'\'nova-manage cell_v2 simple_cell_setup\' and then '
|
'\'nova-manage cell_v2 simple_cell_setup\' and then '
|
||||||
'retry.')
|
'retry.')
|
||||||
|
@ -189,12 +187,38 @@ class UpgradeCommands(upgradecheck.UpgradeCommands):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_non_cell0_mappings():
|
def _get_non_cell0_mappings():
|
||||||
"""Queries the API database for non-cell0 cell mappings."""
|
"""Queries the API database for non-cell0 cell mappings.
|
||||||
meta = MetaData(bind=db_session.get_api_engine())
|
|
||||||
cell_mappings = Table('cell_mappings', meta, autoload=True)
|
:returns: list of nova.objects.CellMapping objects
|
||||||
return cell_mappings.select().where(
|
"""
|
||||||
cell_mappings.c.uuid !=
|
return UpgradeCommands._get_cell_mappings(include_cell0=False)
|
||||||
cell_mapping_obj.CellMapping.CELL0_UUID).execute().fetchall()
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_cell_mappings(include_cell0=True):
|
||||||
|
"""Queries the API database for cell mappings.
|
||||||
|
|
||||||
|
.. note:: This method is unique in that it queries the database using
|
||||||
|
CellMappingList.get_all() rather than a direct query using
|
||||||
|
the sqlalchemy models. This is because
|
||||||
|
CellMapping.database_connection can be a template and the
|
||||||
|
object takes care of formatting the URL. We cannot use
|
||||||
|
RowProxy objects from sqlalchemy because we cannot set the
|
||||||
|
formatted 'database_connection' value back on those objects
|
||||||
|
(they are read-only).
|
||||||
|
|
||||||
|
:param include_cell0: True if cell0 should be returned, False if cell0
|
||||||
|
should be excluded from the results.
|
||||||
|
:returns: list of nova.objects.CellMapping objects
|
||||||
|
"""
|
||||||
|
ctxt = nova_context.get_admin_context()
|
||||||
|
cell_mappings = cell_mapping_obj.CellMappingList.get_all(ctxt)
|
||||||
|
if not include_cell0:
|
||||||
|
# Since CellMappingList does not implement remove() we have to
|
||||||
|
# create a new list and exclude cell0.
|
||||||
|
mappings = [mapping for mapping in cell_mappings
|
||||||
|
if not mapping.is_cell0()]
|
||||||
|
cell_mappings = cell_mapping_obj.CellMappingList(objects=mappings)
|
||||||
|
return cell_mappings
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _is_ironic_instance_migrated(extras, inst):
|
def _is_ironic_instance_migrated(extras, inst):
|
||||||
|
@ -265,7 +289,7 @@ class UpgradeCommands(upgradecheck.UpgradeCommands):
|
||||||
# instance so increment the number of
|
# instance so increment the number of
|
||||||
# unmigrated instances in this cell.
|
# unmigrated instances in this cell.
|
||||||
unmigrated_instance_count_by_cell[
|
unmigrated_instance_count_by_cell[
|
||||||
cell_mapping['uuid']] += 1
|
cell_mapping.uuid] += 1
|
||||||
|
|
||||||
if not cell_mappings:
|
if not cell_mappings:
|
||||||
# There are no non-cell0 mappings so we can't determine this, just
|
# There are no non-cell0 mappings so we can't determine this, just
|
||||||
|
@ -309,8 +333,7 @@ class UpgradeCommands(upgradecheck.UpgradeCommands):
|
||||||
nova-conductor.
|
nova-conductor.
|
||||||
"""
|
"""
|
||||||
meta = MetaData(bind=db_session.get_api_engine())
|
meta = MetaData(bind=db_session.get_api_engine())
|
||||||
cell_mappings = Table('cell_mappings', meta, autoload=True)
|
mappings = self._get_cell_mappings()
|
||||||
mappings = cell_mappings.select().execute().fetchall()
|
|
||||||
|
|
||||||
if not mappings:
|
if not mappings:
|
||||||
# There are no cell mappings so we can't determine this, just
|
# There are no cell mappings so we can't determine this, just
|
||||||
|
@ -344,7 +367,7 @@ class UpgradeCommands(upgradecheck.UpgradeCommands):
|
||||||
if spec_id is None:
|
if spec_id is None:
|
||||||
# This cell does not have all of its instances
|
# This cell does not have all of its instances
|
||||||
# migrated for request specs so track it and move on.
|
# migrated for request specs so track it and move on.
|
||||||
incomplete_cells.append(mapping['uuid'])
|
incomplete_cells.append(mapping.uuid)
|
||||||
break
|
break
|
||||||
|
|
||||||
# It's a failure if there are any unmigrated instances at this point
|
# It's a failure if there are any unmigrated instances at this point
|
||||||
|
@ -380,9 +403,7 @@ class UpgradeCommands(upgradecheck.UpgradeCommands):
|
||||||
# it's possible a deployment could have services stored in the cell0
|
# it's possible a deployment could have services stored in the cell0
|
||||||
# database, if they've defaulted their [database]connection in
|
# database, if they've defaulted their [database]connection in
|
||||||
# nova.conf to cell0.
|
# nova.conf to cell0.
|
||||||
meta = MetaData(bind=db_session.get_api_engine())
|
mappings = self._get_cell_mappings()
|
||||||
cell_mappings = Table('cell_mappings', meta, autoload=True)
|
|
||||||
mappings = cell_mappings.select().execute().fetchall()
|
|
||||||
|
|
||||||
if not mappings:
|
if not mappings:
|
||||||
# There are no cell mappings so we can't determine this, just
|
# There are no cell mappings so we can't determine this, just
|
||||||
|
@ -416,7 +437,7 @@ class UpgradeCommands(upgradecheck.UpgradeCommands):
|
||||||
# supports storing console token auths in the database backend.
|
# supports storing console token auths in the database backend.
|
||||||
for mapping in mappings:
|
for mapping in mappings:
|
||||||
# Skip cell0 as no compute services should be in it.
|
# Skip cell0 as no compute services should be in it.
|
||||||
if mapping['uuid'] == cell_mapping_obj.CellMapping.CELL0_UUID:
|
if mapping.is_cell0():
|
||||||
continue
|
continue
|
||||||
# Get the minimum nova-compute service version in this
|
# Get the minimum nova-compute service version in this
|
||||||
# cell.
|
# cell.
|
||||||
|
|
Loading…
Reference in New Issue