Reject server create with extended resource req
To prepare for the unlikely event that Neutron merges and an operator enables the port-resource-request-groups neutron API extension before nova adds support for it, this patch rejects server creation if such extension is enabled in Neutron. Enabling that extension has zero benefits without nova support hence the harsh but simple rejection. A subsequent patch will reject server lifecycle operations in a more sophisticated way and as soon as we support some operations, like boot, the deployer might rightfully choose to enable the Neutron extension. Change-Id: I2c55d9da13a570efbc1c862116cea31aaa6aa02e blueprint: qos-minimum-guaranteed-packet-rate
This commit is contained in:
parent
017b0a3d23
commit
e357ad3c23
@ -39,5 +39,15 @@ servers with neutron ports having resource requests.
|
||||
As of 23.0.0 (Wallaby), nova supports attaching neutron ports having QoS
|
||||
minimum bandwidth rules.
|
||||
|
||||
Extended resource request
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Since neutron 19.0.0 (Xena), neutron implements an extended resource request
|
||||
format via the the ``port-resource-request-groups`` neutron API extension. As
|
||||
of nova 24.0.0 (Xena), nova does not support the new extension. If the
|
||||
extension is enabled in neutron, then nova will reject server create and move
|
||||
operations, as well as interface attach operation. Admins should not enable
|
||||
this API extension in neutron.
|
||||
|
||||
See :nova-doc:`the admin guide <admin/port_with_resource_request.html>` for
|
||||
administrative details.
|
||||
|
@ -52,6 +52,7 @@ If the ``group_policy`` is missing from the flavor then the server create
|
||||
request will fail with 'No valid host was found' and a warning describing the
|
||||
missing policy will be logged.
|
||||
|
||||
|
||||
Virt driver support
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -63,3 +64,27 @@ If the virt driver on the compute host does not support the needed capability
|
||||
then the PCI claim will fail on the host and re-schedule will be triggered. It
|
||||
is suggested not to configure bandwidth inventory in the neutron agents on
|
||||
these compute hosts to avoid unnecessary reschedule.
|
||||
|
||||
|
||||
Extended resource request
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Since neutron 19.0.0 (Xena), neutron implements an extended resource request
|
||||
format via the the ``port-resource-request-groups`` neutron API extension. As
|
||||
of nova 24.0.0 (Xena), Nova does not support the new extension. If the
|
||||
extension is enabled in neutron, then nova will reject server create and move
|
||||
operations, as well as interface attach operation. Admins should not enable
|
||||
this API extension in neutron.
|
||||
|
||||
The extended resource request allows a single Neutron port to request
|
||||
resources in more than one request groups. This also means that using just one
|
||||
port in a server create request would require a group policy to be provided
|
||||
in the flavor. Today the only case when a single port generates more than one
|
||||
request groups is when that port has QoS policy with both minimum bandwidth
|
||||
and minimum packet rate rules. Due to the placement resource model of these
|
||||
features in this case the two request groups will always be fulfilled from
|
||||
separate resource providers and therefore neither the ``group_policy=none``
|
||||
nor the ``group_policy=isolate`` flavor extra specs will result in any
|
||||
additional restriction on the placement of the resources. In the multi port
|
||||
case the Resource Group policy section above still applies.
|
||||
|
||||
|
@ -843,7 +843,9 @@ class ServersController(wsgi.Controller):
|
||||
exception.CreateWithPortResourceRequestOldVersion,
|
||||
exception.DeviceProfileError,
|
||||
exception.ComputeHostNotFound,
|
||||
exception.ForbiddenPortsWithAccelerator) as error:
|
||||
exception.ForbiddenPortsWithAccelerator,
|
||||
exception.ExtendedResourceRequestNotSupported,
|
||||
) as error:
|
||||
raise exc.HTTPBadRequest(explanation=error.format_message())
|
||||
except INVALID_FLAVOR_IMAGE_EXCEPTIONS as error:
|
||||
raise exc.HTTPBadRequest(explanation=error.format_message())
|
||||
|
@ -1955,6 +1955,12 @@ class CreateWithPortResourceRequestOldVersion(Invalid):
|
||||
"until microversion 2.72.")
|
||||
|
||||
|
||||
class ExtendedResourceRequestNotSupported(Invalid):
|
||||
msg_fmt = _("The port-resource-request-groups neutron API extension is "
|
||||
"not yet supported by Nova. Please turn off this extension in "
|
||||
"Neutron.")
|
||||
|
||||
|
||||
class InvalidReservedMemoryPagesOption(Invalid):
|
||||
msg_fmt = _("The format of the option 'reserved_huge_pages' is invalid. "
|
||||
"(found '%(conf)s') Please refer to the nova "
|
||||
|
@ -2001,6 +2001,15 @@ class API:
|
||||
return (vnic_type, trusted, network_id, resource_request,
|
||||
numa_policy, device_profile)
|
||||
|
||||
def support_create_with_resource_request(self, context):
|
||||
"""Returns false if neutron is configured with extended resource
|
||||
request which is not currently supported.
|
||||
|
||||
This function is only here temporarily to help mocking this check in
|
||||
the functional test environment.
|
||||
"""
|
||||
return not (self._has_extended_resource_request_extension(context))
|
||||
|
||||
def create_resource_requests(
|
||||
self, context, requested_networks, pci_requests=None,
|
||||
affinity_policy=None):
|
||||
@ -2015,7 +2024,8 @@ class API:
|
||||
:type pci_requests: nova.objects.InstancePCIRequests
|
||||
:param affinity_policy: requested pci numa affinity policy
|
||||
: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
|
||||
@ -2024,6 +2034,9 @@ class API:
|
||||
if not requested_networks or requested_networks.no_allocate:
|
||||
return None, []
|
||||
|
||||
if not self.support_create_with_resource_request(context):
|
||||
raise exception.ExtendedResourceRequestNotSupported()
|
||||
|
||||
physnets = set()
|
||||
tunneled = False
|
||||
|
||||
|
@ -2611,3 +2611,38 @@ class CrossCellResizeWithQoSPort(PortResourceRequestBasedSchedulingTestBase):
|
||||
|
||||
self._delete_server_and_check_allocations(
|
||||
server, qos_normal_port, qos_sriov_port)
|
||||
|
||||
|
||||
class ExtendedResourceRequestTempNegativeTest(
|
||||
PortResourceRequestBasedSchedulingTestBase):
|
||||
"""A set of temporary tests to show that nova currently rejects requests
|
||||
that uses the extended-resource-request Neutron API extension. These test
|
||||
are expected to be removed when support for the extension is implemented
|
||||
in nova.
|
||||
"""
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.neutron = self.useFixture(
|
||||
ExtendedResourceRequestNeutronFixture(self))
|
||||
|
||||
def test_boot(self):
|
||||
"""The neutron fixture used in this test class enables the
|
||||
extended-resource-request API extension. This results in any new
|
||||
server to boot. This is harsh but without nova support for this
|
||||
extension there is no way that this extension is helpful. So treat
|
||||
this as a deployment configuration error.
|
||||
"""
|
||||
ex = self.assertRaises(
|
||||
client.OpenStackApiException,
|
||||
self._create_server,
|
||||
flavor=self.flavor,
|
||||
networks=[{'port': self.neutron.port_1['id']}],
|
||||
)
|
||||
|
||||
self.assertEqual(400, ex.response.status_code)
|
||||
self.assertIn(
|
||||
'The port-resource-request-groups neutron API extension is not '
|
||||
'yet supported by Nova. Please turn off this extension in '
|
||||
'Neutron.',
|
||||
str(ex)
|
||||
)
|
||||
|
@ -5795,10 +5795,15 @@ class TestAPI(TestAPIBase):
|
||||
self.assertIsNone(network_metadata)
|
||||
self.assertEqual([], port_resource_requests)
|
||||
|
||||
@mock.patch.object(
|
||||
neutronapi.API, '_has_extended_resource_request_extension',
|
||||
return_value=False)
|
||||
@mock.patch.object(neutronapi.API, '_get_physnet_tunneled_info')
|
||||
@mock.patch.object(neutronapi, 'get_client', return_value=mock.Mock())
|
||||
def test_create_resource_requests_auto_allocated(self, mock_get_client,
|
||||
mock_get_physnet_tunneled_info):
|
||||
def test_create_resource_requests_auto_allocated(
|
||||
self, mock_get_client, mock_get_physnet_tunneled_info,
|
||||
mock_has_extended_res_req
|
||||
):
|
||||
"""Ensure physnet info is not retrieved for auto-allocated networks.
|
||||
|
||||
This isn't possible so we shouldn't attempt to do it.
|
||||
@ -5818,13 +5823,18 @@ class TestAPI(TestAPIBase):
|
||||
self.assertFalse(network_metadata.tunneled)
|
||||
self.assertEqual([], port_resource_requests)
|
||||
|
||||
@mock.patch.object(
|
||||
neutronapi.API, '_has_extended_resource_request_extension',
|
||||
return_value=False)
|
||||
@mock.patch('nova.objects.request_spec.RequestGroup.from_port_request')
|
||||
@mock.patch.object(neutronapi.API, '_get_physnet_tunneled_info')
|
||||
@mock.patch.object(neutronapi.API, "_get_port_vnic_info")
|
||||
@mock.patch.object(neutronapi, 'get_client')
|
||||
def test_create_resource_requests(self, getclient,
|
||||
mock_get_port_vnic_info, mock_get_physnet_tunneled_info,
|
||||
mock_from_port_request):
|
||||
def test_create_resource_requests(
|
||||
self, getclient, mock_get_port_vnic_info,
|
||||
mock_get_physnet_tunneled_info, mock_from_port_request,
|
||||
mock_has_extended_res_req
|
||||
):
|
||||
requested_networks = objects.NetworkRequestList(
|
||||
objects = [
|
||||
objects.NetworkRequest(port_id=uuids.portid_1),
|
||||
@ -5910,6 +5920,26 @@ class TestAPI(TestAPIBase):
|
||||
port_uuid=uuids.trusted_port,
|
||||
port_resource_request=mock.sentinel.resource_request2),
|
||||
])
|
||||
mock_has_extended_res_req.assert_called_once_with(self.context)
|
||||
|
||||
@mock.patch.object(
|
||||
neutronapi.API, '_has_extended_resource_request_extension',
|
||||
return_value=True)
|
||||
def test_create_resource_request_extended_not_supported(
|
||||
self, mock_has_extended_extension
|
||||
):
|
||||
requested_networks = objects.NetworkRequestList(
|
||||
objects=[
|
||||
objects.NetworkRequest(port_id=uuids.portid_1),
|
||||
]
|
||||
)
|
||||
pci_requests = objects.InstancePCIRequests(requests=[])
|
||||
self.assertRaises(
|
||||
exception.ExtendedResourceRequestNotSupported,
|
||||
neutronapi.API().create_resource_requests,
|
||||
self.context, requested_networks, pci_requests
|
||||
)
|
||||
mock_has_extended_extension.assert_called_once_with(self.context)
|
||||
|
||||
@mock.patch(
|
||||
'nova.accelerator.cyborg._CyborgClient.get_device_request_groups')
|
||||
|
Loading…
x
Reference in New Issue
Block a user