Skip to content

Commit 8b8e386

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Add regression test for bug #1899835"
2 parents b9c48af + 2317b92 commit 8b8e386

File tree

1 file changed

+106
-0
lines changed

1 file changed

+106
-0
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
2+
# not use this file except in compliance with the License. You may obtain
3+
# a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations
11+
# under the License.
12+
13+
import mock
14+
15+
from nova import context
16+
from nova import objects
17+
from nova import test
18+
from nova.tests import fixtures as nova_fixtures
19+
from nova.tests.functional.libvirt import base
20+
21+
from oslo_serialization import jsonutils
22+
23+
24+
class TestVolumeDisconnectDuringPreLiveMigrationRollback(base.ServersTestBase):
25+
"""Regression test for bug #1899835
26+
27+
This regression test aims to ensure that no attempt is made to disconnect
28+
volumes from the destination host of a live migration if a failure is
29+
encountered early when creating the new volume attachment during
30+
pre_live_migration ahead of any volumes actually being connected.
31+
"""
32+
# Default self.api to the self.admin_api as live migration is admin only
33+
ADMIN_API = True
34+
microversion = 'latest'
35+
36+
def setUp(self):
37+
super().setUp()
38+
self.start_compute(hostname='src')
39+
self.start_compute(hostname='dest')
40+
41+
def test_disconnect_volume_called_during_pre_live_migration_failure(self):
42+
server = {
43+
'name': 'test',
44+
'imageRef': '',
45+
'flavorRef': 1,
46+
'networks': 'none',
47+
'host': 'src',
48+
'block_device_mapping_v2': [{
49+
'source_type': 'volume',
50+
'destination_type': 'volume',
51+
'boot_index': 0,
52+
'uuid': nova_fixtures.CinderFixture.IMAGE_BACKED_VOL
53+
}]
54+
}
55+
56+
with test.nested(
57+
mock.patch.object(
58+
self.computes['src'].driver, 'get_volume_connector'),
59+
mock.patch.object(
60+
self.computes['src'].driver, '_connect_volume'),
61+
) as (
62+
mock_src_connector, mock_src_connect
63+
):
64+
server = self.api.post_server({'server': server})
65+
self._wait_for_state_change(server, 'ACTIVE')
66+
67+
# Assert that we called the src connector and connect mocks
68+
mock_src_connector.assert_called_once()
69+
mock_src_connect.assert_called_once()
70+
71+
# Fetch the connection_info from the src
72+
ctxt = context.get_admin_context()
73+
bdm = objects.BlockDeviceMapping.get_by_volume_id(
74+
ctxt, nova_fixtures.CinderFixture.IMAGE_BACKED_VOL,
75+
instance_uuid=server['id'])
76+
src_connection_info = jsonutils.loads(bdm.connection_info)
77+
78+
with test.nested(
79+
mock.patch.object(
80+
self.computes['dest'].driver, 'get_volume_connector'),
81+
mock.patch.object(
82+
self.computes['dest'].driver, '_connect_volume'),
83+
mock.patch.object(
84+
self.computes['dest'].driver, '_disconnect_volume'),
85+
mock.patch(
86+
'nova.volume.cinder.API.attachment_create',
87+
side_effect=test.TestingException)
88+
) as (
89+
mock_dest_connector, mock_dest_connect, mock_dest_disconnect,
90+
mock_attachment_create
91+
):
92+
# Attempt to live migrate and ensure it is marked as failed
93+
self._live_migrate(server, 'failed')
94+
95+
# Assert that we called the dest connector and attachment_create mocks
96+
mock_dest_connector.assert_called_once()
97+
mock_attachment_create.assert_called_once()
98+
99+
# Assert that connect_volume hasn't been called on the dest
100+
mock_dest_connect.assert_not_called()
101+
102+
# FIXME(lyarwood): This is bug #1899835, disconnect_volume shouldn't be
103+
# called on the destination host without connect_volume first being
104+
# called and especially using with the connection_info from the source
105+
mock_dest_disconnect.assert_called_with(
106+
mock.ANY, src_connection_info, mock.ANY, encryption=mock.ANY)

0 commit comments

Comments
 (0)