Merge "Reject unshelve with port having resource request"

This commit is contained in:
Zuul 2019-02-05 13:48:40 +00:00 committed by Gerrit Code Review
commit 5283b464b5
3 changed files with 102 additions and 1 deletions

View File

@ -19,7 +19,10 @@ from webob import exc
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova import compute from nova import compute
from nova.compute import vm_states
from nova import exception from nova import exception
from nova.i18n import _
from nova import network
from nova.policies import shelve as shelve_policies from nova.policies import shelve as shelve_policies
@ -27,6 +30,7 @@ class ShelveController(wsgi.Controller):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ShelveController, self).__init__(*args, **kwargs) super(ShelveController, self).__init__(*args, **kwargs)
self.compute_api = compute.API() self.compute_api = compute.API()
self.network_api = network.API()
@wsgi.response(202) @wsgi.response(202)
@wsgi.expected_errors((404, 409)) @wsgi.expected_errors((404, 409))
@ -70,13 +74,23 @@ class ShelveController(wsgi.Controller):
id) id)
@wsgi.response(202) @wsgi.response(202)
@wsgi.expected_errors((404, 409)) @wsgi.expected_errors((400, 404, 409))
@wsgi.action('unshelve') @wsgi.action('unshelve')
def _unshelve(self, req, id, body): def _unshelve(self, req, id, body):
"""Restore an instance from shelved mode.""" """Restore an instance from shelved mode."""
context = req.environ["nova.context"] context = req.environ["nova.context"]
context.can(shelve_policies.POLICY_ROOT % 'unshelve') context.can(shelve_policies.POLICY_ROOT % 'unshelve')
instance = common.get_instance(self.compute_api, context, id) instance = common.get_instance(self.compute_api, context, id)
if (instance.vm_state == vm_states.SHELVED_OFFLOADED
and common.instance_has_port_with_resource_request(
context, instance.uuid, self.network_api)
and not common.supports_port_resource_request_during_move(
req)):
msg = _("The unshelve server operation on a shelve offloaded "
"server with port having QoS policy is not supported.")
raise exc.HTTPBadRequest(explanation=msg)
try: try:
self.compute_api.unshelve(context, instance) self.compute_api.unshelve(context, instance)
except exception.InstanceUnknownCell as e: except exception.InstanceUnknownCell as e:

View File

@ -5584,3 +5584,67 @@ class PortResourceRequestBasedSchedulingTest(
self.assertIn( self.assertIn(
'The evacuate server operation with port having QoS policy is ' 'The evacuate server operation with port having QoS policy is '
'not supported.', six.text_type(ex)) 'not supported.', six.text_type(ex))
def test_unshelve_offloaded_server_with_port_resource_request_old_version(
self):
server = self._create_server(
flavor=self.flavor,
networks=[{'port': self.neutron.port_1['id']}])
self._wait_for_state_change(self.admin_api, server, 'ACTIVE')
# with default config shelve means immediate offload as well
req = {
'shelve': {}
}
self.api.post_server_action(server['id'], req)
self._wait_for_server_parameter(
self.api, server, {'status': 'SHELVED_OFFLOADED'})
# We need to simulate that the above server has a port that has
# resource request, we cannot boot with such a port but legacy servers
# can exists with such a port.
bound_port = self.neutron._ports[self.neutron.port_1['id']]
fake_resource_request = self.neutron.port_with_resource_request[
'resource_request']
bound_port['resource_request'] = fake_resource_request
ex = self.assertRaises(
client.OpenStackApiException,
self.api.post_server_action, server['id'], {'unshelve': {}})
self.assertEqual(400, ex.response.status_code)
self.assertIn(
'The unshelve server operation on a shelve offloaded server with '
'port having QoS policy is not supported.', six.text_type(ex))
def test_unshelve_not_offloaded_server_with_port_resource_request(
self):
"""If the server is not offloaded then unshelving does not cause a new
resource allocation therefore having port resource request is
irrelevant. This test asserts that such unshelve request is not
rejected.
"""
server = self._create_server(
flavor=self.flavor,
networks=[{'port': self.neutron.port_1['id']}])
self._wait_for_state_change(self.admin_api, server, 'ACTIVE')
# avoid automatic shelve offloading
self.flags(shelved_offload_time=-1)
req = {
'shelve': {}
}
self.api.post_server_action(server['id'], req)
self._wait_for_server_parameter(
self.api, server, {'status': 'SHELVED'})
# We need to simulate that the above server has a port that has
# resource request, we cannot boot with such a port but legacy servers
# can exists with such a port.
bound_port = self.neutron._ports[self.neutron.port_1['id']]
fake_resource_request = self.neutron.port_with_resource_request[
'resource_request']
bound_port['resource_request'] = fake_resource_request
self.api.post_server_action(server['id'], {'unshelve': {}})
self._wait_for_state_change(self.admin_api, server, 'ACTIVE')

View File

@ -15,9 +15,11 @@
import mock import mock
from oslo_policy import policy as oslo_policy from oslo_policy import policy as oslo_policy
from oslo_utils.fixture import uuidsentinel from oslo_utils.fixture import uuidsentinel
import six
import webob import webob
from nova.api.openstack.compute import shelve as shelve_v21 from nova.api.openstack.compute import shelve as shelve_v21
from nova.compute import vm_states
from nova import exception from nova import exception
from nova import policy from nova import policy
from nova import test from nova import test
@ -61,6 +63,27 @@ class ShelvePolicyTestV21(test.NoDBTestCase):
self.controller._shelve_offload, self.controller._shelve_offload,
self.req, uuidsentinel.fake, {}) self.req, uuidsentinel.fake, {})
@mock.patch('nova.network.neutronv2.api.API.list_ports')
@mock.patch('nova.api.openstack.common.get_instance')
def test_unshelve_offloaded_with_port_resource_request_old_microversion(
self, get_instance_mock, mock_list_ports):
mock_list_ports.return_value = {'ports': [
{'resource_request': {
"resources": {'CUSTOM_FOO': 1}}}]
}
instance = fake_instance.fake_instance_obj(
self.req.environ['nova.context'])
instance.vm_state = vm_states.SHELVED_OFFLOADED
get_instance_mock.return_value = instance
ex = self.assertRaises(
webob.exc.HTTPBadRequest, self.controller._unshelve, self.req,
uuidsentinel.fake, {})
self.assertIn(
'The unshelve server operation on a shelve offloaded server with '
'port having QoS policy is not supported.', six.text_type(ex))
class ShelvePolicyEnforcementV21(test.NoDBTestCase): class ShelvePolicyEnforcementV21(test.NoDBTestCase):