blob: 7ea8f0968eab8753813e44fadca3b3d555a74b08 [file] [log] [blame]
Matt Riedemannbc8dbd32013-08-02 14:02:12 -07001# Copyright 2013 IBM Corp.
Dan Smithc18d8c62012-07-02 08:09:26 -07002# 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
Steve Noyes83a14122018-01-11 16:12:40 -050016import testtools
17
Sean Dague1937d092013-05-17 16:36:38 -040018from tempest.api.compute import base
lanoux2746ba02016-03-16 17:41:01 +090019from tempest.common import compute
Matt Riedemann81fa9b62016-01-14 13:04:38 -080020from tempest.common import utils
Masayuki Igawa209fd502014-02-17 14:46:43 +090021from tempest.common.utils.linux import remote_client
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +000022from tempest.common import waiters
Sean Dague86bd8422013-12-20 09:56:44 -050023from tempest import config
Ken'ichi Ohmichi6c92edf2017-01-27 17:32:10 -080024from tempest.lib import decorators
Dan Smithc18d8c62012-07-02 08:09:26 -070025
Sean Dague86bd8422013-12-20 09:56:44 -050026CONF = config.CONF
27
Dan Smithc18d8c62012-07-02 08:09:26 -070028
Matt Riedemann039740a2018-01-02 15:47:40 -050029class BaseAttachVolumeTest(base.BaseV2ComputeTest):
30 """Base class for the attach volume tests in this module."""
Eric Fried1f546532020-01-14 17:11:58 -060031 create_default_network = True
Dan Smithc18d8c62012-07-02 08:09:26 -070032
Attila Fazekas19044d52013-02-16 07:35:06 +010033 @classmethod
Emily Hugenbruch8284a342014-12-11 22:04:55 +000034 def skip_checks(cls):
Matt Riedemann039740a2018-01-02 15:47:40 -050035 super(BaseAttachVolumeTest, cls).skip_checks()
Matthew Treinishb0a78fc2014-01-29 16:49:12 +000036 if not CONF.service_available.cinder:
Matthew Treinish4c412922013-07-16 15:27:42 -040037 skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
38 raise cls.skipException(skip_msg)
Dan Smithc18d8c62012-07-02 08:09:26 -070039
Emily Hugenbruch8284a342014-12-11 22:04:55 +000040 @classmethod
41 def setup_credentials(cls):
42 cls.prepare_instance_network()
Matt Riedemann039740a2018-01-02 15:47:40 -050043 super(BaseAttachVolumeTest, cls).setup_credentials()
Emily Hugenbruch8284a342014-12-11 22:04:55 +000044
Fabian Zimmermannbbef2762016-06-23 14:05:33 +020045 def _create_server(self):
Dan Smithc18d8c62012-07-02 08:09:26 -070046 # Start a server and wait for it to become ready
Andrea Frittoli9f416dd2017-08-10 15:38:00 +010047 validation_resources = self.get_test_validation_resources(
48 self.os_primary)
Fabian Zimmermannbbef2762016-06-23 14:05:33 +020049 server = self.create_test_server(
Joseph Lanouxffe09dd2015-03-18 16:45:33 +000050 validatable=True,
Andrea Frittoli9f416dd2017-08-10 15:38:00 +010051 validation_resources=validation_resources,
Lee Yarwoodd548e7a2021-11-12 12:59:22 +000052 wait_until='SSHABLE',
Fabian Zimmermannbbef2762016-06-23 14:05:33 +020053 adminPass=self.image_ssh_password)
Kevin_Zheng7a547df2017-04-27 18:00:13 +080054 self.addCleanup(self.delete_server, server['id'])
Dan Smithc18d8c62012-07-02 08:09:26 -070055 # Record addresses so that we can ssh later
Fabian Zimmermannbbef2762016-06-23 14:05:33 +020056 server['addresses'] = self.servers_client.list_addresses(
57 server['id'])['addresses']
Andrea Frittoli9f416dd2017-08-10 15:38:00 +010058 return server, validation_resources
Dan Smithc18d8c62012-07-02 08:09:26 -070059
Matt Riedemann039740a2018-01-02 15:47:40 -050060
61class AttachVolumeTestJSON(BaseAttachVolumeTest):
zhuflb5603bc2020-05-27 09:18:24 +080062 """Test attaching volume to server"""
Matt Riedemann039740a2018-01-02 15:47:40 -050063
Ken'ichi Ohmichi6c92edf2017-01-27 17:32:10 -080064 @decorators.idempotent_id('52e9045a-e90d-4c0d-9087-79d657faffff')
Matt Riedemann99683152019-02-14 14:35:38 -050065 # This test is conditionally marked slow if SSH validation is enabled.
66 @decorators.attr(type='slow', condition=CONF.validation.run_validation)
Dan Smithc18d8c62012-07-02 08:09:26 -070067 def test_attach_detach_volume(self):
zhuflb5603bc2020-05-27 09:18:24 +080068 """Test attaching and detaching volume from server
69
70 Stop and Start a server with an attached volume, ensuring that
71 the volume remains attached.
72 """
Andrea Frittoli9f416dd2017-08-10 15:38:00 +010073 server, validation_resources = self._create_server()
Andrea Frittolicec44942017-03-24 14:44:19 +000074
75 # NOTE(andreaf) Create one remote client used throughout the test.
76 if CONF.validation.run_validation:
77 linux_client = remote_client.RemoteClient(
Andrea Frittoli9f416dd2017-08-10 15:38:00 +010078 self.get_server_ip(server, validation_resources),
Andrea Frittolicec44942017-03-24 14:44:19 +000079 self.image_ssh_user,
80 self.image_ssh_password,
Andrea Frittoli9f416dd2017-08-10 15:38:00 +010081 validation_resources['keypair']['private_key'],
Andrea Frittolicec44942017-03-24 14:44:19 +000082 server=server,
83 servers_client=self.servers_client)
84 # NOTE(andreaf) We need to ensure the ssh key has been
85 # injected in the guest before we power cycle
86 linux_client.validate_authentication()
Paras Babbar4b45f9e2019-12-11 16:51:57 -050087 disks_before_attach = linux_client.list_disks()
Andrea Frittolicec44942017-03-24 14:44:19 +000088
Benny Kopilov5c5f7d82016-09-13 14:19:53 +030089 volume = self.create_volume()
zhufl2c9d9622018-08-30 16:03:07 +080090
91 # NOTE: As of the 12.0.0 Liberty release, the Nova libvirt driver
Paras Babbarf1185652019-11-15 16:55:45 -050092 # no longer honors a user-supplied device name, and there can be
93 # a mismatch between libvirt provide disk name and actual disk name
94 # on instance, hence we no longer validate this test with the supplied
95 # device name rather we count number of disk before attach
96 # detach to validate the testcase.
97
98 attachment = self.attach_volume(server, volume)
ivan-zhu2f54b282013-03-11 16:39:25 +080099
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200100 self.servers_client.stop_server(server['id'])
101 waiters.wait_for_server_status(self.servers_client, server['id'],
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000102 'SHUTOFF')
Dan Smithc18d8c62012-07-02 08:09:26 -0700103
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200104 self.servers_client.start_server(server['id'])
105 waiters.wait_for_server_status(self.servers_client, server['id'],
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000106 'ACTIVE')
Dan Smithc18d8c62012-07-02 08:09:26 -0700107
Andrea Frittoli (andreaf)3f5aa982016-07-08 12:10:36 +0100108 if CONF.validation.run_validation:
Paras Babbar4b45f9e2019-12-11 16:51:57 -0500109 disks_after_attach = linux_client.list_disks()
110 self.assertGreater(
111 len(disks_after_attach),
112 len(disks_before_attach))
Dan Smithc18d8c62012-07-02 08:09:26 -0700113
zhufl36f0a972017-02-28 15:43:33 +0800114 self.servers_client.detach_volume(server['id'], attachment['volumeId'])
115 waiters.wait_for_volume_resource_status(
116 self.volumes_client, attachment['volumeId'], 'available')
117
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200118 self.servers_client.stop_server(server['id'])
119 waiters.wait_for_server_status(self.servers_client, server['id'],
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000120 'SHUTOFF')
Dan Smithc18d8c62012-07-02 08:09:26 -0700121
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200122 self.servers_client.start_server(server['id'])
123 waiters.wait_for_server_status(self.servers_client, server['id'],
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000124 'ACTIVE')
Dan Smithc18d8c62012-07-02 08:09:26 -0700125
Andrea Frittoli (andreaf)3f5aa982016-07-08 12:10:36 +0100126 if CONF.validation.run_validation:
Paras Babbar4b45f9e2019-12-11 16:51:57 -0500127 disks_after_detach = linux_client.list_disks()
128 self.assertEqual(len(disks_before_attach), len(disks_after_detach))
Dan Smith1ced8422012-08-16 10:35:19 -0700129
Ken'ichi Ohmichi6c92edf2017-01-27 17:32:10 -0800130 @decorators.idempotent_id('7fa563fe-f0f7-43eb-9e22-a1ece036b513')
Ghanshyam5c2a5582014-04-14 17:16:57 +0900131 def test_list_get_volume_attachments(self):
zhuflb5603bc2020-05-27 09:18:24 +0800132 """Test listing and getting volume attachments
133
134 First we attach one volume to the server, check listing and getting
135 the volume attachment of the server. Then we attach another volume to
136 the server, check listing and getting the volume attachments of the
137 server. Finally we detach the volumes from the server one by one.
138 """
Benny Kopilov5c5f7d82016-09-13 14:19:53 +0300139 # List volume attachment of the server
afazekas5d066232019-03-25 18:35:36 +0100140 server, validation_resources = self._create_server()
zhufl16dd62c2017-05-03 15:46:16 +0800141 volume_1st = self.create_volume()
zhufl2c9d9622018-08-30 16:03:07 +0800142 attachment_1st = self.attach_volume(server, volume_1st)
David Kranz3ebc7212015-02-10 12:19:19 -0500143 body = self.servers_client.list_volume_attachments(
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200144 server['id'])['volumeAttachments']
Ghanshyam5c2a5582014-04-14 17:16:57 +0900145 self.assertEqual(1, len(body))
zhufl16dd62c2017-05-03 15:46:16 +0800146 self.assertIn(attachment_1st, body)
Ghanshyam5c2a5582014-04-14 17:16:57 +0900147
Benny Kopilov5c5f7d82016-09-13 14:19:53 +0300148 # Get volume attachment of the server
Ken'ichi Ohmichi277d1882015-11-20 00:44:06 +0000149 body = self.servers_client.show_volume_attachment(
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200150 server['id'],
zhufl16dd62c2017-05-03 15:46:16 +0800151 attachment_1st['id'])['volumeAttachment']
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200152 self.assertEqual(server['id'], body['serverId'])
zhufl16dd62c2017-05-03 15:46:16 +0800153 self.assertEqual(volume_1st['id'], body['volumeId'])
154 self.assertEqual(attachment_1st['id'], body['id'])
lanoux2746ba02016-03-16 17:41:01 +0900155
zhufl16dd62c2017-05-03 15:46:16 +0800156 # attach one more volume to server
Ken'ichi Ohmichi09139282016-12-01 14:36:22 -0800157 volume_2nd = self.create_volume()
zhufl36f0a972017-02-28 15:43:33 +0800158 attachment_2nd = self.attach_volume(server, volume_2nd)
Ken'ichi Ohmichi09139282016-12-01 14:36:22 -0800159 body = self.servers_client.list_volume_attachments(
160 server['id'])['volumeAttachments']
161 self.assertEqual(2, len(body))
162
afazekas5d066232019-03-25 18:35:36 +0100163 if CONF.validation.run_validation:
164 linux_client = remote_client.RemoteClient(
165 self.get_server_ip(server, validation_resources),
166 self.image_ssh_user,
167 self.image_ssh_password,
168 validation_resources['keypair']['private_key'],
169 server=server,
170 servers_client=self.servers_client)
171 linux_client.validate_authentication()
172
zhufl16dd62c2017-05-03 15:46:16 +0800173 for attachment in [attachment_1st, attachment_2nd]:
174 body = self.servers_client.show_volume_attachment(
175 server['id'], attachment['id'])['volumeAttachment']
176 self.assertEqual(server['id'], body['serverId'])
177 self.assertEqual(attachment['volumeId'], body['volumeId'])
178 self.assertEqual(attachment['id'], body['id'])
Steve Noyes5026c502017-08-10 11:12:31 -0400179 self.servers_client.detach_volume(server['id'],
180 attachment['volumeId'])
181 waiters.wait_for_volume_resource_status(
182 self.volumes_client, attachment['volumeId'], 'available')
Ken'ichi Ohmichi09139282016-12-01 14:36:22 -0800183
lanoux2746ba02016-03-16 17:41:01 +0900184
Matt Riedemann039740a2018-01-02 15:47:40 -0500185class AttachVolumeShelveTestJSON(BaseAttachVolumeTest):
lanoux2746ba02016-03-16 17:41:01 +0900186 """Testing volume with shelved instance.
187
188 This test checks the attaching and detaching volumes from
Tianbiao Qi0d1d24e2016-09-28 14:17:12 +0800189 a shelved or shelved offload instance.
Matt Riedemannb5720532018-09-19 16:02:05 -0400190
191 Note that these are uncommon scenarios until blueprint detach-boot-volume
192 is implemented in the compute service.
lanoux2746ba02016-03-16 17:41:01 +0900193 """
194
195 min_microversion = '2.20'
196 max_microversion = 'latest'
197
zhufl11289db2017-08-29 10:59:39 +0800198 @classmethod
199 def skip_checks(cls):
200 super(AttachVolumeShelveTestJSON, cls).skip_checks()
201 if not CONF.compute_feature_enabled.shelve:
202 raise cls.skipException('Shelve is not available.')
Lee Yarwood8581ea22020-07-30 20:21:52 +0100203 if CONF.compute.compute_volume_common_az:
204 # assuming cross_az_attach is set to false in nova.conf
205 # per the compute_volume_common_az option description
206 raise cls.skipException('Cross AZ attach not available.')
zhufl11289db2017-08-29 10:59:39 +0800207
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100208 def _count_volumes(self, server, validation_resources):
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200209 # Count number of volumes on an instance
210 volumes = 0
Andrea Frittoli (andreaf)3f5aa982016-07-08 12:10:36 +0100211 if CONF.validation.run_validation:
212 linux_client = remote_client.RemoteClient(
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100213 self.get_server_ip(server, validation_resources),
Andrea Frittoli (andreaf)3f5aa982016-07-08 12:10:36 +0100214 self.image_ssh_user,
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200215 self.image_ssh_password,
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100216 validation_resources['keypair']['private_key'],
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200217 server=server,
Andrea Frittoli (andreaf)3f5aa982016-07-08 12:10:36 +0100218 servers_client=self.servers_client)
lanoux2746ba02016-03-16 17:41:01 +0900219
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200220 command = 'grep -c -E [vs]d.$ /proc/partitions'
221 volumes = int(linux_client.exec_command(command).strip())
222 return volumes
223
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100224 def _shelve_server(self, server, validation_resources):
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200225 # NOTE(andreaf) If we are going to shelve a server, we should
226 # check first whether the server is ssh-able. Otherwise we
227 # won't be able to distinguish failures introduced by shelve
228 # from pre-existing ones. Also it's good to wait for cloud-init
229 # to be done and sshd server to be running before shelving to
230 # avoid breaking the VM
231 if CONF.validation.run_validation:
232 linux_client = remote_client.RemoteClient(
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100233 self.get_server_ip(server, validation_resources),
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200234 self.image_ssh_user,
235 self.image_ssh_password,
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100236 validation_resources['keypair']['private_key'],
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200237 server=server,
238 servers_client=self.servers_client)
239 linux_client.validate_authentication()
240
241 # If validation went ok, or it was skipped, shelve the server
242 compute.shelve_server(self.servers_client, server['id'])
243
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100244 def _unshelve_server_and_check_volumes(self, server,
245 validation_resources,
246 number_of_volumes):
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200247 # Unshelve the instance and check that there are expected volumes
248 self.servers_client.unshelve_server(server['id'])
249 waiters.wait_for_server_status(self.servers_client,
250 server['id'],
251 'ACTIVE')
252 if CONF.validation.run_validation:
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100253 counted_volumes = self._count_volumes(
254 server, validation_resources)
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200255 self.assertEqual(number_of_volumes, counted_volumes)
lanoux2746ba02016-03-16 17:41:01 +0900256
Matt Riedemannb5720532018-09-19 16:02:05 -0400257 # NOTE(mriedem): Marked as slow since this is an uncommon scenario until
258 # attach/detach root volume is supported in nova, and it's slow.
259 @decorators.attr(type='slow')
Ken'ichi Ohmichi6c92edf2017-01-27 17:32:10 -0800260 @decorators.idempotent_id('13a940b6-3474-4c3c-b03f-29b89112bfee')
lanoux2746ba02016-03-16 17:41:01 +0900261 def test_attach_volume_shelved_or_offload_server(self):
zhuflb5603bc2020-05-27 09:18:24 +0800262 """Test attaching volume to shelved server
263
264 Create server, count number of volumes on it, shelve
265 server and attach pre-created volume to shelved server, then
266 unshelve the server and check that attached volume exists.
267 """
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100268 server, validation_resources = self._create_server()
Benny Kopilov5c5f7d82016-09-13 14:19:53 +0300269 volume = self.create_volume()
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100270 num_vol = self._count_volumes(server, validation_resources)
271 self._shelve_server(server, validation_resources)
zhufl2c9d9622018-08-30 16:03:07 +0800272 attachment = self.attach_volume(server, volume)
lanoux2746ba02016-03-16 17:41:01 +0900273
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200274 # Unshelve the instance and check that attached volume exists
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100275 self._unshelve_server_and_check_volumes(
276 server, validation_resources, num_vol + 1)
lanoux2746ba02016-03-16 17:41:01 +0900277
Benny Kopilov5c5f7d82016-09-13 14:19:53 +0300278 # Get volume attachment of the server
lanoux2746ba02016-03-16 17:41:01 +0900279 volume_attachment = self.servers_client.show_volume_attachment(
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200280 server['id'],
Benny Kopilov5c5f7d82016-09-13 14:19:53 +0300281 attachment['id'])['volumeAttachment']
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200282 self.assertEqual(server['id'], volume_attachment['serverId'])
Benny Kopilov5c5f7d82016-09-13 14:19:53 +0300283 self.assertEqual(attachment['id'], volume_attachment['id'])
lanoux2746ba02016-03-16 17:41:01 +0900284 # Check the mountpoint is not None after unshelve server even in
285 # case of shelved_offloaded.
286 self.assertIsNotNone(volume_attachment['device'])
287
Matt Riedemannb5720532018-09-19 16:02:05 -0400288 # NOTE(mriedem): Marked as slow since this is an uncommon scenario until
289 # attach/detach root volume is supported in nova, and it's slow.
290 @decorators.attr(type='slow')
Ken'ichi Ohmichi6c92edf2017-01-27 17:32:10 -0800291 @decorators.idempotent_id('b54e86dd-a070-49c4-9c07-59ae6dae15aa')
lanoux2746ba02016-03-16 17:41:01 +0900292 def test_detach_volume_shelved_or_offload_server(self):
zhuflb5603bc2020-05-27 09:18:24 +0800293 """Test detaching volume from shelved server
294
295 Count number of volumes on server, shelve server and attach
296 pre-created volume to shelved server, then detach the volume, unshelve
297 the instance and check that we have the expected number of volume(s).
298 """
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100299 server, validation_resources = self._create_server()
Benny Kopilov5c5f7d82016-09-13 14:19:53 +0300300 volume = self.create_volume()
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100301 num_vol = self._count_volumes(server, validation_resources)
302 self._shelve_server(server, validation_resources)
zhufl36f0a972017-02-28 15:43:33 +0800303
304 # Attach and then detach the volume
zhufl2c9d9622018-08-30 16:03:07 +0800305 self.attach_volume(server, volume)
zhufl36f0a972017-02-28 15:43:33 +0800306 self.servers_client.detach_volume(server['id'], volume['id'])
307 waiters.wait_for_volume_resource_status(self.volumes_client,
308 volume['id'], 'available')
lanoux2746ba02016-03-16 17:41:01 +0900309
Fabian Zimmermannbbef2762016-06-23 14:05:33 +0200310 # Unshelve the instance and check that we have the expected number of
311 # volume(s)
Andrea Frittoli9f416dd2017-08-10 15:38:00 +0100312 self._unshelve_server_and_check_volumes(
313 server, validation_resources, num_vol)
Matt Riedemann81fa9b62016-01-14 13:04:38 -0800314
315
316class AttachVolumeMultiAttachTest(BaseAttachVolumeTest):
zhuflb5603bc2020-05-27 09:18:24 +0800317 """Test attaching one volume to multiple servers
318
319 Test attaching one volume to multiple servers with compute
320 microversion greater than 2.59.
321 """
322
Matt Riedemann81fa9b62016-01-14 13:04:38 -0800323 min_microversion = '2.60'
324 max_microversion = 'latest'
325
326 @classmethod
327 def skip_checks(cls):
328 super(AttachVolumeMultiAttachTest, cls).skip_checks()
329 if not CONF.compute_feature_enabled.volume_multiattach:
330 raise cls.skipException('Volume multi-attach is not available.')
331
332 def _attach_volume_to_servers(self, volume, servers):
333 """Attaches the given volume to the list of servers.
334
335 :param volume: The multiattach volume to use.
336 :param servers: list of server instances on which the volume will be
337 attached
338 :returns: dict of server ID to volumeAttachment dict entries
339 """
340 attachments = {}
341 for server in servers:
342 # map the server id to the volume attachment
343 attachments[server['id']] = self.attach_volume(server, volume)
344 # NOTE(mriedem): In the case of multi-attach, after the first
345 # attach the volume will be in-use. On the second attach, nova will
346 # 'reserve' the volume which puts it back into 'attaching' status
347 # and then the volume shouldn't go back to in-use until the compute
348 # actually attaches the server to the volume.
349 return attachments
350
351 def _detach_multiattach_volume(self, volume_id, server_id):
352 """Detaches a multiattach volume from the given server.
353
354 Depending on the number of attachments the volume has, this method
355 will wait for the volume to go to back to 'in-use' status if there are
356 more attachments or 'available' state if there are no more attachments.
357 """
358 # Count the number of attachments before starting the detach.
359 volume = self.volumes_client.show_volume(volume_id)['volume']
360 attachments = volume['attachments']
361 wait_status = 'in-use' if len(attachments) > 1 else 'available'
362 # Now detach the volume from the given server.
363 self.servers_client.detach_volume(server_id, volume_id)
364 # Now wait for the volume status to change.
365 waiters.wait_for_volume_resource_status(
366 self.volumes_client, volume_id, wait_status)
367
368 def _create_multiattach_volume(self, bootable=False):
369 kwargs = {}
370 if bootable:
371 kwargs['image_ref'] = CONF.compute.image_ref
whoami-rajatb04b1022023-02-27 09:41:22 +0000372 multiattach_vol_type = CONF.volume.volume_type_multiattach
373 return self.create_volume(volume_type=multiattach_vol_type,
374 **kwargs)
Matt Riedemann81fa9b62016-01-14 13:04:38 -0800375
376 def _create_and_multiattach(self):
377 """Creates two server instances and a volume and attaches to both.
378
379 :returns: A three-item tuple of the list of created servers,
380 the created volume, and dict of server ID to volumeAttachment
381 dict entries
382 """
Balazs Gibizerd8bbaba2022-05-17 17:15:40 +0200383 validation_resources = self.get_class_validation_resources(
384 self.os_primary)
385
Matt Riedemann81fa9b62016-01-14 13:04:38 -0800386 servers = []
387 for x in range(2):
388 name = 'multiattach-server-%i' % x
Balazs Gibizerd8bbaba2022-05-17 17:15:40 +0200389 servers.append(
390 self.create_test_server(
391 name=name,
392 validatable=True,
393 validation_resources=validation_resources
394 )
395 )
Matt Riedemann81fa9b62016-01-14 13:04:38 -0800396
397 # Now wait for the servers to be ACTIVE.
398 for server in servers:
399 waiters.wait_for_server_status(self.servers_client, server['id'],
400 'ACTIVE')
401
402 volume = self._create_multiattach_volume()
403
404 # Attach the volume to the servers
405 attachments = self._attach_volume_to_servers(volume, servers)
406 return servers, volume, attachments
407
408 @decorators.idempotent_id('8d5853f7-56e7-4988-9b0c-48cea3c7049a')
409 def test_list_get_volume_attachments_multiattach(self):
zhuflb5603bc2020-05-27 09:18:24 +0800410 """Test listing and getting multiattached volume attachments
411
412 Attach a single volume to two servers, list attachments from the
413 volume and make sure the server uuids are in the list, then detach
414 the volume from servers one by one.
415 """
Matt Riedemann81fa9b62016-01-14 13:04:38 -0800416 # Attach a single volume to two servers.
417 servers, volume, attachments = self._create_and_multiattach()
418
419 # List attachments from the volume and make sure the server uuids
420 # are in that list.
421 vol_attachments = self.volumes_client.show_volume(
422 volume['id'])['volume']['attachments']
423 attached_server_ids = [attachment['server_id']
424 for attachment in vol_attachments]
425 self.assertEqual(2, len(attached_server_ids))
426
427 # List Volume attachment of the servers
428 for server in servers:
429 self.assertIn(server['id'], attached_server_ids)
430 vol_attachments = self.servers_client.list_volume_attachments(
431 server['id'])['volumeAttachments']
432 self.assertEqual(1, len(vol_attachments))
433 attachment = attachments[server['id']]
434 self.assertDictEqual(attachment, vol_attachments[0])
435 # Detach the volume from this server.
436 self._detach_multiattach_volume(volume['id'], server['id'])
437
438 def _boot_from_multiattach_volume(self):
439 """Boots a server from a multiattach volume.
440
441 The volume will not be deleted when the server is deleted.
442
443 :returns: 2-item tuple of (server, volume)
444 """
445 volume = self._create_multiattach_volume(bootable=True)
446 # Now create a server from the bootable volume.
447 bdm = [{
448 'uuid': volume['id'],
449 'source_type': 'volume',
450 'destination_type': 'volume',
451 'boot_index': 0,
452 'delete_on_termination': False}]
453 server = self.create_test_server(
454 image_id='', block_device_mapping_v2=bdm, wait_until='ACTIVE')
455 # Assert the volume is attached to the server.
456 attachments = self.servers_client.list_volume_attachments(
457 server['id'])['volumeAttachments']
458 self.assertEqual(1, len(attachments))
459 self.assertEqual(volume['id'], attachments[0]['volumeId'])
460 return server, volume
461
462 @decorators.idempotent_id('65e33aa2-185b-44c8-b22e-e524973ed625')
463 def test_boot_from_multiattach_volume(self):
464 """Simple test to boot an instance from a multiattach volume."""
465 self._boot_from_multiattach_volume()
466
467 @utils.services('image')
468 @decorators.idempotent_id('885ac48a-2d7a-40c5-ae8b-1993882d724c')
Martin Kopeca5441722021-09-14 08:13:13 +0000469 @testtools.skipUnless(CONF.compute_feature_enabled.snapshot,
470 'Snapshotting is not available.')
Matt Riedemann81fa9b62016-01-14 13:04:38 -0800471 def test_snapshot_volume_backed_multiattach(self):
472 """Boots a server from a multiattach volume and snapshots the server.
473
474 Creating the snapshot of the server will also create a snapshot of
475 the volume.
476 """
477 server, volume = self._boot_from_multiattach_volume()
478 # Create a snapshot of the server (and volume implicitly).
479 self.create_image_from_server(
480 server['id'], name='multiattach-snapshot',
481 wait_until='active', wait_for_server=True)
482 # TODO(mriedem): Make sure the volume snapshot exists. This requires
483 # adding the volume snapshots client to BaseV2ComputeTest.
484 # Delete the server, wait for it to be gone, and make sure the volume
485 # still exists.
486 self.servers_client.delete_server(server['id'])
487 waiters.wait_for_server_termination(self.servers_client, server['id'])
488 # Delete the volume and cascade the delete of the volume snapshot.
489 self.volumes_client.delete_volume(volume['id'], cascade=True)
490 # Now we have to wait for the volume to be gone otherwise the normal
491 # teardown will fail since it will race with our call and the snapshot
492 # might still exist.
493 self.volumes_client.wait_for_resource_deletion(volume['id'])
494
Steve Noyes83a14122018-01-11 16:12:40 -0500495 @decorators.idempotent_id('f01c7169-a124-4fc7-ae60-5e380e247c9c')
496 @testtools.skipUnless(CONF.compute_feature_enabled.resize,
497 'Resize not available.')
498 def test_resize_server_with_multiattached_volume(self):
zhuflb5603bc2020-05-27 09:18:24 +0800499 """Test resizing servers with multiattached volume
500
501 Attach a single volume to multiple servers, then resize the servers
502 """
Steve Noyes83a14122018-01-11 16:12:40 -0500503 servers, volume, _ = self._create_and_multiattach()
504
505 for server in servers:
Balazs Gibizerd8bbaba2022-05-17 17:15:40 +0200506 # We need to wait until the guest OS fully boots up as we are going
507 # to detach volumes after the resize. See bug #1960346.
508 self.resize_server(
509 server['id'], self.flavor_ref_alt, wait_until='SSHABLE')
Steve Noyes83a14122018-01-11 16:12:40 -0500510
511 for server in servers:
512 self._detach_multiattach_volume(volume['id'], server['id'])
513
Matt Riedemann81fa9b62016-01-14 13:04:38 -0800514 # TODO(mriedem): Might be interesting to create a bootable multiattach
515 # volume with delete_on_termination=True, create server1 from the
516 # volume, then attach it to server2, and then delete server1 in which
517 # case the volume won't be deleted because it's still attached to
518 # server2 and make sure the volume is still attached to server2.