From a4c3260f56c9189378a1406869eea75e2d023fb2 Mon Sep 17 00:00:00 2001 From: Balazs Gibizer Date: Wed, 18 Mar 2020 10:56:32 +0100 Subject: [PATCH] Enable unshelve with qos ports Previous patches in the blueprint implemented the support for unshelve with qos ports and added functional test coverage for the various scenarios. So this patch changes the API check that rejected such operation to check for the service version and therefore conditionally enable the feature. Change-Id: Iaf70ee41f1bfb1a4964da3f59cd3a0b4b5e20d36 blueprint: support-move-ops-with-qos-ports-ussuri --- .../source/port_with_resource_request.rst | 4 +- nova/api/openstack/common.py | 18 +++---- nova/api/openstack/compute/shelve.py | 14 ++++-- nova/tests/functional/test_servers.py | 47 +++++++------------ .../openstack/compute/test_migrate_server.py | 5 +- .../openstack/compute/test_server_actions.py | 5 +- ...ith-resource-request-d91a282fe56c7489.yaml | 6 +++ 7 files changed, 43 insertions(+), 56 deletions(-) create mode 100644 releasenotes/notes/support-unshelving-servers-with-neutron-ports-with-resource-request-d91a282fe56c7489.yaml diff --git a/api-guide/source/port_with_resource_request.rst b/api-guide/source/port_with_resource_request.rst index 867dd0181230..2d4cc113e24e 100644 --- a/api-guide/source/port_with_resource_request.rst +++ b/api-guide/source/port_with_resource_request.rst @@ -31,8 +31,8 @@ compute services are upgraded to 20.0.0 (Train) and the ``[upgrade_levels]/compute`` configuration does not prevent the computes from using the latest RPC version. -As of 21.0.0 (Ussuri), nova supports evacuating and live migrating servers -with neutron ports having resource requests. +As of 21.0.0 (Ussuri), nova supports evacuating, live migrating and unshelving +servers with neutron ports having resource requests. See :nova-doc:`the admin guide ` for administrative details. diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index 731818ce261e..90615351043c 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -33,6 +33,7 @@ from nova import exception from nova.i18n import _ from nova.network import constants from nova import objects +from nova.objects import service from nova import quota from nova import utils @@ -558,20 +559,15 @@ def supports_port_resource_request(req): return api_version_request.is_supported(req, '2.72') -def supports_port_resource_request_during_move(req): - """Check to see if the requested API version is high enough for support - port resource request during move operation. +def supports_port_resource_request_during_move(): + """Check to see if the global compute service version is high enough to + support port resource request during move operation. - NOTE: At the moment there is no such microversion that supports port - resource request during move. This function is added as a preparation for - that microversion (assuming there will be a new microversion, which is - yet to be decided). - - :param req: The incoming API request - :returns: True if the requested API microversion is high enough for + :returns: True if the compute service version is high enough for port resource request move support, False otherwise. """ - return False + return service.get_minimum_version_all_cells( + nova_context.get_admin_context(), ['nova-compute']) >= 49 def instance_has_port_with_resource_request(instance_uuid, network_api): diff --git a/nova/api/openstack/compute/shelve.py b/nova/api/openstack/compute/shelve.py index 1783013a0434..680d59265569 100644 --- a/nova/api/openstack/compute/shelve.py +++ b/nova/api/openstack/compute/shelve.py @@ -14,6 +14,7 @@ """The shelved mode extension.""" +from oslo_log import log as logging from webob import exc from nova.api.openstack import api_version_request @@ -28,6 +29,8 @@ from nova.i18n import _ from nova.network import neutron from nova.policies import shelve as shelve_policies +LOG = logging.getLogger(__name__) + class ShelveController(wsgi.Controller): def __init__(self): @@ -98,12 +101,15 @@ class ShelveController(wsgi.Controller): if (instance.vm_state == vm_states.SHELVED_OFFLOADED and common.instance_has_port_with_resource_request( instance.uuid, self.network_api) and - not common.supports_port_resource_request_during_move( - req)): + not common.supports_port_resource_request_during_move()): + LOG.warning("The unshelve action on a server with ports having " + "resource requests, like a port with a QoS minimum " + "bandwidth policy, is not supported until every " + "nova-compute is upgraded to Ussuri") msg = _("The unshelve action on a server with ports having " "resource requests, like a port with a QoS minimum " - "bandwidth policy, is not supported with this " - "microversion") + "bandwidth policy, is not supported by this cluster right " + "now") raise exc.HTTPBadRequest(explanation=msg) try: diff --git a/nova/tests/functional/test_servers.py b/nova/tests/functional/test_servers.py index 021f9f0f82d9..e38234ba27a5 100644 --- a/nova/tests/functional/test_servers.py +++ b/nova/tests/functional/test_servers.py @@ -6025,14 +6025,25 @@ class UnsupportedPortResourceRequestBasedSchedulingTest( # can exist with such a port. self._add_resource_request_to_a_bound_port(self.neutron.port_1['id']) - ex = self.assertRaises( - client.OpenStackApiException, - self.api.post_server_action, server['id'], {'unshelve': None}) + with mock.patch( + "nova.objects.service.get_minimum_version_all_cells", + return_value=48, + ): + ex = self.assertRaises( + client.OpenStackApiException, + self.api.post_server_action, server['id'], {'unshelve': None}) self.assertEqual(400, ex.response.status_code) self.assertIn( - 'The unshelve action on a server with ports having resource ' - 'requests', six.text_type(ex)) + "The unshelve action on a server with ports having resource " + "requests, like a port with a QoS minimum bandwidth policy, is " + "not supported by this cluster right now", + six.text_type(ex)) + self.assertIn( + "The unshelve action on a server with ports having resource " + "requests, like a port with a QoS minimum bandwidth policy, is " + "not supported until every nova-compute is upgraded to Ussuri", + self.stdlog.logger.output) def test_unshelve_not_offloaded_server_with_port_resource_request( self): @@ -6076,7 +6087,6 @@ class NonAdminUnsupportedPortResourceRequestBasedSchedulingTest( # allow non-admin to call the operations self.policy.set_rules({ - 'os_compute_api:os-evacuate': '@', 'os_compute_api:servers:create': '@', 'os_compute_api:servers:create:attach_network': '@', 'os_compute_api:servers:show': '@', @@ -6084,7 +6094,6 @@ class NonAdminUnsupportedPortResourceRequestBasedSchedulingTest( 'os_compute_api:os-attach-interfaces:create': '@', 'os_compute_api:os-shelve:shelve': '@', 'os_compute_api:os-shelve:unshelve': '@', - 'os_compute_api:os-migrate-server:migrate_live': '@', }) @@ -7409,23 +7418,7 @@ class ServerMoveWithPortResourceRequestTest( self._delete_server_and_check_allocations( server, qos_normal_port, qos_sriov_port) - def _turn_off_api_check(self): - # The API actively rejecting the move operations with resource - # request so we have to turn off that check. - # TODO(gibi): Remove this when the move operations are supported and - # the API check is removed. - patcher = mock.patch( - 'nova.api.openstack.common.' - 'supports_port_resource_request_during_move', - return_value=True) - self.addCleanup(patcher.stop) - patcher.start() - def test_unshelve_offloaded_server_with_qos_port(self): - # TODO(gibi): remove this when live migration is fully supported and - # therefore the check is removed from the api - self._turn_off_api_check() - non_qos_normal_port = self.neutron.port_1 qos_normal_port = self.neutron.port_with_resource_request qos_sriov_port = self.neutron.port_with_sriov_resource_request @@ -7486,10 +7479,6 @@ class ServerMoveWithPortResourceRequestTest( server, qos_normal_port, qos_sriov_port) def test_unshelve_offloaded_server_with_qos_port_pci_update_fails(self): - # TODO(gibi): remove this when live migration is fully supported and - # therefore the check is removed from the api - self._turn_off_api_check() - # Update the name of the network device RP of PF2 on host2 to something # unexpected. This will cause # update_pci_request_spec_with_allocated_interface_name() to raise @@ -7548,10 +7537,6 @@ class ServerMoveWithPortResourceRequestTest( def test_unshelve_offloaded_server_with_qos_port_fails_due_to_neutron( self): - # TODO(gibi): remove this when live migration is fully supported and - # therefore the check is removed from the api - self._turn_off_api_check() - non_qos_normal_port = self.neutron.port_1 qos_normal_port = self.neutron.port_with_resource_request qos_sriov_port = self.neutron.port_with_sriov_resource_request diff --git a/nova/tests/unit/api/openstack/compute/test_migrate_server.py b/nova/tests/unit/api/openstack/compute/test_migrate_server.py index 4785631c8069..4416405f3d25 100644 --- a/nova/tests/unit/api/openstack/compute/test_migrate_server.py +++ b/nova/tests/unit/api/openstack/compute/test_migrate_server.py @@ -295,14 +295,11 @@ class MigrateServerTestsV21(admin_only_action_common.CommonTests): expected_exc=webob.exc.HTTPInternalServerError, check_response=False) - @mock.patch('nova.api.openstack.common.' - 'supports_port_resource_request_during_move', - return_value=True) @mock.patch('nova.objects.Service.get_by_host_and_binary') @mock.patch('nova.api.openstack.common.' 'instance_has_port_with_resource_request', return_value=True) def test_migrate_with_bandwidth_from_old_compute_not_supported( - self, mock_has_res_req, mock_get_service, mock_support): + self, mock_has_res_req, mock_get_service): instance = self._stub_instance_get() mock_get_service.return_value = objects.Service(host=instance['host']) diff --git a/nova/tests/unit/api/openstack/compute/test_server_actions.py b/nova/tests/unit/api/openstack/compute/test_server_actions.py index 87b77b222187..4a25a3cd669e 100644 --- a/nova/tests/unit/api/openstack/compute/test_server_actions.py +++ b/nova/tests/unit/api/openstack/compute/test_server_actions.py @@ -1247,14 +1247,11 @@ class ServerActionsControllerTestV21(test.TestCase): self.controller._action_create_image, self.req, FAKE_UUID, body=body) - @mock.patch('nova.api.openstack.common.' - 'supports_port_resource_request_during_move', - return_value=True) @mock.patch('nova.objects.Service.get_by_host_and_binary') @mock.patch('nova.api.openstack.common.' 'instance_has_port_with_resource_request', return_value=True) def test_resize_with_bandwidth_from_old_compute_not_supported( - self, mock_has_res_req, mock_get_service, mock_support): + self, mock_has_res_req, mock_get_service): body = dict(resize=dict(flavorRef="http://localhost/3")) mock_get_service.return_value = objects.Service() mock_get_service.return_value.version = 38 diff --git a/releasenotes/notes/support-unshelving-servers-with-neutron-ports-with-resource-request-d91a282fe56c7489.yaml b/releasenotes/notes/support-unshelving-servers-with-neutron-ports-with-resource-request-d91a282fe56c7489.yaml new file mode 100644 index 000000000000..d9a5bfd309d5 --- /dev/null +++ b/releasenotes/notes/support-unshelving-servers-with-neutron-ports-with-resource-request-d91a282fe56c7489.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + The server ``unshelve`` action API now supports servers with neutron + ports having resource requests, e.g. ports that have QoS minimum bandwidth + rules attached.