Set root_provider_id in the database

When nested resource provider feature was added in Rocky,
root_provider_id column, which should be non-None value, is created in
the resource provider DB.

However, online data migration is only done implicitly via listing or
showing resource providers. With this patch, executing the cli command

    `placement-manage db online_data_migrations`

makes sure all the resource providers are ready for nested provider
feature, that is, all the root_provider_ids in the DB have non-None
value.

Change-Id: I42a1afa69f379b095417f5eb106fe52ebff15017
Related-Bug:#1803925
This commit is contained in:
Tetsuro Nakamura 2018-12-11 20:21:04 +00:00 committed by Matt Riedemann
parent 80fa50187a
commit c198326150
5 changed files with 119 additions and 1 deletions

View File

@ -100,6 +100,7 @@ Placement Database
+---------------------------------------------+-------------+-----------+
| Migration | Total Found | Completed |
+---------------------------------------------+-------------+-----------+
| set_root_provider_ids | 0 | 0 |
| create_incomplete_consumers | 2 | 2 |
+---------------------------------------------+-------------+-----------+

View File

@ -25,6 +25,7 @@ from placement import context
from placement.db.sqlalchemy import migration
from placement import db_api
from placement.i18n import _
from placement.objects import resource_provider as rp_obj
version_info = pbr.version.VersionInfo('openstack-placement')
LOG = logging.getLogger(__name__)
@ -44,6 +45,7 @@ online_migrations = (
# have finished.
# Added in Stein
rp_obj.set_root_provider_ids,
)

View File

@ -744,7 +744,8 @@ def _has_child_providers(context, rp_id):
@db_api.placement_context_manager.writer
def _set_root_provider_id(context, rp_id, root_id):
"""Simply sets the root_provider_id value for a provider identified by
rp_id. Used in online data migration.
rp_id. Used in implicit online data migration via REST API getting
resource providers.
:param rp_id: Internal ID of the provider to update
:param root_id: Value to set root provider to
@ -754,6 +755,38 @@ def _set_root_provider_id(context, rp_id, root_id):
context.session.execute(upd)
@db_api.placement_context_manager.writer
def set_root_provider_ids(context, batch_size):
"""Simply sets the root_provider_id value for a provider identified by
rp_id. Used in explicit online data migration via CLI.
:param rp_id: Internal ID of the provider to update
:param root_id: Value to set root provider to
"""
# UPDATE resource_providers
# SET root_provider_id=resource_providers.id
# WHERE resource_providers.id
# IN (SELECT subq_1.id
# FROM (SELECT resource_providers.id AS id
# FROM resource_providers
# WHERE resource_providers.root_provider_id IS NULL
# LIMIT :param_1)
# AS subq_1)
subq_1 = context.session.query(_RP_TBL.c.id)
subq_1 = subq_1.filter(_RP_TBL.c.root_provider_id.is_(None))
subq_1 = subq_1.limit(batch_size)
subq_1 = sa.alias(subq_1.as_scalar(), name="subq_1")
subq_2 = sa.select([subq_1.c.id]).select_from(subq_1)
upd = _RP_TBL.update().where(_RP_TBL.c.id.in_(subq_2.as_scalar()))
upd = upd.values(root_provider_id=_RP_TBL.c.id)
res = context.session.execute(upd)
return res.rowcount, res.rowcount
ProviderIds = collections.namedtuple(
'ProviderIds', 'id uuid parent_id parent_uuid root_id root_uuid')

View File

@ -147,6 +147,78 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
# Make sure the object root_provider_uuid is set on load
self.assertEqual(rp.root_provider_uuid, uuidsentinel.rp1)
def test_set_root_provider(self):
"""Simulate old resource provider records in the database that has no
root_provider_uuid set and ensure the root_provider_uuid field in the
table is set to the provider's ID via set_root_provider_ids().
"""
# First, set up records for "old-style" resource providers with
# no root provider UUID.
rp_tbl = rp_obj._RP_TBL
conn = self.placement_db.get_engine().connect()
ins_stmt1 = rp_tbl.insert().values(
id=1,
uuid=uuidsentinel.rp1,
name='rp-1',
root_provider_id=None,
parent_provider_id=None,
generation=42,
)
ins_stmt2 = rp_tbl.insert().values(
id=2,
uuid=uuidsentinel.rp2,
name='rp-2',
root_provider_id=None,
parent_provider_id=None,
generation=42,
)
conn.execute(ins_stmt1)
conn.execute(ins_stmt2)
# Second, set up records for "new-style" resource providers
# in a tree
self._create_provider('root_rp')
self._create_provider('child_rp', parent=uuidsentinel.root_rp)
self._create_provider('grandchild_rp', parent=uuidsentinel.child_rp)
# Check rp_1 that it has no root provider id
sel_stmt = sa.select([rp_tbl.c.root_provider_id]).where(
rp_tbl.c.id == 1)
res = conn.execute(sel_stmt).fetchall()
self.assertIsNone(res[0][0])
# Check rp_2 that it has no root provider id
sel_stmt = sa.select([rp_tbl.c.root_provider_id]).where(
rp_tbl.c.id == 2)
res = conn.execute(sel_stmt).fetchall()
self.assertIsNone(res[0][0])
# Run set_root_provider_ids()
found, migrated = rp_obj.set_root_provider_ids(self.ctx, batch_size=10)
self.assertEqual(2, found)
self.assertEqual(2, migrated)
# Check rp_1 that it has got the root provider id
sel_stmt = sa.select([rp_tbl.c.root_provider_id]).where(
rp_tbl.c.id == 1)
res = conn.execute(sel_stmt).fetchall()
self.assertEqual(1, res[0][0])
# Check rp_2 that it has got the root provider id
sel_stmt = sa.select([rp_tbl.c.root_provider_id]).where(
rp_tbl.c.id == 2)
res = conn.execute(sel_stmt).fetchall()
self.assertEqual(2, res[0][0])
# Check the new-style providers remains in a tree,
# which means the root provider ids are not changed
rps = rp_obj.ResourceProviderList.get_all_by_filters(
self.ctx,
filters={
'in_tree': uuidsentinel.root_rp,
}
)
self.assertEqual(3, len(rps))
def test_inherit_root_from_parent(self):
"""Tests that if we update an existing provider's parent provider UUID,
that the root provider UUID of the updated provider is automatically

View File

@ -0,0 +1,10 @@
---
features:
- |
A new online data migration has been added to populate missing
``root_provider_id`` in the resource_providers table. This can
be run during the normal placement-manage db online_data_migrations
routine. See the `Bug#1803925`_ for more details.
.. _Bug#1803925: https://bugs.launchpad.net/nova/+bug/1803925