Merge "create test to verify catalog standardization"
diff --git a/doc/source/conf.py b/doc/source/conf.py
index b9e22b5..23f732e 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -55,7 +55,7 @@
 extensions = ['sphinx.ext.autodoc',
               'sphinx.ext.todo',
               'sphinx.ext.viewcode',
-              'oslosphinx',
+              'openstackdocstheme',
               'oslo_config.sphinxconfiggen',
              ]
 
@@ -64,6 +64,14 @@
 
 todo_include_todos = True
 
+# openstackdocstheme options
+repository_name = 'openstack/tempest'
+bug_project = 'tempest'
+bug_tag = ''
+
+# Must set this variable to include year, month, day, hours, and minutes.
+html_last_updated_fmt = '%Y-%m-%d %H:%M'
+
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
 
@@ -127,7 +135,7 @@
 #html_theme_options = {}
 
 # Add any paths that contain custom themes here, relative to this directory.
-html_theme_path = [openstackdocstheme.get_html_theme_path()]
+#html_theme_path = []
 
 # The name for this set of Sphinx documents.  If None, it defaults to
 # "<project> v<release> documentation".
@@ -152,13 +160,6 @@
 
 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
 # using the given strftime format.
-git_cmd = ["git", "log", "--pretty=format:'%ad, commit %h'", "--date=local",
-   "-n1"]
-try:
-    html_last_updated_fmt = subprocess.check_output(git_cmd).decode('utf-8')
-except Exception:
-    warnings.warn('Cannot get last updated time from git repository. '
-                  'Not setting "html_last_updated_fmt".')
 
 # If true, SmartyPants will be used to convert quotes and dashes to
 # typographically correct entities.
