Add v2 Manila API path as base for microversions

To prevent a microversioned client from managing a non-microversioned
Manila server, Manila must update its REST endpoints by adding /v2 for
all microversioned APIs.

This commit does the following:

* Add /v2 to the URL map, connected to all the same /v1 API methods
* Renumber the microversion sequence starting from 2.0
* Update the versions API to reflect v2
* Publish the new endpoint to Keystone in the DevStack plug-in
* Update relevant documentation
* Update Tempest tests for microversions
APIImpact
Co-Authored-By: Andrew Kerr <andrew.kerr@netapp.com>
Closes-Bug: 1488624
Change-Id: I56a516b5f81914557dd2465746629431cfd6deac
diff --git a/manila_tempest_tests/clients_share.py b/manila_tempest_tests/clients_share.py
index 1411286..65ee64e 100644
--- a/manila_tempest_tests/clients_share.py
+++ b/manila_tempest_tests/clients_share.py
@@ -17,12 +17,16 @@
 from tempest.common import cred_provider
 
 from manila_tempest_tests.services.share.json import shares_client
+from manila_tempest_tests.services.share.v2.json import shares_client \
+    as shares_v2_client
 
 
 class Manager(clients.Manager):
     def __init__(self, credentials=None, service=None):
         super(Manager, self).__init__(credentials, service)
         self.shares_client = shares_client.SharesClient(self.auth_provider)
+        self.shares_v2_client = shares_v2_client.SharesV2Client(
+            self.auth_provider)
 
 
 class AltManager(Manager):
diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py
index 046f8cd..daed82e 100644
--- a/manila_tempest_tests/config.py
+++ b/manila_tempest_tests/config.py
@@ -32,11 +32,11 @@
 
 ShareGroup = [
     cfg.StrOpt("min_api_microversion",
-               default="1.0",
+               default="2.0",
                help="The minimum api microversion is configured to be the "
                     "value of the minimum microversion supported by Manila."),
     cfg.StrOpt("max_api_microversion",
-               default="1.6",
+               default="2.5",
                help="The maximum api microversion is configured to be the "
                     "value of the latest microversion supported by Manila."),
     cfg.StrOpt("region",
diff --git a/manila_tempest_tests/services/share/json/shares_client.py b/manila_tempest_tests/services/share/json/shares_client.py
index 1cac0c0..660f16b 100644
--- a/manila_tempest_tests/services/share/json/shares_client.py
+++ b/manila_tempest_tests/services/share/json/shares_client.py
@@ -26,13 +26,6 @@
 from manila_tempest_tests import share_exceptions
 
 CONF = config.CONF
-LATEST_MICRO_API = {
-    'X-OpenStack-Manila-API-Version': CONF.share.max_api_microversion,
-}
-EXPERIMENTAL = {
-    'X-OpenStack-Manila-API-Experimental': 'True',
-    'X-OpenStack-Manila-API-Version': CONF.share.max_api_microversion,
-}
 
 
 class SharesClient(rest_client.RestClient):
@@ -53,48 +46,11 @@
         self.share_network_id = CONF.share.share_network_id
         self.build_interval = CONF.share.build_interval
         self.build_timeout = CONF.share.build_timeout
-        self.API_MICROVERSIONS_HEADER = 'x-openstack-manila-api-version'
-        self.API_MICROVERSIONS_EXPERIMENTAL_HEADER = (
-            'x-openstack-manila-api-experimental')
-
-    def _get_version_dict(self, version):
-        return {self.API_MICROVERSIONS_HEADER: version}
-
-    def migrate_share(self, share_id, host):
-        post_body = {
-            'os-migrate_share': {
-                'host': host,
-            }
-        }
-        body = json.dumps(post_body)
-        headers = self._get_version_dict('1.6')
-        headers[self.API_MICROVERSIONS_EXPERIMENTAL_HEADER] = 'true'
-        return self.post('shares/%s/action' % share_id, body,
-                         headers=headers, extra_headers=True)
-
-    def send_microversion_request(self, version=None):
-        """Prepare and send the HTTP GET Request to the base URL.
-
-        Extracts the base URL from the shares_client endpoint and makes a GET
-        request with the microversions request header.
-        """
-
-        headers = self.get_headers()
-        url, headers, body = self.auth_provider.auth_request(
-            'GET', 'shares', headers, None, self.filters)
-        url = '/'.join(url.split('/')[:3]) + '/'
-        if version:
-            headers[self.API_MICROVERSIONS_HEADER] = version
-        resp, resp_body = self.raw_request(url, 'GET', headers=headers)
-        self.response_checker('GET', resp, resp_body)
-        resp_body = json.loads(resp_body)
-        return resp, resp_body
 
     def create_share(self, share_protocol=None, size=1,
                      name=None, snapshot_id=None, description=None,
                      metadata=None, share_network_id=None,
-                     share_type_id=None, is_public=False,
-                     consistency_group_id=None):
+                     share_type_id=None, is_public=False):
         metadata = metadata or {}
         if name is None:
             name = data_utils.rand_name("tempest-created-share")
@@ -119,18 +75,13 @@
             post_body["share"]["share_network_id"] = share_network_id
         if share_type_id:
             post_body["share"]["share_type"] = share_type_id
-        if consistency_group_id:
-            post_body["share"]["consistency_group_id"] = consistency_group_id
         body = json.dumps(post_body)
-        resp, body = self.post("shares", body, headers=LATEST_MICRO_API,
-                               extra_headers=True)
+        resp, body = self.post("shares", body)
         self.expected_success(200, resp.status)
         return self._parse_resp(body)
 
-    def delete_share(self, share_id, params=None):
-        uri = "shares/%s" % share_id
-        uri += '?%s' % (urllib.urlencode(params) if params else '')
-        resp, body = self.delete(uri)
+    def delete_share(self, share_id):
+        resp, body = self.delete("shares/%s" % share_id)
         self.expected_success(202, resp.status)
         return body
 
@@ -161,8 +112,7 @@
         """Get list of shares w/o filters."""
         uri = 'shares/detail' if detailed else 'shares'
         uri += '?%s' % urllib.urlencode(params) if params else ''
-        resp, body = self.get(uri, headers=LATEST_MICRO_API,
-                              extra_headers=True)
+        resp, body = self.get(uri)
         self.expected_success(200, resp.status)
         return self._parse_resp(body)
 
@@ -171,29 +121,7 @@
         return self.list_shares(detailed=True, params=params)
 
     def get_share(self, share_id):
-        resp, body = self.get("shares/%s" % share_id, headers=LATEST_MICRO_API,
-                              extra_headers=True)
-        self.expected_success(200, resp.status)
-        return self._parse_resp(body)
-
-    def get_instances_of_share(self, share_id):
-        resp, body = self.get("shares/%s/instances" % share_id,
-                              headers=self._get_version_dict('1.4'),
-                              extra_headers=True)
-        self.expected_success(200, resp.status)
-        return self._parse_resp(body)
-
-    def list_share_instances(self):
-        resp, body = self.get("share_instances",
-                              headers=self._get_version_dict('1.4'),
-                              extra_headers=True)
-        self.expected_success(200, resp.status)
-        return self._parse_resp(body)
-
-    def get_share_instance(self, instance_id):
-        resp, body = self.get("share_instances/%s" % instance_id,
-                              headers=self._get_version_dict('1.4'),
-                              extra_headers=True)
+        resp, body = self.get("shares/%s" % share_id)
         self.expected_success(200, resp.status)
         return self._parse_resp(body)
 
@@ -292,30 +220,6 @@
         self.expected_success(202, resp.status)
         return body
 
-    def wait_for_migration_completed(self, share_id, dest_host):
-        """Waits for a share to migrate to a certain host."""
-        share = self.get_share(share_id)
-        migration_timeout = CONF.share.migration_timeout
-        start = int(time.time())
-        while share['task_state'] != 'migration_success':
-            time.sleep(self.build_interval)
-            share = self.get_share(share_id)
-            if share['task_state'] == 'migration_success':
-                return share
-            elif share['task_state'] == 'migration_error':
-                raise share_exceptions.ShareMigrationException(
-                    share_id=share['id'], src=share['host'], dest=dest_host)
-            elif int(time.time()) - start >= migration_timeout:
-                message = ('Share %(share_id)s failed to migrate from '
-                           'host %(src)s to host %(dest)s within the required '
-                           'time %(timeout)s.' % {
-                               'src': share['host'],
-                               'dest': dest_host,
-                               'share_id': share['id'],
-                               'timeout': self.build_timeout
-                           })
-                raise exceptions.TimeoutException(message)
-
     def wait_for_share_status(self, share_id, status):
         """Waits for a share to reach a given status."""
         body = self.get_share(share_id)
@@ -339,28 +243,6 @@
                            (share_name, status, self.build_timeout))
                 raise exceptions.TimeoutException(message)
 
-    def wait_for_share_instance_status(self, instance_id, status):
-        """Waits for a share to reach a given status."""
-        body = self.get_share_instance(instance_id)
-        instance_status = body['status']
-        start = int(time.time())
-
-        while instance_status != status:
-            time.sleep(self.build_interval)
-            body = self.get_share(instance_id)
-            instance_status = body['status']
-            if instance_status == status:
-                return
-            elif 'error' in instance_status.lower():
-                raise share_exceptions.\
-                    ShareInstanceBuildErrorException(id=instance_id)
-
-            if int(time.time()) - start >= self.build_timeout:
-                message = ('Share instance %s failed to reach %s status within'
-                           ' the required time (%s s).' %
-                           (instance_id, status, self.build_timeout))
-                raise exceptions.TimeoutException(message)
-
     def wait_for_snapshot_status(self, snapshot_id, status):
         """Waits for a snapshot to reach a given status."""
         body = self.get_snapshot(snapshot_id)
@@ -382,49 +264,6 @@
                            (snapshot_name, status, self.build_timeout))
                 raise exceptions.TimeoutException(message)
 
-    def wait_for_consistency_group_status(self, consistency_group_id, status):
-        """Waits for a consistency group to reach a given status."""
-        body = self.get_consistency_group(consistency_group_id)
-        consistency_group_name = body['name']
-        consistency_group_status = body['status']
-        start = int(time.time())
-
-        while consistency_group_status != status:
-            time.sleep(self.build_interval)
-            body = self.get_consistency_group(consistency_group_id)
-            consistency_group_status = body['status']
-            if 'error' in consistency_group_status and status != 'error':
-                raise share_exceptions.ConsistencyGroupBuildErrorException(
-                    consistency_group_id=consistency_group_id)
-
-            if int(time.time()) - start >= self.build_timeout:
-                message = ('Consistency Group %s failed to reach %s status '
-                           'within the required time (%s s).' %
-                           (consistency_group_name, status,
-                            self.build_timeout))
-                raise exceptions.TimeoutException(message)
-
-    def wait_for_cgsnapshot_status(self, cgsnapshot_id, status):
-        """Waits for a cgsnapshot to reach a given status."""
-        body = self.get_cgsnapshot(cgsnapshot_id)
-        cgsnapshot_name = body['name']
-        cgsnapshot_status = body['status']
-        start = int(time.time())
-
-        while cgsnapshot_status != status:
-            time.sleep(self.build_interval)
-            body = self.get_cgsnapshot(cgsnapshot_id)
-            cgsnapshot_status = body['status']
-            if 'error' in cgsnapshot_status and status != 'error':
-                raise share_exceptions.CGSnapshotBuildErrorException(
-                    cgsnapshot_id=cgsnapshot_id)
-
-            if int(time.time()) - start >= self.build_timeout:
-                message = ('CGSnapshot %s failed to reach %s status '
-                           'within the required time (%s s).' %
-                           (cgsnapshot_name, status, self.build_timeout))
-                raise exceptions.TimeoutException(message)
-
     def wait_for_access_rule_status(self, share_id, rule_id, status):
         """Waits for an access rule to reach a given status."""
         rule_status = "new"
@@ -502,8 +341,7 @@
         """Verifies whether provided resource deleted or not.
 
         :param kwargs: dict with expected keys 'share_id', 'snapshot_id',
-        :param kwargs: 'sn_id', 'ss_id', 'vt_id', 'server_id', 'cg_id',
-        :param kwargs: and 'cgsnapshot_id'
+        :param kwargs: 'sn_id', 'ss_id', 'vt_id' and 'server_id'
         :raises share_exceptions.InvalidResource
         """
         if "share_id" in kwargs:
@@ -518,9 +356,6 @@
             else:
                 return self._is_resource_deleted(
                     self.get_share, kwargs.get("share_id"))
-        elif "share_instance_id" in kwargs:
-            return self._is_resource_deleted(
-                self.get_share_instance, kwargs.get("share_instance_id"))
         elif "snapshot_id" in kwargs:
             return self._is_resource_deleted(
                 self.get_snapshot, kwargs.get("snapshot_id"))
@@ -539,12 +374,6 @@
         elif "server_id" in kwargs:
             return self._is_resource_deleted(
                 self.show_share_server, kwargs.get("server_id"))
-        elif "cg_id" in kwargs:
-            return self._is_resource_deleted(
-                self.get_consistency_group, kwargs.get("cg_id"))
-        elif "cgsnapshot_id" in kwargs:
-            return self._is_resource_deleted(
-                self.get_cgsnapshot, kwargs.get("cgsnapshot_id"))
         else:
             raise share_exceptions.InvalidResource(
                 message=six.text_type(kwargs))
