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:
Balazs Gibizer 2021-05-28 16:49:50 +02:00
parent 017b0a3d23
commit e357ad3c23
7 changed files with 128 additions and 7 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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())

View File

@ -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 "

View File

@ -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

View File

@ -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)
)

View File

@ -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')