Merge "Create uniq servers in nova console tests" into mcp/caracal
diff --git a/tempest/api/compute/admin/test_create_server.py b/tempest/api/compute/admin/test_create_server.py
index aa358d7..8bc999a 100644
--- a/tempest/api/compute/admin/test_create_server.py
+++ b/tempest/api/compute/admin/test_create_server.py
@@ -22,6 +22,7 @@
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
 
 CONF = config.CONF
 
@@ -210,6 +211,55 @@
             validation_resources=validation_resources,
             wait_until='PINGABLE')
 
+    def _test_live_migration(self):
+        block_migration = (CONF.compute_feature_enabled.
+                           block_migration_for_live_migration)
+        disk_over_commit = False
+        validation_resources = self.get_class_validation_resources(
+            self.os_primary)
+        server_id = self.create_test_server(
+            image_id=self.image_id,
+            flavor=self.flavor_id,
+            validatable=True,
+            validation_resources=validation_resources,
+            wait_until='PINGABLE')['id']
+        source_host = self.get_host_for_server(server_id)
+        if not CONF.compute_feature_enabled.can_migrate_between_any_hosts:
+            # not to specify a host so that the scheduler will pick one
+            destination_host = None
+        else:
+            destination_host = self.get_host_other_than(server_id)
+        self.admin_servers_client.live_migrate_server(
+            server_id,
+            host=destination_host,
+            block_migration=block_migration,
+            disk_over_commit=disk_over_commit)
+        waiters.wait_for_server_status(self.client,
+                                       server_id, 'ACTIVE')
+        destination_host = self.get_host_for_server(server_id)
+        self.assertNotEqual(source_host, destination_host)
+
+    def _test_cold_migration(self):
+        # Run as admin to allow migrate tpm secret
+        validation_resources = self.get_class_validation_resources(
+            self.os_admin)
+        server_id = self.create_test_server(
+            clients=self.os_admin,
+            image_id=self.image_id,
+            flavor=self.flavor_id,
+            validatable=True,
+            validation_resources=validation_resources,
+            wait_until='PINGABLE')['id']
+        source_host = self.get_host_for_server(server_id)
+        self.admin_servers_client.migrate_server(server_id)
+        waiters.wait_for_server_status(self.admin_servers_client,
+                                       server_id, 'VERIFY_RESIZE')
+        self.admin_servers_client.confirm_resize_server(server_id)
+        waiters.wait_for_server_status(self.admin_servers_client,
+                                       server_id, 'ACTIVE')
+        destination_host = self.get_host_for_server(server_id)
+        self.assertNotEqual(source_host, destination_host)
+
 
 class WindowsServers10Test(WindowsServersBaseTest):
 
@@ -220,6 +270,20 @@
     def test_create_server(self):
         self._test_create_server()
 
+    @decorators.attr(type='multinode')
+    @decorators.idempotent_id('6c22fcb1-4c3e-4bf6-b8c7-c3e2322cf5ff')
+    @testtools.skipUnless(CONF.compute_feature_enabled.live_migration,
+                          'Live migration is not available.')
+    def test_live_migration(self):
+        self._test_live_migration()
+
+    @decorators.attr(type='multinode')
+    @decorators.idempotent_id('96d67c40-fd4d-4286-a3c7-880d9eb77a95')
+    @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration,
+                          'Cold migration is not available.')
+    def test_cold_migration(self):
+        self._test_cold_migration()
+
 
 class WindowsServers11Test(WindowsServersBaseTest):
 
@@ -229,3 +293,18 @@
     @decorators.idempotent_id('1cff7fea-f251-4a05-a667-9b946913a3c5')
     def test_create_server(self):
         self._test_create_server()
+
+    @decorators.attr(type=['negative'])
+    @decorators.idempotent_id('9afd991e-0478-41ca-b5cf-bf32b10ae5a7')
+    @testtools.skipUnless(CONF.compute_feature_enabled.live_migration,
+                          'Live migration is not available.')
+    def test_live_migration_with_vtpm_negative(self):
+        """Test live migrating instance with vTPM should not be supported"""
+        self.assertRaises(lib_exc.BadRequest, self._test_live_migration)
+
+    @decorators.attr(type='multinode')
+    @decorators.idempotent_id('7da88453-cc6d-4fef-b893-b4ae8f40767d')
+    @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration,
+                          'Cold migration is not available.')
+    def test_cold_migration(self):
+        self._test_cold_migration()
diff --git a/tempest/api/volume/admin/test_volume_retype.py b/tempest/api/volume/admin/test_volume_retype.py
index 586111c..c17e01c 100644
--- a/tempest/api/volume/admin/test_volume_retype.py
+++ b/tempest/api/volume/admin/test_volume_retype.py
@@ -63,7 +63,7 @@
         src_vol = self.create_volume(volume_type=self.src_vol_type['name'],
                                      snapshot_id=snapshot['id'])
 