diff --git a/releasenotes/notes/10.0-supported-openstack-releases-b88db468695348f6.yaml b/releasenotes/notes/10/10.0-supported-openstack-releases-b88db468695348f6.yaml
similarity index 100%
rename from releasenotes/notes/10.0-supported-openstack-releases-b88db468695348f6.yaml
rename to releasenotes/notes/10/10.0-supported-openstack-releases-b88db468695348f6.yaml
diff --git a/releasenotes/notes/10.0.0-Tempest-library-interface-0eb680b810139a50.yaml b/releasenotes/notes/10/10.0.0-Tempest-library-interface-0eb680b810139a50.yaml
similarity index 100%
rename from releasenotes/notes/10.0.0-Tempest-library-interface-0eb680b810139a50.yaml
rename to releasenotes/notes/10/10.0.0-Tempest-library-interface-0eb680b810139a50.yaml
diff --git a/releasenotes/notes/10.0.0-start-using-reno-ed9518126fd0e1a3.yaml b/releasenotes/notes/10/10.0.0-start-using-reno-ed9518126fd0e1a3.yaml
similarity index 100%
rename from releasenotes/notes/10.0.0-start-using-reno-ed9518126fd0e1a3.yaml
rename to releasenotes/notes/10/10.0.0-start-using-reno-ed9518126fd0e1a3.yaml
diff --git a/releasenotes/notes/11.0.0-api-microversion-testing-support-2ceddd2255670932.yaml b/releasenotes/notes/11/11.0.0-api-microversion-testing-support-2ceddd2255670932.yaml
similarity index 100%
rename from releasenotes/notes/11.0.0-api-microversion-testing-support-2ceddd2255670932.yaml
rename to releasenotes/notes/11/11.0.0-api-microversion-testing-support-2ceddd2255670932.yaml
diff --git a/releasenotes/notes/11.0.0-compute-microversion-support-e0b23f960f894b9b.yaml b/releasenotes/notes/11/11.0.0-compute-microversion-support-e0b23f960f894b9b.yaml
similarity index 100%
rename from releasenotes/notes/11.0.0-compute-microversion-support-e0b23f960f894b9b.yaml
rename to releasenotes/notes/11/11.0.0-compute-microversion-support-e0b23f960f894b9b.yaml
diff --git a/releasenotes/notes/11.0.0-supported-openstack-releases-1e5d7295d939d439.yaml b/releasenotes/notes/11/11.0.0-supported-openstack-releases-1e5d7295d939d439.yaml
similarity index 100%
rename from releasenotes/notes/11.0.0-supported-openstack-releases-1e5d7295d939d439.yaml
rename to releasenotes/notes/11/11.0.0-supported-openstack-releases-1e5d7295d939d439.yaml
diff --git a/releasenotes/notes/12.0.0-supported-openstack-releases-f10aac381d933dd1.yaml b/releasenotes/notes/12/12.0.0-supported-openstack-releases-f10aac381d933dd1.yaml
similarity index 100%
rename from releasenotes/notes/12.0.0-supported-openstack-releases-f10aac381d933dd1.yaml
rename to releasenotes/notes/12/12.0.0-supported-openstack-releases-f10aac381d933dd1.yaml
diff --git a/releasenotes/notes/12.1.0-add-network-versions-client-d90e8334e1443f5c.yaml b/releasenotes/notes/12/12.1.0-add-network-versions-client-d90e8334e1443f5c.yaml
similarity index 100%
rename from releasenotes/notes/12.1.0-add-network-versions-client-d90e8334e1443f5c.yaml
rename to releasenotes/notes/12/12.1.0-add-network-versions-client-d90e8334e1443f5c.yaml
diff --git a/releasenotes/notes/12.1.0-add-scope-to-auth-b5a82493ea89f41e.yaml b/releasenotes/notes/12/12.1.0-add-scope-to-auth-b5a82493ea89f41e.yaml
similarity index 100%
rename from releasenotes/notes/12.1.0-add-scope-to-auth-b5a82493ea89f41e.yaml
rename to releasenotes/notes/12/12.1.0-add-scope-to-auth-b5a82493ea89f41e.yaml
diff --git a/releasenotes/notes/12.1.0-add-tempest-run-3d0aaf69c2ca4115.yaml b/releasenotes/notes/12/12.1.0-add-tempest-run-3d0aaf69c2ca4115.yaml
similarity index 100%
rename from releasenotes/notes/12.1.0-add-tempest-run-3d0aaf69c2ca4115.yaml
rename to releasenotes/notes/12/12.1.0-add-tempest-run-3d0aaf69c2ca4115.yaml
diff --git a/releasenotes/notes/12.1.0-add-tempest-workspaces-228a2ba4690b5589.yaml b/releasenotes/notes/12/12.1.0-add-tempest-workspaces-228a2ba4690b5589.yaml
similarity index 100%
rename from releasenotes/notes/12.1.0-add-tempest-workspaces-228a2ba4690b5589.yaml
rename to releasenotes/notes/12/12.1.0-add-tempest-workspaces-228a2ba4690b5589.yaml
diff --git a/releasenotes/notes/12.1.0-add_subunit_describe_calls-5498a37e6cd66c4b.yaml b/releasenotes/notes/12/12.1.0-add_subunit_describe_calls-5498a37e6cd66c4b.yaml
similarity index 100%
rename from releasenotes/notes/12.1.0-add_subunit_describe_calls-5498a37e6cd66c4b.yaml
rename to releasenotes/notes/12/12.1.0-add_subunit_describe_calls-5498a37e6cd66c4b.yaml
diff --git a/releasenotes/notes/12.1.0-bug-1486834-7ebca15836ae27a9.yaml b/releasenotes/notes/12/12.1.0-bug-1486834-7ebca15836ae27a9.yaml
similarity index 100%
rename from releasenotes/notes/12.1.0-bug-1486834-7ebca15836ae27a9.yaml
rename to releasenotes/notes/12/12.1.0-bug-1486834-7ebca15836ae27a9.yaml
diff --git a/releasenotes/notes/12.1.0-identity-clients-as-library-e663c6132fcac6c2.yaml b/releasenotes/notes/12/12.1.0-identity-clients-as-library-e663c6132fcac6c2.yaml
similarity index 100%
rename from releasenotes/notes/12.1.0-identity-clients-as-library-e663c6132fcac6c2.yaml
rename to releasenotes/notes/12/12.1.0-identity-clients-as-library-e663c6132fcac6c2.yaml
diff --git a/releasenotes/notes/12.1.0-image-clients-as-library-86d17caa26ce3961.yaml b/releasenotes/notes/12/12.1.0-image-clients-as-library-86d17caa26ce3961.yaml
similarity index 100%
rename from releasenotes/notes/12.1.0-image-clients-as-library-86d17caa26ce3961.yaml
rename to releasenotes/notes/12/12.1.0-image-clients-as-library-86d17caa26ce3961.yaml
diff --git a/releasenotes/notes/12.1.0-new-test-utils-module-adf34468c4d52719.yaml b/releasenotes/notes/12/12.1.0-new-test-utils-module-adf34468c4d52719.yaml
similarity index 100%
rename from releasenotes/notes/12.1.0-new-test-utils-module-adf34468c4d52719.yaml
rename to releasenotes/notes/12/12.1.0-new-test-utils-module-adf34468c4d52719.yaml
diff --git a/releasenotes/notes/12.1.0-remove-input-scenarios-functionality-01308e6d4307f580.yaml b/releasenotes/notes/12/12.1.0-remove-input-scenarios-functionality-01308e6d4307f580.yaml
similarity index 100%
rename from releasenotes/notes/12.1.0-remove-input-scenarios-functionality-01308e6d4307f580.yaml
rename to releasenotes/notes/12/12.1.0-remove-input-scenarios-functionality-01308e6d4307f580.yaml
diff --git a/releasenotes/notes/12.1.0-remove-integrated-horizon-bb57551c1e5f5be3.yaml b/releasenotes/notes/12/12.1.0-remove-integrated-horizon-bb57551c1e5f5be3.yaml
similarity index 100%
rename from releasenotes/notes/12.1.0-remove-integrated-horizon-bb57551c1e5f5be3.yaml
rename to releasenotes/notes/12/12.1.0-remove-integrated-horizon-bb57551c1e5f5be3.yaml
diff --git a/releasenotes/notes/12.1.0-remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml b/releasenotes/notes/12/12.1.0-remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml
similarity index 100%
rename from releasenotes/notes/12.1.0-remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml
rename to releasenotes/notes/12/12.1.0-remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml
diff --git a/releasenotes/notes/12.1.0-remove-trove-tests-666522e9113549f9.yaml b/releasenotes/notes/12/12.1.0-remove-trove-tests-666522e9113549f9.yaml
similarity index 100%
rename from releasenotes/notes/12.1.0-remove-trove-tests-666522e9113549f9.yaml
rename to releasenotes/notes/12/12.1.0-remove-trove-tests-666522e9113549f9.yaml
diff --git a/releasenotes/notes/12.1.0-routers-client-as-library-25a363379da351f6.yaml b/releasenotes/notes/12/12.1.0-routers-client-as-library-25a363379da351f6.yaml
similarity index 100%
rename from releasenotes/notes/12.1.0-routers-client-as-library-25a363379da351f6.yaml
rename to releasenotes/notes/12/12.1.0-routers-client-as-library-25a363379da351f6.yaml
diff --git a/releasenotes/notes/12.1.0-support-chunked-encoding-d71f53225f68edf3.yaml b/releasenotes/notes/12/12.1.0-support-chunked-encoding-d71f53225f68edf3.yaml
similarity index 100%
rename from releasenotes/notes/12.1.0-support-chunked-encoding-d71f53225f68edf3.yaml
rename to releasenotes/notes/12/12.1.0-support-chunked-encoding-d71f53225f68edf3.yaml
diff --git a/releasenotes/notes/12.1.0-tempest-init-global-config-dir-location-changes-12260255871d3a2b.yaml b/releasenotes/notes/12/12.1.0-tempest-init-global-config-dir-location-changes-12260255871d3a2b.yaml
similarity index 100%
rename from releasenotes/notes/12.1.0-tempest-init-global-config-dir-location-changes-12260255871d3a2b.yaml
rename to releasenotes/notes/12/12.1.0-tempest-init-global-config-dir-location-changes-12260255871d3a2b.yaml
diff --git a/releasenotes/notes/12.2.0-add-httptimeout-in-restclient-ax78061900e3f3d7.yaml b/releasenotes/notes/12/12.2.0-add-httptimeout-in-restclient-ax78061900e3f3d7.yaml
similarity index 100%
rename from releasenotes/notes/12.2.0-add-httptimeout-in-restclient-ax78061900e3f3d7.yaml
rename to releasenotes/notes/12/12.2.0-add-httptimeout-in-restclient-ax78061900e3f3d7.yaml
diff --git a/releasenotes/notes/12.2.0-add-new-identity-clients-3c3afd674a395bde.yaml b/releasenotes/notes/12/12.2.0-add-new-identity-clients-3c3afd674a395bde.yaml
similarity index 100%
rename from releasenotes/notes/12.2.0-add-new-identity-clients-3c3afd674a395bde.yaml
rename to releasenotes/notes/12/12.2.0-add-new-identity-clients-3c3afd674a395bde.yaml
diff --git a/releasenotes/notes/12.2.0-clients_module-16f3025f515bf9ec.yaml b/releasenotes/notes/12/12.2.0-clients_module-16f3025f515bf9ec.yaml
similarity index 100%
rename from releasenotes/notes/12.2.0-clients_module-16f3025f515bf9ec.yaml
rename to releasenotes/notes/12/12.2.0-clients_module-16f3025f515bf9ec.yaml
diff --git a/releasenotes/notes/12.2.0-nova_cert_default-90eb7c1e3cde624a.yaml b/releasenotes/notes/12/12.2.0-nova_cert_default-90eb7c1e3cde624a.yaml
similarity index 100%
rename from releasenotes/notes/12.2.0-nova_cert_default-90eb7c1e3cde624a.yaml
rename to releasenotes/notes/12/12.2.0-nova_cert_default-90eb7c1e3cde624a.yaml
diff --git a/releasenotes/notes/12.2.0-plugin-service-client-registration-00b19a2dd4935ba0.yaml b/releasenotes/notes/12/12.2.0-plugin-service-client-registration-00b19a2dd4935ba0.yaml
similarity index 100%
rename from releasenotes/notes/12.2.0-plugin-service-client-registration-00b19a2dd4935ba0.yaml
rename to releasenotes/notes/12/12.2.0-plugin-service-client-registration-00b19a2dd4935ba0.yaml
diff --git a/releasenotes/notes/12.2.0-remove-javelin-276f62d04f7e4a1d.yaml b/releasenotes/notes/12/12.2.0-remove-javelin-276f62d04f7e4a1d.yaml
similarity index 100%
rename from releasenotes/notes/12.2.0-remove-javelin-276f62d04f7e4a1d.yaml
rename to releasenotes/notes/12/12.2.0-remove-javelin-276f62d04f7e4a1d.yaml
diff --git a/releasenotes/notes/12.2.0-service_client_config-8a1d7b4de769c633.yaml b/releasenotes/notes/12/12.2.0-service_client_config-8a1d7b4de769c633.yaml
similarity index 100%
rename from releasenotes/notes/12.2.0-service_client_config-8a1d7b4de769c633.yaml
rename to releasenotes/notes/12/12.2.0-service_client_config-8a1d7b4de769c633.yaml
diff --git a/releasenotes/notes/12.2.0-volume-clients-as-library-9a3444dd63c134b3.yaml b/releasenotes/notes/12/12.2.0-volume-clients-as-library-9a3444dd63c134b3.yaml
similarity index 100%
rename from releasenotes/notes/12.2.0-volume-clients-as-library-9a3444dd63c134b3.yaml
rename to releasenotes/notes/12/12.2.0-volume-clients-as-library-9a3444dd63c134b3.yaml
diff --git a/releasenotes/notes/13.0.0-add-new-identity-clients-as-library-5f7ndha733nwdsn9.yaml b/releasenotes/notes/13/13.0.0-add-new-identity-clients-as-library-5f7ndha733nwdsn9.yaml
similarity index 100%
rename from releasenotes/notes/13.0.0-add-new-identity-clients-as-library-5f7ndha733nwdsn9.yaml
rename to releasenotes/notes/13/13.0.0-add-new-identity-clients-as-library-5f7ndha733nwdsn9.yaml
diff --git a/releasenotes/notes/13.0.0-add-volume-clients-as-a-library-d05b6bc35e66c6ef.yaml b/releasenotes/notes/13/13.0.0-add-volume-clients-as-a-library-d05b6bc35e66c6ef.yaml
similarity index 100%
rename from releasenotes/notes/13.0.0-add-volume-clients-as-a-library-d05b6bc35e66c6ef.yaml
rename to releasenotes/notes/13/13.0.0-add-volume-clients-as-a-library-d05b6bc35e66c6ef.yaml
diff --git a/releasenotes/notes/13.0.0-deprecate-get_ipv6_addr_by_EUI64-4673f07677289cf6.yaml b/releasenotes/notes/13/13.0.0-deprecate-get_ipv6_addr_by_EUI64-4673f07677289cf6.yaml
similarity index 100%
rename from releasenotes/notes/13.0.0-deprecate-get_ipv6_addr_by_EUI64-4673f07677289cf6.yaml
rename to releasenotes/notes/13/13.0.0-deprecate-get_ipv6_addr_by_EUI64-4673f07677289cf6.yaml
diff --git a/releasenotes/notes/13.0.0-move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml b/releasenotes/notes/13/13.0.0-move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml
similarity index 100%
rename from releasenotes/notes/13.0.0-move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml
rename to releasenotes/notes/13/13.0.0-move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml
diff --git a/releasenotes/notes/13.0.0-start-of-newton-support-3ebb274f300f28eb.yaml b/releasenotes/notes/13/13.0.0-start-of-newton-support-3ebb274f300f28eb.yaml
similarity index 100%
rename from releasenotes/notes/13.0.0-start-of-newton-support-3ebb274f300f28eb.yaml
rename to releasenotes/notes/13/13.0.0-start-of-newton-support-3ebb274f300f28eb.yaml
diff --git a/releasenotes/notes/13.0.0-tempest-cleanup-nostandalone-39df2aafb2545d35.yaml b/releasenotes/notes/13/13.0.0-tempest-cleanup-nostandalone-39df2aafb2545d35.yaml
similarity index 100%
rename from releasenotes/notes/13.0.0-tempest-cleanup-nostandalone-39df2aafb2545d35.yaml
rename to releasenotes/notes/13/13.0.0-tempest-cleanup-nostandalone-39df2aafb2545d35.yaml
diff --git a/releasenotes/notes/13.0.0-volume-clients-as-library-660811011be29d1a.yaml b/releasenotes/notes/13/13.0.0-volume-clients-as-library-660811011be29d1a.yaml
similarity index 100%
rename from releasenotes/notes/13.0.0-volume-clients-as-library-660811011be29d1a.yaml
rename to releasenotes/notes/13/13.0.0-volume-clients-as-library-660811011be29d1a.yaml
diff --git a/releasenotes/notes/14.0.0-add-cred-provider-abstract-class-to-lib-70ff513221f8a871.yaml b/releasenotes/notes/14/14.0.0-add-cred-provider-abstract-class-to-lib-70ff513221f8a871.yaml
similarity index 100%
rename from releasenotes/notes/14.0.0-add-cred-provider-abstract-class-to-lib-70ff513221f8a871.yaml
rename to releasenotes/notes/14/14.0.0-add-cred-provider-abstract-class-to-lib-70ff513221f8a871.yaml
diff --git a/releasenotes/notes/14.0.0-add-cred_client-to-tempest.lib-4d4af33f969c576f.yaml b/releasenotes/notes/14/14.0.0-add-cred_client-to-tempest.lib-4d4af33f969c576f.yaml
similarity index 100%
rename from releasenotes/notes/14.0.0-add-cred_client-to-tempest.lib-4d4af33f969c576f.yaml
rename to releasenotes/notes/14/14.0.0-add-cred_client-to-tempest.lib-4d4af33f969c576f.yaml
diff --git a/releasenotes/notes/14.0.0-add-error-code-translation-to-versions-clients-acbc78292e24b014.yaml b/releasenotes/notes/14/14.0.0-add-error-code-translation-to-versions-clients-acbc78292e24b014.yaml
similarity index 100%
rename from releasenotes/notes/14.0.0-add-error-code-translation-to-versions-clients-acbc78292e24b014.yaml
rename to releasenotes/notes/14/14.0.0-add-error-code-translation-to-versions-clients-acbc78292e24b014.yaml
diff --git a/releasenotes/notes/14.0.0-add-image-clients-af94564fb34ddca6.yaml b/releasenotes/notes/14/14.0.0-add-image-clients-af94564fb34ddca6.yaml
similarity index 100%
rename from releasenotes/notes/14.0.0-add-image-clients-af94564fb34ddca6.yaml
rename to releasenotes/notes/14/14.0.0-add-image-clients-af94564fb34ddca6.yaml
diff --git a/releasenotes/notes/14.0.0-add-role-assignments-client-as-a-library-d34b4fdf376984ad.yaml b/releasenotes/notes/14/14.0.0-add-role-assignments-client-as-a-library-d34b4fdf376984ad.yaml
similarity index 100%
rename from releasenotes/notes/14.0.0-add-role-assignments-client-as-a-library-d34b4fdf376984ad.yaml
rename to releasenotes/notes/14/14.0.0-add-role-assignments-client-as-a-library-d34b4fdf376984ad.yaml
diff --git a/releasenotes/notes/14.0.0-add-service-provider-client-cbba77d424a30dd3.yaml b/releasenotes/notes/14/14.0.0-add-service-provider-client-cbba77d424a30dd3.yaml
similarity index 100%
rename from releasenotes/notes/14.0.0-add-service-provider-client-cbba77d424a30dd3.yaml
rename to releasenotes/notes/14/14.0.0-add-service-provider-client-cbba77d424a30dd3.yaml
diff --git a/releasenotes/notes/14.0.0-add-ssh-port-parameter-to-client-6d16c374ac4456c1.yaml b/releasenotes/notes/14/14.0.0-add-ssh-port-parameter-to-client-6d16c374ac4456c1.yaml
similarity index 100%
rename from releasenotes/notes/14.0.0-add-ssh-port-parameter-to-client-6d16c374ac4456c1.yaml
rename to releasenotes/notes/14/14.0.0-add-ssh-port-parameter-to-client-6d16c374ac4456c1.yaml
diff --git a/releasenotes/notes/14.0.0-deprecate-nova-api-extensions-df16b02485dae203.yaml b/releasenotes/notes/14/14.0.0-deprecate-nova-api-extensions-df16b02485dae203.yaml
similarity index 100%
rename from releasenotes/notes/14.0.0-deprecate-nova-api-extensions-df16b02485dae203.yaml
rename to releasenotes/notes/14/14.0.0-deprecate-nova-api-extensions-df16b02485dae203.yaml
diff --git a/releasenotes/notes/14.0.0-move-cinder-v3-to-lib-service-be3ba0c20753b594.yaml b/releasenotes/notes/14/14.0.0-move-cinder-v3-to-lib-service-be3ba0c20753b594.yaml
similarity index 100%
rename from releasenotes/notes/14.0.0-move-cinder-v3-to-lib-service-be3ba0c20753b594.yaml
rename to releasenotes/notes/14/14.0.0-move-cinder-v3-to-lib-service-be3ba0c20753b594.yaml
diff --git a/releasenotes/notes/14.0.0-new-volume-limit-client-517c17d9090f4df4.yaml b/releasenotes/notes/14/14.0.0-new-volume-limit-client-517c17d9090f4df4.yaml
similarity index 100%
rename from releasenotes/notes/14.0.0-new-volume-limit-client-517c17d9090f4df4.yaml
rename to releasenotes/notes/14/14.0.0-new-volume-limit-client-517c17d9090f4df4.yaml
diff --git a/releasenotes/notes/14.0.0-remo-stress-tests-81052b211ad95d2e.yaml b/releasenotes/notes/14/14.0.0-remo-stress-tests-81052b211ad95d2e.yaml
similarity index 100%
rename from releasenotes/notes/14.0.0-remo-stress-tests-81052b211ad95d2e.yaml
rename to releasenotes/notes/14/14.0.0-remo-stress-tests-81052b211ad95d2e.yaml
diff --git a/releasenotes/notes/14.0.0-remove-baremetal-tests-65186d9e15d5b8fb.yaml b/releasenotes/notes/14/14.0.0-remove-baremetal-tests-65186d9e15d5b8fb.yaml
similarity index 100%
rename from releasenotes/notes/14.0.0-remove-baremetal-tests-65186d9e15d5b8fb.yaml
rename to releasenotes/notes/14/14.0.0-remove-baremetal-tests-65186d9e15d5b8fb.yaml
diff --git a/releasenotes/notes/14.0.0-remove-bootable-option-024f8944c056a3e0.yaml b/releasenotes/notes/14/14.0.0-remove-bootable-option-024f8944c056a3e0.yaml
similarity index 100%
rename from releasenotes/notes/14.0.0-remove-bootable-option-024f8944c056a3e0.yaml
rename to releasenotes/notes/14/14.0.0-remove-bootable-option-024f8944c056a3e0.yaml
diff --git a/releasenotes/notes/14.0.0-remove-negative-test-generator-1653f4c0f86ccf75.yaml b/releasenotes/notes/14/14.0.0-remove-negative-test-generator-1653f4c0f86ccf75.yaml
similarity index 100%
rename from releasenotes/notes/14.0.0-remove-negative-test-generator-1653f4c0f86ccf75.yaml
rename to releasenotes/notes/14/14.0.0-remove-negative-test-generator-1653f4c0f86ccf75.yaml
diff --git a/releasenotes/notes/14.0.0-remove-sahara-tests-1532c47c7df80e3a.yaml b/releasenotes/notes/14/14.0.0-remove-sahara-tests-1532c47c7df80e3a.yaml
similarity index 100%
rename from releasenotes/notes/14.0.0-remove-sahara-tests-1532c47c7df80e3a.yaml
rename to releasenotes/notes/14/14.0.0-remove-sahara-tests-1532c47c7df80e3a.yaml
diff --git a/releasenotes/notes/14.0.0-volume-clients-as-library-309030c7a16e62ab.yaml b/releasenotes/notes/14/14.0.0-volume-clients-as-library-309030c7a16e62ab.yaml
similarity index 100%
rename from releasenotes/notes/14.0.0-volume-clients-as-library-309030c7a16e62ab.yaml
rename to releasenotes/notes/14/14.0.0-volume-clients-as-library-309030c7a16e62ab.yaml
diff --git a/releasenotes/notes/15.0.0-add-identity-v3-clients-as-a-library-d34b4fdf376984ad.yaml b/releasenotes/notes/15/15.0.0-add-identity-v3-clients-as-a-library-d34b4fdf376984ad.yaml
similarity index 100%
rename from releasenotes/notes/15.0.0-add-identity-v3-clients-as-a-library-d34b4fdf376984ad.yaml
rename to releasenotes/notes/15/15.0.0-add-identity-v3-clients-as-a-library-d34b4fdf376984ad.yaml
diff --git a/releasenotes/notes/15.0.0-add-image-clients-tests-49dbc0a0a4281a77.yaml b/releasenotes/notes/15/15.0.0-add-image-clients-tests-49dbc0a0a4281a77.yaml
similarity index 100%
rename from releasenotes/notes/15.0.0-add-image-clients-tests-49dbc0a0a4281a77.yaml
rename to releasenotes/notes/15/15.0.0-add-image-clients-tests-49dbc0a0a4281a77.yaml
diff --git a/releasenotes/notes/15.0.0-add-implied-roles-to-roles-client-library-edf96408ad9ba82e.yaml b/releasenotes/notes/15/15.0.0-add-implied-roles-to-roles-client-library-edf96408ad9ba82e.yaml
similarity index 100%
rename from releasenotes/notes/15.0.0-add-implied-roles-to-roles-client-library-edf96408ad9ba82e.yaml
rename to releasenotes/notes/15/15.0.0-add-implied-roles-to-roles-client-library-edf96408ad9ba82e.yaml
diff --git a/releasenotes/notes/15.0.0-add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml b/releasenotes/notes/15/15.0.0-add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml
similarity index 100%
rename from releasenotes/notes/15.0.0-add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml
rename to releasenotes/notes/15/15.0.0-add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml
diff --git a/releasenotes/notes/15.0.0-deprecate-allow_port_security_disabled-option-2d3d87f6bd11d03a.yaml b/releasenotes/notes/15/15.0.0-deprecate-allow_port_security_disabled-option-2d3d87f6bd11d03a.yaml
similarity index 100%
rename from releasenotes/notes/15.0.0-deprecate-allow_port_security_disabled-option-2d3d87f6bd11d03a.yaml
rename to releasenotes/notes/15/15.0.0-deprecate-allow_port_security_disabled-option-2d3d87f6bd11d03a.yaml
diff --git a/releasenotes/notes/15.0.0-deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml b/releasenotes/notes/15/15.0.0-deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml
similarity index 100%
rename from releasenotes/notes/15.0.0-deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml
rename to releasenotes/notes/15/15.0.0-deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml
diff --git a/releasenotes/notes/15.0.0-deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml b/releasenotes/notes/15/15.0.0-deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml
similarity index 100%
rename from releasenotes/notes/15.0.0-deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml
rename to releasenotes/notes/15/15.0.0-deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml
diff --git a/releasenotes/notes/15.0.0-jsonschema-validator-2377ba131e12d3c7.yaml b/releasenotes/notes/15/15.0.0-jsonschema-validator-2377ba131e12d3c7.yaml
similarity index 100%
rename from releasenotes/notes/15.0.0-jsonschema-validator-2377ba131e12d3c7.yaml
rename to releasenotes/notes/15/15.0.0-jsonschema-validator-2377ba131e12d3c7.yaml
diff --git a/releasenotes/notes/15.0.0-remove-deprecated-compute-microversion-config-options-eaee6a7d2f8390a8.yaml b/releasenotes/notes/15/15.0.0-remove-deprecated-compute-microversion-config-options-eaee6a7d2f8390a8.yaml
similarity index 100%
rename from releasenotes/notes/15.0.0-remove-deprecated-compute-microversion-config-options-eaee6a7d2f8390a8.yaml
rename to releasenotes/notes/15/15.0.0-remove-deprecated-compute-microversion-config-options-eaee6a7d2f8390a8.yaml
diff --git a/releasenotes/notes/15.0.0-remove-deprecated-compute-validation-config-options-e3d1b89ce074d71c.yaml b/releasenotes/notes/15/15.0.0-remove-deprecated-compute-validation-config-options-e3d1b89ce074d71c.yaml
similarity index 100%
rename from releasenotes/notes/15.0.0-remove-deprecated-compute-validation-config-options-e3d1b89ce074d71c.yaml
rename to releasenotes/notes/15/15.0.0-remove-deprecated-compute-validation-config-options-e3d1b89ce074d71c.yaml
diff --git a/releasenotes/notes/15.0.0-remove-deprecated-input-scenario-config-options-414e0c5442e967e9.yaml b/releasenotes/notes/15/15.0.0-remove-deprecated-input-scenario-config-options-414e0c5442e967e9.yaml
similarity index 100%
rename from releasenotes/notes/15.0.0-remove-deprecated-input-scenario-config-options-414e0c5442e967e9.yaml
rename to releasenotes/notes/15/15.0.0-remove-deprecated-input-scenario-config-options-414e0c5442e967e9.yaml
diff --git a/releasenotes/notes/15.0.0-remove-deprecated-network-config-options-f9ce276231578fe6.yaml b/releasenotes/notes/15/15.0.0-remove-deprecated-network-config-options-f9ce276231578fe6.yaml
similarity index 100%
rename from releasenotes/notes/15.0.0-remove-deprecated-network-config-options-f9ce276231578fe6.yaml
rename to releasenotes/notes/15/15.0.0-remove-deprecated-network-config-options-f9ce276231578fe6.yaml
diff --git a/releasenotes/notes/16.0.0-add-OAUTH-Consumer-Client-tempest-tests-db1df7aae4a9fd4e.yaml b/releasenotes/notes/16/16.0.0-add-OAUTH-Consumer-Client-tempest-tests-db1df7aae4a9fd4e.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-add-OAUTH-Consumer-Client-tempest-tests-db1df7aae4a9fd4e.yaml
rename to releasenotes/notes/16/16.0.0-add-OAUTH-Consumer-Client-tempest-tests-db1df7aae4a9fd4e.yaml
diff --git a/releasenotes/notes/16.0.0-add-additional-methods-to-roles-client-library-178d4a6000dec72d.yaml b/releasenotes/notes/16/16.0.0-add-additional-methods-to-roles-client-library-178d4a6000dec72d.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-add-additional-methods-to-roles-client-library-178d4a6000dec72d.yaml
rename to releasenotes/notes/16/16.0.0-add-additional-methods-to-roles-client-library-178d4a6000dec72d.yaml
diff --git a/releasenotes/notes/16.0.0-add-cascade-parameter-to-volumes-client-ff4f7f12795003a4.yaml b/releasenotes/notes/16/16.0.0-add-cascade-parameter-to-volumes-client-ff4f7f12795003a4.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-add-cascade-parameter-to-volumes-client-ff4f7f12795003a4.yaml
rename to releasenotes/notes/16/16.0.0-add-cascade-parameter-to-volumes-client-ff4f7f12795003a4.yaml
diff --git a/releasenotes/notes/16.0.0-add-compute-server-evaculate-client-as-a-library-ed76baf25f02c3ca.yaml b/releasenotes/notes/16/16.0.0-add-compute-server-evaculate-client-as-a-library-ed76baf25f02c3ca.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-add-compute-server-evaculate-client-as-a-library-ed76baf25f02c3ca.yaml
rename to releasenotes/notes/16/16.0.0-add-compute-server-evaculate-client-as-a-library-ed76baf25f02c3ca.yaml
diff --git a/releasenotes/notes/16.0.0-add-content-type-without-spaces-b2c9b91b257814f3.yaml b/releasenotes/notes/16/16.0.0-add-content-type-without-spaces-b2c9b91b257814f3.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-add-content-type-without-spaces-b2c9b91b257814f3.yaml
rename to releasenotes/notes/16/16.0.0-add-content-type-without-spaces-b2c9b91b257814f3.yaml
diff --git a/releasenotes/notes/16.0.0-add-list-auth-project-client-5905076d914a3943.yaml b/releasenotes/notes/16/16.0.0-add-list-auth-project-client-5905076d914a3943.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-add-list-auth-project-client-5905076d914a3943.yaml
rename to releasenotes/notes/16/16.0.0-add-list-auth-project-client-5905076d914a3943.yaml
diff --git a/releasenotes/notes/16.0.0-add-list-glance-api-versions-ec5fc8081fc8a0ae.yaml b/releasenotes/notes/16/16.0.0-add-list-glance-api-versions-ec5fc8081fc8a0ae.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-add-list-glance-api-versions-ec5fc8081fc8a0ae.yaml
rename to releasenotes/notes/16/16.0.0-add-list-glance-api-versions-ec5fc8081fc8a0ae.yaml
diff --git a/releasenotes/notes/16.0.0-add-list-security-groups-by-servers-to-servers-client-library-088df48f6d81f4be.yaml b/releasenotes/notes/16/16.0.0-add-list-security-groups-by-servers-to-servers-client-library-088df48f6d81f4be.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-add-list-security-groups-by-servers-to-servers-client-library-088df48f6d81f4be.yaml
rename to releasenotes/notes/16/16.0.0-add-list-security-groups-by-servers-to-servers-client-library-088df48f6d81f4be.yaml
diff --git a/releasenotes/notes/16.0.0-add-list-version-to-identity-client-944cb7396088a575.yaml b/releasenotes/notes/16/16.0.0-add-list-version-to-identity-client-944cb7396088a575.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-add-list-version-to-identity-client-944cb7396088a575.yaml
rename to releasenotes/notes/16/16.0.0-add-list-version-to-identity-client-944cb7396088a575.yaml
diff --git a/releasenotes/notes/16.0.0-add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml b/releasenotes/notes/16/16.0.0-add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml
rename to releasenotes/notes/16/16.0.0-add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml
diff --git a/releasenotes/notes/16.0.0-add-quota-sets-detail-kwarg-74b72183295b3ce7.yaml b/releasenotes/notes/16/16.0.0-add-quota-sets-detail-kwarg-74b72183295b3ce7.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-add-quota-sets-detail-kwarg-74b72183295b3ce7.yaml
rename to releasenotes/notes/16/16.0.0-add-quota-sets-detail-kwarg-74b72183295b3ce7.yaml
diff --git a/releasenotes/notes/16.0.0-add-tempest-lib-remote-client-adbeb3f42a36910b.yaml b/releasenotes/notes/16/16.0.0-add-tempest-lib-remote-client-adbeb3f42a36910b.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-add-tempest-lib-remote-client-adbeb3f42a36910b.yaml
rename to releasenotes/notes/16/16.0.0-add-tempest-lib-remote-client-adbeb3f42a36910b.yaml
diff --git a/releasenotes/notes/16.0.0-add-tempest-run-combine-option-e94c1049ba8985d5.yaml b/releasenotes/notes/16/16.0.0-add-tempest-run-combine-option-e94c1049ba8985d5.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-add-tempest-run-combine-option-e94c1049ba8985d5.yaml
rename to releasenotes/notes/16/16.0.0-add-tempest-run-combine-option-e94c1049ba8985d5.yaml
diff --git a/releasenotes/notes/16.0.0-add-update-encryption-type-to-encryption-types-client-f3093532a0bcf9a1.yaml b/releasenotes/notes/16/16.0.0-add-update-encryption-type-to-encryption-types-client-f3093532a0bcf9a1.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-add-update-encryption-type-to-encryption-types-client-f3093532a0bcf9a1.yaml
rename to releasenotes/notes/16/16.0.0-add-update-encryption-type-to-encryption-types-client-f3093532a0bcf9a1.yaml
diff --git a/releasenotes/notes/16.0.0-add-volume-manage-client-as-library-78ab198a1dc1bd41.yaml b/releasenotes/notes/16/16.0.0-add-volume-manage-client-as-library-78ab198a1dc1bd41.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-add-volume-manage-client-as-library-78ab198a1dc1bd41.yaml
rename to releasenotes/notes/16/16.0.0-add-volume-manage-client-as-library-78ab198a1dc1bd41.yaml
diff --git a/releasenotes/notes/16.0.0-create-server-tags-client-8c0042a77e859af6.yaml b/releasenotes/notes/16/16.0.0-create-server-tags-client-8c0042a77e859af6.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-create-server-tags-client-8c0042a77e859af6.yaml
rename to releasenotes/notes/16/16.0.0-create-server-tags-client-8c0042a77e859af6.yaml
diff --git a/releasenotes/notes/16.0.0-deprecate-deactivate_image-config-7a282c471937bbcb.yaml b/releasenotes/notes/16/16.0.0-deprecate-deactivate_image-config-7a282c471937bbcb.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-deprecate-deactivate_image-config-7a282c471937bbcb.yaml
rename to releasenotes/notes/16/16.0.0-deprecate-deactivate_image-config-7a282c471937bbcb.yaml
diff --git a/releasenotes/notes/16.0.0-deprecate-dvr_extra_resources-config-8c319d6dab7f7e5c.yaml b/releasenotes/notes/16/16.0.0-deprecate-dvr_extra_resources-config-8c319d6dab7f7e5c.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-deprecate-dvr_extra_resources-config-8c319d6dab7f7e5c.yaml
rename to releasenotes/notes/16/16.0.0-deprecate-dvr_extra_resources-config-8c319d6dab7f7e5c.yaml
diff --git a/releasenotes/notes/16.0.0-deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml b/releasenotes/notes/16/16.0.0-deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml
rename to releasenotes/notes/16/16.0.0-deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml
diff --git a/releasenotes/notes/16.0.0-deprecate-resources-prefix-option-ad490c0a30a0266b.yaml b/releasenotes/notes/16/16.0.0-deprecate-resources-prefix-option-ad490c0a30a0266b.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-deprecate-resources-prefix-option-ad490c0a30a0266b.yaml
rename to releasenotes/notes/16/16.0.0-deprecate-resources-prefix-option-ad490c0a30a0266b.yaml
diff --git a/releasenotes/notes/16.0.0-deprecate-skip_unless_attr-decorator-450a1ed727494724.yaml b/releasenotes/notes/16/16.0.0-deprecate-skip_unless_attr-decorator-450a1ed727494724.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-deprecate-skip_unless_attr-decorator-450a1ed727494724.yaml
rename to releasenotes/notes/16/16.0.0-deprecate-skip_unless_attr-decorator-450a1ed727494724.yaml
diff --git a/releasenotes/notes/16.0.0-deprecate-skip_unless_config-decorator-64c32d588043ab12.yaml b/releasenotes/notes/16/16.0.0-deprecate-skip_unless_config-decorator-64c32d588043ab12.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-deprecate-skip_unless_config-decorator-64c32d588043ab12.yaml
rename to releasenotes/notes/16/16.0.0-deprecate-skip_unless_config-decorator-64c32d588043ab12.yaml
diff --git a/releasenotes/notes/16.0.0-deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml b/releasenotes/notes/16/16.0.0-deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml
rename to releasenotes/notes/16/16.0.0-deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml
diff --git a/releasenotes/notes/16.0.0-dreprecate_client_parameters-cb8d069e62957f7e.yaml b/releasenotes/notes/16/16.0.0-dreprecate_client_parameters-cb8d069e62957f7e.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-dreprecate_client_parameters-cb8d069e62957f7e.yaml
rename to releasenotes/notes/16/16.0.0-dreprecate_client_parameters-cb8d069e62957f7e.yaml
diff --git a/releasenotes/notes/16.0.0-fix-volume-v2-service-clients-bugfix-1667354-73d2c3c8fedc08bf.yaml b/releasenotes/notes/16/16.0.0-fix-volume-v2-service-clients-bugfix-1667354-73d2c3c8fedc08bf.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-fix-volume-v2-service-clients-bugfix-1667354-73d2c3c8fedc08bf.yaml
rename to releasenotes/notes/16/16.0.0-fix-volume-v2-service-clients-bugfix-1667354-73d2c3c8fedc08bf.yaml
diff --git a/releasenotes/notes/16.0.0-mitaka-eol-88ff8355fff81b55.yaml b/releasenotes/notes/16/16.0.0-mitaka-eol-88ff8355fff81b55.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-mitaka-eol-88ff8355fff81b55.yaml
rename to releasenotes/notes/16/16.0.0-mitaka-eol-88ff8355fff81b55.yaml
diff --git a/releasenotes/notes/16.0.0-remove-call_until_true-of-test-de9c13bc8f969921.yaml b/releasenotes/notes/16/16.0.0-remove-call_until_true-of-test-de9c13bc8f969921.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-remove-call_until_true-of-test-de9c13bc8f969921.yaml
rename to releasenotes/notes/16/16.0.0-remove-call_until_true-of-test-de9c13bc8f969921.yaml
diff --git a/releasenotes/notes/16.0.0-remove-cinder-v1-api-tests-71e266b8d55d475f.yaml b/releasenotes/notes/16/16.0.0-remove-cinder-v1-api-tests-71e266b8d55d475f.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-remove-cinder-v1-api-tests-71e266b8d55d475f.yaml
rename to releasenotes/notes/16/16.0.0-remove-cinder-v1-api-tests-71e266b8d55d475f.yaml
diff --git a/releasenotes/notes/16.0.0-remove-deprecated-allow_port_security_disabled-option-d0ffaeb2e7817707.yaml b/releasenotes/notes/16/16.0.0-remove-deprecated-allow_port_security_disabled-option-d0ffaeb2e7817707.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-remove-deprecated-allow_port_security_disabled-option-d0ffaeb2e7817707.yaml
rename to releasenotes/notes/16/16.0.0-remove-deprecated-allow_port_security_disabled-option-d0ffaeb2e7817707.yaml
diff --git a/releasenotes/notes/16.0.0-remove-deprecated-compute-validation-config-options-part-2-5cd17b6e0e6cb8a3.yaml b/releasenotes/notes/16/16.0.0-remove-deprecated-compute-validation-config-options-part-2-5cd17b6e0e6cb8a3.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-remove-deprecated-compute-validation-config-options-part-2-5cd17b6e0e6cb8a3.yaml
rename to releasenotes/notes/16/16.0.0-remove-deprecated-compute-validation-config-options-part-2-5cd17b6e0e6cb8a3.yaml
diff --git a/releasenotes/notes/16.0.0-remove-deprecated-dvr_extra_resources-option-e8c441c38eab7ddd.yaml b/releasenotes/notes/16/16.0.0-remove-deprecated-dvr_extra_resources-option-e8c441c38eab7ddd.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-remove-deprecated-dvr_extra_resources-option-e8c441c38eab7ddd.yaml
rename to releasenotes/notes/16/16.0.0-remove-deprecated-dvr_extra_resources-option-e8c441c38eab7ddd.yaml
diff --git a/releasenotes/notes/16.0.0-remove-deprecated-identity-reseller-option-4411c7e3951f1094.yaml b/releasenotes/notes/16/16.0.0-remove-deprecated-identity-reseller-option-4411c7e3951f1094.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-remove-deprecated-identity-reseller-option-4411c7e3951f1094.yaml
rename to releasenotes/notes/16/16.0.0-remove-deprecated-identity-reseller-option-4411c7e3951f1094.yaml
diff --git a/releasenotes/notes/16.0.0-remove-sahara-service-available-44a642aa9c634ab4.yaml b/releasenotes/notes/16/16.0.0-remove-sahara-service-available-44a642aa9c634ab4.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-remove-sahara-service-available-44a642aa9c634ab4.yaml
rename to releasenotes/notes/16/16.0.0-remove-sahara-service-available-44a642aa9c634ab4.yaml
diff --git a/releasenotes/notes/16.0.0-remove-volume_feature_enabled.volume_services-c6aa142cc1021297.yaml b/releasenotes/notes/16/16.0.0-remove-volume_feature_enabled.volume_services-c6aa142cc1021297.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-remove-volume_feature_enabled.volume_services-c6aa142cc1021297.yaml
rename to releasenotes/notes/16/16.0.0-remove-volume_feature_enabled.volume_services-c6aa142cc1021297.yaml
diff --git a/releasenotes/notes/16.0.0-use-keystone-v3-api-935860d30ddbb8e9.yaml b/releasenotes/notes/16/16.0.0-use-keystone-v3-api-935860d30ddbb8e9.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-use-keystone-v3-api-935860d30ddbb8e9.yaml
rename to releasenotes/notes/16/16.0.0-use-keystone-v3-api-935860d30ddbb8e9.yaml
diff --git a/releasenotes/notes/16.0.0-volume-transfers-client-e5ed3f5464c0cdc0.yaml b/releasenotes/notes/16/16.0.0-volume-transfers-client-e5ed3f5464c0cdc0.yaml
similarity index 100%
rename from releasenotes/notes/16.0.0-volume-transfers-client-e5ed3f5464c0cdc0.yaml
rename to releasenotes/notes/16/16.0.0-volume-transfers-client-e5ed3f5464c0cdc0.yaml
diff --git a/releasenotes/notes/add-params-to-v2-list-backups-api-c088d2b4bfe90247.yaml b/releasenotes/notes/add-params-to-v2-list-backups-api-c088d2b4bfe90247.yaml
new file mode 100644
index 0000000..cee2d76
--- /dev/null
+++ b/releasenotes/notes/add-params-to-v2-list-backups-api-c088d2b4bfe90247.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    The ``list_backups`` method of the v2 ``BackupsClient`` class now has
+    an additional ``**params`` argument that enables passing additional
+    information in the query string of the HTTP request.
diff --git a/releasenotes/notes/add-save-state-option-5ea67858cbaca969.yaml b/releasenotes/notes/add-save-state-option-5ea67858cbaca969.yaml
new file mode 100644
index 0000000..8fdf4f0
--- /dev/null
+++ b/releasenotes/notes/add-save-state-option-5ea67858cbaca969.yaml
@@ -0,0 +1,4 @@
+---
+features:
+  - |
+    Add --save-state option to allow saving state of cloud before tempest run.
diff --git a/releasenotes/notes/add-show-snapshot-metadata-item-api-to-v2-snapshots-client-bd3cbab3c7f0e0b3.yaml b/releasenotes/notes/add-show-snapshot-metadata-item-api-to-v2-snapshots-client-bd3cbab3c7f0e0b3.yaml
new file mode 100644
index 0000000..140df60
--- /dev/null
+++ b/releasenotes/notes/add-show-snapshot-metadata-item-api-to-v2-snapshots-client-bd3cbab3c7f0e0b3.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Add show snapshot metadata item API to v2 snapshots_client library.
+    This feature enables the possibility to show a snapshot's metadata for
+    a specific key.
diff --git a/releasenotes/notes/add-show-volume-metadata-item-api-to-v2-volumes-client-47d59ecd999ca9df.yaml b/releasenotes/notes/add-show-volume-metadata-item-api-to-v2-volumes-client-47d59ecd999ca9df.yaml
new file mode 100644
index 0000000..49a935c
--- /dev/null
+++ b/releasenotes/notes/add-show-volume-metadata-item-api-to-v2-volumes-client-47d59ecd999ca9df.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Add show volume metadata item API to v2 volumes_client library.
+    This feature enables the possibility to show a volume's metadata for
+    a specific key.
diff --git a/releasenotes/notes/add-update-backup-api-to-v3-backups-client-e8465b2b66617dc0.yaml b/releasenotes/notes/add-update-backup-api-to-v3-backups-client-e8465b2b66617dc0.yaml
new file mode 100644
index 0000000..7cd6887
--- /dev/null
+++ b/releasenotes/notes/add-update-backup-api-to-v3-backups-client-e8465b2b66617dc0.yaml
@@ -0,0 +1,10 @@
+---
+features:
+  - |
+    Define v3 backups_client for the volume service as a library interface,
+    allowing other projects to use this module as a stable library without
+    maintenance changes.
+    Add update backup API to v3 backups_client library, min_microversion
+    of this API is 3.9.
+
+    * backups_client(v3)
diff --git a/releasenotes/notes/extra-compute-services-tests-92b6c0618972e02f.yaml b/releasenotes/notes/extra-compute-services-tests-92b6c0618972e02f.yaml
new file mode 100644
index 0000000..414adf1
--- /dev/null
+++ b/releasenotes/notes/extra-compute-services-tests-92b6c0618972e02f.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Add the ``disable_log_reason`` and the ``update_forced_down`` API endpoints
+    to the compute ``services_client``.
+    Add '2.11' compute validation schema for compute services API.
diff --git a/releasenotes/notes/identity_client-635275d43abbb807.yaml b/releasenotes/notes/identity_client-635275d43abbb807.yaml
new file mode 100644
index 0000000..6f984b7
--- /dev/null
+++ b/releasenotes/notes/identity_client-635275d43abbb807.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Enhances the v3 identity client with the ``check_token_existence``
+    endpoint, allowing users to check the existence of tokens
diff --git a/releasenotes/notes/intermediate-pike-release-2ce492432ff8f012.yaml b/releasenotes/notes/intermediate-pike-release-2ce492432ff8f012.yaml
new file mode 100644
index 0000000..bfebcd9
--- /dev/null
+++ b/releasenotes/notes/intermediate-pike-release-2ce492432ff8f012.yaml
@@ -0,0 +1,4 @@
+---
+prelude: >
+    This is an intermediate release during the Pike development cycle to
+    make new functionality available to plugins and other consumers.
diff --git a/releasenotes/notes/move-volume-v3-base_client-to-volume-1edbz0f207c3b283.yaml b/releasenotes/notes/move-volume-v3-base_client-to-volume-1edbz0f207c3b283.yaml
new file mode 100644
index 0000000..ec81dc5
--- /dev/null
+++ b/releasenotes/notes/move-volume-v3-base_client-to-volume-1edbz0f207c3b283.yaml
@@ -0,0 +1,15 @@
+features:
+  - |
+    Move base_client from tempest.lib.services.volume.v3 to
+    tempest.lib.services.volume, so if we want to add new
+    interfaces based on a v2 client, we can make that v2
+    client inherit from volume.base_client.BaseClient to
+    get microversion support, and then to make the new v3
+    client inherit from the v2 client, thus to avoid the
+    multiple inheritance.
+deprecations:
+  - |
+    Deprecate class BaseClient from volume.v3.base_client
+    and move it to volume.base_client.
+    ``tempest.lib.services.volume.v3.base_client.BaseClient``
+    (new ``tempest.lib.services.volume.base_client.BaseClient``)
diff --git a/releasenotes/notes/pause_teardown-45c9d60ffa889f7f.yaml b/releasenotes/notes/pause_teardown-45c9d60ffa889f7f.yaml
new file mode 100644
index 0000000..a540c7d
--- /dev/null
+++ b/releasenotes/notes/pause_teardown-45c9d60ffa889f7f.yaml
@@ -0,0 +1,9 @@
+---
+features:
+  - |
+    Pause teardown
+    When pause_teardown flag in tempest.conf is set to True a pdb breakpoint
+    is added to tearDown and tearDownClass methods in test.py.
+    This allows to pause cleaning resources process, so that used resources
+    can be examined. Closer examination of used resources may lead to faster
+    debugging.
diff --git a/releasenotes/notes/tempest-workspace-delete-directory-feature-74d6d157a5a05561.yaml b/releasenotes/notes/tempest-workspace-delete-directory-feature-74d6d157a5a05561.yaml
new file mode 100644
index 0000000..ec21098
--- /dev/null
+++ b/releasenotes/notes/tempest-workspace-delete-directory-feature-74d6d157a5a05561.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Added tempest workspace remove --name <workspace_name> --rmdir
+    feature to delete the workspace directory as well as entry.
diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py
index d240467..3137541 100644
--- a/releasenotes/source/conf.py
+++ b/releasenotes/source/conf.py
@@ -37,10 +37,18 @@
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
 extensions = [
-    'oslosphinx',
+    'openstackdocstheme',
     'reno.sphinxext',
 ]
 
