blob: 5005346e3791da9ac58f9ba14de10df928e986a0 [file] [log] [blame]
scottda61f68ac2016-06-07 12:07:55 -06001# 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
13from oslo_log import log as logging
14
Andrea Frittolicd368412017-08-14 21:37:56 +010015from tempest.common import utils
scottda61f68ac2016-06-07 12:07:55 -060016from tempest.common import waiters
17from tempest import config
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -080018from tempest.lib import decorators
scottda61f68ac2016-06-07 12:07:55 -060019from tempest.scenario import manager
scottda61f68ac2016-06-07 12:07:55 -060020
21CONF = config.CONF
22LOG = logging.getLogger(__name__)
23
24
25class TestVolumeMigrateRetypeAttached(manager.ScenarioTest):
26
27 """This test case attempts to reproduce the following steps:
28
29 * Create 2 volume types representing 2 different backends
30 * Create in Cinder some bootable volume importing a Glance image using
31 * volume_type_1
32 * Boot an instance from the bootable volume
33 * Write to the volume
34 * Perform a cinder retype --on-demand of the volume to type of backend #2
35 * Check written content of migrated volume
Lee Yarwood8df5fdc2019-02-26 13:19:53 +000036 * Check the type of the volume has been updated.
37 * Check the volume is still in-use and the migration was successful.
38 * Check that the same volume is attached to the instance.
scottda61f68ac2016-06-07 12:07:55 -060039 """
40
41 credentials = ['primary', 'admin']
42
43 @classmethod
Mohammed Naser65e4f9b2017-12-29 21:22:24 +000044 def setup_clients(cls):
45 super(TestVolumeMigrateRetypeAttached, cls).setup_clients()
ghanshyam6c682ff2018-08-06 09:54:45 +000046 cls.admin_volumes_client = cls.os_admin.volumes_client_latest
Mohammed Naser65e4f9b2017-12-29 21:22:24 +000047
48 @classmethod
scottda61f68ac2016-06-07 12:07:55 -060049 def skip_checks(cls):
50 super(TestVolumeMigrateRetypeAttached, cls).skip_checks()
Ghanshyam Mann2803b572023-08-04 12:11:59 -070051 if not CONF.service_available.cinder:
52 raise cls.skipException("Cinder is not available")
scottda61f68ac2016-06-07 12:07:55 -060053 if not CONF.volume_feature_enabled.multi_backend:
54 raise cls.skipException("Cinder multi-backend feature disabled")
55
56 if len(set(CONF.volume.backend_names)) < 2:
57 raise cls.skipException("Requires at least two different "
58 "backend names")
59
60 def _boot_instance_from_volume(self, vol_id, keypair, security_group):
61
62 key_name = keypair['name']
63 security_groups = [{'name': security_group['name']}]
64 block_device_mapping = [{'device_name': 'vda', 'volume_id': vol_id,
65 'delete_on_termination': False}]
66
zhufl13c9c892017-02-10 12:04:07 +080067 return self.create_server(image_id='',
scottda61f68ac2016-06-07 12:07:55 -060068 key_name=key_name,
69 security_groups=security_groups,
70 block_device_mapping=block_device_mapping)
71
72 def _create_volume_types(self):
73 backend_names = CONF.volume.backend_names
74
75 backend_source = backend_names[0]
76 backend_dest = backend_names[1]
77
78 source_body = self.create_volume_type(backend_name=backend_source)
79 dest_body = self.create_volume_type(backend_name=backend_dest)
80
81 LOG.info("Created Volume types: %(src)s -> %(src_backend)s, %(dst)s "
82 "-> %(dst_backend)s", {'src': source_body['name'],
83 'src_backend': backend_source,
84 'dst': dest_body['name'],
85 'dst_backend': backend_dest})
Lee Yarwood8df5fdc2019-02-26 13:19:53 +000086 return ({'name': source_body['name'], 'host': backend_source},
87 {'name': dest_body['name'], 'host': backend_dest})
scottda61f68ac2016-06-07 12:07:55 -060088
89 def _volume_retype_with_migration(self, volume_id, new_volume_type):
Ken'ichi Ohmichid513a7f2018-01-04 12:55:08 -080090 # NOTE: The 'on-demand' migration requires admin operation, so
91 # admin_volumes_client() should be used here.
scottda61f68ac2016-06-07 12:07:55 -060092 migration_policy = 'on-demand'
Mohammed Naser65e4f9b2017-12-29 21:22:24 +000093 self.admin_volumes_client.retype_volume(
scottda61f68ac2016-06-07 12:07:55 -060094 volume_id, new_type=new_volume_type,
95 migration_policy=migration_policy)
96 waiters.wait_for_volume_retype(self.volumes_client,
97 volume_id, new_volume_type)
98
Jordan Pittier3b46d272017-04-12 16:17:28 +020099 @decorators.attr(type='slow')
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800100 @decorators.idempotent_id('deadd2c2-beef-4dce-98be-f86765ff311b')
Andrea Frittolicd368412017-08-14 21:37:56 +0100101 @utils.services('compute', 'volume')
Lee Yarwoode5597402019-02-15 20:17:00 +0000102 def test_volume_retype_attached(self):
scottda61f68ac2016-06-07 12:07:55 -0600103 LOG.info("Creating keypair and security group")
104 keypair = self.create_keypair()
Soniya Vyas582c1702021-02-22 18:26:17 +0530105 security_group = self.create_security_group()
scottda61f68ac2016-06-07 12:07:55 -0600106
107 # create volume types
108 LOG.info("Creating Volume types")
109 source_type, dest_type = self._create_volume_types()
110
111 # create an instance from volume
112 LOG.info("Booting instance from volume")
Lee Yarwood8df5fdc2019-02-26 13:19:53 +0000113 volume_id = self.create_volume(imageRef=CONF.compute.image_ref,
114 volume_type=source_type['name'])['id']
scottda61f68ac2016-06-07 12:07:55 -0600115
Lee Yarwood8df5fdc2019-02-26 13:19:53 +0000116 instance = self._boot_instance_from_volume(volume_id, keypair,
117 security_group)
scottda61f68ac2016-06-07 12:07:55 -0600118
119 # write content to volume on instance
120 LOG.info("Setting timestamp in instance %s", instance['id'])
121 ip_instance = self.get_server_ip(instance)
122 timestamp = self.create_timestamp(ip_instance,
Slawek Kaplonski79d8b0f2018-07-30 22:43:41 +0200123 private_key=keypair['private_key'],
124 server=instance)
scottda61f68ac2016-06-07 12:07:55 -0600125
126 # retype volume with migration from backend #1 to backend #2
Lee Yarwood8df5fdc2019-02-26 13:19:53 +0000127 LOG.info("Retyping Volume %s to new type %s", volume_id,
128 dest_type['name'])
129 # This method calls for the retype of the volume before calling a
130 # waiter that asserts that the volume type has changed successfully.
131 self._volume_retype_with_migration(volume_id, dest_type['name'])
scottda61f68ac2016-06-07 12:07:55 -0600132
133 # check the content of written file
134 LOG.info("Getting timestamp in postmigrated instance %s",
135 instance['id'])
136 timestamp2 = self.get_timestamp(ip_instance,
Slawek Kaplonski79d8b0f2018-07-30 22:43:41 +0200137 private_key=keypair['private_key'],
138 server=instance)
scottda61f68ac2016-06-07 12:07:55 -0600139 self.assertEqual(timestamp, timestamp2)
Lee Yarwood8df5fdc2019-02-26 13:19:53 +0000140
141 # Assert that the volume is on the new host, is still in-use and has a
142 # migration_status of success
143 volume = self.admin_volumes_client.show_volume(volume_id)['volume']
144 # dest_type is host@backend, os-vol-host-attr:host is host@backend#type
145 self.assertIn(dest_type['host'], volume['os-vol-host-attr:host'])
146 self.assertEqual('in-use', volume['status'])
147 self.assertEqual('success', volume['migration_status'])
148
149 # Assert that the same volume id is attached to the instance, ensuring
150 # the os-migrate_volume_completion Cinder API has been called.
151 attached_volumes = self.servers_client.list_volume_attachments(
152 instance['id'])['volumeAttachments']
153 self.assertEqual(volume_id, attached_volumes[0]['id'])
Lee Yarwoode5597402019-02-15 20:17:00 +0000154
155 @decorators.attr(type='slow')
156 @decorators.idempotent_id('fe47b1ed-640e-4e3b-a090-200e25607362')
157 @utils.services('compute', 'volume')
158 def test_volume_migrate_attached(self):
159 LOG.info("Creating keypair and security group")
160 keypair = self.create_keypair()
Soniya Vyas582c1702021-02-22 18:26:17 +0530161 security_group = self.create_security_group()
Lee Yarwoode5597402019-02-15 20:17:00 +0000162
163 LOG.info("Creating volume")
164 # Create a unique volume type to avoid using the backend default
165 migratable_type = self.create_volume_type()['name']
166 volume_id = self.create_volume(imageRef=CONF.compute.image_ref,
167 volume_type=migratable_type)['id']
168 volume = self.admin_volumes_client.show_volume(volume_id)
169
170 LOG.info("Booting instance from volume")
171 instance = self._boot_instance_from_volume(volume_id, keypair,
172 security_group)
173
174 # Identify the source and destination hosts for the migration
175 src_host = volume['volume']['os-vol-host-attr:host']
176
177 # Select the first c-vol host that isn't hosting the volume as the dest
178 # host['host_name'] should take the format of host@backend.
179 # src_host should take the format of host@backend#type
180 hosts = self.admin_volumes_client.list_hosts()['hosts']
181 for host in hosts:
182 if (host['service'] == 'cinder-volume' and
183 not src_host.startswith(host['host_name'])):
184 dest_host = host['host_name']
185 break
186
187 ip_instance = self.get_server_ip(instance)
188 timestamp = self.create_timestamp(ip_instance,
189 private_key=keypair['private_key'],
190 server=instance)
191
192 LOG.info("Migrating Volume %s from host %s to host %s",
193 volume_id, src_host, dest_host)
194 self.admin_volumes_client.migrate_volume(volume_id, host=dest_host)
195
196 # This waiter asserts that the migration_status is success and that
197 # the volume has moved to the dest_host
198 waiters.wait_for_volume_migration(self.admin_volumes_client, volume_id,
199 dest_host)
200
201 # check the content of written file
202 LOG.info("Getting timestamp in postmigrated instance %s",
203 instance['id'])
204 timestamp2 = self.get_timestamp(ip_instance,
205 private_key=keypair['private_key'],
206 server=instance)
207 self.assertEqual(timestamp, timestamp2)
208
209 # Assert that the volume is in-use
210 volume = self.admin_volumes_client.show_volume(volume_id)['volume']
211 self.assertEqual('in-use', volume['status'])
212
213 # Assert that the same volume id is attached to the instance, ensuring
214 # the os-migrate_volume_completion Cinder API has been called
215 attached_volumes = self.servers_client.list_volume_attachments(
216 instance['id'])['volumeAttachments']
217 attached_volume_id = attached_volumes[0]['id']
218 self.assertEqual(volume_id, attached_volume_id)