From 5251f18d87f21483fca385a0baccf76dfff85e92 Mon Sep 17 00:00:00 2001 From: Mark Goddard Date: Mon, 8 Jan 2018 14:15:10 +0000 Subject: [PATCH] Add get_traits() method to ComputeDriver The get_traits() virt driver method can be used by virt driver implementations to advertise the traits that are associated with the resource provider representing a given compute node. If implemented, the method should return an iterable of traits. Adds a call to the ComputeDriver.get_traits() method in the resource tracker, and submits the traits to the placement API using the scheduler client. Not all compute drivers implement get_traits, so the resource tracker gracefully handles NotImplementedError. blueprint ironic-driver-traits Change-Id: Ia088341d86aa87f72c9decb081e0a43c36939f18 --- nova/compute/resource_tracker.py | 13 ++++++++ .../unit/compute/test_resource_tracker.py | 31 +++++++++++++++++++ nova/virt/driver.py | 10 ++++++ 3 files changed, 54 insertions(+) diff --git a/nova/compute/resource_tracker.py b/nova/compute/resource_tracker.py index b0f64048eaa0..ef2b26b44b30 100644 --- a/nova/compute/resource_tracker.py +++ b/nova/compute/resource_tracker.py @@ -883,6 +883,19 @@ class ResourceTracker(object): # this code branch 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( + compute_node.uuid, traits) + if self.pci_tracker: self.pci_tracker.save(context) diff --git a/nova/tests/unit/compute/test_resource_tracker.py b/nova/tests/unit/compute/test_resource_tracker.py index 94c9e8d493d9..9b957b3fa4ff 100644 --- a/nova/tests/unit/compute/test_resource_tracker.py +++ b/nova/tests/unit/compute/test_resource_tracker.py @@ -433,6 +433,7 @@ 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.get_host_ip_addr.return_value = _NODENAME vd.estimate_instance_overhead.side_effect = estimate_overhead vd.rebalances_nodes = False @@ -1202,6 +1203,7 @@ 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): @@ -1250,6 +1252,7 @@ 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') @@ -1288,6 +1291,34 @@ 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( + new_compute.uuid, + mock.sentinel.traits, + ) + self.driver_mock.get_traits.assert_called_once_with(_NODENAME) def test_get_node_uuid(self): self._setup_rt() diff --git a/nova/virt/driver.py b/nova/virt/driver.py index df81af4f70cd..f575148e9c34 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -836,6 +836,16 @@ class ComputeDriver(object): """ raise NotImplementedError() + def get_traits(self, nodename): + """Get the traits for a given node. + + Returns an iterable of traits for the supplied node. + + :param nodename: the name of the node. + :returns: an iterable of traits for the supplied node. + """ + raise NotImplementedError() + def get_available_resource(self, nodename): """Retrieve resource information.