Merge "Provide better message when no IPv4 addresses found"
diff --git a/setup.cfg b/setup.cfg
index 46e21f1..ee61788 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -34,6 +34,7 @@
     tempest = tempest.cmd.main:main
 tempest.cm =
     init = tempest.cmd.init:TempestInit
+    cleanup = tempest.cmd.cleanup:TempestCleanup
 oslo.config.opts =
     tempest.config = tempest.config:list_opts
 
diff --git a/tempest/api/identity/admin/v3/test_domains_negative.py b/tempest/api/identity/admin/v3/test_domains_negative.py
index 156179c..33819a8 100644
--- a/tempest/api/identity/admin/v3/test_domains_negative.py
+++ b/tempest/api/identity/admin/v3/test_domains_negative.py
@@ -37,3 +37,10 @@
         # domain need to be disabled before deleting
         self.assertRaises(lib_exc.Forbidden, self.client.delete_domain,
                           domain_id)
+
+    @test.attr(type=['negative'])
+    @test.idempotent_id('9018461d-7d24-408d-b3fe-ae37e8cd5c9e')
+    def test_create_domain_with_empty_name(self):
+        # Domain name should not be empty
+        self.assertRaises(lib_exc.BadRequest, self.client.create_domain,
+                          name='')
diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py
old mode 100755
new mode 100644
index 7898035..4fa4302
--- a/tempest/cmd/cleanup.py
+++ b/tempest/cmd/cleanup.py
@@ -50,9 +50,9 @@
 
 Please run with **--help** to see full list of options.
 """
-import argparse
 import sys
 
+from cliff import command
 from oslo_log import log as logging
 from oslo_serialization import jsonutils as json
 
@@ -67,13 +67,17 @@
 CONF = config.CONF
 
 
-class Cleanup(object):
+class TempestCleanup(command.Command):
 
-    def __init__(self):
+    def __init__(self, app, cmd):
+        super(TempestCleanup, self).__init__(app, cmd)
+
+    def take_action(self, parsed_args):
+        cleanup_service.init_conf()
+        self.options = parsed_args
         self.admin_mgr = clients.AdminManager()
         self.dry_run_data = {}
         self.json_data = {}
-        self._init_options()
 
         self.admin_id = ""
         self.admin_role_id = ""
@@ -86,9 +90,7 @@
         self.tenant_services = cleanup_service.get_tenant_cleanup_services()
         self.global_services = cleanup_service.get_global_cleanup_services()
 
-    def run(self):
-        opts = self.options
-        if opts.init_saved_state:
+        if parsed_args.init_saved_state:
             self._init_state()
             return
 
@@ -157,8 +159,8 @@
             tenant_data = dry_run_data["_tenants_to_clean"][tenant_id] = {}
             tenant_data['name'] = tenant_name
 
-        kwargs = {"username": CONF.identity.admin_username,
-                  "password": CONF.identity.admin_password,
+        kwargs = {"username": CONF.auth.admin_username,
+                  "password": CONF.auth.admin_password,
                   "tenant_name": tenant['name']}
         mgr = clients.Manager(credentials=cred_provider.get_credentials(
             **kwargs))
@@ -175,22 +177,21 @@
     def _init_admin_ids(self):
         id_cl = self.admin_mgr.identity_client
 
-        tenant = id_cl.get_tenant_by_name(CONF.identity.admin_tenant_name)
+        tenant = id_cl.get_tenant_by_name(CONF.auth.admin_tenant_name)
         self.admin_tenant_id = tenant['id']
 
         user = id_cl.get_user_by_username(self.admin_tenant_id,
-                                          CONF.identity.admin_username)
+                                          CONF.auth.admin_username)
         self.admin_id = user['id']
 
-        roles = id_cl.list_roles()
+        roles = id_cl.list_roles()['roles']
         for role in roles:
             if role['name'] == CONF.identity.admin_role:
                 self.admin_role_id = role['id']
                 break
 
-    def _init_options(self):
-        parser = argparse.ArgumentParser(
-            description='Cleanup after tempest run')
+    def get_parser(self, prog_name):
+        parser = super(TempestCleanup, self).get_parser(prog_name)
         parser.add_argument('--init-saved-state', action="store_true",
                             dest='init_saved_state', default=False,
                             help="Creates JSON file: " + SAVED_STATE_JSON +
@@ -211,13 +212,15 @@
                             help="Generate JSON file:" + DRY_RUN_JSON +
                             ", that reports the objects that would have "
                             "been deleted had a full cleanup been run.")
+        return parser
 
-        self.options = parser.parse_args()
+    def get_description(self):
+        return 'Cleanup after tempest run'
 
     def _add_admin(self, tenant_id):
         id_cl = self.admin_mgr.identity_client
         needs_role = True
-        roles = id_cl.list_user_roles(tenant_id, self.admin_id)
+        roles = id_cl.list_user_roles(tenant_id, self.admin_id)['roles']
         for role in roles:
             if role['id'] == self.admin_role_id:
                 needs_role = False
@@ -282,14 +285,3 @@
         except Exception as ex:
             LOG.exception("Exception parsing saved state json : %s" % ex)
             sys.exit(ex)
-
-
-def main():
-    cleanup_service.init_conf()
-    cleanup = Cleanup()
-    cleanup.run()
-    LOG.info('Cleanup finished!')
-    return 0
-
-if __name__ == "__main__":
-    sys.exit(main())
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index 64e1303..1b5820b 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -69,10 +69,10 @@
     CONF_PRIV_NETWORK_NAME = CONF.compute.fixed_network_name
     CONF_PUB_NETWORK = CONF.network.public_network_id
     CONF_PUB_ROUTER = CONF.network.public_router_id
-    CONF_TENANTS = [CONF.identity.admin_tenant_name,
+    CONF_TENANTS = [CONF.auth.admin_tenant_name,
                     CONF.identity.tenant_name,
                     CONF.identity.alt_tenant_name]
-    CONF_USERS = [CONF.identity.admin_username, CONF.identity.username,
+    CONF_USERS = [CONF.auth.admin_username, CONF.identity.username,
                   CONF.identity.alt_username]
 
     if IS_NEUTRON:
@@ -147,7 +147,7 @@
 
     def list(self):
         client = self.client
-        snaps = client.list_snapshots()
+        snaps = client.list_snapshots()['snapshots']
         LOG.debug("List count, %s Snapshots" % len(snaps))
         return snaps
 
@@ -169,6 +169,7 @@
     def __init__(self, manager, **kwargs):
         super(ServerService, self).__init__(kwargs)
         self.client = manager.servers_client
+        self.server_groups_client = manager.server_groups_client
 
     def list(self):
         client = self.client
@@ -194,7 +195,7 @@
 class ServerGroupService(ServerService):
 
     def list(self):
-        client = self.client
+        client = self.server_groups_client
         sgs = client.list_server_groups()['server_groups']
         LOG.debug("List count, %s Server Groups" % len(sgs))
         return sgs
@@ -812,7 +813,7 @@
 
     def list(self):
         client = self.client
-        users = client.get_users()
+        users = client.get_users()['users']
 
         if not self.is_save_state:
             users = [user for user in users if user['id']
@@ -824,7 +825,7 @@
 
         elif not self.is_save_state:  # Never delete admin user
             users = [user for user in users if user['name'] !=
-                     CONF.identity.admin_username]
+                     CONF.auth.admin_username]
 
         LOG.debug("List count, %s Users after reconcile" % len(users))
         return users
@@ -854,7 +855,7 @@
     def list(self):
         client = self.client
         try:
-            roles = client.list_roles()
+            roles = client.list_roles()['roles']
             # reconcile roles with saved state and never list admin role
             if not self.is_save_state:
                 roles = [role for role in roles if
@@ -895,7 +896,7 @@
         if not self.is_save_state:
             tenants = [tenant for tenant in tenants if (tenant['id']
                        not in self.saved_state_json['tenants'].keys()
-                       and tenant['name'] != CONF.identity.admin_tenant_name)]
+                       and tenant['name'] != CONF.auth.admin_tenant_name)]
 
         if self.is_preserve:
             tenants = [tenant for tenant in tenants if tenant['name']
diff --git a/tempest/cmd/init.py b/tempest/cmd/init.py
index af8f270..a4ed064 100644
--- a/tempest/cmd/init.py
+++ b/tempest/cmd/init.py
@@ -116,9 +116,9 @@
         if not os.path.isdir(local_dir):
             LOG.debug('Creating local working dir: %s' % local_dir)
             os.mkdir(local_dir)
-        else:
+        elif not os.listdir(local_dir) == []:
             raise OSError("Directory you are trying to initialize already "
-                          "exists: %s" % local_dir)
+                          "exists and is not empty: %s" % local_dir)
 
         lock_dir = os.path.join(local_dir, 'tempest_lock')
         etc_dir = os.path.join(local_dir, 'etc')
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 678fcfc..414305d 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -95,32 +95,17 @@
         vol_name = data_utils.rand_name('volume')
         return self.create_volume(name=vol_name, snapshot_id=snap_id)
 
-    def _ssh_to_server(self, server, keypair):
+    def _get_server_ip(self, server):
         if CONF.compute.use_floatingip_for_ssh:
             ip = self.create_floating_ip(server)['ip']
         else:
             ip = server
-
-        return self.get_remote_client(ip, private_key=keypair['private_key'],
-                                      log_console_of_servers=[server])
-
-    def _get_content(self, ssh_client):
-        return ssh_client.exec_command('cat /tmp/text')
-
-    def _write_text(self, ssh_client):
-        text = data_utils.rand_name('text')
-        ssh_client.exec_command('echo "%s" > /tmp/text; sync' % (text))
-
-        return self._get_content(ssh_client)
+        return ip
 
     def _delete_server(self, server):
         self.servers_client.delete_server(server['id'])
         waiters.wait_for_server_termination(self.servers_client, server['id'])
 
-    def _check_content_of_written_file(self, ssh_client, expected):
-        actual = self._get_content(ssh_client)
-        self.assertEqual(expected, actual)
-
     @test.idempotent_id('557cd2c2-4eb8-4dce-98be-f86765ff311b')
     @test.attr(type='smoke')
     @test.services('compute', 'volume', 'image')
@@ -134,9 +119,9 @@
                                                        keypair, security_group)
 
         # write content to volume on instance
-        ssh_client_for_instance_1st = self._ssh_to_server(instance_1st,
-                                                          keypair)
-        text = self._write_text(ssh_client_for_instance_1st)
+        ip_instance_1st = self._get_server_ip(instance_1st)
+        timestamp = self.create_timestamp(ip_instance_1st,
+                                          private_key=keypair['private_key'])
 
         # delete instance
         self._delete_server(instance_1st)
@@ -146,9 +131,10 @@
                                                        keypair, security_group)
 
         # check the content of written file
-        ssh_client_for_instance_2nd = self._ssh_to_server(instance_2nd,
-                                                          keypair)
-        self._check_content_of_written_file(ssh_client_for_instance_2nd, text)
+        ip_instance_2nd = self._get_server_ip(instance_2nd)
+        timestamp2 = self.get_timestamp(ip_instance_2nd,
+                                        private_key=keypair['private_key'])
+        self.assertEqual(timestamp, timestamp2)
 
         # snapshot a volume
         snapshot = self._create_snapshot_from_volume(volume_origin['id'])
@@ -160,8 +146,10 @@
                                             keypair, security_group))
 
         # check the content of written file
-        ssh_client = self._ssh_to_server(instance_from_snapshot, keypair)
-        self._check_content_of_written_file(ssh_client, text)
+        ip_instance_from_snapshot = self._get_server_ip(instance_from_snapshot)
+        timestamp3 = self.get_timestamp(ip_instance_from_snapshot,
+                                        private_key=keypair['private_key'])
+        self.assertEqual(timestamp, timestamp3)
 
     @test.idempotent_id('36c34c67-7b54-4b59-b188-02a2f458a63b')
     @test.services('compute', 'volume', 'image')
diff --git a/tempest/tests/cmd/test_tempest_init.py b/tempest/tests/cmd/test_tempest_init.py
index 1d60c67..1048a52 100644
--- a/tempest/tests/cmd/test_tempest_init.py
+++ b/tempest/tests/cmd/test_tempest_init.py
@@ -58,9 +58,11 @@
         self.assertTrue(os.path.isfile(local_sample_conf_file))
         self.assertGreater(os.path.getsize(local_sample_conf_file), 0)
 
-    def test_create_working_dir_with_existing_local_dir(self):
+    def test_create_working_dir_with_existing_local_dir_non_empty(self):
         fake_local_dir = self.useFixture(fixtures.TempDir())
         fake_local_conf_dir = self.useFixture(fixtures.TempDir())
+        open("%s/foo" % fake_local_dir.path, 'w').close()
+
         _init = init.TempestInit(None, None)
         self.assertRaises(OSError,
                           _init.create_working_dir,