Drop compat for non-update_provider_tree code paths

In Train [1] we deprecated support for compute drivers
that did not implement the update_provider_tree method.
That compat code is now removed along with the get_inventory
method definition and (most) references to it.

As a result there are more things we can remove but those
will come in separate changes.

[1] I1eae47bce08f6292d38e893a2122289bcd6f4b58

Change-Id: Ib62ac0b692eb92a2ed364ec9f486ded05def39ad
This commit is contained in:
Matt Riedemann 2019-11-07 17:15:50 -05:00
parent 6479d492c0
commit c80912866f
7 changed files with 57 additions and 125 deletions

View File

@ -23,13 +23,13 @@ Background
----------
In the movement towards using placement for scheduling and resource management,
the virt driver method ``get_available_resource`` was initially superseded by
``get_inventory``, whereby the driver could specify its inventory in terms
understood by placement. In Queens, a ``get_traits`` driver method was added.
But ``get_inventory`` is limited to expressing only inventory (not traits or
aggregates). And both of these methods are limited to the resource provider
corresponding to the compute node.
``get_inventory`` (now gone), whereby the driver could specify its inventory in
terms understood by placement. In Queens, a ``get_traits`` driver method was
added. But ``get_inventory`` is limited to expressing only inventory (not
traits or aggregates). And both of these methods are limited to the resource
provider corresponding to the compute node.
Recent developments such as Nested Resource Providers necessitate the ability
Developments such as Nested Resource Providers necessitate the ability
for the virt driver to have deeper control over what the resource tracker
configures in placement on behalf of the compute node. This need is filled by
the virt driver method ``update_provider_tree`` and its consumption by the
@ -130,9 +130,6 @@ aggregates, and traits associated with those resource providers.
PF1 PF2 PF3 PF4------BW1 (root)
agg2
This method supersedes ``get_inventory`` and ``get_traits``: if this method is
implemented, neither ``get_inventory`` nor ``get_traits`` is used.
Driver implementations of ``update_provider_tree`` are expected to use public
``ProviderTree`` methods to effect changes to the provider tree passed in.
Some of the methods which may be useful are as follows:

View File

@ -82,6 +82,7 @@ def _instance_is_live_migrating(instance):
return False
# TODO(mriedem): Remove this now that get_inventory isn't being used anymore
def _normalize_inventory_from_cn_obj(inv_data, cn):
"""Helper function that injects various information from a compute node
object into the inventory dict returned from the virt driver's
@ -1153,59 +1154,38 @@ class ResourceTracker(object):
# the inventory, traits, and aggregates throughout.
allocs = None
try:
try:
self.driver.update_provider_tree(prov_tree, nodename)
except exception.ReshapeNeeded:
if not startup:
# This isn't supposed to happen during periodic, so raise
# it up; the compute manager will treat it specially.
raise
LOG.info("Performing resource provider inventory and "
"allocation data migration during compute service "
"startup or fast-forward upgrade.")
allocs = self.reportclient.get_allocations_for_provider_tree(
context, nodename)
self.driver.update_provider_tree(prov_tree, nodename,
allocations=allocs)
self.driver.update_provider_tree(prov_tree, nodename)
except exception.ReshapeNeeded:
if not startup:
# This isn't supposed to happen during periodic, so raise
# it up; the compute manager will treat it specially.
raise
LOG.info("Performing resource provider inventory and "
"allocation data migration during compute service "
"startup or fast-forward upgrade.")
allocs = self.reportclient.get_allocations_for_provider_tree(
context, nodename)
self.driver.update_provider_tree(prov_tree, nodename,
allocations=allocs)
# Inject driver capabilities traits into the provider
# tree. We need to determine the traits that the virt
# driver owns - so those that come from the tree itself
# (via the virt driver) plus the compute capabilities
# traits, and then merge those with the traits set
# externally that the driver does not own - and remove any
# set on the provider externally that the virt owns but
# aren't in the current list of supported traits. For
# example, let's say we reported multiattach support as a
# trait at t1 and then at t2 it's not, so we need to
# remove it. But at both t1 and t2 there is a
# CUSTOM_VENDOR_TRAIT_X which we can't touch because it
# was set externally on the provider.
# We also want to sync the COMPUTE_STATUS_DISABLED trait based
# on the related nova-compute service's disabled status.
traits = self._get_traits(
context, nodename, provider_tree=prov_tree)
prov_tree.update_traits(nodename, traits)
except NotImplementedError:
# TODO(mriedem): Remove the compatibility code in the U release.
LOG.warning('Compute driver "%s" does not implement the '
'"update_provider_tree" interface. Compatibility for '
'non-update_provider_tree interfaces will be removed '
'in a future release and result in an error to report '
'inventory for this compute service.',
CONF.compute_driver)
# update_provider_tree isn't implemented yet - try get_inventory
try:
inv_data = self.driver.get_inventory(nodename)
_normalize_inventory_from_cn_obj(inv_data, compute_node)
except NotImplementedError:
# Eventually all virt drivers will return an inventory dict in
# the format that the placement API expects and we'll be able
# to remove this code branch
inv_data = compute_utils.compute_node_to_inventory_dict(
compute_node)
prov_tree.update_inventory(nodename, inv_data)
# Inject driver capabilities traits into the provider
# tree. We need to determine the traits that the virt
# driver owns - so those that come from the tree itself
# (via the virt driver) plus the compute capabilities
# traits, and then merge those with the traits set
# externally that the driver does not own - and remove any
# set on the provider externally that the virt owns but
# aren't in the current list of supported traits. For
# example, let's say we reported multiattach support as a
# trait at t1 and then at t2 it's not, so we need to
# remove it. But at both t1 and t2 there is a
# CUSTOM_VENDOR_TRAIT_X which we can't touch because it
# was set externally on the provider.
# We also want to sync the COMPUTE_STATUS_DISABLED trait based
# on the related nova-compute service's disabled status.
traits = self._get_traits(
context, nodename, provider_tree=prov_tree)
prov_tree.update_traits(nodename, traits)
self.provider_tree = prov_tree

View File

@ -1463,6 +1463,8 @@ def notify_about_instance_delete(notifier, context, instance,
phase=fields.NotificationPhase.END)
# TODO(mriedem): We should be able to remove this now that the ResourceTracker
# requires drivers to implement the update_provider_tree interface.
def compute_node_to_inventory_dict(compute_node):
"""Given a supplied `objects.ComputeNode` object, return a dict, keyed
by resource class, of various inventory information.