@@ -598,29 +427,26 @@
         self.expected_success(200, resp.status)
         return self._parse_resp(body)
 
-    def reset_state(self, s_id, status="error", s_type="shares",
-                    headers=None):
-        """Resets the state of a share, snapshot, cg, or a cgsnapshot.
+    def reset_state(self, s_id, status="error", s_type="shares"):
+        """Resets the state of a share or a snapshot.
 
         status: available, error, creating, deleting, error_deleting
-        s_type: shares, snapshots, consistency-groups, cgsnapshots
+        s_type: shares, snapshots
         """
         body = {"os-reset_status": {"status": status}}
         body = json.dumps(body)
-        resp, body = self.post("%s/%s/action" % (s_type, s_id), body,
-                               headers=headers, extra_headers=True)
+        resp, body = self.post("%s/%s/action" % (s_type, s_id), body)
         self.expected_success(202, resp.status)
         return body
 
-    def force_delete(self, s_id, s_type="shares", headers=None):
+    def force_delete(self, s_id, s_type="shares"):
         """Force delete share or snapshot.
 
         s_type: shares, snapshots
         """
         body = {"os-force_delete": None}
         body = json.dumps(body)
-        resp, body = self.post("%s/%s/action" % (s_type, s_id), body,
-                               headers=headers, extra_headers=True)
+        resp, body = self.post("%s/%s/action" % (s_type, s_id), body)
         self.expected_success(202, resp.status)
         return body
 
@@ -925,143 +751,3 @@
         resp, body = self.get(uri)
         self.expected_success(200, resp.status)
         return json.loads(body)
-
-###############
-
-    def create_consistency_group(self, name=None, description=None,
-                                 share_type_ids=(), share_network_id=None,
-                                 source_cgsnapshot_id=None):
-        """Create a new consistency group."""
-        uri = 'consistency-groups'
-        post_body = {}
-        if name:
-            post_body['name'] = name
-        if description:
-            post_body['description'] = description
-        if share_type_ids:
-            post_body['share_types'] = share_type_ids
-        if source_cgsnapshot_id:
-            post_body['source_cgsnapshot_id'] = source_cgsnapshot_id
-        if share_network_id:
-            post_body['share_network_id'] = share_network_id
-        body = json.dumps({'consistency_group': post_body})
-        resp, body = self.post(uri, body, headers=EXPERIMENTAL,
-                               extra_headers=True)
-        self.expected_success(202, resp.status)
-        return self._parse_resp(body)
-
-    def delete_consistency_group(self, consistency_group_id):
-        """Delete a consistency group."""
-        uri = 'consistency-groups/%s' % consistency_group_id
-        resp, body = self.delete(uri, headers=EXPERIMENTAL,
-                                 extra_headers=True)
-        self.expected_success(202, resp.status)
-        return body
-
-    def list_consistency_groups(self, detailed=False, params=None):
-        """Get list of consistency groups w/o filters."""
-        uri = 'consistency-groups%s' % ('/detail' if detailed else '')
-        uri += '?%s' % (urllib.urlencode(params) if params else '')
-        resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True)
-        self.expected_success(200, resp.status)
-        return self._parse_resp(body)
-
-    def get_consistency_group(self, consistency_group_id):
-        """Get consistency group info."""
-        uri = 'consistency-groups/%s' % consistency_group_id
-        resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True)
-        self.expected_success(200, resp.status)
-        return self._parse_resp(body)
-
-    def update_consistency_group(self, consistency_group_id, name=None,
-                                 description=None, **kwargs):
-        """Update an existing consistency group."""
-        uri = 'consistency-groups/%s' % consistency_group_id
-        post_body = {}
-        if name:
-            post_body['name'] = name
-        if description:
-            post_body['description'] = description
-        if kwargs:
-            post_body.update(kwargs)
-        body = json.dumps({'consistency_group': post_body})
-        resp, body = self.put(uri, body, headers=EXPERIMENTAL,
-                              extra_headers=True)
-        self.expected_success(200, resp.status)
-        return self._parse_resp(body)
-
-    def consistency_group_reset_state(self, id, status):
-        self.reset_state(id, status=status,
-                         s_type='consistency-groups', headers=EXPERIMENTAL)
-
-    def consistency_group_force_delete(self, id, status):
-        self.force_delete(id, status=status,
-                          s_type='consistency-groups', headers=EXPERIMENTAL)
-
-###############
-
-    def create_cgsnapshot(self, consistency_group_id,
-                          name=None, description=None):
-        """Create a new cgsnapshot of an existing consistency group."""
-        uri = 'cgsnapshots'
-        post_body = {'consistency_group_id': consistency_group_id}
-        if name:
-            post_body['name'] = name
-        if description:
-            post_body['description'] = description
-        body = json.dumps({'cgsnapshot': post_body})
-        resp, body = self.post(uri, body, headers=EXPERIMENTAL,
-                               extra_headers=True)
-        self.expected_success(202, resp.status)
-        return self._parse_resp(body)
-
-    def delete_cgsnapshot(self, cgsnapshot_id):
-        """Delete an existing cgsnapshot."""
-        uri = 'cgsnapshots/%s' % cgsnapshot_id
-        resp, body = self.delete(uri, headers=EXPERIMENTAL, extra_headers=True)
-        self.expected_success(202, resp.status)
-        return body
-
-    def list_cgsnapshots(self, detailed=False, params=None):
-        """Get list of cgsnapshots w/o filters."""
-        uri = 'cgsnapshots/detail' if detailed else 'cgsnapshots'
-        uri += '?%s' % (urllib.urlencode(params) if params else '')
-        resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True)
-        self.expected_success(200, resp.status)
-        return self._parse_resp(body)
-
-    def list_cgsnapshot_members(self, cgsnapshot_id):
-        """Get list of members of a cgsnapshots."""
-        uri = 'cgsnapshots/%s/members' % cgsnapshot_id
-        resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True)
-        self.expected_success(200, resp.status)
-        return self._parse_resp(body)
-
-    def get_cgsnapshot(self, cgsnapshot_id):
-        """Get cgsnapshot info."""
-        uri = 'cgsnapshots/%s' % cgsnapshot_id
-        resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True)
-        self.expected_success(200, resp.status)
-        return self._parse_resp(body)
-
-    def update_cgsnapshot(self, cgsnapshot_id, name=None, description=None):
-        """Update an existing cgsnapshot."""
-        uri = 'cgsnapshots/%s' % cgsnapshot_id
-        post_body = {}
-        if name:
-            post_body['name'] = name
-        if description:
-            post_body['description'] = description
-        body = json.dumps({'cgsnapshot': post_body})
-        resp, body = self.put(uri, body, headers=EXPERIMENTAL,
-                              extra_headers=True)
-        self.expected_success(200, resp.status)
-        return self._parse_resp(body)
-
-    def cgsnapshot_reset_state(self, id, status):
-        self.reset_state(id, status=status,
-                         s_type='cgsnapshots', headers=EXPERIMENTAL)
-
-    def cgsnapshot_force_delete(self, id, status):
-        self.force_delete(id, status=status,
-                          s_type='cgsnapshots', headers=EXPERIMENTAL)
diff --git a/manila_tempest_tests/services/share/v2/__init__.py b/manila_tempest_tests/services/share/v2/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/manila_tempest_tests/services/share/v2/__init__.py
diff --git a/manila_tempest_tests/services/share/v2/json/__init__.py b/manila_tempest_tests/services/share/v2/json/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/manila_tempest_tests/services/share/v2/json/__init__.py
diff --git a/manila_tempest_tests/services/share/v2/json/shares_client.py b/manila_tempest_tests/services/share/v2/json/shares_client.py
new file mode 100644
index 0000000..da72ffc
--- /dev/null
+++ b/manila_tempest_tests/services/share/v2/json/shares_client.py
@@ -0,0 +1,516 @@
+# Copyright 2015 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.
+
+import json
+import time
+import urllib
+
+from tempest_lib.common.utils import data_utils
+from tempest_lib import exceptions
+
+from manila_tempest_tests.services.share.json import shares_client  # noqa
+from manila_tempest_tests import share_exceptions
+from tempest import config  # noqa
+
+CONF = config.CONF
+LATEST_MICROVERSION = CONF.share.max_api_microversion
+EXPERIMENTAL = {'X-OpenStack-Manila-API-Experimental': 'True'}
+
+
+class SharesV2Client(shares_client.SharesClient):
+    """Tempest REST client for Manila.
+
+    It handles shares and access to it in OpenStack.
+    """
+    api_version = 'v2'
+
+    def __init__(self, auth_provider):
+        super(SharesV2Client, self).__init__(auth_provider)
+        self.API_MICROVERSIONS_HEADER = 'x-openstack-manila-api-version'
+
+    def inject_microversion_header(self, headers, version,
+                                   extra_headers=False):
+        """Inject the required manila microversion header."""
+        new_headers = self.get_headers()
+        new_headers[self.API_MICROVERSIONS_HEADER] = version
+        if extra_headers and headers:
+            new_headers.update(headers)
+        elif headers:
+            new_headers = headers
+        return new_headers
+
+    # Overwrite all http verb calls to inject the micro version header
+    def post(self, url, body, headers=None, extra_headers=False,
+             version=LATEST_MICROVERSION):
+        headers = self.inject_microversion_header(headers, version,
+                                                  extra_headers=extra_headers)
+        return super(SharesV2Client, self).post(url, body, headers=headers)
+
+    def get(self, url, headers=None, extra_headers=False,
+            version=LATEST_MICROVERSION):
+        headers = self.inject_microversion_header(headers, version,
+                                                  extra_headers=extra_headers)
+        return super(SharesV2Client, self).get(url, headers=headers)
+
+    def delete(self, url, headers=None, body=None, extra_headers=False,
+               version=LATEST_MICROVERSION):
+        headers = self.inject_microversion_header(headers, version,
+                                                  extra_headers=extra_headers)
+        return super(SharesV2Client, self).delete(url, headers=headers,
+                                                  body=body)
+
+    def patch(self, url, body, headers=None, extra_headers=False,
+              version=LATEST_MICROVERSION):
+        headers = self.inject_microversion_header(headers, version,
+                                                  extra_headers=extra_headers)
+        return super(SharesV2Client, self).patch(url, body, headers=headers)
+
+    def put(self, url, body, headers=None, extra_headers=False,
+            version=LATEST_MICROVERSION):
+        headers = self.inject_microversion_header(headers, version,
+                                                  extra_headers=extra_headers)
+        return super(SharesV2Client, self).put(url, body, headers=headers)
+
+    def head(self, url, headers=None, extra_headers=False,
+             version=LATEST_MICROVERSION):
+        headers = self.inject_microversion_header(headers, version,
+                                                  extra_headers=extra_headers)
+        return super(SharesV2Client, self).head(url, headers=headers)
+
+    def copy(self, url, headers=None, extra_headers=False,
+             version=LATEST_MICROVERSION):
+        headers = self.inject_microversion_header(headers, version,
+                                                  extra_headers=extra_headers)
+        return super(SharesV2Client, self).copy(url, headers=headers)
+
+    def reset_state(self, s_id, status="error", s_type="shares",
+                    headers=None, version=LATEST_MICROVERSION):
+        """Resets the state of a share, snapshot, cg, or a cgsnapshot.
+
+        status: available, error, creating, deleting, error_deleting
+        s_type: shares, snapshots, consistency-groups, cgsnapshots
+        """
+        body = {"os-reset_status": {"status": status}}
+        body = json.dumps(body)
+        resp, body = self.post("%s/%s/action" % (s_type, s_id), body,
+                               headers=headers, extra_headers=True,
+                               version=version)
+        self.expected_success(202, resp.status)
+        return body
+
+    def force_delete(self, s_id, s_type="shares", headers=None,
+                     version=LATEST_MICROVERSION):
+        """Force delete share or snapshot.
+
+        s_type: shares, snapshots
+        """
+        body = {"os-force_delete": None}
+        body = json.dumps(body)
+        resp, body = self.post("%s/%s/action" % (s_type, s_id), body,
+                               headers=headers, extra_headers=True,
+                               version=version)
+        self.expected_success(202, resp.status)
+        return body
+
+    def send_microversion_request(self, version=None, script_name=None):
+        """Prepare and send the HTTP GET Request to the base URL.
+
+        Extracts the base URL from the shares_client endpoint and makes a GET
+        request with the microversions request header.
+        :param version: The string to send for the value of the microversion
+                        header, or None to omit the header.
+        :param script_name: The first part of the URL (v1 or v2), or None to
+                            omit it.
+        """
+
+        headers = self.get_headers()
+        url, headers, body = self.auth_provider.auth_request(
+            'GET', 'shares', headers, None, self.filters)
+        url = '/'.join(url.split('/')[:3]) + '/'
+        if script_name:
+            url += script_name + '/'
+        if version:
+            headers[self.API_MICROVERSIONS_HEADER] = version
+        resp, resp_body = self.raw_request(url, 'GET', headers=headers)
+        self.response_checker('GET', resp, resp_body)
+        resp_body = json.loads(resp_body)
+        return resp, resp_body
+
+    def is_resource_deleted(self, *args, **kwargs):
+        """Verifies whether provided resource deleted or not.
+
+        :param kwargs: dict with expected keys 'share_id', 'snapshot_id',
+        :param kwargs: 'sn_id', 'ss_id', 'vt_id' and 'server_id'
+        :raises share_exceptions.InvalidResource
+        """
+        if "share_instance_id" in kwargs:
+            return self._is_resource_deleted(
+                self.get_share_instance, kwargs.get("share_instance_id"))
+        elif "cg_id" in kwargs:
+            return self._is_resource_deleted(
+                self.get_consistency_group, kwargs.get("cg_id"))
+        elif "cgsnapshot_id" in kwargs:
+            return self._is_resource_deleted(
+                self.get_cgsnapshot, kwargs.get("cgsnapshot_id"))
+        else:
+            return super(SharesV2Client, self).is_resource_deleted(
+                *args, **kwargs)
+
+###############
+
+    def create_share(self, share_protocol=None, size=1,
+                     name=None, snapshot_id=None, description=None,
+                     metadata=None, share_network_id=None,
+                     share_type_id=None, is_public=False,
+                     consistency_group_id=None, version=LATEST_MICROVERSION):
+        metadata = metadata or {}
+        if name is None:
+            name = data_utils.rand_name("tempest-created-share")
+        if description is None:
+            description = data_utils.rand_name("tempest-created-share-desc")
+        if share_protocol is None:
+            share_protocol = self.share_protocol
+        if share_protocol is None:
+            raise share_exceptions.ShareProtocolNotSpecified()
+        post_body = {
+            "share": {
+                "share_proto": share_protocol,
+                "description": description,
+                "snapshot_id": snapshot_id,
+                "name": name,
+                "size": size,
+                "metadata": metadata,
+                "is_public": is_public,
+            }
+        }
+        if share_network_id:
+            post_body["share"]["share_network_id"] = share_network_id
+        if share_type_id:
+            post_body["share"]["share_type"] = share_type_id
+        if consistency_group_id:
+            post_body["share"]["consistency_group_id"] = consistency_group_id
+        body = json.dumps(post_body)
+        resp, body = self.post("shares", body, version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def list_shares(self, detailed=False, params=None,
+                    version=LATEST_MICROVERSION):
+        """Get list of shares w/o filters."""
+        uri = 'shares/detail' if detailed else 'shares'
+        uri += '?%s' % urllib.urlencode(params) if params else ''
+        resp, body = self.get(uri, version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def list_shares_with_detail(self, params=None,
+                                version=LATEST_MICROVERSION):
+        """Get detailed list of shares w/o filters."""
+        return self.list_shares(detailed=True, params=params, version=version)
+
+    def get_share(self, share_id, version=LATEST_MICROVERSION):
+        resp, body = self.get("shares/%s" % share_id, version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def delete_share(self, share_id, params=None,
+                     version=LATEST_MICROVERSION):
+        uri = "shares/%s" % share_id
+        uri += '?%s' % (urllib.urlencode(params) if params else '')
+        resp, body = self.delete(uri, version=version)
+        self.expected_success(202, resp.status)
+        return body
+
+###############
+
+    def get_instances_of_share(self, share_id, version=LATEST_MICROVERSION):
+        resp, body = self.get("shares/%s/instances" % share_id,
+                              version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def list_share_instances(self, version=LATEST_MICROVERSION):
+        resp, body = self.get("share_instances", version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def get_share_instance(self, instance_id, version=LATEST_MICROVERSION):
+        resp, body = self.get("share_instances/%s" % instance_id,
+                              version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def wait_for_share_instance_status(self, instance_id, status,
+                                       version=LATEST_MICROVERSION):
+        """Waits for a share to reach a given status."""
+        body = self.get_share_instance(instance_id, version=version)
+        instance_status = body['status']
+        start = int(time.time())
+
+        while instance_status != status:
+            time.sleep(self.build_interval)
+            body = self.get_share(instance_id)
+            instance_status = body['status']
+            if instance_status == status:
+                return
+            elif 'error' in instance_status.lower():
+                raise share_exceptions. \
+                    ShareInstanceBuildErrorException(id=instance_id)
+
+            if int(time.time()) - start >= self.build_timeout:
+                message = ('Share instance %s failed to reach %s status within'
+                           ' the required time (%s s).' %
+                           (instance_id, status, self.build_timeout))
+                raise exceptions.TimeoutException(message)
+
+###############
+
+    def create_consistency_group(self, name=None, description=None,
+                                 share_type_ids=(), share_network_id=None,
+                                 source_cgsnapshot_id=None,
+                                 version=LATEST_MICROVERSION):
+        """Create a new consistency group."""
+        uri = 'consistency-groups'
+        post_body = {}
+        if name:
+            post_body['name'] = name
+        if description:
+            post_body['description'] = description
+        if share_type_ids:
+            post_body['share_types'] = share_type_ids
+        if source_cgsnapshot_id:
+            post_body['source_cgsnapshot_id'] = source_cgsnapshot_id
+        if share_network_id:
+            post_body['share_network_id'] = share_network_id
+        body = json.dumps({'consistency_group': post_body})
+        resp, body = self.post(uri, body, headers=EXPERIMENTAL,
+                               extra_headers=True, version=version)
+        self.expected_success(202, resp.status)
+        return self._parse_resp(body)
+
+    def delete_consistency_group(self, consistency_group_id,
+                                 version=LATEST_MICROVERSION):
+        """Delete a consistency group."""
+        uri = 'consistency-groups/%s' % consistency_group_id
+        resp, body = self.delete(uri, headers=EXPERIMENTAL,
+                                 extra_headers=True, version=version)
+        self.expected_success(202, resp.status)
+        return body
+
+    def list_consistency_groups(self, detailed=False, params=None,
+                                version=LATEST_MICROVERSION):
+        """Get list of consistency groups w/o filters."""
+        uri = 'consistency-groups%s' % ('/detail' if detailed else '')
+        uri += '?%s' % (urllib.urlencode(params) if params else '')
+        resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
+                              version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def get_consistency_group(self, consistency_group_id,
+                              version=LATEST_MICROVERSION):
+        """Get consistency group info."""
+        uri = 'consistency-groups/%s' % consistency_group_id
+        resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
+                              version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def update_consistency_group(self, consistency_group_id, name=None,
+                                 description=None,
+                                 version=LATEST_MICROVERSION, **kwargs):
+        """Update an existing consistency group."""
+        uri = 'consistency-groups/%s' % consistency_group_id
+        post_body = {}
+        if name:
+            post_body['name'] = name
+        if description:
+            post_body['description'] = description
+        if kwargs:
+            post_body.update(kwargs)
+        body = json.dumps({'consistency_group': post_body})
+        resp, body = self.put(uri, body, headers=EXPERIMENTAL,
+                              extra_headers=True, version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def consistency_group_reset_state(self, id, status,
+                                      version=LATEST_MICROVERSION):
+        self.reset_state(id, status=status,
+                         s_type='consistency-groups', headers=EXPERIMENTAL,
+                         version=version)
+
+    def consistency_group_force_delete(self, id, version=LATEST_MICROVERSION):
+        self.force_delete(id, s_type='consistency-groups',
+                          headers=EXPERIMENTAL, version=version)
+
+    def wait_for_consistency_group_status(self, consistency_group_id, status):
+        """Waits for a consistency group to reach a given status."""
+        body = self.get_consistency_group(consistency_group_id)
+        consistency_group_name = body['name']
+        consistency_group_status = body['status']
+        start = int(time.time())
+
+        while consistency_group_status != status:
+            time.sleep(self.build_interval)
+            body = self.get_consistency_group(consistency_group_id)
+            consistency_group_status = body['status']
+            if 'error' in consistency_group_status and status != 'error':
+                raise share_exceptions.ConsistencyGroupBuildErrorException(
+                    consistency_group_id=consistency_group_id)
+
+            if int(time.time()) - start >= self.build_timeout:
+                message = ('Consistency Group %s failed to reach %s status '
+                           'within the required time (%s s).' %
+                           (consistency_group_name, status,
+                            self.build_timeout))
+                raise exceptions.TimeoutException(message)
+
+###############
+
+    def create_cgsnapshot(self, consistency_group_id,
+                          name=None, description=None,
+                          version=LATEST_MICROVERSION):
+        """Create a new cgsnapshot of an existing consistency group."""
+        uri = 'cgsnapshots'
+        post_body = {'consistency_group_id': consistency_group_id}
+        if name:
+            post_body['name'] = name
+        if description:
+            post_body['description'] = description
+        body = json.dumps({'cgsnapshot': post_body})
+        resp, body = self.post(uri, body, headers=EXPERIMENTAL,
+                               extra_headers=True, version=version)
+        self.expected_success(202, resp.status)
+        return self._parse_resp(body)
+
+    def delete_cgsnapshot(self, cgsnapshot_id,
+                          version=LATEST_MICROVERSION):
+        """Delete an existing cgsnapshot."""
+        uri = 'cgsnapshots/%s' % cgsnapshot_id
+        resp, body = self.delete(uri, headers=EXPERIMENTAL,
+                                 extra_headers=True, version=version)
+        self.expected_success(202, resp.status)
+        return body
+
+    def list_cgsnapshots(self, detailed=False, params=None,
+                         version=LATEST_MICROVERSION):
+        """Get list of cgsnapshots w/o filters."""
+        uri = 'cgsnapshots/detail' if detailed else 'cgsnapshots'
+        uri += '?%s' % (urllib.urlencode(params) if params else '')
+        resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
+                              version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def list_cgsnapshot_members(self, cgsnapshot_id,
+                                version=LATEST_MICROVERSION):
+        """Get list of members of a cgsnapshots."""
+        uri = 'cgsnapshots/%s/members' % cgsnapshot_id
+        resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
+                              version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def get_cgsnapshot(self, cgsnapshot_id, version=LATEST_MICROVERSION):
+        """Get cgsnapshot info."""
+        uri = 'cgsnapshots/%s' % cgsnapshot_id
+        resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
+                              version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def update_cgsnapshot(self, cgsnapshot_id, name=None, description=None,
+                          version=LATEST_MICROVERSION):
+        """Update an existing cgsnapshot."""
+        uri = 'cgsnapshots/%s' % cgsnapshot_id
+        post_body = {}
+        if name:
+            post_body['name'] = name
+        if description:
+            post_body['description'] = description
+        body = json.dumps({'cgsnapshot': post_body})
+        resp, body = self.put(uri, body, headers=EXPERIMENTAL,
+                              extra_headers=True, version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def cgsnapshot_reset_state(self, id, status,
+                               version=LATEST_MICROVERSION):
+        self.reset_state(id, status=status,
+                         s_type='cgsnapshots', headers=EXPERIMENTAL,
+                         version=version)
+
+    def cgsnapshot_force_delete(self, id, version=LATEST_MICROVERSION):
+        self.force_delete(id, s_type='cgsnapshots', headers=EXPERIMENTAL,
+                          version=version)
+
+    def wait_for_cgsnapshot_status(self, cgsnapshot_id, status):
+        """Waits for a cgsnapshot to reach a given status."""
+        body = self.get_cgsnapshot(cgsnapshot_id)
+        cgsnapshot_name = body['name']
+        cgsnapshot_status = body['status']
+        start = int(time.time())
+
+        while cgsnapshot_status != status:
+            time.sleep(self.build_interval)
+            body = self.get_cgsnapshot(cgsnapshot_id)
+            cgsnapshot_status = body['status']
+            if 'error' in cgsnapshot_status and status != 'error':
+                raise share_exceptions.CGSnapshotBuildErrorException(
+                    cgsnapshot_id=cgsnapshot_id)
+
+            if int(time.time()) - start >= self.build_timeout:
+                message = ('CGSnapshot %s failed to reach %s status '
+                           'within the required time (%s s).' %
+                           (cgsnapshot_name, status, self.build_timeout))
+                raise exceptions.TimeoutException(message)
+
+###############
+
+    def migrate_share(self, share_id, host, version=LATEST_MICROVERSION):
+        post_body = {
+            'os-migrate_share': {
+                'host': host,
+            }
+        }
+        body = json.dumps(post_body)
+        return self.post('shares/%s/action' % share_id, body,
+                         headers=EXPERIMENTAL, extra_headers=True,
+                         version=version)
+
+    def wait_for_migration_completed(self, share_id, dest_host):
+        """Waits for a share to migrate to a certain host."""
+        share = self.get_share(share_id)
+        migration_timeout = CONF.share.migration_timeout
+        start = int(time.time())
+        while share['task_state'] != 'migration_success':
+            time.sleep(self.build_interval)
+            share = self.get_share(share_id)
+            if share['task_state'] == 'migration_success':
+                return share
+            elif share['task_state'] == 'migration_error':
+                raise share_exceptions.ShareMigrationException(
+                    share_id=share['id'], src=share['host'], dest=dest_host)
+            elif int(time.time()) - start >= migration_timeout:
+                message = ('Share %(share_id)s failed to migrate from '
+                           'host %(src)s to host %(dest)s within the required '
+                           'time %(timeout)s.' % {
+                               'src': share['host'],
+                               'dest': dest_host,
+                               'share_id': share['id'],
+                               'timeout': self.build_timeout
+                           })
+                raise exceptions.TimeoutException(message)
diff --git a/manila_tempest_tests/tests/api/admin/test_admin_actions.py b/manila_tempest_tests/tests/api/admin/test_admin_actions.py
index 6acec11..e70fd6a 100644
--- a/manila_tempest_tests/tests/api/admin/test_admin_actions.py
+++ b/manila_tempest_tests/tests/api/admin/test_admin_actions.py
@@ -32,7 +32,7 @@
         cls.bad_status = "error_deleting"
         cls.sh = cls.create_share()
         cls.sh_instance = (
-            cls.shares_client.get_instances_of_share(cls.sh["id"])[0]
+            cls.shares_v2_client.get_instances_of_share(cls.sh["id"])[0]
         )
         if CONF.share.run_snapshot_tests:
             cls.sn = cls.create_snapshot_wait_for_active(cls.sh["id"])
@@ -49,7 +49,7 @@
         for status in self.states:
             self.shares_client.reset_state(
                 id, s_type="share_instances", status=status)
-            self.shares_client.wait_for_share_instance_status(id, status)
+            self.shares_v2_client.wait_for_share_instance_status(id, status)
 
     @test.attr(type=["gate", ])
     @testtools.skipUnless(CONF.share.run_snapshot_tests,
@@ -78,7 +78,7 @@
     @test.attr(type=["gate", ])
     def test_force_delete_share_instance(self):
         share = self.create_share(cleanup_in_class=False)
-        instances = self.shares_client.get_instances_of_share(share["id"])
+        instances = self.shares_v2_client.get_instances_of_share(share["id"])
         # Check that instance was created
         self.assertEqual(1, len(instances))
 
@@ -89,13 +89,13 @@
             instance["id"], s_type="share_instances", status=self.bad_status)
 
         # Check that status was changed
-        check_status = self.shares_client.get_share_instance(instance["id"])
+        check_status = self.shares_v2_client.get_share_instance(instance["id"])
         self.assertEqual(self.bad_status, check_status["status"])
 
         # Share with status 'error_deleting' should be deleted
         self.shares_client.force_delete(
             instance["id"], s_type="share_instances")
-        self.shares_client.wait_for_resource_deletion(
+        self.shares_v2_client.wait_for_resource_deletion(
             share_instance_id=instance["id"])
 
     @test.attr(type=["gate", ])
diff --git a/manila_tempest_tests/tests/api/admin/test_admin_actions_negative.py b/manila_tempest_tests/tests/api/admin/test_admin_actions_negative.py
index 7df3b30..d25dc75 100644
--- a/manila_tempest_tests/tests/api/admin/test_admin_actions_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_admin_actions_negative.py
@@ -31,11 +31,12 @@
         super(AdminActionsNegativeTest, cls).resource_setup()
         cls.sh = cls.create_share()
         cls.sh_instance = (
-            cls.shares_client.get_instances_of_share(cls.sh["id"])[0]
+            cls.shares_v2_client.get_instances_of_share(cls.sh["id"])[0]
         )
         if CONF.share.run_snapshot_tests:
             cls.sn = cls.create_snapshot_wait_for_active(cls.sh["id"])
         cls.member_shares_client = clients.Manager().shares_client
+        cls.member_shares_v2_client = clients.Manager().shares_v2_client
 
     @test.attr(type=["gate", "negative", ])
     def test_reset_nonexistent_share_state(self):
@@ -149,19 +150,19 @@
     def test_try_get_share_instance_with_member(self):
         # If a non-admin tries to get instance, it should be unauthorized
         self.assertRaises(lib_exc.Forbidden,
-                          self.member_shares_client.get_share_instance,
+                          self.member_shares_v2_client.get_share_instance,
                           self.sh_instance["id"])
 
     @test.attr(type=["gate", "negative", ])
     def test_try_list_share_instance_with_member(self):
         # If a non-admin tries to list instances, it should be unauthorized
         self.assertRaises(lib_exc.Forbidden,
-                          self.member_shares_client.list_share_instances)
+                          self.member_shares_v2_client.list_share_instances)
 
     @test.attr(type=["gate", "negative", ])
     def test_try_get_instances_of_share_with_member(self):
         # If a non-admin tries to list instances of given share, it should be
         # unauthorized
         self.assertRaises(lib_exc.Forbidden,
-                          self.member_shares_client.get_instances_of_share,
+                          self.member_shares_v2_client.get_instances_of_share,
                           self.sh['id'])
diff --git a/manila_tempest_tests/tests/api/admin/test_consistency_group_actions.py b/manila_tempest_tests/tests/api/admin/test_consistency_group_actions.py
index c1fdb15..d5142b6 100644
--- a/manila_tempest_tests/tests/api/admin/test_consistency_group_actions.py
+++ b/manila_tempest_tests/tests/api/admin/test_consistency_group_actions.py
@@ -45,13 +45,19 @@
             share_type_ids=[cls.share_type['id'], cls.share_type2['id']])
 
     @test.attr(type=["gate", ])
-    def test_create_cg_from_cgsnapshot_with_multiple_share_types(self):
+    def test_create_cg_from_cgsnapshot_with_multiple_share_types_v2_4(self):
         # Create cgsnapshot
         cgsnapshot = self.create_cgsnapshot_wait_for_active(
-            self.consistency_group["id"], cleanup_in_class=False)
+            self.consistency_group["id"],
+            cleanup_in_class=False,
+            version='2.4',
+        )
 
         new_consistency_group = self.create_consistency_group(
-            cleanup_in_class=False, source_cgsnapshot_id=cgsnapshot['id'])
+            cleanup_in_class=False,
+            source_cgsnapshot_id=cgsnapshot['id'],
+            version='2.4',
+        )
 
         # Verify share_types are the same
         expected_types = sorted(self.consistency_group['share_types'])
@@ -61,7 +67,7 @@
                              expected_types, actual_types))
 
     @test.attr(type=["gate", ])
-    def test_create_cg_from_multi_typed_populated_cgsnapshot(self):
+    def test_create_cg_from_multi_typed_populated_cgsnapshot_v2_4(self):
         share_name = data_utils.rand_name("tempest-share-name")
         share_desc = data_utils.rand_name("tempest-share-description")
         share_size = 1
@@ -71,7 +77,9 @@
             description=share_desc,
             size=share_size,
             consistency_group_id=self.consistency_group['id'],
-            share_type_id=self.share_type['id']
+            share_type_id=self.share_type['id'],
+            client=self.shares_v2_client,
+            version='2.4',
         )
 
         share_name2 = data_utils.rand_name("tempest-share-name")
@@ -83,11 +91,16 @@
             description=share_desc2,
             size=share_size2,
             consistency_group_id=self.consistency_group['id'],
-            share_type_id=self.share_type2['id']
+            share_type_id=self.share_type2['id'],
+            client=self.shares_v2_client,
+            version='2.4',
         )
 
-        cg_shares = self.shares_client.list_shares(detailed=True, params={
-            'consistency_group_id': self.consistency_group['id']})
+        cg_shares = self.shares_v2_client.list_shares(
+            detailed=True,
+            params={'consistency_group_id': self.consistency_group['id']},
+            version='2.4',
+        )
 
         cg_share_ids = [s['id'] for s in cg_shares]
         for share_id in [share['id'], share2['id']]:
@@ -101,10 +114,13 @@
             self.consistency_group["id"],
             name=cgsnap_name,
             description=cgsnap_desc,
-            cleanup_in_class=False)
+            cleanup_in_class=False,
+            version='2.4',
+        )
 
-        self.create_consistency_group(
-            cleanup_in_class=False, source_cgsnapshot_id=cgsnapshot['id'])
+        self.create_consistency_group(cleanup_in_class=False,
+                                      source_cgsnapshot_id=cgsnapshot['id'],
+                                      version='2.4')
 
         # TODO(akerr): Skip until bug 1483886 is resolved
         # Verify that the new shares correspond to correct share types
diff --git a/manila_tempest_tests/tests/api/admin/test_consistency_groups.py b/manila_tempest_tests/tests/api/admin/test_consistency_groups.py
index 4fbe7f9..d562e45 100644
--- a/manila_tempest_tests/tests/api/admin/test_consistency_groups.py
+++ b/manila_tempest_tests/tests/api/admin/test_consistency_groups.py
@@ -43,11 +43,13 @@
         cls.share_type2 = share_type['share_type']
 
     @test.attr(type=["gate", ])
-    def test_create_cg_with_multiple_share_types(self):
+    def test_create_cg_with_multiple_share_types_v2_4(self):
         # Create a consistency group
         consistency_group = self.create_consistency_group(
-            cleanup_in_class=False, share_type_ids=[self.share_type['id'],
-                                                    self.share_type2['id']])
+            cleanup_in_class=False,
+            share_type_ids=[self.share_type['id'], self.share_type2['id']],
+            version='2.4',
+        )
 
         self.assertTrue(CG_REQUIRED_ELEMENTS.issubset(
             consistency_group.keys()),
diff --git a/manila_tempest_tests/tests/api/admin/test_consistency_groups_negative.py b/manila_tempest_tests/tests/api/admin/test_consistency_groups_negative.py
index a7a715f..eafb5e8 100644
--- a/manila_tempest_tests/tests/api/admin/test_consistency_groups_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_consistency_groups_negative.py
@@ -51,6 +51,7 @@
             size=cls.share_size,
             consistency_group_id=cls.consistency_group['id'],
             share_type_id=cls.share_type['id'],
+            client=cls.shares_v2_client,
         )
 
         # Create a cgsnapshot of the consistency group
@@ -69,91 +70,105 @@
                           self.share_type['id'])
 
     @test.attr(type=["negative", "gate", ])
-    def test_create_share_of_unsupported_type_in_cg(self):
+    def test_create_share_of_unsupported_type_in_cg_v2_4(self):
         # Attempt to create share of default type in the cg
         self.assertRaises(exceptions.BadRequest,
-                          self.shares_client.create_share, size=1,
-                          consistency_group_id=self.consistency_group['id'])
+                          self.create_share,
+                          size=1,
+                          consistency_group_id=self.consistency_group['id'],
+                          client=self.shares_v2_client,
+                          version='2.4')
 
     @test.attr(type=["negative", "gate", ])
-    def test_create_share_in_cg_that_is_not_available(self):
+    def test_create_share_in_cg_that_is_not_available_v2_4(self):
         consistency_group = self.create_consistency_group(
-            cleanup_in_class=False)
-        self.addCleanup(self.shares_client.consistency_group_reset_state,
+            cleanup_in_class=False, version='2.4')
+        self.addCleanup(self.shares_v2_client.consistency_group_reset_state,
                         consistency_group['id'],
-                        status='available')
+                        status='available',
+                        version='2.4')
         # creating
-        self.shares_client.consistency_group_reset_state(
-            consistency_group['id'], status='creating')
-        self.shares_client.wait_for_consistency_group_status(
+        self.shares_v2_client.consistency_group_reset_state(
+            consistency_group['id'], status='creating', version='2.4')
+        self.shares_v2_client.wait_for_consistency_group_status(
             consistency_group['id'], 'creating')
         self.assertRaises(exceptions.BadRequest, self.create_share,
                           name=self.share_name,
                           description=self.share_desc,
                           size=self.share_size,
                           consistency_group_id=consistency_group['id'],
-                          cleanup_in_class=False)
+                          cleanup_in_class=False,
+                          client=self.shares_v2_client,
+                          version='2.4')
         # deleting
-        self.shares_client.consistency_group_reset_state(
-            consistency_group['id'], status='deleting')
-        self.shares_client.wait_for_consistency_group_status(
+        self.shares_v2_client.consistency_group_reset_state(
+            consistency_group['id'], status='deleting', version='2.4')
+        self.shares_v2_client.wait_for_consistency_group_status(
             consistency_group['id'], 'deleting')
         self.assertRaises(exceptions.BadRequest, self.create_share,
                           name=self.share_name,
                           description=self.share_desc,
                           size=self.share_size,
                           consistency_group_id=consistency_group['id'],
-                          cleanup_in_class=False)
+                          cleanup_in_class=False,
+                          client=self.shares_v2_client,
+                          version='2.4')
         # error
-        self.shares_client.consistency_group_reset_state(
-            consistency_group['id'], status='error')
-        self.shares_client.wait_for_consistency_group_status(
+        self.shares_v2_client.consistency_group_reset_state(
+            consistency_group['id'], status='error', version='2.4')
+        self.shares_v2_client.wait_for_consistency_group_status(
             consistency_group['id'], 'error')
         self.assertRaises(exceptions.BadRequest, self.create_share,
                           name=self.share_name,
                           description=self.share_desc,
                           size=self.share_size,
                           consistency_group_id=consistency_group['id'],
-                          cleanup_in_class=False)
+                          cleanup_in_class=False,
+                          client=self.shares_v2_client,
+                          version='2.4')
 
     @test.attr(type=["negative", "gate", ])
-    def test_create_cgsnapshot_of_cg_that_is_not_available(self):
+    def test_create_cgsnapshot_of_cg_that_is_not_available_v2_4(self):
         consistency_group = self.create_consistency_group(
-            cleanup_in_class=False)
-        self.addCleanup(self.shares_client.consistency_group_reset_state,
+            cleanup_in_class=False, version='2.4')
+        self.addCleanup(self.shares_v2_client.consistency_group_reset_state,
                         consistency_group['id'],
-                        status='available')
+                        status='available',
+                        version='2.4')
         # creating
-        self.shares_client.consistency_group_reset_state(
-            consistency_group['id'], status='creating')
-        self.shares_client.wait_for_consistency_group_status(
+        self.shares_v2_client.consistency_group_reset_state(
+            consistency_group['id'], status='creating', version='2.4')
+        self.shares_v2_client.wait_for_consistency_group_status(
             consistency_group['id'], 'creating')
         self.assertRaises(exceptions.Conflict,
                           self.create_cgsnapshot_wait_for_active,
                           consistency_group['id'],
-                          cleanup_in_class=False)
+                          cleanup_in_class=False,
+                          version='2.4')
         # deleting
-        self.shares_client.consistency_group_reset_state(
-            consistency_group['id'], status='deleting')
-        self.shares_client.wait_for_consistency_group_status(
+        self.shares_v2_client.consistency_group_reset_state(
+            consistency_group['id'], status='deleting', version='2.4')
+        self.shares_v2_client.wait_for_consistency_group_status(
             consistency_group['id'], 'deleting')
         self.assertRaises(exceptions.Conflict,
                           self.create_cgsnapshot_wait_for_active,
                           consistency_group['id'],
-                          cleanup_in_class=False)
+                          cleanup_in_class=False,
+                          version='2.4')
         # error
-        self.shares_client.consistency_group_reset_state(
-            consistency_group['id'], status='error')
-        self.shares_client.wait_for_consistency_group_status(
+        self.shares_v2_client.consistency_group_reset_state(
+            consistency_group['id'], status='error', version='2.4')
+        self.shares_v2_client.wait_for_consistency_group_status(
             consistency_group['id'], 'error')
         self.assertRaises(exceptions.Conflict,
                           self.create_cgsnapshot_wait_for_active,
                           consistency_group['id'],
-                          cleanup_in_class=False)
+                          cleanup_in_class=False,
+                          version='2.4')
 
     @test.attr(type=["negative", "gate", ])
-    def test_create_cgsnapshot_of_cg_with_share_in_error_state(self):
-        consistency_group = self.create_consistency_group()
+    def test_create_cgsnapshot_of_cg_with_share_in_error_state_v2_4(self):
+        consistency_group = self.create_consistency_group(version='2.4')
         share_name = data_utils.rand_name("tempest-share-name")
         share_desc = data_utils.rand_name("tempest-share-description")
         share_size = 1
@@ -163,65 +178,79 @@
             size=share_size,
             consistency_group_id=consistency_group['id'],
             cleanup_in_class=False,
+            client=self.shares_v2_client,
+            version='2.4',
         )
         self.shares_client.reset_state(s_id=share['id'])
         self.shares_client.wait_for_share_status(share['id'], 'error')
         self.assertRaises(exceptions.Conflict,
                           self.create_cgsnapshot_wait_for_active,
                           consistency_group['id'],
-                          cleanup_in_class=False)
+                          cleanup_in_class=False,
+                          version='2.4')
 
     @test.attr(type=["negative", "gate", ])
-    def test_delete_cgsnapshot_not_in_available_or_error(self):
+    def test_delete_cgsnapshot_not_in_available_or_error_v2_4(self):
         cgsnapshot = self.create_cgsnapshot_wait_for_active(
-            self.consistency_group['id'], cleanup_in_class=False)
-        self.addCleanup(self.shares_client.cgsnapshot_reset_state,
+            self.consistency_group['id'],
+            cleanup_in_class=False,
+            version='2.4',
+        )
+        self.addCleanup(self.shares_v2_client.cgsnapshot_reset_state,
                         cgsnapshot['id'],
-                        status='available')
+                        status='available',
+                        version='2.4')
 
         # creating
-        self.shares_client.cgsnapshot_reset_state(cgsnapshot['id'],
-                                                  status='creating')
-        self.shares_client.wait_for_cgsnapshot_status(cgsnapshot['id'],
-                                                      'creating')
+        self.shares_v2_client.cgsnapshot_reset_state(cgsnapshot['id'],
+                                                     status='creating',
+                                                     version='2.4')
+        self.shares_v2_client.wait_for_cgsnapshot_status(cgsnapshot['id'],
+                                                         'creating')
         self.assertRaises(exceptions.Conflict,
-                          self.shares_client.delete_cgsnapshot,
-                          cgsnapshot['id'])
+                          self.shares_v2_client.delete_cgsnapshot,
+                          cgsnapshot['id'],
+                          version='2.4')
         # deleting
-        self.shares_client.cgsnapshot_reset_state(cgsnapshot['id'],
-                                                  status='deleting')
-        self.shares_client.wait_for_cgsnapshot_status(cgsnapshot['id'],
-                                                      'deleting')
+        self.shares_v2_client.cgsnapshot_reset_state(cgsnapshot['id'],
+                                                     status='deleting',
+                                                     version='2.4')
+        self.shares_v2_client.wait_for_cgsnapshot_status(cgsnapshot['id'],
+                                                         'deleting')
         self.assertRaises(exceptions.Conflict,
-                          self.shares_client.delete_cgsnapshot,
-                          cgsnapshot['id'])
+                          self.shares_v2_client.delete_cgsnapshot,
+                          cgsnapshot['id'],
+                          version='2.4')
 
     @test.attr(type=["negative", "gate", ])
-    def test_delete_cg_not_in_available_or_error(self):
+    def test_delete_cg_not_in_available_or_error_v2_4(self):
         consistency_group = self.create_consistency_group(
-            cleanup_in_class=False)
-        self.addCleanup(self.shares_client.consistency_group_reset_state,
+            cleanup_in_class=False, version='2.4')
+        self.addCleanup(self.shares_v2_client.consistency_group_reset_state,
                         consistency_group['id'],
-                        status='available')
+                        status='available',
+                        version='2.4')
         # creating
-        self.shares_client.consistency_group_reset_state(
-            consistency_group['id'], status='creating')
-        self.shares_client.wait_for_consistency_group_status(
+        self.shares_v2_client.consistency_group_reset_state(
+            consistency_group['id'], status='creating', version='2.4')
+        self.shares_v2_client.wait_for_consistency_group_status(
             consistency_group['id'], 'creating')
         self.assertRaises(exceptions.Conflict,
-                          self.shares_client.delete_consistency_group,
-                          consistency_group['id'])
+                          self.shares_v2_client.delete_consistency_group,
+                          consistency_group['id'],
+                          version='2.4')
         # deleting
-        self.shares_client.consistency_group_reset_state(
-            consistency_group['id'], status='deleting')
-        self.shares_client.wait_for_consistency_group_status(
+        self.shares_v2_client.consistency_group_reset_state(
+            consistency_group['id'], status='deleting', version='2.4')
+        self.shares_v2_client.wait_for_consistency_group_status(
             consistency_group['id'], 'deleting')
         self.assertRaises(exceptions.Conflict,
-                          self.shares_client.delete_consistency_group,
-                          consistency_group['id'])
+                          self.shares_v2_client.delete_consistency_group,
+                          consistency_group['id'],
+                          version='2.4')
 
     @test.attr(type=["negative", "gate", ])
-    def test_create_cg_with_conflicting_share_types(self):
+    def test_create_cg_with_conflicting_share_types_v2_4(self):
         # Create conflicting share types
         name = data_utils.rand_name("tempest-manila")
         extra_specs = {"driver_handles_share_servers": False}
@@ -237,10 +266,12 @@
                           self.create_consistency_group,
                           share_type_ids=[single_tenant_share_type['id'],
                                           multi_tenant_share_type['id']],
-                          cleanup_in_class=False)
+                          cleanup_in_class=False,
+                          version='2.4')
 
     @test.attr(type=["negative", "gate", ])
-    def test_create_cg_with_multi_tenant_share_type_and_no_share_network(self):
+    def test_create_cg_with_multi_tenant_share_type_and_no_share_network_v2_4(
+            self):
         # Create multi tenant share type
         name = data_utils.rand_name("tempest-manila")
         extra_specs = {"driver_handles_share_servers": True}
@@ -248,12 +279,15 @@
         multi_tenant_share_type = share_type['share_type']
 
         def create_cg():
-            cg = self.shares_client.create_consistency_group(
-                share_type_ids=[multi_tenant_share_type['id']])
+            cg = self.shares_v2_client.create_consistency_group(
+                share_type_ids=[multi_tenant_share_type['id']],
+                version='2.4'
+            )
             resource = {
                 "type": "consistency_group",
                 "id": cg["id"],
-                "client": self.shares_client}
+                "client": self.shares_client
+            }
             self.method_resources.insert(0, resource)
             return cg
 
@@ -262,9 +296,10 @@
     @test.attr(type=["negative", "gate", ])
     def test_update_cg_share_types(self):
         consistency_group = self.create_consistency_group(
-            cleanup_in_class=False)
+            cleanup_in_class=False, version='2.4')
 
         self.assertRaises(exceptions.BadRequest,
-                          self.shares_client.update_consistency_group,
+                          self.shares_v2_client.update_consistency_group,
                           consistency_group['id'],
-                          share_types=[self.share_type['id']])
+                          share_types=[self.share_type['id']],
+                          version='2.4')
diff --git a/manila_tempest_tests/tests/api/admin/test_migration.py b/manila_tempest_tests/tests/api/admin/test_migration.py
index 4c6bacf..75b4ba7 100644
--- a/manila_tempest_tests/tests/api/admin/test_migration.py
+++ b/manila_tempest_tests/tests/api/admin/test_migration.py
@@ -37,7 +37,7 @@
             raise cls.skipException(message)
 
     @test.attr(type=["gate", "smoke", ])
-    def test_migration_empty(self):
+    def test_migration_empty_v2_5(self):
 
         if not CONF.share.migration_enabled:
             raise self.skipException("Migration tests disabled. Skipping.")
@@ -60,7 +60,7 @@
 
         old_export_location = share['export_locations'][0]
 
-        share = self.migrate_share(share['id'], dest_pool)
+        share = self.migrate_share(share['id'], dest_pool, version='2.5')
 
         self.assertEqual(dest_pool, share['host'])
         self.assertNotEqual(old_export_location, share['export_locations'][0])
diff --git a/manila_tempest_tests/tests/api/admin/test_share_instances.py b/manila_tempest_tests/tests/api/admin/test_share_instances.py
new file mode 100644
index 0000000..1202b9d
--- /dev/null
+++ b/manila_tempest_tests/tests/api/admin/test_share_instances.py
@@ -0,0 +1,78 @@
+# Copyright 2015 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 import config
+from tempest import test
+
+from manila_tempest_tests.tests.api import base
+
+CONF = config.CONF
+
+
+class ShareInstancesTest(base.BaseSharesAdminTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(ShareInstancesTest, cls).resource_setup()
+        cls.share = cls.create_share()
+
+    @test.attr(type=["gate", ])
+    def test_get_instances_of_share_v2_3(self):
+        """Test that we get only the 1 share instance back for the share."""
+        share_instances = self.shares_v2_client.get_instances_of_share(
+            self.share['id'], version='2.3'
+        )
+
+        self.assertEqual(1, len(share_instances),
+                         'Too many share instances found; expected 1, '
+                         'found %s' % len(share_instances))
+
+        si = share_instances[0]
+        self.assertEqual(self.share['id'], si['share_id'],
+                         'Share instance %s has incorrect share id value; '
+                         'expected %s, got %s.' % (si['id'],
+                                                   self.share['id'],
+                                                   si['share_id']))
+
+    @test.attr(type=["gate", ])
+    def test_list_share_instances_v2_3(self):
+        """Test that we get at least the share instance back for the share."""
+        share_instances = self.shares_v2_client.get_instances_of_share(
+            self.share['id'], version='2.3'
+        )
+
+        share_ids = [si['share_id'] for si in share_instances]
+
+        msg = 'Share instance for share %s was not found.' % self.share['id']
+        self.assertIn(self.share['id'], share_ids, msg)
+
+    @test.attr(type=["gate", ])
+    def test_get_share_instance_v2_3(self):
+        """Test that we get the proper keys back for the instance."""
+        share_instances = self.shares_v2_client.get_instances_of_share(
+            self.share['id'], version='2.3'
+        )
+        si = self.shares_v2_client.get_share_instance(share_instances[0]['id'],
+                                                      version='2.3')
+
+        expected_keys = ['host', 'share_id', 'id', 'share_network_id',
+                         'status', 'availability_zone', 'share_server_id',
+                         'export_locations', 'export_location', 'created_at']
+        actual_keys = si.keys()
+        self.assertEqual(sorted(expected_keys), sorted(actual_keys),
+                         'Share instance %s returned incorrect keys; '
+                         'expected %s, got %s.' % (si['id'],
+                                                   sorted(expected_keys),
+                                                   sorted(actual_keys)))
diff --git a/manila_tempest_tests/tests/api/base.py b/manila_tempest_tests/tests/api/base.py
index 65e299d..591347e 100644
--- a/manila_tempest_tests/tests/api/base.py
+++ b/manila_tempest_tests/tests/api/base.py
@@ -98,7 +98,8 @@
     def get_client_with_isolated_creds(cls,
                                        name=None,
                                        type_of_creds="admin",
-                                       cleanup_in_class=False):
+                                       cleanup_in_class=False,
+                                       client_version='1'):
         """Creates isolated creds.
 
         :param name: name, will be used for naming ic and related stuff
