blob: 14be9476486618fa5b2d30348dc0b2e7c7b1f54b [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
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_migration_client = cls.os_admin.migrations_client
Mate Lakat99ee9142012-09-14 12:34:46 +010052
Claudiu Belu516b7a42016-03-03 06:28:43 -080053 def _migrate_server_to(self, server_id, dest_host, volume_backed=False):
Eli Qiaoe07eacc2016-03-03 13:49:37 +080054 kwargs = dict()
55 block_migration = getattr(self, 'block_migration', None)
56 if self.block_migration is None:
57 kwargs['disk_over_commit'] = False
58 block_migration = (CONF.compute_feature_enabled.
59 block_migration_for_live_migration and
60 not volume_backed)
zhufl4a2cfff2017-01-03 15:45:02 +080061 self.admin_servers_client.live_migrate_server(
Timofey Durakovf358a7e2015-10-05 13:06:51 +030062 server_id, host=dest_host, block_migration=block_migration,
Eli Qiaoe07eacc2016-03-03 13:49:37 +080063 **kwargs)
Mate Lakat99ee9142012-09-14 12:34:46 +010064
Sarafraj Singh61e40452016-09-29 13:06:59 -050065 def _live_migrate(self, server_id, target_host, state,
66 volume_backed=False):
67 self._migrate_server_to(server_id, target_host, volume_backed)
68 waiters.wait_for_server_status(self.servers_client, server_id, state)
69 migration_list = (self.admin_migration_client.list_migrations()
70 ['migrations'])
71
72 msg = ("Live Migration failed. Migrations list for Instance "
73 "%s: [" % server_id)
74 for live_migration in migration_list:
75 if (live_migration['instance_uuid'] == server_id):
76 msg += "\n%s" % live_migration
77 msg += "]"
Duc Truong09941202017-06-07 10:15:20 -070078 self.assertEqual(target_host, self.get_host_for_server(server_id),
Sarafraj Singh61e40452016-09-29 13:06:59 -050079 msg)
80
Joe Gordon8843f0f2015-03-17 15:07:34 -070081 def _test_live_migration(self, state='ACTIVE', volume_backed=False):
82 """Tests live migration between two hosts.
Matt Riedemannbb9f7042015-03-03 08:53:11 -080083
84 Requires CONF.compute_feature_enabled.live_migration to be True.
85
86 :param state: The vm_state the migrated server should be in before and
87 after the live migration. Supported values are 'ACTIVE'
88 and 'PAUSED'.
Joe Gordon8843f0f2015-03-17 15:07:34 -070089 :param volume_backed: If the instance is volume backed or not. If
90 volume_backed, *block* migration is not used.
Matt Riedemannbb9f7042015-03-03 08:53:11 -080091 """
Timofey Durakovf358a7e2015-10-05 13:06:51 +030092 # Live migrate an instance to another host
Jordan Pittier599a3562016-01-08 17:38:14 +010093 server_id = self.create_test_server(wait_until="ACTIVE",
94 volume_backed=volume_backed)['id']
Duc Truong09941202017-06-07 10:15:20 -070095 source_host = self.get_host_for_server(server_id)
96 destination_host = self.get_host_other_than(server_id)
Matt Riedemannbb9f7042015-03-03 08:53:11 -080097
98 if state == 'PAUSED':
99 self.admin_servers_client.pause_server(server_id)
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000100 waiters.wait_for_server_status(self.admin_servers_client,
101 server_id, state)
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800102
Sarafraj Singh61e40452016-09-29 13:06:59 -0500103 LOG.info("Live migrate from source %s to destination %s",
104 source_host, destination_host)
105 self._live_migrate(server_id, destination_host, state, volume_backed)
106 if CONF.compute_feature_enabled.live_migrate_back_and_forth:
107 # If live_migrate_back_and_forth is enabled it is a grenade job.
108 # Therefore test should validate whether LM is compatible in both
109 # ways, so live migrate VM back to the source host
110 LOG.info("Live migrate back to source %s", source_host)
111 self._live_migrate(server_id, source_host, state, volume_backed)
Mate Lakat99ee9142012-09-14 12:34:46 +0100112
Ken'ichi Ohmichiebbfd1c2017-01-27 16:37:00 -0800113 @decorators.idempotent_id('1dce86b8-eb04-4c03-a9d8-9c1dc3ee0c7b')
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800114 def test_live_block_migration(self):
Joe Gordon8843f0f2015-03-17 15:07:34 -0700115 self._test_live_migration()
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800116
Ken'ichi Ohmichiebbfd1c2017-01-27 16:37:00 -0800117 @decorators.idempotent_id('1e107f21-61b2-4988-8f22-b196e938ab88')
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800118 @testtools.skipUnless(CONF.compute_feature_enabled.pause,
119 'Pause is not available.')
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800120 def test_live_block_migration_paused(self):
Joe Gordon8843f0f2015-03-17 15:07:34 -0700121 self._test_live_migration(state='PAUSED')
122
Matt Riedemannea8796a2016-10-15 13:44:09 -0400123 @decorators.skip_because(bug="1524898")
Ken'ichi Ohmichiebbfd1c2017-01-27 16:37:00 -0800124 @decorators.idempotent_id('5071cf17-3004-4257-ae61-73a84e28badd')
Andrea Frittolicd368412017-08-14 21:37:56 +0100125 @utils.services('volume')
Joe Gordon8843f0f2015-03-17 15:07:34 -0700126 def test_volume_backed_live_migration(self):
127 self._test_live_migration(volume_backed=True)
Matt Riedemannbb9f7042015-03-03 08:53:11 -0800128
Ken'ichi Ohmichiebbfd1c2017-01-27 16:37:00 -0800129 @decorators.idempotent_id('e19c0cc6-6720-4ed8-be83-b6603ed5c812')
Timofey Durakovad7aea52015-10-12 13:37:44 +0300130 @testtools.skipIf(not CONF.compute_feature_enabled.
Matthew Treinishd5c96022013-10-17 21:51:23 +0000131 block_migration_for_live_migration,
Bob Ballc078be92013-04-09 14:25:00 +0100132 'Block Live migration not available')
Matthew Treinishd5c96022013-10-17 21:51:23 +0000133 @testtools.skipIf(not CONF.compute_feature_enabled.
134 block_migrate_cinder_iscsi,
Bob Ballc078be92013-04-09 14:25:00 +0100135 'Block Live migration not configured for iSCSI')
136 def test_iscsi_volume(self):
Matt Riedemanncb16a662016-10-01 18:30:05 -0400137 server = self.create_test_server(wait_until="ACTIVE")
138 server_id = server['id']
Duc Truong09941202017-06-07 10:15:20 -0700139 target_host = self.get_host_other_than(server_id)
Bob Ballc078be92013-04-09 14:25:00 +0100140
Matt Riedemanncb16a662016-10-01 18:30:05 -0400141 volume = self.create_volume()
Bob Ballc078be92013-04-09 14:25:00 +0100142
143 # Attach the volume to the server
Matt Riedemanncb16a662016-10-01 18:30:05 -0400144 self.attach_volume(server, volume, device='/dev/xvdb')
lianghao39d86992017-04-11 16:01:26 +0800145 server = self.admin_servers_client.show_server(server_id)['server']
146 volume_id1 = server["os-extended-volumes:volumes_attached"][0]["id"]
Bob Ballc078be92013-04-09 14:25:00 +0100147 self._migrate_server_to(server_id, target_host)
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000148 waiters.wait_for_server_status(self.servers_client,
149 server_id, 'ACTIVE')
lianghao39d86992017-04-11 16:01:26 +0800150
151 server = self.admin_servers_client.show_server(server_id)['server']
152 volume_id2 = server["os-extended-volumes:volumes_attached"][0]["id"]
153
Duc Truong09941202017-06-07 10:15:20 -0700154 self.assertEqual(target_host, self.get_host_for_server(server_id))
lianghao39d86992017-04-11 16:01:26 +0800155 self.assertEqual(volume_id1, volume_id2)
Eli Qiaoe07eacc2016-03-03 13:49:37 +0800156
157
Duc Truong09941202017-06-07 10:15:20 -0700158class LiveMigrationRemoteConsolesV26Test(LiveMigrationTest):
Markus Zoeller69d58b82017-02-17 10:09:22 +0100159 min_microversion = '2.6'
160 max_microversion = 'latest'
161
162 @decorators.idempotent_id('6190af80-513e-4f0f-90f2-9714e84955d7')
163 @testtools.skipUnless(CONF.compute_feature_enabled.serial_console,
164 'Serial console not supported.')
165 @testtools.skipUnless(
Andrea Frittoli88eb6772017-08-07 21:06:27 +0100166 compute.is_scheduler_filter_enabled("DifferentHostFilter"),
Markus Zoeller69d58b82017-02-17 10:09:22 +0100167 'DifferentHostFilter is not available.')
168 def test_live_migration_serial_console(self):
169 """Test the live-migration of an instance which has a serial console
170
171 The serial console feature of an instance uses ports on the host.
172 These ports need to be updated when they are already in use by
173 another instance on the target host. This test checks if this
174 update behavior is correctly done, by connecting to the serial
175 consoles of the instances before and after the live migration.
176 """
177 server01_id = self.create_test_server(wait_until='ACTIVE')['id']
178 hints = {'different_host': server01_id}
179 server02_id = self.create_test_server(scheduler_hints=hints,
180 wait_until='ACTIVE')['id']
Duc Truong09941202017-06-07 10:15:20 -0700181 host01_id = self.get_host_for_server(server01_id)
182 host02_id = self.get_host_for_server(server02_id)
Markus Zoeller69d58b82017-02-17 10:09:22 +0100183 self.assertNotEqual(host01_id, host02_id)
184
185 # At this step we have 2 instances on different hosts, both with
186 # serial consoles, both with port 10000 (the default value).
187 # https://bugs.launchpad.net/nova/+bug/1455252 describes the issue
188 # when live-migrating in such a scenario.
189
190 self._verify_console_interaction(server01_id)
191 self._verify_console_interaction(server02_id)
192
193 self._migrate_server_to(server01_id, host02_id)
194 waiters.wait_for_server_status(self.servers_client,
195 server01_id, 'ACTIVE')
Duc Truong09941202017-06-07 10:15:20 -0700196 self.assertEqual(host02_id, self.get_host_for_server(server01_id))
Markus Zoeller69d58b82017-02-17 10:09:22 +0100197 self._verify_console_interaction(server01_id)
198 # At this point, both instances have a valid serial console
199 # connection, which means the ports got updated.
200
201 def _verify_console_interaction(self, server_id):
202 body = self.servers_client.get_remote_console(server_id,
203 console_type='serial',
204 protocol='serial')
205 console_url = body['remote_console']['url']
206 data = "test_live_migration_serial_console"
207 console_output = ''
208 t = 0.0
209 interval = 0.1
210
211 ws = compute.create_websocket(console_url)
212 try:
213 # NOTE (markus_z): It can take a long time until the terminal
214 # of the instance is available for interaction. Hence the
215 # long timeout value.
216 while data not in console_output and t <= 120.0:
217 try:
218 ws.send_frame(data)
219 recieved = ws.receive_frame()
220 console_output += recieved
221 except Exception:
222 # In case we had an issue with send/receive on the
223 # websocket connection, we create a new one.
224 ws = compute.create_websocket(console_url)
225 time.sleep(interval)
226 t += interval
227 finally:
228 ws.close()
229 self.assertIn(data, console_output)
230
231
Duc Truong09941202017-06-07 10:15:20 -0700232class LiveAutoBlockMigrationV225Test(LiveMigrationTest):
Eli Qiaoe07eacc2016-03-03 13:49:37 +0800233 min_microversion = '2.25'
234 max_microversion = 'latest'
235 block_migration = 'auto'