Matt Riedemann | 342b37c | 2016-09-21 15:38:12 -0400 | [diff] [blame] | 1 | # 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 | |
jeremy.zhang | c9d5800 | 2017-03-22 11:03:54 +0800 | [diff] [blame] | 13 | import time |
| 14 | |
Matt Riedemann | 342b37c | 2016-09-21 15:38:12 -0400 | [diff] [blame] | 15 | from tempest.api.compute import base |
Andrea Frittoli | cd36841 | 2017-08-14 21:37:56 +0100 | [diff] [blame] | 16 | from tempest.common import utils |
Matt Riedemann | 342b37c | 2016-09-21 15:38:12 -0400 | [diff] [blame] | 17 | from tempest.common import waiters |
| 18 | from tempest import config |
Ken'ichi Ohmichi | ebbfd1c | 2017-01-27 16:37:00 -0800 | [diff] [blame] | 19 | from tempest.lib import decorators |
jeremy.zhang | c9d5800 | 2017-03-22 11:03:54 +0800 | [diff] [blame] | 20 | from tempest.lib import exceptions as lib_exc |
Matt Riedemann | 342b37c | 2016-09-21 15:38:12 -0400 | [diff] [blame] | 21 | |
| 22 | CONF = config.CONF |
| 23 | |
| 24 | |
| 25 | class TestVolumeSwap(base.BaseV2ComputeAdminTest): |
| 26 | """The test suite for swapping of volume with admin user. |
| 27 | |
| 28 | The following is the scenario outline: |
| 29 | 1. Create a volume "volume1" with non-admin. |
| 30 | 2. Create a volume "volume2" with non-admin. |
| 31 | 3. Boot an instance "instance1" with non-admin. |
| 32 | 4. Attach "volume1" to "instance1" with non-admin. |
| 33 | 5. Swap volume from "volume1" to "volume2" as admin. |
| 34 | 6. Check the swap volume is successful and "volume2" |
| 35 | is attached to "instance1" and "volume1" is in available state. |
Lee Yarwood | 89a6cfc | 2017-02-01 16:01:14 +0000 | [diff] [blame] | 36 | 7. Swap volume from "volume2" to "volume1" as admin. |
| 37 | 8. Check the swap volume is successful and "volume1" |
| 38 | is attached to "instance1" and "volume2" is in available state. |
Matt Riedemann | 342b37c | 2016-09-21 15:38:12 -0400 | [diff] [blame] | 39 | """ |
| 40 | |
| 41 | @classmethod |
| 42 | def skip_checks(cls): |
| 43 | super(TestVolumeSwap, cls).skip_checks() |
| 44 | if not CONF.compute_feature_enabled.swap_volume: |
| 45 | raise cls.skipException("Swapping volumes is not supported.") |
| 46 | |
jeremy.zhang | c9d5800 | 2017-03-22 11:03:54 +0800 | [diff] [blame] | 47 | def _wait_for_server_volume_swap(self, server_id, old_volume_id, |
| 48 | new_volume_id): |
| 49 | """Waits for a server to swap the old volume to a new one.""" |
| 50 | volume_attachments = self.servers_client.list_volume_attachments( |
| 51 | server_id)['volumeAttachments'] |
| 52 | attached_volume_ids = [attachment['volumeId'] |
| 53 | for attachment in volume_attachments] |
| 54 | start = int(time.time()) |
| 55 | |
| 56 | while (old_volume_id in attached_volume_ids) \ |
| 57 | or (new_volume_id not in attached_volume_ids): |
| 58 | time.sleep(self.servers_client.build_interval) |
| 59 | volume_attachments = self.servers_client.list_volume_attachments( |
| 60 | server_id)['volumeAttachments'] |
| 61 | attached_volume_ids = [attachment['volumeId'] |
| 62 | for attachment in volume_attachments] |
| 63 | |
| 64 | if int(time.time()) - start >= self.servers_client.build_timeout: |
| 65 | old_vol_bdm_status = 'in BDM' \ |
| 66 | if old_volume_id in attached_volume_ids else 'not in BDM' |
| 67 | new_vol_bdm_status = 'in BDM' \ |
| 68 | if new_volume_id in attached_volume_ids else 'not in BDM' |
| 69 | message = ('Failed to swap old volume %(old_volume_id)s ' |
| 70 | '(current %(old_vol_bdm_status)s) to new volume ' |
| 71 | '%(new_volume_id)s (current %(new_vol_bdm_status)s)' |
| 72 | ' on server %(server_id)s within the required time ' |
| 73 | '(%(timeout)s s)' % |
| 74 | {'old_volume_id': old_volume_id, |
| 75 | 'old_vol_bdm_status': old_vol_bdm_status, |
| 76 | 'new_volume_id': new_volume_id, |
| 77 | 'new_vol_bdm_status': new_vol_bdm_status, |
| 78 | 'server_id': server_id, |
| 79 | 'timeout': self.servers_client.build_timeout}) |
| 80 | raise lib_exc.TimeoutException(message) |
| 81 | |
Ken'ichi Ohmichi | ebbfd1c | 2017-01-27 16:37:00 -0800 | [diff] [blame] | 82 | @decorators.idempotent_id('1769f00d-a693-4d67-a631-6a3496773813') |
Andrea Frittoli | cd36841 | 2017-08-14 21:37:56 +0100 | [diff] [blame] | 83 | @utils.services('volume') |
Matt Riedemann | 342b37c | 2016-09-21 15:38:12 -0400 | [diff] [blame] | 84 | def test_volume_swap(self): |
| 85 | # Create two volumes. |
| 86 | # NOTE(gmann): Volumes are created before server creation so that |
| 87 | # volumes cleanup can happen successfully irrespective of which volume |
| 88 | # is attached to server. |
| 89 | volume1 = self.create_volume() |
| 90 | volume2 = self.create_volume() |
| 91 | # Boot server |
| 92 | server = self.create_test_server(wait_until='ACTIVE') |
| 93 | # Attach "volume1" to server |
| 94 | self.attach_volume(server, volume1) |
| 95 | # Swap volume from "volume1" to "volume2" |
zhufl | e5b62a6 | 2017-02-15 16:04:21 +0800 | [diff] [blame] | 96 | self.admin_servers_client.update_attached_volume( |
Matt Riedemann | 342b37c | 2016-09-21 15:38:12 -0400 | [diff] [blame] | 97 | server['id'], volume1['id'], volumeId=volume2['id']) |
lkuchlan | 52d7b0d | 2016-11-07 20:53:19 +0200 | [diff] [blame] | 98 | waiters.wait_for_volume_resource_status(self.volumes_client, |
| 99 | volume1['id'], 'available') |
| 100 | waiters.wait_for_volume_resource_status(self.volumes_client, |
| 101 | volume2['id'], 'in-use') |
jeremy.zhang | c9d5800 | 2017-03-22 11:03:54 +0800 | [diff] [blame] | 102 | self._wait_for_server_volume_swap(server['id'], volume1['id'], |
| 103 | volume2['id']) |
Matt Riedemann | 342b37c | 2016-09-21 15:38:12 -0400 | [diff] [blame] | 104 | # Verify "volume2" is attached to the server |
| 105 | vol_attachments = self.servers_client.list_volume_attachments( |
| 106 | server['id'])['volumeAttachments'] |
| 107 | self.assertEqual(1, len(vol_attachments)) |
| 108 | self.assertIn(volume2['id'], vol_attachments[0]['volumeId']) |
| 109 | |
Lee Yarwood | 89a6cfc | 2017-02-01 16:01:14 +0000 | [diff] [blame] | 110 | # Swap volume from "volume2" to "volume1" |
| 111 | self.admin_servers_client.update_attached_volume( |
| 112 | server['id'], volume2['id'], volumeId=volume1['id']) |
| 113 | waiters.wait_for_volume_resource_status(self.volumes_client, |
| 114 | volume2['id'], 'available') |
| 115 | waiters.wait_for_volume_resource_status(self.volumes_client, |
| 116 | volume1['id'], 'in-use') |
jeremy.zhang | c9d5800 | 2017-03-22 11:03:54 +0800 | [diff] [blame] | 117 | self._wait_for_server_volume_swap(server['id'], volume2['id'], |
| 118 | volume1['id']) |
Lee Yarwood | 89a6cfc | 2017-02-01 16:01:14 +0000 | [diff] [blame] | 119 | # Verify "volume1" is attached to the server |
| 120 | vol_attachments = self.servers_client.list_volume_attachments( |
| 121 | server['id'])['volumeAttachments'] |
| 122 | self.assertEqual(1, len(vol_attachments)) |
| 123 | self.assertIn(volume1['id'], vol_attachments[0]['volumeId']) |