@@ -126,7 +127,10 @@
 
         # create client with isolated creds
         os = clients.Manager(credentials=creds)
-        client = os.shares_client
+        if client_version == '1':
+            client = os.shares_client
+        elif client_version == '2':
+            client = os.shares_v2_client
 
         # Set place where will be deleted isolated creds
         ic_res = {
@@ -183,7 +187,9 @@
             nc = cls.os.network_client
             share_network_id = cls.provide_share_network(sc, nc)
             cls.os.shares_client.share_network_id = share_network_id
+            cls.os.shares_v2_client.share_network_id = share_network_id
         cls.shares_client = cls.os.shares_client
+        cls.shares_v2_client = cls.os.shares_v2_client
 
     def setUp(self):
         super(BaseSharesTest, self).setUp()
@@ -281,12 +287,12 @@
                       snapshot_id=None, description=None, metadata=None,
                       share_network_id=None, share_type_id=None,
                       consistency_group_id=None, client=None,
-                      cleanup_in_class=True, is_public=False):
+                      cleanup_in_class=True, is_public=False, **kwargs):
         client = client or cls.shares_client
         description = description or "Tempest's share"
         share_network_id = share_network_id or client.share_network_id or None
         metadata = metadata or {}
-        kwargs = {
+        kwargs.update({
             'share_protocol': share_protocol,
             'size': size,
             'name': name,
@@ -296,7 +302,7 @@
             'share_network_id': share_network_id,
             'share_type_id': share_type_id,
             'is_public': is_public,
-        }
+        })
         if consistency_group_id:
             kwargs['consistency_group_id'] = consistency_group_id
 