View File

@ -449,7 +449,6 @@ def setup_rt(hostname, virt_resources=_VIRT_DRIVER_AVAIL_RESOURCES):
# Make sure we don't change any global fixtures during tests
virt_resources = copy.deepcopy(virt_resources)
vd.get_available_resource.return_value = virt_resources
vd.get_inventory.side_effect = NotImplementedError
def fake_upt(provider_tree, nodename, allocations=None):
inventory = {
@ -1514,11 +1513,11 @@ class TestInitComputeNode(BaseTestCase):
class TestUpdateComputeNode(BaseTestCase):
@mock.patch('nova.compute.resource_tracker.ResourceTracker.'
'_sync_compute_service_disabled_trait', new=mock.Mock())
@mock.patch('nova.objects.ComputeNode.save')
def test_existing_compute_node_updated_same_resources(self, save_mock):
self._setup_rt()
self.driver_mock.update_provider_tree.side_effect = NotImplementedError
# This is the same set of resources as the fixture, deliberately. We
# are checking below to see that compute_node.save is not needlessly
@ -1531,8 +1530,9 @@ class TestUpdateComputeNode(BaseTestCase):
self.rt._update(mock.sentinel.ctx, new_compute)
self.assertFalse(save_mock.called)
# Even the compute node is not updated, get_inventory still got called.
self.driver_mock.get_inventory.assert_called_once_with(_NODENAME)
# Even the compute node is not updated, update_provider_tree
# still got called.
self.driver_mock.update_provider_tree.assert_called_once()
@mock.patch('nova.compute.resource_tracker.ResourceTracker.'
'_sync_compute_service_disabled_trait', new=mock.Mock())
@ -1558,11 +1558,8 @@ class TestUpdateComputeNode(BaseTestCase):
@mock.patch('nova.compute.resource_tracker.ResourceTracker.'
'_sync_compute_service_disabled_trait', new=mock.Mock())
@mock.patch('nova.compute.resource_tracker.'
'_normalize_inventory_from_cn_obj')
@mock.patch('nova.objects.ComputeNode.save')
def test_existing_compute_node_updated_new_resources(self, save_mock,
norm_mock):
def test_existing_compute_node_updated_new_resources(self, save_mock):
self._setup_rt()
orig_compute = _COMPUTE_NODE_FIXTURES[0].obj_clone()
@ -1580,42 +1577,6 @@ class TestUpdateComputeNode(BaseTestCase):
self.rt._update(mock.sentinel.ctx, new_compute)
save_mock.assert_called_once_with()
# The get_inventory() is not implemented, it shouldn't call
# _normalize_inventory_from_cn_obj
norm_mock.assert_not_called()
@mock.patch('nova.compute.resource_tracker.'
'_normalize_inventory_from_cn_obj')
@mock.patch('nova.objects.ComputeNode.save')
def test_existing_node_get_inventory_implemented(self, save_mock,
norm_mock):
"""The get_inventory() virt driver method is only implemented for some
virt drivers. This method returns inventory information for a
node/provider in a way that the placement API better understands.
"""
self._setup_rt()
self.driver_mock.update_provider_tree.side_effect = NotImplementedError
# Emulate a driver that has implemented the newish get_inventory() virt
# driver method
self.driver_mock.get_inventory.side_effect = [mock.sentinel.inv_data]
orig_compute = _COMPUTE_NODE_FIXTURES[0].obj_clone()
self.rt.compute_nodes[_NODENAME] = orig_compute
self.rt.old_resources[_NODENAME] = orig_compute
# Deliberately changing local_gb to trigger updating inventory
new_compute = orig_compute.obj_clone()
new_compute.local_gb = 210000
self.rt._update(mock.sentinel.ctx, new_compute)
save_mock.assert_called_once_with()
norm_mock.assert_called_once_with(mock.sentinel.inv_data, new_compute)
# Assert a warning was logged about using a virt driver that does not
# implement update_provider_tree.
self.assertIn('Compute driver "%s" does not implement the '
'"update_provider_tree" interface.' %
CONF.compute_driver, self.stdlog.logger.output)
@mock.patch('nova.compute.resource_tracker.ResourceTracker.'
'_sync_compute_service_disabled_trait')
@ -1654,14 +1615,10 @@ class TestUpdateComputeNode(BaseTestCase):
@mock.patch('nova.objects.ComputeNode.save')
def test_existing_node_update_provider_tree_implemented(
self, save_mock, mock_sync_disabled):
"""The update_provider_tree() virt driver method is only implemented
for some virt drivers. This method returns inventory, trait, and
"""The update_provider_tree() virt driver method must be implemented
by all virt drivers. This method returns inventory, trait, and
aggregate information for resource providers in a tree associated with
the compute node. If this method doesn't raise a NotImplementedError,
it triggers _update() to try get_inventory() and then
compute_node_to_inventory_dict() to produce the inventory data with
which to call the update_from_provider_tree() method of the reporting
client instead.
the compute node.
"""
fake_inv = {
orc.VCPU: {
@ -1721,7 +1678,6 @@ class TestUpdateComputeNode(BaseTestCase):
ptree, new_compute.hypervisor_hostname)
self.rt.reportclient.update_from_provider_tree.assert_called_once_with(
mock.sentinel.ctx, ptree, allocations=None)
self.driver_mock.get_inventory.assert_not_called()
ptree.update_traits.assert_called_once_with(
new_compute.hypervisor_hostname,
[]

View File

@ -972,9 +972,6 @@ class ComputeDriver(object):
node, as well as the inventory, aggregates, and traits associated with
those resource providers.
This method supersedes get_inventory(): if this method is implemented,
get_inventory() is not used.
Implementors of this interface are expected to set ``allocation_ratio``
and ``reserved`` values for inventory records, which may be based on
configuration options, e.g. ``[DEFAULT]/cpu_allocation_ratio``,
@ -1048,12 +1045,6 @@ class ComputeDriver(object):
"""
raise NotImplementedError()
def get_inventory(self, nodename):
"""Return a dict, keyed by resource class, of inventory information for
the supplied node.
"""
raise NotImplementedError()
def capabilities_as_traits(self):
"""Returns this driver's capabilities dict where the keys are traits

View File

@ -167,8 +167,6 @@ class PowerVMDriver(driver.ComputeDriver):
this.
:return: Dictionary describing resources.
"""
# TODO(efried): Switch to get_inventory, per blueprint
# custom-resource-classes-pike
# Do this here so it refreshes each time this method is called.
self.host_wrapper = pvm_ms.System.get(self.adapter)[0]
return self._get_available_resource()

View File

@ -0,0 +1,8 @@
---
upgrade:
- |
Compatibility code for compute drivers that do not implement the
`update_provider_tree`__ interface has been removed. All compute drivers
must now implement ``update_provider_tree``.
__ https://docs.openstack.org/nova/latest/reference/update-provider-tree.html