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:
+14
-9
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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'],
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user