Merge "Transfer RequestLevelParams from ports to scheduling"

This commit is contained in:
Zuul 2021-08-31 16:21:30 +00:00 committed by Gerrit Code Review
commit 982d459c65
12 changed files with 232 additions and 74 deletions

View File

@ -1064,7 +1064,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)
@ -1104,7 +1104,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)
@ -1296,6 +1298,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
@ -1325,13 +1328,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

View File

@ -7627,6 +7627,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
@ -7638,6 +7639,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
@ -7666,7 +7669,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
@ -7789,12 +7793,17 @@ 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
)
)
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:

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

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

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

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

View File

@ -226,9 +226,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)
@ -4891,7 +4893,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(
@ -5062,10 +5067,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,
@ -5076,9 +5083,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(
@ -5115,6 +5126,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))
@ -5168,7 +5191,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(
@ -5265,7 +5291,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(
@ -5331,7 +5361,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,

View File

@ -8703,11 +8703,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,
@ -10206,7 +10208,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,
@ -10266,7 +10269,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(
@ -10311,7 +10315,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):
@ -10348,7 +10354,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
@ -10424,7 +10430,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
@ -10475,9 +10481,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):
@ -10498,7 +10506,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,
@ -10574,7 +10583,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,
@ -10652,7 +10662,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
@ -10727,7 +10737,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 = (
@ -10752,7 +10762,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)
@ -10764,6 +10779,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'),
@ -10792,7 +10811,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(
@ -10808,6 +10829,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(
@ -10822,6 +10848,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'),
@ -10847,7 +10877,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)
@ -10862,6 +10894,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'),
@ -10896,7 +10932,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)
@ -10907,6 +10945,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)
@ -10918,6 +10961,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'),
@ -10954,7 +11001,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)
@ -10965,6 +11014,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(

View File

@ -2627,7 +2627,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,

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(

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'],

View File

@ -1369,8 +1369,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&'
@ -1379,7 +1384,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):