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