FUPs: ReportClient traffic series
This is a catch-all patch for the code series around reducing the traffic from the ReportClient to placement. The following issues are addressed: - https://review.openstack.org/#/c/615677/20/nova/scheduler/client/report.py@310 - https://review.openstack.org/#/c/615695/20/nova/scheduler/client/report.py@808 - https://review.openstack.org/#/c/615695/20/nova/scheduler/client/report.py@872 - https://review.openstack.org/#/c/615695/20/nova/tests/unit/scheduler/client/test_report.py@2864 - https://review.openstack.org/#/c/615695/20/nova/tests/unit/scheduler/client/test_report.py@2884 - https://review.openstack.org/#/c/615695/20/nova/tests/unit/scheduler/client/test_report.py@2894 Change-Id: If3f3dd6487243a506488f068f8c820257098b855
This commit is contained in:
parent
35ce77835b
commit
f4ec394e86
|
@ -259,8 +259,8 @@ class SchedulerReportClient(object):
|
||||||
# timer dict, so nothing to clear.
|
# timer dict, so nothing to clear.
|
||||||
return
|
return
|
||||||
|
|
||||||
# get_provider_uuids returns UUIDs in top-down order, so the first one
|
# get_provider_uuids_in_tree returns UUIDs in top-down order, so the
|
||||||
# is the root; and .remove() is recursive.
|
# first one is the root; and .remove() is recursive.
|
||||||
self._provider_tree.remove(uuids[0])
|
self._provider_tree.remove(uuids[0])
|
||||||
for uuid in uuids:
|
for uuid in uuids:
|
||||||
self._association_refresh_time.pop(uuid, None)
|
self._association_refresh_time.pop(uuid, None)
|
||||||
|
@ -757,8 +757,8 @@ class SchedulerReportClient(object):
|
||||||
|
|
||||||
def _refresh_associations(self, context, rp_uuid, force=False,
|
def _refresh_associations(self, context, rp_uuid, force=False,
|
||||||
refresh_sharing=True):
|
refresh_sharing=True):
|
||||||
"""Refresh aggregates, traits, and (optionally) aggregate-associated
|
"""Refresh inventories, aggregates, traits, and (optionally) aggregate-
|
||||||
sharing providers for the specified resource provider uuid.
|
associated sharing providers for the specified resource provider uuid.
|
||||||
|
|
||||||
Only refresh if there has been no refresh during the lifetime of
|
Only refresh if there has been no refresh during the lifetime of
|
||||||
this process, CONF.compute.resource_provider_association_refresh
|
this process, CONF.compute.resource_provider_association_refresh
|
||||||
|
@ -820,11 +820,11 @@ class SchedulerReportClient(object):
|
||||||
self._provider_tree.new_root(
|
self._provider_tree.new_root(
|
||||||
rp['name'], rp['uuid'],
|
rp['name'], rp['uuid'],
|
||||||
generation=rp['generation'])
|
generation=rp['generation'])
|
||||||
# Now we have to (populate or) refresh that guy's traits,
|
# Now we have to (populate or) refresh that provider's
|
||||||
# aggregates, and inventories (but not *his* aggregate-
|
# traits, aggregates, and inventories (but not *its*
|
||||||
# associated providers). No need to override force=True for
|
# aggregate-associated providers). No need to override
|
||||||
# newly- added providers - the missing timestamp will
|
# force=True for newly-added providers - the missing
|
||||||
# always trigger them to refresh.
|
# timestamp will always trigger them to refresh.
|
||||||
self._refresh_associations(context, rp['uuid'],
|
self._refresh_associations(context, rp['uuid'],
|
||||||
force=force,
|
force=force,
|
||||||
refresh_sharing=False)
|
refresh_sharing=False)
|
||||||
|
@ -1050,7 +1050,7 @@ class SchedulerReportClient(object):
|
||||||
|
|
||||||
url = '/resource_providers/%s/traits' % rp_uuid
|
url = '/resource_providers/%s/traits' % rp_uuid
|
||||||
# NOTE(efried): Don't use the DELETE API when traits is empty, because
|
# NOTE(efried): Don't use the DELETE API when traits is empty, because
|
||||||
# that guy doesn't return content, and we need to update the cached
|
# that method doesn't return content, and we need to update the cached
|
||||||
# provider tree with the new generation.
|
# provider tree with the new generation.
|
||||||
traits = list(traits) if traits else []
|
traits = list(traits) if traits else []
|
||||||
generation = self._provider_tree.data(rp_uuid).generation
|
generation = self._provider_tree.data(rp_uuid).generation
|
||||||
|
|
|
@ -2861,7 +2861,7 @@ class TestAssociations(SchedulerReportClientTestCase):
|
||||||
'nova.scheduler.client.report.SchedulerReportClient.'
|
'nova.scheduler.client.report.SchedulerReportClient.'
|
||||||
'_get_sharing_providers')).mock
|
'_get_sharing_providers')).mock
|
||||||
|
|
||||||
def assert_things_were_called(self, uuid, sharing=True):
|
def assert_getters_were_called(self, uuid, sharing=True):
|
||||||
self.mock_get_inv.assert_called_once_with(self.context, uuid)
|
self.mock_get_inv.assert_called_once_with(self.context, uuid)
|
||||||
self.mock_get_aggs.assert_called_once_with(self.context, uuid)
|
self.mock_get_aggs.assert_called_once_with(self.context, uuid)
|
||||||
self.mock_get_traits.assert_called_once_with(self.context, uuid)
|
self.mock_get_traits.assert_called_once_with(self.context, uuid)
|
||||||
|
@ -2881,7 +2881,7 @@ class TestAssociations(SchedulerReportClientTestCase):
|
||||||
self.client._provider_tree.has_traits(uuid, ['CUSTOM_SILVER']))
|
self.client._provider_tree.has_traits(uuid, ['CUSTOM_SILVER']))
|
||||||
self.assertEqual(43, self.client._provider_tree.data(uuid).generation)
|
self.assertEqual(43, self.client._provider_tree.data(uuid).generation)
|
||||||
|
|
||||||
def assert_things_not_called(self, timer_entry=None):
|
def assert_getters_not_called(self, timer_entry=None):
|
||||||
self.mock_get_inv.assert_not_called()
|
self.mock_get_inv.assert_not_called()
|
||||||
self.mock_get_aggs.assert_not_called()
|
self.mock_get_aggs.assert_not_called()
|
||||||
self.mock_get_traits.assert_not_called()
|
self.mock_get_traits.assert_not_called()
|
||||||
|
@ -2891,7 +2891,7 @@ class TestAssociations(SchedulerReportClientTestCase):
|
||||||
else:
|
else:
|
||||||
self.assertIn(timer_entry, self.client._association_refresh_time)
|
self.assertIn(timer_entry, self.client._association_refresh_time)
|
||||||
|
|
||||||
def reset_things(self):
|
def reset_getter_mocks(self):
|
||||||
self.mock_get_inv.reset_mock()
|
self.mock_get_inv.reset_mock()
|
||||||
self.mock_get_aggs.reset_mock()
|
self.mock_get_aggs.reset_mock()
|
||||||
self.mock_get_traits.reset_mock()
|
self.mock_get_traits.reset_mock()
|
||||||
|
@ -2903,7 +2903,7 @@ class TestAssociations(SchedulerReportClientTestCase):
|
||||||
# Seed the provider tree so _refresh_associations finds the provider
|
# Seed the provider tree so _refresh_associations finds the provider
|
||||||
self.client._provider_tree.new_root('compute', uuid, generation=1)
|
self.client._provider_tree.new_root('compute', uuid, generation=1)
|
||||||
self.client._refresh_associations(self.context, uuid)
|
self.client._refresh_associations(self.context, uuid)
|
||||||
self.assert_things_were_called(uuid)
|
self.assert_getters_were_called(uuid)
|
||||||
|
|
||||||
def test_refresh_associations_no_refresh_sharing(self):
|
def test_refresh_associations_no_refresh_sharing(self):
|
||||||
"""Test refresh_sharing=False."""
|
"""Test refresh_sharing=False."""
|
||||||
|
@ -2912,7 +2912,7 @@ class TestAssociations(SchedulerReportClientTestCase):
|
||||||
self.client._provider_tree.new_root('compute', uuid, generation=1)
|
self.client._provider_tree.new_root('compute', uuid, generation=1)
|
||||||
self.client._refresh_associations(self.context, uuid,
|
self.client._refresh_associations(self.context, uuid,
|
||||||
refresh_sharing=False)
|
refresh_sharing=False)
|
||||||
self.assert_things_were_called(uuid, sharing=False)
|
self.assert_getters_were_called(uuid, sharing=False)
|
||||||
|
|
||||||
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
|
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
|
||||||
'_associations_stale')
|
'_associations_stale')
|
||||||
|
@ -2923,7 +2923,7 @@ class TestAssociations(SchedulerReportClientTestCase):
|
||||||
mock_stale.return_value = False
|
mock_stale.return_value = False
|
||||||
uuid = uuids.compute_node
|
uuid = uuids.compute_node
|
||||||
self.client._refresh_associations(self.context, uuid)
|
self.client._refresh_associations(self.context, uuid)
|
||||||
self.assert_things_not_called()
|
self.assert_getters_not_called()
|
||||||
|
|
||||||
@mock.patch.object(report.LOG, 'debug')
|
@mock.patch.object(report.LOG, 'debug')
|
||||||
def test_refresh_associations_time(self, log_mock):
|
def test_refresh_associations_time(self, log_mock):
|
||||||
|
@ -2935,7 +2935,7 @@ class TestAssociations(SchedulerReportClientTestCase):
|
||||||
# Called a first time because association_refresh_time is empty.
|
# Called a first time because association_refresh_time is empty.
|
||||||
now = time.time()
|
now = time.time()
|
||||||
self.client._refresh_associations(self.context, uuid)
|
self.client._refresh_associations(self.context, uuid)
|
||||||
self.assert_things_were_called(uuid)
|
self.assert_getters_were_called(uuid)
|
||||||
log_mock.assert_has_calls([
|
log_mock.assert_has_calls([
|
||||||
mock.call('Refreshing inventories for resource provider %s', uuid),
|
mock.call('Refreshing inventories for resource provider %s', uuid),
|
||||||
mock.call('Updating ProviderTree inventory for provider %s from '
|
mock.call('Updating ProviderTree inventory for provider %s from '
|
||||||
|
@ -2948,20 +2948,20 @@ class TestAssociations(SchedulerReportClientTestCase):
|
||||||
])
|
])
|
||||||
|
|
||||||
# Clear call count.
|
# Clear call count.
|
||||||
self.reset_things()
|
self.reset_getter_mocks()
|
||||||
|
|
||||||
with mock.patch('time.time') as mock_future:
|
with mock.patch('time.time') as mock_future:
|
||||||
# Not called a second time because not enough time has passed.
|
# Not called a second time because not enough time has passed.
|
||||||
mock_future.return_value = (now +
|
mock_future.return_value = (now +
|
||||||
CONF.compute.resource_provider_association_refresh / 2)
|
CONF.compute.resource_provider_association_refresh / 2)
|
||||||
self.client._refresh_associations(self.context, uuid)
|
self.client._refresh_associations(self.context, uuid)
|
||||||
self.assert_things_not_called(timer_entry=uuid)
|
self.assert_getters_not_called(timer_entry=uuid)
|
||||||
|
|
||||||
# Called because time has passed.
|
# Called because time has passed.
|
||||||
mock_future.return_value = (now +
|
mock_future.return_value = (now +
|
||||||
CONF.compute.resource_provider_association_refresh + 1)
|
CONF.compute.resource_provider_association_refresh + 1)
|
||||||
self.client._refresh_associations(self.context, uuid)
|
self.client._refresh_associations(self.context, uuid)
|
||||||
self.assert_things_were_called(uuid)
|
self.assert_getters_were_called(uuid)
|
||||||
|
|
||||||
def test_refresh_associations_disabled(self):
|
def test_refresh_associations_disabled(self):
|
||||||
"""Test that refresh associations can be disabled."""
|
"""Test that refresh associations can be disabled."""
|
||||||
|
@ -2973,31 +2973,31 @@ class TestAssociations(SchedulerReportClientTestCase):
|
||||||
# Called a first time because association_refresh_time is empty.
|
# Called a first time because association_refresh_time is empty.
|
||||||
now = time.time()
|
now = time.time()
|
||||||
self.client._refresh_associations(self.context, uuid)
|
self.client._refresh_associations(self.context, uuid)
|
||||||
self.assert_things_were_called(uuid)
|
self.assert_getters_were_called(uuid)
|
||||||
|
|
||||||
# Clear call count.
|
# Clear call count.
|
||||||
self.reset_things()
|
self.reset_getter_mocks()
|
||||||
|
|
||||||
with mock.patch('time.time') as mock_future:
|
with mock.patch('time.time') as mock_future:
|
||||||
# A lot of time passes
|
# A lot of time passes
|
||||||
mock_future.return_value = now + 10000000000000
|
mock_future.return_value = now + 10000000000000
|
||||||
self.client._refresh_associations(self.context, uuid)
|
self.client._refresh_associations(self.context, uuid)
|
||||||
self.assert_things_not_called(timer_entry=uuid)
|
self.assert_getters_not_called(timer_entry=uuid)
|
||||||
|
|
||||||
self.reset_things()
|
self.reset_getter_mocks()
|
||||||
|
|
||||||
# Forever passes
|
# Forever passes
|
||||||
mock_future.return_value = float('inf')
|
mock_future.return_value = float('inf')
|
||||||
self.client._refresh_associations(self.context, uuid)
|
self.client._refresh_associations(self.context, uuid)
|
||||||
self.assert_things_not_called(timer_entry=uuid)
|
self.assert_getters_not_called(timer_entry=uuid)
|
||||||
|
|
||||||
self.reset_things()
|
self.reset_getter_mocks()
|
||||||
|
|
||||||
# Even if no time passes, clearing the counter triggers refresh
|
# Even if no time passes, clearing the counter triggers refresh
|
||||||
mock_future.return_value = now
|
mock_future.return_value = now
|
||||||
del self.client._association_refresh_time[uuid]
|
del self.client._association_refresh_time[uuid]
|
||||||
self.client._refresh_associations(self.context, uuid)
|
self.client._refresh_associations(self.context, uuid)
|
||||||
self.assert_things_were_called(uuid)
|
self.assert_getters_were_called(uuid)
|
||||||
|
|
||||||
|
|
||||||
class TestAllocations(SchedulerReportClientTestCase):
|
class TestAllocations(SchedulerReportClientTestCase):
|
||||||
|
|
Loading…
Reference in New Issue