Merge "Track provider traits in report client"

This commit is contained in:
Zuul
2018-01-13 09:49:15 +00:00
committed by Gerrit Code Review
3 changed files with 230 additions and 70 deletions

View File

@@ -42,8 +42,9 @@ _RE_INV_IN_USE = re.compile("Inventory for (.+) on resource provider "
"(.+) in use")
WARN_EVERY = 10
PLACEMENT_CLIENT_SEMAPHORE = 'placement_client'
# Number of seconds between attempts to update a provider's aggregates
AGGREGATE_REFRESH = 300
# Number of seconds between attempts to update a provider's aggregates and
# traits
ASSOCIATION_REFRESH = 300
NESTED_PROVIDER_API_VERSION = '1.14'
POST_ALLOCATIONS_API_VERSION = '1.13'
@@ -261,8 +262,8 @@ class SchedulerReportClient(object):
# An object that contains a nova-compute-side cache of resource
# provider and inventory information
self._provider_tree = provider_tree.ProviderTree()
# Track the last time we updated the aggregate map.
self.aggregate_refresh_time = {}
# Track the last time we updated providers' aggregates and traits
self.association_refresh_time = {}
self._client = self._create_client()
# NOTE(danms): Keep track of how naggy we've been
self._warn_count = 0
@@ -270,9 +271,9 @@ class SchedulerReportClient(object):
@utils.synchronized(PLACEMENT_CLIENT_SEMAPHORE)
def _create_client(self):
"""Create the HTTP session accessing the placement service."""
# Flush provider tree and aggregates so we start from a clean slate.
# Flush provider tree and associations so we start from a clean slate.
self._provider_tree = provider_tree.ProviderTree()
self.aggregate_refresh_time = {}
self.association_refresh_time = {}
# TODO(mriedem): Perform some version discovery at some point.
client = utils.get_ksa_adapter('placement')
# Set accept header on every request to ensure we notify placement
@@ -396,6 +397,35 @@ class SchedulerReportClient(object):
}
LOG.error(msg, args)
@safe_connect
def _get_provider_traits(self, rp_uuid):
"""Queries the placement API for a resource provider's traits. Returns
a set() of string trait names, or None if no such resource provider was
found or there was an error communicating with the placement API.
:param rp_uuid: UUID of the resource provider to grab traits for.
"""
resp = self.get("/resource_providers/%s/traits" % rp_uuid,
version='1.6')
if resp.status_code == 200:
return set(resp.json()['traits'])
placement_req_id = get_placement_request_id(resp)
if resp.status_code == 404:
LOG.warning(
"[%(placement_req_id)s] Tried to get a provider's traits, but "
"the provider %(uuid)s does not exist.",
{'uuid': rp_uuid, 'placement_req_id': placement_req_id})
else:
LOG.error(
"[%(placement_req_id)s] Failed to retrieve traits from "
"placement API for resource provider with UUID %(uuid)s. Got "
"%(status_code)d: %(err_text)s.",
{'placement_req_id': placement_req_id, 'uuid': rp_uuid,
'status_code': resp.status_code, 'err_text': resp.text})
return None
@safe_connect
def _get_resource_provider(self, uuid):
"""Queries the placement API for a resource provider record with the
@@ -585,7 +615,7 @@ class SchedulerReportClient(object):
# parent_provider_uuid on a previously-parent-less provider - so we do
# NOT handle that scenario here.
if self._provider_tree.exists(uuid):
self._refresh_aggregates(uuid)
self._refresh_associations(uuid)
return uuid
# No local information about the resource provider in our tree. Check
@@ -609,8 +639,8 @@ class SchedulerReportClient(object):
generation=rp['generation'])
# If there had been no local resource provider record, force refreshing
# the aggregate map.
self._refresh_aggregates(uuid, rp['generation'], force=True)
# the aggregate & trait caches.
self._refresh_associations(uuid, rp['generation'], force=True)
return ret
@@ -640,20 +670,22 @@ class SchedulerReportClient(object):
self._provider_tree.update_inventory(rp_uuid, curr_inv, cur_gen)
return curr
def _refresh_aggregates(self, rp_uuid, generation=None, force=False):
"""Refresh the aggregate map for the provided resource provider uuid.
def _refresh_associations(self, rp_uuid, generation=None, force=False):
"""Refresh the aggregates and traits for the provided resource provider
uuid.
Only refresh if there has been no refresh during the lifetime of
this process, AGGREGATE_REFRESH seconds have passed, or the force arg
this process, ASSOCIATION_REFRESH seconds have passed, or the force arg
has been set to True.
:param rp_uuid: UUID of the resource provider to check for fresh
aggregates
aggregates and traits
:param generation: The resource provider generation to set. If None,
the provider's generation is not updated.
:param force: If True, force the refresh
"""
if force or self._aggregate_map_stale(rp_uuid):
if force or self._associations_stale(rp_uuid):
# Refresh aggregates
aggs = self._get_provider_aggregates(rp_uuid)
if aggs is not None:
msg = ("Refreshing aggregate associations for resource "
@@ -664,16 +696,29 @@ class SchedulerReportClient(object):
# doesn't exist in our _provider_tree.
self._provider_tree.update_aggregates(
rp_uuid, aggs, generation=generation)
self.aggregate_refresh_time[rp_uuid] = time.time()
def _aggregate_map_stale(self, uuid):
"""Respond True if aggregates have not been refreshed "recently".
# Refresh traits
traits = self._get_provider_traits(rp_uuid)
if traits is not None:
msg = ("Refreshing trait associations for resource "
"provider %s, traits: %s")
LOG.debug(msg, rp_uuid, ','.join(traits or ['None']))
# NOTE(efried): This will blow up if called for a RP that
# doesn't exist in our _provider_tree.
self._provider_tree.update_traits(
rp_uuid, traits, generation=generation)
It is old if aggregate_refresh_time for this uuid is not set
or more than AGGREGATE_REFRESH seconds ago.
self.association_refresh_time[rp_uuid] = time.time()
def _associations_stale(self, uuid):
"""Respond True if aggregates and traits have not been refreshed
"recently".
It is old if association_refresh_time for this uuid is not set
or more than ASSOCIATION_REFRESH seconds ago.
"""
refresh_time = self.aggregate_refresh_time.get(uuid, 0)
return (time.time() - refresh_time) > AGGREGATE_REFRESH
refresh_time = self.association_refresh_time.get(uuid, 0)
return (time.time() - refresh_time) > ASSOCIATION_REFRESH
def _update_inventory_attempt(self, rp_uuid, inv_data):
"""Update the inventory for this resource provider if needed.
@@ -874,7 +919,7 @@ class SchedulerReportClient(object):
"inventory. Ignoring.",
msg_args)
self._provider_tree.remove(rp_uuid)
self.aggregate_refresh_time.pop(rp_uuid, None)
self.association_refresh_time.pop(rp_uuid, None)
return
elif r.status_code == 409:
rc_str = _extract_inventory_in_use(r.text)
@@ -1435,7 +1480,7 @@ class SchedulerReportClient(object):
self._provider_tree.remove(rp_uuid)
except ValueError:
pass
self.aggregate_refresh_time.pop(rp_uuid, None)
self.association_refresh_time.pop(rp_uuid, None)
else:
# Check for 404 since we don't need to log a warning if we tried to
# delete something which doesn"t actually exist.

