Follow up (#2) for the bw resource provider series
This addresses review comments from the following changes: I61a3e8902a891bac36911812e4e7c080570e3850 I48e6db9693e470b177bf4c75211d8b883c768433 Ic70d2bb781b6a844849a5cf2fe4d271b5a81093d I5a956513f3485074023e027430cc52ee7a3f92e4 Ica6152ccb97dce805969d964d6ed032bfe22a33f Part of blueprint bandwidth-resource-provider Change-Id: Idffaa6d206cda3f507e6be095356537f22302ad7
This commit is contained in:
parent
bff3fd1cdb
commit
2ed304e9cc
|
@ -558,7 +558,8 @@ def supports_port_resource_request_during_move(req):
|
||||||
|
|
||||||
NOTE: At the moment there is no such microversion that supports port
|
NOTE: At the moment there is no such microversion that supports port
|
||||||
resource request during move. This function is added as a preparation for
|
resource request during move. This function is added as a preparation for
|
||||||
that microversion.
|
that microversion (assuming there will be a new microversion, which is
|
||||||
|
yet to be decided).
|
||||||
|
|
||||||
:param req: The incoming API request
|
:param req: The incoming API request
|
||||||
:returns: True if the requested API microversion is high enough for
|
:returns: True if the requested API microversion is high enough for
|
||||||
|
@ -570,8 +571,12 @@ def supports_port_resource_request_during_move(req):
|
||||||
def instance_has_port_with_resource_request(
|
def instance_has_port_with_resource_request(
|
||||||
context, instance_uuid, network_api):
|
context, instance_uuid, network_api):
|
||||||
|
|
||||||
search_opts = {'device_id': instance_uuid}
|
# If we ever store any information about resource requests in the
|
||||||
|
# instance info cache then we can replace this neutron API call.
|
||||||
|
search_opts = {'device_id': instance_uuid,
|
||||||
|
'fields': ['resource_request']}
|
||||||
ports = network_api.list_ports(context, **search_opts).get('ports', [])
|
ports = network_api.list_ports(context, **search_opts).get('ports', [])
|
||||||
ports_with_resource_request = [port for port in ports
|
for port in ports:
|
||||||
if port.get('resource_request', None)]
|
if port.get('resource_request'):
|
||||||
return bool(ports_with_resource_request)
|
return True
|
||||||
|
return False
|
||||||
|
|
|
@ -117,11 +117,16 @@ class EvacuateController(wsgi.Controller):
|
||||||
msg = _("The target host can't be the same one.")
|
msg = _("The target host can't be the same one.")
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
|
|
||||||
|
# We could potentially move this check to conductor and avoid the
|
||||||
|
# extra API call to neutron when we support move operations with ports
|
||||||
|
# having resource requests.
|
||||||
if (common.instance_has_port_with_resource_request(
|
if (common.instance_has_port_with_resource_request(
|
||||||
context, instance.uuid, self.network_api) and not
|
context, instance.uuid, self.network_api) and not
|
||||||
common.supports_port_resource_request_during_move(req)):
|
common.supports_port_resource_request_during_move(req)):
|
||||||
msg = _("The evacuate server operation with port having QoS "
|
msg = _("The evacuate action on a server with ports having "
|
||||||
"policy is not supported.")
|
"resource requests, like a port with a QoS minimum "
|
||||||
|
"bandwidth policy, is not supported with this "
|
||||||
|
"microversion")
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -54,11 +54,16 @@ class MigrateServerController(wsgi.Controller):
|
||||||
|
|
||||||
instance = common.get_instance(self.compute_api, context, id)
|
instance = common.get_instance(self.compute_api, context, id)
|
||||||
|
|
||||||
|
# We could potentially move this check to conductor and avoid the
|
||||||
|
# extra API call to neutron when we support move operations with ports
|
||||||
|
# having resource requests.
|
||||||
if (common.instance_has_port_with_resource_request(
|
if (common.instance_has_port_with_resource_request(
|
||||||
context, instance.uuid, self.network_api) and not
|
context, instance.uuid, self.network_api) and not
|
||||||
common.supports_port_resource_request_during_move(req)):
|
common.supports_port_resource_request_during_move(req)):
|
||||||
msg = _("The migrate server operation with port having QoS policy "
|
msg = _("The migrate action on a server with ports having "
|
||||||
"is not supported.")
|
"resource requests, like a port with a QoS minimum "
|
||||||
|
"bandwidth policy, is not supported with this "
|
||||||
|
"microversion")
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -118,11 +123,16 @@ class MigrateServerController(wsgi.Controller):
|
||||||
instance = common.get_instance(self.compute_api, context, id,
|
instance = common.get_instance(self.compute_api, context, id,
|
||||||
expected_attrs=['numa_topology'])
|
expected_attrs=['numa_topology'])
|
||||||
|
|
||||||
|
# We could potentially move this check to conductor and avoid the
|
||||||
|
# extra API call to neutron when we support move operations with ports
|
||||||
|
# having resource requests.
|
||||||
if (common.instance_has_port_with_resource_request(
|
if (common.instance_has_port_with_resource_request(
|
||||||
context, instance.uuid, self.network_api) and not
|
context, instance.uuid, self.network_api) and not
|
||||||
common.supports_port_resource_request_during_move(req)):
|
common.supports_port_resource_request_during_move(req)):
|
||||||
msg = _("The live migrate server operation with port having QoS "
|
msg = _("The os-migrateLive action on a server with ports having "
|
||||||
"policy is not supported.")
|
"resource requests, like a port with a QoS minimum "
|
||||||
|
"bandwidth policy, is not supported with this "
|
||||||
|
"microversion")
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -808,11 +808,16 @@ class ServersController(wsgi.Controller):
|
||||||
target={'user_id': instance.user_id,
|
target={'user_id': instance.user_id,
|
||||||
'project_id': instance.project_id})
|
'project_id': instance.project_id})
|
||||||
|
|
||||||
|
# We could potentially move this check to conductor and avoid the
|
||||||
|
# extra API call to neutron when we support move operations with ports
|
||||||
|
# having resource requests.
|
||||||
if (common.instance_has_port_with_resource_request(
|
if (common.instance_has_port_with_resource_request(
|
||||||
context, instance_id, self.network_api) and not
|
context, instance_id, self.network_api) and not
|
||||||
common.supports_port_resource_request_during_move(req)):
|
common.supports_port_resource_request_during_move(req)):
|
||||||
msg = _("The resize server operation with port having QoS policy "
|
msg = _("The resize action on a server with ports having "
|
||||||
"is not supported.")
|
"resource requests, like a port with a QoS minimum "
|
||||||
|
"bandwidth policy, is not supported with this "
|
||||||
|
"microversion")
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -82,13 +82,18 @@ class ShelveController(wsgi.Controller):
|
||||||
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)
|
||||||
|
|
||||||
|
# We could potentially move this check to conductor and avoid the
|
||||||
|
# extra API call to neutron when we support move operations with ports
|
||||||
|
# having resource requests.
|
||||||
if (instance.vm_state == vm_states.SHELVED_OFFLOADED
|
if (instance.vm_state == vm_states.SHELVED_OFFLOADED
|
||||||
and common.instance_has_port_with_resource_request(
|
and common.instance_has_port_with_resource_request(
|
||||||
context, instance.uuid, self.network_api)
|
context, instance.uuid, self.network_api)
|
||||||
and not common.supports_port_resource_request_during_move(
|
and not common.supports_port_resource_request_during_move(
|
||||||
req)):
|
req)):
|
||||||
msg = _("The unshelve server operation on a shelve offloaded "
|
msg = _("The unshelve action on a server with ports having "
|
||||||
"server with port having QoS policy is not supported.")
|
"resource requests, like a port with a QoS minimum "
|
||||||
|
"bandwidth policy, is not supported with this "
|
||||||
|
"microversion")
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1408,6 +1408,9 @@ class NeutronFixture(fixtures.Fixture):
|
||||||
return {'networks': copy.deepcopy(networks)}
|
return {'networks': copy.deepcopy(networks)}
|
||||||
|
|
||||||
def list_ports(self, retrieve_all=True, **_params):
|
def list_ports(self, retrieve_all=True, **_params):
|
||||||
|
# If 'fields' is passed we need to strip that out since it will mess
|
||||||
|
# up the filtering as 'fields' is not a filter parameter.
|
||||||
|
_params.pop('fields', None)
|
||||||
ports = [p for p in self._ports.values()
|
ports = [p for p in self._ports.values()
|
||||||
if all(p.get(opt) == _params[opt] for opt in _params)]
|
if all(p.get(opt) == _params[opt] for opt in _params)]
|
||||||
return {'ports': copy.deepcopy(ports)}
|
return {'ports': copy.deepcopy(ports)}
|
||||||
|
|
|
@ -488,18 +488,16 @@ class ProviderUsageBaseTestCase(test.TestCase, InstanceHelperMixin):
|
||||||
url= ('/resource_providers/%s/inventories' % rp_uuid),
|
url= ('/resource_providers/%s/inventories' % rp_uuid),
|
||||||
version='1.15', body=inv_body).body
|
version='1.15', body=inv_body).body
|
||||||
|
|
||||||
def _update_inventory(self, rp_uuid, inv_body, version='1.20'):
|
def _update_inventory(self, rp_uuid, inv_body):
|
||||||
"""This will update the inventory for a given resource provider.
|
"""This will update the inventory for a given resource provider.
|
||||||
|
|
||||||
:param rp_uuid: UUID of the resource provider to update
|
:param rp_uuid: UUID of the resource provider to update
|
||||||
:param inv_body: inventory to set on the provider
|
:param inv_body: inventory to set on the provider
|
||||||
:param version: the placement microversion used in the request
|
|
||||||
:returns: APIResponse object with the results
|
:returns: APIResponse object with the results
|
||||||
"""
|
"""
|
||||||
return self.placement_api.put(
|
return self.placement_api.put(
|
||||||
url= ('/resource_providers/%s/inventories' % rp_uuid),
|
url= ('/resource_providers/%s/inventories' % rp_uuid),
|
||||||
body=inv_body,
|
body=inv_body).body
|
||||||
version=version).body
|
|
||||||
|
|
||||||
def _get_resource_provider_by_uuid(self, rp_uuid):
|
def _get_resource_provider_by_uuid(self, rp_uuid):
|
||||||
return self.placement_api.get(
|
return self.placement_api.get(
|
||||||
|
|
|
@ -5549,6 +5549,15 @@ class PortResourceRequestBasedSchedulingTest(
|
||||||
PortResourceRequestBasedSchedulingTestBase):
|
PortResourceRequestBasedSchedulingTestBase):
|
||||||
"""Tests for handling servers with ports having resource requests """
|
"""Tests for handling servers with ports having resource requests """
|
||||||
|
|
||||||
|
def _add_resource_request_to_a_bound_port(self, port_id):
|
||||||
|
# NOTE(gibi): self.neutron._ports contains a copy of each neutron port
|
||||||
|
# defined on class level in the fixture. So modifying what is in the
|
||||||
|
# _ports list is safe as it is re-created for each Neutron fixture
|
||||||
|
# instance therefore for each individual test using that fixture.
|
||||||
|
bound_port = self.neutron._ports[port_id]
|
||||||
|
bound_port['resource_request'] = (
|
||||||
|
self.neutron.port_with_resource_request['resource_request'])
|
||||||
|
|
||||||
def test_interface_attach_with_port_resource_request(self):
|
def test_interface_attach_with_port_resource_request(self):
|
||||||
# create a server
|
# create a server
|
||||||
server = self._create_server(
|
server = self._create_server(
|
||||||
|
@ -5638,12 +5647,9 @@ class PortResourceRequestBasedSchedulingTest(
|
||||||
self._wait_for_state_change(self.admin_api, server, 'ACTIVE')
|
self._wait_for_state_change(self.admin_api, server, 'ACTIVE')
|
||||||
|
|
||||||
# We need to simulate that the above server has a port that has
|
# 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
|
# resource request; we cannot boot with such a port but legacy servers
|
||||||
# can exists with such a port.
|
# can exist with such a port.
|
||||||
bound_port = self.neutron._ports[self.neutron.port_1['id']]
|
self._add_resource_request_to_a_bound_port(self.neutron.port_1['id'])
|
||||||
fake_resource_request = self.neutron.port_with_resource_request[
|
|
||||||
'resource_request']
|
|
||||||
bound_port['resource_request'] = fake_resource_request
|
|
||||||
|
|
||||||
resize_req = {
|
resize_req = {
|
||||||
'resize': {
|
'resize': {
|
||||||
|
@ -5656,8 +5662,8 @@ class PortResourceRequestBasedSchedulingTest(
|
||||||
|
|
||||||
self.assertEqual(400, ex.response.status_code)
|
self.assertEqual(400, ex.response.status_code)
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
'The resize server operation with port having QoS policy is not '
|
'The resize action on a server with ports having resource '
|
||||||
'supported.', six.text_type(ex))
|
'requests', six.text_type(ex))
|
||||||
|
|
||||||
def test_migrate_server_with_port_resource_request_old_microversion(self):
|
def test_migrate_server_with_port_resource_request_old_microversion(self):
|
||||||
server = self._create_server(
|
server = self._create_server(
|
||||||
|
@ -5666,12 +5672,9 @@ class PortResourceRequestBasedSchedulingTest(
|
||||||
self._wait_for_state_change(self.admin_api, server, 'ACTIVE')
|
self._wait_for_state_change(self.admin_api, server, 'ACTIVE')
|
||||||
|
|
||||||
# We need to simulate that the above server has a port that has
|
# 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
|
# resource request; we cannot boot with such a port but legacy servers
|
||||||
# can exists with such a port.
|
# can exist with such a port.
|
||||||
bound_port = self.neutron._ports[self.neutron.port_1['id']]
|
self._add_resource_request_to_a_bound_port(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(
|
ex = self.assertRaises(
|
||||||
client.OpenStackApiException,
|
client.OpenStackApiException,
|
||||||
|
@ -5679,8 +5682,8 @@ class PortResourceRequestBasedSchedulingTest(
|
||||||
|
|
||||||
self.assertEqual(400, ex.response.status_code)
|
self.assertEqual(400, ex.response.status_code)
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
'The migrate server operation with port having QoS policy is not '
|
'The migrate action on a server with ports having resource '
|
||||||
'supported.', six.text_type(ex))
|
'requests', six.text_type(ex))
|
||||||
|
|
||||||
def test_live_migrate_server_with_port_resource_request_old_microversion(
|
def test_live_migrate_server_with_port_resource_request_old_microversion(
|
||||||
self):
|
self):
|
||||||
|
@ -5690,12 +5693,9 @@ class PortResourceRequestBasedSchedulingTest(
|
||||||
self._wait_for_state_change(self.admin_api, server, 'ACTIVE')
|
self._wait_for_state_change(self.admin_api, server, 'ACTIVE')
|
||||||
|
|
||||||
# We need to simulate that the above server has a port that has
|
# 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
|
# resource request; we cannot boot with such a port but legacy servers
|
||||||
# can exists with such a port.
|
# can exist with such a port.
|
||||||
bound_port = self.neutron._ports[self.neutron.port_1['id']]
|
self._add_resource_request_to_a_bound_port(self.neutron.port_1['id'])
|
||||||
fake_resource_request = self.neutron.port_with_resource_request[
|
|
||||||
'resource_request']
|
|
||||||
bound_port['resource_request'] = fake_resource_request
|
|
||||||
|
|
||||||
post = {
|
post = {
|
||||||
'os-migrateLive': {
|
'os-migrateLive': {
|
||||||
|
@ -5709,8 +5709,8 @@ class PortResourceRequestBasedSchedulingTest(
|
||||||
|
|
||||||
self.assertEqual(400, ex.response.status_code)
|
self.assertEqual(400, ex.response.status_code)
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
'The live migrate server operation with port having QoS policy is '
|
'The os-migrateLive action on a server with ports having resource '
|
||||||
'not supported.', six.text_type(ex))
|
'requests', six.text_type(ex))
|
||||||
|
|
||||||
def test_evacuate_server_with_port_resource_request_old_microversion(
|
def test_evacuate_server_with_port_resource_request_old_microversion(
|
||||||
self):
|
self):
|
||||||
|
@ -5720,12 +5720,9 @@ class PortResourceRequestBasedSchedulingTest(
|
||||||
self._wait_for_state_change(self.admin_api, server, 'ACTIVE')
|
self._wait_for_state_change(self.admin_api, server, 'ACTIVE')
|
||||||
|
|
||||||
# We need to simulate that the above server has a port that has
|
# 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
|
# resource request; we cannot boot with such a port but legacy servers
|
||||||
# can exists with such a port.
|
# can exist with such a port.
|
||||||
bound_port = self.neutron._ports[self.neutron.port_1['id']]
|
self._add_resource_request_to_a_bound_port(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(
|
ex = self.assertRaises(
|
||||||
client.OpenStackApiException,
|
client.OpenStackApiException,
|
||||||
|
@ -5733,8 +5730,8 @@ class PortResourceRequestBasedSchedulingTest(
|
||||||
|
|
||||||
self.assertEqual(400, ex.response.status_code)
|
self.assertEqual(400, ex.response.status_code)
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
'The evacuate server operation with port having QoS policy is '
|
'The evacuate action on a server with ports having resource '
|
||||||
'not supported.', six.text_type(ex))
|
'requests', six.text_type(ex))
|
||||||
|
|
||||||
def test_unshelve_offloaded_server_with_port_resource_request_old_version(
|
def test_unshelve_offloaded_server_with_port_resource_request_old_version(
|
||||||
self):
|
self):
|
||||||
|
@ -5752,12 +5749,9 @@ class PortResourceRequestBasedSchedulingTest(
|
||||||
self.api, server, {'status': 'SHELVED_OFFLOADED'})
|
self.api, server, {'status': 'SHELVED_OFFLOADED'})
|
||||||
|
|
||||||
# We need to simulate that the above server has a port that has
|
# 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
|
# resource request; we cannot boot with such a port but legacy servers
|
||||||
# can exists with such a port.
|
# can exist with such a port.
|
||||||
bound_port = self.neutron._ports[self.neutron.port_1['id']]
|
self._add_resource_request_to_a_bound_port(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(
|
ex = self.assertRaises(
|
||||||
client.OpenStackApiException,
|
client.OpenStackApiException,
|
||||||
|
@ -5765,8 +5759,8 @@ class PortResourceRequestBasedSchedulingTest(
|
||||||
|
|
||||||
self.assertEqual(400, ex.response.status_code)
|
self.assertEqual(400, ex.response.status_code)
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
'The unshelve server operation on a shelve offloaded server with '
|
'The unshelve action on a server with ports having resource '
|
||||||
'port having QoS policy is not supported.', six.text_type(ex))
|
'requests', six.text_type(ex))
|
||||||
|
|
||||||
def test_unshelve_not_offloaded_server_with_port_resource_request(
|
def test_unshelve_not_offloaded_server_with_port_resource_request(
|
||||||
self):
|
self):
|
||||||
|
@ -5790,19 +5784,22 @@ class PortResourceRequestBasedSchedulingTest(
|
||||||
self.api, server, {'status': 'SHELVED'})
|
self.api, server, {'status': 'SHELVED'})
|
||||||
|
|
||||||
# We need to simulate that the above server has a port that has
|
# 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
|
# resource request; we cannot boot with such a port but legacy servers
|
||||||
# can exists with such a port.
|
# can exist with such a port.
|
||||||
bound_port = self.neutron._ports[self.neutron.port_1['id']]
|
self._add_resource_request_to_a_bound_port(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.api.post_server_action(server['id'], {'unshelve': {}})
|
||||||
self._wait_for_state_change(self.admin_api, server, 'ACTIVE')
|
self._wait_for_state_change(self.admin_api, server, 'ACTIVE')
|
||||||
|
|
||||||
|
|
||||||
class PortResourceRequestBasedSchedulingTestIgnoreMicroversionCheck(
|
class PortResourceRequestBasedSchedulingTestIgnoreMicroversionCheck(
|
||||||
PortResourceRequestBasedSchedulingTestBase):
|
PortResourceRequestBasedSchedulingTestBase):
|
||||||
|
"""Tests creating a server with a pre-existing port that has a resource
|
||||||
|
request for a QoS minimum bandwidth policy. Stubs out the
|
||||||
|
supports_port_resource_request control method in the API in order to
|
||||||
|
test the functionality between the API and scheduler before the
|
||||||
|
microversion is added.
|
||||||
|
"""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(
|
super(
|
||||||
|
@ -5810,7 +5807,7 @@ class PortResourceRequestBasedSchedulingTestIgnoreMicroversionCheck(
|
||||||
self).setUp()
|
self).setUp()
|
||||||
|
|
||||||
# NOTE(gibi): This mock turns off the api microversion that prevents
|
# NOTE(gibi): This mock turns off the api microversion that prevents
|
||||||
# handling of instances operations if the request involves port's with
|
# handling of instances operations if the request involves ports with
|
||||||
# resource request with old microversion. The new microversion does not
|
# resource request with old microversion. The new microversion does not
|
||||||
# exists yet as the whole feature is not read for end user consumption.
|
# exists yet as the whole feature is not read for end user consumption.
|
||||||
# This functional tests however would like to prove that some use cases
|
# This functional tests however would like to prove that some use cases
|
||||||
|
@ -5846,15 +5843,17 @@ class PortResourceRequestBasedSchedulingTestIgnoreMicroversionCheck(
|
||||||
compute_allocations)
|
compute_allocations)
|
||||||
self.assertPortMatchesAllocation(qos_port, network_allocations)
|
self.assertPortMatchesAllocation(qos_port, network_allocations)
|
||||||
|
|
||||||
self.api.delete_server(server['id'])
|
self._delete_and_check_allocations(server)
|
||||||
self._wait_until_deleted(server)
|
|
||||||
fake_notifier.wait_for_versioned_notifications('instance.delete.end')
|
|
||||||
allocations = self._get_allocations_by_server_uuid(server['id'])
|
|
||||||
self.assertEqual(0, len(allocations))
|
|
||||||
|
|
||||||
|
|
||||||
class PortResourceRequestReSchedulingTestIgnoreMicroversionCheck(
|
class PortResourceRequestReSchedulingTestIgnoreMicroversionCheck(
|
||||||
PortResourceRequestBasedSchedulingTestBase):
|
PortResourceRequestBasedSchedulingTestBase):
|
||||||
|
"""Similar to PortResourceRequestBasedSchedulingTestIgnoreMicroversionCheck
|
||||||
|
except this test uses FakeRescheduleDriver which will test reschedules
|
||||||
|
during server create work as expected, i.e. that the resource request
|
||||||
|
allocations are moved from the initially selected compute to the
|
||||||
|
alternative compute.
|
||||||
|
"""
|
||||||
|
|
||||||
compute_driver = 'fake.FakeRescheduleDriver'
|
compute_driver = 'fake.FakeRescheduleDriver'
|
||||||
|
|
||||||
|
@ -5867,7 +5866,7 @@ class PortResourceRequestReSchedulingTestIgnoreMicroversionCheck(
|
||||||
self._create_networking_rp_tree(self.compute2_rp_uuid)
|
self._create_networking_rp_tree(self.compute2_rp_uuid)
|
||||||
|
|
||||||
# NOTE(gibi): This mock turns off the api microversion that prevents
|
# NOTE(gibi): This mock turns off the api microversion that prevents
|
||||||
# handling of instances operations if the request involves port's with
|
# handling of instances operations if the request involves ports with
|
||||||
# resource request with old microversion. The new microversion does not
|
# resource request with old microversion. The new microversion does not
|
||||||
# exists yet as the whole feature is not read for end user consumption.
|
# exists yet as the whole feature is not read for end user consumption.
|
||||||
# This functional tests however would like to prove that some use cases
|
# This functional tests however would like to prove that some use cases
|
||||||
|
@ -5918,8 +5917,4 @@ class PortResourceRequestReSchedulingTestIgnoreMicroversionCheck(
|
||||||
self._get_provider_usages(
|
self._get_provider_usages(
|
||||||
self.ovs_bridge_rp_per_host[failed_compute_rp]))
|
self.ovs_bridge_rp_per_host[failed_compute_rp]))
|
||||||
|
|
||||||
self.api.delete_server(server['id'])
|
self._delete_and_check_allocations(server)
|
||||||
self._wait_until_deleted(server)
|
|
||||||
fake_notifier.wait_for_versioned_notifications('instance.delete.end')
|
|
||||||
allocations = self._get_allocations_by_server_uuid(server['id'])
|
|
||||||
self.assertEqual(0, len(allocations))
|
|
||||||
|
|
|
@ -243,21 +243,6 @@ class EvacuateTestV21(test.NoDBTestCase):
|
||||||
else:
|
else:
|
||||||
self.assertIsNone(res)
|
self.assertIsNone(res)
|
||||||
|
|
||||||
def test_evacuate_with_port_resource_request_old_microversion(self):
|
|
||||||
self.mock_list_port.return_value = {'ports': [
|
|
||||||
{'resource_request': {
|
|
||||||
"resources": {'CUSTOM_FOO': 1}}}]
|
|
||||||
}
|
|
||||||
|
|
||||||
admin_pass = 'MyNewPass'
|
|
||||||
ex = self.assertRaises(
|
|
||||||
webob.exc.HTTPBadRequest, self._get_evacuate_response,
|
|
||||||
{'host': 'my-host', 'onSharedStorage': 'False',
|
|
||||||
'adminPass': admin_pass})
|
|
||||||
|
|
||||||
self.assertIn('The evacuate server operation with port having QoS '
|
|
||||||
'policy is not supported.', six.text_type(ex))
|
|
||||||
|
|
||||||
|
|
||||||
class EvacuatePolicyEnforcementv21(test.NoDBTestCase):
|
class EvacuatePolicyEnforcementv21(test.NoDBTestCase):
|
||||||
|
|
||||||
|
|
|
@ -106,26 +106,6 @@ class MigrateServerTestsV21(admin_only_action_common.CommonTests):
|
||||||
args_map=args_map, method_translations=method_translations,
|
args_map=args_map, method_translations=method_translations,
|
||||||
exception_args=exception_arg)
|
exception_args=exception_arg)
|
||||||
|
|
||||||
def test_migrate_with_port_resource_request_old_microversion(self):
|
|
||||||
self.mock_list_port.return_value = {'ports': [
|
|
||||||
{'resource_request': {
|
|
||||||
"resources": {'CUSTOM_FOO': 1}}}]
|
|
||||||
}
|
|
||||||
method_translations = {'_migrate': 'resize',
|
|
||||||
'_migrate_live': 'live_migrate'}
|
|
||||||
body_map = {'_migrate_live': self._get_migration_body(host='hostname')}
|
|
||||||
args_map = {'_migrate_live': ((False, self.disk_over_commit,
|
|
||||||
'hostname', self.force, self.async_),
|
|
||||||
{}),
|
|
||||||
'_migrate': ((), {'host_name': self.host_name})}
|
|
||||||
ex = self.assertRaises(
|
|
||||||
webob.exc.HTTPBadRequest, self._test_actions,
|
|
||||||
['_migrate', '_migrate_live'], body_map=body_map,
|
|
||||||
method_translations=method_translations, args_map=args_map)
|
|
||||||
self.assertIn(
|
|
||||||
'The migrate server operation with port having QoS policy is not '
|
|
||||||
'supported.', six.text_type(ex))
|
|
||||||
|
|
||||||
def test_actions_with_locked_instance(self):
|
def test_actions_with_locked_instance(self):
|
||||||
method_translations = {'_migrate': 'resize',
|
method_translations = {'_migrate': 'resize',
|
||||||
'_migrate_live': 'live_migrate'}
|
'_migrate_live': 'live_migrate'}
|
||||||
|
@ -554,20 +534,6 @@ class MigrateServerTestsV256(MigrateServerTestsV234):
|
||||||
method_translations=self.method_translations,
|
method_translations=self.method_translations,
|
||||||
exception_args=exception_arg)
|
exception_args=exception_arg)
|
||||||
|
|
||||||
def test_migrate_with_port_resource_request_old_microversion(self):
|
|
||||||
self.mock_list_port.return_value = {'ports': [
|
|
||||||
{'resource_request': {
|
|
||||||
"resources": {'CUSTOM_FOO': 1}}}]
|
|
||||||
}
|
|
||||||
ex = self.assertRaises(
|
|
||||||
webob.exc.HTTPBadRequest, self._test_actions,
|
|
||||||
['_migrate'], body_map=self.body_map,
|
|
||||||
method_translations=self.method_translations,
|
|
||||||
args_map=self.args_map)
|
|
||||||
self.assertIn(
|
|
||||||
'The migrate server operation with port having QoS policy is not '
|
|
||||||
'supported.', six.text_type(ex))
|
|
||||||
|
|
||||||
def test_actions_with_locked_instance(self):
|
def test_actions_with_locked_instance(self):
|
||||||
self._test_actions_with_locked_instance(
|
self._test_actions_with_locked_instance(
|
||||||
['_migrate'], body_map=self.body_map,
|
['_migrate'], body_map=self.body_map,
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import fixtures
|
||||||
import mock
|
import mock
|
||||||
from oslo_utils.fixture import uuidsentinel as uuids
|
from oslo_utils.fixture import uuidsentinel as uuids
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
|
@ -95,6 +96,11 @@ class ServerActionsControllerTestV21(test.TestCase):
|
||||||
self.controller.compute_api, 'compute_task_api')
|
self.controller.compute_api, 'compute_task_api')
|
||||||
mock_conductor.start()
|
mock_conductor.start()
|
||||||
self.addCleanup(mock_conductor.stop)
|
self.addCleanup(mock_conductor.stop)
|
||||||
|
# Assume that none of the tests are using ports with resource requests.
|
||||||
|
self.mock_list_port = self.useFixture(
|
||||||
|
fixtures.MockPatch(
|
||||||
|
'nova.network.neutronv2.api.API.list_ports')).mock
|
||||||
|
self.mock_list_port.return_value = {'ports': []}
|
||||||
|
|
||||||
def _get_controller(self):
|
def _get_controller(self):
|
||||||
return self.servers.ServersController()
|
return self.servers.ServersController()
|
||||||
|
@ -123,10 +129,7 @@ class ServerActionsControllerTestV21(test.TestCase):
|
||||||
mock.patch.object(compute_api.API, method,
|
mock.patch.object(compute_api.API, method,
|
||||||
side_effect=exception.InstanceIsLocked(
|
side_effect=exception.InstanceIsLocked(
|
||||||
instance_uuid=instance['uuid'])),
|
instance_uuid=instance['uuid'])),
|
||||||
mock.patch('nova.api.openstack.common.'
|
) as (mock_get, mock_method):
|
||||||
'instance_has_port_with_resource_request',
|
|
||||||
return_value=False)
|
|
||||||
) as (mock_get, mock_method, mock_port_check):
|
|
||||||
|
|
||||||
controller_function = 'self.controller.' + action
|
controller_function = 'self.controller.' + action
|
||||||
self.assertRaises(webob.exc.HTTPConflict,
|
self.assertRaises(webob.exc.HTTPConflict,
|
||||||
|
@ -620,11 +623,8 @@ class ServerActionsControllerTestV21(test.TestCase):
|
||||||
self.assertEqual(instance_meta['kernel_id'], uuids.kernel_image_id)
|
self.assertEqual(instance_meta['kernel_id'], uuids.kernel_image_id)
|
||||||
self.assertEqual(instance_meta['ramdisk_id'], uuids.ramdisk_image_id)
|
self.assertEqual(instance_meta['ramdisk_id'], uuids.ramdisk_image_id)
|
||||||
|
|
||||||
@mock.patch('nova.api.openstack.common.'
|
|
||||||
'instance_has_port_with_resource_request', return_value=False)
|
|
||||||
@mock.patch.object(compute_api.API, 'rebuild')
|
@mock.patch.object(compute_api.API, 'rebuild')
|
||||||
def test_rebuild_instance_raise_auto_disk_config_exc(
|
def test_rebuild_instance_raise_auto_disk_config_exc(self, mock_rebuild):
|
||||||
self, mock_rebuild, mock_port_check):
|
|
||||||
body = {
|
body = {
|
||||||
"rebuild": {
|
"rebuild": {
|
||||||
"imageRef": self._image_href,
|
"imageRef": self._image_href,
|
||||||
|
@ -638,10 +638,7 @@ class ServerActionsControllerTestV21(test.TestCase):
|
||||||
self.controller._action_rebuild,
|
self.controller._action_rebuild,
|
||||||
self.req, FAKE_UUID, body=body)
|
self.req, FAKE_UUID, body=body)
|
||||||
|
|
||||||
@mock.patch('nova.api.openstack.common.'
|
def test_resize_server(self):
|
||||||
'instance_has_port_with_resource_request',
|
|
||||||
return_value=False)
|
|
||||||
def test_resize_server(self, mock_port_check):
|
|
||||||
|
|
||||||
body = dict(resize=dict(flavorRef="http://localhost/3"))
|
body = dict(resize=dict(flavorRef="http://localhost/3"))
|
||||||
|
|
||||||
|
@ -693,9 +690,7 @@ class ServerActionsControllerTestV21(test.TestCase):
|
||||||
self.controller._action_resize,
|
self.controller._action_resize,
|
||||||
self.req, FAKE_UUID, body=body)
|
self.req, FAKE_UUID, body=body)
|
||||||
|
|
||||||
@mock.patch('nova.api.openstack.common.'
|
def test_resize_with_image_exceptions(self):
|
||||||
'instance_has_port_with_resource_request', return_value=False)
|
|
||||||
def test_resize_with_image_exceptions(self, mock_port_check):
|
|
||||||
body = dict(resize=dict(flavorRef="http://localhost/3"))
|
body = dict(resize=dict(flavorRef="http://localhost/3"))
|
||||||
self.resize_called = 0
|
self.resize_called = 0
|
||||||
image_id = 'fake_image_id'
|
image_id = 'fake_image_id'
|
||||||
|
@ -736,33 +731,24 @@ class ServerActionsControllerTestV21(test.TestCase):
|
||||||
' disk resize disabled.')
|
' disk resize disabled.')
|
||||||
self.assertEqual(self.resize_called, call_no + 1)
|
self.assertEqual(self.resize_called, call_no + 1)
|
||||||
|
|
||||||
@mock.patch('nova.api.openstack.common.'
|
|
||||||
'instance_has_port_with_resource_request', return_value=False)
|
|
||||||
@mock.patch('nova.compute.api.API.resize',
|
@mock.patch('nova.compute.api.API.resize',
|
||||||
side_effect=exception.CannotResizeDisk(reason=''))
|
side_effect=exception.CannotResizeDisk(reason=''))
|
||||||
def test_resize_raises_cannot_resize_disk(
|
def test_resize_raises_cannot_resize_disk(self, mock_resize):
|
||||||
self, mock_resize, mock_port_check):
|
|
||||||
body = dict(resize=dict(flavorRef="http://localhost/3"))
|
body = dict(resize=dict(flavorRef="http://localhost/3"))
|
||||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||||
self.controller._action_resize,
|
self.controller._action_resize,
|
||||||
self.req, FAKE_UUID, body=body)
|
self.req, FAKE_UUID, body=body)
|
||||||
|
|
||||||
@mock.patch('nova.api.openstack.common.'
|
|
||||||
'instance_has_port_with_resource_request', return_value=False)
|
|
||||||
@mock.patch('nova.compute.api.API.resize',
|
@mock.patch('nova.compute.api.API.resize',
|
||||||
side_effect=exception.FlavorNotFound(reason='',
|
side_effect=exception.FlavorNotFound(reason='',
|
||||||
flavor_id='fake_id'))
|
flavor_id='fake_id'))
|
||||||
def test_resize_raises_flavor_not_found(
|
def test_resize_raises_flavor_not_found(self, mock_resize):
|
||||||
self, mock_resize, mock_port_check):
|
|
||||||
body = dict(resize=dict(flavorRef="http://localhost/3"))
|
body = dict(resize=dict(flavorRef="http://localhost/3"))
|
||||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||||
self.controller._action_resize,
|
self.controller._action_resize,
|
||||||
self.req, FAKE_UUID, body=body)
|
self.req, FAKE_UUID, body=body)
|
||||||
|
|
||||||
@mock.patch('nova.api.openstack.common.'
|
def test_resize_with_too_many_instances(self):
|
||||||
'instance_has_port_with_resource_request',
|
|
||||||
return_value=False)
|
|
||||||
def test_resize_with_too_many_instances(self, mock_port_check):
|
|
||||||
body = dict(resize=dict(flavorRef="http://localhost/3"))
|
body = dict(resize=dict(flavorRef="http://localhost/3"))
|
||||||
|
|
||||||
def fake_resize(*args, **kwargs):
|
def fake_resize(*args, **kwargs):
|
||||||
|
@ -774,9 +760,7 @@ class ServerActionsControllerTestV21(test.TestCase):
|
||||||
self.controller._action_resize,
|
self.controller._action_resize,
|
||||||
self.req, FAKE_UUID, body=body)
|
self.req, FAKE_UUID, body=body)
|
||||||
|
|
||||||
@mock.patch('nova.api.openstack.common.'
|
def test_resize_raises_conflict_on_invalid_state(self):
|
||||||
'instance_has_port_with_resource_request', return_value=False)
|
|
||||||
def test_resize_raises_conflict_on_invalid_state(self, mock_port_check):
|
|
||||||
body = dict(resize=dict(flavorRef="http://localhost/3"))
|
body = dict(resize=dict(flavorRef="http://localhost/3"))
|
||||||
|
|
||||||
def fake_resize(*args, **kwargs):
|
def fake_resize(*args, **kwargs):
|
||||||
|
@ -790,24 +774,17 @@ class ServerActionsControllerTestV21(test.TestCase):
|
||||||
self.controller._action_resize,
|
self.controller._action_resize,
|
||||||
self.req, FAKE_UUID, body=body)
|
self.req, FAKE_UUID, body=body)
|
||||||
|
|
||||||
@mock.patch('nova.api.openstack.common.'
|
|
||||||
'instance_has_port_with_resource_request',
|
|
||||||
return_value=False)
|
|
||||||
@mock.patch('nova.compute.api.API.resize',
|
@mock.patch('nova.compute.api.API.resize',
|
||||||
side_effect=exception.NoValidHost(reason=''))
|
side_effect=exception.NoValidHost(reason=''))
|
||||||
def test_resize_raises_no_valid_host(self, mock_resize, mock_port_check):
|
def test_resize_raises_no_valid_host(self, mock_resize):
|
||||||
body = dict(resize=dict(flavorRef="http://localhost/3"))
|
body = dict(resize=dict(flavorRef="http://localhost/3"))
|
||||||
|
|
||||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||||
self.controller._action_resize,
|
self.controller._action_resize,
|
||||||
self.req, FAKE_UUID, body=body)
|
self.req, FAKE_UUID, body=body)
|
||||||
|
|
||||||
@mock.patch('nova.api.openstack.common.'
|
|
||||||
'instance_has_port_with_resource_request',
|
|
||||||
return_value=False)
|
|
||||||
@mock.patch.object(compute_api.API, 'resize')
|
@mock.patch.object(compute_api.API, 'resize')
|
||||||
def test_resize_instance_raise_auto_disk_config_exc(
|
def test_resize_instance_raise_auto_disk_config_exc(self, mock_resize):
|
||||||
self, mock_resize, mock_port_check):
|
|
||||||
mock_resize.side_effect = exception.AutoDiskConfigDisabledByImage(
|
mock_resize.side_effect = exception.AutoDiskConfigDisabledByImage(
|
||||||
image='dummy')
|
image='dummy')
|
||||||
|
|
||||||
|
@ -817,12 +794,10 @@ class ServerActionsControllerTestV21(test.TestCase):
|
||||||
self.controller._action_resize,
|
self.controller._action_resize,
|
||||||
self.req, FAKE_UUID, body=body)
|
self.req, FAKE_UUID, body=body)
|
||||||
|
|
||||||
@mock.patch('nova.api.openstack.common.'
|
|
||||||
'instance_has_port_with_resource_request', return_value=False)
|
|
||||||
@mock.patch('nova.compute.api.API.resize',
|
@mock.patch('nova.compute.api.API.resize',
|
||||||
side_effect=exception.PciRequestAliasNotDefined(
|
side_effect=exception.PciRequestAliasNotDefined(
|
||||||
alias='fake_name'))
|
alias='fake_name'))
|
||||||
def test_resize_pci_alias_not_defined(self, mock_resize, mock_check_port):
|
def test_resize_pci_alias_not_defined(self, mock_resize):
|
||||||
# Tests that PciRequestAliasNotDefined is translated to a 400 error.
|
# Tests that PciRequestAliasNotDefined is translated to a 400 error.
|
||||||
body = dict(resize=dict(flavorRef="http://localhost/3"))
|
body = dict(resize=dict(flavorRef="http://localhost/3"))
|
||||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||||
|
|
|
@ -15,11 +15,9 @@
|
||||||
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
|
||||||
|
@ -63,27 +61,6 @@ 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):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue