Merge "Use addClassResourceCleanup to clear domains"
diff --git a/.zuul.yaml b/.zuul.yaml
new file mode 100644
index 0000000..5b73695
--- /dev/null
+++ b/.zuul.yaml
@@ -0,0 +1,23 @@
+- job:
+    name: devstack-tempest
+    parent: devstack
+    description: Base Tempest job.
+    required-projects:
+      - openstack/tempest
+    timeout: 7200
+    roles:
+      - zuul: openstack-dev/devstack
+    vars:
+      devstack_services:
+        tempest: True
+    run: playbooks/devstack-tempest.yaml
+
+- project:
+    name: openstack/tempest
+    check:
+      jobs:
+        - devstack-tempest:
+            files:
+              - ^playbooks/
+              - ^roles/
+              - ^.zuul.yaml$
diff --git a/HACKING.rst b/HACKING.rst
index 8407734..c942cb1 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -84,7 +84,7 @@
 It is recommended to use testtools `matcher`_ for the more tricky assertions.
 You can implement your own specific `matcher`_ as well.
 
-.. _matcher: http://testtools.readthedocs.org/en/latest/for-test-authors.html#matchers
+.. _matcher: https://testtools.readthedocs.org/en/latest/for-test-authors.html#matchers
 
 If the test case fails you can see the related logs and the information
 carried by the exception (exception class, backtrack and exception info).
@@ -178,7 +178,7 @@
 All negative tests should be based on `API-WG guideline`_ . Such negative
 tests can block any changes from accurate failure code to invalid one.
 
-.. _API-WG guideline: http://specs.openstack.org/openstack/api-wg/guidelines/http.html#failure-code-clarifications
+.. _API-WG guideline: https://specs.openstack.org/openstack/api-wg/guidelines/http.html#failure-code-clarifications
 
 If facing some gray area which is not clarified on the above guideline, propose
 a new guideline to the API-WG. With a proposal to the API-WG we will be able to
diff --git a/README.rst b/README.rst
index c67362a..c087f29 100644
--- a/README.rst
+++ b/README.rst
@@ -2,7 +2,7 @@
 Team and repository tags
 ========================
 
-.. image:: http://governance.openstack.org/badges/tempest.svg
+.. image:: https://governance.openstack.org/badges/tempest.svg
     :target: https://governance.openstack.org/tc/reference/tags/index.html
 
 .. Change things from this point on
@@ -61,7 +61,7 @@
 #. You first need to install Tempest. This is done with pip after you check out
    the Tempest repo::
 
-    $ git clone http://git.openstack.org/openstack/tempest
+    $ git clone https://git.openstack.org/openstack/tempest
     $ pip install tempest/
 
    This can be done within a venv, but the assumption for this guide is that
@@ -133,7 +133,7 @@
 
 Release Versioning
 ------------------
-`Tempest Release Notes <http://docs.openstack.org/releasenotes/tempest>`_
+`Tempest Release Notes <https://docs.openstack.org/releasenotes/tempest>`_
 shows what changes have been released on each version.
 
 Tempest's released versions are broken into 2 sets of information. Depending on
diff --git a/REVIEWING.rst b/REVIEWING.rst
index 7d28320..5e08a6b 100644
--- a/REVIEWING.rst
+++ b/REVIEWING.rst
@@ -2,7 +2,7 @@
 ======================
 
 To start read the `OpenStack Common Review Checklist
-<http://docs.openstack.org/infra/manual/developers.html#peer-review>`_
+<https://docs.openstack.org/infra/manual/developers.html#peer-review>`_
 
 
 Ensuring code is executed
@@ -16,7 +16,7 @@
 If a new test is added that depends on a new config option (like a feature
 flag), the commit message must reference a change in DevStack or DevStack-Gate
 that enables the execution of this newly introduced test. This reference could
-either be a `Cross-Repository Dependency <http://docs.openstack.org/infra/
+either be a `Cross-Repository Dependency <https://docs.openstack.org/infra/
 manual/developers.html#cross-repository-dependencies>`_ or a simple link
 to a Gerrit review.
 
diff --git a/doc/source/_extra/.htaccess b/doc/source/_extra/.htaccess
new file mode 100644
index 0000000..7745594
--- /dev/null
+++ b/doc/source/_extra/.htaccess
@@ -0,0 +1 @@
+redirectmatch 301 ^/developer/tempest/(.*) /tempest/latest/$1
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 067eb81..0a061b8 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -154,6 +154,9 @@
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
 html_static_path = ['_static']
+# Add any paths that contain "extra" files, such as .htaccess or
+# robots.txt.
+html_extra_path = ['_extra']
 
 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
 # using the given strftime format.
diff --git a/playbooks/devstack-tempest.yaml b/playbooks/devstack-tempest.yaml
new file mode 100644
index 0000000..a684984
--- /dev/null
+++ b/playbooks/devstack-tempest.yaml
@@ -0,0 +1,14 @@
+# Changes that run through devstack-tempest are likely to have an impact on
+# the devstack part of the job, so we keep devstack in the main play to
+# avoid zuul retrying on legitimate failures.
+- hosts: all
+  roles:
+    - run-devstack
+
+# We run tests only on one node, regardless how many nodes are in the system
+- hosts: tempest
+  roles:
+    - setup-tempest-run-dir
+    - setup-tempest-data-dir
+    - acl-devstack-files
+    - run-tempest
diff --git a/releasenotes/notes/add-support-args-kwargs-in-call-until-true-a91k592h5a64exf7.yaml b/releasenotes/notes/add-support-args-kwargs-in-call-until-true-a91k592h5a64exf7.yaml
new file mode 100644
index 0000000..e23abe3
--- /dev/null
+++ b/releasenotes/notes/add-support-args-kwargs-in-call-until-true-a91k592h5a64exf7.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - Add support of args and kwargs when calling func in call_until_true,
+    also to log the cost time when call_until_true returns True or False
+    for debuggin.
diff --git a/requirements.txt b/requirements.txt
index 8a2fa99..4b8de27 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -12,7 +12,7 @@
 oslo.config>=4.6.0 # Apache-2.0
 oslo.log>=3.30.0 # Apache-2.0
 oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
-oslo.utils>=3.28.0 # Apache-2.0
+oslo.utils>=3.31.0 # Apache-2.0
 six>=1.9.0 # MIT
 fixtures>=3.0.0 # Apache-2.0/BSD
 PyYAML>=3.10 # MIT
diff --git a/roles/acl-devstack-files/README.rst b/roles/acl-devstack-files/README.rst
new file mode 100644
index 0000000..76e7e58
--- /dev/null
+++ b/roles/acl-devstack-files/README.rst
@@ -0,0 +1,10 @@
+Grant global read access to devstack `files` folder.
+
+This is handy to grant the `tempest` user access to VM images for testing.
+
+**Role Variables**
+
+.. zuul:rolevar:: devstack_data_dir
+   :default: /opt/stack/data
+
+   The devstack data directory.
diff --git a/roles/acl-devstack-files/defaults/main.yaml b/roles/acl-devstack-files/defaults/main.yaml
new file mode 100644
index 0000000..14265f0
--- /dev/null
+++ b/roles/acl-devstack-files/defaults/main.yaml
@@ -0,0 +1 @@
+devstack_data_dir: /opt/stack/data
diff --git a/roles/acl-devstack-files/tasks/main.yaml b/roles/acl-devstack-files/tasks/main.yaml
new file mode 100644
index 0000000..b3eeec7
--- /dev/null
+++ b/roles/acl-devstack-files/tasks/main.yaml
@@ -0,0 +1,6 @@
+- name: Grant global read access to devstack files
+  file:
+    path: "{{devstack_data_dir}}/files"
+    mode: "o+rx"
+    recurse: yes
+  become: yes
diff --git a/roles/run-tempest/README.rst b/roles/run-tempest/README.rst
new file mode 100644
index 0000000..a75fc31
--- /dev/null
+++ b/roles/run-tempest/README.rst
@@ -0,0 +1,18 @@
+Run Tempest
+
+**Role Variables**
+
+.. zuul:rolevar:: devstack_base_dir
+   :default: /opt/stack
+
+   The devstack base directory.
+
+.. zuul:rolevar:: tempest_concurrency
+   :default: 0
+
+   The number of parallel test processes.
+
+.. zuul:rolevar:: tox_venvlist
+   :default: smoke
+
+   The Tempest tox environment to run.
diff --git a/roles/run-tempest/defaults/main.yaml b/roles/run-tempest/defaults/main.yaml
new file mode 100644
index 0000000..e1e81da
--- /dev/null
+++ b/roles/run-tempest/defaults/main.yaml
@@ -0,0 +1,2 @@
+devstack_base_dir: /opt/stack
+tox_venvlist: smoke
diff --git a/roles/run-tempest/tasks/main.yaml b/roles/run-tempest/tasks/main.yaml
new file mode 100644
index 0000000..d079513
--- /dev/null
+++ b/roles/run-tempest/tasks/main.yaml
@@ -0,0 +1,28 @@
+# NOTE(andreaf) The number of vcpus is not available on all systems.
+# See https://github.com/ansible/ansible/issues/30688
+# When not available, we fall back to ansible_processor_cores
+- name: Get hw.logicalcpu from sysctl
+  shell: sysctl hw.logicalcpu | cut -d' ' -f2
+  register: sysctl_hw_logicalcpu
+  when: ansible_processor_vcpus is not defined
+
+- name: Number of cores
+  set_fact:
+    num_cores: "{{ansible_processor_vcpus|default(sysctl_hw_logicalcpu.stdout)}}"
+
+- name: Set concurrency for cores == 3 or less
+  set_fact:
+    default_concurrency: "{{ num_cores }}"
+  when: num_cores|int <= 3
+
+- name: Limit max concurrency when more than 3 vcpus are available
+  set_fact:
+    default_concurrency: "{{ num_cores|int // 2 }}"
+  when: num_cores|int > 3
+
+- name: Run Tempest
+  command: tox -e {{tox_venvlist}} -- --concurrency={{tempest_concurrency|default(default_concurrency)}}
+  args:
+    chdir: "{{devstack_base_dir}}/tempest"
+  become: true
+  become_user: tempest
diff --git a/roles/setup-tempest-data-dir/README.rst b/roles/setup-tempest-data-dir/README.rst
new file mode 100644
index 0000000..db0b083
--- /dev/null
+++ b/roles/setup-tempest-data-dir/README.rst
@@ -0,0 +1,12 @@
+Setup the `tempest` user as owner of Tempest's data folder.
+
+Tempest's devstack plugin creates the data folder, but it has no knowledge
+of the `tempest` user, so we need a role to fix ownership on the data folder.
+
+
+**Role Variables**
+
+.. zuul:rolevar:: devstack_data_dir
+   :default: /opt/stack/data
+
+   The devstack data directory.
diff --git a/roles/setup-tempest-data-dir/defaults/main.yaml b/roles/setup-tempest-data-dir/defaults/main.yaml
new file mode 100644
index 0000000..14265f0
--- /dev/null
+++ b/roles/setup-tempest-data-dir/defaults/main.yaml
@@ -0,0 +1 @@
+devstack_data_dir: /opt/stack/data
diff --git a/roles/setup-tempest-data-dir/tasks/main.yaml b/roles/setup-tempest-data-dir/tasks/main.yaml
new file mode 100644
index 0000000..9dd6309
--- /dev/null
+++ b/roles/setup-tempest-data-dir/tasks/main.yaml
@@ -0,0 +1,7 @@
+- name: Set tempest as owner of Tempest data folder
+  file:
+    path: "{{devstack_data_dir}}/tempest"
+    owner: tempest
+    group: stack
+    recurse: yes
+  become: yes
diff --git a/roles/setup-tempest-run-dir/README.rst b/roles/setup-tempest-run-dir/README.rst
new file mode 100644
index 0000000..c8e2339
--- /dev/null
+++ b/roles/setup-tempest-run-dir/README.rst
@@ -0,0 +1,14 @@
+Setup Tempest run folder.
+
+To support isolation between multiple runs, separate run folders are required.
+Set `tempest` as owner of Tempest's current run folder.
+There is an implicit assumption here of a one to one relationship between
+devstack versions and Tempest runs.
+
+
+**Role Variables**
+
+.. zuul:rolevar:: devstack_base_dir
+   :default: /opt/stack
+
+   The devstack base directory.
diff --git a/roles/setup-tempest-run-dir/defaults/main.yaml b/roles/setup-tempest-run-dir/defaults/main.yaml
new file mode 100644
index 0000000..fea05c8
--- /dev/null
+++ b/roles/setup-tempest-run-dir/defaults/main.yaml
@@ -0,0 +1 @@
+devstack_base_dir: /opt/stack
diff --git a/roles/setup-tempest-run-dir/tasks/main.yaml b/roles/setup-tempest-run-dir/tasks/main.yaml
new file mode 100644
index 0000000..a012d72
--- /dev/null
+++ b/roles/setup-tempest-run-dir/tasks/main.yaml
@@ -0,0 +1,7 @@
+- name: Set tempest as owner of Tempest run folder
+  file:
+    path: "{{devstack_base_dir}}/tempest"
+    owner: tempest
+    group: stack
+    recurse: yes
+  become: yes
diff --git a/tempest/api/compute/admin/test_fixed_ips.py b/tempest/api/compute/admin/test_fixed_ips.py
index ebba73c..66c2c2d 100644
--- a/tempest/api/compute/admin/test_fixed_ips.py
+++ b/tempest/api/compute/admin/test_fixed_ips.py
@@ -42,6 +42,7 @@
         super(FixedIPsTestJson, cls).resource_setup()
         server = cls.create_test_server(wait_until='ACTIVE')
         server = cls.servers_client.show_server(server['id'])['server']
+        cls.ip = None
         for ip_set in server['addresses']:
             for ip in server['addresses'][ip_set]:
                 if ip['OS-EXT-IPS:type'] == 'fixed':
@@ -49,6 +50,9 @@
                     break
             if cls.ip:
                 break
+        if cls.ip is None:
+            raise cls.skipException("No fixed ip found for server: %s"
+                                    % server['id'])
 
     @decorators.idempotent_id('16b7d848-2f7c-4709-85a3-2dfb4576cc52')
     def test_list_fixed_ip_details(self):
diff --git a/tempest/api/compute/admin/test_fixed_ips_negative.py b/tempest/api/compute/admin/test_fixed_ips_negative.py
index a5deb3c..7d41f46 100644
--- a/tempest/api/compute/admin/test_fixed_ips_negative.py
+++ b/tempest/api/compute/admin/test_fixed_ips_negative.py
@@ -43,6 +43,7 @@
         super(FixedIPsNegativeTestJson, cls).resource_setup()
         server = cls.create_test_server(wait_until='ACTIVE')
         server = cls.servers_client.show_server(server['id'])['server']
+        cls.ip = None
         for ip_set in server['addresses']:
             for ip in server['addresses'][ip_set]:
                 if ip['OS-EXT-IPS:type'] == 'fixed':
@@ -50,6 +51,9 @@
                     break
             if cls.ip:
                 break
+        if cls.ip is None:
+            raise cls.skipException("No fixed ip found for server: %s"
+                                    % server['id'])
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('9f17f47d-daad-4adc-986e-12370c93e407')
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 6fe4d82..bce7524 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -281,45 +281,61 @@
         self.assertEqual(self.server_id,
                          vol_after_rebuild['attachments'][0]['server_id'])
 
-    def _test_resize_server_confirm(self, stop=False):
+    def _test_resize_server_confirm(self, server_id, stop=False):
         # The server's RAM and disk space should be modified to that of
         # the provided flavor
 
         if stop:
