Share Replication API and Scheduler Support

This patch provides the scheduler support to filter share
backends matching replication capabilities reported by the
hosts and the replication_type extra_spec provided via the
share_type during share creation.

It also adds wsgi routes, API endpoints and driver entry
routines to support the actions: list, show, create, delete
and promote share replicas. It augments the ShareInstance
DB model with a 'replica_state' attribute and the Share DB
Model with 'replication_type' attribute to support these
workflows.

Replica states are periodically updated from the respective
backends that the replicas are created on.

APIImpact
Impact on existing APIs:
In Microversion 2.11, the /shares APIs return 2 additional
fields during index and show calls for each share: 'has_replicas'
and 'replication_type'. Similarly, the field 'replica_state' is
added to the API response for /share-instances.
Also, deletion of a share that has replicas is forbidden,
returning error code 403.

DocImpact

Co-Authored-By: Alex Meade <mr.alex.meade@gmail.com>

Implements: blueprint manila-share-replication

Change-Id: I10515d55b1291c34777a31d8c6a3a1954f551235
diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py
index ad64b4b..e52ca42 100644
--- a/manila_tempest_tests/config.py
+++ b/manila_tempest_tests/config.py
@@ -36,7 +36,7 @@
                help="The minimum api microversion is configured to be the "
                     "value of the minimum microversion supported by Manila."),
     cfg.StrOpt("max_api_microversion",
-               default="2.10",
+               default="2.11",
                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/tests/api/test_shares.py b/manila_tempest_tests/tests/api/test_shares.py
index 2527aa9..7f8ae9f 100644
--- a/manila_tempest_tests/tests/api/test_shares.py
+++ b/manila_tempest_tests/tests/api/test_shares.py
@@ -13,10 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest import config  # noqa
-from tempest import test  # noqa
-from tempest_lib import exceptions as lib_exc  # noqa
-import testtools  # noqa
+from tempest import config
+from tempest import test
+from tempest_lib import exceptions as lib_exc
+import testtools
 
 from manila_tempest_tests.tests.api import base
 from manila_tempest_tests import utils
@@ -78,6 +78,12 @@
             detailed_elements.remove('export_location')
             self.assertTrue(detailed_elements.issubset(share_get.keys()), msg)
 
+        # In v 2.11 and beyond, we expect key 'replication_type' in the
+        # share data returned by the share create API.
+        if utils.is_microversion_supported('2.11'):
+            detailed_elements.add('replication_type')
+            self.assertTrue(detailed_elements.issubset(share.keys()), msg)
+
         # Delete share
         self.shares_v2_client.delete_share(share['id'])
         self.shares_v2_client.wait_for_resource_deletion(share_id=share['id'])
diff --git a/manila_tempest_tests/tests/api/test_shares_actions.py b/manila_tempest_tests/tests/api/test_shares_actions.py
index f249efb..703dc71 100644
--- a/manila_tempest_tests/tests/api/test_shares_actions.py
+++ b/manila_tempest_tests/tests/api/test_shares_actions.py
@@ -97,6 +97,8 @@
             expected_keys.append("share_type_name")
         if utils.is_microversion_ge(version, '2.10'):
             expected_keys.append("access_rules_status")
+        if utils.is_microversion_ge(version, '2.11'):
+            expected_keys.append("replication_type")
         actual_keys = list(share.keys())
         [self.assertIn(key, actual_keys) for key in expected_keys]
 
@@ -144,6 +146,11 @@
         self._get_share('2.10')
 
     @test.attr(type=["gate", ])
+    @utils.skip_if_microversion_not_supported('2.11')
+    def test_get_share_with_replication_type_key(self):
+        self._get_share('2.11')
+
+    @test.attr(type=["gate", ])
     def test_list_shares(self):
 
         # list shares
@@ -183,6 +190,8 @@
             keys.append("share_type_name")
         if utils.is_microversion_ge(version, '2.10'):
             keys.append("access_rules_status")
+        if utils.is_microversion_ge(version, '2.11'):
+            keys.append("replication_type")
 
         [self.assertIn(key, sh.keys()) for sh in shares for key in keys]
 
@@ -221,6 +230,11 @@
         self._list_shares_with_detail('2.10')
 
     @test.attr(type=["gate", ])
+    @utils.skip_if_microversion_not_supported('2.11')
+    def test_list_shares_with_detail_replication_type_key(self):
+        self._list_shares_with_detail('2.11')
+
+    @test.attr(type=["gate", ])
     def test_list_shares_with_detail_filter_by_metadata(self):
         filters = {'metadata': self.metadata}