Merge "Convert ironic virt driver to update_provider_tree"

This commit is contained in:
Zuul 2018-06-20 16:42:53 +00:00 committed by Gerrit Code Review
commit 697eeae50c
6 changed files with 104 additions and 123 deletions

View File

@ -912,19 +912,6 @@ class ResourceTracker(object):
self.scheduler_client.update_compute_node(context,
compute_node)
try:
traits = self.driver.get_traits(nodename)
except NotImplementedError:
pass
else:
# NOTE(mgoddard): set_traits_for_provider does not refresh the
# provider tree in the report client, so we rely on the above
# call to set_inventory_for_provider or update_compute_node to
# ensure that the resource provider exists in the tree and has
# had its cached traits refreshed.
self.reportclient.set_traits_for_provider(
context, compute_node.uuid, traits)
if self.pci_tracker:
self.pci_tracker.save(context)

View File

@ -1714,24 +1714,6 @@ class ProviderTreeTests(integrated_helpers.ProviderUsageBaseTestCase):
self.assertNotIn('FOO', traits)
class TraitsTrackingTests(integrated_helpers.ProviderUsageBaseTestCase):
compute_driver = 'fake.SmallFakeDriver'
@mock.patch.object(fake.SmallFakeDriver, 'get_traits')
def test_resource_provider_traits(self, mock_traits):
traits = ['CUSTOM_FOO', 'HW_CPU_X86_VMX']
mock_traits.return_value = traits
self.assertNotIn('CUSTOM_FOO', self._get_all_traits())
self.assertEqual([], self._get_all_providers())
self.compute = self._start_compute(host='host1')
rp_uuid = self._get_provider_uuid_by_host('host1')
self.assertEqual(traits, sorted(self._get_provider_traits(rp_uuid)))
self.assertIn('CUSTOM_FOO', self._get_all_traits())
class ServerMovingTests(integrated_helpers.ProviderUsageBaseTestCase):
"""Tests moving servers while checking the resource allocations and usages

View File

@ -438,7 +438,6 @@ def setup_rt(hostname, virt_resources=_VIRT_DRIVER_AVAIL_RESOURCES,
virt_resources = copy.deepcopy(virt_resources)
vd.get_available_resource.return_value = virt_resources
vd.get_inventory.side_effect = NotImplementedError
vd.get_traits.side_effect = NotImplementedError
vd.update_provider_tree.side_effect = NotImplementedError
vd.get_host_ip_addr.return_value = _NODENAME
vd.estimate_instance_overhead.side_effect = estimate_overhead
@ -1209,7 +1208,6 @@ class TestUpdateComputeNode(BaseTestCase):
self.driver_mock.get_inventory.assert_called_once_with(_NODENAME)
ucn_mock = self.sched_client_mock.update_compute_node
ucn_mock.assert_called_once_with(mock.sentinel.ctx, new_compute)
self.driver_mock.get_traits.assert_called_once_with(_NODENAME)
@mock.patch('nova.objects.ComputeNode.save')
def test_existing_compute_node_updated_diff_updated_at(self, save_mock):
@ -1258,7 +1256,6 @@ class TestUpdateComputeNode(BaseTestCase):
self.assertFalse(norm_mock.called)
ucn_mock = self.sched_client_mock.update_compute_node
ucn_mock.assert_called_once_with(mock.sentinel.ctx, new_compute)
self.driver_mock.get_traits.assert_called_once_with(_NODENAME)
@mock.patch('nova.compute.resource_tracker.'
'_normalize_inventory_from_cn_obj')
@ -1274,7 +1271,7 @@ class TestUpdateComputeNode(BaseTestCase):
"""
self._setup_rt()
# Emulate a driver that has implemented the new get_inventory() virt
# Emulate a driver that has implemented the newish get_inventory() virt
# driver method
self.driver_mock.get_inventory.side_effect = [mock.sentinel.inv_data]
@ -1297,35 +1294,6 @@ class TestUpdateComputeNode(BaseTestCase):
mock.sentinel.inv_data,
)
self.assertFalse(ucn_mock.called)
self.driver_mock.get_traits.assert_called_once_with(_NODENAME)
def test_existing_node_get_traits_implemented(self):
"""The get_traits() virt driver method is only implemented for some
virt drivers. This method returns traits information for a
node/provider, and if this method doesn't raise a NotImplementedError,
this triggers _update() to call the set_traits_for_provider() method of
the reporting client.
"""
self._setup_rt()
rc = self.rt.reportclient
rc.set_traits_for_provider = mock.MagicMock()
# Emulate a driver that has implemented the new get_traits() virt
# driver method
self.driver_mock.get_traits.side_effect = [mock.sentinel.traits]
orig_compute = _COMPUTE_NODE_FIXTURES[0].obj_clone()
self.rt.compute_nodes[_NODENAME] = orig_compute
self.rt.old_resources[_NODENAME] = orig_compute
new_compute = orig_compute.obj_clone()
self.rt._update(mock.sentinel.ctx, new_compute)
rc.set_traits_for_provider.assert_called_once_with(
mock.sentinel.ctx,
new_compute.uuid,
mock.sentinel.traits,
)
self.driver_mock.get_traits.assert_called_once_with(_NODENAME)
@mock.patch('nova.objects.ComputeNode.save')
def test_existing_node_update_provider_tree_implemented(self, save_mock):