@@ -309,9 +315,9 @@
         return share
 
     @classmethod
-    def migrate_share(cls, share_id, dest_host, client=None):
-        client = client or cls.shares_client
-        client.migrate_share(share_id, dest_host)
+    def migrate_share(cls, share_id, dest_host, client=None, **kwargs):
+        client = client or cls.shares_v2_client
+        client.migrate_share(share_id, dest_host, **kwargs)
         share = client.wait_for_migration_completed(share_id, dest_host)
         return share
 
@@ -383,7 +389,7 @@
     @classmethod
     def create_consistency_group(cls, client=None, cleanup_in_class=True,
                                  share_network_id=None, **kwargs):
-        client = client or cls.shares_client
+        client = client or cls.shares_v2_client
         kwargs['share_network_id'] = (share_network_id or
                                       client.share_network_id or None)
         consistency_group = client.create_consistency_group(**kwargs)
@@ -440,12 +446,15 @@
     @classmethod
     def create_cgsnapshot_wait_for_active(cls, consistency_group_id,
                                           name=None, description=None,
-                                          client=None, cleanup_in_class=True):
-        client = client or cls.shares_client
+                                          client=None, cleanup_in_class=True,
+                                          **kwargs):
+        client = client or cls.shares_v2_client
         if description is None:
             description = "Tempest's cgsnapshot"