+# openstackdocstheme options
+repository_name = 'openstack/tempest'
+bug_project = 'tempest'
+bug_tag = ''
+
+# Must set this variable to include year, month, day, hours, and minutes.
+html_last_updated_fmt = '%Y-%m-%d %H:%M'
+
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
 
@@ -119,9 +127,6 @@
 # html_theme_options = {}
 
 # Add any paths that contain custom themes here, relative to this directory.
-import openstackdocstheme
-
-html_theme_path = [openstackdocstheme.get_html_theme_path()]
 
 # The name for this set of Sphinx documents.  If None, it defaults to
 # "<project> v<release> documentation".
diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst
index d2be814..db01da0 100644
--- a/releasenotes/source/index.rst
+++ b/releasenotes/source/index.rst
@@ -6,6 +6,7 @@
     :maxdepth: 1
 
     unreleased
+    v16.1.0
     v16.0.0
     v15.0.0
     v14.0.0
diff --git a/releasenotes/source/v16.1.0.rst b/releasenotes/source/v16.1.0.rst
new file mode 100644
index 0000000..e24a70f
--- /dev/null
+++ b/releasenotes/source/v16.1.0.rst
@@ -0,0 +1,6 @@
+=====================
+v16.1.0 Release Notes
+=====================
+
+.. release-notes:: 16.1.0 Release Notes
+   :version: 16.1.0
diff --git a/tempest/api/compute/admin/test_auto_allocate_network.py b/tempest/api/compute/admin/test_auto_allocate_network.py
index ba8a214..83fe215 100644
--- a/tempest/api/compute/admin/test_auto_allocate_network.py
+++ b/tempest/api/compute/admin/test_auto_allocate_network.py
@@ -111,10 +111,12 @@
             LOG.info('(%s) Found more than one router for tenant.',
                      test_utils.find_test_caller())
 
-        # Let's just blindly remove any networks, duplicate or otherwise, that
-        # the test might have created even though Neutron will cleanup
-        # duplicate resources automatically (so ignore 404s).
-        networks = cls.networks_client.list_networks().get('networks', [])
+        # Remove any networks, duplicate or otherwise, that these tests
+        # created. All such networks will be in the current tenant. Neutron
+        # will cleanup duplicate resources automatically, so ignore 404s.
+        search_opts = {'tenant_id': cls.networks_client.tenant_id}
+        networks = cls.networks_client.list_networks(
+            **search_opts).get('networks', [])
 
         for router in routers:
             # Disassociate the subnets from the router. Because of the race
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index 3859e64..705e567 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -29,13 +29,13 @@
 LOG = logging.getLogger(__name__)
 
 
-class LiveBlockMigrationTestJSON(base.BaseV2ComputeAdminTest):
+class LiveMigrationTest(base.BaseV2ComputeAdminTest):
     max_microversion = '2.24'
     block_migration = None
 
     @classmethod
     def skip_checks(cls):
-        super(LiveBlockMigrationTestJSON, cls).skip_checks()
+        super(LiveMigrationTest, cls).skip_checks()
 
         if not CONF.compute_feature_enabled.live_migration:
             skip_msg = ("%s skipped as live-migration is "
@@ -47,26 +47,10 @@
 
     @classmethod
     def setup_clients(cls):
-        super(LiveBlockMigrationTestJSON, cls).setup_clients()
+        super(LiveMigrationTest, cls).setup_clients()
         cls.admin_hosts_client = cls.os_admin.hosts_client
         cls.admin_migration_client = cls.os_admin.migrations_client
 
-    @classmethod
-    def _get_compute_hostnames(cls):
-        body = cls.admin_hosts_client.list_hosts()['hosts']
-        return [
-            host_record['host_name']
-            for host_record in body
-            if host_record['service'] == 'compute'
-        ]
-
-    def _get_server_details(self, server_id):
-        body = self.admin_servers_client.show_server(server_id)['server']
-        return body
-
-    def _get_host_for_server(self, server_id):
-        return self._get_server_details(server_id)['OS-EXT-SRV-ATTR:host']
-
     def _migrate_server_to(self, server_id, dest_host, volume_backed=False):
         kwargs = dict()
         block_migration = getattr(self, 'block_migration', None)
@@ -79,11 +63,6 @@
             server_id, host=dest_host, block_migration=block_migration,
             **kwargs)
 
-    def _get_host_other_than(self, host):
-        for target_host in self._get_compute_hostnames():
-            if host != target_host:
-                return target_host
-
     def _live_migrate(self, server_id, target_host, state,
                       volume_backed=False):
         self._migrate_server_to(server_id, target_host, volume_backed)
@@ -97,7 +76,7 @@
             if (live_migration['instance_uuid'] == server_id):
                 msg += "\n%s" % live_migration
         msg += "]"
-        self.assertEqual(target_host, self._get_host_for_server(server_id),
+        self.assertEqual(target_host, self.get_host_for_server(server_id),
                          msg)
 
     def _test_live_migration(self, state='ACTIVE', volume_backed=False):
@@ -114,8 +93,8 @@
         # Live migrate an instance to another host
         server_id = self.create_test_server(wait_until="ACTIVE",
                                             volume_backed=volume_backed)['id']
-        source_host = self._get_host_for_server(server_id)
-        destination_host = self._get_host_other_than(source_host)
+        source_host = self.get_host_for_server(server_id)
+        destination_host = self.get_host_other_than(server_id)
 
         if state == 'PAUSED':
             self.admin_servers_client.pause_server(server_id)
@@ -158,8 +137,7 @@
     def test_iscsi_volume(self):
         server = self.create_test_server(wait_until="ACTIVE")
         server_id = server['id']
-        actual_host = self._get_host_for_server(server_id)
-        target_host = self._get_host_other_than(actual_host)
+        target_host = self.get_host_other_than(server_id)
 
         volume = self.create_volume()
 
@@ -174,11 +152,11 @@
         server = self.admin_servers_client.show_server(server_id)['server']
         volume_id2 = server["os-extended-volumes:volumes_attached"][0]["id"]
 
-        self.assertEqual(target_host, self._get_host_for_server(server_id))
+        self.assertEqual(target_host, self.get_host_for_server(server_id))
         self.assertEqual(volume_id1, volume_id2)
 
 
-class LiveBlockMigrationRemoteConsolesV26TestJson(LiveBlockMigrationTestJSON):
+class LiveMigrationRemoteConsolesV26Test(LiveMigrationTest):
     min_microversion = '2.6'
     max_microversion = 'latest'
 
@@ -201,8 +179,8 @@
         hints = {'different_host': server01_id}
         server02_id = self.create_test_server(scheduler_hints=hints,
                                               wait_until='ACTIVE')['id']
-        host01_id = self._get_host_for_server(server01_id)
-        host02_id = self._get_host_for_server(server02_id)
+        host01_id = self.get_host_for_server(server01_id)
+        host02_id = self.get_host_for_server(server02_id)
         self.assertNotEqual(host01_id, host02_id)
 
         # At this step we have 2 instances on different hosts, both with
@@ -216,7 +194,7 @@
         self._migrate_server_to(server01_id, host02_id)
         waiters.wait_for_server_status(self.servers_client,
                                        server01_id, 'ACTIVE')
-        self.assertEqual(host02_id, self._get_host_for_server(server01_id))
+        self.assertEqual(host02_id, self.get_host_for_server(server01_id))
         self._verify_console_interaction(server01_id)
         # At this point, both instances have a valid serial console
         # connection, which means the ports got updated.
@@ -252,7 +230,7 @@
         self.assertIn(data, console_output)
 
 
-class LiveAutoBlockMigrationV225TestJSON(LiveBlockMigrationTestJSON):
+class LiveAutoBlockMigrationV225Test(LiveMigrationTest):
     min_microversion = '2.25'
     max_microversion = 'latest'
     block_migration = 'auto'
diff --git a/tempest/api/compute/admin/test_live_block_migration_negative.py b/tempest/api/compute/admin/test_live_migration_negative.py
similarity index 72%
rename from tempest/api/compute/admin/test_live_block_migration_negative.py
rename to tempest/api/compute/admin/test_live_migration_negative.py
index ab63154..deabbc2 100644
--- a/tempest/api/compute/admin/test_live_block_migration_negative.py
+++ b/tempest/api/compute/admin/test_live_migration_negative.py
@@ -23,10 +23,10 @@
 CONF = config.CONF
 
 
-class LiveBlockMigrationNegativeTestJSON(base.BaseV2ComputeAdminTest):
+class LiveMigrationNegativeTest(base.BaseV2ComputeAdminTest):
     @classmethod
     def skip_checks(cls):
-        super(LiveBlockMigrationNegativeTestJSON, cls).skip_checks()
+        super(LiveMigrationNegativeTest, cls).skip_checks()
         if not CONF.compute_feature_enabled.live_migration:
             raise cls.skipException("Live migration is not enabled")
 
@@ -47,3 +47,17 @@
                           server['id'], target_host)
         waiters.wait_for_server_status(self.servers_client, server['id'],
                                        'ACTIVE')
+
+    @decorators.attr(type=['negative'])
+    @decorators.idempotent_id('6e2f94f5-2ee8-4830-bef5-5bc95bb0795b')
+    def test_live_block_migration_suspended(self):
+        server = self.create_test_server(wait_until="ACTIVE")
+
+        self.admin_servers_client.suspend_server(server['id'])
+        waiters.wait_for_server_status(self.servers_client,
+                                       server['id'], 'SUSPENDED')
+
+        destination_host = self.get_host_other_than(server['id'])
+
+        self.assertRaises(lib_exc.Conflict, self._migrate_server_to,
+                          server['id'], destination_host)
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 429ded5..feabe35 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -424,7 +424,7 @@
                 LOG.exception('Waiting for deletion of volume %s failed',
                               volume['id'])
 
-    def attach_volume(self, server, volume, device=None):
+    def attach_volume(self, server, volume, device=None, check_reserved=False):
         """Attaches volume to server and waits for 'in-use' volume status.
 
         The volume will be detached when the test tears down.
@@ -433,10 +433,15 @@
         :param volume: The volume to attach.
         :param device: Optional mountpoint for the attached volume. Note that
             this is not guaranteed for all hypervisors and is not recommended.
+        :param check_reserved: Consider a status of reserved as valid for
+            completion. This is to handle new Cinder attach where we more
+            accurately use 'reserved' for things like attaching to a shelved
+            server.
         """
         attach_kwargs = dict(volumeId=volume['id'])
         if device:
             attach_kwargs['device'] = device
+
         attachment = self.servers_client.attach_volume(
             server['id'], **attach_kwargs)['volumeAttachment']
         # On teardown detach the volume and wait for it to be available. This
@@ -449,8 +454,11 @@
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         self.servers_client.detach_volume,
                         server['id'], volume['id'])
+        statuses = ['in-use']
+        if check_reserved:
+            statuses.append('reserved')
         waiters.wait_for_volume_resource_status(self.volumes_client,
-                                                volume['id'], 'in-use')
+                                                volume['id'], statuses)
         return attachment
 
 
@@ -479,3 +487,21 @@
         self.addCleanup(client.wait_for_resource_deletion, flavor['id'])
         self.addCleanup(client.delete_flavor, flavor['id'])
         return flavor
+
+    def get_host_for_server(self, server_id):
+        server_details = self.admin_servers_client.show_server(server_id)
+        return server_details['server']['OS-EXT-SRV-ATTR:host']
+
+    def get_host_other_than(self, server_id):
+        source_host = self.get_host_for_server(server_id)
+
+        list_hosts_resp = self.os_admin.hosts_client.list_hosts()['hosts']
+        hosts = [
+            host_record['host_name']
+            for host_record in list_hosts_resp
+            if host_record['service'] == 'compute'
+        ]
+
+        for target_host in hosts:
+            if source_host != target_host:
+                return target_host
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 6f072b2..cd09177 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -517,23 +517,33 @@
     @decorators.idempotent_id('77eba8e0-036e-4635-944b-f7a8f3b78dc9')
     @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
                           'Shelve is not available.')
+    @test.services('image')
     def test_shelve_unshelve_server(self):
+        if CONF.image_feature_enabled.api_v2:
+            glance_client = self.os_primary.image_client_v2
+        elif CONF.image_feature_enabled.api_v1:
+            glance_client = self.os_primary.image_client
+        else:
+            raise lib_exc.InvalidConfiguration(
+                'Either api_v1 or api_v2 must be True in '
+                '[image-feature-enabled].')
         compute.shelve_server(self.client, self.server_id,
                               force_shelve_offload=True)
 
         server = self.client.show_server(self.server_id)['server']
         image_name = server['name'] + '-shelved'
         params = {'name': image_name}
-        images = self.compute_images_client.list_images(**params)['images']
+        if CONF.image_feature_enabled.api_v2:
+            images = glance_client.list_images(params)['images']
+        elif CONF.image_feature_enabled.api_v1:
+            images = glance_client.list_images(
+                detail=True, **params)['images']
         self.assertEqual(1, len(images))
         self.assertEqual(image_name, images[0]['name'])
 
         self.client.unshelve_server(self.server_id)
         waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE')
-
-        images = self.compute_images_client.list_images(**params)['images']
-        msg = ('After unshelve, shelved image is not deleted.')
-        self.assertEmpty(images, msg)
+        glance_client.wait_for_resource_deletion(images[0]['id'])
 
     @decorators.idempotent_id('af8eafd4-38a7-4a4b-bdbc-75145a580560')
     def test_stop_start_server(self):
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index ed5f9a6..502bc1b 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -212,7 +212,8 @@
         num_vol = self._count_volumes(server)
         self._shelve_server(server)
         attachment = self.attach_volume(server, volume,
-                                        device=('/dev/%s' % self.device))
+                                        device=('/dev/%s' % self.device),
+                                        check_reserved=True)
 
         # Unshelve the instance and check that attached volume exists
         self._unshelve_server_and_check_volumes(server, num_vol + 1)
@@ -239,7 +240,8 @@
         self._shelve_server(server)
 
         # Attach and then detach the volume
-        self.attach_volume(server, volume, device=('/dev/%s' % self.device))
+        self.attach_volume(server, volume, device=('/dev/%s' % self.device),
+                           check_reserved=True)
         self.servers_client.detach_volume(server['id'], volume['id'])
         waiters.wait_for_volume_resource_status(self.volumes_client,
                                                 volume['id'], 'available')
diff --git a/tempest/api/identity/admin/v3/test_endpoint_groups.py b/tempest/api/identity/admin/v3/test_endpoint_groups.py
index 5cd456c..49dbba1 100644
--- a/tempest/api/identity/admin/v3/test_endpoint_groups.py
+++ b/tempest/api/identity/admin/v3/test_endpoint_groups.py
@@ -54,17 +54,17 @@
         super(EndPointGroupsTest, cls).resource_cleanup()
 
     @classmethod
-    def _create_service(self):
+    def _create_service(cls):
         s_name = data_utils.rand_name('service')
         s_type = data_utils.rand_name('type')
         s_description = data_utils.rand_name('description')
         service_data = (
-            self.services_client.create_service(name=s_name,
-                                                type=s_type,
-                                                description=s_description))
+            cls.services_client.create_service(name=s_name,
+                                               type=s_type,
+                                               description=s_description))
 
         service_id = service_data['service']['id']
-        self.service_ids.append(service_id)
+        cls.service_ids.append(service_id)
         return service_id
 
     @decorators.idempotent_id('7c69e7a1-f865-402d-a2ea-44493017315a')
diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py
index 1acc67d..5c3cd26 100644
--- a/tempest/api/identity/admin/v3/test_tokens.py
+++ b/tempest/api/identity/admin/v3/test_tokens.py
@@ -39,6 +39,7 @@
         resp = self.token.auth(user_id=user['id'],
                                password=u_password).response
         subject_token = resp['x-subject-token']
+        self.client.check_token_existence(subject_token)
         # Perform GET Token
         token_details = self.client.show_token(subject_token)['token']
         self.assertEqual(resp['x-subject-token'], subject_token)
@@ -46,7 +47,7 @@
         self.assertEqual(token_details['user']['name'], u_name)
         # Perform Delete Token
         self.client.delete_token(subject_token)
-        self.assertRaises(lib_exc.NotFound, self.client.show_token,
+        self.assertRaises(lib_exc.NotFound, self.client.check_token_existence,
                           subject_token)
 
     @decorators.idempotent_id('565fa210-1da1-4563-999b-f7b5b67cf112')
diff --git a/tempest/api/network/admin/test_routers.py b/tempest/api/network/admin/test_routers.py
index 07c4157..f180cda 100644
--- a/tempest/api/network/admin/test_routers.py
+++ b/tempest/api/network/admin/test_routers.py
@@ -61,13 +61,6 @@
             msg = "router extension not enabled."
             raise cls.skipException(msg)
 
-    @classmethod
-    def resource_setup(cls):
-        super(RoutersAdminTest, cls).resource_setup()
-        cls.tenant_cidr = (CONF.network.project_network_cidr
-                           if cls._ip_version == 4 else
-                           CONF.network.project_network_v6_cidr)
-
     @decorators.idempotent_id('e54dd3a3-4352-4921-b09d-44369ae17397')
     def test_create_router_setting_project_id(self):
         # Test creating router from admin user setting project_id.
diff --git a/tempest/api/volume/admin/test_volume_quotas.py b/tempest/api/volume/admin/test_volume_quotas.py
index ae4b579..754104e 100644
--- a/tempest/api/volume/admin/test_volume_quotas.py
+++ b/tempest/api/volume/admin/test_volume_quotas.py
@@ -36,7 +36,7 @@
     def setup_credentials(cls):
         super(BaseVolumeQuotasAdminTestJSON, cls).setup_credentials()
         cls.demo_tenant_id = cls.os_primary.credentials.tenant_id
-        cls.alt_client = cls.os_alt.volumes_client
+        cls.alt_client = cls.os_alt.volumes_client_latest
 
     @classmethod
     def setup_clients(cls):
@@ -155,7 +155,7 @@
 
         # Accepts a volume transfer
         self.alt_transfer_client.accept_volume_transfer(
-            transfer_id, auth_key=auth_key)['transfer']
+            transfer_id, auth_key=auth_key)
 
         # Verify volume transferred is available
         waiters.wait_for_volume_resource_status(
diff --git a/tempest/api/volume/admin/test_volume_type_access.py b/tempest/api/volume/admin/test_volume_type_access.py
index 297ab6e..e93bcb5 100644
--- a/tempest/api/volume/admin/test_volume_type_access.py
+++ b/tempest/api/volume/admin/test_volume_type_access.py
@@ -30,7 +30,7 @@
     @classmethod
     def setup_clients(cls):
         super(VolumeTypesAccessTest, cls).setup_clients()
-        cls.alt_client = cls.os_alt.volumes_client
+        cls.alt_client = cls.os_alt.volumes_client_latest
 
     @decorators.idempotent_id('d4dd0027-835f-4554-a6e5-50903fb79184')
     def test_volume_type_access_add(self):
diff --git a/tempest/api/volume/api_microversion_fixture.py b/tempest/api/volume/api_microversion_fixture.py
index 64bc537..7bbe674 100644
--- a/tempest/api/volume/api_microversion_fixture.py
+++ b/tempest/api/volume/api_microversion_fixture.py
@@ -13,7 +13,7 @@
 
 import fixtures
 
-from tempest.lib.services.volume.v3 import base_client
+from tempest.lib.services.volume import base_client
 
 
 class APIMicroversionFixture(fixtures.Fixture):
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 394c453..ef69ba3 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -69,11 +69,14 @@
         if CONF.service_available.glance:
             cls.images_client = cls.os_primary.image_client_v2
 
-        cls.snapshots_client = cls.os_primary.snapshots_v2_client
-        cls.volumes_client = cls.os_primary.volumes_v2_client
         if cls._api_version == 3:
+            cls.backups_client = cls.os_primary.backups_v3_client
             cls.volumes_client = cls.os_primary.volumes_v3_client
-        cls.backups_client = cls.os_primary.backups_v2_client
+        else:
+            cls.backups_client = cls.os_primary.backups_v2_client
+            cls.volumes_client = cls.os_primary.volumes_v2_client
+
+        cls.snapshots_client = cls.os_primary.snapshots_v2_client
         cls.volumes_extension_client =\
             cls.os_primary.volumes_v2_extension_client
         cls.availability_zone_client = (
diff --git a/tempest/api/volume/test_snapshot_metadata.py b/tempest/api/volume/test_snapshot_metadata.py
index 164ed37..e6fe25d 100644
--- a/tempest/api/volume/test_snapshot_metadata.py
+++ b/tempest/api/volume/test_snapshot_metadata.py
@@ -55,6 +55,7 @@
         # Create metadata
         body = self.snapshots_client.create_snapshot_metadata(
             self.snapshot['id'], metadata)['metadata']
+        self.assertThat(body.items(), matchers.ContainsAll(metadata.items()))
 
         # Get the metadata of the snapshot
         body = self.snapshots_client.show_snapshot_metadata(
@@ -65,6 +66,7 @@
         # Update metadata
         body = self.snapshots_client.update_snapshot_metadata(
             self.snapshot['id'], metadata=update)['metadata']
+        self.assertEqual(update, body)
         body = self.snapshots_client.show_snapshot_metadata(
             self.snapshot['id'])['metadata']
         self.assertEqual(update, body, 'Update snapshot metadata failed')
@@ -79,7 +81,7 @@
         self.assertNotIn("key3", body)
 
     @decorators.idempotent_id('e8ff85c5-8f97-477f-806a-3ac364a949ed')
-    def test_update_snapshot_metadata_item(self):
+    def test_update_show_snapshot_metadata_item(self):
         # Update metadata item for the snapshot
         metadata = {"key1": "value1",
                     "key2": "value2",
@@ -89,8 +91,8 @@
                   "key2": "value2",
                   "key3": "value3_update"}
         # Create metadata for the snapshot
-        body = self.snapshots_client.create_snapshot_metadata(
-            self.snapshot['id'], metadata)['metadata']
+        self.snapshots_client.create_snapshot_metadata(
+            self.snapshot['id'], metadata)
         # Get the metadata of the snapshot
         body = self.snapshots_client.show_snapshot_metadata(
             self.snapshot['id'])['metadata']
@@ -98,6 +100,13 @@
         # Update metadata item
         body = self.snapshots_client.update_snapshot_metadata_item(
             self.snapshot['id'], "key3", meta=update_item)['meta']
+        self.assertEqual(update_item, body)
+
+        # Get a specific metadata item of the snapshot
+        body = self.snapshots_client.show_snapshot_metadata_item(
+            self.snapshot['id'], "key3")['meta']
+        self.assertEqual({"key3": expect['key3']}, body)
+
         # Get the metadata of the snapshot
         body = self.snapshots_client.show_snapshot_metadata(
             self.snapshot['id'])['metadata']
diff --git a/tempest/api/volume/test_volume_metadata.py b/tempest/api/volume/test_volume_metadata.py
index b4d22fe..d203b2d 100644
--- a/tempest/api/volume/test_volume_metadata.py
+++ b/tempest/api/volume/test_volume_metadata.py
@@ -45,6 +45,7 @@
 
         body = self.volumes_client.create_volume_metadata(self.volume['id'],
                                                           metadata)['metadata']
+        self.assertThat(body.items(), matchers.ContainsAll(metadata.items()))
         # Get the metadata of the volume
         body = self.volumes_client.show_volume_metadata(
             self.volume['id'])['metadata']
@@ -54,6 +55,7 @@
         # Update metadata
         body = self.volumes_client.update_volume_metadata(
             self.volume['id'], update)['metadata']
+        self.assertEqual(update, body)
         body = self.volumes_client.show_volume_metadata(
             self.volume['id'])['metadata']
         self.assertEqual(update, body, 'Update metadata failed')
@@ -68,7 +70,7 @@
                         'Delete one item metadata of the volume failed')
 
     @decorators.idempotent_id('862261c5-8df4-475a-8c21-946e50e36a20')
-    def test_update_volume_metadata_item(self):
+    def test_update_show_volume_metadata_item(self):
         # Update metadata item for the volume
         metadata = {"key1": "value1",
                     "key2": "value2",
@@ -85,6 +87,13 @@
         # Update metadata item
         body = self.volumes_client.update_volume_metadata_item(
             self.volume['id'], "key3", update_item)['meta']
+        self.assertEqual(update_item, body)
+
+        # Get a specific metadata item of the volume
+        body = self.volumes_client.show_volume_metadata_item(
+            self.volume['id'], "key3")['meta']
+        self.assertEqual({"key3": expect['key3']}, body)
+
         # Get the metadata of the volume
         body = self.volumes_client.show_volume_metadata(
             self.volume['id'])['metadata']
diff --git a/tempest/api/volume/test_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py
index 2c13a3c..4108da5 100644
--- a/tempest/api/volume/test_volume_transfers.py
+++ b/tempest/api/volume/test_volume_transfers.py
@@ -59,6 +59,8 @@
         # Accept a volume transfer by alt_tenant
         body = self.alt_client.accept_volume_transfer(
             transfer_id, auth_key=auth_key)['transfer']
+        for key in ['id', 'name', 'links', 'volume_id']:
+            self.assertIn(key, body)
         waiters.wait_for_volume_resource_status(self.alt_volumes_client,
                                                 volume['id'], 'available')
         accepted_volume = self.alt_volumes_client.show_volume(
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index 8541c6d..c4d10c3 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -115,12 +115,12 @@
     @decorators.idempotent_id('92c4ef64-51b2-40c0-9f7e-4749fbaaba33')
     def test_reserve_unreserve_volume(self):
         # Mark volume as reserved.
-        body = self.volumes_client.reserve_volume(self.volume['id'])
+        self.volumes_client.reserve_volume(self.volume['id'])
         # To get the volume info
         body = self.volumes_client.show_volume(self.volume['id'])['volume']
         self.assertIn('attaching', body['status'])
         # Unmark volume as reserved.
-        body = self.volumes_client.unreserve_volume(self.volume['id'])
+        self.volumes_client.unreserve_volume(self.volume['id'])
         # To get the volume info
         body = self.volumes_client.show_volume(self.volume['id'])['volume']
         self.assertIn('available', body['status'])
diff --git a/tempest/api/volume/test_volumes_backup.py b/tempest/api/volume/test_volumes_backup.py
index 4b4aeec..1f91db6 100644
--- a/tempest/api/volume/test_volumes_backup.py
+++ b/tempest/api/volume/test_volumes_backup.py
@@ -140,3 +140,39 @@
             restored_volume_id)['volume']
 
         self.assertEqual('true', restored_volume_info['bootable'])
+
+
+class VolumesBackupsV39Test(base.BaseVolumeTest):
+
+    _api_version = 3
+    min_microversion = '3.9'
+    max_microversion = 'latest'
+
+    @classmethod
+    def skip_checks(cls):
+        super(VolumesBackupsV39Test, cls).skip_checks()
+        if not CONF.volume_feature_enabled.backup:
+            raise cls.skipException("Cinder backup feature disabled")
+
+    @decorators.idempotent_id('9b374cbc-be5f-4d37-8848-7efb8a873dcc')
+    def test_update_backup(self):
+        # Create volume and backup
+        volume = self.create_volume()
+        backup = self.create_backup(volume_id=volume['id'])
+
+        # Update backup and assert response body for update_backup method
+        update_kwargs = {
+            'name': data_utils.rand_name(self.__class__.__name__ + '-Backup'),
+            'description': data_utils.rand_name("volume-backup-description")
+        }
+        update_backup = self.backups_client.update_backup(
+            backup['id'], **update_kwargs)['backup']
+        self.assertEqual(backup['id'], update_backup['id'])
+        self.assertEqual(update_kwargs['name'], update_backup['name'])
+        self.assertIn('links', update_backup)
+
+        # Assert response body for show_backup method
+        retrieved_backup = self.backups_client.show_backup(
+            backup['id'])['backup']
+        for key in update_kwargs:
+            self.assertEqual(update_kwargs[key], retrieved_backup[key])
diff --git a/tempest/api/volume/test_volumes_clone.py b/tempest/api/volume/test_volumes_clone.py
index 4c13375..927bfa5 100644
--- a/tempest/api/volume/test_volumes_clone.py
+++ b/tempest/api/volume/test_volumes_clone.py
@@ -30,6 +30,18 @@
         if not CONF.volume_feature_enabled.clone:
             raise cls.skipException("Cinder volume clones are disabled")
 
+    def _verify_volume_clone(self, source_volume, cloned_volume,
+                             bootable='false', extra_size=0):
+
+        cloned_vol_details = self.volumes_client.show_volume(
+            cloned_volume['id'])['volume']
+
+        self.assertEqual(source_volume['id'],
+                         cloned_vol_details['source_volid'])
+        self.assertEqual(source_volume['size'] + extra_size,
+                         cloned_vol_details['size'])
+        self.assertEqual(bootable, cloned_vol_details['bootable'])
+
     @decorators.idempotent_id('9adae371-a257-43a5-9555-dc7c88e66e0e')
     def test_create_from_volume(self):
         # Creates a volume from another volume passing a size different from
@@ -41,10 +53,7 @@
         dst_vol = self.create_volume(source_volid=src_vol['id'],
                                      size=src_size + 1)
 
-        volume = self.volumes_client.show_volume(dst_vol['id'])['volume']
-        # Should allow
-        self.assertEqual(volume['source_volid'], src_vol['id'])
-        self.assertEqual(volume['size'], src_size + 1)
+        self._verify_volume_clone(src_vol, dst_vol, extra_size=1)
 
     @decorators.idempotent_id('cbbcd7c6-5a6c-481a-97ac-ca55ab715d16')
     @test.services('image')
@@ -55,10 +64,5 @@
 
         # Create a volume from the bootable volume
         cloned_vol = self.create_volume(source_volid=src_vol['id'])
-        cloned_vol_details = self.volumes_client.show_volume(
-            cloned_vol['id'])['volume']
 
-        # Verify cloned volume creation as expected
-        self.assertEqual('true', cloned_vol_details['bootable'])
-        self.assertEqual(src_vol['id'], cloned_vol_details['source_volid'])
-        self.assertEqual(src_vol['size'], cloned_vol_details['size'])
+        self._verify_volume_clone(src_vol, cloned_vol, bootable='true')
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 44c1def..e68ab7e 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -10,6 +10,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import testtools
 from testtools import matchers
 
 from tempest.api.volume import base
@@ -149,3 +150,16 @@
         # Should allow
         self.assertEqual(volume['snapshot_id'], src_snap['id'])
         self.assertEqual(volume['size'], src_size + 1)
+
+    @decorators.idempotent_id('bbcfa285-af7f-479e-8c1a-8c34fc16543c')
+    @testtools.skipUnless(CONF.volume_feature_enabled.backup,
+                          "Cinder backup is disabled")
+    def test_snapshot_backup(self):
+        # Create a snapshot
+        snapshot = self.create_snapshot(volume_id=self.volume_origin['id'])
+
+        backup = self.create_backup(volume_id=self.volume_origin['id'],
+                                    snapshot_id=snapshot['id'])
+        backup_info = self.backups_client.show_backup(backup['id'])['backup']
+        self.assertEqual(self.volume_origin['id'], backup_info['volume_id'])
+        self.assertEqual(snapshot['id'], backup_info['snapshot_id'])
diff --git a/tempest/clients.py b/tempest/clients.py
index 3f206b0..ee12a5e 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -13,8 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from oslo_log import log as logging
-
 from tempest import config
 from tempest.lib import auth
 from tempest.lib import exceptions as lib_exc
@@ -23,7 +21,6 @@
 from tempest.services import orchestration
 
 CONF = config.CONF
-LOG = logging.getLogger(__name__)
 
 
 class Manager(clients.ServiceClients):
@@ -230,48 +227,63 @@
 
     def _set_volume_clients(self):
 
-        self.volume_qos_client = self.volume_v1.QosSpecsClient()
-        self.volume_qos_v2_client = self.volume_v2.QosSpecsClient()
-        self.volume_services_client = self.volume_v1.ServicesClient()
-        self.volume_services_v2_client = self.volume_v2.ServicesClient()
-        self.backups_client = self.volume_v1.BackupsClient()
-        self.backups_v2_client = self.volume_v2.BackupsClient()
-        self.encryption_types_client = self.volume_v1.EncryptionTypesClient()
-        self.encryption_types_v2_client = \
-            self.volume_v2.EncryptionTypesClient()
-        self.snapshot_manage_v2_client = self.volume_v2.SnapshotManageClient()
-        self.snapshots_client = self.volume_v1.SnapshotsClient()
-        self.snapshots_v2_client = self.volume_v2.SnapshotsClient()
-        self.volume_manage_v2_client = self.volume_v2.VolumeManageClient()
-        self.volumes_client = self.volume_v1.VolumesClient()
-        self.volumes_v2_client = self.volume_v2.VolumesClient()
-        self.volumes_v3_client = self.volume_v3.VolumesClient()
-        self.volume_v3_messages_client = self.volume_v3.MessagesClient()
-        self.volume_v3_versions_client = self.volume_v3.VersionsClient()
-        self.volume_types_client = self.volume_v1.TypesClient()
-        self.volume_types_v2_client = self.volume_v2.TypesClient()
-        self.volume_hosts_client = self.volume_v1.HostsClient()
-        self.volume_hosts_v2_client = self.volume_v2.HostsClient()
-        self.volume_quotas_client = self.volume_v1.QuotasClient()
-        self.volume_quotas_v2_client = self.volume_v2.QuotasClient()
-        self.volume_quota_classes_v2_client = \
-            self.volume_v2.QuotaClassesClient()
-        self.volumes_extension_client = self.volume_v1.ExtensionsClient()
-        self.volumes_v2_extension_client = self.volume_v2.ExtensionsClient()
-        self.groups_v3_client = self.volume_v3.GroupsClient()
-        self.group_types_v3_client = self.volume_v3.GroupTypesClient()
-        self.volume_availability_zone_client = \
-            self.volume_v1.AvailabilityZoneClient()
-        self.volume_v2_availability_zone_client = \
-            self.volume_v2.AvailabilityZoneClient()
-        self.volume_limits_client = self.volume_v1.LimitsClient()
-        self.volume_v2_limits_client = self.volume_v2.LimitsClient()
-        self.volume_capabilities_v2_client = \
-            self.volume_v2.CapabilitiesClient()
-        self.volume_scheduler_stats_v2_client = \
-            self.volume_v2.SchedulerStatsClient()
-        self.volume_transfers_v2_client = \
-            self.volume_v2.TransfersClient()
+        if CONF.volume_feature_enabled.api_v1:
+            self.backups_client = self.volume_v1.BackupsClient()
+            self.encryption_types_client = \
+                self.volume_v1.EncryptionTypesClient()
+            self.snapshots_client = self.volume_v1.SnapshotsClient()
+            self.volume_availability_zone_client = \
+                self.volume_v1.AvailabilityZoneClient()
+            self.volume_hosts_client = self.volume_v1.HostsClient()
+            self.volume_limits_client = self.volume_v1.LimitsClient()
+            self.volume_qos_client = self.volume_v1.QosSpecsClient()
+            self.volume_quotas_client = self.volume_v1.QuotasClient()
+            self.volume_services_client = self.volume_v1.ServicesClient()
+            self.volume_types_client = self.volume_v1.TypesClient()
+            self.volumes_client = self.volume_v1.VolumesClient()
+            self.volumes_extension_client = self.volume_v1.ExtensionsClient()
+
+        if CONF.volume_feature_enabled.api_v2:
+            self.backups_v2_client = self.volume_v2.BackupsClient()
+            self.encryption_types_v2_client = \
+                self.volume_v2.EncryptionTypesClient()
+            self.snapshot_manage_v2_client = \
+                self.volume_v2.SnapshotManageClient()
+            self.snapshots_v2_client = self.volume_v2.SnapshotsClient()
+            self.volume_capabilities_v2_client = \
+                self.volume_v2.CapabilitiesClient()
+            self.volume_manage_v2_client = self.volume_v2.VolumeManageClient()
+            self.volume_qos_v2_client = self.volume_v2.QosSpecsClient()
+            self.volume_services_v2_client = self.volume_v2.ServicesClient()
+            self.volume_types_v2_client = self.volume_v2.TypesClient()
+            self.volume_hosts_v2_client = self.volume_v2.HostsClient()
+            self.volume_quotas_v2_client = self.volume_v2.QuotasClient()
+            self.volume_quota_classes_v2_client = \
+                self.volume_v2.QuotaClassesClient()
+            self.volume_scheduler_stats_v2_client = \
+                self.volume_v2.SchedulerStatsClient()
+            self.volume_transfers_v2_client = \
+                self.volume_v2.TransfersClient()
+            self.volume_v2_availability_zone_client = \
+                self.volume_v2.AvailabilityZoneClient()
+            self.volume_v2_limits_client = self.volume_v2.LimitsClient()
+            self.volumes_v2_client = self.volume_v2.VolumesClient()
+            self.volumes_v2_extension_client = \
+                self.volume_v2.ExtensionsClient()
+
+            # Set default client for users that don't need explicit version
+            self.volumes_client_latest = self.volumes_v2_client
+
+        if CONF.volume_feature_enabled.api_v3:
+            self.backups_v3_client = self.volume_v3.BackupsClient()
+            self.group_types_v3_client = self.volume_v3.GroupTypesClient()
+            self.groups_v3_client = self.volume_v3.GroupsClient()
+            self.volume_v3_messages_client = self.volume_v3.MessagesClient()
+            self.volume_v3_versions_client = self.volume_v3.VersionsClient()
+            self.volumes_v3_client = self.volume_v3.VolumesClient()
+
+            # Set default client for users that don't need explicit version
+            self.volumes_client_latest = self.volumes_v3_client
 
     def _set_object_storage_clients(self):
         # NOTE(andreaf) Load configuration from config. Once object storage
diff --git a/tempest/cmd/run.py b/tempest/cmd/run.py
index b36bf5c..350dd0b 100644
--- a/tempest/cmd/run.py
+++ b/tempest/cmd/run.py
@@ -97,15 +97,19 @@
 from cliff import command
 from os_testr import regex_builder
 from os_testr import subunit_trace
+from oslo_serialization import jsonutils as json
 import six
 from testrepository.commands import run_argv
 
+from tempest.cmd import cleanup_service
 from tempest.cmd import init
 from tempest.cmd import workspace
+from tempest.common import credentials_factory as credentials
 from tempest import config
 
 
 CONF = config.CONF
+SAVED_STATE_JSON = "saved_state.json"
 
 
 class TempestRun(command.Command):
@@ -174,6 +178,11 @@
         else:
             print("No .testr.conf file was found for local execution")
             sys.exit(2)
+        if parsed_args.state:
+            self._init_state()
+        else:
+            pass
+
         if parsed_args.combine:
             temp_stream = tempfile.NamedTemporaryFile()
             return_code = run_argv(['tempest', 'last', '--subunit'], sys.stdin,
@@ -203,6 +212,25 @@
     def get_description(self):
         return 'Run tempest'
 
+    def _init_state(self):
+        print("Initializing saved state.")
+        data = {}
+        self.global_services = cleanup_service.get_global_cleanup_services()
+        self.admin_mgr = credentials.AdminManager()
+        admin_mgr = self.admin_mgr
+        kwargs = {'data': data,
+                  'is_dry_run': False,
+                  'saved_state_json': data,
+                  'is_preserve': False,
+                  'is_save_state': True}
+        for service in self.global_services:
+            svc = service(admin_mgr, **kwargs)
+            svc.run()
+
+        with open(SAVED_STATE_JSON, 'w+') as f:
+            f.write(json.dumps(data,
+                    sort_keys=True, indent=2, separators=(',', ': ')))
+
     def get_parser(self, prog_name):
         parser = super(TempestRun, self).get_parser(prog_name)
         parser = self._add_args(parser)
@@ -253,6 +281,10 @@
         parallel.add_argument('--serial', '-t', dest='parallel',
                               action='store_false',
                               help='Run tests serially')
+        parser.add_argument('--save-state', dest='state',
+                            action='store_true',
+                            help="To save the state of the cloud before "
+                                 "running tempest.")
         # output args
         parser.add_argument("--subunit", action='store_true',
                             help='Enable subunit v2 output')
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index 6b81e0d..2f4d120 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -95,10 +95,11 @@
     client_dict = {
         'nova': os.servers_client,
         'keystone': os.identity_client,
-        'cinder': os.volumes_client,
+        'cinder': os.volumes_client_latest,
     }
-    if service != 'keystone':
-        # Since keystone may be listening on a path, do not remove the path.
+    if service != 'keystone' and service != 'cinder':
+        # Since keystone and cinder may be listening on a path,
+        # do not remove the path.
         client_dict[service].skip_path()
     endpoint = _get_unversioned_endpoint(client_dict[service].base_url)
 
diff --git a/tempest/cmd/workspace.py b/tempest/cmd/workspace.py
index 96d2300..8166b4f 100644
--- a/tempest/cmd/workspace.py
+++ b/tempest/cmd/workspace.py
@@ -40,6 +40,8 @@
 ------
 Deletes the entry for a given tempest workspace --name
 
+--rmdir Deletes the given tempest workspace directory
+
 General Options
 ===============
 
@@ -49,6 +51,7 @@
 """
 
 import os
+import shutil
 import sys
 
 from cliff import command
@@ -102,11 +105,16 @@
             sys.exit(1)
 
     @lockutils.synchronized('workspaces', external=True)
-    def remove_workspace(self, name):
+    def remove_workspace_entry(self, name):
         self._populate()
         self._name_exists(name)
-        self.workspaces.pop(name)
+        workspace_path = self.workspaces.pop(name)
         self._write_file()
+        return workspace_path
+
+    @lockutils.synchronized('workspaces', external=True)
+    def remove_workspace_directory(self, workspace_path):
+        shutil.rmtree(workspace_path)
 
     @lockutils.synchronized('workspaces', external=True)
     def list_workspaces(self):
@@ -226,12 +234,16 @@
         parser = super(TempestWorkspaceRemove, self).get_parser(prog_name)
         add_global_arguments(parser)
         parser.add_argument('--name', required=True)
+        parser.add_argument('--rmdir', action='store_true',
+                            help='Deletes the given workspace directory')
 
         return parser
 
     def take_action(self, parsed_args):
         self.manager = WorkspaceManager(parsed_args.workspace_path)
-        self.manager.remove_workspace(parsed_args.name)
+        workspace_path = self.manager.remove_workspace_entry(parsed_args.name)
+        if parsed_args.rmdir:
+            self.manager.remove_workspace_directory(workspace_path)
         sys.exit(0)
 
 
diff --git a/tempest/common/dynamic_creds.py b/tempest/common/dynamic_creds.py
index 88fe26c..1e040e6 100644
--- a/tempest/common/dynamic_creds.py
+++ b/tempest/common/dynamic_creds.py
@@ -12,6 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import ipaddress
+
 import netaddr
 from oslo_log import log as logging
 import six
@@ -275,14 +277,16 @@
                             name=subnet_name,
                             tenant_id=tenant_id,
                             enable_dhcp=self.network_resources['dhcp'],
-                            ip_version=4)
+                            ip_version=(ipaddress.ip_network(
+                                six.text_type(subnet_cidr)).version))
                 else:
                     resp_body = self.subnets_admin_client.\
                         create_subnet(network_id=network_id,
                                       cidr=str(subnet_cidr),
                                       name=subnet_name,
                                       tenant_id=tenant_id,
-                                      ip_version=4)
+                                      ip_version=(ipaddress.ip_network(
+                                          six.text_type(subnet_cidr)).version))
                 break
             except lib_exc.BadRequest as e:
                 if 'overlaps with another subnet' not in str(e):
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index 93e6fbf..cf187e6 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -179,25 +179,26 @@
     raise lib_exc.TimeoutException(message)
 
 
-def wait_for_volume_resource_status(client, resource_id, status):
-    """Waits for a volume resource to reach a given status.
+def wait_for_volume_resource_status(client, resource_id, statuses):
+    """Waits for a volume resource to reach any of the specified statuses.
 
     This function is a common function for volume, snapshot and backup
     resources. The function extracts the name of the desired resource from
     the client class name of the resource.
     """
-    resource_name = re.findall(
-        r'(Volume|Snapshot|Backup|Group)',
-        client.__class__.__name__)[0].lower()
+    if not isinstance(statuses, list):
+        statuses = [statuses]
+    resource_name = re.findall(r'(Volume|Snapshot|Backup|Group)',
+                               client.__class__.__name__)[0].lower()
     show_resource = getattr(client, 'show_' + resource_name)
     resource_status = show_resource(resource_id)[resource_name]['status']
     start = int(time.time())
 
-    while resource_status != status:
+    while resource_status not in statuses:
         time.sleep(client.build_interval)
         resource_status = show_resource(resource_id)[
             '{}'.format(resource_name)]['status']
-        if resource_status == 'error' and resource_status != status:
+        if resource_status == 'error' and resource_status not in statuses:
             raise exceptions.VolumeResourceBuildErrorException(
                 resource_name=resource_name, resource_id=resource_id)
         if resource_name == 'volume' and resource_status == 'error_restoring':
@@ -206,7 +207,7 @@
         if int(time.time()) - start >= client.build_timeout:
             message = ('%s %s failed to reach %s status (current %s) '
                        'within the required time (%s s).' %
-                       (resource_name, resource_id, status, resource_status,
+                       (resource_name, resource_id, statuses, resource_status,
                         client.build_timeout))
             raise lib_exc.TimeoutException(message)
 
diff --git a/tempest/config.py b/tempest/config.py
index 7b96281..af9eefc 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -1070,6 +1070,15 @@
                                  "prefix to ideintify resources which are "
                                  "created by Tempest and no projects set "
                                  "this option on OpenStack dev community."),
+    cfg.BoolOpt('pause_teardown',
+                default=False,
+                help="""Whether to pause a test in global teardown.
+
+The best use case is investigating used resources of one test.
+A test can be run as follows:
+ $ ostestr --pdb TEST_ID
+or
+ $ python -m testtools.run TEST_ID"""),
 ]
 
 _opts = [
diff --git a/tempest/lib/api_schema/response/compute/v2_1/servers.py b/tempest/lib/api_schema/response/compute/v2_1/servers.py
index 7360396..2954de0 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/servers.py
@@ -420,8 +420,13 @@
         'properties': {
             'event': {'type': 'string'},
             'start_time': parameter_types.date_time,
-            'finish_time': parameter_types.date_time,
-            'result': {'type': 'string'},
+            # The finish_time, result and optionally traceback are all
+            # possibly None (null) until the event is actually finished.
+            # The traceback would only be set if there was an error, but
+            # when the event is complete both finish_time and result will
+            # be set.
+            'finish_time': parameter_types.date_time_or_null,
+            'result': {'type': ['string', 'null']},
             'traceback': {'type': ['string', 'null']}
         },
         'additionalProperties': False,
diff --git a/tempest/lib/api_schema/response/compute/v2_1/services.py b/tempest/lib/api_schema/response/compute/v2_1/services.py
index 6949f86..3b58ece 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/services.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/services.py
@@ -65,3 +65,25 @@
         'required': ['service']
     }
 }
+
+disable_log_reason = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'service': {
+                'type': 'object',
+                'properties': {
+                    'disabled_reason': {'type': 'string'},
+                    'binary': {'type': 'string'},
+                    'host': {'type': 'string'},
+                    'status': {'type': 'string'}
+                },
+                'additionalProperties': False,
+                'required': ['disabled_reason', 'binary', 'host', 'status']
+            }
+        },
+        'additionalProperties': False,
+        'required': ['service']
+    }
+}
diff --git a/tempest/lib/api_schema/response/compute/v2_11/__init__.py b/tempest/lib/api_schema/response/compute/v2_11/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_11/__init__.py
diff --git a/tempest/lib/api_schema/response/compute/v2_11/services.py b/tempest/lib/api_schema/response/compute/v2_11/services.py
new file mode 100644
index 0000000..18b833b
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_11/services.py
@@ -0,0 +1,46 @@
+# Copyright 2017 AT&T Corporation.
+# All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    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 copy
+
+from tempest.lib.api_schema.response.compute.v2_1 import services
+
+
+list_services = copy.deepcopy(services.list_services)
+list_services['response_body']['properties']['services']['items'][
+    'properties']['forced_down'] = {'type': 'boolean'}
+list_services['response_body']['properties']['services']['items'][
+    'required'].append('forced_down')
+
+update_forced_down = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'service': {
+                'type': 'object',
+                'properties': {
+                    'binary': {'type': 'string'},
+                    'host': {'type': 'string'},
+                    'forced_down': {'type': 'boolean'}
+                },
+                'additionalProperties': False,
+                'required': ['binary', 'host', 'forced_down']
+            }
+        },
+        'additionalProperties': False,
+        'required': ['service']
+    }
+}
diff --git a/tempest/lib/services/compute/services_client.py b/tempest/lib/services/compute/services_client.py
index 77ac82f..857c435 100644
--- a/tempest/lib/services/compute/services_client.py
+++ b/tempest/lib/services/compute/services_client.py
@@ -18,12 +18,18 @@
 from six.moves.urllib import parse as urllib
 
 from tempest.lib.api_schema.response.compute.v2_1 import services as schema