View File

@ -27,6 +27,7 @@ from tooz import hashring as hash_ring
from nova.api.metadata import base as instance_metadata
from nova import block_device
from nova.compute import power_state as nova_states
from nova.compute import provider_tree
from nova.compute import task_states
from nova.compute import vm_states
from nova.console import type as console_type
@ -119,6 +120,9 @@ class IronicDriverTestCase(test.NoDBTestCase):
self.ctx = nova_context.get_admin_context()
self.instance_uuid = uuidutils.generate_uuid()
self.ptree = provider_tree.ProviderTree()
self.ptree.new_root(mock.sentinel.nodename, mock.sentinel.nodename)
# mock retries configs to avoid sleeps and make tests run quicker
CONF.set_default('api_max_retries', default=1, group='ironic')
CONF.set_default('api_retry_interval', default=0, group='ironic')
@ -709,8 +713,8 @@ class IronicDriverTestCase(test.NoDBTestCase):
'_node_resources_unavailable', return_value=False)
@mock.patch.object(ironic_driver.IronicDriver, '_node_resource')
@mock.patch.object(ironic_driver.IronicDriver, '_node_from_cache')
def test_get_inventory_no_rc(self, mock_nfc, mock_nr, mock_res_unavail,
mock_res_used):
def test_update_provider_tree_no_rc(self, mock_nfc, mock_nr,
mock_res_unavail, mock_res_used):
"""Ensure that when node.resource_class is missing, that we return the
legacy VCPU, MEMORY_MB and DISK_GB resources for inventory.
"""
@ -724,7 +728,7 @@ class IronicDriverTestCase(test.NoDBTestCase):
'resource_class': None,
}
result = self.driver.get_inventory(mock.sentinel.nodename)
self.driver.update_provider_tree(self.ptree, mock.sentinel.nodename)
expected = {
fields.ResourceClass.VCPU: {
@ -756,6 +760,7 @@ class IronicDriverTestCase(test.NoDBTestCase):
mock_nr.assert_called_once_with(mock_nfc.return_value)
mock_res_used.assert_called_once_with(mock_nfc.return_value)
mock_res_unavail.assert_called_once_with(mock_nfc.return_value)
result = self.ptree.data(mock.sentinel.nodename).inventory
self.assertEqual(expected, result)
@mock.patch.object(ironic_driver.IronicDriver,
@ -764,8 +769,8 @@ class IronicDriverTestCase(test.NoDBTestCase):
'_node_resources_unavailable', return_value=False)
@mock.patch.object(ironic_driver.IronicDriver, '_node_resource')
@mock.patch.object(ironic_driver.IronicDriver, '_node_from_cache')
def test_get_inventory_with_rc(self, mock_nfc, mock_nr, mock_res_unavail,
mock_res_used):
def test_update_provider_tree_with_rc(self, mock_nfc, mock_nr,
mock_res_unavail, mock_res_used):
"""Ensure that when node.resource_class is present, that we return the
legacy VCPU, MEMORY_MB and DISK_GB resources for inventory in addition
to the custom resource class inventory record.
@ -780,7 +785,7 @@ class IronicDriverTestCase(test.NoDBTestCase):
'resource_class': 'iron-nfv',
}
result = self.driver.get_inventory(mock.sentinel.nodename)
self.driver.update_provider_tree(self.ptree, mock.sentinel.nodename)
expected = {
fields.ResourceClass.VCPU: {
@ -820,6 +825,7 @@ class IronicDriverTestCase(test.NoDBTestCase):
mock_nr.assert_called_once_with(mock_nfc.return_value)
mock_res_used.assert_called_once_with(mock_nfc.return_value)
mock_res_unavail.assert_called_once_with(mock_nfc.return_value)
result = self.ptree.data(mock.sentinel.nodename).inventory
self.assertEqual(expected, result)
@mock.patch.object(ironic_driver.IronicDriver,
@ -828,8 +834,8 @@ class IronicDriverTestCase(test.NoDBTestCase):
'_node_resources_unavailable', return_value=False)
@mock.patch.object(ironic_driver.IronicDriver, '_node_resource')
@mock.patch.object(ironic_driver.IronicDriver, '_node_from_cache')
def test_get_inventory_only_rc(self, mock_nfc, mock_nr, mock_res_unavail,
mock_res_used):
def test_update_provider_tree_only_rc(self, mock_nfc, mock_nr,
mock_res_unavail, mock_res_used):
"""Ensure that when node.resource_class is present, that we return the
legacy VCPU, MEMORY_MB and DISK_GB resources for inventory in addition
to the custom resource class inventory record.
@ -844,7 +850,7 @@ class IronicDriverTestCase(test.NoDBTestCase):
'resource_class': 'iron-nfv',
}
result = self.driver.get_inventory(mock.sentinel.nodename)
self.driver.update_provider_tree(self.ptree, mock.sentinel.nodename)
expected = {
'CUSTOM_IRON_NFV': {
@ -860,6 +866,7 @@ class IronicDriverTestCase(test.NoDBTestCase):
mock_nr.assert_called_once_with(mock_nfc.return_value)
mock_res_used.assert_called_once_with(mock_nfc.return_value)
mock_res_unavail.assert_called_once_with(mock_nfc.return_value)
result = self.ptree.data(mock.sentinel.nodename).inventory
self.assertEqual(expected, result)
@mock.patch.object(ironic_driver.IronicDriver,
@ -868,8 +875,9 @@ class IronicDriverTestCase(test.NoDBTestCase):
'_node_resources_unavailable', return_value=False)
@mock.patch.object(ironic_driver.IronicDriver, '_node_resource')
@mock.patch.object(ironic_driver.IronicDriver, '_node_from_cache')
def test_get_inventory_with_rc_occupied(self, mock_nfc, mock_nr,
mock_res_unavail, mock_res_used):
def test_update_provider_tree_with_rc_occupied(self, mock_nfc, mock_nr,
mock_res_unavail,
mock_res_used):
"""Ensure that when a node is used, we report the inventory matching
the consumed resources.
"""
@ -883,7 +891,7 @@ class IronicDriverTestCase(test.NoDBTestCase):
'resource_class': 'iron-nfv',
}
result = self.driver.get_inventory(mock.sentinel.nodename)
self.driver.update_provider_tree(self.ptree, mock.sentinel.nodename)
expected = {
fields.ResourceClass.VCPU: {
@ -923,6 +931,7 @@ class IronicDriverTestCase(test.NoDBTestCase):
mock_nr.assert_called_once_with(mock_nfc.return_value)
mock_res_used.assert_called_once_with(mock_nfc.return_value)
self.assertFalse(mock_res_unavail.called)
result = self.ptree.data(mock.sentinel.nodename).inventory
self.assertEqual(expected, result)
@mock.patch.object(ironic_driver.IronicDriver,
@ -930,37 +939,80 @@ class IronicDriverTestCase(test.NoDBTestCase):
@mock.patch.object(ironic_driver.IronicDriver,
'_node_resources_unavailable', return_value=True)
@mock.patch.object(ironic_driver.IronicDriver, '_node_from_cache')
def test_get_inventory_disabled_node(self, mock_nfc, mock_res_unavail,
mock_res_used):
"""Ensure that when a node is disabled, that get_inventory() returns
an empty dict.
def test_update_provider_tree_disabled_node(self, mock_nfc,
mock_res_unavail,
mock_res_used):
"""Ensure that when a node is disabled, that update_provider_tree()
sets inventory to an empty dict.
"""
result = self.driver.get_inventory(mock.sentinel.nodename)
self.driver.update_provider_tree(self.ptree, mock.sentinel.nodename)
mock_nfc.assert_called_once_with(mock.sentinel.nodename)
mock_res_used.assert_called_once_with(mock_nfc.return_value)
mock_res_unavail.assert_called_once_with(mock_nfc.return_value)
result = self.ptree.data(mock.sentinel.nodename).inventory
self.assertEqual({}, result)
@mock.patch.object(ironic_driver.IronicDriver,
'_node_resources_used', return_value=True)
@mock.patch.object(ironic_driver.IronicDriver,
'_node_resources_unavailable', return_value=False)
@mock.patch.object(ironic_driver.IronicDriver, '_node_resource')
@mock.patch.object(ironic_driver.IronicDriver, '_node_from_cache')
def test_get_traits_no_traits(self, mock_nfc):
"""Ensure that when the node has no traits, we return no traits."""
node = _get_cached_node()
mock_nfc.return_value = node
result = self.driver.get_traits(node.uuid)
def test_update_provider_tree_no_traits(self, mock_nfc, mock_nr,
mock_res_unavail, mock_res_used):
"""Ensure that when the node has no traits, we set no traits."""
mock_nr.return_value = {
'vcpus': 24,
'vcpus_used': 24,
'memory_mb': 1024,
'memory_mb_used': 1024,
'local_gb': 100,
'local_gb_used': 100,
'resource_class': 'iron-nfv',
}
mock_nfc.assert_called_once_with(node.uuid)
self.assertEqual([], result)
mock_nfc.return_value = _get_cached_node(uuid=mock.sentinel.nodename)
self.driver.update_provider_tree(self.ptree, mock.sentinel.nodename)
mock_nfc.assert_called_once_with(mock.sentinel.nodename)
mock_nr.assert_called_once_with(mock_nfc.return_value)
mock_res_used.assert_called_once_with(mock_nfc.return_value)
self.assertFalse(mock_res_unavail.called)
result = self.ptree.data(mock.sentinel.nodename).traits
self.assertEqual(set(), result)
@mock.patch.object(ironic_driver.IronicDriver,
'_node_resources_used', return_value=True)
@mock.patch.object(ironic_driver.IronicDriver,
'_node_resources_unavailable', return_value=False)
@mock.patch.object(ironic_driver.IronicDriver, '_node_resource')
@mock.patch.object(ironic_driver.IronicDriver, '_node_from_cache')
def test_get_traits_with_traits(self, mock_nfc):
"""Ensure that when the node has traits, we return the traits."""
node = _get_cached_node(traits=['trait1', 'trait2'])
mock_nfc.return_value = node
result = self.driver.get_traits(node.uuid)
def test_update_provider_tree_with_traits(self, mock_nfc, mock_nr,
mock_res_unavail, mock_res_used):
"""Ensure that when the node has traits, we set the traits."""
mock_nr.return_value = {
'vcpus': 24,
'vcpus_used': 24,
'memory_mb': 1024,
'memory_mb_used': 1024,
'local_gb': 100,
'local_gb_used': 100,
'resource_class': 'iron-nfv',
}
expected = ['trait1', 'trait2']
mock_nfc.assert_called_once_with(node.uuid)
self.assertEqual(expected, result)
traits = ['trait1', 'trait2']
mock_nfc.return_value = _get_cached_node(
uuid=mock.sentinel.nodename, traits=traits)
self.driver.update_provider_tree(self.ptree, mock.sentinel.nodename)
mock_nfc.assert_called_once_with(mock.sentinel.nodename)
mock_nr.assert_called_once_with(mock_nfc.return_value)
mock_res_used.assert_called_once_with(mock_nfc.return_value)
self.assertFalse(mock_res_unavail.called)
result = self.ptree.data(mock.sentinel.nodename).traits
self.assertEqual(set(traits), result)
@mock.patch.object(FAKE_CLIENT.node, 'get')
@mock.patch.object(FAKE_CLIENT.node, 'list')

View File

@ -883,17 +883,6 @@ class ComputeDriver(object):
"""
raise NotImplementedError()
def get_traits(self, nodename):
"""Get the traits for a given node.
Any custom traits returned are not required to exist in the placement
service - the caller will ensure their existence.
:param nodename: the name of the node.
:returns: an iterable of string trait names for the supplied node.
"""
raise NotImplementedError()
def get_available_resource(self, nodename):
"""Retrieve resource information.

View File

@ -734,9 +734,21 @@ class IronicDriver(virt_driver.ComputeDriver):
return node_uuids
def get_inventory(self, nodename):
"""Return a dict, keyed by resource class, of inventory information for
the supplied node.
def update_provider_tree(self, provider_tree, nodename):
"""Update a ProviderTree object with current resource provider and
inventory information.
:param nova.compute.provider_tree.ProviderTree provider_tree:
A nova.compute.provider_tree.ProviderTree object representing all
the providers in the tree associated with the compute node, and any
sharing providers (those with the ``MISC_SHARES_VIA_AGGREGATE``
trait) associated via aggregate with any of those providers (but
not *their* tree- or aggregate-associated providers), as currently
known by placement.
:param nodename:
String name of the compute node (i.e.
ComputeNode.hypervisor_hostname) for which the caller is requesting
updated provider information.
"""
# nodename is the ironic node's UUID.
node = self._node_from_cache(nodename)
@ -788,19 +800,10 @@ class IronicDriver(virt_driver.ComputeDriver):
'allocation_ratio': 1.0,
}
return result
def get_traits(self, nodename):
"""Get the traits for a given node.
Any custom traits returned are not required to exist in the placement
service - the caller will ensure their existence.
:param nodename: the UUID of the node.
:returns: an iterable of string trait names for the supplied node.
"""
node = self._node_from_cache(nodename)
return list(node.traits)
provider_tree.update_inventory(nodename, result)
# TODO(efried): *Unset* traits that are "owned" by ironic virt but not
# set on the node object.
provider_tree.add_traits(nodename, *node.traits)
def get_available_resource(self, nodename):
"""Retrieve resource information.