-        cgsnapshot = client.create_cgsnapshot(consistency_group_id, name=name,
-                                              description=description)
+        cgsnapshot = client.create_cgsnapshot(consistency_group_id,
+                                              name=name,
+                                              description=description,
+                                              **kwargs)
         resource = {
             "type": "cgsnapshot",
             "id": cgsnapshot["id"],
@@ -556,11 +565,12 @@
                 client = res["client"]
                 with handle_cleanup_exceptions():
                     if res["type"] is "share":
-                        params = None
                         cg_id = res.get('consistency_group_id')
                         if cg_id:
                             params = {'consistency_group_id': cg_id}
-                        client.delete_share(res_id, params=params)
+                            client.delete_share(res_id, params=params)
+                        else:
+                            client.delete_share(res_id)
                         client.wait_for_resource_deletion(share_id=res_id)
                     elif res["type"] is "snapshot":
                         client.delete_snapshot(res_id)
@@ -679,6 +689,7 @@
         cls.os = clients.AltManager()
         alt_share_network_id = CONF.share.alt_share_network_id
         cls.os.shares_client.share_network_id = alt_share_network_id
+        cls.os.shares_v2_client.share_network_id = alt_share_network_id
         super(BaseSharesAltTest, cls).resource_setup()
 
 
@@ -694,4 +705,5 @@
         cls.os = clients.AdminManager()
         admin_share_network_id = CONF.share.admin_share_network_id
         cls.os.shares_client.share_network_id = admin_share_network_id
+        cls.os.shares_v2_client.share_network_id = admin_share_network_id
         super(BaseSharesAdminTest, cls).resource_setup()
diff --git a/manila_tempest_tests/tests/api/test_consistency_group_actions.py b/manila_tempest_tests/tests/api/test_consistency_group_actions.py
index 81bff8a..0bf6e58 100644
--- a/manila_tempest_tests/tests/api/test_consistency_group_actions.py
+++ b/manila_tempest_tests/tests/api/test_consistency_group_actions.py
@@ -57,6 +57,7 @@
             size=cls.share_size,
             consistency_group_id=cls.consistency_group['id'],
             metadata={'key': 'value'},
+            client=cls.shares_v2_client,
         )
 
         cls.share_name2 = data_utils.rand_name("tempest-share-name")