-            self.client.stop_server(self.server_id)
-            waiters.wait_for_server_status(self.client, self.server_id,
+            self.client.stop_server(server_id)
+            waiters.wait_for_server_status(self.client, server_id,
                                            'SHUTOFF')
 
-        self.client.resize_server(self.server_id, self.flavor_ref_alt)
+        self.client.resize_server(server_id, self.flavor_ref_alt)
         # NOTE(jlk): Explicitly delete the server to get a new one for later
         # tests. Avoids resize down race issues.
-        self.addCleanup(self.delete_server, self.server_id)
-        waiters.wait_for_server_status(self.client, self.server_id,
+        self.addCleanup(self.delete_server, server_id)
+        waiters.wait_for_server_status(self.client, server_id,
                                        'VERIFY_RESIZE')
 
-        self.client.confirm_resize_server(self.server_id)
+        self.client.confirm_resize_server(server_id)
         expected_status = 'SHUTOFF' if stop else 'ACTIVE'
-        waiters.wait_for_server_status(self.client, self.server_id,
+        waiters.wait_for_server_status(self.client, server_id,
                                        expected_status)
 
-        server = self.client.show_server(self.server_id)['server']
+        server = self.client.show_server(server_id)['server']
         self.assertEqual(self.flavor_ref_alt, server['flavor']['id'])
 
         if stop:
             # NOTE(mriedem): tearDown requires the server to be started.
-            self.client.start_server(self.server_id)
+            self.client.start_server(server_id)
 
     @decorators.idempotent_id('1499262a-9328-4eda-9068-db1ac57498d2')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize not available.')
     def test_resize_server_confirm(self):
-        self._test_resize_server_confirm(stop=False)
+        self._test_resize_server_confirm(self.server_id, stop=False)
+
+    @decorators.idempotent_id('e6c28180-7454-4b59-b188-0257af08a63b')
+    @decorators.related_bug('1728603')
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
+    @utils.services('volume')
+    def test_resize_volume_backed_server_confirm(self):
+        # We have to create a new server that is volume-backed since the one
+        # from setUp is not volume-backed.
+        server = self.create_test_server(
+            volume_backed=True, wait_until='ACTIVE')
+        self._test_resize_server_confirm(server['id'])
+        # Now do something interactive with the guest like get its console
+        # output; we don't actually care about the output, just that it doesn't
+        # raise an error.
+        self.client.get_console_output(server['id'])
 
     @decorators.idempotent_id('138b131d-66df-48c9-a171-64f45eb92962')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize not available.')
     def test_resize_server_confirm_from_stopped(self):
-        self._test_resize_server_confirm(stop=True)
+        self._test_resize_server_confirm(self.server_id, stop=True)
 
     @decorators.idempotent_id('c03aab19-adb1-44f5-917d-c419577e9e68')
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py
index a128b3f..d0aa7dc 100644
--- a/tempest/cmd/cleanup.py
+++ b/tempest/cmd/cleanup.py
@@ -54,17 +54,17 @@
 not delete the projects themselves.
 
 **--dry-run**: Creates a report (``./dry_run.json``) of the projects that will
-be cleaned up (in the ``_tenants_to_clean`` dictionary [1]_) and the global
+be cleaned up (in the ``_projects_to_clean`` dictionary [1]_) and the global
 objects that will be removed (domains, flavors, images, roles, projects,
 and users). Once the cleanup command is executed (e.g. run without
 parameters), running it again with **--dry-run** should yield an empty report.
 
 **--help**: Print the help text for the command and parameters.
 
-.. [1] The ``_tenants_to_clean`` dictionary in ``dry_run.json`` lists the
+.. [1] The ``_projects_to_clean`` dictionary in ``dry_run.json`` lists the
     projects that ``tempest cleanup`` will loop through to delete child
     objects, but the command will, by default, not delete the projects
-    themselves. This may differ from the ``tenants`` list as you can clean
+    themselves. This may differ from the ``projects`` list as you can clean
     the Tempest and alternate Tempest users and projects but they will not be
     deleted unless the **--delete-tempest-conf-objects** flag is used to
     force their deletion.
@@ -111,13 +111,13 @@
 
         self.admin_id = ""
         self.admin_role_id = ""
-        self.admin_tenant_id = ""
+        self.admin_project_id = ""
         self._init_admin_ids()
 
         self.admin_role_added = []
 
         # available services
-        self.tenant_services = cleanup_service.get_tenant_cleanup_services()
+        self.project_services = cleanup_service.get_project_cleanup_services()
         self.global_services = cleanup_service.get_global_cleanup_services()
 
         if parsed_args.init_saved_state:
@@ -133,24 +133,24 @@
         is_save_state = False
 
         if is_dry_run:
-            self.dry_run_data["_tenants_to_clean"] = {}
+            self.dry_run_data["_projects_to_clean"] = {}
 
         admin_mgr = self.admin_mgr
-        # Always cleanup tempest and alt tempest tenants unless
+        # Always cleanup tempest and alt tempest projects unless
         # they are in saved state json. Therefore is_preserve is False
         kwargs = {'data': self.dry_run_data,
                   'is_dry_run': is_dry_run,
                   'saved_state_json': self.json_data,
                   'is_preserve': False,
                   'is_save_state': is_save_state}
-        tenant_service = cleanup_service.TenantService(admin_mgr, **kwargs)
-        tenants = tenant_service.list()
-        print("Process %s tenants" % len(tenants))
+        project_service = cleanup_service.ProjectService(admin_mgr, **kwargs)
+        projects = project_service.list()
+        print("Process %s projects" % len(projects))
 
-        # Loop through list of tenants and clean them up.
-        for tenant in tenants:
-            self._add_admin(tenant['id'])
-            self._clean_tenant(tenant)
+        # Loop through list of projects and clean them up.
+        for project in projects:
+            self._add_admin(project['id'])
+            self._clean_project(project)
 
         kwargs = {'data': self.dry_run_data,
                   'is_dry_run': is_dry_run,
@@ -169,49 +169,51 @@
         self._remove_admin_user_roles()
 
     def _remove_admin_user_roles(self):
-        tenant_ids = self.admin_role_added
-        LOG.debug("Removing admin user roles where needed for tenants: %s",
-                  tenant_ids)
-        for tenant_id in tenant_ids:
-            self._remove_admin_role(tenant_id)
+        project_ids = self.admin_role_added
+        LOG.debug("Removing admin user roles where needed for projects: %s",
+                  project_ids)
+        for project_id in project_ids:
+            self._remove_admin_role(project_id)
 
-    def _clean_tenant(self, tenant):
-        print("Cleaning tenant:  %s " % tenant['name'])
+    def _clean_project(self, project):
+        print("Cleaning project:  %s " % project['name'])
         is_dry_run = self.options.dry_run
         dry_run_data = self.dry_run_data
         is_preserve = not self.options.delete_tempest_conf_objects
-        tenant_id = tenant['id']
-        tenant_name = tenant['name']
-        tenant_data = None
+        project_id = project['id']
+        project_name = project['name']
+        project_data = None
         if is_dry_run:
-            tenant_data = dry_run_data["_tenants_to_clean"][tenant_id] = {}
-            tenant_data['name'] = tenant_name
+            project_data = dry_run_data["_projects_to_clean"][project_id] = {}
+            project_data['name'] = project_name
 
         kwargs = {"username": CONF.auth.admin_username,
                   "password": CONF.auth.admin_password,
-                  "tenant_name": tenant['name']}
+                  "project_name": project['name']}
         mgr = clients.Manager(credentials=credentials.get_credentials(
             **kwargs))
-        kwargs = {'data': tenant_data,
+        kwargs = {'data': project_data,
                   'is_dry_run': is_dry_run,
                   'saved_state_json': None,
                   'is_preserve': is_preserve,
                   'is_save_state': False,
-                  'tenant_id': tenant_id}
-        for service in self.tenant_services:
+                  'project_id': project_id}
+        for service in self.project_services:
             svc = service(mgr, **kwargs)
             svc.run()
 
     def _init_admin_ids(self):
-        tn_cl = self.admin_mgr.tenants_client
-        rl_cl = self.admin_mgr.roles_client
+        pr_cl = self.admin_mgr.projects_client
+        rl_cl = self.admin_mgr.roles_v3_client
+        rla_cl = self.admin_mgr.role_assignments_client
+        us_cl = self.admin_mgr.users_v3_client
 
-        tenant = identity.get_tenant_by_name(tn_cl,
-                                             CONF.auth.admin_project_name)
-        self.admin_tenant_id = tenant['id']
-
-        user = identity.get_user_by_username(tn_cl, self.admin_tenant_id,
-                                             CONF.auth.admin_username)
+        project = identity.get_project_by_name(pr_cl,
+                                               CONF.auth.admin_project_name)
+        self.admin_project_id = project['id']
+        user = identity.get_user_by_project(us_cl, rla_cl,
+                                            self.admin_project_id,
+                                            CONF.auth.admin_username)
         self.admin_id = user['id']
 
         roles = rl_cl.list_roles()['roles']
@@ -236,7 +238,7 @@
                             dest='delete_tempest_conf_objects',
                             default=False,
                             help="Force deletion of the tempest and "
-                            "alternate tempest users and tenants.")
+                            "alternate tempest users and projects.")
         parser.add_argument('--dry-run', action="store_true",
                             dest='dry_run', default=False,
                             help="Generate JSON file:" + DRY_RUN_JSON +
@@ -247,44 +249,44 @@
     def get_description(self):
         return 'Cleanup after tempest run'
 
-    def _add_admin(self, tenant_id):
-        rl_cl = self.admin_mgr.roles_client
+    def _add_admin(self, project_id):
+        rl_cl = self.admin_mgr.roles_v3_client
         needs_role = True
-        roles = rl_cl.list_user_roles_on_project(tenant_id,
+        roles = rl_cl.list_user_roles_on_project(project_id,
                                                  self.admin_id)['roles']
         for role in roles:
             if role['id'] == self.admin_role_id:
                 needs_role = False
-                LOG.debug("User already had admin privilege for this tenant")
+                LOG.debug("User already had admin privilege for this project")
         if needs_role:
-            LOG.debug("Adding admin privilege for : %s", tenant_id)
-            rl_cl.create_user_role_on_project(tenant_id, self.admin_id,
+            LOG.debug("Adding admin privilege for : %s", project_id)
+            rl_cl.create_user_role_on_project(project_id, self.admin_id,
                                               self.admin_role_id)
-            self.admin_role_added.append(tenant_id)
+            self.admin_role_added.append(project_id)
 
-    def _remove_admin_role(self, tenant_id):
-        LOG.debug("Remove admin user role for tenant: %s", tenant_id)
+    def _remove_admin_role(self, project_id):
+        LOG.debug("Remove admin user role for projectt: %s", project_id)
         # Must initialize Admin Manager for each user role
         # Otherwise authentication exception is thrown, weird
         id_cl = clients.Manager(
             credentials.get_configured_admin_credentials()).identity_client
-        if (self._tenant_exists(tenant_id)):
+        if (self._project_exists(project_id)):
             try:
-                id_cl.delete_role_from_user_on_project(tenant_id,
+                id_cl.delete_role_from_user_on_project(project_id,
                                                        self.admin_id,
                                                        self.admin_role_id)
             except Exception as ex:
-                LOG.exception("Failed removing role from tenant which still"
+                LOG.exception("Failed removing role from project which still"
                               "exists, exception: %s", ex)
 
-    def _tenant_exists(self, tenant_id):
-        tn_cl = self.admin_mgr.tenants_client
+    def _project_exists(self, project_id):
+        pr_cl = self.admin_mgr.projects_client
         try:
-            t = tn_cl.show_tenant(tenant_id)
-            LOG.debug("Tenant is: %s", str(t))
+            p = pr_cl.show_project(project_id)
+            LOG.debug("Project is: %s", str(p))
             return True
         except Exception as ex:
-            LOG.debug("Tenant no longer exists? %s", ex)
+            LOG.debug("Project no longer exists? %s", ex)
             return False
 
     def _init_state(self):
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index c75bc85..d1e80f1 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -32,7 +32,7 @@
 CONF_PRIV_NETWORK_NAME = None
 CONF_PUB_NETWORK = None
 CONF_PUB_ROUTER = None
-CONF_TENANTS = None
+CONF_PROJECTS = None
 CONF_USERS = None
 
 IS_CINDER = None
@@ -50,7 +50,7 @@
     global CONF_PRIV_NETWORK_NAME
     global CONF_PUB_NETWORK
     global CONF_PUB_ROUTER
-    global CONF_TENANTS
+    global CONF_PROJECTS
     global CONF_USERS
     global IS_CINDER
     global IS_GLANCE
@@ -69,7 +69,7 @@
     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.auth.admin_project_name]
+    CONF_PROJECTS = [CONF.auth.admin_project_name]
     CONF_USERS = [CONF.auth.admin_username]
 
     if IS_NEUTRON:
@@ -82,14 +82,14 @@
     am = clients.Manager(
         credentials.get_configured_admin_credentials())
     net_cl = am.networks_client
-    tn_cl = am.tenants_client
+    pr_cl = am.projects_client
 
     networks = net_cl.list_networks()
-    tenant = identity.get_tenant_by_name(tn_cl, project_name)
-    t_id = tenant['id']
+    project = identity.get_project_by_name(pr_cl, project_name)
+    p_id = project['id']
     n_id = None
     for net in networks['networks']:
-        if (net['tenant_id'] == t_id and net['name'] == net_name):
+        if (net['project_id'] == p_id and net['name'] == net_name):
             n_id = net['id']
             break
     return n_id
@@ -141,7 +141,7 @@
 
     def __init__(self, manager, **kwargs):
         super(SnapshotService, self).__init__(kwargs)
-        self.client = manager.snapshots_client
+        self.client = manager.snapshots_client_latest
 
     def list(self):
         client = self.client
@@ -319,7 +319,7 @@
 class VolumeService(BaseService):
     def __init__(self, manager, **kwargs):
         super(VolumeService, self).__init__(kwargs)
-        self.client = manager.volumes_client
+        self.client = manager.volumes_client_latest
 
     def list(self):
         client = self.client
@@ -344,7 +344,7 @@
 class VolumeQuotaService(BaseService):
     def __init__(self, manager, **kwargs):
         super(VolumeQuotaService, self).__init__(kwargs)
-        self.client = manager.volume_quotas_client
+        self.client = manager.volume_quotas_v2_client
 
     def delete(self):
         client = self.client
@@ -786,14 +786,14 @@
 class IdentityService(BaseService):
     def __init__(self, manager, **kwargs):
         super(IdentityService, self).__init__(kwargs)
-        self.client = manager.identity_client
+        self.client = manager.identity_v3_client
 
 
 class UserService(BaseService):
 
     def __init__(self, manager, **kwargs):
         super(UserService, self).__init__(kwargs)
-        self.client = manager.users_client
+        self.client = manager.users_v3_client
 
     def list(self):
         users = self.client.list_users()['users']
@@ -872,43 +872,43 @@
             self.data['roles'][role['id']] = role['name']
 
 
-class TenantService(BaseService):
+class ProjectService(BaseService):
 
     def __init__(self, manager, **kwargs):
-        super(TenantService, self).__init__(kwargs)
-        self.client = manager.tenants_client
+        super(ProjectService, self).__init__(kwargs)
+        self.client = manager.projects_client
 
     def list(self):
-        tenants = self.client.list_tenants()['tenants']
+        projects = self.client.list_projects()['projects']
         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.auth.admin_project_name)]
+            projects = [project for project in projects if (project['id']
+                        not in self.saved_state_json['projects'].keys()
+                        and project['name'] != CONF.auth.admin_project_name)]
 
         if self.is_preserve:
-            tenants = [tenant for tenant in tenants if tenant['name']
-                       not in CONF_TENANTS]
+            projects = [project for project in projects if project['name']
+                        not in CONF_PROJECTS]
 
-        LOG.debug("List count, %s Tenants after reconcile", len(tenants))
-        return tenants
+        LOG.debug("List count, %s Projects after reconcile", len(projects))
+        return projects
 
     def delete(self):
-        tenants = self.list()
-        for tenant in tenants:
+        projects = self.list()
+        for project in projects:
             try:
-                self.client.delete_tenant(tenant['id'])
+                self.client.delete_project(project['id'])
             except Exception:
-                LOG.exception("Delete Tenant exception.")
+                LOG.exception("Delete project exception.")
 
     def dry_run(self):
-        tenants = self.list()
-        self.data['tenants'] = tenants
+        projects = self.list()
+        self.data['projects'] = projects
 
     def save_state(self):
-        tenants = self.list()
-        self.data['tenants'] = {}
-        for tenant in tenants:
-            self.data['tenants'][tenant['id']] = tenant['name']
+        projects = self.list()
+        self.data['projects'] = {}
+        for project in projects:
+            self.data['projects'][project['id']] = project['name']
 
 
 class DomainService(BaseService):
@@ -948,35 +948,35 @@
             self.data['domains'][domain['id']] = domain['name']
 
 
-def get_tenant_cleanup_services():
-    tenant_services = []
+def get_project_cleanup_services():
+    project_services = []
     # TODO(gmann): Tempest should provide some plugin hook for cleanup
     # script extension to plugin tests also.
     if IS_NOVA:
-        tenant_services.append(ServerService)
-        tenant_services.append(KeyPairService)
-        tenant_services.append(SecurityGroupService)
-        tenant_services.append(ServerGroupService)
+        project_services.append(ServerService)
+        project_services.append(KeyPairService)
+        project_services.append(SecurityGroupService)
+        project_services.append(ServerGroupService)
         if not IS_NEUTRON:
-            tenant_services.append(FloatingIpService)
-        tenant_services.append(NovaQuotaService)
+            project_services.append(FloatingIpService)
+        project_services.append(NovaQuotaService)
     if IS_HEAT:
-        tenant_services.append(StackService)
+        project_services.append(StackService)
     if IS_NEUTRON:
-        tenant_services.append(NetworkFloatingIpService)
+        project_services.append(NetworkFloatingIpService)
         if utils.is_extension_enabled('metering', 'network'):
-            tenant_services.append(NetworkMeteringLabelRuleService)
-            tenant_services.append(NetworkMeteringLabelService)
-        tenant_services.append(NetworkRouterService)
-        tenant_services.append(NetworkPortService)
-        tenant_services.append(NetworkSubnetService)
-        tenant_services.append(NetworkService)
-        tenant_services.append(NetworkSecGroupService)
+            project_services.append(NetworkMeteringLabelRuleService)
+            project_services.append(NetworkMeteringLabelService)
+        project_services.append(NetworkRouterService)
+        project_services.append(NetworkPortService)
+        project_services.append(NetworkSubnetService)
+        project_services.append(NetworkService)
+        project_services.append(NetworkSecGroupService)
     if IS_CINDER:
-        tenant_services.append(SnapshotService)
-        tenant_services.append(VolumeService)
-        tenant_services.append(VolumeQuotaService)
-    return tenant_services
+        project_services.append(SnapshotService)
+        project_services.append(VolumeService)
+        project_services.append(VolumeQuotaService)
+    return project_services
 
 
 def get_global_cleanup_services():
@@ -986,7 +986,7 @@
     if IS_GLANCE:
         global_services.append(ImageService)
     global_services.append(UserService)
-    global_services.append(TenantService)
+    global_services.append(ProjectService)
     global_services.append(DomainService)
     global_services.append(RoleService)
     return global_services
diff --git a/tempest/common/identity.py b/tempest/common/identity.py
index 6e496d3..eaf651b 100644
--- a/tempest/common/identity.py
+++ b/tempest/common/identity.py
@@ -20,6 +20,15 @@
 CONF = config.CONF
 
 
+def get_project_by_name(client, project_name):
+    projects = client.list_projects({'name': project_name})['projects']
+    for project in projects:
+        if project['name'] == project_name:
+            return project
+    raise lib_exc.NotFound('No such project(%s) in %s' % (project_name,
+                           projects))
+
+
 def get_tenant_by_name(client, tenant_name):
     tenants = client.list_tenants()['tenants']
     for tenant in tenants:
@@ -36,6 +45,18 @@
     raise lib_exc.NotFound('No such user(%s) in %s' % (username, users))
 
 
+def get_user_by_project(users_client, roles_client, project_id, username):
+    users = users_client.list_users(**{'name': username})['users']
+    users_in_project = roles_client.list_role_assignments(
+        **{'scope.project.id': project_id})['role_assignments']
+    for user in users:
+        if user['name'] == username:
+            for u in users_in_project:
+                if u['user']['id'] == user['id']:
+                    return user
+    raise lib_exc.NotFound('No such user(%s) in %s' % (username, users))
+
+
 def identity_utils(clients):
     """A client that abstracts v2 and v3 identity operations.
 
diff --git a/tempest/lib/common/utils/test_utils.py b/tempest/lib/common/utils/test_utils.py
index bd0db7c..c2e93ee 100644
--- a/tempest/lib/common/utils/test_utils.py
+++ b/tempest/lib/common/utils/test_utils.py
@@ -86,22 +86,29 @@
         pass
 
 
-def call_until_true(func, duration, sleep_for):
+def call_until_true(func, duration, sleep_for, *args, **kwargs):
     """Call the given function until it returns True (and return True)
 
     or until the specified duration (in seconds) elapses (and return False).
 
-    :param func: A zero argument callable that returns True on success.
+    :param func: A callable that returns True on success.
     :param duration: The number of seconds for which to attempt a
         successful call of the function.
     :param sleep_for: The number of seconds to sleep after an unsuccessful
                       invocation of the function.
+    :param args: args that are passed to func.
+    :param kwargs: kwargs that are passed to func.
     """
     now = time.time()
+    begin_time = now
     timeout = now + duration
     while now < timeout:
-        if func():
+        if func(*args, **kwargs):
+            LOG.debug("Call %s returns true in %f seconds",
+                      getattr(func, '__name__'), time.time() - begin_time)
             return True
         time.sleep(sleep_for)
         now = time.time()
+    LOG.debug("Call %s returns false in %f seconds",
+              getattr(func, '__name__'), duration)
     return False
diff --git a/tempest/lib/services/volume/v1/encryption_types_client.py b/tempest/lib/services/volume/v1/encryption_types_client.py
index 067b4e8..0fac6bd 100644
--- a/tempest/lib/services/volume/v1/encryption_types_client.py
+++ b/tempest/lib/services/volume/v1/encryption_types_client.py
@@ -49,9 +49,9 @@
     def create_encryption_type(self, volume_type_id, **kwargs):
         """Create encryption type.
 
-        TODO: Current api-site doesn't contain this API description.
-        After fixing the api-site, we need to fix here also for putting
-        the link to api-site.
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/block-storage/v2/#create-an-encryption-type-for-v2
         """
         url = "/types/%s/encryption" % volume_type_id
         post_body = json.dumps({'encryption': kwargs})
diff --git a/tempest/lib/services/volume/v1/hosts_client.py b/tempest/lib/services/volume/v1/hosts_client.py
index 56ba12c..9b19b84 100644
--- a/tempest/lib/services/volume/v1/hosts_client.py
+++ b/tempest/lib/services/volume/v1/hosts_client.py
@@ -23,8 +23,12 @@
     """Client class to send CRUD Volume Host API V1 requests"""
 
     def list_hosts(self, **params):
-        """Lists all hosts."""
+        """Lists all hosts.
 
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/block-storage/v2/#list-all-hosts
+        """
         url = 'os-hosts'
         if params:
             url += '?%s' % urllib.urlencode(params)
diff --git a/tempest/lib/services/volume/v1/qos_client.py b/tempest/lib/services/volume/v1/qos_client.py
index e247b7b..593bddd 100644
--- a/tempest/lib/services/volume/v1/qos_client.py
+++ b/tempest/lib/services/volume/v1/qos_client.py
@@ -92,7 +92,9 @@
 
         :param keys: keys to delete from the QoS specification.
 
-        TODO(jordanP): Add a link once LP #1524877 is fixed.
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/block-storage/v2/#unset-keys-in-qos-specification
         """
         put_body = json.dumps({'keys': keys})
         resp, body = self.put('qos-specs/%s/delete_keys' % qos_id, put_body)
diff --git a/tempest/lib/services/volume/v1/quotas_client.py b/tempest/lib/services/volume/v1/quotas_client.py
index 678fd82..84f34f2 100644
--- a/tempest/lib/services/volume/v1/quotas_client.py
+++ b/tempest/lib/services/volume/v1/quotas_client.py
@@ -47,7 +47,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref-blockstorage-v1.html#updateQuota
+        https://developer.openstack.org/api-ref/block-storage/v2/#update-quotas
         """
         put_body = jsonutils.dumps({'quota_set': kwargs})
         resp, body = self.put('os-quota-sets/%s' % tenant_id, put_body)
diff --git a/tempest/lib/services/volume/v1/snapshots_client.py b/tempest/lib/services/volume/v1/snapshots_client.py
index 3433e68..51f7b9b 100644
--- a/tempest/lib/services/volume/v1/snapshots_client.py
+++ b/tempest/lib/services/volume/v1/snapshots_client.py
@@ -27,7 +27,8 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#list-snapshots-with-details-v1
+        https://developer.openstack.org/api-ref/block-storage/v2/#list-snapshots
+        https://developer.openstack.org/api-ref/block-storage/v2/#list-snapshots-with-details
         """
         url = 'snapshots'
         if detail:
@@ -45,7 +46,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#show-snapshot-details-v1
+        https://developer.openstack.org/api-ref/block-storage/v2/#show-snapshot-details
         """
         url = "snapshots/%s" % snapshot_id
         resp, body = self.get(url)
@@ -58,7 +59,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#create-snapshot-v1
+        https://developer.openstack.org/api-ref/block-storage/v2/#create-snapshot
         """
         post_body = json.dumps({'snapshot': kwargs})
         resp, body = self.post('snapshots', post_body)
@@ -71,7 +72,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#delete-snapshot-v1
+        https://developer.openstack.org/api-ref/block-storage/v2/#delete-snapshot
         """
         resp, body = self.delete("snapshots/%s" % snapshot_id)
         self.expected_success(202, resp.status)
@@ -123,7 +124,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#update-snapshot-v1
+        https://developer.openstack.org/api-ref/block-storage/v2/#update-snapshot
         """
         put_body = json.dumps({'snapshot': kwargs})
         resp, body = self.put('snapshots/%s' % snapshot_id, put_body)
@@ -136,7 +137,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#show-snapshot-metadata-v1
+        https://developer.openstack.org/api-ref/block-storage/v2/#show-snapshot-metadata
         """
         url = "snapshots/%s/metadata" % snapshot_id
         resp, body = self.get(url)
@@ -149,7 +150,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#update-snapshot-metadata-v1
+        https://developer.openstack.org/api-ref/block-storage/v2/#update-snapshot-metadata
         """
         put_body = json.dumps(kwargs)
         url = "snapshots/%s/metadata" % snapshot_id
diff --git a/tempest/lib/services/volume/v1/types_client.py b/tempest/lib/services/volume/v1/types_client.py
index 4ae9935..58a80b7 100644
--- a/tempest/lib/services/volume/v1/types_client.py
+++ b/tempest/lib/services/volume/v1/types_client.py
@@ -40,7 +40,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#list-volume-types-v1
+        https://developer.openstack.org/api-ref/block-storage/v2/#list-all-volume-types-for-v2
         """
         url = 'types'
         if params:
@@ -56,7 +56,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#show-volume-type-v1
+        https://developer.openstack.org/api-ref/block-storage/v2/#show-volume-type-details-for-v2
         """
         url = "types/%s" % volume_type_id
         resp, body = self.get(url)
@@ -69,7 +69,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#create-volume-type-v1
+        https://developer.openstack.org/api-ref/block-storage/v2/#create-volume-type-for-v2
         """
         post_body = json.dumps({'volume_type': kwargs})
         resp, body = self.post('types', post_body)
@@ -82,7 +82,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#delete-volume-type-v1
+        https://developer.openstack.org/api-ref/block-storage/v2/#delete-volume-type
         """
         resp, body = self.delete("types/%s" % volume_type_id)
         self.expected_success(202, resp.status)
@@ -137,7 +137,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#update-volume-type-v1
+        https://developer.openstack.org/api-ref/block-storage/v2/#update-volume-type
         """
         put_body = json.dumps({'volume_type': kwargs})
         resp, body = self.put('types/%s' % volume_type_id, put_body)
@@ -155,7 +155,7 @@
                      updated value.
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#update-extra-specs-for-a-volume-type-v1
+        https://developer.openstack.org/api-ref/block-storage/v2/#update-extra-specs-for-a-volume-type
         """
         url = "types/%s/extra_specs/%s" % (volume_type_id, extra_spec_name)
         put_body = json.dumps(extra_specs)
diff --git a/tempest/lib/services/volume/v1/volumes_client.py b/tempest/lib/services/volume/v1/volumes_client.py
index 7a25697..0e6ea9f 100644
--- a/tempest/lib/services/volume/v1/volumes_client.py
+++ b/tempest/lib/services/volume/v1/volumes_client.py
@@ -38,6 +38,11 @@
         """List all the volumes created.
 
         Params can be a string (must be urlencoded) or a dictionary.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/block-storage/v2/#list-volumes
+        https://developer.openstack.org/api-ref/block-storage/v2/#list-volumes-with-details
         """
         url = 'volumes'
         if detail:
@@ -63,7 +68,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#create-volume
+        https://developer.openstack.org/api-ref/block-storage/v2/#create-volume
         """
         post_body = json.dumps({'volume': kwargs})
         resp, body = self.post('volumes', post_body)
@@ -76,7 +81,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#update-volume
+        https://developer.openstack.org/api-ref/block-storage/v2/#update-volume
         """
         put_body = json.dumps({'volume': kwargs})
         resp, body = self.put('volumes/%s' % volume_id, put_body)
@@ -104,7 +109,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#attach-volume
+        https://developer.openstack.org/api-ref/block-storage/v2/#attach-volume-to-server
         """
         post_body = json.dumps({'os-attach': kwargs})
         url = 'volumes/%s/action' % (volume_id)
@@ -161,7 +166,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#extend-volume
+        https://developer.openstack.org/api-ref/block-storage/v2/#extend-volume-size
         """
         post_body = json.dumps({'os-extend': kwargs})
         url = 'volumes/%s/action' % (volume_id)
@@ -174,7 +179,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#reset-volume-status
+        https://developer.openstack.org/api-ref/block-storage/v2/#reset-volume-statuses
         """
         post_body = json.dumps({'os-reset_status': kwargs})
         resp, body = self.post('volumes/%s/action' % volume_id, post_body)
@@ -186,7 +191,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#create-volume-transfer
+        https://developer.openstack.org/api-ref/block-storage/v2/#create-volume-transfer
         """
         post_body = json.dumps({'transfer': kwargs})
         resp, body = self.post('os-volume-transfer', post_body)
@@ -207,7 +212,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#list-volume-transfers
+        https://developer.openstack.org/api-ref/block-storage/v2/#list-volume-transfers
         """
         url = 'os-volume-transfer'
         if params:
@@ -228,7 +233,7 @@
 
         For a full list of available parameters, please refer to the official
         API reference:
-        http://developer.openstack.org/api-ref/block-storage/v1/#accept-volume-transfer
+        https://developer.openstack.org/api-ref/block-storage/v2/#accept-volume-transfer
         """
         url = 'os-volume-transfer/%s/accept' % transfer_id
         post_body = json.dumps({'accept': kwargs})
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index 210f0ba..934e1dd 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -12,8 +12,6 @@
 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 #    License for the specific language governing permissions and limitations
 #    under the License.
-import functools
-
 from tempest.common import utils
 from tempest import config
 from tempest.lib.common.utils import test_utils
@@ -183,17 +181,13 @@
         for i in range(n_subnets6):
             # v6 should be configured since the image supports it
             # It can take time for ipv6 automatic address to get assigned
-            srv1_v6_addr_assigned = functools.partial(
-                guest_has_address, sshv4_1, ips_from_api_1['6'][i])
+            self.assertTrue(test_utils.call_until_true(guest_has_address,
+                            CONF.validation.ping_timeout, 1,
+                            sshv4_1, ips_from_api_1['6'][i]))
 
-            srv2_v6_addr_assigned = functools.partial(
-                guest_has_address, sshv4_2, ips_from_api_2['6'][i])
-
-            self.assertTrue(test_utils.call_until_true(srv1_v6_addr_assigned,
-                            CONF.validation.ping_timeout, 1))
-
-            self.assertTrue(test_utils.call_until_true(srv2_v6_addr_assigned,
-                            CONF.validation.ping_timeout, 1))
+            self.assertTrue(test_utils.call_until_true(guest_has_address,
+                            CONF.validation.ping_timeout, 1,
+                            sshv4_2, ips_from_api_2['6'][i]))
 
         self.check_remote_connectivity(sshv4_1, ips_from_api_2['4'])
         self.check_remote_connectivity(sshv4_2, ips_from_api_1['4'])
diff --git a/tempest/scenario/test_server_advanced_ops.py b/tempest/scenario/test_server_advanced_ops.py
index d4f29ad..89b9fdd 100644
--- a/tempest/scenario/test_server_advanced_ops.py
+++ b/tempest/scenario/test_server_advanced_ops.py
@@ -42,28 +42,6 @@
         super(TestServerAdvancedOps, cls).setup_credentials()
 
     @decorators.attr(type='slow')
-    @decorators.idempotent_id('e6c28180-7454-4b59-b188-0257af08a63b')
-    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
-                          'Resize is not available.')
-    @utils.services('compute', 'volume')
-    def test_resize_volume_backed_server_confirm(self):
-        # We create an instance for use in this test
-        instance = self.create_server(volume_backed=True)
-        instance_id = instance['id']
-        resize_flavor = CONF.compute.flavor_ref_alt
-        LOG.debug("Resizing instance %s from flavor %s to flavor %s",
-                  instance['id'], instance['flavor']['id'], resize_flavor)
-        self.servers_client.resize_server(instance_id, resize_flavor)
-        waiters.wait_for_server_status(self.servers_client, instance_id,
-                                       'VERIFY_RESIZE')
-
-        LOG.debug("Confirming resize of instance %s", instance_id)
-        self.servers_client.confirm_resize_server(instance_id)
-
-        waiters.wait_for_server_status(self.servers_client, instance_id,
-                                       'ACTIVE')
-
-    @decorators.attr(type='slow')
     @decorators.idempotent_id('949da7d5-72c8-4808-8802-e3d70df98e2c')
     @testtools.skipUnless(CONF.compute_feature_enabled.suspend,
                           'Suspend is not available.')
diff --git a/tempest/test_discover/plugins.py b/tempest/test_discover/plugins.py
index 1206e3f..9c18052 100644
--- a/tempest/test_discover/plugins.py
+++ b/tempest/test_discover/plugins.py
@@ -76,7 +76,7 @@
                 conf.register_opt(my_config.service_option,
                                   group='service_available')
                 conf.register_group(my_config.my_service_group)
-                conf.register_opts(my_config.MyService +
+                conf.register_opts(my_config.MyServiceGroup,
                                    my_config.my_service_group)
 
                 conf.register_group(my_config.my_service_feature_group)
diff --git a/tempest/tests/lib/common/utils/test_test_utils.py b/tempest/tests/lib/common/utils/test_test_utils.py
index 29c5684..f638ba6 100644
--- a/tempest/tests/lib/common/utils/test_test_utils.py
+++ b/tempest/tests/lib/common/utils/test_test_utils.py
@@ -81,11 +81,13 @@
     @mock.patch('time.sleep')
     @mock.patch('time.time')
     def test_call_until_true_when_f_never_returns_true(self, m_time, m_sleep):
+        def set_value(bool_value):
+            return bool_value
         timeout = 42  # The value doesn't matter as we mock time.time()
         sleep = 60  # The value doesn't matter as we mock time.sleep()
         m_time.side_effect = utils.generate_timeout_series(timeout)
         self.assertEqual(
-            False, test_utils.call_until_true(lambda: False, timeout, sleep)
+            False, test_utils.call_until_true(set_value, timeout, sleep, False)
         )
         m_sleep.call_args_list = [mock.call(sleep)] * 2
         m_time.call_args_list = [mock.call()] * 2
@@ -93,11 +95,30 @@
     @mock.patch('time.sleep')
     @mock.patch('time.time')
     def test_call_until_true_when_f_returns_true(self, m_time, m_sleep):
+        def set_value(bool_value=False):
+            return bool_value
         timeout = 42  # The value doesn't matter as we mock time.time()
         sleep = 60  # The value doesn't matter as we mock time.sleep()
         m_time.return_value = 0
         self.assertEqual(
-            True, test_utils.call_until_true(lambda: True, timeout, sleep)
+            True, test_utils.call_until_true(set_value, timeout, sleep,
+                                             bool_value=True)
         )
         self.assertEqual(0, m_sleep.call_count)
-        self.assertEqual(1, m_time.call_count)
+        # when logging cost time we need to acquire current time.
+        self.assertEqual(2, m_time.call_count)
+
+    @mock.patch('time.sleep')
+    @mock.patch('time.time')
+    def test_call_until_true_when_f_returns_true_no_param(
+            self, m_time, m_sleep):
+        def set_value(bool_value=False):
+            return bool_value
+        timeout = 42  # The value doesn't matter as we mock time.time()
+        sleep = 60  # The value doesn't matter as we mock time.sleep()
+        m_time.side_effect = utils.generate_timeout_series(timeout)
+        self.assertEqual(
+            False, test_utils.call_until_true(set_value, timeout, sleep)
+        )
+        m_sleep.call_args_list = [mock.call(sleep)] * 2
+        m_time.call_args_list = [mock.call()] * 2