Transfer RequestLevelParams from ports to scheduling

The new format of the resource_request field of the Neutron port allows
expressing not just request groups but also request global parameters
for the allocation candidate query. This patch adapts the neutron client
in nova to parse such parameters. Then transfer this information to the
scheduler to include it in the allocation candidate request.

It relies on previous patches that already extended the
RequestLevelParams ovo and the allocation candidate query generation.

Change-Id: Icb91f6429050a161f577d0ed94d4cd906d3da461
blueprint: qos-minimum-guaranteed-packet-rate
This commit is contained in:
Balazs Gibizer
2021-05-28 14:26:05 +02:00
parent d6cd4420bb
commit 94f47471e0
12 changed files with 232 additions and 74 deletions
+14 -9
View File
@@ -1063,7 +1063,7 @@ class API:
result = self.network_api.create_resource_requests(
context, requested_networks, pci_request_info,
affinity_policy=pci_numa_affinity_policy)
network_metadata, port_resource_requests = result
network_metadata, port_resource_requests, req_lvl_params = result
self._check_support_vnic_accelerator(context, requested_networks)
@@ -1103,7 +1103,9 @@ class API:
'pci_requests': pci_request_info,
'numa_topology': numa_topology,
'system_metadata': system_metadata,
'port_resource_requests': port_resource_requests}
'port_resource_requests': port_resource_requests,
'request_level_params': req_lvl_params,
}
options_from_image = self._inherit_properties_from_image(
boot_meta, auto_disk_config)
@@ -1295,6 +1297,7 @@ class API:
security_groups = security_group_api.populate_security_groups(
security_groups)
port_resource_requests = base_options.pop('port_resource_requests')
req_lvl_params = base_options.pop('request_level_params')
instances_to_build = []
# We could be iterating over several instances with several BDMs per
# instance and those BDMs could be using a lot of the same images so
@@ -1324,13 +1327,15 @@ class API:
# RequestSpec before the instance is created.
instance_uuid = uuidutils.generate_uuid()
# Store the RequestSpec that will be used for scheduling.
req_spec = objects.RequestSpec.from_components(context,
instance_uuid, boot_meta, flavor,
base_options['numa_topology'],
base_options['pci_requests'], filter_properties,
instance_group, base_options['availability_zone'],
security_groups=security_groups,
port_resource_requests=port_resource_requests)
req_spec = objects.RequestSpec.from_components(
context,
instance_uuid, boot_meta, flavor,
base_options['numa_topology'],
base_options['pci_requests'], filter_properties,
instance_group, base_options['availability_zone'],
security_groups=security_groups,
port_resource_requests=port_resource_requests,
request_level_params=req_lvl_params)
if block_device_mapping:
# Record whether or not we are a BFV instance
+14 -5
View File
@@ -7643,6 +7643,7 @@ class ComputeManager(manager.Manager):
instance: 'objects.Instance',
pci_reqs: 'objects.InstancePCIRequests',
request_groups: ty.List['objects.RequestGroup'],
request_level_params: 'objects.RequestLevelParams',
) -> ty.Tuple[ty.Optional[ty.Dict[str, ty.List[str]]],
ty.Optional[ty.Dict[str, ty.Dict[str, ty.Dict[str, int]]]]]:
"""Allocate resources for the request in placement
@@ -7654,6 +7655,8 @@ class ComputeManager(manager.Manager):
needed PCI devices
:param request_groups: A list of RequestGroup objects describing the
resources the port requests from placement
:param request_level_params: A RequestLevelParams object describing the
non group specific request of the port.
:raises InterfaceAttachResourceAllocationFailed: if we failed to
allocate resource in placement for the request
:returns: A tuple of provider mappings and allocated resources or
@@ -7682,7 +7685,8 @@ class ComputeManager(manager.Manager):
# NOTE(gibi): when support is added for attaching a cyborg based
# smart NIC the ResourceRequest could be extended to handle multiple
# request groups.
rr = scheduler_utils.ResourceRequest.from_request_group(request_group)
rr = scheduler_utils.ResourceRequest.from_request_group(
request_group, request_level_params)
res = self.reportclient.get_allocation_candidates(context, rr)
alloc_reqs, provider_sums, version = res
@@ -7805,9 +7809,14 @@ class ComputeManager(manager.Manager):
instance.flavor, instance.image_meta)
pci_reqs = objects.InstancePCIRequests(
requests=[], instance_uuid=instance.uuid)
_, request_groups = self.network_api.create_resource_requests(
context, requested_networks, pci_reqs,
affinity_policy=pci_numa_affinity_policy)
_, request_groups, req_lvl_params = (
self.network_api.create_resource_requests(
context,
requested_networks,
pci_reqs,
affinity_policy=pci_numa_affinity_policy
)
)
# We only support one port per attach request so we at most have one
# pci request
@@ -7816,7 +7825,7 @@ class ComputeManager(manager.Manager):
requested_networks[0].pci_request_id = pci_req.request_id
result = self._allocate_port_resource_for_instance(
context, instance, pci_reqs, request_groups)
context, instance, pci_reqs, request_groups, req_lvl_params)
provider_mappings, resources = result
try:
+16 -7
View File
@@ -2050,13 +2050,15 @@ class API:
:type affinity_policy: nova.objects.fields.PCINUMAAffinityPolicy
:raises ExtendedResourceRequestNotSupported: if the
extended-resource-request Neutron API extension is enabled.
:returns: A tuple with an instance of ``objects.NetworkMetadata`` for
use by the scheduler or None and a list of RequestGroup
objects representing the resource needs of each requested
port
:returns: A three tuple with an instance of ``objects.NetworkMetadata``
for use by the scheduler or None, a list of RequestGroup
objects representing the resource needs of each requested port and
a RequestLevelParam object that contains global scheduling
instructions not specific to any of the RequestGroups
"""
if not requested_networks or requested_networks.no_allocate:
return None, []
return None, [], None
if not self.support_create_with_resource_request(context):
raise exception.ExtendedResourceRequestNotSupported()
@@ -2068,6 +2070,7 @@ class API:
has_extended_resource_request_extension = (
self._has_extended_resource_request_extension(context, neutron))
resource_requests = []
request_level_params = objects.RequestLevelParams()
for request_net in requested_networks:
physnet = None
@@ -2122,6 +2125,9 @@ class API:
objects.RequestGroup.from_extended_port_request(
context=None,
port_resource_request=resource_request))
request_level_params.extend_with(
objects.RequestLevelParams.from_port_request(
port_resource_request=resource_request))
else:
# keep supporting the old format of the
# resource_request
@@ -2183,8 +2189,11 @@ class API:
# Add pci_request_id into the requested network
request_net.pci_request_id = pci_request_id
return (objects.NetworkMetadata(physnets=physnets, tunneled=tunneled),
resource_requests)
return (
objects.NetworkMetadata(physnets=physnets, tunneled=tunneled),
resource_requests,
request_level_params
)
def _can_auto_allocate_network(self, context, neutron):
"""Helper method to determine if we can auto-allocate networks
+12 -8
View File
@@ -474,10 +474,12 @@ class RequestSpec(base.NovaObject):
return filt_props
@classmethod
def from_components(cls, context, instance_uuid, image, flavor,
numa_topology, pci_requests, filter_properties, instance_group,
availability_zone, security_groups=None, project_id=None,
user_id=None, port_resource_requests=None):
def from_components(
cls, context, instance_uuid, image, flavor,
numa_topology, pci_requests, filter_properties, instance_group,
availability_zone, security_groups=None, project_id=None,
user_id=None, port_resource_requests=None, request_level_params=None
):
"""Returns a new RequestSpec object hydrated by various components.
This helper is useful in creating the RequestSpec from the various
@@ -503,6 +505,7 @@ class RequestSpec(base.NovaObject):
:param port_resource_requests: a list of RequestGroup objects
representing the resource needs of the
neutron ports
:param request_level_params: a RequestLevelParams object
"""
spec_obj = cls(context)
spec_obj.num_instances = 1
@@ -536,10 +539,11 @@ class RequestSpec(base.NovaObject):
if port_resource_requests:
spec_obj.requested_resources.extend(port_resource_requests)
# NOTE(efried): We don't need to handle request_level_params here yet
# because they're set dynamically by the scheduler. That could change
# in the future.
# TODO(gibi): handle same_subtree here coming from the neutron ports
# NOTE(gibi): later the scheduler adds more request level params but
# never overrides existing ones so we can initialize them here.
if request_level_params is None:
request_level_params = objects.RequestLevelParams()
spec_obj.request_level_params = request_level_params
# NOTE(sbauza): Default the other fields that are not part of the
# original contract
+4
View File
@@ -202,9 +202,13 @@ class ResourceRequest(object):
def from_request_group(
cls,
request_group: 'objects.RequestGroup',
request_level_params: 'objects.RequestLevelParams',
) -> 'ResourceRequest':
"""Create a new instance of ResourceRequest from a RequestGroup."""
res_req = cls()
res_req._root_required = request_level_params.root_required
res_req._root_forbidden = request_level_params.root_forbidden
res_req._same_subtree = request_level_params.same_subtree
res_req._add_request_group(request_group)
res_req.strip_zeros()
return res_req
+1 -1
View File
@@ -184,7 +184,7 @@ def stub_out_nw_api(test, cls=None, private=None, publics=None):
def create_resource_requests(
self, context, requested_networks,
pci_requests=None, affinity_policy=None):
return None, []
return None, [], objects.RequestLevelParams()
if cls is None:
cls = Fake
+43 -11
View File
@@ -223,9 +223,11 @@ class _ComputeAPIUnitTestMixIn(object):
objects=[objects.NetworkRequest(address=address,
port_id=port)])
with mock.patch.object(self.compute_api.network_api,
'create_resource_requests',
return_value=(None, [])):
with mock.patch.object(
self.compute_api.network_api,
'create_resource_requests',
return_value=(None, [], mock.sentinel.req_lvl_params)
):
self.compute_api.create(self.context, flavor, 'image_id',
requested_networks=requested_networks,
max_count=None)
@@ -4888,7 +4890,10 @@ class _ComputeAPIUnitTestMixIn(object):
'user_data': None,
'numa_topology': None,
'pci_requests': None,
'port_resource_requests': None}
'port_resource_requests': None,
'request_level_params':
objects.RequestLevelParams(),
}
security_groups = {}
block_device_mapping = objects.BlockDeviceMappingList(
objects=[objects.BlockDeviceMapping(
@@ -5059,10 +5064,12 @@ class _ComputeAPIUnitTestMixIn(object):
'properties': {'mappings': []},
'status': 'fake-status',
'location': 'far-away'}
numa_topology = objects.InstanceNUMATopology()
pci_requests = objects.InstancePCIRequests()
base_options = {'image_ref': 'fake-ref',
'display_name': 'fake-name',
'project_id': 'fake-project',
'availability_zone': None,
'availability_zone': 'fake-az',
'metadata': {},
'access_ip_v4': None,
'access_ip_v6': None,
@@ -5073,9 +5080,13 @@ class _ComputeAPIUnitTestMixIn(object):
'ramdisk_id': None,
'root_device_name': None,
'user_data': None,
'numa_topology': None,
'pci_requests': None,
'port_resource_requests': None}
'numa_topology': numa_topology,
'pci_requests': pci_requests,
'port_resource_requests':
mock.sentinel.resource_reqs,
'request_level_params':
mock.sentinel.req_lvl_params,
}
security_groups = {}
block_device_mappings = objects.BlockDeviceMappingList(
objects=[objects.BlockDeviceMapping(
@@ -5112,6 +5123,18 @@ class _ComputeAPIUnitTestMixIn(object):
block_device_mappings, {}, mock_get_volumes.return_value,
False)] * max_count)
mock_req_spec_from_components.assert_has_calls(
[
mock.call(
ctxt, mock.ANY, boot_meta, flavor, numa_topology,
pci_requests, filter_properties, instance_group,
'fake-az', security_groups=mock.ANY,
port_resource_requests=mock.sentinel.resource_reqs,
request_level_params=mock.sentinel.req_lvl_params
),
] * 2
)
for rs, br, im in instances_to_build:
self.assertIsInstance(br.instance, objects.Instance)
self.assertTrue(uuidutils.is_uuid_like(br.instance.uuid))
@@ -5165,7 +5188,10 @@ class _ComputeAPIUnitTestMixIn(object):
'user_data': None,
'numa_topology': None,
'pci_requests': None,
'port_resource_requests': None}
'port_resource_requests': None,
'request_level_params':
objects.RequestLevelParams(),
}
security_groups = {}
block_device_mapping = objects.BlockDeviceMappingList(
objects=[objects.BlockDeviceMapping(
@@ -5262,7 +5288,11 @@ class _ComputeAPIUnitTestMixIn(object):
'user_data': None,
'numa_topology': None,
'pci_requests': None,
'port_resource_requests': None}
'port_resource_requests': None,
'request_level_params':
objects.RequestLevelParams(),
}
security_groups = {}
block_device_mapping = objects.BlockDeviceMappingList(
objects=[objects.BlockDeviceMapping(
@@ -5328,7 +5358,9 @@ class _ComputeAPIUnitTestMixIn(object):
mock_objects.RequestSpec.from_components.assert_called_once_with(
mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY,
mock.ANY, mock.ANY, mock.ANY,
security_groups=secgroups, port_resource_requests=mock.ANY)
security_groups=secgroups, port_resource_requests=mock.ANY,
request_level_params=mock.ANY
)
test()
def _test_rescue(self, vm_state=vm_states.ACTIVE, rescue_password=None,
+75 -21
View File
@@ -8692,11 +8692,13 @@ class ComputeAPITestCase(BaseTestCase):
objects=[objects.NetworkRequest(port_id=uuids.port_instance)])
with test.nested(
mock.patch.object(self.compute_api.compute_task_api,
'schedule_and_build_instances'),
mock.patch.object(self.compute_api.network_api,
'create_resource_requests',
return_value=(None, [])),
mock.patch.object(
self.compute_api.compute_task_api,
'schedule_and_build_instances'),
mock.patch.object(
self.compute_api.network_api,
'create_resource_requests',
return_value=(None, [], objects.RequestLevelParams())),
) as (mock_sbi, _mock_create_resreqs):
self.compute_api.create(
self.context,
@@ -10195,7 +10197,8 @@ class ComputeAPITestCase(BaseTestCase):
"_claim_pci_device_for_interface_attach",
return_value=None)
) as (cap, mock_lock, mock_create_resource_req, mock_claim_pci):
mock_create_resource_req.return_value = (None, [])
mock_create_resource_req.return_value = (
None, [], mock.sentinel.req_lvl_params)
vif = self.compute.attach_interface(self.context,
instance,
network_id,
@@ -10255,7 +10258,8 @@ class ComputeAPITestCase(BaseTestCase):
mock_allocate_res
):
request_groups = [objects.RequestGroup]
mock_create_resource_req.return_value = (None, request_groups)
mock_create_resource_req.return_value = (
None, request_groups, mock.sentinel.req_lvl_params)
mock_allocate_res.return_value = (
mock.sentinel.provider_mappings, mock.sentinel.resources)
vif = self.compute.attach_interface(
@@ -10300,7 +10304,9 @@ class ComputeAPITestCase(BaseTestCase):
# as this port has resource request we need to call
# _allocate_port_resource_for_instance for it
mock_allocate_res.assert_called_once_with(
self.context, instance, pci_reqs, request_groups)
self.context, instance, pci_reqs, request_groups,
mock.sentinel.req_lvl_params
)
@mock.patch.object(compute_utils, 'notify_about_instance_action')
def test_attach_sriov_interface(self, mock_notify):
@@ -10337,7 +10343,7 @@ class ComputeAPITestCase(BaseTestCase):
# Simulate that the requested port is an SRIOV port
pci_requests.requests.append(pci_req)
# without resource request
return None, []
return None, [], mock.sentinel.req_lvl_params
mock_create_resource_req.side_effect = create_resource_req
@@ -10413,7 +10419,7 @@ class ComputeAPITestCase(BaseTestCase):
# Simulate that the requested port is an SRIOV port
pci_requests.requests.append(pci_req)
# with resource request
return None, request_groups
return None, request_groups, mock.sentinel.req_lvl_params
mock_create_resource_req.side_effect = create_resource_req
@@ -10464,9 +10470,11 @@ class ComputeAPITestCase(BaseTestCase):
self.assertIn(pci_device, instance.pci_devices.objects)
# ensure that we called _allocate_port_resource_for_instance as it has
# resource reques
# resource request
mock_allocate_res.assert_called_once_with(
self.context, instance, pci_reqs, request_groups)
self.context, instance, pci_reqs, request_groups,
mock.sentinel.req_lvl_params
)
@mock.patch.object(compute_utils, 'notify_about_instance_action')
def test_interface_tagged_attach(self, mock_notify):
@@ -10487,7 +10495,8 @@ class ComputeAPITestCase(BaseTestCase):
'_claim_pci_device_for_interface_attach',
return_value=None)
) as (mock_capabilities, mock_create_resource_req, mock_claim_pci):
mock_create_resource_req.return_value = (None, [])
mock_create_resource_req.return_value = (
None, [], mock.sentinel.req_lvl_params)
vif = self.compute.attach_interface(self.context,
instance,
network_id,
@@ -10563,7 +10572,8 @@ class ComputeAPITestCase(BaseTestCase):
) as (mock_notify, mock_attach, mock_allocate, mock_deallocate,
mock_dict, mock_create_resource_req, mock_claim_pci):
mock_create_resource_req.return_value = (None, [])
mock_create_resource_req.return_value = (
None, [], mock.sentinel.req_lvl_params)
mock_allocate.return_value = nwinfo
mock_attach.side_effect = exception.NovaException("attach_failed")
self.assertRaises(exception.InterfaceAttachFailed,
@@ -10641,7 +10651,7 @@ class ComputeAPITestCase(BaseTestCase):
pci_requests=None, affinity_policy=None):
# Simulate that the requested port is an SRIOV port
pci_requests.requests.append(pci_req)
return None, []
return None, [], mock.sentinel.req_lvl_params
mock_create_resource_req.side_effect = create_resource_req
mock_allocate.return_value = nwinfo
@@ -10716,7 +10726,7 @@ class ComputeAPITestCase(BaseTestCase):
pci_requests=None, affinity_policy=None):
# Simulate that the requested port is an SRIOV port
pci_requests.requests.append(pci_req)
return None, request_groups
return None, request_groups, mock.sentinel.req_lvl_params
mock_create_resource_req.side_effect = create_resource_req
mock_allocate_res.return_value = (
@@ -10741,7 +10751,12 @@ class ComputeAPITestCase(BaseTestCase):
self.assertNotIn(pci_req, instance.pci_requests.requests)
mock_allocate_res.assert_called_once_with(
self.context, instance, pci_reqs, request_groups)
self.context,
instance,
pci_reqs,
request_groups,
mock.sentinel.req_lvl_params
)
mock_remove_res.assert_called_once_with(
self.context, instance.uuid, mock.sentinel.resources)
@@ -10753,6 +10768,10 @@ class ComputeAPITestCase(BaseTestCase):
resources={"CUSTOM_FOO": 13},
requester_id=uuids.requester_id)
]
req_lvl_params = objects.RequestLevelParams(
root_required={"CUSTOM_BLUE"},
same_subtree=[[uuids.group1, uuids.group2]]
)
with test.nested(
mock.patch.object(objects.ComputeNode, 'get_by_nodename'),
@@ -10781,7 +10800,9 @@ class ComputeAPITestCase(BaseTestCase):
alloc_reqs, mock.sentinel.provider_sums, mock.sentinel.version)
res = self.compute._allocate_port_resource_for_instance(
self.context, instance, pci_reqs, request_groups)
self.context, instance, pci_reqs, request_groups,
req_lvl_params
)
provider_mappings, resources = res
self.assertEqual(
@@ -10797,6 +10818,11 @@ class ComputeAPITestCase(BaseTestCase):
request_groups[0].requester_id)
self.assertEqual(request_groups[0], actual_rg)
self.assertEqual(uuids.compute_node, actual_rg.in_tree)
self.assertEqual({"CUSTOM_BLUE"}, resource_request._root_required)
self.assertEqual(
[[uuids.group1, uuids.group2]],
resource_request._same_subtree
)
mock_add_res.assert_called_once_with(
self.context, instance.uuid, mock.sentinel.resources)
mock_update_pci.assert_called_once_with(
@@ -10811,6 +10837,10 @@ class ComputeAPITestCase(BaseTestCase):
resources={"CUSTOM_FOO": 13},
requester_id=uuids.requester_id)
]
req_lvl_params = objects.RequestLevelParams(
root_required={"CUSTOM_BLUE"},
same_subtree=[[uuids.group1, uuids.group2]]
)
with test.nested(
mock.patch.object(objects.ComputeNode, 'get_by_nodename'),
@@ -10836,7 +10866,9 @@ class ComputeAPITestCase(BaseTestCase):
self.assertRaises(
exception.InterfaceAttachResourceAllocationFailed,
self.compute._allocate_port_resource_for_instance,
self.context, instance, pci_reqs, request_groups)
self.context, instance, pci_reqs, request_groups,
req_lvl_params,
)
mock_get_nodename.assert_called_once_with(
self.context, instance.node)
@@ -10851,6 +10883,10 @@ class ComputeAPITestCase(BaseTestCase):
resources={"CUSTOM_FOO": 13},
requester_id=uuids.requester_id)
]
req_lvl_params = objects.RequestLevelParams(
root_required={"CUSTOM_BLUE"},
same_subtree=[[uuids.group1, uuids.group2]]
)
with test.nested(
mock.patch.object(objects.ComputeNode, 'get_by_nodename'),
@@ -10885,7 +10921,9 @@ class ComputeAPITestCase(BaseTestCase):
self.assertRaises(
exception.InterfaceAttachResourceAllocationFailed,
self.compute._allocate_port_resource_for_instance,
self.context, instance, pci_reqs, request_groups)
self.context, instance, pci_reqs, request_groups,
req_lvl_params
)
mock_get_nodename.assert_called_once_with(
self.context, instance.node)
@@ -10896,6 +10934,11 @@ class ComputeAPITestCase(BaseTestCase):
request_groups[0].requester_id)
self.assertEqual(request_groups[0], actual_rg)
self.assertEqual(uuids.compute_node, actual_rg.in_tree)
self.assertEqual({"CUSTOM_BLUE"}, resource_request._root_required)
self.assertEqual(
[[uuids.group1, uuids.group2]],
resource_request._same_subtree
)
mock_add_res.assert_called_once_with(
self.context, instance.uuid, mock.sentinel.resources)
@@ -10907,6 +10950,10 @@ class ComputeAPITestCase(BaseTestCase):
resources={"CUSTOM_FOO": 13},
requester_id=uuids.requester_id)
]
req_lvl_params = objects.RequestLevelParams(
root_required={"CUSTOM_BLUE"},
same_subtree=[[uuids.group1, uuids.group2]]
)
with test.nested(
mock.patch.object(objects.ComputeNode, 'get_by_nodename'),
@@ -10943,7 +10990,9 @@ class ComputeAPITestCase(BaseTestCase):
self.assertRaises(
exception.AmbiguousResourceProviderForPCIRequest,
self.compute._allocate_port_resource_for_instance,
self.context, instance, pci_reqs, request_groups)
self.context, instance, pci_reqs, request_groups,
req_lvl_params
)
mock_get_nodename.assert_called_once_with(
self.context, instance.node)
@@ -10954,6 +11003,11 @@ class ComputeAPITestCase(BaseTestCase):
request_groups[0].requester_id)
self.assertEqual(request_groups[0], actual_rg)
self.assertEqual(uuids.compute_node, actual_rg.in_tree)
self.assertEqual({"CUSTOM_BLUE"}, resource_request._root_required)
self.assertEqual(
[[uuids.group1, uuids.group2]],
resource_request._same_subtree
)
mock_add_res.assert_called_once_with(
self.context, instance.uuid, mock.sentinel.resources)
mock_update_pci.assert_called_once_with(
+2 -1
View File
@@ -2600,7 +2600,8 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase,
def do_test(
update, meth, add_fault, notify, event, mock_claim_pci,
mock_create_resource_req):
mock_create_resource_req.return_value = None, []
mock_create_resource_req.return_value = (
None, [], mock.sentinel.req_lvl_params)
self.assertRaises(exception.InterfaceAttachFailed,
self.compute.attach_interface,
self.context, f_instance, uuids.network_id,
+34 -5
View File
@@ -5789,7 +5789,7 @@ class TestAPI(TestAPIBase):
result = api.create_resource_requests(
self.context, requested_networks, pci_requests)
network_metadata, port_resource_requests = result
network_metadata, port_resource_requests, _ = result
self.assertFalse(mock_get_client.called)
self.assertIsNone(network_metadata)
@@ -5816,7 +5816,7 @@ class TestAPI(TestAPIBase):
result = api.create_resource_requests(
self.context, requested_networks, pci_requests)
network_metadata, port_resource_requests = result
network_metadata, port_resource_requests, _ = result
mock_get_physnet_tunneled_info.assert_not_called()
self.assertEqual(set(), network_metadata.physnets)
@@ -5875,7 +5875,7 @@ class TestAPI(TestAPIBase):
result = api.create_resource_requests(
self.context, requested_networks, pci_requests)
network_metadata, port_resource_requests = result
network_metadata, port_resource_requests, _ = result
self.assertEqual([
mock.sentinel.request_group1,
@@ -5982,7 +5982,7 @@ class TestAPI(TestAPIBase):
result = self.api.create_resource_requests(
self.context, requested_networks, pci_requests=None)
network_metadata, port_resource_requests = result
network_metadata, port_resource_requests, _ = result
mock_get_dp_group.assert_called_once_with('smat_nic')
mock_get_physnet_tunneled_info.assert_called_once_with(
self.context, mock.ANY, 'netN')
@@ -6046,6 +6046,12 @@ class TestAPI(TestAPIBase):
@mock.patch.object(
neutronapi.API, '_has_extended_resource_request_extension',
return_value=True)
@mock.patch(
'nova.objects.request_spec.RequestLevelParams.extend_with'
)
@mock.patch(
'nova.objects.request_spec.RequestLevelParams.from_port_request'
)
@mock.patch(
'nova.objects.request_spec.RequestGroup.from_extended_port_request')
@mock.patch.object(neutronapi.API, '_get_physnet_tunneled_info')
@@ -6054,6 +6060,7 @@ class TestAPI(TestAPIBase):
def test_create_resource_request_extended(
self, getclient, mock_get_port_vnic_info,
mock_get_physnet_tunneled_info, mock_from_port_request,
mock_req_lvl_param, mock_extened_req_lvl_param,
mock_has_extended_res_req
):
requested_networks = objects.NetworkRequestList(
@@ -6088,10 +6095,15 @@ class TestAPI(TestAPIBase):
mock.sentinel.port2_request_group2,
],
]
# also both port1 and port2 has same subtree params
mock_req_lvl_param.side_effect = [
mock.sentinel.port1_req_lvl_param,
mock.sentinel.port2_req_lvl_param,
]
result = api.create_resource_requests(
self.context, requested_networks, pci_requests)
network_metadata, port_resource_requests = result
network_metadata, port_resource_requests, req_lvl_param = result
# assert that all the request groups are collected from both ports
self.assertEqual(
@@ -6102,6 +6114,23 @@ class TestAPI(TestAPIBase):
mock.sentinel.port2_request_group2,
],
port_resource_requests)
# the same subtree requests are combined from the two ports
mock_req_lvl_param.assert_has_calls(
[
mock.call(
port_resource_request=mock.sentinel.resource_request1),
mock.call(
port_resource_request=mock.sentinel.resource_request2),
]
)
mock_extened_req_lvl_param.assert_has_calls(
[
mock.call(mock.sentinel.port1_req_lvl_param),
mock.call(mock.sentinel.port2_req_lvl_param),
]
)
self.assertIsInstance(req_lvl_param, objects.RequestLevelParams)
mock_from_port_request.assert_has_calls([
mock.call(
+8 -4
View File
@@ -412,13 +412,17 @@ class _TestRequestSpecObject(object):
filter_properties = {'fake': 'property'}
rg = request_spec.RequestGroup()
req_lvl_params = request_spec.RequestLevelParams()
spec = objects.RequestSpec.from_components(ctxt, instance.uuid, image,
flavor, instance.numa_topology, instance.pci_requests,
filter_properties, None, instance.availability_zone,
port_resource_requests=[rg])
spec = objects.RequestSpec.from_components(
ctxt, instance.uuid, image,
flavor, instance.numa_topology, instance.pci_requests,
filter_properties, None, instance.availability_zone,
port_resource_requests=[rg], request_level_params=req_lvl_params
)
self.assertListEqual([rg], spec.requested_resources)
self.assertEqual(req_lvl_params, spec.request_level_params)
def test_get_scheduler_hint(self):
spec_obj = objects.RequestSpec(scheduler_hints={'foo_single': ['1'],
+9 -2
View File
@@ -1346,8 +1346,13 @@ class TestUtils(TestUtilsBase):
"CUSTOM_VNIC_TYPE_NORMAL"]
}
)
req_lvl_params = objects.RequestLevelParams(
root_required={"CUSTOM_BLUE"},
root_forbidden={"CUSTOM_DIRTY"},
same_subtree=[[uuids.group1]],
)
rr = utils.ResourceRequest.from_request_group(rg)
rr = utils.ResourceRequest.from_request_group(rg, req_lvl_params)
self.assertEqual(
f'limit=1000&'
@@ -1356,7 +1361,9 @@ class TestUtils(TestUtilsBase):
f'CUSTOM_VNIC_TYPE_NORMAL&'
f'resources{uuids.port_id}='
f'NET_BW_EGR_KILOBIT_PER_SEC%3A1000%2C'
f'NET_BW_IGR_KILOBIT_PER_SEC%3A1000',
f'NET_BW_IGR_KILOBIT_PER_SEC%3A1000&'
f'root_required=CUSTOM_BLUE%2C%21CUSTOM_DIRTY&'
f'same_subtree={uuids.group1}',
rr.to_querystring())
def test_resource_request_add_group_inserts_the_group(self):