Merge "Reproduce bug 1907522 in functional test"

This commit is contained in:
Zuul 2020-12-21 14:55:48 +00:00 committed by Gerrit Code Review
commit 282299eced
2 changed files with 117 additions and 0 deletions

View File

@ -3861,6 +3861,8 @@ class API(base.Base):
:param instance: Instance object being resized
:returns: True if cross-cell resize is allowed, False otherwise
"""
# TODO(gibi): do not allow cross cell migration if the instance has
# neutron ports with resource request. See bug 1907522.
# First check to see if the requesting project/user is allowed by
# policy to perform cross-cell resize.
allowed = context.can(

View File

@ -40,6 +40,8 @@ from nova.network import constants
from nova.network import neutron as neutronapi
from nova import objects
from nova.objects import block_device as block_device_obj
from nova.policies import base as base_policies
from nova.policies import servers as servers_policies
from nova.scheduler import utils
from nova import test
from nova.tests import fixtures as nova_fixtures
@ -7948,3 +7950,116 @@ class AcceleratorServerOpsTest(AcceleratorServerBase):
'OS-DCF:diskConfig': 'AUTO'}})
self.assertEqual(403, ex.response.status_code)
self._check_allocations_usage(self.server)
class CrossCellResizeWithQoSPort(PortResourceRequestBasedSchedulingTestBase):
NUMBER_OF_CELLS = 2
def setUp(self):
# Use our custom weigher defined above to make sure that we have
# a predictable host order in the alternate list returned by the
# scheduler for migration.
self.useFixture(nova_fixtures.HostNameWeigherFixture())
super(CrossCellResizeWithQoSPort, self).setUp()
# start compute2 in cell2, compute1 is started in cell1 by default
self.compute2 = self._start_compute('host2', cell_name='cell2')
self.compute2_rp_uuid = self._get_provider_uuid_by_host('host2')
self._create_networking_rp_tree('host2', self.compute2_rp_uuid)
self.compute2_service_id = self.admin_api.get_services(
host='host2', binary='nova-compute')[0]['id']
# Enable cross-cell resize policy since it defaults to not allow
# anyone to perform that type of operation. For these tests we'll
# just allow admins to perform cross-cell resize.
self.policy.set_rules({
servers_policies.CROSS_CELL_RESIZE:
base_policies.RULE_ADMIN_API},
overwrite=False)
def test_cross_cell_migrate_server_with_qos_ports(self):
"""Test that cross cell migration is not supported with qos ports and
nova therefore falls back to do a same cell migration instead.
To test this properly we first make sure that there is no valid host
in the same cell but there is valid host in another cell and observe
that the migration fails with NoValidHost. Then we start a new compute
in the same cell the instance is in and retry the migration that is now
expected to pass.
"""
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
server = self._create_server_with_ports_and_check_allocation(
non_qos_normal_port, qos_normal_port, qos_sriov_port)
orig_create_binding = neutronapi.API._create_port_binding
hosts = {
'host1': self.compute1_rp_uuid, 'host2': self.compute2_rp_uuid}
# Add an extra check to our neutron fixture. This check makes sure that
# the RP sent in the binding corresponds to host of the binding. In a
# real deployment this is checked by the Neutron server. As bug
# 1907522 showed we fail this check for cross cell migration with qos
# ports in a real deployment. So to reproduce that bug we need to have
# the same check in our test env too.
def spy_on_create_binding(context, client, port_id, data):
host_rp_uuid = hosts[data['binding']['host']]
device_rp_uuid = data['binding']['profile'].get('allocation')
if port_id == qos_normal_port['id']:
if device_rp_uuid != self.ovs_bridge_rp_per_host[host_rp_uuid]:
raise exception.PortBindingFailed(port_id=port_id)
elif port_id == qos_sriov_port['id']:
if (device_rp_uuid not in
self.sriov_dev_rp_per_host[host_rp_uuid].values()):
raise exception.PortBindingFailed(port_id=port_id)
return orig_create_binding(context, client, port_id, data)
with mock.patch(
'nova.network.neutron.API._create_port_binding',
side_effect=spy_on_create_binding, autospec=True
):
# We expect the migration to fail as the only available target
# host is in a different cell and while cross cell migration is
# enabled it is not supported for neutron ports with resource
# request.
# FIXME(gibi): We expect this to fail with NoValidHost.
# Unfortunately it fails due to sending an invalid port binding to
# Neutron today. This is bug 1907522.
self.api.post_server_action(server['id'], {'migrate': None})
self._wait_for_migration_status(server, ['error'])
# FIXME(gibi): This is also the result of the bug1907522 as the
# cleanup after the failure is incomplete.
self._wait_for_server_parameter(
server,
{'status': 'RESIZE', 'OS-EXT-STS:task_state': 'resize_prep'})
event = self._wait_for_action_fail_completion(
server, 'migrate', 'conductor_migrate_server')
# This is just the last exception in the chain of exceptions
# happening after the port binding fails.
self.assertIn(
'exception.InstanceInfoCacheNotFound', event['traceback'])
# This is the root case
self.assertIn(
'nova.exception.PortBindingFailed: Binding failed for port',
self.stdlog.logger.output)
# Now start a new compute in the same cell as the instance and retry
# the migration.
#
# This should work after the fallback to same cell resize is
# implemented
#
# self._start_compute('host3', cell_name='cell1')
#
# with mock.patch(
# 'nova.network.neutron.API._create_port_binding',
# side_effect=spy_on_create_binding, autospec=True
# ):
# server = self._migrate_server(server)
# self.assertEqual('host3', server['OS-EXT-SRV-ATTR:host'])
self._delete_server_and_check_allocations(
server, qos_normal_port, qos_sriov_port)