From fc4010176a5e445a1e5d333bbbd3e273e2448e79 Mon Sep 17 00:00:00 2001 From: Balazs Gibizer Date: Fri, 14 Dec 2018 15:56:14 +0100 Subject: [PATCH] Record requester in the InstancePCIRequest An InstancePCIRequest might represent the VF device request of a neutron port that has bandwidth request as well. In this case nova needs to correlate the pci request with the port's resource request to make sure the bandwidth and the VF are allocated from the same PF. This patch introduces the new ``requester_id`` field to the InstancePCIRequest ovo and stores the port_id in that field if the pci request is created from a neutron port. The value of the ``requester_id`` field will be used in a subsequent patch to match it against the existing RequestGroup.requester_id. Change-Id: I73786b7900957faca72d6ddfd01023a4b186e14d blueprint: bandwidth-resource-provider --- nova/network/neutronv2/api.py | 7 ++++++- nova/objects/instance_pci_requests.py | 12 +++++++++--- nova/pci/request.py | 4 ++++ nova/tests/unit/network/test_neutronv2.py | 5 +++++ nova/tests/unit/objects/test_instance.py | 3 ++- .../objects/test_instance_pci_requests.py | 19 ++++++++++++++++++- nova/tests/unit/objects/test_objects.py | 2 +- nova/tests/unit/pci/test_request.py | 2 ++ 8 files changed, 47 insertions(+), 7 deletions(-) diff --git a/nova/network/neutronv2/api.py b/nova/network/neutronv2/api.py index aba87fbb5ee1..c012baefd42f 100644 --- a/nova/network/neutronv2/api.py +++ b/nova/network/neutronv2/api.py @@ -2048,6 +2048,7 @@ class API(base_api.NetworkAPI): tunneled_ = False vnic_type = network_model.VNIC_TYPE_NORMAL pci_request_id = None + requester_id = None if request_net.port_id: result = self._get_port_vnic_info( @@ -2057,6 +2058,9 @@ class API(base_api.NetworkAPI): context, neutron, network_id) if resource_request: + # InstancePCIRequest.requester_id is semantically linked + # to a port with a resource_request. + requester_id = request_net.port_id # NOTE(gibi): explicitly orphan the RequestGroup by setting # context=None as we never intended to save it to the DB. resource_requests.append( @@ -2101,7 +2105,8 @@ class API(base_api.NetworkAPI): request = objects.InstancePCIRequest( count=1, spec=[spec], - request_id=uuidutils.generate_uuid()) + request_id=uuidutils.generate_uuid(), + requester_id=requester_id) pci_requests.requests.append(request) pci_request_id = request.request_id diff --git a/nova/objects/instance_pci_requests.py b/nova/objects/instance_pci_requests.py index 7a4f0b62c824..7e3a920c5a9e 100644 --- a/nova/objects/instance_pci_requests.py +++ b/nova/objects/instance_pci_requests.py @@ -25,7 +25,8 @@ class InstancePCIRequest(base.NovaObject, # Version 1.0: Initial version # Version 1.1: Add request_id # Version 1.2: Add PCI NUMA affinity policy - VERSION = '1.2' + # Version 1.3: Add requester_id + VERSION = '1.3' fields = { 'count': fields.IntegerField(), @@ -35,6 +36,7 @@ class InstancePCIRequest(base.NovaObject, # on major version bump 'is_new': fields.BooleanField(default=False), 'request_id': fields.UUIDField(nullable=True), + 'requester_id': fields.StringField(nullable=True), 'numa_policy': fields.PCINUMAAffinityPolicyField(nullable=True), } @@ -45,6 +47,8 @@ class InstancePCIRequest(base.NovaObject, super(InstancePCIRequest, self).obj_make_compatible(primitive, target_version) target_version = versionutils.convert_version_to_tuple(target_version) + if target_version < (1, 3) and 'requester_id' in primitive: + del primitive['requester_id'] if target_version < (1, 2) and 'numa_policy' in primitive: del primitive['numa_policy'] if target_version < (1, 1) and 'request_id' in primitive: @@ -86,7 +90,8 @@ class InstancePCIRequests(base.NovaObject, request_obj = InstancePCIRequest( count=request['count'], spec=request['spec'], alias_name=request['alias_name'], is_new=False, - request_id=request['request_id']) + request_id=request['request_id'], + requester_id=request.get('requester_id')) request_obj.obj_reset_changes() self.requests.append(request_obj) self.obj_reset_changes() @@ -137,7 +142,8 @@ class InstancePCIRequests(base.NovaObject, 'spec': x.spec, 'alias_name': x.alias_name, 'is_new': x.is_new, - 'request_id': x.request_id} for x in self.requests] + 'request_id': x.request_id, + 'requester_id': x.requester_id} for x in self.requests] return jsonutils.dumps(blob) @classmethod diff --git a/nova/pci/request.py b/nova/pci/request.py index c16c49102992..688caf064e74 100644 --- a/nova/pci/request.py +++ b/nova/pci/request.py @@ -159,6 +159,10 @@ def _translate_alias_to_requests(alias_spec): count = int(count) numa_policy, spec = pci_aliases[name] + # NOTE(gibi): InstancePCIRequest has a requester_id field that could + # be filled with the flavor.flavorid but currently there is no special + # handling for InstancePCIRequests created from the flavor. So it is + # left empty. pci_requests.append(objects.InstancePCIRequest( count=count, spec=spec, diff --git a/nova/tests/unit/network/test_neutronv2.py b/nova/tests/unit/network/test_neutronv2.py index 8bbc769a4663..449cd182d138 100644 --- a/nova/tests/unit/network/test_neutronv2.py +++ b/nova/tests/unit/network/test_neutronv2.py @@ -5463,6 +5463,11 @@ class TestNeutronv2WithMock(_TestNeutronv2Common): else: self.assertNotIn(pci_request.PCI_TRUSTED_TAG, spec) + # Only the port with a resource_request will have pci_req.requester_id. + self.assertEqual( + [None, None, None, None, uuids.trusted_port], + [pci_req.requester_id for pci_req in pci_requests.requests]) + self.assertItemsEqual( ['physnet1', 'physnet2', 'physnet3', 'physnet4'], network_metadata.physnets) diff --git a/nova/tests/unit/objects/test_instance.py b/nova/tests/unit/objects/test_instance.py index e193a5ce0a91..4b301ee280c9 100644 --- a/nova/tests/unit/objects/test_instance.py +++ b/nova/tests/unit/objects/test_instance.py @@ -572,7 +572,8 @@ class _TestInstanceObject(object): @mock.patch('nova.db.api.instance_extra_update_by_uuid') def test_save_object_pci_requests(self, mock_instance_extra_update): expected_json = ('[{"count": 1, "alias_name": null, "is_new": false,' - '"request_id": null, "spec": [{"vendor_id": "8086",' + '"request_id": null, "requester_id": null,' + '"spec": [{"vendor_id": "8086", ' '"product_id": "1502"}]}]') inst = objects.Instance() diff --git a/nova/tests/unit/objects/test_instance_pci_requests.py b/nova/tests/unit/objects/test_instance_pci_requests.py index c5ea05048739..98f5255cf03a 100644 --- a/nova/tests/unit/objects/test_instance_pci_requests.py +++ b/nova/tests/unit/objects/test_instance_pci_requests.py @@ -38,7 +38,8 @@ fake_pci_requests = [ 'device_id': '07B5'}], 'alias_name': 'alias_2', 'is_new': True, - 'request_id': FAKE_REQUEST_UUID}, + 'request_id': FAKE_REQUEST_UUID, + 'requester_id': uuids.requester_id}, ] fake_legacy_pci_requests = [ @@ -117,6 +118,8 @@ class _TestInstancePCIRequests(object): self.assertEqual(FAKE_UUID, req.instance_uuid) self.assertEqual(2, len(req.requests)) self.assertEqual('alias_1', req.requests[0].alias_name) + self.assertIsNone(None, req.requests[0].requester_id) + self.assertEqual(uuids.requester_id, req.requests[1].requester_id) def test_from_request_spec_instance_props(self): requests = objects.InstancePCIRequests( @@ -159,6 +162,20 @@ class _TestInstancePCIRequests(object): self.assertNotIn('request_id', primitive['nova_object.data']) + def test_obj_make_compatible_pre_1_3(self): + topo_obj = objects.InstancePCIRequest( + count=1, + spec=[{'vendor_id': '8086', 'device_id': '1502'}], + request_id=uuids.pci_request_id, + requester_id=uuids.requester_id, + numa_policy=fields.PCINUMAAffinityPolicy.PREFERRED) + versions = ovo_base.obj_tree_get_versions('InstancePCIRequest') + primitive = topo_obj.obj_to_primitive(target_version='1.2', + version_manifest=versions) + + self.assertNotIn('requester_id', primitive['nova_object.data']) + self.assertIn('numa_policy', primitive['nova_object.data']) + class TestInstancePCIRequests(test_objects._LocalTest, _TestInstancePCIRequests): diff --git a/nova/tests/unit/objects/test_objects.py b/nova/tests/unit/objects/test_objects.py index 12efdf353107..37947c87ec6a 100644 --- a/nova/tests/unit/objects/test_objects.py +++ b/nova/tests/unit/objects/test_objects.py @@ -1111,7 +1111,7 @@ object_data = { 'InstanceMappingList': '1.2-ee638619aa3d8a82a59c0c83bfa64d78', 'InstanceNUMACell': '1.4-7c1eb9a198dee076b4de0840e45f4f55', 'InstanceNUMATopology': '1.3-ec0030cb0402a49c96da7051c037082a', - 'InstancePCIRequest': '1.2-6344dd8bd1bf873e7325c07afe47f774', + 'InstancePCIRequest': '1.3-f6d324f1c337fad4f34892ed5f484c9a', 'InstancePCIRequests': '1.1-65e38083177726d806684cb1cc0136d2', 'KeyPair': '1.4-1244e8d1b103cc69d038ed78ab3a8cc6', 'KeyPairList': '1.3-94aad3ac5c938eef4b5e83da0212f506', diff --git a/nova/tests/unit/pci/test_request.py b/nova/tests/unit/pci/test_request.py index 7ac20859c8b0..bfeea10711c8 100644 --- a/nova/tests/unit/pci/test_request.py +++ b/nova/tests/unit/pci/test_request.py @@ -208,12 +208,14 @@ class AliasTestCase(test.NoDBTestCase): self.flags(alias=[_fake_alias1, _fake_alias3], group='pci') expect_request = [ {'count': 3, + 'requester_id': None, 'spec': [{'vendor_id': '8086', 'product_id': '4443', 'dev_type': 'type-PCI', 'capability_type': 'pci'}], 'alias_name': 'QuicAssist'}, {'count': 1, + 'requester_id': None, 'spec': [{'vendor_id': '8086', 'product_id': '1111', 'dev_type': "type-PF", 'capability_type': 'pci'}],