@@ -67,6 +68,7 @@
             description=cls.share_desc2,
             size=cls.share_size2,
             consistency_group_id=cls.consistency_group['id'],
+            client=cls.shares_v2_client,
         )
 
         cls.cgsnap_name = data_utils.rand_name("tempest-cgsnap-name")
@@ -93,6 +95,7 @@
             description=cls.share_desc3,
             size=cls.share_size,
             consistency_group_id=cls.consistency_group2['id'],
+            client=cls.shares_v2_client,
         )
 
         cls.cgsnap_name2 = data_utils.rand_name("tempest-cgsnap-name")
@@ -103,11 +106,11 @@
             description=cls.cgsnap_desc2)
 
     @test.attr(type=["gate", ])
-    def test_get_consistency_group(self):
+    def test_get_consistency_group_v2_4(self):
 
         # Get consistency group
-        consistency_group = self.shares_client.get_consistency_group(
-            self.consistency_group['id'])
+        consistency_group = self.shares_v2_client.get_consistency_group(
+            self.consistency_group['id'], version='2.4')
 
         # Verify keys
         actual_keys = set(consistency_group.keys())
@@ -129,10 +132,11 @@
                          msg)
 
     @test.attr(type=["gate", ])
-    def test_get_share(self):
+    def test_get_share_v2_4(self):
 
         # Get share
-        share = self.shares_client.get_share(self.share['id'])
+        share = self.shares_v2_client.get_share(self.share['id'],
+                                                version='2.4')
 
         # Verify keys
         expected_keys = {"status", "description", "links", "availability_zone",
@@ -165,10 +169,11 @@
             self.consistency_group["id"], share["consistency_group_id"], msg)
 
     @test.attr(type=["gate", ])
-    def test_list_consistency_groups(self):
+    def test_list_consistency_groups_v2_4(self):
 
         # List consistency groups
-        consistency_groups = self.shares_client.list_consistency_groups()
+        consistency_groups = self.shares_v2_client.list_consistency_groups(
+            version='2.4')
 
         # Verify keys
         [self.assertEqual(CG_SIMPLE_KEYS, set(cg.keys())) for cg in
@@ -184,11 +189,11 @@
             self.assertEqual(1, len(gen), msg)
 
     @test.attr(type=["gate", ])
-    def test_list_consistency_groups_with_detail(self):
+    def test_list_consistency_groups_with_detail_v2_4(self):
 
         # List consistency groups
-        consistency_groups = self.shares_client.list_consistency_groups(
-            detailed=True)
+        consistency_groups = self.shares_v2_client.list_consistency_groups(
+            detailed=True, version='2.4')
 
         # Verify keys
         [self.assertTrue(CG_DETAIL_REQUIRED_KEYS.issubset(set(cg.keys())))
@@ -204,10 +209,13 @@
             self.assertEqual(1, len(gen), msg)
 
     @test.attr(type=["gate", ])
-    def test_filter_shares_by_consistency_group_id(self):
+    def test_filter_shares_by_consistency_group_id_v2_4(self):
 
-        shares = self.shares_client.list_shares(detailed=True, params={
-            'consistency_group_id': self.consistency_group['id']})
+        shares = self.shares_v2_client.list_shares(
+            detailed=True,
+            params={'consistency_group_id': self.consistency_group['id']},
+            version='2.4'
+        )
 
         share_ids = [share['id'] for share in shares]
 
@@ -222,10 +230,10 @@
                       % (self.share['id'], share_ids))
 
     @test.attr(type=["gate", ])
-    def test_get_cgsnapshot(self):
+    def test_get_cgsnapshot_v2_4(self):
         # Get consistency group
-        consistency_group = self.shares_client.get_consistency_group(
-            self.consistency_group['id'])
+        consistency_group = self.shares_v2_client.get_consistency_group(
+            self.consistency_group['id'], version='2.4')
 
         # Verify keys
         actual_keys = set(consistency_group.keys())
@@ -247,10 +255,10 @@
                          msg)
 
     @test.attr(type=["gate", ])
-    def test_get_cgsnapshot_members(self):
+    def test_get_cgsnapshot_members_v2_4(self):
 
-        cgsnapshot_members = self.shares_client.list_cgsnapshot_members(
-            self.cgsnapshot['id'])
+        cgsnapshot_members = self.shares_v2_client.list_cgsnapshot_members(
+            self.cgsnapshot['id'], version='2.4')
         member_share_ids = [member['share_id'] for member in
                             cgsnapshot_members]
         self.assertEqual(2, len(cgsnapshot_members),
@@ -272,17 +280,22 @@
                     #                  member['share_type_id'])
 
     @test.attr(type=["gate", "smoke", ])
-    def test_create_consistency_group_from_populated_cgsnapshot(self):
+    def test_create_consistency_group_from_populated_cgsnapshot_v2_4(self):
 
-        cgsnapshot_members = self.shares_client.list_cgsnapshot_members(
-            self.cgsnapshot['id'])
+        cgsnapshot_members = self.shares_v2_client.list_cgsnapshot_members(
+            self.cgsnapshot['id'], version='2.4')
 
         new_consistency_group = self.create_consistency_group(
-            cleanup_in_class=False, source_cgsnapshot_id=self.cgsnapshot['id'])
+            cleanup_in_class=False,
+            source_cgsnapshot_id=self.cgsnapshot['id'],
+            version='2.4'
+        )
 
-        new_shares = self.shares_client.list_shares(
+        new_shares = self.shares_v2_client.list_shares(
             params={'consistency_group_id': new_consistency_group['id']},
-            detailed=True)
+            detailed=True,
+            version='2.4'
+        )
 
         # Verify each new share is available
         for share in new_shares:
@@ -326,46 +339,58 @@
         )
 
     @test.attr(type=["gate", ])
-    def test_update_consistency_group(self):
+    def test_update_consistency_group_v2_4(self):
 
         # Get consistency_group
-        consistency_group = self.shares_client.get_consistency_group(
-            self.consistency_group['id'])
+        consistency_group = self.shares_v2_client.get_consistency_group(
+            self.consistency_group['id'], version='2.4')
         self.assertEqual(self.cg_name, consistency_group["name"])
         self.assertEqual(self.cg_desc, consistency_group["description"])
 
         # Update consistency_group
         new_name = data_utils.rand_name("tempest-new-name")
         new_desc = data_utils.rand_name("tempest-new-description")
-        updated = self.shares_client.update_consistency_group(
-            consistency_group["id"], name=new_name, description=new_desc)
+        updated = self.shares_v2_client.update_consistency_group(
+            consistency_group["id"],
+            name=new_name,
+            description=new_desc,
+            version='2.4'
+        )
         self.assertEqual(new_name, updated["name"])
         self.assertEqual(new_desc, updated["description"])
 
         # Get consistency_group
-        consistency_group = self.shares_client.get_consistency_group(
-            self.consistency_group['id'])
+        consistency_group = self.shares_v2_client.get_consistency_group(
+            self.consistency_group['id'], version='2.4')
         self.assertEqual(new_name, consistency_group["name"])
         self.assertEqual(new_desc, consistency_group["description"])
 
     @test.attr(type=["gate", ])
-    def test_create_update_read_consistency_group_with_unicode(self):
+    def test_create_update_read_consistency_group_with_unicode_v2_4(self):
         value1 = u'ಠ_ಠ'
         value2 = u'ಠ_ರೃ'
         # Create consistency_group
         consistency_group = self.create_consistency_group(
-            cleanup_in_class=False, name=value1, description=value1)
+            cleanup_in_class=False,
+            name=value1,
+            description=value1,
+            version='2.4'
+        )
         self.assertEqual(value1, consistency_group["name"])
         self.assertEqual(value1, consistency_group["description"])
 
         # Update consistency_group
-        updated = self.shares_client.update_consistency_group(
-            consistency_group["id"], name=value2, description=value2)
+        updated = self.shares_v2_client.update_consistency_group(
+            consistency_group["id"],
+            name=value2,
+            description=value2,
+            version='2.4'
+        )
         self.assertEqual(value2, updated["name"])
         self.assertEqual(value2, updated["description"])
 
         # Get consistency_group
