Fix for test_volume_swap

In volume swap procedure, server's BDM is updated after the old volume has
been changed to 'available' and the new volume to 'in-use'. When the old
volume is 'available' and the new volume is 'in-use', it is possible that
the server's BDM has not been updated yet. So it is necessary to wait for
volume swap to make sure that the server's BDM has been updated.

Change-Id: I069a603159ecdec924868f45f12408e55eb235ea
diff --git a/tempest/api/compute/admin/test_volume_swap.py b/tempest/api/compute/admin/test_volume_swap.py
index 984f1a9..22a5bc4 100644
--- a/tempest/api/compute/admin/test_volume_swap.py
+++ b/tempest/api/compute/admin/test_volume_swap.py
@@ -10,10 +10,13 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import time
+
 from tempest.api.compute import base
 from tempest.common import waiters
 from tempest import config
 from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
 from tempest import test
 
 CONF = config.CONF
@@ -41,6 +44,41 @@
         if not CONF.compute_feature_enabled.swap_volume:
             raise cls.skipException("Swapping volumes is not supported.")
 
+    def _wait_for_server_volume_swap(self, server_id, old_volume_id,
+                                     new_volume_id):
+        """Waits for a server to swap the old volume to a new one."""
+        volume_attachments = self.servers_client.list_volume_attachments(
+            server_id)['volumeAttachments']
+        attached_volume_ids = [attachment['volumeId']
+                               for attachment in volume_attachments]
+        start = int(time.time())
+
+        while (old_volume_id in attached_volume_ids) \
+                or (new_volume_id not in attached_volume_ids):
+            time.sleep(self.servers_client.build_interval)
+            volume_attachments = self.servers_client.list_volume_attachments(
+                server_id)['volumeAttachments']
+            attached_volume_ids = [attachment['volumeId']
+                                   for attachment in volume_attachments]
+
+            if int(time.time()) - start >= self.servers_client.build_timeout:
+                old_vol_bdm_status = 'in BDM' \
+                    if old_volume_id in attached_volume_ids else 'not in BDM'
+                new_vol_bdm_status = 'in BDM' \
+                    if new_volume_id in attached_volume_ids else 'not in BDM'
+                message = ('Failed to swap old volume %(old_volume_id)s '
+                           '(current %(old_vol_bdm_status)s) to new volume '
+                           '%(new_volume_id)s (current %(new_vol_bdm_status)s)'
+                           ' on server %(server_id)s within the required time '
+                           '(%(timeout)s s)' %
+                           {'old_volume_id': old_volume_id,
+                            'old_vol_bdm_status': old_vol_bdm_status,
+                            'new_volume_id': new_volume_id,
+                            'new_vol_bdm_status': new_vol_bdm_status,
+                            'server_id': server_id,
+                            'timeout': self.servers_client.build_timeout})
+                raise lib_exc.TimeoutException(message)
+
     @decorators.idempotent_id('1769f00d-a693-4d67-a631-6a3496773813')
     @test.services('volume')
     def test_volume_swap(self):
@@ -61,6 +99,8 @@
                                                 volume1['id'], 'available')
         waiters.wait_for_volume_resource_status(self.volumes_client,
                                                 volume2['id'], 'in-use')
+        self._wait_for_server_volume_swap(server['id'], volume1['id'],
+                                          volume2['id'])
         # Verify "volume2" is attached to the server
         vol_attachments = self.servers_client.list_volume_attachments(
             server['id'])['volumeAttachments']
@@ -74,6 +114,8 @@
                                                 volume2['id'], 'available')
         waiters.wait_for_volume_resource_status(self.volumes_client,
                                                 volume1['id'], 'in-use')
+        self._wait_for_server_volume_swap(server['id'], volume2['id'],
+                                          volume1['id'])
         # Verify "volume1" is attached to the server
         vol_attachments = self.servers_client.list_volume_attachments(
             server['id'])['volumeAttachments']