+from tempest.lib.api_schema.response.compute.v2_11 import services \
+    as schemav211
 from tempest.lib.common import rest_client
 from tempest.lib.services.compute import base_compute_client
 
 
 class ServicesClient(base_compute_client.BaseComputeClient):
 
+    schema_versions_info = [
+        {'min': None, 'max': '2.10', 'schema': schema},
+        {'min': '2.11', 'max': None, 'schema': schemav211}]
+
     def list_services(self, **params):
         """Lists all running Compute services for a tenant.
 
@@ -37,7 +43,8 @@
 
         resp, body = self.get(url)
         body = json.loads(body)
-        self.validate_response(schema.list_services, resp, body)
+        _schema = self.get_schema(self.schema_versions_info)
+        self.validate_response(_schema.list_services, resp, body)
         return rest_client.ResponseBody(resp, body)
 
     def enable_service(self, **kwargs):
@@ -65,3 +72,31 @@
         body = json.loads(body)
         self.validate_response(schema.enable_disable_service, resp, body)
         return rest_client.ResponseBody(resp, body)
+
+    def disable_log_reason(self, **kwargs):
+        """Disables scheduling for a Compute service and logs reason.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/compute/#log-disabled-compute-service-information
+        """
+        post_body = json.dumps(kwargs)
+        resp, body = self.put('os-services/disable-log-reason', post_body)
+        body = json.loads(body)
+        self.validate_response(schema.disable_log_reason, resp, body)
+        return rest_client.ResponseBody(resp, body)
+
+    def update_forced_down(self, **kwargs):
+        """Set or unset ``forced_down`` flag for the service.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/compute/#update-forced-down
+        """
+        post_body = json.dumps(kwargs)
+        resp, body = self.put('os-services/force-down', post_body)
+        body = json.loads(body)
+        # NOTE: Use schemav211.update_forced_down directly because there is no
+        # update_forced_down schema for <2.11.
+        self.validate_response(schemav211.update_forced_down, resp, body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/identity/v3/identity_client.py b/tempest/lib/services/identity/v3/identity_client.py
index 755c14b..2512a3e 100644
--- a/tempest/lib/services/identity/v3/identity_client.py
+++ b/tempest/lib/services/identity/v3/identity_client.py
@@ -44,6 +44,13 @@
         self.expected_success(204, resp.status)
         return rest_client.ResponseBody(resp, body)
 
+    def check_token_existence(self, resp_token):
+        """Validates a token."""
+        headers = {'X-Subject-Token': resp_token}
+        resp, body = self.head("auth/tokens", headers=headers)
+        self.expected_success(200, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
     def list_auth_projects(self):
         """Get available project scopes."""
         resp, body = self.get("auth/projects")
diff --git a/tempest/lib/services/volume/base_client.py b/tempest/lib/services/volume/base_client.py
new file mode 100644
index 0000000..c7fb21a
--- /dev/null
+++ b/tempest/lib/services/volume/base_client.py
@@ -0,0 +1,45 @@
+# Copyright 2016 Andrew Kerr
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.lib.common import api_version_utils
+from tempest.lib.common import rest_client
+
+VOLUME_MICROVERSION = None
+
+
+class BaseClient(rest_client.RestClient):
+    """Base volume service clients class to support microversion."""
+    api_microversion_header_name = 'Openstack-Api-Version'
+
+    def get_headers(self, accept_type=None, send_type=None):
+        headers = super(BaseClient, self).get_headers(
+            accept_type=accept_type, send_type=send_type)
+        if VOLUME_MICROVERSION:
+            headers[self.api_microversion_header_name] = ('volume %s' %
+                                                          VOLUME_MICROVERSION)
+        return headers
+
+    def request(self, method, url, extra_headers=False, headers=None,
+                body=None, chunked=False):
+
+        resp, resp_body = super(BaseClient, self).request(
+            method, url, extra_headers, headers, body, chunked)
+        if (VOLUME_MICROVERSION and
+            VOLUME_MICROVERSION != api_version_utils.LATEST_MICROVERSION):
+            api_version_utils.assert_version_header_matches_request(
+                self.api_microversion_header_name,
+                'volume %s' % VOLUME_MICROVERSION,
+                resp)
+        return resp, resp_body
diff --git a/tempest/lib/services/volume/v2/backups_client.py b/tempest/lib/services/volume/v2/backups_client.py
index 2b5e82d..830fb82 100644
--- a/tempest/lib/services/volume/v2/backups_client.py
+++ b/tempest/lib/services/volume/v2/backups_client.py
@@ -14,12 +14,14 @@
 #    under the License.
 
 from oslo_serialization import jsonutils as json
+from six.moves.urllib import parse as urllib
 
 from tempest.lib.common import rest_client
 from tempest.lib import exceptions as lib_exc
+from tempest.lib.services.volume import base_client
 
 
-class BackupsClient(rest_client.RestClient):
+class BackupsClient(base_client.BaseClient):
     """Volume V2 Backups client"""
     api_version = "v2"
 
@@ -63,11 +65,19 @@
         self.expected_success(200, resp.status)
         return rest_client.ResponseBody(resp, body)
 
-    def list_backups(self, detail=False):
-        """Information for all the tenant's backups."""
+    def list_backups(self, detail=False, **params):
+        """List all the tenant's backups.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        http://developer.openstack.org/api-ref/block-storage/v2/#list-backups
+        http://developer.openstack.org/api-ref/block-storage/v2/#list-backups-with-details
+        """
         url = "backups"
         if detail:
             url += "/detail"
+        if params:
+            url += '?%s' % urllib.urlencode(params)
         resp, body = self.get(url)
         body = json.loads(body)
         self.expected_success(200, resp.status)
diff --git a/tempest/lib/services/volume/v2/snapshots_client.py b/tempest/lib/services/volume/v2/snapshots_client.py
index 5f4e7de..4bc2842 100644
--- a/tempest/lib/services/volume/v2/snapshots_client.py
+++ b/tempest/lib/services/volume/v2/snapshots_client.py
@@ -164,6 +164,14 @@
         self.expected_success(200, resp.status)
         return rest_client.ResponseBody(resp, body)
 