View File

@@ -116,13 +116,16 @@ class SchedulerReportClientTests(test.TestCase):
rps = self.client._get_providers_in_tree(self.compute_uuid)
self.assertEqual(1, len(rps))
# We should also have an empty list set of aggregate UUID
# We should also have empty sets of aggregate and trait
# associations
self.assertEqual(
[], self.client._get_providers_in_aggregates([uuids.agg]))
self.assertFalse(
self.client._provider_tree.have_aggregates_changed(
self.compute_uuid, []))
self.assertFalse(
self.client._provider_tree.have_traits_changed(
self.compute_uuid, []))
# TODO(cdent): change this to use the methods built in
# to the report client to retrieve inventory?

View File

@@ -1195,10 +1195,12 @@ class TestProviderOperations(SchedulerReportClientTestCase):
'_create_resource_provider')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_get_provider_aggregates')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_get_provider_traits')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_get_resource_provider')
def test_ensure_resource_provider_exists_in_cache(self, get_rp_mock,
get_agg_mock, create_rp_mock):
get_trait_mock, get_agg_mock, create_rp_mock):
# Override the client object's cache to contain a resource provider
# object for the compute host and check that
# _ensure_resource_provider() doesn't call _get_resource_provider() or
@@ -1211,12 +1213,18 @@ class TestProviderOperations(SchedulerReportClientTestCase):
)
get_agg_mock.return_value = set([uuids.agg1, uuids.agg2])
get_trait_mock.return_value = set(['CUSTOM_GOLD', 'CUSTOM_SILVER'])
self.client._ensure_resource_provider(cn.uuid)
get_agg_mock.assert_called_once_with(cn.uuid)
self.assertTrue(self.client._provider_tree.in_aggregates(
uuids.compute_node, [uuids.agg1, uuids.agg2]))
self.assertFalse(self.client._provider_tree.in_aggregates(
uuids.compute_node, [uuids.agg1, uuids.agg3]))
get_trait_mock.assert_called_once_with(cn.uuid)
self.assertTrue(self.client._provider_tree.has_traits(
uuids.compute_node, ['CUSTOM_GOLD', 'CUSTOM_SILVER']))
self.assertFalse(self.client._provider_tree.has_traits(
uuids.compute_node, ['CUSTOM_GOLD', 'CUSTOM_BRONZE']))
self.assertFalse(get_rp_mock.called)
self.assertFalse(create_rp_mock.called)
@@ -1224,10 +1232,12 @@ class TestProviderOperations(SchedulerReportClientTestCase):
'_create_resource_provider')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_get_provider_aggregates')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_get_provider_traits')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_get_resource_provider')
def test_ensure_resource_provider_get(self, get_rp_mock, get_agg_mock,
create_rp_mock):
def test_ensure_resource_provider_get(self, get_rp_mock, get_trait_mock,
get_agg_mock, create_rp_mock):
# No resource provider exists in the client's cache, so validate that
# if we get the resource provider from the placement API that we don't
# try to create the resource provider.
@@ -1238,6 +1248,7 @@ class TestProviderOperations(SchedulerReportClientTestCase):
}
get_agg_mock.return_value = set([uuids.agg1])
get_trait_mock.return_value = set(['CUSTOM_GOLD'])
self.client._ensure_resource_provider(uuids.compute_node)
@@ -1250,6 +1261,13 @@ class TestProviderOperations(SchedulerReportClientTestCase):
self.assertFalse(
self.client._provider_tree.in_aggregates(uuids.compute_node,
[uuids.agg2]))
get_trait_mock.assert_called_once_with(uuids.compute_node)
self.assertTrue(
self.client._provider_tree.has_traits(uuids.compute_node,
['CUSTOM_GOLD']))
self.assertFalse(
self.client._provider_tree.has_traits(uuids.compute_node,
['CUSTOM_SILVER']))
self.assertTrue(self.client._provider_tree.exists(uuids.compute_node))
self.assertFalse(create_rp_mock.called)
@@ -1257,10 +1275,12 @@ class TestProviderOperations(SchedulerReportClientTestCase):
'_create_resource_provider')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_get_provider_aggregates')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_get_provider_traits')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_get_resource_provider')
def test_ensure_resource_provider_create_fail(self, get_rp_mock,
get_agg_mock, create_rp_mock):
get_trait_mock, get_agg_mock, create_rp_mock):
# No resource provider exists in the client's cache, and
# _create_provider raises, indicating there was an error with the
# create call. Ensure we don't populate the resource provider cache
@@ -1277,18 +1297,24 @@ class TestProviderOperations(SchedulerReportClientTestCase):
uuids.compute_node, uuids.compute_node, parent_provider_uuid=None)
self.assertFalse(self.client._provider_tree.exists(uuids.compute_node))
self.assertFalse(get_agg_mock.called)
self.assertFalse(get_trait_mock.called)
self.assertRaises(
ValueError,
self.client._provider_tree.in_aggregates, uuids.compute_node, [])
self.assertRaises(
ValueError,
self.client._provider_tree.has_traits, uuids.compute_node, [])
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_create_resource_provider')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_get_provider_aggregates')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_get_provider_traits')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_get_resource_provider')
def test_ensure_resource_provider_create(self, get_rp_mock, get_agg_mock,
create_rp_mock):
def test_ensure_resource_provider_create(self, get_rp_mock, get_trait_mock,
get_agg_mock, create_rp_mock):
# No resource provider exists in the client's cache and no resource
# provider was returned from the placement API, so verify that in this
# case we try to create the resource provider via the placement API.
@@ -1299,14 +1325,17 @@ class TestProviderOperations(SchedulerReportClientTestCase):
'generation': 1,
}
get_agg_mock.return_value = set([uuids.agg1, uuids.agg2])
get_trait_mock.return_value = set(['CUSTOM_FOO'])
self.assertEqual(
uuids.compute_node,
self.client._ensure_resource_provider(uuids.compute_node))
self._validate_provider(uuids.compute_node, name='compute-name',
generation=1, parent_uuid=None,
aggregates=set([uuids.agg1, uuids.agg2]))
aggregates=set([uuids.agg1, uuids.agg2]),
traits=set(['CUSTOM_FOO']))
get_agg_mock.assert_called_once_with(uuids.compute_node)
get_trait_mock.assert_called_once_with(uuids.compute_node)
get_rp_mock.assert_called_once_with(uuids.compute_node)
create_rp_mock.assert_called_once_with(
uuids.compute_node,
@@ -1332,7 +1361,7 @@ class TestProviderOperations(SchedulerReportClientTestCase):
uuids.cn2, 'a-name', parent_provider_uuid=None)
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_refresh_aggregates', new=mock.Mock())
'_refresh_associations', new=mock.Mock())
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_create_resource_provider')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
@@ -1739,9 +1768,6 @@ class TestProviderOperations(SchedulerReportClientTestCase):
class TestAggregates(SchedulerReportClientTestCase):
def test_get_provider_aggregates_found(self):
"""Test that when the placement API returns a list of aggregate UUIDs,
that we cache that aggregate information in the appropriate map.
"""
uuid = uuids.compute_node
resp_mock = mock.Mock(status_code=200)
json_data = {
@@ -1808,66 +1834,152 @@ class TestAggregates(SchedulerReportClientTestCase):
log_mock.call_args[0][1]['placement_req_id'])
self.assertIsNone(result)
class TestTraits(SchedulerReportClientTestCase):
def test_get_provider_traits_found(self):
uuid = uuids.compute_node
resp_mock = mock.Mock(status_code=200)
traits = [
'CUSTOM_GOLD',
'CUSTOM_SILVER',
]
resp_mock.json.return_value = {'traits': traits}
self.ks_adap_mock.get.return_value = resp_mock
result = self.client._get_provider_traits(uuid)
expected_url = '/resource_providers/' + uuid + '/traits'
self.ks_adap_mock.get.assert_called_once_with(
expected_url, raise_exc=False, microversion='1.6')
self.assertEqual(set(traits), result)
@mock.patch.object(report.LOG, 'warning')
def test_get_provider_traits_not_found(self, log_mock):
"""Test that when the placement API returns a 404 when looking up a
provider's traits, we simply return None and log a warning.
"""
uuid = uuids.compute_node
self.ks_adap_mock.get.return_value = mock.Mock(
status_code=404, headers={
'x-openstack-request-id': uuids.request_id})
result = self.client._get_provider_traits(uuid)
expected_url = '/resource_providers/' + uuid + '/traits'
self.ks_adap_mock.get.assert_called_once_with(
expected_url, raise_exc=False, microversion='1.6')
self.assertTrue(log_mock.called)
self.assertEqual(uuids.request_id,
log_mock.call_args[0][1]['placement_req_id'])
self.assertIsNone(result)
@mock.patch.object(report.LOG, 'error')
def test_get_provider_traits_bad_request(self, log_mock):
"""Test that when the placement API returns a 400 when looking up a
provider's traits, that we simply return None and log an error.
"""
uuid = uuids.compute_node
self.ks_adap_mock.get.return_value = mock.Mock(
status_code=400, headers={
'x-openstack-request-id': uuids.request_id})
result = self.client._get_provider_traits(uuid)
expected_url = '/resource_providers/' + uuid + '/traits'
self.ks_adap_mock.get.assert_called_once_with(
expected_url, raise_exc=False, microversion='1.6')
self.assertTrue(log_mock.called)
self.assertEqual(uuids.request_id,
log_mock.call_args[0][1]['placement_req_id'])
self.assertIsNone(result)
class TestAssociations(SchedulerReportClientTestCase):
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_get_provider_aggregates')
def test_refresh_aggregates_no_last(self, mock_get):
"""Test that aggregates are updated when a new provider is added."""
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_get_provider_traits')
def test_refresh_associations_no_last(self, mock_trait_get, mock_agg_get):
"""Test that associations are refreshed when stale."""
uuid = uuids.compute_node
# Seed the provider tree so _refresh_aggregates finds the provider
# Seed the provider tree so _refresh_associations finds the provider
self.client._provider_tree.new_root('compute', uuid, 1)
mock_get.return_value = set([uuids.agg1])
self.client._refresh_aggregates(uuid)
mock_get.assert_called_once_with(uuid)
self.assertIn(uuid, self.client.aggregate_refresh_time)
mock_agg_get.return_value = set([uuids.agg1])
mock_trait_get.return_value = set(['CUSTOM_GOLD'])
self.client._refresh_associations(uuid)
mock_agg_get.assert_called_once_with(uuid)
mock_trait_get.assert_called_once_with(uuid)
self.assertIn(uuid, self.client.association_refresh_time)
self.assertTrue(
self.client._provider_tree.in_aggregates(uuid, [uuids.agg1]))
self.assertFalse(
self.client._provider_tree.in_aggregates(uuid, [uuids.agg2]))
self.assertTrue(
self.client._provider_tree.has_traits(uuid, ['CUSTOM_GOLD']))
self.assertFalse(
self.client._provider_tree.has_traits(uuid, ['CUSTOM_SILVER']))
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_get_provider_aggregates')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_aggregate_map_stale')
def test_refresh_aggregates_not_stale(self, mock_stale, mock_get):
"""Test that aggregates are not updated when there are no changes."""
'_get_provider_traits')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_associations_stale')
def test_refresh_associations_not_stale(self, mock_stale, mock_trait_get,
mock_agg_get):
"""Test that refresh associations is not called when the map is
not stale.
"""
mock_stale.return_value = False
uuid = uuids.compute_node
self.client._refresh_aggregates(uuid)
mock_get.assert_not_called()
self.assertFalse(self.client.aggregate_refresh_time)
self.client._refresh_associations(uuid)
mock_agg_get.assert_not_called()
mock_trait_get.assert_not_called()
self.assertFalse(self.client.association_refresh_time)
@mock.patch.object(report.LOG, 'debug')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_get_provider_aggregates')
def test_refresh_aggregates_time(self, mock_get, log_mock):
"""Test that aggregates are updated at a given interval."""
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'_get_provider_traits')
def test_refresh_associations_time(self, mock_trait_get, mock_agg_get,
log_mock):
"""Test that refresh associations is called when the map is stale."""
uuid = uuids.compute_node
# Seed the provider tree so _refresh_aggregates finds the provider
# Seed the provider tree so _refresh_associations finds the provider
self.client._provider_tree.new_root('compute', uuid, 1)
mock_get.return_value = set([])
mock_agg_get.return_value = set([])
mock_trait_get.return_value = set([])
# Called a first time because aggregate_refresh_time is empty.
# Called a first time because association_refresh_time is empty.
now = time.time()
self.client._refresh_aggregates(uuid)
mock_get.assert_called_once_with(uuid)
log_mock.assert_called_once_with(
'Refreshing aggregate associations for resource '
'provider %s, aggregates: %s', uuid, 'None')
self.assertIn(uuid, self.client.aggregate_refresh_time)
self.client._refresh_associations(uuid)
mock_agg_get.assert_called_once_with(uuid)
mock_trait_get.assert_called_once_with(uuid)
log_mock.assert_has_calls([
mock.call('Refreshing aggregate associations for resource '
'provider %s, aggregates: %s', uuid, 'None'),
mock.call('Refreshing trait associations for resource '
'provider %s, traits: %s', uuid, 'None')
])
self.assertIn(uuid, self.client.association_refresh_time)
# Clear call count.
mock_get.reset_mock()
mock_agg_get.reset_mock()
mock_trait_get.reset_mock()
with mock.patch('time.time') as mock_future:
# Not called a second time because not enough time has passed.
mock_future.return_value = now + report.AGGREGATE_REFRESH / 2
self.client._refresh_aggregates(uuid)
mock_get.assert_not_called()
mock_future.return_value = now + report.ASSOCIATION_REFRESH / 2
self.client._refresh_associations(uuid)
mock_agg_get.assert_not_called()
mock_trait_get.assert_not_called()
# Called because time has passed.
mock_future.return_value = now + report.AGGREGATE_REFRESH + 1
self.client._refresh_aggregates(uuid)
mock_get.assert_called_once_with(uuid)
mock_future.return_value = now + report.ASSOCIATION_REFRESH + 1
self.client._refresh_associations(uuid)
mock_agg_get.assert_called_once_with(uuid)
mock_trait_get.assert_called_once_with(uuid)
class TestComputeNodeToInventoryDict(test.NoDBTestCase):
@@ -2221,7 +2333,7 @@ There was a conflict when trying to complete your request.
cn = self.compute_node
# Make sure the resource provider exists for preventing to call the API
self._init_provider_tree()
self.client.aggregate_refresh_time[uuids.cn] = mock.Mock()
self.client.association_refresh_time[uuids.cn] = mock.Mock()
mock_get.return_value.json.return_value = {
'resource_provider_generation': 1,
@@ -2238,7 +2350,7 @@ There was a conflict when trying to complete your request.
self.assertIsNone(result)
self.assertFalse(self.client._provider_tree.exists(cn.uuid))
self.assertTrue(mock_debug.called)
self.assertNotIn(cn.uuid, self.client.aggregate_refresh_time)
self.assertNotIn(cn.uuid, self.client.association_refresh_time)
self.assertIn('deleted by another thread', mock_debug.call_args[0][0])
self.assertEqual(uuids.request_id,
mock_debug.call_args[0][1]['placement_req_id'])
@@ -3130,7 +3242,7 @@ class TestAllocations(SchedulerReportClientTestCase):
def test_delete_resource_provider_no_cascade(self, mock_by_host,
mock_del_alloc, mock_delete):
self.client._provider_tree.new_root(uuids.cn, uuids.cn, 1)
self.client.aggregate_refresh_time[uuids.cn] = mock.Mock()
self.client.association_refresh_time[uuids.cn] = mock.Mock()
cn = objects.ComputeNode(uuid=uuids.cn, host="fake_host",
hypervisor_hostname="fake_hostname", )
inst1 = objects.Instance(uuid=uuids.inst1)
@@ -3144,7 +3256,7 @@ class TestAllocations(SchedulerReportClientTestCase):
exp_url = "/resource_providers/%s" % uuids.cn
mock_delete.assert_called_once_with(
exp_url, global_request_id=self.context.global_id)
self.assertNotIn(uuids.cn, self.client.aggregate_refresh_time)
self.assertNotIn(uuids.cn, self.client.association_refresh_time)
@mock.patch("nova.scheduler.client.report.SchedulerReportClient."
"delete")