-        consistency_group = self.shares_client.get_consistency_group(
-            consistency_group['id'])
+        consistency_group = self.shares_v2_client.get_consistency_group(
+            consistency_group['id'], version='2.4')
         self.assertEqual(value2, consistency_group["name"])
         self.assertEqual(value2, consistency_group["description"])
diff --git a/manila_tempest_tests/tests/api/test_consistency_groups.py b/manila_tempest_tests/tests/api/test_consistency_groups.py
index 1ba3902..33ea334 100644
--- a/manila_tempest_tests/tests/api/test_consistency_groups.py
+++ b/manila_tempest_tests/tests/api/test_consistency_groups.py
@@ -33,10 +33,10 @@
     """Covers consistency group functionality."""
 
     @test.attr(type=["gate", ])
-    def test_create_populate_delete_consistency_group(self):
+    def test_create_populate_delete_consistency_group_v2_4(self):
         # Create a consistency group
         consistency_group = self.create_consistency_group(
-            cleanup_in_class=False)
+            cleanup_in_class=False, version='2.4')
         self.assertTrue(CG_REQUIRED_ELEMENTS.issubset(
             consistency_group.keys()),
             'At least one expected element missing from consistency group '
@@ -45,31 +45,35 @@
                 "actual": consistency_group.keys()})
         # Populate
         share = self.create_share(consistency_group_id=consistency_group['id'],
-                                  cleanup_in_class=False)
+                                  cleanup_in_class=False,
+                                  client=self.shares_v2_client,
+                                  version='2.4')
         # Delete
         params = {"consistency_group_id": consistency_group['id']}
-        self.shares_client.delete_share(share['id'], params=params)
+        self.shares_v2_client.delete_share(share['id'], params=params,
+                                           version='2.4')
         self.shares_client.wait_for_resource_deletion(share_id=share['id'])
-        self.shares_client.delete_consistency_group(consistency_group['id'])
-        self.shares_client.wait_for_resource_deletion(
+        self.shares_v2_client.delete_consistency_group(consistency_group['id'],
+                                                       version='2.4')
+        self.shares_v2_client.wait_for_resource_deletion(
             cg_id=consistency_group['id'])
 
         # Verify
         self.assertRaises(lib_exc.NotFound,
-                          self.shares_client.get_consistency_group,
+                          self.shares_v2_client.get_consistency_group,
                           consistency_group['id'])
         self.assertRaises(lib_exc.NotFound,
                           self.shares_client.get_share,
                           share['id'])
 
     @test.attr(type=["gate", ])
-    def test_create_delete_empty_cgsnapshot(self):
+    def test_create_delete_empty_cgsnapshot_v2_4(self):
         # Create base consistency group
         consistency_group = self.create_consistency_group(
-            cleanup_in_class=False)
+            cleanup_in_class=False, version='2.4')
         # Create cgsnapshot
         cgsnapshot = self.create_cgsnapshot_wait_for_active(
-            consistency_group["id"], cleanup_in_class=False)
+            consistency_group["id"], cleanup_in_class=False, version='2.4')
 
         self.assertTrue(CGSNAPSHOT_REQUIRED_ELEMENTS.issubset(
             cgsnapshot.keys()),
@@ -78,19 +82,22 @@
                 "expected": CGSNAPSHOT_REQUIRED_ELEMENTS,
                 "actual": cgsnapshot.keys()})
 
-        cgsnapshot_members = self.shares_client.list_cgsnapshot_members(
-            cgsnapshot['id'])
+        cgsnapshot_members = self.shares_v2_client.list_cgsnapshot_members(
+            cgsnapshot['id'], version='2.4')
 
         self.assertEmpty(cgsnapshot_members,
                          'Expected 0 cgsnapshot members, got %s' % len(
                              cgsnapshot_members))
 
         # delete snapshot
-        self.shares_client.delete_cgsnapshot(cgsnapshot["id"])
-        self.shares_client.wait_for_resource_deletion(
+        self.shares_v2_client.delete_cgsnapshot(cgsnapshot["id"],
+                                                version='2.4')
+        self.shares_v2_client.wait_for_resource_deletion(
             cgsnapshot_id=cgsnapshot["id"])
         self.assertRaises(lib_exc.NotFound,
-                          self.shares_client.get_cgsnapshot, cgsnapshot['id'])
+                          self.shares_v2_client.get_cgsnapshot,
+                          cgsnapshot['id'],
+                          version='2.4')
 
     @test.attr(type=["gate", "smoke", ])
     def test_create_consistency_group_from_empty_cgsnapshot(self):
@@ -102,7 +109,7 @@
         cgsnapshot = self.create_cgsnapshot_wait_for_active(
             consistency_group["id"], cleanup_in_class=False)
 
-        cgsnapshot_members = self.shares_client.list_cgsnapshot_members(
+        cgsnapshot_members = self.shares_v2_client.list_cgsnapshot_members(
             cgsnapshot['id'])
 
         self.assertEmpty(cgsnapshot_members,
@@ -123,8 +130,8 @@
         self.assertEqual(new_consistency_group['source_cgsnapshot_id'],
                          cgsnapshot['id'], msg)
 
-        msg = 'Unexpected share_types on new consistency group. Expected %s, ' \
-              'got %s.' % (consistency_group['share_types'],
-                           new_consistency_group['share_types'])
+        msg = ('Unexpected share_types on new consistency group. Expected '
+               '%s, got %s.' % (consistency_group['share_types'],
+                                new_consistency_group['share_types']))
         self.assertEqual(sorted(consistency_group['share_types']),
                          sorted(new_consistency_group['share_types']), msg)
diff --git a/manila_tempest_tests/tests/api/test_consistency_groups_negative.py b/manila_tempest_tests/tests/api/test_consistency_groups_negative.py
index 7c813c0..34c0a6d 100644
--- a/manila_tempest_tests/tests/api/test_consistency_groups_negative.py
+++ b/manila_tempest_tests/tests/api/test_consistency_groups_negative.py
@@ -46,7 +46,8 @@
             name=cls.share_name,
             description=cls.share_desc,
             size=cls.share_size,
-            consistency_group_id=cls.consistency_group['id']
+            consistency_group_id=cls.consistency_group['id'],
+            client=cls.shares_v2_client
         )
         # Create a cgsnapshot of the consistency group
         cls.cgsnap_name = data_utils.rand_name("tempest-cgsnap-name")
@@ -57,149 +58,174 @@
             description=cls.cgsnap_desc)
 
     @test.attr(type=["negative", "smoke", "gate", ])
-    def test_create_cg_with_invalid_source_cgsnapshot_id_value(
+    def test_create_cg_with_invalid_source_cgsnapshot_id_value_v2_4(
             self):
         self.assertRaises(lib_exc.BadRequest,
                           self.create_consistency_group,
                           source_cgsnapshot_id='foobar',
-                          cleanup_in_class=False)
+                          cleanup_in_class=False,
+                          version='2.4')
 
     @test.attr(type=["negative", "smoke", "gate", ])
-    def test_create_cg_with_nonexistent_source_cgsnapshot_id_value(self):
+    def test_create_cg_with_nonexistent_source_cgsnapshot_id_value_v2_4(self):
         self.assertRaises(lib_exc.BadRequest,
                           self.create_consistency_group,
                           source_cgsnapshot_id=self.share['id'],
-                          cleanup_in_class=False)
+                          cleanup_in_class=False,
+                          version='2.4')
 
     @test.attr(type=["negative", "smoke", "gate", ])
-    def test_create_cg_with_invalid_share_network_id_value(
-            self):
+    def test_create_cg_with_invalid_share_network_id_value_v2_4(self):
         self.assertRaises(lib_exc.BadRequest,
                           self.create_consistency_group,
                           share_network_id='foobar',
-                          cleanup_in_class=False)
+                          cleanup_in_class=False,
+                          version='2.4')
 
     @test.attr(type=["negative", "smoke", "gate", ])
-    def test_create_cg_with_nonexistent_share_network_id_value(self):
+    def test_create_cg_with_nonexistent_share_network_id_value_v2_4(self):
         self.assertRaises(lib_exc.BadRequest,
                           self.create_consistency_group,
                           share_network_id=self.share['id'],
-                          cleanup_in_class=False)
+                          cleanup_in_class=False,
+                          version='2.4')
 
     @test.attr(type=["negative", "smoke", "gate", ])
-    def test_create_cg_with_invalid_share_type_id_value(
-            self):
+    def test_create_cg_with_invalid_share_type_id_value_v2_4(self):
         self.assertRaises(lib_exc.BadRequest,
                           self.create_consistency_group,
                           share_type_ids=['foobar'],
-                          cleanup_in_class=False)
+                          cleanup_in_class=False,
+                          version='2.4')
 
     @test.attr(type=["negative", "smoke", "gate", ])
-    def test_create_cg_with_nonexistent_share_type_id_value(self):
+    def test_create_cg_with_nonexistent_share_type_id_value_v2_4(self):
         self.assertRaises(lib_exc.BadRequest,
                           self.create_consistency_group,
                           share_type_ids=[self.share['id']],
-                          cleanup_in_class=False)
+                          cleanup_in_class=False,
+                          version='2.4')
 
     @test.attr(type=["negative", "smoke", "gate", ])
-    def test_create_cgsnapshot_with_invalid_cg_id_value(
-            self):
+    def test_create_cgsnapshot_with_invalid_cg_id_value_v2_4(self):
         self.assertRaises(lib_exc.BadRequest,
                           self.create_cgsnapshot_wait_for_active,
                           'foobar',
-                          cleanup_in_class=False)
+                          cleanup_in_class=False,
+                          version='2.4')
 
     @test.attr(type=["negative", "smoke", "gate", ])
-    def test_create_cgsnapshot_with_nonexistent_cg_id_value(self):
+    def test_create_cgsnapshot_with_nonexistent_cg_id_value_v2_4(self):
         self.assertRaises(lib_exc.BadRequest,
                           self.create_cgsnapshot_wait_for_active,
                           self.share['id'],
-                          cleanup_in_class=False)
+                          cleanup_in_class=False,
+                          version='2.4')
 
     @test.attr(type=["negative", "smoke", "gate", ])
-    def test_get_cg_with_wrong_id(self):
+    def test_get_cg_with_wrong_id_v2_4(self):
         self.assertRaises(lib_exc.NotFound,
-                          self.shares_client.get_consistency_group,
-                          "wrong_consistency_group_id")
+                          self.shares_v2_client.get_consistency_group,
+                          "wrong_consistency_group_id",
+                          version='2.4')
 
     @test.attr(type=["negative", "smoke", "gate", ])
-    def test_get_cg_without_passing_cg_id(self):
+    def test_get_cg_without_passing_cg_id_v2_4(self):
         self.assertRaises(lib_exc.NotFound,
-                          self.shares_client.get_consistency_group, '')
+                          self.shares_v2_client.get_consistency_group,
+                          '',
+                          version='2.4')
 
     @test.attr(type=["negative", "smoke", "gate", ])
-    def test_update_cg_with_wrong_id(self):
+    def test_update_cg_with_wrong_id_v2_4(self):
         self.assertRaises(lib_exc.NotFound,
-                          self.shares_client.update_consistency_group,
+                          self.shares_v2_client.update_consistency_group,
                           'wrong_consistency_group_id',
                           name='new_name',
-                          description='new_description')
+                          description='new_description',
+                          version='2.4')
 
     @test.attr(type=["negative", "smoke", "gate", ])
-    def test_delete_cg_with_wrong_id(self):
+    def test_delete_cg_with_wrong_id_v2_4(self):
         self.assertRaises(lib_exc.NotFound,
-                          self.shares_client.delete_consistency_group,
-                          "wrong_consistency_group_id")
+                          self.shares_v2_client.delete_consistency_group,
+                          "wrong_consistency_group_id",
+                          version='2.4')
 
     @test.attr(type=["negative", "smoke", "gate", ])
-    def test_delete_cg_without_passing_cg_id(self):
+    def test_delete_cg_without_passing_cg_id_v2_4(self):
         self.assertRaises(lib_exc.NotFound,
-                          self.shares_client.delete_consistency_group, '')
+                          self.shares_v2_client.delete_consistency_group,
+                          '',
+                          version='2.4')
 
     @test.attr(type=["negative", "gate", ])
-    def test_delete_cg_in_use_by_cgsnapshot(self):
+    def test_delete_cg_in_use_by_cgsnapshot_v2_4(self):
         # Attempt delete of share type
         self.assertRaises(lib_exc.Conflict,
-                          self.shares_client.delete_consistency_group,
-                          self.consistency_group['id'])
+                          self.shares_v2_client.delete_consistency_group,
+                          self.consistency_group['id'],
+                          version='2.4')
 
     @test.attr(type=["negative", "gate", ])
-    def test_delete_share_in_use_by_cgsnapshot(self):
+    def test_delete_share_in_use_by_cgsnapshot_v2_4(self):
         # Attempt delete of share type
         params = {'consistency_group_id': self.share['consistency_group_id']}
         self.assertRaises(lib_exc.Forbidden,
-                          self.shares_client.delete_share,
+                          self.shares_v2_client.delete_share,
                           self.share['id'],
-                          params=params)
+                          params=params,
+                          version='2.4')
 
     @test.attr(type=["negative", "smoke", "gate", ])