+    def show_snapshot_metadata_item(self, snapshot_id, id):
+        """Show metadata item for the snapshot."""
+        url = "snapshots/%s/metadata/%s" % (snapshot_id, id)
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.expected_success(200, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
     def update_snapshot_metadata_item(self, snapshot_id, id, **kwargs):
         """Update metadata item for the snapshot."""
         # TODO(piyush): Current api-site doesn't contain this API description.
diff --git a/tempest/lib/services/volume/v2/volumes_client.py b/tempest/lib/services/volume/v2/volumes_client.py
index 86e3836..d31259f 100644
--- a/tempest/lib/services/volume/v2/volumes_client.py
+++ b/tempest/lib/services/volume/v2/volumes_client.py
@@ -21,10 +21,11 @@
 
 from tempest.lib.common import rest_client
 from tempest.lib import exceptions as lib_exc
+from tempest.lib.services.volume import base_client
 from tempest.lib.services.volume.v2 import transfers_client
 
 
-class VolumesClient(rest_client.RestClient):
+class VolumesClient(base_client.BaseClient):
     """Client class to send CRUD Volume V2 API requests"""
     api_version = "v2"
 
@@ -283,6 +284,14 @@
         self.expected_success(200, resp.status)
         return rest_client.ResponseBody(resp, body)
 
+    def show_volume_metadata_item(self, volume_id, id):
+        """Show metadata item for the volume."""
+        url = "volumes/%s/metadata/%s" % (volume_id, id)
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.expected_success(200, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
     def update_volume_metadata_item(self, volume_id, id, meta_item):
         """Update metadata item for the volume."""
         put_body = json.dumps({'meta': meta_item})
diff --git a/tempest/lib/services/volume/v3/__init__.py b/tempest/lib/services/volume/v3/__init__.py
index a351d61..ff58fc2 100644
--- a/tempest/lib/services/volume/v3/__init__.py
+++ b/tempest/lib/services/volume/v3/__init__.py
@@ -12,6 +12,7 @@
 # License for the specific language governing permissions and limitations under
 # the License.
 
+from tempest.lib.services.volume.v3.backups_client import BackupsClient
 from tempest.lib.services.volume.v3.base_client import BaseClient
 from tempest.lib.services.volume.v3.group_types_client import GroupTypesClient
 from tempest.lib.services.volume.v3.groups_client import GroupsClient
@@ -19,5 +20,5 @@
 from tempest.lib.services.volume.v3.versions_client import VersionsClient
 from tempest.lib.services.volume.v3.volumes_client import VolumesClient
 
-__all__ = ['BaseClient', 'GroupsClient', 'GroupTypesClient',
+__all__ = ['BackupsClient', 'BaseClient', 'GroupsClient', 'GroupTypesClient',
            'MessagesClient', 'VersionsClient', 'VolumesClient']
diff --git a/tempest/lib/services/volume/v3/backups_client.py b/tempest/lib/services/volume/v3/backups_client.py
new file mode 100644
index 0000000..e742e39
--- /dev/null
+++ b/tempest/lib/services/volume/v3/backups_client.py
@@ -0,0 +1,37 @@
+# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+from tempest.lib.services.volume.v2 import backups_client
+
+
+class BackupsClient(backups_client.BackupsClient):
+    """Volume V3 Backups client"""
+    api_version = "v3"
+
+    def update_backup(self, backup_id, **kwargs):
+        """Updates the specified volume backup.
+
+        For a full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/block-storage/v3/#update-a-backup
+        """
+        put_body = json.dumps({'backup': kwargs})
+        resp, body = self.put('backups/%s' % backup_id, put_body)
+        body = json.loads(body)
+        self.expected_success(200, resp.status)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/volume/v3/base_client.py b/tempest/lib/services/volume/v3/base_client.py
index 958212a..e78380b 100644
--- a/tempest/lib/services/volume/v3/base_client.py
+++ b/tempest/lib/services/volume/v3/base_client.py
@@ -13,34 +13,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.lib.common import api_version_utils
-from tempest.lib.common import rest_client
+from debtcollector import moves
 
-VOLUME_MICROVERSION = None
+from tempest.lib.services.volume import base_client
 
 
-class BaseClient(rest_client.RestClient):
-    """Base class to handle Cinder v3 client microversion support."""
-    api_version = 'v3'
-    api_microversion_header_name = 'Openstack-Api-Version'
-
-    def get_headers(self, accept_type=None, send_type=None):
-        headers = super(BaseClient, self).get_headers(
-            accept_type=accept_type, send_type=send_type)
-        if VOLUME_MICROVERSION:
-            headers[self.api_microversion_header_name] = ('volume %s' %
-                                                          VOLUME_MICROVERSION)
-        return headers
-
-    def request(self, method, url, extra_headers=False, headers=None,
-                body=None, chunked=False):
-
-        resp, resp_body = super(BaseClient, self).request(
-            method, url, extra_headers, headers, body, chunked)
-        if (VOLUME_MICROVERSION and
-            VOLUME_MICROVERSION != api_version_utils.LATEST_MICROVERSION):
-            api_version_utils.assert_version_header_matches_request(
-                self.api_microversion_header_name,
-                'volume %s' % VOLUME_MICROVERSION,
-                resp)
-        return resp, resp_body
+BaseClient = moves.moved_class(base_client.BaseClient, 'BaseClient', __name__,
+                               version="Pike", removal_version='?')
+BaseClient.api_version = 'v3'
diff --git a/tempest/lib/services/volume/v3/group_types_client.py b/tempest/lib/services/volume/v3/group_types_client.py
index 390d44d..a6edbf5 100644
--- a/tempest/lib/services/volume/v3/group_types_client.py
+++ b/tempest/lib/services/volume/v3/group_types_client.py
@@ -16,11 +16,12 @@
 from oslo_serialization import jsonutils as json
 
 from tempest.lib.common import rest_client
-from tempest.lib.services.volume.v3 import base_client
+from tempest.lib.services.volume import base_client
 
 
 class GroupTypesClient(base_client.BaseClient):
     """Client class to send CRUD Volume V3 Group Types API requests"""
+    api_version = 'v3'
 
     @property
     def resource_type(self):
diff --git a/tempest/lib/services/volume/v3/groups_client.py b/tempest/lib/services/volume/v3/groups_client.py
index c06997a..9b53bb7 100644
--- a/tempest/lib/services/volume/v3/groups_client.py
+++ b/tempest/lib/services/volume/v3/groups_client.py
@@ -18,11 +18,12 @@
 
 from tempest.lib.common import rest_client
 from tempest.lib import exceptions as lib_exc
-from tempest.lib.services.volume.v3 import base_client
+from tempest.lib.services.volume import base_client
 
 
 class GroupsClient(base_client.BaseClient):
     """Client class to send CRUD Volume Group API requests"""
+    api_version = 'v3'
 
     def create_group(self, **kwargs):
         """Creates a group.
diff --git a/tempest/lib/services/volume/v3/messages_client.py b/tempest/lib/services/volume/v3/messages_client.py
index 8a01864..0127271 100644
--- a/tempest/lib/services/volume/v3/messages_client.py
+++ b/tempest/lib/services/volume/v3/messages_client.py
@@ -17,11 +17,12 @@
 
 from tempest.lib.common import rest_client
 from tempest.lib import exceptions as lib_exc
-from tempest.lib.services.volume.v3 import base_client
+from tempest.lib.services.volume import base_client
 
 
 class MessagesClient(base_client.BaseClient):
     """Client class to send user messages API requests."""
+    api_version = 'v3'
 
     def show_message(self, message_id):
         """Show details for a single message."""
diff --git a/tempest/lib/services/volume/v3/versions_client.py b/tempest/lib/services/volume/v3/versions_client.py
index e2941c4..5702f95 100644
--- a/tempest/lib/services/volume/v3/versions_client.py
+++ b/tempest/lib/services/volume/v3/versions_client.py
@@ -18,10 +18,11 @@
 
 from tempest.lib.api_schema.response.volume import versions as schema
 from tempest.lib.common import rest_client
-from tempest.lib.services.volume.v3 import base_client
+from tempest.lib.services.volume import base_client
 
 
 class VersionsClient(base_client.BaseClient):
+    api_version = 'v3'
 
     def list_versions(self):
         """List API versions
diff --git a/tempest/lib/services/volume/v3/volumes_client.py b/tempest/lib/services/volume/v3/volumes_client.py
index aec0205..5f4b278 100644
--- a/tempest/lib/services/volume/v3/volumes_client.py
+++ b/tempest/lib/services/volume/v3/volumes_client.py
@@ -18,11 +18,9 @@
 
 from tempest.lib.common import rest_client
 from tempest.lib.services.volume.v2 import volumes_client
-from tempest.lib.services.volume.v3 import base_client
 
 
-class VolumesClient(base_client.BaseClient,
-                    volumes_client.VolumesClient):
+class VolumesClient(volumes_client.VolumesClient):
     """Client class to send CRUD Volume V3 API requests"""
     api_version = "v3"
 
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 38e03c7..aecb374 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -1249,6 +1249,17 @@
             type_id, provider=provider, key_size=key_size, cipher=cipher,
             control_location=control_location)['encryption']
 
+    def create_encrypted_volume(self, encryption_provider, volume_type,
+                                key_size=256, cipher='aes-xts-plain64',
+                                control_location='front-end'):
+        volume_type = self.create_volume_type(name=volume_type)
+        self.create_encryption_type(type_id=volume_type['id'],
+                                    provider=encryption_provider,
+                                    key_size=key_size,
+                                    cipher=cipher,
+                                    control_location=control_location)
+        return self.create_volume(volume_type=volume_type['name'])
+
 
 class ObjectStorageScenarioTest(ScenarioTest):
     """Provide harness to do Object Storage scenario tests.
diff --git a/tempest/scenario/test_encrypted_cinder_volumes.py b/tempest/scenario/test_encrypted_cinder_volumes.py
index d7b86f6..cbdf307 100644
--- a/tempest/scenario/test_encrypted_cinder_volumes.py
+++ b/tempest/scenario/test_encrypted_cinder_volumes.py
@@ -48,15 +48,6 @@
 
         return self.create_server(image_id=image, key_name=keypair['name'])
 
-    def create_encrypted_volume(self, encryption_provider, volume_type):
-        volume_type = self.create_volume_type(name=volume_type)
-        self.create_encryption_type(type_id=volume_type['id'],
-                                    provider=encryption_provider,
-                                    key_size=256,
-                                    cipher='aes-xts-plain64',
-                                    control_location='front-end')
-        return self.create_volume(volume_type=volume_type['name'])
-
     def attach_detach_volume(self, server, volume):
         attached_volume = self.nova_volume_attach(server, volume)
         self.nova_volume_detach(server, attached_volume)
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 3dfbf18..96d0474 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -24,7 +24,7 @@
 LOG = logging.getLogger(__name__)
 
 
-class TestVolumeBootPattern(manager.ScenarioTest):
+class TestVolumeBootPattern(manager.EncryptionScenarioTest):
 
     # Boot from volume scenario is quite slow, and needs extra
     # breathing room to get through deletes in the time allotted.
@@ -227,3 +227,26 @@
 
         # delete instance
         self._delete_server(instance)
+
+    @decorators.idempotent_id('cb78919a-e553-4bab-b73b-10cf4d2eb125')
+    @testtools.skipIf(CONF.volume.storage_protocol.lower() in ['ceph', 'nfs'],
+                      'Currently, {} does not support volume encryption'
+                      .format(CONF.volume.storage_protocol))
+    @test.services('compute', 'volume')
+    def test_boot_server_from_encrypted_volume_luks(self):
+        # Create an encrypted volume
+        volume = self.create_encrypted_volume('nova.volume.encryptors.'
+                                              'luks.LuksEncryptor',
+                                              volume_type='luks')
+
+        self.volumes_client.set_bootable_volume(volume['id'], bootable=True)
+
+        # Boot a server from the encrypted volume
+        server = self._boot_instance_from_resource(
+            source_id=volume['id'],
+            source_type='volume',
+            delete_on_termination=False)
+
+        server_info = self.servers_client.show_server(server['id'])['server']
+        created_volume = server_info['os-extended-volumes:volumes_attached']
+        self.assertEqual(volume['id'], created_volume[0]['id'])
diff --git a/tempest/test.py b/tempest/test.py
index f07c071..fc846ff 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -63,7 +63,14 @@
         'compute': CONF.service_available.nova,
         'image': CONF.service_available.glance,
         'volume': CONF.service_available.cinder,
+        # NOTE(masayukig): We have two network services which are neutron and
+        # nova-network. And we have no way to know whether nova-network is
+        # available or not. After the pending removal of nova-network from
+        # nova, we can treat the network/neutron case in the same manner as
+        # the other services.
         'network': True,
+        # NOTE(masayukig): Tempest tests always require the identity service.
+        # So we should set this True here.
         'identity': True,
         'object_storage': CONF.service_available.swift,
     }
@@ -247,6 +254,9 @@
 
     @classmethod
     def tearDownClass(cls):
+        # insert pdb breakpoint when pause_teardown is enabled
+        if CONF.pause_teardown:
+            cls.insert_pdb_breakpoint()
         at_exit_set.discard(cls)
         # It should never be overridden by descendants
         if hasattr(super(BaseTestCase, cls), 'tearDownClass'):
@@ -283,6 +293,22 @@
             finally:
                 del trace  # to avoid circular refs
 
+    def tearDown(self):
+        super(BaseTestCase, self).tearDown()
+        # insert pdb breakpoint when pause_teardown is enabled
+        if CONF.pause_teardown:
+            BaseTestCase.insert_pdb_breakpoint()
+
+    @classmethod
+    def insert_pdb_breakpoint(cls):
+        """Add pdb breakpoint.
+
+        This can help in debugging process, cleaning of resources is
+        paused, so they can be examined.
+        """
+        import pdb
+        pdb.set_trace()
+
     @classmethod
     def skip_checks(cls):
         """Class level skip checks.
diff --git a/tempest/tests/cmd/test_workspace.py b/tempest/tests/cmd/test_workspace.py
index dc6c0c8..a1c8c53 100644
--- a/tempest/tests/cmd/test_workspace.py
+++ b/tempest/tests/cmd/test_workspace.py
@@ -80,13 +80,20 @@
         self.assertEqual(
             self.workspace_manager.get_workspace(self.name), new_path)
 
-    def test_run_workspace_remove(self):
+    def test_run_workspace_remove_entry(self):
         cmd = ['tempest', 'workspace', 'remove',
                '--workspace-path', self.store_file,
                '--name', self.name]
         self._run_cmd_gets_return_code(cmd, 0)
         self.assertIsNone(self.workspace_manager.get_workspace(self.name))
 
+    def test_run_workspace_remove_directory(self):
+        cmd = ['tempest', 'workspace', 'remove',
+               '--workspace-path', self.store_file,
+               '--name', self.name, '--rmdir']
+        self._run_cmd_gets_return_code(cmd, 0)
+        self.assertIsNone(self.workspace_manager.get_workspace(self.name))
+
 
 class TestTempestWorkspaceManager(TestTempestWorkspaceBase):
     def setUp(self):
@@ -117,8 +124,13 @@
         self.assertEqual(
             self.workspace_manager.get_workspace(self.name), new_path)
 
-    def test_workspace_manager_remove(self):
-        self.workspace_manager.remove_workspace(self.name)
+    def test_workspace_manager_remove_entry(self):
+        self.workspace_manager.remove_workspace_entry(self.name)
+        self.assertIsNone(self.workspace_manager.get_workspace(self.name))
+
+    def test_workspace_manager_remove_directory(self):
+        path = self.workspace_manager.remove_workspace_entry(self.name)
+        self.workspace_manager.remove_workspace_directory(path)
         self.assertIsNone(self.workspace_manager.get_workspace(self.name))
 
     def test_path_expansion(self):
diff --git a/tempest/tests/lib/services/base.py b/tempest/tests/lib/services/base.py
index 90c9f63..778c966 100644
--- a/tempest/tests/lib/services/base.py
+++ b/tempest/tests/lib/services/base.py
@@ -40,7 +40,7 @@
                function.
         :param body: Expected response body returned by the service client
                function.
-        :param to_utf: Whether to use UTF-8 encoding for request.
+        :param to_utf: Whether to use UTF-8 encoding for response.
         :param status: Expected response status returned by the service client
                function.
         :param headers: Expected headers returned by the service client
diff --git a/tempest/tests/lib/services/compute/test_services_client.py b/tempest/tests/lib/services/compute/test_services_client.py
index 41da39c..2dd981c 100644
--- a/tempest/tests/lib/services/compute/test_services_client.py
+++ b/tempest/tests/lib/services/compute/test_services_client.py
@@ -14,6 +14,9 @@
 
 import copy
 
+import mock
+
+from tempest.lib.services.compute import base_compute_client
 from tempest.lib.services.compute import services_client
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib.services import base
@@ -44,11 +47,21 @@
         }
     }
 
+    FAKE_UPDATE_FORCED_DOWN = {
+        "service":
+        {
+            "forced_down": True,
+            "binary": "nova-conductor",
+            "host": "controller"
+        }
+    }
+
     def setUp(self):
         super(TestServicesClient, self).setUp()
         fake_auth = fake_auth_provider.FakeAuthProvider()
         self.client = services_client.ServicesClient(
             fake_auth, 'compute', 'regionOne')
+        self.addCleanup(mock.patch.stopall)
 
     def test_list_services_with_str_body(self):
         self.check_service_client_function(
@@ -68,7 +81,7 @@
             'tempest.lib.common.rest_client.RestClient.put',
             self.FAKE_SERVICE,
             bytes_body,
-            host_name="nova-conductor", binary="controller")
+            host="nova-conductor", binary="controller")
 
     def test_enable_service_with_str_body(self):
         self._test_enable_service()
@@ -85,10 +98,49 @@
             'tempest.lib.common.rest_client.RestClient.put',
             fake_service,
             bytes_body,
-            host_name="nova-conductor", binary="controller")
+            host="nova-conductor", binary="controller")
 
     def test_disable_service_with_str_body(self):
         self._test_disable_service()
 
     def test_disable_service_with_bytes_body(self):
         self._test_disable_service(bytes_body=True)
+
+    def _test_log_reason_disabled_service(self, bytes_body=False):
+        resp_body = copy.deepcopy(self.FAKE_SERVICE)
+        resp_body['service']['disabled_reason'] = 'test reason'
+
+        self.check_service_client_function(
+            self.client.disable_log_reason,
+            'tempest.lib.common.rest_client.RestClient.put',
+            resp_body,
+            bytes_body,
+            host="nova-conductor",
+            binary="controller",
+            disabled_reason='test reason')
+
+    def test_log_reason_disabled_service_with_str_body(self):
+        self._test_log_reason_disabled_service()
+
+    def test_log_reason_disabled_service_with_bytes_body(self):
+        self._test_log_reason_disabled_service(bytes_body=True)
+
+    def _test_update_forced_down(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.update_forced_down,
+            'tempest.lib.common.rest_client.RestClient.put',
+            self.FAKE_UPDATE_FORCED_DOWN,
+            bytes_body,
+            host="nova-conductor",
+            binary="controller",
+            forced_down=True)
+
+    @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION',
+                       new_callable=mock.PropertyMock(return_value='2.11'))
+    def test_update_forced_down_with_str_body(self, _):
+        self._test_update_forced_down()
+
+    @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION',
+                       new_callable=mock.PropertyMock(return_value='2.11'))
+    def test_update_forced_down_with_bytes_body(self, _):
+        self._test_update_forced_down(bytes_body=True)
diff --git a/tempest/tests/lib/services/identity/v3/test_identity_client.py b/tempest/tests/lib/services/identity/v3/test_identity_client.py
index e435fe2..6572947 100644
--- a/tempest/tests/lib/services/identity/v3/test_identity_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_identity_client.py
@@ -109,6 +109,14 @@
             resp_token="cbc36478b0bd8e67e89",
             status=204)
 
+    def test_check_token_existence(self):
+        self.check_service_client_function(
+            self.client.check_token_existence,
+            'tempest.lib.common.rest_client.RestClient.head',
+            {},
+            resp_token="cbc36478b0bd8e67e89",
+            status=200)
+
     def test_list_auth_projects_with_str_body(self):
         self._test_list_auth_projects()
 
diff --git a/tempest/tests/lib/services/identity/v3/test_oauth_token_client.py b/tempest/tests/lib/services/identity/v3/test_oauth_token_client.py
index b9b9b15..420ea5f 100644
--- a/tempest/tests/lib/services/identity/v3/test_oauth_token_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_oauth_token_client.py
@@ -13,7 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from oslotest import mockpatch
+import fixtures
 
 from tempest.lib.services.identity.v3 import oauth_token_client
 from tempest.tests.lib import fake_auth_provider
@@ -137,7 +137,7 @@
     def test_create_request_token(self):
         mock_resp = self._mock_token_response(self.FAKE_CREATE_REQUEST_TOKEN)
         resp = fake_http.fake_http_response(None, status=201), mock_resp
