blob: 941315e2c96653fc591cbd3850d673d4f2191638 [file] [log] [blame]
ZhiQiang Fan39f97222013-09-20 04:49:44 +08001# Copyright 2012 OpenStack Foundation
Mate Lakat99ee9142012-09-14 12:34:46 +01002# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
Markus Zoeller69d58b82017-02-17 10:09:22 +010016import time
17
Sarafraj Singh61e40452016-09-29 13:06:59 -050018from oslo_log import log as logging
ivan-zhu1feeb382013-01-24 10:14:39 +080019import testtools
Matthew Treinisha83a16e2012-12-07 13:44:02 -050020
Sean Dague1937d092013-05-17 16:36:38 -040021from tempest.api.compute import base
Markus Zoeller69d58b82017-02-17 10:09:22 +010022from tempest.common import compute
Andrea Frittolicd368412017-08-14 21:37:56 +010023from tempest.common import utils
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +000024from tempest.common import waiters
Mate Lakat99ee9142012-09-14 12:34:46 +010025from tempest import config
Brian Haleya3879b52016-02-24 16:53:47 -060026from tempest.lib import decorators
Mate Lakat99ee9142012-09-14 12:34:46 +010027
Matthew Treinishb0a78fc2014-01-29 16:49:12 +000028CONF = config.CONF
Sarafraj Singh61e40452016-09-29 13:06:59 -050029LOG = logging.getLogger(__name__)
Matthew Treinishb0a78fc2014-01-29 16:49:12 +000030
Mate Lakat99ee9142012-09-14 12:34:46 +010031
zhufl0d784eb2018-08-23 11:19:16 +080032class LiveMigrationTestBase(base.BaseV2ComputeAdminTest):
zhufl1b3b03d2020-04-16 08:38:16 +080033 """Test live migration operations supported by admin user"""
Mate Lakat99ee9142012-09-14 12:34:46 +010034
Eric Friedbfaa50f2020-01-09 12:04:54 -060035 # These tests don't attempt any SSH validation nor do they use
36 # floating IPs on the instance, so all we need is a network and
37 # a subnet so the instance being migrated has a single port, but
38 # we need that to make sure we are properly updating the port
39 # host bindings during the live migration.
40 create_default_network = True
41
Mate Lakat99ee9142012-09-14 12:34:46 +010042 @classmethod
Timofey Durakovad7aea52015-10-12 13:37:44 +030043 def skip_checks(cls):
zhufl0d784eb2018-08-23 11:19:16 +080044 super(LiveMigrationTestBase, cls).skip_checks()
Timofey Durakovad7aea52015-10-12 13:37:44 +030045
46 if not CONF.compute_feature_enabled.live_migration:
47 skip_msg = ("%s skipped as live-migration is "
48 "not available" % cls.__name__)
49 raise cls.skipException(skip_msg)
Jordan Pittierf60c1002015-11-16 11:24:09 +010050 if CONF.compute.min_compute_nodes < 2:
Timofey Durakov7a04e912015-11-17 17:37:53 +030051 raise cls.skipException(
Timofey Durakovad7aea52015-10-12 13:37:44 +030052 "Less than 2 compute nodes, skipping migration test.")
53
54 @classmethod
Rohan Kanade60b73092015-02-04 17:58:19 +053055 def setup_clients(cls):
zhufl0d784eb2018-08-23 11:19:16 +080056 super(LiveMigrationTestBase, cls).setup_clients()
Jordan Pittier8160d312017-04-18 11:52:23 +020057 cls.admin_migration_client = cls.os_admin.migrations_client
Mate Lakat99ee9142012-09-14 12:34:46 +010058
Claudiu Belu516b7a42016-03-03 06:28:43 -080059 def _migrate_server_to(self, server_id, dest_host, volume_backed=False):
Eli Qiaoe07eacc2016-03-03 13:49:37 +080060 kwargs = dict()
61 block_migration = getattr(self, 'block_migration', None)
62 if self.block_migration is None:
zhufl40891d22018-03-30 10:45:05 +080063 if self.is_requested_microversion_compatible('2.24'):
64 kwargs['disk_over_commit'] = False
Eli Qiaoe07eacc2016-03-03 13:49:37 +080065 block_migration = (CONF.compute_feature_enabled.
66 block_migration_for_live_migration and
67 not volume_backed)
zhufl4a2cfff2017-01-03 15:45:02 +080068 self.admin_servers_client.live_migrate_server(
Timofey Durakovf358a7e2015-10-05 13:06:51 +030069 server_id, host=dest_host, block_migration=block_migration,
Eli Qiaoe07eacc2016-03-03 13:49:37 +080070 **kwargs)
Mate Lakat99ee9142012-09-14 12:34:46 +010071
Sarafraj Singh61e40452016-09-29 13:06:59 -050072 def _live_migrate(self, server_id, target_host, state,
73 volume_backed=False):
zhuflbe052d62019-11-04 10:56:02 +080074 # If target_host is None, check whether source host is different with
75 # the new host after migration.
76 if target_host is None:
77 source_host = self.get_host_for_server(server_id)
Sarafraj Singh61e40452016-09-29 13:06:59 -050078 self._migrate_server_to(server_id, target_host, volume_backed)
79 waiters.wait_for_server_status(self.servers_client, server_id, state)
80 migration_list = (self.admin_migration_client.list_migrations()
81 ['migrations'])
82
83 msg = ("Live Migration failed. Migrations list for Instance "
84 "%s: [" % server_id)
85 for live_migration in migration_list:
86 if (live_migration['instance_uuid'] == server_id):
87 msg += "\n%s" % live_migration
88 msg += "]"
zhuflbe052d62019-11-04 10:56:02 +080089 if target_host is None:
90 self.assertNotEqual(source_host,
91 self.get_host_for_server(server_id), msg)
92 else:
93 self.assertEqual(target_host, self.get_host_for_server(server_id),
94 msg)
Sarafraj Singh61e40452016-09-29 13:06:59 -050095
zhufl0d784eb2018-08-23 11:19:16 +080096
97class LiveMigrationTest(LiveMigrationTestBase):
98 max_microversion = '2.24'
99 block_migration = None
100
Joe Gordon8843f0f2015-03-17 15:07:34 -0700101 def _test_live_migration(self, state='ACTIVE', volume_backed=False):
102 """Tests live migration between two hosts.
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800103
104 Requires CONF.compute_feature_enabled.live_migration to be True.
105
106 :param state: The vm_state the migrated server should be in before and
107 after the live migration. Supported values are 'ACTIVE'
108 and 'PAUSED'.
Joe Gordon8843f0f2015-03-17 15:07:34 -0700109 :param volume_backed: If the instance is volume backed or not. If
110 volume_backed, *block* migration is not used.
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800111 """
Timofey Durakovf358a7e2015-10-05 13:06:51 +0300112 # Live migrate an instance to another host
Jordan Pittier599a3562016-01-08 17:38:14 +0100113 server_id = self.create_test_server(wait_until="ACTIVE",
114 volume_backed=volume_backed)['id']
Duc Truong09941202017-06-07 10:15:20 -0700115 source_host = self.get_host_for_server(server_id)
zhuflbe052d62019-11-04 10:56:02 +0800116 if not CONF.compute_feature_enabled.can_migrate_between_any_hosts:
117 # not to specify a host so that the scheduler will pick one
118 destination_host = None
119 else:
120 destination_host = self.get_host_other_than(server_id)
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800121
122 if state == 'PAUSED':
123 self.admin_servers_client.pause_server(server_id)
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000124 waiters.wait_for_server_status(self.admin_servers_client,
125 server_id, state)
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800126
Sarafraj Singh61e40452016-09-29 13:06:59 -0500127 LOG.info("Live migrate from source %s to destination %s",
128 source_host, destination_host)
129 self._live_migrate(server_id, destination_host, state, volume_backed)
130 if CONF.compute_feature_enabled.live_migrate_back_and_forth:
131 # If live_migrate_back_and_forth is enabled it is a grenade job.
132 # Therefore test should validate whether LM is compatible in both
133 # ways, so live migrate VM back to the source host
134 LOG.info("Live migrate back to source %s", source_host)
135 self._live_migrate(server_id, source_host, state, volume_backed)
Mate Lakat99ee9142012-09-14 12:34:46 +0100136
Ken'ichi Ohmichiebbfd1c2017-01-27 16:37:00 -0800137 @decorators.idempotent_id('1dce86b8-eb04-4c03-a9d8-9c1dc3ee0c7b')
Paras Babbare18335e2020-06-23 17:09:19 -0400138 @testtools.skipUnless(CONF.compute_feature_enabled.
139 block_migration_for_live_migration,
140 'Block Live migration not available')
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800141 def test_live_block_migration(self):
zhufl1b3b03d2020-04-16 08:38:16 +0800142 """Test live migrating an active server"""
Joe Gordon8843f0f2015-03-17 15:07:34 -0700143 self._test_live_migration()
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800144
Ken'ichi Ohmichiebbfd1c2017-01-27 16:37:00 -0800145 @decorators.idempotent_id('1e107f21-61b2-4988-8f22-b196e938ab88')
Paras Babbare18335e2020-06-23 17:09:19 -0400146 @testtools.skipUnless(CONF.compute_feature_enabled.
147 block_migration_for_live_migration,
148 'Block Live migration not available')
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800149 @testtools.skipUnless(CONF.compute_feature_enabled.pause,
150 'Pause is not available.')
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800151 def test_live_block_migration_paused(self):
zhufl1b3b03d2020-04-16 08:38:16 +0800152 """Test live migrating a paused server"""
Joe Gordon8843f0f2015-03-17 15:07:34 -0700153 self._test_live_migration(state='PAUSED')
154
melanie witt334f3132017-12-14 21:49:55 +0000155 @testtools.skipUnless(CONF.compute_feature_enabled.
156 volume_backed_live_migration,
157 'Volume-backed live migration not available')
Ken'ichi Ohmichiebbfd1c2017-01-27 16:37:00 -0800158 @decorators.idempotent_id('5071cf17-3004-4257-ae61-73a84e28badd')
Andrea Frittolicd368412017-08-14 21:37:56 +0100159 @utils.services('volume')
Joe Gordon8843f0f2015-03-17 15:07:34 -0700160 def test_volume_backed_live_migration(self):
zhufl1b3b03d2020-04-16 08:38:16 +0800161 """Test live migrating an active server booted from volume"""
Joe Gordon8843f0f2015-03-17 15:07:34 -0700162 self._test_live_migration(volume_backed=True)
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800163
Ken'ichi Ohmichiebbfd1c2017-01-27 16:37:00 -0800164 @decorators.idempotent_id('e19c0cc6-6720-4ed8-be83-b6603ed5c812')
Timofey Durakovad7aea52015-10-12 13:37:44 +0300165 @testtools.skipIf(not CONF.compute_feature_enabled.
Matthew Treinishd5c96022013-10-17 21:51:23 +0000166 block_migration_for_live_migration,
Bob Ballc078be92013-04-09 14:25:00 +0100167 'Block Live migration not available')
Matthew Treinishd5c96022013-10-17 21:51:23 +0000168 @testtools.skipIf(not CONF.compute_feature_enabled.
169 block_migrate_cinder_iscsi,
Bob Ballc078be92013-04-09 14:25:00 +0100170 'Block Live migration not configured for iSCSI')
lkuchlanf4413c42018-05-03 07:49:35 +0300171 @utils.services('volume')
Bob Ballc078be92013-04-09 14:25:00 +0100172 def test_iscsi_volume(self):
zhufl1b3b03d2020-04-16 08:38:16 +0800173 """Test live migrating a server with volume attached"""
Matt Riedemanncb16a662016-10-01 18:30:05 -0400174 server = self.create_test_server(wait_until="ACTIVE")
175 server_id = server['id']
zhuflbe052d62019-11-04 10:56:02 +0800176 if not CONF.compute_feature_enabled.can_migrate_between_any_hosts:
177 # not to specify a host so that the scheduler will pick one
178 target_host = None
179 else:
180 target_host = self.get_host_other_than(server_id)
Bob Ballc078be92013-04-09 14:25:00 +0100181
Matt Riedemanncb16a662016-10-01 18:30:05 -0400182 volume = self.create_volume()
Bob Ballc078be92013-04-09 14:25:00 +0100183
184 # Attach the volume to the server
Matt Riedemanncb16a662016-10-01 18:30:05 -0400185 self.attach_volume(server, volume, device='/dev/xvdb')
lianghao39d86992017-04-11 16:01:26 +0800186 server = self.admin_servers_client.show_server(server_id)['server']
187 volume_id1 = server["os-extended-volumes:volumes_attached"][0]["id"]
lianghaod5818442018-01-11 19:07:26 +0800188 self._live_migrate(server_id, target_host, 'ACTIVE')
lianghao39d86992017-04-11 16:01:26 +0800189
190 server = self.admin_servers_client.show_server(server_id)['server']
191 volume_id2 = server["os-extended-volumes:volumes_attached"][0]["id"]
192
lianghao39d86992017-04-11 16:01:26 +0800193 self.assertEqual(volume_id1, volume_id2)
Eli Qiaoe07eacc2016-03-03 13:49:37 +0800194
195
zhufl0d784eb2018-08-23 11:19:16 +0800196class LiveMigrationRemoteConsolesV26Test(LiveMigrationTestBase):
Markus Zoeller69d58b82017-02-17 10:09:22 +0100197 min_microversion = '2.6'
198 max_microversion = 'latest'
199
200 @decorators.idempotent_id('6190af80-513e-4f0f-90f2-9714e84955d7')
201 @testtools.skipUnless(CONF.compute_feature_enabled.serial_console,
202 'Serial console not supported.')
203 @testtools.skipUnless(
Andrea Frittoli88eb6772017-08-07 21:06:27 +0100204 compute.is_scheduler_filter_enabled("DifferentHostFilter"),
Markus Zoeller69d58b82017-02-17 10:09:22 +0100205 'DifferentHostFilter is not available.')
206 def test_live_migration_serial_console(self):
207 """Test the live-migration of an instance which has a serial console
208
209 The serial console feature of an instance uses ports on the host.
210 These ports need to be updated when they are already in use by
211 another instance on the target host. This test checks if this
212 update behavior is correctly done, by connecting to the serial
213 consoles of the instances before and after the live migration.
214 """
215 server01_id = self.create_test_server(wait_until='ACTIVE')['id']
216 hints = {'different_host': server01_id}
217 server02_id = self.create_test_server(scheduler_hints=hints,
218 wait_until='ACTIVE')['id']
Duc Truong09941202017-06-07 10:15:20 -0700219 host01_id = self.get_host_for_server(server01_id)
220 host02_id = self.get_host_for_server(server02_id)
Markus Zoeller69d58b82017-02-17 10:09:22 +0100221 self.assertNotEqual(host01_id, host02_id)
222
223 # At this step we have 2 instances on different hosts, both with
224 # serial consoles, both with port 10000 (the default value).
225 # https://bugs.launchpad.net/nova/+bug/1455252 describes the issue
226 # when live-migrating in such a scenario.
227
228 self._verify_console_interaction(server01_id)
229 self._verify_console_interaction(server02_id)
230
lianghaod5818442018-01-11 19:07:26 +0800231 self._live_migrate(server01_id, host02_id, 'ACTIVE')
Markus Zoeller69d58b82017-02-17 10:09:22 +0100232 self._verify_console_interaction(server01_id)
233 # At this point, both instances have a valid serial console
234 # connection, which means the ports got updated.
235
236 def _verify_console_interaction(self, server_id):
237 body = self.servers_client.get_remote_console(server_id,
238 console_type='serial',
239 protocol='serial')
240 console_url = body['remote_console']['url']
241 data = "test_live_migration_serial_console"
242 console_output = ''
243 t = 0.0
244 interval = 0.1
245
246 ws = compute.create_websocket(console_url)
247 try:
248 # NOTE (markus_z): It can take a long time until the terminal
249 # of the instance is available for interaction. Hence the
250 # long timeout value.
251 while data not in console_output and t <= 120.0:
252 try:
253 ws.send_frame(data)
Pengfei Zhang20f41542018-01-19 11:48:18 +0800254 received = ws.receive_frame()
255 console_output += received
Markus Zoeller69d58b82017-02-17 10:09:22 +0100256 except Exception:
257 # In case we had an issue with send/receive on the
258 # websocket connection, we create a new one.
259 ws = compute.create_websocket(console_url)
260 time.sleep(interval)
261 t += interval
262 finally:
263 ws.close()
264 self.assertIn(data, console_output)
265
266
Duc Truong09941202017-06-07 10:15:20 -0700267class LiveAutoBlockMigrationV225Test(LiveMigrationTest):
Eli Qiaoe07eacc2016-03-03 13:49:37 +0800268 min_microversion = '2.25'
269 max_microversion = 'latest'
270 block_migration = 'auto'