blob: 705e567e925915ab6e4b6a190e8dc3b46649d550 [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
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +000023from tempest.common import waiters
Mate Lakat99ee9142012-09-14 12:34:46 +010024from tempest import config
Brian Haleya3879b52016-02-24 16:53:47 -060025from tempest.lib import decorators
Yuiko Takadae9999d62014-03-06 09:22:54 +000026from tempest import test
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
Rohan Kanade60b73092015-02-04 17:58:19 +053049 def setup_clients(cls):
Duc Truong09941202017-06-07 10:15:20 -070050 super(LiveMigrationTest, cls).setup_clients()
Jordan Pittier8160d312017-04-18 11:52:23 +020051 cls.admin_hosts_client = cls.os_admin.hosts_client
52 cls.admin_migration_client = cls.os_admin.migrations_client
Mate Lakat99ee9142012-09-14 12:34:46 +010053
Claudiu Belu516b7a42016-03-03 06:28:43 -080054 def _migrate_server_to(self, server_id, dest_host, volume_backed=False):
Eli Qiaoe07eacc2016-03-03 13:49:37 +080055 kwargs = dict()
56 block_migration = getattr(self, 'block_migration', None)
57 if self.block_migration is None:
58 kwargs['disk_over_commit'] = False
59 block_migration = (CONF.compute_feature_enabled.
60 block_migration_for_live_migration and
61 not volume_backed)
zhufl4a2cfff2017-01-03 15:45:02 +080062 self.admin_servers_client.live_migrate_server(
Timofey Durakovf358a7e2015-10-05 13:06:51 +030063 server_id, host=dest_host, block_migration=block_migration,
Eli Qiaoe07eacc2016-03-03 13:49:37 +080064 **kwargs)
Mate Lakat99ee9142012-09-14 12:34:46 +010065
Sarafraj Singh61e40452016-09-29 13:06:59 -050066 def _live_migrate(self, server_id, target_host, state,
67 volume_backed=False):
68 self._migrate_server_to(server_id, target_host, volume_backed)
69 waiters.wait_for_server_status(self.servers_client, server_id, state)
70 migration_list = (self.admin_migration_client.list_migrations()
71 ['migrations'])
72
73 msg = ("Live Migration failed. Migrations list for Instance "
74 "%s: [" % server_id)
75 for live_migration in migration_list:
76 if (live_migration['instance_uuid'] == server_id):
77 msg += "\n%s" % live_migration
78 msg += "]"
Duc Truong09941202017-06-07 10:15:20 -070079 self.assertEqual(target_host, self.get_host_for_server(server_id),
Sarafraj Singh61e40452016-09-29 13:06:59 -050080 msg)
81
Joe Gordon8843f0f2015-03-17 15:07:34 -070082 def _test_live_migration(self, state='ACTIVE', volume_backed=False):
83 """Tests live migration between two hosts.
Matt Riedemannbb9f7042015-03-03 08:53:11 -080084
85 Requires CONF.compute_feature_enabled.live_migration to be True.
86
87 :param state: The vm_state the migrated server should be in before and
88 after the live migration. Supported values are 'ACTIVE'
89 and 'PAUSED'.
Joe Gordon8843f0f2015-03-17 15:07:34 -070090 :param volume_backed: If the instance is volume backed or not. If
91 volume_backed, *block* migration is not used.
Matt Riedemannbb9f7042015-03-03 08:53:11 -080092 """
Timofey Durakovf358a7e2015-10-05 13:06:51 +030093 # Live migrate an instance to another host
Jordan Pittier599a3562016-01-08 17:38:14 +010094 server_id = self.create_test_server(wait_until="ACTIVE",
95 volume_backed=volume_backed)['id']
Duc Truong09941202017-06-07 10:15:20 -070096 source_host = self.get_host_for_server(server_id)
97 destination_host = self.get_host_other_than(server_id)
Matt Riedemannbb9f7042015-03-03 08:53:11 -080098
99 if state == 'PAUSED':
100 self.admin_servers_client.pause_server(server_id)
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000101 waiters.wait_for_server_status(self.admin_servers_client,
102 server_id, state)
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800103
Sarafraj Singh61e40452016-09-29 13:06:59 -0500104 LOG.info("Live migrate from source %s to destination %s",
105 source_host, destination_host)
106 self._live_migrate(server_id, destination_host, state, volume_backed)
107 if CONF.compute_feature_enabled.live_migrate_back_and_forth:
108 # If live_migrate_back_and_forth is enabled it is a grenade job.
109 # Therefore test should validate whether LM is compatible in both
110 # ways, so live migrate VM back to the source host
111 LOG.info("Live migrate back to source %s", source_host)
112 self._live_migrate(server_id, source_host, state, volume_backed)
Mate Lakat99ee9142012-09-14 12:34:46 +0100113
Ken'ichi Ohmichiebbfd1c2017-01-27 16:37:00 -0800114 @decorators.idempotent_id('1dce86b8-eb04-4c03-a9d8-9c1dc3ee0c7b')
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800115 def test_live_block_migration(self):
Joe Gordon8843f0f2015-03-17 15:07:34 -0700116 self._test_live_migration()
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800117
Ken'ichi Ohmichiebbfd1c2017-01-27 16:37:00 -0800118 @decorators.idempotent_id('1e107f21-61b2-4988-8f22-b196e938ab88')
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800119 @testtools.skipUnless(CONF.compute_feature_enabled.pause,
120 'Pause is not available.')
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800121 def test_live_block_migration_paused(self):
Joe Gordon8843f0f2015-03-17 15:07:34 -0700122 self._test_live_migration(state='PAUSED')
123
Matt Riedemannea8796a2016-10-15 13:44:09 -0400124 @decorators.skip_because(bug="1524898")
Ken'ichi Ohmichiebbfd1c2017-01-27 16:37:00 -0800125 @decorators.idempotent_id('5071cf17-3004-4257-ae61-73a84e28badd')
Joe Gordon8843f0f2015-03-17 15:07:34 -0700126 @test.services('volume')
127 def test_volume_backed_live_migration(self):
128 self._test_live_migration(volume_backed=True)
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800129
Ken'ichi Ohmichiebbfd1c2017-01-27 16:37:00 -0800130 @decorators.idempotent_id('e19c0cc6-6720-4ed8-be83-b6603ed5c812')
Timofey Durakovad7aea52015-10-12 13:37:44 +0300131 @testtools.skipIf(not CONF.compute_feature_enabled.
Matthew Treinishd5c96022013-10-17 21:51:23 +0000132 block_migration_for_live_migration,
Bob Ballc078be92013-04-09 14:25:00 +0100133 'Block Live migration not available')
Matthew Treinishd5c96022013-10-17 21:51:23 +0000134 @testtools.skipIf(not CONF.compute_feature_enabled.
135 block_migrate_cinder_iscsi,
Bob Ballc078be92013-04-09 14:25:00 +0100136 'Block Live migration not configured for iSCSI')
137 def test_iscsi_volume(self):
Matt Riedemanncb16a662016-10-01 18:30:05 -0400138 server = self.create_test_server(wait_until="ACTIVE")
139 server_id = server['id']
Duc Truong09941202017-06-07 10:15:20 -0700140 target_host = self.get_host_other_than(server_id)
Bob Ballc078be92013-04-09 14:25:00 +0100141
Matt Riedemanncb16a662016-10-01 18:30:05 -0400142 volume = self.create_volume()
Bob Ballc078be92013-04-09 14:25:00 +0100143
144 # Attach the volume to the server
Matt Riedemanncb16a662016-10-01 18:30:05 -0400145 self.attach_volume(server, volume, device='/dev/xvdb')
lianghao39d86992017-04-11 16:01:26 +0800146 server = self.admin_servers_client.show_server(server_id)['server']
147 volume_id1 = server["os-extended-volumes:volumes_attached"][0]["id"]
Bob Ballc078be92013-04-09 14:25:00 +0100148 self._migrate_server_to(server_id, target_host)
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000149 waiters.wait_for_server_status(self.servers_client,
150 server_id, 'ACTIVE')
lianghao39d86992017-04-11 16:01:26 +0800151
152 server = self.admin_servers_client.show_server(server_id)['server']
153 volume_id2 = server["os-extended-volumes:volumes_attached"][0]["id"]
154
Duc Truong09941202017-06-07 10:15:20 -0700155 self.assertEqual(target_host, self.get_host_for_server(server_id))
lianghao39d86992017-04-11 16:01:26 +0800156 self.assertEqual(volume_id1, volume_id2)
Eli Qiaoe07eacc2016-03-03 13:49:37 +0800157
158
Duc Truong09941202017-06-07 10:15:20 -0700159class LiveMigrationRemoteConsolesV26Test(LiveMigrationTest):
Markus Zoeller69d58b82017-02-17 10:09:22 +0100160 min_microversion = '2.6'
161 max_microversion = 'latest'
162
163 @decorators.idempotent_id('6190af80-513e-4f0f-90f2-9714e84955d7')
164 @testtools.skipUnless(CONF.compute_feature_enabled.serial_console,
165 'Serial console not supported.')
166 @testtools.skipUnless(
167 test.is_scheduler_filter_enabled("DifferentHostFilter"),
168 'DifferentHostFilter is not available.')
169 def test_live_migration_serial_console(self):
170 """Test the live-migration of an instance which has a serial console
171
172 The serial console feature of an instance uses ports on the host.
173 These ports need to be updated when they are already in use by
174 another instance on the target host. This test checks if this
175 update behavior is correctly done, by connecting to the serial
176 consoles of the instances before and after the live migration.
177 """
178 server01_id = self.create_test_server(wait_until='ACTIVE')['id']
179 hints = {'different_host': server01_id}
180 server02_id = self.create_test_server(scheduler_hints=hints,
181 wait_until='ACTIVE')['id']
Duc Truong09941202017-06-07 10:15:20 -0700182 host01_id = self.get_host_for_server(server01_id)
183 host02_id = self.get_host_for_server(server02_id)
Markus Zoeller69d58b82017-02-17 10:09:22 +0100184 self.assertNotEqual(host01_id, host02_id)
185
186 # At this step we have 2 instances on different hosts, both with
187 # serial consoles, both with port 10000 (the default value).
188 # https://bugs.launchpad.net/nova/+bug/1455252 describes the issue
189 # when live-migrating in such a scenario.
190
191 self._verify_console_interaction(server01_id)
192 self._verify_console_interaction(server02_id)
193
194 self._migrate_server_to(server01_id, host02_id)
195 waiters.wait_for_server_status(self.servers_client,
196 server01_id, 'ACTIVE')
Duc Truong09941202017-06-07 10:15:20 -0700197 self.assertEqual(host02_id, self.get_host_for_server(server01_id))
Markus Zoeller69d58b82017-02-17 10:09:22 +0100198 self._verify_console_interaction(server01_id)
199 # At this point, both instances have a valid serial console
200 # connection, which means the ports got updated.
201
202 def _verify_console_interaction(self, server_id):
203 body = self.servers_client.get_remote_console(server_id,
204 console_type='serial',
205 protocol='serial')
206 console_url = body['remote_console']['url']
207 data = "test_live_migration_serial_console"
208 console_output = ''
209 t = 0.0
210 interval = 0.1
211
212 ws = compute.create_websocket(console_url)
213 try:
214 # NOTE (markus_z): It can take a long time until the terminal
215 # of the instance is available for interaction. Hence the
216 # long timeout value.
217 while data not in console_output and t <= 120.0:
218 try:
219 ws.send_frame(data)
220 recieved = ws.receive_frame()
221 console_output += recieved
222 except Exception:
223 # In case we had an issue with send/receive on the
224 # websocket connection, we create a new one.
225 ws = compute.create_websocket(console_url)
226 time.sleep(interval)
227 t += interval
228 finally:
229 ws.close()
230 self.assertIn(data, console_output)
231
232
Duc Truong09941202017-06-07 10:15:20 -0700233class LiveAutoBlockMigrationV225Test(LiveMigrationTest):
Eli Qiaoe07eacc2016-03-03 13:49:37 +0800234 min_microversion = '2.25'
235 max_microversion = 'latest'
236 block_migration = 'auto'