blob: 411159b2645a7d5e69a614572eafeaa6fe5b81eb [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
Duc Truong09941202017-06-07 10:15:20 -070032class LiveMigrationTest(base.BaseV2ComputeAdminTest):
Eli Qiaoe07eacc2016-03-03 13:49:37 +080033 max_microversion = '2.24'
34 block_migration = None
Mate Lakat99ee9142012-09-14 12:34:46 +010035
Mate Lakat99ee9142012-09-14 12:34:46 +010036 @classmethod
Timofey Durakovad7aea52015-10-12 13:37:44 +030037 def skip_checks(cls):
Duc Truong09941202017-06-07 10:15:20 -070038 super(LiveMigrationTest, cls).skip_checks()
Timofey Durakovad7aea52015-10-12 13:37:44 +030039
40 if not CONF.compute_feature_enabled.live_migration:
41 skip_msg = ("%s skipped as live-migration is "
42 "not available" % cls.__name__)
43 raise cls.skipException(skip_msg)
Jordan Pittierf60c1002015-11-16 11:24:09 +010044 if CONF.compute.min_compute_nodes < 2:
Timofey Durakov7a04e912015-11-17 17:37:53 +030045 raise cls.skipException(
Timofey Durakovad7aea52015-10-12 13:37:44 +030046 "Less than 2 compute nodes, skipping migration test.")
47
48 @classmethod
Matt Riedemann75891d82017-10-11 12:10:16 -040049 def setup_credentials(cls):
50 # These tests don't attempt any SSH validation nor do they use
51 # floating IPs on the instance, so all we need is a network and
52 # a subnet so the instance being migrated has a single port, but
53 # we need that to make sure we are properly updating the port
54 # host bindings during the live migration.
55 # TODO(mriedem): SSH validation before and after the instance is
56 # live migrated would be a nice test wrinkle addition.
57 cls.set_network_resources(network=True, subnet=True)
58 super(LiveMigrationTest, cls).setup_credentials()
59
60 @classmethod
Rohan Kanade60b73092015-02-04 17:58:19 +053061 def setup_clients(cls):
Duc Truong09941202017-06-07 10:15:20 -070062 super(LiveMigrationTest, cls).setup_clients()
Jordan Pittier8160d312017-04-18 11:52:23 +020063 cls.admin_migration_client = cls.os_admin.migrations_client
Mate Lakat99ee9142012-09-14 12:34:46 +010064
Claudiu Belu516b7a42016-03-03 06:28:43 -080065 def _migrate_server_to(self, server_id, dest_host, volume_backed=False):
Eli Qiaoe07eacc2016-03-03 13:49:37 +080066 kwargs = dict()
67 block_migration = getattr(self, 'block_migration', None)
68 if self.block_migration is None:
69 kwargs['disk_over_commit'] = False
70 block_migration = (CONF.compute_feature_enabled.
71 block_migration_for_live_migration and
72 not volume_backed)
zhufl4a2cfff2017-01-03 15:45:02 +080073 self.admin_servers_client.live_migrate_server(
Timofey Durakovf358a7e2015-10-05 13:06:51 +030074 server_id, host=dest_host, block_migration=block_migration,
Eli Qiaoe07eacc2016-03-03 13:49:37 +080075 **kwargs)
Mate Lakat99ee9142012-09-14 12:34:46 +010076
Sarafraj Singh61e40452016-09-29 13:06:59 -050077 def _live_migrate(self, server_id, target_host, state,
78 volume_backed=False):
79 self._migrate_server_to(server_id, target_host, volume_backed)
80 waiters.wait_for_server_status(self.servers_client, server_id, state)
81 migration_list = (self.admin_migration_client.list_migrations()
82 ['migrations'])
83
84 msg = ("Live Migration failed. Migrations list for Instance "
85 "%s: [" % server_id)
86 for live_migration in migration_list:
87 if (live_migration['instance_uuid'] == server_id):
88 msg += "\n%s" % live_migration
89 msg += "]"
Duc Truong09941202017-06-07 10:15:20 -070090 self.assertEqual(target_host, self.get_host_for_server(server_id),
Sarafraj Singh61e40452016-09-29 13:06:59 -050091 msg)
92
Joe Gordon8843f0f2015-03-17 15:07:34 -070093 def _test_live_migration(self, state='ACTIVE', volume_backed=False):
94 """Tests live migration between two hosts.
Matt Riedemannbb9f7042015-03-03 08:53:11 -080095
96 Requires CONF.compute_feature_enabled.live_migration to be True.
97
98 :param state: The vm_state the migrated server should be in before and
99 after the live migration. Supported values are 'ACTIVE'
100 and 'PAUSED'.
Joe Gordon8843f0f2015-03-17 15:07:34 -0700101 :param volume_backed: If the instance is volume backed or not. If
102 volume_backed, *block* migration is not used.
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800103 """
Timofey Durakovf358a7e2015-10-05 13:06:51 +0300104 # Live migrate an instance to another host
Jordan Pittier599a3562016-01-08 17:38:14 +0100105 server_id = self.create_test_server(wait_until="ACTIVE",
106 volume_backed=volume_backed)['id']
Duc Truong09941202017-06-07 10:15:20 -0700107 source_host = self.get_host_for_server(server_id)
108 destination_host = self.get_host_other_than(server_id)
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800109
110 if state == 'PAUSED':
111 self.admin_servers_client.pause_server(server_id)
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000112 waiters.wait_for_server_status(self.admin_servers_client,
113 server_id, state)
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800114
Sarafraj Singh61e40452016-09-29 13:06:59 -0500115 LOG.info("Live migrate from source %s to destination %s",
116 source_host, destination_host)
117 self._live_migrate(server_id, destination_host, state, volume_backed)
118 if CONF.compute_feature_enabled.live_migrate_back_and_forth:
119 # If live_migrate_back_and_forth is enabled it is a grenade job.
120 # Therefore test should validate whether LM is compatible in both
121 # ways, so live migrate VM back to the source host
122 LOG.info("Live migrate back to source %s", source_host)
123 self._live_migrate(server_id, source_host, state, volume_backed)
Mate Lakat99ee9142012-09-14 12:34:46 +0100124
Ken'ichi Ohmichiebbfd1c2017-01-27 16:37:00 -0800125 @decorators.idempotent_id('1dce86b8-eb04-4c03-a9d8-9c1dc3ee0c7b')
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800126 def test_live_block_migration(self):
Joe Gordon8843f0f2015-03-17 15:07:34 -0700127 self._test_live_migration()
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800128
Ken'ichi Ohmichiebbfd1c2017-01-27 16:37:00 -0800129 @decorators.idempotent_id('1e107f21-61b2-4988-8f22-b196e938ab88')
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800130 @testtools.skipUnless(CONF.compute_feature_enabled.pause,
131 'Pause is not available.')
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800132 def test_live_block_migration_paused(self):
Joe Gordon8843f0f2015-03-17 15:07:34 -0700133 self._test_live_migration(state='PAUSED')
134
Matt Riedemannea8796a2016-10-15 13:44:09 -0400135 @decorators.skip_because(bug="1524898")
Ken'ichi Ohmichiebbfd1c2017-01-27 16:37:00 -0800136 @decorators.idempotent_id('5071cf17-3004-4257-ae61-73a84e28badd')
Andrea Frittolicd368412017-08-14 21:37:56 +0100137 @utils.services('volume')
Joe Gordon8843f0f2015-03-17 15:07:34 -0700138 def test_volume_backed_live_migration(self):
139 self._test_live_migration(volume_backed=True)
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800140
Ken'ichi Ohmichiebbfd1c2017-01-27 16:37:00 -0800141 @decorators.idempotent_id('e19c0cc6-6720-4ed8-be83-b6603ed5c812')
Timofey Durakovad7aea52015-10-12 13:37:44 +0300142 @testtools.skipIf(not CONF.compute_feature_enabled.
Matthew Treinishd5c96022013-10-17 21:51:23 +0000143 block_migration_for_live_migration,
Bob Ballc078be92013-04-09 14:25:00 +0100144 'Block Live migration not available')
Matthew Treinishd5c96022013-10-17 21:51:23 +0000145 @testtools.skipIf(not CONF.compute_feature_enabled.
146 block_migrate_cinder_iscsi,
Bob Ballc078be92013-04-09 14:25:00 +0100147 'Block Live migration not configured for iSCSI')
148 def test_iscsi_volume(self):
Matt Riedemanncb16a662016-10-01 18:30:05 -0400149 server = self.create_test_server(wait_until="ACTIVE")
150 server_id = server['id']
Duc Truong09941202017-06-07 10:15:20 -0700151 target_host = self.get_host_other_than(server_id)
Bob Ballc078be92013-04-09 14:25:00 +0100152
Matt Riedemanncb16a662016-10-01 18:30:05 -0400153 volume = self.create_volume()
Bob Ballc078be92013-04-09 14:25:00 +0100154
155 # Attach the volume to the server
Matt Riedemanncb16a662016-10-01 18:30:05 -0400156 self.attach_volume(server, volume, device='/dev/xvdb')
lianghao39d86992017-04-11 16:01:26 +0800157 server = self.admin_servers_client.show_server(server_id)['server']
158 volume_id1 = server["os-extended-volumes:volumes_attached"][0]["id"]
Bob Ballc078be92013-04-09 14:25:00 +0100159 self._migrate_server_to(server_id, target_host)
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000160 waiters.wait_for_server_status(self.servers_client,
161 server_id, 'ACTIVE')
lianghao39d86992017-04-11 16:01:26 +0800162
163 server = self.admin_servers_client.show_server(server_id)['server']
164 volume_id2 = server["os-extended-volumes:volumes_attached"][0]["id"]
165
Duc Truong09941202017-06-07 10:15:20 -0700166 self.assertEqual(target_host, self.get_host_for_server(server_id))
lianghao39d86992017-04-11 16:01:26 +0800167 self.assertEqual(volume_id1, volume_id2)
Eli Qiaoe07eacc2016-03-03 13:49:37 +0800168
169
Duc Truong09941202017-06-07 10:15:20 -0700170class LiveMigrationRemoteConsolesV26Test(LiveMigrationTest):
Markus Zoeller69d58b82017-02-17 10:09:22 +0100171 min_microversion = '2.6'
172 max_microversion = 'latest'
173
174 @decorators.idempotent_id('6190af80-513e-4f0f-90f2-9714e84955d7')
175 @testtools.skipUnless(CONF.compute_feature_enabled.serial_console,
176 'Serial console not supported.')
177 @testtools.skipUnless(
Andrea Frittoli88eb6772017-08-07 21:06:27 +0100178 compute.is_scheduler_filter_enabled("DifferentHostFilter"),
Markus Zoeller69d58b82017-02-17 10:09:22 +0100179 'DifferentHostFilter is not available.')
180 def test_live_migration_serial_console(self):
181 """Test the live-migration of an instance which has a serial console
182
183 The serial console feature of an instance uses ports on the host.
184 These ports need to be updated when they are already in use by
185 another instance on the target host. This test checks if this
186 update behavior is correctly done, by connecting to the serial
187 consoles of the instances before and after the live migration.
188 """
189 server01_id = self.create_test_server(wait_until='ACTIVE')['id']
190 hints = {'different_host': server01_id}
191 server02_id = self.create_test_server(scheduler_hints=hints,
192 wait_until='ACTIVE')['id']
Duc Truong09941202017-06-07 10:15:20 -0700193 host01_id = self.get_host_for_server(server01_id)
194 host02_id = self.get_host_for_server(server02_id)
Markus Zoeller69d58b82017-02-17 10:09:22 +0100195 self.assertNotEqual(host01_id, host02_id)
196
197 # At this step we have 2 instances on different hosts, both with
198 # serial consoles, both with port 10000 (the default value).
199 # https://bugs.launchpad.net/nova/+bug/1455252 describes the issue
200 # when live-migrating in such a scenario.
201
202 self._verify_console_interaction(server01_id)
203 self._verify_console_interaction(server02_id)
204
205 self._migrate_server_to(server01_id, host02_id)
206 waiters.wait_for_server_status(self.servers_client,
207 server01_id, 'ACTIVE')
Duc Truong09941202017-06-07 10:15:20 -0700208 self.assertEqual(host02_id, self.get_host_for_server(server01_id))
Markus Zoeller69d58b82017-02-17 10:09:22 +0100209 self._verify_console_interaction(server01_id)
210 # At this point, both instances have a valid serial console
211 # connection, which means the ports got updated.
212
213 def _verify_console_interaction(self, server_id):
214 body = self.servers_client.get_remote_console(server_id,
215 console_type='serial',
216 protocol='serial')
217 console_url = body['remote_console']['url']
218 data = "test_live_migration_serial_console"
219 console_output = ''
220 t = 0.0
221 interval = 0.1
222
223 ws = compute.create_websocket(console_url)
224 try:
225 # NOTE (markus_z): It can take a long time until the terminal
226 # of the instance is available for interaction. Hence the
227 # long timeout value.
228 while data not in console_output and t <= 120.0:
229 try:
230 ws.send_frame(data)
231 recieved = ws.receive_frame()
232 console_output += recieved
233 except Exception:
234 # In case we had an issue with send/receive on the
235 # websocket connection, we create a new one.
236 ws = compute.create_websocket(console_url)
237 time.sleep(interval)
238 t += interval
239 finally:
240 ws.close()
241 self.assertIn(data, console_output)
242
243
Duc Truong09941202017-06-07 10:15:20 -0700244class LiveAutoBlockMigrationV225Test(LiveMigrationTest):
Eli Qiaoe07eacc2016-03-03 13:49:37 +0800245 min_microversion = '2.25'
246 max_microversion = 'latest'
247 block_migration = 'auto'