-        self.useFixture(mockpatch.Patch(
+        self.useFixture(fixtures.MockPatch(
             'tempest.lib.common.rest_client.RestClient.post',
             return_value=resp))
 
@@ -157,7 +157,7 @@
         mock_resp = self._mock_token_response(self.FAKE_CREATE_ACCESS_TOKEN)
         req_secret = self.FAKE_CREATE_REQUEST_TOKEN['oauth_token_secret']
         resp = fake_http.fake_http_response(None, status=201), mock_resp
-        self.useFixture(mockpatch.Patch(
+        self.useFixture(fixtures.MockPatch(
             'tempest.lib.common.rest_client.RestClient.post',
             return_value=resp))
 
diff --git a/tempest/tests/lib/services/volume/v2/test_backups_client.py b/tempest/tests/lib/services/volume/v2/test_backups_client.py
new file mode 100644
index 0000000..14e5fb0
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v2/test_backups_client.py
@@ -0,0 +1,117 @@
+# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.lib.services.volume.v2 import backups_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestBackupsClient(base.BaseServiceTest):
+
+    FAKE_BACKUP_LIST = {
+        "backups": [
+            {
+                "id": "2ef47aee-8844-490c-804d-2a8efe561c65",
+                "links": [
+                    {
+                        "href": "fake-url-1",
+                        "rel": "self"
+                    },
+                    {
+                        "href": "fake-url-2",
+                        "rel": "bookmark"
+                    }
+                ],
+                "name": "backup001"
+            }
+        ]
+    }
+
+    FAKE_BACKUP_LIST_WITH_DETAIL = {
+        "backups": [
+            {
+                "availability_zone": "az1",
+                "container": "volumebackups",
+                "created_at": "2013-04-02T10:35:27.000000",
+                "description": None,
+                "fail_reason": None,
+                "id": "2ef47aee-8844-490c-804d-2a8efe561c65",
+                "links": [
+                    {
+                        "href": "fake-url-1",
+                        "rel": "self"
+                    },
+                    {
+                        "href": "fake-url-2",
+                        "rel": "bookmark"
+                    }
+                ],
+                "name": "backup001",
+                "object_count": 22,
+                "size": 1,
+                "status": "available",
+                "volume_id": "e5185058-943a-4cb4-96d9-72c184c337d6",
+                "is_incremental": True,
+                "has_dependent_backups": False
+            }
+        ]
+    }
+
+    def setUp(self):
+        super(TestBackupsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = backups_client.BackupsClient(fake_auth,
+                                                   'volume',
+                                                   'regionOne')
+
+    def _test_list_backups(self, detail=False, mock_args='backups',
+                           bytes_body=False, **params):
+        if detail:
+            resp_body = self.FAKE_BACKUP_LIST_WITH_DETAIL
+        else:
+            resp_body = self.FAKE_BACKUP_LIST
+        self.check_service_client_function(
+            self.client.list_backups,
+            'tempest.lib.common.rest_client.RestClient.get',
+            resp_body,
+            to_utf=bytes_body,
+            mock_args=[mock_args],
+            detail=detail,
+            **params)
+
+    def test_list_backups_with_str_body(self):
+        self._test_list_backups()
+
+    def test_list_backups_with_bytes_body(self):
+        self._test_list_backups(bytes_body=True)
+
+    def test_list_backups_with_detail_with_str_body(self):
+        mock_args = "backups/detail"
+        self._test_list_backups(detail=True, mock_args=mock_args)
+
+    def test_list_backups_with_detail_with_bytes_body(self):
+        mock_args = "backups/detail"
+        self._test_list_backups(detail=True, mock_args=mock_args,
+                                bytes_body=True)
+
+    def test_list_backups_with_params(self):
+        # Run the test separately for each param, to avoid assertion error
+        # resulting from randomized params order.
+        mock_args = 'backups?sort_key=name'
+        self._test_list_backups(mock_args=mock_args, sort_key='name')
+
+        mock_args = 'backups/detail?limit=10'
+        self._test_list_backups(detail=True, mock_args=mock_args,
+                                bytes_body=True, limit=10)
diff --git a/tempest/tests/lib/services/volume/v2/test_snapshots_client.py b/tempest/tests/lib/services/volume/v2/test_snapshots_client.py
index 7d656f1..c9f57a0 100644
--- a/tempest/tests/lib/services/volume/v2/test_snapshots_client.py
+++ b/tempest/tests/lib/services/volume/v2/test_snapshots_client.py
@@ -72,6 +72,12 @@
         ]
     }
 
+    FAKE_SNAPSHOT_METADATA_ITEM = {
+        "meta": {
+            "key1": "value1"
+        }
+    }
+
     def setUp(self):
         super(TestSnapshotsClient, self).setUp()
         fake_auth = fake_auth_provider.FakeAuthProvider()
@@ -142,6 +148,15 @@
             self.FAKE_INFO_SNAPSHOT,
             bytes_body, volume_type_id="cbc36478b0bd8e67e89")
 
+    def _test_show_snapshot_metadata_item(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_snapshot_metadata_item,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_SNAPSHOT_METADATA_ITEM,
+            bytes_body,
+            snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5",
+            id="key1")
+
     def test_create_snapshot_with_str_body(self):
         self._test_create_snapshot()
 
@@ -184,6 +199,12 @@
     def test_update_snapshot_metadata_with_bytes_body(self):
         self._test_update_snapshot_metadata(bytes_body=True)
 
+    def test_show_snapshot_metadata_item_with_str_body(self):
+        self._test_show_snapshot_metadata_item()
+
+    def test_show_snapshot_metadata_item_with_bytes_body(self):
+        self._test_show_snapshot_metadata_item(bytes_body=True)
+
     def test_force_delete_snapshot(self):
         self.check_service_client_function(
             self.client.force_delete_snapshot,
diff --git a/tempest/tests/lib/services/volume/v2/test_transfers_client.py b/tempest/tests/lib/services/volume/v2/test_transfers_client.py
index 0c59bf2..84f4992 100644
--- a/tempest/tests/lib/services/volume/v2/test_transfers_client.py
+++ b/tempest/tests/lib/services/volume/v2/test_transfers_client.py
@@ -13,6 +13,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import copy
+
+import mock
+from oslo_serialization import jsonutils as json
+
 from tempest.lib.services.volume.v2 import transfers_client
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib.services import base
@@ -20,11 +25,14 @@
 
 class TestTransfersClient(base.BaseServiceTest):
 
-    FAKE_LIST_VOLUME_TRANSFERS_WITH_DETAIL = {
-        "transfers": [{
-            "created_at": "2017-04-18T09:10:03.000000",
+    FAKE_VOLUME_TRANSFER_ID = "0e89cdd1-6249-421b-96d8-25fac0623d42"
+
+    FAKE_VOLUME_TRANSFER_INFO = {
+        "transfer": {
+            "id": FAKE_VOLUME_TRANSFER_ID,
+            "name": "fake-volume-transfer",
             "volume_id": "47bf04ef-1ea5-4c5f-a375-430a086d6747",
-            "id": "0e89cdd1-6249-421b-96d8-25fac0623d42",
+            "created_at": "2017-04-18T09:10:03.000000",
             "links": [
                 {
                     "href": "fake-url-1",
@@ -34,9 +42,8 @@
                     "href": "fake-url-2",
                     "rel": "bookmark"
                 }
-            ],
-            "name": "fake-volume-transfer"
-        }]
+            ]
+        }
     }
 
     def setUp(self):
@@ -46,16 +53,106 @@
                                                        'volume',
                                                        'regionOne')
 
-    def _test_list_volume_transfers_with_detail(self, bytes_body=False):
+    def _test_create_volume_transfer(self, bytes_body=False):
+        resp_body = copy.deepcopy(self.FAKE_VOLUME_TRANSFER_INFO)
+        resp_body['transfer'].update({"auth_key": "fake-auth-key"})
+        kwargs = {"name": "fake-volume-transfer",
+                  "volume_id": "47bf04ef-1ea5-4c5f-a375-430a086d6747"}
+        payload = json.dumps({"transfer": kwargs}, sort_keys=True)
+        json_dumps = json.dumps
+
+        # NOTE: Use sort_keys for json.dumps so that the expected and actual
+        # payloads are guaranteed to be identical for mock_args assert check.
+        with mock.patch.object(transfers_client.json, 'dumps') as mock_dumps:
+            mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True)
+
+            self.check_service_client_function(
+                self.client.create_volume_transfer,
+                'tempest.lib.common.rest_client.RestClient.post',
+                resp_body,
+                to_utf=bytes_body,
+                status=202,
+                mock_args=['os-volume-transfer', payload],
+                **kwargs)
+
+    def _test_accept_volume_transfer(self, bytes_body=False):
+        resp_body = copy.deepcopy(self.FAKE_VOLUME_TRANSFER_INFO)
+        resp_body['transfer'].pop('created_at')
+        kwargs = {"auth_key": "fake-auth-key"}
+        payload = json.dumps({"accept": kwargs}, sort_keys=True)
+        json_dumps = json.dumps
+
+        # NOTE: Use sort_keys for json.dumps so that the expected and actual
+        # payloads are guaranteed to be identical for mock_args assert check.
+        with mock.patch.object(transfers_client.json, 'dumps') as mock_dumps:
+            mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True)
+
+            self.check_service_client_function(
+                self.client.accept_volume_transfer,
+                'tempest.lib.common.rest_client.RestClient.post',
+                resp_body,
+                to_utf=bytes_body,
+                status=202,
+                mock_args=['os-volume-transfer/%s/accept' %
+                           self.FAKE_VOLUME_TRANSFER_ID, payload],
+                transfer_id=self.FAKE_VOLUME_TRANSFER_ID,
+                **kwargs)
+
+    def _test_show_volume_transfer(self, bytes_body=False):
+        resp_body = self.FAKE_VOLUME_TRANSFER_INFO
+        self.check_service_client_function(
+            self.client.show_volume_transfer,
+            'tempest.lib.common.rest_client.RestClient.get',
+            resp_body,
+            to_utf=bytes_body,
+            transfer_id="0e89cdd1-6249-421b-96d8-25fac0623d42")
+
+    def _test_list_volume_transfers(self, detail=False, bytes_body=False):
+        resp_body = copy.deepcopy(self.FAKE_VOLUME_TRANSFER_INFO)
+        if not detail:
+            resp_body['transfer'].pop('created_at')
+        resp_body = {"transfers": [resp_body['transfer']]}
         self.check_service_client_function(
             self.client.list_volume_transfers,
             'tempest.lib.common.rest_client.RestClient.get',
-            self.FAKE_LIST_VOLUME_TRANSFERS_WITH_DETAIL,
-            bytes_body,
-            detail=True)
+            resp_body,
+            to_utf=bytes_body,
+            detail=detail)
+
+    def test_create_volume_transfer_with_str_body(self):
+        self._test_create_volume_transfer()
+
+    def test_create_volume_transfer_with_bytes_body(self):
+        self._test_create_volume_transfer(bytes_body=True)
+
+    def test_accept_volume_transfer_with_str_body(self):
+        self._test_accept_volume_transfer()
+
+    def test_accept_volume_transfer_with_bytes_body(self):
+        self._test_accept_volume_transfer(bytes_body=True)
+
+    def test_show_volume_transfer_with_str_body(self):
+        self._test_show_volume_transfer()
+
+    def test_show_volume_transfer_with_bytes_body(self):
+        self._test_show_volume_transfer(bytes_body=True)
+
+    def test_list_volume_transfers_with_str_body(self):
+        self._test_list_volume_transfers()
+
+    def test_list_volume_transfers_with_bytes_body(self):
+        self._test_list_volume_transfers(bytes_body=True)
 
     def test_list_volume_transfers_with_detail_with_str_body(self):
-        self._test_list_volume_transfers_with_detail()
+        self._test_list_volume_transfers(detail=True)
 
     def test_list_volume_transfers_with_detail_with_bytes_body(self):
-        self._test_list_volume_transfers_with_detail(bytes_body=True)
+        self._test_list_volume_transfers(detail=True, bytes_body=True)
+
+    def test_delete_volume_transfer(self):
+        self.check_service_client_function(
+            self.client.delete_volume_transfer,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {},
+            status=202,
+            transfer_id="0e89cdd1-6249-421b-96d8-25fac0623d42")
diff --git a/tempest/tests/lib/services/volume/v2/test_volumes_client.py b/tempest/tests/lib/services/volume/v2/test_volumes_client.py
index 498b963..befb1f6 100644
--- a/tempest/tests/lib/services/volume/v2/test_volumes_client.py
+++ b/tempest/tests/lib/services/volume/v2/test_volumes_client.py
@@ -20,6 +20,12 @@
 
 class TestVolumesClient(base.BaseServiceTest):
 
+    FAKE_VOLUME_METADATA_ITEM = {
+        "meta": {
+            "key1": "value1"
+        }
+    }
+
     def setUp(self):
         super(TestVolumesClient, self).setUp()
         fake_auth = fake_auth_provider.FakeAuthProvider()
@@ -45,8 +51,23 @@
             **kwargs
         )
 
+    def _test_show_volume_metadata_item(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_volume_metadata_item,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_VOLUME_METADATA_ITEM,
+            to_utf=bytes_body,
+            volume_id="a3be971b-8de5-4bdf-bdb8-3d8eb0fb69f8",
+            id="key1")
+
     def test_force_detach_volume_with_str_body(self):
         self._test_force_detach_volume()
 
     def test_force_detach_volume_with_bytes_body(self):
         self._test_force_detach_volume(bytes_body=True)
+
+    def test_show_volume_metadata_item_with_str_body(self):
+        self._test_show_volume_metadata_item()
+
+    def test_show_volume_metadata_item_with_bytes_body(self):
+        self._test_show_volume_metadata_item(bytes_body=True)
diff --git a/tempest/tests/lib/services/volume/v3/test_backups_client.py b/tempest/tests/lib/services/volume/v3/test_backups_client.py
new file mode 100644
index 0000000..f1ce987
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v3/test_backups_client.py
@@ -0,0 +1,50 @@
+# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.lib.services.volume.v3 import backups_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestBackupsClient(base.BaseServiceTest):
+
+    FAKE_BACKUP_UPDATE = {
+        "backup": {
+            "id": "4c65c15f-a5c5-464b-b92a-90e4c04636a7",
+            "name": "fake-backup-name",
+            "links": "fake-links"
+        }
+    }
+
+    def setUp(self):
+        super(TestBackupsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = backups_client.BackupsClient(fake_auth,
+                                                   'volume',
+                                                   'regionOne')
+
+    def _test_update_backup(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.update_backup,
+            'tempest.lib.common.rest_client.RestClient.put',
+            self.FAKE_BACKUP_UPDATE,
+            bytes_body,
+            backup_id='4c65c15f-a5c5-464b-b92a-90e4c04636a7')
+
+    def test_update_backup_with_str_body(self):
+        self._test_update_backup()
+
+    def test_update_backup_with_bytes_body(self):
+        self._test_update_backup(bytes_body=True)
diff --git a/test-requirements.txt b/test-requirements.txt
index f8793be..6a5ea03 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -4,10 +4,9 @@
 hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
 # needed for doc build
 sphinx>=1.6.2 # BSD
-oslosphinx>=4.7.0 # Apache-2.0
+openstackdocstheme>=1.11.0 # Apache-2.0
 reno!=2.3.1,>=1.8.0 # Apache-2.0
 mock>=2.0 # BSD
 coverage!=4.4,>=4.0 # Apache-2.0
 oslotest>=1.10.0 # Apache-2.0
 flake8-import-order==0.11 # LGPLv3
-openstackdocstheme>=1.11.0 # Apache-2.0
diff --git a/tools/generate-tempest-plugins-list.py b/tools/generate-tempest-plugins-list.py
index 5e63c0d..99df0d1 100644
--- a/tools/generate-tempest-plugins-list.py
+++ b/tools/generate-tempest-plugins-list.py
@@ -26,7 +26,14 @@
 import json
 import re
 
-from six.moves import urllib
+try:
+    # For Python 3.0 and later
+    from urllib.error import HTTPError as HTTPError
+    import urllib.request as urllib
+except ImportError:
+    # Fall back to Python 2's urllib2
+    import urllib2 as urllib
+    from urllib2 import HTTPError as HTTPError
 
 
 url = 'https://review.openstack.org/projects/'
@@ -51,9 +58,9 @@
 
 def has_tempest_plugin(proj):
     try:
-        r = urllib.request.urlopen(
+        r = urllib.urlopen(
             "https://git.openstack.org/cgit/%s/plain/setup.cfg" % proj)
-    except urllib.error.HTTPError as err:
+    except HTTPError as err:
         if err.code == 404:
             return False
     p = re.compile('^tempest\.test_plugins', re.M)
@@ -62,7 +69,7 @@
     else:
         False
 
-r = urllib.request.urlopen(url)
+r = urllib.urlopen(url)
 # Gerrit prepends 4 garbage octets to the JSON, in order to counter
 # cross-site scripting attacks.  Therefore we must discard it so the
 # json library won't choke.
diff --git a/tools/tempest-plugin-sanity.sh b/tools/tempest-plugin-sanity.sh
new file mode 100644
index 0000000..a4f706e
--- /dev/null
+++ b/tools/tempest-plugin-sanity.sh
@@ -0,0 +1,122 @@
+#!/usr/bin/env bash
+
+# Copyright 2017 Red Hat, Inc.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+# This script is intended to check the sanity of tempest plugins against
+# tempest master.
+# What it does:
+# * Creates the virtualenv
+# * Install tempest
+# * Retrive the project lists having tempest plugin if project name is
+#   given.
+# * For each project in a list, It does:
+#   * Clone the Project
+#   * Install the Project and also installs dependencies from
+#     test-requirements.txt.
+#   * Create Tempest workspace
+#   * List tempest plugins
+#   * List tempest plugins tests
+#   * Uninstall the project and its dependencies
+#   * Again Install tempest
+#   * Again repeat the step from cloning project
+#
+# If one of the step fails, The script will exit with failure.
+
+if [ "$1" == "-h" ]; then
+    echo -e "This script performs the sanity of tempest plugins to find
+configuration and dependency issues with the tempest.\n
+Usage: sh ./tools/tempest-plugin-sanity.sh [Run sanity on tempest plugins]"
+    exit 0
+fi
+
+set -ex
+
+# retrieve a list of projects having tempest plugins
+PROJECT_LIST="$(python tools/generate-tempest-plugins-list.py)"
+# List of projects having tempest plugin stale or unmaintained from long time
+BLACKLIST="trio2o"
+
+# Function to clone project using zuul-cloner or from git
+function clone_project() {
+    if [ -e /usr/zuul-env/bin/zuul-cloner ]; then
+        /usr/zuul-env/bin/zuul-cloner --cache-dir /opt/git \
+        git://git.openstack.org \
+        openstack/"$1"
+
+    elif [ -e /usr/bin/git ]; then
+        /usr/bin/git clone git://git.openstack.org/openstack/"$1" \
+        openstack/"$1"
+
+    fi
+}
+
+# Create virtualenv to perform sanity operation
+SANITY_DIR=$(pwd)
+virtualenv "$SANITY_DIR"/.venv
+export TVENV="$SANITY_DIR/tools/with_venv.sh"
+cd "$SANITY_DIR"
+
+# Install tempest in a venv
+"$TVENV" pip install .
+
+# Function to install project
+function install_project() {
+    "$TVENV" pip install "$SANITY_DIR"/openstack/"$1"
+    # Check for test-requirements.txt file in a project then install it.
+    if [ -e "$SANITY_DIR"/openstack/"$1"/test-requirements.txt ]; then
+        "$TVENV" pip install -r "$SANITY_DIR"/openstack/"$1"/test-requirements.txt
+    fi
+}
+
+# Function to perform sanity checking on Tempest plugin
+function tempest_sanity() {
+    "$TVENV" tempest init "$SANITY_DIR"/tempest_sanity
+    cd "$SANITY_DIR"/tempest_sanity
+    "$TVENV" tempest list-plugins
+    "$TVENV" tempest run -l
+    # Delete tempest workspace
+    "$TVENV" tempest workspace remove --name tempest_sanity --rmdir
+    cd "$SANITY_DIR"
+}
+
+# Function to uninstall project
+function uninstall_project() {
+    "$TVENV" pip uninstall -y "$SANITY_DIR"/openstack/"$1"
+    # Check for *requirements.txt file in a project then uninstall it.
+    if [ -e "$SANITY_DIR"/openstack/"$1"/*requirements.txt ]; then
+        "$TVENV" pip uninstall -y -r "$SANITY_DIR"/openstack/"$1"/*requirements.txt
+    fi
+    # Remove the project directory after sanity run
+    rm -fr "$SANITY_DIR"/openstack/"$1"
+}
+
+# Function to run sanity check on each project
+function plugin_sanity_check() {
+        clone_project "$1"  &&  install_project "$1"  &&  tempest_sanity "$1" \
+        &&  uninstall_project "$1"  &&  "$TVENV" pip install .
+}
+
+# Log status
+passed_plugin=''
+failed_plugin=''
+# Perform sanity on all tempest plugin projects
+for project in $PROJECT_LIST; do
+    # Remove blacklisted tempest plugins
+    if ! [[ `echo $BLACKLIST | grep -c $project ` -gt 0 ]]; then
+        plugin_sanity_check $project && passed_plugin+=", $project" || \
+        failed_plugin+=", $project"
+    fi
+done
diff --git a/tox.ini b/tox.ini
index 892f834..2120818 100644
--- a/tox.ini
+++ b/tox.ini
@@ -185,3 +185,9 @@
 # separately, outside of the requirements files.
 deps = bindep
 commands = bindep test
+
+[testenv:plugin-sanity-check]
+# perform tempest plugin sanity
+whitelist_externals = bash
+commands =
+  bash tools/tempest-plugin-sanity.sh