summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2021-06-04 15:52:03 +0000
committerGerrit Code Review <review@openstack.org>2021-06-04 15:52:03 +0000
commitc5c9713f140cd407a97b07614258ce093a1260f5 (patch)
tree64dbcc2e7eb8027a38088da6485446f74c1ebb50
parentc5619c7e3e1c55b7ac711fff8f7a836c206d96f8 (diff)
parenta4e2a6a41239a682c0da553ec5938737d0b85b52 (diff)
downloadnova-c5c9713f140cd407a97b07614258ce093a1260f5.tar.gz
Merge "add functional regression test for bug #1888395" into stable/train
-rw-r--r--nova/network/neutronv2/constants.py1
-rw-r--r--nova/tests/functional/regressions/test_bug_1888395.py122
-rw-r--r--nova/tests/unit/virt/libvirt/fake_imagebackend.py8
3 files changed, 130 insertions, 1 deletions
diff --git a/nova/network/neutronv2/constants.py b/nova/network/neutronv2/constants.py
index 1bb4605c9f..6a5e6b8e0e 100644
--- a/nova/network/neutronv2/constants.py
+++ b/nova/network/neutronv2/constants.py
@@ -19,6 +19,7 @@ VNIC_INDEX_EXT = 'VNIC Index'
DNS_INTEGRATION = 'DNS Integration'
MULTI_NET_EXT = 'Multi Provider Network'
SUBSTR_PORT_FILTERING = 'IP address substring filtering'
+PORT_BINDING = 'Port Binding'
PORT_BINDING_EXTENDED = 'Port Bindings Extended'
LIVE_MIGRATION = 'live-migration'
DEFAULT_SECGROUP = 'default'
diff --git a/nova/tests/functional/regressions/test_bug_1888395.py b/nova/tests/functional/regressions/test_bug_1888395.py
new file mode 100644
index 0000000000..8376814a3e
--- /dev/null
+++ b/nova/tests/functional/regressions/test_bug_1888395.py
@@ -0,0 +1,122 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import fixtures
+import mock
+
+from nova import context
+from nova.network.neutronv2 import api as neutron
+from nova.network.neutronv2 import constants as neutron_constants
+from nova.tests.functional import integrated_helpers
+from nova.tests.functional.libvirt import base as libvirt_base
+from nova.tests.unit.virt.libvirt import fake_os_brick_connector
+from nova.tests.unit.virt.libvirt import fakelibvirt
+
+
+class TestLiveMigrationWithoutMultiplePortBindings(
+ integrated_helpers.InstanceHelperMixin,
+ libvirt_base.ServersTestBase):
+ """Regression test for bug 1888395.
+
+ This regression test asserts that Live migration works when
+ neutron does not support the binding-extended api extension
+ and the legacy single port binding workflow is used.
+ """
+
+ ADMIN_API = True
+ api_major_version = 'v2.1'
+ microversion = 'latest'
+
+ def list_extensions(self, *args, **kwargs):
+ return {
+ 'extensions': [
+ {
+ # Copied from neutron-lib portbindings.py
+ "updated": "2014-02-03T10:00:00-00:00",
+ "name": neutron_constants.PORT_BINDING,
+ "links": [],
+ "alias": "binding",
+ "description": "Expose port bindings of a virtual port to "
+ "external application"
+ }
+ ]
+ }
+
+ def setUp(self):
+ self.flags(instances_path=self.useFixture(fixtures.TempDir()).path)
+ super(TestLiveMigrationWithoutMultiplePortBindings, self).setUp()
+ self.neutron.list_extensions = self.list_extensions
+ self.neutron_api = neutron.API()
+ # TODO(sean-k-mooney): remove after
+ # I275509eb0e0eb9eaf26fe607b7d9a67e1edc71f8
+ # has merged.
+ self.useFixture(fixtures.MonkeyPatch(
+ 'nova.virt.libvirt.driver.connector',
+ fake_os_brick_connector))
+
+ self.computes = {}
+ for host in ['start_host', 'end_host']:
+ host_info = fakelibvirt.HostInfo(
+ cpu_nodes=1, cpu_sockets=1, cpu_cores=4, cpu_threads=2,
+ kB_mem=10740000)
+ fake_connection = self._get_connection(
+ host_info=host_info, hostname=host)
+
+ # This is fun. Firstly we need to do a global'ish mock so we can
+ # actually start the service.
+ with mock.patch('nova.virt.libvirt.host.Host.get_connection',
+ return_value=fake_connection):
+ compute = self.start_service('compute', host=host)
+
+ # Once that's done, we need to do some tweaks to each individual
+ # compute "service" to make sure they return unique objects
+ compute.driver._host.get_connection = lambda: fake_connection
+ self.computes[host] = compute
+
+ self.ctxt = context.get_admin_context()
+
+ def test_live_migrate(self):
+ flavors = self.api.get_flavors()
+ flavor = flavors[0]
+ server_req = self._build_minimal_create_server_request(
+ self.api, 'some-server', flavor_id=flavor['id'],
+ image_uuid='155d900f-4e14-4e4c-a73d-069cbf4541e6',
+ networks=[{'port': self.neutron.port_1['id']}])
+ server_req['availability_zone'] = 'nova:%s' % "start_host"
+ created_server = self.api.post_server({'server': server_req})
+ server = self._wait_for_state_change(
+ self.api, created_server, 'ACTIVE')
+ self.assertFalse(
+ self.neutron_api.supports_port_binding_extension(self.ctxt))
+ # TODO(sean-k-mooney): extend _live_migrate to support passing a host
+ self.api.post_server_action(
+ server['id'],
+ {
+ 'os-migrateLive': {
+ 'host': 'end_host',
+ 'block_migration': 'auto'
+ }
+ }
+ )
+
+ # FIXME(sean-k-mooney): this should succeed but because of bug #188395
+ # it will fail.
+ # self._wait_for_server_parameter(
+ # server, {'OS-EXT-SRV-ATTR:host': 'end_host', 'status': 'ACTIVE'})
+ # because of the bug the migration will fail in pre_live_migrate so
+ # the vm should still be active on the start_host
+ self._wait_for_server_parameter(
+ self.api, server,
+ {'OS-EXT-SRV-ATTR:host': 'start_host', 'status': 'ACTIVE'})
+
+ msg = "NotImplementedError: Cannot load 'vif_type' in the base class"
+ self.assertIn(msg, self.stdlog.logger.output)
diff --git a/nova/tests/unit/virt/libvirt/fake_imagebackend.py b/nova/tests/unit/virt/libvirt/fake_imagebackend.py
index d73a396ab5..4a940fa45e 100644
--- a/nova/tests/unit/virt/libvirt/fake_imagebackend.py
+++ b/nova/tests/unit/virt/libvirt/fake_imagebackend.py
@@ -184,11 +184,17 @@ class ImageBackendFixture(fixtures.Fixture):
# class.
image_init.SUPPORTS_CLONE = False
- # Ditto for the 'is_shared_block_storage' function
+ # Ditto for the 'is_shared_block_storage' function and
+ # 'is_file_in_instance_path'
def is_shared_block_storage():
return False
+ def is_file_in_instance_path():
+ return False
+
setattr(image_init, 'is_shared_block_storage', is_shared_block_storage)
+ setattr(image_init, 'is_file_in_instance_path',
+ is_file_in_instance_path)
return image_init