Merge "Ensure that os-traits sync is attempted only at start of process"

This commit is contained in:
Zuul 2018-06-20 18:23:01 +00:00 committed by Gerrit Code Review
commit 4938584f6b
10 changed files with 35 additions and 36 deletions

View File

@ -38,3 +38,8 @@ def configure(conf):
def get_placement_engine():
return placement_context_manager.get_legacy_facade().get_engine()
@enginefacade.transaction_context_provider
class DbContext(object):
"""Stub class for db session handling outside of web requests."""

View File

@ -16,9 +16,11 @@ import oslo_middleware
from oslo_middleware import cors
from nova.api.openstack.placement import auth
from nova.api.openstack.placement import db_api
from nova.api.openstack.placement import fault_wrap
from nova.api.openstack.placement import handler
from nova.api.openstack.placement import microversion
from nova.api.openstack.placement.objects import resource_provider
from nova.api.openstack.placement import requestlog
from nova.api.openstack.placement import util
@ -82,6 +84,14 @@ def deploy(conf):
return application
def update_database():
"""Do any database updates required at process boot time, such as
updating the traits database.
"""
ctx = db_api.DbContext()
resource_provider.ensure_trait_sync(ctx)
# NOTE(cdent): Althought project_name is no longer used because of the
# resolution of https://bugs.launchpad.net/nova/+bug/1734491, loadapp()
# is considered a public interface for the creation of a placement
@ -98,4 +108,5 @@ def loadapp(config, project_name=NAME):
backwards compatibility
"""
application = deploy(config)
update_database()
return application

View File

@ -123,7 +123,7 @@ def _trait_sync(ctx):
pass # some other process sync'd, just ignore
def _ensure_trait_sync(ctx):
def ensure_trait_sync(ctx):
"""Ensures that the os_traits library is synchronized to the traits db.
If _TRAITS_SYNCED is False then this process has not tried to update the
@ -1448,7 +1448,6 @@ class ResourceProviderList(base.ObjectListBase, base.VersionedObject):
:type filters: dict
"""
_ensure_rc_cache(context)
_ensure_trait_sync(context)
resource_providers = cls._get_all_by_filters_from_db(context, filters)
return base.obj_make_list(context, cls(context),
ResourceProvider, resource_providers)
@ -2387,7 +2386,6 @@ class Trait(base.VersionedObject, base.TimestampedObject):
@staticmethod
@db_api.placement_context_manager.writer # trait sync can cause a write
def _get_by_name_from_db(context, name):
_ensure_trait_sync(context)
result = context.session.query(models.Trait).filter_by(
name=name).first()
if not result:
@ -2437,7 +2435,6 @@ class TraitList(base.ObjectListBase, base.VersionedObject):
@staticmethod
@db_api.placement_context_manager.writer # trait sync can cause a write
def _get_all_from_db(context, filters):
_ensure_trait_sync(context)
if not filters:
filters = {}
@ -3826,7 +3823,6 @@ class AllocationCandidates(base.VersionedObject):
according to `limit`.
"""
_ensure_rc_cache(context)
_ensure_trait_sync(context)
alloc_reqs, provider_summaries = cls._get_by_requests(
context, requests, limit=limit, group_policy=group_policy)
return cls(

View File

@ -312,7 +312,10 @@ class TestCase(testtools.TestCase):
utils._IS_NEUTRON = None
# Reset the traits sync and rc cache flags
resource_provider._TRAITS_SYNCED = False
def _reset_traits():
resource_provider._TRAITS_SYNCED = False
_reset_traits()
self.addCleanup(_reset_traits)
resource_provider._RC_CACHE = None
# Reset the global QEMU version flag.
images.QEMU_VERSION = None

View File

@ -14,6 +14,7 @@
from oslo_utils import uuidutils
from nova.api.openstack.placement import deploy
from nova.api.openstack.placement import exception
from nova.api.openstack.placement.objects import consumer as consumer_obj
from nova.api.openstack.placement.objects import project as project_obj
@ -55,26 +56,18 @@ class PlacementDbBaseTestCase(test.NoDBTestCase):
self.useFixture(fixtures.Database())
self.placement_db = self.useFixture(
fixtures.Database(database='placement'))
# Reset the _TRAITS_SYNCED global before we start and after
# we are done since other tests (notably the gabbi tests)
# may have caused it to change.
self._reset_traits_synced()
self.addCleanup(self._reset_traits_synced)
self.ctx = context.RequestContext('fake-user', 'fake-project')
self.user_obj = user_obj.User(self.ctx, external_id='fake-user')
self.user_obj.create()
self.project_obj = project_obj.Project(
self.ctx, external_id='fake-project')
self.project_obj.create()
# Do database syncs, such as traits sync.
deploy.update_database()
# For debugging purposes, populated by _create_provider and used by
# _validate_allocation_requests to make failure results more readable.
self.rp_uuid_to_name = {}
@staticmethod
def _reset_traits_synced():
"""Reset the _TRAITS_SYNCED boolean to base state."""
rp_obj._TRAITS_SYNCED = False
def _create_provider(self, name, *aggs, **kwargs):
parent = kwargs.get('parent')
root = kwargs.get('root')

View File

@ -2032,6 +2032,10 @@ class ResourceProviderTraitTestCase(tb.PlacementDbBaseTestCase):
# in an exception, the sync transaction rolled back and the table
# stayed empty; but _TRAITS_SYNCED got set to True, so it didn't resync
# next time.
# NOTE(cdent): With change Ic87518948ed5bf4ab79f9819cd94714e350ce265
# syncing is no longer done in the same way, so the bug fix that this
# test was testing is gone, but this test has been left in place to
# make sure we still get behavior we expect.
try:
rp_obj.Trait.get_by_name(self.ctx, 'CUSTOM_GOLD')
except exception.TraitNotFound:
@ -2193,25 +2197,6 @@ class ResourceProviderTraitTestCase(tb.PlacementDbBaseTestCase):
rp_obj.TraitList.get_all(self.ctx,
filters={'associated': False}))
def test_sync_standard_traits(self):
"""Tests that on a clean DB, we have zero traits in the DB but after
list all traits, os_traits have been synchronized.
"""
std_traits = os_traits.get_traits()
conn = self.placement_db.get_engine().connect()
def _db_traits(conn):
sel = sa.select([rp_obj._TRAIT_TBL.c.name])
return [r[0] for r in conn.execute(sel).fetchall()]
self.assertEqual([], _db_traits(conn))
all_traits = [trait.name for trait in
rp_obj.TraitList.get_all(self.ctx)]
self.assertEqual(set(std_traits), set(all_traits))
# confirm with a raw request
self.assertEqual(set(std_traits), set(_db_traits(conn)))
class SharedProviderTestCase(tb.PlacementDbBaseTestCase):
"""Tests that the queries used to determine placement in deployments with

View File

@ -88,6 +88,9 @@ class APIFixture(fixture.GabbiFixture):
self.placement_db_fixture.reset()
self.api_db_fixture.reset()
self.main_db_fixture.reset()
# Do this now instead of waiting for the WSGI app to start so that
# fixtures can have traits.
deploy.update_database()
os.environ['RP_UUID'] = uuidutils.generate_uuid()
os.environ['RP_NAME'] = uuidutils.generate_uuid()

View File

@ -85,6 +85,7 @@ class _IntegratedTestBase(test.TestCase):
nova.tests.unit.image.fake.stub_out_image_service(self)
self.useFixture(cast_as_call.CastAsCall(self))
self.useFixture(nova_fixtures.Database(database='placement'))
placement = self.useFixture(nova_fixtures.PlacementFixture())
self.placement_api = placement.api

View File

@ -338,7 +338,7 @@ class TestTraits(_TestCase):
synced = resource_provider._TRAITS_SYNCED
self.assertFalse(synced)
# Sync the traits
resource_provider._ensure_trait_sync(self.context)
resource_provider.ensure_trait_sync(self.context)
synced = resource_provider._TRAITS_SYNCED
self.assertTrue(synced)

View File

@ -478,6 +478,8 @@ class TestPlacementFixture(testtools.TestCase):
self.useFixture(conf_fixture.ConfFixture())
# We need PlacementPolicyFixture because placement-api checks policy.
self.useFixture(policy_fixture.PlacementPolicyFixture())
# Database is needed to start placement API
self.useFixture(fixtures.Database(database='placement'))
def test_responds_to_version(self):
"""Ensure the Placement server responds to calls sensibly."""