-        if not CONF.volume_feature_enabled.snapshot_locked_by_volume:
+        if not CONF.volume_feature_enabled.volume_locked_by_snapshot:
             # Delete the snapshot
             self.snapshots_client.delete_snapshot(snapshot['id'])
             self.snapshots_client.wait_for_resource_deletion(snapshot['id'])
diff --git a/tempest/config.py b/tempest/config.py
index b41ec84..01e65f9 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -1133,10 +1133,11 @@
     cfg.ListOpt('supported_crypto_providers',
                 default=['luks'],
                 help='A list of enabled cryptoproviders for volumes'),
-    cfg.BoolOpt('snapshot_locked_by_volume',
+    cfg.BoolOpt('volume_locked_by_snapshot',
                 default=False,
-                help='Whether snapshot can be deleted, i.e. there is no '
-                     'volume dependent on (created from) it'),
+                help='Whether the volume is locked by snapshot, i.e. '
+                     'can remove volume only when no dependent '
+                     'snapshot exist.'),
 ]
 
 
diff --git a/tempest/lib/common/preprov_creds.py b/tempest/lib/common/preprov_creds.py
index 8bb41d1..cdc66bf 100644
--- a/tempest/lib/common/preprov_creds.py
+++ b/tempest/lib/common/preprov_creds.py
@@ -114,7 +114,7 @@
                       object_storage_operator_role=None,
                       object_storage_reseller_admin_role=None):
         hash_dict = {'roles': {}, 'creds': {}, 'networks': {},
-                     'scoped_roles': {}}
+                     'scoped_roles': {}, 'projects': {}}
 
         # Loop over the accounts read from the yaml file
         for account in accounts:
@@ -180,6 +180,7 @@
                         'Unknown resource type %s, ignoring this field',
                         resource
                     )
+            hash_dict = cls._append_project(account, temp_hash_key, hash_dict)
         return hash_dict
 
     def is_multi_user(self):
@@ -246,6 +247,7 @@
             hashes = temp_list
         else:
             hashes = self.hash_dict['creds'].keys()
+        hashes = self._exclude_used_projects(hashes)
         # NOTE(mtreinish): admin is a special case because of the increased
         # privilege set which could potentially cause issues on tests where
         # that is not expected. So unless the admin role isn't specified do
@@ -272,7 +274,8 @@
         free_hash = self._get_free_hash(useable_hashes)
         clean_creds = self._sanitize_creds(
             self.hash_dict['creds'][free_hash])
-        LOG.info('%s allocated creds:\n%s', self.name, clean_creds)
+        LOG.info('%s allocated creds for roles %s in scope %s:\n%s',
+                 self.name, roles, scope, clean_creds)
         return self._wrap_creds_with_network(free_hash)
 
     @lockutils.synchronized('test_accounts_io', external=True)
@@ -310,12 +313,10 @@
     # TODO(gmann): Remove this method in favor of get_project_member_creds()
     # after the deprecation phase.
     def get_primary_creds(self):
-        if self._creds.get('primary'):
-            return self._creds.get('primary')
-        # NOTE(pas-ha) use the same call as get_project_member_creds
-        net_creds = self._get_creds(['member'], scope='project')
-        self._creds['primary'] = net_creds
-        return net_creds
+        # NOTE(pas-ha) force os_primary and os_project_member
+        # to be exactly the same creds, otherwise they may be from
+        # different projects and fail some RBAC tests
+        return self.get_project_member_creds()
 
     # TODO(gmann): Replace this method with more appropriate name.
     # like get_project_alt_member_creds()
@@ -479,3 +480,16 @@
             for attr in domain_fields.intersection(set(creds_dict.keys())):
                 creds_dict.pop(attr)
         return creds_dict
+
+    @classmethod
+    def _append_project(cls, account, account_hash, hash_dict):
+        key_to_add = account.get('project_name') or account.get('tenant_name')
+        hash_dict['projects'].setdefault(key_to_add, [])
+        hash_dict['projects'][key_to_add].append(account_hash)
+        return hash_dict
+
+    def _exclude_used_projects(self, hashes):
+        excluded_accounts = []
+        for project in [cred.tenant_name for cred in self._creds.values()]:
+            excluded_accounts.extend(self.hash_dict['projects'][project])
+        return hashes - set(excluded_accounts)