-    def test_delete_cg_containing_a_share(self):
+    def test_delete_cg_containing_a_share_v2_4(self):
         self.assertRaises(lib_exc.Conflict,
-                          self.shares_client.delete_consistency_group,
-                          self.consistency_group['id'])
+                          self.shares_v2_client.delete_consistency_group,
+                          self.consistency_group['id'],
+                          version='2.4')
         # Verify consistency group is not put into error state from conflict
-        cg = self.shares_client.get_consistency_group(
-            self.consistency_group['id'])
+        cg = self.shares_v2_client.get_consistency_group(
+            self.consistency_group['id'], version='2.4')
         self.assertEqual('available', cg['status'])
 
     @test.attr(type=["negative", "smoke", "gate", ])
-    def test_filter_shares_on_invalid_cg_id(self):
-        shares = self.shares_client.list_shares(detailed=True, params={
-            'consistency_group_id': 'foobar'})
+    def test_filter_shares_on_invalid_cg_id_v2_4(self):
+        shares = self.shares_v2_client.list_shares(
+            detailed=True,
+            params={'consistency_group_id': 'foobar'},
+            version='2.4'
+        )
 
-        self.assertEqual(0, len(shares), 'Incorrect number of shares '
-                                         'returned. Expected 0, got %s.' %
-                         len(shares))
+        self.assertEqual(0, len(shares),
+                         'Incorrect number of shares returned. Expected 0, '
+                         'got %s.' % len(shares))
 
     @test.attr(type=["negative", "smoke", "gate", ])
-    def test_filter_shares_on_nonexistent_cg_id(self):
-        shares = self.shares_client.list_shares(detailed=True, params={
-            'consistency_group_id': self.share['id']})
+    def test_filter_shares_on_nonexistent_cg_id_v2_4(self):
+        shares = self.shares_v2_client.list_shares(
+            detailed=True,
+            params={'consistency_group_id': self.share['id']},
+            version='2.4'
+        )
 
-        self.assertEqual(0, len(shares), 'Incorrect number of shares '
-                                         'returned. Expected 0, got %s.' %
-                         len(shares))
+        self.assertEqual(0, len(shares),
+                         'Incorrect number of shares returned. Expected 0, '
+                         'got %s.' % len(shares))
 
     @test.attr(type=["negative", "smoke", "gate", ])
-    def test_filter_shares_on_empty_cg_id(self):
+    def test_filter_shares_on_empty_cg_id_v2_4(self):
         consistency_group = self.create_consistency_group(
             name='tempest_cg',
             description='tempest_cg_desc',
             cleanup_in_class=False,
+            version='2.4',
         )
-        shares = self.shares_client.list_shares(detailed=True, params={
-            'consistency_group_id': consistency_group['id']})
+        shares = self.shares_v2_client.list_shares(
+            detailed=True,
+            params={'consistency_group_id': consistency_group['id']},
+            version='2.4',
+        )
 
-        self.assertEqual(0, len(shares), 'Incorrect number of shares '
-                                         'returned. Expected 0, got %s.' %
-                         len(shares))
+        self.assertEqual(0, len(shares),
+                         'Incorrect number of shares returned. Expected 0, '
+                         'got %s.' % len(shares))
diff --git a/manila_tempest_tests/tests/api/test_microversions.py b/manila_tempest_tests/tests/api/test_microversions.py
index 2984b04..1de8b59 100644
--- a/manila_tempest_tests/tests/api/test_microversions.py
+++ b/manila_tempest_tests/tests/api/test_microversions.py
@@ -1,4 +1,5 @@
 # Copyright 2015 Goutham Pacha Ravi
+# Copyright 2015 Clinton Knight
 # All Rights Reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -20,90 +21,152 @@
 
 CONF = config.CONF
 
+API_MICROVERSIONS_HEADER_LOWER = 'x-openstack-manila-api-version'
+API_MICROVERSIONS_HEADER = 'X-OpenStack-Manila-API-Version'
+_MIN_API_VERSION = CONF.share.min_api_microversion
+_MAX_API_VERSION = CONF.share.max_api_microversion
+
 
 class MicroversionsTest(base.BaseSharesTest):
     """Request and validate REST API Microversions.
 
-    Sends a HTTP GET request with the base endpoint to request a Microversion.
+    Sends HTTP GET requests to the version API to validate microversions.
     """
 
-    _MIN_API_VERSION = CONF.share.min_api_microversion
-    _MAX_API_VERSION = CONF.share.max_api_microversion
+    @test.attr(type=["gate", "smoke", ])
+    def test_microversions_root_version(self):
+
+        resp, resp_body = self.shares_v2_client.send_microversion_request()
+
+        self.assertEqual(300, resp.status)
+
+        version_list = resp_body['versions']
+        ids = [v['id'] for v in version_list]
+        self.assertEqual({'v1.0', 'v2.0'}, set(ids))
+
+        self.assertNotIn(API_MICROVERSIONS_HEADER_LOWER, resp)
+        self.assertNotIn('vary', resp)
+
+        v1 = [v for v in version_list if v['id'] == 'v1.0'][0]
+        self.assertEqual('', v1.get('min_version'))
+        self.assertEqual('', v1.get('version'))
+
+        v2 = [v for v in version_list if v['id'] == 'v2.0'][0]
+        self.assertEqual(_MIN_API_VERSION, v2.get('min_version'))
+        self.assertEqual(_MAX_API_VERSION, v2.get('version'))
 
     @test.attr(type=["gate", "smoke", ])
-    def test_microversions_no_version(self):
-        resp, resp_body = self.shares_client.send_microversion_request()
+    def test_microversions_v1_no_version(self):
 
-        self.assertEqual(self._MIN_API_VERSION,
-                         resp[self.shares_client.API_MICROVERSIONS_HEADER])
-        self.assertTrue(len(resp_body['versions']) > 0)
-        self.assertNotIn('min_version', resp_body['versions'][0])
-        self.assertNotIn('version', resp_body['versions'][0])
+        resp, resp_body = self.shares_v2_client.send_microversion_request(
+            script_name='v1')
+
+        self.assertEqual(200, resp.status)
+
+        version_list = resp_body['versions']
+        ids = [v['id'] for v in version_list]
+        self.assertEqual({'v1.0'}, set(ids))
+
+        self.assertEqual('1.0', resp.get(API_MICROVERSIONS_HEADER_LOWER))
+        self.assertEqual(API_MICROVERSIONS_HEADER, resp.get('vary'))
+        self.assertEqual('', version_list[0].get('min_version'))
+        self.assertEqual('', version_list[0].get('version'))
 
     @test.attr(type=["gate", "smoke", ])
-    def test_microversions_version_min_version(self):
-        """Requests base version 1.0."""
+    def test_microversions_v1_with_version(self):
 
-        resp, resp_body = self.shares_client.send_microversion_request(
-            self._MIN_API_VERSION)
+        resp, resp_body = self.shares_v2_client.send_microversion_request(
+            script_name='v1', version='5.0')
 
-        self.assertEqual(self._MIN_API_VERSION,
-                         resp[self.shares_client.API_MICROVERSIONS_HEADER])
-        self.assertTrue(len(resp_body['versions']) > 0)
-        self.assertNotIn('min_version', resp_body['versions'][0])
-        self.assertNotIn('version', resp_body['versions'][0])
+        self.assertEqual(200, resp.status)
+
+        version_list = resp_body['versions']
+        ids = [v['id'] for v in version_list]
+        self.assertEqual({'v1.0'}, set(ids))
+
+        self.assertEqual('1.0', resp.get(API_MICROVERSIONS_HEADER_LOWER))
+        self.assertEqual(API_MICROVERSIONS_HEADER, resp.get('vary'))
+        self.assertEqual('', version_list[0].get('min_version'))
+        self.assertEqual('', version_list[0].get('version'))
 
     @test.attr(type=["gate", "smoke", ])
-    def test_microversions_version_max_configured_version(self):
-        """Requests maximum API microversion.
+    def test_microversions_v2_no_version(self):
 
-        Requests the current maximum API microversion from the Manila API
-        service, and confirms that version is the same as what Tempest is
-        configured to request in other versioned API calls.
-        """
+        resp, resp_body = self.shares_v2_client.send_microversion_request(
+            script_name='v2')
 
-        resp, resp_body = self.shares_client.send_microversion_request(
-            self._MAX_API_VERSION)
+        self.assertEqual(200, resp.status)
 
-        self.assertEqual(self._MAX_API_VERSION,
-                         resp[self.shares_client.API_MICROVERSIONS_HEADER])
-        self.assertTrue(len(resp_body['versions']) > 0)
-        self.assertEqual(self._MAX_API_VERSION,
-                         resp_body['versions'][0]['version'])
+        version_list = resp_body['versions']
+        ids = [v['id'] for v in version_list]
+        self.assertEqual({'v2.0'}, set(ids))
+
+        self.assertEqual(_MIN_API_VERSION,
+                         resp.get(API_MICROVERSIONS_HEADER_LOWER))
+        self.assertEqual(API_MICROVERSIONS_HEADER, resp.get('vary'))
+        self.assertEqual(_MIN_API_VERSION, version_list[0].get('min_version'))
+        self.assertEqual(_MAX_API_VERSION, version_list[0].get('version'))
 
     @test.attr(type=["gate", "smoke", ])
-    def test_microversions_version_1_1(self):
-        """Requests version 1.1, the first Manila microversion."""
+    def test_microversions_v2_min_version(self):
 
-        resp, resp_body = self.shares_client.send_microversion_request('1.1')
+        resp, resp_body = self.shares_v2_client.send_microversion_request(
+            script_name='v2', version=_MIN_API_VERSION)
 
-        self.assertEqual('1.1',
-                         resp[self.shares_client.API_MICROVERSIONS_HEADER])
-        self.assertTrue(len(resp_body['versions']) > 0)
-        self.assertEqual(self._MIN_API_VERSION,
-                         resp_body['versions'][0]['min_version'])
+        self.assertEqual(200, resp.status)
+
+        version_list = resp_body['versions']
+        ids = [v['id'] for v in version_list]
+        self.assertEqual({'v2.0'}, set(ids))
+
+        self.assertEqual(_MIN_API_VERSION,
+                         resp.get(API_MICROVERSIONS_HEADER_LOWER))
+        self.assertEqual(API_MICROVERSIONS_HEADER, resp.get('vary'))
+        self.assertEqual(_MIN_API_VERSION, version_list[0].get('min_version'))
+        self.assertEqual(_MAX_API_VERSION, version_list[0].get('version'))
 
     @test.attr(type=["gate", "smoke", ])
-    def test_microversions_unavailable_versions(self):
-        """Requests a version greater than the latest available version."""
+    def test_microversions_v2_max_version(self):
 
-        resp, resp_body = self.shares_client.send_microversion_request('1.1')
-        self.assertTrue(len(resp_body['versions']) > 0)
-        major_ver, minor_ver = [int(ver) for ver in
-                                resp_body['versions'][0]['version'].split(".")]
-        req_version = ('%s.%s' % (major_ver + 1, minor_ver + 1))
-        resp, _ = self.shares_client.send_microversion_request(req_version)
+        resp, resp_body = self.shares_v2_client.send_microversion_request(
+            script_name='v2', version=_MAX_API_VERSION)
+
+        self.assertEqual(200, resp.status)
+
+        version_list = resp_body['versions']
+        ids = [v['id'] for v in version_list]
+        self.assertEqual({'v2.0'}, set(ids))
+
+        self.assertEqual(_MAX_API_VERSION,
+                         resp.get(API_MICROVERSIONS_HEADER_LOWER))
+        self.assertEqual(API_MICROVERSIONS_HEADER, resp.get('vary'))
+        self.assertEqual(_MIN_API_VERSION, version_list[0].get('min_version'))
+        self.assertEqual(_MAX_API_VERSION, version_list[0].get('version'))
+
+    @test.attr(type=["gate", "smoke", ])
+    def test_microversions_v2_invalid_version(self):
+
+        resp, _ = self.shares_v2_client.send_microversion_request(
+            script_name='v2', version='1.2.1')
+
+        self.assertEqual(400, resp.status)
+
+    @test.attr(type=["gate", "smoke", ])
+    def test_microversions_v2_unacceptable_version(self):
+
+        # First get max version from the server
+        resp, resp_body = self.shares_v2_client.send_microversion_request(
+            script_name='v2')
+
+        self.assertEqual(200, resp.status)
+
+        version_list = resp_body['versions']
+        latest_version = version_list[0].get('version')
+        major, minor = [int(ver) for ver in latest_version.split(".")]
+        next_version = ('%s.%s' % (major + 1, minor + 1))
+
+        # Request a version that is too high
+        resp, _ = self.shares_v2_client.send_microversion_request(
+            script_name='v2', version=next_version)
 
         self.assertEqual(406, resp.status)
-
-    @test.attr(type=["gate", "smoke", ])
-    def test_microversions_invalid_versions(self):
-        """Requests invalid versions."""
-
-        resp, resp_body = self.shares_client.send_microversion_request('1.2.1')
-
-        self.assertEqual(400, resp.status)
-
-        resp, _ = self.shares_client.send_microversion_request('None')
-
-        self.assertEqual(400, resp.status)